[Telink] Peripheral modules optimization & Update builds to docker version 46 (#32754)

* [telink] Rename config option according to zephyr.

* [telink] Link application buttons from .dts.

* [telink] Fix Lock application building.

* [telink] Fix Window application building.

* [telink] Link application LEDs from .dts.

* [telink] Add pwm pool.

* [Telink] Add boards pwm overlays.

* [telink] Add led strip.

* [telink] Fix b92 builds.

* [Telink] Update Zephyr to specific revision

* [telink] Fix github builds.

* [Telink] Fix builds

* [Telink] Update builds to docker version 44

* Restyled by whitespace

* Restyled by clang-format

* [Telink] Update copyrights

* [Telink] Update builds to docker version 46

---------

Co-authored-by: Andrii Bilynskyi <andrii.bilynskyi@telink-semi.com>
Co-authored-by: Restyled.io <commits@restyled.io>
diff --git a/.github/workflows/bloat_check.yaml b/.github/workflows/bloat_check.yaml
index 148426d..7b97c51 100644
--- a/.github/workflows/bloat_check.yaml
+++ b/.github/workflows/bloat_check.yaml
@@ -34,7 +34,7 @@
         runs-on: ubuntu-latest
 
         container:
-            image: ghcr.io/project-chip/chip-build:41
+            image: ghcr.io/project-chip/chip-build:46
 
         steps:
             - name: Checkout
diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml
index 1da7dd0..f6abbd7 100644
--- a/.github/workflows/build.yaml
+++ b/.github/workflows/build.yaml
@@ -40,7 +40,7 @@
         if: github.actor != 'restyled-io[bot]'
 
         container:
-            image: ghcr.io/project-chip/chip-build:41
+            image: ghcr.io/project-chip/chip-build:46
             volumes:
                 - "/:/runner-root-volume"
                 - "/tmp/log_output:/tmp/test_logs"
@@ -136,7 +136,7 @@
         if: github.actor != 'restyled-io[bot]'
 
         container:
-            image: ghcr.io/project-chip/chip-build:41
+            image: ghcr.io/project-chip/chip-build:46
             volumes:
                 - "/:/runner-root-volume"
                 - "/tmp/log_output:/tmp/test_logs"
@@ -279,7 +279,7 @@
         if: github.actor != 'restyled-io[bot]'
 
         container:
-            image: ghcr.io/project-chip/chip-build:41
+            image: ghcr.io/project-chip/chip-build:46
             volumes:
                 - "/:/runner-root-volume"
                 - "/tmp/log_output:/tmp/test_logs"
@@ -340,7 +340,7 @@
         if: github.actor != 'restyled-io[bot]'
 
         container:
-            image: ghcr.io/project-chip/chip-build:41
+            image: ghcr.io/project-chip/chip-build:46
             volumes:
                 - "/:/runner-root-volume"
                 - "/tmp/log_output:/tmp/test_logs"
@@ -449,7 +449,7 @@
         if: github.actor != 'restyled-io[bot]'
 
         container:
-            image: ghcr.io/project-chip/chip-build:41
+            image: ghcr.io/project-chip/chip-build:46
             volumes:
                 - "/:/runner-root-volume"
                 - "/tmp/log_output:/tmp/test_logs"
diff --git a/.github/workflows/chef.yaml b/.github/workflows/chef.yaml
index c2c4a77..862ada5 100644
--- a/.github/workflows/chef.yaml
+++ b/.github/workflows/chef.yaml
@@ -33,7 +33,7 @@
         if: github.actor != 'restyled-io[bot]'
 
         container:
-            image: ghcr.io/project-chip/chip-build:41
+            image: ghcr.io/project-chip/chip-build:46
             options: --user root
 
         steps:
@@ -54,7 +54,7 @@
         if: github.actor != 'restyled-io[bot]'
 
         container:
-            image: ghcr.io/project-chip/chip-build-esp32:41
+            image: ghcr.io/project-chip/chip-build-esp32:46
             options: --user root
 
         steps:
@@ -75,7 +75,7 @@
         if: github.actor != 'restyled-io[bot]'
 
         container:
-            image: ghcr.io/project-chip/chip-build-nrf-platform:41
+            image: ghcr.io/project-chip/chip-build-nrf-platform:46
             options: --user root
 
         steps:
@@ -96,7 +96,7 @@
         if: github.actor != 'restyled-io[bot]'
 
         container:
-            image: ghcr.io/project-chip/chip-build-telink:41
+            image: ghcr.io/project-chip/chip-build-telink:46
             options: --user root
 
         steps:
@@ -108,7 +108,7 @@
                 platform: telink
             # - name: Update Zephyr to specific revision (for developers purpose)
             #   shell: bash
-            #   run: scripts/run_in_build_env.sh "python3 scripts/tools/telink/update_zephyr.py b5c8028ec94f3efa69decff3a09f0d6f8a21fd6d"
+            #   run: scripts/run_in_build_env.sh "python3 scripts/tools/telink/update_zephyr.py 65dc1812431bf946dfc110682298acf83d63e27a"
             - name: CI Examples Telink
               shell: bash
               run: |
diff --git a/.github/workflows/cirque.yaml b/.github/workflows/cirque.yaml
index 919085a..a82750e 100644
--- a/.github/workflows/cirque.yaml
+++ b/.github/workflows/cirque.yaml
@@ -40,7 +40,7 @@
         # need to run with privilege, which isn't supported by job.XXX.contaner
         #  https://github.com/actions/container-action/issues/2
         #         container:
-        #             image: ghcr.io/project-chip/chip-build-cirque:41
+        #             image: ghcr.io/project-chip/chip-build-cirque:46
         #             volumes:
         #                 - "/tmp:/tmp"
         #                 - "/dev/pts:/dev/pts"
diff --git a/.github/workflows/doxygen.yaml b/.github/workflows/doxygen.yaml
index cc93947..e94296b 100644
--- a/.github/workflows/doxygen.yaml
+++ b/.github/workflows/doxygen.yaml
@@ -81,7 +81,7 @@
 
         runs-on: ubuntu-latest
         container:
-            image: ghcr.io/project-chip/chip-build-doxygen:41
+            image: ghcr.io/project-chip/chip-build-doxygen:46
 
         if: github.actor != 'restyled-io[bot]'
 
diff --git a/.github/workflows/examples-ameba.yaml b/.github/workflows/examples-ameba.yaml
index 1d4d478..16cfb4c 100644
--- a/.github/workflows/examples-ameba.yaml
+++ b/.github/workflows/examples-ameba.yaml
@@ -36,7 +36,7 @@
         if: github.actor != 'restyled-io[bot]'
 
         container:
-            image: ghcr.io/project-chip/chip-build-ameba:42
+            image: ghcr.io/project-chip/chip-build-ameba:46
             options: --user root
 
         steps:
diff --git a/.github/workflows/examples-asr.yaml b/.github/workflows/examples-asr.yaml
index 52c63ed..6e9d4a8 100644
--- a/.github/workflows/examples-asr.yaml
+++ b/.github/workflows/examples-asr.yaml
@@ -34,7 +34,7 @@
         if: github.actor != 'restyled-io[bot]'
 
         container:
-            image: ghcr.io/project-chip/chip-build-asr:41
+            image: ghcr.io/project-chip/chip-build-asr:46
             options: --user root
 
         steps:
diff --git a/.github/workflows/examples-bouffalolab.yaml b/.github/workflows/examples-bouffalolab.yaml
index 8d12696..ce38acd 100644
--- a/.github/workflows/examples-bouffalolab.yaml
+++ b/.github/workflows/examples-bouffalolab.yaml
@@ -35,7 +35,7 @@
     if: github.actor != 'restyled-io[bot]'
 
     container:
-      image: ghcr.io/project-chip/chip-build-bouffalolab:41
+      image: ghcr.io/project-chip/chip-build-bouffalolab:46
       volumes:
         - "/tmp/bloat_reports:/tmp/bloat_reports"
     steps:
diff --git a/.github/workflows/examples-efr32.yaml b/.github/workflows/examples-efr32.yaml
index c4af320..0ec8a54 100644
--- a/.github/workflows/examples-efr32.yaml
+++ b/.github/workflows/examples-efr32.yaml
@@ -38,7 +38,7 @@
     if: github.actor != 'restyled-io[bot]'
 
     container:
-      image: ghcr.io/project-chip/chip-build-efr32:41
+      image: ghcr.io/project-chip/chip-build-efr32:46
       volumes:
         - "/tmp/bloat_reports:/tmp/bloat_reports"
     steps:
diff --git a/.github/workflows/examples-esp32.yaml b/.github/workflows/examples-esp32.yaml
index d262bd7..09eca99 100644
--- a/.github/workflows/examples-esp32.yaml
+++ b/.github/workflows/examples-esp32.yaml
@@ -34,7 +34,7 @@
         if: github.actor != 'restyled-io[bot]'
 
         container:
-            image: ghcr.io/project-chip/chip-build-esp32:41
+            image: ghcr.io/project-chip/chip-build-esp32:46
             volumes:
                 - "/tmp/bloat_reports:/tmp/bloat_reports"
 
@@ -124,7 +124,7 @@
         if: github.actor != 'restyled-io[bot]'
 
         container:
-            image: ghcr.io/project-chip/chip-build-esp32:41
+            image: ghcr.io/project-chip/chip-build-esp32:46
             volumes:
                 - "/tmp/bloat_reports:/tmp/bloat_reports"
 
diff --git a/.github/workflows/examples-infineon.yaml b/.github/workflows/examples-infineon.yaml
index 0f94ce1..9aba6a2 100644
--- a/.github/workflows/examples-infineon.yaml
+++ b/.github/workflows/examples-infineon.yaml
@@ -35,7 +35,7 @@
         if: github.actor != 'restyled-io[bot]'
 
         container:
-            image: ghcr.io/project-chip/chip-build-infineon:41
+            image: ghcr.io/project-chip/chip-build-infineon:46
             volumes:
                 - "/tmp/bloat_reports:/tmp/bloat_reports"
         steps:
diff --git a/.github/workflows/examples-linux-arm.yaml b/.github/workflows/examples-linux-arm.yaml
index 562279a..6dc8061 100644
--- a/.github/workflows/examples-linux-arm.yaml
+++ b/.github/workflows/examples-linux-arm.yaml
@@ -34,7 +34,7 @@
         if: github.actor != 'restyled-io[bot]'
 
         container:
-            image: ghcr.io/project-chip/chip-build-crosscompile:41
+            image: ghcr.io/project-chip/chip-build-crosscompile:46
             volumes:
                 - "/tmp/bloat_reports:/tmp/bloat_reports"
 
diff --git a/.github/workflows/examples-linux-imx.yaml b/.github/workflows/examples-linux-imx.yaml
index 843e76b..27a997d 100644
--- a/.github/workflows/examples-linux-imx.yaml
+++ b/.github/workflows/examples-linux-imx.yaml
@@ -34,7 +34,7 @@
         if: github.actor != 'restyled-io[bot]'
 
         container:
-            image: ghcr.io/project-chip/chip-build-imx:41
+            image: ghcr.io/project-chip/chip-build-imx:46
 
         steps:
             - name: Checkout
diff --git a/.github/workflows/examples-linux-standalone.yaml b/.github/workflows/examples-linux-standalone.yaml
index ea60e6a..ffec5da 100644
--- a/.github/workflows/examples-linux-standalone.yaml
+++ b/.github/workflows/examples-linux-standalone.yaml
@@ -34,7 +34,7 @@
         if: github.actor != 'restyled-io[bot]'
 
         container:
-            image: ghcr.io/project-chip/chip-build:41
+            image: ghcr.io/project-chip/chip-build:46
             volumes:
                 - "/tmp/bloat_reports:/tmp/bloat_reports"
 
diff --git a/.github/workflows/examples-mbed.yaml b/.github/workflows/examples-mbed.yaml
index 4b5748b..3744047 100644
--- a/.github/workflows/examples-mbed.yaml
+++ b/.github/workflows/examples-mbed.yaml
@@ -40,7 +40,7 @@
         if: github.actor != 'restyled-io[bot]'
 
         container:
-            image: ghcr.io/project-chip/chip-build-mbed-os:41
+            image: ghcr.io/project-chip/chip-build-mbed-os:46
             volumes:
                 - "/tmp/bloat_reports:/tmp/bloat_reports"
 
diff --git a/.github/workflows/examples-mw320.yaml b/.github/workflows/examples-mw320.yaml
index a16ea66..1f2940a 100644
--- a/.github/workflows/examples-mw320.yaml
+++ b/.github/workflows/examples-mw320.yaml
@@ -37,7 +37,7 @@
         if: github.actor != 'restyled-io[bot]'
 
         container:
-            image: ghcr.io/project-chip/chip-build:41
+            image: ghcr.io/project-chip/chip-build:46
             volumes:
                 - "/tmp/bloat_reports:/tmp/bloat_reports"
         steps:
diff --git a/.github/workflows/examples-nrfconnect.yaml b/.github/workflows/examples-nrfconnect.yaml
index eb62c69..d305ebf 100644
--- a/.github/workflows/examples-nrfconnect.yaml
+++ b/.github/workflows/examples-nrfconnect.yaml
@@ -37,7 +37,7 @@
         if: github.actor != 'restyled-io[bot]'
 
         container:
-            image: ghcr.io/project-chip/chip-build-nrf-platform:41
+            image: ghcr.io/project-chip/chip-build-nrf-platform:46
             volumes:
                 - "/tmp/bloat_reports:/tmp/bloat_reports"
 
diff --git a/.github/workflows/examples-nxp.yaml b/.github/workflows/examples-nxp.yaml
index 9a8a7b8..01ff636 100644
--- a/.github/workflows/examples-nxp.yaml
+++ b/.github/workflows/examples-nxp.yaml
@@ -37,7 +37,7 @@
         if: github.actor != 'restyled-io[bot]'
 
         container:
-            image: ghcr.io/project-chip/chip-build-k32w:38
+            image: ghcr.io/project-chip/chip-build-k32w:46
             volumes:
                 - "/tmp/bloat_reports:/tmp/bloat_reports"
         steps:
diff --git a/.github/workflows/examples-openiotsdk.yaml b/.github/workflows/examples-openiotsdk.yaml
index b6f6979..fead442 100644
--- a/.github/workflows/examples-openiotsdk.yaml
+++ b/.github/workflows/examples-openiotsdk.yaml
@@ -38,7 +38,7 @@
         if: github.actor != 'restyled-io[bot]'
 
         container:
-            image: ghcr.io/project-chip/chip-build-openiotsdk:41
+            image: ghcr.io/project-chip/chip-build-openiotsdk:46
             volumes:
                 - "/tmp/bloat_reports:/tmp/bloat_reports"
             options: --privileged
diff --git a/.github/workflows/examples-qpg.yaml b/.github/workflows/examples-qpg.yaml
index b0af5ab..b67ef06 100644
--- a/.github/workflows/examples-qpg.yaml
+++ b/.github/workflows/examples-qpg.yaml
@@ -37,7 +37,7 @@
         if: github.actor != 'restyled-io[bot]'
 
         container:
-            image: ghcr.io/project-chip/chip-build:41
+            image: ghcr.io/project-chip/chip-build:46
             volumes:
                 - "/tmp/bloat_reports:/tmp/bloat_reports"
         steps:
diff --git a/.github/workflows/examples-rw61x.yaml b/.github/workflows/examples-rw61x.yaml
index 42df033..7c13186 100644
--- a/.github/workflows/examples-rw61x.yaml
+++ b/.github/workflows/examples-rw61x.yaml
@@ -37,7 +37,7 @@
         if: github.actor != 'restyled-io[bot]'
 
         container:
-            image: ghcr.io/project-chip/chip-build-rw61x:37
+            image: ghcr.io/project-chip/chip-build-rw61x:46
             volumes:
                 - "/tmp/bloat_reports:/tmp/bloat_reports"
         steps:
diff --git a/.github/workflows/examples-stm32.yaml b/.github/workflows/examples-stm32.yaml
index 9a30af5..57d0c31 100644
--- a/.github/workflows/examples-stm32.yaml
+++ b/.github/workflows/examples-stm32.yaml
@@ -38,7 +38,7 @@
         if: github.actor != 'restyled-io[bot]'
 
         container:
-            image: ghcr.io/project-chip/chip-build:41
+            image: ghcr.io/project-chip/chip-build:46
             volumes:
                 - "/tmp/bloat_reports:/tmp/bloat_reports"
         steps:
diff --git a/.github/workflows/examples-telink.yaml b/.github/workflows/examples-telink.yaml
index 285ba96..a21d497 100644
--- a/.github/workflows/examples-telink.yaml
+++ b/.github/workflows/examples-telink.yaml
@@ -36,7 +36,7 @@
         if: github.actor != 'restyled-io[bot]'
 
         container:
-            image: ghcr.io/project-chip/chip-build-telink:41
+            image: ghcr.io/project-chip/chip-build-telink:46
             volumes:
                 - "/tmp/bloat_reports:/tmp/bloat_reports"
 
@@ -55,7 +55,7 @@
                 gh-context: ${{ toJson(github) }}
 
             # - name: Update Zephyr to specific revision (for developers purpose)
-            #   run: scripts/run_in_build_env.sh "python3 scripts/tools/telink/update_zephyr.py b5c8028ec94f3efa69decff3a09f0d6f8a21fd6d"
+            #   run: scripts/run_in_build_env.sh "python3 scripts/tools/telink/update_zephyr.py 65dc1812431bf946dfc110682298acf83d63e27a"
 
             - name: Build example Telink (B92 retention) Air Quality Sensor App
               run: |
diff --git a/.github/workflows/examples-tizen.yaml b/.github/workflows/examples-tizen.yaml
index 65c15e5..f89c2d2 100644
--- a/.github/workflows/examples-tizen.yaml
+++ b/.github/workflows/examples-tizen.yaml
@@ -34,7 +34,7 @@
         if: github.actor != 'restyled-io[bot]'
 
         container:
-            image: ghcr.io/project-chip/chip-build-tizen:41
+            image: ghcr.io/project-chip/chip-build-tizen:46
             options: --user root
             volumes:
                 - "/tmp/bloat_reports:/tmp/bloat_reports"
diff --git a/.github/workflows/full-android.yaml b/.github/workflows/full-android.yaml
index 81a277d..48f0af1 100644
--- a/.github/workflows/full-android.yaml
+++ b/.github/workflows/full-android.yaml
@@ -36,7 +36,7 @@
         if: github.actor != 'restyled-io[bot]'
 
         container:
-            image: ghcr.io/project-chip/chip-build-android:41
+            image: ghcr.io/project-chip/chip-build-android:46
             volumes:
                 - "/tmp/log_output:/tmp/test_logs"
 
diff --git a/.github/workflows/fuzzing-build.yaml b/.github/workflows/fuzzing-build.yaml
index f354ce3..4ba9c49 100644
--- a/.github/workflows/fuzzing-build.yaml
+++ b/.github/workflows/fuzzing-build.yaml
@@ -33,7 +33,7 @@
         if: github.actor != 'restyled-io[bot]'
 
         container:
-            image: ghcr.io/project-chip/chip-build:41
+            image: ghcr.io/project-chip/chip-build:46
             volumes:
                 - "/tmp/log_output:/tmp/test_logs"
 
diff --git a/.github/workflows/java-tests.yaml b/.github/workflows/java-tests.yaml
index 4356924..b609ad7 100644
--- a/.github/workflows/java-tests.yaml
+++ b/.github/workflows/java-tests.yaml
@@ -40,7 +40,7 @@
         runs-on: ubuntu-latest
 
         container:
-            image: ghcr.io/project-chip/chip-build-java:41
+            image: ghcr.io/project-chip/chip-build-java:46
             options: --privileged --sysctl "net.ipv6.conf.all.disable_ipv6=0
                 net.ipv4.conf.all.forwarding=0 net.ipv6.conf.all.forwarding=0"
 
diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
index 36a5a0b..1968718 100644
--- a/.github/workflows/lint.yml
+++ b/.github/workflows/lint.yml
@@ -29,7 +29,7 @@
         if: github.actor != 'restyled-io[bot]'
 
         container:
-            image: ghcr.io/project-chip/chip-build:41
+            image: ghcr.io/project-chip/chip-build:46
 
         steps:
             - name: Checkout
diff --git a/.github/workflows/minimal-build.yaml b/.github/workflows/minimal-build.yaml
index 029f3d7..3320dab 100644
--- a/.github/workflows/minimal-build.yaml
+++ b/.github/workflows/minimal-build.yaml
@@ -31,7 +31,7 @@
         runs-on: ubuntu-latest
 
         container:
-            image: ghcr.io/project-chip/chip-build-minimal:41
+            image: ghcr.io/project-chip/chip-build-minimal:46
 
         steps:
             - name: Checkout
diff --git a/.github/workflows/qemu.yaml b/.github/workflows/qemu.yaml
index dc35658..9b6c855 100644
--- a/.github/workflows/qemu.yaml
+++ b/.github/workflows/qemu.yaml
@@ -38,7 +38,7 @@
         if: github.actor != 'restyled-io[bot]'
 
         container:
-            image: ghcr.io/project-chip/chip-build-esp32-qemu:41
+            image: ghcr.io/project-chip/chip-build-esp32-qemu:46
             volumes:
                 - "/tmp/log_output:/tmp/test_logs"
 
@@ -78,7 +78,7 @@
         if: github.actor != 'restyled-io[bot]'
 
         container:
-            image: ghcr.io/project-chip/chip-build-tizen-qemu:41
+            image: ghcr.io/project-chip/chip-build-tizen-qemu:46
             volumes:
                 - "/tmp/log_output:/tmp/test_logs"
 
diff --git a/.github/workflows/release_artifacts.yaml b/.github/workflows/release_artifacts.yaml
index 57a1ce7..78b50ad 100644
--- a/.github/workflows/release_artifacts.yaml
+++ b/.github/workflows/release_artifacts.yaml
@@ -32,7 +32,7 @@
         runs-on: ubuntu-latest
 
         container:
-            image: ghcr.io/project-chip/chip-build-esp32:41
+            image: ghcr.io/project-chip/chip-build-esp32:46
 
         steps:
             - name: Checkout
@@ -64,7 +64,7 @@
         runs-on: ubuntu-latest
 
         container:
-            image: ghcr.io/project-chip/chip-build-efr32:41
+            image: ghcr.io/project-chip/chip-build-efr32:46
         steps:
             - name: Checkout
               uses: actions/checkout@v4
diff --git a/.github/workflows/smoketest-android.yaml b/.github/workflows/smoketest-android.yaml
index d1dd509..d9d81ab 100644
--- a/.github/workflows/smoketest-android.yaml
+++ b/.github/workflows/smoketest-android.yaml
@@ -37,7 +37,7 @@
         if: github.actor != 'restyled-io[bot]'
 
         container:
-            image: ghcr.io/project-chip/chip-build-android:41
+            image: ghcr.io/project-chip/chip-build-android:46
             volumes:
                 - "/:/runner-root-volume"
                 - "/tmp/log_output:/tmp/test_logs"
diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml
index 2907a4a..e024d16 100644
--- a/.github/workflows/tests.yaml
+++ b/.github/workflows/tests.yaml
@@ -47,7 +47,7 @@
         runs-on: ubuntu-latest
 
         container:
-            image: ghcr.io/project-chip/chip-build:41
+            image: ghcr.io/project-chip/chip-build:46
             options: --privileged --sysctl "net.ipv6.conf.all.disable_ipv6=0
                 net.ipv4.conf.all.forwarding=1 net.ipv6.conf.all.forwarding=1"
 
@@ -437,7 +437,7 @@
         runs-on: ubuntu-latest
 
         container:
-            image: ghcr.io/project-chip/chip-build:41
+            image: ghcr.io/project-chip/chip-build:46
             options: --privileged --sysctl "net.ipv6.conf.all.disable_ipv6=0
                 net.ipv4.conf.all.forwarding=0 net.ipv6.conf.all.forwarding=0"
 
diff --git a/.github/workflows/unit_integration_test.yaml b/.github/workflows/unit_integration_test.yaml
index 478d347..480e9ec 100644
--- a/.github/workflows/unit_integration_test.yaml
+++ b/.github/workflows/unit_integration_test.yaml
@@ -37,7 +37,7 @@
         runs-on: ubuntu-latest
 
         container:
-            image: ghcr.io/project-chip/chip-build:41
+            image: ghcr.io/project-chip/chip-build:46
             volumes:
                 - "/:/runner-root-volume"
                 - "/tmp/log_output:/tmp/test_logs"
diff --git a/.github/workflows/zap_regeneration.yaml b/.github/workflows/zap_regeneration.yaml
index 4488e23..93b966f 100644
--- a/.github/workflows/zap_regeneration.yaml
+++ b/.github/workflows/zap_regeneration.yaml
@@ -30,7 +30,7 @@
 
         runs-on: ubuntu-20.04
         container:
-            image: ghcr.io/project-chip/chip-build:41
+            image: ghcr.io/project-chip/chip-build:46
         defaults:
             run:
                 shell: sh
diff --git a/.github/workflows/zap_templates.yaml b/.github/workflows/zap_templates.yaml
index f14b914..ea8c72a 100644
--- a/.github/workflows/zap_templates.yaml
+++ b/.github/workflows/zap_templates.yaml
@@ -32,7 +32,7 @@
 
         runs-on: ubuntu-20.04
         container:
-            image: ghcr.io/project-chip/chip-build:41
+            image: ghcr.io/project-chip/chip-build:46
         defaults:
             run:
                 shell: sh
diff --git a/config/telink/chip-module/Kconfig.defaults b/config/telink/chip-module/Kconfig.defaults
index 964b085..5e21bb7 100644
--- a/config/telink/chip-module/Kconfig.defaults
+++ b/config/telink/chip-module/Kconfig.defaults
@@ -158,8 +158,8 @@
 endchoice
 
 # Board retention config
-if BOARD_TLSR9528A_RETENTION || BOARD_TLSR9258A_RETENTION || BOARD_TLSR9518ADK80D_RETENTION 
-config BOARD_TLSR9X_NON_RETENTION_RAM_CODE
+if BOARD_TLSR9528A_RETENTION || BOARD_TLSR9258A_RETENTION || BOARD_TLSR9518ADK80D_RETENTION
+config SOC_SERIES_RISCV_TELINK_B9X_NON_RETENTION_RAM_CODE
     default y if PM
 
 config TELINK_B9x_MATTER_RETENTION_LAYOUT
diff --git a/examples/air-quality-sensor-app/telink/CMakeLists.txt b/examples/air-quality-sensor-app/telink/CMakeLists.txt
index 5ed8c31..a27ab91 100644
--- a/examples/air-quality-sensor-app/telink/CMakeLists.txt
+++ b/examples/air-quality-sensor-app/telink/CMakeLists.txt
@@ -76,7 +76,7 @@
 include(${CHIP_ROOT}/config/telink/app/enable-gnu-std.cmake)
 include(${CHIP_ROOT}/src/app/chip_data_model.cmake)
 
-target_compile_options(app PRIVATE -fpermissive)
+target_compile_options(app PRIVATE $<$<COMPILE_LANGUAGE:CXX>:-fpermissive>)
 
 target_include_directories(app PRIVATE
                            include
@@ -84,7 +84,8 @@
                            ${GEN_DIR}/air-quality-sensor-app
                            ${TELINK_COMMON}/common/include
                            ${TELINK_COMMON}/util/include
-                           ${CHIP_ROOT}/examples/air-quality-sensor-app/air-quality-sensor-common/include)
+                           ${CHIP_ROOT}/examples/air-quality-sensor-app/air-quality-sensor-common/include
+                           ${TELINK_COMMON}/zephyr_ext)
 
 target_sources(app PRIVATE
                src/AppTask.cpp
@@ -92,12 +93,16 @@
                ${TELINK_COMMON}/common/src/mainCommon.cpp
                ${TELINK_COMMON}/common/src/AppTaskCommon.cpp
                ${TELINK_COMMON}/common/src/SensorManagerCommon.cpp
-               ${TELINK_COMMON}/util/src/LEDWidget.cpp
+               ${TELINK_COMMON}/util/src/LEDManager.cpp
                ${TELINK_COMMON}/util/src/ButtonManager.cpp
                ${TELINK_COMMON}/util/src/ThreadUtil.cpp
-               ${TELINK_COMMON}/util/src/PWMDevice.cpp
-               ${TELINK_COMMON}/util/src/WS2812Device.cpp
-               ${CHIP_ROOT}/examples/air-quality-sensor-app/air-quality-sensor-common/src/air-quality-sensor-manager.cpp)
+               ${TELINK_COMMON}/util/src/PWMManager.cpp
+               ${CHIP_ROOT}/examples/air-quality-sensor-app/air-quality-sensor-common/src/air-quality-sensor-manager.cpp
+               ${TELINK_COMMON}/zephyr_ext/zephyr_key_matrix.c
+               ${TELINK_COMMON}/zephyr_ext/zephyr_key_pool.c
+               ${TELINK_COMMON}/zephyr_ext/zephyr_led_pool.c
+               ${TELINK_COMMON}/zephyr_ext/zephyr_pwm_pool.c
+               ${TELINK_COMMON}/zephyr_ext/zephyr_ws2812.c)
 
 chip_configure_data_model(app
     INCLUDE_SERVER
diff --git a/examples/air-quality-sensor-app/telink/include/AppConfig.h b/examples/air-quality-sensor-app/telink/include/AppConfig.h
index 7513ed3..0888260 100644
--- a/examples/air-quality-sensor-app/telink/include/AppConfig.h
+++ b/examples/air-quality-sensor-app/telink/include/AppConfig.h
@@ -20,11 +20,5 @@
 
 // ---- Air Quality Example App Config ----
 
-#define APP_USE_EXAMPLE_START_BUTTON 1
-#define APP_USE_BLE_START_BUTTON 0
-#define APP_USE_THREAD_START_BUTTON 0
 #define APP_SET_DEVICE_INFO_PROVIDER 1
 #define APP_SET_NETWORK_COMM_ENDPOINT_SEC 0
-#if defined(CONFIG_BOARD_TLSR9518ADK80D) || defined(CONFIG_BOARD_TLSR9528A)
-#define APP_USE_IDENTIFY_PWM 1
-#endif
diff --git a/examples/air-quality-sensor-app/telink/src/AppTask.cpp b/examples/air-quality-sensor-app/telink/src/AppTask.cpp
index ac2f61b..da0f80e 100644
--- a/examples/air-quality-sensor-app/telink/src/AppTask.cpp
+++ b/examples/air-quality-sensor-app/telink/src/AppTask.cpp
@@ -37,9 +37,7 @@
 {
     CHIP_ERROR err;
 
-#if APP_USE_EXAMPLE_START_BUTTON
     SetExampleButtonCallbacks(AirQualitySensorUpdateTimerEventHandler);
-#endif
     InitCommonParts();
 
     err = SensorMgr().Init();
diff --git a/examples/all-clusters-app/ameba/README.md b/examples/all-clusters-app/ameba/README.md
index 3450d27..f54a534 100644
--- a/examples/all-clusters-app/ameba/README.md
+++ b/examples/all-clusters-app/ameba/README.md
@@ -27,11 +27,11 @@
 
 -   Pull docker image:
 
-          $ docker pull ghcr.io/project-chip/chip-build-ameba:42
+          $ docker pull ghcr.io/project-chip/chip-build-ameba:46
 
 -   Run docker container:
 
-          $ docker run -it -v ${CHIP_DIR}:/root/chip ghcr.io/project-chip/chip-build-ameba:42
+          $ docker run -it -v ${CHIP_DIR}:/root/chip ghcr.io/project-chip/chip-build-ameba:46
 
 -   Setup build environment:
 
diff --git a/examples/all-clusters-app/telink/CMakeLists.txt b/examples/all-clusters-app/telink/CMakeLists.txt
index 2c59e65..7787f42 100644
--- a/examples/all-clusters-app/telink/CMakeLists.txt
+++ b/examples/all-clusters-app/telink/CMakeLists.txt
@@ -61,7 +61,7 @@
 include(${CHIP_ROOT}/config/telink/app/enable-gnu-std.cmake)
 include(${CHIP_ROOT}/src/app/chip_data_model.cmake)
 
-target_compile_options(app PRIVATE -fpermissive)
+target_compile_options(app PRIVATE $<$<COMPILE_LANGUAGE:CXX>:-fpermissive>)
 
 target_include_directories(app PRIVATE
                            include
@@ -70,7 +70,8 @@
                            ${GEN_DIR}/app-common
                            ${GEN_DIR}/all-clusters-app
                            ${TELINK_COMMON}/common/include
-                           ${TELINK_COMMON}/util/include)
+                           ${TELINK_COMMON}/util/include
+                           ${TELINK_COMMON}/zephyr_ext)
 
 target_sources(app PRIVATE
                src/AppTask.cpp
@@ -92,10 +93,15 @@
                ${ENERGY_MANAGEMENT_COMMON_DIR}/src/DeviceEnergyManagementManager.cpp                  
                ${TELINK_COMMON}/common/src/mainCommon.cpp
                ${TELINK_COMMON}/common/src/AppTaskCommon.cpp
-               ${TELINK_COMMON}/util/src/LEDWidget.cpp
+               ${TELINK_COMMON}/util/src/LEDManager.cpp
                ${TELINK_COMMON}/util/src/ButtonManager.cpp
                ${TELINK_COMMON}/util/src/ThreadUtil.cpp
-               ${TELINK_COMMON}/util/src/PWMDevice.cpp)
+               ${TELINK_COMMON}/util/src/PWMManager.cpp
+               ${TELINK_COMMON}/zephyr_ext/zephyr_key_matrix.c
+               ${TELINK_COMMON}/zephyr_ext/zephyr_key_pool.c
+               ${TELINK_COMMON}/zephyr_ext/zephyr_led_pool.c
+               ${TELINK_COMMON}/zephyr_ext/zephyr_pwm_pool.c
+               ${TELINK_COMMON}/zephyr_ext/zephyr_ws2812.c)
 
 chip_configure_data_model(app
     INCLUDE_SERVER
diff --git a/examples/all-clusters-app/telink/include/AppConfig.h b/examples/all-clusters-app/telink/include/AppConfig.h
index 68263bb..602aa60 100644
--- a/examples/all-clusters-app/telink/include/AppConfig.h
+++ b/examples/all-clusters-app/telink/include/AppConfig.h
@@ -19,11 +19,5 @@
 #pragma once
 
 // ---- All Clusters Application example config ----
-#define APP_USE_EXAMPLE_START_BUTTON 0
-#define APP_USE_BLE_START_BUTTON 0
-#define APP_USE_THREAD_START_BUTTON 1
 #define APP_SET_DEVICE_INFO_PROVIDER 1
 #define APP_SET_NETWORK_COMM_ENDPOINT_SEC 1
-#if defined(CONFIG_BOARD_TLSR9518ADK80D) || defined(CONFIG_BOARD_TLSR9528A)
-#define APP_USE_IDENTIFY_PWM 1
-#endif
diff --git a/examples/all-clusters-minimal-app/ameba/README.md b/examples/all-clusters-minimal-app/ameba/README.md
index 693b06c..6daa682 100644
--- a/examples/all-clusters-minimal-app/ameba/README.md
+++ b/examples/all-clusters-minimal-app/ameba/README.md
@@ -27,13 +27,13 @@
 -   Pull docker image:
 
           ```
-          $ docker pull ghcr.io/project-chip/chip-build-ameba:35
+          $ docker pull ghcr.io/project-chip/chip-build-ameba:46
           ```
 
 -   Run docker container:
 
           ```
-          $ docker run -it -v ${CHIP_DIR}:/root/chip ghcr.io/project-chip/chip-build-ameba:35
+          $ docker run -it -v ${CHIP_DIR}:/root/chip ghcr.io/project-chip/chip-build-ameba:46
           ```
 
 -   Setup build environment:
diff --git a/examples/all-clusters-minimal-app/telink/CMakeLists.txt b/examples/all-clusters-minimal-app/telink/CMakeLists.txt
index a68471e..ee47129 100644
--- a/examples/all-clusters-minimal-app/telink/CMakeLists.txt
+++ b/examples/all-clusters-minimal-app/telink/CMakeLists.txt
@@ -60,7 +60,7 @@
 include(${CHIP_ROOT}/config/telink/app/enable-gnu-std.cmake)
 include(${CHIP_ROOT}/src/app/chip_data_model.cmake)
 
-target_compile_options(app PRIVATE -fpermissive)
+target_compile_options(app PRIVATE $<$<COMPILE_LANGUAGE:CXX>:-fpermissive>)
 
 target_include_directories(app PRIVATE
                            include
@@ -68,7 +68,8 @@
                            ${GEN_DIR}/app-common
                            ${GEN_DIR}/all-clusters-minimal-app
                            ${TELINK_COMMON}/common/include
-                           ${TELINK_COMMON}/util/include)
+                           ${TELINK_COMMON}/util/include
+                           ${TELINK_COMMON}/zephyr_ext)
 
 target_sources(app PRIVATE
                src/AppTask.cpp
@@ -78,9 +79,15 @@
                ${ALL_CLUSTERS_COMMON_DIR}/src/binding-handler.cpp
                ${TELINK_COMMON}/common/src/mainCommon.cpp
                ${TELINK_COMMON}/common/src/AppTaskCommon.cpp
-               ${TELINK_COMMON}/util/src/LEDWidget.cpp
+               ${TELINK_COMMON}/util/src/LEDManager.cpp
+               ${TELINK_COMMON}/util/src/PWMManager.cpp
                ${TELINK_COMMON}/util/src/ButtonManager.cpp
-               ${TELINK_COMMON}/util/src/ThreadUtil.cpp)
+               ${TELINK_COMMON}/util/src/ThreadUtil.cpp
+               ${TELINK_COMMON}/zephyr_ext/zephyr_key_matrix.c
+               ${TELINK_COMMON}/zephyr_ext/zephyr_key_pool.c
+               ${TELINK_COMMON}/zephyr_ext/zephyr_led_pool.c
+               ${TELINK_COMMON}/zephyr_ext/zephyr_pwm_pool.c
+               ${TELINK_COMMON}/zephyr_ext/zephyr_ws2812.c)
 
 chip_configure_data_model(app
     INCLUDE_SERVER
diff --git a/examples/all-clusters-minimal-app/telink/include/AppConfig.h b/examples/all-clusters-minimal-app/telink/include/AppConfig.h
index 5ef62e0..38bbe54 100644
--- a/examples/all-clusters-minimal-app/telink/include/AppConfig.h
+++ b/examples/all-clusters-minimal-app/telink/include/AppConfig.h
@@ -20,8 +20,5 @@
 
 // ---- All Clusters Minimal Application example config ----
 
-#define APP_USE_EXAMPLE_START_BUTTON 0
-#define APP_USE_BLE_START_BUTTON 0
-#define APP_USE_THREAD_START_BUTTON 0
 #define APP_SET_DEVICE_INFO_PROVIDER 0
 #define APP_SET_NETWORK_COMM_ENDPOINT_SEC 1
diff --git a/examples/bridge-app/telink/CMakeLists.txt b/examples/bridge-app/telink/CMakeLists.txt
index f4da959..d4e78b1 100644
--- a/examples/bridge-app/telink/CMakeLists.txt
+++ b/examples/bridge-app/telink/CMakeLists.txt
@@ -59,7 +59,7 @@
 include(${CHIP_ROOT}/config/telink/app/enable-gnu-std.cmake)
 include(${CHIP_ROOT}/src/app/chip_data_model.cmake)
 
-target_compile_options(app PRIVATE -fpermissive)
+target_compile_options(app PRIVATE $<$<COMPILE_LANGUAGE:CXX>:-fpermissive>)
 
 target_include_directories(app PRIVATE
                            include
@@ -67,19 +67,24 @@
                            ${GEN_DIR}/bridge-app
                            ${TELINK_COMMON}/common/include
                            ${TELINK_COMMON}/util/include
-                           ${TELINK_COMMON}/app/include)
+                           ${TELINK_COMMON}/app/include
+                           ${TELINK_COMMON}/zephyr_ext)
 
 target_sources(app PRIVATE
                src/AppTask.cpp
-               src/ZclCallbacks.cpp
                src/Device.cpp
                src/DeviceCallbacks.cpp
                ${TELINK_COMMON}/common/src/mainCommon.cpp
                ${TELINK_COMMON}/common/src/AppTaskCommon.cpp
-               ${TELINK_COMMON}/util/src/LEDWidget.cpp
+               ${TELINK_COMMON}/util/src/LEDManager.cpp
                ${TELINK_COMMON}/util/src/ButtonManager.cpp
                ${TELINK_COMMON}/util/src/ThreadUtil.cpp
-               ${TELINK_COMMON}/util/src/PWMDevice.cpp)
+               ${TELINK_COMMON}/util/src/PWMManager.cpp
+               ${TELINK_COMMON}/zephyr_ext/zephyr_key_matrix.c
+               ${TELINK_COMMON}/zephyr_ext/zephyr_key_pool.c
+               ${TELINK_COMMON}/zephyr_ext/zephyr_led_pool.c
+               ${TELINK_COMMON}/zephyr_ext/zephyr_pwm_pool.c
+               ${TELINK_COMMON}/zephyr_ext/zephyr_ws2812.c)
 
 chip_configure_data_model(app
     INCLUDE_SERVER
diff --git a/examples/bridge-app/telink/include/AppConfig.h b/examples/bridge-app/telink/include/AppConfig.h
index e5e26ef..e4af613 100644
--- a/examples/bridge-app/telink/include/AppConfig.h
+++ b/examples/bridge-app/telink/include/AppConfig.h
@@ -20,11 +20,5 @@
 
 // ---- Bridge App Example Config ----
 
-#define APP_USE_EXAMPLE_START_BUTTON 1
-#define APP_USE_BLE_START_BUTTON 0
-#define APP_USE_THREAD_START_BUTTON 1
 #define APP_SET_DEVICE_INFO_PROVIDER 1
 #define APP_SET_NETWORK_COMM_ENDPOINT_SEC 0
-#if defined(CONFIG_BOARD_TLSR9518ADK80D) || defined(CONFIG_BOARD_TLSR9528A)
-#define APP_USE_IDENTIFY_PWM 1
-#endif
diff --git a/examples/bridge-app/telink/include/AppTask.h b/examples/bridge-app/telink/include/AppTask.h
index 6b8a60d..1827584 100644
--- a/examples/bridge-app/telink/include/AppTask.h
+++ b/examples/bridge-app/telink/include/AppTask.h
@@ -19,14 +19,20 @@
 #pragma once
 
 #include "AppTaskCommon.h"
-#include "PWMDevice.h"
 
 class AppTask : public AppTaskCommon
 {
 public:
+    enum Action_t : uint8_t
+    {
+        ON_ACTION = 0,
+        OFF_ACTION,
+        LEVEL_ACTION,
+        INVALID_ACTION
+    };
+
     void UpdateClusterState(void);
     static void InitServer(intptr_t context);
-    PWMDevice & GetPWMDevice(void) { return mPwmRgbBlueLed; }
 
 private:
     friend AppTask & GetAppTask(void);
@@ -34,13 +40,8 @@
 
     CHIP_ERROR Init(void);
 
-    static void ActionInitiated(PWMDevice::Action_t aAction, int32_t aActor);
-    static void ActionCompleted(PWMDevice::Action_t aAction, int32_t aActor);
-
     static void LightingActionEventHandler(AppEvent * aEvent);
 
-    PWMDevice mPwmRgbBlueLed;
-
     static AppTask sAppTask;
 };
 
diff --git a/examples/bridge-app/telink/src/AppTask.cpp b/examples/bridge-app/telink/src/AppTask.cpp
index d70f9c0..76a59c4 100644
--- a/examples/bridge-app/telink/src/AppTask.cpp
+++ b/examples/bridge-app/telink/src/AppTask.cpp
@@ -18,6 +18,7 @@
 
 #include "AppTask.h"
 #include "Device.h"
+#include "PWMManager.h"
 
 #include <app-common/zap-generated/attributes/Accessors.h>
 #include <app/reporting/reporting.h>
@@ -27,7 +28,8 @@
 LOG_MODULE_DECLARE(app, CONFIG_CHIP_APP_LOG_LEVEL);
 
 namespace {
-const struct pwm_dt_spec sPwmRgbSpecBlueLed = PWM_DT_SPEC_GET(DT_ALIAS(pwm_led0));
+bool sTurnedOn;
+uint8_t sLevel;
 } // namespace
 
 AppTask AppTask::sAppTask;
@@ -395,29 +397,32 @@
 
 CHIP_ERROR AppTask::Init(void)
 {
-    // Init lighting manager
-    uint8_t minLightLevel = kDefaultMinLevel;
-    Clusters::LevelControl::Attributes::MinLevel::Get(kExampleEndpointId, &minLightLevel);
-
-    uint8_t maxLightLevel = kDefaultMaxLevel;
-    Clusters::LevelControl::Attributes::MaxLevel::Get(kExampleEndpointId, &maxLightLevel);
-
-    // Initialize PWM LED
-    CHIP_ERROR err = sAppTask.mPwmRgbBlueLed.Init(&sPwmRgbSpecBlueLed, minLightLevel, maxLightLevel, maxLightLevel);
-    if (err != CHIP_NO_ERROR)
-    {
-        LOG_ERR("Blue RGB PWM Device Init fail");
-        return err;
-    }
-
-    sAppTask.mPwmRgbBlueLed.SetCallbacks(ActionInitiated, ActionCompleted, nullptr);
-
-#if APP_USE_EXAMPLE_START_BUTTON
     SetExampleButtonCallbacks(LightingActionEventHandler);
-#endif
     InitCommonParts();
 
-    memset(gDevices, 0, sizeof(gDevices));
+    Protocols::InteractionModel::Status status;
+
+    app::DataModel::Nullable<uint8_t> level;
+    // Read brightness value
+    status = Clusters::LevelControl::Attributes::CurrentLevel::Get(kExampleEndpointId, level);
+    if (status == Protocols::InteractionModel::Status::Success && !level.IsNull())
+    {
+        sLevel = level.Value();
+    }
+
+    bool isOn;
+    // Read storedValue on/off value
+    status = Clusters::OnOff::Attributes::OnOff::Get(1, &isOn);
+    if (status == Protocols::InteractionModel::Status::Success)
+    {
+        sTurnedOn = isOn;
+        PwmManager::getInstance().setPwm(PwmManager::EAppPwm_Red, sTurnedOn);
+    }
+
+    for (size_t i = 0; i < CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT; i++)
+    {
+        gDevices[i] = nullptr;
+    }
 
     gLight1.SetReachable(true);
     gLight2.SetReachable(true);
@@ -531,66 +536,26 @@
 
 void AppTask::LightingActionEventHandler(AppEvent * aEvent)
 {
-    PWMDevice::Action_t action = PWMDevice::INVALID_ACTION;
-    int32_t actor              = 0;
+    Action_t action = INVALID_ACTION;
+    int32_t actor   = 0;
 
     if (aEvent->Type == AppEvent::kEventType_Lighting)
     {
-        action = static_cast<PWMDevice::Action_t>(aEvent->LightingEvent.Action);
+        action = static_cast<Action_t>(aEvent->LightingEvent.Action);
         actor  = aEvent->LightingEvent.Actor;
     }
     else if (aEvent->Type == AppEvent::kEventType_Button)
     {
-        action = sAppTask.mPwmRgbBlueLed.IsTurnedOn() ? PWMDevice::OFF_ACTION : PWMDevice::ON_ACTION;
-        actor  = AppEvent::kEventType_Button;
-    }
+        sTurnedOn = !sTurnedOn;
 
-    if (action != PWMDevice::INVALID_ACTION && (!sAppTask.mPwmRgbBlueLed.InitiateAction(action, actor, NULL)))
-    {
-        LOG_INF("Action is in progress or active");
-    }
-}
-
-void AppTask::ActionInitiated(PWMDevice::Action_t aAction, int32_t aActor)
-{
-    if (aAction == PWMDevice::ON_ACTION)
-    {
-        LOG_DBG("ON_ACTION initiated");
-    }
-    else if (aAction == PWMDevice::OFF_ACTION)
-    {
-        LOG_DBG("OFF_ACTION initiated");
-    }
-    else if (aAction == PWMDevice::LEVEL_ACTION)
-    {
-        LOG_DBG("LEVEL_ACTION initiated");
-    }
-}
-
-void AppTask::ActionCompleted(PWMDevice::Action_t aAction, int32_t aActor)
-{
-    if (aAction == PWMDevice::ON_ACTION)
-    {
-        LOG_DBG("ON_ACTION completed");
-    }
-    else if (aAction == PWMDevice::OFF_ACTION)
-    {
-        LOG_DBG("OFF_ACTION completed");
-    }
-    else if (aAction == PWMDevice::LEVEL_ACTION)
-    {
-        LOG_DBG("LEVEL_ACTION completed");
-    }
-
-    if (aActor == AppEvent::kEventType_Button)
-    {
-        sAppTask.UpdateClusterState();
+        PwmManager::getInstance().setPwm(PwmManager::EAppPwm_Red, sTurnedOn);
+        GetAppTask().UpdateClusterState();
     }
 }
 
 void AppTask::UpdateClusterState(void)
 {
-    bool isTurnedOn = sAppTask.mPwmRgbBlueLed.IsTurnedOn();
+    bool isTurnedOn = sTurnedOn;
 
     // write the new on/off value
     Protocols::InteractionModel::Status status = Clusters::OnOff::Attributes::OnOff::Set(kExampleEndpointId, isTurnedOn);
@@ -599,7 +564,7 @@
     {
         LOG_ERR("Update OnOff fail: %x", to_underlying(status));
     }
-    uint8_t setLevel = sAppTask.mPwmRgbBlueLed.GetLevel();
+    uint8_t setLevel = sLevel;
     status           = Clusters::LevelControl::Attributes::CurrentLevel::Set(kExampleEndpointId, setLevel);
     if (status != Protocols::InteractionModel::Status::Success)
     {
diff --git a/examples/bridge-app/telink/src/ZclCallbacks.cpp b/examples/bridge-app/telink/src/ZclCallbacks.cpp
deleted file mode 100644
index e839931..0000000
--- a/examples/bridge-app/telink/src/ZclCallbacks.cpp
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- *
- *    Copyright (c) 2023 Project CHIP Authors
- *    All rights reserved.
- *
- *    Licensed under the Apache License, Version 2.0 (the "License");
- *    you may not use this file except in compliance with the License.
- *    You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *    Unless required by applicable law or agreed to in writing, software
- *    distributed under the License is distributed on an "AS IS" BASIS,
- *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *    See the License for the specific language governing permissions and
- *    limitations under the License.
- */
-
-#include "AppTask.h"
-#include "ColorFormat.h"
-#include "PWMDevice.h"
-
-#include <app-common/zap-generated/attributes/Accessors.h>
-#include <app-common/zap-generated/ids/Attributes.h>
-#include <app-common/zap-generated/ids/Clusters.h>
-#include <app/ConcreteAttributePath.h>
-#include <lib/support/logging/CHIPLogging.h>
-
-LOG_MODULE_DECLARE(app, CONFIG_CHIP_APP_LOG_LEVEL);
-
-using namespace chip;
-using namespace chip::app::Clusters;
-using namespace chip::app::Clusters::OnOff;
-
-/** @brief OnOff Cluster Init
- *
- * This function is called when a specific cluster is initialized. It gives the
- * application an opportunity to take care of cluster initialization procedures.
- * It is called exactly once for each endpoint where cluster is present.
- *
- * @param endpoint   Ver.: always
- *
- */
-void emberAfOnOffClusterInitCallback(EndpointId endpoint)
-{
-    Protocols::InteractionModel::Status status;
-    bool storedValue;
-
-    // Read storedValue on/off value
-    status = Attributes::OnOff::Get(1, &storedValue);
-    if (status == Protocols::InteractionModel::Status::Success)
-    {
-        // Set actual state to stored before reboot
-        GetAppTask().GetPWMDevice().Set(storedValue);
-    }
-
-    GetAppTask().UpdateClusterState();
-}
diff --git a/examples/chef/telink/CMakeLists.txt b/examples/chef/telink/CMakeLists.txt
index 71f0c54..8538e2a 100755
--- a/examples/chef/telink/CMakeLists.txt
+++ b/examples/chef/telink/CMakeLists.txt
@@ -64,7 +64,7 @@
 include(${CHIP_ROOT}/config/telink/app/enable-gnu-std.cmake)
 include(${CHIP_ROOT}/src/app/chip_data_model.cmake)
 
-target_compile_options(app PRIVATE -fpermissive)
+target_compile_options(app PRIVATE $<$<COMPILE_LANGUAGE:CXX>:-fpermissive>)
 
 target_include_directories(app PRIVATE
                            ${CMAKE_CURRENT_SOURCE_DIR}
@@ -78,6 +78,7 @@
                            ${TELINK_COMMON}/common/include
                            ${TELINK_COMMON}/util/include
                            ${TELINK_COMMON}/app/include
+                           ${TELINK_COMMON}/zephyr_ext
 )
 
 if (CONFIG_CHIP_LIB_SHELL)
@@ -96,9 +97,15 @@
     src/AppTask.cpp
     ${TELINK_COMMON}/common/src/mainCommon.cpp
     ${TELINK_COMMON}/common/src/AppTaskCommon.cpp
-    ${TELINK_COMMON}/util/src/PWMDevice.cpp
+    ${TELINK_COMMON}/util/src/LEDManager.cpp
     ${TELINK_COMMON}/util/src/ButtonManager.cpp
     ${TELINK_COMMON}/util/src/ThreadUtil.cpp
+    ${TELINK_COMMON}/util/src/PWMManager.cpp
+    ${TELINK_COMMON}/zephyr_ext/zephyr_key_matrix.c
+    ${TELINK_COMMON}/zephyr_ext/zephyr_key_pool.c
+    ${TELINK_COMMON}/zephyr_ext/zephyr_led_pool.c
+    ${TELINK_COMMON}/zephyr_ext/zephyr_pwm_pool.c
+    ${TELINK_COMMON}/zephyr_ext/zephyr_ws2812.c
     ${CHEF}/common/stubs.cpp
 )
 
diff --git a/examples/chef/telink/include/AppConfig.h b/examples/chef/telink/include/AppConfig.h
index b309285..b5c1335 100644
--- a/examples/chef/telink/include/AppConfig.h
+++ b/examples/chef/telink/include/AppConfig.h
@@ -20,8 +20,5 @@
 
 // ---- Chef Example App Config ----
 
-#define APP_USE_EXAMPLE_START_BUTTON 0
-#define APP_USE_BLE_START_BUTTON 1
-#define APP_USE_THREAD_START_BUTTON 1
 #define APP_SET_DEVICE_INFO_PROVIDER 1
 #define APP_SET_NETWORK_COMM_ENDPOINT_SEC 0
diff --git a/examples/chef/telink/include/AppTask.h b/examples/chef/telink/include/AppTask.h
index 3b91e9a..13ede39 100644
--- a/examples/chef/telink/include/AppTask.h
+++ b/examples/chef/telink/include/AppTask.h
@@ -20,6 +20,8 @@
 
 #include "AppTaskCommon.h"
 
+class ButtonManager;
+
 class AppTask : public AppTaskCommon
 {
 public:
@@ -28,6 +30,7 @@
     friend class AppTaskCommon;
 
     CHIP_ERROR Init(void);
+    void LinkButtons(ButtonManager & buttonManager);
 
     static AppTask sAppTask;
 };
diff --git a/examples/chef/telink/src/AppTask.cpp b/examples/chef/telink/src/AppTask.cpp
index a9683f0..4b3116d 100644
--- a/examples/chef/telink/src/AppTask.cpp
+++ b/examples/chef/telink/src/AppTask.cpp
@@ -17,6 +17,7 @@
  */
 
 #include "AppTask.h"
+#include "ButtonManager.h"
 #include <app/server/Server.h>
 
 LOG_MODULE_DECLARE(app, CONFIG_CHIP_APP_LOG_LEVEL);
@@ -49,3 +50,10 @@
 
     return CHIP_NO_ERROR;
 }
+
+void AppTask::LinkButtons(ButtonManager & buttonManager)
+{
+    buttonManager.addCallback(FactoryResetButtonEventHandler, 0, true);
+    buttonManager.addCallback(ExampleActionButtonEventHandler, 1, true);
+    buttonManager.addCallback(StartBleAdvButtonEventHandler, 2, true);
+}
diff --git a/examples/contact-sensor-app/telink/CMakeLists.txt b/examples/contact-sensor-app/telink/CMakeLists.txt
index c29ef94..379a1f0 100755
--- a/examples/contact-sensor-app/telink/CMakeLists.txt
+++ b/examples/contact-sensor-app/telink/CMakeLists.txt
@@ -59,14 +59,15 @@
 include(${CHIP_ROOT}/config/telink/app/enable-gnu-std.cmake)
 include(${CHIP_ROOT}/src/app/chip_data_model.cmake)
 
-target_compile_options(app PRIVATE -fpermissive)
+target_compile_options(app PRIVATE $<$<COMPILE_LANGUAGE:CXX>:-fpermissive>)
 
 target_include_directories(app PRIVATE
                            include
                            ${GEN_DIR}/app-common
                            ${GEN_DIR}/contact-sensor-app
                            ${TELINK_COMMON}/common/include
-                           ${TELINK_COMMON}/util/include)
+                           ${TELINK_COMMON}/util/include
+                           ${TELINK_COMMON}/zephyr_ext)
 
 target_sources(app PRIVATE
                src/AppTask.cpp
@@ -74,10 +75,15 @@
                src/ZclCallbacks.cpp
                ${TELINK_COMMON}/common/src/mainCommon.cpp
                ${TELINK_COMMON}/common/src/AppTaskCommon.cpp
-               ${TELINK_COMMON}/util/src/LEDWidget.cpp
+               ${TELINK_COMMON}/util/src/LEDManager.cpp
                ${TELINK_COMMON}/util/src/ButtonManager.cpp
                ${TELINK_COMMON}/util/src/ThreadUtil.cpp
-               ${TELINK_COMMON}/util/src/PWMDevice.cpp)
+               ${TELINK_COMMON}/util/src/PWMManager.cpp
+               ${TELINK_COMMON}/zephyr_ext/zephyr_key_matrix.c
+               ${TELINK_COMMON}/zephyr_ext/zephyr_key_pool.c
+               ${TELINK_COMMON}/zephyr_ext/zephyr_led_pool.c
+               ${TELINK_COMMON}/zephyr_ext/zephyr_pwm_pool.c
+               ${TELINK_COMMON}/zephyr_ext/zephyr_ws2812.c)
 
 chip_configure_data_model(app
     INCLUDE_SERVER
diff --git a/examples/contact-sensor-app/telink/include/AppConfig.h b/examples/contact-sensor-app/telink/include/AppConfig.h
index feb2b82..ecde0f2 100644
--- a/examples/contact-sensor-app/telink/include/AppConfig.h
+++ b/examples/contact-sensor-app/telink/include/AppConfig.h
@@ -19,11 +19,5 @@
 #pragma once
 
 // ---- All Clusters Application example config ----
-#define APP_USE_EXAMPLE_START_BUTTON 1
-#define APP_USE_BLE_START_BUTTON 0
-#define APP_USE_THREAD_START_BUTTON 0
 #define APP_SET_DEVICE_INFO_PROVIDER 1
 #define APP_SET_NETWORK_COMM_ENDPOINT_SEC 0
-#if defined(CONFIG_BOARD_TLSR9518ADK80D) || defined(CONFIG_BOARD_TLSR9528A)
-#define APP_USE_IDENTIFY_PWM 1
-#endif
diff --git a/examples/contact-sensor-app/telink/include/AppTask.h b/examples/contact-sensor-app/telink/include/AppTask.h
index 3ac0028..8d888da 100644
--- a/examples/contact-sensor-app/telink/include/AppTask.h
+++ b/examples/contact-sensor-app/telink/include/AppTask.h
@@ -39,6 +39,7 @@
     friend class AppTaskCommon;
 
     CHIP_ERROR Init(void);
+    void LinkLeds(LedManager & ledManager);
 
     static void OnStateChanged(ContactSensorManager::State aState);
 
diff --git a/examples/contact-sensor-app/telink/src/AppTask.cpp b/examples/contact-sensor-app/telink/src/AppTask.cpp
index dbcf9e1..8ddb43d 100644
--- a/examples/contact-sensor-app/telink/src/AppTask.cpp
+++ b/examples/contact-sensor-app/telink/src/AppTask.cpp
@@ -17,6 +17,7 @@
  */
 
 #include "AppTask.h"
+#include "LEDManager.h"
 
 #include <app-common/zap-generated/attributes/Accessors.h>
 
@@ -25,25 +26,14 @@
 
 LOG_MODULE_DECLARE(app, CONFIG_CHIP_APP_LOG_LEVEL);
 
-namespace {
-#if CONFIG_CHIP_ENABLE_APPLICATION_STATUS_LED
-LEDWidget sContactSensorLED;
-#endif
-} // namespace
-
 AppTask AppTask::sAppTask;
 
 CHIP_ERROR AppTask::Init(void)
 {
-#if APP_USE_EXAMPLE_START_BUTTON
     SetExampleButtonCallbacks(ContactActionEventHandler);
-#endif
     InitCommonParts();
 
-#if CONFIG_CHIP_ENABLE_APPLICATION_STATUS_LED
-    sContactSensorLED.Init(GPIO_DT_SPEC_GET(DT_ALIAS(led2), gpios));
-    sContactSensorLED.Set(ContactSensorMgr().IsContactClosed());
-#endif
+    LedManager::getInstance().setLed(LedManager::EAppLed_App0, ContactSensorMgr().IsContactClosed());
 
     UpdateDeviceState();
 
@@ -60,16 +50,12 @@
     if (ContactSensorManager::State::kContactClosed == aState)
     {
         LOG_INF("Contact state changed to CLOSED");
-#if CONFIG_CHIP_ENABLE_APPLICATION_STATUS_LED
-        sContactSensorLED.Set(true);
-#endif
+        LedManager::getInstance().setLed(LedManager::EAppLed_App0, true);
     }
     else if (ContactSensorManager::State::kContactOpened == aState)
     {
         LOG_INF("Contact state changed to OPEN");
-#if CONFIG_CHIP_ENABLE_APPLICATION_STATUS_LED
-        sContactSensorLED.Set(false);
-#endif
+        LedManager::getInstance().setLed(LedManager::EAppLed_App0, false);
     }
 
     if (sAppTask.IsSyncClusterToButtonAction())
@@ -155,8 +141,15 @@
     /* get boolean state attribute value */
     (void) app::Clusters::BooleanState::Attributes::StateValue::Get(1, &stateValueAttrValue);
 
-    ChipLogProgress(NotSpecified, "StateValue::Get : %d", stateValueAttrValue);
+    LedManager::getInstance().setLed(LedManager::EAppLed_App0, stateValueAttrValue);
+}
+
+void AppTask::LinkLeds(LedManager & ledManager)
+{
 #if CONFIG_CHIP_ENABLE_APPLICATION_STATUS_LED
-    sContactSensorLED.Set(stateValueAttrValue);
-#endif
+    ledManager.linkLed(LedManager::EAppLed_Status, 0);
+    ledManager.linkLed(LedManager::EAppLed_App0, 1);
+#else
+    ledManager.linkLed(LedManager::EAppLed_App0, 0);
+#endif // CONFIG_CHIP_ENABLE_APPLICATION_STATUS_LED
 }
diff --git a/examples/light-switch-app/ameba/README.md b/examples/light-switch-app/ameba/README.md
index bc7953a..4437e4c 100644
--- a/examples/light-switch-app/ameba/README.md
+++ b/examples/light-switch-app/ameba/README.md
@@ -26,11 +26,11 @@
 
 -   Pull docker image:
 
-          $ docker pull ghcr.io/project-chip/chip-build-ameba:42
+          $ docker pull ghcr.io/project-chip/chip-build-ameba:46
 
 -   Run docker container:
 
-          $ docker run -it -v ${CHIP_DIR}:/root/chip ghcr.io/project-chip/chip-build-ameba:42
+          $ docker run -it -v ${CHIP_DIR}:/root/chip ghcr.io/project-chip/chip-build-ameba:46
 
 -   Setup build environment:
 
diff --git a/examples/light-switch-app/telink/CMakeLists.txt b/examples/light-switch-app/telink/CMakeLists.txt
index 451727b..f634efa 100755
--- a/examples/light-switch-app/telink/CMakeLists.txt
+++ b/examples/light-switch-app/telink/CMakeLists.txt
@@ -59,7 +59,7 @@
 include(${CHIP_ROOT}/config/telink/app/enable-gnu-std.cmake)
 include(${CHIP_ROOT}/src/app/chip_data_model.cmake)
 
-target_compile_options(app PRIVATE -fpermissive)
+target_compile_options(app PRIVATE $<$<COMPILE_LANGUAGE:CXX>:-fpermissive>)
 
 target_include_directories(app PRIVATE
                            include
@@ -67,7 +67,8 @@
                            ${GEN_DIR}/light-switch-app
                            ${TELINK_COMMON}/common/include
                            ${TELINK_COMMON}/util/include
-                           ${TELINK_COMMON}/app/include)
+                           ${TELINK_COMMON}/app/include
+                           ${TELINK_COMMON}/zephyr_ext)
 
 target_sources(app PRIVATE
                src/AppTask.cpp
@@ -75,10 +76,15 @@
                src/binding-handler.cpp
                ${TELINK_COMMON}/common/src/mainCommon.cpp
                ${TELINK_COMMON}/common/src/AppTaskCommon.cpp
-               ${TELINK_COMMON}/util/src/LEDWidget.cpp
+               ${TELINK_COMMON}/util/src/LEDManager.cpp
                ${TELINK_COMMON}/util/src/ButtonManager.cpp
                ${TELINK_COMMON}/util/src/ThreadUtil.cpp
-               ${TELINK_COMMON}/util/src/PWMDevice.cpp)
+               ${TELINK_COMMON}/util/src/PWMManager.cpp
+               ${TELINK_COMMON}/zephyr_ext/zephyr_key_matrix.c
+               ${TELINK_COMMON}/zephyr_ext/zephyr_key_pool.c
+               ${TELINK_COMMON}/zephyr_ext/zephyr_led_pool.c
+               ${TELINK_COMMON}/zephyr_ext/zephyr_pwm_pool.c
+               ${TELINK_COMMON}/zephyr_ext/zephyr_ws2812.c)
 
 chip_configure_data_model(app
     INCLUDE_SERVER
diff --git a/examples/light-switch-app/telink/include/AppConfig.h b/examples/light-switch-app/telink/include/AppConfig.h
index 8258f39..15715b0 100644
--- a/examples/light-switch-app/telink/include/AppConfig.h
+++ b/examples/light-switch-app/telink/include/AppConfig.h
@@ -20,11 +20,5 @@
 
 // ---- Light Switch Example App Config ----
 
-#define APP_USE_EXAMPLE_START_BUTTON 1
-#define APP_USE_BLE_START_BUTTON 0
-#define APP_USE_THREAD_START_BUTTON 0
 #define APP_SET_DEVICE_INFO_PROVIDER 1
 #define APP_SET_NETWORK_COMM_ENDPOINT_SEC 0
-#if defined(CONFIG_BOARD_TLSR9518ADK80D) || defined(CONFIG_BOARD_TLSR9528A)
-#define APP_USE_IDENTIFY_PWM 1
-#endif
diff --git a/examples/light-switch-app/telink/src/AppTask.cpp b/examples/light-switch-app/telink/src/AppTask.cpp
index 39b92cc..96dcdd0 100644
--- a/examples/light-switch-app/telink/src/AppTask.cpp
+++ b/examples/light-switch-app/telink/src/AppTask.cpp
@@ -25,9 +25,7 @@
 
 CHIP_ERROR AppTask::Init(void)
 {
-#if APP_USE_EXAMPLE_START_BUTTON
     SetExampleButtonCallbacks(SwitchActionEventHandler);
-#endif
     InitCommonParts();
 
     // Configure Bindings
diff --git a/examples/lighting-app/ameba/README.md b/examples/lighting-app/ameba/README.md
index 44bc04a..36fbe0f 100644
--- a/examples/lighting-app/ameba/README.md
+++ b/examples/lighting-app/ameba/README.md
@@ -23,11 +23,11 @@
 
 -   Pull docker image:
 
-          $ docker pull ghcr.io/project-chip/chip-build-ameba:42
+          $ docker pull ghcr.io/project-chip/chip-build-ameba:46
 
 -   Run docker container:
 
-          $ docker run -it -v ${CHIP_DIR}:/root/chip ghcr.io/project-chip/chip-build-ameba:42
+          $ docker run -it -v ${CHIP_DIR}:/root/chip ghcr.io/project-chip/chip-build-ameba:46
 
 -   Setup build environment:
 
diff --git a/examples/lighting-app/telink/CMakeLists.txt b/examples/lighting-app/telink/CMakeLists.txt
index 9620a00..d0b0da7 100644
--- a/examples/lighting-app/telink/CMakeLists.txt
+++ b/examples/lighting-app/telink/CMakeLists.txt
@@ -91,7 +91,7 @@
 include(${CHIP_ROOT}/config/telink/app/enable-gnu-std.cmake)
 include(${CHIP_ROOT}/src/app/chip_data_model.cmake)
 
-target_compile_options(app PRIVATE -fpermissive)
+target_compile_options(app PRIVATE $<$<COMPILE_LANGUAGE:CXX>:-fpermissive>)
 
 target_include_directories(app PRIVATE
                            include
@@ -99,19 +99,24 @@
                            ${GEN_DIR}/lighting-app
                            ${TELINK_COMMON}/common/include
                            ${TELINK_COMMON}/util/include
-                           ${TELINK_COMMON}/app/include)
+                           ${TELINK_COMMON}/app/include
+                           ${TELINK_COMMON}/zephyr_ext)
 
 target_sources(app PRIVATE
                src/AppTask.cpp
                src/ZclCallbacks.cpp
                ${TELINK_COMMON}/common/src/mainCommon.cpp
                ${TELINK_COMMON}/common/src/AppTaskCommon.cpp
-               ${TELINK_COMMON}/util/src/LEDWidget.cpp
+               ${TELINK_COMMON}/util/src/LEDManager.cpp
                ${TELINK_COMMON}/util/src/ButtonManager.cpp
                ${TELINK_COMMON}/util/src/ThreadUtil.cpp
-               ${TELINK_COMMON}/util/src/PWMDevice.cpp
-               ${TELINK_COMMON}/util/src/WS2812Device.cpp
-               ${TELINK_COMMON}/util/src/ColorFormat.cpp)
+               ${TELINK_COMMON}/util/src/PWMManager.cpp
+               ${TELINK_COMMON}/util/src/ColorFormat.cpp
+               ${TELINK_COMMON}/zephyr_ext/zephyr_key_matrix.c
+               ${TELINK_COMMON}/zephyr_ext/zephyr_key_pool.c
+               ${TELINK_COMMON}/zephyr_ext/zephyr_led_pool.c
+               ${TELINK_COMMON}/zephyr_ext/zephyr_pwm_pool.c
+               ${TELINK_COMMON}/zephyr_ext/zephyr_ws2812.c)
 
 chip_configure_data_model(app
     INCLUDE_SERVER
diff --git a/examples/lighting-app/telink/README.md b/examples/lighting-app/telink/README.md
index 2f69617..f4dfefe 100644
--- a/examples/lighting-app/telink/README.md
+++ b/examples/lighting-app/telink/README.md
@@ -98,30 +98,6 @@
 | Blinks (950 ms on/50 ms off)    | Finish ( `Clusters::Identify::EffectIdentifierEnum::kFinishEffect`)          |
 | LED off                         | Stop (`Clusters::Identify::EffectIdentifierEnum::kStopEffect`)               |
 
-#### Indicate current state of lightbulb
-
-By default, only **Blue** LED is used to show current state of lightbulb (only
-for lightning-app).
-
-To enable RGB functionality in Your application set this config:
-
-In Matter examples/lighting-app/telink/include/**AppConfig.h**, set the define
-`USE_RGB_PWM`:
-
-```bash
-    define USE_RGB_PWM 1
-```
-
-To get current state of lightbulb in RGB mode, connect 3-color LED module to
-following pins:
-
-| Name  |         Pin         |
-| :---: | :-----------------: |
-|  Red  | PE2 (pin 8 of J34)  |
-| Green | PE0 (pin 5 of J34)  |
-| Blue  | PB4 (pin 20 of J34) |
-|  GND  | GND (pin 24 of J50) |
-
 ### CHIP tool commands
 
 1. Build
diff --git a/examples/lighting-app/telink/include/AppConfig.h b/examples/lighting-app/telink/include/AppConfig.h
index b616746..a3639ef 100644
--- a/examples/lighting-app/telink/include/AppConfig.h
+++ b/examples/lighting-app/telink/include/AppConfig.h
@@ -20,14 +20,5 @@
 
 // ---- Lighting Example App Config ----
 
-#define APP_USE_EXAMPLE_START_BUTTON 1
-#define APP_USE_BLE_START_BUTTON 1
-#define APP_USE_THREAD_START_BUTTON 1
 #define APP_SET_DEVICE_INFO_PROVIDER 1
 #define APP_SET_NETWORK_COMM_ENDPOINT_SEC 0
-#if defined(CONFIG_BOARD_TLSR9518ADK80D) || defined(CONFIG_BOARD_TLSR9528A)
-#define APP_USE_IDENTIFY_PWM 1
-#endif
-
-// Lighting LED config
-#define USE_RGB_PWM 0
diff --git a/examples/lighting-app/telink/include/AppTask.h b/examples/lighting-app/telink/include/AppTask.h
index 67b69ef..c835c88 100644
--- a/examples/lighting-app/telink/include/AppTask.h
+++ b/examples/lighting-app/telink/include/AppTask.h
@@ -19,22 +19,29 @@
 #pragma once
 
 #include "AppTaskCommon.h"
-#include "PWMDevice.h"
 
 class AppTask : public AppTaskCommon
 {
 public:
+    enum Fixture_Action : uint8_t
+    {
+        ON_ACTION = 0,
+        OFF_ACTION,
+        LEVEL_ACTION,
+        COLOR_ACTION_XY,
+        COLOR_ACTION_HSV,
+        COLOR_ACTION_CT,
+
+        INVALID_ACTION
+    };
+
 #ifdef CONFIG_CHIP_ENABLE_POWER_ON_FACTORY_RESET
     void PowerOnFactoryReset(void);
 #endif /* CONFIG_CHIP_ENABLE_POWER_ON_FACTORY_RESET */
-    void SetInitiateAction(PWMDevice::Action_t aAction, int32_t aActor, uint8_t * value);
-    void UpdateClusterState(void);
 
-#ifdef CONFIG_WS2812_STRIP
-    WS2812Device & GetLightingDevice(void) { return mWS2812Device; }
-#else
-    PWMDevice & GetLightingDevice(void) { return mPwmRgbBlueLed; }
-#endif /* CONFIG_WS2812_STRIP */
+    bool IsTurnedOn() const;
+    void SetInitiateAction(Fixture_Action aAction, int32_t aActor, uint8_t * value);
+    void UpdateClusterState(void);
 
 private:
     friend AppTask & GetAppTask(void);
@@ -42,9 +49,6 @@
 
     CHIP_ERROR Init(void);
 
-    static void ActionInitiated(PWMDevice::Action_t aAction, int32_t aActor);
-    static void ActionCompleted(PWMDevice::Action_t aAction, int32_t aActor);
-
     static void LightingActionEventHandler(AppEvent * aEvent);
 #ifdef CONFIG_CHIP_ENABLE_POWER_ON_FACTORY_RESET
     static void PowerOnFactoryResetEventHandler(AppEvent * aEvent);
@@ -54,16 +58,6 @@
     static k_timer sPowerOnFactoryResetTimer;
 #endif /* CONFIG_CHIP_ENABLE_POWER_ON_FACTORY_RESET */
 
-#ifdef CONFIG_WS2812_STRIP
-    WS2812Device mWS2812Device;
-#else
-    PWMDevice mPwmRgbBlueLed;
-#if USE_RGB_PWM
-    PWMDevice mPwmRgbGreenLed;
-    PWMDevice mPwmRgbRedLed;
-#endif
-#endif /* CONFIG_WS2812_STRIP */
-
     static AppTask sAppTask;
 };
 
diff --git a/examples/lighting-app/telink/src/AppTask.cpp b/examples/lighting-app/telink/src/AppTask.cpp
index 54dd270..bb4dc41 100644
--- a/examples/lighting-app/telink/src/AppTask.cpp
+++ b/examples/lighting-app/telink/src/AppTask.cpp
@@ -20,34 +20,29 @@
 #include <app/server/Server.h>
 
 #include "ColorFormat.h"
-#include "PWMDevice.h"
+#include "PWMManager.h"
 
 #include <app-common/zap-generated/attributes/Accessors.h>
 
 LOG_MODULE_DECLARE(app, CONFIG_CHIP_APP_LOG_LEVEL);
 
 namespace {
-#ifdef CONFIG_WS2812_STRIP
-const struct device * const ws2812_dev = DEVICE_DT_GET(DT_ALIAS(led_strip));
-#else
-const struct pwm_dt_spec sPwmRgbSpecBlueLed  = PWM_DT_SPEC_GET_OR(DT_ALIAS(pwm_led0), {});
-#if USE_RGB_PWM
-const struct pwm_dt_spec sPwmRgbSpecGreenLed = PWM_DT_SPEC_GET_OR(DT_ALIAS(pwm_led1), {});
-const struct pwm_dt_spec sPwmRgbSpecRedLed   = PWM_DT_SPEC_GET_OR(DT_ALIAS(pwm_led2), {});
-#endif
-#endif // CONFIG_WS2812_STRIP
-
-#if defined(CONFIG_WS2812_STRIP) || USE_RGB_PWM
+bool sfixture_on;
 uint8_t sBrightness;
-PWMDevice::Action_t sColorAction = PWMDevice::INVALID_ACTION;
+AppTask::Fixture_Action sColorAction = AppTask::INVALID_ACTION;
 XyColor_t sXY;
 HsvColor_t sHSV;
 CtColor_t sCT;
-#endif // CONFIG_WS2812_STRIP || USE_RGB_PWM
+RgbColor_t sLedRgb;
 } // namespace
 
 AppTask AppTask::sAppTask;
 
+bool AppTask::IsTurnedOn() const
+{
+    return sfixture_on;
+}
+
 #ifdef CONFIG_CHIP_ENABLE_POWER_ON_FACTORY_RESET
 void AppTask::PowerOnFactoryReset(void)
 {
@@ -61,143 +56,47 @@
 
 CHIP_ERROR AppTask::Init(void)
 {
-    CHIP_ERROR err;
-
-    // Init lighting manager
-    uint8_t minLightLevel = kDefaultMinLevel;
-    Clusters::LevelControl::Attributes::MinLevel::Get(kExampleEndpointId, &minLightLevel);
-
-    uint8_t maxLightLevel = kDefaultMaxLevel;
-    Clusters::LevelControl::Attributes::MaxLevel::Get(kExampleEndpointId, &maxLightLevel);
-
-#ifdef CONFIG_WS2812_STRIP
-    err = sAppTask.mWS2812Device.Init(ws2812_dev, STRIP_NUM_PIXELS(led_strip));
-    if (err != CHIP_NO_ERROR)
-    {
-        LOG_ERR("WS2812 Device Init fail");
-        return err;
-    }
-#else
-    err = sAppTask.mPwmRgbBlueLed.Init(&sPwmRgbSpecBlueLed, minLightLevel, maxLightLevel, maxLightLevel);
-    if (err != CHIP_NO_ERROR)
-    {
-        LOG_ERR("Blue RGB PWM Device Init fail");
-        return err;
-    }
-#if USE_RGB_PWM
-    err = sAppTask.mPwmRgbRedLed.Init(&sPwmRgbSpecRedLed, minLightLevel, maxLightLevel, maxLightLevel);
-    if (err != CHIP_NO_ERROR)
-    {
-        LOG_ERR("Red RGB PWM Device Init fail");
-        return err;
-    }
-
-    err = sAppTask.mPwmRgbGreenLed.Init(&sPwmRgbSpecGreenLed, minLightLevel, maxLightLevel, maxLightLevel);
-    if (err != CHIP_NO_ERROR)
-    {
-        LOG_ERR("Green RGB PWM Device Init fail");
-        return err;
-    }
-#endif
-    sAppTask.mPwmRgbBlueLed.SetCallbacks(ActionInitiated, ActionCompleted, nullptr);
-#endif // CONFIG_WS2812_STRIP
-
-#if APP_USE_EXAMPLE_START_BUTTON
     SetExampleButtonCallbacks(LightingActionEventHandler);
-#endif
     InitCommonParts();
 
+    Protocols::InteractionModel::Status status;
+
+    app::DataModel::Nullable<uint8_t> brightness;
+    // Read brightness value
+    status = Clusters::LevelControl::Attributes::CurrentLevel::Get(kExampleEndpointId, brightness);
+    if (status == Protocols::InteractionModel::Status::Success && !brightness.IsNull())
+    {
+        sBrightness = brightness.Value();
+    }
+
+    memset(&sLedRgb, sBrightness, sizeof(RgbColor_t));
+
+    bool storedValue;
+    // Read storedValue on/off value
+    status = Clusters::OnOff::Attributes::OnOff::Get(1, &storedValue);
+    if (status == Protocols::InteractionModel::Status::Success)
+    {
+        // Set actual state to stored before reboot
+        SetInitiateAction(storedValue ? ON_ACTION : OFF_ACTION, static_cast<int32_t>(AppEvent::kEventType_Lighting), nullptr);
+    }
+
     return CHIP_NO_ERROR;
 }
 
 void AppTask::LightingActionEventHandler(AppEvent * aEvent)
 {
-#ifdef CONFIG_WS2812_STRIP
-    if (aEvent->Type == AppEvent::kEventType_Button)
-    {
-        if (sAppTask.mWS2812Device.IsTurnedOn())
-        {
-            sAppTask.mWS2812Device.Set(SET_RGB_TURN_OFF);
-        }
-        else
-        {
-            sAppTask.mWS2812Device.Set(SET_RGB_TURN_ON);
-        }
-
-        sAppTask.UpdateClusterState();
-    }
-#else
-    PWMDevice::Action_t action = PWMDevice::INVALID_ACTION;
-    int32_t actor              = 0;
+    Fixture_Action action = INVALID_ACTION;
+    int32_t actor         = 0;
 
     if (aEvent->Type == AppEvent::kEventType_Lighting)
     {
-        action = static_cast<PWMDevice::Action_t>(aEvent->LightingEvent.Action);
+        action = static_cast<Fixture_Action>(aEvent->LightingEvent.Action);
         actor  = aEvent->LightingEvent.Actor;
     }
     else if (aEvent->Type == AppEvent::kEventType_Button)
     {
-#if USE_RGB_PWM
-        if (sAppTask.mPwmRgbRedLed.IsTurnedOn() || sAppTask.mPwmRgbGreenLed.IsTurnedOn() || sAppTask.mPwmRgbBlueLed.IsTurnedOn())
-        {
-            action = PWMDevice::OFF_ACTION;
-        }
-        else
-        {
-            action = PWMDevice::ON_ACTION;
-        }
-#else
-        action = sAppTask.mPwmRgbBlueLed.IsTurnedOn() ? PWMDevice::OFF_ACTION : PWMDevice::ON_ACTION;
-#endif
-        actor = AppEvent::kEventType_Button;
-    }
+        sfixture_on = !sfixture_on;
 
-    if (action != PWMDevice::INVALID_ACTION &&
-        (
-#if USE_RGB_PWM
-            !sAppTask.mPwmRgbRedLed.InitiateAction(action, actor, NULL) ||
-            !sAppTask.mPwmRgbGreenLed.InitiateAction(action, actor, NULL) ||
-#endif
-            !sAppTask.mPwmRgbBlueLed.InitiateAction(action, actor, NULL)))
-    {
-        LOG_INF("Action is in progress or active");
-    }
-#endif // CONFIG_WS2812_STRIP
-}
-
-void AppTask::ActionInitiated(PWMDevice::Action_t aAction, int32_t aActor)
-{
-    if (aAction == PWMDevice::ON_ACTION)
-    {
-        LOG_DBG("ON_ACTION initiated");
-    }
-    else if (aAction == PWMDevice::OFF_ACTION)
-    {
-        LOG_DBG("OFF_ACTION initiated");
-    }
-    else if (aAction == PWMDevice::LEVEL_ACTION)
-    {
-        LOG_DBG("LEVEL_ACTION initiated");
-    }
-}
-
-void AppTask::ActionCompleted(PWMDevice::Action_t aAction, int32_t aActor)
-{
-    if (aAction == PWMDevice::ON_ACTION)
-    {
-        LOG_DBG("ON_ACTION completed");
-    }
-    else if (aAction == PWMDevice::OFF_ACTION)
-    {
-        LOG_DBG("OFF_ACTION completed");
-    }
-    else if (aAction == PWMDevice::LEVEL_ACTION)
-    {
-        LOG_DBG("LEVEL_ACTION completed");
-    }
-
-    if (aActor == AppEvent::kEventType_Button)
-    {
         sAppTask.UpdateClusterState();
     }
 }
@@ -205,38 +104,8 @@
 void AppTask::UpdateClusterState(void)
 {
     Protocols::InteractionModel::Status status;
-    bool isTurnedOn;
-    uint8_t setLevel;
-
-#if defined(CONFIG_WS2812_STRIP) || USE_RGB_PWM
-#ifdef CONFIG_WS2812_STRIP
-    isTurnedOn = sAppTask.mWS2812Device.IsTurnedOn();
-#else
-    isTurnedOn =
-        sAppTask.mPwmRgbRedLed.IsTurnedOn() || sAppTask.mPwmRgbGreenLed.IsTurnedOn() || sAppTask.mPwmRgbBlueLed.IsTurnedOn();
-#endif // CONFIG_WS2812_STRIP
-
-    if (sColorAction == PWMDevice::COLOR_ACTION_XY || sColorAction == PWMDevice::COLOR_ACTION_HSV ||
-        sColorAction == PWMDevice::COLOR_ACTION_CT)
-    {
-        setLevel = sBrightness;
-    }
-    else
-    {
-#ifdef CONFIG_WS2812_STRIP
-        setLevel = sAppTask.mWS2812Device.GetBlueLevel();
-        if (setLevel > kDefaultMaxLevel)
-        {
-            setLevel = kDefaultMaxLevel;
-        }
-#else
-        setLevel = sAppTask.mPwmRgbBlueLed.GetLevel();
-#endif // CONFIG_WS2812_STRIP
-    }
-#else
-    isTurnedOn = sAppTask.mPwmRgbBlueLed.IsTurnedOn();
-    setLevel   = sAppTask.mPwmRgbBlueLed.GetLevel();
-#endif // CONFIG_WS2812_STRIP || USE_RGB_PWM
+    bool isTurnedOn  = sfixture_on;
+    uint8_t setLevel = sBrightness;
 
     // write the new on/off value
     status = Clusters::OnOff::Attributes::OnOff::Set(kExampleEndpointId, isTurnedOn);
@@ -252,100 +121,86 @@
     }
 }
 
-void AppTask::SetInitiateAction(PWMDevice::Action_t aAction, int32_t aActor, uint8_t * value)
+void AppTask::SetInitiateAction(Fixture_Action aAction, int32_t aActor, uint8_t * value)
 {
-#if defined(CONFIG_WS2812_STRIP) || USE_RGB_PWM
     bool setRgbAction = false;
-    RgbColor_t rgb;
-#endif // CONFIG_WS2812_STRIP || USE_RGB_PWM
 
-    if (aAction == PWMDevice::ON_ACTION || aAction == PWMDevice::OFF_ACTION)
+    if (aAction == ON_ACTION || aAction == OFF_ACTION)
     {
-#ifdef CONFIG_WS2812_STRIP
-        if (aAction == PWMDevice::ON_ACTION)
+        if (aAction == ON_ACTION)
         {
-            sAppTask.mWS2812Device.Set(SET_RGB_TURN_ON);
-        }
-        else if (aAction == PWMDevice::OFF_ACTION)
-        {
-            sAppTask.mWS2812Device.Set(SET_RGB_TURN_OFF);
-        }
-#else
-        sAppTask.mPwmRgbBlueLed.InitiateAction(aAction, aActor, value);
-#if USE_RGB_PWM
-        sAppTask.mPwmRgbRedLed.InitiateAction(aAction, aActor, value);
-        sAppTask.mPwmRgbGreenLed.InitiateAction(aAction, aActor, value);
-#endif
-#endif // CONFIG_WS2812_STRIP
-    }
-    else if (aAction == PWMDevice::LEVEL_ACTION)
-    {
-#if defined(CONFIG_WS2812_STRIP) || USE_RGB_PWM
-        // Save a new brightness for ColorControl
-        sBrightness = *value;
-
-        if (sColorAction == PWMDevice::COLOR_ACTION_XY)
-        {
-            rgb = XYToRgb(sBrightness, sXY.x, sXY.y);
-        }
-        else if (sColorAction == PWMDevice::COLOR_ACTION_HSV)
-        {
-            sHSV.v = sBrightness;
-            rgb    = HsvToRgb(sHSV);
+            sfixture_on = true;
+            PwmManager::getInstance().setPwm(PwmManager::EAppPwm_Red, (((uint32_t) sLedRgb.r * 1000) / UINT8_MAX));
+            PwmManager::getInstance().setPwm(PwmManager::EAppPwm_Green, (((uint32_t) sLedRgb.g * 1000) / UINT8_MAX));
+            PwmManager::getInstance().setPwm(PwmManager::EAppPwm_Blue, (((uint32_t) sLedRgb.b * 1000) / UINT8_MAX));
         }
         else
         {
-            memset(&rgb, sBrightness, sizeof(RgbColor_t));
+            sfixture_on = false;
+            PwmManager::getInstance().setPwm(PwmManager::EAppPwm_Red, false);
+            PwmManager::getInstance().setPwm(PwmManager::EAppPwm_Green, false);
+            PwmManager::getInstance().setPwm(PwmManager::EAppPwm_Blue, false);
+        }
+    }
+    else if (aAction == LEVEL_ACTION)
+    {
+        // Save a new brightness for ColorControl
+        sBrightness = *value;
+
+        if (sColorAction == COLOR_ACTION_XY)
+        {
+            sLedRgb = XYToRgb(sBrightness, sXY.x, sXY.y);
+        }
+        else if (sColorAction == COLOR_ACTION_HSV)
+        {
+            sHSV.v  = sBrightness;
+            sLedRgb = HsvToRgb(sHSV);
+        }
+        else
+        {
+            memset(&sLedRgb, sBrightness, sizeof(RgbColor_t));
         }
 
-        ChipLogProgress(Zcl, "New brightness: %u | R: %u, G: %u, B: %u", sBrightness, rgb.r, rgb.g, rgb.b);
+        ChipLogProgress(Zcl, "New brightness: %u | R: %u, G: %u, B: %u", sBrightness, sLedRgb.r, sLedRgb.g, sLedRgb.b);
         setRgbAction = true;
-#else
-        sAppTask.mPwmRgbBlueLed.InitiateAction(aAction, aActor, value);
-#endif // CONFIG_WS2812_STRIP || USE_RGB_PWM
     }
-#if defined(CONFIG_WS2812_STRIP) || USE_RGB_PWM
-    else if (aAction == PWMDevice::COLOR_ACTION_XY)
+    else if (aAction == COLOR_ACTION_XY)
     {
-        sXY = *reinterpret_cast<XyColor_t *>(value);
-        rgb = XYToRgb(sBrightness, sXY.x, sXY.y);
-        ChipLogProgress(Zcl, "XY to RGB: X: %u, Y: %u, Level: %u | R: %u, G: %u, B: %u", sXY.x, sXY.y, sBrightness, rgb.r, rgb.g,
-                        rgb.b);
+        sXY     = *reinterpret_cast<XyColor_t *>(value);
+        sLedRgb = XYToRgb(sBrightness, sXY.x, sXY.y);
+        ChipLogProgress(Zcl, "XY to RGB: X: %u, Y: %u, Level: %u | R: %u, G: %u, B: %u", sXY.x, sXY.y, sBrightness, sLedRgb.r,
+                        sLedRgb.g, sLedRgb.b);
         setRgbAction = true;
-        sColorAction = PWMDevice::COLOR_ACTION_XY;
+        sColorAction = COLOR_ACTION_XY;
     }
-    else if (aAction == PWMDevice::COLOR_ACTION_HSV)
+    else if (aAction == COLOR_ACTION_HSV)
     {
-        sHSV   = *reinterpret_cast<HsvColor_t *>(value);
-        sHSV.v = sBrightness;
-        rgb    = HsvToRgb(sHSV);
-        ChipLogProgress(Zcl, "HSV to RGB: H: %u, S: %u, V: %u | R: %u, G: %u, B: %u", sHSV.h, sHSV.s, sHSV.v, rgb.r, rgb.g, rgb.b);
+        sHSV    = *reinterpret_cast<HsvColor_t *>(value);
+        sHSV.v  = sBrightness;
+        sLedRgb = HsvToRgb(sHSV);
+        ChipLogProgress(Zcl, "HSV to RGB: H: %u, S: %u, V: %u | R: %u, G: %u, B: %u", sHSV.h, sHSV.s, sHSV.v, sLedRgb.r, sLedRgb.g,
+                        sLedRgb.b);
         setRgbAction = true;
-        sColorAction = PWMDevice::COLOR_ACTION_HSV;
+        sColorAction = COLOR_ACTION_HSV;
     }
-    else if (aAction == PWMDevice::COLOR_ACTION_CT)
+    else if (aAction == COLOR_ACTION_CT)
     {
         sCT = *reinterpret_cast<CtColor_t *>(value);
         if (sCT.ctMireds)
         {
-            rgb = CTToRgb(sCT);
-            ChipLogProgress(Zcl, "ColorTemp to RGB: CT: %u | R: %u, G: %u, B: %u", sCT.ctMireds, rgb.r, rgb.g, rgb.b);
+            sLedRgb = CTToRgb(sCT);
+            ChipLogProgress(Zcl, "ColorTemp to RGB: CT: %u | R: %u, G: %u, B: %u", sCT.ctMireds, sLedRgb.r, sLedRgb.g, sLedRgb.b);
             setRgbAction = true;
-            sColorAction = PWMDevice::COLOR_ACTION_CT;
+            sColorAction = COLOR_ACTION_CT;
         }
     }
 
     if (setRgbAction)
     {
-#ifdef CONFIG_WS2812_STRIP
-        sAppTask.mWS2812Device.SetLevel(&rgb);
-#else
-        sAppTask.mPwmRgbRedLed.InitiateAction(aAction, aActor, &rgb.r);
-        sAppTask.mPwmRgbGreenLed.InitiateAction(aAction, aActor, &rgb.g);
-        sAppTask.mPwmRgbBlueLed.InitiateAction(aAction, aActor, &rgb.b);
-#endif // CONFIG_WS2812_STRIP
+        PwmManager::getInstance().setPwm(PwmManager::EAppPwm_Red, (((uint32_t) sLedRgb.r * 1000) / UINT8_MAX));
+        PwmManager::getInstance().setPwm(PwmManager::EAppPwm_Green, (((uint32_t) sLedRgb.g * 1000) / UINT8_MAX));
+        PwmManager::getInstance().setPwm(PwmManager::EAppPwm_Blue, (((uint32_t) sLedRgb.b * 1000) / UINT8_MAX));
     }
-#endif // CONFIG_WS2812_STRIP || USE_RGB_PWM
 }
 
 #ifdef CONFIG_CHIP_ENABLE_POWER_ON_FACTORY_RESET
@@ -359,15 +214,9 @@
 {
     LOG_INF("Lighting App Power On Factory Reset Handler");
     sPowerOnFactoryResetTimerCnt = 1;
-#ifdef CONFIG_WS2812_STRIP
-    sAppTask.mWS2812Device.Set(sPowerOnFactoryResetTimerCnt % 2);
-#else
-    sAppTask.mPwmRgbBlueLed.Set(sPowerOnFactoryResetTimerCnt % 2);
-#if USE_RGB_PWM
-    sAppTask.mPwmRgbRedLed.Set(sPowerOnFactoryResetTimerCnt % 2);
-    sAppTask.mPwmRgbGreenLed.Set(sPowerOnFactoryResetTimerCnt % 2);
-#endif
-#endif // CONFIG_WS2812_STRIP
+    PwmManager::getInstance().setPwm(PwmManager::EAppPwm_Red, (bool) (sPowerOnFactoryResetTimerCnt % 2));
+    PwmManager::getInstance().setPwm(PwmManager::EAppPwm_Green, (bool) (sPowerOnFactoryResetTimerCnt % 2));
+    PwmManager::getInstance().setPwm(PwmManager::EAppPwm_Blue, (bool) (sPowerOnFactoryResetTimerCnt % 2));
     k_timer_init(&sPowerOnFactoryResetTimer, PowerOnFactoryResetTimerEvent, nullptr);
     k_timer_start(&sPowerOnFactoryResetTimer, K_MSEC(kPowerOnFactoryResetIndicationTimeMs),
                   K_MSEC(kPowerOnFactoryResetIndicationTimeMs));
@@ -377,15 +226,9 @@
 {
     sPowerOnFactoryResetTimerCnt++;
     LOG_INF("Lighting App Power On Factory Reset Handler %u", sPowerOnFactoryResetTimerCnt);
-#ifdef CONFIG_WS2812_STRIP
-    sAppTask.mWS2812Device.Set(sPowerOnFactoryResetTimerCnt % 2);
-#else
-    sAppTask.mPwmRgbBlueLed.Set(sPowerOnFactoryResetTimerCnt % 2);
-#if USE_RGB_PWM
-    sAppTask.mPwmRgbRedLed.Set(sPowerOnFactoryResetTimerCnt % 2);
-    sAppTask.mPwmRgbGreenLed.Set(sPowerOnFactoryResetTimerCnt % 2);
-#endif
-#endif // CONFIG_WS2812_STRIP
+    PwmManager::getInstance().setPwm(PwmManager::EAppPwm_Red, (bool) (sPowerOnFactoryResetTimerCnt % 2));
+    PwmManager::getInstance().setPwm(PwmManager::EAppPwm_Green, (bool) (sPowerOnFactoryResetTimerCnt % 2));
+    PwmManager::getInstance().setPwm(PwmManager::EAppPwm_Blue, (bool) (sPowerOnFactoryResetTimerCnt % 2));
     if (sPowerOnFactoryResetTimerCnt > kPowerOnFactoryResetIndicationMax)
     {
         k_timer_stop(timer);
diff --git a/examples/lighting-app/telink/src/ZclCallbacks.cpp b/examples/lighting-app/telink/src/ZclCallbacks.cpp
index 7aebb1b..75b43f7 100644
--- a/examples/lighting-app/telink/src/ZclCallbacks.cpp
+++ b/examples/lighting-app/telink/src/ZclCallbacks.cpp
@@ -18,7 +18,6 @@
 
 #include "AppTask.h"
 #include "ColorFormat.h"
-#include "PWMDevice.h"
 
 #include <app-common/zap-generated/attributes/Accessors.h>
 #include <app-common/zap-generated/ids/Attributes.h>
@@ -30,7 +29,6 @@
 
 using namespace chip;
 using namespace chip::app::Clusters;
-using namespace chip::app::Clusters::OnOff;
 
 void MatterPostAttributeChangeCallback(const chip::app::ConcreteAttributePath & attributePath, uint8_t type, uint16_t size,
                                        uint8_t * value)
@@ -43,15 +41,15 @@
     if (clusterId == OnOff::Id && attributeId == OnOff::Attributes::OnOff::Id)
     {
         ChipLogDetail(Zcl, "Cluster OnOff: attribute OnOff set to %u", *value);
-        GetAppTask().SetInitiateAction(*value ? PWMDevice::ON_ACTION : PWMDevice::OFF_ACTION,
+        GetAppTask().SetInitiateAction(*value ? AppTask::ON_ACTION : AppTask::OFF_ACTION,
                                        static_cast<int32_t>(AppEvent::kEventType_Lighting), value);
     }
     else if (clusterId == LevelControl::Id && attributeId == LevelControl::Attributes::CurrentLevel::Id)
     {
-        if (GetAppTask().GetLightingDevice().IsTurnedOn())
+        if (GetAppTask().IsTurnedOn())
         {
             ChipLogDetail(Zcl, "Cluster LevelControl: attribute CurrentLevel set to %u", *value);
-            GetAppTask().SetInitiateAction(PWMDevice::LEVEL_ACTION, static_cast<int32_t>(AppEvent::kEventType_Lighting), value);
+            GetAppTask().SetInitiateAction(AppTask::LEVEL_ACTION, static_cast<int32_t>(AppEvent::kEventType_Lighting), value);
         }
         else
         {
@@ -81,7 +79,7 @@
             }
 
             ChipLogDetail(Zcl, "New XY color: %u|%u", xy.x, xy.y);
-            GetAppTask().SetInitiateAction(PWMDevice::COLOR_ACTION_XY, static_cast<int32_t>(AppEvent::kEventType_Lighting),
+            GetAppTask().SetInitiateAction(AppTask::COLOR_ACTION_XY, static_cast<int32_t>(AppEvent::kEventType_Lighting),
                                            (uint8_t *) &xy);
         }
         /* HSV color space */
@@ -103,14 +101,14 @@
                 hsv.s = *value;
             }
             ChipLogDetail(Zcl, "New HSV color: hue = %u| saturation = %u", hsv.h, hsv.s);
-            GetAppTask().SetInitiateAction(PWMDevice::COLOR_ACTION_HSV, static_cast<int32_t>(AppEvent::kEventType_Lighting),
+            GetAppTask().SetInitiateAction(AppTask::COLOR_ACTION_HSV, static_cast<int32_t>(AppEvent::kEventType_Lighting),
                                            (uint8_t *) &hsv);
         }
         /* Temperature Mireds color space */
         else if (attributeId == ColorControl::Attributes::ColorTemperatureMireds::Id)
         {
             ChipLogDetail(Zcl, "New Temperature Mireds color = %u", *(uint16_t *) value);
-            GetAppTask().SetInitiateAction(PWMDevice::COLOR_ACTION_CT, static_cast<int32_t>(AppEvent::kEventType_Lighting), value);
+            GetAppTask().SetInitiateAction(AppTask::COLOR_ACTION_CT, static_cast<int32_t>(AppEvent::kEventType_Lighting), value);
         }
         else
         {
@@ -118,28 +116,3 @@
         }
     }
 }
-
-/** @brief OnOff Cluster Init
- *
- * This function is called when a specific cluster is initialized. It gives the
- * application an opportunity to take care of cluster initialization procedures.
- * It is called exactly once for each endpoint where cluster is present.
- *
- * @param endpoint   Ver.: always
- *
- */
-void emberAfOnOffClusterInitCallback(EndpointId endpoint)
-{
-    Protocols::InteractionModel::Status status;
-    bool storedValue;
-
-    // Read storedValue on/off value
-    status = Attributes::OnOff::Get(1, &storedValue);
-    if (status == Protocols::InteractionModel::Status::Success)
-    {
-        // Set actual state to stored before reboot
-        GetAppTask().GetLightingDevice().Set(storedValue);
-    }
-
-    GetAppTask().UpdateClusterState();
-}
diff --git a/examples/lock-app/telink/CMakeLists.txt b/examples/lock-app/telink/CMakeLists.txt
index 58a9e4f..003dcc6 100755
--- a/examples/lock-app/telink/CMakeLists.txt
+++ b/examples/lock-app/telink/CMakeLists.txt
@@ -59,7 +59,7 @@
 include(${CHIP_ROOT}/config/telink/app/enable-gnu-std.cmake)
 include(${CHIP_ROOT}/src/app/chip_data_model.cmake)
 
-target_compile_options(app PRIVATE -fpermissive)
+target_compile_options(app PRIVATE $<$<COMPILE_LANGUAGE:CXX>:-fpermissive>)
 
 target_include_directories(app PRIVATE
                            include
@@ -67,7 +67,8 @@
                            ${GEN_DIR}/lock-app
                            ${TELINK_COMMON}/common/include
                            ${TELINK_COMMON}/util/include
-                           ${TELINK_COMMON}/app/include)
+                           ${TELINK_COMMON}/app/include
+                           ${TELINK_COMMON}/zephyr_ext)
 
 target_sources(app PRIVATE
                src/AppTask.cpp
@@ -76,10 +77,15 @@
                src/LockSettingsStorage.cpp
                ${TELINK_COMMON}/common/src/mainCommon.cpp
                ${TELINK_COMMON}/common/src/AppTaskCommon.cpp
-               ${TELINK_COMMON}/util/src/LEDWidget.cpp
+               ${TELINK_COMMON}/util/src/LEDManager.cpp
                ${TELINK_COMMON}/util/src/ButtonManager.cpp
                ${TELINK_COMMON}/util/src/ThreadUtil.cpp
-               ${TELINK_COMMON}/util/src/PWMDevice.cpp)
+               ${TELINK_COMMON}/util/src/PWMManager.cpp
+               ${TELINK_COMMON}/zephyr_ext/zephyr_key_matrix.c
+               ${TELINK_COMMON}/zephyr_ext/zephyr_key_pool.c
+               ${TELINK_COMMON}/zephyr_ext/zephyr_led_pool.c
+               ${TELINK_COMMON}/zephyr_ext/zephyr_pwm_pool.c
+               ${TELINK_COMMON}/zephyr_ext/zephyr_ws2812.c)
 
 chip_configure_data_model(app
     INCLUDE_SERVER
diff --git a/examples/lock-app/telink/include/AppConfig.h b/examples/lock-app/telink/include/AppConfig.h
index cb4b0c2..756ff5b 100644
--- a/examples/lock-app/telink/include/AppConfig.h
+++ b/examples/lock-app/telink/include/AppConfig.h
@@ -37,11 +37,5 @@
 #define APP_DEFAULT_YEARDAY_SCHEDULE_PER_USER_COUNT 5
 #define APP_DEFAULT_HOLYDAY_SCHEDULE_PER_USER_COUNT 5
 
-#define APP_USE_EXAMPLE_START_BUTTON 1
-#define APP_USE_BLE_START_BUTTON 0
-#define APP_USE_THREAD_START_BUTTON 0
 #define APP_SET_DEVICE_INFO_PROVIDER 1
 #define APP_SET_NETWORK_COMM_ENDPOINT_SEC 0
-#if defined(CONFIG_BOARD_TLSR9518ADK80D) || defined(CONFIG_BOARD_TLSR9528A)
-#define APP_USE_IDENTIFY_PWM 1
-#endif
diff --git a/examples/lock-app/telink/include/AppTask.h b/examples/lock-app/telink/include/AppTask.h
index fb0f411..cec70dd 100644
--- a/examples/lock-app/telink/include/AppTask.h
+++ b/examples/lock-app/telink/include/AppTask.h
@@ -37,6 +37,8 @@
     friend class AppTaskCommon;
 
     CHIP_ERROR Init(void);
+    void LinkButtons(ButtonManager & buttonManager);
+    void LinkLeds(LedManager & ledManager);
 
     static void LockActionEventHandler(AppEvent * event);
     static void LockStateChanged(LockManager::State_t state);
diff --git a/examples/lock-app/telink/src/AppTask.cpp b/examples/lock-app/telink/src/AppTask.cpp
index 1974854..46e34db 100644
--- a/examples/lock-app/telink/src/AppTask.cpp
+++ b/examples/lock-app/telink/src/AppTask.cpp
@@ -18,6 +18,7 @@
 
 #include "AppTask.h"
 #include "ButtonManager.h"
+#include "LEDManager.h"
 #include <LockManager.h>
 #include <app-common/zap-generated/attributes/Accessors.h>
 #include <app/data-model/Nullable.h>
@@ -33,33 +34,14 @@
 using namespace ::chip::DeviceLayer::Internal;
 using namespace TelinkDoorLock::LockInitParams;
 
-namespace {
-#if CONFIG_CHIP_ENABLE_APPLICATION_STATUS_LED
-LEDWidget sLockLED;
-#endif
-} // namespace
-
 AppTask AppTask::sAppTask;
-static const struct gpio_dt_spec sLockJammedInputDt = GPIO_DT_SPEC_GET(DT_NODELABEL(key_5), gpios);
-static const struct gpio_dt_spec sLockStatusInputDt = GPIO_DT_SPEC_GET(DT_NODELABEL(key_6), gpios);
-Button sLockJammedAction;
-Button sLockStatusChangedAction;
 
 CHIP_ERROR AppTask::Init(void)
 {
-#if APP_USE_EXAMPLE_START_BUTTON
     SetExampleButtonCallbacks(LockActionEventHandler);
-#endif
-    sLockJammedAction.Configure(&sLockJammedInputDt, LockJammedEventHandler);
-    sLockStatusChangedAction.Configure(&sLockStatusInputDt, LockStateEventHandler);
-    ButtonManagerInst().AddButton(sLockJammedAction);
-    ButtonManagerInst().AddButton(sLockStatusChangedAction);
     InitCommonParts();
 
-#if CONFIG_CHIP_ENABLE_APPLICATION_STATUS_LED
-    sLockLED.Init(GPIO_DT_SPEC_GET(DT_ALIAS(led2), gpios));
-    sLockLED.Set(LockMgr().IsLocked());
-#endif
+    LedManager::getInstance().setLed(LedManager::EAppLed_App0, LockMgr().IsLocked());
 
     chip::app::DataModel::Nullable<chip::app::Clusters::DoorLock::DlLockState> state;
     chip::EndpointId endpointId{ kExampleEndpointId };
@@ -167,45 +149,31 @@
     {
     case LockManager::State_t::kState_LockInitiated:
         LOG_INF("Callback: Lock action initiated");
-#if CONFIG_CHIP_ENABLE_APPLICATION_STATUS_LED
-        sLockLED.Blink(50, 50);
-#endif
+        LedManager::getInstance().setLed(LedManager::EAppLed_App0, 50, 50);
         break;
     case LockManager::State_t::kState_LockCompleted:
         LOG_INF("Callback: Lock action completed");
-#if CONFIG_CHIP_ENABLE_APPLICATION_STATUS_LED
-        sLockLED.Set(true);
-#endif
+        LedManager::getInstance().setLed(LedManager::EAppLed_App0, true);
         break;
     case LockManager::State_t::kState_UnlockInitiated:
         LOG_INF("Callback: Unlock action initiated");
-#if CONFIG_CHIP_ENABLE_APPLICATION_STATUS_LED
-        sLockLED.Blink(50, 50);
-#endif
+        LedManager::getInstance().setLed(LedManager::EAppLed_App0, 50, 50);
         break;
     case LockManager::State_t::kState_UnlockCompleted:
         LOG_INF("Callback: Unlock action completed");
-#if CONFIG_CHIP_ENABLE_APPLICATION_STATUS_LED
-        sLockLED.Set(false);
-#endif
+        LedManager::getInstance().setLed(LedManager::EAppLed_App0, false);
         break;
     case LockManager::State_t::kState_UnlatchInitiated:
         LOG_INF("Callback: Unbolt action initiated");
-#if CONFIG_CHIP_ENABLE_APPLICATION_STATUS_LED
-        sLockLED.Blink(75, 25);
-#endif
+        LedManager::getInstance().setLed(LedManager::EAppLed_App0, 75, 25);
         break;
     case LockManager::State_t::kState_UnlatchCompleted:
         LOG_INF("Callback: Unbolt action completed");
-#if CONFIG_CHIP_ENABLE_APPLICATION_STATUS_LED
-        sLockLED.Blink(25, 75);
-#endif
+        LedManager::getInstance().setLed(LedManager::EAppLed_App0, 25, 75);
         break;
     case LockManager::State_t::kState_NotFulyLocked:
         LOG_INF("Callback: Lock not fully locked. Unexpected state");
-#if CONFIG_CHIP_ENABLE_APPLICATION_STATUS_LED
-        sLockLED.Blink(10, 90);
-#endif
+        LedManager::getInstance().setLed(LedManager::EAppLed_App0, 10, 90);
         break;
     }
 }
@@ -257,3 +225,21 @@
     /* Generating Door Lock Status event */
     DoorLockServer::Instance().SetDoorState(kExampleEndpointId, mDoorState);
 }
+
+void AppTask::LinkButtons(ButtonManager & buttonManager)
+{
+    buttonManager.addCallback(FactoryResetButtonEventHandler, 0, true);
+    buttonManager.addCallback(ExampleActionButtonEventHandler, 1, true);
+    buttonManager.addCallback(LockJammedEventHandler, 2, true);
+    buttonManager.addCallback(LockStateEventHandler, 3, true);
+}
+
+void AppTask::LinkLeds(LedManager & ledManager)
+{
+#if CONFIG_CHIP_ENABLE_APPLICATION_STATUS_LED
+    ledManager.linkLed(LedManager::EAppLed_Status, 0);
+    ledManager.linkLed(LedManager::EAppLed_App0, 1);
+#else
+    ledManager.linkLed(LedManager::EAppLed_App0, 0);
+#endif // CONFIG_CHIP_ENABLE_APPLICATION_STATUS_LED
+}
diff --git a/examples/ota-requestor-app/ameba/README.md b/examples/ota-requestor-app/ameba/README.md
index 7c10b15..260c41f 100644
--- a/examples/ota-requestor-app/ameba/README.md
+++ b/examples/ota-requestor-app/ameba/README.md
@@ -6,11 +6,11 @@
 
 -   Pull docker image:
 
-          $ docker pull ghcr.io/project-chip/chip-build-ameba:42
+          $ docker pull ghcr.io/project-chip/chip-build-ameba:46
 
 -   Run docker container:
 
-          $ docker run -it -v ${CHIP_DIR}:/root/chip ghcr.io/project-chip/chip-build-ameba:42
+          $ docker run -it -v ${CHIP_DIR}:/root/chip ghcr.io/project-chip/chip-build-ameba:46
 
 -   Setup build environment:
 
diff --git a/examples/ota-requestor-app/telink/CMakeLists.txt b/examples/ota-requestor-app/telink/CMakeLists.txt
index 31be460..b1010d7 100644
--- a/examples/ota-requestor-app/telink/CMakeLists.txt
+++ b/examples/ota-requestor-app/telink/CMakeLists.txt
@@ -59,7 +59,7 @@
 include(${CHIP_ROOT}/config/telink/app/enable-gnu-std.cmake)
 include(${CHIP_ROOT}/src/app/chip_data_model.cmake)
 
-target_compile_options(app PRIVATE -fpermissive)
+target_compile_options(app PRIVATE $<$<COMPILE_LANGUAGE:CXX>:-fpermissive>)
 
 target_include_directories(app PRIVATE
                            include
@@ -67,17 +67,23 @@
                            ${GEN_DIR}/ota-requestor-app
                            ${TELINK_COMMON}/common/include
                            ${TELINK_COMMON}/util/include
-                           ${TELINK_COMMON}/app/include)
+                           ${TELINK_COMMON}/app/include
+                           ${TELINK_COMMON}/zephyr_ext)
 
 target_sources(app PRIVATE
                src/AppTask.cpp
                src/ZclCallbacks.cpp
                ${TELINK_COMMON}/common/src/mainCommon.cpp
                ${TELINK_COMMON}/common/src/AppTaskCommon.cpp
-               ${TELINK_COMMON}/util/src/LEDWidget.cpp
+               ${TELINK_COMMON}/util/src/LEDManager.cpp
                ${TELINK_COMMON}/util/src/ButtonManager.cpp
                ${TELINK_COMMON}/util/src/ThreadUtil.cpp
-               ${TELINK_COMMON}/util/src/PWMDevice.cpp)
+               ${TELINK_COMMON}/util/src/PWMManager.cpp
+               ${TELINK_COMMON}/zephyr_ext/zephyr_key_matrix.c
+               ${TELINK_COMMON}/zephyr_ext/zephyr_key_pool.c
+               ${TELINK_COMMON}/zephyr_ext/zephyr_led_pool.c
+               ${TELINK_COMMON}/zephyr_ext/zephyr_pwm_pool.c
+               ${TELINK_COMMON}/zephyr_ext/zephyr_ws2812.c)
 
 chip_configure_data_model(app
     INCLUDE_SERVER
diff --git a/examples/ota-requestor-app/telink/include/AppConfig.h b/examples/ota-requestor-app/telink/include/AppConfig.h
index 05e62e8..70d3394 100644
--- a/examples/ota-requestor-app/telink/include/AppConfig.h
+++ b/examples/ota-requestor-app/telink/include/AppConfig.h
@@ -20,11 +20,5 @@
 
 // ---- OTA Requestor Example App Config ----
 
-#define APP_USE_EXAMPLE_START_BUTTON 0
-#define APP_USE_BLE_START_BUTTON 0
-#define APP_USE_THREAD_START_BUTTON 1
 #define APP_SET_DEVICE_INFO_PROVIDER 1
 #define APP_SET_NETWORK_COMM_ENDPOINT_SEC 1
-#if defined(CONFIG_BOARD_TLSR9518ADK80D) || defined(CONFIG_BOARD_TLSR9528A)
-#define APP_USE_IDENTIFY_PWM 1
-#endif
diff --git a/examples/pigweed-app/ameba/README.md b/examples/pigweed-app/ameba/README.md
index c9bd9f8..ebd350d 100644
--- a/examples/pigweed-app/ameba/README.md
+++ b/examples/pigweed-app/ameba/README.md
@@ -31,11 +31,11 @@
 
 -   Pull docker image:
 
-          $ docker pull ghcr.io/project-chip/chip-build-ameba:42
+          $ docker pull ghcr.io/project-chip/chip-build-ameba:46
 
 -   Run docker container:
 
-          $ docker run -it -v ${CHIP_DIR}:/root/chip ghcr.io/project-chip/chip-build-ameba:42
+          $ docker run -it -v ${CHIP_DIR}:/root/chip ghcr.io/project-chip/chip-build-ameba:46
 
 -   Setup build environment:
 
diff --git a/examples/platform/telink/common/include/AppTaskCommon.h b/examples/platform/telink/common/include/AppTaskCommon.h
index 7bacaeb..09b776d 100644
--- a/examples/platform/telink/common/include/AppTaskCommon.h
+++ b/examples/platform/telink/common/include/AppTaskCommon.h
@@ -21,18 +21,6 @@
 #include "AppConfig.h"
 #include "AppEventCommon.h"
 
-#if CONFIG_CHIP_ENABLE_APPLICATION_STATUS_LED
-#include "LEDWidget.h"
-#endif
-
-#ifdef APP_USE_IDENTIFY_PWM
-#include "PWMDevice.h"
-#endif
-
-#ifdef CONFIG_WS2812_STRIP
-#include "WS2812Device.h"
-#endif
-
 #include <zephyr/drivers/gpio.h>
 #include <zephyr/kernel.h>
 #include <zephyr/logging/log.h>
@@ -64,6 +52,10 @@
 inline constexpr uint8_t kButtonReleaseEvent   = 0;
 } // namespace
 
+class LedManager;
+class PwmManager;
+class ButtonManager;
+
 class AppTaskCommon
 {
 public:
@@ -80,12 +72,8 @@
     {
         kButtonId_ExampleAction = 1,
         kButtonId_FactoryReset,
-#if APP_USE_THREAD_START_BUTTON
         kButtonId_StartThread,
-#endif
-#if APP_USE_BLE_START_BUTTON
         kButtonId_StartBleAdv
-#endif
     } ButtonId;
 #endif
 
@@ -95,44 +83,34 @@
     void DispatchEvent(AppEvent * event);
     void GetEvent(AppEvent * aEvent);
 
+    void InitLeds();
+    virtual void LinkLeds(LedManager & ledManager);
+    void InitPwms();
+    virtual void LinkPwms(PwmManager & pwmManager);
     void InitButtons(void);
+    virtual void LinkButtons(ButtonManager & buttonManager);
 
     static void FactoryResetTimerTimeoutCallback(k_timer * timer);
     static void FactoryResetTimerEventHandler(AppEvent * aEvent);
     static void FactoryResetButtonEventHandler(void);
     static void FactoryResetHandler(AppEvent * aEvent);
 
-#if APP_USE_BLE_START_BUTTON
     static void StartBleAdvButtonEventHandler(void);
     static void StartBleAdvHandler(AppEvent * aEvent);
-#endif
 
-#if APP_USE_THREAD_START_BUTTON || !CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE
+#if !CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE
     static void StartThreadButtonEventHandler(void);
     static void StartThreadHandler(AppEvent * aEvent);
 #endif
 
-#if APP_USE_EXAMPLE_START_BUTTON
     static void ExampleActionButtonEventHandler(void);
 
     void SetExampleButtonCallbacks(EventHandler aAction_CB);
     EventHandler ExampleActionEventHandler;
-#endif
 
     static void ChipEventHandler(const chip::DeviceLayer::ChipDeviceEvent * event, intptr_t arg);
 
-#ifdef APP_USE_IDENTIFY_PWM
-    PWMDevice mPwmIdentifyLed;
-
-    static void ActionIdentifyStateUpdateHandler(k_timer * timer);
-    static void UpdateIdentifyStateEventHandler(AppEvent * aEvent);
-#endif
-
-#if CONFIG_CHIP_ENABLE_APPLICATION_STATUS_LED
-    static void UpdateLedStateEventHandler(AppEvent * aEvent);
-    static void LEDStateUpdateHandler(LEDWidget * ledWidget);
     static void UpdateStatusLED(void);
-#endif
 
 #if CONFIG_CHIP_FACTORY_DATA
     chip::DeviceLayer::FactoryDataProvider<chip::DeviceLayer::ExternalFlashFactoryData> mFactoryDataProvider;
diff --git a/examples/platform/telink/common/include/SensorManagerCommon.h b/examples/platform/telink/common/include/SensorManagerCommon.h
index 7181f82..25e800b 100644
--- a/examples/platform/telink/common/include/SensorManagerCommon.h
+++ b/examples/platform/telink/common/include/SensorManagerCommon.h
@@ -46,7 +46,6 @@
     static void SensorBanForNextMeasurTimerTimeoutCallback(k_timer * timer);
 
 #ifdef USE_COLOR_TEMPERATURE_LIGHT
-    WS2812Device mWS2812Device;
     void SetColorTemperatureLight(int8_t temp);
 #endif // USE_COLOR_TEMPERATURE_LIGHT
 
diff --git a/examples/platform/telink/common/src/AppTaskCommon.cpp b/examples/platform/telink/common/src/AppTaskCommon.cpp
index 3d93aa3..759e70b 100644
--- a/examples/platform/telink/common/src/AppTaskCommon.cpp
+++ b/examples/platform/telink/common/src/AppTaskCommon.cpp
@@ -21,6 +21,8 @@
 
 #include "BLEManagerImpl.h"
 #include "ButtonManager.h"
+#include "LEDManager.h"
+#include "PWMManager.h"
 
 #include "ThreadUtil.h"
 
@@ -51,25 +53,6 @@
 constexpr int kFactoryResetTriggerCntr = 3;
 constexpr int kAppEventQueueSize       = 10;
 
-#if CONFIG_CHIP_BUTTON_MANAGER_IRQ_MODE
-const struct gpio_dt_spec sFactoryResetButtonDt = GPIO_DT_SPEC_GET(DT_NODELABEL(key_1), gpios);
-#if APP_USE_BLE_START_BUTTON
-const struct gpio_dt_spec sBleStartButtonDt = GPIO_DT_SPEC_GET(DT_NODELABEL(key_2), gpios);
-#endif
-#if APP_USE_THREAD_START_BUTTON
-const struct gpio_dt_spec sThreadStartButtonDt = GPIO_DT_SPEC_GET(DT_NODELABEL(key_3), gpios);
-#endif
-#if APP_USE_EXAMPLE_START_BUTTON
-const struct gpio_dt_spec sExampleActionButtonDt = GPIO_DT_SPEC_GET(DT_NODELABEL(key_4), gpios);
-#endif
-#else
-const struct gpio_dt_spec sButtonCol1Dt = GPIO_DT_SPEC_GET(DT_NODELABEL(key_matrix_col1), gpios);
-const struct gpio_dt_spec sButtonCol2Dt = GPIO_DT_SPEC_GET(DT_NODELABEL(key_matrix_col2), gpios);
-const struct gpio_dt_spec sButtonRow1Dt = GPIO_DT_SPEC_GET(DT_NODELABEL(key_matrix_row1), gpios);
-const struct gpio_dt_spec sButtonRow2Dt = GPIO_DT_SPEC_GET(DT_NODELABEL(key_matrix_row2), gpios);
-#endif
-
-#ifdef APP_USE_IDENTIFY_PWM
 constexpr uint32_t kIdentifyBlinkRateMs         = 200;
 constexpr uint32_t kIdentifyOkayOnRateMs        = 50;
 constexpr uint32_t kIdentifyOkayOffRateMs       = 950;
@@ -78,30 +61,12 @@
 constexpr uint32_t kIdentifyChannelChangeRateMs = 1000;
 constexpr uint32_t kIdentifyBreatheRateMs       = 1000;
 
-const struct pwm_dt_spec sPwmIdentifySpecGreenLed = PWM_DT_SPEC_GET(DT_ALIAS(pwm_led3));
-#endif
-
 #if APP_SET_NETWORK_COMM_ENDPOINT_SEC
 constexpr EndpointId kNetworkCommissioningEndpointSecondary = 0xFFFE;
 #endif
 
 K_MSGQ_DEFINE(sAppEventQueue, sizeof(AppEvent), kAppEventQueueSize, alignof(AppEvent));
 
-#if CONFIG_CHIP_ENABLE_APPLICATION_STATUS_LED
-LEDWidget sStatusLED;
-#endif
-
-Button sFactoryResetButton;
-#if APP_USE_BLE_START_BUTTON
-Button sBleAdvStartButton;
-#endif
-#if APP_USE_EXAMPLE_START_BUTTON
-Button sExampleActionButton;
-#endif
-#if APP_USE_THREAD_START_BUTTON
-Button sThreadStartButton;
-#endif
-
 k_timer sFactoryResetTimer;
 uint8_t sFactoryResetCntr = 0;
 
@@ -115,7 +80,8 @@
 chip::DeviceLayer::DeviceInfoProviderImpl gExampleDeviceInfoProvider;
 #endif
 
-#ifdef APP_USE_IDENTIFY_PWM
+#ifndef IDENTIFY_CLUSTER_DISABLED
+
 void OnIdentifyTriggerEffect(Identify * identify)
 {
     AppTaskCommon::IdentifyEffectHandler(identify->mCurrentEffectIdentifier);
@@ -128,6 +94,7 @@
     Clusters::Identify::IdentifyTypeEnum::kVisibleIndicator,
     OnIdentifyTriggerEffect,
 };
+
 #endif
 
 #if CONFIG_CHIP_FACTORY_DATA
@@ -271,13 +238,10 @@
     CHIP_ERROR err;
     LOG_INF("SW Version: %u, %s", CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION, CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING);
 
-    // Initialize status LED
-#if CONFIG_CHIP_ENABLE_APPLICATION_STATUS_LED
-    LEDWidget::SetStateUpdateCallback(LEDStateUpdateHandler);
-    sStatusLED.Init(GPIO_DT_SPEC_GET_OR(DT_ALIAS(system_state_led), gpios, {}));
-
+    InitLeds();
     UpdateStatusLED();
-#endif
+
+    InitPwms();
 
     InitButtons();
 
@@ -285,18 +249,6 @@
     k_timer_init(&sFactoryResetTimer, &AppTask::FactoryResetTimerTimeoutCallback, nullptr);
     k_timer_user_data_set(&sFactoryResetTimer, this);
 
-#ifdef APP_USE_IDENTIFY_PWM
-    // Initialize PWM Identify led
-    err = GetAppTask().mPwmIdentifyLed.Init(&sPwmIdentifySpecGreenLed, kDefaultMinLevel, kDefaultMaxLevel, kDefaultMaxLevel);
-    if (err != CHIP_NO_ERROR)
-    {
-        LOG_ERR("Green IDENTIFY PWM Device Init fail");
-        return err;
-    }
-
-    GetAppTask().mPwmIdentifyLed.SetCallbacks(nullptr, nullptr, ActionIdentifyStateUpdateHandler);
-#endif
-
     // Initialize CHIP server
 #if CONFIG_CHIP_FACTORY_DATA
     ReturnErrorOnFailure(mFactoryDataProvider.Init());
@@ -370,91 +322,88 @@
 
     switch (btnId)
     {
-#if APP_USE_EXAMPLE_START_BUTTON
     case kButtonId_ExampleAction:
         ExampleActionButtonEventHandler();
         break;
-#endif
     case kButtonId_FactoryReset:
         FactoryResetButtonEventHandler();
         break;
-#if APP_USE_THREAD_START_BUTTON
+#if !CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE
     case kButtonId_StartThread:
         StartThreadButtonEventHandler();
         break;
 #endif
-#if APP_USE_BLE_START_BUTTON
     case kButtonId_StartBleAdv:
         StartBleAdvButtonEventHandler();
         break;
-#endif
     }
 }
 #endif
 
+void AppTaskCommon::InitLeds()
+{
+    LedManager & ledManager = LedManager::getInstance();
+
+    LinkLeds(ledManager);
+
+    ledManager.linkBackend(LedPool::getInstance());
+}
+
+void AppTaskCommon::LinkLeds(LedManager & ledManager)
+{
+#if CONFIG_CHIP_ENABLE_APPLICATION_STATUS_LED
+    ledManager.linkLed(LedManager::EAppLed_Status, 0);
+#endif // CONFIG_CHIP_ENABLE_APPLICATION_STATUS_LED
+}
+
+void AppTaskCommon::InitPwms()
+{
+    PwmManager & pwmManager = PwmManager::getInstance();
+
+    LinkPwms(pwmManager);
+
+#if CONFIG_WS2812_STRIP
+    pwmManager.linkBackend(Ws2812Strip::getInstance());
+#else
+    pwmManager.linkBackend(PwmPool::getInstance());
+#endif // CONFIG_WS2812_STRIP
+}
+
+void AppTaskCommon::LinkPwms(PwmManager & pwmManager)
+{
+#if CONFIG_WS2812_STRIP
+    pwmManager.linkPwm(PwmManager::EAppPwm_Red, 0);
+    pwmManager.linkPwm(PwmManager::EAppPwm_Green, 1);
+    pwmManager.linkPwm(PwmManager::EAppPwm_Blue, 2);
+#else
+    pwmManager.linkPwm(PwmManager::EAppPwm_Indication, 0);
+    pwmManager.linkPwm(PwmManager::EAppPwm_Red, 1);
+    pwmManager.linkPwm(PwmManager::EAppPwm_Green, 2);
+    pwmManager.linkPwm(PwmManager::EAppPwm_Blue, 3);
+#endif // CONFIG_WS2812_STRIP
+}
+
 void AppTaskCommon::InitButtons(void)
 {
+    ButtonManager & buttonManager = ButtonManager::getInstance();
+
+    LinkButtons(buttonManager);
+
 #if CONFIG_CHIP_BUTTON_MANAGER_IRQ_MODE
-    sFactoryResetButton.Configure(&sFactoryResetButtonDt, FactoryResetButtonEventHandler);
-#if APP_USE_BLE_START_BUTTON
-    sBleAdvStartButton.Configure(&sBleStartButtonDt, StartBleAdvButtonEventHandler);
-#endif
-#if APP_USE_EXAMPLE_START_BUTTON
-    if (ExampleActionEventHandler)
-    {
-        sExampleActionButton.Configure(&sExampleActionButtonDt, ExampleActionButtonEventHandler);
-    }
-#endif
-#if APP_USE_THREAD_START_BUTTON
-    sThreadStartButton.Configure(&sThreadStartButtonDt, StartThreadButtonEventHandler);
-#endif
+    buttonManager.linkBackend(ButtonPool::getInstance());
 #else
-    sFactoryResetButton.Configure(&sButtonRow1Dt, &sButtonCol1Dt, FactoryResetButtonEventHandler);
-#if APP_USE_BLE_START_BUTTON
-    sBleAdvStartButton.Configure(&sButtonRow2Dt, &sButtonCol2Dt, StartBleAdvButtonEventHandler);
-#endif
-#if APP_USE_EXAMPLE_START_BUTTON
-    if (ExampleActionEventHandler)
-    {
-        sExampleActionButton.Configure(&sButtonRow1Dt, &sButtonCol2Dt, ExampleActionButtonEventHandler);
-    }
-#endif
-#if APP_USE_THREAD_START_BUTTON
-    sThreadStartButton.Configure(&sButtonRow2Dt, &sButtonCol1Dt, StartThreadButtonEventHandler);
-#endif
-#endif
-
-    ButtonManagerInst().AddButton(sFactoryResetButton);
-#if APP_USE_BLE_START_BUTTON
-    ButtonManagerInst().AddButton(sBleAdvStartButton);
-#endif
-#if APP_USE_THREAD_START_BUTTON
-    ButtonManagerInst().AddButton(sThreadStartButton);
-#endif
-#if APP_USE_EXAMPLE_START_BUTTON
-    if (ExampleActionEventHandler)
-    {
-        ButtonManagerInst().AddButton(sExampleActionButton);
-    }
-#endif
+    buttonManager.linkBackend(ButtonMatrix::getInstance());
+#endif // CONFIG_CHIP_BUTTON_MANAGER_IRQ_MODE
 }
 
-#if CONFIG_CHIP_ENABLE_APPLICATION_STATUS_LED
-void AppTaskCommon::UpdateLedStateEventHandler(AppEvent * aEvent)
+void AppTaskCommon::LinkButtons(ButtonManager & buttonManager)
 {
-    if (aEvent->Type == AppEvent::kEventType_UpdateLedState)
-    {
-        aEvent->UpdateLedStateEvent.LedWidget->UpdateState();
-    }
-}
-
-void AppTaskCommon::LEDStateUpdateHandler(LEDWidget * ledWidget)
-{
-    AppEvent event;
-    event.Type                          = AppEvent::kEventType_UpdateLedState;
-    event.Handler                       = UpdateLedStateEventHandler;
-    event.UpdateLedStateEvent.LedWidget = ledWidget;
-    GetAppTask().PostEvent(&event);
+    buttonManager.addCallback(FactoryResetButtonEventHandler, 0, true);
+    buttonManager.addCallback(ExampleActionButtonEventHandler, 1, true);
+    buttonManager.addCallback(StartBleAdvButtonEventHandler, 2, true);
+#if !CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE
+    buttonManager.addCallback(StartThreadButtonEventHandler, 3, true);
+#endif
 }
 
 void AppTaskCommon::UpdateStatusLED()
@@ -463,86 +412,54 @@
     {
         if (sIsThreadAttached)
         {
-            sStatusLED.Blink(950, 50);
+            LedManager::getInstance().setLed(LedManager::EAppLed_Status, 950, 50);
         }
         else
         {
-            sStatusLED.Blink(100, 100);
+            LedManager::getInstance().setLed(LedManager::EAppLed_Status, 100, 100);
         }
     }
     else
     {
-        sStatusLED.Blink(50, 950);
+        LedManager::getInstance().setLed(LedManager::EAppLed_Status, 50, 950);
     }
 }
-#endif
-
-#ifdef APP_USE_IDENTIFY_PWM
-void AppTaskCommon::ActionIdentifyStateUpdateHandler(k_timer * timer)
-{
-    AppEvent event;
-    event.Type    = AppEvent::kEventType_UpdateLedState;
-    event.Handler = UpdateIdentifyStateEventHandler;
-    GetAppTask().PostEvent(&event);
-}
-
-void AppTaskCommon::UpdateIdentifyStateEventHandler(AppEvent * aEvent)
-{
-    GetAppTask().mPwmIdentifyLed.UpdateAction();
-}
 
 void AppTaskCommon::IdentifyEffectHandler(Clusters::Identify::EffectIdentifierEnum aEffect)
 {
-    AppEvent event;
-    event.Type = AppEvent::kEventType_IdentifyStart;
-
     switch (aEffect)
     {
     case Clusters::Identify::EffectIdentifierEnum::kBlink:
         ChipLogProgress(Zcl, "Clusters::Identify::EffectIdentifierEnum::kBlink");
-        event.Handler = [](AppEvent *) {
-            GetAppTask().mPwmIdentifyLed.InitiateBlinkAction(kIdentifyBlinkRateMs, kIdentifyBlinkRateMs);
-        };
+        PwmManager::getInstance().setPwmBlink(PwmManager::EAppPwm_Indication, kIdentifyBlinkRateMs, kIdentifyBlinkRateMs);
         break;
     case Clusters::Identify::EffectIdentifierEnum::kBreathe:
         ChipLogProgress(Zcl, "Clusters::Identify::EffectIdentifierEnum::kBreathe");
-        event.Handler = [](AppEvent *) {
-            GetAppTask().mPwmIdentifyLed.InitiateBreatheAction(PWMDevice::kBreatheType_Both, kIdentifyBreatheRateMs);
-        };
+        PwmManager::getInstance().setPwmBreath(PwmManager::EAppPwm_Indication, kIdentifyBreatheRateMs);
         break;
     case Clusters::Identify::EffectIdentifierEnum::kOkay:
         ChipLogProgress(Zcl, "Clusters::Identify::EffectIdentifierEnum::kOkay");
-        event.Handler = [](AppEvent *) {
-            GetAppTask().mPwmIdentifyLed.InitiateBlinkAction(kIdentifyOkayOnRateMs, kIdentifyOkayOffRateMs);
-        };
+        PwmManager::getInstance().setPwmBlink(PwmManager::EAppPwm_Indication, kIdentifyOkayOnRateMs, kIdentifyOkayOffRateMs);
         break;
     case Clusters::Identify::EffectIdentifierEnum::kChannelChange:
         ChipLogProgress(Zcl, "Clusters::Identify::EffectIdentifierEnum::kChannelChange");
-        event.Handler = [](AppEvent *) {
-            GetAppTask().mPwmIdentifyLed.InitiateBlinkAction(kIdentifyChannelChangeRateMs, kIdentifyChannelChangeRateMs);
-        };
+        PwmManager::getInstance().setPwmBlink(PwmManager::EAppPwm_Indication, kIdentifyChannelChangeRateMs,
+                                              kIdentifyChannelChangeRateMs);
         break;
     case Clusters::Identify::EffectIdentifierEnum::kFinishEffect:
         ChipLogProgress(Zcl, "Clusters::Identify::EffectIdentifierEnum::kFinishEffect");
-        event.Handler = [](AppEvent *) {
-            GetAppTask().mPwmIdentifyLed.InitiateBlinkAction(kIdentifyFinishOnRateMs, kIdentifyFinishOffRateMs);
-        };
+        PwmManager::getInstance().setPwmBlink(PwmManager::EAppPwm_Indication, kIdentifyFinishOnRateMs, kIdentifyFinishOffRateMs);
         break;
     case Clusters::Identify::EffectIdentifierEnum::kStopEffect:
         ChipLogProgress(Zcl, "Clusters::Identify::EffectIdentifierEnum::kStopEffect");
-        event.Handler = [](AppEvent *) { GetAppTask().mPwmIdentifyLed.StopAction(); };
-        event.Type    = AppEvent::kEventType_IdentifyStop;
+        PwmManager::getInstance().setPwm(PwmManager::EAppPwm_Indication, false);
         break;
     default:
         ChipLogProgress(Zcl, "No identifier effect");
         return;
     }
-
-    GetAppTask().PostEvent(&event);
 }
-#endif
 
-#if APP_USE_BLE_START_BUTTON
 void AppTaskCommon::StartBleAdvButtonEventHandler(void)
 {
     AppEvent event;
@@ -575,7 +492,6 @@
         LOG_ERR("OpenBasicCommissioningWindow fail");
     }
 }
-#endif
 
 void AppTaskCommon::FactoryResetButtonEventHandler(void)
 {
@@ -630,7 +546,7 @@
     LOG_INF("Factory Reset Trigger Counter is cleared");
 }
 
-#if APP_USE_THREAD_START_BUTTON || !CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE
+#if !CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE
 void AppTaskCommon::StartThreadButtonEventHandler(void)
 {
     AppEvent event;
@@ -663,7 +579,6 @@
 }
 #endif
 
-#if APP_USE_EXAMPLE_START_BUTTON
 void AppTaskCommon::ExampleActionButtonEventHandler(void)
 {
     AppEvent event;
@@ -683,7 +598,6 @@
 {
     ExampleActionEventHandler = aAction_CB;
 }
-#endif
 
 void AppTaskCommon::ChipEventHandler(const ChipDeviceEvent * event, intptr_t /* arg */)
 {
@@ -691,9 +605,7 @@
     {
     case DeviceEventType::kCHIPoBLEAdvertisingChange:
         sHaveBLEConnections = ConnectivityMgr().NumBLEConnections() != 0;
-#if CONFIG_CHIP_ENABLE_APPLICATION_STATUS_LED
         UpdateStatusLED();
-#endif
 #ifdef CONFIG_CHIP_NFC_COMMISSIONING
         if (event->CHIPoBLEAdvertisingChange.Result == kActivity_Started)
         {
@@ -716,9 +628,7 @@
         sIsThreadProvisioned = ConnectivityMgr().IsThreadProvisioned();
         sIsThreadEnabled     = ConnectivityMgr().IsThreadEnabled();
         sIsThreadAttached    = ConnectivityMgr().IsThreadAttached();
-#if CONFIG_CHIP_ENABLE_APPLICATION_STATUS_LED
         UpdateStatusLED();
-#endif
         break;
     case DeviceEventType::kDnssdInitialized:
 #if CONFIG_CHIP_OTA_REQUESTOR
diff --git a/examples/platform/telink/common/src/SensorManagerCommon.cpp b/examples/platform/telink/common/src/SensorManagerCommon.cpp
index 1c4d5f9..0164749 100644
--- a/examples/platform/telink/common/src/SensorManagerCommon.cpp
+++ b/examples/platform/telink/common/src/SensorManagerCommon.cpp
@@ -17,6 +17,7 @@
  */
 
 #include "SensorManagerCommon.h"
+#include "PWMManager.h"
 #ifdef CONFIG_CHIP_USE_MARS_SENSOR
 #include <zephyr/drivers/sensor.h>
 #endif // CONFIG_CHIP_USE_MARS_SENSOR
@@ -36,7 +37,6 @@
 const struct device * const sht3xd_dev = DEVICE_DT_GET_ONE(sensirion_sht3xd);
 
 #ifdef USE_COLOR_TEMPERATURE_LIGHT
-const struct device * const ws2812_dev = DEVICE_DT_GET(DT_ALIAS(led_strip));
 
 #define TEMP_LOW_LIM 0   // °C
 #define TEMP_HIGH_LIM 40 // °C
@@ -60,16 +60,6 @@
 
 #ifdef USE_COLOR_TEMPERATURE_LIGHT
     RgbColor_t rgb = { 0 };
-
-    CHIP_ERROR err = sSensorManager.mWS2812Device.Init(ws2812_dev, STRIP_NUM_PIXELS(led_strip));
-    if (err != CHIP_NO_ERROR)
-    {
-        LOG_ERR("WS2812 Device Init fail");
-        return err;
-    }
-
-    sSensorManager.mWS2812Device.SetLevel(&rgb);
-    sSensorManager.mWS2812Device.Set(SET_RGB_TURN_ON);
 #endif // USE_COLOR_TEMPERATURE_LIGHT
 
     // Initialise the timer to ban sensor measurement
@@ -245,7 +235,9 @@
         LOG_ERR("Couldn't set the Color Temperature Light");
     }
 
-    sSensorManager.mWS2812Device.SetLevel(&rgb);
+    PwmManager::getInstance().setPwm(PwmManager::EAppPwm_Red, ((uint32_t) rgb.r * 1000) / 0xff);
+    PwmManager::getInstance().setPwm(PwmManager::EAppPwm_Green, ((uint32_t) rgb.g * 1000) / 0xff);
+    PwmManager::getInstance().setPwm(PwmManager::EAppPwm_Blue, ((uint32_t) rgb.b * 1000) / 0xff);
 }
 #endif // USE_COLOR_TEMPERATURE_LIGHT
 #endif // CONFIG_CHIP_USE_MARS_SENSOR
diff --git a/examples/platform/telink/util/include/ButtonManager.h b/examples/platform/telink/util/include/ButtonManager.h
index e9ea1b6..c61f165 100644
--- a/examples/platform/telink/util/include/ButtonManager.h
+++ b/examples/platform/telink/util/include/ButtonManager.h
@@ -17,53 +17,125 @@
 
 #pragma once
 
-#include <vector>
-#include <zephyr/device.h>
+#include <cstddef>
+#include <set>
 
-#define STATE_HIGH 1
-#define STATE_LOW 0
-
-class Button
+class ButtonBackend
 {
 public:
-    void Configure(const gpio_dt_spec * input_button_dt, const gpio_dt_spec * output_button_dt, void (*callback)(void));
-    void Configure(const gpio_dt_spec * input_button_dt, void (*callback)(void));
-    void Poll(Button * previous);
-    void PollIRQ(const struct device * dev, uint32_t pins);
-    void SetCallback(void (*callback)(void));
-
-private:
-    int Init(void);
-    int Deinit(void);
-
-    const struct gpio_dt_spec * mInput_button;
-    const struct gpio_dt_spec * mOutput_matrix_pin;
-    int mPreviousState = STATE_LOW;
-    struct gpio_callback mButton_cb_data;
-    void (*mCallback)(void) = NULL;
+    virtual bool linkHW(void (*on_button_change)(size_t button, bool pressed, void * context), void * context) = 0;
 };
 
 class ButtonManager
 {
 public:
-    void Init(void);
-    void Poll(void);
-    void PollIRQ(const struct device * dev, uint32_t pins);
-    void AddButton(Button & button);
-    void SetCallback(unsigned int index, void (*callback)(void));
+    static ButtonManager & getInstance();
+    void addCallback(void (*callback)(void), size_t button, bool pressed);
+    void rmCallback(void (*callback)(void));
+    void rmCallback(size_t button, bool pressed);
+    void linkBackend(ButtonBackend & backend);
+
+    ButtonManager(ButtonManager const &)  = delete;
+    void operator=(ButtonManager const &) = delete;
 
 private:
-    std::vector<Button> mButtons;
+    struct Event
+    {
+        size_t button;
+        bool pressed;
+        void (*callback)(void);
 
-    friend ButtonManager & ButtonManagerInst(void);
+        friend bool operator<(const Event & lhs, const Event & rhs)
+        {
+            if (lhs.button < rhs.button)
+            {
+                return true;
+            }
+            else if (lhs.button > rhs.button)
+            {
+                return false;
+            }
+            else if (lhs.pressed < rhs.pressed)
+            {
+                return true;
+            }
+            else if (lhs.pressed > rhs.pressed)
+            {
+                return false;
+            }
+            else if (lhs.callback < rhs.callback)
+            {
+                return true;
+            }
+            else
+            {
+                return false;
+            }
+        }
+        friend bool operator>(const Event & lhs, const Event & rhs)
+        {
+            if (lhs.button > rhs.button)
+            {
+                return true;
+            }
+            else if (lhs.button < rhs.button)
+            {
+                return false;
+            }
+            else if (lhs.pressed > rhs.pressed)
+            {
+                return true;
+            }
+            else if (lhs.pressed < rhs.pressed)
+            {
+                return false;
+            }
+            else if (lhs.callback > rhs.callback)
+            {
+                return true;
+            }
+            else
+            {
+                return false;
+            }
+        }
+    };
 
-    static ButtonManager sInstance;
+    ButtonManager();
+
+    static void onButton(size_t button, bool pressed, void * buttonMgr);
+
+    std::set<Event> m_events;
 };
 
-/**
- * Returns the KeyManager singleton object.
- */
-inline ButtonManager & ButtonManagerInst(void)
+#if CONFIG_CHIP_BUTTON_MANAGER_IRQ_MODE
+
+class ButtonPool : public ButtonBackend
 {
-    return ButtonManager::sInstance;
-}
+public:
+    static ButtonPool & getInstance();
+    bool linkHW(void (*on_button_change)(size_t button, bool pressed, void * context), void * context);
+
+    ButtonPool(ButtonPool const &)     = delete;
+    void operator=(ButtonPool const &) = delete;
+
+private:
+    ButtonPool(){};
+};
+
+#else
+
+class ButtonMatrix : public ButtonBackend
+{
+public:
+    static ButtonMatrix & getInstance();
+    bool linkHW(void (*on_button_change)(size_t button, bool pressed, void * context), void * context);
+
+    ButtonMatrix(ButtonMatrix const &)   = delete;
+    void operator=(ButtonMatrix const &) = delete;
+
+private:
+    ButtonMatrix(){};
+};
+
+#endif // CONFIG_CHIP_BUTTON_MANAGER_IRQ_MODE
diff --git a/examples/platform/telink/util/include/LEDManager.h b/examples/platform/telink/util/include/LEDManager.h
new file mode 100644
index 0000000..72792fa
--- /dev/null
+++ b/examples/platform/telink/util/include/LEDManager.h
@@ -0,0 +1,119 @@
+/*
+ *    Copyright (c) 2021 Project CHIP Authors
+ *    All rights reserved.
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+
+#pragma once
+
+#include <cstddef>
+#include <set>
+
+class LedBackend
+{
+public:
+    virtual bool linkHW()                                        = 0;
+    virtual void setLedHW(size_t led, bool state)                = 0;
+    virtual void setLedHW(size_t led, size_t onMs, size_t offMs) = 0;
+};
+
+class LedManager
+{
+public:
+    enum EAppLed
+    {
+        EAppLed_Status = 0,
+        EAppLed_App0,
+        EAppLed_App1,
+    };
+
+    static LedManager & getInstance();
+
+    void setLed(EAppLed appLed, bool state);
+    void setLed(EAppLed appLed, size_t onMs, size_t offMs);
+
+    void linkLed(EAppLed appLed, size_t led);
+    void unlinkLed(EAppLed appLed);
+    void unlinkLed(size_t led);
+    void linkBackend(LedBackend & backend);
+
+    LedManager(LedManager const &)     = delete;
+    void operator=(LedManager const &) = delete;
+
+private:
+    struct LedLink
+    {
+        enum EAppLed appLed;
+        size_t led;
+
+        friend bool operator<(const LedLink & lhs, const LedLink & rhs)
+        {
+            if (lhs.appLed < rhs.appLed)
+            {
+                return true;
+            }
+            else if (lhs.appLed > rhs.appLed)
+            {
+                return false;
+            }
+            else if (lhs.led < rhs.led)
+            {
+                return true;
+            }
+            else
+            {
+                return false;
+            }
+        }
+        friend bool operator>(const LedLink & lhs, const LedLink & rhs)
+        {
+            if (lhs.appLed > rhs.appLed)
+            {
+                return true;
+            }
+            else if (lhs.appLed < rhs.appLed)
+            {
+                return false;
+            }
+            else if (lhs.led > rhs.led)
+            {
+                return true;
+            }
+            else
+            {
+                return false;
+            }
+        }
+    };
+
+    LedManager();
+
+    std::set<LedLink> m_leds;
+    LedBackend * m_backend;
+};
+
+class LedPool : public LedBackend
+{
+public:
+    static LedPool & getInstance();
+    bool linkHW();
+    void setLedHW(size_t led, bool state);
+    void setLedHW(size_t led, size_t onMs, size_t offMs);
+
+    LedPool(LedPool const &)        = delete;
+    void operator=(LedPool const &) = delete;
+
+private:
+    LedPool(){};
+};
diff --git a/examples/platform/telink/util/include/LEDWidget.h b/examples/platform/telink/util/include/LEDWidget.h
deleted file mode 100644
index 3829e7a..0000000
--- a/examples/platform/telink/util/include/LEDWidget.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- *    Copyright (c) 2021 Project CHIP Authors
- *    All rights reserved.
- *
- *    Licensed under the Apache License, Version 2.0 (the "License");
- *    you may not use this file except in compliance with the License.
- *    You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *    Unless required by applicable law or agreed to in writing, software
- *    distributed under the License is distributed on an "AS IS" BASIS,
- *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *    See the License for the specific language governing permissions and
- *    limitations under the License.
- */
-
-#pragma once
-
-#include <cstdint>
-#include <zephyr/drivers/gpio.h>
-#include <zephyr/kernel.h>
-
-class LEDWidget
-{
-public:
-    typedef void (*LEDWidgetStateUpdateHandler)(LEDWidget * ledWidget);
-
-    static void SetStateUpdateCallback(LEDWidgetStateUpdateHandler stateUpdateCb);
-    void Init(gpio_dt_spec gpio);
-    void Set(bool state);
-    void Invert(void);
-    void Blink(uint32_t changeRateMS);
-    void Blink(uint32_t onTimeMS, uint32_t offTimeMS);
-    void UpdateState();
-
-private:
-    uint32_t mBlinkOnTimeMS;
-    uint32_t mBlinkOffTimeMS;
-    gpio_dt_spec mGPIO;
-    bool mState;
-    k_timer mLedTimer;
-
-    static void LedStateTimerHandler(k_timer * timer);
-
-    void DoSet(bool state);
-    void ScheduleStateChange();
-};
diff --git a/examples/platform/telink/util/include/PWMDevice.h b/examples/platform/telink/util/include/PWMDevice.h
deleted file mode 100644
index 9b3bc24..0000000
--- a/examples/platform/telink/util/include/PWMDevice.h
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- *    Copyright (c) 2022 Project CHIP Authors
- *    All rights reserved.
- *
- *    Licensed under the Apache License, Version 2.0 (the "License");
- *    you may not use this file except in compliance with the License.
- *    You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *    Unless required by applicable law or agreed to in writing, software
- *    distributed under the License is distributed on an "AS IS" BASIS,
- *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *    See the License for the specific language governing permissions and
- *    limitations under the License.
- */
-
-#pragma once
-
-#include <system/SystemError.h>
-
-#include <cstdint>
-#include <zephyr/drivers/gpio.h>
-#include <zephyr/drivers/pwm.h>
-
-class PWMDevice
-{
-public:
-    enum Action_t : uint8_t
-    {
-        ON_ACTION = 0,
-        OFF_ACTION,
-        LEVEL_ACTION,
-        COLOR_ACTION_XY,
-        COLOR_ACTION_HSV,
-        COLOR_ACTION_CT,
-
-        INVALID_ACTION
-    };
-
-    enum State_t : uint8_t
-    {
-        kState_On = 0,
-        kState_Off,
-    };
-
-    enum BreatheType_t : uint8_t
-    {
-        kBreatheType_Invalid = 0,
-        kBreatheType_Rising,
-        kBreatheType_Falling,
-        kBreatheType_Both,
-    };
-
-    using PWMCallback_fn      = void (*)(Action_t, int32_t);
-    using PWMTimerCallback_fn = void (*)(k_timer *);
-
-    CHIP_ERROR Init(const pwm_dt_spec * pwmDevice, uint8_t aMinLevel, uint8_t aMaxLevel, uint8_t aDefaultLevel = 0);
-    void Set(bool aOn);
-    bool IsTurnedOn(void) const { return mState == kState_On; }
-    uint8_t GetLevel(void) const { return mLevel; }
-    uint8_t GetMinLevel(void) const { return mMinLevel; }
-    uint8_t GetMaxLevel(void) const { return mMaxLevel; }
-    void SetCallbacks(PWMCallback_fn aActionInitiated_CB, PWMCallback_fn aActionCompleted_CB,
-                      PWMTimerCallback_fn aActionBlinkStateUpdate_CB);
-    bool InitiateAction(Action_t aAction, int32_t aActor, uint8_t * value);
-    void InitiateBlinkAction(uint32_t onTimeMS, uint32_t offTimeMS);
-    void InitiateBreatheAction(BreatheType_t type, uint32_t cycleTimeMS);
-    void StopAction(void);
-    void UpdateAction(void);
-
-private:
-    State_t mState;
-    uint8_t mMinLevel;
-    uint8_t mMaxLevel;
-    uint8_t mLevel;
-    uint8_t mBreatheStepLevel;
-    uint8_t mBreatheStepCntr;
-    bool mBreatheBothDirection;
-    BreatheType_t mBreatheType;
-    uint32_t mBreatheStepNumb;
-    uint32_t mBlinkOnTimeMS;
-    uint32_t mBlinkOffTimeMS;
-    k_timer mPwmLedTimer;
-    const pwm_dt_spec * mPwmDevice;
-
-    PWMCallback_fn mActionInitiated_CB;
-    PWMCallback_fn mActionCompleted_CB;
-
-    void SetLevel(uint8_t aLevel);
-    void UpdateLight(void);
-    void StartBlinkTimer(void);
-    void StartBreatheTimer(uint32_t stepTimeMS);
-    void ClearAction(void);
-    static void PwmLedTimerHandler(k_timer * timer);
-};
diff --git a/examples/platform/telink/util/include/PWMManager.h b/examples/platform/telink/util/include/PWMManager.h
new file mode 100644
index 0000000..852216d
--- /dev/null
+++ b/examples/platform/telink/util/include/PWMManager.h
@@ -0,0 +1,153 @@
+/*
+ *    Copyright (c) 2022 Project CHIP Authors
+ *    All rights reserved.
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+
+#pragma once
+
+#include <cstddef>
+#include <cstdint>
+#include <set>
+
+class PwmBackend
+{
+public:
+    virtual bool linkHW() = 0;
+
+    virtual void setPwmHW(size_t pwm, bool state)                     = 0;
+    virtual void setPwmHW(size_t pwm, uint32_t permille)              = 0;
+    virtual void setPwmHWBlink(size_t pwm, size_t onMs, size_t offMs) = 0;
+    virtual void setPwmHWBreath(size_t pwm, size_t onMs)              = 0;
+};
+
+class PwmManager
+{
+public:
+    enum EAppPwm
+    {
+        EAppPwm_Indication = 0,
+        EAppPwm_Red,
+        EAppPwm_Green,
+        EAppPwm_Blue,
+    };
+
+    static PwmManager & getInstance();
+
+    void setPwm(EAppPwm appPwm, bool state);
+    void setPwm(EAppPwm appPwm, uint32_t permille);
+    void setPwmBlink(EAppPwm appPwm, size_t onMs, size_t offMs);
+    void setPwmBreath(EAppPwm appPwm, size_t BrathMs);
+
+    void linkPwm(EAppPwm appPwm, size_t pwm);
+    void unlinkPwm(EAppPwm appPwm);
+    void unlinkPwm(size_t pwm);
+    void linkBackend(PwmBackend & backend);
+
+    PwmManager(PwmManager const &)     = delete;
+    void operator=(PwmManager const &) = delete;
+
+private:
+    struct PwmLink
+    {
+        enum EAppPwm appPwm;
+        size_t pwm;
+
+        friend bool operator<(const PwmLink & lhs, const PwmLink & rhs)
+        {
+            if (lhs.appPwm < rhs.appPwm)
+            {
+                return true;
+            }
+            else if (lhs.appPwm > rhs.appPwm)
+            {
+                return false;
+            }
+            else if (lhs.pwm < rhs.pwm)
+            {
+                return true;
+            }
+            else
+            {
+                return false;
+            }
+        }
+        friend bool operator>(const PwmLink & lhs, const PwmLink & rhs)
+        {
+            if (lhs.appPwm > rhs.appPwm)
+            {
+                return true;
+            }
+            else if (lhs.appPwm < rhs.appPwm)
+            {
+                return false;
+            }
+            else if (lhs.pwm > rhs.pwm)
+            {
+                return true;
+            }
+            else
+            {
+                return false;
+            }
+        }
+    };
+
+    PwmManager();
+
+    std::set<PwmLink> m_pwms;
+    PwmBackend * m_backend;
+};
+
+#if CONFIG_WS2812_STRIP
+
+class Ws2812Strip : public PwmBackend
+{
+public:
+    static Ws2812Strip & getInstance();
+    bool linkHW();
+
+    void setPwmHW(size_t pwm, bool state);
+    void setPwmHW(size_t pwm, uint32_t permille);
+    void setPwmHWBlink(size_t pwm, size_t onMs, size_t offMs);
+    void setPwmHWBreath(size_t pwm, size_t breathMs);
+
+    Ws2812Strip(Ws2812Strip const &)    = delete;
+    void operator=(Ws2812Strip const &) = delete;
+
+private:
+    Ws2812Strip(){};
+};
+
+#else
+
+class PwmPool : public PwmBackend
+{
+public:
+    static PwmPool & getInstance();
+    bool linkHW();
+
+    void setPwmHW(size_t pwm, bool state);
+    void setPwmHW(size_t pwm, uint32_t permille);
+    void setPwmHWBlink(size_t pwm, size_t onMs, size_t offMs);
+    void setPwmHWBreath(size_t pwm, size_t breathMs);
+
+    PwmPool(PwmPool const &)        = delete;
+    void operator=(PwmPool const &) = delete;
+
+private:
+    PwmPool(){};
+};
+
+#endif // CONFIG_WS2812_STRIP
diff --git a/examples/platform/telink/util/include/WS2812Device.h b/examples/platform/telink/util/include/WS2812Device.h
deleted file mode 100644
index 261802b..0000000
--- a/examples/platform/telink/util/include/WS2812Device.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- *    Copyright (c) 2023 Project CHIP Authors
- *    All rights reserved.
- *
- *    Licensed under the Apache License, Version 2.0 (the "License");
- *    you may not use this file except in compliance with the License.
- *    You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *    Unless required by applicable law or agreed to in writing, software
- *    distributed under the License is distributed on an "AS IS" BASIS,
- *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *    See the License for the specific language governing permissions and
- *    limitations under the License.
- */
-
-#pragma once
-
-#include <ColorFormat.h>
-
-#include <zephyr/drivers/led_strip.h>
-
-#include <system/SystemError.h>
-
-#define STRIP_NUM_PIXELS(LED_STRIP) DT_PROP(DT_ALIAS(LED_STRIP), chain_length)
-#define RGB_MIN_VALUE 0
-#define RGB_MAX_VALUE 255
-
-#define SET_RGB_TURN_OFF 0
-#define SET_RGB_TURN_ON 1
-
-class WS2812Device
-{
-public:
-    CHIP_ERROR Init(const struct device * ws2812Device, uint32_t aChainLength);
-    void SetLevel(RgbColor_t * pRgb);
-    void Set(bool aTurnOn);
-    bool IsTurnedOn(void);
-    uint8_t GetBlueLevel(void) const { return mLedRgb.b; }
-    uint8_t GetGreenLevel(void) const { return mLedRgb.g; }
-    uint8_t GetRedLevel(void) const { return mLedRgb.r; }
-
-private:
-    enum WS2812State_t : uint8_t
-    {
-        kRgbState_On = 0,
-        kRgbState_Off,
-    };
-
-    void UpdateRgbLight();
-
-    const struct device * mWs2812Device;
-    uint32_t mChainLength;
-    RgbColor_t mLedRgb;
-    WS2812State_t mState;
-};
diff --git a/examples/platform/telink/util/src/ButtonManager.cpp b/examples/platform/telink/util/src/ButtonManager.cpp
index a4c5e73..5d0d297 100644
--- a/examples/platform/telink/util/src/ButtonManager.cpp
+++ b/examples/platform/telink/util/src/ButtonManager.cpp
@@ -16,203 +16,135 @@
  *    limitations under the License.
  */
 
-#include <zephyr/device.h>
-#include <zephyr/drivers/gpio.h>
-#include <zephyr/irq.h>
-#include <zephyr/kernel.h>
-#include <zephyr/logging/log.h>
-
-LOG_MODULE_REGISTER(ButtonManager);
-
 #include <ButtonManager.h>
+#include <zephyr/logging/log.h>
+LOG_MODULE_REGISTER(ButtonManager, CONFIG_CHIP_APP_LOG_LEVEL);
 
-ButtonManager ButtonManager::sInstance;
-
-#if CONFIG_CHIP_BUTTON_MANAGER_IRQ_MODE
-void button_pressed(const struct device * dev, struct gpio_callback * cb, uint32_t pins);
-#endif
-
-void Button::Configure(const gpio_dt_spec * input_button_dt, const gpio_dt_spec * output_button_dt, void (*callback)(void))
+ButtonManager & ButtonManager::getInstance()
 {
-    if (!device_is_ready(input_button_dt->port))
-    {
-        LOG_ERR("Input port %s is not ready\n", input_button_dt->port->name);
-    }
+    static ButtonManager instance;
 
-    mInput_button      = input_button_dt;
-    mOutput_matrix_pin = output_button_dt;
-    mCallback          = callback;
+    return instance;
 }
 
-int Button::Init(void)
+ButtonManager::ButtonManager() : m_events{} {}
+
+void ButtonManager::addCallback(void (*callback)(void), size_t button, bool pressed)
 {
-    int ret = 0;
+    Event event = { .button = button, .pressed = pressed, .callback = callback };
 
-#if CONFIG_CHIP_BUTTON_MANAGER_IRQ_MODE
-    ret = gpio_pin_configure_dt(mInput_button, GPIO_INPUT);
-    if (ret < 0)
-    {
-        LOG_ERR("Config in pin err: %d", ret);
-        return ret;
-    }
-
-    ret = gpio_pin_interrupt_configure_dt(mInput_button, GPIO_INT_EDGE_TO_ACTIVE);
-    if (ret < 0)
-    {
-        LOG_ERR("Config irq pin err: %d", ret);
-        return ret;
-    }
-
-    gpio_init_callback(&mButton_cb_data, button_pressed, BIT(mInput_button->pin));
-    ret = gpio_add_callback(mInput_button->port, &mButton_cb_data);
-    if (ret < 0)
-    {
-        LOG_ERR("Config gpio_init_callback err: %d", ret);
-        return ret;
-    }
-#else
-
-    ret = gpio_pin_configure_dt(mOutput_matrix_pin, GPIO_OUTPUT_ACTIVE);
-    if (ret < 0)
-    {
-        LOG_ERR("Config out pin err: %d", ret);
-        return ret;
-    }
-
-    ret = gpio_pin_configure_dt(mInput_button, GPIO_INPUT);
-    if (ret < 0)
-    {
-        LOG_ERR("Config in pin err: %d", ret);
-        return ret;
-    }
-#endif
-
-    return ret;
+    m_events.insert(event);
 }
 
-int Button::Deinit(void)
+void ButtonManager::rmCallback(void (*callback)(void))
 {
-    int ret = 0;
-
-    /* Reconfigure output key pin to input */
-    ret = gpio_pin_configure_dt(mOutput_matrix_pin, GPIO_INPUT | GPIO_PULL_DOWN);
-    if (ret < 0)
+    for (auto it = m_events.begin(); it != m_events.end();)
     {
-        LOG_ERR("Reconfig out pin err: %d", ret);
-        return ret;
-    }
-
-    return ret;
-}
-
-void Button::Poll(Button * previous)
-{
-    int ret = 0;
-
-    if (previous != NULL)
-    {
-        ret = previous->Deinit();
-        assert(ret >= 0);
-    }
-
-    ret = Init();
-    assert(ret >= 0);
-
-    ret = gpio_pin_get_dt(mInput_button);
-    assert(ret >= 0);
-
-    if (ret == STATE_HIGH && ret != mPreviousState)
-    {
-        if (mCallback != NULL)
+        if (it->callback == callback)
         {
-            mCallback();
+            it = m_events.erase(it);
+        }
+        else
+        {
+            ++it;
         }
     }
-
-    mPreviousState = ret;
-
-    k_msleep(10);
 }
 
-void Button::SetCallback(void (*callback)(void))
+void ButtonManager::rmCallback(size_t button, bool pressed)
 {
-    mCallback = callback;
-}
-
-void ButtonManager::AddButton(Button & button)
-{
-    mButtons.push_back(button);
-}
-
-void ButtonManager::SetCallback(unsigned int index, void (*callback)(void))
-{
-    if (mButtons.size() <= index)
+    for (auto it = m_events.begin(); it != m_events.end();)
     {
-        LOG_ERR("Wrong button index");
+        if (it->button == button && it->pressed == pressed)
+        {
+            it = m_events.erase(it);
+        }
+        else
+        {
+            ++it;
+        }
     }
-
-    mButtons[index].SetCallback(callback);
 }
 
-void ButtonManager::Poll(void)
+void ButtonManager::linkBackend(ButtonBackend & backend)
 {
-    static Button * previous = NULL;
-
-    for (unsigned int i = 0; i < mButtons.size(); i++)
+    if (!backend.linkHW(onButton, this))
     {
-        mButtons[i].Poll(previous);
-        previous = &mButtons[i];
+        LOG_ERR("Button backend not inited!");
     }
-
-    k_msleep(10);
 }
 
-void ButtonEntry(void * param1, void * param2, void * param3)
+void ButtonManager::onButton(size_t button, bool pressed, void * buttonMgr)
 {
-    ButtonManager & sInstance = ButtonManagerInst();
+    ButtonManager * buttonManager = static_cast<ButtonManager *>(buttonMgr);
 
-    while (true)
+    for (auto it = buttonManager->m_events.begin(); it != buttonManager->m_events.end(); ++it)
     {
-        sInstance.Poll();
+        if (it->button == button && it->pressed == pressed && it->callback)
+        {
+            it->callback();
+        }
     }
 }
 
 #if CONFIG_CHIP_BUTTON_MANAGER_IRQ_MODE
-void button_pressed(const struct device * dev, struct gpio_callback * cb, uint32_t pins)
+
+#include <zephyr_key_pool.h>
+
+static KEY_POOL_DEFINE(key_pool);
+
+ButtonPool & ButtonPool::getInstance()
 {
-    ButtonManager & sInstance = ButtonManagerInst();
-    sInstance.PollIRQ(dev, pins);
+    static ButtonPool instance;
+
+    return instance;
 }
 
-void ButtonManager::PollIRQ(const struct device * dev, uint32_t pins)
+bool ButtonPool::linkHW(void (*on_button_change)(size_t button, bool pressed, void * context), void * context)
 {
-    for (unsigned int i = 0; i < mButtons.size(); i++)
+    bool result = false;
+
+    if (key_pool_init(&key_pool))
     {
-        mButtons[i].PollIRQ(dev, pins);
+        key_pool_set_callback(&key_pool, on_button_change, context);
+        LOG_INF("Key pool inited");
+        result = true;
     }
-}
-
-void Button::PollIRQ(const struct device * dev, uint32_t pins)
-{
-    if ((BIT(mInput_button->pin) & pins) && (mCallback != NULL) && (dev == mInput_button->port))
+    else
     {
-        mCallback();
+        LOG_ERR("Key pool not inited!");
     }
-}
-
-void Button::Configure(const gpio_dt_spec * input_button_dt, void (*callback)(void))
-{
-    if (!device_is_ready(input_button_dt->port))
-    {
-        LOG_ERR("%s is not ready\n", input_button_dt->port->name);
-    }
-
-    mInput_button = input_button_dt;
-    mCallback     = callback;
-
-    Init();
+    return result;
 }
 
 #else
-K_THREAD_DEFINE(buttonThread, 512, ButtonEntry, NULL, NULL, NULL, K_PRIO_COOP(CONFIG_NUM_COOP_PRIORITIES - 1), 0, 0);
-#endif
+
+#include <zephyr_key_matrix.h>
+
+static KEY_MATRIX_DEFINE(key_matrix);
+
+ButtonMatrix & ButtonMatrix::getInstance()
+{
+    static ButtonMatrix instance;
+
+    return instance;
+}
+
+bool ButtonMatrix::linkHW(void (*on_button_change)(size_t button, bool pressed, void * context), void * context)
+{
+    bool result = false;
+
+    if (key_matrix_init(&key_matrix))
+    {
+        key_matrix_set_callback(&key_matrix, on_button_change, context);
+        LOG_INF("Key matrix inited");
+        result = true;
+    }
+    else
+    {
+        LOG_ERR("Key matrix not inited!");
+    }
+    return result;
+}
+
+#endif // CONFIG_CHIP_BUTTON_MANAGER_IRQ_MODE
diff --git a/examples/platform/telink/util/src/LEDManager.cpp b/examples/platform/telink/util/src/LEDManager.cpp
new file mode 100644
index 0000000..f2717c5
--- /dev/null
+++ b/examples/platform/telink/util/src/LEDManager.cpp
@@ -0,0 +1,154 @@
+/*
+ *
+ *    Copyright (c) 2021 Project CHIP Authors
+ *    All rights reserved.
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+
+#include "LEDManager.h"
+#include <zephyr/logging/log.h>
+LOG_MODULE_REGISTER(LedManager, CONFIG_CHIP_APP_LOG_LEVEL);
+
+LedManager & LedManager::getInstance()
+{
+    static LedManager instance;
+
+    return instance;
+}
+
+LedManager::LedManager() : m_leds{}, m_backend(NULL) {}
+
+void LedManager::setLed(EAppLed appLed, bool state)
+{
+    if (!m_backend)
+    {
+        return;
+    }
+
+    for (auto it = m_leds.begin(); it != m_leds.end(); ++it)
+    {
+        if (it->appLed == appLed)
+        {
+            m_backend->setLedHW(it->led, state);
+        }
+    }
+}
+
+void LedManager::setLed(EAppLed appLed, size_t onMs, size_t offMs)
+{
+    if (!m_backend)
+    {
+        return;
+    }
+
+    for (auto it = m_leds.begin(); it != m_leds.end(); ++it)
+    {
+        if (it->appLed == appLed)
+        {
+            m_backend->setLedHW(it->led, onMs, offMs);
+        }
+    }
+}
+
+void LedManager::linkLed(EAppLed appLed, size_t led)
+{
+    LedLink link = { .appLed = appLed, .led = led };
+
+    m_leds.insert(link);
+}
+
+void LedManager::unlinkLed(EAppLed appLed)
+{
+    for (auto it = m_leds.begin(); it != m_leds.end();)
+    {
+        if (it->appLed == appLed)
+        {
+            it = m_leds.erase(it);
+        }
+        else
+        {
+            ++it;
+        }
+    }
+}
+
+void LedManager::unlinkLed(size_t led)
+{
+    for (auto it = m_leds.begin(); it != m_leds.end();)
+    {
+        if (it->led == led)
+        {
+            it = m_leds.erase(it);
+        }
+        else
+        {
+            ++it;
+        }
+    }
+}
+
+void LedManager::linkBackend(LedBackend & backend)
+{
+    if (backend.linkHW())
+    {
+        m_backend = &backend;
+    }
+    else
+    {
+        LOG_ERR("LED backend not inited!");
+    }
+}
+
+#include <zephyr_led_pool.h>
+
+static LED_POOL_DEFINE(led_pool);
+
+LedPool & LedPool::getInstance()
+{
+    static LedPool instance;
+
+    return instance;
+}
+
+bool LedPool::linkHW()
+{
+    bool result = false;
+
+    if (led_pool_init(&led_pool))
+    {
+        LOG_INF("LED pool inited");
+        result = true;
+    }
+    else
+    {
+        LOG_ERR("LED pool not inited!");
+    }
+    return result;
+}
+
+void LedPool::setLedHW(size_t led, bool state)
+{
+    if (!led_pool_set(&led_pool, led, state ? LED_ON : LED_OFF))
+    {
+        LOG_WRN("LED pool set led %u failed!", led);
+    }
+}
+
+void LedPool::setLedHW(size_t led, size_t onMs, size_t offMs)
+{
+    if (!led_pool_set(&led_pool, led, LED_BLINK, K_MSEC(onMs), K_MSEC(offMs)))
+    {
+        LOG_WRN("LED pool set led %u failed!", led);
+    }
+}
diff --git a/examples/platform/telink/util/src/LEDWidget.cpp b/examples/platform/telink/util/src/LEDWidget.cpp
deleted file mode 100644
index 9db2010..0000000
--- a/examples/platform/telink/util/src/LEDWidget.cpp
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- *
- *    Copyright (c) 2021 Project CHIP Authors
- *    All rights reserved.
- *
- *    Licensed under the Apache License, Version 2.0 (the "License");
- *    you may not use this file except in compliance with the License.
- *    You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *    Unless required by applicable law or agreed to in writing, software
- *    distributed under the License is distributed on an "AS IS" BASIS,
- *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *    See the License for the specific language governing permissions and
- *    limitations under the License.
- */
-
-#include "LEDWidget.h"
-
-#include <zephyr/kernel.h>
-#include <zephyr/logging/log.h>
-
-LOG_MODULE_REGISTER(LEDWidget);
-
-static LEDWidget::LEDWidgetStateUpdateHandler sStateUpdateCallback;
-
-void LEDWidget::SetStateUpdateCallback(LEDWidgetStateUpdateHandler stateUpdateCb)
-{
-    if (stateUpdateCb)
-        sStateUpdateCallback = stateUpdateCb;
-}
-
-void LEDWidget::Init(gpio_dt_spec gpio)
-{
-    mBlinkOnTimeMS  = 0;
-    mBlinkOffTimeMS = 0;
-    mGPIO           = gpio;
-    mState          = false;
-
-    if (!gpio_is_ready_dt(&mGPIO))
-    {
-        LOG_ERR("GPIO device not ready");
-    }
-    else
-    {
-        int ret = gpio_pin_configure_dt(&mGPIO, GPIO_OUTPUT_ACTIVE);
-        if (ret < 0)
-        {
-            LOG_ERR("GPIO pin %d configure - fail. Status%d\n", mGPIO.pin, ret);
-        }
-    }
-
-    k_timer_init(&mLedTimer, &LEDWidget::LedStateTimerHandler, nullptr);
-    k_timer_user_data_set(&mLedTimer, this);
-
-    Set(false);
-}
-
-void LEDWidget::Invert(void)
-{
-    Set(!mState);
-}
-
-void LEDWidget::Set(bool state)
-{
-    k_timer_stop(&mLedTimer);
-    mBlinkOnTimeMS = mBlinkOffTimeMS = 0;
-    DoSet(state);
-}
-
-void LEDWidget::Blink(uint32_t changeRateMS)
-{
-    Blink(changeRateMS, changeRateMS);
-}
-
-void LEDWidget::Blink(uint32_t onTimeMS, uint32_t offTimeMS)
-{
-    k_timer_stop(&mLedTimer);
-
-    mBlinkOnTimeMS  = onTimeMS;
-    mBlinkOffTimeMS = offTimeMS;
-
-    if (mBlinkOnTimeMS != 0 && mBlinkOffTimeMS != 0)
-    {
-        DoSet(!mState);
-        ScheduleStateChange();
-    }
-}
-
-void LEDWidget::ScheduleStateChange()
-{
-    k_timer_start(&mLedTimer, K_MSEC(mState ? mBlinkOnTimeMS : mBlinkOffTimeMS), K_NO_WAIT);
-}
-
-void LEDWidget::DoSet(bool state)
-{
-    if (!gpio_is_ready_dt(&mGPIO))
-    {
-        return;
-    }
-    mState  = state;
-    int ret = gpio_pin_set_dt(&mGPIO, state);
-    if (ret < 0)
-    {
-        LOG_ERR("GPIO pin %d set -fail. Status: %d\n", mGPIO.pin, ret);
-    }
-}
-
-void LEDWidget::UpdateState()
-{
-    /* Prevent from keep updating the state if LED was set to solid On/Off value */
-    if (mBlinkOnTimeMS != 0 && mBlinkOffTimeMS != 0)
-    {
-        DoSet(!mState);
-        ScheduleStateChange();
-    }
-}
-
-void LEDWidget::LedStateTimerHandler(k_timer * timer)
-{
-    if (sStateUpdateCallback)
-        sStateUpdateCallback(reinterpret_cast<LEDWidget *>(timer->user_data));
-}
diff --git a/examples/platform/telink/util/src/PWMDevice.cpp b/examples/platform/telink/util/src/PWMDevice.cpp
deleted file mode 100644
index 8456d54..0000000
--- a/examples/platform/telink/util/src/PWMDevice.cpp
+++ /dev/null
@@ -1,298 +0,0 @@
-/*
- *    Copyright (c) 2022 Project CHIP Authors
- *    All rights reserved.
- *
- *    Licensed under the Apache License, Version 2.0 (the "License");
- *    you may not use this file except in compliance with the License.
- *    You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *    Unless required by applicable law or agreed to in writing, software
- *    distributed under the License is distributed on an "AS IS" BASIS,
- *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *    See the License for the specific language governing permissions and
- *    limitations under the License.
- */
-
-#include "PWMDevice.h"
-
-#include "AppConfig.h"
-
-#include <lib/support/CodeUtils.h>
-
-#include <zephyr/drivers/pwm.h>
-#include <zephyr/kernel.h>
-#include <zephyr/logging/log.h>
-
-LOG_MODULE_REGISTER(PWMDevice);
-
-constexpr uint32_t kBreatheStepTimeMS = 10;
-
-static PWMDevice::PWMTimerCallback_fn mActionBlinkStateUpdate_CB;
-
-CHIP_ERROR PWMDevice::Init(const pwm_dt_spec * pwmDevice, uint8_t aMinLevel, uint8_t aMaxLevel, uint8_t aDefaultLevel)
-{
-    // We use a gpioPin instead of a LEDWidget here because we want to use PWM
-    // and other features instead of just on/off.
-
-    mState     = kState_On;
-    mMinLevel  = aMinLevel;
-    mMaxLevel  = aMaxLevel;
-    mLevel     = aDefaultLevel;
-    mPwmDevice = pwmDevice;
-
-    if (!device_is_ready(mPwmDevice->dev))
-    {
-        LOG_ERR("PWM device %s is not ready", mPwmDevice->dev ? mPwmDevice->dev->name : "N/A");
-    }
-
-    k_timer_init(&mPwmLedTimer, &PWMDevice::PwmLedTimerHandler, nullptr);
-    k_timer_user_data_set(&mPwmLedTimer, this);
-
-    ClearAction();
-    Set(false);
-    return CHIP_NO_ERROR;
-}
-
-void PWMDevice::SetCallbacks(PWMCallback_fn aActionInitiated_CB, PWMCallback_fn aActionCompleted_CB,
-                             PWMTimerCallback_fn aActionBlinkStateUpdate_CB)
-{
-    mActionInitiated_CB        = aActionInitiated_CB;
-    mActionCompleted_CB        = aActionCompleted_CB;
-    mActionBlinkStateUpdate_CB = aActionBlinkStateUpdate_CB;
-}
-
-bool PWMDevice::InitiateAction(Action_t aAction, int32_t aActor, uint8_t * value)
-{
-    bool action_initiated = false;
-    State_t new_state;
-
-    // Initiate On/Off Action only when the previous one is complete.
-    if (mState == kState_Off && aAction == ON_ACTION)
-    {
-        action_initiated = true;
-        new_state        = kState_On;
-    }
-    else if (mState == kState_On && aAction == OFF_ACTION)
-    {
-        action_initiated = true;
-        new_state        = kState_Off;
-    }
-    else if ((aAction == LEVEL_ACTION || aAction == COLOR_ACTION_XY || aAction == COLOR_ACTION_HSV || aAction == COLOR_ACTION_CT) &&
-             *value != mLevel)
-    {
-        action_initiated = true;
-        if (*value == 0)
-        {
-            new_state = kState_Off;
-        }
-        else
-        {
-            new_state = kState_On;
-        }
-    }
-
-    if (action_initiated)
-    {
-        if (mActionInitiated_CB)
-        {
-            mActionInitiated_CB(aAction, aActor);
-        }
-
-        if (aAction == ON_ACTION || aAction == OFF_ACTION)
-        {
-            Set(new_state == kState_On);
-        }
-        else if (aAction == LEVEL_ACTION || aAction == COLOR_ACTION_XY || aAction == COLOR_ACTION_HSV || aAction == COLOR_ACTION_CT)
-        {
-            SetLevel(*value);
-        }
-
-        if (mActionCompleted_CB)
-        {
-            mActionCompleted_CB(aAction, aActor);
-        }
-    }
-
-    return action_initiated;
-}
-
-void PWMDevice::SetLevel(uint8_t aLevel)
-{
-    LOG_DBG("Setting brightness level to %u", aLevel);
-    mLevel = aLevel;
-    UpdateLight();
-}
-
-void PWMDevice::Set(bool aOn)
-{
-    mState = aOn ? kState_On : kState_Off;
-    UpdateLight();
-}
-
-void PWMDevice::UpdateLight(void)
-{
-    if (!device_is_ready(mPwmDevice->dev))
-    {
-        return;
-    }
-    constexpr uint32_t kPwmWidthUs  = 20000u;
-    const uint8_t maxEffectiveLevel = mMaxLevel - mMinLevel;
-    const uint8_t effectiveLevel    = mState == kState_On ? chip::min<uint8_t>(mLevel - mMinLevel, maxEffectiveLevel) : 0;
-
-    pwm_set(mPwmDevice->dev, mPwmDevice->channel, PWM_USEC(kPwmWidthUs), PWM_USEC(kPwmWidthUs * effectiveLevel / maxEffectiveLevel),
-            0);
-}
-
-void PWMDevice::InitiateBlinkAction(uint32_t onTimeMS, uint32_t offTimeMS)
-{
-    ClearAction();
-
-    if (onTimeMS != 0 && offTimeMS != 0)
-    {
-        mBlinkOnTimeMS  = onTimeMS;
-        mBlinkOffTimeMS = offTimeMS;
-
-        Set(mState != kState_On ? true : false);
-        StartBlinkTimer();
-    }
-    else
-    {
-        LOG_ERR("Invalid InitiateBlinkAction parameters. onTimeMS = %u, offTimeMS = %u", onTimeMS, offTimeMS);
-    }
-}
-
-void PWMDevice::InitiateBreatheAction(BreatheType_t type, uint32_t cycleTimeMS)
-{
-    ClearAction();
-
-    if (type != kBreatheType_Invalid && cycleTimeMS != 0)
-    {
-        mBreatheType      = type;
-        mBreatheStepNumb  = cycleTimeMS / kBreatheStepTimeMS;
-        mBreatheStepLevel = (mMaxLevel - mMinLevel) / mBreatheStepNumb;
-
-        if (mBreatheType == kBreatheType_Both)
-        {
-            mBreatheBothDirection = true;
-            mBreatheType          = mState == kState_On ? kBreatheType_Falling : kBreatheType_Rising;
-        }
-
-        if (mBreatheType == kBreatheType_Falling)
-        {
-            mLevel = mMaxLevel;
-        }
-        else
-        {
-            mLevel = mMinLevel;
-        }
-
-        Set(true);
-        StartBreatheTimer(kBreatheStepTimeMS);
-    }
-    else
-    {
-        LOG_ERR("Invalid InitiateBreatheAction parameters. Type = %u, cycleTimeMS = %u", type, cycleTimeMS);
-    }
-}
-
-void PWMDevice::StopAction(void)
-{
-    ClearAction();
-    Set(false);
-}
-
-void PWMDevice::UpdateAction(void)
-{
-    // Update of Breathe action
-    if (mBreatheType != kBreatheType_Invalid && mBreatheStepLevel != 0 && mBreatheStepNumb != 0)
-    {
-        if (mBreatheStepCntr == mBreatheStepNumb)
-        {
-            mBreatheStepCntr = 0;
-            if (mBreatheBothDirection)
-            {
-                mBreatheType = mBreatheType == kBreatheType_Rising ? kBreatheType_Falling : kBreatheType_Rising;
-            }
-        }
-        else
-        {
-            mBreatheStepCntr++;
-        }
-
-        if (mBreatheType == kBreatheType_Rising)
-        {
-            if (mBreatheStepCntr == mBreatheStepNumb)
-            {
-                mLevel = mMaxLevel;
-            }
-            else if (mBreatheStepCntr == 0)
-            {
-                mLevel = mMinLevel;
-            }
-            else
-            {
-                mLevel += mBreatheStepLevel;
-            }
-        }
-        else if (mBreatheType == kBreatheType_Falling)
-        {
-            if (mBreatheStepCntr == mBreatheStepNumb)
-            {
-                mLevel = mMinLevel;
-            }
-            else if (mBreatheStepCntr == 0)
-            {
-                mLevel = mMaxLevel;
-            }
-            else
-            {
-                mLevel -= mBreatheStepLevel;
-            }
-        }
-
-        Set(true);
-        StartBreatheTimer(kBreatheStepTimeMS);
-    }
-    // Update of Blink action
-    else if (mBlinkOnTimeMS != 0 && mBlinkOffTimeMS != 0)
-    {
-        Set(mState != kState_On ? true : false);
-        StartBlinkTimer();
-    }
-    else
-    {
-        LOG_ERR("PWM LED update state is incorrect");
-    }
-}
-
-void PWMDevice::StartBlinkTimer(void)
-{
-    k_timer_start(&mPwmLedTimer, K_MSEC(mState == kState_On ? mBlinkOnTimeMS : mBlinkOffTimeMS), K_NO_WAIT);
-}
-
-void PWMDevice::StartBreatheTimer(uint32_t stepTimeMS)
-{
-    k_timer_start(&mPwmLedTimer, K_MSEC(stepTimeMS), K_NO_WAIT);
-}
-
-void PWMDevice::ClearAction(void)
-{
-    k_timer_stop(&mPwmLedTimer);
-    mBreatheBothDirection = false;
-    mBreatheType          = kBreatheType_Invalid;
-    mBreatheStepLevel     = 0;
-    mBreatheStepNumb      = 0;
-    mBlinkOnTimeMS        = 0;
-    mBlinkOffTimeMS       = 0;
-    mLevel                = mMaxLevel;
-}
-
-void PWMDevice::PwmLedTimerHandler(k_timer * timer)
-{
-    if (mActionBlinkStateUpdate_CB)
-    {
-        mActionBlinkStateUpdate_CB(timer);
-    }
-}
diff --git a/examples/platform/telink/util/src/PWMManager.cpp b/examples/platform/telink/util/src/PWMManager.cpp
new file mode 100644
index 0000000..987b665
--- /dev/null
+++ b/examples/platform/telink/util/src/PWMManager.cpp
@@ -0,0 +1,264 @@
+/*
+ *    Copyright (c) 2022 Project CHIP Authors
+ *    All rights reserved.
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+
+#include "PWMManager.h"
+
+#include <zephyr/logging/log.h>
+LOG_MODULE_REGISTER(PwmManager, CONFIG_CHIP_APP_LOG_LEVEL);
+
+PwmManager & PwmManager::getInstance()
+{
+    static PwmManager instance;
+
+    return instance;
+}
+
+PwmManager::PwmManager() : m_pwms{}, m_backend(NULL) {}
+
+void PwmManager::setPwm(EAppPwm appPwm, bool state)
+{
+    if (!m_backend)
+    {
+        return;
+    }
+
+    for (auto it = m_pwms.begin(); it != m_pwms.end(); ++it)
+    {
+        if (it->appPwm == appPwm)
+        {
+            m_backend->setPwmHW(it->pwm, state);
+        }
+    }
+}
+
+void PwmManager::setPwm(EAppPwm appPwm, uint32_t permille)
+{
+    if (!m_backend)
+    {
+        return;
+    }
+
+    for (auto it = m_pwms.begin(); it != m_pwms.end(); ++it)
+    {
+        if (it->appPwm == appPwm)
+        {
+            m_backend->setPwmHW(it->pwm, permille);
+        }
+    }
+}
+
+void PwmManager::setPwmBlink(EAppPwm appPwm, size_t onMs, size_t offMs)
+{
+    if (!m_backend)
+    {
+        return;
+    }
+
+    for (auto it = m_pwms.begin(); it != m_pwms.end(); ++it)
+    {
+        if (it->appPwm == appPwm)
+        {
+            m_backend->setPwmHWBlink(it->pwm, onMs, offMs);
+        }
+    }
+}
+
+void PwmManager::setPwmBreath(EAppPwm appPwm, size_t BrathMs)
+{
+    if (!m_backend)
+    {
+        return;
+    }
+
+    for (auto it = m_pwms.begin(); it != m_pwms.end(); ++it)
+    {
+        if (it->appPwm == appPwm)
+        {
+            m_backend->setPwmHWBreath(it->pwm, BrathMs);
+        }
+    }
+}
+
+void PwmManager::linkPwm(EAppPwm appPwm, size_t pwm)
+{
+    PwmLink link = { .appPwm = appPwm, .pwm = pwm };
+
+    m_pwms.insert(link);
+}
+
+void PwmManager::unlinkPwm(EAppPwm appPwm)
+{
+    for (auto it = m_pwms.begin(); it != m_pwms.end();)
+    {
+        if (it->appPwm == appPwm)
+        {
+            it = m_pwms.erase(it);
+        }
+        else
+        {
+            ++it;
+        }
+    }
+}
+
+void PwmManager::unlinkPwm(size_t pwm)
+{
+    for (auto it = m_pwms.begin(); it != m_pwms.end();)
+    {
+        if (it->pwm == pwm)
+        {
+            it = m_pwms.erase(it);
+        }
+        else
+        {
+            ++it;
+        }
+    }
+}
+
+void PwmManager::linkBackend(PwmBackend & backend)
+{
+    if (backend.linkHW())
+    {
+        m_backend = &backend;
+    }
+    else
+    {
+        LOG_ERR("PWM backend not inited!");
+    }
+}
+
+#if CONFIG_WS2812_STRIP
+
+#include <zephyr_ws2812.h>
+
+static WS2812_LED_DEFINE(led_strip);
+
+Ws2812Strip & Ws2812Strip::getInstance()
+{
+    static Ws2812Strip instance;
+
+    return instance;
+}
+
+bool Ws2812Strip::linkHW()
+{
+    bool result = false;
+
+    if (ws2812_led_init(&led_strip))
+    {
+        LOG_INF("WS2812 LED inited");
+        result = true;
+    }
+    else
+    {
+        LOG_ERR("WS2812 LED not inited!");
+    }
+    return result;
+}
+
+void Ws2812Strip::setPwmHW(size_t pwm, bool state)
+{
+    LOG_INF("PWM %u turn %s", pwm, state ? "on" : "off");
+    if (!ws2812_led_set(&led_strip, pwm, state ? WS2812_LED_ON : WS2812_LED_OFF))
+    {
+        LOG_WRN("WS2812 LED set pwm %u failed!", pwm);
+    }
+}
+
+void Ws2812Strip::setPwmHW(size_t pwm, uint32_t permille)
+{
+    LOG_INF("PWM %u set %u", pwm, permille);
+    if (!ws2812_led_set(&led_strip, pwm, WS2812_LED_FIXED, permille))
+    {
+        LOG_WRN("WS2812 LED set pwm %u to %u permille failed!", pwm, permille);
+    }
+}
+
+void Ws2812Strip::setPwmHWBlink(size_t pwm, size_t onMs, size_t offMs)
+{
+    LOG_WRN("WS2812 LED setPwmHWBlink not supported");
+}
+
+void Ws2812Strip::setPwmHWBreath(size_t pwm, size_t breathMs)
+{
+
+    LOG_WRN("WS2812 LED setPwmHWBreath not supported");
+}
+
+#else
+
+#include <zephyr_pwm_pool.h>
+
+static PWM_POOL_DEFINE(pwm_pool);
+
+PwmPool & PwmPool::getInstance()
+{
+    static PwmPool instance;
+
+    return instance;
+}
+
+bool PwmPool::linkHW()
+{
+    bool result = false;
+
+    if (pwm_pool_init(&pwm_pool))
+    {
+        LOG_INF("PWM pool inited");
+        result = true;
+    }
+    else
+    {
+        LOG_ERR("PWM pool not inited!");
+    }
+    return result;
+}
+
+void PwmPool::setPwmHW(size_t pwm, bool state)
+{
+    if (!pwm_pool_set(&pwm_pool, pwm, state ? PWM_ON : PWM_OFF))
+    {
+        LOG_WRN("PWM pool set pwm %u failed!", pwm);
+    }
+}
+
+void PwmPool::setPwmHW(size_t pwm, uint32_t permille)
+{
+    if (!pwm_pool_set(&pwm_pool, pwm, PWM_FIXED, permille))
+    {
+        LOG_WRN("PWM pool set pwm %u to %u permille failed!", pwm, permille);
+    }
+}
+
+void PwmPool::setPwmHWBlink(size_t pwm, size_t onMs, size_t offMs)
+{
+    if (!pwm_pool_set(&pwm_pool, pwm, PWM_BLINK, K_MSEC(onMs), K_MSEC(offMs)))
+    {
+        LOG_WRN("PWM pool set pwm %u blink to (%u-%u)mS failed!", pwm, onMs, offMs);
+    }
+}
+
+void PwmPool::setPwmHWBreath(size_t pwm, size_t breathMs)
+{
+    if (!pwm_pool_set(&pwm_pool, pwm, PWM_BREATH, K_MSEC(breathMs)))
+    {
+        LOG_WRN("PWM pool set pwm %u breath to %umS failed!", pwm, breathMs);
+    }
+}
+
+#endif // CONFIG_WS2812_STRIP
diff --git a/examples/platform/telink/util/src/WS2812Device.cpp b/examples/platform/telink/util/src/WS2812Device.cpp
deleted file mode 100644
index 06b7037..0000000
--- a/examples/platform/telink/util/src/WS2812Device.cpp
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- *    Copyright (c) 2023 Project CHIP Authors
- *    All rights reserved.
- *
- *    Licensed under the Apache License, Version 2.0 (the "License");
- *    you may not use this file except in compliance with the License.
- *    You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *    Unless required by applicable law or agreed to in writing, software
- *    distributed under the License is distributed on an "AS IS" BASIS,
- *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *    See the License for the specific language governing permissions and
- *    limitations under the License.
- */
-
-#include "WS2812Device.h"
-
-#include <lib/support/CodeUtils.h>
-
-#include <zephyr/kernel.h>
-#include <zephyr/logging/log.h>
-
-LOG_MODULE_REGISTER(WS2812Device);
-
-using namespace chip;
-
-CHIP_ERROR WS2812Device::Init(const struct device * ws2812Device, uint32_t aChainLength)
-{
-    mWs2812Device = ws2812Device;
-    mChainLength  = aChainLength;
-    mState        = kRgbState_Off;
-    memset(&mLedRgb, RGB_MAX_VALUE, sizeof(RgbColor_t));
-
-    if (!device_is_ready(mWs2812Device))
-    {
-        LOG_ERR("Device %s is not ready", mWs2812Device->name);
-        return CHIP_ERROR_INCORRECT_STATE;
-    }
-
-    UpdateRgbLight();
-
-    return CHIP_NO_ERROR;
-}
-
-void WS2812Device::UpdateRgbLight()
-{
-    int status;
-    led_rgb setRgb = { 0 };
-
-    if (mState == kRgbState_On)
-    {
-        setRgb.r = mLedRgb.r;
-        setRgb.g = mLedRgb.g;
-        setRgb.b = mLedRgb.b;
-    }
-
-    status = led_strip_update_rgb(mWs2812Device, &setRgb, mChainLength);
-    if (status)
-    {
-        LOG_ERR("Couldn't update strip: %d", status);
-    }
-}
-
-void WS2812Device::SetLevel(RgbColor_t * pRgb)
-{
-    if (pRgb != NULL)
-    {
-        memcpy(&mLedRgb, pRgb, sizeof(RgbColor_t));
-    }
-
-    UpdateRgbLight();
-}
-
-void WS2812Device::Set(bool aTurnOn)
-{
-    mState = aTurnOn ? kRgbState_On : kRgbState_Off;
-    UpdateRgbLight();
-}
-
-bool WS2812Device::IsTurnedOn()
-{
-    return mState == kRgbState_On;
-}
diff --git a/examples/platform/telink/zephyr_ext/zephyr_key_matrix.c b/examples/platform/telink/zephyr_ext/zephyr_key_matrix.c
new file mode 100644
index 0000000..00ea46c
--- /dev/null
+++ b/examples/platform/telink/zephyr_ext/zephyr_key_matrix.c
@@ -0,0 +1,139 @@
+/*
+ *
+ *    Copyright (c) 2024 Project CHIP Authors
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+
+#include "zephyr_key_matrix.h"
+
+/* Key matrix scanning period */
+#define KEY_MATRIX_SCAN_PERIOD_MS 100
+
+/* Poll key matrix and rise event on key change */
+static void key_matrix_poll(struct key_matrix_data * key_matrix, bool init)
+{
+    for (size_t i = 0; i < key_matrix->col_len; i++)
+    {
+        gpio_pin_configure_dt(&key_matrix->col[i], GPIO_OUTPUT_ACTIVE);
+        for (size_t j = 0; j < key_matrix->row_len; j++)
+        {
+            size_t button_num = i * key_matrix->col_len + j;
+            bool pin          = gpio_pin_get_dt(&key_matrix->row[j]);
+
+            if (pin != (bool) (key_matrix->buttons[button_num / 8] & BIT(button_num % 8)))
+            {
+                WRITE_BIT(key_matrix->buttons[button_num / 8], button_num % 8, pin);
+                if (!init && key_matrix->on_button_change)
+                {
+                    key_matrix->on_button_change(button_num, pin, key_matrix->context);
+                }
+            }
+        }
+        gpio_pin_configure_dt(&key_matrix->col[i], GPIO_INPUT);
+    }
+}
+
+/* Key matrix scan worker */
+static void key_matrix_scan_work(struct k_work * item)
+{
+    struct key_matrix_data * key_matrix = CONTAINER_OF(item, struct key_matrix_data, work);
+
+    (void) k_work_schedule(&key_matrix->work, K_MSEC(KEY_MATRIX_SCAN_PERIOD_MS));
+    key_matrix_poll(key_matrix, false);
+}
+
+/* Public APIs */
+
+bool key_matrix_init(struct key_matrix_data * key_matrix)
+{
+    bool result = true;
+
+    do
+    {
+        if (!key_matrix->col_len || !key_matrix->row_len)
+        {
+            result = false;
+            break;
+        }
+        /* check if all GPIOs are ready */
+        for (size_t i = 0; i < key_matrix->col_len; i++)
+        {
+            if (!gpio_is_ready_dt(&key_matrix->col[i]))
+            {
+                result = false;
+                break;
+            }
+        }
+        if (!result)
+        {
+            break;
+        }
+        for (size_t i = 0; i < key_matrix->row_len; i++)
+        {
+            if (!gpio_is_ready_dt(&key_matrix->row[i]))
+            {
+                result = false;
+                break;
+            }
+        }
+        if (!result)
+        {
+            break;
+        }
+        /* init all GPIOs are ready */
+        for (size_t i = 0; i < key_matrix->col_len; i++)
+        {
+            if (gpio_pin_configure_dt(&key_matrix->col[i], GPIO_INPUT))
+            {
+                result = false;
+                break;
+            }
+        }
+        if (!result)
+        {
+            break;
+        }
+        for (size_t i = 0; i < key_matrix->row_len; i++)
+        {
+            if (gpio_pin_configure_dt(&key_matrix->row[i], GPIO_INPUT))
+            {
+                result = false;
+                break;
+            }
+        }
+        if (!result)
+        {
+            break;
+        }
+        /* set all keys to current state */
+        key_matrix_poll(key_matrix, true);
+        key_matrix->on_button_change = NULL;
+        key_matrix->context          = NULL;
+        /* work init */
+        k_work_init_delayable(&key_matrix->work, key_matrix_scan_work);
+        while (k_work_schedule(&key_matrix->work, K_NO_WAIT) == -EBUSY)
+        {
+            k_usleep(10); /* Let other stuffs run */
+        }
+        /* all done */
+    } while (0);
+
+    return result;
+}
+
+void key_matrix_set_callback(struct key_matrix_data * key_matrix, key_matrix_on_button_change_t on_button_change, void * context)
+{
+    key_matrix->on_button_change = on_button_change;
+    key_matrix->context          = context;
+}
diff --git a/examples/platform/telink/zephyr_ext/zephyr_key_matrix.h b/examples/platform/telink/zephyr_ext/zephyr_key_matrix.h
new file mode 100644
index 0000000..52f2db2
--- /dev/null
+++ b/examples/platform/telink/zephyr_ext/zephyr_key_matrix.h
@@ -0,0 +1,88 @@
+/*
+ *
+ *    Copyright (c) 2024 Project CHIP Authors
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+
+#ifndef ZEPHYR_KEY_MATRIX_H
+#define ZEPHYR_KEY_MATRIX_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <zephyr/drivers/gpio.h>
+#include <zephyr/kernel.h>
+
+/* Data types */
+
+typedef void (*key_matrix_on_button_change_t)(size_t button, bool pressed, void * context);
+
+struct key_matrix_data
+{
+    const struct gpio_dt_spec * col;
+    const size_t col_len;
+    const struct gpio_dt_spec * row;
+    const size_t row_len;
+    uint8_t * buttons;
+    key_matrix_on_button_change_t on_button_change;
+    void * context;
+    struct k_work_delayable work;
+};
+
+/*
+ * Declare struct key_matrix_data variable base on data from .dts.
+ * The name of variable should correspond to .dts node name.
+ * .dts fragment example:
+ * name {
+ *     compatible = "gpio-keys";
+ *     col {
+ *         gpios = <&gpiod 6 GPIO_ACTIVE_HIGH>, <&gpiof 6 GPIO_ACTIVE_HIGH>;
+ *     };
+ *     row {
+ *         gpios = <&gpiod 2 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)>,
+ *                 <&gpiod 7 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)>;
+ *     };
+ * };
+ */
+#define KEY_MATRIX_DEFINE(name)                                                                                                    \
+    struct key_matrix_data name = {                                                                                                \
+        .col     = (const struct gpio_dt_spec[]){ COND_CODE_1(                                                                     \
+            DT_NODE_HAS_PROP(DT_PATH_INTERNAL(DT_CHILD(name, col)), gpios),                                                    \
+            (DT_FOREACH_PROP_ELEM_SEP(DT_PATH_INTERNAL(DT_CHILD(name, col)), gpios, GPIO_DT_SPEC_GET_BY_IDX, (, ))), ()) },    \
+        .col_len = COND_CODE_1(DT_NODE_HAS_PROP(DT_PATH_INTERNAL(DT_CHILD(name, col)), gpios),                                     \
+                               (DT_PROP_LEN(DT_PATH_INTERNAL(DT_CHILD(name, col)), gpios)), (0)),                                  \
+        .row     = (const struct gpio_dt_spec[]){ COND_CODE_1(                                                                     \
+            DT_NODE_HAS_PROP(DT_PATH_INTERNAL(DT_CHILD(name, row)), gpios),                                                    \
+            (DT_FOREACH_PROP_ELEM_SEP(DT_PATH_INTERNAL(DT_CHILD(name, row)), gpios, GPIO_DT_SPEC_GET_BY_IDX, (, ))), ()) },    \
+        .row_len = COND_CODE_1(DT_NODE_HAS_PROP(DT_PATH_INTERNAL(DT_CHILD(name, row)), gpios),                                     \
+                               (DT_PROP_LEN(DT_PATH_INTERNAL(DT_CHILD(name, row)), gpios)), (0)),                                  \
+        .buttons = (uint8_t[COND_CODE_1(UTIL_AND(DT_NODE_HAS_PROP(DT_PATH_INTERNAL(DT_CHILD(name, col)), gpios),                   \
+                                                 DT_NODE_HAS_PROP(DT_PATH_INTERNAL(DT_CHILD(name, row)), gpios)),                  \
+                                        (DIV_ROUND_UP(DT_PROP_LEN(DT_PATH_INTERNAL(DT_CHILD(name, col)), gpios) *                  \
+                                                          DT_PROP_LEN(DT_PATH_INTERNAL(DT_CHILD(name, row)), gpios),               \
+                                                      8)),                                                                         \
+                                        (0))]){},                                                                                  \
+    }
+
+/* Public APIs */
+
+bool key_matrix_init(struct key_matrix_data * key_matrix);
+void key_matrix_set_callback(struct key_matrix_data * key_matrix, key_matrix_on_button_change_t on_button_change, void * context);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ZEPHYR_KEY_MATRIX_H */
diff --git a/examples/platform/telink/zephyr_ext/zephyr_key_pool.c b/examples/platform/telink/zephyr_ext/zephyr_key_pool.c
new file mode 100644
index 0000000..5a88d15
--- /dev/null
+++ b/examples/platform/telink/zephyr_ext/zephyr_key_pool.c
@@ -0,0 +1,194 @@
+/*
+ *
+ *    Copyright (c) 2024 Project CHIP Authors
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+
+#include "zephyr_key_pool.h"
+#include <stdlib.h>
+
+/* Key pool denouncing settle time */
+#define KEY_POOL_DEBOUNCING_GUARD_MS 10
+
+/* Auxiliary data to link key pool with pin isr */
+struct key_pool_aux_data
+{
+    struct key_pool_data * key_pool;
+    const struct device * port;
+    struct gpio_callback callback;
+};
+
+/* Auxiliary function to get ports number in pool */
+static size_t key_pool_port_number(const struct key_pool_data * key_pool)
+{
+    size_t port_num = 0;
+
+    for (size_t i = 0; i < key_pool->inp_len; i++)
+    {
+        bool port_already = false;
+
+        for (size_t j = 0; j < i; j++)
+        {
+            if (key_pool->inp[i].port == key_pool->inp[j].port)
+            {
+                port_already = true;
+                break;
+            }
+        }
+        if (!port_already)
+        {
+            port_num++;
+        }
+    }
+    return port_num;
+}
+
+/* Poll key pool and rise event on key change */
+static void key_pool_poll(struct key_pool_data * key_pool, bool init)
+{
+    for (size_t i = 0; i < key_pool->inp_len; i++)
+    {
+        bool pin = gpio_pin_get_dt(&key_pool->inp[i]);
+
+        if (pin != (bool) (key_pool->buttons[i / 8] & BIT(i % 8)))
+        {
+            WRITE_BIT(key_pool->buttons[i / 8], i % 8, pin);
+            if (!init && key_pool->on_button_change)
+            {
+                key_pool->on_button_change(i, pin, key_pool->context);
+            }
+        }
+    }
+}
+
+/* Key pool scan worker */
+static void key_pool_event_work(struct k_work * item)
+{
+    struct key_pool_data * key_pool = CONTAINER_OF(item, struct key_pool_data, work);
+
+    key_pool_poll(key_pool, false);
+}
+
+/* Key pool pin isr */
+static void key_pool_on_pin_isr(const struct device * dev, struct gpio_callback * cb, uint32_t pins)
+{
+    struct key_pool_aux_data * key_pool_aux = CONTAINER_OF(cb, struct key_pool_aux_data, callback);
+
+    (void) k_work_reschedule(&key_pool_aux->key_pool->work, K_MSEC(KEY_POOL_DEBOUNCING_GUARD_MS));
+}
+
+/* Public APIs */
+
+bool key_pool_init(struct key_pool_data * key_pool)
+{
+    bool result = true;
+
+    do
+    {
+        if (!key_pool->inp_len)
+        {
+            result = false;
+            break;
+        }
+        /* check if all GPIOs are ready */
+        for (size_t i = 0; i < key_pool->inp_len; i++)
+        {
+            if (!gpio_is_ready_dt(&key_pool->inp[i]))
+            {
+                result = false;
+                break;
+            }
+        }
+        if (!result)
+        {
+            break;
+        }
+        /* init all GPIOs are ready */
+        for (size_t i = 0; i < key_pool->inp_len; i++)
+        {
+            if (gpio_pin_configure_dt(&key_pool->inp[i], GPIO_INPUT))
+            {
+                result = false;
+                break;
+            }
+            if (gpio_pin_interrupt_configure_dt(&key_pool->inp[i], GPIO_INT_EDGE_BOTH))
+            {
+                result = false;
+                break;
+            }
+        }
+        if (!result)
+        {
+            break;
+        }
+        /* add callbacks to all ports */
+        struct key_pool_aux_data * key_pool_aux =
+            (struct key_pool_aux_data *) malloc(sizeof(struct key_pool_aux_data) * key_pool_port_number(key_pool));
+
+        if (!key_pool_aux)
+        {
+            result = false;
+            break;
+        }
+
+        key_pool->aux                  = key_pool_aux;
+        size_t key_pool_aux_inited_cnt = 0;
+
+        for (size_t i = 0; i < key_pool->inp_len; i++)
+        {
+            bool port_found = false;
+
+            for (size_t j = 0; j < key_pool_aux_inited_cnt; j++)
+            {
+                if (key_pool->inp[i].port == key_pool_aux[j].port)
+                {
+                    port_found = true;
+                    key_pool_aux[j].callback.pin_mask |= BIT(key_pool->inp[i].pin);
+                }
+            }
+            if (!port_found)
+            {
+                key_pool_aux[key_pool_aux_inited_cnt].key_pool = key_pool;
+                key_pool_aux[key_pool_aux_inited_cnt].port     = key_pool->inp[i].port;
+                gpio_init_callback(&key_pool_aux[key_pool_aux_inited_cnt].callback, key_pool_on_pin_isr, BIT(key_pool->inp[i].pin));
+                key_pool_aux_inited_cnt++;
+            }
+        }
+        for (size_t i = 0; i < key_pool_aux_inited_cnt; i++)
+        {
+            if (gpio_add_callback(key_pool_aux[i].port, &key_pool_aux[i].callback))
+            {
+                result = false;
+                break;
+            }
+        }
+        if (!result)
+        {
+            break;
+        }
+        /* set all keys to current state */
+        key_pool_poll(key_pool, true);
+        /* init work */
+        k_work_init_delayable(&key_pool->work, key_pool_event_work);
+        /* all done */
+    } while (0);
+
+    return result;
+}
+
+void key_pool_set_callback(struct key_pool_data * key_pool, key_pool_on_button_change_t on_button_change, void * context)
+{
+    key_pool->on_button_change = on_button_change;
+    key_pool->context          = context;
+}
diff --git a/examples/platform/telink/zephyr_ext/zephyr_key_pool.h b/examples/platform/telink/zephyr_ext/zephyr_key_pool.h
new file mode 100644
index 0000000..bc39227
--- /dev/null
+++ b/examples/platform/telink/zephyr_ext/zephyr_key_pool.h
@@ -0,0 +1,75 @@
+/*
+ *
+ *    Copyright (c) 2024 Project CHIP Authors
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+
+#ifndef ZEPHYR_KEY_POOL_H
+#define ZEPHYR_KEY_POOL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <zephyr/drivers/gpio.h>
+#include <zephyr/kernel.h>
+
+/* Data types */
+
+typedef void (*key_pool_on_button_change_t)(size_t button, bool pressed, void * context);
+
+struct key_pool_data
+{
+    const struct gpio_dt_spec * inp;
+    const size_t inp_len;
+    uint8_t * buttons;
+    void * aux;
+    key_pool_on_button_change_t on_button_change;
+    void * context;
+    struct k_work_delayable work;
+};
+
+/*
+ * Declare struct key_pool_data variable base on data from .dts.
+ * The name of variable should correspond to .dts node name.
+ * .dts fragment example:
+ * name {
+ *     compatible = "gpio-keys";
+ *     inp {
+ *         gpios = <&gpioc 3 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>,
+ *                 <&gpioc 1 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
+ *     };
+ * };
+ */
+#define KEY_POOL_DEFINE(name)                                                                                                      \
+    struct key_pool_data name = {                                                                                                  \
+        .inp     = (const struct gpio_dt_spec[]){ COND_CODE_1(                                                                     \
+            DT_NODE_HAS_PROP(DT_PATH_INTERNAL(DT_CHILD(name, inp)), gpios),                                                    \
+            (DT_FOREACH_PROP_ELEM_SEP(DT_PATH_INTERNAL(DT_CHILD(name, inp)), gpios, GPIO_DT_SPEC_GET_BY_IDX, (, ))), ()) },    \
+        .inp_len = COND_CODE_1(DT_NODE_HAS_PROP(DT_PATH_INTERNAL(DT_CHILD(name, inp)), gpios),                                     \
+                               (DT_PROP_LEN(DT_PATH_INTERNAL(DT_CHILD(name, inp)), gpios)), (0)),                                  \
+        .buttons = (uint8_t[COND_CODE_1(DT_NODE_HAS_PROP(DT_PATH_INTERNAL(DT_CHILD(name, inp)), gpios),                            \
+                                        (DIV_ROUND_UP(DT_PROP_LEN(DT_PATH_INTERNAL(DT_CHILD(name, inp)), gpios), 8)), (0))]){},    \
+    }
+
+/* Public APIs */
+
+bool key_pool_init(struct key_pool_data * key_pool);
+void key_pool_set_callback(struct key_pool_data * key_pool, key_pool_on_button_change_t on_button_change, void * context);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ZEPHYR_KEY_POOL_H */
diff --git a/examples/platform/telink/zephyr_ext/zephyr_led_pool.c b/examples/platform/telink/zephyr_ext/zephyr_led_pool.c
new file mode 100644
index 0000000..f8ced2d
--- /dev/null
+++ b/examples/platform/telink/zephyr_ext/zephyr_led_pool.c
@@ -0,0 +1,202 @@
+/*
+ *
+ *    Copyright (c) 2024 Project CHIP Authors
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+
+#include "zephyr_led_pool.h"
+#include <stdarg.h>
+#include <stdlib.h>
+
+/* Auxiliary data to support blink */
+struct led_pool_aux_data
+{
+    enum led_state state;
+    k_ticks_t t_event;
+    k_timeout_t t_on;
+    k_timeout_t t_off;
+    bool current_state;
+};
+
+/* Get timeout to next event in auxiliary data */
+static k_timeout_t led_pool_aux_timeout(const struct led_pool_data * led_pool)
+{
+    k_timeout_t timeout                           = { .ticks = K_TICKS_FOREVER };
+    const struct led_pool_aux_data * led_pool_aux = (const struct led_pool_aux_data *) led_pool->aux;
+    size_t led_pool_aux_len                       = led_pool->out_len;
+
+    for (size_t i = 0; i < led_pool_aux_len; i++)
+    {
+        if (led_pool_aux[i].state == LED_BLINK)
+        {
+            k_ticks_t t_next = led_pool_aux[i].t_event +
+                (led_pool_aux[i].current_state ? led_pool_aux[i].t_on.ticks : led_pool_aux[i].t_off.ticks);
+            k_ticks_t t_now  = sys_clock_tick_get();
+            k_timeout_t this = { .ticks = t_next > t_now ? t_next - t_now : 0 };
+            if (timeout.ticks == K_TICKS_FOREVER || this.ticks < timeout.ticks)
+            {
+                timeout.ticks = this.ticks;
+            }
+        }
+    }
+    return timeout;
+}
+
+/* Process events in auxiliary data */
+static void led_pool_aux_update(const struct led_pool_data * led_pool)
+{
+    struct led_pool_aux_data * led_pool_aux = (struct led_pool_aux_data *) led_pool->aux;
+    size_t led_pool_aux_len                 = led_pool->out_len;
+
+    for (size_t i = 0; i < led_pool_aux_len; i++)
+    {
+        if (led_pool_aux[i].state == LED_BLINK)
+        {
+            k_ticks_t t_next = led_pool_aux[i].t_event +
+                (led_pool_aux[i].current_state ? led_pool_aux[i].t_on.ticks : led_pool_aux[i].t_off.ticks);
+            k_ticks_t t_now = sys_clock_tick_get();
+
+            if (t_next <= t_now)
+            {
+                led_pool_aux[i].current_state = !led_pool_aux[i].current_state;
+                led_pool_aux[i].t_event       = t_now;
+                (void) gpio_pin_set_dt(&led_pool->out[i], led_pool_aux[i].current_state);
+            }
+        }
+    }
+}
+
+/* Led pool worker */
+static void led_pool_event_work(struct k_work * item)
+{
+    struct led_pool_data * led_pool = CONTAINER_OF(item, struct led_pool_data, work);
+
+    led_pool_aux_update(led_pool);
+    (void) k_work_reschedule(&led_pool->work, led_pool_aux_timeout(led_pool));
+}
+
+/* Public APIs */
+
+bool led_pool_init(struct led_pool_data * led_pool)
+{
+    bool result = true;
+
+    do
+    {
+        if (!led_pool->out_len)
+        {
+            result = false;
+            break;
+        }
+        /* check if all GPIOs are ready */
+        for (size_t i = 0; i < led_pool->out_len; i++)
+        {
+            if (!gpio_is_ready_dt(&led_pool->out[i]))
+            {
+                result = false;
+                break;
+            }
+        }
+        if (!result)
+        {
+            break;
+        }
+        /* init all GPIOs are ready */
+        for (size_t i = 0; i < led_pool->out_len; i++)
+        {
+            if (gpio_pin_configure_dt(&led_pool->out[i], GPIO_OUTPUT))
+            {
+                result = false;
+                break;
+            }
+            if (gpio_pin_set_dt(&led_pool->out[i], 0))
+            {
+                result = false;
+                break;
+            }
+        }
+        if (!result)
+        {
+            break;
+        }
+        /* set auxiliary blink structure */
+        struct led_pool_aux_data * led_pool_aux =
+            (struct led_pool_aux_data *) malloc(sizeof(struct led_pool_aux_data) * led_pool->out_len);
+
+        if (!led_pool_aux)
+        {
+            result = false;
+            break;
+        }
+
+        for (size_t i = 0; i < led_pool->out_len; i++)
+        {
+            led_pool_aux[i].state = LED_OFF;
+        }
+        led_pool->aux = led_pool_aux;
+        /* init work */
+        k_work_init_delayable(&led_pool->work, led_pool_event_work);
+        if (k_work_reschedule(&led_pool->work, led_pool_aux_timeout(led_pool)) < 0)
+        {
+            result = false;
+            break;
+        }
+        /* all done */
+    } while (0);
+
+    return result;
+}
+
+bool led_pool_set(struct led_pool_data * led_pool, size_t led, enum led_state state, ...)
+{
+    bool result = false;
+
+    if (led < led_pool->out_len)
+    {
+        if (state == LED_ON || state == LED_OFF)
+        {
+            if (!gpio_pin_set_dt(&led_pool->out[led], state))
+            {
+                struct led_pool_aux_data * led_pool_aux = led_pool->aux;
+
+                led_pool_aux[led].state = state;
+                if (k_work_reschedule(&led_pool->work, led_pool_aux_timeout(led_pool)) >= 0)
+                {
+                    result = true;
+                }
+            }
+        }
+        else if (state == LED_BLINK)
+        {
+            if (!gpio_pin_set_dt(&led_pool->out[led], 1))
+            {
+                struct led_pool_aux_data * led_pool_aux = led_pool->aux;
+                va_list argptr;
+
+                va_start(argptr, state);
+                led_pool_aux[led].state         = state;
+                led_pool_aux[led].t_event       = sys_clock_tick_get();
+                led_pool_aux[led].t_on          = va_arg(argptr, k_timeout_t);
+                led_pool_aux[led].t_off         = va_arg(argptr, k_timeout_t);
+                led_pool_aux[led].current_state = true;
+                va_end(argptr);
+                if (k_work_reschedule(&led_pool->work, led_pool_aux_timeout(led_pool)) >= 0)
+                {
+                    result = true;
+                }
+            }
+        }
+    }
+    return result;
+}
diff --git a/examples/platform/telink/zephyr_ext/zephyr_led_pool.h b/examples/platform/telink/zephyr_ext/zephyr_led_pool.h
new file mode 100644
index 0000000..e25de9f
--- /dev/null
+++ b/examples/platform/telink/zephyr_ext/zephyr_led_pool.h
@@ -0,0 +1,75 @@
+/*
+ *
+ *    Copyright (c) 2024 Project CHIP Authors
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+
+#ifndef ZEPHYR_LED_POOL_H
+#define ZEPHYR_LED_POOL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <zephyr/drivers/gpio.h>
+#include <zephyr/kernel.h>
+
+/* Data types */
+
+enum led_state
+{
+    LED_OFF = 0,
+    LED_ON,
+    LED_BLINK
+};
+
+struct led_pool_data
+{
+    const struct gpio_dt_spec * out;
+    const size_t out_len;
+    void * aux;
+    struct k_work_delayable work;
+};
+
+/*
+ * Declare struct led_pool_data variable base on data from .dts.
+ * The name of variable should correspond to .dts node name.
+ * .dts fragment example:
+ * name {
+ *     compatible = "gpio-leds";
+ *     out {
+ *         gpios = <&gpioe 6 GPIO_ACTIVE_HIGH>,
+ *                 <&gpiod 0 GPIO_ACTIVE_HIGH>;
+ *     };
+ * };
+ */
+#define LED_POOL_DEFINE(name)                                                                                                      \
+    struct led_pool_data name = {                                                                                                  \
+        .out     = (const struct gpio_dt_spec[]){ COND_CODE_1(                                                                     \
+            DT_NODE_HAS_PROP(DT_PATH_INTERNAL(DT_CHILD(name, out)), gpios),                                                    \
+            (DT_FOREACH_PROP_ELEM_SEP(DT_PATH_INTERNAL(DT_CHILD(name, out)), gpios, GPIO_DT_SPEC_GET_BY_IDX, (, ))), ()) },    \
+        .out_len = COND_CODE_1(DT_NODE_HAS_PROP(DT_PATH_INTERNAL(DT_CHILD(name, out)), gpios),                                     \
+                               (DT_PROP_LEN(DT_PATH_INTERNAL(DT_CHILD(name, out)), gpios)), (0)),                                  \
+    }
+
+/* Public APIs */
+
+bool led_pool_init(struct led_pool_data * led_pool);
+bool led_pool_set(struct led_pool_data * led_pool, size_t led, enum led_state state, ...);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ZEPHYR_KEY_POOL_H */
diff --git a/examples/platform/telink/zephyr_ext/zephyr_pwm_pool.c b/examples/platform/telink/zephyr_ext/zephyr_pwm_pool.c
new file mode 100644
index 0000000..3f16518
--- /dev/null
+++ b/examples/platform/telink/zephyr_ext/zephyr_pwm_pool.c
@@ -0,0 +1,329 @@
+/*
+ *
+ *    Copyright (c) 2024 Project CHIP Authors
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+
+#include "zephyr_pwm_pool.h"
+#include <stdarg.h>
+#include <stdlib.h>
+
+/* Auxiliary data to support blink & breath */
+struct pwm_pool_aux_data
+{
+    /* common */
+    enum pwm_state state;
+    k_ticks_t t_event;
+    bool current_state;
+    union
+    {
+        struct blink
+        {
+            k_timeout_t t_on;
+            k_timeout_t t_off;
+        } blink;
+        struct breath
+        {
+            uint32_t period;
+            uint32_t current_pulse;
+            uint32_t step_pulse;
+        } breath;
+    } mode;
+};
+
+/* Get timeout to next event in auxiliary data */
+static k_timeout_t pwm_pool_aux_timeout(const struct pwm_pool_data * pwm_pool)
+{
+    k_timeout_t timeout                           = { .ticks = K_TICKS_FOREVER };
+    const struct pwm_pool_aux_data * pwm_pool_aux = (const struct pwm_pool_aux_data *) pwm_pool->aux;
+    size_t pwm_pool_aux_len                       = pwm_pool->out_len;
+
+    for (size_t i = 0; i < pwm_pool_aux_len; i++)
+    {
+        if (pwm_pool_aux[i].state == PWM_BLINK)
+        {
+            k_ticks_t t_next = pwm_pool_aux[i].t_event +
+                (pwm_pool_aux[i].current_state ? pwm_pool_aux[i].mode.blink.t_on.ticks : pwm_pool_aux[i].mode.blink.t_off.ticks);
+            k_ticks_t t_now  = sys_clock_tick_get();
+            k_timeout_t this = { .ticks = t_next > t_now ? t_next - t_now : 0 };
+            if (timeout.ticks == K_TICKS_FOREVER || this.ticks < timeout.ticks)
+            {
+                timeout.ticks = this.ticks;
+            }
+        }
+        else if (pwm_pool_aux[i].state == PWM_BREATH)
+        {
+            k_ticks_t t_next = pwm_pool_aux[i].t_event + K_NSEC(pwm_pool_aux[i].mode.breath.period).ticks;
+            k_ticks_t t_now  = sys_clock_tick_get();
+            k_timeout_t this = { .ticks = t_next > t_now ? t_next - t_now : 0 };
+            if (timeout.ticks == K_TICKS_FOREVER || this.ticks < timeout.ticks)
+            {
+                timeout.ticks = this.ticks;
+            }
+        }
+    }
+    return timeout;
+}
+
+/* Process events in auxiliary data */
+static void pwm_pool_aux_update(const struct pwm_pool_data * pwm_pool)
+{
+    struct pwm_pool_aux_data * pwm_pool_aux = (struct pwm_pool_aux_data *) pwm_pool->aux;
+    size_t pwm_pool_aux_len                 = pwm_pool->out_len;
+
+    for (size_t i = 0; i < pwm_pool_aux_len; i++)
+    {
+        if (pwm_pool_aux[i].state == PWM_BLINK)
+        {
+            k_ticks_t t_next = pwm_pool_aux[i].t_event +
+                (pwm_pool_aux[i].current_state ? pwm_pool_aux[i].mode.blink.t_on.ticks : pwm_pool_aux[i].mode.blink.t_off.ticks);
+            k_ticks_t t_now = sys_clock_tick_get();
+
+            if (t_next <= t_now)
+            {
+                pwm_pool_aux[i].t_event       = t_now;
+                pwm_pool_aux[i].current_state = !pwm_pool_aux[i].current_state;
+                (void) pwm_set_dt(&pwm_pool->out[i], pwm_pool->out[i].period,
+                                  pwm_pool_aux[i].current_state ? pwm_pool->out[i].period : 0);
+            }
+        }
+        else if (pwm_pool_aux[i].state == PWM_BREATH)
+        {
+            k_ticks_t t_next = pwm_pool_aux[i].t_event + K_NSEC(pwm_pool_aux[i].mode.breath.period).ticks;
+            k_ticks_t t_now  = sys_clock_tick_get();
+
+            if (t_next <= t_now)
+            {
+                pwm_pool_aux[i].t_event = t_now;
+                if (pwm_pool_aux[i].current_state)
+                {
+                    if (pwm_pool_aux[i].mode.breath.current_pulse <=
+                        pwm_pool_aux[i].mode.breath.period - pwm_pool_aux[i].mode.breath.step_pulse)
+                    {
+                        pwm_pool_aux[i].mode.breath.current_pulse += pwm_pool_aux[i].mode.breath.step_pulse;
+                    }
+                    else
+                    {
+                        pwm_pool_aux[i].mode.breath.current_pulse = pwm_pool_aux[i].mode.breath.period;
+                        pwm_pool_aux[i].current_state             = false;
+                    }
+                }
+                else
+                {
+                    if (pwm_pool_aux[i].mode.breath.current_pulse >= pwm_pool_aux[i].mode.breath.step_pulse)
+                    {
+                        pwm_pool_aux[i].mode.breath.current_pulse -= pwm_pool_aux[i].mode.breath.step_pulse;
+                    }
+                    else
+                    {
+                        pwm_pool_aux[i].mode.breath.current_pulse = 0;
+                        pwm_pool_aux[i].current_state             = true;
+                    }
+                }
+                (void) pwm_set_dt(&pwm_pool->out[i], pwm_pool->out[i].period, pwm_pool_aux[i].mode.breath.current_pulse);
+            }
+        }
+    }
+}
+
+/* Pwm pool worker */
+static void pwm_pool_event_work(struct k_work * item)
+{
+    struct pwm_pool_data * pwm_pool = CONTAINER_OF(item, struct pwm_pool_data, work);
+
+    pwm_pool_aux_update(pwm_pool);
+    (void) k_work_reschedule(&pwm_pool->work, pwm_pool_aux_timeout(pwm_pool));
+}
+
+/* Public APIs */
+
+bool pwm_pool_init(struct pwm_pool_data * pwm_pool)
+{
+    bool result = true;
+
+    do
+    {
+        if (!pwm_pool->out_len)
+        {
+            result = false;
+            break;
+        }
+        /* check if all PWMs are ready */
+        for (size_t i = 0; i < pwm_pool->out_len; i++)
+        {
+            if (!device_is_ready(pwm_pool->out[i].dev))
+            {
+                result = false;
+                break;
+            }
+        }
+        if (!result)
+        {
+            break;
+        }
+        /* init all PWMs are ready */
+        for (size_t i = 0; i < pwm_pool->out_len; i++)
+        {
+            if (pwm_set_dt(&pwm_pool->out[i], pwm_pool->out[i].period, 0))
+            {
+                result = false;
+                break;
+            }
+        }
+        if (!result)
+        {
+            break;
+        }
+        /* set auxiliary blink/breath structure */
+        struct pwm_pool_aux_data * pwm_pool_aux =
+            (struct pwm_pool_aux_data *) malloc(sizeof(struct pwm_pool_aux_data) * pwm_pool->out_len);
+
+        if (!pwm_pool_aux)
+        {
+            result = false;
+            break;
+        }
+
+        for (size_t i = 0; i < pwm_pool->out_len; i++)
+        {
+            pwm_pool_aux[i].state = PWM_OFF;
+        }
+        pwm_pool->aux = pwm_pool_aux;
+        /* init work */
+        k_work_init_delayable(&pwm_pool->work, pwm_pool_event_work);
+        if (k_work_reschedule(&pwm_pool->work, pwm_pool_aux_timeout(pwm_pool)) < 0)
+        {
+            result = false;
+            break;
+        }
+        /* all done */
+    } while (0);
+
+    return result;
+}
+
+bool pwm_pool_set(struct pwm_pool_data * pwm_pool, size_t pwm, enum pwm_state state, ...)
+{
+    bool result = false;
+
+    if (pwm < pwm_pool->out_len)
+    {
+        if (state == PWM_ON || state == PWM_OFF)
+        {
+            if (!pwm_set_dt(&pwm_pool->out[pwm], pwm_pool->out[pwm].period, state ? pwm_pool->out[pwm].period : 0))
+            {
+                struct pwm_pool_aux_data * pwm_pool_aux = pwm_pool->aux;
+
+                pwm_pool_aux[pwm].state = state;
+                if (k_work_reschedule(&pwm_pool->work, pwm_pool_aux_timeout(pwm_pool)) >= 0)
+                {
+                    result = true;
+                }
+            }
+        }
+        else if (state == PWM_FIXED)
+        {
+            va_list argptr;
+
+            va_start(argptr, state);
+            uint32_t permille = va_arg(argptr, uint32_t);
+
+            va_end(argptr);
+            if (permille <= PERMILLE_MAX)
+            {
+                if (!pwm_set_dt(&pwm_pool->out[pwm], pwm_pool->out[pwm].period,
+                                ((uint64_t) permille * pwm_pool->out[pwm].period) / PERMILLE_MAX))
+                {
+                    struct pwm_pool_aux_data * pwm_pool_aux = pwm_pool->aux;
+
+                    pwm_pool_aux[pwm].state = state;
+                    if (k_work_reschedule(&pwm_pool->work, pwm_pool_aux_timeout(pwm_pool)) >= 0)
+                    {
+                        result = true;
+                    }
+                }
+            }
+        }
+        else if (state == PWM_BLINK)
+        {
+            va_list argptr;
+
+            va_start(argptr, state);
+            k_timeout_t t_on  = va_arg(argptr, k_timeout_t);
+            k_timeout_t t_off = va_arg(argptr, k_timeout_t);
+
+            va_end(argptr);
+            if (t_on.ticks >= K_NSEC(pwm_pool->out[pwm].period).ticks && t_off.ticks >= K_NSEC(pwm_pool->out[pwm].period).ticks)
+            {
+                if (!pwm_set_dt(&pwm_pool->out[pwm], pwm_pool->out[pwm].period, pwm_pool->out[pwm].period))
+                {
+                    struct pwm_pool_aux_data * pwm_pool_aux = pwm_pool->aux;
+
+                    pwm_pool_aux[pwm].state            = state;
+                    pwm_pool_aux[pwm].t_event          = sys_clock_tick_get();
+                    pwm_pool_aux[pwm].current_state    = true;
+                    pwm_pool_aux[pwm].mode.blink.t_on  = t_on;
+                    pwm_pool_aux[pwm].mode.blink.t_off = t_off;
+
+                    if (k_work_reschedule(&pwm_pool->work, pwm_pool_aux_timeout(pwm_pool)) >= 0)
+                    {
+                        result = true;
+                    }
+                }
+            }
+        }
+        else if (state == PWM_BREATH)
+        {
+            va_list argptr;
+
+            va_start(argptr, state);
+            k_timeout_t t_breath = va_arg(argptr, k_timeout_t);
+
+            va_end(argptr);
+            if (t_breath.ticks >= K_NSEC(pwm_pool->out[pwm].period).ticks * 2)
+            {
+                if (!pwm_set_dt(&pwm_pool->out[pwm], pwm_pool->out[pwm].period, 0))
+                {
+                    struct pwm_pool_aux_data * pwm_pool_aux = pwm_pool->aux;
+
+                    pwm_pool_aux[pwm].state   = state;
+                    pwm_pool_aux[pwm].t_event = sys_clock_tick_get();
+                    /*
+                     * set new value now because pwm will be updated
+                     * with its value when current cycle will finished
+                     */
+                    if (pwm_pool_aux[pwm].t_event > K_NSEC(pwm_pool->out[pwm].period).ticks)
+                    {
+                        pwm_pool_aux[pwm].t_event -= K_NSEC(pwm_pool->out[pwm].period).ticks;
+                    }
+                    else
+                    {
+                        pwm_pool_aux[pwm].t_event = 0;
+                    }
+                    pwm_pool_aux[pwm].current_state             = true;
+                    pwm_pool_aux[pwm].mode.breath.period        = pwm_pool->out[pwm].period;
+                    pwm_pool_aux[pwm].mode.breath.current_pulse = 0;
+                    pwm_pool_aux[pwm].mode.breath.step_pulse =
+                        ((uint64_t) pwm_pool->out[pwm].period * pwm_pool->out[pwm].period * 2) /
+                        k_ticks_to_ns_ceil64(t_breath.ticks);
+                    if (k_work_reschedule(&pwm_pool->work, pwm_pool_aux_timeout(pwm_pool)) >= 0)
+                    {
+                        result = true;
+                    }
+                }
+            }
+        }
+    }
+    return result;
+}
diff --git a/examples/platform/telink/zephyr_ext/zephyr_pwm_pool.h b/examples/platform/telink/zephyr_ext/zephyr_pwm_pool.h
new file mode 100644
index 0000000..df50f40
--- /dev/null
+++ b/examples/platform/telink/zephyr_ext/zephyr_pwm_pool.h
@@ -0,0 +1,88 @@
+/*
+ *
+ *    Copyright (c) 2024 Project CHIP Authors
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+
+#ifndef ZEPHYR_PWM_POOL_H
+#define ZEPHYR_PWM_POOL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <zephyr/drivers/pwm.h>
+#include <zephyr/kernel.h>
+
+/* Zephyr PWM device tree compatibility macro */
+
+#define PWM_DT_SPEC_GET_BY_IDX_COMPAT(node_id, prop, idx) PWM_DT_SPEC_GET_BY_IDX(node_id, idx)
+
+/* Defines */
+
+#ifndef PERMILLE_MAX
+#define PERMILLE_MAX 1000
+#endif /* PERMILLE_MAX */
+
+/* Data types */
+
+enum pwm_state
+{
+    PWM_OFF = 0,
+    PWM_ON,
+    PWM_FIXED,
+    PWM_BLINK,
+    PWM_BREATH
+};
+
+struct pwm_pool_data
+{
+    const struct pwm_dt_spec * out;
+    const size_t out_len;
+    void * aux;
+    struct k_work_delayable work;
+};
+
+/*
+ * Declare struct led_pool_data variable base on data from .dts.
+ * The name of variable should correspond to .dts node name.
+ * .dts fragment example:
+ * name {
+ *     compatible = "pwm-leds";
+ *     out {
+ *         pwms = <&pwm0 0 PWM_MSEC(20) PWM_POLARITY_NORMAL>,
+ *                <&pwm0 1 PWM_MSEC(20) PWM_POLARITY_NORMAL>,
+ *                <&pwm0 2 PWM_MSEC(20) PWM_POLARITY_NORMAL>;
+ *     };
+ * };
+ */
+#define PWM_POOL_DEFINE(name)                                                                                                        \
+    struct pwm_pool_data name = {                                                                                                    \
+        .out     = (const struct pwm_dt_spec[]){ COND_CODE_1(                                                                        \
+            DT_NODE_HAS_PROP(DT_PATH_INTERNAL(DT_CHILD(name, out)), pwms),                                                       \
+            (DT_FOREACH_PROP_ELEM_SEP(DT_PATH_INTERNAL(DT_CHILD(name, out)), pwms, PWM_DT_SPEC_GET_BY_IDX_COMPAT, (, ))), ()) }, \
+        .out_len = COND_CODE_1(DT_NODE_HAS_PROP(DT_PATH_INTERNAL(DT_CHILD(name, out)), pwms),                                        \
+                               (DT_PROP_LEN(DT_PATH_INTERNAL(DT_CHILD(name, out)), pwms)), (0)),                                     \
+    }
+
+/* Public APIs */
+
+bool pwm_pool_init(struct pwm_pool_data * pwm_pool);
+bool pwm_pool_set(struct pwm_pool_data * pwm_pool, size_t pwm, enum pwm_state state, ...);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ZEPHYR_KEY_POOL_H */
diff --git a/examples/platform/telink/zephyr_ext/zephyr_ws2812.c b/examples/platform/telink/zephyr_ext/zephyr_ws2812.c
new file mode 100644
index 0000000..f8ce1c0
--- /dev/null
+++ b/examples/platform/telink/zephyr_ext/zephyr_ws2812.c
@@ -0,0 +1,112 @@
+/*
+ *
+ *    Copyright (c) 2024 Project CHIP Authors
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+
+#include "zephyr_ws2812.h"
+#include <stdarg.h>
+#include <string.h>
+
+/* Public APIs */
+
+bool ws2812_led_init(struct ws2812_led_data * ws2812_led)
+{
+    bool result = true;
+
+    do
+    {
+        if (!ws2812_led->led_len)
+        {
+            result = false;
+            break;
+        }
+        /* check if ws2812 is ready */
+        if (!device_is_ready(ws2812_led->led))
+        {
+            result = false;
+            break;
+        }
+        /* init all LEDs ready */
+        memset(ws2812_led->pix, 0x00, sizeof(struct led_rgb) * ws2812_led->led_len);
+        memcpy(ws2812_led->aux, ws2812_led->pix, sizeof(struct led_rgb) * ws2812_led->led_len);
+        if (led_strip_update_rgb(ws2812_led->led, (struct led_rgb *) ws2812_led->aux, ws2812_led->led_len))
+        {
+            result = false;
+            break;
+        }
+        /* all done */
+    } while (0);
+
+    return result;
+}
+
+bool ws2812_led_set(struct ws2812_led_data * ws2812_led, size_t id, enum ws2812_led_state state, ...)
+{
+    bool result = false;
+
+    if (id < ws2812_led->led_len * 3)
+    {
+        if (state == WS2812_LED_ON || state == WS2812_LED_OFF)
+        {
+            switch (id % 3)
+            {
+            case 0:
+                ws2812_led->pix[id / 3].r = (state ? 0xff : 0);
+                break;
+            case 1:
+                ws2812_led->pix[id / 3].g = (state ? 0xff : 0);
+                break;
+            case 2:
+                ws2812_led->pix[id / 3].b = (state ? 0xff : 0);
+                break;
+            }
+            memcpy(ws2812_led->aux, ws2812_led->pix, sizeof(struct led_rgb) * ws2812_led->led_len);
+            if (!led_strip_update_rgb(ws2812_led->led, (struct led_rgb *) ws2812_led->aux, ws2812_led->led_len))
+            {
+                result = true;
+            }
+        }
+        else if (state == WS2812_LED_FIXED)
+        {
+            va_list argptr;
+
+            va_start(argptr, state);
+            uint32_t permille = va_arg(argptr, uint32_t);
+
+            va_end(argptr);
+            if (permille <= PERMILLE_MAX)
+            {
+                switch (id % 3)
+                {
+                case 0:
+                    ws2812_led->pix[id / 3].r = (permille * 0xff + PERMILLE_MAX / 2) / PERMILLE_MAX;
+                    break;
+                case 1:
+                    ws2812_led->pix[id / 3].g = (permille * 0xff + PERMILLE_MAX / 2) / PERMILLE_MAX;
+                    break;
+                case 2:
+                    ws2812_led->pix[id / 3].b = (permille * 0xff + PERMILLE_MAX / 2) / PERMILLE_MAX;
+                    break;
+                }
+                memcpy(ws2812_led->aux, ws2812_led->pix, sizeof(struct led_rgb) * ws2812_led->led_len);
+                if (!led_strip_update_rgb(ws2812_led->led, (struct led_rgb *) ws2812_led->aux, ws2812_led->led_len))
+                {
+                    result = true;
+                }
+            }
+        }
+    }
+    return result;
+}
diff --git a/examples/platform/telink/zephyr_ext/zephyr_ws2812.h b/examples/platform/telink/zephyr_ext/zephyr_ws2812.h
new file mode 100644
index 0000000..6abb668
--- /dev/null
+++ b/examples/platform/telink/zephyr_ext/zephyr_ws2812.h
@@ -0,0 +1,85 @@
+/*
+ *
+ *    Copyright (c) 2024 Project CHIP Authors
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+
+#ifndef ZEPHYR_WS2812_H
+#define ZEPHYR_WS2812_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <zephyr/drivers/led_strip.h>
+#include <zephyr/kernel.h>
+
+/* Defines */
+
+#ifndef PERMILLE_MAX
+#define PERMILLE_MAX 1000
+#endif /* PERMILLE_MAX */
+
+/* Data types */
+
+enum ws2812_led_state
+{
+    WS2812_LED_OFF = 0,
+    WS2812_LED_ON,
+    WS2812_LED_FIXED
+};
+
+struct ws2812_led_data
+{
+    const struct device * led;
+    const size_t led_len;
+    struct led_rgb * pix;
+    void * aux;
+};
+
+/*
+ * Declare struct ws2812_led_data variable base on data from .dts.
+ * The name of variable should correspond to .dts node name.
+ * .dts fragment example:
+ * name: ws2812 {
+ *     compatible = "worldsemi,ws2812-gpio";
+ *     chain-length = <1>;
+ *     color-mapping = <LED_COLOR_ID_GREEN
+ *                      LED_COLOR_ID_RED
+ *                      LED_COLOR_ID_BLUE>;
+ *     in-gpios = <&gpiob 4 0>;
+ * };
+ */
+#define WS2812_LED_DEFINE(name)                                                                                                    \
+    struct ws2812_led_data name = {                                                                                                \
+        .led     = COND_CODE_1(DT_NODE_HAS_COMPAT(DT_NODELABEL(name), worldsemi_ws2812_gpio), (DEVICE_DT_GET(DT_NODELABEL(name))), \
+                               (NULL)),                                                                                            \
+        .led_len = COND_CODE_1(DT_NODE_HAS_COMPAT(DT_NODELABEL(name), worldsemi_ws2812_gpio),                                      \
+                               (DT_PROP(DT_NODELABEL(name), chain_length)), (0)),                                                  \
+        .pix     = (struct led_rgb[COND_CODE_1(DT_NODE_HAS_COMPAT(DT_NODELABEL(name), worldsemi_ws2812_gpio),                      \
+                                               (DT_PROP(DT_NODELABEL(name), chain_length)), (0))]){},                              \
+        .aux     = (struct led_rgb[COND_CODE_1(DT_NODE_HAS_COMPAT(DT_NODELABEL(name), worldsemi_ws2812_gpio),                      \
+                                               (DT_PROP(DT_NODELABEL(name), chain_length)), (0))]){},                              \
+    }
+
+/* Public APIs */
+
+bool ws2812_led_init(struct ws2812_led_data * ws2812_led);
+bool ws2812_led_set(struct ws2812_led_data * ws2812_led, size_t id, enum ws2812_led_state state, ...);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ZEPHYR_WS2812_H */
diff --git a/examples/pump-app/telink/CMakeLists.txt b/examples/pump-app/telink/CMakeLists.txt
index 5c3ad5d..6efcc7e 100755
--- a/examples/pump-app/telink/CMakeLists.txt
+++ b/examples/pump-app/telink/CMakeLists.txt
@@ -59,7 +59,7 @@
 include(${CHIP_ROOT}/config/telink/app/enable-gnu-std.cmake)
 include(${CHIP_ROOT}/src/app/chip_data_model.cmake)
 
-target_compile_options(app PRIVATE -fpermissive)
+target_compile_options(app PRIVATE $<$<COMPILE_LANGUAGE:CXX>:-fpermissive>)
 
 target_include_directories(app PRIVATE
                            include
@@ -67,17 +67,23 @@
                            ${GEN_DIR}/pump-app
                            ${TELINK_COMMON}/common/include
                            ${TELINK_COMMON}/util/include
-                           ${TELINK_COMMON}/app/include)
+                           ${TELINK_COMMON}/app/include
+                           ${TELINK_COMMON}/zephyr_ext)
 
 target_sources(app PRIVATE
                src/AppTask.cpp
                src/PumpManager.cpp
                ${TELINK_COMMON}/common/src/mainCommon.cpp
                ${TELINK_COMMON}/common/src/AppTaskCommon.cpp
-               ${TELINK_COMMON}/util/src/LEDWidget.cpp
+               ${TELINK_COMMON}/util/src/LEDManager.cpp
                ${TELINK_COMMON}/util/src/ButtonManager.cpp
                ${TELINK_COMMON}/util/src/ThreadUtil.cpp
-               ${TELINK_COMMON}/util/src/PWMDevice.cpp)
+               ${TELINK_COMMON}/util/src/PWMManager.cpp
+               ${TELINK_COMMON}/zephyr_ext/zephyr_key_matrix.c
+               ${TELINK_COMMON}/zephyr_ext/zephyr_key_pool.c
+               ${TELINK_COMMON}/zephyr_ext/zephyr_led_pool.c
+               ${TELINK_COMMON}/zephyr_ext/zephyr_pwm_pool.c
+               ${TELINK_COMMON}/zephyr_ext/zephyr_ws2812.c)
 
 chip_configure_data_model(app
     INCLUDE_SERVER
diff --git a/examples/pump-app/telink/include/AppConfig.h b/examples/pump-app/telink/include/AppConfig.h
index 85792a5..9f3fae6 100644
--- a/examples/pump-app/telink/include/AppConfig.h
+++ b/examples/pump-app/telink/include/AppConfig.h
@@ -20,14 +20,8 @@
 
 // ---- Pump Example App Config ----
 
-#define APP_USE_EXAMPLE_START_BUTTON 1
-#define APP_USE_BLE_START_BUTTON 0
-#define APP_USE_THREAD_START_BUTTON 0
 #define APP_SET_DEVICE_INFO_PROVIDER 1
 #define APP_SET_NETWORK_COMM_ENDPOINT_SEC 0
-#if defined(CONFIG_BOARD_TLSR9518ADK80D) || defined(CONFIG_BOARD_TLSR9528A)
-#define APP_USE_IDENTIFY_PWM 1
-#endif
 
 // Time it takes in ms for the simulated pump to move from one state to another.
 #define PUMP_START_PERIOS_MS 2000
diff --git a/examples/pump-app/telink/include/AppTask.h b/examples/pump-app/telink/include/AppTask.h
index 5d4537b..ce6dd79 100644
--- a/examples/pump-app/telink/include/AppTask.h
+++ b/examples/pump-app/telink/include/AppTask.h
@@ -21,6 +21,8 @@
 #include "AppTaskCommon.h"
 #include "PumpManager.h"
 
+class LedManager;
+
 class AppTask : public AppTaskCommon
 {
 public:
@@ -33,6 +35,7 @@
     friend class AppTaskCommon;
 
     CHIP_ERROR Init(void);
+    void LinkLeds(LedManager & ledManager);
 
     static void ActionInitiated(PumpManager::Action_t action, int32_t actor);
     static void ActionCompleted(PumpManager::Action_t action, int32_t actor);
diff --git a/examples/pump-app/telink/src/AppTask.cpp b/examples/pump-app/telink/src/AppTask.cpp
index 368702d..a7a360b 100644
--- a/examples/pump-app/telink/src/AppTask.cpp
+++ b/examples/pump-app/telink/src/AppTask.cpp
@@ -17,6 +17,7 @@
  */
 
 #include "AppTask.h"
+#include "LEDManager.h"
 #include "PumpManager.h"
 
 #include <app-common/zap-generated/attributes/Accessors.h>
@@ -26,25 +27,16 @@
 namespace {
 constexpr EndpointId kPccClusterEndpoint   = 1;
 constexpr EndpointId kOnOffClusterEndpoint = 1;
-
-#if CONFIG_CHIP_ENABLE_APPLICATION_STATUS_LED
-LEDWidget sPumpStateLED;
-#endif
 } // namespace
 
 AppTask AppTask::sAppTask;
 
 CHIP_ERROR AppTask::Init(void)
 {
-#if APP_USE_EXAMPLE_START_BUTTON
     SetExampleButtonCallbacks(StartActionEventHandler);
-#endif
     InitCommonParts();
 
-#if CONFIG_CHIP_ENABLE_APPLICATION_STATUS_LED
-    sPumpStateLED.Init(GPIO_DT_SPEC_GET(DT_ALIAS(led2), gpios));
-    sPumpStateLED.Set(!PumpMgr().IsStopped());
-#endif
+    LedManager::getInstance().setLed(LedManager::EAppLed_App0, !PumpMgr().IsStopped());
 
     PumpMgr().Init();
     PumpMgr().SetCallbacks(ActionInitiated, ActionCompleted);
@@ -65,9 +57,7 @@
         LOG_INF("Pump Stop Action has been initiated");
     }
 
-#if CONFIG_CHIP_ENABLE_APPLICATION_STATUS_LED
-    sPumpStateLED.Blink(50, 50);
-#endif
+    LedManager::getInstance().setLed(LedManager::EAppLed_App0, 50, 50);
 }
 
 void AppTask::ActionCompleted(PumpManager::Action_t action, int32_t actor)
@@ -78,16 +68,12 @@
     if (action == PumpManager::START_ACTION)
     {
         LOG_INF("Pump Start Action has been completed");
-#if CONFIG_CHIP_ENABLE_APPLICATION_STATUS_LED
-        sPumpStateLED.Set(true);
-#endif
+        LedManager::getInstance().setLed(LedManager::EAppLed_App0, true);
     }
     else if (action == PumpManager::STOP_ACTION)
     {
         LOG_INF("Pump Stop Action has been completed");
-#if CONFIG_CHIP_ENABLE_APPLICATION_STATUS_LED
-        sPumpStateLED.Set(false);
-#endif
+        LedManager::getInstance().setLed(LedManager::EAppLed_App0, false);
     }
 
     if (actor == static_cast<uint8_t>(AppEvent::kEventType_Button))
@@ -157,3 +143,13 @@
             maxPressure, maxSpeed, maxFlow, minConstPress, maxConstPress, minCompPress, maxCompPress, minConstSpeed, maxConstSpeed,
             minConstFlow, maxConstFlow, minConstTemp, maxConstTemp);
 }
+
+void AppTask::LinkLeds(LedManager & ledManager)
+{
+#if CONFIG_CHIP_ENABLE_APPLICATION_STATUS_LED
+    ledManager.linkLed(LedManager::EAppLed_Status, 0);
+    ledManager.linkLed(LedManager::EAppLed_App0, 1);
+#else
+    ledManager.linkLed(LedManager::EAppLed_App0, 0);
+#endif // CONFIG_CHIP_ENABLE_APPLICATION_STATUS_LED
+}
diff --git a/examples/pump-controller-app/telink/CMakeLists.txt b/examples/pump-controller-app/telink/CMakeLists.txt
index 684bb89..c24e478 100755
--- a/examples/pump-controller-app/telink/CMakeLists.txt
+++ b/examples/pump-controller-app/telink/CMakeLists.txt
@@ -59,7 +59,7 @@
 include(${CHIP_ROOT}/config/telink/app/enable-gnu-std.cmake)
 include(${CHIP_ROOT}/src/app/chip_data_model.cmake)
 
-target_compile_options(app PRIVATE -fpermissive)
+target_compile_options(app PRIVATE $<$<COMPILE_LANGUAGE:CXX>:-fpermissive>)
 
 target_include_directories(app PRIVATE
                            include
@@ -67,17 +67,23 @@
                            ${GEN_DIR}/pump-controller-app
                            ${TELINK_COMMON}/common/include
                            ${TELINK_COMMON}/util/include
-                           ${TELINK_COMMON}/app/include)
+                           ${TELINK_COMMON}/app/include
+                           ${TELINK_COMMON}/zephyr_ext)
 
 target_sources(app PRIVATE
                src/AppTask.cpp
                src/PumpManager.cpp
                ${TELINK_COMMON}/common/src/mainCommon.cpp
                ${TELINK_COMMON}/common/src/AppTaskCommon.cpp
-               ${TELINK_COMMON}/util/src/LEDWidget.cpp
+               ${TELINK_COMMON}/util/src/LEDManager.cpp
                ${TELINK_COMMON}/util/src/ButtonManager.cpp
                ${TELINK_COMMON}/util/src/ThreadUtil.cpp
-               ${TELINK_COMMON}/util/src/PWMDevice.cpp)
+               ${TELINK_COMMON}/util/src/PWMManager.cpp
+               ${TELINK_COMMON}/zephyr_ext/zephyr_key_matrix.c
+               ${TELINK_COMMON}/zephyr_ext/zephyr_key_pool.c
+               ${TELINK_COMMON}/zephyr_ext/zephyr_led_pool.c
+               ${TELINK_COMMON}/zephyr_ext/zephyr_pwm_pool.c
+               ${TELINK_COMMON}/zephyr_ext/zephyr_ws2812.c)
 
 chip_configure_data_model(app
     INCLUDE_SERVER
diff --git a/examples/pump-controller-app/telink/include/AppConfig.h b/examples/pump-controller-app/telink/include/AppConfig.h
index 1650e13..2e7e3af 100644
--- a/examples/pump-controller-app/telink/include/AppConfig.h
+++ b/examples/pump-controller-app/telink/include/AppConfig.h
@@ -20,14 +20,8 @@
 
 // ---- Pump Controller Example App Config ----
 
-#define APP_USE_EXAMPLE_START_BUTTON 1
-#define APP_USE_BLE_START_BUTTON 0
-#define APP_USE_THREAD_START_BUTTON 0
 #define APP_SET_DEVICE_INFO_PROVIDER 1
 #define APP_SET_NETWORK_COMM_ENDPOINT_SEC 0
-#if defined(CONFIG_BOARD_TLSR9518ADK80D) || defined(CONFIG_BOARD_TLSR9528A)
-#define APP_USE_IDENTIFY_PWM 1
-#endif
 
 // Time it takes in ms for the simulated pump to move from one state to another.
 #define PUMP_START_PERIOS_MS 2000
diff --git a/examples/pump-controller-app/telink/include/AppTask.h b/examples/pump-controller-app/telink/include/AppTask.h
index 5d4537b..ce6dd79 100644
--- a/examples/pump-controller-app/telink/include/AppTask.h
+++ b/examples/pump-controller-app/telink/include/AppTask.h
@@ -21,6 +21,8 @@
 #include "AppTaskCommon.h"
 #include "PumpManager.h"
 
+class LedManager;
+
 class AppTask : public AppTaskCommon
 {
 public:
@@ -33,6 +35,7 @@
     friend class AppTaskCommon;
 
     CHIP_ERROR Init(void);
+    void LinkLeds(LedManager & ledManager);
 
     static void ActionInitiated(PumpManager::Action_t action, int32_t actor);
     static void ActionCompleted(PumpManager::Action_t action, int32_t actor);
diff --git a/examples/pump-controller-app/telink/src/AppTask.cpp b/examples/pump-controller-app/telink/src/AppTask.cpp
index fa8ed8a..681f0fa 100644
--- a/examples/pump-controller-app/telink/src/AppTask.cpp
+++ b/examples/pump-controller-app/telink/src/AppTask.cpp
@@ -17,6 +17,7 @@
  */
 
 #include "AppTask.h"
+#include "LEDManager.h"
 #include "PumpManager.h"
 
 LOG_MODULE_DECLARE(app, CONFIG_CHIP_APP_LOG_LEVEL);
@@ -24,25 +25,16 @@
 namespace {
 constexpr EndpointId kPccClusterEndpoint   = 1;
 constexpr EndpointId kOnOffClusterEndpoint = 1;
-
-#if CONFIG_CHIP_ENABLE_APPLICATION_STATUS_LED
-LEDWidget sPumpStateLED;
-#endif
 } // namespace
 
 AppTask AppTask::sAppTask;
 
 CHIP_ERROR AppTask::Init(void)
 {
-#if APP_USE_EXAMPLE_START_BUTTON
     SetExampleButtonCallbacks(StartActionEventHandler);
-#endif
     InitCommonParts();
 
-#if CONFIG_CHIP_ENABLE_APPLICATION_STATUS_LED
-    sPumpStateLED.Init(GPIO_DT_SPEC_GET(DT_ALIAS(led2), gpios));
-    sPumpStateLED.Set(!PumpMgr().IsStopped());
-#endif
+    LedManager::getInstance().setLed(LedManager::EAppLed_App0, !PumpMgr().IsStopped());
 
     PumpMgr().Init();
     PumpMgr().SetCallbacks(ActionInitiated, ActionCompleted);
@@ -83,9 +75,7 @@
         LOG_INF("Pump Stop Action has been initiated");
     }
 
-#if CONFIG_CHIP_ENABLE_APPLICATION_STATUS_LED
-    sPumpStateLED.Blink(50, 50);
-#endif
+    LedManager::getInstance().setLed(LedManager::EAppLed_App0, 50, 50);
 }
 
 void AppTask::ActionCompleted(PumpManager::Action_t action, int32_t actor)
@@ -96,16 +86,12 @@
     if (action == PumpManager::START_ACTION)
     {
         LOG_INF("Pump Start Action has been completed");
-#if CONFIG_CHIP_ENABLE_APPLICATION_STATUS_LED
-        sPumpStateLED.Set(true);
-#endif
+        LedManager::getInstance().setLed(LedManager::EAppLed_App0, true);
     }
     else if (action == PumpManager::STOP_ACTION)
     {
         LOG_INF("Pump Stop Action has been completed");
-#if CONFIG_CHIP_ENABLE_APPLICATION_STATUS_LED
-        sPumpStateLED.Set(false);
-#endif
+        LedManager::getInstance().setLed(LedManager::EAppLed_App0, false);
     }
 
     if (actor == static_cast<uint8_t>(AppEvent::kEventType_Button))
@@ -125,3 +111,13 @@
 }
 
 void AppTask::UpdateClusterState() {}
+
+void AppTask::LinkLeds(LedManager & ledManager)
+{
+#if CONFIG_CHIP_ENABLE_APPLICATION_STATUS_LED
+    ledManager.linkLed(LedManager::EAppLed_Status, 0);
+    ledManager.linkLed(LedManager::EAppLed_App0, 1);
+#else
+    ledManager.linkLed(LedManager::EAppLed_App0, 0);
+#endif // CONFIG_CHIP_ENABLE_APPLICATION_STATUS_LED
+}
diff --git a/examples/smoke-co-alarm-app/telink/CMakeLists.txt b/examples/smoke-co-alarm-app/telink/CMakeLists.txt
index 96cb66c..5c269a1 100755
--- a/examples/smoke-co-alarm-app/telink/CMakeLists.txt
+++ b/examples/smoke-co-alarm-app/telink/CMakeLists.txt
@@ -59,14 +59,15 @@
 include(${CHIP_ROOT}/config/telink/app/enable-gnu-std.cmake)
 include(${CHIP_ROOT}/src/app/chip_data_model.cmake)
 
-target_compile_options(app PRIVATE -fpermissive)
+target_compile_options(app PRIVATE $<$<COMPILE_LANGUAGE:CXX>:-fpermissive>)
 
 target_include_directories(app PRIVATE
                            include
                            ${GEN_DIR}/app-common
                            ${GEN_DIR}/smoke-co-alarm-app
                            ${TELINK_COMMON}/common/include
-                           ${TELINK_COMMON}/util/include)
+                           ${TELINK_COMMON}/util/include
+                           ${TELINK_COMMON}/zephyr_ext)
 
 target_sources(app PRIVATE
                src/AppTask.cpp
@@ -74,10 +75,15 @@
                src/ZclCallbacks.cpp
                ${TELINK_COMMON}/common/src/mainCommon.cpp
                ${TELINK_COMMON}/common/src/AppTaskCommon.cpp
-               ${TELINK_COMMON}/util/src/LEDWidget.cpp
+               ${TELINK_COMMON}/util/src/LEDManager.cpp
                ${TELINK_COMMON}/util/src/ButtonManager.cpp
                ${TELINK_COMMON}/util/src/ThreadUtil.cpp
-               ${TELINK_COMMON}/util/src/PWMDevice.cpp)
+               ${TELINK_COMMON}/util/src/PWMManager.cpp
+               ${TELINK_COMMON}/zephyr_ext/zephyr_key_matrix.c
+               ${TELINK_COMMON}/zephyr_ext/zephyr_key_pool.c
+               ${TELINK_COMMON}/zephyr_ext/zephyr_led_pool.c
+               ${TELINK_COMMON}/zephyr_ext/zephyr_pwm_pool.c
+               ${TELINK_COMMON}/zephyr_ext/zephyr_ws2812.c)
 
 chip_configure_data_model(app
     INCLUDE_SERVER
diff --git a/examples/smoke-co-alarm-app/telink/include/AppConfig.h b/examples/smoke-co-alarm-app/telink/include/AppConfig.h
index f002310..a67196c 100644
--- a/examples/smoke-co-alarm-app/telink/include/AppConfig.h
+++ b/examples/smoke-co-alarm-app/telink/include/AppConfig.h
@@ -20,11 +20,5 @@
 
 // ---- Smoke Co Sendor App Example Config ----
 
-#define APP_USE_EXAMPLE_START_BUTTON 1
-#define APP_USE_BLE_START_BUTTON 0
-#define APP_USE_THREAD_START_BUTTON 0
 #define APP_SET_DEVICE_INFO_PROVIDER 1
 #define APP_SET_NETWORK_COMM_ENDPOINT_SEC 0
-#if defined(CONFIG_BOARD_TLSR9518ADK80D) || defined(CONFIG_BOARD_TLSR9528A)
-#define APP_USE_IDENTIFY_PWM 1
-#endif
diff --git a/examples/smoke-co-alarm-app/telink/src/AppTask.cpp b/examples/smoke-co-alarm-app/telink/src/AppTask.cpp
index 94be7e0..9680cc1 100644
--- a/examples/smoke-co-alarm-app/telink/src/AppTask.cpp
+++ b/examples/smoke-co-alarm-app/telink/src/AppTask.cpp
@@ -26,9 +26,7 @@
 
 CHIP_ERROR AppTask::Init(void)
 {
-#if APP_USE_EXAMPLE_START_BUTTON
     SetExampleButtonCallbacks(SelfTestEventHandler);
-#endif
     InitCommonParts();
 
     CHIP_ERROR err = AlarmMgr().Init();
diff --git a/examples/temperature-measurement-app/telink/CMakeLists.txt b/examples/temperature-measurement-app/telink/CMakeLists.txt
index fe84759..c57b827 100644
--- a/examples/temperature-measurement-app/telink/CMakeLists.txt
+++ b/examples/temperature-measurement-app/telink/CMakeLists.txt
@@ -74,7 +74,9 @@
 include(${CHIP_ROOT}/config/telink/app/enable-gnu-std.cmake)
 include(${CHIP_ROOT}/src/app/chip_data_model.cmake)
 
-target_compile_options(app PRIVATE -fpermissive)
+add_compile_definitions(IDENTIFY_CLUSTER_DISABLED=1)
+
+target_compile_options(app PRIVATE $<$<COMPILE_LANGUAGE:CXX>:-fpermissive>)
 
 target_include_directories(app PRIVATE
                            include
@@ -83,18 +85,22 @@
                            ${TELINK_COMMON}/common/include
                            ${TELINK_COMMON}/util/include
                            ${TELINK_COMMON}/app/include
-                           )
+                           ${TELINK_COMMON}/zephyr_ext)
 
 target_sources(app PRIVATE
                src/AppTask.cpp
                ${TELINK_COMMON}/common/src/mainCommon.cpp
                ${TELINK_COMMON}/common/src/AppTaskCommon.cpp
                ${TELINK_COMMON}/common/src/SensorManagerCommon.cpp
-               ${TELINK_COMMON}/util/src/LEDWidget.cpp
+               ${TELINK_COMMON}/util/src/LEDManager.cpp
                ${TELINK_COMMON}/util/src/ButtonManager.cpp
                ${TELINK_COMMON}/util/src/ThreadUtil.cpp
-               ${TELINK_COMMON}/util/src/PWMDevice.cpp
-               ${TELINK_COMMON}/util/src/WS2812Device.cpp)
+               ${TELINK_COMMON}/util/src/PWMManager.cpp
+               ${TELINK_COMMON}/zephyr_ext/zephyr_key_matrix.c
+               ${TELINK_COMMON}/zephyr_ext/zephyr_key_pool.c
+               ${TELINK_COMMON}/zephyr_ext/zephyr_led_pool.c
+               ${TELINK_COMMON}/zephyr_ext/zephyr_pwm_pool.c
+               ${TELINK_COMMON}/zephyr_ext/zephyr_ws2812.c)
 
 chip_configure_data_model(app
     INCLUDE_SERVER
diff --git a/examples/temperature-measurement-app/telink/include/AppConfig.h b/examples/temperature-measurement-app/telink/include/AppConfig.h
index b0e7847..136c5e5 100644
--- a/examples/temperature-measurement-app/telink/include/AppConfig.h
+++ b/examples/temperature-measurement-app/telink/include/AppConfig.h
@@ -20,8 +20,5 @@
 
 // ---- Temperature measurement Example App Config ----
 
-#define APP_USE_EXAMPLE_START_BUTTON 0
-#define APP_USE_BLE_START_BUTTON 0
-#define APP_USE_THREAD_START_BUTTON 0
 #define APP_SET_DEVICE_INFO_PROVIDER 1
 #define APP_SET_NETWORK_COMM_ENDPOINT_SEC 0
diff --git a/examples/thermostat/telink/CMakeLists.txt b/examples/thermostat/telink/CMakeLists.txt
index d46ba24..8f33541 100755
--- a/examples/thermostat/telink/CMakeLists.txt
+++ b/examples/thermostat/telink/CMakeLists.txt
@@ -74,7 +74,7 @@
 include(${CHIP_ROOT}/config/telink/app/enable-gnu-std.cmake)
 include(${CHIP_ROOT}/src/app/chip_data_model.cmake)
 
-target_compile_options(app PRIVATE -fpermissive)
+target_compile_options(app PRIVATE $<$<COMPILE_LANGUAGE:CXX>:-fpermissive>)
 
 target_include_directories(app PRIVATE
                            include
@@ -82,7 +82,8 @@
                            ${GEN_DIR}/thermostat
                            ${TELINK_COMMON}/common/include
                            ${TELINK_COMMON}/util/include
-                           ${TELINK_COMMON}/app/include)
+                           ${TELINK_COMMON}/app/include
+                           ${TELINK_COMMON}/zephyr_ext)
 
 target_sources(app PRIVATE
                src/AppTask.cpp
@@ -91,11 +92,15 @@
                ${TELINK_COMMON}/common/src/mainCommon.cpp
                ${TELINK_COMMON}/common/src/AppTaskCommon.cpp
                ${TELINK_COMMON}/common/src/SensorManagerCommon.cpp
-               ${TELINK_COMMON}/util/src/LEDWidget.cpp
+               ${TELINK_COMMON}/util/src/LEDManager.cpp
                ${TELINK_COMMON}/util/src/ButtonManager.cpp
                ${TELINK_COMMON}/util/src/ThreadUtil.cpp
-               ${TELINK_COMMON}/util/src/PWMDevice.cpp
-               ${TELINK_COMMON}/util/src/WS2812Device.cpp)
+               ${TELINK_COMMON}/util/src/PWMManager.cpp
+               ${TELINK_COMMON}/zephyr_ext/zephyr_key_matrix.c
+               ${TELINK_COMMON}/zephyr_ext/zephyr_key_pool.c
+               ${TELINK_COMMON}/zephyr_ext/zephyr_led_pool.c
+               ${TELINK_COMMON}/zephyr_ext/zephyr_pwm_pool.c
+               ${TELINK_COMMON}/zephyr_ext/zephyr_ws2812.c)
 
 chip_configure_data_model(app
     INCLUDE_SERVER
diff --git a/examples/thermostat/telink/include/AppConfig.h b/examples/thermostat/telink/include/AppConfig.h
index 9b427c5..b0b6c34 100644
--- a/examples/thermostat/telink/include/AppConfig.h
+++ b/examples/thermostat/telink/include/AppConfig.h
@@ -20,11 +20,5 @@
 
 // ---- Thermostat Example App Config ----
 
-#define APP_USE_EXAMPLE_START_BUTTON 0
-#define APP_USE_BLE_START_BUTTON 0
-#define APP_USE_THREAD_START_BUTTON 0
 #define APP_SET_DEVICE_INFO_PROVIDER 1
 #define APP_SET_NETWORK_COMM_ENDPOINT_SEC 0
-#if defined(CONFIG_BOARD_TLSR9518ADK80D) || defined(CONFIG_BOARD_TLSR9528A)
-#define APP_USE_IDENTIFY_PWM 1
-#endif
diff --git a/examples/window-app/telink/CMakeLists.txt b/examples/window-app/telink/CMakeLists.txt
index 629a0a0..f1e39be 100644
--- a/examples/window-app/telink/CMakeLists.txt
+++ b/examples/window-app/telink/CMakeLists.txt
@@ -59,7 +59,7 @@
 include(${CHIP_ROOT}/config/telink/app/enable-gnu-std.cmake)

 include(${CHIP_ROOT}/src/app/chip_data_model.cmake)

 

-target_compile_options(app PRIVATE -fpermissive)

+target_compile_options(app PRIVATE $<$<COMPILE_LANGUAGE:CXX>:-fpermissive>)

 

 target_include_directories(app PRIVATE

                            include

@@ -67,7 +67,8 @@
                            ${GEN_DIR}/window-app

                            ${TELINK_COMMON}/common/include

                            ${TELINK_COMMON}/util/include

-                           ${TELINK_COMMON}/app/include)

+                           ${TELINK_COMMON}/app/include

+                           ${TELINK_COMMON}/zephyr_ext)

 

 target_sources(app PRIVATE

                src/AppTask.cpp

@@ -75,10 +76,15 @@
                src/WindowCovering.cpp

                ${TELINK_COMMON}/common/src/mainCommon.cpp

                ${TELINK_COMMON}/common/src/AppTaskCommon.cpp

-               ${TELINK_COMMON}/util/src/LEDWidget.cpp

+               ${TELINK_COMMON}/util/src/LEDManager.cpp

                ${TELINK_COMMON}/util/src/ButtonManager.cpp

                ${TELINK_COMMON}/util/src/ThreadUtil.cpp

-               ${TELINK_COMMON}/util/src/PWMDevice.cpp

+               ${TELINK_COMMON}/util/src/PWMManager.cpp

+               ${TELINK_COMMON}/zephyr_ext/zephyr_key_matrix.c

+               ${TELINK_COMMON}/zephyr_ext/zephyr_key_pool.c

+               ${TELINK_COMMON}/zephyr_ext/zephyr_led_pool.c

+               ${TELINK_COMMON}/zephyr_ext/zephyr_pwm_pool.c

+               ${TELINK_COMMON}/zephyr_ext/zephyr_ws2812.c

                )

 

 chip_configure_data_model(app

diff --git a/examples/window-app/telink/include/AppConfig.h b/examples/window-app/telink/include/AppConfig.h
index f0ace63..dcf9449 100644
--- a/examples/window-app/telink/include/AppConfig.h
+++ b/examples/window-app/telink/include/AppConfig.h
@@ -20,10 +20,5 @@
 
 // ---- Window App Example Config ----
 
-#define APP_USE_EXAMPLE_START_BUTTON 0
-#define APP_USE_THREAD_START_BUTTON 0
 #define APP_SET_DEVICE_INFO_PROVIDER 1
 #define APP_SET_NETWORK_COMM_ENDPOINT_SEC 0
-#if defined(CONFIG_BOARD_TLSR9518ADK80D) || defined(CONFIG_BOARD_TLSR9528A)
-#define APP_USE_IDENTIFY_PWM 1
-#endif
diff --git a/examples/window-app/telink/include/AppTask.h b/examples/window-app/telink/include/AppTask.h
index 05a356f..07dafb2 100644
--- a/examples/window-app/telink/include/AppTask.h
+++ b/examples/window-app/telink/include/AppTask.h
@@ -35,6 +35,7 @@
     friend class AppTaskCommon;
 
     CHIP_ERROR Init(void);
+    void LinkButtons(ButtonManager & buttonManager);
 
     static void OpenActionAndToggleMoveTypeButtonEventHandler(void);
     static void CloseActionButtonEventHandler(void);
diff --git a/examples/window-app/telink/include/WindowCovering.h b/examples/window-app/telink/include/WindowCovering.h
index 872e3c5..aee1fdd 100644
--- a/examples/window-app/telink/include/WindowCovering.h
+++ b/examples/window-app/telink/include/WindowCovering.h
@@ -17,8 +17,7 @@
 
 #pragma once
 
-#include "LEDWidget.h"
-#include "PWMDevice.h"
+#include "LEDManager.h"
 
 #include <app/clusters/window-covering-server/window-covering-delegate.h>
 #include <app/clusters/window-covering-server/window-covering-server.h>
@@ -30,6 +29,15 @@
 class WindowCovering
 {
 public:
+    enum Action_t : uint8_t
+    {
+        ON_ACTION = 0,
+        OFF_ACTION,
+        LEVEL_ACTION,
+
+        INVALID_ACTION
+    };
+
     struct AttributeUpdateData
     {
         chip::EndpointId mEndpoint;
@@ -43,9 +51,6 @@
         return sInstance;
     }
 
-    PWMDevice & GetLiftIndicator() { return mLiftIndicator; }
-    PWMDevice & GetTiltIndicator() { return mTiltIndicator; }
-
     void StartMove(WindowCoveringType aMoveType);
     void SetSingleStepTarget(OperationalState aDirection);
     void SetMoveType(WindowCoveringType aMoveType) { mCurrentUIMoveType = aMoveType; }
@@ -71,8 +76,6 @@
 
     WindowCoveringType mCurrentUIMoveType;
 
-    PWMDevice mLiftIndicator;
-    PWMDevice mTiltIndicator;
     bool mInLiftMove{ false };
     bool mInTiltMove{ false };
 };
diff --git a/examples/window-app/telink/src/AppTask.cpp b/examples/window-app/telink/src/AppTask.cpp
index 9817b47..15f1341 100644
--- a/examples/window-app/telink/src/AppTask.cpp
+++ b/examples/window-app/telink/src/AppTask.cpp
@@ -27,22 +27,6 @@
 
 k_timer sToggleMoveTypeTimer;
 
-#if CONFIG_CHIP_BUTTON_MANAGER_IRQ_MODE
-#define OPEN_WINDOW_BUTTON GPIO_DT_SPEC_GET(DT_NODELABEL(key_4), gpios)
-#define CLOSE_WINDOW_BUTTON GPIO_DT_SPEC_GET(DT_NODELABEL(key_3), gpios)
-
-const struct gpio_dt_spec sOpenWindowButtonDt  = OPEN_WINDOW_BUTTON;
-const struct gpio_dt_spec sCloseWindowButtonDt = CLOSE_WINDOW_BUTTON;
-#else
-const struct gpio_dt_spec sButtonCol1Dt = GPIO_DT_SPEC_GET(DT_NODELABEL(key_matrix_col1), gpios);
-const struct gpio_dt_spec sButtonCol2Dt = GPIO_DT_SPEC_GET(DT_NODELABEL(key_matrix_col2), gpios);
-const struct gpio_dt_spec sButtonRow1Dt = GPIO_DT_SPEC_GET(DT_NODELABEL(key_matrix_row1), gpios);
-const struct gpio_dt_spec sButtonRow2Dt = GPIO_DT_SPEC_GET(DT_NODELABEL(key_matrix_row2), gpios);
-#endif
-
-Button sOpenButton;
-Button sCloseButton;
-
 bool sIsToggleMoveTypeTimerActive = false;
 } // namespace
 
@@ -52,16 +36,6 @@
 {
     InitCommonParts();
 
-#if CONFIG_CHIP_BUTTON_MANAGER_IRQ_MODE
-    sOpenButton.Configure(&sOpenWindowButtonDt, OpenActionAndToggleMoveTypeButtonEventHandler);
-    sCloseButton.Configure(&sCloseWindowButtonDt, CloseActionButtonEventHandler);
-#else
-    sOpenButton.Configure(&sButtonRow1Dt, &sButtonCol2Dt, OpenActionAndToggleMoveTypeButtonEventHandler);
-    sCloseButton.Configure(&sButtonRow2Dt, &sButtonCol1Dt, CloseActionButtonEventHandler);
-#endif
-    ButtonManagerInst().AddButton(sOpenButton);
-    ButtonManagerInst().AddButton(sCloseButton);
-
     // Initialize ToggleMoveType timer
     k_timer_init(&sToggleMoveTypeTimer, &AppTask::OpenTimerTimeoutCallback, nullptr);
     k_timer_user_data_set(&sToggleMoveTypeTimer, this);
@@ -153,3 +127,11 @@
         LOG_INF("Window covering move: lift");
     }
 }
+
+void AppTask::LinkButtons(ButtonManager & buttonManager)
+{
+    buttonManager.addCallback(FactoryResetButtonEventHandler, 0, true);
+    buttonManager.addCallback(ExampleActionButtonEventHandler, 1, true);
+    buttonManager.addCallback(OpenActionAndToggleMoveTypeButtonEventHandler, 2, true);
+    buttonManager.addCallback(CloseActionButtonEventHandler, 3, true);
+}
diff --git a/examples/window-app/telink/src/WindowCovering.cpp b/examples/window-app/telink/src/WindowCovering.cpp
index 1ed5bdb..302eecc 100644
--- a/examples/window-app/telink/src/WindowCovering.cpp
+++ b/examples/window-app/telink/src/WindowCovering.cpp
@@ -17,7 +17,7 @@
 
 #include "WindowCovering.h"
 #include "AppConfig.h"
-#include "PWMDevice.h"
+#include "PWMManager.h"
 
 #include <app-common/zap-generated/attributes/Accessors.h>
 #include <platform/CHIPDeviceLayer.h>
@@ -30,9 +30,6 @@
 using namespace ::chip::DeviceLayer;
 using namespace chip::app::Clusters::WindowCovering;
 
-static const struct pwm_dt_spec sLiftPwmDevice = PWM_DT_SPEC_GET(DT_ALIAS(pwm_led0));
-static const struct pwm_dt_spec sTiltPwmDevice = PWM_DT_SPEC_GET(DT_ALIAS(pwm_led1));
-
 static constexpr uint32_t sMoveTimeoutMs{ 200 };
 constexpr uint16_t sPercentDelta   = 500;
 constexpr uint8_t kDefaultMinLevel = 0;
@@ -40,16 +37,8 @@
 
 WindowCovering::WindowCovering()
 {
-    if (mLiftIndicator.Init(&sLiftPwmDevice, kDefaultMinLevel, kDefaultMaxLevel, kDefaultMinLevel) != CHIP_NO_ERROR)
-    {
-        LOG_ERR("Cannot initialize the lift indicator");
-    }
-    if (mTiltIndicator.Init(&sTiltPwmDevice, kDefaultMinLevel, kDefaultMaxLevel, kDefaultMinLevel) != CHIP_NO_ERROR)
-    {
-        LOG_ERR("Cannot initialize the tilt indicator");
-    }
-    mLiftIndicator.InitiateAction(PWMDevice::ON_ACTION, 0, nullptr);
-    mTiltIndicator.InitiateAction(PWMDevice::ON_ACTION, 0, nullptr);
+    PwmManager::getInstance().setPwm(PwmManager::EAppPwm_Red, false);
+    PwmManager::getInstance().setPwm(PwmManager::EAppPwm_Green, false);
 }
 
 void WindowCovering::DriveCurrentLiftPosition(intptr_t)
@@ -274,11 +263,11 @@
     uint8_t brightness = PositionToBrightness(aPosition, aMoveType);
     if (aMoveType == WindowCoveringType::Lift)
     {
-        mLiftIndicator.InitiateAction(PWMDevice::LEVEL_ACTION, 0, &brightness);
+        PwmManager::getInstance().setPwm(PwmManager::EAppPwm_Red, (((uint32_t) brightness * 1000) / UINT8_MAX));
     }
     else if (aMoveType == WindowCoveringType::Tilt)
     {
-        mTiltIndicator.InitiateAction(PWMDevice::LEVEL_ACTION, 0, &brightness);
+        PwmManager::getInstance().setPwm(PwmManager::EAppPwm_Green, (((uint32_t) brightness * 1000) / UINT8_MAX));
     }
 }
 
@@ -288,13 +277,13 @@
 
     if (aMoveType == WindowCoveringType::Lift)
     {
-        pwmLimits.open   = mLiftIndicator.GetMinLevel();
-        pwmLimits.closed = mLiftIndicator.GetMaxLevel();
+        pwmLimits.open   = kDefaultMinLevel;
+        pwmLimits.closed = kDefaultMaxLevel;
     }
     else if (aMoveType == WindowCoveringType::Tilt)
     {
-        pwmLimits.open   = mTiltIndicator.GetMinLevel();
-        pwmLimits.closed = mTiltIndicator.GetMaxLevel();
+        pwmLimits.open   = kDefaultMinLevel;
+        pwmLimits.closed = kDefaultMaxLevel;
     }
 
     return Percent100thsToValue(pwmLimits, aPosition);
diff --git a/examples/window-app/telink/src/ZclCallbacks.cpp b/examples/window-app/telink/src/ZclCallbacks.cpp
index 844e58e..dc7f537 100644
--- a/examples/window-app/telink/src/ZclCallbacks.cpp
+++ b/examples/window-app/telink/src/ZclCallbacks.cpp
@@ -17,7 +17,6 @@
  */
 
 #include "AppTask.h"
-#include "PWMDevice.h"
 #include "WindowCovering.h"
 #include <AppConfig.h>
 
diff --git a/integrations/cloudbuild/chef.yaml b/integrations/cloudbuild/chef.yaml
index 4a3655c..050acdf 100644
--- a/integrations/cloudbuild/chef.yaml
+++ b/integrations/cloudbuild/chef.yaml
@@ -1,5 +1,5 @@
 steps:
-    - name: "ghcr.io/project-chip/chip-build-vscode:41"
+    - name: "ghcr.io/project-chip/chip-build-vscode:46"
       entrypoint: "bash"
       args:
           - "-c"
@@ -7,7 +7,7 @@
               git config --global --add safe.directory "*"
               python scripts/checkout_submodules.py --shallow --recursive --platform esp32 nrfconnect silabs linux android 
       id: Submodules
-    - name: "ghcr.io/project-chip/chip-build-vscode:41"
+    - name: "ghcr.io/project-chip/chip-build-vscode:46"
       # NOTE: silabs boostrap is NOT done with the rest as it requests a conflicting
       #       jinja2 version (asks for 3.1.3 when constraints.txt asks for 3.0.3)
       env:
@@ -23,7 +23,7 @@
           - name: pwenv
             path: /pwenv
       timeout: 900s
-    - name: "ghcr.io/project-chip/chip-build-vscode:41"
+    - name: "ghcr.io/project-chip/chip-build-vscode:46"
       env:
           - PW_ENVIRONMENT_ROOT=/pwenv
       args:
@@ -38,7 +38,7 @@
           - name: pwenv
             path: /pwenv
 
-    - name: "ghcr.io/project-chip/chip-build-vscode:41"
+    - name: "ghcr.io/project-chip/chip-build-vscode:46"
       env:
           - PW_ENVIRONMENT_ROOT=/pwenv
       args:
diff --git a/integrations/cloudbuild/smoke-test.yaml b/integrations/cloudbuild/smoke-test.yaml
index 659c8be..2612667 100644
--- a/integrations/cloudbuild/smoke-test.yaml
+++ b/integrations/cloudbuild/smoke-test.yaml
@@ -1,5 +1,5 @@
 steps:
-    - name: "ghcr.io/project-chip/chip-build-vscode:41"
+    - name: "ghcr.io/project-chip/chip-build-vscode:46"
       entrypoint: "bash"
       args:
           - "-c"
@@ -7,7 +7,7 @@
               git config --global --add safe.directory "*"
               python scripts/checkout_submodules.py --shallow --recursive --platform esp32 nrfconnect silabs linux android 
       id: Submodules
-    - name: "ghcr.io/project-chip/chip-build-vscode:41"
+    - name: "ghcr.io/project-chip/chip-build-vscode:46"
       # NOTE: silabs boostrap is NOT done with the rest as it requests a conflicting
       #       jinja2 version (asks for 3.1.3 when constraints.txt asks for 3.0.3)
       env:
@@ -24,7 +24,7 @@
             path: /pwenv
       timeout: 900s
 
-    - name: "ghcr.io/project-chip/chip-build-vscode:41"
+    - name: "ghcr.io/project-chip/chip-build-vscode:46"
       id: ESP32
       env:
           - PW_ENVIRONMENT_ROOT=/pwenv
@@ -45,7 +45,7 @@
       volumes:
           - name: pwenv
             path: /pwenv
-    - name: "ghcr.io/project-chip/chip-build-vscode:41"
+    - name: "ghcr.io/project-chip/chip-build-vscode:46"
       id: NRFConnect
       env:
           - PW_ENVIRONMENT_ROOT=/pwenv
@@ -66,7 +66,7 @@
           - name: pwenv
             path: /pwenv
 
-    - name: "ghcr.io/project-chip/chip-build-vscode:41"
+    - name: "ghcr.io/project-chip/chip-build-vscode:46"
       id: EFR32
       env:
           - PW_ENVIRONMENT_ROOT=/pwenv
@@ -88,7 +88,7 @@
           - name: pwenv
             path: /pwenv
 
-    - name: "ghcr.io/project-chip/chip-build-vscode:41"
+    - name: "ghcr.io/project-chip/chip-build-vscode:46"
       id: Linux
       env:
           - PW_ENVIRONMENT_ROOT=/pwenv
@@ -141,7 +141,7 @@
           - name: pwenv
             path: /pwenv
 
-    - name: "ghcr.io/project-chip/chip-build-vscode:41"
+    - name: "ghcr.io/project-chip/chip-build-vscode:46"
       id: Android
       env:
           - PW_ENVIRONMENT_ROOT=/pwenv
diff --git a/src/platform/telink/tlsr9258a.overlay b/src/platform/telink/tlsr9258a.overlay
index b300411..b794576 100644
--- a/src/platform/telink/tlsr9258a.overlay
+++ b/src/platform/telink/tlsr9258a.overlay
@@ -26,37 +26,6 @@
 			label = "PWM IDENTIFY LED Green";
 	    };
     };
-
-	keys {
-		/delete-node/ button_1;
-		/delete-node/ button_3;
-		compatible = "gpio-keys";
-		key_1: button_1 {
-			gpios = <&gpiod 2 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
-		};
-		key_2: button_2 {
-			gpios = <&gpiod 7 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
-		};
-		key_3: button_3 {
-			gpios = <&gpiod 6 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
-		};
-		key_4: button_4 {
-			gpios = <&gpiof 6 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
-		};
-
-		key_matrix_col1: key_matrix_col1 {
-			gpios = <&gpiod 6 GPIO_ACTIVE_HIGH>;
-		};
-		key_matrix_col2: key_matrix_col2 {
-			gpios = <&gpiof 6 GPIO_ACTIVE_HIGH>;
-		};
-		key_matrix_row1: key_matrix_row1 {
-			gpios = <&gpiod 2 GPIO_PULL_DOWN>;
-		};
-		key_matrix_row2: key_matrix_row2 {
-			gpios = <&gpiod 7 GPIO_PULL_DOWN>;
-		};
-	};
 };
 
 &pinctrl {
diff --git a/src/platform/telink/tlsr9258a_retention.overlay b/src/platform/telink/tlsr9258a_retention.overlay
index 98a0e5a..0890951 100644
--- a/src/platform/telink/tlsr9258a_retention.overlay
+++ b/src/platform/telink/tlsr9258a_retention.overlay
@@ -17,37 +17,6 @@
 
 	/delete-node/ leds;
 	/delete-node/ pwm_leds;
-
-	keys {
-		/delete-node/ button_1;
-		/delete-node/ button_3;
-		compatible = "gpio-keys";
-		key_1: button_1 {
-			gpios = <&gpiod 2 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
-		};
-		key_2: button_2 {
-			gpios = <&gpiod 7 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
-		};
-		key_3: button_3 {
-			gpios = <&gpiod 6 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
-		};
-		key_4: button_4 {
-			gpios = <&gpiof 6 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
-		};
-
-		key_matrix_col1: key_matrix_col1 {
-			gpios = <&gpiod 6 GPIO_ACTIVE_HIGH>;
-		};
-		key_matrix_col2: key_matrix_col2 {
-			gpios = <&gpiof 6 GPIO_ACTIVE_HIGH>;
-		};
-		key_matrix_row1: key_matrix_row1 {
-			gpios = <&gpiod 2 GPIO_PULL_DOWN>;
-		};
-		key_matrix_row2: key_matrix_row2 {
-			gpios = <&gpiod 7 GPIO_PULL_DOWN>;
-		};
-	};
 };
 
 &pwm0 {
diff --git a/src/platform/telink/tlsr9518adk80d.overlay b/src/platform/telink/tlsr9518adk80d.overlay
index 7ad86ef..30ba76f 100644
--- a/src/platform/telink/tlsr9518adk80d.overlay
+++ b/src/platform/telink/tlsr9518adk80d.overlay
@@ -1,80 +1,63 @@
 / {
-	aliases {
-		system-state-led = &led_red;
-		pwm-led0 = &pwm_led0;
-		pwm-led1 = &pwm_led1;
-		pwm-led2 = &pwm_led2;
-		pwm-led3 = &pwm_led3;
-	};
-
-	pwm_leds {
-		/delete-node/ pwm_led_0;
-		pwm_led0: pwm_led_0 {
-			pwms = <&pwm0 0 PWM_MSEC(20) PWM_POLARITY_NORMAL>;
-			label = "PWM LED Blue";
-		};
-		pwm_led1: pwm_led_1 {
-			pwms = <&pwm0 3 PWM_MSEC(20) PWM_POLARITY_NORMAL>;
-			label = "PWM LED Green";
-		};
-		pwm_led2: pwm_led_2 {
-			pwms = <&pwm0 2 PWM_MSEC(20) PWM_POLARITY_NORMAL>;
-			label = "PWM LED Red";
-		};
-		pwm_led3: pwm_led_3 {
-			pwms = <&pwm0 1 PWM_MSEC(20) PWM_POLARITY_NORMAL>;
-			label = "PWM IDENTIFY LED Green";
-	    };
-    };
-
-	keys {
-		/delete-node/ button_1;
-		/delete-node/ button_3;
+	/* Short TL_Key1 (J20 pin 15) to ground (J50 pin 15-23) */
+	key_pool {
 		compatible = "gpio-keys";
-		key_1: button_1 {
-			gpios = <&gpioc 2 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
+
+		inp {
+			gpios = <&gpioc 3 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>,
+					<&gpioc 1 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>;
 		};
-		key_2: button_2 {
-			gpios = <&gpioc 0 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
-		};
-		key_3: button_3 {
-			gpios = <&gpioc 3 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
-		};
-		key_4: button_4 {
-			gpios = <&gpioc 1 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
+	};
+
+	key_matrix {
+		compatible = "gpio-keys";
+
+		col {
+			gpios = <&gpioc 2 GPIO_ACTIVE_HIGH>,
+					<&gpioc 0 GPIO_ACTIVE_HIGH>;
 		};
 
-		key_matrix_col1: key_matrix_col1 {
-			gpios = <&gpioc 3 GPIO_ACTIVE_HIGH>;
-		};
-		key_matrix_col2: key_matrix_col2 {
-			gpios = <&gpioc 1 GPIO_ACTIVE_HIGH>;
-		};
-		key_matrix_row1: key_matrix_row1 {
-			gpios = <&gpioc 2 GPIO_PULL_DOWN>;
-		};
-		key_matrix_row2: key_matrix_row2 {
-			gpios = <&gpioc 0 GPIO_PULL_DOWN>;
+		row {
+			gpios = <&gpioc 3 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)>,
+					<&gpioc 1 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)>;
 		};
 	};
-};
 
-&pinctrl {
-	pwm_ch0_pb4_default: pwm_ch0_pb4_default {
-		pinmux = <B9x_PINMUX_SET(B9x_PORT_B, B9x_PIN_4, B91_FUNC_B)>;
+	led_pool{
+		compatible = "gpio-leds";
+
+		out {
+			gpios = <&gpiob 6 GPIO_ACTIVE_HIGH>;
+		};
 	};
-	pwm_ch1_pb5_default: pwm_ch1_pb5_default {
-		pinmux = <B9x_PINMUX_SET(B9x_PORT_B, B9x_PIN_5, B91_FUNC_C)>;
-	};
-	pwm_ch2_pe2_default: pwm_ch2_pe2_default {
-		pinmux = <B9x_PINMUX_SET(B9x_PORT_E, B9x_PIN_2, B91_FUNC_C)>;
-	};
-	pwm_ch3_pe0_default: pwm_ch3_pe0_default {
-		pinmux = <B9x_PINMUX_SET(B9x_PORT_E, B9x_PIN_0, B91_FUNC_C)>;
+
+	pwm_pool {
+		compatible = "pwm-leds";
+		out {
+			/* Use blue led as indication, red & green - RGB-fixture */
+			pwms = <&pwm0 0 PWM_MSEC(20) PWM_POLARITY_NORMAL>,
+					<&pwm0 2 PWM_MSEC(20) PWM_POLARITY_NORMAL>,
+					<&pwm0 1 PWM_MSEC(20) PWM_POLARITY_NORMAL>;
+		};
 	};
 };
 
 &pwm0 {
-	pinctrl-0 = <&pwm_ch0_pb4_default &pwm_ch1_pb5_default &pwm_ch2_pe2_default &pwm_ch3_pe0_default>;
+	/* On board RGB LEDs */
+	pinctrl-ch2 = <&pwm_ch2_pb7_default>;
+	pinctrl-ch1 = <&pwm_ch1_pb5_default>;
+	pinctrl-ch0 = <&pwm_ch0_pb4_default>;
+};
+
+&pinctrl {
+	pwm_ch2_pb7_default: pwm_ch2_pb7_default {
+		pinmux = <B9x_PINMUX_SET(B9x_PORT_B, B9x_PIN_7, B91_FUNC_A)>;
+	};
+	pwm_ch1_pb5_default: pwm_ch1_pb5_default {
+		pinmux = <B9x_PINMUX_SET(B9x_PORT_B, B9x_PIN_5, B91_FUNC_C)>;
+	};
+	pwm_ch0_pb4_default: pwm_ch0_pb4_default {
+		pinmux = <B9x_PINMUX_SET(B9x_PORT_B, B9x_PIN_4, B91_FUNC_B)>;
+	};
 };
 
diff --git a/src/platform/telink/tlsr9518adk80d_mars.overlay b/src/platform/telink/tlsr9518adk80d_mars.overlay
index 303474c..a8a130a 100644
--- a/src/platform/telink/tlsr9518adk80d_mars.overlay
+++ b/src/platform/telink/tlsr9518adk80d_mars.overlay
@@ -2,54 +2,24 @@
 #include <zephyr/dt-bindings/led/led.h>
 
 / {
-	aliases {
-		led-strip = &led_strip;
+	key_pool {
+		compatible = "gpio-keys";
+
+		inp {
+			gpios = <&gpiod 1 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>,
+					<&gpiod 3 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>;
+		};
 	};
 
-	leds {
-		/delete-node/ led_3;
+	led_pool {
+		compatible = "gpio-leds";
 
-		led_red: led_3 {
-			label = "LED Red";
+		out {
 			gpios = <&gpiob 6 GPIO_ACTIVE_HIGH>;
 		};
 	};
 
-	pwm_leds {
-		/delete-node/ pwm_led_0;
-		/delete-node/ pwm_led_1;
-		/delete-node/ pwm_led_2;
-		/delete-node/ pwm_led_3;
-
-		pwm_led0: pwm_led_0 {
-			pwms = <&pwm0 0 PWM_MSEC(20) PWM_POLARITY_NORMAL>;
-			label = "PWM LED Blue";
-		};
-		pwm_led1: pwm_led_1 {
-			pwms = <&pwm0 3 PWM_MSEC(20) PWM_POLARITY_NORMAL>;
-			label = "PWM LED Green";
-		};
-		pwm_led2: pwm_led_2 {
-			pwms = <&pwm0 2 PWM_MSEC(20) PWM_POLARITY_NORMAL>;
-			label = "PWM LED Red";
-		};
-		pwm_led3: pwm_led_3 {
-			pwms = <&pwm0 1 PWM_MSEC(20) PWM_POLARITY_NORMAL>;
-			label = "PWM IDENTIFY LED Green";
-		};
-	};
-
-	keys {
-		/delete-node/ button_1;
-		/delete-node/ button_4;
-		compatible = "gpio-keys";
-		key_1: button_1 {
-			gpios = <&gpiod 1 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
-		};
-		key_4: button_4 {
-			gpios = <&gpiod 3 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
-		};
-	};
+	/delete-node/ pwm_pool;
 
 	led_strip: ws2812 {
 		compatible = "worldsemi,ws2812-gpio";
@@ -79,20 +49,6 @@
 	i2c_sda_pc2_default: i2c_sda_pc2_default {
 		pinmux = <B9x_PINMUX_SET(B9x_PORT_C, B9x_PIN_2, B91_FUNC_A)>;
 	};
-
-	/* PWMs */
-	pwm_ch0_pe3_default: pwm_ch0_pe3_default {
-		pinmux = <B9x_PINMUX_SET(B9x_PORT_E, B9x_PIN_3, B91_FUNC_C)>;
-	};
-	pwm_ch1_pb5_default: pwm_ch1_pb5_default {
-		pinmux = <B9x_PINMUX_SET(B9x_PORT_B, B9x_PIN_5, B91_FUNC_C)>;
-	};
-	pwm_ch2_pe2_default: pwm_ch2_pe2_default {
-		pinmux = <B9x_PINMUX_SET(B9x_PORT_E, B9x_PIN_2, B91_FUNC_C)>;
-	};
-	pwm_ch4_pe4_default: pwm_ch4_pe4_default {
-		pinmux = <B9x_PINMUX_SET(B9x_PORT_E, B9x_PIN_4, B91_FUNC_C)>;
-	};
 };
 
 &i2c {
@@ -103,7 +59,3 @@
 		reg = <0x44>;
 	};
 };
-
-&pwm0 {
-	pinctrl-0 = <&pwm_ch0_pe3_default &pwm_ch1_pb5_default &pwm_ch2_pe2_default &pwm_ch4_pe4_default>;
-};
diff --git a/src/platform/telink/tlsr9518adk80d_retention.overlay b/src/platform/telink/tlsr9518adk80d_retention.overlay
new file mode 100644
index 0000000..7921c61
--- /dev/null
+++ b/src/platform/telink/tlsr9518adk80d_retention.overlay
@@ -0,0 +1,31 @@
+/ {
+	/*
+	 * There is no way to keep GPIOs
+	 * during deep-sleep mode so output GPIOs
+	 * and PWM's are useless.
+	 */
+
+	/* Short TL_Key1 (J20 pin 15) to ground (J50 pin 15-23) */
+	key_pool {
+		compatible = "gpio-keys";
+
+		inp {
+			gpios = <&gpioc 3 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>,
+					<&gpioc 1 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>;
+		};
+	};
+
+	key_matrix {
+		compatible = "gpio-keys";
+
+		col {
+			gpios = <&gpioc 2 GPIO_ACTIVE_HIGH>,
+					<&gpioc 0 GPIO_ACTIVE_HIGH>;
+		};
+
+		row {
+			gpios = <&gpioc 3 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)>,
+					<&gpioc 1 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)>;
+		};
+	};
+};
diff --git a/src/platform/telink/tlsr9518adk80d_usb.overlay b/src/platform/telink/tlsr9518adk80d_usb.overlay
index f252379..452205e 100644
--- a/src/platform/telink/tlsr9518adk80d_usb.overlay
+++ b/src/platform/telink/tlsr9518adk80d_usb.overlay
@@ -4,81 +4,57 @@
 		zephyr,shell-uart = &cdc_acm_uart0;
 	};
 
-	keys {
-		/delete-node/ button_1;
-		/delete-node/ button_2;
-		/delete-node/ button_3;
-		/delete-node/ button_4;
+	key_pool {
+		compatible = "gpio-keys";
 
-		key_1: button_1 {
-			gpios = <&gpiob 2 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
-		};
-		key_2: button_2 {
-			gpios = <&gpioc 3 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
-		};
-		key_3: button_3 {
-			gpios = <&gpioc 4 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
-		};
-		key_4: button_4 {
-			gpios = <&gpiob 3 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
+		inp {
+			gpios = <&gpiob 2 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>,
+					<&gpiob 3 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>;
 		};
 	};
 
-	pwm_leds {
-		/delete-node/ pwm_led_0;
-		/delete-node/ pwm_led_1;
-		/delete-node/ pwm_led_2;
-		/delete-node/ pwm_led_3;
+	led_pool {
+		compatible = "gpio-leds";
 
-		pwm_led0: pwm_led_0 {
-			pwms = <&pwm0 2 PWM_MSEC(20) PWM_POLARITY_NORMAL>;
-			label = "PWM LED Blue";
-		};
-		pwm_led1: pwm_led_1 {
-			pwms = <&pwm0 5 PWM_MSEC(20) PWM_POLARITY_NORMAL>;
-			label = "PWM LED Green";
-		};
-		pwm_led2: pwm_led_2 {
-			pwms = <&pwm0 0 PWM_MSEC(20) PWM_POLARITY_NORMAL>;
-			label = "PWM LED Red";
-		};
-		pwm_led3: pwm_led_3 {
-			pwms = <&pwm0 3 PWM_MSEC(20) PWM_POLARITY_NORMAL>;
-			label = "PWM IDENTIFY LED White";
-	    };
-    };
-
-    aliases {
-		system-state-led = &led_yellow;
-	};
-
-	leds {
-		led_yellow: led_yellow {
-			gpios = <&gpiob 5 GPIO_ACTIVE_HIGH>;
-			label = "LED Yellow";
+		out {
+			gpios = <&gpiob 1 GPIO_ACTIVE_HIGH>,
+					<&gpioe 3 GPIO_ACTIVE_HIGH>;
 		};
 	};
-};
 
-&pinctrl {
-	pwm_ch2_pb7_default: pwm_ch2_pb7_default {
-		pinmux = <B9x_PINMUX_SET(B9x_PORT_B, B9x_PIN_7, B91_FUNC_A)>;
-	};
-	pwm_ch5_pb0_default: pwm_ch5_pb0_default {
-		pinmux = <B9x_PINMUX_SET(B9x_PORT_B, B9x_PIN_0, B91_FUNC_C)>;
-	};
-	pwm_ch0_pb4_default: pwm_ch0_pb4_default {
-		pinmux = <B9x_PINMUX_SET(B9x_PORT_B, B9x_PIN_4, B91_FUNC_B)>;
-	};
-	pwm_ch3_pb1_default: pwm_ch3_pb1_default {
-		pinmux = <B9x_PINMUX_SET(B9x_PORT_B, B9x_PIN_1, B91_FUNC_C)>;
+	pwm_pool {
+		compatible = "pwm-leds";
+		out {
+			pwms = <&pwm0 1 PWM_MSEC(20) PWM_POLARITY_NORMAL>,
+					<&pwm0 0 PWM_MSEC(20) PWM_POLARITY_NORMAL>,
+					<&pwm0 5 PWM_MSEC(20) PWM_POLARITY_NORMAL>,
+					<&pwm0 2 PWM_MSEC(20) PWM_POLARITY_NORMAL>;
+		};
 	};
 };
 
 &pwm0 {
-	pinctrl-0 = <&pwm_ch2_pb7_default &pwm_ch5_pb0_default &pwm_ch0_pb4_default &pwm_ch3_pb1_default>;
+	pinctrl-ch1 = <&pwm_ch1_pb5_default>;
+	/* On board RGB LEDs */
+	pinctrl-ch0 = <&pwm_ch0_pb4_default>;
+	pinctrl-ch5 = <&pwm_ch5_pb0_default>;
+	pinctrl-ch2 = <&pwm_ch2_pb7_default>;
 };
 
+&pinctrl {
+	pwm_ch1_pb5_default: pwm_ch1_pb5_default {
+		pinmux = <B9x_PINMUX_SET(B9x_PORT_B, B9x_PIN_5, B91_FUNC_C)>;
+	};
+	pwm_ch0_pb4_default: pwm_ch0_pb4_default {
+		pinmux = <B9x_PINMUX_SET(B9x_PORT_B, B9x_PIN_4, B91_FUNC_B)>;
+	};
+	pwm_ch5_pb0_default: pwm_ch5_pb0_default {
+		pinmux = <B9x_PINMUX_SET(B9x_PORT_B, B9x_PIN_0, B91_FUNC_C)>;
+	};
+	pwm_ch2_pb7_default: pwm_ch2_pb7_default {
+		pinmux = <B9x_PINMUX_SET(B9x_PORT_B, B9x_PIN_7, B91_FUNC_A)>;
+	};
+};
 
 &zephyr_udc0 {
 	cdc_acm_uart0: cdc_acm_uart0 {
@@ -97,3 +73,7 @@
 &gpioc {
 	interrupts = <38 1>;
 };
+
+&gpioe {
+	status = "okay";
+};
diff --git a/src/platform/telink/tlsr9528a.overlay b/src/platform/telink/tlsr9528a.overlay
index 9ba662d..fcd5192 100644
--- a/src/platform/telink/tlsr9528a.overlay
+++ b/src/platform/telink/tlsr9528a.overlay
@@ -1,80 +1,62 @@
 / {
-	aliases {
-		system-state-led = &led_red;
-		pwm-led0 = &pwm_led0;
-		pwm-led1 = &pwm_led1;
-		pwm-led2 = &pwm_led2;
-		pwm-led3 = &pwm_led3;
-	};
-
-	pwm_leds {
-		/delete-node/ pwm_led_0;
-		pwm_led0: pwm_led_0 {
-			pwms = <&pwm0 0 PWM_MSEC(20) PWM_POLARITY_NORMAL>;
-			label = "PWM LED Blue";
-		};
-		pwm_led1: pwm_led_1 {
-			pwms = <&pwm0 3 PWM_MSEC(20) PWM_POLARITY_NORMAL>;
-			label = "PWM LED Green";
-		};
-		pwm_led2: pwm_led_2 {
-			pwms = <&pwm0 2 PWM_MSEC(20) PWM_POLARITY_NORMAL>;
-			label = "PWM LED Red";
-		};
-		pwm_led3: pwm_led_3 {
-			pwms = <&pwm0 1 PWM_MSEC(20) PWM_POLARITY_NORMAL>;
-			label = "PWM IDENTIFY LED Green";
-	    };
-    };
-
-	keys {
-		/delete-node/ button_1;
-		/delete-node/ button_3;
+	/* Short TL_Key3 (J5 pin 13) to ground (J3 pin 24, 26, 28, 30) */
+	key_pool {
 		compatible = "gpio-keys";
-		key_1: button_1 {
-			gpios = <&gpiod 2 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
+
+		inp {
+			gpios = <&gpiod 2 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>,
+					<&gpiod 7 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>;
 		};
-		key_2: button_2 {
-			gpios = <&gpiod 7 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
-		};
-		key_3: button_3 {
-			gpios = <&gpiod 6 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
-		};
-		key_4: button_4 {
-			gpios = <&gpiof 6 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
+	};
+
+	key_matrix {
+		compatible = "gpio-keys";
+
+		col {
+			gpios = <&gpiod 6 GPIO_ACTIVE_HIGH>,
+					<&gpiof 6 GPIO_ACTIVE_HIGH>;
 		};
 
-		key_matrix_col1: key_matrix_col1 {
-			gpios = <&gpiod 6 GPIO_ACTIVE_HIGH>;
-		};
-		key_matrix_col2: key_matrix_col2 {
-			gpios = <&gpiof 6 GPIO_ACTIVE_HIGH>;
-		};
-		key_matrix_row1: key_matrix_row1 {
-			gpios = <&gpiod 2 GPIO_PULL_DOWN>;
-		};
-		key_matrix_row2: key_matrix_row2 {
-			gpios = <&gpiod 7 GPIO_PULL_DOWN>;
+		row {
+			gpios = <&gpiod 2 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)>,
+					<&gpiod 7 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)>;
 		};
 	};
-};
 
-&pinctrl {
-	pwm_ch0_pd0_default: pwm_ch0_pd0_default {
-		pinmux = <B9x_PINMUX_SET(B9x_PORT_D, B9x_PIN_0, B92_FUNC_PWM0)>;
+	led_pool {
+		compatible = "gpio-leds";
+
+		out {
+			gpios = <&gpioe 6 GPIO_ACTIVE_HIGH>;
+		};
 	};
-	pwm_ch1_pd1_default: pwm_ch1_pd1_default {
-		pinmux = <B9x_PINMUX_SET(B9x_PORT_D, B9x_PIN_1, B92_FUNC_PWM1)>;
-	};
-	pwm_ch2_pe2_default: pwm_ch2_pe2_default {
-		pinmux = <B9x_PINMUX_SET(B9x_PORT_E, B9x_PIN_2, B92_FUNC_PWM2)>;
-	};
-	pwm_ch3_pe0_default: pwm_ch3_pe0_default {
-		pinmux = <B9x_PINMUX_SET(B9x_PORT_E, B9x_PIN_0, B92_FUNC_PWM3)>;
+
+	pwm_pool {
+		compatible = "pwm-leds";
+		out {
+			pwms = <&pwm0 2 PWM_MSEC(20) PWM_POLARITY_NORMAL>,
+					<&pwm0 0 PWM_MSEC(20) PWM_POLARITY_NORMAL>,
+					<&pwm0 1 PWM_MSEC(20) PWM_POLARITY_NORMAL>;
+		};
 	};
 };
 
 &pwm0 {
-	pinctrl-0 = <&pwm_ch0_pd0_default &pwm_ch1_pd1_default &pwm_ch2_pe2_default &pwm_ch3_pe0_default>;
+	/* On board RGB LEDs */
+	pinctrl-ch0 = <&pwm_ch0_pe7_default>;
+	pinctrl-ch2 = <&pwm_ch1_pd1_default>;
+	pinctrl-ch1 = <&pwm_ch2_pd0_default>;
+};
+
+&pinctrl {
+	pwm_ch0_pe7_default: pwm_ch0_pe7_default {
+		pinmux = <B9x_PINMUX_SET(B9x_PORT_E, B9x_PIN_7, B92_FUNC_PWM0)>;
+	};
+	pwm_ch1_pd1_default: pwm_ch1_pd1_default {
+		pinmux = <B9x_PINMUX_SET(B9x_PORT_D, B9x_PIN_1, B92_FUNC_PWM1)>;
+	};
+	pwm_ch2_pd0_default: pwm_ch2_pd0_default {
+		pinmux = <B9x_PINMUX_SET(B9x_PORT_D, B9x_PIN_0, B92_FUNC_PWM2)>;
+	};
 };
 
diff --git a/src/platform/telink/tlsr9528a_retention.overlay b/src/platform/telink/tlsr9528a_retention.overlay
index 98a0e5a..b7204b7 100644
--- a/src/platform/telink/tlsr9528a_retention.overlay
+++ b/src/platform/telink/tlsr9528a_retention.overlay
@@ -5,51 +5,27 @@
 	 * and PWM's are useless.
 	 */
 
-	aliases {
-		/delete-property/ led0;
-		/delete-property/ led1;
-		/delete-property/ led2;
-		/delete-property/ led3;
-		/delete-property/ mcuboot-led0;
-		/delete-property/ pwm-led0;
-		/delete-property/ pwm-0;
-	};
-
-	/delete-node/ leds;
-	/delete-node/ pwm_leds;
-
-	keys {
-		/delete-node/ button_1;
-		/delete-node/ button_3;
+	/* Short TL_Key3 (J5 pin 13) to ground (J3 pin 24, 26, 28, 30) */
+	key_pool {
 		compatible = "gpio-keys";
-		key_1: button_1 {
-			gpios = <&gpiod 2 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
-		};
-		key_2: button_2 {
-			gpios = <&gpiod 7 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
-		};
-		key_3: button_3 {
-			gpios = <&gpiod 6 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
-		};
-		key_4: button_4 {
-			gpios = <&gpiof 6 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
-		};
 
-		key_matrix_col1: key_matrix_col1 {
-			gpios = <&gpiod 6 GPIO_ACTIVE_HIGH>;
-		};
-		key_matrix_col2: key_matrix_col2 {
-			gpios = <&gpiof 6 GPIO_ACTIVE_HIGH>;
-		};
-		key_matrix_row1: key_matrix_row1 {
-			gpios = <&gpiod 2 GPIO_PULL_DOWN>;
-		};
-		key_matrix_row2: key_matrix_row2 {
-			gpios = <&gpiod 7 GPIO_PULL_DOWN>;
+		inp {
+			gpios = <&gpiod 2 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>,
+					<&gpiod 7 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>;
 		};
 	};
-};
 
-&pwm0 {
-	status = "disabled";
+	key_matrix {
+		compatible = "gpio-keys";
+
+		col {
+			gpios = <&gpiod 6 GPIO_ACTIVE_HIGH>,
+					<&gpiof 6 GPIO_ACTIVE_HIGH>;
+		};
+
+		row {
+			gpios = <&gpiod 2 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)>,
+					<&gpiod 7 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)>;
+		};
+	};
 };
diff --git a/src/test_driver/tizen/README.md b/src/test_driver/tizen/README.md
index 559b756..080d9c7 100644
--- a/src/test_driver/tizen/README.md
+++ b/src/test_driver/tizen/README.md
@@ -12,7 +12,7 @@
 
 ```sh
 # Pull the image from hub.docker.com
-docker pull ghcr.io/project-chip/chip-build-tizen-qemu:35
+docker pull ghcr.io/project-chip/chip-build-tizen-qemu:46
 ```
 
 ## Building and Running Tests on QEMU
@@ -21,7 +21,7 @@
 
 ```sh
 docker run -it --rm --name chip-tizen-qemu \
-    ghcr.io/project-chip/chip-build-tizen-qemu:35 /bin/bash
+    ghcr.io/project-chip/chip-build-tizen-qemu:46 /bin/bash
 ```
 
 ### Clone the connectedhomeip repository