요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.
1. 요약·해설
원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.
2. 영어 원문 전체
번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.
원문 전체 펼치기
=================
SPI userspace API
=================
SPI devices have a limited userspace API, supporting basic half-duplex
read() and write() access to SPI slave devices. Using ioctl() requests,
full duplex transfers and device I/O configuration are also available.
::
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <linux/spi/spidev.h>
Some reasons you might want to use this programming interface include:
* Prototyping in an environment that's not crash-prone; stray pointers
in userspace won't normally bring down any Linux system.
* Developing simple protocols used to talk to microcontrollers acting
as SPI slaves, which you may need to change quite often.
Of course there are drivers that can never be written in userspace, because
they need to access kernel interfaces (such as IRQ handlers or other layers
of the driver stack) that are not accessible to userspace.
DEVICE CREATION, DRIVER BINDING
===============================
The spidev driver contains lists of SPI devices that are supported for
the different hardware topology representations.
The following are the SPI device tables supported by the spidev driver:
- struct spi_device_id spidev_spi_ids[]: list of devices that can be
bound when these are defined using a struct spi_board_info with a
.modalias field matching one of the entries in the table.
- struct of_device_id spidev_dt_ids[]: list of devices that can be
bound when these are defined using a Device Tree node that has a
compatible string matching one of the entries in the table.
- struct acpi_device_id spidev_acpi_ids[]: list of devices that can
be bound when these are defined using a ACPI device object with a
_HID matching one of the entries in the table.
You are encouraged to add an entry for your SPI device name to relevant
tables, if these don't already have an entry for the device. To do that,
post a patch for spidev to the linux-spi@vger.kernel.org mailing list.
It used to be supported to define an SPI device using the "spidev" name.
For example, as .modalias = "spidev" or compatible = "spidev". But this
is no longer supported by the Linux kernel and instead a real SPI device
name as listed in one of the tables must be used.
Not having a real SPI device name will lead to an error being printed and
the spidev driver failing to probe.
Sysfs also supports userspace driven binding/unbinding of drivers to
devices that do not bind automatically using one of the tables above.
To make the spidev driver bind to such a device, use the following::
echo spidev > /sys/bus/spi/devices/spiB.C/driver_override
echo spiB.C > /sys/bus/spi/drivers/spidev/bind
When the spidev driver is bound to a SPI device, the sysfs node for the
device will include a child device node with a "dev" attribute that will
be understood by udev or mdev (udev replacement from BusyBox; it's less
featureful, but often enough).
For a SPI device with chipselect C on bus B, you should see:
/dev/spidevB.C ...
character special device, major number 153 with
a dynamically chosen minor device number. This is the node
that userspace programs will open, created by "udev" or "mdev".
/sys/devices/.../spiB.C ...
as usual, the SPI device node will
be a child of its SPI master controller.
/sys/class/spidev/spidevB.C ...
created when the "spidev" driver
binds to that device. (Directory or symlink, based on whether
or not you enabled the "deprecated sysfs files" Kconfig option.)
Do not try to manage the /dev character device special file nodes by hand.
That's error prone, and you'd need to pay careful attention to system
security issues; udev/mdev should already be configured securely.
If you unbind the "spidev" driver from that device, those two "spidev" nodes
(in sysfs and in /dev) should automatically be removed (respectively by the
kernel and by udev/mdev). You can unbind by removing the "spidev" driver
module, which will affect all devices using this driver. You can also unbind
by having kernel code remove the SPI device, probably by removing the driver
for its SPI controller (so its spi_master vanishes).
Since this is a standard Linux device driver -- even though it just happens
to expose a low level API to userspace -- it can be associated with any number
of devices at a time. Just provide one spi_board_info record for each such
SPI device, and you'll get a /dev device node for each device.
BASIC CHARACTER DEVICE API
==========================
Normal open() and close() operations on /dev/spidevB.D files work as you
would expect.
Standard read() and write() operations are obviously only half-duplex, and
the chipselect is deactivated between those operations. Full-duplex access,
and composite operation without chipselect de-activation, is available using
the SPI_IOC_MESSAGE(N) request.
Several ioctl() requests let your driver read or override the device's current
settings for data transfer parameters:
SPI_IOC_RD_MODE, SPI_IOC_WR_MODE ...
pass a pointer to a byte which will
return (RD) or assign (WR) the SPI transfer mode. Use the constants
SPI_MODE_0..SPI_MODE_3; or if you prefer you can combine SPI_CPOL
(clock polarity, idle high iff this is set) or SPI_CPHA (clock phase,
sample on trailing edge iff this is set) flags.
Note that this request is limited to SPI mode flags that fit in a
single byte.
SPI_IOC_RD_MODE32, SPI_IOC_WR_MODE32 ...
pass a pointer to a uin32_t
which will return (RD) or assign (WR) the full SPI transfer mode,
not limited to the bits that fit in one byte.
SPI_IOC_RD_LSB_FIRST, SPI_IOC_WR_LSB_FIRST ...
pass a pointer to a byte
which will return (RD) or assign (WR) the bit justification used to
transfer SPI words. Zero indicates MSB-first; other values indicate
the less common LSB-first encoding. In both cases the specified value
is right-justified in each word, so that unused (TX) or undefined (RX)
bits are in the MSBs.
SPI_IOC_RD_BITS_PER_WORD, SPI_IOC_WR_BITS_PER_WORD ...
pass a pointer to
a byte which will return (RD) or assign (WR) the number of bits in
each SPI transfer word. The value zero signifies eight bits.
SPI_IOC_RD_MAX_SPEED_HZ, SPI_IOC_WR_MAX_SPEED_HZ ...
pass a pointer to a
u32 which will return (RD) or assign (WR) the maximum SPI transfer
speed, in Hz. The controller can't necessarily assign that specific
clock speed.
NOTES:
- At this time there is no async I/O support; everything is purely
synchronous.
- There's currently no way to report the actual bit rate used to
shift data to/from a given device.
- From userspace, you can't currently change the chip select polarity;
that could corrupt transfers to other devices sharing the SPI bus.
Each SPI device is deselected when it's not in active use, allowing
other drivers to talk to other devices.
- There's a limit on the number of bytes each I/O request can transfer
to the SPI device. It defaults to one page, but that can be changed
using a module parameter.
- Because SPI has no low-level transfer acknowledgement, you usually
won't see any I/O errors when talking to a non-existent device.
FULL DUPLEX CHARACTER DEVICE API
================================
See the spidev_fdx.c sample program for one example showing the use of the
full duplex programming interface. (Although it doesn't perform a full duplex
transfer.) The model is the same as that used in the kernel spi_sync()
request; the individual transfers offer the same capabilities as are
available to kernel drivers (except that it's not asynchronous).
The example shows one half-duplex RPC-style request and response message.
These requests commonly require that the chip not be deselected between
the request and response. Several such requests could be chained into
a single kernel request, even allowing the chip to be deselected after
each response. (Other protocol options include changing the word size
and bitrate for each transfer segment.)
To make a full duplex request, provide both rx_buf and tx_buf for the
same transfer. It's even OK if those are the same buffer.
3. 한국어 전문 번역
영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.
제한된 사용자 공간 SPI 접근
1-29SPI device는 제한된 userspace API를 제공한다. 기본 `read()`와 `write()`로 SPI target에 half-duplex 접근할 수 있고, `ioctl()` request를 사용하면 full-duplex transfer와 device I/O configuration도 수행할 수 있다.
Program은 `<fcntl.h>`, `<unistd.h>`, `<sys/ioctl.h>`, `<linux/types.h>`, `<linux/spi/spidev.h>`를 include한다. 이 interface는 stray pointer가 전체 Linux system을 보통 중단시키지 않는 userspace에서 안정적으로 prototype을 만들거나, 자주 바뀌는 SPI target microcontroller용 단순 protocol을 개발할 때 유용하다.
IRQ handler나 driver stack의 다른 layer처럼 userspace에서 접근할 수 없는 kernel interface가 필요한 driver는 userspace로 작성할 수 없다.
기본 file operation과 ioctl이 제공하는 기능을 구분한다.
=================
SPI userspace API
=================
SPI devices have a limited userspace API, supporting basic half-duplex
read() and write() access to SPI slave devices. Using ioctl() requests,
full duplex transfers and device I/O configuration are also available.
::
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <linux/spi/spidev.h>
Some reasons you might want to use this programming interface include:
* Prototyping in an environment that's not crash-prone; stray pointers
in userspace won't normally bring down any Linux system.
* Developing simple protocols used to talk to microcontrollers acting
as SPI slaves, which you may need to change quite often.
Of course there are drivers that can never be written in userspace, because
they need to access kernel interfaces (such as IRQ handlers or other layers
of the driver stack) that are not accessible to userspace.
Device 생성과 driver binding
30-61`spidev` driver는 hardware topology 표현별로 지원하는 SPI device table을 가진다. `spidev_spi_ids[]`는 `struct spi_board_info`의 `.modalias`가 table entry와 일치할 때 bind할 device 목록이다. `spidev_dt_ids[]`는 Device Tree node의 `compatible`, `spidev_acpi_ids[]`는 ACPI device object의 `_HID`가 entry와 일치할 때 사용한다.
해당 SPI device 이름이 관련 table에 없다면 `linux-spi@vger.kernel.org` mailing list로 spidev patch를 보내 entry를 추가하는 것이 권장된다.
과거에는 `.modalias = "spidev"` 또는 `compatible = "spidev"`처럼 device 이름 자체를 `spidev`로 선언할 수 있었지만 Linux kernel은 더 이상 이를 지원하지 않는다. Table에 나열된 실제 SPI device 이름을 써야 하며, 실제 이름이 없으면 error가 출력되고 spidev probe가 실패한다.
Topology별 실제 device 이름의 대조 위치다.
DEVICE CREATION, DRIVER BINDING
===============================
The spidev driver contains lists of SPI devices that are supported for
the different hardware topology representations.
The following are the SPI device tables supported by the spidev driver:
- struct spi_device_id spidev_spi_ids[]: list of devices that can be
bound when these are defined using a struct spi_board_info with a
.modalias field matching one of the entries in the table.
- struct of_device_id spidev_dt_ids[]: list of devices that can be
bound when these are defined using a Device Tree node that has a
compatible string matching one of the entries in the table.
- struct acpi_device_id spidev_acpi_ids[]: list of devices that can
be bound when these are defined using a ACPI device object with a
_HID matching one of the entries in the table.
You are encouraged to add an entry for your SPI device name to relevant
tables, if these don't already have an entry for the device. To do that,
post a patch for spidev to the linux-spi@vger.kernel.org mailing list.
It used to be supported to define an SPI device using the "spidev" name.
For example, as .modalias = "spidev" or compatible = "spidev". But this
is no longer supported by the Linux kernel and instead a real SPI device
name as listed in one of the tables must be used.
Not having a real SPI device name will lead to an error being printed and
the spidev driver failing to probe.
Sysfs 강제 binding과 device node
62-106지원 table로 자동 bind되지 않는 device도 sysfs에서 userspace가 driver를 bind·unbind할 수 있다. 먼저 `echo spidev > /sys/bus/spi/devices/spiB.C/driver_override`로 override를 지정하고, 이어 `echo spiB.C > /sys/bus/spi/drivers/spidev/bind`를 실행한다.
Spidev가 SPI device에 bind되면 device의 sysfs node에 `dev` attribute를 가진 child node가 생긴다. `udev` 또는 기능은 적지만 embedded system에서 흔히 충분한 BusyBox의 `mdev`가 이를 인식해 `/dev` node를 만든다.
Bus B의 chipselect C device에는 `/dev/spidevB.C`가 나타난다. Major 153과 동적으로 선택된 minor를 가진 character special device이며 userspace program이 open한다. `/sys/devices/.../spiB.C`는 SPI master controller의 child인 일반 SPI device node다. `/sys/class/spidev/spidevB.C`는 spidev가 bind할 때 생기며 `deprecated sysfs files` Kconfig option에 따라 directory 또는 symlink다.
`/dev` character special file을 수동 관리하면 오류와 보안 문제가 생기므로 안전하게 설정된 udev/mdev에 맡겨야 한다. Spidev를 unbind하면 sysfs와 `/dev`의 두 spidev node가 kernel과 udev/mdev에 의해 자동 제거되어야 한다. Module 제거는 이 driver를 쓰는 모든 device에 영향을 주며, kernel code가 SPI device 또는 그 controller driver를 제거해 `spi_master`가 사라지게 해도 unbind할 수 있다.
Spidev는 low-level userspace API를 공개할 뿐 표준 Linux device driver이므로 동시에 여러 device에 연결할 수 있다. 각 SPI device마다 `spi_board_info` record 하나를 제공하면 각각의 `/dev` node가 생긴다.
실제 SPI device를 driver에 연결하면 userspace node가 자동 생성된다.
같은 device를 가리키는 주요 경로다.
Sysfs also supports userspace driven binding/unbinding of drivers to
devices that do not bind automatically using one of the tables above.
To make the spidev driver bind to such a device, use the following::
echo spidev > /sys/bus/spi/devices/spiB.C/driver_override
echo spiB.C > /sys/bus/spi/drivers/spidev/bind
When the spidev driver is bound to a SPI device, the sysfs node for the
device will include a child device node with a "dev" attribute that will
be understood by udev or mdev (udev replacement from BusyBox; it's less
featureful, but often enough).
For a SPI device with chipselect C on bus B, you should see:
/dev/spidevB.C ...
character special device, major number 153 with
a dynamically chosen minor device number. This is the node
that userspace programs will open, created by "udev" or "mdev".
/sys/devices/.../spiB.C ...
as usual, the SPI device node will
be a child of its SPI master controller.
/sys/class/spidev/spidevB.C ...
created when the "spidev" driver
binds to that device. (Directory or symlink, based on whether
or not you enabled the "deprecated sysfs files" Kconfig option.)
Do not try to manage the /dev character device special file nodes by hand.
That's error prone, and you'd need to pay careful attention to system
security issues; udev/mdev should already be configured securely.
If you unbind the "spidev" driver from that device, those two "spidev" nodes
(in sysfs and in /dev) should automatically be removed (respectively by the
kernel and by udev/mdev). You can unbind by removing the "spidev" driver
module, which will affect all devices using this driver. You can also unbind
by having kernel code remove the SPI device, probably by removing the driver
for its SPI controller (so its spi_master vanishes).
Since this is a standard Linux device driver -- even though it just happens
to expose a low level API to userspace -- it can be associated with any number
of devices at a time. Just provide one spi_board_info record for each such
SPI device, and you'll get a /dev device node for each device.
기본 character device와 ioctl
107-173`/dev/spidevB.D`의 `open()`과 `close()`는 일반 character device처럼 동작한다. 표준 `read()`와 `write()`는 half-duplex이고 두 operation 사이에 chip select가 비활성화된다. Full-duplex 또는 chip select를 내리지 않는 복합 operation은 `SPI_IOC_MESSAGE(N)` request로 수행한다.
`SPI_IOC_RD_MODE`와 `SPI_IOC_WR_MODE`는 byte pointer로 한 byte 안에 들어가는 transfer mode flag를 읽거나 쓴다. `SPI_MODE_0`부터 `SPI_MODE_3`을 사용하거나 `SPI_CPOL`과 `SPI_CPHA`를 조합한다. `SPI_CPOL`이 설정되면 clock idle은 high이고, `SPI_CPHA`가 설정되면 trailing edge에서 sample한다.
`SPI_IOC_RD_MODE32`와 `SPI_IOC_WR_MODE32`는 원문에 `uin32_t`로 적힌 32-bit 값 pointer를 받아 한 byte 제한 없이 전체 transfer mode를 읽거나 설정한다. 원문의 identifier 표기는 아래 source block에 그대로 보존된다.
`SPI_IOC_RD_LSB_FIRST`와 `SPI_IOC_WR_LSB_FIRST`는 byte pointer로 SPI word의 bit 순서를 읽거나 설정한다. 0은 MSB-first, 그 밖의 값은 덜 흔한 LSB-first다. 두 경우 모두 지정 값은 각 word에서 right-justified되므로 사용하지 않는 TX bit 또는 정의되지 않은 RX bit는 MSB 쪽에 놓인다.
`SPI_IOC_RD_BITS_PER_WORD`와 `SPI_IOC_WR_BITS_PER_WORD`는 byte pointer로 word당 bit 수를 읽거나 설정하며 0은 8 bit를 뜻한다. `SPI_IOC_RD_MAX_SPEED_HZ`와 `SPI_IOC_WR_MAX_SPEED_HZ`는 `u32` pointer로 최대 transfer speed를 Hz 단위로 읽거나 설정한다. Controller가 요청한 정확한 clock speed를 반드시 제공할 수 있는 것은 아니다.
현재 async I/O는 없어 모든 동작이 synchronous다. 특정 device에 실제로 사용된 bit rate를 보고하는 방법도 없다. Bus를 공유하는 다른 device의 transfer를 손상시킬 수 있어 userspace에서는 chip select polarity를 바꿀 수 없다. 사용 중이 아닌 SPI device는 deselect되어 다른 driver가 다른 device와 통신할 수 있다.
각 I/O request가 SPI device로 전송할 수 있는 byte 수에는 제한이 있다. 기본은 한 page이며 module parameter로 변경할 수 있다. SPI에는 저수준 transfer acknowledgement가 없으므로 존재하지 않는 device와 통신해도 보통 I/O error가 보이지 않는다.
RD는 현재 값을 읽고 WR은 값을 덮어쓴다.
BASIC CHARACTER DEVICE API
==========================
Normal open() and close() operations on /dev/spidevB.D files work as you
would expect.
Standard read() and write() operations are obviously only half-duplex, and
the chipselect is deactivated between those operations. Full-duplex access,
and composite operation without chipselect de-activation, is available using
the SPI_IOC_MESSAGE(N) request.
Several ioctl() requests let your driver read or override the device's current
settings for data transfer parameters:
SPI_IOC_RD_MODE, SPI_IOC_WR_MODE ...
pass a pointer to a byte which will
return (RD) or assign (WR) the SPI transfer mode. Use the constants
SPI_MODE_0..SPI_MODE_3; or if you prefer you can combine SPI_CPOL
(clock polarity, idle high iff this is set) or SPI_CPHA (clock phase,
sample on trailing edge iff this is set) flags.
Note that this request is limited to SPI mode flags that fit in a
single byte.
SPI_IOC_RD_MODE32, SPI_IOC_WR_MODE32 ...
pass a pointer to a uin32_t
which will return (RD) or assign (WR) the full SPI transfer mode,
not limited to the bits that fit in one byte.
SPI_IOC_RD_LSB_FIRST, SPI_IOC_WR_LSB_FIRST ...
pass a pointer to a byte
which will return (RD) or assign (WR) the bit justification used to
transfer SPI words. Zero indicates MSB-first; other values indicate
the less common LSB-first encoding. In both cases the specified value
is right-justified in each word, so that unused (TX) or undefined (RX)
bits are in the MSBs.
SPI_IOC_RD_BITS_PER_WORD, SPI_IOC_WR_BITS_PER_WORD ...
pass a pointer to
a byte which will return (RD) or assign (WR) the number of bits in
each SPI transfer word. The value zero signifies eight bits.
SPI_IOC_RD_MAX_SPEED_HZ, SPI_IOC_WR_MAX_SPEED_HZ ...
pass a pointer to a
u32 which will return (RD) or assign (WR) the maximum SPI transfer
speed, in Hz. The controller can't necessarily assign that specific
clock speed.
NOTES:
- At this time there is no async I/O support; everything is purely
synchronous.
- There's currently no way to report the actual bit rate used to
shift data to/from a given device.
- From userspace, you can't currently change the chip select polarity;
that could corrupt transfers to other devices sharing the SPI bus.
Each SPI device is deselected when it's not in active use, allowing
other drivers to talk to other devices.
- There's a limit on the number of bytes each I/O request can transfer
to the SPI device. It defaults to one page, but that can be changed
using a module parameter.
- Because SPI has no low-level transfer acknowledgement, you usually
won't see any I/O errors when talking to a non-existent device.
Full-duplex character device API
174-191`spidev_fdx.c` sample은 full-duplex programming interface 사용 예를 보여 주지만 실제 full-duplex transfer를 수행하지는 않는다. Model은 kernel의 `spi_sync()` request와 같고 개별 transfer는 asynchronous가 아니라는 점을 제외하면 kernel driver와 같은 기능을 제공한다.
예제는 half-duplex RPC형 request와 response message 하나를 보여 준다. 이런 request는 보통 request와 response 사이에 chip이 deselect되지 않아야 한다. 여러 request를 하나의 kernel request로 chain할 수 있고 각 response 뒤 chip을 deselect하도록 할 수도 있다. Transfer segment마다 word size와 bitrate를 바꾸는 protocol option도 있다.
실제 full-duplex request를 만들려면 같은 transfer에 `rx_buf`와 `tx_buf`를 모두 제공한다. 두 field가 같은 buffer를 가리켜도 된다.
한 transfer에서 TX와 RX buffer가 동시에 clock된다.
FULL DUPLEX CHARACTER DEVICE API
================================
See the spidev_fdx.c sample program for one example showing the use of the
full duplex programming interface. (Although it doesn't perform a full duplex
transfer.) The model is the same as that used in the kernel spi_sync()
request; the individual transfers offer the same capabilities as are
available to kernel drivers (except that it's not asynchronous).
The example shows one half-duplex RPC-style request and response message.
These requests commonly require that the chip not be deselected between
the request and response. Several such requests could be chained into
a single kernel request, even allowing the chip to be deselected after
each response. (Other protocol options include changing the word size
and bitrate for each transfer segment.)
To make a full duplex request, provide both rx_buf and tx_buf for the
same transfer. It's even OK if those are the same buffer.
요약·해설
spidev.rst:1-191Spidev의 실제 장치 이름 기반 binding, sysfs override, `/dev/spidevB.C` node, half·full-duplex와 mode·bit order·word size·speed ioctl 계약을 설명합니다.