2025年11月19日 星期三

Data transmission process for WE310G4

After testing, no data will be lost during the data transmission process.
Telit WE310G4

Client_We310G4.c (created by ChatGPT)
#include <fcntl.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/select.h>
#include <termios.h>
#include <time.h>
#include <unistd.h>

#define SERIAL_PORT "/dev/ttyUSB0"
#define BAUDRATE B115200
#define CMD_BUF_SIZE 2048
#define READ_BUF_SIZE 1024
// #define SERVER_ADDR "192.168.43.137"
#define SERVER_ADDR "192.168.2.37"
#define SERVER_PORT 8080

#define TEXT_FILE "messages.txt"

#define MAX_LINE 1024
#define MAX_SEND (MAX_LINE + 32) // extra space for =number

int serial_fd;
char cid_value[16] = {0};
char recv_data_len[16] = {0};

void tprintf(const char *format, ...);

// Helper function to print timestamped messages
void tprintf(const char *format, ...) {
  time_t current_time;
  struct tm *local_time;
  char time_str[32];

  time(&current_time);
  local_time = localtime(&current_time);
  strftime(time_str, sizeof(time_str), "[%Y-%m-%d %H:%M:%S]", local_time);

  printf("%s ", time_str);

  va_list args;
  va_start(args, format);
  vprintf(format, args);
  va_end(args);
}

int configure_serial(const char *device) {
  struct termios tty;
  serial_fd = open(device, O_RDWR | O_NOCTTY);
  if (serial_fd < 0) {
    perror("Error opening serial port");
    return -1;
  }
  if (tcgetattr(serial_fd, &tty) != 0) {
    perror("tcgetattr");
    return -1;
  }
  cfsetospeed(&tty, BAUDRATE);
  cfsetispeed(&tty, BAUDRATE);

  tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8;
  tty.c_iflag &= ~IGNBRK;
  tty.c_lflag = 0;
  tty.c_oflag = 0;
  tty.c_cc[VMIN] = 0;
  tty.c_cc[VTIME] = 10;

  tty.c_iflag &= ~(IXON | IXOFF | IXANY);
  tty.c_cflag |= (CLOCAL | CREAD);
  tty.c_cflag &= ~(PARENB | PARODD);
  tty.c_cflag &= ~CSTOPB;
  tty.c_cflag &= ~CRTSCTS;

  if (tcsetattr(serial_fd, TCSANOW, &tty) != 0) {
    perror("tcsetattr");
    return -1;
  }
  return 0;
}

// send_command now returns:
//  0 = OK
// -1 = timeout/error
// -2 = module returned ERROR
int send_command(const char *cmd, char *response, size_t resp_size,
                 int timeout_sec) {
  char cmd_with_crlf[CMD_BUF_SIZE];
  fd_set readfds;
  struct timeval tv;
  int n;

  snprintf(cmd_with_crlf, sizeof(cmd_with_crlf), "%s\r\n", cmd);
  write(serial_fd, cmd_with_crlf, strlen(cmd_with_crlf));

  size_t total_read = 0;
  memset(response, 0, resp_size);

  while (1) {
    FD_ZERO(&readfds);
    FD_SET(serial_fd, &readfds);
    tv.tv_sec = timeout_sec;
    tv.tv_usec = 0;

    int rv = select(serial_fd + 1, &readfds, NULL, NULL, &tv);
    if (rv == -1) {
      perror("select");
      return -1;
    } else if (rv == 0) {
      tprintf("Timeout waiting for response to: %s\n", cmd);
      return -1;
    } else {
      n = read(serial_fd, response + total_read, resp_size - total_read - 1);
      if (n > 0) {
        total_read += n;
        response[total_read] = '\0';
        // if (strstr(response, "OK")) {
        //   return 0; // Success
        // }
        // if (strstr(response, "ERROR")) {
        //   return -2; // Module ERROR
        // }
        if (strstr(cmd, "AT+SRR")) {
          if (strstr(response, "+SRR:") && strstr(response, "OK")) {
            return 0; // Valid AT+SRR response
          }
          if (strstr(response, "OK") && !strstr(response, "+SRR:")) {
            tprintf("AT+SRR returned only OK, retry needed.\n");
            return -1; // Treat as timeout/incomplete → force retry
          }
        } else {
          if (strstr(response, "OK")) {
            return 0; // Success
          }
        }

        if (strstr(response, "ERROR")) {
          return -2; // Module ERROR
        }
      } else if (n < 0) {
        perror("read");
        return -1;
      }
    }
  }
  return -1; // No valid result found before timeout
}

void extract_cid(const char *resp) {
  char *p = strstr(resp, "+SC:");
  if (p) {
    int cid;
    if (sscanf(p, "+SC:%d", &cid) == 1) {
      snprintf(cid_value, sizeof(cid_value), "%d", cid);
      tprintf("CID recorded: %s\n", cid_value);
    }
  }
}

void extract_recv_len(const char *resp) {
  char *p = strstr(resp, "+SRR:");
  if (p) {
    int cid, port, len;
    char ip[32];
    if (sscanf(p, "+SRR:%d,%31[^,],%d,%d", &cid, ip, &port, &len) == 4) {
      snprintf(recv_data_len, sizeof(recv_data_len), "%d", len);
      tprintf("recv_data_len recorded: %s\n", recv_data_len);
    }
  }
}

#define CMD_CHECK_RETRY(cmd, resp, t, retries)                                 \
  do {                                                                         \
    int attempt = 0;                                                           \
    while (attempt < retries) {                                                \
      int ret = send_command(cmd, resp, sizeof(resp), t);                      \
      tprintf("[RX] %s", resp);                                                \
      if (ret == 0)                                                            \
        break; /* Success */                                                   \
      if (ret == -1) {                                                         \
        tprintf("TIMEOUT: %s (attempt %d/%d)\n", cmd, attempt + 1, retries);   \
      } else if (ret == -2) {                                                  \
        tprintf("ERROR: %s (attempt %d/%d)\n", cmd, attempt + 1, retries);     \
      }                                                                        \
      attempt++;                                                               \
      if (attempt < retries) {                                                 \
        sleep(2); /* wait before retry */                                      \
      } else {                                                                 \
        tprintf("Command failed after %d retries: %s\n", retries, cmd);        \
        goto recover; /* jump to recovery */                                   \
      }                                                                        \
    }                                                                          \
  } while (0)

int main() {
  char resp[READ_BUF_SIZE];
  if (configure_serial(SERIAL_PORT) != 0)
    return 1;

  FILE *fp = fopen(TEXT_FILE, "r");
  if (!fp) {
    perror("Failed to open messages.txt");
    return 1;
  }

recover:
  CMD_CHECK_RETRY("AT+WNI=0", resp, 15, 3);
  CMD_CHECK_RETRY("AT+WNCN=1,\"UNEO_Pi4\",\"uneo1234\"", resp, 15, 3);

  CMD_CHECK_RETRY("AT+SC=2,1,0", resp, 15, 3);
  extract_cid(resp);

  char cmd[CMD_BUF_SIZE];
  snprintf(cmd, sizeof(cmd), "AT+SCO=%s,%s,%d", cid_value, SERVER_ADDR,
           SERVER_PORT);
  CMD_CHECK_RETRY(cmd, resp, 15, 3);

  char line[MAX_LINE];
  char send_str[MAX_SEND];
  int i = 0;

  for (;;) {
    // Try reading next line
    if (!fgets(line, sizeof(line), fp)) {
      // If EOF, rewind file and read again
      rewind(fp);
      if (!fgets(line, sizeof(line), fp)) {
        tprintf("No messages in file!\n");
        break;
      }
    }

    // Remove newline
    line[strcspn(line, "\r\n")] = 0;

    snprintf(send_str, sizeof(send_str), "%s", line);

    int msg_len = strlen(send_str);
    snprintf(cmd, sizeof(cmd), "AT+SN=%s,%s,%d,%d,%s", cid_value, SERVER_ADDR,
             SERVER_PORT, msg_len, send_str);

    // snprintf(cmd, sizeof(cmd), "AT+SN=%s,%s,%d,%ld,%s", cid_value,
    // SERVER_ADDR,
    //         SERVER_PORT, strlen(send_str) + 1, send_str);
    CMD_CHECK_RETRY(cmd, resp, 15, 3);

    snprintf(cmd, sizeof(cmd), "AT+SRR=%s", cid_value);
    CMD_CHECK_RETRY(cmd, resp, 15, 3);
    extract_recv_len(resp);

    snprintf(cmd, sizeof(cmd), "AT+SR=%s,%s", cid_value, recv_data_len);
    CMD_CHECK_RETRY(cmd, resp, 15, 3);

    sleep(1);
    // i++;
  }

  fclose(fp);

  snprintf(cmd, sizeof(cmd), "AT+SCL=%s", cid_value);
  CMD_CHECK_RETRY(cmd, resp, 3, 3);

  close(serial_fd);
  return 0;
}


Server_Client.c (created by Gemini)
#include <arpa/inet.h>
#include <asm-generic/socket.h>
#include <errno.h>
#include <fcntl.h>
#include <netinet/tcp.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <time.h>
#include <unistd.h>

#define BUFFER_SIZE 16384
#define RESPONSE_BUF_SIZE 128
#define TIMEOUT_SEC 300

void log_with_timestamp(const char *format, ...) {
  time_t now = time(NULL);
  struct tm *t = localtime(&now);
  char timestamp[64];
  strftime(timestamp, sizeof(timestamp), "%Y-%m-%d %H:%M:%S", t);

  printf("[%s] ", timestamp);

  va_list args;
  va_start(args, format);
  vprintf(format, args);
  va_end(args);
}

void server(int port) {
  int server_fd, new_socket;
  struct sockaddr_in address;
  int opt = 1;
  int addrlen = sizeof(address);
  char buffer[BUFFER_SIZE] = {0};
  char resp[RESPONSE_BUF_SIZE] = {0};
  int keepalive = 1; // Enable keepalive
  int keepidle =
      TIMEOUT_SEC +
      10; // Start keeplives after TIMEOUT_SEC + 10 seconds of idle time
  int keepcnt = 3;   // Send 3 keepalive probes
  int keepintvl = 2; // Interval between keepalive probes: 2 seconds
  struct timeval tv;
  fd_set readfds;

  if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
    perror("socket failed");
    exit(EXIT_FAILURE);
  }

  if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt,
                 sizeof(opt))) {
    perror("setsockopt");
    exit(EXIT_FAILURE);
  }
  address.sin_family = AF_INET;
  address.sin_addr.s_addr = INADDR_ANY;
  address.sin_port = htons(port);

  if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
    perror("bind failed");
    exit(EXIT_FAILURE);
  }
  if (listen(server_fd, 3) < 0) {
    perror("listen");
    exit(EXIT_FAILURE);
  }

  // Enable keepalive on the server socket
  if (setsockopt(server_fd, SOL_SOCKET, SO_KEEPALIVE, &keepalive,
                 sizeof(keepalive)) < 0) {
    perror("setsockopt SO_KEEPALIVE");
    exit(EXIT_FAILURE);
  }

  // Set keepalive options (TCP_KEEPIDLE, TCP_KEEPINTVL, TCP_KEEPCNT)
  if (setsockopt(server_fd, IPPROTO_TCP, TCP_KEEPIDLE, &keepidle,
                 sizeof(keepidle)) < 0) {
    perror("setsockopt TCP_KEEPIDLE");
    exit(EXIT_FAILURE);
  }

  if (setsockopt(server_fd, IPPROTO_TCP, TCP_KEEPINTVL, &keepintvl,
                 sizeof(keepintvl)) < 0) {
    perror("setsockopt TCP_KEEPINTVL");
    exit(EXIT_FAILURE);
  }

  if (setsockopt(server_fd, IPPROTO_TCP, TCP_KEEPCNT, &keepcnt,
                 sizeof(keepcnt)) < 0) {
    perror("setsockopt TCP_KEEPCNT");
    exit(EXIT_FAILURE);
  }

  log_with_timestamp("Server listening on port %d...\n", port);

  int i = 0;
  while (1) {
    if ((new_socket = accept(server_fd, (struct sockaddr *)&address,
                             (socklen_t *)&addrlen)) < 0) {
      perror("accept");
      continue;
    }

    log_with_timestamp("Client connected.\n");

    // Set socket to non-blocking
    fcntl(new_socket, F_SETFL, O_NONBLOCK);

    while (1) {
      FD_ZERO(&readfds);
      FD_SET(new_socket, &readfds);

      tv.tv_sec = TIMEOUT_SEC;
      tv.tv_usec = 0;

      int retval = select(new_socket + 1, &readfds, NULL, NULL, &tv);

      if (retval == -1) {
        perror("select");
        break;
      } else if (retval == 0) {
        // Timeout: No data received within TIMEOUT_SEC
        log_with_timestamp("Client timeout (no data received).\n");
        break;
      } else {
        memset(buffer, 0, BUFFER_SIZE);
        ssize_t bytes_received = recv(new_socket, buffer, BUFFER_SIZE - 1, 0);

        if (bytes_received > 0) {
          buffer[bytes_received] = '\0';
          log_with_timestamp("Received from client: %s\n", buffer);

          // Prepare and send response to client
          char *response = "Message received successfully!Message received "
                           "successfully!Message received successfully!";
          snprintf(resp, sizeof(resp), "%s-%d", response, i);
          send(new_socket, resp, strlen(resp), 0);
          log_with_timestamp("Sent response to client.\n");
          i++;
          if (i == 65534)
            i = 0;
        } else if (bytes_received == 0) {
          printf("Client disconnected gracefully.\n");
          break;
        } else {
          if (errno == ECONNRESET || errno == EPIPE) {
            log_with_timestamp("Client disconnected unexpectedly.\n");
            break;
          } else {
            perror("recv");
            break;
          }
        }
      }
    }
    close(new_socket);
  }
  close(server_fd);
}

void client(const char *ip_address, int port) {
  int sock = 0;
  struct sockaddr_in serv_addr;
  char buffer[BUFFER_SIZE] = {0};
  char message[BUFFER_SIZE];
  int keepalive = 1; // Enable keepalive
  int keepidle = 10; // Start keeplives after 10 seconds of idle time
  int keepcnt = 3;   // Send 3 keepalive probes
  int keepintvl = 2; // Interval between keepalive probes: 2 seconds
  fd_set readfds;
  struct timeval tv;

  if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
    perror("Socket creation error");
    return;
  }

  // Enable keepalive
  if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &keepalive,
                 sizeof(keepalive)) < 0) {
    perror("setsockopt SO_KEEPALIVE");
    close(sock);
    return;
  }

  // Set keepalive options (TCP_KEEPIDLE, TCP_KEEPINTVL, TCP_KEEPCNT)
  if (setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, &keepidle, sizeof(keepidle)) <
      0) {
    perror("setsockopt TCP_KEEPIDLE");
    close(sock);
    return;
  }

  if (setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, &keepintvl,
                 sizeof(keepintvl)) < 0) {
    perror("setsockopt TCP_KEEPINTVL");
    close(sock);
    return;
  }

  if (setsockopt(sock, IPPROTO_TCP, TCP_KEEPCNT, &keepcnt, sizeof(keepcnt)) <
      0) {
    perror("setsockopt TCP_KEEPCNT");
    close(sock);
    return;
  }

  serv_addr.sin_family = AF_INET;
  serv_addr.sin_port = htons(port);

  if (inet_pton(AF_INET, ip_address, &serv_addr.sin_addr) <= 0) {
    perror("Invalid address/ Address not supported");
    return;
  }

  if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
    perror("Connection Failed");
    return;
  }

  log_with_timestamp(
      "Connected to server. Enter messages (type 'exit' to quit):\n");

  // Set socket to non-blocking
  fcntl(sock, F_SETFL, O_NONBLOCK);
  // Set stdin to non-blocking
  int flags = fcntl(STDIN_FILENO, F_GETFL, 0);
  fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK);

  while (1) {
    FD_ZERO(&readfds);
    FD_SET(sock, &readfds);
    FD_SET(STDIN_FILENO, &readfds);

    tv.tv_sec = 1; // 1-second timeout for select
    tv.tv_usec = 0;

    printf("> ");
    fflush(stdout);

    int max_fd = (sock > STDIN_FILENO) ? sock : STDIN_FILENO;
    int retval = select(max_fd + 1, &readfds, NULL, NULL, &tv);

    if (retval == -1) {
      perror("select");
      break;
    }

    // Check if there is data from the server
    if (FD_ISSET(sock, &readfds)) {
      memset(buffer, 0, BUFFER_SIZE);
      ssize_t bytes_received = recv(sock, buffer, BUFFER_SIZE - 1, 0);
      if (bytes_received > 0) {
        buffer[bytes_received] = '\0';
        printf("\nServer response: %s\n", buffer);
      } else if (bytes_received == 0) {
        printf("\nServer disconnected gracefully.\n");
        break;
      } else {
        if (errno != EWOULDBLOCK && errno != EINTR) {
          perror("\nrecv");
          break;
        }
      }
    }

    // Check if there is user input
    if (FD_ISSET(STDIN_FILENO, &readfds)) {
      fgets(message, BUFFER_SIZE, stdin);
      message[strcspn(message, "\n")] = 0;

      if (strcmp(message, "exit") == 0) {
        break;
      }

      send(sock, message, strlen(message), 0);
    }
  }

  close(sock);
}

int main(int argc, char const *argv[]) {
  if (argc < 3) {
    fprintf(stderr, "Usage: %s &lt;server|client> &lt;port> [ip_address]\n", argv[0]);
    return 1;
  }

  int port = atoi(argv[2]);
  if (port <= 0 || port > 65535) {
    fprintf(stderr, "Invalid port number\n");
    return 1;
  }

  if (strcmp(argv[1], "server") == 0) {
    server(port);
  } else if (strcmp(argv[1], "client") == 0) {
    if (argc < 4) {
      fprintf(stderr, "Usage: %s client <port> <ip_address>\n", argv[0]);
      return 1;
    }
    client(argv[3], port);
  } else {
    fprintf(stderr, "Invalid mode: %s\n", argv[1]);
    return 1;
  }

  return 0;
}

2025年10月29日 星期三

WE310K6 on NV Orin

The main chip is RTL8852be.
Found another driver below, not tested yet


The drive comes from Telit, not downloaded from above.
  • WiFi
source/kernel/kernel-jammy-src/drivers/net/wireless/Makefile
...
...
obj-$(CONFIG_RTL8852BE) += we310k6/

source/kernel/kernel-jammy-src/drivers/net/wireless/Kconfig
...
...
source "drivers/net/wireless/we310k6/Kconfig"

source/kernel/kernel-jammy-src/drivers/net/wireless/we310k6/Makefile
...
...
EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT
EXTRA_CFLAGS += -DCONFIG_RADIO_WORK -DCONFIG_PLATFORM_OPS
...
...
EXTRA_CFLAGS += -I$(src)/platform
...
...
CONFIG_PLATFORM_I386_PC = n
...
...
########### PLATFORM OPS  ##########################
# Import platform specific compile options
EXTRA_CFLAGS += -I$(src)/platform

# Explicitly select platform-specific PCI operations file
# Based on your system (Orin is AArch64 Linux), we'll assume platform_linux_pc_pci.c is correct.
# You might need to adjust this logic if you have a more specific platform configuration macro.
# Check the ARCH variable that the kernel build system passes.

# Clear _PLATFORM_FILES to prevent unintended inclusions from .mk files if they re-assign it.
_PLATFORM_FILES =

ifeq ($(ARCH),arm64) # For NVIDIA Orin
    # This assumes platform_linux_pc_pci.c is the correct file for ARM64 Linux
    _PLATFORM_FILES += platform/platform_linux_pc_pci.o platform/platform_ops.o
    EXTRA_CFLAGS += -DCONFIG_PLATFORM_LINUX_PC # If this define is used in your code
    # Comment out other platform-specific configs if they are set to 'y' earlier
    # For example, ensure CONFIG_PLATFORM_I386_PC is 'n'
endif
ifeq ($(ARCH),x86) # For generic Linux PC (i386/x86_64)
    _PLATFORM_FILES += platform/platform_linux_pc_pci.o
    EXTRA_CFLAGS += -DCONFIG_PLATFORM_I386_PC # If this define is used in your code
endif
ifeq ($(ARCH),mips) # For MIPS platforms
    _PLATFORM_FILES += platform/platform_mips_98d_pci.o
    EXTRA_CFLAGS += -DCONFIG_PLATFORM_RTL8198D # If this define is used in your code
endif
# Add more conditions for other platforms if needed, following the same pattern.
# Make sure only one of these blocks evaluates to true for your target system.

# Add the selected platform files to the build objects
OBJS += $(_PLATFORM_FILES)
...
...

  • BT
Note: BT is working on UART
Since the default setting is PCIE+USB via M.2 on NV Orin, WE310K6 BT didn't work on it.
source/kernel/kernel-jammy-src/drivers/bluetooth/Kconfig
config BT_WE310K6
        tristate "WE310K6 Bluetooth driver support"
        depends on BT
        help
          This is a driver for the WE310K6 Bluetooth controller.
          If you have this hardware, say Y or M here.
          Say N otherwise.

source "drivers/bluetooth/we310k6/Kconfig"


source/kernel/kernel-jammy-src/drivers/bluetooth/Makefile
obj-$(CONFIG_BT_WE310K6) += we310k6/


source/kernel/kernel-jammy-src/drivers/bluetooth/we310k6/Makefile
obj-$(config_bt_we310k6) += bt_we310k6.o

bt_we310k6-y := hci_h4.o hci_ldisc.o hci_rtk_h5.o rtk_coex.o


Telit's document.
Bluetooth® controller. For WE310K6 Bluetooth UART, please use rtk_hciattach.
Do not use the hciattach compiled by BlueZ.
Initialization is performed by rtk_hciattach -n -s 115200 ttyUSB0 rtk_h5 
or 
rtk_hciattach -n -s 115200 ttyUSB0 rtk_h4 commands, where the serial device name will be different on each platform. 
We are using 3 wire protocol So please use the below command to Initialization.

2025年10月15日 星期三

STM32MP257f-EV1 enable SPI3

Board: STM32MP257f-EV1
OS: buildroot (tag: openstlinux-6.6-buildroot-2024.02.9-mpu-v24.11.06))
patch: buildroot-external-st (branch: st/2025.02.5)


enable SPI3
$ vim buildroot-external-st/board/stmicroelectronics/stm32mp2/linux-dts/st/stm32mp257f-ev1-mx.dts

...
...
#include "stm32mp25-pinctrl.dtsi"

aliases{
		ethernet0 = ð2;
		ethernet1 = ð1;
		serial0 = &usart2;
		serial1 = &usart6;
		serial2 = &lpuart1;
        spi3 = &spi3;
	};
...
...
&spi3 {
	pinctrl-names = "default", "sleep";
	pinctrl-0 = <&spi3_pins_a>;
	pinctrl-1 = <&spi3_sleep_pins_a>;
	status = "okay";

    spidev@0 {
        compatible = "lwn,bk4";
        reg = <0>;
        spi-max-frequency = <10000000>;
    };
};

Kernel code
CONFIG_SPI_SPIDEV=m or y


drivers/spi/spidev.c
static const struct of_device_id spidev_dt_ids[] = {
	{ .compatible = "cisco,spi-petra", .data = &spidev_of_check },
	{ .compatible = "dh,dhcom-board", .data = &spidev_of_check },
	{ .compatible = "lineartechnology,ltc2488", .data = &spidev_of_check },
	{ .compatible = "lwn,bk4", .data = &spidev_of_check },
	{ .compatible = "menlo,m53cpld", .data = &spidev_of_check },
	{ .compatible = "micron,spi-authenta", .data = &spidev_of_check },
	{ .compatible = "rohm,bh2228fv", .data = &spidev_of_check },
	{ .compatible = "rohm,dh2228fv", .data = &spidev_of_check },
	{ .compatible = "semtech,sx1301", .data = &spidev_of_check },
	{ .compatible = "silabs,em3581", .data = &spidev_of_check },
	{ .compatible = "silabs,si3210", .data = &spidev_of_check },
	{},
};
MODULE_DEVICE_TABLE(of, spidev_dt_ids);


drivers/spi/spi-stm32.c
static const struct of_device_id stm32_spi_of_match[] = {
	{ .compatible = "st,stm32mp25-spi", .data = (void *)&stm32mp25_spi_cfg },
	{ .compatible = "st,stm32h7-spi", .data = (void *)&stm32h7_spi_cfg },
	{ .compatible = "st,stm32f4-spi", .data = (void *)&stm32f4_spi_cfg },
	{},
};
MODULE_DEVICE_TABLE(of, stm32_spi_of_match);

on EV-1 board
# dtc -I fs -O dts /proc/device-tree > dts

# vi dts

...
...
 aliases {
                ethernet0 = "/soc@0/bus@42080000/eth2@482d0000";
                serial1 = "/soc@0/bus@42080000/serial@40220000";
                ethernet1 = "/soc@0/bus@42080000/eth1@482c0000";
                spi3 = "/soc@0/bus@42080000/spi@400c0000";
                serial2 = "/soc@0/bus@42080000/serial@46030000";
                serial0 = "/soc@0/bus@42080000/serial@400e0000";
        };
...
...
spi@400c0000 {
                                power-domains = <0x0c>;
                                pinctrl-names = "default\0sleep";
                                #address-cells = <0x01>;
                                pinctrl-0 = <0x27>;
                                resets = <0x16 0x18>;
                                interrupts = <0x00 0x7d 0x04>;
                                clocks = <0x16 0x104>;
                                #size-cells = <0x00>;
                                dma-names = "rx\0tx";
                                compatible = "st,stm32mp25-spi";
                                pinctrl-1 = <0x28>;
                                status = "okay";
                                reg = <0x400c0000 0x400>;
                                phandle = <0xbc>;
                                dmas = <0x23 0x35 0x20 0x3012 0x23 0x36 0x20 0x3021>;
                                access-controllers = <0x1b 0x18>;

                                spidev@0 {
                                        spi-max-frequency = <0x989680>;
                                        compatible = "lwn,bk4";
                                        reg = <0x00>;
                                };
                        };
install spidev.ko
# modprobe spidev.ko

# ls /dev/spidev3.0
/dev/spidev3.0