diff --git a/.github/workflows/telink-tl322x-build.yaml b/.github/workflows/telink-tl322x-build.yaml new file mode 100644 index 0000000000000..4a83acd3ad3f3 --- /dev/null +++ b/.github/workflows/telink-tl322x-build.yaml @@ -0,0 +1,157 @@ +name: Telink TL322x build examples + +on: pull_request + +jobs: + telink_build_examples: + runs-on: ubuntu-22.04 + name: Telink build examples + env: + ZEPHYR_SDK_VERSION: 0.15.2 + steps: + + - name: Install dependencies + run: | + sudo apt update + sudo apt install -y --no-install-recommends libdigest-sha-perl cmake python3 ninja-build + + - name: Setup Zephyr toolchain + run: | + mkdir ~/zephyr_sdk + wget -q -P ~/zephyr_sdk https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v"${ZEPHYR_SDK_VERSION}"/zephyr-sdk-"${ZEPHYR_SDK_VERSION}"_linux-x86_64.tar.gz + (cd ~/zephyr_sdk && wget -O - https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v"${ZEPHYR_SDK_VERSION}"/sha256.sum | shasum --check --ignore-missing) + tar xf ~/zephyr_sdk/zephyr-sdk-"${ZEPHYR_SDK_VERSION}"_linux-x86_64.tar.gz -C ~/zephyr_sdk + (cd ~/zephyr_sdk/zephyr-sdk-"${ZEPHYR_SDK_VERSION}" && ./setup.sh -t riscv64-zephyr-elf -c) + + - name: Checkout Zephyr + uses: actions/checkout@v3 + with: + ref: ${{ github.event.pull_request.head.sha }} + fetch-depth: 0 + + - name: West setup + run: | + pip install west + cd .. + west init -l zephyr + west update + west blobs fetch hal_telink + west zephyr-export + pip install -r zephyr/scripts/requirements.txt + + - name: Build TL322x samples/basic/blinky + run: | + cd .. + west build -b tl3228x -d build_blinky_tl322x zephyr/samples/basic/blinky -- -DCONFIG_COMPILER_WARNINGS_AS_ERRORS=y + + - name: Build TL322x samples/hello_world + run: | + cd .. + west build -b tl3228x -d build_hello_tl322x zephyr/samples/hello_world -- -DCONFIG_COMPILER_WARNINGS_AS_ERRORS=y + + - name: Build TL322x samples/basic/button + run: | + cd .. + west build -b tl3228x -d build_button_tl322x zephyr/samples/basic/button -- -DCONFIG_COMPILER_WARNINGS_AS_ERRORS=y + + - name: Build TL322x samples/sensor/sht3xd + run: | + cd .. + west build -b tl3228x -d build_sht3xd_tl322x zephyr/samples/sensor/sht3xd -- -DCONFIG_COMPILER_WARNINGS_AS_ERRORS=y + + - name: Build TL322x samples/drivers/adc + run: | + cd .. + west build -b tl3228x -d build_adc_tl322x zephyr/samples/drivers/adc -- -DCONFIG_COMPILER_WARNINGS_AS_ERRORS=y + + - name: Build TL322x samples/drivers/watchdog + run: | + cd .. + west build -b tl3228x -d build_watchdog_tl322x zephyr/samples/drivers/watchdog -- -DCONFIG_COMPILER_WARNINGS_AS_ERRORS=y + + - name: Build TL322x tests/drivers/flash/common + run: | + cd .. + west build -b tl3228x -d build_tests_flash_tl322x zephyr/tests/drivers/flash/common -- -DCONFIG_COMPILER_WARNINGS_AS_ERRORS=y + + - name: Build TL322x samples/drivers/spi_flash + run: | + cd .. + west build -b tl3228x -d build_spi_flash_tl322x zephyr/samples/drivers/spi_flash -- -DCONFIG_COMPILER_WARNINGS_AS_ERRORS=y + + - name: Build TL322x samples/basic/fade_led/ + run: | + cd .. + west build -b tl3228x -d build_fade_tl322x zephyr/samples/basic/fade_led/ -- -DCONFIG_COMPILER_WARNINGS_AS_ERRORS=y + + - name: Build TL322x bluetooth/peripheral_ht + run: | + cd .. + west build -b tl3228x -d build_peripheral_ht_tl322x zephyr/samples/bluetooth/peripheral_ht -- -DCONFIG_COMPILER_WARNINGS_AS_ERRORS=y + + - name: Build TL322x net/openthread/cli + run: | + cd .. + west build -b tl3228x -d build_ot_cli_tl322x zephyr/samples/net/openthread/cli -- -DCONFIG_COMPILER_WARNINGS_AS_ERRORS=y + + - name: Build TL322x net/openthread/coprocessor in RCP configuration with UART interface + run: | + cd .. + west build -b tl3228x -d build_ot_coprocessor_rcp_uart_tl322x zephyr/samples/net/openthread/coprocessor -- -DCONFIG_COMPILER_WARNINGS_AS_ERRORS=y -DOVERLAY_CONFIG=overlay-rcp.conf + + - name: Build TL322x subsys/usb/console for USB driver + run: | + cd .. + west build -b tl3228x -d build_usb_console_tl322x zephyr/samples/subsys/usb/console -- -DCONFIG_COMPILER_WARNINGS_AS_ERRORS=y + + - name: Build TL322x subsys/usb/cdc_acm for USB CDC + run: | + cd .. + west build -b tl3228x -d build_usb_cdc_acm_tl322x zephyr/samples/subsys/usb/cdc_acm -- -DCONFIG_COMPILER_WARNINGS_AS_ERRORS=y + + - name: Build TL322X net/openthread/coprocessor in RCP configuration with USB interface + run: | + cd .. + west build -b tl3228x -d build_ot_coprocessor_rcp_usb_tl322x zephyr/samples/net/openthread/coprocessor -- -DCONFIG_COMPILER_WARNINGS_AS_ERRORS=y -DDTC_OVERLAY_FILE="usb.overlay boards/tl3228x-dongle.overlay" -DOVERLAY_CONFIG=overlay-rcp-usb-telink.conf + + - name: Build TL322X crypto/mbedtls + run: | + cd .. + west build -b tl3228x -d build_crypto_mbedtls_tl322x zephyr/tests/crypto/mbedtls -- -DCONFIG_COMPILER_WARNINGS_AS_ERRORS=y -DCONFIG_MBEDTLS_ECP_C=y -DCONFIG_MBEDTLS_ECP_ALL_ENABLED=y + + - name: Build TL322X bootloader/mcuboot/boot for compressed LZMA image + run: | + cd .. + west build -b tl3228x -d build_mcuboot_tl322x_lzma bootloader/mcuboot/boot/zephyr -- -DCONFIG_COMPILER_WARNINGS_AS_ERRORS=y -DCONFIG_COMPRESS_LZMA=y -DCONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE=78000 -DCONFIG_BOOT_UPGRADE_ONLY=y + + - name: Build TL322X net/sockets/echo_client for OpenThread with PM deep-sleep + run: | + cd .. + west build -b tl3228x_retention -d build_ot_echo_client_pm_deep_tl3228x zephyr/samples/net/sockets/echo_client -- -DCONFIG_COMPILER_WARNINGS_AS_ERRORS=y -DOVERLAY_CONFIG=overlay-ot-sed.conf -DCONFIG_OPENTHREAD_NETWORKKEY=\"09:24:01:56:04:4a:45:0b:23:22:1e:0e:3b:0d:0e:61:2f:1b:2c:24\" -DCONFIG_PM=y -DCONFIG_SOC_SERIES_RISCV_TELINK_TLX_NON_RETENTION_RAM_CODE=y -DCONFIG_TELINK_TLX_2_WIRE_SPI_ENABLE=y + + - name: Collect artifacts + run: | + mkdir telink_build_artifacts + cp ../build_blinky_tl322x/zephyr/zephyr.bin telink_build_artifacts/tl322x_blinky.bin + cp ../build_hello_tl322x/zephyr/zephyr.bin telink_build_artifacts/tl322x_hello_world.bin + cp ../build_button_tl322x/zephyr/zephyr.bin telink_build_artifacts/tl322x_button.bin + cp ../build_sht3xd_tl322x/zephyr/zephyr.bin telink_build_artifacts/tl322x_sht3xd.bin + cp ../build_adc_tl322x/zephyr/zephyr.bin telink_build_artifacts/tl322x_adc.bin + cp ../build_watchdog_tl322x/zephyr/zephyr.bin telink_build_artifacts/tl322x_watchdog.bin + cp ../build_tests_flash_tl322x/zephyr/zephyr.bin telink_build_artifacts/tl322x_tests_flash.bin + cp ../build_spi_flash_tl322x/zephyr/zephyr.bin telink_build_artifacts/tl322x_spi_flash.bin + cp ../build_fade_tl322x/zephyr/zephyr.bin telink_build_artifacts/tl322x_tests_pwm.bin + cp ../build_peripheral_ht_tl322x/zephyr/zephyr.bin telink_build_artifacts/tl322x_peripheral_ht.bin + cp ../build_ot_cli_tl322x/zephyr/zephyr.bin telink_build_artifacts/tl322x_ot_cli.bin + cp ../build_ot_coprocessor_rcp_uart_tl322x/zephyr/zephyr.bin telink_build_artifacts/tl322x_ot_coprocessor_rcp_uart.bin + cp ../build_usb_console_tl322x/zephyr/zephyr.bin telink_build_artifacts/tl322x_usb_console.bin + cp ../build_usb_cdc_acm_tl322x/zephyr/zephyr.bin telink_build_artifacts/tl322x_usb_cdc_acm.bin + cp ../build_ot_coprocessor_rcp_usb_tl322x/zephyr/zephyr.bin telink_build_artifacts/tl322x_ot_coprocessor_rcp_usb.bin + cp ../build_crypto_mbedtls_tl322x/zephyr/zephyr.bin telink_build_artifacts/tl322x_mbedtls.bin + cp ../build_ot_echo_client_pm_deep_tl3228x/zephyr/zephyr.bin telink_build_artifacts/tl322x_ot_echo_client_pm_retention.bin + + - name: Publish artifacts + uses: actions/upload-artifact@v4 + with: + path: | + telink_build_artifacts/* diff --git a/.github/workflows/telink-tl322x-nds-build.yaml b/.github/workflows/telink-tl322x-nds-build.yaml new file mode 100644 index 0000000000000..9e278186125f1 --- /dev/null +++ b/.github/workflows/telink-tl322x-nds-build.yaml @@ -0,0 +1,159 @@ +# Copyright (c) 2025 Telink Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +name: Telink TL322X build examples using Andes GCC + +on: pull_request + +jobs: + telink_build_examples: + runs-on: ubuntu-22.04 + name: Telink build examples + env: + ZEPHYR_TOOLCHAIN_VARIANT: "andes-gcc" + ANDES_GCC_PATH: "~/nds-gcc/nds32le-elf-newlib-v5f" + steps: + + - name: Install dependencies + run: | + sudo apt update + sudo apt install -y --no-install-recommends libdigest-sha-perl cmake python3 ninja-build + + - name: Setup Andes toolchain + run: | + mkdir ~/nds-gcc + wget -q -P ~/nds-gcc https://doc.telink-semi.cn/Zephyr/binaries/public/tools/nds32le-elf-newlib-v5f.tar.gz + tar xf ~/nds-gcc/nds32le-elf-newlib-v5f.tar.gz -C ~/nds-gcc + + - name: Checkout Zephyr + uses: actions/checkout@v3 + with: + ref: ${{ github.event.pull_request.head.sha }} + fetch-depth: 0 + + - name: West setup + run: | + pip install west + cd .. + west init -l zephyr + west update + west blobs fetch hal_telink + west zephyr-export + pip install -r zephyr/scripts/requirements.txt + + - name: Build TL322x samples/basic/blinky + run: | + cd .. + west build -b tl3228x -d build_blinky_tl322x zephyr/samples/basic/blinky -- -DCONFIG_COMPILER_WARNINGS_AS_ERRORS=y + + - name: Build TL322x samples/hello_world + run: | + cd .. + west build -b tl3228x -d build_hello_tl322x zephyr/samples/hello_world -- -DCONFIG_COMPILER_WARNINGS_AS_ERRORS=y + + - name: Build TL322x samples/basic/button + run: | + cd .. + west build -b tl3228x -d build_button_tl322x zephyr/samples/basic/button -- -DCONFIG_COMPILER_WARNINGS_AS_ERRORS=y + + - name: Build TL322x samples/sensor/sht3xd + run: | + cd .. + west build -b tl3228x -d build_sht3xd_tl322x zephyr/samples/sensor/sht3xd -- -DCONFIG_COMPILER_WARNINGS_AS_ERRORS=y + + - name: Build TL322x samples/drivers/adc + run: | + cd .. + west build -b tl3228x -d build_adc_tl322x zephyr/samples/drivers/adc -- -DCONFIG_COMPILER_WARNINGS_AS_ERRORS=y + + - name: Build TL322x samples/drivers/watchdog + run: | + cd .. + west build -b tl3228x -d build_watchdog_tl322x zephyr/samples/drivers/watchdog -- -DCONFIG_COMPILER_WARNINGS_AS_ERRORS=y + + - name: Build TL322x tests/drivers/flash/common + run: | + cd .. + west build -b tl3228x -d build_tests_flash_tl322x zephyr/tests/drivers/flash/common -- -DCONFIG_COMPILER_WARNINGS_AS_ERRORS=y + + - name: Build TL322x samples/drivers/spi_flash + run: | + cd .. + west build -b tl3228x -d build_spi_flash_tl322x zephyr/samples/drivers/spi_flash -- -DCONFIG_COMPILER_WARNINGS_AS_ERRORS=y + + - name: Build TL322x samples/basic/fade_led/ + run: | + cd .. + west build -b tl3228x -d build_fade_tl322x zephyr/samples/basic/fade_led/ -- -DCONFIG_COMPILER_WARNINGS_AS_ERRORS=y + + - name: Build TL322x bluetooth/peripheral_ht + run: | + cd .. + west build -b tl3228x -d build_peripheral_ht_tl322x zephyr/samples/bluetooth/peripheral_ht -- -DCONFIG_COMPILER_WARNINGS_AS_ERRORS=y + + - name: Build TL322x net/openthread/cli + run: | + cd .. + west build -b tl3228x -d build_ot_cli_tl322x zephyr/samples/net/openthread/cli -- -DCONFIG_COMPILER_WARNINGS_AS_ERRORS=y + + - name: Build TL322x net/openthread/coprocessor in RCP configuration with UART interface + run: | + cd .. + west build -b tl3228x -d build_ot_coprocessor_rcp_uart_tl322x zephyr/samples/net/openthread/coprocessor -- -DCONFIG_COMPILER_WARNINGS_AS_ERRORS=y -DOVERLAY_CONFIG=overlay-rcp.conf + + - name: Build TL322x subsys/usb/console for USB driver + run: | + cd .. + west build -b tl3228x -d build_usb_console_tl322x zephyr/samples/subsys/usb/console -- -DCONFIG_COMPILER_WARNINGS_AS_ERRORS=y + + - name: Build TL322x subsys/usb/cdc_acm for USB CDC + run: | + cd .. + west build -b tl3228x -d build_usb_cdc_acm_tl322x zephyr/samples/subsys/usb/cdc_acm -- -DCONFIG_COMPILER_WARNINGS_AS_ERRORS=y + + - name: Build TL322X net/openthread/coprocessor in RCP configuration with USB interface + run: | + cd .. + west build -b tl3228x -d build_ot_coprocessor_rcp_usb_tl322x zephyr/samples/net/openthread/coprocessor -- -DCONFIG_COMPILER_WARNINGS_AS_ERRORS=y -DDTC_OVERLAY_FILE="usb.overlay boards/tl3228x-dongle.overlay" -DOVERLAY_CONFIG=overlay-rcp-usb-telink.conf + + - name: Build TL322X crypto/mbedtls + run: | + cd .. + west build -b tl3228x -d build_crypto_mbedtls_tl322x zephyr/tests/crypto/mbedtls -- -DCONFIG_COMPILER_WARNINGS_AS_ERRORS=y -DCONFIG_MBEDTLS_ECP_C=y -DCONFIG_MBEDTLS_ECP_ALL_ENABLED=y + + - name: Build TL322X bootloader/mcuboot/boot for compressed LZMA image + run: | + cd .. + west build -b tl3228x -d build_mcuboot_tl322x_lzma bootloader/mcuboot/boot/zephyr -- -DCONFIG_COMPILER_WARNINGS_AS_ERRORS=y -DCONFIG_COMPRESS_LZMA=y -DCONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE=78000 -DCONFIG_BOOT_UPGRADE_ONLY=y + + - name: Build TL322X net/sockets/echo_client for OpenThread with PM deep-sleep + run: | + cd .. + west build -b tl3228x_retention -d build_ot_echo_client_pm_deep_tl3228x zephyr/samples/net/sockets/echo_client -- -DCONFIG_COMPILER_WARNINGS_AS_ERRORS=y -DOVERLAY_CONFIG=overlay-ot-sed.conf -DCONFIG_OPENTHREAD_NETWORKKEY=\"09:24:01:56:04:4a:45:0b:23:22:1e:0e:3b:0d:0e:61:2f:1b:2c:24\" -DCONFIG_PM=y -DCONFIG_SOC_SERIES_RISCV_TELINK_TLX_NON_RETENTION_RAM_CODE=y -DCONFIG_TELINK_TLX_2_WIRE_SPI_ENABLE=y + + - name: Collect artifacts + run: | + mkdir telink_build_artifacts + cp ../build_blinky_tl322x/zephyr/zephyr.bin telink_build_artifacts/tl322x_blinky.bin + cp ../build_hello_tl322x/zephyr/zephyr.bin telink_build_artifacts/tl322x_hello_world.bin + cp ../build_button_tl322x/zephyr/zephyr.bin telink_build_artifacts/tl322x_button.bin + cp ../build_sht3xd_tl322x/zephyr/zephyr.bin telink_build_artifacts/tl322x_sht3xd.bin + cp ../build_adc_tl322x/zephyr/zephyr.bin telink_build_artifacts/tl322x_adc.bin + cp ../build_watchdog_tl322x/zephyr/zephyr.bin telink_build_artifacts/tl322x_watchdog.bin + cp ../build_tests_flash_tl322x/zephyr/zephyr.bin telink_build_artifacts/tl322x_tests_flash.bin + cp ../build_spi_flash_tl322x/zephyr/zephyr.bin telink_build_artifacts/tl322x_spi_flash.bin + cp ../build_fade_tl322x/zephyr/zephyr.bin telink_build_artifacts/tl322x_tests_pwm.bin + cp ../build_peripheral_ht_tl322x/zephyr/zephyr.bin telink_build_artifacts/tl322x_peripheral_ht.bin + cp ../build_ot_cli_tl322x/zephyr/zephyr.bin telink_build_artifacts/tl322x_ot_cli.bin + cp ../build_ot_coprocessor_rcp_uart_tl322x/zephyr/zephyr.bin telink_build_artifacts/tl322x_ot_coprocessor_rcp_uart.bin + cp ../build_usb_console_tl322x/zephyr/zephyr.bin telink_build_artifacts/tl322x_usb_console.bin + cp ../build_usb_cdc_acm_tl322x/zephyr/zephyr.bin telink_build_artifacts/tl322x_usb_cdc_acm.bin + cp ../build_ot_coprocessor_rcp_usb_tl322x/zephyr/zephyr.bin telink_build_artifacts/tl322x_ot_coprocessor_rcp_usb.bin + cp ../build_crypto_mbedtls_tl322x/zephyr/zephyr.bin telink_build_artifacts/tl322x_mbedtls.bin + cp ../build_ot_echo_client_pm_deep_tl3228x/zephyr/zephyr.bin telink_build_artifacts/tl322x_ot_echo_client_pm_retention.bin + + - name: Publish artifacts + uses: actions/upload-artifact@v4 + with: + path: | + telink_build_artifacts/* diff --git a/.github/workflows/telink-tl323x-build.yaml b/.github/workflows/telink-tl323x-build.yaml new file mode 100644 index 0000000000000..f2663672d8e20 --- /dev/null +++ b/.github/workflows/telink-tl323x-build.yaml @@ -0,0 +1,157 @@ +name: Telink TL323x build examples + +on: pull_request + +jobs: + telink_build_examples: + runs-on: ubuntu-22.04 + name: Telink build examples + env: + ZEPHYR_SDK_VERSION: 0.15.2 + steps: + + - name: Install dependencies + run: | + sudo apt update + sudo apt install -y --no-install-recommends libdigest-sha-perl cmake python3 ninja-build + + - name: Setup Zephyr toolchain + run: | + mkdir ~/zephyr_sdk + wget -q -P ~/zephyr_sdk https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v"${ZEPHYR_SDK_VERSION}"/zephyr-sdk-"${ZEPHYR_SDK_VERSION}"_linux-x86_64.tar.gz + (cd ~/zephyr_sdk && wget -O - https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v"${ZEPHYR_SDK_VERSION}"/sha256.sum | shasum --check --ignore-missing) + tar xf ~/zephyr_sdk/zephyr-sdk-"${ZEPHYR_SDK_VERSION}"_linux-x86_64.tar.gz -C ~/zephyr_sdk + (cd ~/zephyr_sdk/zephyr-sdk-"${ZEPHYR_SDK_VERSION}" && ./setup.sh -t riscv64-zephyr-elf -c) + + - name: Checkout Zephyr + uses: actions/checkout@v3 + with: + ref: ${{ github.event.pull_request.head.sha }} + fetch-depth: 0 + + - name: West setup + run: | + pip install west + cd .. + west init -l zephyr + west update + west blobs fetch hal_telink + west zephyr-export + pip install -r zephyr/scripts/requirements.txt + + - name: Build TL323x samples/basic/blinky + run: | + cd .. + west build -b tl3238x -d build_blinky_tl323x zephyr/samples/basic/blinky -- -DCONFIG_COMPILER_WARNINGS_AS_ERRORS=y + + - name: Build TL323x samples/hello_world + run: | + cd .. + west build -b tl3238x -d build_hello_tl323x zephyr/samples/hello_world -- -DCONFIG_COMPILER_WARNINGS_AS_ERRORS=y + + - name: Build TL323x samples/basic/button + run: | + cd .. + west build -b tl3238x -d build_button_tl323x zephyr/samples/basic/button -- -DCONFIG_COMPILER_WARNINGS_AS_ERRORS=y + + - name: Build TL323x samples/sensor/sht3xd + run: | + cd .. + west build -b tl3238x -d build_sht3xd_tl323x zephyr/samples/sensor/sht3xd -- -DCONFIG_COMPILER_WARNINGS_AS_ERRORS=y + + - name: Build TL323x samples/drivers/adc + run: | + cd .. + west build -b tl3238x -d build_adc_tl323x zephyr/samples/drivers/adc -- -DCONFIG_COMPILER_WARNINGS_AS_ERRORS=y + + - name: Build TL323x samples/drivers/watchdog + run: | + cd .. + west build -b tl3238x -d build_watchdog_tl323x zephyr/samples/drivers/watchdog -- -DCONFIG_COMPILER_WARNINGS_AS_ERRORS=y + + - name: Build TL323x tests/drivers/flash/common + run: | + cd .. + west build -b tl3238x -d build_tests_flash_tl323x zephyr/tests/drivers/flash/common -- -DCONFIG_COMPILER_WARNINGS_AS_ERRORS=y + + - name: Build TL323x samples/drivers/spi_flash + run: | + cd .. + west build -b tl3238x -d build_spi_flash_tl323x zephyr/samples/drivers/spi_flash -- -DCONFIG_COMPILER_WARNINGS_AS_ERRORS=y + + - name: Build TL323x samples/basic/fade_led/ + run: | + cd .. + west build -b tl3238x -d build_fade_tl323x zephyr/samples/basic/fade_led/ -- -DCONFIG_COMPILER_WARNINGS_AS_ERRORS=y + + - name: Build TL323x bluetooth/peripheral_ht + run: | + cd .. + west build -b tl3238x -d build_peripheral_ht_tl323x zephyr/samples/bluetooth/peripheral_ht -- -DCONFIG_COMPILER_WARNINGS_AS_ERRORS=y + + - name: Build TL323x net/openthread/cli + run: | + cd .. + west build -b tl3238x -d build_ot_cli_tl323x zephyr/samples/net/openthread/cli -- -DCONFIG_COMPILER_WARNINGS_AS_ERRORS=y + + - name: Build TL323x net/openthread/coprocessor in RCP configuration with UART interface + run: | + cd .. + west build -b tl3238x -d build_ot_coprocessor_rcp_uart_tl323x zephyr/samples/net/openthread/coprocessor -- -DCONFIG_COMPILER_WARNINGS_AS_ERRORS=y -DOVERLAY_CONFIG=overlay-rcp.conf + + - name: Build TL323x subsys/usb/console for USB driver + run: | + cd .. + west build -b tl3238x -d build_usb_console_tl323x zephyr/samples/subsys/usb/console -- -DCONFIG_COMPILER_WARNINGS_AS_ERRORS=y + + - name: Build TL323x subsys/usb/cdc_acm for USB CDC + run: | + cd .. + west build -b tl3238x -d build_usb_cdc_acm_tl323x zephyr/samples/subsys/usb/cdc_acm -- -DCONFIG_COMPILER_WARNINGS_AS_ERRORS=y + + - name: Build TL323X net/openthread/coprocessor in RCP configuration with USB interface + run: | + cd .. + west build -b tl3238x -d build_ot_coprocessor_rcp_usb_tl323x zephyr/samples/net/openthread/coprocessor -- -DCONFIG_COMPILER_WARNINGS_AS_ERRORS=y -DDTC_OVERLAY_FILE="usb.overlay boards/tl3238x-dongle.overlay" -DOVERLAY_CONFIG=overlay-rcp-usb-telink.conf + + - name: Build TL323X crypto/mbedtls + run: | + cd .. + west build -b tl3238x -d build_crypto_mbedtls_tl323x zephyr/tests/crypto/mbedtls -- -DCONFIG_COMPILER_WARNINGS_AS_ERRORS=y -DCONFIG_MBEDTLS_ECP_C=y -DCONFIG_MBEDTLS_ECP_ALL_ENABLED=y + + - name: Build TL323X bootloader/mcuboot/boot for compressed LZMA image + run: | + cd .. + west build -b tl3238x -d build_mcuboot_tl323x_lzma bootloader/mcuboot/boot/zephyr -- -DCONFIG_COMPILER_WARNINGS_AS_ERRORS=y -DCONFIG_COMPRESS_LZMA=y -DCONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE=78000 -DCONFIG_BOOT_UPGRADE_ONLY=y + + - name: Build TL323X net/sockets/echo_client for OpenThread with PM deep-sleep + run: | + cd .. + west build -b tl3238x_retention -d build_ot_echo_client_pm_deep_tl3238x zephyr/samples/net/sockets/echo_client -- -DCONFIG_COMPILER_WARNINGS_AS_ERRORS=y -DOVERLAY_CONFIG=overlay-ot-sed.conf -DCONFIG_OPENTHREAD_NETWORKKEY=\"09:24:01:56:04:4a:45:0b:23:22:1e:0e:3b:0d:0e:61:2f:1b:2c:24\" -DCONFIG_PM=y -DCONFIG_SOC_SERIES_RISCV_TELINK_TLX_NON_RETENTION_RAM_CODE=y -DCONFIG_TELINK_TLX_2_WIRE_SPI_ENABLE=y + + - name: Collect artifacts + run: | + mkdir telink_build_artifacts + cp ../build_blinky_tl323x/zephyr/zephyr.bin telink_build_artifacts/tl323x_blinky.bin + cp ../build_hello_tl323x/zephyr/zephyr.bin telink_build_artifacts/tl323x_hello_world.bin + cp ../build_button_tl323x/zephyr/zephyr.bin telink_build_artifacts/tl323x_button.bin + cp ../build_sht3xd_tl323x/zephyr/zephyr.bin telink_build_artifacts/tl323x_sht3xd.bin + cp ../build_adc_tl323x/zephyr/zephyr.bin telink_build_artifacts/tl323x_adc.bin + cp ../build_watchdog_tl323x/zephyr/zephyr.bin telink_build_artifacts/tl323x_watchdog.bin + cp ../build_tests_flash_tl323x/zephyr/zephyr.bin telink_build_artifacts/tl323x_tests_flash.bin + cp ../build_spi_flash_tl323x/zephyr/zephyr.bin telink_build_artifacts/tl323x_spi_flash.bin + cp ../build_fade_tl323x/zephyr/zephyr.bin telink_build_artifacts/tl323x_tests_pwm.bin + cp ../build_peripheral_ht_tl323x/zephyr/zephyr.bin telink_build_artifacts/tl323x_peripheral_ht.bin + cp ../build_ot_cli_tl323x/zephyr/zephyr.bin telink_build_artifacts/tl323x_ot_cli.bin + cp ../build_ot_coprocessor_rcp_uart_tl323x/zephyr/zephyr.bin telink_build_artifacts/tl323x_ot_coprocessor_rcp_uart.bin + cp ../build_usb_console_tl323x/zephyr/zephyr.bin telink_build_artifacts/tl323x_usb_console.bin + cp ../build_usb_cdc_acm_tl323x/zephyr/zephyr.bin telink_build_artifacts/tl323x_usb_cdc_acm.bin + cp ../build_ot_coprocessor_rcp_usb_tl323x/zephyr/zephyr.bin telink_build_artifacts/tl323x_ot_coprocessor_rcp_usb.bin + cp ../build_crypto_mbedtls_tl323x/zephyr/zephyr.bin telink_build_artifacts/tl323x_mbedtls.bin + cp ../build_ot_echo_client_pm_deep_tl3238x/zephyr/zephyr.bin telink_build_artifacts/tl323x_ot_echo_client_pm_retention.bin + + - name: Publish artifacts + uses: actions/upload-artifact@v4 + with: + path: | + telink_build_artifacts/* diff --git a/CMakeLists.txt b/CMakeLists.txt index 4ea64339f6d0f..c198e8158652c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1646,7 +1646,7 @@ if(CONFIG_OUTPUT_DISASSEMBLE_ALL) list(APPEND post_build_commands COMMAND $ - $ + $ -x ${disassembly_type} $${KERNEL_ELF_NAME} $${KERNEL_LST_NAME} diff --git a/boards/riscv/tl322x/Kconfig.board b/boards/riscv/tl322x/Kconfig.board new file mode 100644 index 0000000000000..50370801d7df8 --- /dev/null +++ b/boards/riscv/tl322x/Kconfig.board @@ -0,0 +1,10 @@ +# Copyright (c) 2024 Telink Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_TL3228X + bool "Telink TL322X Platform" + depends on SOC_RISCV_TELINK_TL322X + +config BOARD_TL3228X_RETENTION + bool "Telink TL322X Platform with retention" + depends on SOC_RISCV_TELINK_TL322X diff --git a/boards/riscv/tl322x/Kconfig.defconfig b/boards/riscv/tl322x/Kconfig.defconfig new file mode 100644 index 0000000000000..25f37b038d26f --- /dev/null +++ b/boards/riscv/tl322x/Kconfig.defconfig @@ -0,0 +1,65 @@ +# Copyright (c) 2024 Telink Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_TL3228X + +config BOARD + default "tl3228x" + +endif + +if BOARD_TL3228X_RETENTION + +config BOARD + default "tl3228x_retention" + +endif + +config HEAP_MEM_POOL_SIZE + default 4096 + +if BOARD_TL3228X || BOARD_TL3228X_RETENTION + +config SOC_FLASH_TELINK_TLX + default y if FLASH + +config USB_TELINK_TLX + default n + +if BT + +# BLE Controller SDK from hal_telink requires +# Telink's toolchain with FPU support +config FPU + default y if "$(ZEPHYR_TOOLCHAIN_VARIANT)" != "zephyr" + +config BT_HCI_ACL_FLOW_CONTROL + default n + +choice BT_HCI_BUS_TYPE + default BT_TLX +endchoice + +endif # BT + +# Workaround for not being able to have commas in macro arguments +DT_CHOSEN_Z_CODE_PARTITION := zephyr,code-partition + +config FLASH_LOAD_OFFSET + default $(dt_chosen_reg_addr_hex,$(DT_CHOSEN_Z_CODE_PARTITION)) if USE_DT_CODE_PARTITION + +# Buffer for image writter shall be less(multiple of access alignment) or +# equal to flash page. tl3228x boards use external P25Q16 IC as +# flesh memory. Flash page size of the IC is 256 bytes. So that, it is +# maximum image writer buffer size for such kind of boards. +config IMG_BLOCK_BUF_SIZE + default 256 if MCUBOOT_IMG_MANAGER + +# MCU boot application options +config MCUBOOT_SIGNATURE_KEY_FILE + default "bootloader/mcuboot/root-rsa-2048.pem" if BOOTLOADER_MCUBOOT + +config MCUBOOT_EXTRA_IMGTOOL_ARGS + default "--max-sectors 4096" if BOOTLOADER_MCUBOOT + +endif diff --git a/boards/riscv/tl322x/board.cmake b/boards/riscv/tl322x/board.cmake new file mode 100644 index 0000000000000..63d04e1dc719c --- /dev/null +++ b/boards/riscv/tl322x/board.cmake @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: Apache-2.0 + +board_runner_args(bdt_tool) +include(${ZEPHYR_BASE}/boards/common/bdt_tool.board.cmake) diff --git a/boards/riscv/tl322x/doc/img/tl3228x.jpg b/boards/riscv/tl322x/doc/img/tl3228x.jpg new file mode 100644 index 0000000000000..4284664d5f7cd Binary files /dev/null and b/boards/riscv/tl322x/doc/img/tl3228x.jpg differ diff --git a/boards/riscv/tl322x/doc/img/tl3228x_block_diagram.png b/boards/riscv/tl322x/doc/img/tl3228x_block_diagram.png new file mode 100644 index 0000000000000..9591f39ae866b Binary files /dev/null and b/boards/riscv/tl322x/doc/img/tl3228x_block_diagram.png differ diff --git a/boards/riscv/tl322x/doc/index.rst b/boards/riscv/tl322x/doc/index.rst new file mode 100644 index 0000000000000..a2d22f24f8523 --- /dev/null +++ b/boards/riscv/tl322x/doc/index.rst @@ -0,0 +1,259 @@ +.. _tl3228x: + +Telink TL3228X +##################### + +Overview +******** + +The TL3228X Generic Starter Kit is a hardware platform which +can be used to verify the `Telink TLX series chipset` and develop applications +for several 2.4 GHz air interface standards including Bluetooth low energy, +Zigbee 3.0, Homekit, 6LoWPAN, Thread and 2.4 Ghz proprietary. + +.. figure:: img/tl3228x.jpg + :align: center + :alt: TL3228X + +.. More information about the board can be found at the `Telink TL3228X Generic Starter Kit Hardware Guide`_ website. + +Hardware +******** + +TL3228X is a single chip SoC for Bluetooth low energy and 802.15.4. The embedded 2.4GHz transceiver +supports Bluetooth low energy, 802.15.4 as well as 2.4GHz proprietary operation. +The TL3228X integrates a powerful 32-bit RISC-V MCU, 512 or 256 KB SRAM including up to 256 KB retention SRAM, +2 MB or 1 MB embedded flash, 12-bit ADC, PWM, flexible IO interfaces, and other peripheral blocks for IoT +applications. + +.. figure:: img/tl3228x_block_diagram.png + :align: center + :alt: TL3228X_SOC + +The TL3228X default board configuration provides the following hardware components: + +- RF conducted antenna +- 2 MB External SPI Flash memory with reset button. (Possible to mount 1/2/4 MB) +- Chip reset button +- USB type-C interface +- 4-wire JTAG +- Key matrix up to 4 keys +- 4 LEDs +- 1 infra-red LED +- 1 analogue microphone with line-in function (switching by a jumper in microphone path) +- Dual Digital microphone + +Supported Features +================== + +The Zephyr TL3228X board configuration supports the following hardware features: + ++----------------+------------+------------------------------+ +| Interface | Controller | Driver/Component | ++================+============+==============================+ +| PLIC | on-chip | interrupt_controller | ++----------------+------------+------------------------------+ +| RISC-V Machine | on-chip | timer | +| Timer (32 KHz) | | | ++----------------+------------+------------------------------+ +| PINCTRL | on-chip | pinctrl | ++----------------+------------+------------------------------+ +| GPIO | on-chip | gpio | ++----------------+------------+------------------------------+ +| UART | on-chip | serial | ++----------------+------------+------------------------------+ +| PWM | on-chip | pwm | ++----------------+------------+------------------------------+ +| TRNG | on-chip | entropy | ++----------------+------------+------------------------------+ +| FLASH (MSPI) | on-chip | flash | ++----------------+------------+------------------------------+ +| RADIO | on-chip | Bluetooth, | +| | | ieee802154, OpenThread | ++----------------+------------+------------------------------+ +| SPI (Master) | on-chip | spi | ++----------------+------------+------------------------------+ +| I2C (Master) | on-chip | i2c | ++----------------+------------+------------------------------+ +| ADC | on-chip | adc | ++----------------+------------+------------------------------+ +| USB (device) | on-chip | usb_dc | ++----------------+------------+------------------------------+ +| PKE | on-chip | mbedtls | ++----------------+------------+------------------------------+ + +Board includes power management module: Embedded LDO and DCDC, Battery monitor for low battery voltage detection, +Brownout detection/shutdown and Power-On-Reset, Deep sleep with external wakeup (without SRAM retention), +Deep sleep with RTC and SRAM retention (32 KB SRAM retention). + +Limitations +----------- + +- Maximum 3 GPIO ports could be configured to generate external interrupts simultaneously. All ports should use different IRQ numbers. +- DMA mode is not supported by I2C, SPI and Serial Port. +- SPI Slave mode is not implemented. +- I2C Slave mode is not implemented. +- Bluetooth is not compatible with deep-sleep mode. Only suspend is allowed when Bluetooth is active. +- USB working only in active mode (No power down supported). +- During deep-sleep all GPIO's are in Hi-Z mode. +- Shell is not compatible with sleep modes. + +Default configuration and IOs +============================= + +System Clock +------------ + +The TL3228X board is configured to use the 24 MHz external crystal oscillator +with the on-chip PLL/DIV generating the 60 MHz system clock. +The following values also could be assigned to the system clock in the board DTS file +(``boards/riscv/tl322x/tl3228x-common.dtsi``): + +- 40000000 +- 48000000 +- 60000000 +- 80000000 +- 120000000 + +.. code-block:: + + &cpu0 { + clock-frequency = <60000000>; + }; + +PINs Configuration +------------------ + +The TL3228X SoC has five GPIO controllers (PORT_A to PORT_F), and the next are +currently enabled: + +- LED0 (blue): PC0, LED1 (green): PC2, LED2 (white): PC3, LED3 (red): PC1 +- Key Matrix SW3: PD4_PD5, SW4: PD4_PD7, SW5: PD6_PD5, SW6: PD6_PD7 + +Peripheral's pins on the SoC are mapped to the following GPIO pins in the +``boards/riscv/tl322x/tl3228x-common.dtsi`` file: + +- UART0 TX: PB2, RX: PB3 +- PWM Channel 0: PB7 +- LSPI CLK: PE1, MISO: PE3, MOSI: PE2 +- GSPI CLK: PF4, MISO: PF6, MOSI: PF7 +- I2C SCL: PE6, SDA: PE7 + +Serial Port +----------- + +The Zephyr console output is assigned to UART0. +The default settings are 115200 8N1. + +USB COM Port (ACM) as Serial Port Configuration +----------------------------------------------- + +To use the USB COM port (ACM) instead of UART, follow these steps: + +1. Add the following configuration to your project: + +.. code-block:: none + + CONFIG_LOG=y + CONFIG_USB_DEVICE_STACK=y + CONFIG_USB_DEVICE_INITIALIZE_AT_BOOT=n + CONFIG_USB_CDC_ACM_LOG_LEVEL_OFF=y + +2. Include the following overlay configuration: + +.. code-block:: dts + + / { + chosen { + zephyr,console = &cdc_acm_uart0; + zephyr,shell-uart = &cdc_acm_uart0; + }; + }; + + &zephyr_udc0 { + cdc_acm_uart0: cdc_acm_uart0 { + compatible = "zephyr,cdc-acm-uart"; + }; + }; + +3. Connect the USB cable to your device. A new ACM serial device should appear in your system (e.g., ``/dev/ttyACM0`` on Linux or a COM port on Windows). +4. Use your preferred terminal application (like ``minicom``, ``screen``, or ``PuTTY``) to connect to the newly detected ACM serial device. + +5. In your source code, ensure the following header is included and the USB device stack is initialized: + +.. code-block:: c + + #ifdef CONFIG_USB_DEVICE_STACK + #include + #endif + #ifdef CONFIG_USB_DEVICE_STACK + usb_enable(NULL); + #endif + +Programming and debugging +************************* + +Building +======== + +.. important:: + + These instructions assume you've set up a development environment as + described in the `Zephyr Getting Started Guide`_. + +To build applications using the default RISC-V toolchain from Zephyr SDK, just run the west build command. +Here is an example for the "hello_world" application. + +.. code-block:: console + + # From the root of the zephyr repository + west build -b tl3228x samples/hello_world + +Open a serial terminal with the following settings: + +- Speed: 115200 +- Data: 8 bits +- Parity: None +- Stop bits: 1 + +Flash the board, reset and observe the following messages on the selected +serial port: + +.. code-block:: console + + *** Booting Zephyr OS build zephyr-v3.3.0-xxxx-xxxxxxxxxxxxx *** + Hello World! tl3228x + + +Flashing +======== + +To flash the TL3228X board see the sources below: + +- `Burning and Debugging Tools for all Series`_ + +It is also possible to use the west flash command. Download BDT tool for Linux `Burning and Debugging Tool for Linux`_ or +`Burning and Debugging Tool for Windows`_ and extract archive into some directory you wish TELINK_BDT_BASE_DIR + +- Now you should be able to run the west flash command with the BDT path specified (TELINK_BDT_BASE_DIR). + +.. code-block:: console + + west flash --bdt-path=$TELINK_BDT_BASE_DIR --erase + +- You can also run the west flash command without BDT path specification if TELINK_BDT_BASE_DIR is in your environment (.bashrc). + +.. code-block:: console + + export TELINK_BDT_BASE_DIR="/opt/telink_bdt/" + + +References +********** + +.. target-notes:: + +.. _Burning and Debugging Tools for all Series: https://wiki.telink-semi.cn/wiki/IDE-and-Tools/Burning-and-Debugging-Tools-for-all-Series/ +.. _Burning and Debugging Tool for Linux: https://wiki.telink-semi.cn/tools_and_sdk/Tools/BDT/Telink_libusb_BDT-Linux-X64-V1.6.0.zip +.. _Burning and Debugging Tool for Windows: https://wiki.telink-semi.cn/tools_and_sdk/Tools/BDT/BDT.zip +.. _Zephyr Getting Started Guide: https://docs.zephyrproject.org/latest/getting_started/index.html diff --git a/boards/riscv/tl322x/tl3228x-common.dtsi b/boards/riscv/tl322x/tl3228x-common.dtsi new file mode 100644 index 0000000000000..65ae2864af1e3 --- /dev/null +++ b/boards/riscv/tl322x/tl3228x-common.dtsi @@ -0,0 +1,264 @@ +/* + * Copyright (c) 2024 Telink Semiconductor + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include +#include +#include "tl3228x-pinctrl.dtsi" + +/ { + model = "telink,tl322x"; + compatible = "telink,tl3228x"; + + aliases { + led0 = &led_red; + led1 = &led_blue; + led2 = &led_white; + led3 = &led_green; + sw0 = &key_1; + sw1 = &key_2; + sw2 = &key_3; + sw3 = &key_4; + pwm-led0 = &pwm_led_green; + pwm-0 = &pwm0; + watchdog0 = &wdt; + mcuboot-button0 = &key_dfu; + mcuboot-led0 = &led_red; + }; + + leds { + compatible = "gpio-leds"; + + led_red: led_0 { + gpios = <&gpioc 4 GPIO_ACTIVE_HIGH>; + label = "LED Red"; + }; + + led_blue: led_1 { + gpios = <&gpioc 5 GPIO_ACTIVE_HIGH>; + label = "LED Blue"; + }; + + led_white: led_2 { + gpios = <&gpioc 6 GPIO_ACTIVE_HIGH>; + label = "LED White"; + }; + + led_green: led_3 { + gpios = <&gpioc 7 GPIO_ACTIVE_HIGH>; + label = "LED Green"; + }; + }; + + pwm_leds { + compatible = "pwm-leds"; + + pwm_led_green: pwm_led_0 { + pwms = <&pwm0 0 PWM_MSEC(20) PWM_POLARITY_NORMAL>; + label = "PWM LED Green"; + }; + }; + + keys { + compatible = "gpio-keys"; + key_1: button_1 { + label = "User KEY1"; + gpios = <&gpiog 3 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + }; + key_2: button_2 { + label = "User KEY2"; + gpios = <&gpiog 2 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + }; + key_3: button_3 { + label = "User KEY3"; + gpios = <&gpiog 1 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + }; + key_4: button_4 { + label = "User KEY4"; + gpios = <&gpiog 0 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + }; + key_dfu: button_dfu { + label = "USB DFU"; + gpios = <&gpiob 0 GPIO_PULL_DOWN>; + }; + }; + + key_pool { + compatible = "gpio-keys"; + + inp { + gpios = <&gpiog 3 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>, + <&gpiog 2 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + }; + }; + + key_matrix { + compatible = "gpio-keys"; + + col { + gpios = <&gpiog 1 GPIO_ACTIVE_HIGH>, + <&gpiog 0 GPIO_ACTIVE_HIGH>; + }; + + row { + gpios = <&gpiog 3 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)>, + <&gpiog 2 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)>; + }; + }; + + chosen { + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + zephyr,sram = &ram_dlm; + zephyr,flash = &flash; + zephyr,flash-controller = &flash_mspi; + zephyr,entropy = &trng0; + zephyr,code-partition = &slot0_partition; + zephyr,ieee802154 = &ieee802154; + }; +}; + +&cpu0 { + clock-frequency = <64000000>; /* TL_BLE_SDK use 64M CCLK by default */ +}; + +&ram_ilm { + reg = <0x00000000 0x00080000>; +}; + +&ram_dlm { + reg = <0x00080000 0x00020000>; +}; + +&flash { + reg = <0x20000000 0x100000>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x00000000 0x20000>; + }; + slot0_partition: partition@20000 { + label = "image-0"; + reg = <0x20000 0x68000>; + }; + slot1_partition: partition@88000 { + label = "image-1"; + reg = <0x88000 0x68000>; + }; + scratch_partition: partition@f0000 { + label = "image-scratch"; + reg = <0xf0000 0x4000>; + }; + storage_partition: partition@f4000 { + label = "storage"; + reg = <0xf4000 0x0000a000>; + }; + + /* region <0xfe000 0x2000> is used for Telink TLx RF parameters */ + /* For 1M MCU - the partition address is 0xfe000 */ + /* For 2M MCU - the partition address is 0x1fe000 */ + /* For 4M MCU - the partition address is 0x3fe000 */ + /* For 16M MCU - the partition address is 0xffe000 */ + vendor_partition: partition@fe000 { + label = "vendor-data"; + reg = <0xfe000 0x2000>; + }; + }; +}; + +&gpiob { + status = "okay"; +}; + +&gpioc { + status = "okay"; +}; + +&gpiod { + interrupts = <47 1>; + status = "okay"; +}; + +&gpioe { + status = "okay"; +}; + +&gpiof { + interrupts = <48 1>; + status = "okay"; +}; + +&gpiog { + interrupts = <49 1>; + status = "okay"; +}; + +&gpioh { + status = "okay"; +}; + +&gpioi { + status = "okay"; +}; + +&uart0 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart0_tx_pa0_default &uart0_rx_pa1_default>; + pinctrl-names = "default"; +}; + +&trng0 { + status = "okay"; +}; + +&ieee802154 { + status = "okay"; +}; + +&pwm0 { + status = "okay"; + clock-frequency = <300000>; + pinctrl-ch0 = <&pwm_ch0_pc7_default>; +}; + + +&gspi { + status = "okay"; + cs0-pin = "GPIO_PH3"; + pinctrl-0 = <&gspi_clk_ph4_default &gspi_miso_ph6_default &gspi_mosi_ph7_default>; + pinctrl-names = "default"; +}; + +&i2c { + status = "okay"; + clock-frequency = ; + pinctrl-0 = <&i2c_scl_pe0_default &i2c_sda_pe1_default>; + pinctrl-names = "default"; +}; + +&adc { + status = "okay"; + vref-internal-mv = <1200>; + sample-freq = ; + pinctrl-0 = <&adc_pc1_default>; + pinctrl-names = "default"; +}; + +zephyr_udc0: &usbd { + compatible = "telink,tl322x-usbd"; + status = "okay"; +}; + +&wdt { + status = "okay"; +}; diff --git a/boards/riscv/tl322x/tl3228x-pinctrl.dtsi b/boards/riscv/tl322x/tl3228x-pinctrl.dtsi new file mode 100644 index 0000000000000..8df03f1e189c3 --- /dev/null +++ b/boards/riscv/tl322x/tl3228x-pinctrl.dtsi @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2024 Telink Semiconductor + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +&pinctrl { + /* Set pad-mul-sel register value. + * Note: Pins functions below (pinmux = <...>) depend on this value. + */ + pad-mul-sel = <1>; + + /* UART0: TX(PA0), RX(PA1), RTS(PB4), CTS(PB6) */ + + uart0_tx_pa0_default: uart0_tx_pa0_default { + pinmux = ; + }; + uart0_rx_pa1_default: uart0_rx_pa1_default { + pinmux = ; + }; + uart0_rts_pb4_default: uart0_rts_pb4_default { + pinmux = ; + }; + uart0_cts_pb6_default: uart0_cts_pb6_default { + pinmux = ; + }; + + /* UART1: TX(PC6), RX(PC7), RTS(PC5), CTS(PC4) */ + + uart1_tx_pc6_default: uart1_tx_pc6_default { + pinmux = ; + }; + uart1_rx_pc7_default: uart1_rx_pc7_default { + pinmux = ; + }; + uart1_rts_pc5_default: uart1_rts_pc5_default { + pinmux = ; + }; + uart1_cts_pc4_default: uart1_cts_pc4_default { + pinmux = ; + }; + + /* PWM Channel 0 (PB7) */ + + pwm_ch0_pc7_default: pwm_ch0_pc7_default { + pinmux = ; + }; + + /* LSPI: CLK(PE1), MOSI(PE2), MISO(PE3) */ + + lspi_clk_pe1_default: lspi_clk_pe1_default { + pinmux = ; + }; + lspi_mosi_pe2_default: lspi_mosi_pe2_default { + pinmux = ; + }; + lspi_miso_pe3_default: lspi_miso_pe3_default { + pinmux = ; + }; + + /* GSPI: CLK(PF4), MOSI(PF7), MISO(PF6) */ + + gspi_clk_ph4_default: gspi_clk_ph4_default { + pinmux = ; + }; + gspi_mosi_ph7_default: gspi_mosi_ph7_default { + pinmux = ; + }; + gspi_miso_ph6_default: gspi_miso_ph6_default { + pinmux = ; + }; + + /* Define I2C pins: SCL(PE0), SDA(PE1) */ + + i2c_scl_pe0_default: i2c_scl_pe0_default { + pinmux = ; + }; + i2c_sda_pe1_default: i2c_sda_pe1_default { + pinmux = ; + }; + + /* Define ADC pins: PB0..PB7, PD0-PD1 */ + + adc_pc0_default: adc_pc0_default { + pinmux = ; + }; + adc_pc1_default: adc_pc1_default { + pinmux = ; + }; + adc_pc2_default: adc_pc2_default { + pinmux = ; + }; + adc_pc3_default: adc_pc3_default { + pinmux = ; + }; + adc_pc4_default: adc_pc4_default { + pinmux = ; + }; + adc_pc5_default: adc_pc5_default { + pinmux = ; + }; + adc_pc6_default: adc_pc6_default { + pinmux = ; + }; + adc_pc7_default: adc_pc7_default { + pinmux = ; + }; +}; diff --git a/boards/riscv/tl322x/tl3228x.dts b/boards/riscv/tl322x/tl3228x.dts new file mode 100644 index 0000000000000..7c802fd896329 --- /dev/null +++ b/boards/riscv/tl322x/tl3228x.dts @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2024 Telink Semiconductor + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include "tl3228x-common.dtsi" + +/ { + led_pool { + compatible = "gpio-leds"; + + out { + gpios = <&gpioc 6 GPIO_ACTIVE_HIGH>; + }; + }; + + pwm_pool { + 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>; + }; + }; +}; + +&pwm0 { + /* On board RGB LEDs */ + pinctrl-ch0 = <&pwm_ch0_pc7_default>; + pinctrl-ch1 = <&pwm_ch1_pc4_default>; + pinctrl-ch2 = <&pwm_ch2_pc5_default>; +}; + +&pinctrl { + pwm_ch0_pc7_default: pwm_ch0_pc7_default { + pinmux = ; + }; + pwm_ch1_pc4_default: pwm_ch1_pc4_default { + pinmux = ; + }; + pwm_ch2_pc5_default: pwm_ch2_pc5_default { + pinmux = ; + }; +}; + +&wdt { + status = "okay"; +}; diff --git a/boards/riscv/tl322x/tl3228x.yaml b/boards/riscv/tl322x/tl3228x.yaml new file mode 100644 index 0000000000000..3911184b4376f --- /dev/null +++ b/boards/riscv/tl322x/tl3228x.yaml @@ -0,0 +1,15 @@ +identifier: tl3228x +name: Telink TL3228X +type: mcu +arch: riscv32 +toolchain: + - cross-compile + - zephyr +ram: 512 +flash: 1024 +supported: + - gpio + - i2c + - pwm + - spi + - netif:openthread diff --git a/boards/riscv/tl322x/tl3228x_defconfig b/boards/riscv/tl322x/tl3228x_defconfig new file mode 100644 index 0000000000000..3c8fb870ee695 --- /dev/null +++ b/boards/riscv/tl322x/tl3228x_defconfig @@ -0,0 +1,14 @@ +# Copyright (c) 2024 Telink Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_SERIES_RISCV_TELINK_TLX=y +CONFIG_SOC_SERIES_RISCV_TELINK_TLX_RETENTION=n +CONFIG_SOC_RISCV_TELINK_TL322X=y +CONFIG_BOARD_TL3228X=y +CONFIG_GPIO=y +CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000 +CONFIG_UART_INTERRUPT_DRIVEN=y +CONFIG_SERIAL=y +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y +CONFIG_ENTROPY_GENERATOR=y diff --git a/boards/riscv/tl322x/tl3228x_retention.dts b/boards/riscv/tl322x/tl3228x_retention.dts new file mode 100644 index 0000000000000..b0de53e9b8571 --- /dev/null +++ b/boards/riscv/tl322x/tl3228x_retention.dts @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2024 Telink Semiconductor + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include "tl3228x-common.dtsi" + +/ { + soc { + + /delete-node/ memory@0; + /delete-node/ memory@80000; + + ram_ilm_retention: memory@0 { + compatible = "mmio-sram"; + }; + + ram_ilm_nonretention: memory@80000 { + compatible = "mmio-sram"; + }; + }; + + chosen { + zephyr,sram = &ram_ilm_retention; + }; + + cpus { + cpu0: cpu@0 { + cpu-power-states = <&state0 &state1>; + }; + }; + + power-states { + state1: state1 { + compatible = "zephyr,power-state"; + power-state-name = "standby"; + min-residency-us = <100000>; + exit-latency-us = <1000>; + }; + }; +}; + +&ram_ilm_retention { + reg = <0x00000000 0x00080000>; +}; + +&ram_ilm_nonretention { + reg = <0x00080000 0x00020000>; +}; diff --git a/boards/riscv/tl322x/tl3228x_retention.yaml b/boards/riscv/tl322x/tl3228x_retention.yaml new file mode 100644 index 0000000000000..05294c2acc27f --- /dev/null +++ b/boards/riscv/tl322x/tl3228x_retention.yaml @@ -0,0 +1,15 @@ +identifier: tl3228x_retention +name: Telink TL3228X_RETENTION +type: mcu +arch: riscv32 +toolchain: + - cross-compile + - zephyr +ram: 128 +flash: 1024 +supported: + - gpio + - i2c + - pwm + - spi + - netif:openthread diff --git a/boards/riscv/tl322x/tl3228x_retention_defconfig b/boards/riscv/tl322x/tl3228x_retention_defconfig new file mode 100644 index 0000000000000..609a1c4883caf --- /dev/null +++ b/boards/riscv/tl322x/tl3228x_retention_defconfig @@ -0,0 +1,14 @@ +# Copyright (c) 2024 Telink Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_SERIES_RISCV_TELINK_TLX=y +CONFIG_SOC_SERIES_RISCV_TELINK_TLX_RETENTION=y +CONFIG_SOC_RISCV_TELINK_TL322X=y +CONFIG_BOARD_TL3228X_RETENTION=y +CONFIG_GPIO=y +CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000 +CONFIG_UART_INTERRUPT_DRIVEN=y +CONFIG_SERIAL=y +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y +CONFIG_ENTROPY_GENERATOR=y diff --git a/boards/riscv/tl323x/Kconfig.board b/boards/riscv/tl323x/Kconfig.board new file mode 100644 index 0000000000000..aed66207b67ed --- /dev/null +++ b/boards/riscv/tl323x/Kconfig.board @@ -0,0 +1,10 @@ +# Copyright (c) 2024 Telink Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_TL3238X + bool "Telink TL323X Platform" + depends on SOC_RISCV_TELINK_TL323X + +config BOARD_TL3238X_RETENTION + bool "Telink TL323X Platform with retention" + depends on SOC_RISCV_TELINK_TL323X diff --git a/boards/riscv/tl323x/Kconfig.defconfig b/boards/riscv/tl323x/Kconfig.defconfig new file mode 100644 index 0000000000000..4c87810ed4358 --- /dev/null +++ b/boards/riscv/tl323x/Kconfig.defconfig @@ -0,0 +1,65 @@ +# Copyright (c) 2024 Telink Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_TL3238X + +config BOARD + default "tl3238x" + +endif + +if BOARD_TL3238X_RETENTION + +config BOARD + default "tl3238x_retention" + +endif + +config HEAP_MEM_POOL_SIZE + default 4096 + +if BOARD_TL3238X || BOARD_TL3238X_RETENTION + +config SOC_FLASH_TELINK_TLX + default y if FLASH + +config USB_TELINK_TLX + default y + +if BT + +# BLE Controller SDK from hal_telink requires +# Telink's toolchain with FPU support +config FPU + default y if "$(ZEPHYR_TOOLCHAIN_VARIANT)" != "zephyr" + +config BT_HCI_ACL_FLOW_CONTROL + default n + +choice BT_HCI_BUS_TYPE + default BT_TLX +endchoice + +endif # BT + +# Workaround for not being able to have commas in macro arguments +DT_CHOSEN_Z_CODE_PARTITION := zephyr,code-partition + +config FLASH_LOAD_OFFSET + default $(dt_chosen_reg_addr_hex,$(DT_CHOSEN_Z_CODE_PARTITION)) if USE_DT_CODE_PARTITION + +# Buffer for image writter shall be less(multiple of access alignment) or +# equal to flash page. tl3238x boards use external P25Q16 IC as +# flesh memory. Flash page size of the IC is 256 bytes. So that, it is +# maximum image writer buffer size for such kind of boards. +config IMG_BLOCK_BUF_SIZE + default 256 if MCUBOOT_IMG_MANAGER + +# MCU boot application options +config MCUBOOT_SIGNATURE_KEY_FILE + default "bootloader/mcuboot/root-rsa-2048.pem" if BOOTLOADER_MCUBOOT + +config MCUBOOT_EXTRA_IMGTOOL_ARGS + default "--max-sectors 4096" if BOOTLOADER_MCUBOOT + +endif diff --git a/boards/riscv/tl323x/board.cmake b/boards/riscv/tl323x/board.cmake new file mode 100644 index 0000000000000..63d04e1dc719c --- /dev/null +++ b/boards/riscv/tl323x/board.cmake @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: Apache-2.0 + +board_runner_args(bdt_tool) +include(${ZEPHYR_BASE}/boards/common/bdt_tool.board.cmake) diff --git a/boards/riscv/tl323x/doc/index.rst b/boards/riscv/tl323x/doc/index.rst new file mode 100644 index 0000000000000..448652ffcb2d0 --- /dev/null +++ b/boards/riscv/tl323x/doc/index.rst @@ -0,0 +1,258 @@ +.. _tl3238x: + +Telink TL3238X +##################### + +Overview +******** + +The TL3238X Generic Starter Kit is a hardware platform which +can be used to verify the Telink TLx series chipset and develop applications +for several 2.4 GHz air interface standards including Bluetooth LE, Zigbee, RF4CE, +Thread, Matter, and 2.4GHz proprietary standard. + +.. figure:: img/tl3238x.jpg + :align: center + :alt: TL3238X + +.. More information about the board can be found at the `Telink B92 Generic Starter Kit Hardware Guide`_ website. + +Hardware +******** + +The TL3238X SoC integrates a powerful 32-bit RISC-V MCU, DSP, 2.4 GHz ISM Radio, 128 KB SRAM +including 96 KB retention feature SRAM, external Flash memory, 12-bit AUX ADC, PWM, flexible +IO interfaces, and other peripheral blocks required for advanced IoTapplications. + +.. figure:: img/tl3238_block_diagram.png + :align: center + :alt: TL3238X_SOC + +The TL3238X default board configuration provides the following hardware components: + +- RF conducted antenna +- 2 MB External SPI Flash memory with reset button. (Possible to mount 1/2/4 MB) +- Chip reset button +- Mini USB interface +- 4-wire JTAG +- 4 LEDs, Key matrix up to 4 keys +- Stereo line-out + +Supported Features +================== + +The Zephyr TL3238X board configuration supports the following hardware features: + ++----------------+------------+------------------------------+ +| Interface | Controller | Driver/Component | ++================+============+==============================+ +| PLIC | on-chip | interrupt_controller | ++----------------+------------+------------------------------+ +| RISC-V Machine | on-chip | timer | +| Timer (32 KHz) | | | ++----------------+------------+------------------------------+ +| PINCTRL | on-chip | pinctrl | ++----------------+------------+------------------------------+ +| GPIO | on-chip | gpio | ++----------------+------------+------------------------------+ +| UART | on-chip | serial | ++----------------+------------+------------------------------+ +| PWM | on-chip | pwm | ++----------------+------------+------------------------------+ +| TRNG | on-chip | entropy | ++----------------+------------+------------------------------+ +| FLASH (MSPI) | on-chip | flash | ++----------------+------------+------------------------------+ +| RADIO | on-chip | Bluetooth, | +| | | ieee802154, OpenThread | ++----------------+------------+------------------------------+ +| SPI (Master) | on-chip | spi | ++----------------+------------+------------------------------+ +| I2C (Master) | on-chip | i2c | ++----------------+------------+------------------------------+ +| ADC | on-chip | adc | ++----------------+------------+------------------------------+ +| USB (device) | on-chip | usb_dc | ++----------------+------------+------------------------------+ +| AES | on-chip | mbedtls | ++----------------+------------+------------------------------+ +| PKE | on-chip | mbedtls | ++----------------+------------+------------------------------+ + +.. Board supports power-down modes: suspend and deep-sleep. For deep-sleep mode only 96KB of retention memory is available. + +Board supports HW cryptography acceleration (AES and ECC till 256 bits). MbedTLS interface is used as cryptography front-end. + +.. note:: + To support "button" example project PD6-KEY3 (J5-13, J5-14) jumper needs to be removed and KEY3 (J5-13) should be connected to GND (J3-30) externally. + + For the rest example projects use the default jumpers configuration. + +Limitations +----------- + +- Maximum 3 GPIO ports could be configured to generate external interrupts simultaneously. All ports should use different IRQ numbers. +- DMA mode is not supported by I2C, SPI and Serial Port. +- SPI Slave mode is not implemented. +- I2C Slave mode is not implemented. +- Bluetooth is not compatible with deep-sleep mode. Only suspend is allowed when Bluetooth is active. +- USB working only in active mode (No power down supported). +- During deep-sleep all GPIO's are in Hi-Z mode. +- Shell is not compatible with sleep modes. + +Default configuration and IOs +============================= + +System Clock +------------ + +The TL3238X board is configured to use the 24 MHz external crystal oscillator +with the on-chip PLL/DIV generating the 96 MHz system clock. +The following values also could be assigned to the system clock in the board DTS file +(``boards/riscv/tl323x/tl3238x-common.dtsi``): + +- 24000000 +- 48000000 +- 96000000 + +.. code-block:: + + &cpu0 { + clock-frequency = <96000000>; + }; + +PINs Configuration +------------------ + +The TL3238X SoC has five GPIO controllers (PORT_A to PORT_F), and the next are +currently enabled: + +- LED0 (white): PD0, LED1 (green): PB0, LED2 (red): PB1, LED3 (blue): PB2 +- Key Matrix SW3: PB3_PB6, SW4: PB3_PB7, SW5: PB5_PB6, SW6: PB5_PB7 + +Peripheral's pins on the SoC are mapped to the following GPIO pins in the +``boards/riscv/tl323x/tl3238x-common.dtsi`` file: + +- UART0 TX: PE0, RX: PE1 +- PWM Channel 0: PB2 +- GSPI CLK: PE5, MISO: PE6, MOSI: PE7 +- I2C SCL: PC3, SDA: PC2 + +Serial Port +----------- + +The TL3238X SoC has 1 UART. The Zephyr console output is assigned to UART0. +The default settings are 115200 8N1. + +USB COM Port (ACM) as Serial Port Configuration +----------------------------------------------- + +To use the USB COM port (ACM) instead of UART, follow these steps: + +1. Add the following configuration to your project: + +.. code-block:: none + + CONFIG_LOG=y + CONFIG_USB_DEVICE_STACK=y + CONFIG_USB_DEVICE_INITIALIZE_AT_BOOT=n + CONFIG_USB_CDC_ACM_LOG_LEVEL_OFF=y + +2. Include the following overlay configuration: + +.. code-block:: dts + + / { + chosen { + zephyr,console = &cdc_acm_uart0; + zephyr,shell-uart = &cdc_acm_uart0; + }; + }; + + &zephyr_udc0 { + cdc_acm_uart0: cdc_acm_uart0 { + compatible = "zephyr,cdc-acm-uart"; + }; + }; + +3. Connect the USB cable to your device. A new ACM serial device should appear in your system (e.g., ``/dev/ttyACM0`` on Linux or a COM port on Windows). +4. Use your preferred terminal application (like ``minicom``, ``screen``, or ``PuTTY``) to connect to the newly detected ACM serial device. + +5. In your source code, ensure the following header is included and the USB device stack is initialized: + +.. code-block:: c + + #ifdef CONFIG_USB_DEVICE_STACK + #include + #endif + #ifdef CONFIG_USB_DEVICE_STACK + usb_enable(NULL); + #endif + +Programming and debugging +************************* + +Building +======== + +.. important:: + + These instructions assume you've set up a development environment as + described in the `Zephyr Getting Started Guide`_. + +To build applications using the default RISC-V toolchain from Zephyr SDK, just run the west build command. +Here is an example for the "hello_world" application. + +.. code-block:: console + + # From the root of the zephyr repository + west build -b tl3238x samples/hello_world + +Open a serial terminal with the following settings: + +- Speed: 115200 +- Data: 8 bits +- Parity: None +- Stop bits: 1 + +Flash the board, reset and observe the following messages on the selected +serial port: + +.. code-block:: console + + *** Booting Zephyr OS build zephyr-v3.3.0-xxxx-xxxxxxxxxxxxx *** + Hello World! tl3238x + + +Flashing +======== + +To flash the TL3238X board see the sources below: + +- `Burning and Debugging Tools for all Series`_ + +.. It is also possible to use the west flash command. Download BDT tool for Linux `Burning and Debugging Tools for Linux`_ or +.. `Burning and Debugging Tools for Windows`_ and extract archive into some directory you wish TELINK_BDT_BASE_DIR + +.. - Now you should be able to run the west flash command with the BDT path specified (TELINK_BDT_BASE_DIR). + +.. .. code-block:: console + +.. west flash --bdt-path=$TELINK_BDT_BASE_DIR --erase + +.. - You can also run the west flash command without BDT path specification if TELINK_BDT_BASE_DIR is in your environment (.bashrc). + +.. .. code-block:: console + +.. export TELINK_BDT_BASE_DIR="/opt/telink_bdt/" + + +References +********** + +.. target-notes:: + +.. _Burning and Debugging Tools for all Series: https://wiki.telink-semi.cn/wiki/IDE-and-Tools/Burning-and-Debugging-Tools-for-all-Series/ +.. _Burning and Debugging Tools for Linux: https://wiki.telink-semi.cn/tools_and_sdk/Tools/BDT/Telink_libusb_BDT-Linux-X64-V1.6.0.zip +.. _Burning and Debugging Tools for Windows: https://wiki.telink-semi.cn/tools_and_sdk/Tools/BDT/BDT.zip +.. _Zephyr Getting Started Guide: https://docs.zephyrproject.org/latest/getting_started/index.html diff --git a/boards/riscv/tl323x/tl3238x-common.dtsi b/boards/riscv/tl323x/tl3238x-common.dtsi new file mode 100644 index 0000000000000..a9ab9ee3e2dd0 --- /dev/null +++ b/boards/riscv/tl323x/tl3238x-common.dtsi @@ -0,0 +1,249 @@ +/* + * Copyright (c) 2024 Telink Semiconductor + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include +#include +#include "tl3238x-pinctrl.dtsi" + +/ { + model = "telink,tl323x"; + compatible = "telink,tl3238x"; + + aliases { + led0 = &led_white; + led1 = &led_green; + led2 = &led_red; + led3 = &led_blue; + sw0 = &key_1; + sw1 = &key_2; + sw2 = &key_3; + sw3 = &key_4; + pwm-led0 = &pwm_led_blue; + pwm-0 = &pwm0; + watchdog0 = &wdt; + mcuboot-button0 = &key_dfu; + mcuboot-led0 = &led_blue; + }; + + leds { + compatible = "gpio-leds"; + + led_red: led_0 { + gpios = <&gpioc 2 GPIO_ACTIVE_HIGH>; + label = "LED Red"; + }; + + led_blue: led_1 { + gpios = <&gpioc 3 GPIO_ACTIVE_HIGH>; + label = "LED Blue"; + }; + + led_white: led_2 { + gpios = <&gpioc 0 GPIO_ACTIVE_HIGH>; + label = "LED White"; + }; + + led_green: led_3 { + gpios = <&gpioc 1 GPIO_ACTIVE_HIGH>; + label = "LED Green"; + }; + }; + + pwm_leds { + compatible = "pwm-leds"; + + pwm_led_blue: pwm_led_0 { + pwms = <&pwm0 0 PWM_MSEC(20) PWM_POLARITY_NORMAL>; + label = "PWM LED Blue"; + }; + }; + + keys { + compatible = "gpio-keys"; + key_1: button_1 { + label = "User KEY1"; + gpios = <&gpioc 4 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + }; + key_2: button_2 { + label = "User KEY2"; + gpios = <&gpioc 5 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + }; + key_3: button_3 { + label = "User KEY3"; + gpios = <&gpioc 6 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + }; + key_4: button_4 { + label = "User KEY4"; + gpios = <&gpioc 7 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + }; + key_dfu: button_dfu { + label = "USB DFU"; + gpios = <&gpioa 0 GPIO_PULL_DOWN>; + }; + }; + + /* Short TL_Key3 (J6 pin 21) to ground */ + key_pool { + compatible = "gpio-keys"; + + inp { + gpios = <&gpioc 4 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>, + <&gpioc 5 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + }; + }; + + key_matrix { + compatible = "gpio-keys"; + + col { + gpios = <&gpioc 6 GPIO_ACTIVE_HIGH>, + <&gpioc 7 GPIO_ACTIVE_HIGH>; + }; + + row { + gpios = <&gpioc 4 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)>, + <&gpioc 5 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)>; + }; + }; + + chosen { + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + zephyr,sram = &ram_ilm; + zephyr,flash = &flash; + zephyr,flash-controller = &flash_mspi; + zephyr,entropy = &trng0; + zephyr,code-partition = &slot0_partition; + zephyr,ieee802154 = &ieee802154; + }; +}; + +&cpu0 { + clock-frequency = <96000000>; +}; + +&ram_ilm { + reg = <0x00060000 0x00020000>; +}; +&ram_ilm_non_retention { + reg = <0x00080000 0x00008000>; +}; + +&flash { + reg = <0x20000000 0x100000>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x00000000 0x20000>; + }; + slot0_partition: partition@20000 { + label = "image-0"; + reg = <0x20000 0x68000>; + }; + slot1_partition: partition@88000 { + label = "image-1"; + reg = <0x88000 0x68000>; + }; + scratch_partition: partition@f0000 { + label = "image-scratch"; + reg = <0xf0000 0x4000>; + }; + storage_partition: partition@f4000 { + label = "storage"; + reg = <0xf4000 0x0000a000>; + }; + + /* region <0xfe000 0x2000> is used for Telink TLx RF parameters */ + /* For 1M MCU - the partition address is 0xfe000 */ + /* For 2M MCU - the partition address is 0x1fe000 */ + /* For 4M MCU - the partition address is 0x3fe000 */ + /* For 16M MCU - the partition address is 0xffe000 */ + vendor_partition: partition@fe000 { + label = "vendor-data"; + reg = <0xfe000 0x2000>; + }; + }; +}; + +&gpiob { + interrupts = <47 1>; + status = "okay"; +}; + +&gpioc { + interrupts = <46 1>; + status = "okay"; +}; + +&gpiod { + interrupts = <50 1>; + status = "okay"; +}; + +&gpioe { + interrupts = <48 1>; + status = "okay"; +}; + +&gpiof { + interrupts = <49 1>; + status = "okay"; +}; + +&uart0 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart0_tx_pb2_default &uart0_rx_pb3_default>; + pinctrl-names = "default"; +}; + +&trng0 { + status = "okay"; +}; + +&ieee802154 { + status = "okay"; +}; + +&pwm0 { + status = "okay"; + clock-frequency = <300000>; + pinctrl-ch0 = <&pwm_ch0_pc1_default>; +}; + + +&gspi { + status = "okay"; + cs0-pin = "GPIO_PE4"; + pinctrl-0 = <&gspi_clk_pe5_default &gspi_miso_pe6_default &gspi_mosi_pe7_default>; + pinctrl-names = "default"; +}; + +&i2c { + status = "okay"; + clock-frequency = ; + pinctrl-0 = <&i2c_scl_pc3_default &i2c_sda_pc2_default>; + pinctrl-names = "default"; +}; + +&adc { + status = "okay"; + vref-internal-mv = <1200>; + sample-freq = ; + pinctrl-0 = <&adc_pd1_default>; + pinctrl-names = "default"; +}; + +&wdt { + status = "okay"; +}; diff --git a/boards/riscv/tl323x/tl3238x-pinctrl.dtsi b/boards/riscv/tl323x/tl3238x-pinctrl.dtsi new file mode 100644 index 0000000000000..67afb70ac41ca --- /dev/null +++ b/boards/riscv/tl323x/tl3238x-pinctrl.dtsi @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2024 Telink Semiconductor + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +&pinctrl { + /* Set pad-mul-sel register value. + * Note: Pins functions below (pinmux = <...>) depend on this value. + */ + pad-mul-sel = <1>; + + /* UART0: TX(PE0), RX(PE1), RTS(PE2), CTS(PE3) */ + + uart0_tx_pb2_default: uart0_tx_pb2_default { + pinmux = ; + }; + uart0_rx_pb3_default: uart0_rx_pb3_default { + pinmux = ; + }; + uart0_rts_pe2_default: uart0_rts_pe2_default { + pinmux = ; + }; + uart0_cts_pe3_default: uart0_cts_pe3_default { + pinmux = ; + }; + + /* UART1: TX(PC6), RX(PC7), RTS(PC5), CTS(PC4) */ + + uart1_tx_pc6_default: uart1_tx_pc6_default { + pinmux = ; + }; + uart1_rx_pc7_default: uart1_rx_pc7_default { + pinmux = ; + }; + uart1_rts_pc5_default: uart1_rts_pc5_default { + pinmux = ; + }; + uart1_cts_pc4_default: uart1_cts_pc4_default { + pinmux = ; + }; + + /* PWM Channel 0 (PE4) */ + + pwm_ch0_pc1_default: pwm_ch0_pc1_default { + pinmux = ; + }; + + /* Note:TL323X only supports gspi!!!*/ + /* GSPI: CLK(PE5), MISO(PE6), MOSI(PE7) */ + + gspi_clk_pe5_default: gspi_clk_pe5_default { + pinmux = ; + }; + gspi_miso_pe6_default: gspi_miso_pe6_default { + pinmux = ; + }; + gspi_mosi_pe7_default: gspi_mosi_pe7_default { + pinmux = ; + }; + + /* Define I2C pins: SCL(PC3), SDA(PC2) */ + + i2c_scl_pc3_default: i2c_scl_pc3_default { + pinmux = ; + }; + i2c_sda_pc2_default: i2c_sda_pc2_default { + pinmux = ; + }; + + /* Define ADC pins: PB0..PB7, PD0, PD1 */ + + adc_pb0_default: adc_pb0_default { + pinmux = ; + }; + adc_pb1_default: adc_pb1_default { + pinmux = ; + }; + adc_pb2_default: adc_pb2_default { + pinmux = ; + }; + adc_pb3_default: adc_pb3_default { + pinmux = ; + }; + adc_pb4_default: adc_pb4_default { + pinmux = ; + }; + adc_pb5_default: adc_pb5_default { + pinmux = ; + }; + adc_pb6_default: adc_pb6_default { + pinmux = ; + }; + adc_pb7_default: adc_pb7_default { + pinmux = ; + }; + adc_pd0_default: adc_pd0_default { + pinmux = ; + }; + adc_pd1_default: adc_pd1_default { + pinmux = ; + }; +}; diff --git a/boards/riscv/tl323x/tl3238x.dts b/boards/riscv/tl323x/tl3238x.dts new file mode 100644 index 0000000000000..a0cfef822f1a0 --- /dev/null +++ b/boards/riscv/tl323x/tl3238x.dts @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2024 Telink Semiconductor + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include "tl3238x-common.dtsi" + +/ { + led_pool { + compatible = "gpio-leds"; + + out { + gpios = <&gpioc 0 GPIO_ACTIVE_HIGH>; + }; + }; + + pwm_pool { + compatible = "pwm-leds"; + out { + pwms = <&pwm0 0 PWM_MSEC(20) PWM_POLARITY_NORMAL>, + <&pwm0 0 PWM_MSEC(20) PWM_POLARITY_NORMAL>, + <&pwm0 1 PWM_MSEC(20) PWM_POLARITY_NORMAL>, + <&pwm0 2 PWM_MSEC(20) PWM_POLARITY_NORMAL>; + }; + }; +}; + +&pwm0 { + /* On board RGB LEDs */ + pinctrl-ch0 = <&pwm_ch0_pc1_default>; + pinctrl-ch1 = <&pwm_ch1_pc3_default>; + pinctrl-ch2 = <&pwm_ch2_pc2_default>; +}; + +&pinctrl { + pwm_ch0_pc1_default: pwm_ch0_pc1_default { + pinmux = ; + }; + pwm_ch1_pc3_default: pwm_ch1_pc3_default { + pinmux = ; + }; + pwm_ch2_pc2_default: pwm_ch2_pc2_default { + pinmux = ; + }; +}; diff --git a/boards/riscv/tl323x/tl3238x.yaml b/boards/riscv/tl323x/tl3238x.yaml new file mode 100644 index 0000000000000..fd7d5b28c2d33 --- /dev/null +++ b/boards/riscv/tl323x/tl3238x.yaml @@ -0,0 +1,15 @@ +identifier: tl3238x +name: Telink TL3238X +type: mcu +arch: riscv32 +toolchain: + - cross-compile + - zephyr +ram: 128 +flash: 1024 +supported: + - gpio + - i2c + - pwm + - spi + - netif:openthread diff --git a/boards/riscv/tl323x/tl3238x_defconfig b/boards/riscv/tl323x/tl3238x_defconfig new file mode 100644 index 0000000000000..9776fdabcee63 --- /dev/null +++ b/boards/riscv/tl323x/tl3238x_defconfig @@ -0,0 +1,14 @@ +# Copyright (c) 2024 Telink Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_SERIES_RISCV_TELINK_TLX=y +CONFIG_SOC_SERIES_RISCV_TELINK_TLX_RETENTION=n +CONFIG_SOC_RISCV_TELINK_TL323X=y +CONFIG_BOARD_TL3238X=y +CONFIG_GPIO=y +CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000 +CONFIG_UART_INTERRUPT_DRIVEN=y +CONFIG_SERIAL=y +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y +CONFIG_ENTROPY_GENERATOR=y diff --git a/boards/riscv/tl323x/tl3238x_retention.dts b/boards/riscv/tl323x/tl3238x_retention.dts new file mode 100644 index 0000000000000..d5895e373019e --- /dev/null +++ b/boards/riscv/tl323x/tl3238x_retention.dts @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2024 Telink Semiconductor + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include "tl3238x-common.dtsi" + +/ { + soc { + /delete-node/ memory@60000; + /delete-node/ memory@68000; + /delete-node/ memory@80000; + + ram_ilm_retention_non_reset: memory@60000 { + compatible = "mmio-sram"; + }; + + ram_ilm_retention: memory@68000 { + compatible = "mmio-sram"; + }; + + ram_ilm_nonretention: memory@80000 { + compatible = "mmio-sram"; + }; + }; + + chosen { + zephyr,sram = &ram_ilm_retention; + }; + + cpus { + cpu0: cpu@0 { + cpu-power-states = <&state0 &state1>; + }; + }; + + power-states { + state1: state1 { + compatible = "zephyr,power-state"; + power-state-name = "standby"; + min-residency-us = <100000>; + exit-latency-us = <1000>; + }; + }; +}; +&ram_ilm_retention_non_reset { + reg = <0x00060000 0x00008000>; +}; + +&ram_ilm_retention { + reg = <0x00068000 0x00018000>; +}; + +&ram_ilm_nonretention { + reg = <0x00080000 0x00008000>; +}; diff --git a/boards/riscv/tl323x/tl3238x_retention.yaml b/boards/riscv/tl323x/tl3238x_retention.yaml new file mode 100644 index 0000000000000..eaafc113615e5 --- /dev/null +++ b/boards/riscv/tl323x/tl3238x_retention.yaml @@ -0,0 +1,15 @@ +identifier: tl3238x_retention +name: Telink TL3238_RETENTION +type: mcu +arch: riscv32 +toolchain: + - cross-compile + - zephyr +ram: 128 +flash: 1024 +supported: + - gpio + - i2c + - pwm + - spi + - netif:openthread diff --git a/boards/riscv/tl323x/tl3238x_retention_defconfig b/boards/riscv/tl323x/tl3238x_retention_defconfig new file mode 100644 index 0000000000000..0c469fa44c024 --- /dev/null +++ b/boards/riscv/tl323x/tl3238x_retention_defconfig @@ -0,0 +1,14 @@ +# Copyright (c) 2024 Telink Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_SERIES_RISCV_TELINK_TLX=y +CONFIG_SOC_SERIES_RISCV_TELINK_TLX_RETENTION=y +CONFIG_SOC_RISCV_TELINK_TL323X=y +CONFIG_BOARD_TL3238X_RETENTION=y +CONFIG_GPIO=y +CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000 +CONFIG_UART_INTERRUPT_DRIVEN=y +CONFIG_SERIAL=y +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y +CONFIG_ENTROPY_GENERATOR=y diff --git a/build.sh b/build.sh new file mode 100755 index 0000000000000..4a12f18ee47f8 --- /dev/null +++ b/build.sh @@ -0,0 +1 @@ +west build -p -b tl3228x ~/zephyrproject/zephyr/samples/bluetooth/peripheral_kmd/ -d ~/zephyrproject/build/build_peripheralkmd_tl3228x diff --git a/drivers/adc/CMakeLists.txt b/drivers/adc/CMakeLists.txt index 0f93704a49572..400a0cadf5e29 100644 --- a/drivers/adc/CMakeLists.txt +++ b/drivers/adc/CMakeLists.txt @@ -4,7 +4,12 @@ zephyr_library() zephyr_library_sources_ifdef(CONFIG_ADC adc_common.c) zephyr_library_sources_ifdef(CONFIG_ADC_TELINK_B9X adc_b9x.c) -zephyr_library_sources_ifdef(CONFIG_ADC_TELINK_TLX adc_tlx.c) +# zephyr_library_sources_ifdef(CONFIG_ADC_TELINK_TLX adc_tlx.c) +if(CONFIG_SOC_RISCV_TELINK_TL322X) + zephyr_library_sources(adc_tl322x.c) +else() + zephyr_library_sources(adc_tlx.c) +endif() zephyr_library_sources_ifdef(CONFIG_ADC_ITE_IT8XXX2 adc_ite_it8xxx2.c) zephyr_library_sources_ifdef(CONFIG_ADC_SHELL adc_shell.c) zephyr_library_sources_ifdef(CONFIG_ADC_MCUX_ADC12 adc_mcux_adc12.c) diff --git a/drivers/adc/adc_tl322x.c b/drivers/adc/adc_tl322x.c new file mode 100644 index 0000000000000..7e0ae0eae00d3 --- /dev/null +++ b/drivers/adc/adc_tl322x.c @@ -0,0 +1,477 @@ +/* + * Copyright (c) 2022-2023 Telink Semiconductor + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT telink_tlx_adc + +/* Local driver headers */ +#define ADC_CONTEXT_USES_KERNEL_TIMER +#include "adc_context.h" + +/* Zephyr Device Tree headers */ +#include + +/* Zephyr Logging headers */ +#include +LOG_MODULE_REGISTER(adc_tlx, CONFIG_ADC_LOG_LEVEL); + +/* Telink HAL headers */ +#include +#include + +/* Set ADC resolution value */ +static inline void adc_set_resolution(adc_num_e sar_adc_num,adc_res_e res) +{ + analog_write_reg8(areg_adc_res_m(sar_adc_num), (analog_read_reg8(areg_adc_res_m(sar_adc_num) )&(~FLD_ADC_RES_M)) | res); +} + +/* ADC tlx defines */ +#define SIGN_BIT_POSITION (13) +#define AREG_ADC_DATA_STATUS (0xf6) +#define ADC_DATA_READY BIT(0) + +/* tlx ADC driver data */ +struct tlx_adc_data { + struct adc_context ctx; + int16_t *buffer; + int16_t *repeat_buffer; + uint8_t differential; + uint8_t resolution_divider; + struct k_sem acq_sem; + struct k_thread thread; + + K_THREAD_STACK_MEMBER(stack, CONFIG_ADC_TLX_ACQUISITION_THREAD_STACK_SIZE); +}; + +struct tlx_adc_cfg { + uint32_t sample_freq; + uint16_t vref_internal_mv; + const struct pinctrl_dev_config *pcfg; +}; + +/* Validate ADC data buffer size */ +static int adc_tlx_validate_buffer_size(const struct adc_sequence *sequence) +{ + size_t needed = sizeof(int16_t); + + if (sequence->options) { + needed *= (1 + sequence->options->extra_samplings); + } + + if (sequence->buffer_size < needed) { + return -ENOMEM; + } + + return 0; +} + +/* Validate ADC read API input parameters */ +static int adc_tlx_validate_sequence(const struct adc_sequence *sequence) +{ + int status; + + if (sequence->channels != BIT(0)) { + LOG_ERR("Only channel 0 is supported."); + return -ENOTSUP; + } + + if (sequence->oversampling) { + LOG_ERR("Oversampling is not supported."); + return -ENOTSUP; + } + + status = adc_tlx_validate_buffer_size(sequence); + if (status) { + LOG_ERR("Buffer size too small."); + return status; + } + + return 0; +} + +static uint16_t adc_tlx_get_pin(uint16_t dt_pin, bool positive) +{ + if (positive) { + /* adc_input_pch_e */ + switch (dt_pin) { + case DT_ADC_GPIO_PC0: return ADC0_GPIO_PC0P; + case DT_ADC_GPIO_PC1: return ADC0_GPIO_PC1P; + case DT_ADC_GPIO_PC2: return ADC0_GPIO_PC2P; + case DT_ADC_GPIO_PC3: return ADC0_GPIO_PC3P; + case DT_ADC_GPIO_PC4: return ADC0_GPIO_PC4P; + case DT_ADC_GPIO_PC5: return ADC0_GPIO_PC5P; + case DT_ADC_GPIO_PC6: return ADC0_GPIO_PC6P; + case DT_ADC_GPIO_PC7: return ADC0_GPIO_PC7P; + case DT_ADC_VBAT: return ADC_VBAT_P; + default: return 0; + } + } else { + /* adc_input_nch_e */ + switch (dt_pin) { + case DT_ADC_GPIO_PC0: return ADC0_GPIO_PC0N; + case DT_ADC_GPIO_PC1: return ADC0_GPIO_PC1N; + case DT_ADC_GPIO_PC2: return ADC0_GPIO_PC2N; + case DT_ADC_GPIO_PC3: return ADC0_GPIO_PC3N; + case DT_ADC_GPIO_PC4: return ADC0_GPIO_PC4N; + case DT_ADC_GPIO_PC5: return ADC0_GPIO_PC5N; + case DT_ADC_GPIO_PC6: return ADC0_GPIO_PC6N; + case DT_ADC_GPIO_PC7: return ADC0_GPIO_PC7N; + case DT_ADC_VBAT: return ADC_GND_N; + default: return 0; + } + } +} + +/* Get ADC value */ +static signed short adc_tlx_get_code(adc_num_e sar_adc_num) +{ + signed short adc_code; + adc_code = adc_get_raw_code(sar_adc_num); + return adc_code; +} + +/* ADC Context API implementation: start sampling */ +static void adc_context_start_sampling(struct adc_context *ctx) +{ + struct tlx_adc_data *data = + CONTAINER_OF(ctx, struct tlx_adc_data, ctx); + + data->repeat_buffer = data->buffer; + adc_power_on(ADC0); + + k_sem_give(&data->acq_sem); +} + +/* ADC Context API implementation: buffer pointer */ +static void adc_context_update_buffer_pointer(struct adc_context *ctx, bool repeat_sampling) +{ + struct tlx_adc_data *data = + CONTAINER_OF(ctx, struct tlx_adc_data, ctx); + + if (repeat_sampling) { + data->buffer = data->repeat_buffer; + } +} + +/* Start ADC measurements */ +static int adc_tlx_adc_start_read(const struct device *dev, const struct adc_sequence *sequence) +{ + int status; + struct tlx_adc_data *data = dev->data; + + /* Validate input parameters */ + status = adc_tlx_validate_sequence(sequence); + if (status != 0) { + return status; + } + + /* Set resolution */ + switch (sequence->resolution) { + case 12: + adc_set_resolution(ADC0, ADC_RES12); + data->resolution_divider = 4; + break; + case 10: + adc_set_resolution(ADC0, ADC_RES10); + data->resolution_divider = 16; + break; + case 8: + adc_set_resolution(ADC0, ADC_RES8); + data->resolution_divider = 64; + break; + default: + LOG_ERR("Selected ADC resolution is not supported."); + return -EINVAL; + } + + /* Save buffer */ + data->buffer = sequence->buffer; + + /* Start ADC conversion */ + adc_context_start_read(&data->ctx, sequence); + + return adc_context_wait_for_completion(&data->ctx); +} + +/* Main ADC Acquisition thread */ +static void adc_tlx_acquisition_thread(const struct device *dev) +{ + int16_t adc_code = 0; + struct tlx_adc_data *data = dev->data; + + while (true) { + /* Wait for Acquisition semaphore */ + k_sem_take(&data->acq_sem, K_FOREVER); + adc_start_sample_nodma(ADC0); + while (((reg_adc_rxfifo_trig_num(ADC0) & FLD_BUF_CNT) >> 4) + == 0){ + } + + adc_code = adc_tlx_get_code(ADC0); + if (!data->differential) { + /* Sign bit is not used in case of single-ended configuration */ + adc_code = adc_code * 8; + + /* Do not return negative value for single-ended configuration */ + if (adc_code < 0) { + adc_code = 0; + } + } + *data->buffer++ = adc_code; + + adc_power_off(ADC0); + + /* Release ADC context */ + adc_context_on_sampling_done(&data->ctx, dev); + } +} + +/* ADC Driver initialization */ +static int adc_tlx_init(const struct device *dev) +{ + struct tlx_adc_data *data = dev->data; + const struct tlx_adc_cfg *config = dev->config; + int err; + + /* Configure dt provided device signals when available */ + err = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT); + if (err < 0) { + LOG_ERR("ADC pinctrl setup failed (%d)", err); + return err; + } + + k_sem_init(&data->acq_sem, 0, 1); + + k_thread_create(&data->thread, data->stack, + CONFIG_ADC_TLX_ACQUISITION_THREAD_STACK_SIZE, + (k_thread_entry_t)adc_tlx_acquisition_thread, + (void *)dev, NULL, NULL, + CONFIG_ADC_TLX_ACQUISITION_THREAD_PRIO, + 0, K_NO_WAIT); + + adc_context_unlock_unconditionally(&data->ctx); + + return 0; +} + +/* API implementation: read */ +static int adc_tlx_read(const struct device *dev, + const struct adc_sequence *sequence) +{ + int status; + struct tlx_adc_data *data = dev->data; + + adc_context_lock(&data->ctx, false, NULL); + status = adc_tlx_adc_start_read(dev, sequence); + adc_context_release(&data->ctx, status); + + return status; +} + +/* API implementation: channel_setup */ +static int adc_tlx_channel_setup(const struct device *dev, + const struct adc_channel_cfg *channel_cfg) +{ + adc_ref_vol_e vref_internal_mv; + adc_sample_freq_e sample_freq; + adc_pre_scale_e pre_scale; + adc_sample_cycle_e sample_cycl; + + adc_input_pch_e input_positive; + adc_input_nch_e input_negative; + struct tlx_adc_data *data = dev->data; + const struct tlx_adc_cfg *config = dev->config; + + /* Check reference */ + if (channel_cfg->reference != ADC_REF_INTERNAL) { + LOG_ERR("Selected ADC reference is not supported."); + return -EINVAL; + } + + /* Check internal reference */ + switch (config->vref_internal_mv) { + case 1200: + vref_internal_mv = ADC_VREF_1P2V; + break; + + default: + LOG_ERR("Selected reference voltage is not supported."); + return -EINVAL; + } + + /* Check sample frequency */ + switch (config->sample_freq) { + case 23000: + sample_freq = ADC_SAMPLE_FREQ_23K; + break; + case 48000: + sample_freq = ADC_SAMPLE_FREQ_48K; + break; + case 96000: + sample_freq = ADC_SAMPLE_FREQ_96K; + break; + default: + LOG_ERR("Selected sample frequency is not supported."); + return -EINVAL; + } + + /* Check gain */ + switch (channel_cfg->gain) { + case ADC_GAIN_1: + pre_scale = ADC_PRESCALE_1; + break; + case ADC_GAIN_1_4: + pre_scale = ADC_PRESCALE_1F4; + break; + + default: + LOG_ERR("Selected ADC gain is not supported."); + return -EINVAL; + } + /* Check acquisition time */ + switch (channel_cfg->acquisition_time) { + case ADC_ACQ_TIME(ADC_ACQ_TIME_TICKS, 4): + sample_cycl = ADC_SAMPLE_CYC_4; + break; + case ADC_ACQ_TIME_DEFAULT: + case ADC_ACQ_TIME(ADC_ACQ_TIME_TICKS, 6): + sample_cycl = ADC_SAMPLE_CYC_6; + break; + case ADC_ACQ_TIME(ADC_ACQ_TIME_TICKS, 8): + sample_cycl = ADC_SAMPLE_CYC_8; + break; + case ADC_ACQ_TIME(ADC_ACQ_TIME_TICKS, 10): + sample_cycl = ADC_SAMPLE_CYC_10; + break; + case ADC_ACQ_TIME(ADC_ACQ_TIME_TICKS, 12): + sample_cycl = ADC_SAMPLE_CYC_12; + break; + case ADC_ACQ_TIME(ADC_ACQ_TIME_TICKS, 14): + sample_cycl = ADC_SAMPLE_CYC_14; + break; + case ADC_ACQ_TIME(ADC_ACQ_TIME_TICKS, 16): + sample_cycl = ADC_SAMPLE_CYC_16; + break; + case ADC_ACQ_TIME(ADC_ACQ_TIME_TICKS, 18): + sample_cycl = ADC_SAMPLE_CYC_18; + break; + case ADC_ACQ_TIME(ADC_ACQ_TIME_TICKS, 20): + sample_cycl = ADC_SAMPLE_CYC_20; + break; + case ADC_ACQ_TIME(ADC_ACQ_TIME_TICKS, 22): + sample_cycl = ADC_SAMPLE_CYC_22; + break; + case ADC_ACQ_TIME(ADC_ACQ_TIME_TICKS, 24): + sample_cycl = ADC_SAMPLE_CYC_24; + break; + case ADC_ACQ_TIME(ADC_ACQ_TIME_TICKS, 26): + sample_cycl = ADC_SAMPLE_CYC_26; + break; + case ADC_ACQ_TIME(ADC_ACQ_TIME_TICKS, 28): + sample_cycl = ADC_SAMPLE_CYC_28; + break; + case ADC_ACQ_TIME(ADC_ACQ_TIME_TICKS, 30): + sample_cycl = ADC_SAMPLE_CYC_30; + break; + case ADC_ACQ_TIME(ADC_ACQ_TIME_TICKS, 32): + sample_cycl = ADC_SAMPLE_CYC_32; + break; + case ADC_ACQ_TIME(ADC_ACQ_TIME_TICKS, 34): + sample_cycl = ADC_SAMPLE_CYC_34; + break; + + default: + LOG_ERR("Selected ADC acquisition time is not supported."); + return -EINVAL; + } + + input_positive = (adc_input_pch_e)adc_tlx_get_pin(channel_cfg->input_positive, true); + input_negative = (adc_input_nch_e)adc_tlx_get_pin(channel_cfg->input_negative, false); + if ((input_positive == (uint16_t)ADC_VBAT_P || input_negative == (uint16_t)ADC_GND_N) && + channel_cfg->differential) { + LOG_ERR("VBAT or GND is not available for differential mode."); + return -EINVAL; + } else if (channel_cfg->differential && (input_negative == (uint16_t)0)) { + LOG_ERR("Negative input is not selected."); + return -EINVAL; + } + + adc_init(ADC0, NDMA_M_CHN); + + data->differential = channel_cfg->differential; + + if (channel_cfg->differential) { + /* Differential pins configuration */ + /* The adc_channel_sample_init function has been configured and will not be configured here. */ + // adc_pin_config(input_positive); + // adc_pin_config(input_negative); + adc_set_diff_input(ADC0, ADC_M_CHANNEL, input_positive, input_negative); + } else if (input_positive == (uint16_t)ADC_VBAT_P) { + /* VBAT pin configuration */ + adc_chn_cfg_t adc_vbat_cfg_m = { + .pre_scale = pre_scale, + .sample_freq = sample_freq, + .input_p = input_positive, + .input_n = ADC_GND_N, + }; + adc_channel_sample_init(ADC0, ADC_VBAT_MODE, ADC_M_CHANNEL, &adc_vbat_cfg_m); + } else { + /* Single-ended GPIO pin configuration */ + adc_chn_cfg_t adc_gpio_cfg_m = { + .pre_scale = pre_scale, + .sample_freq = sample_freq, + .input_p = input_positive, + .input_n = ADC_GND_N, + }; + adc_channel_sample_init(ADC0, ADC_GPIO_MODE, ADC_M_CHANNEL, &adc_gpio_cfg_m); + } + return 0; +} + +#ifdef CONFIG_ADC_ASYNC +/* API implementation: read_async */ +static int adc_tlx_read_async(const struct device *dev, + const struct adc_sequence *sequence, + struct k_poll_signal *async) +{ + int status; + struct tlx_adc_data *data = dev->data; + + adc_context_lock(&data->ctx, true, async); + status = adc_tlx_adc_start_read(dev, sequence); + adc_context_release(&data->ctx, status); + + return status; +} +#endif /* CONFIG_ADC_ASYNC */ + +static struct tlx_adc_data data_0 = { + ADC_CONTEXT_INIT_TIMER(data_0, ctx), + ADC_CONTEXT_INIT_LOCK(data_0, ctx), + ADC_CONTEXT_INIT_SYNC(data_0, ctx), +}; + +PINCTRL_DT_INST_DEFINE(0); + +static const struct tlx_adc_cfg cfg_0 = { + .sample_freq = DT_INST_PROP(0, sample_freq), + .vref_internal_mv = DT_INST_PROP(0, vref_internal_mv), + .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(0), +}; + +static const struct adc_driver_api adc_tlx_driver_api = { + .channel_setup = adc_tlx_channel_setup, + .read = adc_tlx_read, +#ifdef CONFIG_ADC_ASYNC + .read_async = adc_tlx_read_async, +#endif + .ref_internal = cfg_0.vref_internal_mv, +}; + +DEVICE_DT_INST_DEFINE(0, adc_tlx_init, NULL, + &data_0, &cfg_0, + POST_KERNEL, + CONFIG_ADC_INIT_PRIORITY, + &adc_tlx_driver_api); diff --git a/drivers/bluetooth/hci/hci_tlx.c b/drivers/bluetooth/hci/hci_tlx.c index b6249785cde5f..0be9aaf84b326 100644 --- a/drivers/bluetooth/hci/hci_tlx.c +++ b/drivers/bluetooth/hci/hci_tlx.c @@ -10,7 +10,7 @@ #include #include -#define LOG_LEVEL CONFIG_BT_HCI_DRIVER_LOG_LEVEL +#define LOG_LEVEL LOG_LEVEL_NONE #include LOG_MODULE_REGISTER(bt_hci_driver_tlx); @@ -141,7 +141,7 @@ static void hci_tlx_host_rcv_pkt(uint8_t *data, uint16_t len) uint8_t pkt_indicator; struct net_buf *buf; - LOG_HEXDUMP_DBG(data, len, "host packet data:"); + LOG_HEXDUMP_WRN(data, len, "host packet data:"); pkt_indicator = *data++; len -= sizeof(pkt_indicator); @@ -234,6 +234,10 @@ static int hci_tlx_open(void) LOG_DBG("TL721X BT started"); #elif CONFIG_SOC_RISCV_TELINK_TL321X LOG_DBG("TL321X BT started"); +#elif CONFIG_SOC_RISCV_TELINK_TL322X + LOG_DBG("TL322X BT started"); +#elif CONFIG_SOC_RISCV_TELINK_TL323X + LOG_DBG("TL323X BT started"); #endif return 0; @@ -258,6 +262,10 @@ static const struct bt_hci_driver drv = { .name = "BT TL721X", #elif CONFIG_SOC_RISCV_TELINK_TL321X .name = "BT TL321X", +#elif CONFIG_SOC_RISCV_TELINK_TL322X + .name = "BT TL322X", +#elif CONFIG_SOC_RISCV_TELINK_TL323X + .name = "BT TL323X", #endif .open = hci_tlx_open, .close = hci_tlx_close, diff --git a/drivers/entropy/entropy_tlx_trng.c b/drivers/entropy/entropy_tlx_trng.c index 7fd597fd6e131..a2360a241966b 100644 --- a/drivers/entropy/entropy_tlx_trng.c +++ b/drivers/entropy/entropy_tlx_trng.c @@ -12,7 +12,7 @@ /* API implementation: driver initialization */ -static int entropy_b9x_trng_init(const struct device *dev) +static int entropy_tlx_trng_init(const struct device *dev) { ARG_UNUSED(dev); @@ -22,7 +22,7 @@ static int entropy_b9x_trng_init(const struct device *dev) } /* API implementation: get_entropy */ -static int entropy_b9x_trng_get_entropy(const struct device *dev, +static int entropy_tlx_trng_get_entropy(const struct device *dev, uint8_t *buffer, uint16_t length) { ARG_UNUSED(dev); @@ -46,26 +46,26 @@ static int entropy_b9x_trng_get_entropy(const struct device *dev, } /* API implementation: get_entropy_isr */ -static int entropy_b9x_trng_get_entropy_isr(const struct device *dev, +static int entropy_tlx_trng_get_entropy_isr(const struct device *dev, uint8_t *buffer, uint16_t length, uint32_t flags) { ARG_UNUSED(flags); /* No specific handling in case of running from ISR, just call standard API */ - entropy_b9x_trng_get_entropy(dev, buffer, length); + entropy_tlx_trng_get_entropy(dev, buffer, length); return 0; } /* Entropy driver APIs structure */ -static const struct entropy_driver_api entropy_b9x_trng_api = { - .get_entropy = entropy_b9x_trng_get_entropy, - .get_entropy_isr = entropy_b9x_trng_get_entropy_isr +static const struct entropy_driver_api entropy_tlx_trng_api = { + .get_entropy = entropy_tlx_trng_get_entropy, + .get_entropy_isr = entropy_tlx_trng_get_entropy_isr }; /* Entropy driver registration */ -DEVICE_DT_INST_DEFINE(0, entropy_b9x_trng_init, +DEVICE_DT_INST_DEFINE(0, entropy_tlx_trng_init, NULL, NULL, NULL, PRE_KERNEL_1, CONFIG_ENTROPY_INIT_PRIORITY, - &entropy_b9x_trng_api); + &entropy_tlx_trng_api); diff --git a/drivers/flash/soc_flash_tlx.c b/drivers/flash/soc_flash_tlx.c index 3cdde94072332..8ea716c12aa6f 100644 --- a/drivers/flash/soc_flash_tlx.c +++ b/drivers/flash/soc_flash_tlx.c @@ -17,6 +17,7 @@ #include #include #include +#include "tl_flash.h" LOG_MODULE_REGISTER(flash_tlx, CONFIG_FLASH_LOG_LEVEL); diff --git a/drivers/gpio/gpio_tlx.c b/drivers/gpio/gpio_tlx.c index 162e01f28e270..5c82e749be519 100644 --- a/drivers/gpio/gpio_tlx.c +++ b/drivers/gpio/gpio_tlx.c @@ -17,7 +17,7 @@ #if CONFIG_SOC_RISCV_TELINK_TL721X #define GPIO_IRQ_REG reg_gpio_irq_ctrl #include "gpio.h" -#elif CONFIG_SOC_RISCV_TELINK_TL321X +#elif CONFIG_SOC_RISCV_TELINK_TL321X || CONFIG_SOC_RISCV_TELINK_TL322X || CONFIG_SOC_RISCV_TELINK_TL323X #define GPIO_IRQ_REG reg_gpio_irq_ctrl #define GPIO_IRQ_LEVEL_REG reg_gpio_irq_level #define GPIO_IRQ_SRC_MASK_REG reg_gpio_irq_src_mask @@ -46,7 +46,7 @@ /* Check that gpio is port C */ #define IS_PORT_C(gpio) ((uint32_t)gpio == DT_REG_ADDR(DT_NODELABEL(gpioc))) -#if CONFIG_SOC_RISCV_TELINK_TL321X +#if CONFIG_SOC_RISCV_TELINK_TL321X || CONFIG_SOC_RISCV_TELINK_TL322X || CONFIG_SOC_RISCV_TELINK_TL323X /* Check that gpio is port B */ #define IS_PORT_B(gpio) ((uint32_t)gpio == DT_REG_ADDR(DT_NODELABEL(gpiob))) #elif CONFIG_SOC_RISCV_TELINK_TL721X @@ -55,19 +55,28 @@ #endif /* Check that gpio is port F */ -#if CONFIG_SOC_RISCV_TELINK_TL721X || CONFIG_SOC_RISCV_TELINK_TL321X +#if CONFIG_SOC_RISCV_TELINK_TL721X || CONFIG_SOC_RISCV_TELINK_TL321X || CONFIG_SOC_RISCV_TELINK_TL322X || CONFIG_SOC_RISCV_TELINK_TL323X #define IS_PORT_F(gpio) ((uint32_t)gpio == DT_REG_ADDR(DT_NODELABEL(gpiof))) #else #define IS_PORT_F(gpio) 0 #endif /* Check that gpio is port G */ -#if CONFIG_SOC_RISCV_TELINK_TL321X +#if CONFIG_SOC_RISCV_TELINK_TL321X || CONFIG_SOC_RISCV_TELINK_TL323X #define IS_PORT_G(gpio) 0 -#elif CONFIG_SOC_RISCV_TELINK_TL721X +#elif CONFIG_SOC_RISCV_TELINK_TL721X || CONFIG_SOC_RISCV_TELINK_TL322X #define IS_PORT_G(gpio) ((uint32_t)gpio == DT_REG_ADDR(DT_NODELABEL(gpiog))) #endif +/* Check that gpio is port H & I */ +#if CONFIG_SOC_RISCV_TELINK_TL321X || CONFIG_SOC_RISCV_TELINK_TL721X || CONFIG_SOC_RISCV_TELINK_TL323X +#define IS_PORT_H(gpio) 0 +#define IS_PORT_I(gpio) 0 +#elif CONFIG_SOC_RISCV_TELINK_TL322X +#define IS_PORT_H(gpio) ((uint32_t)gpio == DT_REG_ADDR(DT_NODELABEL(gpioh))) +#define IS_PORT_I(gpio) ((uint32_t)gpio == DT_REG_ADDR(DT_NODELABEL(gpioi))) +#endif + /* Check that 'inst' has only 1 interrupt selected in dts */ #define IS_INST_IRQ_EN(inst) (DT_NUM_IRQS(DT_DRV_INST(inst)) == 1) @@ -81,7 +90,7 @@ #endif /* GPIO Wakeup Enable registers */ -#if CONFIG_SOC_RISCV_TELINK_TL721X || CONFIG_SOC_RISCV_TELINK_TL321X +#if CONFIG_SOC_RISCV_TELINK_TL721X || CONFIG_SOC_RISCV_TELINK_TL321X || CONFIG_SOC_RISCV_TELINK_TL322X || CONFIG_SOC_RISCV_TELINK_TL323X #define reg_wakeup_trig_pol_base 0x3f #define reg_wakeup_trig_en_base 0x45 @@ -104,7 +113,7 @@ #if CONFIG_SOC_RISCV_TELINK_TL721X #define IRQ_GPIO2_RISC0 ((uint8_t)26u) #define IRQ_GPIO2_RISC1 ((uint8_t)27u) -#elif CONFIG_SOC_RISCV_TELINK_TL321X +#elif CONFIG_SOC_RISCV_TELINK_TL321X || CONFIG_SOC_RISCV_TELINK_TL322X || CONFIG_SOC_RISCV_TELINK_TL323X #define IRQ_GPIO0 ((uint8_t)34u) #define IRQ_GPIO1 ((uint8_t)35u) #define IRQ_GPIO2 ((uint8_t)36u) @@ -154,6 +163,25 @@ struct gpio_tlx_t { uint8_t irq6; /* IRQ_EN:GPIO interrupt */ uint8_t irq7; /* IRQ_EN:GPIO interrupt */ }; +#elif CONFIG_SOC_RISCV_TELINK_TL322X || CONFIG_SOC_RISCV_TELINK_TL323X +struct gpio_tlx_t { + uint8_t input; /* Input: read GPI input */ + uint8_t ie; /* IE: input enable, high active. 1: enable, 0: disable */ + uint8_t oen; /* OEN: output enable, low active. 0: enable, 1: disable */ + uint8_t polarity; /* Polarity: interrupt polarity: rising, falling */ + uint8_t output; /* Output: GPIO output set */ + uint8_t output_clr; /* Output: GPIO output clear */ + uint8_t actas_gpio; /* Act as GPIO: enable (1) or disable (0) GPIO function */ + uint8_t output_toggle; /* Output: GPIO output toggle */ + uint8_t sr; + uint8_t ds0; + uint8_t ds1; + uint8_t rsvd0; + uint8_t rsvd1; + uint8_t rsvd2; + uint8_t rsvd3; + uint8_t rsvd4; +}; #endif /* GPIO IRQ configuration structure */ @@ -183,6 +211,15 @@ struct gpio_tlx_retention_data { uint8_t risc0_irq_conf; uint8_t risc1_irq_conf; }; +#elif CONFIG_SOC_RISCV_TELINK_TL322X || CONFIG_SOC_RISCV_TELINK_TL323X +struct gpio_tlx_retention_data { + struct gpio_tlx_t gpio_tlx_periph_config; + uint8_t gpio_tlx_irq_conf; + uint8_t analog_in_conf; + uint8_t analog_pupd_conf[2]; + uint8_t level_irq_conf; + uint8_t src_mask_irq_conf; +}; #elif CONFIG_SOC_RISCV_TELINK_TL321X struct gpio_tlx_retention_data { struct gpio_tlx_t gpio_tlx_periph_config; @@ -279,6 +316,27 @@ static inline void gpio_tlx_irq_en_set(const struct device *dev, gpio_pin_t pin) } else { __ASSERT(false, "Not supported GPIO IRQ number."); } +#elif CONFIG_SOC_RISCV_TELINK_TL322X || CONFIG_SOC_RISCV_TELINK_TL323X + uint16_t gpio_pin_elem = (GET_PORT_NUM(gpio) << 8) | pin; + if (irq == IRQ_GPIO0) { + BM_SET(reg_gpio_irq0_en(gpio_pin_elem), BIT(pin)); + } else if (irq == IRQ_GPIO1) { + BM_SET(reg_gpio_irq1_en(gpio_pin_elem), BIT(pin)); + } else if (irq == IRQ_GPIO2) { + BM_SET(reg_gpio_irq2_en(gpio_pin_elem), BIT(pin)); + } else if (irq == IRQ_GPIO3) { + BM_SET(reg_gpio_irq3_en(gpio_pin_elem), BIT(pin)); + } else if (irq == IRQ_GPIO4) { + BM_SET(reg_gpio_irq4_en(gpio_pin_elem), BIT(pin)); + } else if (irq == IRQ_GPIO5) { + BM_SET(reg_gpio_irq5_en(gpio_pin_elem), BIT(pin)); + } else if (irq == IRQ_GPIO6) { + BM_SET(reg_gpio_irq6_en(gpio_pin_elem), BIT(pin)); + } else if (irq == IRQ_GPIO7) { + BM_SET(reg_gpio_irq7_en(gpio_pin_elem), BIT(pin)); + } else { + __ASSERT(false, "Not supported GPIO IRQ number."); + } #endif } @@ -316,6 +374,27 @@ static inline void gpio_tlx_irq_en_clr(const struct device *dev, gpio_pin_t pin) } else if (irq == IRQ_GPIO7) { BM_CLR(gpio->irq7, BIT(pin)); } +#elif CONFIG_SOC_RISCV_TELINK_TL322X || CONFIG_SOC_RISCV_TELINK_TL323X + uint16_t gpio_pin_elem = (GET_PORT_NUM(gpio) << 8) | pin; + if (irq == IRQ_GPIO0) { + BM_CLR(reg_gpio_irq0_en(gpio_pin_elem), BIT(pin)); + } else if (irq == IRQ_GPIO1) { + BM_CLR(reg_gpio_irq1_en(gpio_pin_elem), BIT(pin)); + } else if (irq == IRQ_GPIO2) { + BM_CLR(reg_gpio_irq2_en(gpio_pin_elem), BIT(pin)); + } else if (irq == IRQ_GPIO3) { + BM_CLR(reg_gpio_irq3_en(gpio_pin_elem), BIT(pin)); + } else if (irq == IRQ_GPIO4) { + BM_CLR(reg_gpio_irq4_en(gpio_pin_elem), BIT(pin)); + } else if (irq == IRQ_GPIO5) { + BM_CLR(reg_gpio_irq5_en(gpio_pin_elem), BIT(pin)); + } else if (irq == IRQ_GPIO6) { + BM_CLR(reg_gpio_irq6_en(gpio_pin_elem), BIT(pin)); + } else if (irq == IRQ_GPIO7) { + BM_CLR(reg_gpio_irq7_en(gpio_pin_elem), BIT(pin)); + } else { + __ASSERT(false, "Not supported GPIO IRQ number."); + } #endif #if CONFIG_PM_DEVICE @@ -358,6 +437,25 @@ static inline uint8_t gpio_tlx_irq_en_get(const struct device *dev) } else if (irq == IRQ_GPIO7) { status = gpio->irq7; } +#elif CONFIG_SOC_RISCV_TELINK_TL322X || CONFIG_SOC_RISCV_TELINK_TL323X + uint16_t gpio_pin_elem = (GET_PORT_NUM(gpio) << 8); + if (irq == IRQ_GPIO0) { + status = reg_gpio_irq0_en(gpio_pin_elem); + } else if (irq == IRQ_GPIO1) { + status = reg_gpio_irq1_en(gpio_pin_elem); + } else if (irq == IRQ_GPIO2) { + status = reg_gpio_irq2_en(gpio_pin_elem); + } else if (irq == IRQ_GPIO3) { + status = reg_gpio_irq3_en(gpio_pin_elem); + } else if (irq == IRQ_GPIO4) { + status = reg_gpio_irq4_en(gpio_pin_elem); + } else if (irq == IRQ_GPIO5) { + status = reg_gpio_irq5_en(gpio_pin_elem); + } else if (irq == IRQ_GPIO6) { + status = reg_gpio_irq6_en(gpio_pin_elem); + } else if (irq == IRQ_GPIO7) { + status = reg_gpio_irq7_en(gpio_pin_elem); + } #endif return status; } @@ -377,7 +475,7 @@ static inline void gpio_tlx_irq_status_clr(uint8_t irq) status = FLD_GPIO_IRQ_GPIO2RISC1_CLR; } reg_gpio_irq_clr = status; -#elif CONFIG_SOC_RISCV_TELINK_TL321X +#elif CONFIG_SOC_RISCV_TELINK_TL321X || CONFIG_SOC_RISCV_TELINK_TL322X || CONFIG_SOC_RISCV_TELINK_TL323X gpio_irq_e status = 0; if (irq == IRQ_GPIO0) { @@ -444,7 +542,7 @@ void gpio_tlx_irq_set(const struct device *dev, gpio_pin_t pin, } gpio_tlx_irq_status_clr(irq_num); BM_SET(GPIO_IRQ_REG, irq_mask); -#elif CONFIG_SOC_RISCV_TELINK_TL321X +#elif CONFIG_SOC_RISCV_TELINK_TL321X || CONFIG_SOC_RISCV_TELINK_TL322X || CONFIG_SOC_RISCV_TELINK_TL323X gpio_tlx_irq_status_clr(irq_num); /* Get level and mask based on IRQ number */ @@ -516,12 +614,20 @@ static void gpio_tlx_up_down_res_set(volatile struct gpio_tlx_t *gpio, pin = BIT(pin); val = up_down_res & 0x03; - #if CONFIG_SOC_RISCV_TELINK_TL721X || CONFIG_SOC_RISCV_TELINK_TL321X +#if CONFIG_SOC_RISCV_TELINK_TL321X || CONFIG_SOC_RISCV_TELINK_TL323X if ((IS_PORT_F(gpio)) || (IS_PORT_G(gpio))) { return; } +#elif CONFIG_SOC_RISCV_TELINK_TL721X + if ((IS_PORT_G(gpio))) { + return; + } +#elif CONFIG_SOC_RISCV_TELINK_TL322X + if (IS_PORT_I(gpio)) { + return; + } +#endif analog_reg = 0x17 + (GET_PORT_NUM(gpio) << 1) + ((pin & 0xf0) ? 1 : 0); - #endif if (pin & 0x11) { val = val << 0; @@ -561,12 +667,12 @@ static void gpio_tlx_config_in_out(volatile struct gpio_tlx_t *gpio, gpio_pin_t pin, gpio_flags_t flags) { - uint8_t ie_addr = 0; + uint16_t ie_addr = 0; /* Port C and D Input Enable registers are located in another place: analog */ if (IS_PORT_C(gpio)) { ie_addr = areg_gpio_pc_ie; -#if CONFIG_SOC_RISCV_TELINK_TL321X +#if CONFIG_SOC_RISCV_TELINK_TL321X || CONFIG_SOC_RISCV_TELINK_TL322X || CONFIG_SOC_RISCV_TELINK_TL323X } else if (IS_PORT_B(gpio) && ((pin >= 4) && (pin <= 7))) { ie_addr = areg_gpio_pb_ie; #elif CONFIG_SOC_RISCV_TELINK_TL721X @@ -628,7 +734,7 @@ static int gpio_tlx_pin_configure(const struct device *dev, return -ENOTSUP; } -#if CONFIG_SOC_RISCV_TELINK_TL721X || CONFIG_SOC_RISCV_TELINK_TL321X +#if CONFIG_SOC_RISCV_TELINK_TL721X || CONFIG_SOC_RISCV_TELINK_TL321X || CONFIG_SOC_RISCV_TELINK_TL323X /* Avoid pulls in TL721X SoC in PF[0:5] due to silicone limitation */ if (IS_PORT_F(gpio) && (flags & (GPIO_PULL_UP | GPIO_PULL_DOWN)) && (pin != 6) && (pin != 7)) { @@ -662,7 +768,7 @@ static int gpio_tlx_port_get_raw(const struct device *dev, volatile struct gpio_tlx_t *gpio = GET_GPIO(dev); *value = gpio->input; - + // printk("gpio->input = 0x%08x\n", gpio->input); return 0; } @@ -672,7 +778,7 @@ static int gpio_tlx_port_set_masked_raw(const struct device *dev, gpio_port_value_t value) { volatile struct gpio_tlx_t *gpio = GET_GPIO(dev); -#if CONFIG_SOC_RISCV_TELINK_TL721X || CONFIG_SOC_RISCV_TELINK_TL321X +#if CONFIG_SOC_RISCV_TELINK_TL721X || CONFIG_SOC_RISCV_TELINK_TL321X || CONFIG_SOC_RISCV_TELINK_TL322X || CONFIG_SOC_RISCV_TELINK_TL323X gpio->output_clr = (mask); gpio->output = (value & mask); #endif @@ -684,7 +790,7 @@ static int gpio_tlx_port_set_bits_raw(const struct device *dev, gpio_port_pins_t mask) { volatile struct gpio_tlx_t *gpio = GET_GPIO(dev); -#if CONFIG_SOC_RISCV_TELINK_TL721X || CONFIG_SOC_RISCV_TELINK_TL321X +#if CONFIG_SOC_RISCV_TELINK_TL721X || CONFIG_SOC_RISCV_TELINK_TL321X || CONFIG_SOC_RISCV_TELINK_TL322X || CONFIG_SOC_RISCV_TELINK_TL323X gpio->output = (mask); #endif return 0; @@ -695,7 +801,7 @@ static int gpio_tlx_port_clear_bits_raw(const struct device *dev, gpio_port_pins_t mask) { volatile struct gpio_tlx_t *gpio = GET_GPIO(dev); -#if CONFIG_SOC_RISCV_TELINK_TL721X || CONFIG_SOC_RISCV_TELINK_TL321X +#if CONFIG_SOC_RISCV_TELINK_TL721X || CONFIG_SOC_RISCV_TELINK_TL321X || CONFIG_SOC_RISCV_TELINK_TL322X || CONFIG_SOC_RISCV_TELINK_TL323X gpio->output_clr = (mask); #endif return 0; @@ -706,7 +812,7 @@ static int gpio_tlx_port_toggle_bits(const struct device *dev, gpio_port_pins_t mask) { volatile struct gpio_tlx_t *gpio = GET_GPIO(dev); -#if CONFIG_SOC_RISCV_TELINK_TL721X || CONFIG_SOC_RISCV_TELINK_TL321X +#if CONFIG_SOC_RISCV_TELINK_TL721X || CONFIG_SOC_RISCV_TELINK_TL321X || CONFIG_SOC_RISCV_TELINK_TL322X || CONFIG_SOC_RISCV_TELINK_TL323X uint8_t bits = (mask & 0xff); gpio->output_toggle = bits; @@ -758,6 +864,7 @@ static int gpio_tlx_pin_interrupt_configure(const struct device *dev, enum gpio_int_mode mode, enum gpio_int_trig trig) { + // printk("gpio_tlx_pin_interrupt_configure(): pin=%d, mode=%d, trig=%d\n", pin, mode, trig); const struct gpio_tlx_config *cfg = dev->config; int ret_status = 0; bool current_pin_value = ((GET_GPIO(dev)->input) >> pin) & 0x0001; @@ -841,7 +948,7 @@ static int gpio_tlx_pm_action(const struct device *dev, enum pm_device_action ac if (IS_PORT_C(gpio)) { analog_write_reg8(areg_gpio_pc_ie, data->gpio_tlx_retention.analog_in_conf); -#if CONFIG_SOC_RISCV_TELINK_TL321X +#if CONFIG_SOC_RISCV_TELINK_TL321X || CONFIG_SOC_RISCV_TELINK_TL322X || CONFIG_SOC_RISCV_TELINK_TL323X } else if (IS_PORT_B(gpio)) { analog_write_reg8(areg_gpio_pb_ie, data->gpio_tlx_retention.analog_in_conf); @@ -869,7 +976,7 @@ static int gpio_tlx_pm_action(const struct device *dev, enum pm_device_action ac = data->gpio_tlx_retention.risc0_irq_conf; reg_irq_risc1_en(GET_PORT_NUM(gpio)) = data->gpio_tlx_retention.risc1_irq_conf; -#elif CONFIG_SOC_RISCV_TELINK_TL321X +#elif CONFIG_SOC_RISCV_TELINK_TL321X || CONFIG_SOC_RISCV_TELINK_TL322X || CONFIG_SOC_RISCV_TELINK_TL323X GPIO_IRQ_LEVEL_REG = data->gpio_tlx_retention.level_irq_conf; GPIO_IRQ_SRC_MASK_REG @@ -917,7 +1024,7 @@ static int gpio_tlx_pm_action(const struct device *dev, enum pm_device_action ac = reg_irq_risc0_en(GET_PORT_NUM(gpio)); data->gpio_tlx_retention.risc1_irq_conf = reg_irq_risc1_en(GET_PORT_NUM(gpio)); -#elif CONFIG_SOC_RISCV_TELINK_TL321X +#elif CONFIG_SOC_RISCV_TELINK_TL321X || CONFIG_SOC_RISCV_TELINK_TL322X || CONFIG_SOC_RISCV_TELINK_TL323X data->gpio_tlx_retention.level_irq_conf = GPIO_IRQ_LEVEL_REG; data->gpio_tlx_retention.src_mask_irq_conf @@ -926,7 +1033,7 @@ static int gpio_tlx_pm_action(const struct device *dev, enum pm_device_action ac if (IS_PORT_C(gpio)) { data->gpio_tlx_retention.analog_in_conf = analog_read_reg8(areg_gpio_pc_ie); -#if CONFIG_SOC_RISCV_TELINK_TL321X +#if CONFIG_SOC_RISCV_TELINK_TL321X || CONFIG_SOC_RISCV_TELINK_TL322X || CONFIG_SOC_RISCV_TELINK_TL323X } else if (IS_PORT_B(gpio)) { data->gpio_tlx_retention.analog_in_conf = analog_read_reg8(areg_gpio_pb_ie); @@ -1030,7 +1137,7 @@ static void gpio_tlx_irq_connect_4(void) } #endif -#if CONFIG_SOC_RISCV_TELINK_TL721X || CONFIG_SOC_RISCV_TELINK_TL321X +#if CONFIG_SOC_RISCV_TELINK_TL721X || CONFIG_SOC_RISCV_TELINK_TL321X || CONFIG_SOC_RISCV_TELINK_TL322X || CONFIG_SOC_RISCV_TELINK_TL323X /* If instance 5 is present and has interrupt enabled, connect IRQ */ #if DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) > 5 static void gpio_tlx_irq_connect_5(void) @@ -1055,6 +1162,29 @@ static void gpio_tlx_irq_connect_6(void) } #endif +#if DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) > 7 +static void gpio_tlx_irq_connect_7(void) +{ + #if IS_INST_IRQ_EN(7) + IRQ_CONNECT(DT_INST_IRQN(7), DT_INST_IRQ(7, priority), + gpio_tlx_irq_handler, + DEVICE_DT_INST_GET(7), 0); + #endif +} +#endif + +#if DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) > 8 +static void gpio_tlx_irq_connect_8(void) +{ + #if IS_INST_IRQ_EN(8) + IRQ_CONNECT(DT_INST_IRQN(8), DT_INST_IRQ(8, priority), + gpio_tlx_irq_handler, + DEVICE_DT_INST_GET(8), 0); + #endif +} +#endif + + #endif #if CONFIG_PM_DEVICE && CONFIG_SOC_SERIES_RISCV_TELINK_TLX_RETENTION diff --git a/drivers/hwinfo/hwinfo_tlx.c b/drivers/hwinfo/hwinfo_tlx.c index 2bf91ff3a9cdf..4723339d2d8e5 100644 --- a/drivers/hwinfo/hwinfo_tlx.c +++ b/drivers/hwinfo/hwinfo_tlx.c @@ -13,7 +13,7 @@ extern void pm_update_status_info(unsigned char clr_en); static bool is_mcu_status_updated; -#if CONFIG_SOC_RISCV_TELINK_TL721X +#if CONFIG_SOC_RISCV_TELINK_TL721X || CONFIG_SOC_RISCV_TELINK_TL322X #include #endif @@ -22,7 +22,7 @@ ssize_t z_impl_hwinfo_get_device_id(uint8_t *buffer, size_t length) uint32_t flash_mid = 0; uint8_t uid[16]; -#if CONFIG_SOC_RISCV_TELINK_TL721X +#if CONFIG_SOC_RISCV_TELINK_TL721X || CONFIG_SOC_RISCV_TELINK_TL322X flash_mid = flash_read_mid_with_device_num(SLAVE0); flash_read_mid_uid_with_check_with_device_num(SLAVE0, &flash_mid, uid); #else diff --git a/drivers/i2c/i2c_tlx.c b/drivers/i2c/i2c_tlx.c index 1ba21ec5e5fe7..3824783283f54 100644 --- a/drivers/i2c/i2c_tlx.c +++ b/drivers/i2c/i2c_tlx.c @@ -65,8 +65,13 @@ static int i2c_tlx_configure(const struct device *dev, uint32_t dev_config) } /* init i2c */ +#ifdef CONFIG_SOC_RISCV_TELINK_TL322X + i2c_master_init(I2C0); + i2c_set_master_clk(I2C0, (unsigned char)(sys_clk.pclk * 1000 * 1000 / (4 * i2c_speed))); +#else i2c_master_init(); i2c_set_master_clk((unsigned char)(sys_clk.pclk * 1000 * 1000 / (4 * i2c_speed))); +#endif return 0; } @@ -95,13 +100,26 @@ static int i2c_tlx_transfer(const struct device *dev, /* config stop bit */ send_stop = msgs[i].flags & I2C_MSG_STOP ? 1 : 0; +#ifdef CONFIG_SOC_RISCV_TELINK_TL322X + i2c_master_send_stop(I2C0, send_stop); +#else i2c_master_send_stop(send_stop); +#endif /* transfer data */ if (msgs[i].flags & I2C_MSG_READ) { +#ifdef CONFIG_SOC_RISCV_TELINK_TL322X + status = i2c_master_read(I2C0, addr << 1, msgs[i].buf, msgs[i].len); +#else status = i2c_master_read(addr << 1, msgs[i].buf, msgs[i].len); + +#endif } else { +#ifdef CONFIG_SOC_RISCV_TELINK_TL322X + status = i2c_master_write(I2C0, addr << 1, msgs[i].buf, msgs[i].len); +#else status = i2c_master_write(addr << 1, msgs[i].buf, msgs[i].len); +#endif } /* check status */ @@ -135,7 +153,6 @@ static int i2c_tlx_init(const struct device *dev) LOG_ERR("Failed to configure I2C on init"); return status; } - /* configure pins */ status = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT); if (status < 0) { diff --git a/drivers/ieee802154/ieee802154_b9x.c b/drivers/ieee802154/ieee802154_b9x.c index f93083e983a22..e992d3590dd22 100644 --- a/drivers/ieee802154/ieee802154_b9x.c +++ b/drivers/ieee802154/ieee802154_b9x.c @@ -575,26 +575,32 @@ ALWAYS_INLINE b9x_send_ack(const struct device *dev, struct ieee802154_frame *fr size_t ack_len; #ifdef CONFIG_IEEE802154_2015 const uint8_t *key = NULL; - uint32_t frame_cnt = b9x_mac_keys_frame_cnt_get(b9x->mac_keys, 1); - const uint8_t sec_header[] = { - IEEE802154_FRAME_SECCTRL_SEC_LEVEL_5 | IEEE802154_FRAME_SECCTRL_KEY_ID_MODE_1, - frame_cnt, - frame_cnt >> 8, - frame_cnt >> 16, - frame_cnt >> 24, - 1 + uint32_t frame_cnt; + uint8_t sec_header[] = { + IEEE802154_FRAME_SECCTRL_SEC_LEVEL_5 | IEEE802154_FRAME_SECCTRL_KEY_ID_MODE_1, + 0, + 0, + 0, + 0, + 1 }; uint8_t payload[frame->payload_len + 4]; if (frame->general.ver == IEEE802154_FRAME_FCF_VER_2015) { - key = b9x_mac_keys_get(b9x->mac_keys, 1); - if (key && frame->payload) { - memcpy(payload, frame->payload, frame->payload_len); - frame->sec_header = sec_header; - frame->sec_header_len = sizeof(sec_header); - frame->payload = payload; - frame->payload_len = sizeof(payload); - } + key = b9x_mac_keys_get(b9x->mac_keys, 1); + if (key && frame->payload) { + b9x_mac_keys_frame_cnt_inc(b9x->mac_keys, 1); + frame_cnt = b9x_mac_keys_frame_cnt_get(b9x->mac_keys, 1); + sec_header[1] = frame_cnt; + sec_header[2] = frame_cnt >> 8; + sec_header[3] = frame_cnt >> 16; + sec_header[4] = frame_cnt >> 24; + memcpy(payload, frame->payload, frame->payload_len); + frame->sec_header = sec_header; + frame->sec_header_len = sizeof(sec_header); + frame->payload = payload; + frame->payload_len = sizeof(payload); + } } #endif /* CONFIG_IEEE802154_2015 */ @@ -604,19 +610,17 @@ ALWAYS_INLINE b9x_send_ack(const struct device *dev, struct ieee802154_frame *fr rf_set_txmode(); #ifdef CONFIG_IEEE802154_2015 if (frame->sec_header) { - if (ieee802154_b9x_crypto_encrypt(key, b9x->filter_ieee_addr, - frame_cnt, - IEEE802154_FRAME_SECCTRL_SEC_LEVEL_5, - ack_buf, ack_len - 4, - NULL, 0, - NULL, - &ack_buf[ack_len - 4], 4)) { - b9x_mac_keys_frame_cnt_inc(b9x->mac_keys, 1); - } else { - LOG_WRN("encrypt ack failed"); - } + if (!ieee802154_b9x_crypto_encrypt(key, b9x->filter_ieee_addr, + frame_cnt, + IEEE802154_FRAME_SECCTRL_SEC_LEVEL_5, + ack_buf, ack_len - 4, + NULL, 0, + NULL, + &ack_buf[ack_len - 4], 4)) { + LOG_WRN("encrypt ack failed"); + } } else { - delay_us(CONFIG_IEEE802154_B9X_SET_TXRX_DELAY_US); + delay_us(CONFIG_IEEE802154_B9X_SET_TXRX_DELAY_US); } #else delay_us(CONFIG_IEEE802154_B9X_SET_TXRX_DELAY_US); @@ -924,6 +928,7 @@ static int b9x_cca(const struct device *dev) unsigned int t1 = stimer_get_tick(); rf_set_rxmode(); + delay_us(85); rssi_cur = rf_get_rssi(); rssiSum += rssi_cur; @@ -934,7 +939,6 @@ static int b9x_cca(const struct device *dev) } rssi_peak = rssiSum/cnt; - rf_set_tx_rx_off(); if (rssi_peak > CONFIG_IEEE802154_B9X_CCA_RSSI_THRESHOLD) { return -EBUSY; @@ -1177,6 +1181,8 @@ static int b9x_tx(const struct device *dev, break; } + b9x_mac_keys_frame_cnt_inc(b9x->mac_keys, key_id); + uint8_t *frame_cnt = (uint8_t *)&frame.sec_header[IEEE802154_FRAME_LENGTH_SEC_HEADER]; @@ -1312,11 +1318,6 @@ static int b9x_tx(const struct device *dev, } b9x->ack_handler_en = false; } -#ifdef CONFIG_IEEE802154_2015 - if (!status) { - b9x_mac_keys_frame_cnt_inc(b9x->mac_keys, key_id); - } -#endif /* CONFIG_IEEE802154_2015 */ return status; } diff --git a/drivers/ieee802154/ieee802154_tlx.c b/drivers/ieee802154/ieee802154_tlx.c index 884c4dcfd476f..2f1ba63333482 100644 --- a/drivers/ieee802154/ieee802154_tlx.c +++ b/drivers/ieee802154/ieee802154_tlx.c @@ -6,13 +6,6 @@ #define DT_DRV_COMPAT telink_tlx_zb -#include "rf_common.h" -#include "stimer.h" -#include "tl_rf_power.h" -#include "gpio.h" -#include "plic.h" -#include "clock.h" - #define LOG_MODULE_NAME ieee802154_tlx #if defined(CONFIG_IEEE802154_DRIVER_LOG_LEVEL) #define LOG_LEVEL CONFIG_IEEE802154_DRIVER_LOG_LEVEL @@ -37,6 +30,15 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #include "ieee802154_tlx_frame.c" +#include "rf_common.h" +#include "stimer.h" +#include "tl_rf_power.h" +#include "gpio.h" +#include "plic.h" +#include "clock.h" +#include "tlx_bt.h" +#include "drivers.h" + #if defined(CONFIG_IEEE802154_TLX_MAC_FLASH) #include #include @@ -587,26 +589,32 @@ ALWAYS_INLINE tlx_send_ack(const struct device *dev, struct ieee802154_frame *fr size_t ack_len; #ifdef CONFIG_IEEE802154_2015 const uint8_t *key = NULL; - uint32_t frame_cnt = tlx_mac_keys_frame_cnt_get(tlx->mac_keys, 1); - const uint8_t sec_header[] = { - IEEE802154_FRAME_SECCTRL_SEC_LEVEL_5 | IEEE802154_FRAME_SECCTRL_KEY_ID_MODE_1, - frame_cnt, - frame_cnt >> 8, - frame_cnt >> 16, - frame_cnt >> 24, - 1 + uint32_t frame_cnt; + uint8_t sec_header[] = { + IEEE802154_FRAME_SECCTRL_SEC_LEVEL_5 | IEEE802154_FRAME_SECCTRL_KEY_ID_MODE_1, + 0, + 0, + 0, + 0, + 1 }; uint8_t payload[frame->payload_len + 4]; if (frame->general.ver == IEEE802154_FRAME_FCF_VER_2015) { - key = tlx_mac_keys_get(tlx->mac_keys, 1); - if (key && frame->payload) { - memcpy(payload, frame->payload, frame->payload_len); - frame->sec_header = sec_header; - frame->sec_header_len = sizeof(sec_header); - frame->payload = payload; - frame->payload_len = sizeof(payload); - } + key = tlx_mac_keys_get(tlx->mac_keys, 1); + if (key && frame->payload) { + tlx_mac_keys_frame_cnt_inc(tlx->mac_keys, 1); + frame_cnt = tlx_mac_keys_frame_cnt_get(tlx->mac_keys, 1); + sec_header[1] = frame_cnt; + sec_header[2] = frame_cnt >> 8; + sec_header[3] = frame_cnt >> 16; + sec_header[4] = frame_cnt >> 24; + memcpy(payload, frame->payload, frame->payload_len); + frame->sec_header = sec_header; + frame->sec_header_len = sizeof(sec_header); + frame->payload = payload; + frame->payload_len = sizeof(payload); + } } #endif /* CONFIG_IEEE802154_2015 */ @@ -616,19 +624,17 @@ ALWAYS_INLINE tlx_send_ack(const struct device *dev, struct ieee802154_frame *fr rf_set_txmode(); #ifdef CONFIG_IEEE802154_2015 if (frame->sec_header) { - if (ieee802154_tlx_crypto_encrypt(key, tlx->filter_ieee_addr, - frame_cnt, - IEEE802154_FRAME_SECCTRL_SEC_LEVEL_5, - ack_buf, ack_len - 4, - NULL, 0, - NULL, - &ack_buf[ack_len - 4], 4)) { - tlx_mac_keys_frame_cnt_inc(tlx->mac_keys, 1); - } else { - LOG_WRN("encrypt ack failed"); - } + if (!ieee802154_tlx_crypto_encrypt(key, tlx->filter_ieee_addr, + frame_cnt, + IEEE802154_FRAME_SECCTRL_SEC_LEVEL_5, + ack_buf, ack_len - 4, + NULL, 0, + NULL, + &ack_buf[ack_len - 4], 4)) { + LOG_WRN("encrypt ack failed"); + } } else { - delay_us(CONFIG_IEEE802154_TLX_SET_TXRX_DELAY_US); + delay_us(CONFIG_IEEE802154_TLX_SET_TXRX_DELAY_US); } #else delay_us(CONFIG_IEEE802154_TLX_SET_TXRX_DELAY_US); @@ -650,7 +656,7 @@ static void ALWAYS_INLINE tlx_rf_rx_isr(const struct device *dev) #if defined(CONFIG_NET_PKT_TIMESTAMP) && defined(CONFIG_NET_PKT_TXTIME) uint64_t rx_time = k_ticks_to_us_near64(k_uptime_ticks()); -#if CONFIG_SOC_RISCV_TELINK_TL321X +#if CONFIG_SOC_RISCV_TELINK_TL321X || CONFIG_SOC_RISCV_TELINK_TL322X || CONFIG_SOC_RISCV_TELINK_TL323X uint32_t delta_time = (stimer_get_tick() - ZB_RADIO_TIMESTAMP_GET(tlx->rx_buffer)) / SYSTEM_TIMER_TICK_1US; #elif CONFIG_SOC_RISCV_TELINK_TL721X @@ -943,6 +949,7 @@ static int tlx_cca(const struct device *dev) unsigned int t1 = stimer_get_tick(); rf_set_rxmode(); + delay_us(85); rssi_cur = rf_get_rssi(); rssiSum += rssi_cur; @@ -976,6 +983,7 @@ static int tlx_set_channel(const struct device *dev, uint16_t channel) tlx->current_channel = channel; if (tlx->is_started) { rf_set_chn(TLX_LOGIC_CHANNEL_TO_PHYSICAL(channel)); + rf_set_rxmode(); } } @@ -1058,10 +1066,21 @@ static int tlx_start(const struct device *dev) ske_dig_en(); #endif if (tlx->rf_mode_154 == false) { - rf_baseband_reset(); - rf_reset_dma(); + if(tl_rf_is_inited()){ + rf_baseband_reset(); + rf_reset_dma(); + } + else{ + tl_rf_change_to_inited(); + } + tlx->rf_mode_154 = true; } +#if CONFIG_SOC_RISCV_TELINK_TL322X + sys_n22_init(0x20080000); + rf_n22_dig_init(); + rf_clr_irq_mask(FLD_RF_IRQ_ALL); +#endif rf_mode_init(); rf_set_zigbee_250K_mode(); tlx_rf_zigbee_250K_mode = true; @@ -1076,6 +1095,7 @@ static int tlx_start(const struct device *dev) } rf_set_irq_mask(FLD_RF_IRQ_RX | FLD_RF_IRQ_TX); riscv_plic_irq_enable(DT_INST_IRQN(0) - CONFIG_2ND_LVL_ISR_TBL_OFFSET); + rf_set_rxmode(); tlx->is_started = true; } @@ -1099,7 +1119,7 @@ static int tlx_stop(const struct device *dev) #ifdef CONFIG_PM_DEVICE /* Reset Radio */ rf_radio_reset(); -#if CONFIG_SOC_RISCV_TELINK_TL321X || CONFIG_SOC_RISCV_TELINK_TL721X +#if CONFIG_SOC_RISCV_TELINK_TL321X || CONFIG_SOC_RISCV_TELINK_TL721X || CONFIG_SOC_RISCV_TELINK_TL323X rf_reset_dma(); rf_baseband_reset(); #endif @@ -1214,6 +1234,8 @@ static int tlx_tx(const struct device *dev, break; } + tlx_mac_keys_frame_cnt_inc(tlx->mac_keys, key_id); + uint8_t *frame_cnt = (uint8_t *)&frame.sec_header[IEEE802154_FRAME_LENGTH_SEC_HEADER]; @@ -1375,11 +1397,6 @@ static int tlx_tx(const struct device *dev, } tlx->ack_handler_en = false; } -#ifdef CONFIG_IEEE802154_2015 - if (!status) { - tlx_mac_keys_frame_cnt_inc(tlx->mac_keys, key_id); - } -#endif /* CONFIG_IEEE802154_2015 */ return status; } diff --git a/drivers/ieee802154/ieee802154_tlx_frame.c b/drivers/ieee802154/ieee802154_tlx_frame.c index 7d00bef688967..01507911fcebd 100644 --- a/drivers/ieee802154/ieee802154_tlx_frame.c +++ b/drivers/ieee802154/ieee802154_tlx_frame.c @@ -605,7 +605,7 @@ tlx_ieee802154_get_data(const uint8_t *payload, */ #ifdef CONFIG_IEEE802154_2015 -#if CONFIG_SOC_RISCV_TELINK_TL721X || CONFIG_SOC_RISCV_TELINK_TL321X +#if CONFIG_SOC_RISCV_TELINK_TL721X || CONFIG_SOC_RISCV_TELINK_TL321X || CONFIG_SOC_RISCV_TELINK_TL322X || CONFIG_SOC_RISCV_TELINK_TL323X #include #include #endif @@ -617,7 +617,7 @@ ieee802154_tlx_crypto_ecb( const uint8_t inp[IEEE802154_CRYPTO_LENGTH_AES_BLOCK], uint8_t out[IEEE802154_CRYPTO_LENGTH_AES_BLOCK]) { -#if CONFIG_SOC_RISCV_TELINK_TL721X || CONFIG_SOC_RISCV_TELINK_TL321X +#if CONFIG_SOC_RISCV_TELINK_TL721X || CONFIG_SOC_RISCV_TELINK_TL321X || CONFIG_SOC_RISCV_TELINK_TL322X || CONFIG_SOC_RISCV_TELINK_TL323X uint32_t r = core_interrupt_disable(); (void)ske_lp_crypto(SKE_ALG_AES_128, SKE_MODE_ECB, diff --git a/drivers/interrupt_controller/intc_plic.c b/drivers/interrupt_controller/intc_plic.c index 9fdd1fd273372..0ffc09ab2913d 100644 --- a/drivers/interrupt_controller/intc_plic.c +++ b/drivers/interrupt_controller/intc_plic.c @@ -188,6 +188,7 @@ static int plic_init(void) } /* Set priority of each interrupt line to 0 initially */ + prio++; /* no zero ISR, it's reserved for PLIC features */ for (i = 0; i < PLIC_IRQS; i++) { *prio = 0U; prio++; diff --git a/drivers/pinctrl/pinctrl_tlx.c b/drivers/pinctrl/pinctrl_tlx.c index 0f6c8606d4213..88e72d177e220 100644 --- a/drivers/pinctrl/pinctrl_tlx.c +++ b/drivers/pinctrl/pinctrl_tlx.c @@ -5,17 +5,22 @@ */ #include "analog.h" +#include "gpio.h" #include #if CONFIG_SOC_RISCV_TELINK_TL721X #include #elif CONFIG_SOC_RISCV_TELINK_TL321X #include +#elif CONFIG_SOC_RISCV_TELINK_TL322X +#include +#elif CONFIG_SOC_RISCV_TELINK_TL323X +#include #endif #include #define DT_DRV_COMPAT telink_tlx_pinctrl -#if CONFIG_SOC_RISCV_TELINK_TL721X || CONFIG_SOC_RISCV_TELINK_TL321X +#if CONFIG_SOC_RISCV_TELINK_TL721X || CONFIG_SOC_RISCV_TELINK_TL321X || CONFIG_SOC_RISCV_TELINK_TL322X || CONFIG_SOC_RISCV_TELINK_TL323X /** * GPIO Function Enable Register * ADDR PINS @@ -30,7 +35,7 @@ ((pin >> 8) * 0x10))) #endif -#if CONFIG_SOC_RISCV_TELINK_TL721X || CONFIG_SOC_RISCV_TELINK_TL321X +#if CONFIG_SOC_RISCV_TELINK_TL721X || CONFIG_SOC_RISCV_TELINK_TL321X || CONFIG_SOC_RISCV_TELINK_TL322X || CONFIG_SOC_RISCV_TELINK_TL323X /** * Function Multiplexer Register * ADDR PINS @@ -78,6 +83,13 @@ * pull_up_en + 9: PORT_E[4-7] * pull_up_en + 10: PORT_F[0-3] * pull_up_en + 11: PORT_F[4-7] + * The following resistors are for TL322X + * pull_up_en + 12: PORT_G[0-3] + * pull_up_en + 13: PORT_G[4-7] + * pull_up_en + 14: PORT_H[0-3] + * pull_up_en + 15: PORT_H[4-7] + * pull_up_en + 16: PORT_I[0-3] + * pull_up_en + 17: PORT_I[4-7] */ #define reg_pull_up_en(pin) ((uint8_t)(DT_INST_REG_ADDR_BY_NAME(0, pull_up_en) + \ ((pin >> 8) * 2) + \ @@ -187,6 +199,9 @@ static int pinctrl_configure_pin(const pinctrl_soc_pin_t *pinctrl) uint32_t pin = TLX_PINMUX_GET_PIN(*pinctrl); uint8_t pull_up_en_addr = reg_pull_up_en(pin); + /* set input enable */ + gpio_input_en(pin); + /* calculate offset and mask for the func and pull values */ status = pinctrl_tlx_get_offset(pin, &offset); if (status != 0) { @@ -202,6 +217,12 @@ static int pinctrl_configure_pin(const pinctrl_soc_pin_t *pinctrl) #elif CONFIG_SOC_RISCV_TELINK_TL321X reg_pin_mux(pin) = (reg_pin_mux(pin) & (~TL321X_PIN_FUNC_POS)) | (func & TL321X_PIN_FUNC_POS); +#elif CONFIG_SOC_RISCV_TELINK_TL322X + reg_pin_mux(pin) = + (reg_pin_mux(pin) & (~TL322X_PIN_FUNC_POS)) | (func & TL322X_PIN_FUNC_POS); +#elif CONFIG_SOC_RISCV_TELINK_TL323X + reg_pin_mux(pin) = + (reg_pin_mux(pin) & (~TL323X_PIN_FUNC_POS)) | (func & TL323X_PIN_FUNC_POS); #endif /* disable GPIO function (can be enabled back by GPIO init using GPIO driver) */ diff --git a/drivers/serial/uart_tlx.c b/drivers/serial/uart_tlx.c index 02eb963db390e..31ea3fd862449 100644 --- a/drivers/serial/uart_tlx.c +++ b/drivers/serial/uart_tlx.c @@ -6,7 +6,7 @@ #include "analog.h" #include "clock.h" - +#include "uart.h" #include #include #include @@ -54,7 +54,7 @@ struct __packed uart_tlx_t { uint8_t status; uint8_t txrx_status; uint8_t state; -#if CONFIG_SOC_RISCV_TELINK_TL721X || CONFIG_SOC_RISCV_TELINK_TL321X +#if CONFIG_SOC_RISCV_TELINK_TL721X || CONFIG_SOC_RISCV_TELINK_TL321X || CONFIG_SOC_RISCV_TELINK_TL322X || CONFIG_SOC_RISCV_TELINK_TL323X uint8_t ctrl4; #endif }; @@ -187,12 +187,12 @@ static void uart_tlx_cal_div_and_bwpc(uint32_t baudrate, uint32_t pclk, static void uart_tlx_init(volatile struct uart_tlx_t *uart, uint16_t divider, uint8_t bwpc, uint8_t parity, uint8_t stop_bit) { -#if CONFIG_SOC_RISCV_TELINK_TL721X || CONFIG_SOC_RISCV_TELINK_TL321X +#if CONFIG_SOC_RISCV_TELINK_TL721X || CONFIG_SOC_RISCV_TELINK_TL321X || CONFIG_SOC_RISCV_TELINK_TL322X || CONFIG_SOC_RISCV_TELINK_TL323X uart->ctrl0 = ((uart->ctrl0 & (~FLD_UART_BPWC_O)) | bwpc); #endif /* config clock */ divider = divider | FLD_UART_CLK_DIV_EN; -#if CONFIG_SOC_RISCV_TELINK_TL721X || CONFIG_SOC_RISCV_TELINK_TL321X +#if CONFIG_SOC_RISCV_TELINK_TL721X || CONFIG_SOC_RISCV_TELINK_TL321X || CONFIG_SOC_RISCV_TELINK_TL322X || CONFIG_SOC_RISCV_TELINK_TL323X uart->ctrl0 &= ~(FLD_UART_RX_CLR_EN | FLD_UART_NDMA_RXDONE_EN | FLD_UART_RXTIMEOUT_RTS_EN | FLD_UART_S7816_EN); uart->ctrl4 &= ~FLD_UART_RXDONE_RTS_EN; @@ -316,7 +316,7 @@ static int uart_tlx_driver_init(const struct device *dev) struct uart_tlx_data *data = dev->data; /* Reset Tx, Rx status before usage */ -#if CONFIG_SOC_RISCV_TELINK_TL721X || CONFIG_SOC_RISCV_TELINK_TL321X +#if CONFIG_SOC_RISCV_TELINK_TL721X || CONFIG_SOC_RISCV_TELINK_TL321X || CONFIG_SOC_RISCV_TELINK_TL322X || CONFIG_SOC_RISCV_TELINK_TL323X uart->txrx_status |= FLD_UART_RX_BUF_IRQ | FLD_UART_TX_BUF_IRQ; #endif data->rx_byte_index = 0; @@ -367,7 +367,7 @@ static void uart_tlx_poll_out(const struct device *dev, uint8_t c) uart->data_buf[data->tx_byte_index] = c; data->tx_byte_index = (data->tx_byte_index + 1) % ARRAY_SIZE(uart->data_buf); -#if CONFIG_SOC_RISCV_TELINK_TL721X || CONFIG_SOC_RISCV_TELINK_TL321X +#if CONFIG_SOC_RISCV_TELINK_TL721X || CONFIG_SOC_RISCV_TELINK_TL321X || CONFIG_SOC_RISCV_TELINK_TL322X || CONFIG_SOC_RISCV_TELINK_TL323X while (!(uart->txrx_status & FLD_UART_TXDONE_IRQ)) { } #endif @@ -394,7 +394,7 @@ static int uart_tlx_err_check(const struct device *dev) { volatile struct uart_tlx_t *uart = GET_UART(dev); -#if CONFIG_SOC_RISCV_TELINK_TL721X || CONFIG_SOC_RISCV_TELINK_TL321X +#if CONFIG_SOC_RISCV_TELINK_TL721X || CONFIG_SOC_RISCV_TELINK_TL321X || CONFIG_SOC_RISCV_TELINK_TL322X || CONFIG_SOC_RISCV_TELINK_TL323X return ((uart->txrx_status & FLD_UART_RX_ERR_IRQ) != 0) ? 1 : 0; #endif } @@ -458,7 +458,7 @@ static void uart_tlx_irq_tx_enable(const struct device *dev) uart->ctrl3 = (uart->ctrl3 & (~FLD_UART_TX_IRQ_TRIQ_LEV)) | BIT(FLD_UART_TX_IRQ_TRIQ_LEV_OFFSET); -#if CONFIG_SOC_RISCV_TELINK_TL721X || CONFIG_SOC_RISCV_TELINK_TL321X +#if CONFIG_SOC_RISCV_TELINK_TL721X || CONFIG_SOC_RISCV_TELINK_TL321X || CONFIG_SOC_RISCV_TELINK_TL322X || CONFIG_SOC_RISCV_TELINK_TL323X uart->rxtimeoutH |= FLD_UART_MASK_TX_IRQ; #endif } @@ -468,7 +468,7 @@ static void uart_tlx_irq_tx_disable(const struct device *dev) { volatile struct uart_tlx_t *uart = GET_UART(dev); -#if CONFIG_SOC_RISCV_TELINK_TL721X || CONFIG_SOC_RISCV_TELINK_TL321X +#if CONFIG_SOC_RISCV_TELINK_TL721X || CONFIG_SOC_RISCV_TELINK_TL321X || CONFIG_SOC_RISCV_TELINK_TL322X || CONFIG_SOC_RISCV_TELINK_TL323X uart->rxtimeoutH &= ~FLD_UART_MASK_TX_IRQ; #endif } @@ -478,7 +478,7 @@ static int uart_tlx_irq_tx_ready(const struct device *dev) { volatile struct uart_tlx_t *uart = GET_UART(dev); -#if CONFIG_SOC_RISCV_TELINK_TL721X || CONFIG_SOC_RISCV_TELINK_TL321X +#if CONFIG_SOC_RISCV_TELINK_TL721X || CONFIG_SOC_RISCV_TELINK_TL321X || CONFIG_SOC_RISCV_TELINK_TL322X || CONFIG_SOC_RISCV_TELINK_TL323X return ((uart_tlx_get_tx_bufcnt(uart) < UART_TX_BUF_CNT) && ((uart->rxtimeoutH & FLD_UART_MASK_TX_IRQ) != 0)) ? 1 : 0; #endif @@ -500,7 +500,7 @@ static void uart_tlx_irq_rx_enable(const struct device *dev) uart->ctrl3 = (uart->ctrl3 & (~FLD_UART_RX_IRQ_TRIQ_LEV)) | BIT(FLD_UART_RX_IRQ_TRIQ_LEV_OFFSET); -#if CONFIG_SOC_RISCV_TELINK_TL721X || CONFIG_SOC_RISCV_TELINK_TL321X +#if CONFIG_SOC_RISCV_TELINK_TL721X || CONFIG_SOC_RISCV_TELINK_TL321X || CONFIG_SOC_RISCV_TELINK_TL322X || CONFIG_SOC_RISCV_TELINK_TL323X uart->rxtimeoutH |= FLD_UART_MASK_RX_IRQ; #endif } @@ -510,7 +510,7 @@ static void uart_tlx_irq_rx_disable(const struct device *dev) { volatile struct uart_tlx_t *uart = GET_UART(dev); -#if CONFIG_SOC_RISCV_TELINK_TL721X || CONFIG_SOC_RISCV_TELINK_TL321X +#if CONFIG_SOC_RISCV_TELINK_TL721X || CONFIG_SOC_RISCV_TELINK_TL321X || CONFIG_SOC_RISCV_TELINK_TL322X || CONFIG_SOC_RISCV_TELINK_TL323X uart->rxtimeoutH &= ~FLD_UART_MASK_RX_IRQ; #endif } @@ -587,15 +587,22 @@ static int uart_tlx_pm_action(const struct device *dev, enum pm_device_action ac } } #endif /* CONFIG_SOC_SERIES_RISCV_TELINK_TLX_RETENTION */ + uart_tlx_driver_init(dev); /* reset TX/RX byte index */ data->tx_byte_index = 0; data->rx_byte_index = 0; -#if CONFIG_SOC_RISCV_TELINK_TL721X || CONFIG_SOC_RISCV_TELINK_TL321X +#if CONFIG_SOC_RISCV_TELINK_TL721X || CONFIG_SOC_RISCV_TELINK_TL321X || CONFIG_SOC_RISCV_TELINK_TL322X || CONFIG_SOC_RISCV_TELINK_TL323X uart->txrx_status |= FLD_UART_RX_BUF_IRQ | FLD_UART_TX_BUF_IRQ; #endif break; case PM_DEVICE_ACTION_SUSPEND: + uart_tlx_driver_init(dev); + // /* reset TX/RX byte index */ + data->tx_byte_index = 0; + data->rx_byte_index = 0; + uart->txrx_status |= FLD_UART_RX_BUF_IRQ | FLD_UART_TX_BUF_IRQ; + break; default: diff --git a/drivers/spi/Kconfig.tlx b/drivers/spi/Kconfig.tlx index 1c34a007a20a0..77e6cb690ff43 100644 --- a/drivers/spi/Kconfig.tlx +++ b/drivers/spi/Kconfig.tlx @@ -4,6 +4,6 @@ config SPI_TELINK_TLX bool "Telink Semiconductor TLx SPI driver" default y - depends on DT_HAS_TELINK_TL321X_SPI_ENABLED || DT_HAS_TELINK_TL721X_SPI_ENABLED + depends on DT_HAS_TELINK_TL321X_SPI_ENABLED || DT_HAS_TELINK_TL721X_SPI_ENABLED || DT_HAS_TELINK_TL322X_SPI_ENABLED || DT_HAS_TELINK_TL323X_SPI_ENABLED help Enables Telink TLx SPI driver. diff --git a/drivers/spi/spi_tlx.c b/drivers/spi/spi_tlx.c index 9591c3ce72d9e..dbf67786b11d6 100644 --- a/drivers/spi/spi_tlx.c +++ b/drivers/spi/spi_tlx.c @@ -8,6 +8,10 @@ #define DT_DRV_COMPAT telink_tl321x_spi #elif CONFIG_SOC_RISCV_TELINK_TL721X #define DT_DRV_COMPAT telink_tl721x_spi +#elif CONFIG_SOC_RISCV_TELINK_TL322X +#define DT_DRV_COMPAT telink_tl322x_spi +#elif CONFIG_SOC_RISCV_TELINK_TL323X +#define DT_DRV_COMPAT telink_tl323x_spi #endif /* Redefine 'spi_read' and 'spi_write' functions names from HAL */ @@ -59,7 +63,7 @@ static void spi_tlx_hw_cs_disable(const struct spi_tlx_cfg *config) /* if CS pin is defined in device tree */ if (pin != 0) { -#if CONFIG_SOC_RISCV_TELINK_TL321X +#if CONFIG_SOC_RISCV_TELINK_TL321X || CONFIG_SOC_RISCV_TELINK_TL322X || CONFIG_SOC_RISCV_TELINK_TL323X gspi_cs_pin_dis(pin); #elif CONFIG_SOC_RISCV_TELINK_TL721X if (config->peripheral_id == LSPI_MODULE) { @@ -107,7 +111,7 @@ static bool spi_tlx_config_cs(const struct device *dev, /* disable cs pin if it is defined and is not requested */ if ((cs_pin != 0) && (cs_id != config->slave)) { -#if CONFIG_SOC_RISCV_TELINK_TL321X +#if CONFIG_SOC_RISCV_TELINK_TL321X || CONFIG_SOC_RISCV_TELINK_TL322X || CONFIG_SOC_RISCV_TELINK_TL323X gspi_cs_pin_dis(cs_pin); #elif CONFIG_SOC_RISCV_TELINK_TL721X if (tlx_config->peripheral_id == LSPI_MODULE) { @@ -120,7 +124,7 @@ static bool spi_tlx_config_cs(const struct device *dev, /* enable cs pin if it is defined and is requested */ if ((cs_pin != 0) && (cs_id == config->slave)) { -#if CONFIG_SOC_RISCV_TELINK_TL321X +#if CONFIG_SOC_RISCV_TELINK_TL321X || CONFIG_SOC_RISCV_TELINK_TL322X || CONFIG_SOC_RISCV_TELINK_TL323X gspi_cs_pin_en(cs_pin); #elif CONFIG_SOC_RISCV_TELINK_TL721X if (tlx_config->peripheral_id == LSPI_MODULE) { @@ -240,7 +244,7 @@ static void spi_tlx_txrx(const struct device *dev, uint32_t len) } /* clear TX and RX fifo */ -#if CONFIG_SOC_RISCV_TELINK_TL721X || CONFIG_SOC_RISCV_TELINK_TL321X +#if CONFIG_SOC_RISCV_TELINK_TL721X || CONFIG_SOC_RISCV_TELINK_TL321X || CONFIG_SOC_RISCV_TELINK_TL322X || CONFIG_SOC_RISCV_TELINK_TL323X BM_SET(reg_spi_status(cfg->peripheral_id), FLD_SPI_TXF_CLR_LEVEL); BM_SET(reg_spi_status(cfg->peripheral_id), FLD_SPI_RXF_CLR_LEVEL); #endif @@ -313,7 +317,7 @@ static int spi_tlx_config(const struct device *dev, struct spi_tlx_cfg *tlx_config = SPI_CFG(dev); struct spi_tlx_data *tlx_data = SPI_DATA(dev); const pinctrl_soc_pin_t *pins = tlx_config->pcfg->states->pins; -#if CONFIG_SOC_RISCV_TELINK_TL321X || CONFIG_SOC_RISCV_TELINK_TL721X +#if CONFIG_SOC_RISCV_TELINK_TL321X || CONFIG_SOC_RISCV_TELINK_TL721X || CONFIG_SOC_RISCV_TELINK_TL322X || CONFIG_SOC_RISCV_TELINK_TL323X uint8_t clk_src = sys_clk.pll_clk; #endif @@ -343,7 +347,7 @@ static int spi_tlx_config(const struct device *dev, } /* init SPI master */ -#if CONFIG_SOC_RISCV_TELINK_TL321X || CONFIG_SOC_RISCV_TELINK_TL721X +#if CONFIG_SOC_RISCV_TELINK_TL321X || CONFIG_SOC_RISCV_TELINK_TL721X || CONFIG_SOC_RISCV_TELINK_TL322X || CONFIG_SOC_RISCV_TELINK_TL323X spi_master_init(tlx_config->peripheral_id, clk_src * 1000000/config->frequency, mode); #endif @@ -358,7 +362,7 @@ static int spi_tlx_config(const struct device *dev, } else if (lines == SPI_LINES_DUAL) { spi_set_io_mode(tlx_config->peripheral_id, SPI_DUAL_MODE); } else if (lines == SPI_LINES_QUAD) { -#if CONFIG_SOC_RISCV_TELINK_TL321X || CONFIG_SOC_RISCV_TELINK_TL721X +#if CONFIG_SOC_RISCV_TELINK_TL321X || CONFIG_SOC_RISCV_TELINK_TL721X || CONFIG_SOC_RISCV_TELINK_TL322X || CONFIG_SOC_RISCV_TELINK_TL323X spi_set_io_mode(tlx_config->peripheral_id, SPI_QUAD_MODE); #endif } diff --git a/drivers/usb/device/CMakeLists.txt b/drivers/usb/device/CMakeLists.txt index d6a6bb4c747e7..3ea68f4149b1b 100644 --- a/drivers/usb/device/CMakeLists.txt +++ b/drivers/usb/device/CMakeLists.txt @@ -18,6 +18,10 @@ zephyr_library_sources_ifdef(CONFIG_USB_NATIVE_POSIX zephyr_library_sources_ifdef(CONFIG_USB_NRFX usb_dc_nrfx.c) zephyr_library_sources_ifdef(CONFIG_USB_MCUX usb_dc_mcux.c) zephyr_library_sources_ifdef(CONFIG_USB_TELINK_B9X usb_dc_b9x.c) +if(CONFIG_SOC_RISCV_TELINK_TL322X) +zephyr_library_sources_ifdef(CONFIG_USB_TELINK_TLX usb_dc_tl322x.c) +else() zephyr_library_sources_ifdef(CONFIG_USB_TELINK_TLX usb_dc_tlx.c) +endif() endif() diff --git a/drivers/usb/device/usb_dc_tl322x.c b/drivers/usb/device/usb_dc_tl322x.c new file mode 100644 index 0000000000000..53df8d0131586 --- /dev/null +++ b/drivers/usb/device/usb_dc_tl322x.c @@ -0,0 +1,1585 @@ +/* + * Copyright (c) 2025 Telink Semiconductor + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#if CONFIG_SOC_RISCV_TELINK_TL322X +#include "driver.h" +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#define LOG_LEVEL CONFIG_USB_DRIVER_LOG_LEVEL +#include +LOG_MODULE_REGISTER(usb_tl322x); + +#define DT_DRV_COMPAT telink_tl322x_usbd + +#define USBD_TLX_IRQN_BY_IDX(idx) DT_INST_IRQ_BY_IDX(0, idx, irq) +#define USBD_TLX_IRQ_PRIORITY_BY_IDX(idx) DT_INST_IRQ_BY_IDX(0, idx, priority) + +enum usbd_endpoint_index_e { + USBD_EP0_IDX = 0, /* only for control transfer */ + USBD_EP1_IDX = 1, /* IN and OUT */ + USBD_EP2_IDX = 2, /* IN and OUT */ + USBD_EP3_IDX = 3, /* IN and OUT */ + USBD_EP4_IDX = 4, /* IN and OUT */ + USBD_EP5_IDX = 5, /* IN and OUT */ + USBD_EP6_IDX = 6, /* IN and OUT */ + USBD_EP7_IDX = 7, /* IN and OUT */ + USBD_EP8_IDX = 8, /* IN and OUT */ +}; + +enum usbd_endpoint_index_e endpoint_idx[] = {USBD_EP0_IDX, USBD_EP1_IDX, USBD_EP2_IDX, + USBD_EP3_IDX, USBD_EP4_IDX, USBD_EP5_IDX, + USBD_EP6_IDX, USBD_EP7_IDX, USBD_EP8_IDX}; + +#define USBD_EPIN_BUSY_RETRY_TIMEOUT_US 10000 + +#define USBD_EP_TOTAL_CNT (sizeof(endpoint_idx) / sizeof(enum usbd_endpoint_index_e)) +#define USBD_EP_IN_OUT_CNT (USBD_EP_TOTAL_CNT - 1) + +/** @brief The value of direction bit for the IN endpoint direction. */ +#define USBD_EP_DIR_IN (1U << 7) + +/** @brief The value of direction bit for the OUT endpoint direction. */ +#define USBD_EP_DIR_OUT (0U << 7) + +/** + * @brief Macro for making the IN endpoint identifier from endpoint number. + * + * @details Macro that sets direction bit to make IN endpoint. + * + * @param[in] epn Endpoint number. + * + * @return IN Endpoint identifier. + */ +#define USBD_EPIN(epn) (((uint8_t)(epn)) | USBD_EP_DIR_IN) + +/** + * @brief Macro for making the OUT endpoint identifier from endpoint number. + * + * @details Macro that sets direction bit to make OUT endpoint. + * + * @param[in] epn Endpoint number. + * + * @return OUT Endpoint identifier. + */ +#define USBD_EPOUT(epn) (((uint8_t)(epn)) | USBD_EP_DIR_OUT) + +#define EP_DATA_BUF_LEN (64) + +/* The total hardware buffer size */ +#define EPS_BUFFER_TOTAL_SIZE (8 * 1024) + +#define EPS_BUFFER_OUT_SIZE (0x100) + +#define EPS_BUFFER_IN_SIZE (EPS_BUFFER_TOTAL_SIZE - EPS_BUFFER_OUT_SIZE) + +/** + * @brief Endpoint buffer information. + * + * @param init_list ep_idx that has been configured with BUF address + * @param seg_addr Available starting address of the USB endpoint cache. + * @param init_num Number of eps whose BUF address has been configured Max + * packet size supported by endpoint. + * @param remaining_size The remaining available size of the USB endpoint cache. + */ +struct ep_buf_t { + enum usbd_endpoint_index_e init_list[USBD_EP_TOTAL_CNT]; + uint8_t seg_addr; + uint8_t init_num; + uint16_t remaining_size; +}; + +static struct ep_buf_t eps_buf_inf = {.init_list = {0, 0, 0, 0, 0, 0, 0, 0, 0}, + .seg_addr = 0, + .init_num = 0, + .remaining_size = EPS_BUFFER_IN_SIZE}; + + +/** + * @brief Endpoint configuration. + * + * @param cb Endpoint callback. + * @param max_sz Max packet size supported by endpoint. + * @param en Enable/Disable flag. + * @param addr Endpoint address. + * @param type Endpoint transfer type. + * @param stall Endpoint stall flag. + * @param out_ack Endpoint ready for receive data flag. + */ +struct tlx_usbd_ep_cfg { + usb_dc_ep_callback cb; + unsigned short max_sz; // uint32_t -> unsigned short + bool en; + uint8_t addr; + enum usb_dc_ep_transfer_type type; + bool stall; + bool out_ack; +}; + +/** + * @brief Endpoint buffer + * + * @param total_len Total length to be read/written. + * @param left_len Remaining length to be read/written. + * @param data Pointer to data buffer for the endpoint. + * @param current_pos Pointer to the current offset in the endpoint buffer. + */ +struct tlx_usbd_ep_buf { + uint32_t total_len; + uint32_t left_len; + uint8_t *data; + uint8_t *current_pos; +}; + +/** + * @brief Endpoint context + * + * @param cfg Endpoint configuration + * @param buf Endpoint buffer + */ +struct tlx_usbd_ep_ctx { + struct tlx_usbd_ep_cfg cfg; + struct tlx_usbd_ep_buf buf; + struct k_timer retry_timer; +}; + +/** + * @brief USBD control structure + * + * @param status_cb Status callback for USB DC notifications + * @param attached USBD Attached flag + * @param ready USBD Ready flag set after pullup + * @param suspend Suspend flag + * @param wakeup_feature Wakeup feature flag set by host + * @param usb_work USBD work item + * @param drv_lock Mutex for thread-safe tlx driver use + * @param ep_ctx Endpoint contexts + */ +struct tlx_usbd_ctx { + usb_dc_status_callback status_cb; + bool attached; + bool ready; + bool suspend; + bool wakeup_feature; + struct k_work usb_work; + struct k_mutex drv_lock; + struct tlx_usbd_ep_ctx ep_ctx[USBD_EP_TOTAL_CNT]; +}; + +static struct tlx_usbd_ctx usbd_ctx = { + .attached = false, + .ready = false, + .suspend = true, + .wakeup_feature = false, +}; + +static inline struct tlx_usbd_ctx *get_usbd_ctx(void) +{ + return &usbd_ctx; +} + +static inline bool dev_attached(void) +{ + return get_usbd_ctx()->attached; +} + +static inline bool dev_ready(void) +{ + return get_usbd_ctx()->ready; +} + +static inline bool ep_is_valid(const uint8_t ep) +{ + uint8_t ep_idx = USB_EP_GET_IDX(ep); + + if (ep_idx > USBD_EP_IN_OUT_CNT) { + LOG_ERR("Endpoit index %d is out of range.", ep_idx); + return false; + } + + return true; +} + +/** @brief Gets the structure pointer to the corresponding endpoint */ +static struct tlx_usbd_ep_ctx *endpoint_ctx(const uint8_t ep) +{ + struct tlx_usbd_ctx *ctx; + + if (!ep_is_valid(ep)) { + return NULL; + } + + ctx = get_usbd_ctx(); + + return &ctx->ep_ctx[USB_EP_GET_IDX(ep)]; +} + +/** @brief FIFO used for queuing up events from ISR. */ +K_FIFO_DEFINE(usbd_evt_fifo); + +/** @brief Work queue used for handling the ISR events (i.e. for notifying the USB + * device stack, for executing the endpoints callbacks, etc.) out of the ISR context. + * + * @details The system work queue cannot be used for this purpose as it might be used + * in applications for scheduling USB transfers and this could lead to a deadlock + * when the USB device stack would not be notified about certain event because of + * a system work queue item waiting for a USB transfer to be finished. + */ +static struct k_work_q usbd_work_queue; +#if CONFIG_USB_TELINK_TLX +static K_KERNEL_STACK_DEFINE(usbd_work_queue_stack, CONFIG_USB_TLX_WORK_QUEUE_STACK_SIZE); +#endif + +static inline void usbd_work_schedule(void) +{ + k_work_submit_to_queue(&usbd_work_queue, &(get_usbd_ctx()->usb_work)); +} + +enum usbd_event_type { + USBD_EVT_OUT_COMPLETE, + USBD_EVT_OUT_SETUP, + USBD_EVT_OUT_RCVD, + USBD_EVT_IN_COMPLETE, + USBD_EVT_EP_WRITE_COMPLETE, + USBD_EVT_EP_RETRY, + USBD_EVT_RESET, + USBD_EVT_SUSPEND, + USBD_EVT_WAKEUP, + USBD_EVT_REINIT, +}; + +struct usbd_mem_block { + void *data; +}; + +struct usbd_event { + sys_snode_t node; + struct usbd_mem_block block; + enum usbd_event_type evt_type; + uint8_t ep_addr; +}; + +#define FIFO_ELEM_SZ sizeof(struct usbd_event) +#define FIFO_ELEM_ALIGN sizeof(uint32_t) + +#if CONFIG_USB_TELINK_TLX +K_MEM_SLAB_DEFINE(fifo_elem_slab, FIFO_ELEM_SZ, CONFIG_USB_TLX_EVT_QUEUE_SIZE, FIFO_ELEM_ALIGN); +#endif + +/** + * @brief Free previously allocated USBD event. + * + * @note Should be called after usbd_evt_get(). + * + * @param ev Pointer to the USBD event structure. + */ +static inline void usbd_evt_free(struct usbd_event *ev) +{ + k_mem_slab_free(&fifo_elem_slab, (void **)&ev->block.data); +} + +/** + * @brief Enqueue USBD event. + * + * @param ev Pointer to the previously allocated and filled event structure. + */ +static inline void usbd_evt_put(struct usbd_event *ev) +{ + k_fifo_put(&usbd_evt_fifo, ev); +} + +/** + * @brief Get next enqueued USBD event if present. + */ +static inline struct usbd_event *usbd_evt_get(void) +{ + return k_fifo_get(&usbd_evt_fifo, K_NO_WAIT); +} + +/** + * @brief Drop all enqueued events. + */ +static inline void usbd_evt_flush(void) +{ + struct usbd_event *ev; + + do { + ev = usbd_evt_get(); + if (ev) { + usbd_evt_free(ev); + } + } while (ev != NULL); +} + +static inline struct usbd_event *usbd_evt_alloc(void) +{ + struct usbd_event *ev; + struct usbd_mem_block block; + + if (k_mem_slab_alloc(&fifo_elem_slab, (void **)&block.data, K_NO_WAIT)) { + LOG_ERR("USBD event allocation failed!"); + + /* + * Allocation may fail if workqueue thread is starved or event + * queue size is too small (CONFIG_USB_TLX_EVT_QUEUE_SIZE). + * Wipe all events, free the space and schedule + * reinitialization. + */ + usbd_evt_flush(); + + if (k_mem_slab_alloc(&fifo_elem_slab, (void **)&block.data, K_NO_WAIT)) { + LOG_ERR("USBD event memory corrupted"); + __ASSERT_NO_MSG(0); + return NULL; + } + + ev = (struct usbd_event *)block.data; + ev->block = block; + ev->evt_type = USBD_EVT_REINIT; + usbd_evt_put(ev); + usbd_work_schedule(); + + return NULL; + } + + ev = (struct usbd_event *)block.data; + ev->block = block; + + return ev; +} + +static void submit_usbd_event(enum usbd_event_type evt_type, uint8_t value) +{ + struct usbd_event *ev = usbd_evt_alloc(); + + if (!ev) { + return; + } + + ev->evt_type = evt_type; + + if (ev->evt_type == USBD_EVT_IN_COMPLETE) { + ev->ep_addr = value; + } else if (ev->evt_type == USBD_EVT_EP_WRITE_COMPLETE) { + ev->ep_addr = value; + } else if (ev->evt_type == USBD_EVT_EP_RETRY) { + ev->ep_addr = value; + } else if (ev->evt_type == USBD_EVT_OUT_COMPLETE) { + ev->ep_addr = value; + } else if (ev->evt_type == USBD_EVT_OUT_SETUP) { + ev->ep_addr = value; + } else if (ev->evt_type == USBD_EVT_OUT_RCVD) { + ev->ep_addr = value; + } + usbd_evt_put(ev); + + if (usbd_ctx.attached) { + usbd_work_schedule(); + } +} + +/** + * @brief Reset endpoint state. + * + * @details Reset the internal logic state for a given endpoint. + * + * @param[in] ep_idx Endpoint number + */ +static void ep_ctx_reset(enum usbd_endpoint_index_e ep_idx) +{ + struct tlx_usbd_ep_ctx *ep_ctx; + + ep_ctx = endpoint_ctx(ep_idx); + + ep_ctx->buf.current_pos = ep_ctx->buf.data; + ep_ctx->buf.total_len = 0; + ep_ctx->buf.left_len = 0; +} + +static void ep_buf_clear(uint8_t ep) +{ + struct tlx_usbd_ep_ctx *ep_ctx = endpoint_ctx(ep); + + ep_ctx->buf.current_pos = ep_ctx->buf.data; + ep_ctx->buf.total_len = 0; + ep_ctx->buf.left_len = 0; +} + +static void ep_buf_init(uint8_t ep) +{ + struct tlx_usbd_ep_ctx *ep_ctx = endpoint_ctx(ep); + + ep_ctx->buf.data = NULL; + ep_buf_clear(ep); +} + +static uint32_t ep_write(uint8_t ep, const uint8_t *data, uint32_t data_len) +{ + uint16_t i; + uint8_t ep_idx = USB_EP_GET_IDX(ep); + struct tlx_usbd_ctx *ctx = get_usbd_ctx(); + struct tlx_usbd_ep_ctx *ep_ctx = endpoint_ctx(ep); + uint32_t valid_len = 0; + + k_mutex_lock(&ctx->drv_lock, K_FOREVER); + + if (data_len > ep_ctx->cfg.max_sz) { + valid_len = ep_ctx->cfg.max_sz; + } else { + valid_len = data_len; + } + + usb0hw_write_ep_data(ep_idx, data, valid_len); + + if (data_len == ep_ctx->cfg.max_sz) { + usb0hw_write_ep_data(ep_idx, 0, 0); + } + + submit_usbd_event(USBD_EVT_EP_WRITE_COMPLETE, ep); + + k_mutex_unlock(&ctx->drv_lock); + return valid_len; +} + +static inline void usb_event_out_complete_handler(uint8_t ep) +{ + struct tlx_usbd_ep_ctx *ep_ctx = endpoint_ctx(ep); + unsigned short xfered_len = usb0hw_get_epout_len(USB_EP_GET_IDX(ep)); + + ep_ctx->cfg.out_ack = false; + + if ((USB_EP_GET_IDX(ep) == USBD_EP0_IDX)) { + if ((xfered_len == 0)) { + usb0hw_read_ep_data(USB_EP_GET_IDX(ep), ep_ctx->buf.data, ep_ctx->cfg.max_sz); + ep_ctx->cfg.out_ack = true; + } else { + ep_ctx->buf.left_len = ep_ctx->buf.total_len = xfered_len; + } + } +} + +static inline void usb_event_out_setup_handler(uint8_t ep) +{ + struct tlx_usbd_ep_ctx *ep_ctx = endpoint_ctx(ep); + unsigned short xfered_len = usb0hw_get_epout_len(USB_EP_GET_IDX(ep)); + + if (get_usbd_ctx()->suspend) { + get_usbd_ctx()->suspend = false; + if (get_usbd_ctx()->status_cb) { + get_usbd_ctx()->status_cb(USB_DC_RESUME, NULL); + } + } + if (xfered_len > 0) { + if ((get_usbd_ctx()->ep_ctx[USBD_EP0_IDX].buf.data[1] == USB_SREQ_SET_FEATURE) + && (get_usbd_ctx()->ep_ctx[USBD_EP0_IDX].buf.data[2] == USB_SFS_REMOTE_WAKEUP)) { + usbd_ctx.wakeup_feature = true; + } + if ((get_usbd_ctx()->ep_ctx[USBD_EP0_IDX].buf.data[1] == USB_SREQ_CLEAR_FEATURE) + && (get_usbd_ctx()->ep_ctx[USBD_EP0_IDX].buf.data[2] == USB_SFS_REMOTE_WAKEUP)) { + usbd_ctx.wakeup_feature = false; + } + + ep_ctx->cfg.cb(ep, USB_DC_EP_SETUP); + } +} + +static inline void usb_event_out_rcvd_handler(uint8_t ep) +{ + struct tlx_usbd_ep_ctx *ep_ctx = endpoint_ctx(ep); + unsigned short xfered_len = usb0hw_get_epout_len(USB_EP_GET_IDX(ep)); + + ep_ctx->cfg.cb(ep, USB_DC_EP_DATA_OUT); +} + +static inline void usb_event_in_handler(uint8_t ep) +{ + struct tlx_usbd_ep_ctx *ep_ctx = endpoint_ctx(ep); + unsigned short xfered_len = usb0hw_get_epin_len(USB_EP_GET_IDX(ep)); + + ep_ctx->cfg.cb(ep, USB_DC_EP_DATA_IN); + + if ((USB_EP_GET_IDX(ep) == USBD_EP0_IDX) || (USB_EP_GET_DIR(ep) == USB_EP_DIR_OUT)) { + ep_ctx->cfg.out_ack = false; + } +} + +static inline void usb_event_ep_write_complete_handler(uint8_t ep) +{ + struct tlx_usbd_ep_ctx *ep_ctx = endpoint_ctx(ep); + + if (ep_ctx->cfg.cb) { + ep_ctx->cfg.cb(ep, USB_DC_EP_DATA_IN); + } +} + +static inline void usb_event_ep_retry_handler(uint8_t ep) +{ + struct tlx_usbd_ep_ctx *ep_ctx = endpoint_ctx(ep); + + if (ep_ctx->cfg.cb) { + ep_ctx->cfg.cb(ep, USB_DC_EP_DATA_IN); + } +} + +static void usb_event_reset_handler(void) +{ + uint32_t i; + + usb0hw_reset(); + usb0hw_read_ep_data(USBD_EP0_IDX, endpoint_ctx(USBD_EP0_IDX)->buf.data, + endpoint_ctx(USBD_EP0_IDX)->cfg.max_sz); + + if (get_usbd_ctx()->suspend) { + if (get_usbd_ctx()->status_cb) { + get_usbd_ctx()->status_cb(USB_DC_CONNECTED, NULL); + } + } + if (get_usbd_ctx()->status_cb) { + LOG_DBG("USB reset"); + get_usbd_ctx()->status_cb(USB_DC_RESET, NULL); + } + if (get_usbd_ctx()->suspend) { + get_usbd_ctx()->suspend = false; + if (get_usbd_ctx()->status_cb) { + LOG_DBG("USB resume"); + get_usbd_ctx()->status_cb(USB_DC_RESUME, NULL); + } + } +} + +static inline void usb_event_suspend_handler(void) +{ + if (dev_ready()) { + get_usbd_ctx()->suspend = true; + if (get_usbd_ctx()->status_cb) { + LOG_DBG("USB suspend"); + get_usbd_ctx()->status_cb(USB_DC_SUSPEND, NULL); + + if (!usbd_ctx.wakeup_feature) { + LOG_DBG("USB disconnected"); + get_usbd_ctx()->status_cb(USB_DC_DISCONNECTED, NULL); + } + } + } +} + +static inline void usb_event_wakeup_handler(void) +{ + if (get_usbd_ctx()->suspend) { + get_usbd_ctx()->suspend = false; + if (get_usbd_ctx()->status_cb) { + get_usbd_ctx()->status_cb(USB_DC_RESUME, NULL); + } + } +} + +static inline void usb_irq_out(void) +{ + for (unsigned char ep_num = 0; ep_num < USBD_EP_TOTAL_CNT; ep_num++) { + if ((usb0hw_get_daint() >> 16) & BIT(ep_num)) { + unsigned int doepint = usb0hw_get_doepint(ep_num); + + if (doepint & FLD_USB_DOEPINT_XFERCOMPL) { + usb0hw_clear_doepint(ep_num, FLD_USB_DOEPINT_XFERCOMPL); + unsigned int len = usb0hw_get_epout_len(ep_num); + submit_usbd_event(USBD_EVT_OUT_COMPLETE, + USB_EP_GET_ADDR(ep_num, USB_EP_DIR_OUT)); + } + if (doepint & FLD_USB_DOEPINT_SETUP) { + usb0hw_clear_doepint(ep_num, FLD_USB_DOEPINT_SETUP); + submit_usbd_event(USBD_EVT_OUT_SETUP, USB_EP_GET_ADDR(ep_num, USB_EP_DIR_OUT)); + } + if (doepint & FLD_USB_DOEPINT_STSPHSERCVD) { + usb0hw_clear_doepint(ep_num, FLD_USB_DOEPINT_STSPHSERCVD); + submit_usbd_event(USBD_EVT_OUT_RCVD, USB_EP_GET_ADDR(ep_num, USB_EP_DIR_OUT)); + } + } + } +} + +static inline void usb_irq_in(void) +{ + for (unsigned char ep_num = 0; ep_num < USBD_EP_TOTAL_CNT; ep_num++) { + if ((usb0hw_get_daint()) & BIT(ep_num)) { + unsigned int diepint = usb0hw_get_diepint(ep_num); + if (diepint & FLD_USB_DIEPINT_XFERCOMPL) { + usb0hw_clear_diepint(ep_num, FLD_USB_DIEPINT_XFERCOMPL); + submit_usbd_event(USBD_EVT_IN_COMPLETE, + USB_EP_GET_ADDR(ep_num, USB_EP_DIR_IN)); + } + } + } +} + +static inline void usb_irq_suspend(void) +{ + submit_usbd_event(USBD_EVT_SUSPEND, 0); + usb0hw_clear_gintsts(FLD_USB_GINTSTS_USBSUSP); +} + +static inline void usb_irq_wakeup(void) +{ + submit_usbd_event(USBD_EVT_WAKEUP, 0); + usb0hw_clear_gintsts(FLD_USB_GINTSTS_WKUPINT); +} + +static inline void usb_irq_reset(void) +{ + submit_usbd_event(USBD_EVT_RESET, 0); + usb0hw_clear_gintsts(FLD_USB_GINTSTS_USBRST); +} + +static inline void usb_irq_enumdone(void) +{ + usb0hw_clear_gintsts(FLD_USB_GINTSTS_ENUMDONE); +} + +static inline void usb_irq_sof(void) +{ + usb0hw_clear_gintsts(FLD_USB_GINTSTS_SOF); +} + +__attribute__((section(".ram_code"))) static void usb_irq_handler(void) +{ + unsigned int status = usb0hw_get_gintsts() & reg_usb_gintmsk; + + if (status != 0x8) { + LOG_DBG("usb_irq(0x%X)", status); + } + if (status & FLD_USB_GINTSTS_ENUMDONE) { + usb_irq_enumdone(); + } + + if (status & FLD_USB_GINTSTS_OEPINT) { + usb_irq_out(); + } + + if (status & FLD_USB_GINTSTS_IEPINT) { + usb_irq_in(); + } + + if (status & FLD_USB_GINTSTS_USBSUSP) { + usb_irq_suspend(); + } + + if (status & FLD_USB_GINTSTS_WKUPINT) { + usb_irq_wakeup(); + } + + if (status & FLD_USB_GINTSTS_USBRST) { + usb_irq_reset(); + } + + if (status & FLD_USB_GINTSTS_SOF) { + usb_irq_sof(); + } +} + +static int usb_irq_init(void) +{ + IRQ_CONNECT(USBD_TLX_IRQN_BY_IDX(0), USBD_TLX_IRQ_PRIORITY_BY_IDX(0), usb_irq_handler, 0, 0); + if (USBD_TLX_IRQN_BY_IDX(0) < CONFIG_2ND_LVL_ISR_TBL_OFFSET) { + return -EINVAL; + } + plic_interrupt_enable(USBD_TLX_IRQN_BY_IDX(0) - CONFIG_2ND_LVL_ISR_TBL_OFFSET); + plic_set_priority(USBD_TLX_IRQN_BY_IDX(0) - CONFIG_2ND_LVL_ISR_TBL_OFFSET, + USBD_TLX_IRQ_PRIORITY_BY_IDX(0)); + + return 0; +} + +void usbd_ep_stall(const unsigned char ep) +{ + unsigned char const ep_dir = USB_EP_GET_DIR(ep); + unsigned char const ep_num = USB_EP_GET_IDX(ep); + + if (ep_dir == USB_EP_DIR_IN) { + usb0hw_set_inep_stall(ep_num); + } else { + usb0hw_set_outep_stall(ep_num); + } + + if (ep_num == 0) { + /* receive next setup. */ + usb0hw_read_ep_data(USBD_EP0_IDX, endpoint_ctx(USBD_EP0_IDX)->buf.data, + endpoint_ctx(USBD_EP0_IDX)->cfg.max_sz); + } +} + +void usbd_ep_clear_stall(const unsigned char ep) +{ + unsigned char const ep_dir = USB_EP_GET_DIR(ep); + unsigned char const ep_num = USB_EP_GET_IDX(ep); + + if (ep_dir == USB_EP_DIR_IN) { + usb0hw_clear_epin_stall(ep_num); + } else { + usb0hw_clear_epout_stall(ep_num); + } +} + +/** + * @brief Attach USB for device connection + * + * @details Function to attach USB for device connection. Upon success, the USB PLL + * is enabled, and the USB device is now capable of transmitting and receiving on + * the USB bus and of generating interrupts. + * + * @return 0 on success, negative errno code on fail. + */ +int usb_dc_attach(void) +{ + struct tlx_usbd_ctx *ctx = get_usbd_ctx(); + uint32_t i; + + if (ctx->attached) { + return 0; + } + + k_mutex_init(&ctx->drv_lock); + + for (uint32_t i = USBD_EP0_IDX; i < USBD_EP_TOTAL_CNT; i++) { + ep_ctx_reset(i); + } + + usb0hw_reset(); + + ctx->attached = true; + ctx->ready = true; + + return 0; +} + +/** + * @brief Detach the USB device + * + * @details Function to detach the USB device. Upon success, the USB hardware PLL + * is powered down and USB communication is disabled. + * + * @return 0 on success, negative errno code on fail. + */ +int usb_dc_detach(void) +{ + struct tlx_usbd_ctx *ctx = get_usbd_ctx(); + struct tlx_usbd_ep_ctx *ep_ctx; + uint8_t i; + + k_mutex_lock(&ctx->drv_lock, K_FOREVER); + + for (i = USBD_EP1_IDX; i <= USBD_EP_IN_OUT_CNT; i++) { + ep_ctx = endpoint_ctx(i); + memset(ep_ctx, 0, sizeof(*ep_ctx)); + } + ctx->attached = false; + k_mutex_unlock(&ctx->drv_lock); + + return 0; +} + +/** + * @brief Reset the USB device + * + * @details This function returns the USB device and firmware back to it's initial state. + * N.B. the USB PLL is handled by the usb_detach function + * + * @return 0 on success, negative errno code on fail. + */ +int usb_dc_reset(void) +{ + int ret; + + if (!dev_attached() || !dev_ready()) { + return -ENODEV; + } + + LOG_DBG("USBD Reset"); + + ret = usb_dc_detach(); + if (ret) { + return ret; + } + + ret = usb_dc_attach(); + if (ret) { + return ret; + } + + return 0; +} + +/** + * @brief Set USB device address + * + * @param[in] addr Device address + * + * @return 0 on success, negative errno code on fail. + */ +int usb_dc_set_address(const uint8_t addr) +{ + LOG_DBG("USBD Set_address"); + usb0hw_set_address(addr); + return 0; +} + +/** + * @brief Set USB device controller status callback + * + * @details Function to set USB device controller status callback. The registered + * callback is used to report changes in the status of the device controller. The + * status code are described by the usb_dc_status_code enumeration. + * + * @param[in] cb Callback function + */ +void usb_dc_set_status_callback(const usb_dc_status_callback cb) +{ + get_usbd_ctx()->status_cb = cb; + LOG_DBG("status cb(0x%X)", cb); +} + +/** + * @brief check endpoint capabilities + * + * @details Function to check capabilities of an endpoint. usb_dc_ep_cfg_data structure + * provides the endpoint configuration parameters: endpoint address, endpoint maximum + * packet size and endpoint type. The driver should check endpoint capabilities and + * return 0 if the endpoint configuration is possible. + * + * @param[in] cfg Endpoint config + * + * @return 0 on success, negative errno code on fail. + */ +int usb_dc_ep_check_cap(const struct usb_dc_ep_cfg_data *const ep_cfg) +{ + uint8_t ep_idx = USB_EP_GET_IDX(ep_cfg->ep_addr); + + LOG_DBG("ep 0x%02x, mps %d, type %d", ep_cfg->ep_addr, ep_cfg->ep_mps, ep_cfg->ep_type); + + if (ep_idx > USBD_EP8_IDX) { + LOG_ERR("Endpoint index %d is out of range.", ep_idx); + return -EINVAL; + } + + if (ep_idx == USBD_EP0_IDX) { + if (ep_cfg->ep_type != USB_DC_EP_CONTROL) { + LOG_ERR("EP%d can only be a control endpoint.", USBD_EP0_IDX); + return -EINVAL; + } + if (ep_cfg->ep_mps > 64) { + LOG_ERR("EP%d's max packet size is up to 64.", USBD_EP0_IDX); + return -EINVAL; + } + } else if (USB_EP_DIR_IS_IN(ep_cfg->ep_addr)) { + if (ep_cfg->ep_type == USB_DC_EP_CONTROL) { + LOG_ERR("EP%d cannot be a control endpoint.", ep_idx); + return -EINVAL; + } + } else { + if (ep_cfg->ep_type == USB_DC_EP_CONTROL) { + LOG_ERR("EP%d cannot be a control endpoint.", ep_idx); + return -EINVAL; + } + + if (ep_cfg->ep_mps > EPS_BUFFER_OUT_SIZE) { + LOG_ERR("invalid endpoint max packet size: %d", ep_cfg->ep_mps); + return -EINVAL; + } + } + + if (ep_cfg->ep_mps > EPS_BUFFER_IN_SIZE) { + LOG_ERR("invalid endpoint max packet size: %d", ep_cfg->ep_mps); + return -EINVAL; + } + + return 0; +} + +/** + * @brief Configure endpoint + * + * Function to configure an endpoint. usb_dc_ep_cfg_data structure provides + * the endpoint configuration parameters: endpoint address, endpoint maximum + * packet size and endpoint type. + * + * @param[in] cfg Endpoint config + * + * @return 0 on success, negative errno code on fail. + */ +int usb_dc_ep_configure(const struct usb_dc_ep_cfg_data *const ep_cfg) +{ + struct tlx_usbd_ep_ctx *ep_ctx; + uint8_t i; + uint8_t ep_idx = USB_EP_GET_IDX(ep_cfg->ep_addr); + + if (!dev_attached()) { + return -ENODEV; + } + + ep_ctx = endpoint_ctx(ep_cfg->ep_addr); + if (!ep_ctx) { + return -EINVAL; + } + + LOG_DBG("ep 0x%02x, ep_type:%d, ep_mps:%d", ep_cfg->ep_addr, ep_cfg->ep_type, + ep_cfg->ep_mps); + + if (ep_idx == USBD_EP0_IDX) { + if (ep_cfg->ep_type != USB_DC_EP_CONTROL) { + LOG_ERR("EP%d only supports the control transmission mode.", USBD_EP0_IDX); + return -EINVAL; + } + + for (i = 0; i < eps_buf_inf.init_num; i++) { + if (eps_buf_inf.init_list[i] == ep_idx) { + LOG_DBG("ep%d buf address already configured", ep_idx); + return 0; + } + } + + ep_ctx->cfg.max_sz = ep_cfg->ep_mps; + usb0hw_set_epin_size(ep_idx, eps_buf_inf.seg_addr, ep_ctx->cfg.max_sz); + eps_buf_inf.seg_addr += ep_ctx->cfg.max_sz; + eps_buf_inf.remaining_size -= ep_ctx->cfg.max_sz; + } else { + if (ep_cfg->ep_type == USB_DC_EP_CONTROL) { + LOG_ERR("Only EP%d supports the control transmission mode!", USBD_EP0_IDX); + return -EINVAL; + } + + for (i = 0; i < eps_buf_inf.init_num; i++) { + if (eps_buf_inf.init_list[i] == ep_idx) { + LOG_DBG("ep%d buf address already configured", ep_idx); + return 0; + } + } + + if (eps_buf_inf.remaining_size < ep_cfg->ep_mps) { + LOG_ERR("There is only %d bytes left for endpoint buffer.", + eps_buf_inf.remaining_size); + return -EINVAL; + } + + ep_ctx->cfg.max_sz = ep_cfg->ep_mps; + if (USB_EP_DIR_IS_IN(ep_ctx->cfg.addr)) { + usb0hw_set_epin_size(ep_idx, eps_buf_inf.seg_addr, ep_ctx->cfg.max_sz); + eps_buf_inf.seg_addr += ep_ctx->cfg.max_sz; + eps_buf_inf.remaining_size -= ep_ctx->cfg.max_sz; + } + } + + ep_buf_init(ep_cfg->ep_addr); + + ep_ctx->cfg.addr = ep_cfg->ep_addr; + ep_ctx->cfg.type = ep_cfg->ep_type; + eps_buf_inf.init_list[eps_buf_inf.init_num] = ep_idx; + eps_buf_inf.init_num++; + + return 0; +} + +/** + * @brief Set stall condition for the selected endpoint + * + * @param[in] ep Endpoint address corresponding to the one + * listed in the device configuration table + * + * @return 0 on success, negative errno code on fail. + */ +int usb_dc_ep_set_stall(const uint8_t ep) +{ + struct tlx_usbd_ep_ctx *ep_ctx; + + if (!dev_attached() || !dev_ready()) { + return -ENODEV; + } + + ep_ctx = endpoint_ctx(ep); + if (!ep_ctx) { + return -EINVAL; + } + ep_ctx->cfg.stall = true; + ep_buf_clear(ep); + usbd_ep_stall(ep); + LOG_DBG("Stall on ep%d", USB_EP_GET_IDX(ep)); + + return 0; +} + +/** + * @brief Clear stall condition for the selected endpoint + * + * @param[in] ep Endpoint address corresponding to the one + * listed in the device configuration table + * + * @return 0 on success, negative errno code on fail. + */ +int usb_dc_ep_clear_stall(const uint8_t ep) +{ + struct tlx_usbd_ep_ctx *ep_ctx; + + if (!dev_attached() || !dev_ready()) { + return -ENODEV; + } + + ep_ctx = endpoint_ctx(ep); + if (!ep_ctx) { + return -EINVAL; + } + ep_ctx->cfg.stall = false; + usbd_ep_clear_stall(ep); + LOG_DBG("Unstall on EP 0x%02x", ep); + + return 0; +} + +/** + * @brief Check if the selected endpoint is stalled + * + * @param[in] ep Endpoint address corresponding to the one + * listed in the device configuration table + * @param[out] stalled Endpoint stall status + * + * @return 0 on success, negative errno code on fail. + */ +int usb_dc_ep_is_stalled(const uint8_t ep, uint8_t *const stalled) +{ + struct tlx_usbd_ep_ctx *ep_ctx; + + if (!dev_attached() || !dev_ready()) { + return -ENODEV; + } + + ep_ctx = endpoint_ctx(ep); + if (!ep_ctx) { + return -EINVAL; + } + + if (!stalled) { + return -EINVAL; + } + + *stalled = ep_ctx->cfg.stall; + + return 0; +} + +/** + * @brief Halt the selected endpoint + * + * @param[in] ep Endpoint address corresponding to the one + * listed in the device configuration table + * + * @return 0 on success, negative errno code on fail. + */ +int usb_dc_ep_halt(const uint8_t ep) +{ + return usb_dc_ep_set_stall(ep); +} + +/** + * @brief Enable the selected endpoint + * + * @details Function to enable the selected endpoint. Upon success interrupts are + * enabled for the corresponding endpoint and the endpoint is ready for + * transmitting/receiving data. + * + * @param[in] ep Endpoint address corresponding to the one + * listed in the device configuration table + * + * @return 0 on success, negative errno code on fail. + */ +int usb_dc_ep_enable(const uint8_t ep) +{ + struct tlx_usbd_ep_ctx *ep_ctx; + + if (!dev_attached()) { + return -ENODEV; + } + + ep_ctx = endpoint_ctx(ep); + if (!ep_ctx) { + return -EINVAL; + } + + LOG_DBG("EP enable: 0x%02x", ep); + ep_ctx->cfg.en = true; + + if (dev_ready()) { + ep_ctx->cfg.stall = false; + + if (USB_EP_GET_DIR(ep) == USB_EP_DIR_IN) { + ep_ctx->buf.data = (uint8_t *)malloc(ep_ctx->cfg.max_sz); + if (ep_ctx->buf.data == NULL) { + LOG_ERR("ep(0X%x) malloc fail", ep); + return -ENOSPC; + } + } + + if (USB_EP_GET_IDX(ep) != 0) { + usb0hw_ep_open(USB_EP_GET_IDX(ep_ctx->cfg.addr), + USB_EP_GET_DIR(ep_ctx->cfg.addr) ? USB0_DIR_IN : USB0_DIR_OUT, + ep_ctx->cfg.type, ep_ctx->cfg.max_sz); + return 0; + } + } + + return 0; +} + +/** + * @brief Disable the selected endpoint + * + * @details Function to disable the selected endpoint. Upon success interrupts are + * disabled for the corresponding endpoint and the endpoint is no longer able for + * transmitting/receiving data. + * + * @param[in] ep Endpoint address corresponding to the one + * listed in the device configuration table + * + * @return 0 on success, negative errno code on fail. + */ +int usb_dc_ep_disable(const uint8_t ep) +{ + struct tlx_usbd_ep_ctx *ep_ctx; + + if (!dev_attached() || !dev_ready()) { + return -ENODEV; + } + + ep_ctx = endpoint_ctx(ep); + if (!ep_ctx) { + return -EINVAL; + } + + if (!ep_ctx->cfg.en) { + return -EALREADY; + } + + if (ep_ctx->buf.data != NULL) { + free(ep_ctx->buf.data); + ep_ctx->buf.data = NULL; + } + + LOG_DBG("EP disable: 0x%02x", ep); + usb0hw_ep_close(USB_EP_GET_IDX(ep), USB_EP_GET_DIR(ep_ctx->cfg.addr) ? USB0_DIR_IN : USB0_DIR_OUT); + ep_ctx_reset(USB_EP_GET_IDX(ep)); + + if (USB_EP_GET_DIR(ep) == USB_EP_DIR_IN) { + usb0hw_flush_tx_fifo(USB_EP_GET_IDX(ep)); + } else { + usb0hw_flush_rx_fifo(); + } + + ep_ctx->cfg.stall = true; + ep_ctx->cfg.en = false; + + return 0; +} + +/** + * @brief Flush the selected endpoint + * + * @details This function flushes the FIFOs for the selected endpoint. + * + * @param[in] ep Endpoint address corresponding to the one + * listed in the device configuration table + * + * @return 0 on success, negative errno code on fail. + */ +int usb_dc_ep_flush(const uint8_t ep) +{ + struct tlx_usbd_ep_ctx *ep_ctx; + + if (!dev_attached() || !dev_ready()) { + return -ENODEV; + } + + ep_ctx = endpoint_ctx(ep); + if (!ep_ctx) { + return -EINVAL; + } + ep_buf_clear(ep); + LOG_DBG("ep%d flush", USB_EP_GET_IDX(ep)); + + return 0; +} + +/** + * @brief Write data to the specified endpoint + * + * @details This function is called to write data to the specified endpoint. The + * supplied usb_ep_callback function will be called when data is transmitted out. + * + * @param[in] ep Endpoint address corresponding to the one + * listed in the device configuration table + * @param[in] data Pointer to data to write + * @param[in] data_len Length of the data requested to write. This may + * be zero for a zero length status packet. + * @param[out] ret_bytes Bytes scheduled for transmission. This value + * may be NULL if the application expects all + * bytes to be written + * + * @return 0 on success, negative errno code on fail. + */ +int usb_dc_ep_write(const uint8_t ep, const uint8_t *const data, const uint32_t data_len, + uint32_t *const ret_bytes) +{ + struct tlx_usbd_ep_ctx *ep_ctx; + + LOG_DBG("ep 0x%02x, len %d", ep, data_len); + + if (!dev_attached() || !dev_ready()) { + return -ENODEV; + } + if (USB_EP_DIR_IS_OUT(ep)) { + LOG_ERR("Endpoint 0x%02x is invalid, it has direaction error.", ep); + return -EINVAL; + } + + ep_ctx = endpoint_ctx(ep); + if (!ep_ctx) { + return -EINVAL; + } + if (!ep_ctx->cfg.en) { + LOG_ERR("Endpoint 0x%02x is not enabled", ep); + return -EINVAL; + } + + ep_ctx->cfg.stall = false; + + *ret_bytes = ep_write(ep, data, data_len); + + return 0; +} + +/** + * @brief Read data from the specified endpoint + * + * @details This function is called by the endpoint handler function, after an OUT + * interrupt has been received for that EP. The application must only call this + * function through the supplied usb_ep_callback function. This function clears + * the ENDPOINT NAK, if all data in the endpoint FIFO has been read, so as to + * accept more data from host. + * + * @param[in] ep Endpoint address corresponding to the one + * listed in the device configuration table + * @param[in] data Pointer to data buffer to write to + * @param[in] max_data_len Max length of data to read + * @param[out] read_bytes Number of bytes read. If data is NULL and + * max_data_len is 0 the number of bytes + * available for read should be returned. + * + * @return 0 on success, negative errno code on fail. + */ +int usb_dc_ep_read(const uint8_t ep, uint8_t *const data, const uint32_t max_data_len, + uint32_t *const read_bytes) +{ + int ret; + + LOG_DBG("dc_ep_read: ep 0x%02x, maxlen %d", ep, max_data_len); + ret = usb_dc_ep_read_wait(ep, data, max_data_len, read_bytes); + + if (ret) { + return ret; + } + + if (!data && !max_data_len) { + return ret; + } + + ret = usb_dc_ep_read_continue(ep); + + return ret; +} + +/** + * @brief Set callback function for the specified endpoint + * + * @details Function to set callback function for notification of data received and + * available to application or transmit done on the selected endpoint, NULL if + * callback not required by application code. The callback status code is + * described by usb_dc_ep_cb_status_code. + * + * @param[in] ep Endpoint address corresponding to the one + * listed in the device configuration table + * @param[in] cb Callback function + * + * @return 0 on success, negative errno code on fail. + */ +int usb_dc_ep_set_callback(const uint8_t ep, const usb_dc_ep_callback cb) +{ + struct tlx_usbd_ep_ctx *ep_ctx; + + if (!dev_attached()) { + return -ENODEV; + } + + ep_ctx = endpoint_ctx(ep); + if (!ep_ctx) { + return -EINVAL; + } + + ep_ctx->cfg.cb = cb; + + return 0; +} + +/** + * @brief Read data from the specified endpoint + * + * @details This is similar to usb_dc_ep_read, the difference being that, it doesn't + * clear the endpoint NAKs so that the consumer is not bogged down by further + * upcalls till he is done with the processing of the data. The caller should + * reactivate ep by invoking usb_dc_ep_read_continue() do so. + * + * @param[in] ep Endpoint address corresponding to the one + * listed in the device configuration table + * @param[in] data Pointer to data buffer to write to + * @param[in] max_data_len Max length of data to read + * @param[out] read_bytes Number of bytes read. If data is NULL and + * max_data_len is 0 the number of bytes + * available for read should be returned. + * + * @return 0 on success, negative errno code on fail. + */ +int usb_dc_ep_read_wait(uint8_t ep, uint8_t *data, uint32_t max_data_len, uint32_t *read_bytes) +{ + struct tlx_usbd_ep_ctx *ep_ctx; + struct tlx_usbd_ctx *ctx = get_usbd_ctx(); + uint32_t bytes_to_copy; + + if (!dev_attached() || !dev_ready()) { + return -ENODEV; + } + + if (USB_EP_DIR_IS_IN(ep)) { + return -EINVAL; + } + + if (!data && max_data_len) { + return -EINVAL; + } + + ep_ctx = endpoint_ctx(ep); + if (!ep_ctx) { + return -EINVAL; + } + + if (!ep_ctx->cfg.en) { + LOG_ERR("Endpoint 0x%02x is not enabled", ep); + return -EINVAL; + } + + k_mutex_lock(&ctx->drv_lock, K_FOREVER); + bytes_to_copy = MIN(max_data_len, ep_ctx->buf.total_len); + memcpy(data, ep_ctx->buf.data, bytes_to_copy); + k_mutex_unlock(&ctx->drv_lock); + *read_bytes = bytes_to_copy; + return 0; +} + +/** + * @brief Continue reading data from the endpoint + * + * @details Clear the endpoint NAK and enable the endpoint to accept more data from + * the host. Usually called after usb_dc_ep_read_wait() when the consumer is fine + * to accept more data. Thus these calls together act as a flow control mechanism. + * + * @param[in] ep Endpoint address corresponding to the one + * listed in the device configuration table + * + * @return 0 on success, negative errno code on fail. + */ +int usb_dc_ep_read_continue(uint8_t ep) +{ + struct tlx_usbd_ep_ctx *ep_ctx; + + if (!dev_attached() || !dev_ready()) { + return -ENODEV; + } + + if (USB_EP_DIR_IS_IN(ep)) { + return -EINVAL; + } + + ep_ctx = endpoint_ctx(ep); + if (!ep_ctx) { + return -EINVAL; + } + + if (!ep_ctx->cfg.en) { + LOG_ERR("Ep 0x%02x is not enabled", ep); + return -EINVAL; + } + + LOG_DBG("Continue read ep 0x%02x", ep); + + if (ep_ctx->cfg.out_ack == false) { + usb0hw_read_ep_data(USB_EP_GET_IDX(ep), ep_ctx->buf.data, ep_ctx->cfg.max_sz); + ep_ctx->cfg.out_ack = true; + } + return 0; +} + +/** + * @brief Get endpoint max packet size + * + * @param[in] ep Endpoint address corresponding to the one + * listed in the device configuration table + * + * @return Endpoint max packet size (mps) + */ +int usb_dc_ep_mps(uint8_t ep) +{ + struct tlx_usbd_ep_ctx *ep_ctx; + + if (!dev_attached()) { + return -ENODEV; + } + + ep_ctx = endpoint_ctx(ep); + if (!ep_ctx) { + return -EINVAL; + } + + return ep_ctx->cfg.max_sz; +} + +/** + * @brief Start the host wake up procedure. + * + * @details Function to wake up the host if it's currently in sleep mode. + * + * @return 0 on success, negative errno code on fail. + */ +int usb_dc_wakeup_request(void) +{ + LOG_DBG("Remote wakeup"); + usb0hw_remote_wakeup(); + return 0; +} + +static void usbd_work_handler(struct k_work *item) +{ + struct tlx_usbd_ctx *ctx; + struct tlx_usbd_ep_ctx *ep_ctx; + struct usbd_event *ev; + + ctx = CONTAINER_OF(item, struct tlx_usbd_ctx, usb_work); + while ((ev = usbd_evt_get()) != NULL) { + if (!dev_ready()) { + usbd_evt_free(ev); + LOG_DBG("USBD is not ready, event drops."); + continue; + } + + switch (ev->evt_type) { + case USBD_EVT_IN_COMPLETE: + LOG_DBG("IN_COMPLETE"); + usb_event_in_handler(ev->ep_addr); + break; + + case USBD_EVT_EP_WRITE_COMPLETE: + LOG_DBG("EP_WRITE_COMPLETE(0X%x)", ev->ep_addr); + usb_event_ep_write_complete_handler(ev->ep_addr); + break; + + case USBD_EVT_EP_RETRY: + LOG_DBG("EP_RETRY"); + usb_event_ep_retry_handler(ev->ep_addr); + break; + + case USBD_EVT_OUT_COMPLETE: + LOG_DBG("OUT_COMPLETE"); + usb_event_out_complete_handler(ev->ep_addr); + break; + + case USBD_EVT_OUT_SETUP: + LOG_DBG("OUT_SETUP"); + usb_event_out_setup_handler(ev->ep_addr); + break; + + case USBD_EVT_OUT_RCVD: + LOG_DBG("OUT_RCVD(0X%x)", ev->ep_addr); + usb_event_out_rcvd_handler(ev->ep_addr); + break; + + case USBD_EVT_SUSPEND: + LOG_DBG("SUSPEND"); + usb_event_suspend_handler(); + break; + + case USBD_EVT_WAKEUP: + LOG_DBG("WAKEUP"); + usb_event_wakeup_handler(); + break; + + case USBD_EVT_RESET: + LOG_DBG("RESET"); + usb_event_reset_handler(); + break; + + case USBD_EVT_REINIT: + LOG_DBG("REINIT"); + break; + + default: + LOG_ERR("Unknown USBD event: %" PRId16, ev->evt_type); + break; + } + + usbd_evt_free(ev); + } +} + +static void usbd_retry_timer_expire(struct k_timer *timer) +{ + struct tlx_usbd_ep_ctx *ep_ctx = k_timer_user_data_get(timer); + + submit_usbd_event(USBD_EVT_EP_RETRY, ep_ctx - usbd_ctx.ep_ctx); +} + +static int usb_init(void) +{ + int ret; + +#if CONFIG_USB_DC_HAS_HS_SUPPORT + usb0hw_init(USB0_SPEED_HIGH); +#else + usb0hw_init(USB0_SPEED_FULL); +#endif + + usb0hw_set_grxfsiz(EPS_BUFFER_OUT_SIZE); + + eps_buf_inf.seg_addr = EPS_BUFFER_OUT_SIZE; + + for (size_t i = 0; i < USBD_EP_TOTAL_CNT; i++) { + k_timer_init(&usbd_ctx.ep_ctx[i].retry_timer, usbd_retry_timer_expire, NULL); + k_timer_user_data_set(&usbd_ctx.ep_ctx[i].retry_timer, &usbd_ctx.ep_ctx[i]); + } + + ret = usb_irq_init(); + k_work_queue_start(&usbd_work_queue, usbd_work_queue_stack, + K_KERNEL_STACK_SIZEOF(usbd_work_queue_stack), + CONFIG_SYSTEM_WORKQUEUE_PRIORITY, NULL); + + k_work_init(&get_usbd_ctx()->usb_work, usbd_work_handler); + + return ret; +} + +SYS_INIT(usb_init, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE); diff --git a/drivers/usb/device/usb_dc_tlx.c b/drivers/usb/device/usb_dc_tlx.c index 575611512e944..4ba442872e26b 100644 --- a/drivers/usb/device/usb_dc_tlx.c +++ b/drivers/usb/device/usb_dc_tlx.c @@ -5,9 +5,9 @@ */ #if CONFIG_SOC_RISCV_TELINK_TL721X -#include "driver_tl721x.h" +#include "driver.h" #elif CONFIG_SOC_RISCV_TELINK_TL321X -#include "driver_tl321x.h" +#include "driver.h" #endif #include diff --git a/dts/bindings/power/telink,tl322x-power.yaml b/dts/bindings/power/telink,tl322x-power.yaml new file mode 100644 index 0000000000000..774b061bfc8e1 --- /dev/null +++ b/dts/bindings/power/telink,tl322x-power.yaml @@ -0,0 +1,26 @@ +# Copyright (c) 2023 Telink Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +description: Telink TL322X power control node + +compatible: "telink,tl322x-power" + +include: base.yaml + +properties: + reg: + required: true + + power-mode: + type: string + required: true + enum: + - "LDO_1P25_LDO_1P8" + - "DCDC_1P25_LDO_1P8" + + vbat-type: + type: string + required: true + enum: + - "VBAT_MAX_VALUE_LESS_THAN_3V6" + - "VBAT_MAX_VALUE_GREATER_THAN_3V6" diff --git a/dts/bindings/power/telink,tl323x-power.yaml b/dts/bindings/power/telink,tl323x-power.yaml new file mode 100644 index 0000000000000..0c60bd72d5c84 --- /dev/null +++ b/dts/bindings/power/telink,tl323x-power.yaml @@ -0,0 +1,26 @@ +# Copyright (c) 2023 Telink Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +description: Telink TL323X power control node + +compatible: "telink,tl323x-power" + +include: base.yaml + +properties: + reg: + required: true + + power-mode: + type: string + required: true + enum: + - "LDO_1P25_LDO_1P8" + - "DCDC_1P25_LDO_1P8" + + vbat-type: + type: string + required: true + enum: + - "VBAT_MAX_VALUE_LESS_THAN_3V6" + - "VBAT_MAX_VALUE_GREATER_THAN_3V6" diff --git a/dts/bindings/spi/telink,tl322x-spi.yaml b/dts/bindings/spi/telink,tl322x-spi.yaml new file mode 100644 index 0000000000000..62056c527c7b0 --- /dev/null +++ b/dts/bindings/spi/telink,tl322x-spi.yaml @@ -0,0 +1,51 @@ +# Copyright (c) 2024, Telink Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +description: Telink TL322X SPI + +include: spi-controller.yaml + +compatible: "telink,tl322x-spi" + +properties: + reg: + required: true + + peripheral-id: + type: string + required: true + enum: + - "LSPI_MODULE" + - "GSPI_MODULE" + + pinctrl-0: + type: phandles + required: true + + cs0-pin: + type: string + required: true + enum: + - "0" + - "LSPI_CSN_PE0_PIN" + - "GPIO_PA1" + - "GPIO_PF3" + - "GPIO_PH3" + + cs1-pin: + type: string + enum: + - "0" + - "LSPI_CSN_PE0_PIN" + - "GPIO_PA1" + - "GPIO_PB6" + - "GPIO_PH3" + + cs2-pin: + type: string + enum: + - "0" + - "LSPI_CSN_PE0_PIN" + - "GPIO_PA1" + - "GPIO_PB6" + - "GPIO_PH3" diff --git a/dts/bindings/spi/telink,tl323x-spi.yaml b/dts/bindings/spi/telink,tl323x-spi.yaml new file mode 100644 index 0000000000000..0d918ab7b77df --- /dev/null +++ b/dts/bindings/spi/telink,tl323x-spi.yaml @@ -0,0 +1,51 @@ +# Copyright (c) 2024, Telink Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +description: Telink TL323X SPI + +include: spi-controller.yaml + +compatible: "telink,tl323x-spi" + +properties: + reg: + required: true + + peripheral-id: + type: string + required: true + enum: + - "LSPI_MODULE" + - "GSPI_MODULE" + + pinctrl-0: + type: phandles + required: true + + cs0-pin: + type: string + required: true + enum: + - "0" + - "LSPI_CSN_PE0_PIN" + - "GPIO_PA1" + - "GPIO_PB6" + - "GPIO_PE4" + + cs1-pin: + type: string + enum: + - "0" + - "LSPI_CSN_PE0_PIN" + - "GPIO_PA1" + - "GPIO_PB6" + - "GPIO_PE4" + + cs2-pin: + type: string + enum: + - "0" + - "LSPI_CSN_PE0_PIN" + - "GPIO_PA1" + - "GPIO_PB6" + - "GPIO_PE4" diff --git a/dts/bindings/usb/telink,tl322x-usbd.yaml b/dts/bindings/usb/telink,tl322x-usbd.yaml new file mode 100644 index 0000000000000..4d5814777a787 --- /dev/null +++ b/dts/bindings/usb/telink,tl322x-usbd.yaml @@ -0,0 +1,16 @@ +# Copyright (c) 2023 Telink Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +description: | + Telink Tex USB device controller + +compatible: "telink,tl322x-usbd" + +include: usb-ep.yaml + +properties: + reg: + required: true + + interrupts: + required: true diff --git a/dts/riscv/telink/telink_tl322x.dtsi b/dts/riscv/telink/telink_tl322x.dtsi new file mode 100644 index 0000000000000..890b5a27563a4 --- /dev/null +++ b/dts/riscv/telink/telink_tl322x.dtsi @@ -0,0 +1,298 @@ +/* + * Copyright (c) 2024 Telink Semiconductor + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include +#include +#include +#include +#include + +/ { + #address-cells = <1>; + #size-cells = <1>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + cpu0: cpu@0 { + reg = <0>; + clock-frequency = <64000000>; + compatible ="telink,tlx", "riscv"; + cpu-power-states = <&state0>; + }; + }; + + power-states { + state0: state0 { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + min-residency-us = <1026>; + exit-latency-us = <69>; + }; + }; + + soc { + #address-cells = <1>; + #size-cells = <1>; + compatible = "telink,telink_tl322x-soc"; + ranges; + + ram_ilm: memory@0 { + compatible = "mmio-sram"; + }; + + ram_dlm: memory@80000 { + compatible = "mmio-sram"; + }; + + mtimer: timer@c6000000 { + compatible = "telink,machine-timer"; + reg = <0xc6000000 0x10000>; + interrupts = <7 0>; + interrupt-parent = <&plic0>; + }; + + mbox: mbox@80101c00 { + compatible = "telink,mbox-ipc-tl322x"; + #mbox-cells = <1>; + reg = <0x80101c00 0x36>; + interrupt-parent = <&plic0>; + interrupts = <58 1>; + status = "okay"; + }; + + + flash_mspi: flash-controller@A3FFFF00 { + compatible = "telink,tlx-flash-controller"; + reg = <0xA3FFFF00 0x100>; + + #address-cells = <1>; + #size-cells = <1>; + + flash: flash@20000000 { + compatible = "soc-nv-flash"; + write-block-size = <1>; + }; + }; + + power: power@80140180 { + compatible = "telink,tl322x-power"; + reg = <0x80140180 0x40>; + power-mode = "DCDC_1P25_LDO_1P8"; + vbat-type = "VBAT_MAX_VALUE_GREATER_THAN_3V6"; + status = "okay"; + }; + + gpioa: gpio@80140c00 { + compatible = "telink,tlx-gpio"; + gpio-controller; + interrupt-parent = <&plic0>; + interrupts = <46 1>, <47 1>, <48 1>, <49 1>, <50 1>, <51 1>, <52 1>, <53 1>; + reg = <0x80140c00 0x10>; + status = "disabled"; + #gpio-cells = <2>; + }; + + gpiob: gpio@80140c10 { + compatible = "telink,tlx-gpio"; + gpio-controller; + interrupt-parent = <&plic0>; + interrupts = <46 1>, <47 1>, <48 1>, <49 1>, <50 1>, <51 1>, <52 1>, <53 1>; + reg = <0x80140c10 0x10>; + status = "disabled"; + #gpio-cells = <2>; + }; + + gpioc: gpio@80140c20 { + compatible = "telink,tlx-gpio"; + gpio-controller; + interrupt-parent = <&plic0>; + interrupts = <46 1>, <47 1>, <48 1>, <49 1>, <50 1>, <51 1>, <52 1>, <53 1>; + reg = <0x80140c20 0x10>; + status = "disabled"; + #gpio-cells = <2>; + }; + + gpiod: gpio@80140c30 { + compatible = "telink,tlx-gpio"; + gpio-controller; + interrupt-parent = <&plic0>; + interrupts = <46 1>, <47 1>, <48 1>, <49 1>, <50 1>, <51 1>, <52 1>, <53 1>; + reg = <0x80140c30 0x10>; + status = "disabled"; + #gpio-cells = <2>; + }; + + gpioe: gpio@80140c40 { + compatible = "telink,tlx-gpio"; + gpio-controller; + interrupt-parent = <&plic0>; + interrupts = <46 1>, <47 1>, <48 1>, <49 1>, <50 1>, <51 1>, <52 1>, <53 1>; + reg = <0x80140c40 0x10>; + status = "disabled"; + #gpio-cells = <2>; + }; + + gpiof: gpio@80140c50 { + compatible = "telink,tlx-gpio"; + gpio-controller; + interrupt-parent = <&plic0>; + interrupts = <46 1>, <47 1>, <48 1>, <49 1>, <50 1>, <51 1>, <52 1>, <53 1>; + reg = <0x80140c50 0x10>; + status = "disabled"; + #gpio-cells = <2>; + }; + + gpiog: gpio@80140c60 { + compatible = "telink,tlx-gpio"; + gpio-controller; + interrupt-parent = <&plic0>; + interrupts = <46 1>, <47 1>, <48 1>, <49 1>, <50 1>, <51 1>, <52 1>, <53 1>; + reg = <0x80140c60 0x10>; + status = "disabled"; + #gpio-cells = <2>; + }; + + gpioh: gpio@80140c70 { + compatible = "telink,tlx-gpio"; + gpio-controller; + interrupt-parent = <&plic0>; + interrupts = <46 1>, <47 1>, <48 1>, <49 1>, <50 1>, <51 1>, <52 1>, <53 1>; + reg = <0x80140c70 0x10>; + status = "disabled"; + #gpio-cells = <2>; + }; + + gpioi: gpio@80140c80 { + compatible = "telink,tlx-gpio"; + gpio-controller; + interrupt-parent = <&plic0>; + interrupts = <46 1>, <47 1>, <48 1>, <49 1>, <50 1>, <51 1>, <52 1>, <53 1>; + reg = <0x80140c80 0x10>; + status = "disabled"; + #gpio-cells = <2>; + }; + + plic0: interrupt-controller@c4000000 { + compatible = "sifive,plic-1.0.0"; + #address-cells = <0>; + #interrupt-cells = <2>; + interrupt-controller; + reg = < 0xc4000000 0x00001000 + 0xc4002000 0x00000800 + 0xc4200000 0x00010000 >; + reg-names = "prio", "irq_en", "reg"; + riscv,max-priority = <3>; + riscv,ndev = <64>; + }; + + uart0: serial@80140080 { + compatible = "telink,tlx-uart"; + reg = <0x80140080 0x40>; + interrupts = <31 1>; + interrupt-parent = <&plic0>; + status = "disabled"; + }; + + uart1: serial@801400C0 { + compatible = "telink,tlx-uart"; + reg = <0x801400C0 0x40>; + interrupts = <30 1>; + interrupt-parent = <&plic0>; + status = "disabled"; + }; + + ieee802154: ieee802154@80140800 { + compatible = "telink,tlx-zb"; + reg = <0x80140800 0x800>; + interrupt-parent = <&plic0>; + interrupts = <27 2>; + status = "disabled"; + }; + + trng0: trng@80103000 { + compatible = "telink,tlx-trng"; + reg = <0x80103000 0x20>; + status = "disabled"; + }; + + pwm0: pwm@80140e00 { + compatible = "telink,tlx-pwm"; + reg = <0x80140e00 0x80>; + channels = <6>; + status = "disabled"; + #pwm-cells = <3>; + }; + + gspi: spi@8BFFFF00 { + compatible = "telink,tl322x-spi"; + reg = <0x8BFFFF00 0x100>; + peripheral-id = "GSPI_MODULE"; + cs0-pin = "0"; + cs1-pin = "0"; + cs2-pin = "0"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + lspi: spi@87FFFF00 { + compatible = "telink,tl322x-spi"; + reg = <0x87FFFF00 0x100>; + peripheral-id = "LSPI_MODULE"; + cs0-pin = "0"; + cs1-pin = "0"; + cs2-pin = "0"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c: i2c@80140280 { + compatible = "telink,tlx-i2c"; + reg = <0x80140280 0x40>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + clock-frequency = ; + }; + + adc: adc@ea { + compatible = "telink,tlx-adc"; + reg = <0xea 0x18>; + status = "disabled"; + #io-channel-cells = <1>; + }; + + usbd: usbd@80280000 { + compatible = "telink,tl322x-usbd"; + reg = <0x80280000 0x6000c>; + interrupts = <26 1>; + interrupt-parent = <&plic0>; + num-bidir-endpoints = <9>; + status = "disabled"; + }; + + pinctrl: pinctrl@80140cb0 { + compatible = "telink,tlx-pinctrl"; + reg = <0x80140cb0 0x40 + 0x80140c06 0x90 + 0x00000017 0x12>; + reg-names = "pin_mux", + "gpio_en", + "pull_up_en"; + status = "okay"; + }; + + wdt: watchdog@140140 { + compatible = "telink,tlx-watchdog"; + reg = <0x140140 0x10>; + status = "disabled"; + }; + }; +}; diff --git a/dts/riscv/telink/telink_tl323x.dtsi b/dts/riscv/telink/telink_tl323x.dtsi new file mode 100644 index 0000000000000..523d67014134b --- /dev/null +++ b/dts/riscv/telink/telink_tl323x.dtsi @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2024 Telink Semiconductor + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include +#include +#include +#include +#include + +/ { + #address-cells = <1>; + #size-cells = <1>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + cpu0: cpu@0 { + reg = <0>; + clock-frequency = <24000000>; + compatible ="telink,tlx", "riscv"; + cpu-power-states = <&state0>; + }; + }; + + power-states { + state0: state0 { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + min-residency-us = <20000>; + exit-latency-us = <3000>; + }; + }; + + soc { + #address-cells = <1>; + #size-cells = <1>; + compatible = "telink,telink_tl323x-soc"; + ranges; + + ram_ilm: memory@60000 { + compatible = "mmio-sram"; + }; + + ram_ilm_non_retention: memory@80000 { + compatible = "mmio-sram"; + }; + + mtimer: timer@c6000000 { + compatible = "telink,machine-timer"; + reg = <0xc6000000 0x10000>; + interrupts = <7 0>; + interrupt-parent = <&plic0>; + }; + + flash_mspi: flash-controller@A3FFFF00 { + compatible = "telink,tlx-flash-controller"; + reg = <0xA3FFFF00 0x100>; + + #address-cells = <1>; + #size-cells = <1>; + + flash: flash@20000000 { + compatible = "soc-nv-flash"; + write-block-size = <1>; + }; + }; + + power: power@80140180 { + compatible = "telink,tl323x-power"; + reg = <0x80140180 0x40>; + power-mode = "DCDC_1P25_LDO_1P8"; + vbat-type = "VBAT_MAX_VALUE_GREATER_THAN_3V6"; + status = "okay"; + }; + + gpioa: gpio@80140c00 { + compatible = "telink,tlx-gpio"; + gpio-controller; + interrupt-parent = <&plic0>; + interrupts = <46 1>, <47 1>, <48 1>, <49 1>, <50 1>, <51 1>, <52 1>, <53 1>; + reg = <0x80140c00 0x10>; + status = "disabled"; + #gpio-cells = <2>; + }; + + gpiob: gpio@80140c10 { + compatible = "telink,tlx-gpio"; + gpio-controller; + interrupt-parent = <&plic0>; + interrupts = <46 1>, <47 1>, <48 1>, <49 1>, <50 1>, <51 1>, <52 1>, <53 1>; + reg = <0x80140c10 0x10>; + status = "disabled"; + #gpio-cells = <2>; + }; + + gpioc: gpio@80140c20 { + compatible = "telink,tlx-gpio"; + gpio-controller; + interrupt-parent = <&plic0>; + interrupts = <46 1>, <47 1>, <48 1>, <49 1>, <50 1>, <51 1>, <52 1>, <53 1>; + reg = <0x80140c20 0x10>; + status = "disabled"; + #gpio-cells = <2>; + }; + + gpiod: gpio@80140c30 { + compatible = "telink,tlx-gpio"; + gpio-controller; + interrupt-parent = <&plic0>; + interrupts = <46 1>, <47 1>, <48 1>, <49 1>, <50 1>, <51 1>, <52 1>, <53 1>; + reg = <0x80140c30 0x10>; + status = "disabled"; + #gpio-cells = <2>; + }; + + gpioe: gpio@80140c40 { + compatible = "telink,tlx-gpio"; + gpio-controller; + interrupt-parent = <&plic0>; + interrupts = <46 1>, <47 1>, <48 1>, <49 1>, <50 1>, <51 1>, <52 1>, <53 1>; + reg = <0x80140c40 0x10>; + status = "disabled"; + #gpio-cells = <2>; + }; + + gpiof: gpio@80140c50 { + compatible = "telink,tlx-gpio"; + gpio-controller; + interrupt-parent = <&plic0>; + interrupts = <46 1>, <47 1>, <48 1>, <49 1>, <50 1>, <51 1>, <52 1>, <53 1>; + reg = <0x80140c50 0x10>; + status = "disabled"; + #gpio-cells = <2>; + }; + + plic0: interrupt-controller@c4000000 { + compatible = "sifive,plic-1.0.0"; + #address-cells = <0>; + #interrupt-cells = <2>; + interrupt-controller; + reg = < 0xc4000000 0x00001000 + 0xc4002000 0x00000800 + 0xc4200000 0x00010000 >; + reg-names = "prio", "irq_en", "reg"; + riscv,max-priority = <3>; + riscv,ndev = <52>; + }; + + uart0: serial@80140080 { + compatible = "telink,tlx-uart"; + reg = <0x80140080 0x40>; + interrupts = <31 1>; + interrupt-parent = <&plic0>; + status = "disabled"; + }; + + uart1: serial@801400C0 { + compatible = "telink,tlx-uart"; + reg = <0x801400C0 0x40>; + interrupts = <30 1>; + interrupt-parent = <&plic0>; + status = "disabled"; + }; + + ieee802154: ieee802154@80140800 { + compatible = "telink,tlx-zb"; + reg = <0x80140800 0x800>; + interrupt-parent = <&plic0>; + interrupts = <27 2>; + status = "disabled"; + }; + + trng0: trng@80103000 { + compatible = "telink,tlx-trng"; + reg = <0x80103000 0x20>; + status = "disabled"; + }; + + pwm0: pwm@80140400 { + compatible = "telink,tlx-pwm"; + reg = <0x80140400 0x80>; + channels = <6>; + status = "disabled"; + #pwm-cells = <3>; + }; + + gspi: spi@8BFFFF00 { + compatible = "telink,tl323x-spi"; + reg = <0x8BFFFF00 0x100>; + peripheral-id = "GSPI_MODULE"; + cs0-pin = "0"; + cs1-pin = "0"; + cs2-pin = "0"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c: i2c@80140280 { + compatible = "telink,tlx-i2c"; + reg = <0x80140280 0x40>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + clock-frequency = ; + }; + + adc: adc@ea { + compatible = "telink,tlx-adc"; + reg = <0xea 0x18>; + status = "disabled"; + #io-channel-cells = <1>; + }; + + pinctrl: pinctrl@80140c70 { + compatible = "telink,tlx-pinctrl"; + reg = <0x80140cb0 0x30 + 0x80140c06 0x50 + 0x00000017 0x0C>; + reg-names = "pin_mux", + "gpio_en", + "pull_up_en"; + status = "okay"; + }; + + wdt: watchdog@140140 { + compatible = "telink,tlx-watchdog"; + reg = <0x140140 0x10>; + status = "disabled"; + }; + }; +}; diff --git a/include/zephyr/dt-bindings/adc/tl322x-adc.h b/include/zephyr/dt-bindings/adc/tl322x-adc.h new file mode 100644 index 0000000000000..6ec345cedd1c8 --- /dev/null +++ b/include/zephyr/dt-bindings/adc/tl322x-adc.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2022-2023 Telink Semiconductor + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_ADC_TLX_ADC_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_ADC_TLX_ADC_H_ + +#define DT_ADC_GPIO_PC0 0x01 +#define DT_ADC_GPIO_PC1 0x02 +#define DT_ADC_GPIO_PC2 0x03 +#define DT_ADC_GPIO_PC3 0x04 +#define DT_ADC_GPIO_PC4 0x05 +#define DT_ADC_GPIO_PC5 0x06 +#define DT_ADC_GPIO_PC6 0x07 +#define DT_ADC_GPIO_PC7 0x08 + +#define DT_ADC_VBAT 0x00 /* 仅 SAR0 支持 */ + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_ADC_TLX_ADC_H_ */ diff --git a/include/zephyr/dt-bindings/pinctrl/tl322x-pinctrl.h b/include/zephyr/dt-bindings/pinctrl/tl322x-pinctrl.h new file mode 100644 index 0000000000000..34aec694e8255 --- /dev/null +++ b/include/zephyr/dt-bindings/pinctrl/tl322x-pinctrl.h @@ -0,0 +1,226 @@ +/* + * Copyright (c) 2024 Telink Semiconductor + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_TL322X_PINCTRL_COMMON_H_ +#define ZEPHYR_TL322X_PINCTRL_COMMON_H_ + +/* IDs for TL322X GPIO functions */ + +#define TL322X_FUNC_DEFAULT 0 +#define TL322X_FUNC_PWM0 1 +#define TL322X_FUNC_PWM4 2 +#define TL322X_FUNC_PWM8 3 +#define TL322X_FUNC_PWM12 4 +#define TL322X_FUNC_PWM16 5 +#define TL322X_FUNC_PWM20 6 +#define TL322X_FUNC_PWM0_N 7 +#define TL322X_FUNC_PWM4_N 8 +#define TL322X_FUNC_PWM8_N 9 +#define TL322X_FUNC_PWM12_N 10 +#define TL322X_FUNC_PWM16_N 11 +#define TL322X_FUNC_PWM20_N 12 +#define TL322X_FUNC_MSPI_CN2 13 +#define TL322X_FUNC_MSPI_CN3 14 +#define TL322X_FUNC_MSPI_CN1 15 +#define TL322X_FUNC_I2C_SCL_IO 16 +#define TL322X_FUNC_I2C_SDA_IO 17 +#define TL322X_FUNC_I2C1_SDA_IO 18 +#define TL322X_FUNC_I2C1_SCL_IO 19 +#define TL322X_FUNC_UART0_CTS_I 20 +#define TL322X_FUNC_UART0_RTS 21 +#define TL322X_FUNC_UART0_TX 22 +#define TL322X_FUNC_UART0_RTX_IO 23 +#define TL322X_FUNC_UART1_CTS_I 24 +#define TL322X_FUNC_UART1_RTS 25 +#define TL322X_FUNC_UART1_TX 26 +#define TL322X_FUNC_UART1_RTX_IO 27 +#define TL322X_FUNC_UART2_CTS_I 28 +#define TL322X_FUNC_UART2_RTS 29 +#define TL322X_FUNC_UART2_TX 30 +#define TL322X_FUNC_UART2_RTX_IO 31 +#define TL322X_FUNC_UART3_CTS_I 32 +#define TL322X_FUNC_UART3_RTS 33 +#define TL322X_FUNC_UART3_TX 34 +#define TL322X_FUNC_UART3_RTX_IO 35 +#define TL322X_FUNC_UART4_CTS_I 36 +#define TL322X_FUNC_UART4_RTS 37 +#define TL322X_FUNC_UART4_TX 38 +#define TL322X_FUNC_UART4_RTX_IO 39 +#define TL322X_FUNC_CLK_7816 40 +#define TL322X_FUNC_I2S0_CLK 41 +#define TL322X_FUNC_I2S2_BCK_IO 42 +#define TL322X_FUNC_I2S2_LR0_IO 43 +#define TL322X_FUNC_I2S2_DAT0_IO 44 +#define TL322X_FUNC_I2S2_LR1_IO 45 +#define TL322X_FUNC_I2S2_DAT1_IO 46 +#define TL322X_FUNC_I2S2_CLK 47 +#define TL322X_FUNC_DMIC0_CLK 48 +#define TL322X_FUNC_DMIC0_DAT_I 49 +#define TL322X_FUNC_SDM0_P 50 +#define TL322X_FUNC_SDM0_N 51 +#define TL322X_FUNC_SDM1_P 52 +#define TL322X_FUNC_SDM1_N 53 +#define TL322X_FUNC_IR_LEARN_I 54 +#define TL322X_FUNC_SSPI_CN_I 55 +#define TL322X_FUNC_SSPI_CK_I 56 +#define TL322X_FUNC_SSPI_SI_IO 57 +#define TL322X_FUNC_SSPI_SO_IO 58 +#define TL322X_FUNC_KEYS0_IO 59 +#define TL322X_FUNC_PWM_SYNC_I 60 +#define TL322X_FUNC_RZ_TX 61 +#define TL322X_FUNC_SWM_IO 62 +#define TL322X_FUNC_TX_CYC2PA 63 +#define TL322X_FUNC_WIFI_DENY_I 64 +#define TL322X_FUNC_BT_ACTIVITY 65 +#define TL322X_FUNC_BT_STATUS 66 +#define TL322X_FUNC_ATSEL_0 67 +#define TL322X_FUNC_ATSEL_1 68 +#define TL322X_FUNC_ATSEL_2 69 +#define TL322X_FUNC_ATSEL_3 70 +#define TL322X_FUNC_ATSEL_4 71 +#define TL322X_FUNC_ATSEL_5 72 +#define TL322X_FUNC_RX_CYC2LNA 73 +#define TL322X_FUNC_DBG_PROBE_CLK 74 +#define TL322X_FUNC_DBG_BB0 75 +#define TL322X_FUNC_DBG_ADC_I_DAT0 76 +#define TL322X_FUNC_LIN0_RX_I 77 +#define TL322X_FUNC_LIN0_TX 78 +#define TL322X_FUNC_LIN1_RX_I 79 +#define TL322X_FUNC_LIN1_TX 80 +#define TL322X_FUNC_CAN0_RX_I 81 +#define TL322X_FUNC_CAN0_TX 82 +#define TL322X_FUNC_CAN1_RX_I 83 +#define TL322X_FUNC_CAN1_TX 84 +#define TL322X_FUNC_I3C0_SDA_PULLUP_EN 85 +#define TL322X_FUNC_I3C0_SDA_IO 86 +#define TL322X_FUNC_I3C0_SCL_IO 87 +#define TL322X_FUNC_I3C1_SDA_PULLUP_EN 88 +#define TL322X_FUNC_I3C1_SDA_IO 89 +#define TL322X_FUNC_I3C1_SCL_IO 90 +#define TL322X_FUNC_GSPI_CN_IO 91 +#define TL322X_FUNC_GSPI_IO3_IO 92 +#define TL322X_FUNC_GSPI_IO2_IO 93 +#define TL322X_FUNC_GSPI_MISO_IO 94 +#define TL322X_FUNC_GSPI_MOSI_IO 95 +#define TL322X_FUNC_GSPI_CK_IO 96 +#define TL322X_FUNC_GSPI1_CN_IO 97 +#define TL322X_FUNC_GSPI1_IO3_IO 98 +#define TL322X_FUNC_GSPI1_IO2_IO 99 +#define TL322X_FUNC_GSPI1_MISO_IO 100 +#define TL322X_FUNC_GSPI1_MOSI_IO 101 +#define TL322X_FUNC_GSPI1_CK_IO 102 +#define TL322X_FUNC_GSPI2_CN_IO 103 +#define TL322X_FUNC_GSPI2_IO3_IO 104 +#define TL322X_FUNC_GSPI2_IO2_IO 105 +#define TL322X_FUNC_GSPI2_MISO_IO 106 +#define TL322X_FUNC_GSPI2_MOSI_IO 107 +#define TL322X_FUNC_GSPI2_CK_IO 108 +#define TL322X_FUNC_GSPI3_CN_IO 109 +#define TL322X_FUNC_GSPI3_IO3_IO 110 +#define TL322X_FUNC_GSPI3_IO2_IO 111 +#define TL322X_FUNC_GSPI3_MISO_IO 112 +#define TL322X_FUNC_GSPI3_MOSI_IO 113 +#define TL322X_FUNC_GSPI3_CK_IO 114 +#define TL322X_FUNC_GSPI4_CN_IO 115 +#define TL322X_FUNC_GSPI4_IO3_IO 116 +#define TL322X_FUNC_GSPI4_IO2_IO 117 +#define TL322X_FUNC_GSPI4_MISO_IO 118 +#define TL322X_FUNC_GSPI4_MOSI_IO 119 +#define TL322X_FUNC_GSPI4_CK_IO 120 +#define TL322X_FUNC_LSPI_CN_IO 121 +#define TL322X_FUNC_LSPI_IO3_IO 122 +#define TL322X_FUNC_LSPI_IO2_IO 123 +#define TL322X_FUNC_LSPI_MISO_IO 124 +#define TL322X_FUNC_LSPI_MOSI_IO 125 +#define TL322X_FUNC_LSPI_CK_IO 126 + +/* Some special aliases (with value 0) */ +#define TL322X_FUNC_PA5_USB0_DM_IO 0 +#define TL322X_FUNC_PA6_USB0_DP_IO 0 +#define TL322X_FUNC_PA7_SWS_IO 0 +#define TL322X_FUNC_PC4_TDI_I 0 +#define TL322X_FUNC_PC5_TDO_IO 0 +#define TL322X_FUNC_PC6_TMS_IO 0 +#define TL322X_FUNC_PC7_TCK_I 0 +#define TL322X_FUNC_PI0_MSPI_MOSI_IO 0 +#define TL322X_FUNC_PI1_MSPI_CK_IO 0 +#define TL322X_FUNC_PI2_MSPI_IO3_IO 0 +#define TL322X_FUNC_PI3_MSPI_CN_IO 0 +#define TL322X_FUNC_PI4_MSPI_MISO_IO 0 +#define TL322X_FUNC_PI5_MSPI_IO2_IO 0 + +/* IDs for GPIO Ports */ + +#define TLX_PORT_A 0x00 +#define TLX_PORT_B 0x01 +#define TLX_PORT_C 0x02 +#define TLX_PORT_D 0x03 +#define TLX_PORT_E 0x04 +#define TLX_PORT_F 0x05 +#define TLX_PORT_G 0x06 +#define TLX_PORT_H 0x07 +#define TLX_PORT_I 0x08 + +/* IDs for GPIO Pins */ + +#define TLX_PIN_0 0x01 +#define TLX_PIN_1 0x02 +#define TLX_PIN_2 0x04 +#define TLX_PIN_3 0x08 +#define TLX_PIN_4 0x10 +#define TLX_PIN_5 0x20 +#define TLX_PIN_6 0x40 +#define TLX_PIN_7 0x80 + +/* TLX pinctrl pull-up/down */ + +#define TLX_PULL_NONE 0 +#define TLX_PULL_DOWN 2 +#define TLX_PULL_UP 3 + +/* Pin function positions */ + +#define TL322X_PIN_FUNC_POS 0xFF + +/* Pin pull up positions */ + +#define TLX_PIN_0_PULL_UP_EN_POS 0x00 +#define TLX_PIN_1_PULL_UP_EN_POS 0x02 +#define TLX_PIN_2_PULL_UP_EN_POS 0x04 +#define TLX_PIN_3_PULL_UP_EN_POS 0x06 +#define TLX_PIN_4_PULL_UP_EN_POS 0x00 +#define TLX_PIN_5_PULL_UP_EN_POS 0x02 +#define TLX_PIN_6_PULL_UP_EN_POS 0x04 +#define TLX_PIN_7_PULL_UP_EN_POS 0x06 + +/* TL322X pin configuration bit field positions and masks */ + +#define TLX_PULL_POS 24 +#define TLX_PULL_MSK 0x3 +#define TLX_FUNC_POS 16 +#define TL322X_FUNC_MSK 0xFF +#define TLX_PORT_POS 8 +#define TLX_PORT_MSK 0xFF + +#define TLX_PIN_POS 0 +#define TLX_PIN_MSK 0xFFFF +#define TLX_PIN_ID_MSK 0xFF + +#define TL322X_PULL_NONE (TLX_PULL_NONE << (TLX_PULL_POS - TLX_FUNC_POS)) +#define TL322X_PULL_DOWN (TLX_PULL_DOWN << (TLX_PULL_POS - TLX_FUNC_POS)) +#define TL322X_PULL_UP (TLX_PULL_UP << (TLX_PULL_POS - TLX_FUNC_POS)) + +/* Setters and getters */ + +#define TLX_PINMUX_SET(port, pin, func) ((func << TLX_FUNC_POS) | \ + (port << TLX_PORT_POS) | \ + (pin << TLX_PIN_POS)) +#define TLX_PINMUX_GET_PULL(pinmux) ((pinmux >> TLX_PULL_POS) & TLX_PULL_MSK) +#define TLX_PINMUX_GET_FUNC(pinmux) ((pinmux >> TLX_FUNC_POS) & TL322X_FUNC_MSK) +#define TLX_PINMUX_GET_PIN(pinmux) ((pinmux >> TLX_PIN_POS) & TLX_PIN_MSK) +#define TLX_PINMUX_GET_PIN_ID(pinmux) ((pinmux >> TLX_PIN_POS) & TLX_PIN_ID_MSK) + +#endif /* ZEPHYR_TL322X_PINCTRL_COMMON_H_ */ diff --git a/include/zephyr/dt-bindings/pinctrl/tl323x-pinctrl.h b/include/zephyr/dt-bindings/pinctrl/tl323x-pinctrl.h new file mode 100644 index 0000000000000..6064aa6d8f416 --- /dev/null +++ b/include/zephyr/dt-bindings/pinctrl/tl323x-pinctrl.h @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2024 Telink Semiconductor + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_TL323X_PINCTRL_COMMON_H_ +#define ZEPHYR_TL323X_PINCTRL_COMMON_H_ + +/* IDs for TL323X GPIO functions */ + +#define TL323X_FUNC_DEFAULT 0 +#define TL323X_FUNC_PWM0 1 +#define TL323X_FUNC_PWM1 2 +#define TL323X_FUNC_PWM2 3 +#define TL323X_FUNC_PWM3 4 +#define TL323X_FUNC_PWM4 5 +#define TL323X_FUNC_PWM5 6 +#define TL323X_FUNC_PWM0_N 7 +#define TL323X_FUNC_PWM1_N 8 +#define TL323X_FUNC_PWM2_N 9 +#define TL323X_FUNC_PWM3_N 10 +#define TL323X_FUNC_PWM4_N 11 +#define TL323X_FUNC_PWM5_N 12 + +/* I2C */ +#define TL323X_FUNC_I2C_SCL_IO 13 +#define TL323X_FUNC_I2C_SDA_IO 14 +#define TL323X_FUNC_I2C1_SDA_IO 15 +#define TL323X_FUNC_I2C1_SCL_IO 16 + +/* UART0 */ +#define TL323X_FUNC_UART0_CTS_I 17 +#define TL323X_FUNC_UART0_RTS 18 +#define TL323X_FUNC_UART0_TX 19 +#define TL323X_FUNC_UART0_RTX_IO 20 + +/* UART1 */ +#define TL323X_FUNC_UART1_CTS_I 21 +#define TL323X_FUNC_UART1_RTS 22 +#define TL323X_FUNC_UART1_TX 23 +#define TL323X_FUNC_UART1_RTX_IO 24 + +/* UART2 */ +#define TL323X_FUNC_UART2_CTS_I 25 +#define TL323X_FUNC_UART2_RTS 26 +#define TL323X_FUNC_UART2_TX 27 +#define TL323X_FUNC_UART2_RTX_IO 28 + +/* UART3 */ +#define TL323X_FUNC_UART3_CTS_I 29 +#define TL323X_FUNC_UART3_RTS 30 +#define TL323X_FUNC_UART3_TX 31 +#define TL323X_FUNC_UART3_RTX_IO 32 + +/* UART4 */ +#define TL323X_FUNC_UART4_CTS_I 33 +#define TL323X_FUNC_UART4_RTS 34 +#define TL323X_FUNC_UART4_TX 35 +#define TL323X_FUNC_UART4_RTX_IO 36 + +/* Misc clock / debug / SPI */ +#define TL323X_FUNC_CLK_7816 37 +#define TL323X_FUNC_TDI_I 38 +#define TL323X_FUNC_TDO_IO 38 +#define TL323X_FUNC_TMS_IO 38 +#define TL323X_FUNC_TCK_I 38 + +/* SSPI */ +#define TL323X_FUNC_SSPI_CN_I 39 +#define TL323X_FUNC_SSPI_CK_I 40 +#define TL323X_FUNC_SSPI_SI_IO 41 +#define TL323X_FUNC_SSPI_SO_IO 42 + +/* Misc IOs */ +#define TL323X_FUNC_RZ_TX 43 +#define TL323X_FUNC_SWM_IO 44 +#define TL323X_FUNC_TX_CYC2PA 45 +#define TL323X_FUNC_WIFI_DENY_I 46 +#define TL323X_FUNC_BT_ACTIVITY 47 +#define TL323X_FUNC_BT_STATUS 48 + +/* ATSEL */ +#define TL323X_FUNC_ATSEL_0 49 +#define TL323X_FUNC_ATSEL_1 50 +#define TL323X_FUNC_ATSEL_2 51 +#define TL323X_FUNC_ATSEL_3 52 +#define TL323X_FUNC_ATSEL_4 53 +#define TL323X_FUNC_ATSEL_5 54 + +#define TL323X_FUNC_RX_CYC2LNA 55 +#define TL323X_FUNC_DBG_PROBE_CLK 56 +#define TL323X_FUNC_DBG_BB0 57 +#define TL323X_FUNC_DBG_ADC_I_DAT0 58 +#define TL323X_FUNC_DBG_TRNG0 59 + +/* GSPI */ +#define TL323X_FUNC_GSPI_CN_IO 60 +#define TL323X_FUNC_GSPI_CN0_IO 60 +#define TL323X_FUNC_GSPI_IO3_IO 61 +#define TL323X_FUNC_GSPI_IO2_IO 62 +#define TL323X_FUNC_GSPI_MISO_IO 63 +#define TL323X_FUNC_GSPI_MOSI_IO 64 +#define TL323X_FUNC_GSPI_CK_IO 65 + +/* IDs for GPIO Ports */ + +#define TLX_PORT_A 0x00 +#define TLX_PORT_B 0x01 +#define TLX_PORT_C 0x02 +#define TLX_PORT_D 0x03 +#define TLX_PORT_E 0x04 +#define TLX_PORT_F 0x05 + +/* IDs for GPIO Pins */ + +#define TLX_PIN_0 0x01 +#define TLX_PIN_1 0x02 +#define TLX_PIN_2 0x04 +#define TLX_PIN_3 0x08 +#define TLX_PIN_4 0x10 +#define TLX_PIN_5 0x20 +#define TLX_PIN_6 0x40 +#define TLX_PIN_7 0x80 + +/* TLx pinctrl pull-up/down */ + +#define TLX_PULL_NONE 0 +#define TLX_PULL_DOWN 2 +#define TLX_PULL_UP 3 + +/* Pin function positions */ + +#define TL323X_PIN_FUNC_POS 0xFF + +/* Pin pull up positions */ + +#define TLX_PIN_0_PULL_UP_EN_POS 0x00 +#define TLX_PIN_1_PULL_UP_EN_POS 0x02 +#define TLX_PIN_2_PULL_UP_EN_POS 0x04 +#define TLX_PIN_3_PULL_UP_EN_POS 0x06 +#define TLX_PIN_4_PULL_UP_EN_POS 0x00 +#define TLX_PIN_5_PULL_UP_EN_POS 0x02 +#define TLX_PIN_6_PULL_UP_EN_POS 0x04 +#define TLX_PIN_7_PULL_UP_EN_POS 0x06 + +/* TL323X pin configuration bit field positions and masks */ + +#define TLX_PULL_POS 24 +#define TLX_PULL_MSK 0x3 +#define TLX_FUNC_POS 16 +#define TL323X_FUNC_MSK 0xFF +#define TLX_PORT_POS 8 +#define TLX_PORT_MSK 0xFF + +#define TLX_PIN_POS 0 +#define TLX_PIN_MSK 0xFFFF +#define TLX_PIN_ID_MSK 0xFF + +/* Setters and getters */ + +#define TLX_PINMUX_SET(port, pin, func) ((func << TLX_FUNC_POS) | \ + (port << TLX_PORT_POS) | \ + (pin << TLX_PIN_POS)) +#define TLX_PINMUX_GET_PULL(pinmux) ((pinmux >> TLX_PULL_POS) & TLX_PULL_MSK) +#define TLX_PINMUX_GET_FUNC(pinmux) ((pinmux >> TLX_FUNC_POS) & TL323X_FUNC_MSK) +#define TLX_PINMUX_GET_PIN(pinmux) ((pinmux >> TLX_PIN_POS) & TLX_PIN_MSK) +#define TLX_PINMUX_GET_PIN_ID(pinmux) ((pinmux >> TLX_PIN_POS) & TLX_PIN_ID_MSK) + +#endif /* ZEPHYR_TL323X_PINCTRL_COMMON_H_ */ diff --git a/include/zephyr/usb/usb_ch9.h b/include/zephyr/usb/usb_ch9.h index fa18b1c2dc833..297a1dfad10a7 100644 --- a/include/zephyr/usb/usb_ch9.h +++ b/include/zephyr/usb/usb_ch9.h @@ -163,6 +163,19 @@ struct usb_device_descriptor { uint8_t bNumConfigurations; } __packed; +/** USB Device Qualifier Descriptor defined in spec. Table 9-9 */ +struct usb_device_qualifier_descriptor { + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t bcdUSB; + uint8_t bDeviceClass; + uint8_t bDeviceSubClass; + uint8_t bDeviceProtocol; + uint8_t bMaxPacketSize0; + uint8_t bNumConfigurations; + uint8_t bReserved; +} __packed; + /** USB Standard Configuration Descriptor defined in spec. Table 9-10 */ struct usb_cfg_descriptor { uint8_t bLength; diff --git a/kernel/idle.c b/kernel/idle.c index 2ad336936443d..d9e15776190e4 100644 --- a/kernel/idle.c +++ b/kernel/idle.c @@ -81,9 +81,21 @@ void idle(void *unused1, void *unused2, void *unused3) * which is essential for the kernel's scheduling * logic. */ - if (k_is_pre_kernel() || !pm_system_suspend(_kernel.idle)) { +# if ((defined(CONFIG_BT_B9X) && defined(CONFIG_SOC_RISCV_TELINK_B92)) || \ + (defined(CONFIG_BT_TLX) && defined(CONFIG_SOC_RISCV_TELINK_TL321X)) || \ + (defined(CONFIG_BT_TLX) && defined(CONFIG_SOC_RISCV_TELINK_TL721X)) || \ + (defined(CONFIG_BT_TLX) && defined(CONFIG_SOC_RISCV_TELINK_TL323X))) + + #include "tlx_bt.h" + extern uint32_t blc_ll_checkBleRfFsmIsBusy(void); + + if (blc_ll_checkBleRfFsmIsBusy() && tl_bt_controller_state()) { k_cpu_idle(); - } + } else +# endif + if (k_is_pre_kernel() || !pm_system_suspend(_kernel.idle)) { + k_cpu_idle(); + } #else k_cpu_idle(); #endif diff --git a/samples/bluetooth/peripheral_kmd/CMakeLists.txt b/samples/bluetooth/peripheral_kmd/CMakeLists.txt new file mode 100644 index 0000000000000..5146b58c0fd92 --- /dev/null +++ b/samples/bluetooth/peripheral_kmd/CMakeLists.txt @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(peripheral_hids) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE + ${app_sources} + ) diff --git a/samples/bluetooth/peripheral_kmd/Kconfig b/samples/bluetooth/peripheral_kmd/Kconfig new file mode 100644 index 0000000000000..c28c28cdb1e23 --- /dev/null +++ b/samples/bluetooth/peripheral_kmd/Kconfig @@ -0,0 +1,20 @@ +# Copyright 2023 Google LLC +# SPDX-License-Identifier: Apache-2.0 + +mainmenu "Bluetooth: Peripheral kmd" + +config SAMPLE_BT_USE_AUTHENTICATION + bool "Enable passkey authentication" + default y + help + Enable the passkey authentication callback and register the GATT + read and and write attributes as authentication required. + +config BT_ID_FOR_KMD + bool "Only used for KMD project" + default n + help + This option enables the use of a specific Bluetooth identity for the Keyboard + Mouse Device (KMD) sample application. + +source "Kconfig.zephyr" \ No newline at end of file diff --git a/samples/bluetooth/peripheral_kmd/README.rst b/samples/bluetooth/peripheral_kmd/README.rst new file mode 100644 index 0000000000000..de1e35aaa3856 --- /dev/null +++ b/samples/bluetooth/peripheral_kmd/README.rst @@ -0,0 +1,31 @@ +.. _peripheral_hids: + +Bluetooth: Peripheral HIDs +########################## + +Overview +******** + +Similar to the :ref:`Peripheral ` sample, except that this +application specifically exposes the HID GATT Service. The report map used is +for a generic mouse. + +In the default configuration the sample uses passkey authentication (displays a +code on the peripheral and requires that to be entered on the host during +pairing) and requires an authenticated link to access the GATT characteristics. +To disable authentication and just use encrypted channels instead, build the +sample with `CONFIG_SAMPLE_BT_USE_AUTHENTICATION=n`. + +Requirements +************ + +* BlueZ running on the host, or +* A board with BLE support + +Building and Running +******************** + +This sample can be found under :zephyr_file:`samples/bluetooth/peripheral_hids` in the +Zephyr tree. + +See :ref:`bluetooth samples section ` for details. diff --git a/samples/bluetooth/peripheral_kmd/boards/rv32m1_vega_ri5cy.overlay b/samples/bluetooth/peripheral_kmd/boards/rv32m1_vega_ri5cy.overlay new file mode 100644 index 0000000000000..e53f6265deb51 --- /dev/null +++ b/samples/bluetooth/peripheral_kmd/boards/rv32m1_vega_ri5cy.overlay @@ -0,0 +1,22 @@ +/* + * Copyright 2019 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&lptmr1 { + interrupt-parent = <&intmux0_ch2>; +}; + +&intmux0_ch2 { + status = "okay"; +}; + +&intmux0_ch3 { + status = "okay"; +}; + +&generic_fsk { + interrupt-parent = <&intmux0_ch3>; + status = "okay"; +}; diff --git a/samples/bluetooth/peripheral_kmd/boards/tl3228x.conf b/samples/bluetooth/peripheral_kmd/boards/tl3228x.conf new file mode 100755 index 0000000000000..665e5a7b28cfa --- /dev/null +++ b/samples/bluetooth/peripheral_kmd/boards/tl3228x.conf @@ -0,0 +1 @@ +CONFIG_USB_TELINK_TLX=y \ No newline at end of file diff --git a/samples/bluetooth/peripheral_kmd/boards/tl3228x.overlay b/samples/bluetooth/peripheral_kmd/boards/tl3228x.overlay new file mode 100755 index 0000000000000..aede67c80b613 --- /dev/null +++ b/samples/bluetooth/peripheral_kmd/boards/tl3228x.overlay @@ -0,0 +1,249 @@ +&cpu0 { + clock-frequency = <192000000>; /* USB0 digital voltage must be 1.1V and HCLK min's 48M */ + /*clock-frequency = <96000000>;*/ +}; + +&uart0 { + status = "okay"; + /*alg keyboard*/ + /*pinctrl-0 = <&uart0_tx_pd4_default &uart0_rx_pd5_default>;*/ + /*digital keyboard*/ + pinctrl-0 = <&uart0_tx_pe5_default &uart0_rx_pd7_default>; + current-speed = <2000000>; /* Baud rate for serial port logging */ +}; + +&gpioa { + status = "okay"; +}; + + +/ { + + aliases { + + /delete-property/ led0; + /delete-property/ led1; + /delete-property/ led2; + /delete-property/ led3; + + /delete-property/ mcuboot-button0; + /delete-property/ mcuboot-led0; + + /delete-property/ sw0; + /delete-property/ sw1; + /delete-property/ sw2; + /delete-property/ sw3; + + /delete-property/ pwm-led0; + /delete-property/ pwm0; + + toggle4 = &toggle_b4_pin; + toggle5 = &toggle_b5_pin; + + vbuscheck0 = &vbus_pin; + mode2p4 = &mode_2p4_pin; + modeble = &mode_ble_pin; + + }; + + /delete-node/ leds; + /delete-node/ pwm_leds; + + leds { + compatible = "gpio-leds"; + + toggle_b4_pin: toggle_io_4 { + gpios = <&gpiob 4 GPIO_ACTIVE_HIGH>; + label = "TOGGLE"; + }; + + toggle_b5_pin: toggle_io_5 { + gpios = <&gpiob 5 GPIO_ACTIVE_HIGH>; + label = "TOGGLE"; + }; + + vbus_pin: vbus_io { + gpios = <&gpioc 1 (GPIO_ACTIVE_LOW)>; + label = "VBUS CHECK"; + }; + + mode_2p4_pin: mode_2p4_io { + gpios = <&gpioe 3 (GPIO_ACTIVE_LOW)>; + label = "MODE 2P4 SLECT"; + }; + mode_ble_pin: mode_ble_io { + gpios = <&gpioe 4 (GPIO_ACTIVE_LOW)>; + label = "MODE BLE SLECT"; + }; + }; + + /delete-node/ keys; + /delete-node/ key_pool; + /delete-node/ led_pool; + /delete-node/ pwm_pool; + + key_matrix { + compatible = "gpio-keys"; + + col { + gpios = <&gpioe 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>, + <&gpioe 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>, + <&gpioa 0 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>, + <&gpioa 1 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>, + <&gpioa 2 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>, + <&gpioc 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>, + <&gpioc 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>, + <&gpiog 0 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>, + <&gpiof 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>, + <&gpiof 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>, + <&gpiof 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>, + <&gpiof 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>, + <&gpiob 1 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>, + <&gpiob 0 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>, + <&gpioc 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>, + <&gpioc 3 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>, + <&gpiod 2 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>, + <&gpiog 1 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>, + <&gpiog 2 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>, + <&gpioh 0 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>; + }; + + row { + gpios = <&gpioe 2 GPIO_ACTIVE_HIGH>, + <&gpioe 1 GPIO_ACTIVE_HIGH>, + <&gpioe 0 GPIO_ACTIVE_HIGH>, + <&gpiod 6 GPIO_ACTIVE_HIGH>, + <&gpiod 4 GPIO_ACTIVE_HIGH>, + <&gpiod 5 GPIO_ACTIVE_HIGH>; + }; + }; + + zephyr,user { + /* adjust channel number according to pinmux in board.dts */ + io-channels = <&adc 0>; + }; +}; + +&adc { + #address-cells = <1>; + #size-cells = <0>; + + channel@0 { + reg = <0>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + zephyr,input-positive = ; + }; +}; + +&adc { + status = "okay"; + vref-internal-mv = <1200>; + sample-freq = ; + pinctrl-0 = <&adc_pc0_default>; + pinctrl-names = "default"; +}; + +&flash { + reg = <0x20000000 0x100000>; + /delete-node/ partitions; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + /*boot_partition: 32k*/ + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x00000000 0x8000>; + }; + /*D25F APP 1 partition: 256k*/ + slot0_partition: partition@8000 { + label = "image-0"; + reg = <0x8000 0x40000>; + }; + /*N22 APP 1 partition: 128k*/ + n22_1_partition: partition@48000 { + label = "image-1"; + reg = <0x48000 0x20000>; + }; + /*D25F APP 2 partition: 256k*/ + slot1_partition: partition@68000 { + label = "image-2"; + reg = <0x68000 0x40000>; + }; + /*N22 APP 2 partition: 128k*/ + n22_2_partition: partition@A8000 { + label = "image-3"; + reg = <0xA8000 0x20000>; + }; + + user_app_partition: partition@C8000 { + label = "app-storage"; + reg = <0xC8000 0x00002000>; + }; + + /*BLE SMP storage partition*/ + storage_partition: partition@CA000 { + label = "storage"; + reg = <0xCA000 0x0000a000>; + }; + + /* region <0xfe000 0x2000> is used for Telink TLx RF parameters */ + /* For 1M MCU - the partition address is 0xfe000 */ + /* For 2M MCU - the partition address is 0x1fe000 */ + /* For 4M MCU - the partition address is 0x3fe000 */ + /* For 16M MCU - the partition address is 0xffe000 */ + vendor_partition: partition@fe000 { + label = "vendor-data"; + reg = <0xfe000 0x2000>; + }; + }; +}; + +&pinctrl { + /* Set pad-mul-sel register value. + * Note: Pins functions below (pinmux = <...>) depend on this value. + */ + pad-mul-sel = <1>; + + /* UART0: TX(PA0), RX(PA1), RTS(PB4), CTS(PB6) */ + + /delete-node/ uart0_tx_pa0_default; + /delete-node/ uart0_rx_pa1_default; + + uart0_tx_pe5_default: uart0_tx_pe5_default { + pinmux = ; + }; + uart0_rx_pd7_default: uart0_rx_pd7_default { + pinmux = ; + }; +}; + +&pwm0 { + status = "disabled"; +}; + +&gspi { + status = "disabled"; +}; + +&i2c { + status = "disabled"; + clock-frequency = ; + pinctrl-0 = <&i2c_scl_pe0_default &i2c_sda_pe1_default>; + pinctrl-names = "default"; +}; + +&adc { + status = "okay"; + vref-internal-mv = <1200>; + sample-freq = ; + pinctrl-0 = <&adc_pc0_default>; + pinctrl-names = "default"; +}; \ No newline at end of file diff --git a/samples/bluetooth/peripheral_kmd/prj.conf b/samples/bluetooth/peripheral_kmd/prj.conf new file mode 100644 index 0000000000000..72fc100fba137 --- /dev/null +++ b/samples/bluetooth/peripheral_kmd/prj.conf @@ -0,0 +1,63 @@ +# Increased stack due to settings API usage +CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048 + +CONFIG_BT=y +CONFIG_BT_DEBUG_LOG=y +CONFIG_BT_SMP=y +CONFIG_BT_SMP_ALLOW_UNAUTH_OVERWRITE=y +CONFIG_BT_ID_ALLOW_UNAUTH_OVERWRITE=y +CONFIG_BT_MAX_PAIRED=4 +CONFIG_BT_PERIPHERAL=y +CONFIG_BT_DIS=y +CONFIG_BT_BAS=y +CONFIG_BT_DEVICE_NAME="Test kb" +#CONFIG_BT_DEVICE_NAME_DYNAMIC=y +CONFIG_BT_HCI_CORE_LOG_LEVEL_DBG=n + +CONFIG_BT_SETTINGS=y +CONFIG_FLASH=y +CONFIG_FLASH_PAGE_LAYOUT=y +CONFIG_FLASH_MAP=y +CONFIG_NVS=y +CONFIG_SETTINGS=y + +CONFIG_GPIO=y + +CONFIG_PM=y +CONFIG_PM_DEVICE=n +CONFIG_TELINK_TL322X_ENABLE_N22=y +CONFIG_SAMPLE_BT_USE_AUTHENTICATION=n +CONFIG_BT_ID_MAX=4 +CONFIG_BT_MAX_CONN=4 +CONFIG_BT_SETTINGS=y +CONFIG_BT_ID_UNPAIR_MATCHING_BONDS=y + +CONFIG_BT_ID_FOR_KMD=y + +#usb config +CONFIG_USB_COMPOSITE_DEVICE=y +CONFIG_USB_DEVICE_STACK=y +CONFIG_USB_DEVICE_HID=y +CONFIG_USB_HID_DEVICE_COUNT=3 +CONFIG_USB_DEVICE_PRODUCT="Zephyr HID-keyboard sample" +CONFIG_USB_DEVICE_PID=0x0004 +CONFIG_USB_DEVICE_INITIALIZE_AT_BOOT=n +CONFIG_USB_DC_HAS_HS_SUPPORT=n +CONFIG_USB_TELINK_TLX=y +CONFIG_USB_DC_HAS_HS_SUPPORT=y +CONFIG_USB_DEVICE_VID=0x248A +CONFIG_USB_DEVICE_PID=0x3228 +CONFIG_ENTROPY_GENERATOR=y +CONFIG_ENTROPY_DEVICE_RANDOM_GENERATOR=y +CONFIG_HID_INTERRUPT_EP_MPS=64 + +CONFIG_LOG=y +CONFIG_USB_DRIVER_LOG_LEVEL_ERR=y +CONFIG_USB_DEVICE_LOG_LEVEL_ERR=y + +CONFIG_FLASH=y +CONFIG_FLASH_PAGE_LAYOUT=y +CONFIG_NVS=y +CONFIG_REBOOT=y + +CONFIG_ADC=y \ No newline at end of file diff --git a/samples/bluetooth/peripheral_kmd/sample.yaml b/samples/bluetooth/peripheral_kmd/sample.yaml new file mode 100644 index 0000000000000..9dcbb74de3d46 --- /dev/null +++ b/samples/bluetooth/peripheral_kmd/sample.yaml @@ -0,0 +1,18 @@ +sample: + name: Bluetooth Peripheral HIDs + description: Bluetooth Low Energy HID-over-GATT service sample +tests: + sample.bluetooth.peripheral_hids: + harness: bluetooth + platform_allow: qemu_x86 + tags: bluetooth + integration_platforms: + - qemu_x86 + sample.bluetooth.peripheral_hids.no_authentication: + harness: bluetooth + extra_configs: + - CONFIG_SAMPLE_BT_USE_AUTHENTICATION=n + platform_allow: qemu_x86 + tags: bluetooth + integration_platforms: + - qemu_x86 diff --git a/samples/bluetooth/peripheral_kmd/src/app_24g.c b/samples/bluetooth/peripheral_kmd/src/app_24g.c new file mode 100644 index 0000000000000..07610b16e777a --- /dev/null +++ b/samples/bluetooth/peripheral_kmd/src/app_24g.c @@ -0,0 +1,920 @@ +/* app_24g.c - Application main entry point */ + +/* + * Copyright (c) 2016 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "app_24g.h" +#include "app_public.h" + +#define LOG_LEVEL LOG_LEVEL_DBG +#include +LOG_MODULE_REGISTER(app_24g); + + +#include "stack/multicore_comm/service/mcc.h" +#include "stack/multicore_comm/service/service_d25f.h" + +extern pl_fifo_t d25fKbTxFifo; + +#define WDT_INTV_MS (300) + +#define APP_SLEEP_PREPARE_COUNT (4) +#define APP_SUSPEND_LIMIT_MIN_TIME_US (1500) +#define APP_SUSPEND_LONG_TIME_MIN_US (8000) +#define APP_DELAY_ENTER_SUSPEND_TIME_US (0) +#define APP_WAKEUP_EARLY_TIME_US (50) +#define APP_WFI_WAKEUP_EARLY_TIME_US (20) + + +extern volatile bool n22_rssi_scan_done; + +volatile p24g_device_status_e g_state = STATE_POWERON; +static volatile p24g_device_status_e g_work_state = STATE_NONE; +static volatile p24g_device_status_e g_power_state = STATE_NONE; +static volatile uint32_t g_wakeup_stick = 0; +static volatile uint32_t spp_tick = 0; +static uint8_t g_report_rate = REPORT_RATE_8K; + +volatile p24g_device_status_e last_connect_status = STATE_NONE; +volatile unsigned int tick_status; +app_ctx_t app_ctx; + + + +//ZH_TODO +_attribute_ram_code_sec_ void tlk_d25f_to_n22_mode_info(kb_mode_t mode_flag) +{ + volatile uint32_t key = arch_irq_lock(); + + uint8_t cmd[8] = {0}; + + cmd[0] = TLK_MB_D25F_TO_N22_MODE; + cmd[1] = mode_flag; + + mb_send_with_polling(cmd); + arch_irq_unlock(key); +} + + +/** + * @brief share memory message handler table + */ +static p24g_sm_cmd_handler_t p24g_cmd_table[P24G_SM_CMD_MAX] = {0}; +uint8_t g_app_suspend_ret_flag = 0; + +static inline void app_wdt_init() +{ + if (wd_get_status()) { + wd_clear_status(); + } + wd_set_interval_ms(WDT_INTV_MS); + /** + * Wd_clear() must be executed before each call to wd_start() to avoid abnormal watchdog reset time because the initial count value is not 0. + * For example, the watchdog is reset soon or a few minutes later. + */ + wd_clear(); + wd_start(); +} +static inline void app_timer1_start(uint32_t sys_tick) +{ + unsigned int tick = sys_tick * sys_clk.pclk / SYSTEM_TIMER_TICK_1US; + timer_set_init_tick(TIMER1, 0); + timer_set_cap_tick(TIMER1, tick); + timer_start(TIMER1); +} +static inline void app_timer1_stop(void) +{ + timer_stop(TIMER1); +} +static inline void app_timer1_init(void) +{ + timer_set_init_tick(TIMER1, 0); + + timer_set_mode(TIMER1, TIMER_MODE_SYSCLK); + + timer_set_irq_mask(FLD_TMR1_MODE_IRQ); + tlkapi_printf(APP_LOG_EN, "timer1 init\r\n"); + +#if defined(MCU_CORE_TL322X_N22) + clic_interrupt_enable(IRQ_TIMER1); +#else + plic_interrupt_enable(IRQ_TIMER1); +#endif +} +_attribute_ram_code_sec_ static void app_2p4g_set_power_state(p24g_device_status_e state, uint32_t tick) +{ + // if ((state == STATE_TO_IDLE) && (g_power_state != STATE_TO_SLEEP)) { + // g_power_state = STATE_TO_IDLE; + // if (tick) { + // app_timer1_start((tick - stimer_get_tick() - APP_WFI_WAKEUP_EARLY_TIME_US * SYSTEM_TIMER_TICK_1US)); + // } + // } else if (state == STATE_TO_SLEEP) { + // g_wakeup_stick = tick; + // // app_inf.step_2t2r = STEP_2T2R_NONE; + // g_power_state = STATE_TO_SLEEP; + // } +} + +static inline bool app_2p4g_is_work_busy(void) +{ + return (g_work_state == STATE_BUSY); +} + + +static inline char *tl_hex_to_str(const void *buf, uint8_t len) +{ + static const char hex[] = "0123456789abcdef"; + static char str[301]; + const uint8_t *b = buf; + uint8_t i; + + len = min(len, (sizeof(str) - 1) / 3); + + for (i = 0; i < len; i++) { + str[i * 3] = hex[b[i] >> 4]; + str[i * 3 + 1] = hex[b[i] & 0xf]; + str[i * 3 + 2] = ' '; + } + + str[i * 3] = '\0'; + + return str; +} + +static _attribute_ram_code_sec_ uint16_t app_2p4g_d25f_rx_packet_parse(uint8_t *data, uint16_t len) +{ + p24g_evt_t *p_evt = (p24g_evt_t *) data; + + if (p_evt->type == P24G_MB_CMD_USB) { + return sizeof(p24g_evt_t) + p_evt->len; + } + + return len; +} + +static _attribute_ram_code_sec_ void app_2p4g_packet_enqueue(uint8_t *data, uint16_t len) +{ + // print_app_public("event receive: %s", tl_hex_to_str(data, len)); + + p24g_evt_t *p_evt = (p24g_evt_t *) data; + + if (p_evt->type == P24G_MB_CMD_USB) { + switch (p_evt->opcode) { + case P24G_USB_OP_EP_WRITE: + p24g_usb_pkt_t *p_pkt = (p24g_usb_pkt_t *)p_evt->data; + usb0hw_write_ep_data((p_pkt->ep_addr & (~USB0_DIR_IN_MASK)), p_pkt->data, p_pkt->len); + // usbd_ep_write(0, p_pkt->ep_addr, p_pkt->data, p_pkt->len); + break; + + case P24G_USB_OP_EP_READ: + break; + default: + break; + } + } +} + +_attribute_ram_code_sec_ void app_2p4g_d25f_rx_packet_handler(uint8_t *data, unsigned int len) +{ + while (len != 0) { + uint16_t parsed_len = app_2p4g_d25f_rx_packet_parse(data, len); + app_2p4g_packet_enqueue(data, parsed_len); + len -= parsed_len; + data += parsed_len; + } +} + +_attribute_ram_code_sec_ void event_test(void) +{ + static unsigned int tick=0; + static uint8_t TxBuf[64] = {0}; //[!!important] + static uint8_t cnt = 0; + + if(clock_time_exceed(tick, 2000000)) { + tick=stimer_get_tick(); + + p24g_evt_t * p_evt = (p24g_evt_t *)TxBuf; + + p_evt->type = P24G_MB_CMD_USB; + p_evt->opcode = P24G_USB_OP_EP_WRITE; + + p24g_usb_pkt_t *p_pkt = (p24g_usb_pkt_t *)p_evt->data; + + p_pkt->ep_addr = 0x02; + p_pkt->len = 8; + + p_pkt->data[0] = cnt++; + p_pkt->data[1] = 0x01; + p_pkt->data[2] = 0x01; + p_pkt->data[3] = 0x02; + p_pkt->data[4] = 0x02; + p_pkt->data[5] = 0x03; + p_pkt->data[6] = 0x03; + p_pkt->data[7] = 0x04; + + p_evt->len = sizeof(p24g_usb_pkt_t) + p_pkt->len; + + if(!mcc_d25f_hci_send_msg(TxBuf, sizeof(p24g_evt_t) + p_evt->len)) { +// if(!tlk_n22_sync_send_message(TLK_SHARE_MEMORY_MESSAGE_TYPE_BLE, TxBuf, sizeof(p24g_evt_t) + p_evt->len)) { + tlkapi_printf(APP_LOG_EN, "d25f send sm message success\n"); + } else { + tlkapi_printf(APP_LOG_EN, "d25f send sm message fail\n"); + } + } +} + + +_attribute_ram_code_sec_ uint8_t p24g_send_sm_msg(uint8_t type, uint8_t op, uint8_t *data, uint8_t len) +{ + static uint8_t TxBuf[64] = {0}; //[!!important] + + p24g_evt_t *p_evt = (p24g_evt_t *)TxBuf; + + p_evt->type = type; + p_evt->opcode = op; + uint8_t data_len = len > (sizeof(TxBuf) - 2) ? sizeof(TxBuf) - 2 : len; + + if(data && data_len) + { + memcpy(p_evt->data, data, data_len); + p_evt->len = data_len; + } + //TODO + // gpio_function_en(GPIO_PB4); + // gpio_output_en(GPIO_PB4); + // gpio_input_dis(GPIO_PB4); + // DBG_GPIO_TOGGLE(APP_IO_EN, GPIO_PB4); + // delay_us(27); + // DBG_GPIO_TOGGLE(APP_IO_EN, GPIO_PB4); + + if (!mcc_d25f_shm_send_msg(TxBuf, sizeof(p24g_evt_t) + p_evt->len, TLK_SHM_MSG_2P4G)) + { + //if(!tlk_n22_sync_send_message(TLK_SHARE_MEMORY_MESSAGE_TYPE_BLE, TxBuf, sizeof(p24g_evt_t) + p_evt->len)) { + tlkapi_printf(1, "d25f send sm message success\n"); + //tlkapi_printk(TLK_LOG_EN, "d25f send sm message success %x %x\n", type, op); + } + else + { + tlkapi_printf(1, "d25f send sm message fail\n"); + //tlkapi_printk(TLK_LOG_EN, "d25f send sm message faillll\n"); + return 1; // Error: message sending failed + } + // DBG_GPIO_TOGGLE(APP_IO_EN, GPIO_PA6); + return TLK_SUCCESS; // Success +} + +_attribute_ram_code_sec_ uint8_t p24g_enable_pairing(bool enable) +{ + return p24g_send_sm_msg(P24G_SM_CMD_PAIRING, enable, 0, 0); +} + +_attribute_ram_code_sec_ uint8_t p24g_enable_reconn(bool enable) +{ + return p24g_send_sm_msg(P24G_SM_CMD_SET_STATE, P24G_SM_OP_ENABLE_RECONN, &enable, 1); +} + +_attribute_ram_code_sec_ uint8_t p24g_terminate_connect(void) +{ + return p24g_send_sm_msg(P24G_SM_CMD_LL_CONTROL, P24G_SM_OP_TERMINATE_CONN, 0, 0); +} + +_attribute_ram_code_sec_ uint8_t p24g_rf_enter_idle(void) +{ + return p24g_send_sm_msg(P24G_SM_CMD_LL_CONTROL, P24G_SM_OP_ENTER_RF_IDLE, 0, 0); +} + + +_attribute_ram_code_ void app_2p4g_mb_km_data_cb(uint8_t* data) +{ + + if(data[0] == 0x7a) + { + data[0] = 0; + // app_mouse_report_to_usb(&data[1]); + } + else if(data[6] == 0xa7 && data[5] == 0x57 && data[4] == 0x5a) + { + // tlkapi_send_string_data(APP_LOG_EN, "now usb init",data,7); + // n22_rssi_scan_done = true; + }else{ + // tlkapi_send_string_data(APP_LOG_EN, "d25f kb app_2p4g_mb_km_data_cb",data,7); + } + // tlkapi_send_string_data(APP_LOG_EN, "d25f kb app_2p4g_mb_km_data_cb",data,7); + // tlkapi_printk(TLK_LOG_EN, "d25f kb app_2p4g_mb_km_data_cb: %x %x %x %x\n", data[0], data[1], data[2], data[3]); + +} + + +_attribute_ram_code_sec_ void app_2p4g_d25f_sm_rx_cb(uint8_t *data, uint32_t len) +{ + + if (!data || len == 0) + return; + + uint8_t cmd = data[0]; + if (cmd < P24G_SM_CMD_MAX && p24g_cmd_table[cmd]) + { + p24g_cmd_table[cmd](data, len); + } + else + { + tlkapi_send_string_data(APP_LOG_EN, "error! unknow sm command", data, len); + } + +#if 0 + tlkapi_printf(APP_LOG_EN, "sm rx %x %x %x %x %x %x %x %x\r\n", + p_evt->type, p_evt->opcode, p_evt->len, + p_evt->data[0], p_evt->data[1], p_evt->data[2], p_evt->data[3]); + tlkapi_send_string_data(APP_LOG_EN, "d25f sm rx cb", data, len); +#endif +} + + + +_attribute_ram_code_sec_ uint8_t p24g_send_spp_data(uint8_t cmd, unsigned char *data, unsigned char len) +{ + uint8_t ret = TLK_ERR_INVALID_LENGTH; + + if (len < 17) { + ret = pp_fifo_push(&d25fSppTxFifo, cmd, data, len); + } + + return ret; +} + + + +/** + * @brief resister a command handler for a specific command type + */ +uint8_t p24g_register_sm_cmd_handler(p24g_sm_cmd_e cmd, p24g_sm_cmd_handler_t handler) +{ + uint8_t ret = TLK_ERR_INVALID_PARAM; + + if (cmd < P24G_SM_CMD_MAX && handler) { + p24g_cmd_table[cmd] = handler; + ret = TLK_SUCCESS; + }else { + tlkapi_printf(APP_LOG_EN, "p24g_register_sm_cmd_handler error %x\n", cmd); + } + + return ret; +} + + +/** + * @brief user initialization when MCU wake_up from deepSleep_retention mode + * @param[in] none + * @return none + */ +_attribute_ram_code_ void p24g_user_init_deepRetn(void) +{ +#if (PM_DEEPSLEEP_RETENTION_ENABLE) + + + /*** + * TL321X(buteo): + * PLL_192M_CCLK_96M_HCLK_48M_PCLK_24M_MSPI_48M, the time from retention_reset(.s file) to here is 550us. + * PLL_192M_CCLK_32M_HCLK_32M_PCLK_32M_MSPI_48M, the time from retention_reset(.s file) to here is 578us + */ + DBG_CHN0_HIGH; + irq_enable(); + + + #if (BATT_CHECK_ENABLE) + adc_hw_initialized = 0; + #endif + + #if (TLKAPI_DEBUG_ENABLE) + tlkapi_debug_deepRetn_init(); + #endif +#endif +} + +void app_2p4g_dual_core_comm_init(void) +{ + + mcc_mb_register_cb(TLK_MB_N22_TO_D25F_KM_DATA, app_2p4g_mb_km_data_cb); + mcc_shm_register_cb(TLK_SHM_MSG_2P4G, app_2p4g_d25f_sm_rx_cb); + + uint8_t cmd[7] = {0}; + uint32_t address = (u32)&d25fKbTxFifo; + cmd[3] = (uint8_t)(address & 0xff); + cmd[4] = (uint8_t)(address >> 8 & 0xff); + cmd[5] = (uint8_t)(address >> 16 & 0xff); + cmd[6] = (uint8_t)(address >> 24 & 0xff); + + printk("d25fKbTxFifo %x\n",&d25fKbTxFifo); + mcc_d25f_mb_send_data(TLK_MB_D25F_TO_N22_2P4G_KB_TX_ADDRESS, cmd); + + address = (u32)&d25fSppTxFifo; + cmd[3] = (uint8_t)(address & 0xff); + cmd[4] = (uint8_t)(address >> 8 & 0xff); + cmd[5] = (uint8_t)(address >> 16 & 0xff); + cmd[6] = (uint8_t)(address >> 24 & 0xff); + + mcc_d25f_mb_send_data(TLK_MB_D25F_TO_N22_2P4G_SPP_TX_ADDRESS, cmd); + + pp_fifo_reset(&d25fSppTxFifo); +} + + +_attribute_ram_code_sec_ static void app_2p4g_handle_save_pairing_info(uint8_t *data, uint16_t len) +{ + p24g_evt_t *p_evt = (p24g_evt_t *)data; + + if (p_evt->type == P24G_SM_CMD_SAVE_PAIR_INFO) + { + memcpy(flash_dev_info.peer_addr, p_evt->data, MAC_ADDR_LEN); + uint32_t side_id = fnv1a_hash(flash_dev_info.peer_addr, MAC_ADDR_LEN); + + if (flash_dev_info.side_id != side_id) + { + flash_dev_info.side_id = side_id; + //save_data_to_flash(flash_sector_2p4_inf, sizeof(ST_FLASH_DEV_INFO), (unsigned char *)&flash_dev_info.side_id, (int *)&dev_info_idx); + + int ret = nvs_write(&user_fs, APP_2P4G_PAIR_INFO_ID, (unsigned char *)&flash_dev_info.side_id, sizeof(ST_FLASH_DEV_INFO)); + printk("NVS APP_2P4G_PAIR_INFO_ID Write result: %d\n", ret); + } + + } +} + +_attribute_ram_code_sec_ static void app_2p4g_save_report_rate_info(uint8_t rr) +{ + if ((rr == REPORT_RATE_8K) || (rr == REPORT_RATE_125)) { + flash_dev_other_info.report_rate = rr; + uint32_t side_id = fnv1a_hash(flash_dev_other_info.report_rate, 1); + + if (flash_dev_other_info.side_id != side_id) + { + flash_dev_other_info.side_id = side_id; + tlkapi_send_string_data(APP_LOG_EN, "saving other info", &flash_dev_other_info.side_id, 5); + + //save_data_to_flash(flash_sector_2p4_other_inf, sizeof(ST_FLASH_DEV_OTHER_INFO), (unsigned char *)&flash_dev_other_info.side_id, (int *)&dev_other_info_idx); + int ret = nvs_write(&user_fs, APP_2P4G_APP_INFO_ID, (unsigned char *)&flash_dev_other_info.side_id, sizeof(ST_FLASH_DEV_OTHER_INFO)); + printk("NVS APP_2P4G_APP_INFO_ID Write result: %d\n", ret); + } + } +} + +_attribute_ram_code_sec_ static void app_2p4g_handle_set_state(uint8_t *data, uint16_t len) +{ + p24g_evt_t *p_evt = (p24g_evt_t *)data; + if (p_evt->type == P24G_SM_CMD_SET_STATE) + { + if (p_evt->opcode <= STATE_PAIRING_TIMEOUT) { + app_d24p_set_state(p_evt->opcode); + } + + if (p_evt->opcode == STATE_CONNECTED) + { + tlkapi_send_string_data(APP_LOG_EN, "connected", data, len); + + spp_tick = stimer_get_tick() | 1; + } + else if (p_evt->opcode == STATE_DISCONNECTED) + { + if(p_evt->data[0] == P24G_LL_CONN_TIMEOUT) + { + p24g_enable_reconn(true); + } + } + else if (p_evt->opcode == STATE_PAIRING) + { + + }else if (p_evt->opcode == STATE_RF_IDLE) + { + + }else if (p_evt->opcode == STATE_PAIRING_TIMEOUT) + { + p24g_enable_pairing(true); + } + else if (p_evt->opcode == STATE_IDLE) + { + uint32_t wakeup_stick = 0; + + wakeup_stick = p_evt->data[3]; + wakeup_stick = (wakeup_stick << 8) + p_evt->data[2]; + wakeup_stick = (wakeup_stick << 8) + p_evt->data[1]; + wakeup_stick = (wakeup_stick << 8) + p_evt->data[0]; + + app_2p4g_set_power_state(STATE_TO_IDLE, wakeup_stick); + } + else if (p_evt->opcode == STATE_SLEEP) + { + uint32_t wakeup_stick = 0; + + wakeup_stick = p_evt->data[3]; + wakeup_stick = (wakeup_stick << 8) + p_evt->data[2]; + wakeup_stick = (wakeup_stick << 8) + p_evt->data[1]; + wakeup_stick = (wakeup_stick << 8) + p_evt->data[0]; + + // DBG_GPIO_TOGGLE(STACK_IO_EN, GPIO_PD7); + app_2p4g_set_power_state(STATE_TO_SLEEP, wakeup_stick); + } + } +} + +static inline void app_2p4g_clock_reinit(uint8_t report_rate) +{ + g_report_rate = report_rate; + if (report_rate == REPORT_RATE_8K) { + app_clock_init(CLOCK_CONFIG_1V1_96_96); + if (app_get_kb_mode() == KB_MODE_2P4G) { + app_wdt_init(); + } + } else { + app_clock_init(CLOCK_CONFIG_1V_48_24); + if (app_get_kb_mode() == KB_MODE_2P4G) { + app_wdt_init(); + } + } +} + +_attribute_ram_code_sec_ void app_2p4g_clock_reover(void) +{ + if (g_report_rate == REPORT_RATE_8K) { + app_clock_init(CLOCK_CONFIG_1V1_96_96); + if (app_get_kb_mode() == KB_MODE_2P4G) { + app_wdt_init(); + } + } else { + app_clock_init(CLOCK_CONFIG_1V_48_24); + if (app_get_kb_mode() == KB_MODE_2P4G) { + app_wdt_init(); + } + } +} + +_attribute_ram_code_sec_ static void app_2p4g_handle_spp_data(uint8_t *data, uint16_t len) +{ + p24g_evt_t *p_evt = (p24g_evt_t *)data; + if (p_evt->opcode == P24G_SPP_LED_STATUS) + { + app_pc_kb_led_status(p_evt->data[0]); + + } + else if (p_evt->opcode == P24G_SPP_TEST_DATA) + { + tlkapi_send_string_data(APP_LOG_EN, "rx spp data", data, len); + + } +} + +_attribute_ram_code_sec_ static void app_2p4g_handle_misc(uint8_t *data, uint16_t len) +{ + p24g_evt_t *p_evt = (p24g_evt_t *)data; + switch (p_evt->opcode) { + case P24G_SM_OP_MISC_REPORT_RATE: //report rate changed + tlkapi_send_string_data(APP_LOG_EN, "report rate changed", data, len); + app_2p4g_clock_reinit(data[3]); + break; + + case P24G_SM_OP_MISC_SAVE_REPORT_RATE: + app_2p4g_save_report_rate_info(data[3]); + // DBG_GPIO_TOGGLE(APP_IO_EN, GPIO_PH0); + tlkapi_send_string_data(APP_LOG_EN, "report rate info saved", data, len); + app_2p4g_clock_reinit(data[3]); + break; + + case P24G_SM_OP_MISC_RF_MODE: + tlkapi_printf(APP_LOG_EN, "rf mode:%x\n", p_evt->data[0]); + app_ctx.rf_mode = p_evt->data[0]; + break; + + default: + break; + } +} + +static void app_p24g_sm_cmd_hanlder_init(void) +{ + p24g_register_sm_cmd_handler(P24G_SM_CMD_SAVE_PAIR_INFO, app_2p4g_handle_save_pairing_info); + p24g_register_sm_cmd_handler(P24G_SM_CMD_SET_STATE, app_2p4g_handle_set_state); + p24g_register_sm_cmd_handler(P24G_SM_CMD_DATA_TYPE_SPP, app_2p4g_handle_spp_data); + p24g_register_sm_cmd_handler(P24G_SM_CMD_MISC, app_2p4g_handle_misc); +} + +static void app_p24g_send_info_2_n22(void) +{ + p24g_send_sm_msg(P24G_SM_CMD_MISC, P24G_SM_OP_MISC_TRANS_MAC, app_ctx.mac, MAC_ADDR_LEN); + + if (dev_info_idx >= 0) + { + p24g_send_sm_msg(P24G_SM_CMD_MISC, P24G_SM_OP_MISC_PEER_INFO, flash_dev_info.peer_addr, MAC_ADDR_LEN); + p24g_enable_reconn(true); + } + + #if (HW_BOARD_TYPE == HW_EVK_KEYBOARD || HW_EVK_BOARD == 1) + else{ + tlkapi_send_string_data(APP_LOG_EN, "enter pairing mode ", 0, 0); + p24g_enable_pairing(true); + } + #endif + if (dev_other_info_idx >= 0) { + p24g_send_sm_msg(P24G_SM_CMD_MISC, P24G_SM_OP_MISC_REPORT_RATE, &flash_dev_other_info.report_rate, 1); + } +} + + +static void app_debug_io_init(void) +{ +#if (ALG_KEYSCAN_APP_FUN_ENABLE && APP_IO_EN) + gpio_function_en(GPIO_PD5 | GPIO_PD6 | GPIO_PD7); + gpio_output_en(GPIO_PD5 | GPIO_PD6 | GPIO_PD7); + gpio_input_dis(GPIO_PD5 | GPIO_PD6 | GPIO_PD7); +#endif +} + +/** + * @brief user initialization when MCU power on or wake_up from deepSleep mode + * @param[in] none + * @return none + */ +void p24g_user_init_normal(void) +{ + app_wdt_init(); + + // app_debug_io_init(); + + app_2p4g_dual_core_comm_init(); + + app_p24g_sm_cmd_hanlder_init(); + + app_p24g_send_info_2_n22();//call this fun after sm init + + p24g_send_sm_msg(P24G_SM_CMD_SET_KB_MODE, P24G_KB_MODE_2P4G, 0, 0); + + app_timer1_init(); + tlkapi_send_string_data(APP_LOG_EN, "d25f kb _p24g_init end", 0, 0); +} + + +_attribute_ram_code_sec_ void app_p24g_spp_send_handle(void) +{ + unsigned char *p= pp_fifo_get_ptr(&tx_fifo); + + if(p!=0) + { + unsigned char len=p[0]; + unsigned char cmd=p[1]; + + unsigned char ret=0; + if(cmd==CONSUME_KB_DATA_CMD) + { + ret = p24g_send_spp_data(P24G_SPP_CONSUME_KEY_DATA, &p[2], len); + } + else if(cmd==ALL_KB_DATA_CMD) + { + ret = p24g_send_spp_data(P24G_SPP_ALL_KEY_DATA, &p[2], len); + } + if(ret==TLK_SUCCESS) + { + pp_fifo_pop(&tx_fifo); + tlkapi_send_string_data(APP_LOG_EN, "spp send OK", &ret, 1); + } + else + { + tlkapi_send_string_data(APP_LOG_EN, "spp send failed", &ret, 1); + } + } +} + + +/** + * @brief in 2.4g mode device status check + * @param[in] none + * @return none + */ + +_attribute_ram_code_sec_ void app_pp_check_connect_status(void) +{ + static unsigned int led_tick; + + #if 1 + // if(last_connect_status!=app_inf.dev_now_status) + if(last_connect_status!=app_d24p_get_state() ) + { + tick_status=clock_time()|1; + led_tick=clock_time()|1; + #if 0 + if(last_connect_status==STATE_PAIRING) + { + //auto_draw_flag=0; + } + #endif + // last_connect_status=app_inf.dev_now_status; + last_connect_status = app_d24p_get_state(); + // print_app_public("d24g_status=%d\r\n", last_connect_status); + + #if 0 + if (app_inf.pair_success_flag) + { + + app_inf.pair_success_flag = 0; + + if (flash_dev_info.side_id != app_inf.side_id) + { + + flash_dev_info.side_id = app_inf.side_id; + DBG_GPIO_TOGGLE(APP_IO_EN, GPIO_PG6); + save_data_to_flash(flash_sector_2p4_inf, sizeof(ST_FLASH_DEV_INFO), (unsigned char *)&flash_dev_info.side_id, (int *)&dev_info_idx); + DBG_GPIO_TOGGLE(APP_IO_EN, GPIO_PG6); + } + + } + #endif + + // if((app_inf.dev_now_status==STATE_NORMAL)) + if((app_d24p_get_state() == STATE_CONNECTED)) + { + gpio_set_level(PAIR_LED_PIN,LED_IS_ON); + } + } +#endif + + + if(usb_connected_ok) + { + gpio_set_level(PAIR_LED_PIN,LED_IS_OFF); + } + // else if(app_inf.dev_now_status==STATE_RECONNECT) + else if(app_d24p_get_state() == STATE_RECONNECT) + { + #if 0 + if(clock_time_exceed(tick_status, RECONN_TIMEOUT_US)) + { + + //pp_rf_enter_idle(1); + + + if(pp_get_rf_link_status()==IDLE_RF_STATUS) + { + //app_enter_sleep(D24G_RECONNECT_TIMEOUT_SLEEP); + } + + } + #endif + + if(clock_time_exceed(led_tick, 1000000)) + { + led_tick=clock_time(); + + DBG_GPIO_TOGGLE(APP_IO_EN, PAIR_LED_PIN); + +// tlkapi_printf(APP_LOG_EN, "powron\n"); + } + } + else if(app_d24p_get_state() == STATE_PAIRING) + { + if(clock_time_exceed(led_tick, 100000)) + { + led_tick=clock_time(); + DBG_GPIO_TOGGLE(APP_IO_EN, PAIR_LED_PIN); + } + } + if((app_d24p_get_state() == STATE_CONNECTED)) + { + app_p24g_spp_send_handle(); + } +} + +#define SPP_TEST_EN 0 +uint8_t spp_buf[16] = {0x0, 0x13, 0x34, 0x45, 0x56, 0x67, 0x78, 0x89}; +_attribute_ram_code_sec_ static void app_spp_send_data(void) +{ + DBG_GPIO_TOGGLE(APP_IO_EN, GPIO_PH0); + spp_tick = stimer_get_tick() | 1; + int ret = p24g_send_spp_data(P24G_SPP_TEST_DATA, spp_buf, sizeof(spp_buf)); + if (ret != TLK_SUCCESS) + { + tlkapi_send_string_data(APP_LOG_EN, "spp send test data failed", &ret, 1); + } + spp_buf[0]++; +} + +_attribute_ram_code_sec_ void app_timer1_irq_handler(void) +{ + if (timer_get_irq_status(FLD_TMR1_MODE_IRQ)) { + app_timer1_stop(); + timer_clr_irq_status(FLD_TMR1_MODE_IRQ); //clear irq status + } +} + +_attribute_ram_code_sec_ static void app_2p4g_sleep_check_loop(void) +{ + static uint8_t sleep_prepare_cnt = APP_SLEEP_PREPARE_COUNT; + #if APP_DELAY_ENTER_SUSPEND_TIME_US + static uint32_t stick = 0; + #endif + uint8_t short_suspend_flag = 1; + + if (app_2p4g_is_work_busy() || app_is_usb_det_in()) { + return; + } + + if ((g_power_state == STATE_TO_SLEEP)) { + #if APP_DELAY_ENTER_SUSPEND_TIME_US + if (!stick) { + stick = stimer_get_tick() | 1; + } + #endif + if (!sleep_prepare_cnt) { + #if APP_DELAY_ENTER_SUSPEND_TIME_US + if (stick && tick1_exceed_tick2(stimer_get_tick(), stick + APP_DELAY_ENTER_SUSPEND_TIME_US * SYSTEM_TIMER_TICK_1US)) { + stick = 0; + #endif + g_power_state = STATE_NONE; + sleep_prepare_cnt = APP_SLEEP_PREPARE_COUNT; + if (tick1_exceed_tick2(g_wakeup_stick, stimer_get_tick() + APP_SUSPEND_LIMIT_MIN_TIME_US * SYSTEM_TIMER_TICK_1US)) { + // gpio_set_level(GPIO_PH2, 0); + // app_proc_before_sleep(); + // DBG_GPIO_TOGGLE(APP_IO_EN, GPIO_PD7); + if (tick1_exceed_tick2(g_wakeup_stick, stimer_get_tick() + APP_SUSPEND_LONG_TIME_MIN_US * SYSTEM_TIMER_TICK_1US)) { + short_suspend_flag = 0; + // gpio_set_level(GPIO_PH2, 1); + } + pm_set_suspend_power_cfg(FLD_PD_ZB_EN, short_suspend_flag); + + g_app_suspend_ret_flag = 1; + // DBG_STACK_GPIO_SET_LEVEL(APP_IO_EN, GPIO_PH2, 0); + pm_sleep_wakeup(SUSPEND_MODE, PM_WAKEUP_TIMER, PM_TICK_STIMER, g_wakeup_stick + - (APP_WAKEUP_EARLY_TIME_US + (short_suspend_flag ? 0 : 600)) * SYSTEM_TIMER_TICK_1US); + // DBG_STACK_GPIO_SET_LEVEL(APP_IO_EN, GPIO_PH2, 1); + + // DBG_GPIO_TOGGLE(APP_IO_EN, GPIO_PD7); + // app_proc_after_sleep(); + if (!short_suspend_flag) { + // gpio_set_level(GPIO_PH2, 0); + pm_set_dig_module_power_switch(FLD_PD_ZB_EN, PM_POWER_UP); + p24g_send_sm_msg(P24G_SM_CMD_MISC, P24G_SM_OP_MISC_LONG_SUSP_RET, 0, 0); + } else { + p24g_send_sm_msg(P24G_SM_CMD_MISC, P24G_SM_OP_MISC_SUSP_RET, 0, 0); + } + // gpio_set_level(GPIO_PH2, 1); + app_2p4g_set_power_state(STATE_TO_IDLE, 0); + } + #if APP_DELAY_ENTER_SUSPEND_TIME_US + } + #endif + } else { + sleep_prepare_cnt--; + } + } else if (g_power_state == STATE_TO_IDLE) { + if (!sleep_prepare_cnt) { + g_power_state = STATE_NONE; + sleep_prepare_cnt = APP_SLEEP_PREPARE_COUNT; + // DBG_STACK_GPIO_SET_LEVEL(APP_IO_EN, GPIO_PH2, 0); + // gpio_set_level(GPIO_PG7, 0); + core_entry_wfi_mode(); + // gpio_set_level(GPIO_PG7, 1); + // DBG_STACK_GPIO_SET_LEVEL(APP_IO_EN, GPIO_PH2, 1); + app_2p4g_set_power_state(STATE_TO_IDLE, 0); + } else { + sleep_prepare_cnt--; + } + } +} + +/** + * @brief BLE main loop + * @param[in] none. + * @return none. + */ +_attribute_no_inline_ void app_2p4g_main_loop(void) +{ + //tlk_multi_core_communication_loop(); + mcc_d25f_loop(); +////////////////////////////////////// Debug entry ///////////////////////////////// +#if (TLKAPI_DEBUG_ENABLE) + tlkapi_debug_handler(); +#endif + + + app_pp_check_connect_status(); + + wd_clear(); + +#if SPP_TEST_EN + if (spp_tick && clock_time_exceed(spp_tick, 300000)) + { + app_spp_send_data(); + } +#endif + + app_2p4g_sleep_check_loop(); +} diff --git a/samples/bluetooth/peripheral_kmd/src/app_24g.h b/samples/bluetooth/peripheral_kmd/src/app_24g.h new file mode 100644 index 0000000000000..7e440c0332d42 --- /dev/null +++ b/samples/bluetooth/peripheral_kmd/src/app_24g.h @@ -0,0 +1,379 @@ +/** @file + * @brief app_24g.h + */ + +/* + * Copyright (c) 2016 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __APP_2P4G_H__ +#define __APP_2P4G_H__ + +#include "app_common_config.h" + +typedef void (*p24g_sm_cmd_handler_t)(uint8_t *data, uint16_t len); + +// enum { +// EMPTY_DATA_CMD=0, +// PAIR_DATA_CMD=1, +// RECONNECT_DATA_CMD=2, +// MOUSE_DATA=3, +// SPP_DATA=4, +// SPP_DATA_ACK=5, +// NORMAL_KB_DATA_CMD=6, +// CONSUME_KB_DATA_CMD=7, +// SYSTEM_KB_DATA_CMD=8, +// ALL_KB_DATA_CMD=9, +// }; + +/* Definition of mailbox 2.4g packet types */ +typedef enum { + P24G_MB_CMD_NONE = 0x00, + P24G_MB_CMD_USB = 0x01, +} p24g_mailbox_cmd_e; + +typedef enum { + P24G_USB_OP_EP_WRITE = 0x00, + P24G_USB_OP_EP_READ = 0x01, +} p24g_usb_opcode_e; + +typedef enum +{ + CLOCK_CONFIG_1V1_192_96 = 0, + CLOCK_CONFIG_1V1_96_96, + CLOCK_CONFIG_1V1_48_48, + CLOCK_CONFIG_1V_72_36, + CLOCK_CONFIG_1V_64_32, + CLOCK_CONFIG_1V_48_24, +} app_clock_config_e; + +/* Generic event header */ +typedef struct p24g_evt +{ + uint8_t type; + uint8_t opcode; + uint8_t len; + uint8_t data[0]; +} __attribute__((packed)) p24g_evt_t; + +/* USB packet header */ +typedef struct p24g_usb_packet_header +{ + uint8_t ep_addr; + uint8_t len; + uint8_t data[0]; +} __attribute__((packed)) p24g_usb_pkt_t; + +extern volatile p24g_device_status_e g_state; + + +typedef struct { + uint8_t rf_mode; + uint8_t mac[MAC_ADDR_LEN]; +} app_ctx_t; +extern app_ctx_t app_ctx; + +/** + * @brief Register a shared memory (SM) command handler for the 2.4GHz protocol + * + * This function registers a handler function for a specified SM command in the + * 2.4GHz protocol stack. When the given command is received through the SM + * (shared memory) communication channel, the registered handler will be invoked + * with the associated data buffer. + * + * @param[in] cmd Command identifier of type @ref p24g_sm_cmd_e + * @param[in] handler Callback function pointer of type @ref p24g_sm_cmd_handler_t + * + * @return 0: success + * Other: fail + * + * @note If a handler for the same command is already registered, it will + * be overwritten by the new handler. + */ +uint8_t p24g_register_sm_cmd_handler(p24g_sm_cmd_e cmd, p24g_sm_cmd_handler_t handler); + + +/** + * @brief Shared memory (SM) receive callback for 2.4GHz D25F core + * + * This callback function is invoked when the shared memory (SM) interface + * receives data from another MCU core in an dual-core system. It is + * part of the inter-core communication mechanism used by the 2.4GHz protocol + * stack running on the d25f core. + * + * @param[in] data Pointer to the received data buffer + * @param[in] len Length of the received data in bytes + * + * @note The buffer pointed by @p data is only valid during the callback + * execution. If the data needs to be stored for later processing, + * it must be copied to a safe memory area before the callback returns. + * + * @return None + */ +void app_2p4g_d25f_sm_rx_cb(uint8_t *data, uint32_t len); + + +/** + * @brief Send a shared memory (SM) message in the 2.4GHz protocol + * + * This function sends a message to the 2.4GHz protocol layer through the + * shared memory (SM) interface. The SM interface is used for inter-core + * communication in dual-core systems, enabling fast and low-latency data + * exchange between the application processor d25f and the RF protocol core n22. + * + * @param[in] type Message type identifier + * @param[in] op Message operation code + * @param[in] data Pointer to the message data buffer + * @param[in] len Length of the message data in bytes + * + * @return 0 if sending is successful, non-zero error code if failed + * + * @note The buffer pointed by @p data must remain valid until the message + * is fully copied or processed by the receiving core. + * + */ +uint8_t p24g_send_sm_msg(uint8_t type, uint8_t op, uint8_t *data, uint8_t len); + + + +/** + * @brief Send SPP (Serial Port Profile) data through 2.4GHz protocol + * + * This function sends SPP-format data via the 2.4GHz protocol layer to + * the connected peer device. SPP data is typically used for generic data + * transmission (non-HID) between two devices over the 2.4GHz link. + * + * @param[in] cmd SPP data command identifier + * @param[in] data Pointer to the SPP data buffer + * @param[in] len Length of the SPP data in bytes + * + * @return 0 if sending is successful, non-zero error code if failed + * + */ +uint8_t p24g_send_spp_data(uint8_t cmd, unsigned char *data, unsigned char len); + +/** + * @brief Enable or disable pairing mode for the 2.4GHz protocol + * + * This function enables or disables the pairing mode in the 2.4GHz protocol stack. + * When pairing mode is enabled, the device will search for and allow connections + * from compatible peer devices. When disabled, pairing requests will be ignored. + * + * @param[in] enable true to enable pairing mode, false to disable pairing mode + * + * @return 0 if the operation is successful, non-zero error code if failed + * + * @note This API only controls the pairing state in the protocol stack. + * + */ +uint8_t p24g_enable_pairing(bool enable); + + +/** + * @brief Terminate the current 2.4GHz connection + * + * This function is used to actively terminate the existing 2.4GHz wireless + * connection. It can be called by the application layer when the device + * needs to disconnect from the host or exit the current session. + * + * After a successful disconnection, the device status callback will be invoked + * with @ref STATE_DISCONNECTED, and the disconnection reason will be reported + * as @ref P24G_LL_CONN_TERMINATION_BY_LOCAL. + * + * @param None + * + * @return 0: success + * Other: failure + * + * @note A reconnection procedure may be required if communication + * is needed again. + */ +uint8_t p24g_terminate_connect(void); + + +/** + * @brief Put the 2.4GHz RF module into idle state + * + * This function actively transitions the 2.4GHz RF module to idle state, + * stopping ongoing RF communication and freeing RF resources. + * + * After a successful operation, the device status callback will be invoked + * with @ref STATE_RF_IDLE, indicating that the RF module is now in idle state. + * + * @param None + * + * @return 0: success + * Other: failure + * + * @note Use this function when the application needs to temporarily stop + * RF communication or release RF resources. Communication must be + * re-enabled or reconnected if needed again. + */ +uint8_t p24g_rf_enter_idle(void); + + +/** + * @brief Enable or disable the 2.4GHz automatic reconnection feature + * + * This function enables or disables the automatic reconnection mechanism + * in the 2.4GHz protocol stack. + * + * @param[in] enable true: enable reconnection + * false: disable reconnection + * + * @return 0: success + * Other: failure (e.g., invalid parameter or operation not allowed) + * + * @note This function should be called after the device has been paired. + * + */ +uint8_t p24g_enable_reconn(bool enable); + + +/** + * @brief Initialize 2.4GHz application module + * + * This function performs initialization of the 2.4GHz application layer, + * including RF configuration, state variables setup, and registration + * of necessary callbacks. It should be called once during system startup + * before any 2.4GHz communication begins. + * + * @param[in] None + * + * @return None + * + * @note Must be called before entering the 2.4GHz main loop or + * handling any RF-related events. + */ +void app_2p4g_init(void); + +/** + * @brief Timer1 interrupt service routine + * + * This function is the interrupt handler for Timer1. It is typically used + * for time-critical tasks such as RF scheduling, connection supervision, + * or periodic event triggering related to the 2.4GHz communication stack. + * + * @param[in] None + * + * @return None + * + * @note This function must be registered as the Timer1 ISR and should + * execute as quickly as possible to avoid interrupt latency. + */ +void app_timer1_irq_handler(void); + +/** + * @brief 2.4GHz main loop + * + * This function runs the main execution loop of the 2.4GHz protocol. + * It handles packet transmission, reception, and state transitions. + * The function should be called repeatedly in the system main loop + * to maintain RF communication and process queued events. + * + * @param[in] None + * + * @return None + * + * @note This function is non-blocking and should be invoked + * periodically within the main system loop. + */ +void app_2p4g_main_loop(void); + +/** + * @brief 2.4GHz mailbox callback for keyboard/mouse data + * + * This function is invoked when keyboard or mouse data is received + * through the 2.4GHz mailbox channel. The received data is provided + * through the input buffer for further processing or forwarding to + * higher layers. + * + * @param[in] data Pointer to the received data buffer + * + * @return None + * + * @note This function should be registered as the mailbox callback + * for keyboard/mouse data reception in the 2.4GHz stack. + */ +void app_2p4g_mb_km_data_cb(uint8_t* data); + +/** + * @brief Get the current 2.4GHz device state + * + * This function returns the current operating state of the 2.4GHz device, + * which indicates the RF or connection status such as idle, connected, + * or disconnected. + * + * @return Current device state of type @ref p24g_device_status_e + * + * @note Typically used to check the current communication or RF state + * in higher-level application logic. + */ +static inline p24g_device_status_e app_d24p_get_state(void) +{ + return g_state; +} + +/** + * @brief Set the current 2.4GHz device state + * + * This function updates the internal state variable that represents + * the 2.4GHz device’s current operating status. It is mainly used by + * internal modules to synchronize the system state after major events + * such as connection, disconnection, or idle transitions. + * + * @param[in] state New device state of type @ref p24g_device_status_e + * + * @return None + * + * @note This function is intended for internal use only. Application + * modules should trigger state transitions via higher-level APIs. + */ +static inline void app_d24p_set_state(p24g_device_status_e state) +{ + g_state = state; +} + +/** + * @brief Adjust 2.4GHz clock settings according to stack usage scenario + * + * This function switches or reconfigures the 2.4GHz RF clock settings based + * on the current usage scenario of the 2.4G protocol stack. Depending on the + * stack state and requirements it may: + * - select a high-precision clock source or increase clock frequency for + * timing-critical modes (e.g. continuous TX/RX, high-rate transfers); + * - select a low-power / gated clock configuration for idle or low-activity + * modes to save power; + * - apply timing/phase adjustments required after mode transitions (wake-up, + * role change, channel change, etc.). + * + * The function should be called whenever the stack transitions between modes + * that have different timing/accuracy or power requirements (for example: + * entering/exiting active RF operation, switching from idle to heavy TX/RX, + * after wakeup from deep sleep, or when preparing for connection procedures). + * + * @param[in] None + * + * @return None + * + * @note This routine must ensure clock changes are performed safely: + * synchronize with ongoing RF operations, avoid abrupt clock changes + * during packet transmission/reception, and reconfigure/handover + * hardware PLLs or clock dividers as required by the platform. + */ +void app_2p4g_clock_reover(void); + + + +#ifdef __cplusplus +extern "C" { +#endif + + +#ifdef __cplusplus +} +#endif + +#endif // __APP_2P4G_H__ \ No newline at end of file diff --git a/samples/bluetooth/peripheral_kmd/src/app_alg_keyscan.c b/samples/bluetooth/peripheral_kmd/src/app_alg_keyscan.c new file mode 100644 index 0000000000000..c7958891de1f9 --- /dev/null +++ b/samples/bluetooth/peripheral_kmd/src/app_alg_keyscan.c @@ -0,0 +1,170 @@ +/* main.c - Application main entry point */ + +/* + * Copyright (c) 2016 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include "app_public.h" + +#define LOG_LEVEL LOG_LEVEL_DBG +#include +LOG_MODULE_REGISTER(alg_keyscan); + + +#if ALG_KEYSCAN_APP_FUN_ENABLE + +#define KEYSCAN_TEST_1XADC 0//KEYSCAN_1XADC_MODE +#define KEYSCAN_TEST_2XADC 1//KEYSCAN_2XADC_MODE +#define KEYSCAN_TEST_1XADC_8K_ONCE 2//KEYSCAN_1XADC_8K_ONCE_MODE +#define KEYSCAN_TEST_2XADC_8K_ONCE 3//KEYSCAN_2XADC_8K_ONCE_MODE +#define KEYSCAN_TEST_2XADC_8K_TWICE_M1 4//KEYSCAN_2XADC_8K_TWICE_M1_MODE +#define KEYSCAN_TEST_2XADC_8K_TWICE_M2 5//KEYSCAN_2XADC_8K_TWICE_M2_MODE + +#define KS_TEST_MODE KEYSCAN_TEST_2XADC_8K_ONCE + +#define KS_DMA_LLP_ENABLE 1 +#define DMA1_KEY_SCAN DMA4 +#define DMA2_KEY_SCAN DMA5 + +#define BUFFER_SIZE (256) //the minimum buffer size (unit:byte), adc data format 16bits +#define KEYSCAN_ADC_BUFFER_SIZE (BUFFER_SIZE / 4) +short adc0_buffer[KEYSCAN_ADC_BUFFER_SIZE] = {0}, adc1_buffer[KEYSCAN_ADC_BUFFER_SIZE] = {0}; +_attribute_aligned_(4) unsigned short adc_buffer[KEYSCAN_ADC_BUFFER_SIZE*2] = {0}; + + + + + +#define TOTAL_ROW 8 +#define TOTAL_COL 16 + +//unsigned char const map_window[TOTAL_COL][TOTAL_ROW] = { +unsigned char map_window[TOTAL_COL][TOTAL_ROW] = {\ +/*C01*/{KB_M, KB_Left, KP_jiahao, KP_Del, KB_N, KB_RCtrl, KP_9, KP_0},\ +/*C02*/{KB_B, T_FN, KP_8, KP_enter, KB_V, KB_RAlt, KP_7, KP_3},\ +/*C03*/{KB_C, KB_Space, KP_jianhao, KP_2, KB_X, KB_LAlt, KP_chenghao, KP_1},\ +/*C04*/{KB_Z, KB_LWin, KP_chuhao, KP_6, KB_LShift, KB_LCtrl, KB_Num, KP_5},\ +/*C05*/{KB_douhao, KB_Down, KP_4, 0, KB_juhao, KB_Right, 0, 0},\ +/*C06*/{KB_wenhao, 0, 0, 0, KB_RShift, 0, 0, 0},\ +/*C07*/{KB_Up, 0, 0, 0, 0, 0, 0, 0},\ +/*C08*/{0, 0, 0, 0, 0, 0, 0, 0},\ +/*C09*/{KB_J, KB_U, KB_7, KB_F7, KB_H, KB_Y, KB_6, KB_F6},\ +/*C10*/{KB_G, KB_T, KB_5, KB_F5, KB_F, KB_R, KB_4, KB_F4},\ +/*C11*/{KB_D, KB_E, KB_3, KB_F3, KB_S, KB_W, KB_2, KB_F2},\ +/*C12*/{KB_A, KB_Q, KB_1, KB_F1, KB_Caps, KB_Tab, KB_dunhao, KB_Esc},\ +/*C13*/{KB_K, KB_I, KB_8, KB_F8, KB_L, KB_O, KB_9, KB_F9},\ +/*C14*/{KB_fenhao, KB_P, KB_0, KB_F10, KB_yinhao, KB_Lguohao, KB_jianhao, KB_F11},\ +/*C15*/{KB_Enter, KB_Rguohao, KB_denghao, KB_F12, 0, KB_xiegang, KB_Back, KB_Home},\ +/*C16*/{0, 0, KB_PgUp, KB_Delete, 0, 0, KB_PgDown, KB_Insert},\ +}; + +unsigned char hw_now_bits[TOTAL_COL]; //hardware bits +unsigned char hw_last_bits[TOTAL_COL]; //hardware bits + +unsigned char get_key_value( unsigned short *buf,unsigned short release_threshold,unsigned short press_threshold) +{ + if(buf[0]press_threshold) + { + return 1; + } + else + { + return 2; + } + return 1; +} + +unsigned char key_scan(void) +{ + unsigned char has_new_key_event=0; + unsigned char press_flag=0; + app_key_buf.press_cnt=0; + app_key_buf.cnt=0; + app_key_buf.special_key_press_f=0; + + //tmemset(&app_key_buf.hw_now_bits[0], 0, TOTAL_COL); + for(int col=0;col +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "app_public.h" + +#define LOG_LEVEL LOG_LEVEL_DBG +#include +LOG_MODULE_REGISTER(app_bat); + + + +#if BATT_CHECK_ENABLE +/*ADC*/ +#if !DT_NODE_EXISTS(DT_PATH(zephyr_user)) || \ + !DT_NODE_HAS_PROP(DT_PATH(zephyr_user), io_channels) +#error "No suitable devicetree overlay specified" +#endif + +#define DT_SPEC_AND_COMMA(node_id, prop, idx) \ + ADC_DT_SPEC_GET_BY_IDX(node_id, idx), + +/* Data of ADC io-channels specified in devicetree. */ +static const struct adc_dt_spec adc_channels[] = { + DT_FOREACH_PROP_ELEM(DT_PATH(zephyr_user), io_channels, + DT_SPEC_AND_COMMA) +}; + +uint32_t lowBattDet_tick = 0; + + +uint16_t buf; +struct adc_sequence sequence = { + .buffer = &buf, + /* buffer size in bytes, not number of samples */ + .buffer_size = sizeof(buf), +}; + +void app_battery_check_init(void) +{ + int err; + + /* Configure channels individually prior to sampling. */ + for (size_t i = 0U; i < ARRAY_SIZE(adc_channels); i++) { + if (!device_is_ready(adc_channels[i].dev)) { + tlkapi_printk(TLK_LOG_EN, "ADC controller device %s not ready\n", adc_channels[i].dev->name); + return 0; + } + + err = adc_channel_setup_dt(&adc_channels[i]); + if (err < 0) { + tlkapi_printk(TLK_LOG_EN, "Could not setup channel #%d (%d)\n", i, err); + return 0; + } + } + + tlkapi_printk(TLK_LOG_EN, "ADC battery check init\n"); +} + +_attribute_ram_code_sec_ void app_battery_power_check(uint16_t alarm_vol_mv) +{ + int err; + + tlkapi_printk(TLK_LOG_EN, "ADC reading:\n"); + int32_t val_mv; + + (void)adc_sequence_init_dt(&adc_channels[0], &sequence); + + err = adc_read(adc_channels[0].dev, &sequence); + if (err < 0) { + tlkapi_printk(TLK_LOG_EN, "Could not read (%d)\n", err); + } + + val_mv = (int32_t)buf; + + tlkapi_printk(TLK_LOG_EN, "%"PRId32, val_mv); + err = adc_raw_to_millivolts_dt(&adc_channels[0], + &val_mv); + /* conversion to mV may not be supported, skip if not */ + if (err < 0) { + tlkapi_printk(TLK_LOG_EN, " (value in mV not available)\n"); + } else { + tlkapi_printk(TLK_LOG_EN, " = %"PRId32" mV\n", val_mv); + } +} + + + +#endif \ No newline at end of file diff --git a/samples/bluetooth/peripheral_kmd/src/app_battery.h b/samples/bluetooth/peripheral_kmd/src/app_battery.h new file mode 100644 index 0000000000000..4c65ebcceb5df --- /dev/null +++ b/samples/bluetooth/peripheral_kmd/src/app_battery.h @@ -0,0 +1,21 @@ +/** @file + * @brief app_battery.h + */ + +/* + * Copyright (c) 2016 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern uint32_t lowBattDet_tick; + +void app_battery_check_init(void); +void app_battery_check(uint16_t alarm_vol_mv); +#ifdef __cplusplus +} +#endif diff --git a/samples/bluetooth/peripheral_kmd/src/app_ble.c b/samples/bluetooth/peripheral_kmd/src/app_ble.c new file mode 100644 index 0000000000000..c3d0a0502ae7d --- /dev/null +++ b/samples/bluetooth/peripheral_kmd/src/app_ble.c @@ -0,0 +1,540 @@ +/* main.c - Application main entry point */ + +/* + * Copyright (c) 2016 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include "app_public.h" + +#define LOG_LEVEL LOG_LEVEL_DBG +#include +LOG_MODULE_REGISTER(app_ble); + +#define DEVICE_NAME CONFIG_BT_DEVICE_NAME +#define DEVICE_NAME_LEN (sizeof(DEVICE_NAME) - 1) + +static struct bt_data ad[] = { + BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)), + BT_DATA_BYTES(BT_DATA_GAP_APPEARANCE, BT_BYTES_LIST_LE16(BT_APPEARANCE_HID_KEYBOARD)), + BT_DATA_BYTES(BT_DATA_UUID16_ALL, BT_UUID_16_ENCODE(BT_UUID_HIDS_VAL)), + BT_DATA_BYTES(BT_DATA_MANUFACTURER_DATA, 0x06, 0x00, 0x03, 0x00, 0x80), + // BT_DATA(BT_DATA_NAME_COMPLETE, DEVICE_NAME, DEVICE_NAME_LEN), +}; + +static struct bt_data sd[] = { + // BT_DATA(BT_DATA_NAME_COMPLETE, DEVICE_NAME, DEVICE_NAME_LEN), +}; + +ST_BLE_APP_PIPE_INFO ble_app_pip_info; + + +struct bt_conn *connected_handle; +static struct k_work_delayable ble_change_pipe_delayed_work; +static struct k_work_delayable ble_start_pairing_delayed_work; +uint8_t pair_flag; +volatile uint8_t ble_status = 0; +uint8_t connect_complete = 0; +uint32_t tick_connected = 0; +uint8_t need_enter_sleep = 0; +uint8_t need_save_info = 0; + +bt_addr_le_t ble_addr = {.type = BT_ADDR_LE_RANDOM, .a = {0xC0, 0x79, 0xEE, 0x00, 0x01, 0xD1}}; + +struct bt_le_adv_param adv_param = { + .id = BT_ID_DEFAULT, + .sid = 0, + .secondary_max_skip = 0, + .options = (BT_LE_ADV_OPT_CONNECTABLE |BT_LE_ADV_OPT_USE_NAME | + BT_LE_ADV_OPT_ONE_TIME |BT_LE_ADV_OPT_FORCE_NAME_IN_AD), + .interval_min = 0x0020, /* 20 ms */ + .interval_max = 0x0020, /* 20 ms */ + .peer = NULL, +}; + +static const struct bt_le_conn_param conn_update_param = { + .interval_min = 6, // 7.5ms + .interval_max = 6, // 7.5ms + .latency = 0x2c, + .timeout = 400, // 4s +}; + +static void connected(struct bt_conn *conn, uint8_t err) +{ + char addr[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + if (err) { + printk("Failed to connect to %s (%u)\n", addr, err); + return; + } + + printk("Connected %s\n", addr); + connected_handle = conn; + + if (bt_conn_set_security(conn, BT_SECURITY_L2)) { + printk("Failed to set security\n"); + } + + ble_status = CON_BEGIN_BLE_STATUS; + + int ret = bt_conn_le_param_update(conn, &conn_update_param); + printk("bt_conn_le_param_update %d\n", ret); +} + +static void disconnected(struct bt_conn *conn, uint8_t reason) +{ + char addr[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + connected_handle = NULL; + printk("Disconnected from %s (reason 0x%02x)\n", addr, reason); + + connect_complete = 0; + + if (user_active_disconnect == MULTI_DEVICE_CHANGE_PIPE_1 || + user_active_disconnect == MULTI_DEVICE_CHANGE_PIPE_2 || + user_active_disconnect == MULTI_DEVICE_CHANGE_PIPE_3 || + user_active_disconnect == MULTI_DEVICE_CHANGE_PIPE_4) { + ble_status = BLE_STATUS_INIT; + start_change_ble_pipe_by_delay_work(); + } else if(user_active_disconnect == MULTI_DEVICE_PAIR_PIPE_1 || + user_active_disconnect == MULTI_DEVICE_PAIR_PIPE_2 || + user_active_disconnect == MULTI_DEVICE_PAIR_PIPE_3 || + user_active_disconnect == MULTI_DEVICE_PAIR_PIPE_4) { + user_active_disconnect = 0; + ble_status = BLE_STATUS_INIT; + start_pairing_by_delay_work(); + } else { + ble_status = IDLE_BLE_STATUS; + } +} + +static void security_changed(struct bt_conn *conn, bt_security_t level, + enum bt_security_err err) +{ + char addr[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + if (!err) { + printk("Security changed: %s level %u\n", addr, level); + if (level >= BT_SECURITY_L2) { + printk("Encryption is complete and sufficient.\\n"); + ble_status = CON_FIRST_SMP_BLE_STATUS; + connect_complete = 1; + need_save_info = 1; + } + } else { + printk("Security failed: %s level %u err %d\n", addr, level, + err); + } +} + +static void le_param_updated(struct bt_conn *conn, uint16_t interval, + uint16_t latency, uint16_t timeout) +{ + printk("LE conn param updated: int 0x%04x lat %d to %d", interval, latency, timeout); + +} + +BT_CONN_CB_DEFINE(conn_callbacks) = { + .connected = connected, + .disconnected = disconnected, + .security_changed = security_changed, + .le_param_updated = le_param_updated, +}; + +static void bt_ready(int err) +{ + if (err) { + printk("Bluetooth init failed (err %d)\n", err); + return; + } + + hog_init(); + + if (IS_ENABLED(CONFIG_SETTINGS)) { + settings_load(); + } + + ble_status = IDLE_BLE_STATUS; + #if 0 + adv_param.id = ble_app_pip_info.mast_id; + printk("Bluetooth initialized id %d\n", adv_param.id); + + ble_addr.a.val[5] = 0xD1 + ble_app_pip_info.mast_id; + LOG_HEXDUMP_INF(ble_addr.a.val, 6, "ble_addr:"); + err = bt_le_adv_start(&adv_param, ad, ARRAY_SIZE(ad), sd, ARRAY_SIZE(sd)); + if (err) { + printk("Advertising failed to start (err %d)\n", err); + return; + } + printk("Advertising successfully started\n"); + #else + + #endif +} + +static void auth_passkey_display(struct bt_conn *conn, unsigned int passkey) +{ + char addr[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + printk("Passkey for %s: %06u\n", addr, passkey); +} + +static void auth_cancel(struct bt_conn *conn) +{ + char addr[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + printk("Pairing cancelled: %s\n", addr); +} + +static struct bt_conn_auth_cb auth_cb_display = { + .passkey_display = NULL, + .passkey_entry = NULL, + .cancel = auth_cancel, +}; + +void start_change_ble_pipe_by_delay_work(void) +{ + int ret = k_work_schedule(&ble_change_pipe_delayed_work, K_MSEC(50)); + if (ret != 1) { + printk("Failed to schedule work. Error code: %d\n", ret); + return; + } +} + +_attribute_ram_code_sec_noinline_ void ble_change_pipe_delayed_work_handler(struct k_work *work) { + + uint8_t pipe = (user_active_disconnect - 1); + + if(pipe != ble_app_pip_info.mast_id) + { + ble_app_pip_info.mast_id = pipe; + // save info when smp complete + //save_ble_app_info(); + bt_le_adv_stop(); + printk("switch to mast_id: %d\r\n", ble_app_pip_info.mast_id); + adv_param.id = ble_app_pip_info.ble_id[ble_app_pip_info.mast_id]; + printk("adv_param id %d\n", adv_param.id); + + ble_status = IDLE_BLE_STATUS; + } +} + + +void start_pairing_by_delay_work(void) +{ + int ret = k_work_schedule(&ble_start_pairing_delayed_work, K_MSEC(50)); + if (ret != 1) { + printk("Failed to schedule pariring work. Error code: %d\n", ret); + return; + } +} + +void ble_start_pairing_delayed_work_handler(struct k_work *work) +{ + int err; + + printk("ble_start_pairing_delayed_work_handler mast id %d\r\n", ble_app_pip_info.mast_id); + + err = bt_le_adv_stop(); + if (err) { + printk("Advertising failed to stop (err %d)\n", err); + return; + } + + ble_app_pip_info.slave_mac_addr[ble_app_pip_info.mast_id]++; + ble_addr.a.val[4] = ble_app_pip_info.slave_mac_addr[ble_app_pip_info.mast_id]; + ble_addr.a.val[5] = 0xD1 + ble_app_pip_info.mast_id; + LOG_HEXDUMP_INF(&ble_addr.a.val[0], 6, "bt id reset new mac:"); + printk("user bt_id_reset %d\n", ble_app_pip_info.ble_id[ble_app_pip_info.mast_id]); + // reset bt id with new address + int new_id = bt_id_reset(ble_app_pip_info.ble_id[ble_app_pip_info.mast_id], &ble_addr, NULL); + if (new_id < 0) { + printk("bt_id_reset (err %d)\n", new_id); + return; + } + printk("bt_id %d_reset success\n", new_id); + ble_app_pip_info.ble_id[ble_app_pip_info.mast_id] = new_id; + adv_param.id = ble_app_pip_info.ble_id[ble_app_pip_info.mast_id]; + printk("adv_param id %d\n", adv_param.id); + + ble_status = IDLE_BLE_STATUS; +} + +void ble_init(void) +{ + int err; + + if (ble_app_pip_info.ble_id[0] == 0xff) { + ble_addr.a.val[4] = 0x00; + ble_addr.a.val[5] = 0xD1; + ble_app_pip_info.ble_id[0] = bt_id_create(&ble_addr, NULL); + printk("New ID created: %d\n", ble_app_pip_info.ble_id[0]); + } else { + ble_addr.a.val[4] = ble_app_pip_info.slave_mac_addr[0]; + ble_addr.a.val[5] = 0xD1; + ble_app_pip_info.ble_id[0] = bt_id_create(&ble_addr, NULL); + printk("ID created: %d\n", ble_app_pip_info.ble_id[0]); + } + + if( ble_app_pip_info.ble_id[1] == 0xff) { + ble_addr.a.val[4] = 0x00; + ble_addr.a.val[5] = 0xD2; + ble_app_pip_info.ble_id[1] = bt_id_create(&ble_addr, NULL); + printk("New ID2 created: %d\n", ble_app_pip_info.ble_id[1]); + } else { + ble_addr.a.val[4] = ble_app_pip_info.slave_mac_addr[1]; + ble_addr.a.val[5] = 0xD2; + ble_app_pip_info.ble_id[1] = bt_id_create(&ble_addr, NULL); + printk("ID created: %d\n", ble_app_pip_info.ble_id[1]); + } + + if( ble_app_pip_info.ble_id[2] == 0xff) { + ble_addr.a.val[4] = 0x00; + ble_addr.a.val[5] = 0xD3; + ble_app_pip_info.ble_id[2] = bt_id_create(&ble_addr, NULL); + printk("New ID3 created: %d\n", ble_app_pip_info.ble_id[2]); + } else { + ble_addr.a.val[4] = ble_app_pip_info.slave_mac_addr[2]; + ble_addr.a.val[5] = 0xD3; + ble_app_pip_info.ble_id[2] = bt_id_create(&ble_addr, NULL); + printk("ID created: %d\n", ble_app_pip_info.ble_id[2]); + } + + if( ble_app_pip_info.ble_id[3] == 0xff) { + ble_addr.a.val[4] = 0x00; + ble_addr.a.val[5] = 0xD4; + ble_app_pip_info.ble_id[3] = bt_id_create(&ble_addr, NULL); + printk("New ID4 created: %d\n", ble_app_pip_info.ble_id[3]); + } else { + ble_addr.a.val[4] = ble_app_pip_info.slave_mac_addr[3]; + ble_addr.a.val[5] = 0xD4; + ble_app_pip_info.ble_id[3] = bt_id_create(&ble_addr, NULL); + printk("ID created: %d\n", ble_app_pip_info.ble_id[3]); + } + + save_ble_app_info(); + + adv_param.id = ble_app_pip_info.ble_id[ble_app_pip_info.mast_id]; + printk("Bluetooth initialized id %d\n", adv_param.id); + + LOG_HEXDUMP_INF(ble_addr.a.val, 6, "ble_addr:"); + + err = bt_enable(bt_ready); + if (err) { + printk("Bluetooth init failed (err %d)\n", err); + return 0; + } + + k_work_init_delayable(&ble_change_pipe_delayed_work, ble_change_pipe_delayed_work_handler); + k_work_init_delayable(&ble_start_pairing_delayed_work, ble_start_pairing_delayed_work_handler); + + #if 0 + if (IS_ENABLED(CONFIG_SAMPLE_BT_USE_AUTHENTICATION)) { + bt_conn_auth_cb_register(&auth_cb_display); + printk("Bluetooth authentication callbacks registered.\n"); + } + #endif +} + +void ble_start_adv(void) +{ + int err; + + err = bt_le_adv_start(&adv_param, ad, ARRAY_SIZE(ad), sd, ARRAY_SIZE(sd)); + if (err) { + printk("Advertising failed to start (err %d)\n", err); + return; + } + + printk("Advertising successfully started\n"); +} + +void disconnect_current_connection(void) +{ + if (connected_handle) { + int err = bt_conn_disconnect(connected_handle, BT_HCI_ERR_REMOTE_USER_TERM_CONN); + if (err) { + printk("disconnect error: %d\n", err); + } else { + printk("disconnect send\n"); + } + } +} + +void save_ble_app_info(void) +{ + int ret = nvs_write(&user_fs, USER_STORAGE_APP_INFO_ID, (uint8_t *)&ble_app_pip_info.slave_mac_addr[0], sizeof(ST_BLE_APP_PIPE_INFO)); + printk("NVS Write result: %d\n", ret); +} + + +void app_ble_report_to_client(void) +{ + unsigned char *p = pp_fifo_get_ptr(&tx_fifo); + int ret = 0; + + if(p!=0) + { + unsigned char cmd = p[1]; + + if(cmd == MOUSE_DATA) + { + //unsigned char ret = blc_atts_sendHandleValueNotify(connected_handle,HID_MOUSE_REPORT_INPUT_DP_H,&p[3],sizeof(t_mouse_data)-1); + } + else if(cmd==NORMAL_KB_DATA_CMD) + { + ret = ble_nortify_keyboard_data(&p[2],8); + } + else if(cmd==CONSUME_KB_DATA_CMD) + { + ret = ble_nortify_keyboard_data(&p[2], 2); + } + else if(cmd==SYSTEM_KB_DATA_CMD) + { + } + else if(cmd==ALL_KB_DATA_CMD) + { + ret = ble_nortify_all_key_data(&p[2], REPORT_ALL_KB_SIZE); + } + if(ret == 0) + { + pp_fifo_pop(&tx_fifo); + } + } +} + +_attribute_ram_code_sec_noinline_ void app_ble_status_proc(void) +{ + static uint32_t led_tick; + static uint8_t led_flag = 0; + static uint32_t interval_led = 1000000; + int err; + static uint32_t adv_tick = 0; + + if(ble_status == CON_OK_BLE_STATUS) + { + app_ble_report_to_client(); + + if(need_save_info) + { + need_save_info = 0; + printk("save info\r\n"); + save_ble_app_info(); + } + } + else if(ble_status == IDLE_BLE_STATUS) + { + connect_complete = 0; + if(need_enter_sleep) + { + //app_enter_sleep(need_enter_sleep); + return; + } + else + { + //start advertising + printk("start adv\r\n"); + ble_start_adv(); + } + adv_tick = k_uptime_get_32(); + + if(pair_flag) + { + ble_status = ADV_PAIR_BLE_STATUS; + printk("pair..\r\n"); + interval_led = 100000; + } + else + { + ble_status = ADV_RECONNECT_BLE_STATUS; + interval_led = 1000000; + printk("reconnect\r\n"); + } + printk("adv\r\n"); + led_tick = k_uptime_get_32(); + led_flag = LED_IS_ON; + } + else if(ble_status == ADV_PAIR_BLE_STATUS) + { + #if APP_PM_ENABLE + if ((k_uptime_get_32() - adv_tick) > PAIR_TIMEOUT_US) + { + err = bt_le_adv_stop(); + if (err) { + printk("Advertising failed to stop (err %d)\n", err); + } + need_enter_sleep = 1; + ble_status = IDLE_BLE_STATUS; + } + #endif + } + else if(ble_status == ADV_RECONNECT_BLE_STATUS) + { + #if APP_PM_ENABLE + if ((k_uptime_get_32() - adv_tick) > RECONN_TIMEOUT_US) + { + err = bt_le_adv_stop(); + if (err) { + printk("Advertising failed to stop (err %d)\n", err); + } + need_enter_sleep = 1; + ble_status = IDLE_BLE_STATUS; + } + #endif + } + else if(connect_complete == 1) + { + led_tick = k_uptime_get_32(); + { + printk("con is ok\r\n"); + ble_status = CON_OK_BLE_STATUS; + #if 0 + gpio_set_level(PAIR_LED_PIN,LED_IS_ON); + #endif + pp_fifo_reset(&tx_fifo); + } + } + + if(connect_complete == 0) + { + #if 0 + if(clock_time_exceed(led_tick, interval_led)) + { + led_tick=clock_time(); + led_flag=1-led_flag; + gpio_set_level(PAIR_LED_PIN,led_flag); + } + #endif + } +} + +_attribute_ram_code_sec_noinline_ void app_ble_main_loop(void) +{ + app_ble_status_proc(); +} \ No newline at end of file diff --git a/samples/bluetooth/peripheral_kmd/src/app_ble.h b/samples/bluetooth/peripheral_kmd/src/app_ble.h new file mode 100644 index 0000000000000..de3514e4dd0e1 --- /dev/null +++ b/samples/bluetooth/peripheral_kmd/src/app_ble.h @@ -0,0 +1,55 @@ +/** @file + * @brief HoG Service sample + */ + +/* + * Copyright (c) 2016 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct +{ + unsigned char slave_mac_addr[4];//4 + int ble_id[4];//20 + uint8_t temp2[3]; //23 + uint8_t mast_id;//24 + int idx;//28 +} ST_BLE_APP_PIPE_INFO; +extern ST_BLE_APP_PIPE_INFO ble_app_pip_info; + +#define PAIR_TIMEOUT_US 60*1000//6s +#define RECONN_TIMEOUT_US 60*1000//60s +#define CON_NO_ACTIVE_TIMEOUT_S 600 * 1000//10min + +typedef enum +{ + BLE_STATUS_INIT=0, + IDLE_BLE_STATUS=1, + ADV_PAIR_BLE_STATUS=2, + ADV_RECONNECT_BLE_STATUS=3, + CON_BEGIN_BLE_STATUS=4, + CON_FIRST_SMP_BLE_STATUS=5, + CON_RECONNECT_SMP_BLE_STATUS=6, + CON_WRITE_CCC_BLE_STATUS=7, + CON_OK_BLE_STATUS=8, + SLEEP_BLE_STATUS=9, + +}BLE_STATUS_APP_ENUM; +extern volatile uint8_t ble_status; +extern uint8_t connect_complete; +extern uint32_t tick_connected; +extern uint8_t pair_flag; + + +void ble_init(void); +void ble_start_pairing_delayed_work_handler(struct k_work *work); +void start_pairing_by_delay_work(void); +void app_ble_report_to_client(void); +#ifdef __cplusplus +} +#endif diff --git a/samples/bluetooth/peripheral_kmd/src/app_common_config.h b/samples/bluetooth/peripheral_kmd/src/app_common_config.h new file mode 100644 index 0000000000000..3439bafc5936c --- /dev/null +++ b/samples/bluetooth/peripheral_kmd/src/app_common_config.h @@ -0,0 +1,245 @@ +/******************************************************************************************************** + * @file app_common_config.h + * + * @brief This is the header file for BLE SDK + * + * @author BLE GROUP + * @date 06,2022 + * + * @par Copyright (c) 2022, Telink Semiconductor (Shanghai) Co., Ltd. ("TELINK") + * + * 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 "config.h" +// //#include "types.h" +// #include "bit.h" + +///////////////////////// flash address Configuration//////////////////////////////////////////////// +#define P24G_OTHER_INF_FLASH_ADDR_1M 0xFE000 //4K +#define P24G_PAIR_INF_FLASH_ADDR_1M 0xFD000 //4K +#define BLE_APP_PIPE_FLASH_ADDR_1M 0xFC000 //4K +#define BLE_APP_SMP_FLASH_ADDR_1M 0xFB000 //4K +#define BLE_STACK_SMP_FLASH_ADDR_1M 0xF7000 //16K 0xF7000~0xFAFFF + +#define P24G_OTHER_INF_FLASH_ADDR_2M 0x1FE000 //4K +#define P24G_PAIR_INF_FLASH_ADDR_2M 0x1FD000 //4K +#define BLE_APP_PIPE_FLASH_ADDR_2M 0x1FC000 //4K +#define BLE_APP_SMP_FLASH_ADDR_2M 0x1FB000 //4K +#define BLE_STACK_SMP_FLASH_ADDR_2M 0x1F7000 //16K 0x3F7000~0x3FAFFF + + +#define P24G_OTHER_INF_FLASH_ADDR_4M 0x3FE000 //4K +#define P24G_PAIR_INF_FLASH_ADDR_4M 0x3FD000 //4K +#define BLE_APP_PIPE_FLASH_ADDR_4M 0x3FC000 //4K +#define BLE_APP_SMP_FLASH_ADDR_4M 0x3FB000 //4K +#define BLE_STACK_SMP_FLASH_ADDR_4M 0x3F7000 //16K 0x3F7000~0x3FAFFF + + +///////////////////////////////////////////////////////////////////////// + +#define TLK_ERR_BASE_NUM (0x0) /**< Global error base */ + +#define TLK_SUCCESS (TLK_ERR_BASE_NUM + 0) /**< Successful command */ +#define TLK_ERR_NULL (TLK_ERR_BASE_NUM + 1) /**< Null pointer */ +#define TLK_ERR_INVALID_PARAM (TLK_ERR_BASE_NUM + 2) /**< Invalid parameter */ +#define TLK_ERR_BUSY (TLK_ERR_BASE_NUM + 3) /**< Device or resourse Busy */ +#define TLK_ERR_INVALID_STATE (TLK_ERR_BASE_NUM + 4) /**< Invalid state, operation disallowed in this state */ +#define TLK_ERR_BUFFER_EMPTY (TLK_ERR_BASE_NUM + 5) /**< Buffer/FIFO is empty */ +#define TLK_ERR_NO_MEM (TLK_ERR_BASE_NUM + 6) /**< No memory available for operation */ +#define TLK_ERR_INVALID_LENGTH (TLK_ERR_BASE_NUM + 7) /**< Invalid length */ +#define TLK_ERR_TIMEOUT (TLK_ERR_BASE_NUM + 8) /**< Operation timed out */ +#define TLK_ERR_INTERNAL (TLK_ERR_BASE_NUM + 9) /**< Internal error */ +#define TLK_ERR_DEV_NOT_FOUND (TLK_ERR_BASE_NUM + 10) /**< Destination device not found */ +#define TLK_ERR_CMD_NOT_SUPPORT (TLK_ERR_BASE_NUM + 11) /**< cmd not supported */ +#define TLK_ERR_BUFFER_FULL (TLK_ERR_BASE_NUM + 12) /**< Buffer/FIFO is full */ + +///////////////////////////////////////////////////////////////////////// + +#define SPP_TX_FIFO_SIZE 32 +#define SPP_TX_FIFO_SIZE_KB 24 //In 8K mode, the spp buffer size cannot exceed 24 on kb side. + +#define MAC_ADDR_LEN 6 //MAC address length + +///////////////////////////////////////////////////////////////////////// +#define TLKAPI_DEBUG_ENABLE 0 + +#define DBG_2P4G_IO_EN 1 //2.4G global gpio debug control +#define STACK_IO_EN 1 //stack +#define APP_IO_EN 1 //app + +#define DBG_GPIO_NOOP() do {} while(0) +#if (DBG_2P4G_IO_EN) + + #define DBG_GPIO_SET_LEVEL(en, pin, level) \ + do { \ + if (en) { \ + gpio_set_level(pin, level); \ + } \ + } while(0) + + + #define DBG_GPIO_TOGGLE(en, pin) \ + do { \ + if (en) { \ + gpio_toggle(pin); \ + } \ + } while(0) + + #define DBG_STACK_GPIO_SET_LEVEL(en, pin, level) \ + do { \ + if (en && (pin)) { \ + gpio_set_level(pin, level); \ + } \ + } while(0) + + #define DBG_STACK_GPIO_TOGGLE(en, pin) \ + do { \ + if (en && (pin)) { \ + gpio_toggle(pin); \ + } \ + } while(0) +#else + + #define DBG_GPIO_SET_LEVEL(en, pin, level) DBG_GPIO_NOOP() + #define DBG_GPIO_TOGGLE(en, pin) DBG_GPIO_NOOP() + #define DBG_STACK_GPIO_SET_LEVEL(en, pin, level) DBG_GPIO_NOOP() + #define DBG_STACK_GPIO_TOGGLE(en, pin) DBG_GPIO_NOOP() +#endif + + + +typedef enum { + KB_MODE_2P4G = 0, + KB_MODE_BLE = 1, + KB_MODE_USB = 2, +} kb_mode_t; + + +typedef enum +{ + STATE_POWERON = 0, + STATE_PAIRING, + STATE_RECONNECT, + STATE_NORMAL, + STATE_CONNECTED, + STATE_DISCONNECTED, + STATE_RF_IDLE, + STATE_PAIRING_TIMEOUT, + STATE_NONE, + STATE_BUSY, + STATE_TO_IDLE, + STATE_IDLE, + STATE_TO_SLEEP, + STATE_SLEEP, + + STATE_PAIR_NONE = 0, + STATE_PAIR_INIT, + STATE_PAIR_RSP, + STATE_PAIR_CFM, + STATE_REJOIN, +} p24g_device_status_e; + +typedef enum { + + P24G_SM_CMD_PAIRING = 0x00, + P24G_SM_CMD_LL_CONTROL, + P24G_SM_CMD_MOUSE_DRAW, + P24G_SM_CMD_SET_STATE, + P24G_SM_CMD_SAVE_PAIR_INFO, + P24G_SM_CMD_SET_KB_MODE, + P24G_SM_CMD_DATA_TYPE_SPP, + P24G_SM_CMD_MISC, + P24G_SM_CMD_REPORT_RATE_CHANGE, + P24G_SM_CMD_MAX, + P24G_SM_CMD_NONE = 0xFF, + +} p24g_sm_cmd_e; + +typedef enum { + P24G_SM_OP_NONE = 0x00, + P24G_SM_OP_TERMINATE_CONN = 0x51, + P24G_SM_OP_ENTER_RF_IDLE = 0x52, + P24G_SM_OP_MISC_TRANS_MAC = 0x53, + P24G_SM_OP_MISC_PEER_INFO = 0x54, + P24G_SM_OP_ENABLE_RECONN = 0x55, + P24G_SM_OP_MISC_STOP_STIMER = 0x56, + P24G_SM_OP_MISC_REPORT_RATE = 0x57, + P24G_SM_OP_MISC_SAVE_REPORT_RATE = 0x58, + P24G_SM_OP_MISC_RF_MODE = 0x59, + P24G_SM_OP_MISC_SUSP_RET = 0x5A, + P24G_SM_OP_MISC_LONG_SUSP_RET = 0x5B, +} p24g_sm_op_e; + + +typedef enum +{ + P24G_SPP_NONE = 0x60, + P24G_SPP_LED_STATUS = 0x61, + P24G_SPP_REPORT_RATE = 0x62, + P24G_SPP_BATT_CAP = 0x63, + P24G_SPP_CHG_STATUS = 0x64, + P24G_SPP_TEST_DATA = 0x65, + P24G_SPP_ALL_KEY_DATA = 0x66, + P24G_SPP_CONSUME_KEY_DATA = 0x67, +} p24g_spp_cmd_e; + + +typedef enum +{ + P24G_LL_CMD_NONE = 0x70, + P24G_LL_CMD_TERMINATE_CONN = 0x71, + P24G_LL_CMD_TERMINATE_CONN_RSP = 0x72, + P24G_LL_CMD_8K_RR_ADAPT = 0x73, + P24G_LL_CMD_8K_RR_ADAPT_RSP = 0x74, +} p24g_ll_cmd_e; + + +typedef enum { + P24G_KB_MODE_USB = 0x00, + P24G_KB_MODE_2P4G = 0x01, + + P24G_FLOW_SN = 0x01, + P24G_FLOW_NESN = 0x02, + + P24G_LL_CONN_TIMEOUT = 0x01, + P24G_LL_CONN_TERMINATION_BY_PEER = 0x02, + P24G_LL_CONN_TERMINATION_BY_LOCAL = 0x03, + + P24G_8K_KM_SLOT = 0x00, + P24G_8K_SPP_SLOT = 0x01, + P24G_8K_SLOT_POS = 0x03, + + DEVICE_TYPE_KB = BIT(0), + DEVICE_TYPE_MS = BIT(1), + +}; + +typedef enum +{ + REPORT_RATE_8K = BIT(7), + REPORT_RATE_4K = BIT(0), + REPORT_RATE_2K = BIT(1), + REPORT_RATE_1K = BIT(2), + REPORT_RATE_500 = BIT(3), + REPORT_RATE_250 = BIT(4), + REPORT_RATE_125 = BIT(5), + + RR_8K_HIGH = 0, + RR_8K_LOW = 1, + REPORT_RATE_8K_MODE_LOW = REPORT_RATE_500, + REPORT_RATE_8K_MODE_HIGH = REPORT_RATE_8K, +} report_rate_t; + + diff --git a/samples/bluetooth/peripheral_kmd/src/app_config.h b/samples/bluetooth/peripheral_kmd/src/app_config.h new file mode 100644 index 0000000000000..eaff026a440d7 --- /dev/null +++ b/samples/bluetooth/peripheral_kmd/src/app_config.h @@ -0,0 +1,54 @@ +/** @file + * @brief HoG Service sample + */ + +/* + * Copyright (c) 2016 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifdef __cplusplus +extern "C" { +#endif + +///////////////////////// BOARD TYPE SELECT //////////////////////////////// +#define HW_PRJ_KEYBOARD 1 //8*16 analog keyboard +#define HW_DIGIT_KEYBOARD 2 //digit keyboard + +#define HW_BOARD_TYPE HW_DIGIT_KEYBOARD + +#define HW_EVK_BOARD 0 + +#if (HW_BOARD_TYPE == HW_PRJ_KEYBOARD ) + #define ALLOW_SWITCH_BLE_2P4G_MODE 1 + #define DIGIT_KEYSCAN_FUN_ENABL 0 + #define ALG_KEYSCAN_APP_FUN_ENABLE 1 + #define USB_APP_FUN_ENABLE 1 +#elif(HW_BOARD_TYPE== HW_DIGIT_KEYBOARD) + #define ALLOW_SWITCH_BLE_2P4G_MODE 0 + #define DIGIT_KEYSCAN_FUN_ENABL 1 + #define ALG_KEYSCAN_APP_FUN_ENABLE 0 + #define USB_APP_FUN_ENABLE 1 + #define HARDWARE_MODULE_SCAN_ENABLE 1 + + #define CAP_LED_PIN GPIO_NONE_PIN//GPIO_PB4 + #define NUM_LED_PIN GPIO_NONE_PIN//GPIO_PB5 + #define MODE_LED_PIN GPIO_NONE_PIN//GPIO_PH1 + #define PAIR_LED_PIN GPIO_NONE_PIN//GPIO_PG7 + + #define VBUS_5V_CHECK_PIN GPIO_PC1 + #define VBUS_5V_CHECK_PIN_USB_IN_LEVEL 1 +#endif + +#define APP_PM_ENABLE 0 + +#define BATT_CHECK_ENABLE 0 + +#define TOGGLE_DEBUG_IO_ENABLE 0 +#define USE_K_TIMER_LOOP 1 +#define USER_K_TIMER_SCAN_LOOP_INTERVAL_MS 50 //50ms + +#ifdef __cplusplus +} +#endif diff --git a/samples/bluetooth/peripheral_kmd/src/app_kb_matrix.c b/samples/bluetooth/peripheral_kmd/src/app_kb_matrix.c new file mode 100644 index 0000000000000..16b25852fc425 --- /dev/null +++ b/samples/bluetooth/peripheral_kmd/src/app_kb_matrix.c @@ -0,0 +1,409 @@ +/* main.c - Application main entry point */ + +/* + * Copyright (c) 2016 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include "app_public.h" +#include "compiler.h" + +#include "keyscan.h" +#include "keyscan.c" + +#define LOG_LEVEL LOG_LEVEL_DBG +#include +LOG_MODULE_REGISTER(kb_matrix); + + +#if DIGIT_KEYSCAN_FUN_ENABL + +#define ROW_CNT 6 +#define COL_CNT 20 + +unsigned char map_digit[COL_CNT][ROW_CNT] = {\ +/*C00*/{KB_Esc, KB_dunhao, KB_Tab, KB_Caps, KB_LShift, KB_LCtrl },\ +/*C01*/{KB_F1, KB_1, KB_Q, KB_A, 0, KB_LAlt },\ +/*C02*/{KB_F2, KB_2, KB_W, KB_S, KB_Z, KB_LWin },\ +/*C03*/{KB_F3, KB_3, KB_E, KB_D, KB_X, 0 },\ +/*C04*/{KB_F4, KB_4, KB_R, KB_F, KB_C, 0 },\ +/*C05*/{KB_F5, KB_5, KB_T, KB_G, KB_V, 0 },\ +/*C06*/{KB_F6, KB_6, KB_Y, KB_H, KB_B, KB_Space },\ +/*C07*/{KB_F7, KB_7, KB_U, KB_J, KB_N, 0 },\ +/*C08*/{KB_F8, KB_8, KB_I, KB_K, KB_M, 0 },\ +/*C09*/{KB_F9, KB_9, KB_O, KB_L, KB_douhao, 0 },\ +/*C10*/{KB_F10, KB_0, KB_P, KB_fenhao, KB_juhao, KB_RWin },\ +/*C11*/{KB_F11, KB_jianhao, KB_Lguohao, KB_yinhao, KB_wenhao, KB_RAlt },\ +/*C12*/{KB_F12, KB_denghao, KB_Rguohao, KB_Enter, KB_RShift, T_FN },\ +/*C13*/{KB_F13, KB_Back, KB_xiegang, 0, 0, KB_RCtrl },\ +/*C14*/{KB_F14, KB_Insert, KB_Delete, KP_jiahao, 0, KB_Left },\ +/*C15*/{KB_F15, KB_Home, KB_End, KP_jianhao, KB_Up, KB_Down },\ +/*C16*/{KB_F16, KB_PgUp, KB_PgDown, KB_F20, 0, KB_Right },\ +/*C17*/{KB_F17, KB_Num, KP_7, KP_4, KP_1, KP_0 },\ +/*C18*/{KB_F18, KP_chuhao, KP_8, KP_5, KP_2, KP_enter },\ +/*C19*/{KB_F19, KP_chenghao, KP_9, KP_6, KP_3, KP_Del },\ + /*R0*/ +}; + + + +static unsigned int last_result[ROW_CNT]={0}; +static unsigned int debug_result[ROW_CNT]={0}; + +static KEY_MATRIX_DEFINE(key_matrix); + +// 全局变量 +static struct k_timer scan_timer; +static bool scanning_active = false; + + +static unsigned int last_scan_result = 0; +static unsigned int flag_count = 0; +int debounce_cnt = 0; +static uint32_t key_change_tick = 0; +static unsigned char need_debounce_flag=0; + +#if HARDWARE_MODULE_SCAN_ENABLE //digit hardware module key scan + + +unsigned char g_ks_row[ROW_CNT] = {KS_PE2, KS_PE1, KS_PE0, KS_PD6, KS_PD4, KS_PD5}; +unsigned char g_ks_col[COL_CNT] = {KS_PE6, KS_PE7, KS_PA0, KS_PA1, KS_PA2,KS_PC6, KS_PC7,KS_PG0, KS_PF7, KS_PF6, KS_PF5, KS_PF4, KS_PB1,KS_PB0, KS_PC4,KS_PC3,KS_PD2,KS_PG1,KS_PG2,KS_PH0}; +unsigned char g_ks_col_map_position[32]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + +#define DMA_SIZE (8 * 4) + +unsigned int dma_ks_scanning_buff[8] ={0}; +unsigned int last_ks_scanning_buff[8] ={0}; +unsigned int now_ks_scanning_buff[8] ={0}; + +void digit_keyscan_init(void) +{ + for(int i = 0; i < COL_CNT; i++) + { + g_ks_col_map_position[g_ks_col[i]&0x1f] = i; + } + keyscan_set_martix(g_ks_row, ROW_CNT, g_ks_col, COL_CNT, KS_INT_PIN_PULLUP); + + keyscan_init_clk_24m(KEYSCAN_8K,KS_24MXTAL,1); + keyscan_dma_enable(); + + dma_set_llp_sof_mode(DMA4, 1); + keyscan_dma_config_llp(DMA4, dma_ks_scanning_buff, DMA_SIZE); + keyscan_set_scan_mode(KEYSCAN_MODE1); + + keyscan_enable(); + printk("digit hw keyscan init\r\n"); + + #if (USE_K_TIMER_SCAN_MATRIX) + k_timer_start(&scan_timer, K_MSEC(SCAN_INTERVAL_MS), + K_MSEC(SCAN_INTERVAL_MS)); + #else + user_timer_init(); + #endif +} + + +_attribute_ram_code_sec_noinline_ void digit_new_key_handle(void) +{ + app_key_buf.press_cnt=0; + app_key_buf.cnt=0; + app_key_buf.special_key_press_f=0; + for(int i=0;i= 5) + { + need_debounce_flag = 0; + } + else + { + return; + } + } + + for(int i = 0; i < ROW_CNT; i++) + { + if(last_ks_scanning_buff[i] != now_ks_scanning_buff[i]) + { + has_new_evnt_flag = 1; + last_ks_scanning_buff[i]=now_ks_scanning_buff[i]; + } + } + + if(has_new_evnt_flag) + { + key_change_tick = k_uptime_get_32(); + if(need_debounce_flag == 0) + { + debounce_cnt = 2; + } + else + { + debounce_cnt = 1; + } + need_debounce_flag = 1 - need_debounce_flag; + } + + if(debounce_cnt) + { + debounce_cnt++; + if(debounce_cnt >= 3) + { + debounce_cnt = 0; + digit_new_key_handle(); + } + } +} + +#else + +void digit_keyscan_init(void) +{ + // 初始化按键扫描 + if (matrix_keypad_init() != 0) { + LOG_ERR("Failed to initialize keypad\n"); + return; + } + +#if (USE_K_TIMER_SCAN_MATRIX) + k_timer_start(&scan_timer, K_MSEC(SCAN_INTERVAL_MS), + K_MSEC(SCAN_INTERVAL_MS)); +#else + user_timer_init(); +#endif + + LOG_INF("Matrix keyscan init\n"); +} + +_attribute_ram_code_sec_noinline_ void digit_new_key_handle(void) +{ + unsigned int now_bit = 0; + app_key_buf.press_cnt = 0; + + app_key_buf.cnt = 0; + app_key_buf.special_key_press_f = 0; + + for(int i = 0; i < ROW_CNT; i++) + { + for(int k = 0; k < COL_CNT; k++) + { + now_bit = last_result[i]&(1<= 1) + { + need_debounce_flag = 0; + } + else + { + return; + } + } + + unsigned int has_new_evnt_flag = digit_key_soft_scan(); + + if(has_new_evnt_flag) + { + key_change_tick = k_uptime_get_32(); + if(need_debounce_flag == 0) + { + debounce_cnt = 2; + } + else + { + debounce_cnt = 1; + } + need_debounce_flag = 1 - need_debounce_flag; + } + + if(debounce_cnt) + { + debounce_cnt++; + if(debounce_cnt >= 4) + { + debounce_cnt = 0; + digit_new_key_handle(); + } + } +} + +_attribute_ram_code_sec_noinline_ unsigned int get_scan_gpio_value(void) +{ + unsigned int value = 0; + + for(int col = 0; col < COL_CNT; col++) + { + if(gpio_pin_get_dt(&key_matrix.col[col]) == 0) + { + BIT_SET(value, col); + } + } + return value; +} + +_attribute_ram_code_sec_noinline_ unsigned int digit_key_soft_scan(void) +{ + unsigned int scan_result = 0; + unsigned int has_key_change = 0; + + scan_result = get_scan_gpio_value();//50us + + flag_count++; + if (last_scan_result != scan_result) + { + last_scan_result = scan_result; + flag_count=0; + } + if ((flag_count > 2) && (scan_result == 0)) + { + flag_count = 0X3F; + return 0; + } + + for(int i = 0; i < ROW_CNT; i++) + { + gpio_pin_set_dt(&key_matrix.row[i], 1); + } + + for(int i = 0; i < ROW_CNT; i++) + { + gpio_pin_set_dt(&key_matrix.row[i], 0); + k_busy_wait(10);//96M 5us 192M 1.2us + scan_result = get_scan_gpio_value(); + + gpio_pin_set_dt(&key_matrix.row[i], 1); + if(last_result[i] != scan_result) + { + last_result[i] = scan_result; + has_key_change = 1; + } + } + + for(int i = 0; i < ROW_CNT; i++) + { + gpio_pin_set_dt(&key_matrix.row[i], 0); + } + return has_key_change; +} + + +// 初始化按键扫描 +int matrix_keypad_init(void) +{ + int ret; + + // 检查GPIO设备是否就绪 + for (int i = 0; i < ROW_CNT; i++) { + if (!gpio_is_ready_dt(&key_matrix.row[i])) { + LOG_ERR("Row GPIO %d not ready", i); + return -ENODEV; + } + } + + for (int i = 0; i < COL_CNT; i++) { + if (!gpio_is_ready_dt(&key_matrix.col[i])) { + LOG_ERR("Col GPIO %d not ready", i); + return -ENODEV; + } + } + + // 配置行GPIO为输出 + for (int i = 0; i < ROW_CNT; i++) { + ret = gpio_pin_configure_dt(&key_matrix.row[i], GPIO_OUTPUT_ACTIVE); + if (ret < 0) { + LOG_ERR("Failed to configure row GPIO %d: %d", i, ret); + return ret; + } + gpio_pin_set_dt(&key_matrix.row[i], 0); + } + + // 配置列GPIO为输入,带上拉 + for (int i = 0; i < COL_CNT; i++) { + ret = gpio_pin_configure_dt(&key_matrix.col[i], + GPIO_INPUT | GPIO_PULL_UP); + if (ret < 0) { + LOG_ERR("Failed to configure col GPIO %d: %d", i, ret); + return ret; + } + gpio_pin_set_dt(&key_matrix.row[i], 1); + } + +#if (USE_K_TIMER_SCAN_MATRIX) + // 初始化定时器 + k_timer_init(&scan_timer, keyscan_loop, NULL); +#endif + + LOG_INF("Matrix keypad initialized"); + return 0; +} +#endif +#endif diff --git a/samples/bluetooth/peripheral_kmd/src/app_kb_matrix.h b/samples/bluetooth/peripheral_kmd/src/app_kb_matrix.h new file mode 100644 index 0000000000000..ae9327d50d12a --- /dev/null +++ b/samples/bluetooth/peripheral_kmd/src/app_kb_matrix.h @@ -0,0 +1,333 @@ +/** @file + * @brief HoG Service sample + */ + +/* + * Copyright (c) 2016 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +//keyboard vaule + + +#define T_FN 0xff +#define KB_WIN_LOCK 0x01 + +#define KB_A 0x04 +#define KB_B 0x05 +#define KB_C 0x06//6 +#define KB_D 0x07//7 +#define KB_E 0x08//8 +#define KB_F 0x09//9 +#define KB_G 0x0a//10 +#define KB_H 0x0b//11 +#define KB_I 0x0c//12 +#define KB_J 0x0d//13 +#define KB_K 0x0e//14 +#define KB_L 0x0f//15 +#define KB_M 0x10//16 +#define KB_N 0x11//17 +#define KB_O 0x12//18 +#define KB_P 0x13//19 +#define KB_Q 0x14//20 +#define KB_R 0x15//21 +#define KB_S 0x16//22 +#define KB_T 0x17//23 +#define KB_U 0x18//24 +#define KB_V 0x19//25 +#define KB_W 0x1a//26 +#define KB_X 0x1b//27 +#define KB_Y 0x1c//28 +#define KB_Z 0x1d//29 +#define KB_1 0x1e//30 +#define KB_2 0x1f//31 +#define KB_3 0x20//32 +#define KB_4 0x21//33 +#define KB_5 0x22//34 +#define KB_6 0x23//35 +#define KB_7 0x24//36 +#define KB_8 0x25//37 +#define KB_9 0x26//38 +#define KB_0 0x27//39 +#define KB_Enter 0x28//40 +#define KB_Esc 0x29//41 +#define KB_Back 0x2a//42 +#define KB_Tab 0x2b//43 +#define KB_Space 0x2c//44 +#define KB_jianhao 0x2d//45//-_jianhao +#define KB_denghao 0x2e//46//+= denghao +#define KB_Lguohao 0x2f//47//{[ +#define KB_Rguohao 0x30//48//}] +#define KB_xiegang 0x31//49//|\ xiegang +#define KB_K42 0x32//50 +#define KB_fenhao 0x33//51//:; fen hao +#define KB_yinhao 0x34//52//" ' yin hao +#define KB_dunhao 0x35//53//~`dun hao +#define KB_douhao 0x36//54 //<, +#define KB_juhao 0x37//55 //>. +#define KB_wenhao 0x38//56//?/ +#define KB_Caps 0x39//57 +#define KB_F1 0x3a//58 +#define KB_F2 0x3b//59 +#define KB_F3 0x3c//60 +#define KB_F4 0x3d//61 +#define KB_F5 0x3e//62 +#define KB_F6 0x3f//63 +#define KB_F7 0x40//64 +#define KB_F8 0x41//65 +#define KB_F9 0x42//66 +#define KB_F10 0x43//67 +#define KB_F11 0x44//68 +#define KB_F12 0x45//69 + +#define KB_PrtSc 0x46//70 +#define KB_Scroll 0x47//71 +#define KB_Pause 0x48//72//Pause_Break +#define KB_Insert 0x49//73 +#define KB_Home 0x4a//74 +#define KB_PgUp 0x4b//75//page up +#define KB_Delete 0x4c//76 +#define KB_End 0x4d//77 +#define KB_PgDown 0x4e//78//page down +#define KB_Right 0x4f//79 +#define KB_Left 0x50//80 +#define KB_Down 0x51//81 +#define KB_Up 0x52//82 +#define KB_Num 0x53//83 +#define KP_chuhao 0x54//84 +#define KP_chenghao 0x55//85 +#define KP_jianhao 0x56//86 +#define KP_jiahao 0x57//87 +#define KP_enter 0x58//88 +#define KP_1 0x59//89 +#define KP_2 0x5a//90 +#define KP_3 0x5b//91 +#define KP_4 0x5c//92 +#define KP_5 0x5d//93 +#define KP_6 0x5e//94 +#define KP_7 0x5f//95 +#define KP_8 0x60//96 +#define KP_9 0x61//97 +#define KP_0 0x62//98 +#define KP_Del 0x63//99 +#define KB_K45 0x64//100 +#define KB_APP 0x65//101 +#define KB_Power 0x66//102 +#define KP_Equal 0x67//103 +#define KB_F13 0x68//104 +#define KB_F14 0x69//105 +#define KB_F15 0x6a//106 +#define KB_F16 0x6b//107 +#define KB_F17 0x6c//108 +#define KB_F18 0x6d//109 + +#define KB_F19 0x6e//110 +#define KB_F20 0x6f//111 +#define KB_F21 0x70//112 +#define KB_F22 0x71//113 +#define KB_F23 0x72//114 +#define KB_F24 0x73//115 + + +#define KB_K107 0x85//133 +#define KB_K56 0x87//135 +#define KB_K133 0x88//136 +#define KB_K14 0x89//137 +#define KB_K132 0x8a//138 +#define KB_K131 0x8b//139 +#define KB_K150 0x90//144 +#define KB_K151 0x91//145 + +#define KB_LCtrl 0xE0 +#define KB_LShift 0xE1 +#define KB_LAlt 0xE2 +#define KB_LWin 0xE3 +#define KB_RCtrl 0xE4 +#define KB_RShift 0xE5 +#define KB_RAlt 0xE6 +#define KB_RWin 0xE7 + + +#define S_SLEEP 0xa0 +#define S_POWER 0xa1 +#define S_WAKEUP 0xa2 + +#define C_INDEX_START 0xa3 +#define C_wSearch 0xa3//www search +#define C_wHome 0xa4 +#define C_wBack 0xa5 +#define C_wForward 0xa6 +#define C_wStop 0xa7 +#define C_wRefresh 0xa8 +#define C_wFavorite 0xa9 +#define C_Media 0xaa +#define C_email 0xab +#define C_calculator 0xac +#define C_computer 0xad +#define C_nextTrace 0xae +#define C_prevTrace 0xaf +#define C_stop 0xb0 +#define C_Play 0xb1 +#define C_mute 0xb2 +#define C_volUP 0xb3 +#define C_volDown 0xb4 +#define C_TELINK 0xb5 +#define C_zoomIn 0xb6 +#define C_zoomOUT 0xb7 +#define C_panLeft 0xb8 +#define C_panRight 0xb9 +#define C_brightUp 0xba +#define C_brightDn 0xbb +#define C_RJECT 0Xbc +#define C_POWER 0xBD +#define C_terminalLock 0xBE + +#define C_INDEX_END 0xBe + +#define MS_CPI 0xc0 +#define MS_LEFT 0xc1 +#define MS_RIGHT 0xc2 +#define MS_MIDDLE 0xc3 +#define MS_K4 0xc4 +#define MS_K5 0xc5 +#define MS_WUP 0xc6//wheel up +#define MS_WDOWN 0xc7// wheel dowm + +#if 0 +#define T_INDEX_START 0xc8 + +#define T_Power 0xc8 +#define T_bind 0xc9 +#define T_Keyobard 0xca +#define T_lock 0xcb +#define T_brightUP 0xcc +#define T_brightDN 0xcd +#define T_languageC 0xce +#define T_copy 0xcf +#define T_paste 0xd0 +#define T_shear 0xd1 +#define T_Phone 0xd2 +#define T_PrtSc 0xd3 +#define T_BackLight 0XD4 +#define T_TaskManager 0xd5 +#define KB_ALT_NBS 0xd6 +#define KB_SHIFT_NBS 0xd7 +#define T_INDEX_END 0xd7 + +#define J_start 0xdd +#define J_back 0xde +#define J_select 0xdf +#define J_A 0xf0 +#define J_B 0xf1 +#define J_X 0xf2 +#define J_Y 0xf3 +#define J_HAT_LEFT 0xf4 +#define J_HAT_RIGH 0xf5 +#define J_HAT_UP 0xf6 +#define J_HAT_RIGHT 0xf7 +#define J_L1 0xf8 +#define J_R1 0xf9 +#define J_L2 0xfa +#define J_R2 0xfb +#define J_L3 0xfc +#define J_R3 0xfd +#define J_HOME 0xfe +#endif +/////////////////////////////////////////////////////////////////////////////////////////// +/* 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))]) {}, \ + } + + + +void digital_keyscan_init(void); + + +//////////////////////////////////////////K_timer scan/////////////////////////////////////////// + + +#define SCAN_INTERVAL_MS 1 // 扫描间隔5ms +#define DEBOUNCE_COUNT 1 // 消抖计数4次(20ms) + +#define USE_K_TIMER_SCAN_MATRIX 0 + + +// 按键回调函数类型 +typedef void (*key_callback_t)(uint8_t row, uint8_t col); + +// 按键扫描初始化 +int matrix_keypad_init(void); +// 启动按键扫描 +int matrix_keypad_start(void); +// 停止按键扫描 +void matrix_keypad_stop(void); +void digit_keyscan_handle(void); +_attribute_ram_code_sec_noinline_ unsigned int digit_key_soft_scan(void); +#ifdef __cplusplus +} +#endif diff --git a/samples/bluetooth/peripheral_kmd/src/app_public.c b/samples/bluetooth/peripheral_kmd/src/app_public.c new file mode 100644 index 0000000000000..68a042f11739d --- /dev/null +++ b/samples/bluetooth/peripheral_kmd/src/app_public.c @@ -0,0 +1,1131 @@ +/* app_public.c - Application main entry point */ + +/* + * Copyright (c) 2016 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + + +#include "timer.c" +#include "app_public.h" +#include +#include "drivers.h" +#include "stack/ble/ble.h" + + +#define LOG_LEVEL LOG_LEVEL_DBG +#include +LOG_MODULE_REGISTER(app_public); + +volatile unsigned char fun_mode = 0; +static unsigned char last_fun_mode = 1; +unsigned char mode_pin_level = 0; + +unsigned char g_report_rate_pin_level=0; +static unsigned char g_last_report_rate_pin_level=0; + +extern struct bt_conn *connected_handle; +volatile uint32_t user_active_disconnect = 0; + +//ZH_TODO +ST_FLASH_DEV_INFO flash_dev_info __attribute__ ((aligned (4))); +int dev_info_idx; + +ST_FLASH_DEV_OTHER_INFO flash_dev_other_info __attribute__ ((aligned (4))); +int dev_other_info_idx; + +#if (HW_EVK_BOARD == 1) +_attribute_data_retention_ uint32_t flash_sector_2p4_inf=P24G_PAIR_INF_FLASH_ADDR_4M; +_attribute_data_retention_ uint32_t flash_sector_2p4_other_inf=P24G_OTHER_INF_FLASH_ADDR_4M; +#else +_attribute_data_retention_ uint32_t flash_sector_2p4_inf=P24G_PAIR_INF_FLASH_ADDR_2M; +_attribute_data_retention_ uint32_t flash_sector_2p4_other_inf=P24G_OTHER_INF_FLASH_ADDR_2M; +#endif +// _attribute_data_retention_ u32 flash_sector_ble_app_smp=BLE_APP_SMP_FLASH_ADDR_1M ; +// _attribute_data_retention_ u32 flash_sector_ble_app_pipe=BLE_APP_PIPE_FLASH_ADDR_1M; +// + +#if TOGGLE_DEBUG_IO_ENABLE +struct gpio_dt_spec toggle_pin = GPIO_DT_SPEC_GET_OR(DT_ALIAS(toggle4), gpios, {0}); +struct gpio_dt_spec toggle_pin_b5 = GPIO_DT_SPEC_GET_OR(DT_ALIAS(toggle5), gpios, {0}); +#endif + +#if (HW_BOARD_TYPE == HW_PRJ_KEYBOARD ) + struct gpio_dt_spec vbus_check_pin = GPIO_DT_SPEC_GET_OR(DT_ALIAS(vbuscheck0), gpios, {0}); + struct gpio_dt_spec mode_slect_pin = GPIO_DT_SPEC_GET_OR(DT_ALIAS(modeslect0), gpios, {0}); +#elif(HW_BOARD_TYPE== HW_DIGIT_KEYBOARD) + struct gpio_dt_spec vbus_check_pin = GPIO_DT_SPEC_GET_OR(DT_ALIAS(vbuscheck0), gpios, {0}); + struct gpio_dt_spec mode_2p4_pin = GPIO_DT_SPEC_GET_OR(DT_ALIAS(mode2p4), gpios, {0}); + struct gpio_dt_spec mode_ble_pin = GPIO_DT_SPEC_GET_OR(DT_ALIAS(modeble), gpios, {0}); +#endif + + +/* 定义NVS使用的Flash存储分区 */ +#define NVS_USER_PARTITION user_app_partition +#define NVS_PARTITION_DEVICE FIXED_PARTITION_DEVICE(NVS_USER_PARTITION) +#define NVS_PARTITION_OFFSET FIXED_PARTITION_OFFSET(NVS_USER_PARTITION) +/* NVS扇区大小,需与Flash的擦除页大小匹配 */ +#define NVS_SECTOR_SIZE (4096) +/* NVS扇区数量 */ +#define NVS_SECTOR_COUNT (2) +/* 定义NVS实例 */ +struct nvs_fs user_fs; + +static struct k_spinlock pool_lock; + +_attribute_ram_code_sec_ void pp_fifo_reset (pl_fifo_t *f) +{ + k_spinlock_key_t key = k_spin_lock(&pool_lock); + f->wptr = 0; + f->rptr = 0; + k_spin_unlock(&pool_lock, key); +} + +_attribute_ram_code_sec_ int pp_fifo_push(pl_fifo_t *f,unsigned char cmd,unsigned char *buf, unsigned char len) +{ + k_spinlock_key_t key = k_spin_lock(&pool_lock); + if(len>(f->size-2)) + { + k_spin_unlock(&pool_lock, key); + return TLK_ERR_INVALID_LENGTH; + } + if (((f->wptr - f->rptr) & 255) <(f->num-1)) + { + unsigned char *pd =(unsigned char*) (f->p + (f->wptr& (f->num-1)) * f->size); + + pd[0] = len; + pd[1]=cmd; + memcpy (&pd[2], &buf[0], len); + + f->wptr++; + k_spin_unlock(&pool_lock, key); + return TLK_SUCCESS; + } + k_spin_unlock(&pool_lock, key); + return TLK_ERR_BUFFER_FULL; +} + +_attribute_ram_code_sec_ unsigned char *pp_fifo_get_ptr (pl_fifo_t *f) +{ + k_spinlock_key_t key = k_spin_lock(&pool_lock); + if (f->rptr != f->wptr) + { + unsigned char *p = f->p + (f->rptr & (f->num-1)) * f->size; + k_spin_unlock(&pool_lock, key); + return p; + } + k_spin_unlock(&pool_lock, key); + return 0; +} + + +_attribute_ram_code_sec_ unsigned short pp_fifo_get_num(pl_fifo_t *f) +{ + k_spinlock_key_t key = k_spin_lock(&pool_lock); + unsigned short num =(f->wptr - f->rptr) & 255; + k_spin_unlock(&pool_lock, key); + return num; +} + +_attribute_ram_code_sec_ void pp_fifo_pop(pl_fifo_t *f) + { + k_spinlock_key_t key = k_spin_lock(&pool_lock); + f->rptr++; + k_spin_unlock(&pool_lock, key); + } + + +unsigned short consumer_list[]={ +0x221, //0xa3 C_WWW_SEARCH +0x223, //0xa4 C_WWW_HOME +0x224, //0xa5 C_WWW_BACKWARD +0x225, //0xa6 C_WWW_FORWARD +0x226, //0xa7 C_WWW_STOP +0x227, //0xa8 C_WWW_REFRESH +0x22A, //0xa9 C_MY_FAVORITE +0x183, //0xaa C_MEDIA_SELECT + +0x18A, //0xab C_EMAIL +0x192, //0xac C_CALCULATOR +0x194, //0xad C_MY_COMPUTER +0xB5, //0xae C_NEXT_TRACK +0xB6, //0xaf C_PRE_TRACK +0xB7, //0xb0 C_STOP +0xCD, //0xb1 C_PLAY_PAUSE +0xE2, //0xb2 C_MUTE + +0xE9, //0xb3 C_VOL_INC +0xEA, //0xb4 C_VOL_DEC +0x00, //0xb5 telink Զ ?? +0x22D, //0xb6 USAGE ZOOM IN +0x22E, //0xb7 USAGE ZOOM OUT +0x236, //0xb8 USAGE PAN LEFT +0x237, //0xb9 USAGE PAN RIGHT +0x30B, //0xba C_BRIGHT_INC + +0x30A, //0xbb C_BRIGHT_DEC +0xB8, //0Xbc c_rject +0x30, //0Xbd C_POWER +0x19E, //0Xbe C_TERMINAL_LOCK +}; + +#define KB_TX_FIFO_SIZE 24 +#define KB_TX_FIFO_NUM 8 + +__aligned(4) unsigned char buf_txfifo[40*8]; +pl_fifo_t tx_fifo={ + .size=40, + .num=8, + .wptr=0, + .rptr=0, + .p=buf_txfifo, + }; + +__aligned(4) unsigned char kb_buf_txfifo[KB_TX_FIFO_SIZE * KB_TX_FIFO_NUM]; +pl_fifo_t d25fKbTxFifo = { + .size = KB_TX_FIFO_SIZE, + .num = KB_TX_FIFO_NUM, + .wptr = 0, + .rptr = 0, + .p = kb_buf_txfifo, +}; + +#define SPP_TX_FIFO_NUM 8 +_attribute_aligned_(4) unsigned char spp_buf_txfifo[SPP_TX_FIFO_SIZE_KB * SPP_TX_FIFO_NUM]; +pl_fifo_t d25fSppTxFifo = { + .size = SPP_TX_FIFO_SIZE_KB, + .num = SPP_TX_FIFO_NUM, + .wptr = 0, + .rptr = 0, + .p = spp_buf_txfifo, +}; + + +app_kb_data_t app_key_buf; +unsigned char fn_flag = 0; + + +/* Timer0 interrupt handler */ +_attribute_ram_code_sec_ void timer0_isr(void) +{ + if (timer_get_irq_status(FLD_TMR0_MODE_IRQ)){ + timer_clr_irq_status(FLD_TMR0_MODE_IRQ); //Clear IRQ status + + keyscan_loop(); + } +} + +void user_timer_init(void) +{ + /* Timer0 configuration */ + timer_set_init_tick(TIMER0, 0); + timer_set_cap_tick(TIMER0, 125 * sys_clk.pclk * 1); //125uS + timer_set_mode(TIMER0, TIMER_MODE_SYSCLK); + timer_set_irq_mask(FLD_TMR0_MODE_IRQ); + IRQ_CONNECT(CONFIG_2ND_LVL_ISR_TBL_OFFSET + IRQ_TIMER0, 2, timer0_isr, 0, 0); + riscv_plic_set_priority(IRQ_TIMER0, 3); + riscv_plic_irq_enable(IRQ_TIMER0); + + /* Start timers */ + timer_start(TIMER0); +} + + + +_attribute_ram_code_sec_ void key_fifo(unsigned char key_code) +{ + unsigned char real_key_code = special_key_press_flag_set(key_code); + if (real_key_code==0) //key_code=0 not save + { + return; + } + + app_key_buf.cnt++; + if (app_key_buf.cnt > MAX_BTN_CNT) + { + return; + } + app_key_buf.keycode[app_key_buf.cnt-1] = real_key_code; +} + + +_attribute_ram_code_sec_noinline_ unsigned char proc_hotkey(unsigned char key_code) +{ + + if((key_code>=0xe0) && (key_code<0xe8)) + { + app_key_buf.nk[0] |= (1 << (key_code-0xe0)); + return 1; + } + + if((key_code >= C_INDEX_START) && (key_code <= C_INDEX_END)) + { + app_key_buf.ck = key_code; + return 1; + } + + if ((key_code >= S_SLEEP) && (key_code <= S_WAKEUP)) + { + app_key_buf.sk = key_code; + return 1; + } + + if(key_code>0x9f) + { + return 1; + } + + return 0; +} + + +_attribute_ram_code_sec_noinline_ unsigned char special_key_press_flag_set(unsigned char key_code) +{ + unsigned char real_key_code = key_code; + if(key_code==T_FN) + { + app_key_buf.special_key_press_f |= PRESS_T_FN_FLAG; + fn_flag = 1; + } + else if(fn_flag) + { + switch (key_code) + { + case KB_M: + app_key_buf.special_key_press_f|=PRESS_KB_M_FLAG; + real_key_code=0; + break; + case KB_P: + app_key_buf.special_key_press_f|=PRESS_KB_P_FLAG; + real_key_code=0; + break; + case KB_H: + app_key_buf.special_key_press_f|=PRESS_KB_H_FLAG; + real_key_code=0; + break; + case KB_L: + app_key_buf.special_key_press_f|=PRESS_KB_L_FLAG; + real_key_code=0; + break; + case KB_1: + app_key_buf.special_key_press_f|=PRESS_KB_1_FLAG; + real_key_code=0; + break; + case KB_2: + app_key_buf.special_key_press_f|=PRESS_KB_2_FLAG; + real_key_code=0; + break; + case KB_3: + app_key_buf.special_key_press_f|=PRESS_KB_3_FLAG; + real_key_code=0; + break; + case KB_4: + app_key_buf.special_key_press_f|=PRESS_KB_4_FLAG; + real_key_code=0; + break; + case KB_F1: + real_key_code=C_mute; + break; + + } + } + + return real_key_code; +} + +//ZH_TODO + /** + * @brief save data to flash + * @param[in] addr - the base address of flash. + * @param[in] len - the length(in byte, must be above 0) of content needs to read out from the page. + * @param[in] buf - data buffer(ram address) + * @param[in,out] offset - The offset address of the last data + * @return 1: success ,other: fail + */ + +_attribute_ram_code_sec_ int save_data_to_flash(unsigned long addr, int len, unsigned char *buf,int *offset) +{ + unsigned char tmp_buf[len]; + int tmp_offset=0; + + + if(offset[0]>(4096-2*len)) + { + flash_erase_sector(addr); + offset[0]=-len; + } + + tmp_offset=offset[0]+len; + + for(unsigned char i=0;i<3;i++) + { + flash_write_page(addr+tmp_offset, len, buf); + flash_read_page(addr+tmp_offset, len, tmp_buf); + + if(memcmp(tmp_buf, buf, len)==0) //ZH_TODO memcpy to tmemcpy + { + offset[0]=tmp_offset; + return 1;//#define SUCCESS 0x00 + } + else + { + flash_erase_sector(addr); + tmp_offset=0; + } + } + + return 0;//write fail + } + + /** + * @brief FNV-1a 32-bit hash function + * @param data + * @param len + * @return 16-bit hash value + */ + _attribute_ram_code_sec_ uint32_t fnv1a_hash(uint8_t *data, size_t len) +{ + uint32_t hash = 0x811C9DC5; + + for (size_t i = 0; i < len; i++) { + hash ^= data[i]; + hash = hash + (hash << 24) + (hash << 8) + (hash << 5); + hash ^= (hash >> 16);//Avalanche Effect + } + + return hash; +} + + + /** + * @brief read flash information + * @param[in] s_addr - the base address of flash. + * @param[in] len - the length(in byte, must be above 0) of content needs to read out from the page. + * @param[out] d_addr - the start address of the buffer(ram address). + * @return The offset address of the last data + */ + +int flash_info_load(unsigned int s_addr, unsigned char *d_addr, int len) +{ + int idx; + unsigned int buf; + for (idx = 0; idx < (4096 - len); idx += len) + { + flash_read_page((unsigned int)(s_addr + idx), 4, (unsigned char *)(&buf)); + if (buf == 0xffffffff) + { + break; + } + } + idx -= len; + if (idx < 0) // no binding + { + return idx; + } + flash_read_page((unsigned int)(s_addr + idx), len, d_addr); + + if (idx > 3000) //3k, erase flash + { + flash_erase_sector((unsigned int)s_addr); + + // sleep_us(10); + + flash_write_page((unsigned int)s_addr, len, d_addr); + idx = 0; + } + return idx; +} + +static void p24g_pairing_info_check(void) +{ + //dev_info_idx = flash_info_load(flash_sector_2p4_inf, (unsigned char *)&flash_dev_info.side_id, sizeof(ST_FLASH_DEV_INFO)); + + int ret = nvs_read(&user_fs, APP_2P4G_PAIR_INFO_ID, (unsigned char *)&flash_dev_info.side_id, sizeof(ST_FLASH_DEV_INFO)); + if (ret == -ENOENT) { + printk("NVS APP_2P4G_PAIR_INFO_ID naver saved\n"); + LOG_INF("not paired: %x %x\n", flash_dev_info.side_id, flash_sector_2p4_inf); + } else { + LOG_INF("paired: %x %x\n", flash_dev_info.side_id, flash_sector_2p4_inf); + } + + + //dev_other_info_idx = flash_info_load(flash_sector_2p4_other_inf, (unsigned char *)&flash_dev_other_info.side_id, sizeof(ST_FLASH_DEV_OTHER_INFO)); + + ret = nvs_read(&user_fs, APP_2P4G_APP_INFO_ID, (unsigned char *)&flash_dev_other_info.side_id, sizeof(ST_FLASH_DEV_OTHER_INFO)); + if (ret == -ENOENT) { + printk("NVS APP_2P4G_APP_INFO_ID naver saved\n"); + + } else { + LOG_INF("read flash get report rate: %x\n", flash_dev_other_info.side_id); + } +} + + +_attribute_ram_code_sec_ uint8_t app_2p4g_set_stack_report_rate(uint8_t report_rate) +{ + uint8_t ret = TLK_SUCCESS; + + if (app_d24p_get_state() == STATE_CONNECTED) { + ret = p24g_send_spp_data(P24G_SPP_REPORT_RATE, &report_rate, 1); + if (TLK_SUCCESS == ret) { + ret = p24g_send_sm_msg(P24G_SM_CMD_REPORT_RATE_CHANGE, report_rate, 0, 0); + // DBG_GPIO_TOGGLE(APP_IO_EN, GPIO_PH0); + } + } else { + ret = TLK_ERR_INVALID_STATE; + } + + return ret; +} + +_attribute_ram_code_sec_noinline_ void special_key_event_handle(void) +{ + uint8_t ret; + + if(app_key_buf.special_key_press_f==0) + { + fn_flag=0; + } + switch (app_key_buf.special_key_press_f) + { + case PRESS_MOUSE_AUTO_BTN_FLAG: + #if 0 + auto_test_mouse ^= 0x01; + p24g_send_sm_msg(P24G_SM_CMD_MOUSE_DRAW, 0, 0, 0); + #endif + break; + case PRESS_PAIR_BTN_FLAG: + if(fun_mode==KB_MODE_2P4G) + { + LOG_INF("2p4g mode pair start\r\n"); + // DBG_GPIO_TOGGLE(APP_IO_EN, GPIO_PA6); + p24g_enable_pairing(true); + } + else if(fun_mode==KB_MODE_BLE) + { + printk("ble mode pair start\r\n"); + user_active_disconnect = 0; + user_active_disconnect += MULTI_DEVICE_PAIR_PIPE_1 + ble_app_pip_info.mast_id; + if (connected_handle) { + BIT_SET(user_active_disconnect, BLE_START_PAIR); + } else { + start_pairing_by_delay_work(); + } + } + break; + case PRESS_REPORT_RATE_8K_FLAG: + if(usb_connected_ok==0) + { + if(fun_mode==KB_MODE_2P4G) + { + uint8_t ret = app_2p4g_set_stack_report_rate(REPORT_RATE_8K); + + if (TLK_SUCCESS == ret) { + //LOG_INF("report rate change(%s)...\n", g_last_report_rate_pin_level ? "8k" : "125"); + LOG_INF("report rate change()...\n"); + } else { + LOG_INF("report rate change failed(ret %d)\n", ret); + } + } + } + break; + case PRESS_REPORT_RATE_125_FLAG: + if(usb_connected_ok==0) + { + if(fun_mode==KB_MODE_2P4G) + { + uint8_t ret = app_2p4g_set_stack_report_rate(REPORT_RATE_125); + + if (TLK_SUCCESS == ret) { + //LOG_INF("report rate change(%s)...\n", g_last_report_rate_pin_level ? "8k" : "125"); + LOG_INF("report rate change...\n"); + } else { + LOG_INF("report rate change failed(ret %d)\n", ret); + } + } + } + break; + case PRESS_BLE_PIPE1_FLAG: + printk("switch ble pipe 1\r\n"); + if(fun_mode == KB_MODE_BLE && ble_app_pip_info.mast_id != 0) + { + user_active_disconnect = 0; + user_active_disconnect += MULTI_DEVICE_CHANGE_PIPE_1; + + if (connected_handle) { + BIT_SET(user_active_disconnect, BLE_SWITCH_PIPE); + } else { + start_change_ble_pipe_by_delay_work(); + } + } + break; + case PRESS_BLE_PIPE2_FLAG: + printk("switch ble pipe 2\r\n"); + if(fun_mode == KB_MODE_BLE && ble_app_pip_info.mast_id != 1) + { + user_active_disconnect = 0; + user_active_disconnect += MULTI_DEVICE_CHANGE_PIPE_2; + if (connected_handle) { + BIT_SET(user_active_disconnect, BLE_SWITCH_PIPE); + } else { + start_change_ble_pipe_by_delay_work(); + } + } + break; + case PRESS_BLE_PIPE3_FLAG: + printk("switch ble pipe 3\r\n"); + if(fun_mode==KB_MODE_BLE && ble_app_pip_info.mast_id != 2) + { + user_active_disconnect = 0; + user_active_disconnect += MULTI_DEVICE_CHANGE_PIPE_3; + if (connected_handle) { + BIT_SET(user_active_disconnect, BLE_SWITCH_PIPE); + } else { + start_change_ble_pipe_by_delay_work(); + } + } + break; + case PRESS_BLE_PIPE4_FLAG: + printk("switch ble pipe 4\r\n"); + if(fun_mode==KB_MODE_BLE && ble_app_pip_info.mast_id != 3) + { + user_active_disconnect = 0; + user_active_disconnect += MULTI_DEVICE_CHANGE_PIPE_4; + if (connected_handle) { + BIT_SET(user_active_disconnect, BLE_SWITCH_PIPE); + } else { + start_change_ble_pipe_by_delay_work(); + } + } + break; + } +} + +_attribute_ram_code_sec_noinline_ void key_data_handle(void) +{ + static unsigned char nk_cnt=0; + static unsigned char ck_last=0; + static unsigned char sk_last=0; + static unsigned char nk_last[8]={0,0,0,0,0,0,0,0}; + static unsigned char ak_last[ALL_KEY_BUF_SIZE]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + unsigned char i; + unsigned char index=0; + unsigned char bit=0; + unsigned char key=0; + app_key_buf.nk[0]=0; + app_key_buf.ck=0; + app_key_buf.sk=0; + + memset((unsigned char *)&app_key_buf.tk_bits[0], 0, ALL_KEY_BUF_SIZE); + + for(i = 0; i < app_key_buf.cnt; i++) + { + key = app_key_buf.keycode[i]; + if(proc_hotkey(key) == 0) + { + index = key/8; + bit = key%8; + app_key_buf.tk_bits[index] |= 1 << bit; + } + } + //get normal kb pipe key bits and all kb pipe key bits + int cnt=0; + memset((unsigned char *)&app_key_buf.nk[2], 0, 6); + + for( i=0;i 15) { // (15 * 3)ms + loop_cnt = 0; + + if(k_uptime_get_32() - last_time > 5000)//5s + { + last_time = k_uptime_get_32(); + printk("fun_mode %d \n", fun_mode); + printk("vbus_status %d \n", vbus_status); + printk("ble_status %d \n", ble_status); + printk("mast_id %d \n", ble_app_pip_info.mast_id); + printk("usb_connected_ok %d \n", usb_connected_ok); + } + + if (BIT_IS_SET(user_active_disconnect, BLE_SWITCH_PIPE)) { + printk("disconnect in loop \r\n"); + disconnect_current_connection(); + BIT_CLR(user_active_disconnect, BLE_SWITCH_PIPE); + } else if(BIT_IS_SET(user_active_disconnect, BLE_START_PAIR)){ + disconnect_current_connection(); + BIT_CLR(user_active_disconnect, BLE_START_PAIR); + } + + + #if (BATT_CHECK_ENABLE) + if ((k_uptime_get_32() - lowBattDet_tick) > 5000) + { + LOG_INF("battery check\r\n"); + lowBattDet_tick = k_uptime_get_32(); + app_battery_check(0); + } + #endif + +#if USB_APP_FUN_ENABLE + app_usb_status_check(); +#endif + + check_mode(); + + if (fun_mode != last_fun_mode) { + printk("fun_mode change %d \n", fun_mode); + pp_fifo_reset(&tx_fifo); + pp_fifo_reset(&d25fKbTxFifo); + + if (fun_mode == KB_MODE_2P4G){ + if (last_fun_mode == KB_MODE_USB) { + printk("usb mode_exit enter 2p4g mode\r\n"); + // app_usb_mode_exit(); + sys_reboot(SYS_REBOOT_COLD); + } else if (last_fun_mode == KB_MODE_BLE) { + printk("ble_mode_exit enter 2p4g mode\r\n"); + // ble_mode_exit(); + sys_reboot(SYS_REBOOT_COLD); + } + } else if (fun_mode == KB_MODE_BLE){ + if (last_fun_mode == KB_MODE_USB) { + printk("app_usb_mode_exit enter ble mode\r\n"); + // app_usb_mode_exit(); + //ble_init(); + sys_reboot(SYS_REBOOT_COLD); + } else if (last_fun_mode == KB_MODE_2P4G) { + printk("app_usb_mode_exit enter 2p4g mode\r\n"); + // app_2p4g_mode_exit(); + sys_reboot(SYS_REBOOT_COLD); + } + // ble_mode_enter(); + } else if (fun_mode == KB_MODE_USB){ + if (last_fun_mode == KB_MODE_2P4G) { + printk("2p4g mode exit enter usb mode\r\n"); + // app_2p4g_mode_exit(); + sys_reboot(SYS_REBOOT_COLD); + } else if (last_fun_mode == KB_MODE_BLE) { + printk("ble mode exit enter usb mode\r\n"); + //ble_mode_exit(); + //bt_disable(); + sys_reboot(SYS_REBOOT_COLD); + } + if (vbus_status == 1) { + // app_usb_mode_enter(); + } + } + last_fun_mode = fun_mode; + } + } +} diff --git a/samples/bluetooth/peripheral_kmd/src/app_public.h b/samples/bluetooth/peripheral_kmd/src/app_public.h new file mode 100644 index 0000000000000..06fbc122f0c2a --- /dev/null +++ b/samples/bluetooth/peripheral_kmd/src/app_public.h @@ -0,0 +1,251 @@ +/** @file + * @brief HoG Service sample + */ + +/* + * Copyright (c) 2016 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifdef __cplusplus +extern "C" { +#endif +#include "app_config.h" +#include "compiler.h" +#include "hog.h" +#include "app_usb.h" +#include "app_ble.h" +#include "app_24g.h" +#include "app_battery.h" +#include "app_kb_matrix.h" +#include "app_alg_keyscan.h" + +#define BIT_SET(x, n) ((x) |= BIT(n)) +#define BIT_CLR(x, n) ((x) &= ~BIT(n)) +#define BIT_IS_SET(x, n) ((x) & BIT(n)) +#define BIT_FLIP(x, n) ((x) ^= BIT(n)) +#define BIT_SET_HIGH(x) ((x) |= BIT((sizeof((x)) * 8 - 1))) // set the highest bit +#define BIT_CLR_HIGH(x) ((x) &= ~BIT((sizeof((x)) * 8 - 1))) // clr the highest bit +#define BIT_IS_SET_HIGH(x) ((x) & BIT((sizeof((x)) * 8 - 1))) // check the highest bit + +typedef struct __attribute__((packed)) { + unsigned short size; + unsigned short num; + + unsigned short wptr; + unsigned short rptr; + + unsigned char *p; +} pl_fifo_t; + +void pp_fifo_reset (pl_fifo_t *f); +unsigned short pp_fifo_get_num(pl_fifo_t * f); +unsigned char *pp_fifo_get_ptr(pl_fifo_t * f); +int pp_fifo_push(pl_fifo_t * f, unsigned char cmd, unsigned char * buf, unsigned char len); +void pp_fifo_pop(pl_fifo_t *f); + +extern pl_fifo_t tx_fifo; +extern pl_fifo_t d25fKbTxFifo; +extern pl_fifo_t d25fSppTxFifo; + +extern void mb_irq_handler(void); + +//ZH_TODO +typedef struct +{ + uint32_t side_id; //4 + + // unsigned char key[12];//12 + + uint8_t peer_addr[MAC_ADDR_LEN];//6 + + // unsigned char mode; + // unsigned char mast_id; + // unsigned short temp1; //24 + + // unsigned char temp2[8]; //32 + +} ST_FLASH_DEV_INFO; +extern ST_FLASH_DEV_INFO flash_dev_info; +extern int dev_info_idx; +extern uint32_t flash_sector_2p4_inf; + +typedef struct +{ + uint32_t side_id; //4 + uint8_t report_rate; //1 + +} ST_FLASH_DEV_OTHER_INFO; + +extern ST_FLASH_DEV_OTHER_INFO flash_dev_other_info; +extern int dev_other_info_idx; +extern uint32_t flash_sector_2p4_other_inf; + +// + +// #define TLK_ERR_BASE_NUM (0x0) /**< Global error base */ + +// #define TLK_SUCCESS (TLK_ERR_BASE_NUM + 0) /**< Successful command */ +// #define TLK_ERR_NULL (TLK_ERR_BASE_NUM + 1) /**< Null pointer */ +// #define TLK_ERR_INVALID_PARAM (TLK_ERR_BASE_NUM + 2) /**< Invalid parameter */ +// #define TLK_ERR_BUSY (TLK_ERR_BASE_NUM + 3) /**< Device or resourse Busy */ +// #define TLK_ERR_INVALID_STATE (TLK_ERR_BASE_NUM + 4) /**< Invalid state, operation disallowed in this state */ +// #define TLK_ERR_BUFFER_EMPTY (TLK_ERR_BASE_NUM + 5) /**< Buffer/FIFO is empty */ +// #define TLK_ERR_NO_MEM (TLK_ERR_BASE_NUM + 6) /**< No memory available for operation */ +// #define TLK_ERR_INVALID_LENGTH (TLK_ERR_BASE_NUM + 7) /**< Invalid length */ +// #define TLK_ERR_TIMEOUT (TLK_ERR_BASE_NUM + 8) /**< Operation timed out */ +// #define TLK_ERR_INTERNAL (TLK_ERR_BASE_NUM + 9) /**< Internal error */ +// #define TLK_ERR_DEV_NOT_FOUND (TLK_ERR_BASE_NUM + 10) /**< Destination device not found */ +// #define TLK_ERR_CMD_NOT_SUPPORT (TLK_ERR_BASE_NUM + 11) /**< cmd not supported */ +// #define TLK_ERR_BUFFER_FULL (TLK_ERR_BASE_NUM + 12) /**< Buffer/FIFO is full */ + + +#define LED_IS_ON 0 +#define LED_IS_OFF 1 + +/////////////////////////////////////////////////////////////////////////////////////////// +#define PRESS_T_FN_FLAG 0X01 +#define PRESS_KB_M_FLAG 0X02 +#define PRESS_KB_P_FLAG 0X04 +#define PRESS_KB_1_FLAG 0X08 +#define PRESS_KB_2_FLAG 0X10 +#define PRESS_KB_3_FLAG 0X20 +#define PRESS_KB_4_FLAG 0X40 +#define PRESS_KB_H_FLAG 0X80 +#define PRESS_KB_L_FLAG 0X0100 + + + +#define PRESS_PAIR_BTN_FLAG (PRESS_T_FN_FLAG|PRESS_KB_P_FLAG) +#define PRESS_MOUSE_AUTO_BTN_FLAG (PRESS_T_FN_FLAG|PRESS_KB_M_FLAG) +#define PRESS_REPORT_RATE_8K_FLAG (PRESS_T_FN_FLAG|PRESS_KB_H_FLAG) +#define PRESS_REPORT_RATE_125_FLAG (PRESS_T_FN_FLAG|PRESS_KB_L_FLAG) +#define PRESS_BLE_PIPE1_FLAG (PRESS_T_FN_FLAG|PRESS_KB_1_FLAG) +#define PRESS_BLE_PIPE2_FLAG (PRESS_T_FN_FLAG|PRESS_KB_2_FLAG) +#define PRESS_BLE_PIPE3_FLAG (PRESS_T_FN_FLAG|PRESS_KB_3_FLAG) +#define PRESS_BLE_PIPE4_FLAG (PRESS_T_FN_FLAG|PRESS_KB_4_FLAG) + +extern struct nvs_fs user_fs; +#define USER_STORAGE_APP_INFO_ID 1 +#define APP_2P4G_PAIR_INFO_ID 2 +#define APP_2P4G_APP_INFO_ID 3 + +enum { + EMPTY_DATA_CMD=0, + PAIR_DATA_CMD=1, + RECONNECT_DATA_CMD=2, + MOUSE_DATA=3, + SPP_DATA=4, + SPP_DATA_ACK=5, + NORMAL_KB_DATA_CMD=6, + CONSUME_KB_DATA_CMD=7, + SYSTEM_KB_DATA_CMD=8, + ALL_KB_DATA_CMD=9, +}; + + +enum { + MULTI_DEVICE_CMD = 0, + MULTI_DEVICE_CHANGE_PIPE_1, + MULTI_DEVICE_CHANGE_PIPE_2, + MULTI_DEVICE_CHANGE_PIPE_3, + MULTI_DEVICE_CHANGE_PIPE_4, + MULTI_DEVICE_PAIR_PIPE_1, + MULTI_DEVICE_PAIR_PIPE_2, + MULTI_DEVICE_PAIR_PIPE_3, + MULTI_DEVICE_PAIR_PIPE_4, +}; + +enum { + BLE_USER_CMD = 0, + BLE_SWITCH_PIPE = 7, + BLE_START_PAIR = 16, +}; + +#define ALL_KEY_BUF_SIZE 16 +#define MAX_BTN_CNT 128//8*16 TOTAL_ROW*TOTAL_COL +#define REPORT_ALL_KB_SIZE 16 + +typedef struct{ + + unsigned char nk[8];//normal key + + unsigned char tk_bits[ALL_KEY_BUF_SIZE]; //total key + unsigned char nk_bits[ALL_KEY_BUF_SIZE]; //all_key + unsigned char ak_bits[ALL_KEY_BUF_SIZE]; //all_key + + unsigned char press_cnt; + unsigned char cnt; + unsigned char ck; // consume_key + unsigned char sk; //system_key + + unsigned int special_key_press_f; + + unsigned char keycode[MAX_BTN_CNT]; + +}app_kb_data_t; + +extern app_kb_data_t app_key_buf; +extern unsigned char fn_flag; +extern struct gpio_dt_spec toggle_pin; + +extern volatile uint32_t user_active_disconnect; +extern volatile unsigned char fun_mode; +extern struct gpio_dt_spec vbus_check_pin; +void key_fifo(unsigned char key_code); +unsigned char proc_hotkey(unsigned char key_code); +unsigned char special_key_press_flag_set(unsigned char key_code); + +//ZH_TODO +/** + * @brief read flash information + * @param[in] s_addr - the base address of flash. + * @param[in] len - the length(in byte, must be above 0) of content needs to read out from the page. + * @param[out] d_addr - the start address of the buffer(ram address). + * @return The offset address of the last data + */ + +int flash_info_load(unsigned int s_addr, unsigned char *d_addr, int len); + + +/** + * @brief save data to flash + * @param[in] addr - the base address of flash. + * @param[in] len - the length(in byte, must be above 0) of content needs to read out from the page. + * @param[in] buf - data buffer(ram address) + * @param[in,out] offset - The offset address of the last data + * @return 1: success ,other: fail + */ + +_attribute_ram_code_sec_ int save_data_to_flash(unsigned long addr, int len, unsigned char *buf,int *offset); +uint32_t fnv1a_hash(uint8_t *data, size_t len); + +// + + +void special_key_event_handle(void); +int keyboard_comm_init(void); +void app_ble_report_to_client(void); +void public_loop(void); +void k_timer_scan_loop_init(void); +#if USE_K_TIMER_SCAN_MATRIX +_attribute_ram_code_sec_ void keyscan_loop(struct k_work *work); +#else +_attribute_ram_code_sec_ void keyscan_loop(void); +#endif +void start_change_ble_pipe_by_delay_work(void); +_attribute_ram_code_sec_noinline_ void app_ble_main_loop(void); + +static inline kb_mode_t app_get_kb_mode(void) +{ + #if (HW_BOARD_TYPE==HW_EVK_KEYBOARD) + return KB_MODE_2P4G; + #else + return fun_mode; + #endif +} + +#ifdef __cplusplus +} +#endif diff --git a/samples/bluetooth/peripheral_kmd/src/app_usb.c b/samples/bluetooth/peripheral_kmd/src/app_usb.c new file mode 100644 index 0000000000000..f66be2bddea36 --- /dev/null +++ b/samples/bluetooth/peripheral_kmd/src/app_usb.c @@ -0,0 +1,431 @@ +/* main.c - Application main entry point */ + +/* + * Copyright (c) 2016 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + + +#include "app_public.h" + +#define LOG_LEVEL LOG_LEVEL_DBG +#include +LOG_MODULE_REGISTER(app_usb); + +#define APP_VBUS_CHECK_DE_JT_CNT 2 + +//static struct gpio_dt_spec led_caps = GPIO_DT_SPEC_GET_OR(DT_ALIAS(led-caps), gpios, {0}); +//static struct gpio_dt_spec led_num = GPIO_DT_SPEC_GET_OR(DT_ALIAS(led-num), gpios, {0}); +//static struct gpio_dt_spec led_scrol = GPIO_DT_SPEC_GET_OR(DT_ALIAS(led-scrol), gpios, {0}); +//static struct gpio_dt_spec led_pair = GPIO_DT_SPEC_GET_OR(DT_ALIAS(led-pair), gpios, {0}); + +volatile unsigned int vbus_status = 0; +static unsigned char last_vbus_status = 0; +volatile unsigned int usb_connected_ok = 0; + +#if 1 + static const uint8_t hid_report_kb_desc[] = HID_KEYBOARD_REPORT_DESC(); +#else +__aligned(4) static const unsigned char hid_report_kb_desc[] = { + //keyboard report in + 0x05, 0x01, // Usage Pg (Generic Desktop) + 0x09, 0x06, // Usage (Keyboard) + 0xA1, 0x01, // Collection: (Application) + //0x85, REPORT_ID_KEYBOARD_INPUT_AAA, // Report Id (keyboard) + // + 0x05, 0x07, // Usage Pg (Key Codes) + 0x19, 0xE0, // Usage Min (224) VK_CTRL:0xe0 + 0x29, 0xE7, // Usage Max (231) VK_RWIN:0xe7 + 0x15, 0x00, // Log Min (0) + 0x25, 0x01, // Log Max (1) + // + // Modifier byte + 0x75, 0x01, // Report Size (1) 1 bit * 8 + 0x95, 0x08, // Report Count (8) + 0x81, 0x02, // Input: (Data, Variable, Absolute) + // + // Reserved byte + 0x95, 0x01, // Report Count (1) + 0x75, 0x08, // Report Size (8) + 0x81, 0x01, // Input: (Constant) + + //keyboard output + //5 bit led ctrl: NumLock CapsLock ScrollLock Compose kana + 0x95, 0x05, //Report Count (5) + 0x75, 0x01, //Report Size (1) + 0x05, 0x08, //Usage Pg (LEDs ) + 0x19, 0x01, //Usage Min + 0x29, 0x05, //Usage Max + 0x91, 0x02, //Output (Data, Variable, Absolute) + //3 bit reserved + 0x95, 0x01, //Report Count (1) + 0x75, 0x03, //Report Size (3) + 0x91, 0x01, //Output (Constant) + + // Key arrays (6 bytes) + 0x95, 0x06, // Report Count (6) + 0x75, 0x08, // Report Size (8) + 0x15, 0x00, // Log Min (0) + 0x26, 0xF1,0x00, // Log Max (241) + 0x05, 0x07, // Usage Pg (Key Codes) + 0x19, 0x00, // Usage Min (0) + 0x2a, 0xf1,0x00, // Usage Max (241) + 0x81, 0x00, // Input: (Data, Array) + + 0xC0, // End Collection +}; +#endif + +//static const uint8_t hid_report_ms_desc[] = HID_MOUSE_REPORT_DESC(5); +static const uint8_t hid_report_n_keys_desc[] = HID_N_KEY_REPORT_DESC(); +#if 0 +static const uint8_t hid_report_ms_desc[] = { + //mouse report in + 0x05, 0x01, // Usage Page (Generic Desktop) + 0x09, 0x02, // Usage (Mouse) + 0xA1, 0x01, // Collection (Application) + 0x85, 0x01, // Report Id + 0x09, 0x01, // Usage (Pointer) + 0xA1, 0x00, // Collection (Physical) + 0x05, 0x09, // Usage Page (Buttons) + 0x19, 0x01, // Usage Minimum (01) - Button 1 + 0x29, 0x05, // Usage Maximum (03) - Button 3 + 0x15, 0x00, // Logical Minimum (0) + 0x25, 0x01, // Logical Maximum (1) + 0x75, 0x01, // Report Size (1) + 0x95, 0x05, // Report Count (3) + 0x81, 0x02, // Input (Data, Variable, Absolute) - Button states + 0x75, 0x03, // Report Size (5) + 0x95, 0x01, // Report Count (1) + 0x81, 0x01, // Input (Constant) - Padding or Reserved bits + + 0x05, 0x01, // Usage Page (Generic Desktop Control) + 0x09, 0x30, // Usage (X) + 0x09, 0x31, // Usage (Y) + + 0x16, 0x01, 0x80, // LOGICAL_MINIMUM(0) + 0x26, 0xff, 0x7f, + 0x75, 0x10, // Report Size (16) + 0x95, 0x02, // Report Count (2) + 0x81, 0x06, // Input (Data, Variable, Relative) + + //0x05,0x01, // Usage Page (Generic Desktop Control) + 0x09, 0x38, // Usage (Wheel) + 0x15, 0x81, // Logical Minimum (-4) + 0x25, 0x7F, // Logical Maximum (3) + 0x75, 0x08, // Report Size (3) + 0x95, 0x01, // Report Count (1) + 0x81, 0x06, // Input (Data, Variable, Relative) + + 0x05,0x0c, // Usage Page(Consumer) + 0x0a,0x38,0x02, // Usage (AC Pan) tilt + 0x15,0x81, // Logical Minimum (-128) + 0x25,0x7F, // Logical Maximum (127) + 0x75,0x08, // Report Size (8) + 0x95,0x01, // Report Count (3) + 0x81,0x06, // Input (Data, Variable, Relative) + + 0xC0, // End Collection + 0xC0, // End Collection +}; +#endif +static const uint8_t hid_report_vendor_defined[] = HID_MOUSE_REPORT_DESC(5); +#if 0 +static const uint8_t hid_report_vendor_defined[] = { + 0x06, 0xEF, 0xff, //global usage page + 0x09, 0x00, //usage undefined + 0xa1, 0x01, //main collection + 0x85, 0x06, //global report ID 0x6 + 0x15, 0x00, //LOGICAL_MINIMUM (0) + 0x26, 0xff, 0x00, //LOGICAL_MAXIMUM (255) + 0x95, 63, //Report Count (32) //MTU_SIZE=23 + 0x75, 0x08, //Report Size (8) + 0x09, 0x01, + 0x81, 0x02, //INPUT (Data,Var,Abs) + 0x09, 0x02, + 0x91, 0x02, //Output (Data, Variable, Absolute) + 0x09, 0x03, + 0xB1, 0x02, //feature (Data, Variable, Absolute) + 0xc0, //main, end collection + +}; +#endif + +static enum usb_dc_status_code usb_status; + +static K_SEM_DEFINE(usb_sem, 1, 1); /* starts off "available" */ +static void in_ready_cb(const struct device *dev) +{ + ARG_UNUSED(dev); + k_sem_give(&usb_sem); +} + +/* LED control handler implementation */ +int kbd_set_report(const struct device *dev, struct usb_setup_packet *setup, int32_t *len, + uint8_t **data) +{ + printk("kb_out: %x, len %d", **data, *len); + + //gpio_pin_set(led1.port, led1.pin, (**data & HID_KBD_LED_NUM_LOCK)); + //gpio_pin_set(led2.port, led2.pin, (**data & HID_KBD_LED_CAPS_LOCK)); + + return 0; +} + +struct hid_ops kbd_ops = { + .set_report = kbd_set_report, + .int_in_ready = in_ready_cb, +}; + +static void status_cb(enum usb_dc_status_code status, const uint8_t *param) +{ + usb_status = status; + LOG_INF("usb_status: %d", usb_status); +} + +const struct device *hid_dev_kb; +const struct device *hid_dev_n_key; +const struct device *hid_vendor; + +const struct device *hid_vendor_4; +const struct device *hid_vendor_5; +const struct device *hid_vendor_6; +int usb_hw_init(void) +{ + int ret; + + hid_dev_kb = device_get_binding("HID_0"); + if (hid_dev_kb == NULL) { + LOG_ERR("Cannot get USB HID Device"); + return 0; + } + + hid_dev_n_key = device_get_binding("HID_1"); + if (hid_dev_n_key == NULL) { + LOG_ERR("Cannot get USB HID 1 Device"); + return 0; + } + + hid_vendor = device_get_binding("HID_2"); + if (hid_vendor == NULL) { + LOG_ERR("Cannot get USB HID 2 Device"); + return 0; + } + + usb_hid_register_device(hid_dev_kb, hid_report_kb_desc, sizeof(hid_report_kb_desc), &kbd_ops); + usb_hid_register_device(hid_dev_n_key, hid_report_n_keys_desc, sizeof(hid_report_n_keys_desc), &kbd_ops); + usb_hid_register_device(hid_vendor, hid_report_vendor_defined, sizeof(hid_report_vendor_defined), &kbd_ops); + + usb_hid_init(hid_dev_kb); + usb_hid_init(hid_dev_n_key); + usb_hid_init(hid_vendor); + + ret = usb_enable(status_cb); + if (ret != 0) { + LOG_ERR("Failed to enable USB"); + return 0; + } + + LOG_INF("Enable USB, usb hw init"); +} + +void app_usb_mode_exit(void) +{ + usb_disable(); + usb_connected_ok = 0; + printk("usb mode exit\r\n"); +} + +_attribute_ram_code_sec_ int app_normal_key_report_to_usb(unsigned char *buf) +{ + static unsigned char kb[8] = {0, 0, 1, 0, 0, 0, 0, 0}; + unsigned char status = 0; + #if 0 + status=app_usb_ep_is_idle(HID_KEYBOARD_IN_ENDPOINT_NUM); + if(status!=0) + { + return status; + } + #endif + memcpy(&kb[0], &buf[0], 8); + //return app_usb_epin_send(HID_KEYBOARD_IN_ENDPOINT_ADDRESS, tmp, 8); + return hid_int_ep_write(hid_dev_kb, kb, sizeof(kb), NULL); +} + + +_attribute_ram_code_sec_ int app_all_key_report_to_usb(unsigned char *buf) +{ + static unsigned char kb[17] ={8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + unsigned char status = 0; + #if 0 + status=app_usb_ep_is_idle(HID_KEYBOARD_IN_ENDPOINT_NUM); + if(status!=0) + { + return status; + } + #endif + memcpy(&kb[1], &buf[0], 16); + //return app_usb_epin_send(HID_KEYBOARD_IN_ENDPOINT_ADDRESS, tmp, 8); + return hid_int_ep_write(hid_dev_n_key, kb, sizeof(kb), NULL); +} + +_attribute_ram_code_sec_ int app_consume_key_report_to_usb(unsigned char *buf) +{ + static unsigned char kb[3]={2,0,0}; // first is report id + unsigned char status = 0; + #if 0 + status=app_usb_ep_is_idle(HID_KEYBOARD_IN_ENDPOINT_NUM); + if(status!=0) + { + return status; + } + #endif + memcpy(&kb[1],&buf[0],2); + //return app_usb_epin_send(HID_KEYBOARD_IN_ENDPOINT_ADDRESS, tmp, 8); + return hid_int_ep_write(hid_dev_n_key, kb, sizeof(kb), NULL); +} + +_attribute_ram_code_sec_ void app_usb_report_to_pc(void) +{ + unsigned char *p= pp_fifo_get_ptr(&tx_fifo); + if(p!=0) + { + unsigned char cmd = p[1]; + int ret = 0; + + if(cmd==MOUSE_DATA) + { + //ret=app_mouse_report_to_usb(&p[3]); + } + else if(cmd == NORMAL_KB_DATA_CMD) + { + ret = app_normal_key_report_to_usb(&p[2]); + } + else if(cmd == CONSUME_KB_DATA_CMD) + { + ret = app_consume_key_report_to_usb(&p[2]); + } + else if(cmd == SYSTEM_KB_DATA_CMD) + { + //ret = app_system_key_report_to_usb(&p[2]); + } + else if(cmd == ALL_KB_DATA_CMD) + { + ret = app_all_key_report_to_usb(&p[2]); + } + if(ret == 0) + { + pp_fifo_pop(&tx_fifo); + } + } +} + +_attribute_ram_code_sec_ void app_usb_main_loop(void) +{ + if (usb_connected_ok == 1) { + app_usb_report_to_pc(); + } +} + +_attribute_ram_code_sec_ void check_vbus(void) +{ + static int8_t vbus_cnt = 0; + + if(gpio_pin_get_dt(&vbus_check_pin) == VBUS_5V_CHECK_PIN_USB_IN_LEVEL) { + if (vbus_cnt < APP_VBUS_CHECK_DE_JT_CNT) { + vbus_cnt ++; + } else { + vbus_status=1; + } + } else { + if (vbus_cnt > -APP_VBUS_CHECK_DE_JT_CNT) { + vbus_cnt --; + } else { + vbus_status=0; + } + } + +} + +// _attribute_ram_code_sec_ void check_vbus(void) +// { +// #if (HW_BOARD_TYPE == HW_PRJ_KEYBOARD || HW_BOARD_TYPE == HW_DIGIT_KEYBOARD) +// vbus_status = 1; +// if(gpio_pin_get_dt(&vbus_check_pin) == 0) +// { +// vbus_status = 0; +// } +// #endif +// } + +_attribute_ram_code_sec_ uint8_t app_is_usb_det_in(void) +{ + return (vbus_status == 1); +} + +_attribute_ram_code_sec_ void app_usb_status_check(void) +{ + static unsigned int last_usb_status = 0xff; + + check_vbus(); + + if(last_vbus_status != vbus_status) + { + printk("vbus_status = %d\r\n",vbus_status); + if(last_vbus_status == 0) + { + // TODO:app_usb_bus_reset_init(); + } + else + { + usb_status = 0; + } + last_vbus_status = vbus_status; + } + + if(last_usb_status != usb_status) + { + if(usb_status == USB_DC_CONFIGURED) + { + printk("mode is usb mode\r\n"); + // TODO:gpio_set_level(MODE_LED_PIN, LED_IS_ON); + // TODO: gpio_set_level(PAIR_LED_PIN,LED_IS_OFF); + usb_connected_ok = 1; + if(fun_mode == KB_MODE_2P4G) + { + // TODO:p24g_send_sm_msg(P24G_SM_CMD_SET_KB_MODE, P24G_KB_MODE_USB, 0, 0); + } + else + { + printk("ble enter idle mode\r\n"); + // TODO:ble_mode_enter_idle(); + } + } + else if(usb_status == USB_DC_DISCONNECTED) + { + // TODO:gpio_set_level(MODE_LED_PIN, LED_IS_OFF); + usb_connected_ok = 0; + + if(fun_mode == KB_MODE_2P4G) + { + printk("mode is 2.4g\r\n"); + // TODO:p24g_send_sm_msg(P24G_SM_CMD_SET_KB_MODE, P24G_KB_MODE_2P4G, 0, 0); + } + } + last_usb_status = usb_status; + } +} \ No newline at end of file diff --git a/samples/bluetooth/peripheral_kmd/src/app_usb.h b/samples/bluetooth/peripheral_kmd/src/app_usb.h new file mode 100644 index 0000000000000..060ce110850d6 --- /dev/null +++ b/samples/bluetooth/peripheral_kmd/src/app_usb.h @@ -0,0 +1,60 @@ +/** @file + * @brief HoG Service sample + */ + +/* + * Copyright (c) 2016 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#define HID_USAGE_GEN_DESKTOP_CONSUMER 0x0C + +/** + * @brief Simple HID N-keys keyboard report descriptor. + */ +#define HID_N_KEY_REPORT_DESC() { \ + HID_USAGE_PAGE(HID_USAGE_GEN_DESKTOP), \ + HID_USAGE(HID_USAGE_GEN_DESKTOP_KEYBOARD), \ + HID_COLLECTION(HID_COLLECTION_APPLICATION), \ + HID_REPORT_ID(0x08), \ + HID_USAGE_PAGE(HID_USAGE_GEN_DESKTOP_KEYPAD),\ + HID_USAGE_MIN8(0x00), \ + HID_USAGE_MAX8(0x80), \ + HID_LOGICAL_MIN8(0), \ + HID_LOGICAL_MAX8(1), \ + HID_REPORT_SIZE(1), \ + HID_REPORT_COUNT(0x80), \ + HID_INPUT(0x02), \ + HID_END_COLLECTION, \ + \ + /*Consumer */ \ + HID_USAGE_PAGE(HID_USAGE_GEN_DESKTOP_CONSUMER), \ + HID_USAGE(HID_USAGE_GEN_DESKTOP), \ + HID_COLLECTION(HID_COLLECTION_APPLICATION), \ + HID_REPORT_ID(0x02), \ + HID_REPORT_SIZE(0x10), \ + HID_REPORT_COUNT(0x01), \ + HID_LOGICAL_MIN8(1), \ + HID_LOGICAL_MAX16(0x8c, 0x02), \ + HID_USAGE_MIN8(0x00), \ + HID_USAGE_MAX16(0x8c, 0x02), \ + HID_INPUT(0x00), \ + HID_END_COLLECTION, \ +} + +extern volatile unsigned int vbus_status; +extern volatile unsigned int usb_connected_ok; + +int usb_hw_init(void); +void usb_test_loop(void); +void app_usb_main_loop(void); +void app_usb_status_check(void); +uint8_t app_is_usb_det_in(void); +#ifdef __cplusplus +} +#endif diff --git a/samples/bluetooth/peripheral_kmd/src/hog.c b/samples/bluetooth/peripheral_kmd/src/hog.c new file mode 100644 index 0000000000000..7778f676d4f23 --- /dev/null +++ b/samples/bluetooth/peripheral_kmd/src/hog.c @@ -0,0 +1,603 @@ +/** @file + * @brief HoG Service sample + */ + +/* + * Copyright (c) 2016 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "app_public.h" + +enum { + HIDS_REMOTE_WAKE = BIT(0), + HIDS_NORMALLY_CONNECTABLE = BIT(1), +}; + +static uint8_t ctrl_point; + +/*! HID Report Type/ID and attribute handle map */ +static const struct hid_report_id_map_t hid_app_report_id_set[] = { + /* type ID handle */ + {HID_REPORT_TYPE_INPUT, HIDS_MOUSE_INPUT_REPORT_ID, HID_INPUT_REPORT_1_HDL}, /* Mouse Input Report */ + {HID_REPORT_TYPE_INPUT, HIDS_KEYBOARD_INPUT_REPORT_ID, HID_INPUT_REPORT_2_HDL}, /* Keyboard Input Report */ + {HID_REPORT_TYPE_OUTPUT, HIDS_KEYBOARD_INPUT_REPORT_ID, HID_OUTPUT_REPORT_HDL}, /* Keyboard Output Report */ + {HID_REPORT_TYPE_FEATURE, HIDS_KEYBOARD_INPUT_REPORT_ID, HID_FEATURE_REPORT_HDL}, /* Keyboard Feature Report */ + {HID_REPORT_TYPE_INPUT, HIDS_CONSUMER_INPUT_REPORT_ID, HID_INPUT_REPORT_3_HDL}, /* consumer Input Report */ + {HID_REPORT_TYPE_INPUT, HIDS_SYSTEM_INPUT_REPORT_ID , HID_INPUT_REPORT_4_HDL}, /* system Input Report */ + {HID_REPORT_TYPE_INPUT, HIDS_ALL_KEY_INPUT_REPORT_ID , HID_INPUT_REPORT_5_HDL}, /* kb all key Input Report */ + {HID_REPORT_TYPE_INPUT, HIDS_VENDOR_INPUT_REPORT_ID , HID_INPUT_REPORT_6_HDL}, /* kb all key Input Report */ + {HID_REPORT_TYPE_INPUT, HID_KEYBOARD_BOOT_ID, HID_KEYBOARD_BOOT_IN_HDL}, /* Boot Keyboard Input Report */ + {HID_REPORT_TYPE_OUTPUT, HID_KEYBOARD_BOOT_ID, HID_KEYBOARD_BOOT_OUT_HDL}, /* Boot Keyboard Output Report */ + {HID_REPORT_TYPE_INPUT, HID_MOUSE_BOOT_ID, HID_MOUSE_BOOT_IN_HDL}, /* Boot Mouse Input Report */ +}; + +static uint8_t hid_report_map[] = { + //keyboard report in + 0x05, 0x01, // Usage Pg (Generic Desktop) + 0x09, 0x06, // Usage (Keyboard) + 0xA1, 0x01, // Collection: (Application) + 0x85, HIDS_KEYBOARD_INPUT_REPORT_ID, // Report Id (keyboard) + // + 0x05, 0x07, // Usage Pg (Key Codes) + 0x19, 0xE0, // Usage Min (224) VK_CTRL:0xe0 + 0x29, 0xE7, // Usage Max (231) VK_RWIN:0xe7 + 0x15, 0x00, // Log Min (0) + 0x25, 0x01, // Log Max (1) + // + // Modifier byte + 0x75, 0x01, // Report Size (1) 1 bit * 8 + 0x95, 0x08, // Report Count (8) + 0x81, 0x02, // Input: (Data, Variable, Absolute) + // + // Reserved byte + 0x95, 0x01, // Report Count (1) + 0x75, 0x08, // Report Size (8) + 0x81, 0x01, // Input: (Constant) + + //keyboard output + //5 bit led ctrl: NumLock CapsLock ScrollLock Compose kana + 0x95, 0x05, //Report Count (5) + 0x75, 0x01, //Report Size (1) + 0x05, 0x08, //Usage Pg (LEDs ) + 0x19, 0x01, //Usage Min + 0x29, 0x05, //Usage Max + 0x91, 0x02, //Output (Data, Variable, Absolute) + //3 bit reserved + 0x95, 0x01, //Report Count (1) + 0x75, 0x03, //Report Size (3) + 0x91, 0x01, //Output (Constant) + + // Key arrays (6 bytes) + 0x95, 0x06, // Report Count (6) + 0x75, 0x08, // Report Size (8) + 0x15, 0x00, // Log Min (0) + 0x26, 0xF1, 0x00, // Log Max (241) + 0x05, 0x07, // Usage Pg (Key Codes) + 0x19, 0x00, // Usage Min (0) + 0x2a, 0xf1, 0x00, // Usage Max (241) + 0x81, 0x00, // Input: (Data, Array) + + 0xC0, // End Collection + +/////////////////////////Consumer/////////////////////////////////// + 0x05, 0x0C, // Usage Page (Consumer) + 0x09, 0x01, // Usage (Consumer Control) + 0xA1, 0x01, // Collection (Application) + 0x85, HIDS_CONSUMER_INPUT_REPORT_ID, // Report Id + 0x75,0x10, //global, report size 16 bits + 0x95,0x01, //global, report count 1 + 0x15,0x01, //global, min 0x01 + 0x26,0x8c,0x02, //global, max 0x28c + 0x19,0x01, //local, min 0x01 + 0x2a,0x8c,0x02, //local, max 0x28c + 0x81,0x00, //main, input data varible, absolute + 0xc0, //main, end collection + + /////////////////////////System report/////////////////////////////////// + + 0x05,0x01, //Usage Page (Generic Desktop Control) + 0x09,0x80, //Usage (SYSTEM CONTROL) + 0xA1,0x01, //Collection (Application) + + 0x85,HIDS_SYSTEM_INPUT_REPORT_ID, //Report ID (ACPI) + + 0x25,0x01, // Logical Maximum (1) + 0x15,0x00, // Logical Minimum (0) + 0x75,0x01, // Report Size + + 0x09,0x82, // USAGE SYSTEM SLEEP + 0x09,0x81, // USAGE SYSTEM POWER DOWN + 0x09,0x83, // USAGE SYSTEM WAKE UP + + 0x95,0x03, // REPORT_COUNT (03H) + 0x81,0x02, // INPUT (DATA, VAR) + 0x95,0x05, // Report Count (05) + + 0x81,0x01, // Input (CONSTANT) + 0xC0, // END COLLECTION +/////////////////////////ALL key report/////////////////////////////////// + + 0x05, 0x01, // Usage Pg (Generic Desktop) + 0x09, 0x06, // Usage (Keyboard) + 0xA1, 0x01, // Collection: (Application) + 0x85, HIDS_ALL_KEY_INPUT_REPORT_ID, // Report Id (keyboard) + 0x05, 0x07, // Usage Pg (Key Codes) + 0x19, 0x00, // Usage Min + 0x29, 0x80, // Usage Max + 0x15, 0x00, // Log Min (0) + 0x25, 0x01, // Log Max (1) + + 0x75, 0x01, // Report Size (1) 1 bit * 8 + 0x95, 0x80, // Report Count (8) + 0x81, 0x02, // Input: (Data, Variable, Absolute + + 0xC0, // End Collection + + /////////////////////////Mouse/////////////////////////////////// + 0x05, 0x01, // Usage Page (Generic Desktop) + 0x09, 0x02, // Usage (Mouse) + 0xA1, 0x01, // Collection (Application) + 0x85, HIDS_MOUSE_INPUT_REPORT_ID, // Report Id + 0x09, 0x01, // Usage (Pointer) + 0xA1, 0x00, // Collection (Physical) + 0x05, 0x09, // Usage Page (Buttons) + 0x19, 0x01, // Usage Minimum (01) - Button 1 + 0x29, 0x03, // Usage Maximum (03) - Button 3 + 0x15, 0x00, // Logical Minimum (0) + 0x25, 0x01, // Logical Maximum (1) + 0x75, 0x01, // Report Size (1) + 0x95, 0x05, // Report Count (3) + 0x81, 0x02, // Input (Data, Variable, Absolute) - Button states + 0x75, 0x03, // Report Size (5) + 0x95, 0x01, // Report Count (1) + 0x81, 0x01, // Input (Constant) - Padding or Reserved bits + + 0x05,0x01, // Usage Page (Generic Desktop Control) + 0x09,0x30, // Usage (X) + 0x09,0x31, // Usage (Y) + + 0x16,0x01,0x80, // LOGICAL_MINIMUM(0) + 0x26,0xff,0x7f, + 0x75,0x10, // Report Size (16) + 0x95,0x02, // Report Count (2) + 0x81,0x06, // Input (Data, Variable, Relative) + + //0x05,0x01, // Usage Page (Generic Desktop Control) + 0x09,0x38, // Usage (Wheel) + 0x15,0x81, // Logical Minimum (-4) + 0x25,0x7F, // Logical Maximum (3) + 0x75,0x08, // Report Size (3) + 0x95,0x01, // Report Count (1) + 0x81,0x06, // Input (Data, Variable, Relative) + + 0xC0, // End Collection + 0xC0, // End Collection +}; + + +struct hids_info { + uint16_t version; /* version number of base USB HID Specification */ + uint8_t code; /* country HID Device hardware is localized for. */ + uint8_t flags; +} __packed; + +struct hids_report { + uint8_t id; /* report id */ + uint8_t type; /* report type */ +} __packed; + +/* HID Info Value: HID Spec version, country code, flags */ +const struct hids_info hid_info_val = { + .version = HID_VERSION, + .code = 0x00, + .flags = HIDS_NORMALLY_CONNECTABLE, +}; + +/* HID Control Point Value */ +uint8_t hid_cp_val; + +struct _bt_gatt_ccc hid_ccc[5]; + +/* HID Input Report Reference - ID, Type */ +const struct hids_report hid_val_irep1_id_map = { + .id = HIDS_MOUSE_INPUT_REPORT_ID, + .type = HID_REPORT_TYPE_INPUT, +}; + +/* HID Input Report Reference - ID, Type */ +const struct hids_report hid_val_irep2_id_map = { + .id = HIDS_KEYBOARD_INPUT_REPORT_ID, + .type = HID_REPORT_TYPE_INPUT, +}; + +/* HID Input Report Reference - ID, Type */ +const struct hids_report hid_val_irep3_id_map = { + .id = HIDS_CONSUMER_INPUT_REPORT_ID, + .type = HID_REPORT_TYPE_INPUT, +}; + +/* HID Input Report Reference - ID, Type */ +const struct hids_report hid_val_irep4_id_map = { + .id = HIDS_SYSTEM_INPUT_REPORT_ID, + .type = HID_REPORT_TYPE_INPUT, +}; + +/* HID Input Report Reference - ID, Type */ +const struct hids_report hid_val_irep5_id_map = { + .id = HIDS_ALL_KEY_INPUT_REPORT_ID, + .type = HID_REPORT_TYPE_INPUT, +}; + +/* HID Input Report Reference - ID, Type */ +const struct hids_report hid_val_irep6_id_map = { + .id = HIDS_VENDOR_INPUT_REPORT_ID, + .type = HID_REPORT_TYPE_INPUT, +}; + +/* HID Output Report Reference - ID, Type */ +const struct hids_report hid_val_orep_id_map = { + .id = 0x0a, + .type = HID_REPORT_TYPE_OUTPUT, +}; + +/* HID Feature Report Reference - ID, Type */ +const struct hids_report hid_val_frep_id_map = { + .id = 0x00, + .type = HID_REPORT_TYPE_FEATURE, +}; + +/* HID Protocol Mode Value */ +static uint8_t hid_pm_val = HID_PROTOCOL_MODE_REPORT; +static const uint16_t hid_len_pm_val = sizeof(hid_pm_val); + +static uint8_t bt_attr_get_id(const struct bt_gatt_attr *attr); +//static struct hid_report_id_map_t *hid_get_report_id_map(uint16_t handle); + +static ssize_t read_info(struct bt_conn *conn, + const struct bt_gatt_attr *attr, void *buf, + uint16_t len, uint16_t offset) +{ + return bt_gatt_attr_read(conn, attr, buf, len, offset, attr->user_data, + sizeof(struct hids_info)); +} + +static ssize_t read_report_map(struct bt_conn *conn, + const struct bt_gatt_attr *attr, void *buf, + uint16_t len, uint16_t offset) +{ + return bt_gatt_attr_read(conn, attr, buf, len, offset, hid_report_map, + sizeof(hid_report_map)); +} + +static ssize_t read_ext_report(struct bt_conn *conn, + const struct bt_gatt_attr *attr, void *buf, + uint16_t len, uint16_t offset) +{ + uint8_t hid_ext_report[] = {((uint8_t) (BT_UUID_BAS_BATTERY_LEVEL_VAL)), ((uint8_t)((BT_UUID_BAS_BATTERY_LEVEL_VAL) >> 8))}; + uint16_t hid_len_ext_report = sizeof(hid_ext_report); + + return bt_gatt_attr_read(conn, attr, buf, len, offset, hid_ext_report, + hid_len_ext_report); +} + +static ssize_t write_ctrl_point(struct bt_conn *conn, + const struct bt_gatt_attr *attr, + const void *buf, uint16_t len, uint16_t offset, + uint8_t flags) +{ + uint8_t *value = attr->user_data; + + if (offset + len > sizeof(ctrl_point)) { + return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET); + } + + memcpy(value + offset, buf, len); + + return len; +} + +static ssize_t read_report_reference(struct bt_conn *conn, + const struct bt_gatt_attr *attr, void *buf, + uint16_t len, uint16_t offset) +{ + return bt_gatt_attr_read(conn, attr, buf, len, offset, attr->user_data, + sizeof(struct hids_report)); +} + +static ssize_t read_report_value(struct bt_conn *conn, + const struct bt_gatt_attr *attr, void *buf, + uint16_t len, uint16_t offset) +{ + struct hid_report_id_map_t *p_id_map; + + if (offset > HID_MAX_REPORT_LEN) + return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET); + #if 0 + /* notify the application */ + if (hid_cb.p_config->input_cback != NULL) { + p_id_map = hid_get_report_id_map(bt_attr_get_id(attr)); + + if (p_id_map != NULL) + hid_cb.p_config->input_cback(conn, p_id_map->id, len, (uint8_t *)buf); + } + #endif + return len; +} + +static ssize_t write_report_value(struct bt_conn *conn, + const struct bt_gatt_attr *attr, + const void *buf, uint16_t len, uint16_t offset, + uint8_t flags) +{ + struct hid_report_id_map_t *p_id_map; + + printk("write_report_value: len %d\r\n", len); + printk("write_report_value: buf[0] %x\r\n"); + + if (offset + len > HID_MAX_REPORT_LEN) + return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET); + + #if 0 + /* notify the application */ + if (hid_cb.p_config->output_cback != NULL) { + p_id_map = hid_get_report_id_map(bt_attr_get_id(attr)); + + if (p_id_map != NULL) + hid_cb.p_config->output_cback(conn, p_id_map->id, len, (uint8_t *)buf); + } + #endif + return len; +} + +static void hid_ccc_changed(const struct bt_gatt_attr *attr, uint16_t value) +{ + hid_set_ccc_table_value(bt_attr_get_id(attr), value); + connect_complete = 1; + printk("handle: %d, ccc_value : %d", bt_attr_get_id(attr), value); +} + +static ssize_t read_protocol_mode(struct bt_conn *conn, + const struct bt_gatt_attr *attr, void *buf, + uint16_t len, uint16_t offset) +{ + return bt_gatt_attr_read(conn, attr, buf, len, offset, attr->user_data, + hid_len_pm_val); +} + + +static ssize_t write_protocol_mode(struct bt_conn *conn, + const struct bt_gatt_attr *attr, + const void *buf, uint16_t len, uint16_t offset, + uint8_t flags) +{ + if (offset + len > 1) + return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET); + #if 0 + if (hid_cb.p_config->info_cback != NULL) + hid_cb.p_config->info_cback(conn, HID_INFO_PROTOCOL_MODE, *((uint8_t *)buf)); + #endif + return len; +} + +/* HID Service Declaration */ +BT_GATT_SERVICE_DEFINE(hog_svc, + + BT_GATT_PRIMARY_SERVICE(BT_UUID_HIDS), + + BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_INFO, BT_GATT_CHRC_READ, + BT_GATT_PERM_READ_ENCRYPT, + read_info, NULL, (void *)&hid_info_val), + + BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_REPORT_MAP, BT_GATT_CHRC_READ, + BT_GATT_PERM_READ_ENCRYPT, + read_report_map, NULL, NULL), + BT_GATT_DESCRIPTOR(BT_UUID_HIDS_EXT_REPORT, BT_GATT_PERM_READ_ENCRYPT, + read_ext_report, NULL, NULL), + + BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_CTRL_POINT, + BT_GATT_CHRC_WRITE_WITHOUT_RESP, + BT_GATT_PERM_WRITE_ENCRYPT, + NULL, write_ctrl_point, &hid_cp_val), + + BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_BOOT_KB_IN_REPORT, + BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, + BT_GATT_PERM_READ_ENCRYPT, + read_report_value, NULL, NULL), + BT_GATT_CCC(hid_ccc_changed, + BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_WRITE_ENCRYPT), + + BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_BOOT_KB_OUT_REPORT, + BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE_WITHOUT_RESP | BT_GATT_CHRC_WRITE, + BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_WRITE_ENCRYPT, + read_report_value, write_report_value, NULL), + + BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_BOOT_MOUSE_IN_REPORT, + BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, + BT_GATT_PERM_READ_ENCRYPT, + read_report_value, NULL, (void *)NULL), + BT_GATT_CCC(hid_ccc_changed, + BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_WRITE_ENCRYPT), + /*hid input report 1*/ + BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_REPORT, + BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, + BT_GATT_PERM_READ_ENCRYPT, + read_report_value, NULL, NULL), + BT_GATT_CCC(hid_ccc_changed, + BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_WRITE_ENCRYPT), + BT_GATT_DESCRIPTOR(BT_UUID_HIDS_REPORT_REF, BT_GATT_PERM_READ_ENCRYPT, + read_report_reference, NULL, (void *)&hid_val_irep1_id_map), + /*hid input report 2*/ + BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_REPORT, + BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, + BT_GATT_PERM_READ_ENCRYPT, + read_report_value, NULL, NULL), + BT_GATT_CCC(hid_ccc_changed, + BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_WRITE_ENCRYPT), + BT_GATT_DESCRIPTOR(BT_UUID_HIDS_REPORT_REF, BT_GATT_PERM_READ_ENCRYPT, + read_report_reference, NULL, (void *)&hid_val_irep2_id_map), + /*hid input report 3*/ + BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_REPORT, + BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, + BT_GATT_PERM_READ_ENCRYPT, + read_report_value, NULL, NULL), + BT_GATT_CCC(hid_ccc_changed, + BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_WRITE_ENCRYPT), + BT_GATT_DESCRIPTOR(BT_UUID_HIDS_REPORT_REF, BT_GATT_PERM_READ_ENCRYPT, + read_report_reference, NULL, (void *)&hid_val_irep3_id_map), + + /*hid input report 4*/ + BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_REPORT, + BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, + BT_GATT_PERM_READ_ENCRYPT, + read_report_value, NULL, NULL), + BT_GATT_CCC(hid_ccc_changed, + BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_WRITE_ENCRYPT), + BT_GATT_DESCRIPTOR(BT_UUID_HIDS_REPORT_REF, BT_GATT_PERM_READ_ENCRYPT, + read_report_reference, NULL, (void *)&hid_val_irep4_id_map), + + /*hid input report 5*/ + BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_REPORT, + BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, + BT_GATT_PERM_READ_ENCRYPT, + read_report_value, NULL, NULL), + BT_GATT_CCC(hid_ccc_changed, + BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_WRITE_ENCRYPT), + BT_GATT_DESCRIPTOR(BT_UUID_HIDS_REPORT_REF, BT_GATT_PERM_READ_ENCRYPT, + read_report_reference, NULL, (void *)&hid_val_irep5_id_map), + + /*hid input report 6*/ + BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_REPORT, + BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, + BT_GATT_PERM_READ_ENCRYPT, + read_report_value, NULL, NULL), + BT_GATT_CCC(hid_ccc_changed, + BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_WRITE_ENCRYPT), + BT_GATT_DESCRIPTOR(BT_UUID_HIDS_REPORT_REF, BT_GATT_PERM_READ_ENCRYPT, + read_report_reference, NULL, (void *)&hid_val_irep6_id_map), + + /*hid output report*/ + BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_REPORT, + BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE_WITHOUT_RESP | BT_GATT_CHRC_WRITE, + BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_WRITE_ENCRYPT, + read_report_value, write_report_value, NULL), + BT_GATT_DESCRIPTOR(BT_UUID_HIDS_REPORT_REF, BT_GATT_PERM_READ_ENCRYPT, + read_report_reference, NULL, (void *)&hid_val_orep_id_map), + /*hid feature report*/ + BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_REPORT, + BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE, + BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_WRITE_ENCRYPT, + read_report_value, write_report_value, NULL), + BT_GATT_DESCRIPTOR(BT_UUID_HIDS_REPORT_REF, BT_GATT_PERM_READ_ENCRYPT, + read_report_reference, NULL, (void *)&hid_val_frep_id_map), + /*hid protocol mode*/ + BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_PROTOCOL_MODE, + BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE_WITHOUT_RESP, + BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_WRITE_ENCRYPT, + read_protocol_mode, write_protocol_mode, &hid_pm_val), +); + +void hog_init(void) +{ + +} + +static uint8_t bt_attr_get_id(const struct bt_gatt_attr *attr) +{ + return attr - attr_hog_svc; +} + +struct hids_ccc hids_ccc_table[] = { + /* handle value*/ +{HID_KEYBOARD_BOOT_IN_CH_CCC_HDL, 0}, +{HID_MOUSE_BOOT_IN_CH_CCC_HDL, 0}, +{HID_INPUT_REPORT_1_CH_CCC_HDL, 0}, +{HID_INPUT_REPORT_2_CH_CCC_HDL, 0}, +{HID_INPUT_REPORT_3_CH_CCC_HDL, 0}, +{HID_INPUT_REPORT_4_CH_CCC_HDL, 0}, +{HID_INPUT_REPORT_5_CH_CCC_HDL, 0}, +{HID_INPUT_REPORT_6_CH_CCC_HDL, 0}, +}; + +void hid_set_ccc_table_value(uint16_t handle, uint8_t value) +{ + uint8_t i = 0; + + for (i = 0; i < ARRAY_SIZE(hids_ccc_table); i++) { + if (hids_ccc_table[i].handle == handle) { + hids_ccc_table[i].value = value; + break; + } + } +} + +uint8_t hid_get_ccc_table_value(uint16_t handle) +{ + uint8_t i = 0; + + for (i = 0; i < ARRAY_SIZE(hids_ccc_table); i++) { + if (hids_ccc_table[i].handle == handle) + return hids_ccc_table[i].value; + } + return 0; +} + +int hid_send_input_report(struct bt_conn *conn, uint8_t report_id, uint8_t *p_value, uint16_t len) +{ + #if 0 + uint16_t handle = hid_get_report_handle(HID_REPORT_TYPE_INPUT, report_id); + + if ((handle != 0) && hid_ccc_is_enabled(handle+1)) + return bt_gatt_notify(conn, &attrs[handle], p_value, len); + else + return -EIO; + #endif + + return bt_gatt_notify(conn, &hog_svc.attrs[HID_INPUT_REPORT_3_HDL], p_value, len); +} + +int ble_nortify_keyboard_data(const void *data, uint16_t len) +{ + if (hid_get_ccc_table_value(HID_INPUT_REPORT_2_CH_CCC_HDL)) { + return bt_gatt_notify(NULL, &hog_svc.attrs[HID_INPUT_REPORT_2_HDL], data, len); + } else { + //printk("k"); + return -1; + } +} + +int ble_nortify_consumer_data(const void *data, uint16_t len) +{ + if (hid_get_ccc_table_value(HID_INPUT_REPORT_3_CH_CCC_HDL)) { + return bt_gatt_notify(NULL, &hog_svc.attrs[HID_INPUT_REPORT_3_HDL], data, len); + } else { + //printk("c"); + return -1; + } +} + +int ble_nortify_all_key_data(const void *data, uint16_t len) +{ + if (hid_get_ccc_table_value(HID_INPUT_REPORT_5_CH_CCC_HDL)) { + return bt_gatt_notify(NULL, &hog_svc.attrs[HID_INPUT_REPORT_5_HDL], data, len); + } else { + //printk("a"); + return -1; + } +} diff --git a/samples/bluetooth/peripheral_kmd/src/hog.h b/samples/bluetooth/peripheral_kmd/src/hog.h new file mode 100644 index 0000000000000..ba6ba3661b5b0 --- /dev/null +++ b/samples/bluetooth/peripheral_kmd/src/hog.h @@ -0,0 +1,130 @@ +/** @file + * @brief HoG Service sample + */ + +/* + * Copyright (c) 2016 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#define HIDS_MOUSE_INPUT_REPORT_ID 0x01 +#define HIDS_KEYBOARD_INPUT_REPORT_ID 0x02 +#define HIDS_CONSUMER_INPUT_REPORT_ID 0x03 +#define HIDS_SYSTEM_INPUT_REPORT_ID 0x04 +#define HIDS_ALL_KEY_INPUT_REPORT_ID 0x05 +#define HIDS_VENDOR_INPUT_REPORT_ID 0x06 + + +/* HID Boot Report ID */ +#define HID_KEYBOARD_BOOT_ID 0xFF +#define HID_MOUSE_BOOT_ID 0xFE + +/* HID Report Type/ID to Attribute handle map item */ +struct hid_report_id_map_t { + uint8_t type; + uint8_t id; + uint16_t handle; +}; + + +struct hids_ccc { + uint16_t handle; /* ccc handle */ + uint8_t value; /* ccc value */ +} __packed; + +/* HID Spec Version: 1.11 */ +#define HID_VERSION 0x0111 + +/* HID Report Types */ +#define HID_REPORT_TYPE_INPUT 0x01 +#define HID_REPORT_TYPE_OUTPUT 0x02 +#define HID_REPORT_TYPE_FEATURE 0x03 + +/* HID Protocol Mode Types */ +#define HID_PROTOCOL_MODE_BOOT 0x00 +#define HID_PROTOCOL_MODE_REPORT 0x01 + +/* HID Control Point Values */ +#define HID_CONTROL_POINT_SUSPEND 0x00 +#define HID_CONTROL_POINT_RESUME 0x01 + +/* Max length of an output report value */ +#define HID_MAX_REPORT_LEN 32 + +/* Proprietary Service */ +#define HID_START_HDL 0x0 +#define HID_END_HDL (HID_MAX_HDL - 1) + +/* Proprietary Service Handles Common to HID Devices */ +enum { + HID_SVC_HDL = HID_START_HDL, /* Proprietary Service Declaration */ + HID_INFO_CH_HDL, /* HID Information Characteristic Declaration */ + HID_INFO_HDL, /* HID Information Value */ + HID_REPORT_MAP_CH_HDL, /* HID Report Map Characteristic Declaration */ + HID_REPORT_MAP_HDL, /* HID Report Map Value */ + HID_EXTERNAL_REPORT_HDL, /* HID External Report Descriptor */ + HID_CONTROL_POINT_CH_HDL, /* HID Control Point Characteristic Declaration */ + HID_CONTROL_POINT_HDL, /* HID Control Point Value */ + HID_KEYBOARD_BOOT_IN_CH_HDL, /* HID Keyboard Boot Input Characteristic Declaration */ + HID_KEYBOARD_BOOT_IN_HDL, /* HID Keyboard Boot Input Value */ + HID_KEYBOARD_BOOT_IN_CH_CCC_HDL, /* HID Keyboard Boot Input CCC Descriptor */ + HID_KEYBOARD_BOOT_OUT_CH_HDL, /* HID Keyboard Boot Output Characteristic Declaration */ + HID_KEYBOARD_BOOT_OUT_HDL, /* HID Keyboard Boot Output Value */ + HID_MOUSE_BOOT_IN_CH_HDL, /* HID Mouse Boot Input Characteristic Declaration */ + HID_MOUSE_BOOT_IN_HDL, /* HID Mouse Boot Input Value */ + HID_MOUSE_BOOT_IN_CH_CCC_HDL, /* HID Mouse Boot Input CCC Descriptor */ + HID_INPUT_REPORT_1_CH_HDL, /* HID Input Report Characteristic Declaration */ + HID_INPUT_REPORT_1_HDL, /* HID Input Report Value */ + HID_INPUT_REPORT_1_CH_CCC_HDL, /* HID Input Report CCC Descriptor */ + HID_INPUT_REPORT_1_REFERENCE_HDL, /* HID Input Report Reference Descriptor */ + HID_INPUT_REPORT_2_CH_HDL, /* HID Input Report Characteristic Declaration */ + HID_INPUT_REPORT_2_HDL, /* HID Input Report Value */ + HID_INPUT_REPORT_2_CH_CCC_HDL, /* HID Input Report CCC Descriptor */ + HID_INPUT_REPORT_2_REFERENCE_HDL, /* HID Input Report Reference Descriptor */ + HID_INPUT_REPORT_3_CH_HDL, /* HID Input Report Characteristic Declaration */ + HID_INPUT_REPORT_3_HDL, /* HID Input Report Value */ + HID_INPUT_REPORT_3_CH_CCC_HDL, /* HID Input Report CCC Descriptor */ + HID_INPUT_REPORT_3_REFERENCE_HDL, /* HID Input Report Reference Descriptor */ + HID_INPUT_REPORT_4_CH_HDL, /* HID Input Report Characteristic Declaration */ + HID_INPUT_REPORT_4_HDL, /* HID Input Report Value */ + HID_INPUT_REPORT_4_CH_CCC_HDL, /* HID Input Report CCC Descriptor */ + HID_INPUT_REPORT_4_REFERENCE_HDL, /* HID Input Report Reference Descriptor */ + + HID_INPUT_REPORT_5_CH_HDL, /* HID Input Report Characteristic Declaration */ + HID_INPUT_REPORT_5_HDL, /* HID Input Report Value */ + HID_INPUT_REPORT_5_CH_CCC_HDL, /* HID Input Report CCC Descriptor */ + HID_INPUT_REPORT_5_REFERENCE_HDL, /* HID Input Report Reference Descriptor */ + + HID_INPUT_REPORT_6_CH_HDL, /* HID Input Report Characteristic Declaration */ + HID_INPUT_REPORT_6_HDL, /* HID Input Report Value */ + HID_INPUT_REPORT_6_CH_CCC_HDL, /* HID Input Report CCC Descriptor */ + HID_INPUT_REPORT_6_REFERENCE_HDL, /* HID Input Report Reference Descriptor */ + + HID_OUTPUT_REPORT_CH_HDL, /* HID Output Report Characteristic Declaration */ + HID_OUTPUT_REPORT_HDL, /* HID Output Report Value */ + HID_OUTPUT_REPORT_REFERENCE_HDL, /* HID Output Report Reference Descriptor */ + HID_FEATURE_REPORT_CH_HDL, /* HID Feature Report Characteristic Declaration */ + HID_FEATURE_REPORT_HDL, /* HID Feature Report Value */ + HID_FEATURE_REPORT_REFERENCE_HDL, /* HID Feature Report Reference Descriptor */ + HID_PROTOCOL_MODE_CH_HDL, /* HID Protocol Mode Characteristic Declaration */ + HID_PROTOCOL_MODE_HDL, /* HID Protocol Mode Value */ + HID_MAX_HDL +}; + +void hog_init(void); + +void hog_button_loop(void); + +void hid_set_ccc_table_value(uint16_t handle, uint8_t value); +uint8_t hid_get_ccc_table_value(uint16_t handle); +int ble_nortify_all_key_data(const void *data, uint16_t len); +int ble_nortify_keyboard_data(const void *data, uint16_t len); +int ble_nortify_consumer_data(const void *data, uint16_t len); +#ifdef __cplusplus +} +#endif diff --git a/samples/bluetooth/peripheral_kmd/src/main.c b/samples/bluetooth/peripheral_kmd/src/main.c new file mode 100644 index 0000000000000..af5ffbaa71629 --- /dev/null +++ b/samples/bluetooth/peripheral_kmd/src/main.c @@ -0,0 +1,65 @@ +/* main.c - Application main entry point */ + +/* + * Copyright (c) 2016 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include "app_public.h" + +#include "keyscan_ana.h" + +#define LOG_LEVEL LOG_LEVEL_DBG +#include +LOG_MODULE_REGISTER(main); + + +int main(void) +{ + gpio_function_en(GPIO_PH1); + gpio_output_en(GPIO_PH1); + gpio_input_dis(GPIO_PH1); + + gpio_function_en(GPIO_PG7); + gpio_output_en(GPIO_PG7); + gpio_input_dis(GPIO_PG7); + + gpio_function_en(GPIO_PB4); + gpio_output_en(GPIO_PB4); + gpio_input_dis(GPIO_PB4); + + gpio_function_en(GPIO_PB5); + gpio_output_en(GPIO_PB5); + gpio_input_dis(GPIO_PB5); + + + gpio_set_level(GPIO_PB5, 1); + gpio_set_level(GPIO_PG7, 1); + + keyboard_comm_init(); + + while(1) { + + public_loop(); + k_sleep(K_MSEC(3)); + } + + return 0; +} diff --git a/samples/bluetooth/peripheral_ota/CMakeLists.txt b/samples/bluetooth/peripheral_ota/CMakeLists.txt new file mode 100644 index 0000000000000..2ac6fd5c1f370 --- /dev/null +++ b/samples/bluetooth/peripheral_ota/CMakeLists.txt @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(peripheral_ht) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE + ${app_sources} + ) diff --git a/samples/bluetooth/peripheral_ota/Kconfig b/samples/bluetooth/peripheral_ota/Kconfig new file mode 100644 index 0000000000000..078f853a4cd86 --- /dev/null +++ b/samples/bluetooth/peripheral_ota/Kconfig @@ -0,0 +1,6 @@ +# Copyright (c) 2021 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +mainmenu "Bluetooth: Peripheral OTA" + +source "Kconfig.zephyr" diff --git a/samples/bluetooth/peripheral_ota/README.rst b/samples/bluetooth/peripheral_ota/README.rst new file mode 100644 index 0000000000000..9bf90915e528c --- /dev/null +++ b/samples/bluetooth/peripheral_ota/README.rst @@ -0,0 +1,25 @@ +.. _peripheral_ht: + +Bluetooth: Peripheral OTA +######################## + +Overview +******** + +Similar to the :ref:`Peripheral ` sample, except that this +application specifically exposes the Telink OTA GATT Service. + + +Requirements +************ + +* BlueZ running on the host, or +* A board with BLE support + +Building and Running +******************** + +This sample can be found under :zephyr_file:`samples/bluetooth/peripheral_ota` in the +Zephyr tree. + +See :ref:`bluetooth samples section ` for details. diff --git a/samples/bluetooth/peripheral_ota/prj.conf b/samples/bluetooth/peripheral_ota/prj.conf new file mode 100644 index 0000000000000..77c30669b9f73 --- /dev/null +++ b/samples/bluetooth/peripheral_ota/prj.conf @@ -0,0 +1,8 @@ +CONFIG_BT=y +CONFIG_BT_DEBUG_LOG=y +CONFIG_BT_SMP=y +CONFIG_BT_PERIPHERAL=y +CONFIG_BT_DIS=y +CONFIG_BT_DIS_PNP=n +CONFIG_BT_DEVICE_NAME="Zephyr OTA" +CONFIG_BT_ATT_ENFORCE_FLOW=n diff --git a/samples/bluetooth/peripheral_ota/sample.yaml b/samples/bluetooth/peripheral_ota/sample.yaml new file mode 100644 index 0000000000000..0831cb7b71c63 --- /dev/null +++ b/samples/bluetooth/peripheral_ota/sample.yaml @@ -0,0 +1,17 @@ +sample: + name: Bluetooth Peripheral OTA + description: Demonstrates the Telink OTA Service +tests: + sample.bluetooth.peripheral_ota: + harness: bluetooth + platform_allow: qemu_cortex_m3 qemu_x86 nrf51dk_nrf51422 nrf52dk_nrf52832 + tags: bluetooth + integration_platforms: + - qemu_cortex_m3 + sample.bluetooth.peripheral_ht.frdm_kw41z_shield: + harness: bluetooth + platform_allow: mimxrt1020_evk mimxrt1050_evk mimxrt1060_evk frdm_k64f + tags: bluetooth + extra_args: SHIELD=frdm_kw41z + integration_platforms: + - mimxrt1020_evk diff --git a/samples/bluetooth/peripheral_ota/src/main.c b/samples/bluetooth/peripheral_ota/src/main.c new file mode 100644 index 0000000000000..ac9a86e338c50 --- /dev/null +++ b/samples/bluetooth/peripheral_ota/src/main.c @@ -0,0 +1,95 @@ +/* main.c - Application main entry point */ + +/* + * Copyright (c) 2019 Aaron Tsui + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +static const struct bt_data ad[] = { + BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)), +}; + +static void connected(struct bt_conn *conn, uint8_t err) +{ + if (err) { + printk("Connection failed (err 0x%02x)\n", err); + } else { + printk("Connected\n"); + } +} + +static void disconnected(struct bt_conn *conn, uint8_t reason) +{ + printk("Disconnected (reason 0x%02x)\n", reason); +} + +BT_CONN_CB_DEFINE(conn_callbacks) = { + .connected = connected, + .disconnected = disconnected, +}; + +static void bt_ready(void) +{ + int err; + + printk("Bluetooth initialized\n"); + + err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, ARRAY_SIZE(ad), NULL, 0); + if (err) { + printk("Advertising failed to start (err %d)\n", err); + return; + } + + printk("Advertising successfully started\n"); +} + +static void auth_cancel(struct bt_conn *conn) +{ + char addr[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + printk("Pairing cancelled: %s\n", addr); +} + +static struct bt_conn_auth_cb auth_cb_display = { + .cancel = auth_cancel, +}; + +int main(void) +{ + int err; + + err = bt_enable(NULL); + if (err) { + printk("Bluetooth init failed (err %d)\n", err); + return 0; + } + + bt_ready(); + + bt_conn_auth_cb_register(&auth_cb_display); + + /* Implement indicate. At the moment there is no suitable way + * of starting delayed work so we do it here + */ + while (1) { + k_sleep(K_SECONDS(1)); + } + return 0; +} diff --git a/samples/boards/tlsr9x/nested_isr/CMakeLists.txt b/samples/boards/tlsr9x/nested_isr/CMakeLists.txt new file mode 100644 index 0000000000000..88670d7ec7460 --- /dev/null +++ b/samples/boards/tlsr9x/nested_isr/CMakeLists.txt @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(nested_isr) + +target_sources(app PRIVATE src/main.c) diff --git a/samples/boards/tlsr9x/nested_isr/boards/tl3228x.overlay b/samples/boards/tlsr9x/nested_isr/boards/tl3228x.overlay new file mode 100644 index 0000000000000..f6ae4b9c0a855 --- /dev/null +++ b/samples/boards/tlsr9x/nested_isr/boards/tl3228x.overlay @@ -0,0 +1,10 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2023 Telink Semiconductor (Shanghai) Co., Ltd. + */ + +&gpiog { + interrupts = <49 3>; + status = "okay"; +}; diff --git a/samples/boards/tlsr9x/nested_isr/prj.conf b/samples/boards/tlsr9x/nested_isr/prj.conf new file mode 100644 index 0000000000000..932b79829cf36 --- /dev/null +++ b/samples/boards/tlsr9x/nested_isr/prj.conf @@ -0,0 +1 @@ +# Empty file diff --git a/samples/boards/tlsr9x/nested_isr/src/main.c b/samples/boards/tlsr9x/nested_isr/src/main.c new file mode 100644 index 0000000000000..c71a241738a06 --- /dev/null +++ b/samples/boards/tlsr9x/nested_isr/src/main.c @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2016 Open-RnD Sp. z o.o. + * Copyright (c) 2020 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Get button configuration from the devicetree sw0 alias. This is mandatory. + */ +#define SW0_NODE DT_ALIAS(sw0) +#if !DT_NODE_HAS_STATUS(SW0_NODE, okay) +#error "Unsupported board: sw0 devicetree alias is not defined" +#endif +static const struct gpio_dt_spec button = GPIO_DT_SPEC_GET_OR(SW0_NODE, gpios, + {0}); +static struct gpio_callback button_cb_data; + +/* + * The led0 devicetree alias is optional. If present, we'll use it + * to turn on the LED whenever the button is pressed. + */ +static struct gpio_dt_spec led = GPIO_DT_SPEC_GET_OR(DT_ALIAS(led0), gpios, + {0}); + +static struct gpio_dt_spec led1 = GPIO_DT_SPEC_GET_OR(DT_ALIAS(led1), gpios, + {1}); + +static struct gpio_dt_spec led2 = GPIO_DT_SPEC_GET_OR(DT_ALIAS(led2), gpios, + {2}); + +/* Button interrupt handler */ +void button_pressed(const struct device *dev, struct gpio_callback *cb, + uint32_t pins) +{ + printk("Button ISR Start\n"); + gpio_pin_toggle_dt(&led1); + delay_ms(50); + gpio_pin_toggle_dt(&led1); + printk("Button ISR Finish\n"); +} + +/* Timer0 interrupt handler */ +static void timer0_isr(const struct gpio_dt_spec *led) +{ + if (timer_get_irq_status(FLD_TMR0_MODE_IRQ)){ + printk("Timer 0 ISR Start\n"); + gpio_pin_toggle_dt(led); + timer_clr_irq_status(FLD_TMR0_MODE_IRQ); //Clear IRQ status + delay_ms(150); + gpio_pin_toggle_dt(led); + printk("Timer 0 ISR Finish\n"); + } +} + +/* Timer1 interrupt handler */ +static void timer1_isr(const struct gpio_dt_spec *led2) +{ + if (timer_get_irq_status(FLD_TMR1_MODE_IRQ)){ + printk("Timer 1 ISR Start\n"); + gpio_pin_toggle_dt(led2); + timer_clr_irq_status(FLD_TMR1_MODE_IRQ); //Clear IRQ status + delay_ms(80); + gpio_pin_toggle_dt(led2); + printk("Timer 1 ISR Finish\n"); + } +} + +/* Print current PLIC and interrupt configuration */ +static void show_isr_configuration(void) +{ + printk("mmisc_ctl %08x [vector mode %s]\n", (uint32_t) csr_read(mmisc_ctl), + (uint32_t) csr_read(mmisc_ctl) & 0x2 ? "enabled" : "disabled"); + + const uint32_t * const plic_base = (uint32_t *)DT_REG_ADDR(DT_NODELABEL(plic0)); + + printk("PLIC base address %p\n", plic_base); + + uint32_t plic_fen = *(plic_base); + + printk("PLIC_FEN %08x [vector mode %s, preemptive priority interrupt %s]\n", + plic_fen, + plic_fen & 0x2 ? "enabled" : "disabled", + plic_fen & 0x1 ? "enabled" : "disabled"); + + + printk("PLIC_PRI:\n"); + for (size_t i = 1; i <= DT_PROP(DT_NODELABEL(plic0), riscv_ndev); i++) { + if (*(plic_base + i)) { + printk("[%02zu] %u\n", i, *(plic_base + i)); + } + } + + printk("PLIC_IE:"); + for (size_t i = 1; i <= DT_PROP(DT_NODELABEL(plic0), riscv_ndev); i++) { + size_t word = i / 32; + uint8_t bit = i % 32; + + if (*((uint32_t *)((uint8_t *)plic_base + 0x2000) + word) & (1 << bit)) { + printk(" %02zu",i); + } + } + printk("\n"); +} + +int main(void) +{ + int ret; + + if (!gpio_is_ready_dt(&button)) { + printk("Error: button device %s is not ready\n", + button.port->name); + return 0; + } + + ret = gpio_pin_configure_dt(&button, GPIO_INPUT); + if (ret != 0) { + printk("Error %d: failed to configure %s pin %d\n", + ret, button.port->name, button.pin); + return 0; + } + + ret = gpio_pin_interrupt_configure_dt(&button, + GPIO_INT_EDGE_TO_ACTIVE); + if (ret != 0) { + printk("Error %d: failed to configure interrupt on %s pin %d\n", + ret, button.port->name, button.pin); + return 0; + } + + gpio_init_callback(&button_cb_data, button_pressed, BIT(button.pin)); + gpio_add_callback(button.port, &button_cb_data); + riscv_plic_set_priority(IRQ_GPIO_IRQ3, 3); + printk("Set up button at %s pin %d\n", button.port->name, button.pin); + + if (led.port && !device_is_ready(led.port)) { + printk("Error %d: LED device %s is not ready; ignoring it\n", + ret, led.port->name); + led.port = NULL; + } + if (led.port) { + ret = gpio_pin_configure_dt(&led, GPIO_OUTPUT); + if (ret != 0) { + printk("Error %d: failed to configure LED device %s pin %d\n", + ret, led.port->name, led.pin); + led.port = NULL; + } else { + printk("Set up LED at %s pin %d\n", led.port->name, led.pin); + } + } + + /* Initialize LED1 */ + if (led1.port && !gpio_is_ready_dt(&led1)) { + printk("Error: LED1 device %s is not ready; ignoring it\n", + led1.port->name); + led1.port = NULL; + } + if (led1.port) { + ret = gpio_pin_configure_dt(&led1, GPIO_OUTPUT); + if (ret != 0) { + printk("Error %d: failed to configure LED1 device %s pin %d\n", + ret, led1.port->name, led1.pin); + led1.port = NULL; + } else { + printk("Set up LED1 at %s pin %d\n", led1.port->name, led1.pin); + } + } + + /* Initialize LED2 */ + if (led2.port && !gpio_is_ready_dt(&led2)) { + printk("Error: LED2 device %s is not ready; ignoring it\n", + led2.port->name); + led2.port = NULL; + } + if (led2.port) { + ret = gpio_pin_configure_dt(&led2, GPIO_OUTPUT); + if (ret != 0) { + printk("Error %d: failed to configure LED2 device %s pin %d\n", + ret, led2.port->name, led2.pin); + led2.port = NULL; + } else { + printk("Set up LED2 at %s pin %d\n", led2.port->name, led2.pin); + } + } + + /* Initialize and configure timers */ + if (led.port) { + /* Timer0 configuration */ + timer_set_init_tick(TIMER0, 0); + timer_set_cap_tick(TIMER0, 1000*sys_clk.pclk * 300); //300ms + timer_set_mode(TIMER0, TIMER_MODE_SYSCLK); + timer_set_irq_mask(FLD_TMR0_MODE_IRQ); + IRQ_CONNECT(CONFIG_2ND_LVL_ISR_TBL_OFFSET + IRQ_TIMER0, 2, timer0_isr, &led, 0); + riscv_plic_set_priority(IRQ_TIMER0, 1); + riscv_plic_irq_enable(IRQ_TIMER0); + + /* Timer1 configuration */ + timer_set_init_tick(TIMER1, 0); + timer_set_cap_tick(TIMER1, 1000*sys_clk.pclk * 150); //150ms + timer_set_mode(TIMER1, TIMER_MODE_SYSCLK); + timer_set_irq_mask(FLD_TMR1_MODE_IRQ); + IRQ_CONNECT(CONFIG_2ND_LVL_ISR_TBL_OFFSET + IRQ_TIMER1, 2, timer1_isr, &led2, 0); + riscv_plic_set_priority(IRQ_TIMER1, 2); + riscv_plic_irq_enable(IRQ_TIMER1); + + /* Start timers */ + timer_start(TIMER0); + timer_start(TIMER1); + } + + show_isr_configuration(); + + return 0; +} diff --git a/samples/drivers/adc/boards/tl3228x.overlay b/samples/drivers/adc/boards/tl3228x.overlay new file mode 100644 index 0000000000000..a0b53864530dd --- /dev/null +++ b/samples/drivers/adc/boards/tl3228x.overlay @@ -0,0 +1,26 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2022 Telink Semiconductor (Shanghai) Co., Ltd. + */ + +/ { + zephyr,user { + /* adjust channel number according to pinmux in board.dts */ + io-channels = <&adc 0>; + }; +}; + +&adc { + #address-cells = <1>; + #size-cells = <0>; + + channel@0 { + reg = <0>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + zephyr,input-positive = ; + }; +}; diff --git a/samples/drivers/spi_flash/boards/tl3228x.overlay b/samples/drivers/spi_flash/boards/tl3228x.overlay new file mode 100644 index 0000000000000..c18afdc3ca25f --- /dev/null +++ b/samples/drivers/spi_flash/boards/tl3228x.overlay @@ -0,0 +1,25 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2023 Telink Semiconductor (Shanghai) Co., Ltd. + */ + +/ { + aliases { + spi-flash0 = &spi1_cs0_flash; + }; +}; + + +&gspi { + status = "okay"; + spi1_cs0_flash: p25q16@0 { + compatible = "jedec,spi-nor"; + /* 16777216 bits = 2 Mbytes */ + size = <0x1000000>; + reg = <0>; + spi-max-frequency = <24000000>; + jedec-id = [ef 40 16]; + status = "okay"; + }; +}; diff --git a/samples/net/openthread/cli/boards/tl3228x.conf b/samples/net/openthread/cli/boards/tl3228x.conf new file mode 100644 index 0000000000000..7fadeeaacf67d --- /dev/null +++ b/samples/net/openthread/cli/boards/tl3228x.conf @@ -0,0 +1,10 @@ +# usb +CONFIG_USB_DEVICE_STACK=n +CONFIG_USB_DEVICE_INITIALIZE_AT_BOOT=n + +# Telink relative thread features +CONFIG_NET_PKT_TXTIME=y +CONFIG_NET_PKT_TIMESTAMP=y +CONFIG_IEEE802154_2015=y +CONFIG_OPENTHREAD_NUM_MESSAGE_BUFFERS=350 +CONFIG_IEEE802154_TLX_MAC_FLASH=y diff --git a/samples/net/openthread/cli/boards/tl3228x.overlay b/samples/net/openthread/cli/boards/tl3228x.overlay new file mode 100644 index 0000000000000..724aca7852ec6 --- /dev/null +++ b/samples/net/openthread/cli/boards/tl3228x.overlay @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2024 Telink Semiconductor + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + chosen { + zephyr,shell-uart = &uart0; + }; +}; diff --git a/samples/net/openthread/cli/boards/tl3238x.conf b/samples/net/openthread/cli/boards/tl3238x.conf new file mode 100644 index 0000000000000..21063c26284ef --- /dev/null +++ b/samples/net/openthread/cli/boards/tl3238x.conf @@ -0,0 +1,10 @@ +# usb +CONFIG_USB_DEVICE_STACK=n +CONFIG_USB_DEVICE_INITIALIZE_AT_BOOT=n + +# Telink relative thread features +CONFIG_NET_PKT_TXTIME=y +CONFIG_NET_PKT_TIMESTAMP=y +CONFIG_IEEE802154_2015=y +CONFIG_OPENTHREAD_NUM_MESSAGE_BUFFERS=250 +CONFIG_IEEE802154_TLX_MAC_FLASH=y \ No newline at end of file diff --git a/samples/net/openthread/cli/boards/tl3238x.overlay b/samples/net/openthread/cli/boards/tl3238x.overlay new file mode 100644 index 0000000000000..724aca7852ec6 --- /dev/null +++ b/samples/net/openthread/cli/boards/tl3238x.overlay @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2024 Telink Semiconductor + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + chosen { + zephyr,shell-uart = &uart0; + }; +}; diff --git a/samples/net/openthread/coprocessor/boards/tl3228x.conf b/samples/net/openthread/coprocessor/boards/tl3228x.conf new file mode 100644 index 0000000000000..de9ffd953e364 --- /dev/null +++ b/samples/net/openthread/coprocessor/boards/tl3228x.conf @@ -0,0 +1,20 @@ +CONFIG_IEEE802154_TLX_MAC_STATIC=y +CONFIG_IEEE802154_TLX_MAC4=0x01 +CONFIG_IEEE802154_TLX_MAC5=0x02 +CONFIG_IEEE802154_TLX_MAC6=0x03 +CONFIG_IEEE802154_TLX_MAC7=0x04 + +CONFIG_OPENTHREAD_THREAD_VERSION_1_3=y +CONFIG_OPENTHREAD_FTD=y +CONFIG_OPENTHREAD_MANUAL_START=y +CONFIG_OPENTHREAD_LINK_METRICS_SUBJECT=y +CONFIG_NET_PKT_TXTIME=y +CONFIG_NET_PKT_TIMESTAMP=y +CONFIG_IEEE802154_2015=n +CONFIG_OPENTHREAD_NUM_MESSAGE_BUFFERS=1025 +CONFIG_OPENTHREAD_MESSAGE_BUFFER_SIZE=256 + +CONFIG_LOG_MAX_LEVEL=4 +CONFIG_LOG_BACKEND_SPINEL=n +CONFIG_LOG_BACKEND_RTT=n +CONFIG_LOG_BACKEND_UART=y \ No newline at end of file diff --git a/samples/net/openthread/coprocessor/boards/tl3228x.overlay b/samples/net/openthread/coprocessor/boards/tl3228x.overlay new file mode 100644 index 0000000000000..fd40d88e7fde0 --- /dev/null +++ b/samples/net/openthread/coprocessor/boards/tl3228x.overlay @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2024 Telink Semiconductor + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + chosen { + zephyr,ot-uart = &uart1; + zephyr,console = &uart0; + }; +}; + +&uart1 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart1_tx_pc6_default &uart1_rx_pc7_default &uart1_rts_pc5_default &uart1_cts_pc4_default>; + pinctrl-names = "default"; + hw-flow-control; +}; + +&uart0 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart0_tx_pa0_default &uart0_rx_pa1_default>; + pinctrl-names = "default"; +}; diff --git a/samples/sensor/sht3xd/boards/tl3228x.overlay b/samples/sensor/sht3xd/boards/tl3228x.overlay new file mode 100644 index 0000000000000..dd77026fd1814 --- /dev/null +++ b/samples/sensor/sht3xd/boards/tl3228x.overlay @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2024 Telink Semiconductor + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include + +&pinctrl { + /* Define I2C pins: SCL(PE0), SDA(PE1) */ + + i2c_scl_pe0_default: i2c_scl_pe0_default { + pinmux = ; + bias-pull-up; + }; + i2c_sda_pe1_default: i2c_sda_pe1_default { + pinmux = ; + bias-pull-up; + }; +}; + +&i2c { + pinctrl-0 = <&i2c_scl_pe0_default &i2c_sda_pe1_default>; + + sht3xd@44 { + compatible = "sensirion,sht3xd"; + reg = <0x44>; + }; +}; diff --git a/samples/subsys/usb/cdc_acm/boards/tl3228x.conf b/samples/subsys/usb/cdc_acm/boards/tl3228x.conf new file mode 100644 index 0000000000000..665e5a7b28cfa --- /dev/null +++ b/samples/subsys/usb/cdc_acm/boards/tl3228x.conf @@ -0,0 +1 @@ +CONFIG_USB_TELINK_TLX=y \ No newline at end of file diff --git a/samples/subsys/usb/cdc_acm/boards/tl3228x.overlay b/samples/subsys/usb/cdc_acm/boards/tl3228x.overlay new file mode 100644 index 0000000000000..f6890fcf9feae --- /dev/null +++ b/samples/subsys/usb/cdc_acm/boards/tl3228x.overlay @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2024 Telink Semiconductor + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&zephyr_udc0 { + cdc_acm_uart0 { + compatible = "zephyr,cdc-acm-uart"; + }; +}; + +&cpu0 { + clock-frequency = <96000000>; /* USB0 digital voltage must be 1.1V and HCLK min's 48M */ +}; + + diff --git a/samples/subsys/usb/console/boards/tl3228x.conf b/samples/subsys/usb/console/boards/tl3228x.conf new file mode 100644 index 0000000000000..665e5a7b28cfa --- /dev/null +++ b/samples/subsys/usb/console/boards/tl3228x.conf @@ -0,0 +1 @@ +CONFIG_USB_TELINK_TLX=y \ No newline at end of file diff --git a/samples/subsys/usb/console/boards/tl3228x.overlay b/samples/subsys/usb/console/boards/tl3228x.overlay new file mode 100644 index 0000000000000..46766f82ebf00 --- /dev/null +++ b/samples/subsys/usb/console/boards/tl3228x.overlay @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2024 Telink Semiconductor + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + chosen { + zephyr,console = &cdc_acm_uart0; + }; +}; + +&zephyr_udc0 { + cdc_acm_uart0: cdc_acm_uart0 { + compatible = "zephyr,cdc-acm-uart"; + }; +}; + +&cpu0 { + clock-frequency = <96000000>; /* USB0 digital voltage must be 1.1V and HCLK min's 48M */ +}; + + diff --git a/samples/subsys/usb/hid-cdc/app.overlay b/samples/subsys/usb/hid-cdc/app.overlay index dc6bcf2f10575..ab92f58db0e29 100644 --- a/samples/subsys/usb/hid-cdc/app.overlay +++ b/samples/subsys/usb/hid-cdc/app.overlay @@ -4,12 +4,20 @@ * SPDX-License-Identifier: Apache-2.0 */ -&zephyr_udc0 { - cdc_acm_uart0 { - compatible = "zephyr,cdc-acm-uart"; - }; +// &zephyr_udc0 { +// cdc_acm_uart0 { +// compatible = "zephyr,cdc-acm-uart"; +// }; - cdc_acm_uart1 { - compatible = "zephyr,cdc-acm-uart"; - }; +// cdc_acm_uart1 { +// compatible = "zephyr,cdc-acm-uart"; +// }; +// }; +&cpu0 { + clock-frequency = <192000000>; /* USB0 digital voltage must be 1.1V and HCLK min's 48M */ +}; + +&uart0 { + status = "okay"; + current-speed = <2000000>; /* Baud rate for serial port logging */ }; diff --git a/samples/subsys/usb/hid-cdc/prj.conf b/samples/subsys/usb/hid-cdc/prj.conf index cf274459fb5a5..7c8e8adb03865 100644 --- a/samples/subsys/usb/hid-cdc/prj.conf +++ b/samples/subsys/usb/hid-cdc/prj.conf @@ -7,13 +7,15 @@ CONFIG_ENTROPY_GENERATOR=y CONFIG_ENTROPY_DEVICE_RANDOM_GENERATOR=y CONFIG_USB_DEVICE_HID=y -CONFIG_USB_HID_DEVICE_COUNT=2 +CONFIG_USB_HID_DEVICE_COUNT=3 CONFIG_LOG=y -CONFIG_USB_DRIVER_LOG_LEVEL_INF=y -CONFIG_USB_DEVICE_LOG_LEVEL_INF=y +CONFIG_USB_DRIVER_LOG_LEVEL_ERR=y +CONFIG_USB_DEVICE_LOG_LEVEL_ERR=y CONFIG_SERIAL=y CONFIG_UART_LINE_CTRL=y CONFIG_GPIO=y +CONFIG_USB_TELINK_TLX=y +CONFIG_USB_DC_HAS_HS_SUPPORT=y \ No newline at end of file diff --git a/samples/subsys/usb/hid-cdc/src/main.c b/samples/subsys/usb/hid-cdc/src/main.c index 77550b541f06f..ed9dff241addb 100644 --- a/samples/subsys/usb/hid-cdc/src/main.c +++ b/samples/subsys/usb/hid-cdc/src/main.c @@ -6,13 +6,13 @@ #include #include #include -#include +// #include #include #include #include #include -#include +// #include #define LOG_LEVEL LOG_LEVEL_DBG LOG_MODULE_REGISTER(main); @@ -129,6 +129,7 @@ static inline struct app_evt_t *app_evt_alloc(void) static const uint8_t hid_mouse_report_desc[] = HID_MOUSE_REPORT_DESC(2); static const uint8_t hid_kbd_report_desc[] = HID_KEYBOARD_REPORT_DESC(); +static const uint8_t hid_kb_report_desc[] = HID_MOUSE_REPORT_DESC(2); static K_SEM_DEFINE(evt_sem, 0, 1); /* starts off "not available" */ static K_SEM_DEFINE(usb_sem, 1, 1); /* starts off "available" */ @@ -146,33 +147,6 @@ static uint8_t chr_ptr_mouse, chr_ptr_kbd, str_pointer; #define MOUSE_BTN_RIGHT BIT(1) #define MOUSE_BTN_MIDDLE BIT(2) -static const char *welcome = "Welcome to "; -static const char *banner0 = "\r\n" - "Supported commands:\r\n" - "up - moves the mouse up\r\n" - "down - moves the mouse down\r\n" - "right - moves the mouse to right\r\n" - "left - moves the mouse to left\r\n"; -static const char *banner1 = "\r\n" - "Enter a string and terminate " - "it with ENTER.\r\n" - "It will be sent via HID " - "when BUTTON 2 is pressed.\r\n" - "You can modify it by sending " - "a new one here.\r\n"; -static const char *gpio0 = "Button 0 pressed\r\n"; -static const char *gpio1 = "Button 1 pressed\r\n"; -static const char *gpio2 = "Button 2 pressed\r\n"; -static const char *gpio3 = "Button 3 pressed\r\n"; -static const char *unknown = "Command not recognized.\r\n"; -static const char *up = "Mouse up\r\n"; -static const char *down = "Mouse down\r\n"; -static const char *left = "Mouse left\r\n"; -static const char *right = "Mouse right\r\n"; -static const char *evt_fail = "Unknown event detected!\r\n"; -static const char *set_str = "String set to: "; -static const char *endl = "\r\n"; - static void in_ready_cb(const struct device *dev) { ARG_UNUSED(dev); @@ -359,107 +333,6 @@ static void flush_buffer_kbd(void) memset(data_buf_kbd, 0, sizeof(data_buf_kbd)); } -static void write_data(const struct device *dev, const char *buf, int len) -{ - uart_irq_tx_enable(dev); - - while (len) { - int written; - - data_transmitted = false; - written = uart_fifo_fill(dev, (const uint8_t *)buf, len); - while (data_transmitted == false) { - k_yield(); - } - - len -= written; - buf += written; - } - - uart_irq_tx_disable(dev); -} - -static void cdc_mouse_int_handler(const struct device *dev, void *user_data) -{ - ARG_UNUSED(user_data); - - uart_irq_update(dev); - - if (uart_irq_tx_ready(dev)) { - data_transmitted = true; - } - - if (!uart_irq_rx_ready(dev)) { - return; - } - uint32_t bytes_read; - - while ((bytes_read = uart_fifo_read(dev, - (uint8_t *)data_buf_mouse+chr_ptr_mouse, - sizeof(data_buf_mouse)-chr_ptr_mouse))) { - chr_ptr_mouse += bytes_read; - if (data_buf_mouse[chr_ptr_mouse - 1] == '\r') { - /* ENTER */ - struct app_evt_t *ev = app_evt_alloc(); - - data_buf_mouse[chr_ptr_mouse - 1] = '\0'; - - if (!strcmp(data_buf_mouse, "up")) { - ev->event_type = CDC_UP; - } else if (!strcmp(data_buf_mouse, "down")) { - ev->event_type = CDC_DOWN; - } else if (!strcmp(data_buf_mouse, "right")) { - ev->event_type = CDC_RIGHT; - } else if (!strcmp(data_buf_mouse, "left")) { - ev->event_type = CDC_LEFT; - } else { - ev->event_type = CDC_UNKNOWN; - } - flush_buffer_mouse(); - app_evt_put(ev); - k_sem_give(&evt_sem); - } - - if (chr_ptr_mouse >= sizeof(data_buf_mouse)) { - LOG_WRN("Buffer overflow"); - flush_buffer_mouse(); - } - } -} - -static void cdc_kbd_int_handler(const struct device *dev, void *user_data) -{ - ARG_UNUSED(user_data); - - uart_irq_update(dev); - - if (uart_irq_tx_ready(dev)) { - data_transmitted = true; - } - - if (!uart_irq_rx_ready(dev)) { - return; - } - uint32_t bytes_read; - - while ((bytes_read = uart_fifo_read(dev, - (uint8_t *)data_buf_kbd+chr_ptr_kbd, - sizeof(data_buf_kbd)-chr_ptr_kbd))) { - chr_ptr_kbd += bytes_read; - if (data_buf_kbd[chr_ptr_kbd - 1] == '\r') { - /* ENTER */ - struct app_evt_t *ev = app_evt_alloc(); - - data_buf_kbd[chr_ptr_kbd - 1] = '\0'; - strcpy(string, data_buf_kbd); - ev->event_type = CDC_STRING; - flush_buffer_kbd(); - app_evt_put(ev); - k_sem_give(&evt_sem); - } - } -} - /* Devices */ static void btn0(const struct device *gpio, struct gpio_callback *cb, @@ -536,11 +409,7 @@ static void status_cb(enum usb_dc_status_code status, const uint8_t *param) int main(void) { - const struct device *cdc_dev[] = { - DT_FOREACH_STATUS_OKAY(zephyr_cdc_acm_uart, DEVICE_AND_COMMA) - }; - BUILD_ASSERT(ARRAY_SIZE(cdc_dev) >= 2, "Not enough CDC ACM instances"); - const struct device *hid0_dev, *hid1_dev; + const struct device *hid0_dev, *hid1_dev, *hid2_dev; struct app_evt_t *ev; uint32_t dtr = 0U; int ret; @@ -559,12 +428,10 @@ int main(void) return 0; } - for (int idx = 0; idx < ARRAY_SIZE(cdc_dev); idx++) { - if (!device_is_ready(cdc_dev[idx])) { - LOG_ERR("CDC ACM device %s is not ready", - cdc_dev[idx]->name); - return 0; - } + hid2_dev = device_get_binding("HID_2"); + if (hid2_dev == NULL) { + LOG_ERR("Cannot get USB HID 2 Device"); + return 0; } if (callbacks_configure(&sw0_gpio, &btn0, &callback[0])) { @@ -601,8 +468,12 @@ int main(void) usb_hid_register_device(hid1_dev, hid_kbd_report_desc, sizeof(hid_kbd_report_desc), &ops); + usb_hid_register_device(hid2_dev, hid_kb_report_desc, + sizeof(hid_kb_report_desc), &ops); + usb_hid_init(hid0_dev); usb_hid_init(hid1_dev); + usb_hid_init(hid2_dev); ret = usb_enable(status_cb); if (ret != 0) { @@ -610,40 +481,6 @@ int main(void) return 0; } - /* Initialize CDC ACM */ - for (int idx = 0; idx < ARRAY_SIZE(cdc_dev); idx++) { - LOG_INF("Wait for DTR on %s", cdc_dev[idx]->name); - while (1) { - uart_line_ctrl_get(cdc_dev[idx], - UART_LINE_CTRL_DTR, - &dtr); - if (dtr) { - break; - } else { - /* Give CPU resources to low priority threads. */ - k_sleep(K_MSEC(100)); - } - } - - LOG_INF("DTR on device %s", cdc_dev[idx]->name); - } - - /* Wait 1 sec for the host to do all settings */ - k_busy_wait(USEC_PER_SEC); - - uart_irq_callback_set(cdc_dev[0], cdc_mouse_int_handler); - uart_irq_callback_set(cdc_dev[1], cdc_kbd_int_handler); - - write_data(cdc_dev[0], welcome, strlen(welcome)); - write_data(cdc_dev[0], cdc_dev[0]->name, strlen(cdc_dev[0]->name)); - write_data(cdc_dev[0], banner0, strlen(banner0)); - write_data(cdc_dev[1], welcome, strlen(welcome)); - write_data(cdc_dev[1], cdc_dev[1]->name, strlen(cdc_dev[1]->name)); - write_data(cdc_dev[1], banner1, strlen(banner1)); - - uart_irq_rx_enable(cdc_dev[0]); - uart_irq_rx_enable(cdc_dev[1]); - while (true) { k_sem_take(&evt_sem, K_FOREVER); @@ -658,38 +495,10 @@ int main(void) k_sem_take(&usb_sem, K_FOREVER); hid_int_ep_write(hid0_dev, rep, sizeof(rep), NULL); - write_data(cdc_dev[0], gpio0, strlen(gpio0)); clear_mouse_report(); break; } case GPIO_BUTTON_1: - { - /* Press left mouse button */ - uint8_t rep[] = {0x00, 0x00, 0x00, 0x00}; - - rep[MOUSE_BTN_REPORT_POS] |= MOUSE_BTN_LEFT; - k_sem_take(&usb_sem, K_FOREVER); - hid_int_ep_write(hid0_dev, rep, - sizeof(rep), NULL); - write_data(cdc_dev[0], gpio1, strlen(gpio1)); - clear_mouse_report(); - break; - } - case GPIO_BUTTON_2: - { - /* Send string on HID keyboard */ - write_data(cdc_dev[1], gpio2, strlen(gpio2)); - if (strlen(string) > 0) { - struct app_evt_t *ev = app_evt_alloc(); - - ev->event_type = HID_KBD_STRING, - app_evt_put(ev); - str_pointer = 0U; - k_sem_give(&evt_sem); - } - break; - } - case GPIO_BUTTON_3: { /* Toggle CAPS LOCK */ uint8_t rep[] = {0x00, 0x00, 0x00, 0x00, @@ -699,75 +508,9 @@ int main(void) k_sem_take(&usb_sem, K_FOREVER); hid_int_ep_write(hid1_dev, rep, sizeof(rep), NULL); - write_data(cdc_dev[1], gpio3, strlen(gpio3)); clear_kbd_report(); break; } - case CDC_UP: - { - /* Mouse up */ - uint8_t rep[] = {0x00, 0x00, 0xE0, 0x00}; - - k_sem_take(&usb_sem, K_FOREVER); - hid_int_ep_write(hid0_dev, rep, - sizeof(rep), NULL); - write_data(cdc_dev[0], up, strlen(up)); - clear_mouse_report(); - break; - } - case CDC_DOWN: - { - /* Mouse down */ - uint8_t rep[] = {0x00, 0x00, 0x20, 0x00}; - - k_sem_take(&usb_sem, K_FOREVER); - hid_int_ep_write(hid0_dev, rep, - sizeof(rep), NULL); - write_data(cdc_dev[0], down, strlen(down)); - clear_mouse_report(); - break; - } - case CDC_RIGHT: - { - /* Mouse right */ - uint8_t rep[] = {0x00, 0x20, 0x00, 0x00}; - - k_sem_take(&usb_sem, K_FOREVER); - hid_int_ep_write(hid0_dev, rep, - sizeof(rep), NULL); - write_data(cdc_dev[0], right, strlen(right)); - clear_mouse_report(); - break; - } - case CDC_LEFT: - { - /* Mouse left */ - uint8_t rep[] = {0x00, 0xE0, 0x00, 0x00}; - - k_sem_take(&usb_sem, K_FOREVER); - hid_int_ep_write(hid0_dev, rep, - sizeof(rep), NULL); - write_data(cdc_dev[0], left, strlen(left)); - clear_mouse_report(); - break; - } - case CDC_UNKNOWN: - { - write_data(cdc_dev[0], unknown, strlen(unknown)); - write_data(cdc_dev[1], unknown, strlen(unknown)); - break; - } - case CDC_STRING: - { - write_data(cdc_dev[0], set_str, strlen(set_str)); - write_data(cdc_dev[0], string, strlen(string)); - write_data(cdc_dev[0], endl, strlen(endl)); - - write_data(cdc_dev[1], set_str, strlen(set_str)); - write_data(cdc_dev[1], string, strlen(string)); - write_data(cdc_dev[1], endl, strlen(endl)); - break; - } case HID_MOUSE_CLEAR: { /* Clear mouse report */ @@ -789,48 +532,9 @@ int main(void) sizeof(rep), NULL); break; } - case HID_KBD_STRING: - { - int ch = ascii_to_hid(string[str_pointer]); - - if (ch == -1) { - LOG_WRN("Unsupported character: %d", - string[str_pointer]); - } else { - uint8_t rep[] = {0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00}; - if (needs_shift(string[str_pointer])) { - rep[0] |= - HID_KBD_MODIFIER_RIGHT_SHIFT; - } - rep[7] = ch; - - k_sem_take(&usb_sem, K_FOREVER); - hid_int_ep_write(hid1_dev, rep, - sizeof(rep), NULL); - } - - str_pointer++; - - if (strlen(string) > str_pointer) { - struct app_evt_t *ev = app_evt_alloc(); - - ev->event_type = HID_KBD_STRING, - app_evt_put(ev); - k_sem_give(&evt_sem); - } else if (strlen(string) == str_pointer) { - clear_kbd_report(); - } - - break; - } default: { LOG_ERR("Unknown event to execute"); - write_data(cdc_dev[0], evt_fail, - strlen(evt_fail)); - write_data(cdc_dev[1], evt_fail, - strlen(evt_fail)); break; } break; diff --git a/samples/subsys/usb/hid-keyboard-nested/CMakeLists.txt b/samples/subsys/usb/hid-keyboard-nested/CMakeLists.txt new file mode 100644 index 0000000000000..18b92cb106a3c --- /dev/null +++ b/samples/subsys/usb/hid-keyboard-nested/CMakeLists.txt @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(hid-keyboard-nested) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/samples/subsys/usb/hid-keyboard-nested/README.rst b/samples/subsys/usb/hid-keyboard-nested/README.rst new file mode 100644 index 0000000000000..28b819bf1fbde --- /dev/null +++ b/samples/subsys/usb/hid-keyboard-nested/README.rst @@ -0,0 +1,184 @@ +.. zephyr:code-sample:: usb-hid-keyboard-nested + :name: USB HID keyboard nested + + Implement a basic HID keyboard device. + +Overview +******** + +This sample app demonstrates use of a USB Human Interface Device (HID) driver +by the Zephyr project. This very simple driver enumerates a board with a button +into a keyboard that at least one key is required and up to four can be used. +The first three keys are used for Key 0, Caps Lock and Num Lock. The fourth +key is for Left Shift modifier. + +Requirements +************ + +This project requires an USB device driver, and there must has at least one +GPIO button in your board. There must be a :dtcompatible:`gpio-keys` group of buttons +or keys defined at the board level that can generate input events. + +The example can use up to three LEDs, configured via the devicetree alias such +as ``led0``, to indicate the state of the keyboard LEDs. + +Building and Running +******************** + +This sample can be built for multiple boards, in this example we will build it +for the tl3228x board: + +.. zephyr-app-commands:: + :zephyr-app: samples/subsys/usb/hid-keyboard-nested + :board: tl3228x + :goals: build + :compact: + + +Programming Guide +***************** + +Handling SET REPORT for USB HID Keyboard LED Control in Zephyr Version 3.3 + +1. Implement the SET REPORT Callback Function +============================================= +To handle LED state changes initiated by the host, augment the ``hid_on_set_report`` +function in ``zephyr/subsys/usb/device/class/hid/core.c`` with callback logic. +This function processes incoming SET REPORT requests and delegates device-specific +handling to registered operations. + +.. code-block:: c + + static int hid_on_set_report(struct hid_device_info *dev_data, + struct usb_setup_packet *setup, int32_t *len, + uint8_t **data) + { + LOG_DBG("Set Report callback"); + + /* Implementation validated exclusively on Telink TL322x SoC */ + const struct hid_ops *ops = dev_data->ops; + if (ops->set_report != NULL) { + return ops->set_report(dev_data, setup, len, data); + } + + return -ENOTSUP; + } + +2. Register the Callback in Device Operations +============================================= +In the application's ``main.c``, define a ``struct hid_ops`` structure and invoke +``usb_hid_register_device`` to register the callback function. This associates +keyboard-specific LED control logic with the HID subsystem. + +.. code-block:: c + + /* Define keyboard-specific HID operation set */ + struct hid_ops kbd_ops = { + .set_report = kbd_set_report, /* LED control handler implementation */ + ... + }; + + usb_hid_register_device(hid_dev, hid_report_desc, sizeof(hid_report_desc), &kbd_ops); + +- ``kbd_set_report``: Keyboard-specific function responsible for processing LED state data. + +3. Implement the Device-Specific LED Control Function +===================================================== +The following function, implemented in ``main.c``, processes HID output reports to +control keyboard LEDs based on data received from the host. + +.. code-block:: c + + int kbd_set_report(const struct device *dev, struct usb_setup_packet *setup, + int32_t *len, uint8_t **data) + { + /* Control Num Lock LED using corresponding bit in report data */ + gpio_pin_set(led1.port, led1.pin, (** data & HID_KBD_LED_NUM_LOCK) != 0); + + /* Control Caps Lock LED using corresponding bit in report data */ + gpio_pin_set(led2.port, led2.pin, (**data & HID_KBD_LED_CAPS_LOCK) != 0); + + return 0; + } + +4. Conclusion +============= +This implementation in the hid-keyboard sample has been validated exclusively for +Zephyr version 3.3. In subsequent versions of Zephyr, the usage methods of related +APIs may be modified. For adaptation to newer versions, further technical investigation +is advised. + +NOTE: +===== +Since Zephyr version 3.7, a revised SET REPORT mechanism has introduced +via the USBD HID Device API. A new structure replaces ``hid_ops`` in +``zephyr/include/zephyr/usb/class/usbd_hid.h``: + +.. code-block:: c + + struct hid_device_ops { + void (*iface_ready)(const struct device *dev, const bool ready); + + int (*get_report)(const struct device *dev, + const uint8_t type, const uint8_t id, + const uint16_t len, uint8_t *const buf); + + int (*set_report)(const struct device *dev, + const uint8_t type, const uint8_t id, + const uint16_t len, const uint8_t *const buf); + + void (*set_idle)(const struct device *dev, + const uint8_t id, const uint32_t duration); + + uint32_t (*get_idle)(const struct device *dev, const uint8_t id); + + void (*set_protocol)(const struct device *dev, const uint8_t proto); + + void (*input_report_done)(const struct device *dev, + const uint8_t *const report); + + void (*output_report)(const struct device *dev, const uint16_t len, + const uint8_t *const buf); + + void (*sof)(const struct device *dev); + }; + +A new handler function replaces ``hid_on_set_report`` in ``zephyr/subsys/usb/device_next/class/usbd_hid.c``: + +.. code-block:: c + + static int handle_set_report(const struct device *dev, + const struct usb_setup_packet *const setup, + const struct net_buf *const buf) + { + const uint8_t type = HID_GET_REPORT_TYPE(setup->wValue); + const uint8_t id = HID_GET_REPORT_ID(setup->wValue); + struct hid_device_data *const ddata = dev->data; + const struct hid_device_ops *ops = ddata->ops; + + if (ops->set_report == NULL) { + errno = -ENOTSUP; + LOG_DBG("Set Report functionality not supported"); + return 0; + } + + switch (type) { + case HID_REPORT_TYPE_INPUT: + LOG_DBG("Processing Set Report: Input Report ID %u", id); + errno = ops->set_report(dev, type, id, buf->len, buf->data); + break; + case HID_REPORT_TYPE_OUTPUT: + LOG_DBG("Processing Set Report: Output Report ID %u", id); + errno = ops->set_report(dev, type, id, buf->len, buf->data); + break; + case HID_REPORT_TYPE_FEATURE: + LOG_DBG("Processing Set Report: Feature Report ID %u", id); + errno = ops->set_report(dev, type, id, buf->len, buf->data); + break; + default: + errno = -ENOTSUP; + break; + } + + return 0; + } diff --git a/samples/subsys/usb/hid-keyboard-nested/boards/tl3228x.overlay b/samples/subsys/usb/hid-keyboard-nested/boards/tl3228x.overlay new file mode 100644 index 0000000000000..84e3b603a648b --- /dev/null +++ b/samples/subsys/usb/hid-keyboard-nested/boards/tl3228x.overlay @@ -0,0 +1,8 @@ +&cpu0 { + clock-frequency = <192000000>; /* USB0 digital voltage must be 1.1V and HCLK min's 48M */ +}; + +&uart0 { + status = "okay"; + current-speed = <2000000>; /* Baud rate for serial port logging */ +}; diff --git a/samples/subsys/usb/hid-keyboard-nested/prj.conf b/samples/subsys/usb/hid-keyboard-nested/prj.conf new file mode 100644 index 0000000000000..41f6e51a2decf --- /dev/null +++ b/samples/subsys/usb/hid-keyboard-nested/prj.conf @@ -0,0 +1,25 @@ +CONFIG_USB_DEVICE_STACK=y +CONFIG_USB_DEVICE_HID=y +CONFIG_USB_DEVICE_PRODUCT="Zephyr HID-keyboard-nested sample" +CONFIG_USB_DEVICE_PID=0x0004 +CONFIG_USB_DEVICE_INITIALIZE_AT_BOOT=n + +CONFIG_USB_DC_HAS_HS_SUPPORT=n + +CONFIG_LOG=y +CONFIG_USB_DRIVER_LOG_LEVEL_ERR=y +CONFIG_USB_DEVICE_LOG_LEVEL_ERR=y + +CONFIG_LOG_BLOCK_IN_THREAD=y +CONFIG_LOG_BLOCK_IN_THREAD_TIMEOUT_MS=1000 +CONFIG_LOG_PROCESS_TRIGGER_THRESHOLD=10 +CONFIG_LOG_PROCESS_THREAD=y +CONFIG_LOG_PROCESS_THREAD_STARTUP_DELAY_MS=0 +CONFIG_LOG_PROCESS_THREAD_SLEEP_MS=1 +CONFIG_LOG_PROCESS_THREAD_STACK_SIZE=4096 +CONFIG_LOG_BUFFER_SIZE=4096 +CONFIG_LOG_TRACE_SHORT_TIMESTAMP=y + +CONFIG_GPIO=y +CONFIG_USB_DC_HAS_HS_SUPPORT=y +CONFIG_USB_TELINK_TLX=y diff --git a/samples/subsys/usb/hid-keyboard-nested/sample.yaml b/samples/subsys/usb/hid-keyboard-nested/sample.yaml new file mode 100644 index 0000000000000..8de6f60f15b92 --- /dev/null +++ b/samples/subsys/usb/hid-keyboard-nested/sample.yaml @@ -0,0 +1,9 @@ +sample: + name: USB HID keyboard-nested sample +tests: + sample.usb.hid-keyboard-nested + depends_on: usb_device gpio + harness: button + filter: dt_alias_exists("sw0") and + dt_alias_exists("led0") + tags: usb diff --git a/samples/subsys/usb/hid-keyboard-nested/src/main.c b/samples/subsys/usb/hid-keyboard-nested/src/main.c new file mode 100644 index 0000000000000..760c6c35252be --- /dev/null +++ b/samples/subsys/usb/hid-keyboard-nested/src/main.c @@ -0,0 +1,476 @@ +/* + * Copyright (c) 2025 Telink Semiconductor + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#define LOG_LEVEL LOG_LEVEL_DBG +#include +LOG_MODULE_REGISTER(main); + +/* + * Devicetree node identifiers for the buttons and LED this sample + * supports. + */ +#define SW0_NODE DT_ALIAS(sw0) +#define SW1_NODE DT_ALIAS(sw1) +#define SW2_NODE DT_ALIAS(sw2) +#define SW3_NODE DT_ALIAS(sw3) +#define LED0_NODE DT_ALIAS(led0) +#define LED1_NODE DT_ALIAS(led1) +#define LED2_NODE DT_ALIAS(led2) +#define LED3_NODE DT_ALIAS(led3) + +/* + * Button sw0 and LED led0 are required. + */ +#if !DT_NODE_EXISTS(SW0_NODE) +#error "Unsupported board: sw0 devicetree alias is not defined" +#endif + +#if !DT_NODE_EXISTS(LED0_NODE) +#error "Unsupported board: led0 devicetree alias is not defined" +#endif + +/* + * Helper macro for initializing a gpio_dt_spec from the devicetree + * with fallback values when the nodes are missing. + */ +#define GPIO_SPEC(node_id) GPIO_DT_SPEC_GET_OR(node_id, gpios, {0}) + +/* + * Create gpio_dt_spec structures from the devicetree. + */ +static const struct gpio_dt_spec sw0 = GPIO_SPEC(SW0_NODE), + sw1 = GPIO_SPEC(SW1_NODE), + sw2 = GPIO_SPEC(SW2_NODE), + sw3 = GPIO_SPEC(SW3_NODE), + led0 = GPIO_SPEC(LED0_NODE), + led1 = GPIO_SPEC(LED1_NODE), + led2 = GPIO_SPEC(LED2_NODE), + led3 = GPIO_SPEC(LED3_NODE); + +static const struct gpio_dt_spec leds[] = { + led0, + led1, + led2, + led3 +}; + +static K_SEM_DEFINE(evt_sem, 0, 1); /* starts off "not available" */ +static K_SEM_DEFINE(usb_sem, 1, 1); /* starts off "available" */ +static struct gpio_callback callback[4]; +static enum usb_dc_status_code usb_status; +static const uint8_t hid_report_desc[] = HID_KEYBOARD_REPORT_DESC(); + +/* + * Keyboard report structure. + */ +enum kbd_report_idx { + KB_MOD_KEY = 0, + KB_RESERVED, + KB_KEY_CODE1, + KB_KEY_CODE2, + KB_KEY_CODE3, + KB_KEY_CODE4, + KB_KEY_CODE5, + KB_KEY_CODE6, + KB_REPORT_COUNT, +}; + +/* + * Event FIFO + */ +K_FIFO_DEFINE(evt_fifo); + +enum evt_t { + GPIO_BUTTON_0 = 0x00, + GPIO_BUTTON_1 = 0x01, + GPIO_BUTTON_2 = 0x02, + GPIO_BUTTON_3 = 0x03, + HID_KBD_CLEAR = 0x04, +}; + +struct app_evt_t { + sys_snode_t node; + enum evt_t event_type; +}; + +#define FIFO_ELEM_MIN_SZ sizeof(struct app_evt_t) +#define FIFO_ELEM_MAX_SZ sizeof(struct app_evt_t) +#define FIFO_ELEM_COUNT 255 +#define FIFO_ELEM_ALIGN sizeof(unsigned int) + +K_HEAP_DEFINE(event_elem_pool, FIFO_ELEM_MAX_SZ *FIFO_ELEM_COUNT + 256); + +static inline void app_evt_free(struct app_evt_t *ev) +{ + k_heap_free(&event_elem_pool, ev); +} + +static inline void app_evt_put(struct app_evt_t *ev) +{ + k_fifo_put(&evt_fifo, ev); +} + +static inline struct app_evt_t *app_evt_get(void) +{ + return k_fifo_get(&evt_fifo, K_NO_WAIT); +} + +static inline void app_evt_flush(void) +{ + struct app_evt_t *ev; + + do { + ev = app_evt_get(); + if (ev) { + app_evt_free(ev); + } + } while (ev != NULL); +} + +static inline struct app_evt_t *app_evt_alloc(void) +{ + struct app_evt_t *ev; + + ev = k_heap_alloc(&event_elem_pool, sizeof(struct app_evt_t), K_NO_WAIT); + if (ev == NULL) { + LOG_ERR("APP event allocation failed!"); + app_evt_flush(); + + ev = k_heap_alloc(&event_elem_pool, sizeof(struct app_evt_t), K_NO_WAIT); + if (ev == NULL) { + LOG_ERR("APP event memory corrupted."); + __ASSERT_NO_MSG(0); + return NULL; + } + return NULL; + } + + return ev; +} + +static void in_ready_cb(const struct device *dev) +{ + ARG_UNUSED(dev); + k_sem_give(&usb_sem); +} + +/* LED control handler implementation */ +int kbd_set_report(const struct device *dev, struct usb_setup_packet *setup, int32_t *len, + uint8_t **data) +{ + gpio_pin_set(led1.port, led1.pin, (**data & HID_KBD_LED_CAPS_LOCK)); + + return 0; +} + +struct hid_ops kbd_ops = { + .set_report = kbd_set_report, + .int_in_ready = in_ready_cb, +}; + +static void status_cb(enum usb_dc_status_code status, const uint8_t *param) +{ + usb_status = status; +} + +/* + * GPIO callback handler. + */ +static void btn0(const struct device *gpio, struct gpio_callback *cb, uint32_t pins) +{ + struct app_evt_t *ev = app_evt_alloc(); + + if (IS_ENABLED(CONFIG_USB_DEVICE_REMOTE_WAKEUP)) { + if (usb_status == USB_DC_SUSPEND) { + LOG_DBG("btn0 wakeup_request"); + usb_wakeup_request(); + return; + } + } + + ev->event_type = GPIO_BUTTON_0, app_evt_put(ev); + k_sem_give(&evt_sem); +} + +static void btn1(const struct device *gpio, struct gpio_callback *cb, uint32_t pins) +{ + struct app_evt_t *ev = app_evt_alloc(); + + if (IS_ENABLED(CONFIG_USB_DEVICE_REMOTE_WAKEUP)) { + if (usb_status == USB_DC_SUSPEND) { + LOG_DBG("btn1 wakeup_request"); + usb_wakeup_request(); + return; + } + } + + ev->event_type = GPIO_BUTTON_1, app_evt_put(ev); + k_sem_give(&evt_sem); +} + +static void btn2(const struct device *gpio, struct gpio_callback *cb, uint32_t pins) +{ + struct app_evt_t *ev = app_evt_alloc(); + + if (IS_ENABLED(CONFIG_USB_DEVICE_REMOTE_WAKEUP)) { + if (usb_status == USB_DC_SUSPEND) { + LOG_DBG("btn2 wakeup_request"); + usb_wakeup_request(); + return; + } + } + + ev->event_type = GPIO_BUTTON_2, app_evt_put(ev); + k_sem_give(&evt_sem); +} + +static void btn3(const struct device *gpio, struct gpio_callback *cb, uint32_t pins) +{ + struct app_evt_t *ev = app_evt_alloc(); + + if (IS_ENABLED(CONFIG_USB_DEVICE_REMOTE_WAKEUP)) { + if (usb_status == USB_DC_SUSPEND) { + LOG_DBG("btn3 wakeup_request"); + usb_wakeup_request(); + return; + } + } + + ev->event_type = GPIO_BUTTON_3, app_evt_put(ev); + k_sem_give(&evt_sem); +} + +static void clear_kbd_report(void) +{ + struct app_evt_t *new_evt = app_evt_alloc(); + + new_evt->event_type = HID_KBD_CLEAR; + app_evt_put(new_evt); + k_sem_give(&evt_sem); +} + +int callbacks_configure(const struct gpio_dt_spec *spec, gpio_callback_handler_t handler, + struct gpio_callback *callback) +{ + const struct device *gpio = spec->port; + gpio_pin_t pin = spec->pin; + int ret; + + if (gpio == NULL) { + /* Optional GPIO is missing. */ + return 0; + } + + if (!device_is_ready(gpio)) { + LOG_ERR("GPIO port %s is not ready", gpio->name); + return -ENODEV; + } + + ret = gpio_pin_configure_dt(spec, GPIO_INPUT); + if (ret < 0) { + LOG_ERR("Failed to configure port %s pin %u, error: %d", gpio->name, pin, ret); + return ret; + } + + gpio_init_callback(callback, handler, BIT(pin)); + ret = gpio_add_callback(gpio, callback); + if (ret < 0) { + LOG_ERR("Failed to add the callback for port %s pin %u, " + "error: %d", + gpio->name, pin, ret); + return ret; + } + + ret = gpio_pin_interrupt_configure_dt(spec, GPIO_INT_EDGE_TO_ACTIVE); + if (ret < 0) { + LOG_ERR("Failed to configure interrupt for port %s pin %u, " + "error: %d", + gpio->name, pin, ret); + return ret; + } + + return 0; +} + +/* Timer0 interrupt handler */ +static void timer0_isr(const struct gpio_dt_spec *led) +{ + if (timer_get_irq_status(FLD_TMR0_MODE_IRQ)){ + gpio_pin_toggle_dt(led); + timer_clr_irq_status(FLD_TMR0_MODE_IRQ); //Clear IRQ status + delay_us(30); + gpio_pin_toggle_dt(led); + } +} + +/* Timer1 interrupt handler */ +static void timer1_isr(const struct gpio_dt_spec *led) +{ + if (timer_get_irq_status(FLD_TMR1_MODE_IRQ)){ + gpio_pin_toggle_dt(led); + timer_clr_irq_status(FLD_TMR1_MODE_IRQ); //Clear IRQ status + delay_us(20); + gpio_pin_toggle_dt(led); + delay_us(20); + gpio_pin_toggle_dt(led); + delay_us(20); + gpio_pin_toggle_dt(led); + delay_us(20); + gpio_pin_toggle_dt(led); + delay_us(20); + gpio_pin_toggle_dt(led); + } +} + +int main(void) +{ + int ret; + uint8_t report[KB_REPORT_COUNT] = {0x00}; + const struct device *hid_dev; + struct app_evt_t *ev; + + for (uint8_t i = 0; i < ARRAY_SIZE(leds); i++) { + if (!device_is_ready(leds[i].port)) { + LOG_ERR("LED%d device %s is not ready", i, leds[i].port->name); + return 0; + } + + ret = gpio_pin_configure_dt(&leds[i], GPIO_OUTPUT); + if (ret < 0) { + LOG_ERR("Failed to configure LED%d pin, error: %d", i, ret); + return 0; + } + } + + if (callbacks_configure(&sw0, &btn0, &callback[0])) { + LOG_ERR("Failed configuring button 0 callback."); + return 0; + } + if (callbacks_configure(&sw1, &btn1, &callback[1])) { + LOG_ERR("Failed configuring button 1 callback."); + return 0; + } + if (callbacks_configure(&sw2, &btn2, &callback[2])) { + LOG_ERR("Failed configuring button 2 callback."); + return 0; + } + if (callbacks_configure(&sw3, &btn3, &callback[3])) { + LOG_ERR("Failed configuring button 3 callback."); + return 0; + } + + riscv_plic_set_priority(IRQ_GPIO_IRQ3, 1); + + hid_dev = device_get_binding("HID_0"); + if (hid_dev == NULL) { + LOG_ERR("Cannot get USB HID Device"); + return 0; + } + + usb_hid_register_device(hid_dev, hid_report_desc, sizeof(hid_report_desc), &kbd_ops); + usb_hid_init(hid_dev); + + ret = usb_enable(status_cb); + if (ret != 0) { + LOG_ERR("Failed to enable USB"); + return 0; + } + + /* Initialize and configure timers */ + if (led2.port) { + /* Timer0 configuration */ + timer_set_init_tick(TIMER0, 0); + timer_set_cap_tick(TIMER0, sys_clk.pclk * 88); //88us + timer_set_mode(TIMER0, TIMER_MODE_SYSCLK); + timer_set_irq_mask(FLD_TMR0_MODE_IRQ); + IRQ_CONNECT(CONFIG_2ND_LVL_ISR_TBL_OFFSET + IRQ_TIMER0, 2, timer0_isr, &led2, 0); + riscv_plic_set_priority(IRQ_TIMER0, 3); + riscv_plic_irq_enable(IRQ_TIMER0); + + /* Timer1 configuration */ + timer_set_init_tick(TIMER1, 0); + timer_set_cap_tick(TIMER1, 1000 * sys_clk.pclk * 1); //1ms + timer_set_mode(TIMER1, TIMER_MODE_SYSCLK); + timer_set_irq_mask(FLD_TMR1_MODE_IRQ); + IRQ_CONNECT(CONFIG_2ND_LVL_ISR_TBL_OFFSET + IRQ_TIMER1, 2, timer1_isr, &led3, 0); + riscv_plic_set_priority(IRQ_TIMER1, 2); + riscv_plic_irq_enable(IRQ_TIMER1); + + /* Start timers */ + timer_start(TIMER0); + timer_start(TIMER1); + } + + + while (true) { + k_sem_take(&evt_sem, K_FOREVER); + + while ((ev = app_evt_get()) != NULL) { + switch (ev->event_type) { + case GPIO_BUTTON_0: { + /* Press the Key 0 */ + report[KB_KEY_CODE1] = HID_KEY_0; + k_sem_take(&usb_sem, K_FOREVER); + hid_int_ep_write(hid_dev, report, sizeof(report), NULL); + clear_kbd_report(); + break; + } + case GPIO_BUTTON_1: { + /* Toggle Caps Lock */ + report[KB_KEY_CODE2] = HID_KEY_CAPSLOCK; + k_sem_take(&usb_sem, K_FOREVER); + hid_int_ep_write(hid_dev, report, sizeof(report), NULL); + clear_kbd_report(); + break; + } + case GPIO_BUTTON_2: { + /* Toggle Num Lock */ + report[KB_KEY_CODE3] = HID_KEY_NUMLOCK; + k_sem_take(&usb_sem, K_FOREVER); + hid_int_ep_write(hid_dev, report, sizeof(report), NULL); + clear_kbd_report(); + break; + } + case GPIO_BUTTON_3: { + /* Toggle Left Shift */ + report[KB_MOD_KEY] = HID_KBD_MODIFIER_LEFT_SHIFT; + k_sem_take(&usb_sem, K_FOREVER); + hid_int_ep_write(hid_dev, report, sizeof(report), NULL); + clear_kbd_report(); + break; + } + case HID_KBD_CLEAR: { + /* Clear keyboard report */ + for (int i = 0; i < KB_REPORT_COUNT; i++) { + report[i] = 0x00; + } + k_sem_take(&usb_sem, K_FOREVER); + hid_int_ep_write(hid_dev, report, sizeof(report), NULL); + gpio_pin_toggle(led0.port, led0.pin); + break; + } + default: { + LOG_ERR("Unknown event to execute"); + break; + } break; + } + app_evt_free(ev); + } + } + return 0; +} diff --git a/samples/subsys/usb/hid-keyboard/CMakeLists.txt b/samples/subsys/usb/hid-keyboard/CMakeLists.txt new file mode 100644 index 0000000000000..8e91147205e14 --- /dev/null +++ b/samples/subsys/usb/hid-keyboard/CMakeLists.txt @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(hid-keyboard) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/samples/subsys/usb/hid-keyboard/README.rst b/samples/subsys/usb/hid-keyboard/README.rst new file mode 100644 index 0000000000000..728fef5f8dd2a --- /dev/null +++ b/samples/subsys/usb/hid-keyboard/README.rst @@ -0,0 +1,184 @@ +.. zephyr:code-sample:: usb-hid-keyboard + :name: USB HID keyboard + + Implement a basic HID keyboard device. + +Overview +******** + +This sample app demonstrates use of a USB Human Interface Device (HID) driver +by the Zephyr project. This very simple driver enumerates a board with a button +into a keyboard that at least one key is required and up to four can be used. +The first three keys are used for Key 0, Caps Lock and Num Lock. The fourth +key is for Left Shift modifier. + +Requirements +************ + +This project requires an USB device driver, and there must has at least one +GPIO button in your board. There must be a :dtcompatible:`gpio-keys` group of buttons +or keys defined at the board level that can generate input events. + +The example can use up to three LEDs, configured via the devicetree alias such +as ``led0``, to indicate the state of the keyboard LEDs. + +Building and Running +******************** + +This sample can be built for multiple boards, in this example we will build it +for the tl3228x board: + +.. zephyr-app-commands:: + :zephyr-app: samples/subsys/usb/hid-keyboard + :board: tl3228x + :goals: build + :compact: + + +Programming Guide +***************** + +Handling SET REPORT for USB HID Keyboard LED Control in Zephyr Version 3.3 + +1. Implement the SET REPORT Callback Function +============================================= +To handle LED state changes initiated by the host, augment the ``hid_on_set_report`` +function in ``zephyr/subsys/usb/device/class/hid/core.c`` with callback logic. +This function processes incoming SET REPORT requests and delegates device-specific +handling to registered operations. + +.. code-block:: c + + static int hid_on_set_report(struct hid_device_info *dev_data, + struct usb_setup_packet *setup, int32_t *len, + uint8_t **data) + { + LOG_DBG("Set Report callback"); + + /* Implementation validated exclusively on Telink TL322x SoC */ + const struct hid_ops *ops = dev_data->ops; + if (ops->set_report != NULL) { + return ops->set_report(dev_data, setup, len, data); + } + + return -ENOTSUP; + } + +2. Register the Callback in Device Operations +============================================= +In the application's ``main.c``, define a ``struct hid_ops`` structure and invoke +``usb_hid_register_device`` to register the callback function. This associates +keyboard-specific LED control logic with the HID subsystem. + +.. code-block:: c + + /* Define keyboard-specific HID operation set */ + struct hid_ops kbd_ops = { + .set_report = kbd_set_report, /* LED control handler implementation */ + ... + }; + + usb_hid_register_device(hid_dev, hid_report_desc, sizeof(hid_report_desc), &kbd_ops); + +- ``kbd_set_report``: Keyboard-specific function responsible for processing LED state data. + +3. Implement the Device-Specific LED Control Function +===================================================== +The following function, implemented in ``main.c``, processes HID output reports to +control keyboard LEDs based on data received from the host. + +.. code-block:: c + + int kbd_set_report(const struct device *dev, struct usb_setup_packet *setup, + int32_t *len, uint8_t **data) + { + /* Control Num Lock LED using corresponding bit in report data */ + gpio_pin_set(led1.port, led1.pin, (** data & HID_KBD_LED_NUM_LOCK) != 0); + + /* Control Caps Lock LED using corresponding bit in report data */ + gpio_pin_set(led2.port, led2.pin, (**data & HID_KBD_LED_CAPS_LOCK) != 0); + + return 0; + } + +4. Conclusion +============= +This implementation in the hid-keyboard sample has been validated exclusively for +Zephyr version 3.3. In subsequent versions of Zephyr, the usage methods of related +APIs may be modified. For adaptation to newer versions, further technical investigation +is advised. + +NOTE: +===== +Since Zephyr version 3.7, a revised SET REPORT mechanism has introduced +via the USBD HID Device API. A new structure replaces ``hid_ops`` in +``zephyr/include/zephyr/usb/class/usbd_hid.h``: + +.. code-block:: c + + struct hid_device_ops { + void (*iface_ready)(const struct device *dev, const bool ready); + + int (*get_report)(const struct device *dev, + const uint8_t type, const uint8_t id, + const uint16_t len, uint8_t *const buf); + + int (*set_report)(const struct device *dev, + const uint8_t type, const uint8_t id, + const uint16_t len, const uint8_t *const buf); + + void (*set_idle)(const struct device *dev, + const uint8_t id, const uint32_t duration); + + uint32_t (*get_idle)(const struct device *dev, const uint8_t id); + + void (*set_protocol)(const struct device *dev, const uint8_t proto); + + void (*input_report_done)(const struct device *dev, + const uint8_t *const report); + + void (*output_report)(const struct device *dev, const uint16_t len, + const uint8_t *const buf); + + void (*sof)(const struct device *dev); + }; + +A new handler function replaces ``hid_on_set_report`` in ``zephyr/subsys/usb/device_next/class/usbd_hid.c``: + +.. code-block:: c + + static int handle_set_report(const struct device *dev, + const struct usb_setup_packet *const setup, + const struct net_buf *const buf) + { + const uint8_t type = HID_GET_REPORT_TYPE(setup->wValue); + const uint8_t id = HID_GET_REPORT_ID(setup->wValue); + struct hid_device_data *const ddata = dev->data; + const struct hid_device_ops *ops = ddata->ops; + + if (ops->set_report == NULL) { + errno = -ENOTSUP; + LOG_DBG("Set Report functionality not supported"); + return 0; + } + + switch (type) { + case HID_REPORT_TYPE_INPUT: + LOG_DBG("Processing Set Report: Input Report ID %u", id); + errno = ops->set_report(dev, type, id, buf->len, buf->data); + break; + case HID_REPORT_TYPE_OUTPUT: + LOG_DBG("Processing Set Report: Output Report ID %u", id); + errno = ops->set_report(dev, type, id, buf->len, buf->data); + break; + case HID_REPORT_TYPE_FEATURE: + LOG_DBG("Processing Set Report: Feature Report ID %u", id); + errno = ops->set_report(dev, type, id, buf->len, buf->data); + break; + default: + errno = -ENOTSUP; + break; + } + + return 0; + } diff --git a/samples/subsys/usb/hid-keyboard/boards/tl3228x.conf b/samples/subsys/usb/hid-keyboard/boards/tl3228x.conf new file mode 100644 index 0000000000000..fb8df7d2f6abd --- /dev/null +++ b/samples/subsys/usb/hid-keyboard/boards/tl3228x.conf @@ -0,0 +1,2 @@ +CONFIG_USB_TELINK_TLX=y +CONFIG_USB_DC_HAS_HS_SUPPORT=y \ No newline at end of file diff --git a/samples/subsys/usb/hid-keyboard/boards/tl3228x.overlay b/samples/subsys/usb/hid-keyboard/boards/tl3228x.overlay new file mode 100644 index 0000000000000..84e3b603a648b --- /dev/null +++ b/samples/subsys/usb/hid-keyboard/boards/tl3228x.overlay @@ -0,0 +1,8 @@ +&cpu0 { + clock-frequency = <192000000>; /* USB0 digital voltage must be 1.1V and HCLK min's 48M */ +}; + +&uart0 { + status = "okay"; + current-speed = <2000000>; /* Baud rate for serial port logging */ +}; diff --git a/samples/subsys/usb/hid-keyboard/prj.conf b/samples/subsys/usb/hid-keyboard/prj.conf new file mode 100644 index 0000000000000..09467dd5a160b --- /dev/null +++ b/samples/subsys/usb/hid-keyboard/prj.conf @@ -0,0 +1,23 @@ +CONFIG_USB_DEVICE_STACK=y +CONFIG_USB_DEVICE_HID=y +CONFIG_USB_DEVICE_PRODUCT="Zephyr HID-keyboard sample" +CONFIG_USB_DEVICE_PID=0x0004 +CONFIG_USB_DEVICE_INITIALIZE_AT_BOOT=n + +CONFIG_USB_DC_HAS_HS_SUPPORT=n + +CONFIG_LOG=y +CONFIG_USB_DRIVER_LOG_LEVEL_ERR=y +CONFIG_USB_DEVICE_LOG_LEVEL_ERR=y + +CONFIG_LOG_BLOCK_IN_THREAD=y +CONFIG_LOG_BLOCK_IN_THREAD_TIMEOUT_MS=1000 +CONFIG_LOG_PROCESS_TRIGGER_THRESHOLD=10 +CONFIG_LOG_PROCESS_THREAD=y +CONFIG_LOG_PROCESS_THREAD_STARTUP_DELAY_MS=0 +CONFIG_LOG_PROCESS_THREAD_SLEEP_MS=1 +CONFIG_LOG_PROCESS_THREAD_STACK_SIZE=4096 +CONFIG_LOG_BUFFER_SIZE=4096 +CONFIG_LOG_TRACE_SHORT_TIMESTAMP=y + +CONFIG_GPIO=y diff --git a/samples/subsys/usb/hid-keyboard/sample.yaml b/samples/subsys/usb/hid-keyboard/sample.yaml new file mode 100644 index 0000000000000..47eccc75b6148 --- /dev/null +++ b/samples/subsys/usb/hid-keyboard/sample.yaml @@ -0,0 +1,9 @@ +sample: + name: USB HID keyboard sample +tests: + sample.usb.hid-keyboard: + depends_on: usb_device gpio + harness: button + filter: dt_alias_exists("sw0") and + dt_alias_exists("led0") + tags: usb diff --git a/samples/subsys/usb/hid-keyboard/src/main.c b/samples/subsys/usb/hid-keyboard/src/main.c new file mode 100644 index 0000000000000..0adf4bd5cba4a --- /dev/null +++ b/samples/subsys/usb/hid-keyboard/src/main.c @@ -0,0 +1,410 @@ +/* + * Copyright (c) 2025 Telink Semiconductor + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include + +#include +#include + +#define LOG_LEVEL LOG_LEVEL_DBG +#include +LOG_MODULE_REGISTER(main); + +/* + * Devicetree node identifiers for the buttons and LED this sample + * supports. + */ +#define SW0_NODE DT_ALIAS(sw0) +#define SW1_NODE DT_ALIAS(sw1) +#define SW2_NODE DT_ALIAS(sw2) +#define SW3_NODE DT_ALIAS(sw3) +#define LED0_NODE DT_ALIAS(led0) +#define LED1_NODE DT_ALIAS(led1) +#define LED2_NODE DT_ALIAS(led2) + +/* + * Button sw0 and LED led0 are required. + */ +#if !DT_NODE_EXISTS(SW0_NODE) +#error "Unsupported board: sw0 devicetree alias is not defined" +#endif + +#if !DT_NODE_EXISTS(LED0_NODE) +#error "Unsupported board: led0 devicetree alias is not defined" +#endif + +/* + * Helper macro for initializing a gpio_dt_spec from the devicetree + * with fallback values when the nodes are missing. + */ +#define GPIO_SPEC(node_id) GPIO_DT_SPEC_GET_OR(node_id, gpios, {0}) + +/* + * Create gpio_dt_spec structures from the devicetree. + */ +static const struct gpio_dt_spec sw0 = GPIO_SPEC(SW0_NODE), + sw1 = GPIO_SPEC(SW1_NODE), + sw2 = GPIO_SPEC(SW2_NODE), + sw3 = GPIO_SPEC(SW3_NODE), + led0 = GPIO_SPEC(LED0_NODE), + led1 = GPIO_SPEC(LED1_NODE), + led2 = GPIO_SPEC(LED2_NODE); + +static const struct gpio_dt_spec leds[] = { + led0, + led1, + led2 +}; + +static K_SEM_DEFINE(evt_sem, 0, 1); /* starts off "not available" */ +static K_SEM_DEFINE(usb_sem, 1, 1); /* starts off "available" */ +static struct gpio_callback callback[4]; +static enum usb_dc_status_code usb_status; +static const uint8_t hid_report_desc[] = HID_KEYBOARD_REPORT_DESC(); + +/* + * Keyboard report structure. + */ +enum kbd_report_idx { + KB_MOD_KEY = 0, + KB_RESERVED, + KB_KEY_CODE1, + KB_KEY_CODE2, + KB_KEY_CODE3, + KB_KEY_CODE4, + KB_KEY_CODE5, + KB_KEY_CODE6, + KB_REPORT_COUNT, +}; + +/* + * Event FIFO + */ +K_FIFO_DEFINE(evt_fifo); + +enum evt_t { + GPIO_BUTTON_0 = 0x00, + GPIO_BUTTON_1 = 0x01, + GPIO_BUTTON_2 = 0x02, + GPIO_BUTTON_3 = 0x03, + HID_KBD_CLEAR = 0x04, +}; + +struct app_evt_t { + sys_snode_t node; + enum evt_t event_type; +}; + +#define FIFO_ELEM_MIN_SZ sizeof(struct app_evt_t) +#define FIFO_ELEM_MAX_SZ sizeof(struct app_evt_t) +#define FIFO_ELEM_COUNT 255 +#define FIFO_ELEM_ALIGN sizeof(unsigned int) + +K_HEAP_DEFINE(event_elem_pool, FIFO_ELEM_MAX_SZ *FIFO_ELEM_COUNT + 256); + +static inline void app_evt_free(struct app_evt_t *ev) +{ + k_heap_free(&event_elem_pool, ev); +} + +static inline void app_evt_put(struct app_evt_t *ev) +{ + k_fifo_put(&evt_fifo, ev); +} + +static inline struct app_evt_t *app_evt_get(void) +{ + return k_fifo_get(&evt_fifo, K_NO_WAIT); +} + +static inline void app_evt_flush(void) +{ + struct app_evt_t *ev; + + do { + ev = app_evt_get(); + if (ev) { + app_evt_free(ev); + } + } while (ev != NULL); +} + +static inline struct app_evt_t *app_evt_alloc(void) +{ + struct app_evt_t *ev; + + ev = k_heap_alloc(&event_elem_pool, sizeof(struct app_evt_t), K_NO_WAIT); + if (ev == NULL) { + LOG_ERR("APP event allocation failed!"); + app_evt_flush(); + + ev = k_heap_alloc(&event_elem_pool, sizeof(struct app_evt_t), K_NO_WAIT); + if (ev == NULL) { + LOG_ERR("APP event memory corrupted."); + __ASSERT_NO_MSG(0); + return NULL; + } + return NULL; + } + + return ev; +} + +static void in_ready_cb(const struct device *dev) +{ + ARG_UNUSED(dev); + k_sem_give(&usb_sem); +} + +/* LED control handler implementation */ +int kbd_set_report(const struct device *dev, struct usb_setup_packet *setup, int32_t *len, + uint8_t **data) +{ + gpio_pin_set(led1.port, led1.pin, (**data & HID_KBD_LED_NUM_LOCK)); + gpio_pin_set(led2.port, led2.pin, (**data & HID_KBD_LED_CAPS_LOCK)); + + return 0; +} + +struct hid_ops kbd_ops = { + .set_report = kbd_set_report, + .int_in_ready = in_ready_cb, +}; + +static void status_cb(enum usb_dc_status_code status, const uint8_t *param) +{ + usb_status = status; +} + +/* + * GPIO callback handler. + */ +static void btn0(const struct device *gpio, struct gpio_callback *cb, uint32_t pins) +{ + struct app_evt_t *ev = app_evt_alloc(); + + if (IS_ENABLED(CONFIG_USB_DEVICE_REMOTE_WAKEUP)) { + if (usb_status == USB_DC_SUSPEND) { + LOG_DBG("btn0 wakeup_request"); + usb_wakeup_request(); + return; + } + } + + ev->event_type = GPIO_BUTTON_0, app_evt_put(ev); + k_sem_give(&evt_sem); +} + +static void btn1(const struct device *gpio, struct gpio_callback *cb, uint32_t pins) +{ + struct app_evt_t *ev = app_evt_alloc(); + + if (IS_ENABLED(CONFIG_USB_DEVICE_REMOTE_WAKEUP)) { + if (usb_status == USB_DC_SUSPEND) { + LOG_DBG("btn1 wakeup_request"); + usb_wakeup_request(); + return; + } + } + + ev->event_type = GPIO_BUTTON_1, app_evt_put(ev); + k_sem_give(&evt_sem); +} + +static void btn2(const struct device *gpio, struct gpio_callback *cb, uint32_t pins) +{ + struct app_evt_t *ev = app_evt_alloc(); + + if (IS_ENABLED(CONFIG_USB_DEVICE_REMOTE_WAKEUP)) { + if (usb_status == USB_DC_SUSPEND) { + LOG_DBG("btn2 wakeup_request"); + usb_wakeup_request(); + return; + } + } + + ev->event_type = GPIO_BUTTON_2, app_evt_put(ev); + k_sem_give(&evt_sem); +} + +static void btn3(const struct device *gpio, struct gpio_callback *cb, uint32_t pins) +{ + struct app_evt_t *ev = app_evt_alloc(); + + if (IS_ENABLED(CONFIG_USB_DEVICE_REMOTE_WAKEUP)) { + if (usb_status == USB_DC_SUSPEND) { + LOG_DBG("btn3 wakeup_request"); + usb_wakeup_request(); + return; + } + } + + ev->event_type = GPIO_BUTTON_3, app_evt_put(ev); + k_sem_give(&evt_sem); +} + +static void clear_kbd_report(void) +{ + struct app_evt_t *new_evt = app_evt_alloc(); + + new_evt->event_type = HID_KBD_CLEAR; + app_evt_put(new_evt); + k_sem_give(&evt_sem); +} + +int callbacks_configure(const struct gpio_dt_spec *spec, gpio_callback_handler_t handler, + struct gpio_callback *callback) +{ + const struct device *gpio = spec->port; + gpio_pin_t pin = spec->pin; + int ret; + + if (gpio == NULL) { + /* Optional GPIO is missing. */ + return 0; + } + + if (!device_is_ready(gpio)) { + LOG_ERR("GPIO port %s is not ready", gpio->name); + return -ENODEV; + } + + ret = gpio_pin_configure_dt(spec, GPIO_INPUT); + if (ret < 0) { + LOG_ERR("Failed to configure port %s pin %u, error: %d", gpio->name, pin, ret); + return ret; + } + + gpio_init_callback(callback, handler, BIT(pin)); + ret = gpio_add_callback(gpio, callback); + if (ret < 0) { + LOG_ERR("Failed to add the callback for port %s pin %u, " + "error: %d", + gpio->name, pin, ret); + return ret; + } + + ret = gpio_pin_interrupt_configure_dt(spec, GPIO_INT_EDGE_TO_ACTIVE); + if (ret < 0) { + LOG_ERR("Failed to configure interrupt for port %s pin %u, " + "error: %d", + gpio->name, pin, ret); + return ret; + } + + return 0; +} + +int main(void) +{ + int ret; + uint8_t report[KB_REPORT_COUNT] = {0x00}; + const struct device *hid_dev; + struct app_evt_t *ev; + + for (uint8_t i = 0; i < ARRAY_SIZE(leds); i++) { + if (!device_is_ready(leds[i].port)) { + LOG_ERR("LED%d device %s is not ready", i, leds[i].port->name); + return 0; + } + + ret = gpio_pin_configure_dt(&leds[i], GPIO_OUTPUT); + if (ret < 0) { + LOG_ERR("Failed to configure LED%d pin, error: %d", i, ret); + return 0; + } + } + + if (callbacks_configure(&sw0, &btn0, &callback[0])) { + LOG_ERR("Failed configuring button 0 callback."); + return 0; + } + if (callbacks_configure(&sw1, &btn1, &callback[1])) { + LOG_ERR("Failed configuring button 1 callback."); + return 0; + } + if (callbacks_configure(&sw2, &btn2, &callback[2])) { + LOG_ERR("Failed configuring button 2 callback."); + return 0; + } + if (callbacks_configure(&sw3, &btn3, &callback[3])) { + LOG_ERR("Failed configuring button 3 callback."); + return 0; + } + + hid_dev = device_get_binding("HID_0"); + if (hid_dev == NULL) { + LOG_ERR("Cannot get USB HID Device"); + return 0; + } + + usb_hid_register_device(hid_dev, hid_report_desc, sizeof(hid_report_desc), &kbd_ops); + usb_hid_init(hid_dev); + + ret = usb_enable(status_cb); + if (ret != 0) { + LOG_ERR("Failed to enable USB"); + return 0; + } + + while (true) { + k_sem_take(&evt_sem, K_FOREVER); + + while ((ev = app_evt_get()) != NULL) { + switch (ev->event_type) { + case GPIO_BUTTON_0: { + /* Press the Key 0 */ + report[KB_KEY_CODE1] = HID_KEY_0; + k_sem_take(&usb_sem, K_FOREVER); + hid_int_ep_write(hid_dev, report, sizeof(report), NULL); + clear_kbd_report(); + break; + } + case GPIO_BUTTON_1: { + /* Toggle Caps Lock */ + report[KB_KEY_CODE2] = HID_KEY_CAPSLOCK; + k_sem_take(&usb_sem, K_FOREVER); + hid_int_ep_write(hid_dev, report, sizeof(report), NULL); + clear_kbd_report(); + break; + } + case GPIO_BUTTON_2: { + /* Toggle Num Lock */ + report[KB_KEY_CODE3] = HID_KEY_NUMLOCK; + k_sem_take(&usb_sem, K_FOREVER); + hid_int_ep_write(hid_dev, report, sizeof(report), NULL); + clear_kbd_report(); + break; + } + case GPIO_BUTTON_3: { + /* Toggle Left Shift */ + report[KB_MOD_KEY] = HID_KBD_MODIFIER_LEFT_SHIFT; + k_sem_take(&usb_sem, K_FOREVER); + hid_int_ep_write(hid_dev, report, sizeof(report), NULL); + clear_kbd_report(); + break; + } + case HID_KBD_CLEAR: { + /* Clear keyboard report */ + for (int i = 0; i < KB_REPORT_COUNT; i++) { + report[i] = 0x00; + } + k_sem_take(&usb_sem, K_FOREVER); + hid_int_ep_write(hid_dev, report, sizeof(report), NULL); + gpio_pin_toggle(led0.port, led0.pin); + break; + } + default: { + LOG_ERR("Unknown event to execute"); + break; + } break; + } + app_evt_free(ev); + } + } + return 0; +} diff --git a/samples/subsys/usb/hid-mouse/boards/tl3228x.overlay b/samples/subsys/usb/hid-mouse/boards/tl3228x.overlay new file mode 100644 index 0000000000000..84e3b603a648b --- /dev/null +++ b/samples/subsys/usb/hid-mouse/boards/tl3228x.overlay @@ -0,0 +1,8 @@ +&cpu0 { + clock-frequency = <192000000>; /* USB0 digital voltage must be 1.1V and HCLK min's 48M */ +}; + +&uart0 { + status = "okay"; + current-speed = <2000000>; /* Baud rate for serial port logging */ +}; diff --git a/scripts/west_commands/runners/bdt_tool.py b/scripts/west_commands/runners/bdt_tool.py index 4f34dbf044402..1d6ca9e74da66 100644 --- a/scripts/west_commands/runners/bdt_tool.py +++ b/scripts/west_commands/runners/bdt_tool.py @@ -51,15 +51,22 @@ def _flash(self): build_conf = BuildConfiguration(self.cfg.build_dir) # get chip soc_type = None - if 'CONFIG_SOC_RISCV_TELINK_TL321X' in build_conf: - if build_conf['CONFIG_SOC_RISCV_TELINK_TL321X']: - soc_type = 'TL321X' - if 'CONFIG_SOC_RISCV_TELINK_B92' in build_conf: - if build_conf['CONFIG_SOC_RISCV_TELINK_B92']: - soc_type = 'B92' - if 'CONFIG_SOC_RISCV_TELINK_B91' in build_conf: - if build_conf['CONFIG_SOC_RISCV_TELINK_B91']: - soc_type = '9518' + if ('CONFIG_SOC_RISCV_TELINK_B92' in build_conf and + build_conf['CONFIG_SOC_RISCV_TELINK_B92']): + soc_type = 'B92' + print('Telink B92') + if ('CONFIG_SOC_RISCV_TELINK_B91' in build_conf and + build_conf['CONFIG_SOC_RISCV_TELINK_B91']): + soc_type = '9518' + print('Telink B91') + if ('CONFIG_SOC_RISCV_TELINK_TL321X' in build_conf and + build_conf['CONFIG_SOC_RISCV_TELINK_TL321X']): + soc_type = 'TL321X' + print('Telink TL321') + if ('CONFIG_SOC_RISCV_TELINK_TL721X' in build_conf and + build_conf['CONFIG_SOC_RISCV_TELINK_TL721X']): + soc_type = 'TL721X' + print('Telink TL721') if soc_type is None: print('only Telink chips are supported!') exit() diff --git a/soc/riscv/riscv-privilege/Kconfig b/soc/riscv/riscv-privilege/Kconfig index 377b3c7935516..5bd077d9f8950 100644 --- a/soc/riscv/riscv-privilege/Kconfig +++ b/soc/riscv/riscv-privilege/Kconfig @@ -34,6 +34,8 @@ config RISCV_MTVEC_VECTORED_MODE config TELINK_TLX_MATTER_RETENTION_LAYOUT bool "link mcu_boot_tlx.ld for tl3218x" default y if BOARD_TL3218X + default y if BOARD_TL3238X + default y if BOARD_TL3238X_RETENTION default n help link mcu_boot_tlx.ld for tl3218x diff --git a/soc/riscv/riscv-privilege/telink_tlx/CMakeLists.txt b/soc/riscv/riscv-privilege/telink_tlx/CMakeLists.txt index 7fcc02163cf5f..dd958edd35c33 100644 --- a/soc/riscv/riscv-privilege/telink_tlx/CMakeLists.txt +++ b/soc/riscv/riscv-privilege/telink_tlx/CMakeLists.txt @@ -25,10 +25,20 @@ zephyr_sources_ifdef(CONFIG_PM power.c ) +zephyr_sources_ifdef(CONFIG_RISCV_MTVEC_VECTORED_MODE + isr_table.c + isr_vectored.S +) + # Force using BFD-LD zephyr_ld_options(-fuse-ld=bfd) # Set compile options +zephyr_linker_sources_ifdef(CONFIG_RISCV_MTVEC_VECTORED_MODE + ROM_START + SORT_KEY 0x0vectors + ${ZEPHYR_BASE}/include/zephyr/linker/irq-vector-table-section.ld +) zephyr_compile_options_ifdef(CONFIG_ANDES_HWDSP -mext-dsp) zephyr_compile_options_ifndef(CONFIG_RISCV_GP -mno-relax) zephyr_linker_sources(ROM_START SORT_KEY 0x0 init.ld) diff --git a/soc/riscv/riscv-privilege/telink_tlx/Kconfig.defconfig.series b/soc/riscv/riscv-privilege/telink_tlx/Kconfig.defconfig.series index 621714f062834..91ac83504229d 100644 --- a/soc/riscv/riscv-privilege/telink_tlx/Kconfig.defconfig.series +++ b/soc/riscv/riscv-privilege/telink_tlx/Kconfig.defconfig.series @@ -20,6 +20,10 @@ config RISCV_SOC_INTERRUPT_INIT bool default y +config RISCV_MTVEC_VECTORED_MODE + bool + default y + config RISCV_HAS_CPU_IDLE bool default y @@ -102,4 +106,16 @@ config TELINK_TLX_2_WIRE_SPI_ENABLE default n endif # SOC_RISCV_TELINK_TL321X +if SOC_RISCV_TELINK_TL322X +config TELINK_TLX_2_WIRE_SPI_ENABLE + bool + default n +endif # SOC_RISCV_TELINK_TL322X + +if SOC_RISCV_TELINK_TL323X +config TELINK_TLX_2_WIRE_SPI_ENABLE + bool + default n +endif # SOC_RISCV_TELINK_TL323X + endif # SOC_SERIES_RISCV_TELINK_TLX diff --git a/soc/riscv/riscv-privilege/telink_tlx/Kconfig.n22 b/soc/riscv/riscv-privilege/telink_tlx/Kconfig.n22 new file mode 100644 index 0000000000000..c685463cbaab4 --- /dev/null +++ b/soc/riscv/riscv-privilege/telink_tlx/Kconfig.n22 @@ -0,0 +1,42 @@ +# Copyright (c) 2024 Telink Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +config TELINK_TL322X_ENABLE_N22 + bool "Enable N22 core" + default n + depends on SOC_SERIES_RISCV_TELINK_TLX + help + This option enables N22 usage. + +config TELINK_TL322X_N22_HART + int "N22 HART ID" + default 1 + depends on SOC_SERIES_RISCV_TELINK_TLX && TELINK_TL322X_ENABLE_N22 + help + This option sets N22 HART ID. + +config TELINK_TL322X_FETCH_N22_BIN + bool "Fetch N22 binary after build" + default y + depends on SOC_SERIES_RISCV_TELINK_TLX && TELINK_TL322X_ENABLE_N22 + help + This option fetching N22 binary after build. + +config TELINK_TL322X_FETCH_N22_BIN_REVISION + string "N22 binaries revision" + default "c8397b726468c1c63b098bc06eec2d9acad4887d" + depends on TELINK_TL322X_FETCH_N22_BIN && TELINK_TL322X_ENABLE_N22 + help + This option sets N22 binary revision. + +config TELINK_TL322X_N22_PARTITION_ADDR + hex "N22 partition address" + depends on SOC_SERIES_RISCV_TELINK_TLX && TELINK_TL322X_ENABLE_N22 + default $(dt_node_reg_addr_hex,$(dt_nodelabel_path,n22_partition),0) + +config TELINK_TL322X_N22_MATTER_OTA_LAYOUT + bool "Support Matter dual core OTA" + depends on TELINK_TL322X_FETCH_N22_BIN && TELINK_TL322X_ENABLE_N22 + default n + help + This option enables support Matter dual core OTA diff --git a/soc/riscv/riscv-privilege/telink_tlx/Kconfig.soc b/soc/riscv/riscv-privilege/telink_tlx/Kconfig.soc index 80a1053d7a5fa..fbcb803c64517 100644 --- a/soc/riscv/riscv-privilege/telink_tlx/Kconfig.soc +++ b/soc/riscv/riscv-privilege/telink_tlx/Kconfig.soc @@ -30,6 +30,20 @@ config TELINK_TL721X_PMP help This option enables Telink TL721X PMP(memory protection) module. +config TELINK_TL322X_PMP + bool "Support Hardware Memory Protection" + depends on SOC_RISCV_TELINK_TL322X + select RISCV_PMP + help + This option enables Telink TL322X PMP(memory protection) module. + +config TELINK_TL323X_PMP + bool "Support Hardware Memory Protection" + depends on SOC_RISCV_TELINK_TL323X + select RISCV_PMP + help + This option enables Telink TL323X PMP(memory protection) module. + config TELINK_TLX_MBEDTLS_HW_ACCELERATION bool "Use Telink TLx platform mbedtls HW acceleration" depends on SOC_SERIES_RISCV_TELINK_TLX && MBEDTLS @@ -58,6 +72,17 @@ config SOC_RISCV_TELINK_TL321X select ATOMIC_OPERATIONS_BUILTIN select INCLUDE_RESET_VECTOR +config SOC_RISCV_TELINK_TL322X + bool "Telink TL322X SoC implementation" + select ATOMIC_OPERATIONS_BUILTIN + select CPU_HAS_FPU + select INCLUDE_RESET_VECTOR + +config SOC_RISCV_TELINK_TL323X + bool "Telink TL323X SoC implementation" + select ATOMIC_OPERATIONS_BUILTIN + select INCLUDE_RESET_VECTOR + endchoice config PMP_SLOTS @@ -135,3 +160,5 @@ config MICRO_SPEECH_EXTRA_DRIVER depends on SOC_RISCV_TELINK_TL721X help This option enables audio and dma driver for micro speech sample + +source "soc/riscv/riscv-privilege/telink_tlx/Kconfig.n22" \ No newline at end of file diff --git a/soc/riscv/riscv-privilege/telink_tlx/idle.c b/soc/riscv/riscv-privilege/telink_tlx/idle.c index 1360516aeb405..94654d219a12d 100644 --- a/soc/riscv/riscv-privilege/telink_tlx/idle.c +++ b/soc/riscv/riscv-privilege/telink_tlx/idle.c @@ -22,8 +22,13 @@ static ALWAYS_INLINE void riscv_idle(unsigned int key) irq_unlock(key); /* Due to silicon bug in B92 platform, the WFI emulation is implemented */ - while (__irq_pending) { - } + /* Wait for interrupt */ + #if CONFIG_SOC_RISCV_TELINK_TL322X + __asm__ volatile("wfi"); + #else + while (__irq_pending) { + } + #endif } /** diff --git a/soc/riscv/riscv-privilege/telink_tlx/ilm.ld b/soc/riscv/riscv-privilege/telink_tlx/ilm.ld index a2babf35a25c7..082240ad96f30 100644 --- a/soc/riscv/riscv-privilege/telink_tlx/ilm.ld +++ b/soc/riscv/riscv-privilege/telink_tlx/ilm.ld @@ -31,6 +31,8 @@ SECTION_DATA_PROLOGUE(retention_data,,) . = ALIGN(4); *(.retention_data) *(".retention_data.*") + *(.retention_data_ble) + *(".retention_data_ble.*") PROVIDE (_RETENTION_DATA_VMA_END = .); PROVIDE (_RETENTION_DATA_VMA_START = ADDR(retention_data)); diff --git a/soc/riscv/riscv-privilege/telink_tlx/isr_table.c b/soc/riscv/riscv-privilege/telink_tlx/isr_table.c new file mode 100644 index 0000000000000..7d303eb641b63 --- /dev/null +++ b/soc/riscv/riscv-privilege/telink_tlx/isr_table.c @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2025 Telink Semiconductor + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#define _IRQ_VECTOR_NUMBER UTIL_OR(DT_PROP(DT_NODELABEL(plic0), riscv_ndev), 0) +#define _IRQ_VECTOR_PLIC_COMP_ADDR (DT_REG_ADDR(DT_NODELABEL(plic0)) + 0x200004) +#define _IRQ_VECTOR_TABLE_RECORD(i, _) ((uintptr_t)&_isr_vectored_wrapper) + +extern void _isr_vectored_wrapper(void); + +uintptr_t __irq_vector_table _irq_vector_table[_IRQ_VECTOR_NUMBER + 1] = { + ((uintptr_t)&_isr_wrapper), + LISTIFY(_IRQ_VECTOR_NUMBER, _IRQ_VECTOR_TABLE_RECORD, (,)) +}; + +void _irq_vector_handler(uint32_t num) +{ + struct _isr_table_entry *entry = &_sw_isr_table[CONFIG_2ND_LVL_ISR_TBL_OFFSET + num]; + + csr_set(mstatus, MSTATUS_IEN); + entry->isr(entry->arg); + csr_clear(mstatus, MSTATUS_IEN); + *(volatile uint32_t *)(_IRQ_VECTOR_PLIC_COMP_ADDR) = num; +} diff --git a/soc/riscv/riscv-privilege/telink_tlx/isr_vectored.S b/soc/riscv/riscv-privilege/telink_tlx/isr_vectored.S new file mode 100644 index 0000000000000..213fb3aef1208 --- /dev/null +++ b/soc/riscv/riscv-privilege/telink_tlx/isr_vectored.S @@ -0,0 +1,412 @@ +/* + * Copyright (c) 2016 Jean-Paul Etienne + * Copyright (c) 2018 Foundries.io Ltd + * Copyright (c) 2020 BayLibre, SAS + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include <../arch/riscv/core/asm_macros.inc> + +#ifdef CONFIG_RISCV_SOC_HAS_ISR_STACKING +#include +#endif + +/* Convenience macro for loading/storing register states. */ +#define DO_CALLER_SAVED(op) \ + RV_E( op t0, __z_arch_esf_t_t0_OFFSET(sp) );\ + RV_E( op t1, __z_arch_esf_t_t1_OFFSET(sp) );\ + RV_E( op t2, __z_arch_esf_t_t2_OFFSET(sp) );\ + RV_I( op t3, __z_arch_esf_t_t3_OFFSET(sp) );\ + RV_I( op t4, __z_arch_esf_t_t4_OFFSET(sp) );\ + RV_I( op t5, __z_arch_esf_t_t5_OFFSET(sp) );\ + RV_I( op t6, __z_arch_esf_t_t6_OFFSET(sp) );\ + RV_E( op a0, __z_arch_esf_t_a0_OFFSET(sp) );\ + RV_E( op a1, __z_arch_esf_t_a1_OFFSET(sp) );\ + RV_E( op a2, __z_arch_esf_t_a2_OFFSET(sp) );\ + RV_E( op a3, __z_arch_esf_t_a3_OFFSET(sp) );\ + RV_E( op a4, __z_arch_esf_t_a4_OFFSET(sp) );\ + RV_E( op a5, __z_arch_esf_t_a5_OFFSET(sp) );\ + RV_I( op a6, __z_arch_esf_t_a6_OFFSET(sp) );\ + RV_I( op a7, __z_arch_esf_t_a7_OFFSET(sp) );\ + RV_E( op ra, __z_arch_esf_t_ra_OFFSET(sp) ) + + .macro get_current_cpu dst +#if defined(CONFIG_SMP) || defined(CONFIG_USERSPACE) + csrr \dst, mscratch +#else + la \dst, _kernel + ___kernel_t_cpus_OFFSET +#endif + .endm + +/* imports */ +GTEXT(_irq_vector_handler) +#ifdef CONFIG_RISCV_SOC_CONTEXT_SAVE +GTEXT(__soc_save_context) +GTEXT(__soc_restore_context) +#endif /* CONFIG_RISCV_SOC_CONTEXT_SAVE */ + +GTEXT(z_get_next_switch_handle) +GTEXT(z_riscv_switch) + +#ifdef CONFIG_TRACING +GTEXT(sys_trace_isr_enter) +GTEXT(sys_trace_isr_exit) +#endif + +/* exports */ +GTEXT(_isr_vectored_wrapper) + +/* + * Handler called upon each interrupt + */ +SECTION_FUNC(exception.entry, _isr_vectored_wrapper) + +#ifdef CONFIG_USERSPACE + /* retrieve address of _current_cpu preserving s0 */ + csrrw s0, mscratch, s0 + + /* preserve t0 and t1 temporarily */ + sr t0, _curr_cpu_arch_user_exc_tmp0(s0) + sr t1, _curr_cpu_arch_user_exc_tmp1(s0) + + /* determine if we come from user space */ + csrr t0, mstatus + li t1, MSTATUS_MPP + and t0, t0, t1 + bnez t0, 1f + + /* in user space we were: switch to our privileged stack */ + mv t0, sp + lr sp, _curr_cpu_arch_user_exc_sp(s0) + + /* Save user stack value. Coming from user space, we know this + * can't overflow the privileged stack. The esf will be allocated + * later but it is safe to store our saved user sp here. */ + sr t0, (-__z_arch_esf_t_SIZEOF + __z_arch_esf_t_sp_OFFSET)(sp) + + /* Make sure tls pointer is sane */ + lr t0, ___cpu_t_current_OFFSET(s0) + lr tp, _thread_offset_to_tls(t0) + + /* Clear our per-thread usermode flag */ + lui t0, %tprel_hi(is_user_mode) + add t0, t0, tp, %tprel_add(is_user_mode) + sb zero, %tprel_lo(is_user_mode)(t0) +1: + /* retrieve original t0/t1 values */ + lr t0, _curr_cpu_arch_user_exc_tmp0(s0) + lr t1, _curr_cpu_arch_user_exc_tmp1(s0) + + /* retrieve original s0 and restore _current_cpu in mscratch */ + csrrw s0, mscratch, s0 +#endif + +#ifdef CONFIG_RISCV_SOC_HAS_ISR_STACKING + SOC_ISR_SW_STACKING +#else + /* Save caller-saved registers on current thread stack. */ + addi sp, sp, -__z_arch_esf_t_SIZEOF + DO_CALLER_SAVED(sr) ; +#endif /* CONFIG_RISCV_SOC_HAS_ISR_STACKING */ + + /* Save s0 in the esf and load it with &_current_cpu. */ + sr s0, __z_arch_esf_t_s0_OFFSET(sp) + get_current_cpu s0 + + /* Save MEPC register */ + csrr t0, mepc + sr t0, __z_arch_esf_t_mepc_OFFSET(sp) + + /* Save MSTATUS register */ + csrr t2, mstatus + sr t2, __z_arch_esf_t_mstatus_OFFSET(sp) + +#if defined(CONFIG_FPU_SHARING) + /* determine if FPU access was disabled */ + li t1, MSTATUS_FS + and t1, t1, t2 + bnez t1, no_fp + /* determine if this is an Illegal Instruction exception */ + csrr t2, mcause + li t1, 2 /* 2 = illegal instruction */ + bne t1, t2, no_fp + /* determine if we trapped on an FP instruction. */ + csrr t2, mtval /* get faulting instruction */ +#ifdef CONFIG_QEMU_TARGET + /* + * Some implementations may not support MTVAL in this capacity. + * Notably QEMU when a CSR instruction is involved. + */ + bnez t2, 1f + lw t2, 0(t0) /* t0 = mepc */ +1: +#endif + andi t0, t2, 0x7f /* keep only the opcode bits */ + xori t1, t0, 0b1010011 /* OP-FP */ + beqz t1, is_fp + ori t0, t0, 0b0100000 + xori t1, t0, 0b0100111 /* LOAD-FP / STORE-FP */ + beqz t1, is_fp + /* + * The FRCSR, FSCSR, FRRM, FSRM, FSRMI, FRFLAGS, FSFLAGS and FSFLAGSI + * are in fact CSR instructions targeting the fcsr, frm and fflags + * registers. They should be caught as FPU instructions as well. + * + * CSR format: csr#[31-20] src[19-15] op[14-12] dst[11-7] SYSTEM[6-0] + * SYSTEM = 0b1110011, op = 0b.xx where xx is never 0 + * The csr# of interest are: 1=fflags, 2=frm, 3=fcsr + */ + xori t1, t0, 0b1110011 /* SYSTEM opcode */ + bnez t1, 2f /* not a CSR insn */ + srli t0, t2, 12 + andi t0, t0, 0x3 + beqz t0, 2f /* not a CSR insn */ + srli t0, t2, 20 /* isolate the csr register number */ + beqz t0, 2f /* 0=ustatus */ + andi t0, t0, ~0x3 /* 1=fflags, 2=frm, 3=fcsr */ +#if !defined(CONFIG_RISCV_ISA_EXT_C) + bnez t0, no_fp +#else + beqz t0, is_fp +2: /* remaining non RVC (0b11) and RVC with 0b01 are not FP instructions */ + andi t1, t2, 1 + bnez t1, no_fp + /* + * 001...........00 = C.FLD RV32/64 (RV128 = C.LQ) + * 001...........10 = C.FLDSP RV32/64 (RV128 = C.LQSP) + * 011...........00 = C.FLW RV32 (RV64/128 = C.LD) + * 011...........10 = C.FLWSPP RV32 (RV64/128 = C.LDSP) + * 101...........00 = C.FSD RV32/64 (RV128 = C.SQ) + * 101...........10 = C.FSDSP RV32/64 (RV128 = C.SQSP) + * 111...........00 = C.FSW RV32 (RV64/128 = C.SD) + * 111...........10 = C.FSWSP RV32 (RV64/128 = C.SDSP) + * + * so must be .01............. on RV64 and ..1............. on RV32. + */ + srli t0, t2, 8 +#if defined(CONFIG_64BIT) + andi t1, t0, 0b01100000 + xori t1, t1, 0b00100000 + bnez t1, no_fp +#else + andi t1, t0, 0b00100000 + beqz t1, no_fp +#endif +#endif /* CONFIG_RISCV_ISA_EXT_C */ + +is_fp: /* Process the FP trap and quickly return from exception */ + la ra, fp_trap_exit + mv a0, sp + tail z_riscv_fpu_trap +2: +no_fp: /* increment _current->arch.exception_depth */ + lr t0, ___cpu_t_current_OFFSET(s0) + lb t1, _thread_offset_to_exception_depth(t0) + add t1, t1, 1 + sb t1, _thread_offset_to_exception_depth(t0) + + /* configure the FPU for exception mode */ + call z_riscv_fpu_enter_exc +#endif /* CONFIG_FPU_SHARING */ + +#ifdef CONFIG_RISCV_SOC_CONTEXT_SAVE + /* Handle context saving at SOC level. */ + addi a0, sp, __z_arch_esf_t_soc_context_OFFSET + jal ra, __soc_save_context +#endif /* CONFIG_RISCV_SOC_CONTEXT_SAVE */ + +#ifdef CONFIG_PMP_STACK_GUARD +#ifdef CONFIG_USERSPACE + /* + * If we came from userspace then we need to reconfigure the + * PMP for kernel mode stack guard. + */ + lr t0, __z_arch_esf_t_mstatus_OFFSET(sp) + li t1, MSTATUS_MPP + and t0, t0, t1 + bnez t0, 1f + lr a0, ___cpu_t_current_OFFSET(s0) + call z_riscv_pmp_stackguard_enable + j 2f +#endif /* CONFIG_USERSPACE */ +1: /* Re-activate PMP for m-mode */ + li t1, MSTATUS_MPP + csrc mstatus, t1 + li t1, MSTATUS_MPRV + csrs mstatus, t1 +2: +#endif + + /* Increment _current_cpu->nested */ + lw t1, ___cpu_t_nested_OFFSET(s0) + addi t2, t1, 1 + sw t2, ___cpu_t_nested_OFFSET(s0) + bnez t1, on_irq_stack + + /* Switch to interrupt stack */ + mv t0, sp + lr sp, ___cpu_t_irq_stack_OFFSET(s0) + + /* + * Save thread stack pointer on interrupt stack + * In RISC-V, stack pointer needs to be 16-byte aligned + */ + addi sp, sp, -16 + sr t0, 0(sp) + +on_irq_stack: + +#ifdef CONFIG_TRACING_ISR + call sys_trace_isr_enter +#endif + + /* Get IRQ causing interrupt */ + csrr a0, mcause + li t0, SOC_MCAUSE_EXP_MASK + and a0, a0, t0 + + call _irq_vector_handler + +#ifdef CONFIG_TRACING_ISR + call sys_trace_isr_exit +#endif + +irq_done: + /* Decrement _current_cpu->nested */ + lw t2, ___cpu_t_nested_OFFSET(s0) + addi t2, t2, -1 + sw t2, ___cpu_t_nested_OFFSET(s0) + bnez t2, no_reschedule + + /* nested count is back to 0: Return to thread stack */ + lr sp, 0(sp) + +#ifdef CONFIG_STACK_SENTINEL + call z_check_stack_sentinel +#endif + +check_reschedule: + + /* Get pointer to current thread on this CPU */ + lr a1, ___cpu_t_current_OFFSET(s0) + + /* + * Get next thread to schedule with z_get_next_switch_handle(). + * We pass it a NULL as we didn't save the whole thread context yet. + * If no scheduling is necessary then NULL will be returned. + */ + addi sp, sp, -16 + sr a1, 0(sp) + mv a0, zero + call z_get_next_switch_handle + lr a1, 0(sp) + addi sp, sp, 16 + beqz a0, no_reschedule + +reschedule: + + /* + * Perform context switch: + * a0 = new thread + * a1 = old thread + */ + call z_riscv_switch + +might_have_rescheduled: + /* reload s0 with &_current_cpu as it might have changed or be unset */ + get_current_cpu s0 + +no_reschedule: + +#ifdef CONFIG_RISCV_SOC_CONTEXT_SAVE + /* Restore context at SOC level */ + addi a0, sp, __z_arch_esf_t_soc_context_OFFSET + jal ra, __soc_restore_context +#endif /* CONFIG_RISCV_SOC_CONTEXT_SAVE */ + +#if defined(CONFIG_FPU_SHARING) + /* FPU handling upon exception mode exit */ + mv a0, sp + call z_riscv_fpu_exit_exc + + /* decrement _current->arch.exception_depth */ + lr t0, ___cpu_t_current_OFFSET(s0) + lb t1, _thread_offset_to_exception_depth(t0) + add t1, t1, -1 + sb t1, _thread_offset_to_exception_depth(t0) +fp_trap_exit: +#endif + + /* Restore MEPC and MSTATUS registers */ + lr t0, __z_arch_esf_t_mepc_OFFSET(sp) + lr t2, __z_arch_esf_t_mstatus_OFFSET(sp) + csrw mepc, t0 + csrw mstatus, t2 + +#ifdef CONFIG_USERSPACE + /* + * Check if we are returning to user mode. If so then we must + * set is_user_mode to true and preserve our kernel mode stack for + * the next exception to come. + */ + li t1, MSTATUS_MPP + and t0, t2, t1 + bnez t0, 1f + +#ifdef CONFIG_PMP_STACK_GUARD + /* Remove kernel stack guard and Reconfigure PMP for user mode */ + lr a0, ___cpu_t_current_OFFSET(s0) + call z_riscv_pmp_usermode_enable +#endif + + /* Set our per-thread usermode flag */ + li t1, 1 + lui t0, %tprel_hi(is_user_mode) + add t0, t0, tp, %tprel_add(is_user_mode) + sb t1, %tprel_lo(is_user_mode)(t0) + + /* preserve stack pointer for next exception entry */ + add t0, sp, __z_arch_esf_t_SIZEOF + sr t0, _curr_cpu_arch_user_exc_sp(s0) + + j 2f +1: + /* + * We are returning to kernel mode. Store the stack pointer to + * be re-loaded further down. + */ + addi t0, sp, __z_arch_esf_t_SIZEOF + sr t0, __z_arch_esf_t_sp_OFFSET(sp) +2: +#endif + + /* Restore s0 (it is no longer ours) */ + lr s0, __z_arch_esf_t_s0_OFFSET(sp) + +#ifdef CONFIG_RISCV_SOC_HAS_ISR_STACKING + SOC_ISR_SW_UNSTACKING +#else + /* Restore caller-saved registers from thread stack */ + DO_CALLER_SAVED(lr) + +#ifdef CONFIG_USERSPACE + /* retrieve saved stack pointer */ + lr sp, __z_arch_esf_t_sp_OFFSET(sp) +#else + /* remove esf from the stack */ + addi sp, sp, __z_arch_esf_t_SIZEOF +#endif + +#endif /* CONFIG_RISCV_SOC_HAS_ISR_STACKING */ + + mret diff --git a/soc/riscv/riscv-privilege/telink_tlx/linker.ld b/soc/riscv/riscv-privilege/telink_tlx/linker.ld index c0e33c5593981..a29cbd41576e7 100644 --- a/soc/riscv/riscv-privilege/telink_tlx/linker.ld +++ b/soc/riscv/riscv-privilege/telink_tlx/linker.ld @@ -22,17 +22,20 @@ MEMORY { #if !CONFIG_SOC_SERIES_RISCV_TELINK_TLX_RETENTION - #if CONFIG_SOC_RISCV_TELINK_TL721X + #if CONFIG_SOC_RISCV_TELINK_TL721X || CONFIG_SOC_RISCV_TELINK_TL322X RAMILM (rwx) : ORIGIN = DT_REG_ADDR(DT_NODELABEL(ram_ilm)), LENGTH = DT_REG_SIZE(DT_NODELABEL(ram_ilm)) - #elif CONFIG_SOC_RISCV_TELINK_TL321X + #elif CONFIG_SOC_RISCV_TELINK_TL321X || CONFIG_SOC_RISCV_TELINK_TL323X RAM_ILM_N (rwx) : ORIGIN = DT_REG_ADDR(DT_NODELABEL(ram_ilm_non_retention)),LENGTH = DT_REG_SIZE(DT_NODELABEL(ram_ilm_non_retention)) #endif #else - #if CONFIG_SOC_RISCV_TELINK_TL721X + #if CONFIG_SOC_RISCV_TELINK_TL721X || CONFIG_SOC_RISCV_TELINK_TL322X RAM_ILM_N (rwx) : ORIGIN = DT_REG_ADDR(DT_NODELABEL(ram_ilm_nonretention)), LENGTH = DT_REG_SIZE(DT_NODELABEL(ram_ilm_nonretention)) RAM_DLM (rwx) : ORIGIN = DT_REG_ADDR(DT_NODELABEL(ram_dlm)), LENGTH = DT_REG_SIZE(DT_NODELABEL(ram_dlm)) #elif CONFIG_SOC_RISCV_TELINK_TL321X RAM_ILM_N (rwx) : ORIGIN = DT_REG_ADDR(DT_NODELABEL(ram_ilm_nonretention)), LENGTH = DT_REG_SIZE(DT_NODELABEL(ram_ilm_nonretention)) + #elif CONFIG_SOC_RISCV_TELINK_TL323X + RAM_ILM_NON_RESET (rwx) : ORIGIN = DT_REG_ADDR(DT_NODELABEL(ram_ilm_retention_non_reset)), LENGTH = DT_REG_SIZE(DT_NODELABEL(ram_ilm_retention_non_reset)) + RAM_ILM_N (rwx) : ORIGIN = DT_REG_ADDR(DT_NODELABEL(ram_ilm_nonretention)), LENGTH = DT_REG_SIZE(DT_NODELABEL(ram_ilm_nonretention)) #endif #endif /* CONFIG_SOC_SERIES_RISCV_TELINK_TLX_RETENTION */ } diff --git a/soc/riscv/riscv-privilege/telink_tlx/matter_retention.ld b/soc/riscv/riscv-privilege/telink_tlx/matter_retention.ld index 4deb1d69db2d0..1153ce4010359 100644 --- a/soc/riscv/riscv-privilege/telink_tlx/matter_retention.ld +++ b/soc/riscv/riscv-privilege/telink_tlx/matter_retention.ld @@ -14,7 +14,8 @@ SECTION_DATA_PROLOGUE(ram_dlm_data,,) . = ALIGN(4); *(.data) *(.sdata) - + *(.retention_data_ble) + *(".retention_data_ble.*") PROVIDE (_RAM_DLM_DATA_VMA_END = .); PROVIDE (_RAM_DLM_DATA_VMA_START = ADDR(ram_dlm_data)); PROVIDE (_RAM_DLM_DATA_LMA_START = LOADADDR(ram_dlm_data)); diff --git a/soc/riscv/riscv-privilege/telink_tlx/pinctrl_soc.h b/soc/riscv/riscv-privilege/telink_tlx/pinctrl_soc.h index 4a611d8dde891..7090bcfa9e346 100644 --- a/soc/riscv/riscv-privilege/telink_tlx/pinctrl_soc.h +++ b/soc/riscv/riscv-privilege/telink_tlx/pinctrl_soc.h @@ -13,6 +13,10 @@ #include #elif CONFIG_SOC_RISCV_TELINK_TL321X #include +#elif CONFIG_SOC_RISCV_TELINK_TL322X +#include +#elif CONFIG_SOC_RISCV_TELINK_TL323X +#include #endif /** diff --git a/soc/riscv/riscv-privilege/telink_tlx/soc.c b/soc/riscv/riscv-privilege/telink_tlx/soc.c index dfceca06211c2..2c787356a6fed 100644 --- a/soc/riscv/riscv-privilege/telink_tlx/soc.c +++ b/soc/riscv/riscv-privilege/telink_tlx/soc.c @@ -15,16 +15,45 @@ #include #include +#if DEBUG_GPIO_ENABLE +#include "gpio_default.h" +#endif + #if (defined(CONFIG_BT_TLX) || defined(CONFIG_IEEE802154)) #include "tlx_bt_flash.h" #endif +#if CONFIG_SOC_RISCV_TELINK_TL322X +# if TLK_ONLY_BLE_HOST + #include "stack/multicore_comm/service/service_d25f.h" +# endif +#endif + +/* Drivers changes , so should not change castart.s, add external*/ +#if CONFIG_SOC_RISCV_TELINK_TL321X || CONFIG_SOC_RISCV_TELINK_TL323X +_attribute_data_retention_sec_ unsigned int g_pm_mspi_cfg; +__attribute__((section(".ram_code_retention"))) __attribute__((noinline)) +void pm_retention_register_recover(void){ +} +#endif + /* Power Mode value */ #if CONFIG_SOC_RISCV_TELINK_TL321X /* List of supported CCLK frequencies */ #define CLK_24MHZ 24000000u #define CLK_48MHZ 48000000u #define CLK_96MHZ 96000000u +#elif CONFIG_SOC_RISCV_TELINK_TL322X + /* List of supported CCLK frequencies */ + #define CLK_48MHZ 48000000u + #define CLK_64MHZ 64000000u + #define CLK_72MHZ 72000000u + #define CLK_96MHZ 96000000u + #define CLK_192MHZ 192000000u +#elif CONFIG_SOC_RISCV_TELINK_TL323X + #define CLK_24MHZ 24000000u + #define CLK_48MHZ 48000000u + #define CLK_96MHZ 96000000u #elif CONFIG_SOC_RISCV_TELINK_TL721X /* List of supported CCLK frequencies */ #define CLK_40MHZ 40000000u @@ -35,6 +64,14 @@ #define CLK_240MHZ 240000000u #endif + +#if CONFIG_SOC_RISCV_TELINK_TL322X && CONFIG_USB_TELINK_TLX + /* Check Clock value for USB0. */ + #if DT_PROP(DT_PATH(cpus, cpu_0), clock_frequency) < CLK_96MHZ + #error "USB0 digital voltage must be 1.1V and HCLK min's 48M" + #endif +#endif + /* MID register flash size */ #define FLASH_MID_SIZE_OFFSET 16 #define FLASH_MID_SIZE_MASK 0x00ff0000 @@ -48,6 +85,26 @@ #else #error "Wrong value for power-mode parameter" #endif +#elif CONFIG_SOC_RISCV_TELINK_TL322X + #if DT_ENUM_IDX(DT_NODELABEL(power), power_mode) == 0 + #define POWER_MODE LDO_1P25_LDO_1P8 + #elif DT_ENUM_IDX(DT_NODELABEL(power), power_mode) == 1 + #define POWER_MODE DCDC_1P25_LDO_1P8 + #elif DT_ENUM_IDX(DT_NODELABEL(power), power_mode) == 2 + #define POWER_MODE DCDC_1P25_DCDC_1P8 + #else + #error "Wrong value for power-mode parameter" + #endif +#elif CONFIG_SOC_RISCV_TELINK_TL323X + #if DT_ENUM_IDX(DT_NODELABEL(power), power_mode) == 0 + #define POWER_MODE LDO_1P25_LDO_1P8 + #elif DT_ENUM_IDX(DT_NODELABEL(power), power_mode) == 1 + #define POWER_MODE DCDC_1P25_LDO_1P8 + #elif DT_ENUM_IDX(DT_NODELABEL(power), power_mode) == 2 + #define POWER_MODE DCDC_1P25_DCDC_1P8 + #else + #error "Wrong value for power-mode parameter" + #endif #elif CONFIG_SOC_RISCV_TELINK_TL721X #if DT_ENUM_IDX(DT_NODELABEL(power), power_mode) == 0 #define POWER_MODE LDO_0P94_LDO_1P8 @@ -77,6 +134,20 @@ (DT_PROP(DT_PATH(cpus, cpu_0), clock_frequency) != CLK_96MHZ)) #error "Invalid clock-frequency. Supported values: 24, 48, 96 MHz" #endif +#elif CONFIG_SOC_RISCV_TELINK_TL322X + #if ((DT_PROP(DT_PATH(cpus, cpu_0), clock_frequency) != CLK_48MHZ) && \ + (DT_PROP(DT_PATH(cpus, cpu_0), clock_frequency) != CLK_64MHZ) && \ + (DT_PROP(DT_PATH(cpus, cpu_0), clock_frequency) != CLK_72MHZ) && \ + (DT_PROP(DT_PATH(cpus, cpu_0), clock_frequency) != CLK_96MHZ) && \ + (DT_PROP(DT_PATH(cpus, cpu_0), clock_frequency) != CLK_192MHZ)) + #error "Invalid clock-frequency. Supported values: 48,64,72,96,192 MHz" + #endif +#elif CONFIG_SOC_RISCV_TELINK_TL323X + #if ((DT_PROP(DT_PATH(cpus, cpu_0), clock_frequency) != CLK_24MHZ) && \ + (DT_PROP(DT_PATH(cpus, cpu_0), clock_frequency) != CLK_48MHZ) && \ + (DT_PROP(DT_PATH(cpus, cpu_0), clock_frequency) != CLK_96MHZ)) + #error "Invalid clock-frequency. Supported values: 24, 48, 96 MHz" + #endif #elif CONFIG_SOC_RISCV_TELINK_TL721X #if ((DT_PROP(DT_PATH(cpus, cpu_0), clock_frequency) != CLK_40MHZ) && \ (DT_PROP(DT_PATH(cpus, cpu_0), clock_frequency) != CLK_48MHZ) && \ @@ -160,11 +231,19 @@ static int soc_tlx_init(void) case CLK_24MHZ: PLL_192M_CCLK_24M_HCLK_24M_PCLK_24M_MSPI_48M; break; +#elif CONFIG_SOC_RISCV_TELINK_TL323X + case CLK_24MHZ: + PLL_192M_CCLK_24M_HCLK_24M_PCLK_24M_MSPI_48M; + break; #endif case CLK_48MHZ: #if CONFIG_SOC_RISCV_TELINK_TL321X PLL_192M_CCLK_48M_HCLK_48M_PCLK_48M_MSPI_48M; +#elif CONFIG_SOC_RISCV_TELINK_TL322X + PLL_192M_D25F_48M_HCLK_N22_24M_PCLK_12M_MSPI_48M; +#elif CONFIG_SOC_RISCV_TELINK_TL323X + PLL_192M_CCLK_48M_HCLK_24M_PCLK_12M_MSPI_48M; #elif CONFIG_SOC_RISCV_TELINK_TL721X PLL_240M_CCLK_48M_HCLK_48M_PCLK_48M_MSPI_48M; #endif @@ -180,9 +259,38 @@ static int soc_tlx_init(void) break; #endif +#if CONFIG_SOC_RISCV_TELINK_TL322X + case CLK_64MHZ: + PLL_192M_D25F_64M_HCLK_N22_32M_PCLK_32M_MSPI_48M; + pm_set_dig_ldo(DIG_VOL_1V_MODE, 1000); + break; + + case CLK_72MHZ: + PLL_144M_D25F_72M_HCLK_N22_36M_PCLK_36M_MSPI_48M; + pm_set_dig_ldo(DIG_VOL_1V_MODE, 1000); + break; + + case CLK_96MHZ: + pm_set_dig_ldo(DIG_VOL_1V1_MODE, 1000); + PLL_192M_D25F_96M_HCLK_N22_48M_PCLK_48M_MSPI_48M; + break; +#endif + #if CONFIG_SOC_RISCV_TELINK_TL321X + // case CLK_96MHZ: + // PLL_192M_CCLK_96M_HCLK_48M_PCLK_48M_MSPI_64M; + // break; +#elif CONFIG_SOC_RISCV_TELINK_TL323X + // Need to set PLL_CLK to 96MHz case CLK_96MHZ: - PLL_192M_CCLK_96M_HCLK_48M_PCLK_48M_MSPI_64M; + PLL_192M_CCLK_96M_HCLK_48M_PCLK_48M_MSPI_48M; + break; +#endif + +#if CONFIG_SOC_RISCV_TELINK_TL322X + case CLK_192MHZ: + pm_set_dig_ldo(DIG_VOL_1V1_MODE, 1000); + PLL_192M_D25F_192M_HCLK_N22_96M_PCLK_96M_MSPI_48M; break; #endif @@ -201,8 +309,33 @@ static int soc_tlx_init(void) clock_32k_init(CLK_32K_RC); clock_cal_32k_rc(); + /* pke is not enabled by default on TL323X */ +#if CONFIG_SOC_RISCV_TELINK_TL323X + extern void pke_dig_en(void); + pke_dig_en(); +#endif + /* Stop 32k watchdog */ wd_32k_stop(); +#if CONFIG_SOC_RISCV_TELINK_TL322X +#undef N22_FW_DOWNLOAD_FLASH_ADDR +#if defined(CONFIG_BT_ID_FOR_KMD) +#define N22_FW_DOWNLOAD_FLASH_ADDR 0x20048000 +#else +#define N22_FW_DOWNLOAD_FLASH_ADDR 0x20080000+0x13040 +#endif + sys_n22_init(N22_FW_DOWNLOAD_FLASH_ADDR); + #if !defined(TLK_ONLY_BLE_HOST) + rf_n22_dig_init(); + #endif +#endif + + int deepRetWakeUp = pm_is_MCU_deepRetentionWakeup(); //MCU deep retention wakeUp +#if DEBUG_GPIO_ENABLE + gpio_init(!deepRetWakeUp); +#else + (void)deepRetWakeUp; // remove warning +#endif return 0; } @@ -240,12 +373,20 @@ void soc_tlx_restore(void) #if CONFIG_SOC_RISCV_TELINK_TL321X case CLK_24MHZ: PLL_192M_CCLK_24M_HCLK_24M_PCLK_24M_MSPI_48M; -#endif break; +#elif CONFIG_SOC_RISCV_TELINK_TL323X + case CLK_24MHZ: + PLL_192M_CCLK_24M_HCLK_24M_PCLK_24M_MSPI_48M; + break; +#endif case CLK_48MHZ: #if CONFIG_SOC_RISCV_TELINK_TL321X PLL_192M_CCLK_48M_HCLK_48M_PCLK_48M_MSPI_48M; +#elif CONFIG_SOC_RISCV_TELINK_TL322X + PLL_192M_D25F_48M_HCLK_N22_24M_PCLK_12M_MSPI_48M; +#elif CONFIG_SOC_RISCV_TELINK_TL323X + PLL_192M_CCLK_48M_HCLK_24M_PCLK_12M_MSPI_48M; #elif CONFIG_SOC_RISCV_TELINK_TL721X PLL_240M_CCLK_48M_HCLK_48M_PCLK_48M_MSPI_48M; #endif @@ -261,9 +402,38 @@ void soc_tlx_restore(void) break; #endif +#if CONFIG_SOC_RISCV_TELINK_TL322X + case CLK_64MHZ: + PLL_192M_D25F_64M_HCLK_N22_32M_PCLK_32M_MSPI_48M; + pm_set_dig_ldo(DIG_VOL_1V_MODE, 1000); + break; + + case CLK_72MHZ: + PLL_144M_D25F_72M_HCLK_N22_36M_PCLK_36M_MSPI_48M; + pm_set_dig_ldo(DIG_VOL_1V_MODE, 1000); + break; + + case CLK_96MHZ: + pm_set_dig_ldo(DIG_VOL_1V1_MODE, 1000); + PLL_192M_D25F_96M_HCLK_N22_48M_PCLK_48M_MSPI_48M; + break; +#endif + #if CONFIG_SOC_RISCV_TELINK_TL321X + // case CLK_96MHZ: + // PLL_192M_CCLK_96M_HCLK_48M_PCLK_48M_MSPI_64M; + // break; +#elif CONFIG_SOC_RISCV_TELINK_TL323X + // Need to set PLL_CLK to 96MHz case CLK_96MHZ: - PLL_192M_CCLK_96M_HCLK_48M_PCLK_48M_MSPI_64M; + PLL_192M_CCLK_96M_HCLK_48M_PCLK_48M_MSPI_48M; + break; +#endif + +#if CONFIG_SOC_RISCV_TELINK_TL322X + case CLK_192MHZ: + pm_set_dig_ldo(DIG_VOL_1V1_MODE, 1000); + PLL_192M_D25F_192M_HCLK_N22_96M_PCLK_96M_MSPI_48M; break; #endif @@ -276,6 +446,17 @@ void soc_tlx_restore(void) break; #endif } + /* pke is not enabled by default on TL323X */ +#if CONFIG_SOC_RISCV_TELINK_TL323X + extern void pke_dig_en(void); + pke_dig_en(); +#endif + int deepRetWakeUp = pm_is_MCU_deepRetentionWakeup(); //MCU deep retention wakeUp +#if DEBUG_GPIO_ENABLE + gpio_init(!deepRetWakeUp); +#else + (void)deepRetWakeUp; // remove warning +#endif } #if CONFIG_SOC_RISCV_TELINK_TL721X @@ -299,7 +480,28 @@ unsigned char flash_set_4line_read_write(mspi_slave_device_num_e device_num, uns return status; } -#elif CONFIG_SOC_RISCV_TELINK_TL321X +#elif CONFIG_SOC_RISCV_TELINK_TL322X +#include "flash/flash_common.h" +#include "flash_base.h" +/** + * @brief This function is used to set the use of four lines when reading and writing flash. + * @param[in] device_num - the number of slave device. + * @param[in] flash_mid - the mid of flash. + * @return 1: success, 0: error, 2: mid is not supported. + */ +unsigned char flash_set_4line_read_write(mspi_slave_device_num_e device_num, unsigned int flash_mid) +{ + unsigned char status = flash_4line_en_with_device_num(device_num, flash_mid); + + if (status == 1) { + flash_read_page = flash_4read; + flash_set_rd_xip_config_sram(device_num, FLASH_X4READ_CMD); + flash_write_page = flash_quad_page_program; + } + + return status; +} +#elif CONFIG_SOC_RISCV_TELINK_TL321X || CONFIG_SOC_RISCV_TELINK_TL323X #include "flash/flash_common.h" #include "flash_base.h" /** @@ -321,6 +523,7 @@ unsigned char flash_set_4line_read_write(unsigned int flash_mid) } #endif + /** * @brief Check mounted flash size (should be greater than in .dts). */ @@ -331,16 +534,20 @@ static int soc_tlx_check_flash(void) flash_capacity_e hw_flash_cap; uint32_t mid; -#if CONFIG_SOC_RISCV_TELINK_TL321X +#if CONFIG_SOC_RISCV_TELINK_TL321X || CONFIG_SOC_RISCV_TELINK_TL323X mid = flash_read_mid(); +#elif CONFIG_SOC_RISCV_TELINK_TL322X + mid = flash_read_mid_with_device_num(SLAVE0); #elif CONFIG_SOC_RISCV_TELINK_TL721X mid = flash_read_mid_with_device_num(SLAVE0); #endif hw_flash_cap = (flash_capacity_e)((mid & FLASH_MID_SIZE_MASK) >> FLASH_MID_SIZE_OFFSET); /* Enable Quad SPI (4x) read and write mode */ -#if CONFIG_SOC_RISCV_TELINK_TL321X +#if CONFIG_SOC_RISCV_TELINK_TL321X || CONFIG_SOC_RISCV_TELINK_TL323X if (flash_set_4line_read_write(mid) != 1) { +#elif CONFIG_SOC_RISCV_TELINK_TL322X + if (flash_set_4line_read_write(SLAVE0, mid) != 1) { #elif CONFIG_SOC_RISCV_TELINK_TL721X if (flash_set_4line_read_write(SLAVE0, mid) != 1) { #endif @@ -390,3 +597,18 @@ __attribute__((noinline)) void telink_bt_blc_mac_init(uint8_t *bt_mac) SYS_INIT(soc_tlx_init, PRE_KERNEL_1, 0); SYS_INIT(soc_tlx_check_flash, POST_KERNEL, 0); + +#ifdef CONFIG_TELINK_TL322X_ENABLE_N22 +static int soc_tlx_mcc_init(void) +{ + extern void mb_irq_handler(void); + IRQ_CONNECT(IRQ_MAILBOX_N22_TO_D25 + CONFIG_2ND_LVL_ISR_TBL_OFFSET, 2, mb_irq_handler, 0, 0); + volatile uint32_t key = arch_irq_lock(); + sys_n22_start(); + mcc_d25f_service_init(); + arch_irq_unlock(key); + + return 0; +} +SYS_INIT(soc_tlx_mcc_init, POST_KERNEL, 1); +#endif \ No newline at end of file diff --git a/soc/riscv/riscv-privilege/telink_tlx/start.S b/soc/riscv/riscv-privilege/telink_tlx/start.S index 80d8c8083e10e..1b44380158c7b 100644 --- a/soc/riscv/riscv-privilege/telink_tlx/start.S +++ b/soc/riscv/riscv-privilege/telink_tlx/start.S @@ -7,8 +7,27 @@ #define NDS_MCACHE_CTL 0x7ca #define NDS_MMISC_CTL 0x7d0 #define NDS_UITB 0x800 +#if CONFIG_SOC_RISCV_TELINK_TL322X + .equ __D25F_IRAM_SIZE, 2 //64KB + .equ __D25F_DRAM_SIZE, 3 //96KB + .equ __N22_IRAM_SIZE, 5 //160KB + .equ __N22_DRAM_SIZE, 2 //64KB + + .equ __D25F_N22_RAM_REG, ((__N22_DRAM_SIZE+__N22_IRAM_SIZE)<<12)|(__N22_DRAM_SIZE<<8)|(__D25F_DRAM_SIZE) + + .section .vectors, "ax" + + .global __D25F_IRAM_SIZE + .global __D25F_DRAM_SIZE + .global __N22_IRAM_SIZE + .global __N22_DRAM_SIZE + .global __D25F_N22_RAM_REG +#endif + +#define PLIC_BASE_ADDRESS DT_REG_ADDR(DT_NODELABEL(plic0)) #include +#include .option push .option norelax @@ -35,18 +54,34 @@ entry: .align 2 start: +#if CONFIG_SOC_RISCV_TELINK_TL322X + /*Initialize D25 & N22 ILM DLM Size */ + lui t0 , 0x80141 + li t1 , __D25F_N22_RAM_REG + sh t1 , -2036(t0) //write16(0x8014080c,0x2105) +#endif + #if defined(CONFIG_ANDES_CODENSE) && CONFIG_ANDES_CODENSE la t0, _ITB_BASE_ csrw NDS_UITB, t0 #/ CoDense instruction table #endif - /* Disable vector mode */ - csrci 0x7d0, 2 + /* Select PLIC mode */ +#ifdef CONFIG_RISCV_MTVEC_VECTORED_MODE + csrsi NDS_MMISC_CTL, 2 - /* Disable vector feture enable address */ - lui t0 ,0xc4000 - li t1 ,0x00 + lui t0, %hi(PLIC_BASE_ADDRESS) + addi t0, t0, %lo(PLIC_BASE_ADDRESS) + li t1 ,0x03 sw t1 ,0x0(t0) +#else + csrci NDS_MMISC_CTL, 2 + + lui t0, %hi(PLIC_BASE_ADDRESS) + addi t0, t0, %lo(PLIC_BASE_ADDRESS) + li t1 ,0x00 + sw t1 ,0x0(t0) +#endif /* CONFIG_RISCV_MTVEC_VECTORED_MODE */ /* Enable I/D-Cache */ csrr t0, NDS_MCACHE_CTL @@ -172,6 +207,25 @@ retention_entry: retention_start: + /* Select PLIC mode */ +#ifdef CONFIG_RISCV_VECTORED_MODE + csrsi NDS_MMISC_CTL, 2 + + /* Enable vector feture enable address */ + lui t0, %hi(PLIC_BASE_ADDRESS) + addi t0, t0, %lo(PLIC_BASE_ADDRESS) + li t1 ,0x03 + sw t1 ,0x0(t0) +#else + csrci NDS_MMISC_CTL, 2 + + /* Disable vector feture enable address */ + lui t0, %hi(PLIC_BASE_ADDRESS) + addi t0, t0, %lo(PLIC_BASE_ADDRESS) + li t1 ,0x00 + sw t1 ,0x0(t0) +#endif /* CONFIG_RISCV_VECTORED_MODE */ + /* Enable I/D-Cache */ csrr t0, NDS_MCACHE_CTL ori t0, t0, 1 #/ I-Cache @@ -184,7 +238,7 @@ retention_start: csrs NDS_MMISC_CTL, t0 /* flash wakeup */ -#if CONFIG_SOC_RISCV_TELINK_TL721X || CONFIG_SOC_RISCV_TELINK_TL321X +#if CONFIG_SOC_RISCV_TELINK_TL721X || CONFIG_SOC_RISCV_TELINK_TL321X || CONFIG_SOC_RISCV_TELINK_TL322X || CONFIG_SOC_RISCV_TELINK_TL323X /* we are not in ISR so use ISR stack to restore registers */ la sp, z_interrupt_stacks li t0, CONFIG_ISR_STACK_SIZE diff --git a/soc/riscv/riscv-privilege/telink_tlx/telink_tlx_regions.ld b/soc/riscv/riscv-privilege/telink_tlx/telink_tlx_regions.ld index 41cf2c720c2e9..0193f6417286d 100644 --- a/soc/riscv/riscv-privilege/telink_tlx/telink_tlx_regions.ld +++ b/soc/riscv/riscv-privilege/telink_tlx/telink_tlx_regions.ld @@ -5,21 +5,21 @@ */ #if !CONFIG_SOC_SERIES_RISCV_TELINK_TLX_RETENTION - #if CONFIG_SOC_RISCV_TELINK_TL721X + #if CONFIG_SOC_RISCV_TELINK_TL721X || CONFIG_SOC_RISCV_TELINK_TL322X #define TELINK_RAM_REGION RAMILM #define TELINK_RAM_CODE_REGION RAMILM #define TELINK_RAM_CODE_RET_REGION RAMILM - #elif CONFIG_SOC_RISCV_TELINK_TL321X + #elif CONFIG_SOC_RISCV_TELINK_TL321X || CONFIG_SOC_RISCV_TELINK_TL323X #define TELINK_RAM_REGION RAMABLE_REGION - #define TELINK_RAM_CODE_REGION RAM_ILM_N - #define TELINK_RAM_CODE_RET_REGION RAM_ILM_N + #define TELINK_RAM_CODE_REGION RAMABLE_REGION + #define TELINK_RAM_CODE_RET_REGION RAMABLE_REGION #define TELINK_RAM_DATA_REGION RAM_ILM_N - #define TELINK_RAM_CODE_BLE_REGION RAM_ILM_N + #define TELINK_RAM_CODE_BLE_REGION RAMABLE_REGION #endif #else #define TELINK_RAM_REGION RAMABLE_REGION #define TELINK_RAM_CODE_RET_REGION RAMABLE_REGION - #if CONFIG_SOC_RISCV_TELINK_TL721X + #if CONFIG_SOC_RISCV_TELINK_TL721X || CONFIG_SOC_RISCV_TELINK_TL322X #define TELINK_RAM_DATA_REGION RAM_DLM #define TELINK_RAM_CODE_BLE_REGION RAM_ILM_N #if CONFIG_SOC_SERIES_RISCV_TELINK_TLX_NON_RETENTION_RAM_CODE @@ -40,5 +40,18 @@ #else #define TELINK_RAM_CODE_REGION RAMABLE_REGION #endif + #elif CONFIG_SOC_RISCV_TELINK_TL323X + #if CONFIG_PM + #define TELINK_RAM_DATA_REGION RAM_ILM_N + #define TELINK_RAM_CODE_BLE_REGION RAM_ILM_N + #else + #define TELINK_RAM_DATA_REGION RAMABLE_REGION + #define TELINK_RAM_CODE_BLE_REGION RAMABLE_REGION + #endif + #if CONFIG_SOC_SERIES_RISCV_TELINK_TLX_NON_RETENTION_RAM_CODE + #define TELINK_RAM_CODE_REGION RAM_ILM_N + #else + #define TELINK_RAM_CODE_REGION RAM_ILM_NON_RESET + #endif #endif #endif /* CONFIG_SOC_SERIES_RISCV_TELINK_TLX_RETENTION */ diff --git a/subsys/bluetooth/host/id.c b/subsys/bluetooth/host/id.c index 49bbf47c855d0..cd2466d131e2a 100644 --- a/subsys/bluetooth/host/id.c +++ b/subsys/bluetooth/host/id.c @@ -1297,7 +1297,11 @@ int bt_id_reset(uint8_t id, bt_addr_le_t *addr, uint8_t *irk) return -EINVAL; } +#if defined(CONFIG_BT_ID_FOR_KMD) + if (id >= bt_dev.id_count) { +#else if (id == BT_ID_DEFAULT || id >= bt_dev.id_count) { +#endif return -EINVAL; } diff --git a/subsys/usb/device/usb_descriptor.c b/subsys/usb/device/usb_descriptor.c index 5533828bc9267..a72d83a7f718b 100644 --- a/subsys/usb/device/usb_descriptor.c +++ b/subsys/usb/device/usb_descriptor.c @@ -471,15 +471,15 @@ static int usb_fix_descriptor(struct usb_desc_header *head) if (str_descr_idx) { ascii7_to_utf16le(head); } else { - if (!cfg_descr) { + if (!(cfg_descr)) { LOG_ERR("Incomplete device descriptor"); return -1; } LOG_DBG("Now the wTotalLength is %zd", - (uint8_t *)head - (uint8_t *)cfg_descr); + (uint8_t *)head - (uint8_t *)cfg_descr); sys_put_le16((uint8_t *)head - (uint8_t *)cfg_descr, - (uint8_t *)&cfg_descr->wTotalLength); + (uint8_t *)&cfg_descr->wTotalLength); cfg_descr->bNumInterfaces = numof_ifaces; } diff --git a/subsys/usb/device/usb_device.c b/subsys/usb/device/usb_device.c index 41bcb8526573e..dd76c43e94545 100644 --- a/subsys/usb/device/usb_device.c +++ b/subsys/usb/device/usb_device.c @@ -501,7 +501,7 @@ static bool usb_get_descriptor(struct usb_setup_packet *setup, * 2 and 3 */ *len = (p[CONF_DESC_wTotalLength]) | - (p[CONF_DESC_wTotalLength + 1] << 8); + (p[CONF_DESC_wTotalLength + 1] << 8); } else { /* normally length is at offset 0 */ *len = p[DESC_bLength]; diff --git a/west.yml b/west.yml index 18c821bc83913..2b0ac10021d34 100644 --- a/west.yml +++ b/west.yml @@ -141,9 +141,15 @@ manifest: groups: - hal - name: hal_telink - url: https://github.com/telink-semi/hal_telink - revision: 541f19515a7796411ed68352ffd9718472212ca6 + url: git@github.com:telink-semi/hal_telink.git + revision: 9df5ff319e923f11c04d28a19e81452aa1791eba path: modules/hal/telink + groups: + - hal + - name: tl_ble_sdk + url: git@github.com:telink-semi/tl_ble_sdk.git + revision: 74d355e3780b332ff5eeac631a8e31a533ce6501 + path: modules/hal/telink/tl_ble_sdk groups: - hal - name: hal_ti @@ -193,7 +199,8 @@ manifest: groups: - crypto - name: mcuboot - revision: 1558e7ab0aadb4eac11f03befb5ccd3fa3f0aafe + url: git@github.com:telink-semi/mcuboot.git + revision: 3b46cd5423b3fd2d3fdfe41111025f439db23117 path: bootloader/mcuboot - name: mipi-sys-t path: modules/debug/mipi-sys-t