In the previous stage, I was not familiar with the writing of Linux device drivers and could not find any information. So I temporarily put the experiment of SPI devices on hold. A few days ago, I was inspired by the evaluation of netizens and began to learn about SPI drivers again. After having some preliminary understanding of Linux drivers, I started to experiment with SPI devices. If you want to use SPI devices, you must start with the configuration of the device tree. The Linux device tree is actually a configuration file for device information. It is a bit like JSON and XML files. The main idea of the device tree file is to separate the device driver from the device configuration. In this way, writing device drivers has nothing to do with the BPS of specific devices. Drivers can only be written for such devices. If specific boards with different requirements want to use a certain peripheral, just configure the information of this peripheral in the "configuration file" of the device, and the driver can work. Just like the STM32MP157A-DK1 board we tested, the SPI5 device is not turned on by default, and the SPI5 PIN defaults to GPIO. If your device needs to use SPI5 by default, just turn on the SPI5 configuration. There is no need to write drivers for specific devices. The device tree mechanism can abstract the same type of devices into a driver. By modifying the register address, you can drive different devices of the same type. For example, SPI, I2C, CAN, Uart and other character devices. For example, the driver operation method of Uart devices is the same, but the configuration is different. In this way, there is no need to write multiple drivers. Different uarts use the same driver, but their addresses are different.
If you want to use the SPI5 device of STM32MP157A-DK1. First, you need to modify the configuration in arch/arm/boot/dts/stm32mp157a-dk1.dts.
&spi5 {
pinctrl-names = "default", "sleep";
pinctrl-0 = <&spi5_pins_a>;
pinctrl-1 = <&spi5_sleep_pins_a>;
cs-gpios = <&gpiog 15 GPIO_ACTIVE_LOW>;
cd-gpios = <&gpiod 7 GPIO_ACTIVE_LOW>;
status = "okay";
spidev0: spidev@0 {
compatible = "rohm,dh2228fv";
reg = <0>;
spi-max-frequency = <50000000>;
};
};
The spi5 pin configuration items pinctrl-0 and pinctrl-1 are in the included file .dtsi. These are the pin configurations for SPI. My SD1306 also needs two control pins, CS and CD. They are also configured in this declaration. In fact, the default configuration of the two pins cs-gpios and cd-gpios can also be used. arch/arm/boot/dts/stm32mp157-pinctrl.dtsi
spi5_sleep_pins_a: spi5-sleep-0 {
pins {
pinmux = <STM32_PINMUX('F', 7, ANALOG)>, /* SPI5_SCK */
<STM32_PINMUX('F', 8, ANALOG)>, /* SPI5_MISO */
<STM32_PINMUX('F', 9, ANALOG)>; /* SPI5_MOSI */
};
};
gpiod: gpio@50005000 {
gpio-controller;
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x3000 0x400>;
clocks = <&rcc GPIOD>;
st,bank-name = "GPIOD";
status = "disabled";
};
gpiog: gpio@50008000 {
gpio-controller;
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x6000 0x400>;
clocks = <&rcc GPIOG>;
st,bank-name = "GPIOG";
status = "disabled";
};
You can see that the pin configuration of SPI5 (spi5_sleep_pins_a) is consistent with the documentation. PF7, PF8, PF9 are the chip pin function numbers. The device tree also configures other parameters. These configurations can be found in the spidev.c driver. For example: spidev0: spidev@0 sets the driver file spidev.c and the function in the driver to be compatible. Refer to the code below
static struct class *spidev_class;
#ifdef CONFIG_OF
static const struct of_device_id spidev_dt_ids[] = {
{ .compatible = "rohm,dh2228fv" },
{ .compatible = "lineartechnology,ltc2488" },
{ .compatible = "ge,achc" },
{ .compatible = "semtech,sx1301" },
{},
};
MODULE_DEVICE_TABLE(of, spidev_dt_ids);
#endif
#ifdef CONFIG_ACPI
There is no code to use these pins in the driver. The driver just uses the registers in the configuration. There is no difference between the SPI4 and SPI5 drivers. As long as the SPI5 settings are configured, the SPI5 function can be used, and the three main function pins of SPI are all set. After the driver configuration is completed, you only need to write the application layer driver. In other words, as long as the file is filled with data into /dev/spidev0.0, you can drive SPI5. I use the SD1306 OLED SPI serial screen. In addition to the SPI pins, two control pins (CS and CD) are required. Note that the CS pin is "low" by default, which enables it to be turned on. The function of the CD pin is command selection. The program mainly refers to the tools\spi\spidev_test.c file, in which there are two main APIs:
#include <linux/gpio.h> The API function gpio_data.values is used to set the state of the cs-gpios pin.
#include <linux/spi/spidev.h> mainly uses the macro definitions, such as: ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed); The definition of SPI_IOC_WR_MAX_SPEED_HZ. There are
two main files :
const char gpio_dev_cs = "/dev/gpiochip3";
const char gpio_dev_ds = "/dev/gpiochip5";
const char spidev_name = "/dev/spidev0.0";
int cd_gpio_set(void)
{
int ret;
ret = ioctl(cd_fd, GPIOHANDLE_SET_LINE_VALUES_IOCTL, &gpio_data);
if (ret == -1) {
ret = -errno;
fprintf(stderr, "Failed to issue %s (%d)\n",
"GPIOHANDLE_SET_LINE_VALUES_IOCTL", ret);
}
return ret;
}
void send_byte_spi(unsigned char data)
{
int status;
spi_tx[0] = data;
status = ioctl(fd, SPI_IOC_MESSAGE(1), xfer);
if (status < 0)
{
perror("SPI_IOC_MESSAGE");
return;
}
}
The user program can refer to the SD1306 program.
This content is originally created by bigbat , a user of EEWORLD forum. If you want to reprint or use it for commercial purposes, you must obtain the author's consent and indicate the source.