Table of Contents |
---|
Zynq/ZynqMP has two SPI hard IP. This is a Cadence IP. Some minor properties in the cadence IP offer multiple options which were customized as desirable.
This driver supports master mode and slave modes.
Detailed below are its use two slaves - EEPROM and flash.
HW IP Features
- Master mode
- All SPI flash instructions
- Support for 3 slaves - can be extended using a 3 to 8 decoder
- Driver uses manual chip select and auto start options
- Programmable clock frequency, polarity and phase
- Interrupt support
Missing Features and known Issues/Limitations in Driver
- None
Kernel Configuration Options
The following config options need to be enabled:CONFIG_SPI_CADENCE
It depends on:
CONFIG_SPI_MASTER
CONFIG_ARM
Device-tree
Refer to Documentation/devicetree/bindings/spi/spi-cadence.txt for complete description.These are some specific points to be noted about the properties:
- compatible string: This can be either cdns or xlnx compatible string.
- num-cs: This is SOC specific - Since this driver is for the cadence IP in the mainline, this option is made available in the devicetree.
- is-decoded-cs: This refers to whether a decoder is used to extend the existing chip selects.
- spi-max-frequency - This should reflect the maximum frequency supported by the slave/master (or) user intends to use.
- partitions - The size and number of these are user configurable and the sum should not exceed the total flash size.
Using SPI with EEPROM
Adding an SPI EEPROM to the devicetree
The following example shows adding an SPI EEPROM to a device treeCode Block | ||
---|---|---|
| ||
spi: spi@e0006000 { compatible = "xlnx,spi-zynq-r196"; clock-names = "ref_clk", "pclk"; clocks = <&&clkc 25>, <&&clkc 34>; interrupt-parent = <&&gic>; interrupts = <0 26 4>; num-cs = <4>; is-decoded-cs = <0>; reg = <0xe0006000 0x1000>; #address-cells = <1>; #size-cells = <0>; eeprom: at25@0 { compatible = "atmel,at25"; at25,byte-len = <8192>; at25,addr-mode = <2>; at25,page-size = <32>; reg = <2>; spi-max-frequency = <1000000>; }; }; |
Using SPI with flash
Adding an SPI flash to the devicetree
Zynq:
Note: The interrupt number and the controller register space information are mentioned in Zynq-7000 TRM
Code Block | ||
---|---|---|
| ||
spi: spi@e0007000 { compatible = "cdns,spi-r1p6"; clock-names = "ref_clk", "pclk"; clocks = <&&clkc 26>, <&&clkc 35>; interrupt-parent = <&&ps7_scugic_0>; interrupts = <0 49 4>; num-cs = <4>; is-decoded-cs = <0>; reg = <0xe0007000 0x1000>; #address-cells = <1>; #size-cells = <0>; flash@0 { compatible = "sst25wf080"; reg = <1>; spi-max-frequency = <1000000>; #address-cells = <1>; #size-cells = <1>; partition@test { label = "spi-flash"; reg = <0x0 0x100000>; }; }; }; |
ZynqMP:
Note: The interrupt number and the controller register space information are mentioned in Zynq Ultrascale TRM
Code Block | ||
---|---|---|
| ||
spi0: spi@ff040000 { compatible = "cdns,spi-r1p6"; interrupt-parent = <&&gic>; interrupts = <0 19 4>; reg = <0x0 0xff040000 0x0 0x1000>; clock-names = "ref_clk", "pclk"; #address-cells = <1>; #size-cells = <0>; power-domains = <&&pd_spi0>; num-cs = <1>; pinctrl-names = "default"; pinctrl-0 = <&&pinctrl_spi0_default>; spi0_flash0: spi0_flash0@0 { compatible = "m25p80"; #address-cells = <1>; #size-cells = <1>; spi-max-frequency = <50000000>; reg = <0>; spi0_flash0@00000000 { label = "spi0_flash0"; reg = <0x0 0x100000>; }; }; }; |
Test Procedure
Testing using sysfs
#/#SPI - eeprom testing
#*/
#check whether eeprom device is present or not .
dmesg | grep eeprom
#read from the EEPROM
cat sys/bus/spi/devices/spi0.2/eeprom
#write to the EEPROM
echo "Hi this is testing the eeprom device through spi interface" > sys/bus/spi/devices/spi0.2/eeprom
#read from the EEPROM to verify
cat sys/bus/spi/devices/spi0.2/eeprom
#/**/
Testing using flashcp
#/*#*SPI flash testing with flashcp
#*/
#To know MTD partion(partitions) is(are) present and size of partition(partitions)in flash
cat /proc/mtd
Code Block | ||
---|---|---|
| ||
dev: size erasesize name mtd0: 00100000 00001000 "spi-flash" |
#Creating a file to be written to the flash
dd if=/dev/urandom of=./sample.bin bs=1024 count=900
Code Block | ||
---|---|---|
| ||
900+0 records in 900+0 records out 921600 bytes (900.0KB) copied, 0.706526 seconds, 1.2MB/s |
#Write the file to the partition - this erases the partition, writes the file and verifies
flashcp -v ./smaple.bin /dev/mtd0
Code Block | ||
---|---|---|
| ||
Erasing block: 225/225 (100%) Writing kb: 896/900 (99%) Verifying kb: 896/900 (99%) |
Testing using jffs2
##/*
#*SPI flash testing with jffs2
#*/
#Erase a the whole partition with jffs2 markers
flash_eraseall -j /dev/mtd0
Code Block | ||
---|---|---|
| ||
Erasing 4 Kibyte @ ff000 - 97% complete. Cleanmarker written at ff0000. Erasing 4 Kibyte @ 100000 - 100% complete |
mkdir spi_flash0
#Mount the partition to spi_flash0
mount -t jffs2 /dev/mtdblock0 /spi_flash0
#Creating a file to be written to the flash
dd if=/dev/urandom of=./sample.bin bs=1024 count=900
Code Block | ||
---|---|---|
| ||
900+0 records in 900+0 records out 921600 bytes (900.0KB) copied, 0.706526 seconds, 1.2MB/s |
cp ./sample.bin /spi_flash0/
#Check the presence of the file(s) in spi_flash0
ls /spi_flash0
Code Block | ||
---|---|---|
| ||
sample.bin |
umount spi_flash0
#Mount again - MTD 0 to spi_flash0
mount -t jffs2 /dev/mtdblock0 /spi_flash0
#Compare the files - there should be no differences
diff ./sample.bin /spi_flash0/sample.bin
#Unmount
umount spi_flash0
#The data can be verified again after a power on reset if desired.
Expected Output
Code Block | ||
---|---|---|
| ||
jffs2 log: #flash_eraseall -j /dev/mtd0 Erasing 4 Kibyte @ ff000 - 97% complete. Cleanmarker written at ff0000. Erasing 4 Kibyte @ 100000 - 100% complete #mkdir spi_flash0 #mount -t jffs2 /dev/mtdblock0 /spi_flash0 #dd if=/dev/urandom of=./sample.bin bs=1024 count=900 900+0 records in 900+0 records out 921600 bytes (900.0KB) copied, 0.706526 seconds, 1.2MB/s #cp ./sample.bin /spi_flash0/ #ls /spi_flash0 sample.bin #umount spi_flash0 #mount -t jffs2 /dev/mtdblock0 /spi_flash0 #diff ./sample.bin /spi_flash0/sample.bin |
SPI Slave Support
See the following page: Linux PS SPI Slave Mode.
Mainline Status
In sync with mainline driver.
Change Log
2016.3
- Summary
- Use to_platform_devive( ) api
- Commits
- Summary
2016.4
- Summary
- None
- Commits
- None
- Summary
2017.1
- Summary
- Fix checkpatch warning
- Remove _MASK and _OFFSET suffix
- Fix probe error handling
- Fix kernel doc warning
- Add runtime pm adaptation
- Remove the clock enable and disable from suspend and resume
- Return the error code for cdns_spi_suspend and cdns_spi_resume
- Fix some checkpatch warnings
- mark pm functions __maybe_unused
- Commits
- Summary
2017.2
- Summary
- Add support for context loss
- Commits
- Summary
2017.3
- Summary
- Update PM APIs sequence of calling
- Summary
- Commits
2017.4
- Summary
- None
- Commits
- None
- Summary
2018.1
- Summary
- None
- Commits
- None
- Summary
2018.2
- Summary
- None
- Commits
- None
- Summary
2018.3
- Summary
- None
- Commits
- None
- Summary
2019.1
2019.2
- Summary
- None
- Commits
- None
- Summary
2020.1
2020.2
2021.1
- Summary
- None
- Commits
- None
- Summary
2021.2
2022.1
- Summary
- None
- Commits
- None
- Summary
2022.2
- Summary
- Fix SPI NO Slave Select macro definition
- Commits
- Summary
2023.1
- Summary
- Replace all spi->chip_select and spi->cs_gpiod references with function call
- Commits
- Summary
2023.2
Related Links
...