^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) #include <stdio.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) #include <unistd.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) #include <stdlib.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) #include <fcntl.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <sys/ioctl.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <sys/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <sys/stat.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/spi/spidev.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) static int verbose;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) static void do_read(int fd, int len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) unsigned char buf[32], *bp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) int status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) /* read at least 2 bytes, no more than 32 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) if (len < 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) len = 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) else if (len > sizeof(buf))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) len = sizeof(buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) memset(buf, 0, sizeof buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) status = read(fd, buf, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) if (status < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) perror("read");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) if (status != len) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) fprintf(stderr, "short read\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) printf("read(%2d, %2d): %02x %02x,", len, status,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) buf[0], buf[1]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) status -= 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) bp = buf + 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) while (status-- > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) printf(" %02x", *bp++);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) printf("\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) static void do_msg(int fd, int len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) struct spi_ioc_transfer xfer[2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) unsigned char buf[32], *bp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) int status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) memset(xfer, 0, sizeof xfer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) memset(buf, 0, sizeof buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) if (len > sizeof buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) len = sizeof buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) buf[0] = 0xaa;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) xfer[0].tx_buf = (unsigned long)buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) xfer[0].len = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) xfer[1].rx_buf = (unsigned long) buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) xfer[1].len = len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) status = ioctl(fd, SPI_IOC_MESSAGE(2), xfer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) if (status < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) perror("SPI_IOC_MESSAGE");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) printf("response(%2d, %2d): ", len, status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) for (bp = buf; len; len--)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) printf(" %02x", *bp++);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) printf("\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) static void dumpstat(const char *name, int fd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) __u8 lsb, bits;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) __u32 mode, speed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) if (ioctl(fd, SPI_IOC_RD_MODE32, &mode) < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) perror("SPI rd_mode");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) if (ioctl(fd, SPI_IOC_RD_LSB_FIRST, &lsb) < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) perror("SPI rd_lsb_fist");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) if (ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits) < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) perror("SPI bits_per_word");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) if (ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed) < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) perror("SPI max_speed_hz");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) printf("%s: spi mode 0x%x, %d bits %sper word, %d Hz max\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) name, mode, bits, lsb ? "(lsb first) " : "", speed);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) int main(int argc, char **argv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) int c;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) int readcount = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) int msglen = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) int fd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) const char *name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) while ((c = getopt(argc, argv, "hm:r:v")) != EOF) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) switch (c) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) case 'm':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) msglen = atoi(optarg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) if (msglen < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) goto usage;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) case 'r':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) readcount = atoi(optarg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) if (readcount < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) goto usage;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) case 'v':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) verbose++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) case 'h':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) case '?':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) usage:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) fprintf(stderr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) "usage: %s [-h] [-m N] [-r N] /dev/spidevB.D\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) argv[0]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) if ((optind + 1) != argc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) goto usage;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) name = argv[optind];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) fd = open(name, O_RDWR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) if (fd < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) perror("open");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) dumpstat(name, fd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) if (msglen)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) do_msg(fd, msglen);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) if (readcount)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) do_read(fd, readcount);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) close(fd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) }