I am running Arch Linux ARM on a Raspberry Pi 2 Model B, and I am attempting to communicate with a TFT display. I am writing a kernel module to interface with the display using SPI, and it works, but I cannot get the SPI frequency to go above 500 kHz. I have successfully used higher frequencies in the user space when using the BCM2835 library, so I know it is possible.
Using the following command to parse the device tree:
dtc -I fs /sys/firmware/devicetree/base | grep max-frequency
I can see that spi-max-frequency = <0x7735940>
, which is hexadecimal for 150 MHz.
hexdump /sys/class/spi_master/spi0/of_node/spi-max-frequency
gives me 7307 4059
, hexadecimal for the same number (just with the byte order reversed). In my kernel module, I did the following:
struct spi_board_info spiBoardInfo = {
.modalias = "spi",
.max_speed_hz = 32000000,
.bus_num = 0,
.chip_select = 0,
.mode = 0
};
master = spi_busnum_to_master(spiBoardInfo.bus_num);
spiDevice = spi_new_device(master, &spiBoardInfo);
spiDevice->bits_per_word = 8;
ret = spi_setup(spiDevice);
printk(KERN_INFO "TFT: device max speed %ld\n", spiDevice->max_speed_hz);
which prints out 32000000
, as expected (error checking code was removed above for brevity). To write to the slave, I use the following command
spi_write(spiDevice, &data, sizeof(data));
(I have also tried using spi_sync_transfer()
and setting the speed there as well, to no avail). This command successfully writes the data, but at a speed of 500 kHz.
Does anyone know why I am being limited to this frequency?
EDIT
After investigating further, I strongly feel it has to do with the device tree. I added the following overlay:
/dts-v1/;
/plugin/;
/ {
compatible = "brcm,bcm2708";
fragment@0 {
target = <&spidev0>;
__overlay__ {
status = "disabled";
};
};
fragment@1 {
target = <&spi0>;
__overlay__ {
#address-cells = <1>;
#size-cells = <0>;
status = "okay";
tft@0 {
compatible = "tft,st7789";
spi-max-frequency = <320000000>;
reg = <0>;
};
};
};
__overrides__ {
tft = <0>, "=0=1";
};
};
And now receive:
spi-bcm2835 3f204000.spi: chipselect 0 already in use
The name of my kernel module is tft
, and then I do the following:
static const struct of_device_id dtIDs[] = {
{.compatible = "tft,st7789"},
{}
};
MODULE_DEVICE_TABLE(of, dtIDs);
So it seems as if the SPI driver is not recognizing my kernel module as the owner of chipselect 0, and not letting me access SPI as a result. I feel as though if I got this working, I would get the correct speeds, as the spi-max-frequency
will have been directly set for my driver.