diff options
-rw-r--r-- | Documentation/spi/spidev | 307 | ||||
-rw-r--r-- | drivers/spi/Kconfig | 9 | ||||
-rw-r--r-- | drivers/spi/Makefile | 1 | ||||
-rw-r--r-- | drivers/spi/spidev.c | 584 | ||||
-rw-r--r-- | include/linux/Kbuild | 1 | ||||
-rw-r--r-- | include/linux/spi/Kbuild | 1 | ||||
-rw-r--r-- | include/linux/spi/spidev.h | 124 |
7 files changed, 1027 insertions, 0 deletions
diff --git a/Documentation/spi/spidev b/Documentation/spi/spidev new file mode 100644 index 000000000000..5c8e1b988a08 --- /dev/null +++ b/Documentation/spi/spidev | |||
@@ -0,0 +1,307 @@ | |||
1 | SPI devices have a limited userspace API, supporting basic half-duplex | ||
2 | read() and write() access to SPI slave devices. Using ioctl() requests, | ||
3 | full duplex transfers and device I/O configuration are also available. | ||
4 | |||
5 | #include <fcntl.h> | ||
6 | #include <unistd.h> | ||
7 | #include <sys/ioctl.h> | ||
8 | #include <linux/types.h> | ||
9 | #include <linux/spi/spidev.h> | ||
10 | |||
11 | Some reasons you might want to use this programming interface include: | ||
12 | |||
13 | * Prototyping in an environment that's not crash-prone; stray pointers | ||
14 | in userspace won't normally bring down any Linux system. | ||
15 | |||
16 | * Developing simple protocols used to talk to microcontrollers acting | ||
17 | as SPI slaves, which you may need to change quite often. | ||
18 | |||
19 | Of course there are drivers that can never be written in userspace, because | ||
20 | they need to access kernel interfaces (such as IRQ handlers or other layers | ||
21 | of the driver stack) that are not accessible to userspace. | ||
22 | |||
23 | |||
24 | DEVICE CREATION, DRIVER BINDING | ||
25 | =============================== | ||
26 | The simplest way to arrange to use this driver is to just list it in the | ||
27 | spi_board_info for a device as the driver it should use: the "modalias" | ||
28 | entry is "spidev", matching the name of the driver exposing this API. | ||
29 | Set up the other device characteristics (bits per word, SPI clocking, | ||
30 | chipselect polarity, etc) as usual, so you won't always need to override | ||
31 | them later. | ||
32 | |||
33 | (Sysfs also supports userspace driven binding/unbinding of drivers to | ||
34 | devices. That mechanism might be supported here in the future.) | ||
35 | |||
36 | When you do that, the sysfs node for the SPI device will include a child | ||
37 | device node with a "dev" attribute that will be understood by udev or mdev. | ||
38 | (Larger systems will have "udev". Smaller ones may configure "mdev" into | ||
39 | busybox; it's less featureful, but often enough.) For a SPI device with | ||
40 | chipselect C on bus B, you should see: | ||
41 | |||
42 | /dev/spidevB.C ... character special device, major number 153 with | ||
43 | a dynamically chosen minor device number. This is the node | ||
44 | that userspace programs will open, created by "udev" or "mdev". | ||
45 | |||
46 | /sys/devices/.../spiB.C ... as usual, the SPI device node will | ||
47 | be a child of its SPI master controller. | ||
48 | |||
49 | /sys/class/spidev/spidevB.C ... created when the "spidev" driver | ||
50 | binds to that device. (Directory or symlink, based on whether | ||
51 | or not you enabled the "deprecated sysfs files" Kconfig option.) | ||
52 | |||
53 | Do not try to manage the /dev character device special file nodes by hand. | ||
54 | That's error prone, and you'd need to pay careful attention to system | ||
55 | security issues; udev/mdev should already be configured securely. | ||
56 | |||
57 | If you unbind the "spidev" driver from that device, those two "spidev" nodes | ||
58 | (in sysfs and in /dev) should automatically be removed (respectively by the | ||
59 | kernel and by udev/mdev). You can unbind by removing the "spidev" driver | ||
60 | module, which will affect all devices using this driver. You can also unbind | ||
61 | by having kernel code remove the SPI device, probably by removing the driver | ||
62 | for its SPI controller (so its spi_master vanishes). | ||
63 | |||
64 | Since this is a standard Linux device driver -- even though it just happens | ||
65 | to expose a low level API to userspace -- it can be associated with any number | ||
66 | of devices at a time. Just provide one spi_board_info record for each such | ||
67 | SPI device, and you'll get a /dev device node for each device. | ||
68 | |||
69 | |||
70 | BASIC CHARACTER DEVICE API | ||
71 | ========================== | ||
72 | Normal open() and close() operations on /dev/spidevB.D files work as you | ||
73 | would expect. | ||
74 | |||
75 | Standard read() and write() operations are obviously only half-duplex, and | ||
76 | the chipselect is deactivated between those operations. Full-duplex access, | ||
77 | and composite operation without chipselect de-activation, is available using | ||
78 | the SPI_IOC_MESSAGE(N) request. | ||
79 | |||
80 | Several ioctl() requests let your driver read or override the device's current | ||
81 | settings for data transfer parameters: | ||
82 | |||
83 | SPI_IOC_RD_MODE, SPI_IOC_WR_MODE ... pass a pointer to a byte which will | ||
84 | return (RD) or assign (WR) the SPI transfer mode. Use the constants | ||
85 | SPI_MODE_0..SPI_MODE_3; or if you prefer you can combine SPI_CPOL | ||
86 | (clock polarity, idle high iff this is set) or SPI_CPHA (clock phase, | ||
87 | sample on trailing edge iff this is set) flags. | ||
88 | |||
89 | SPI_IOC_RD_LSB_FIRST, SPI_IOC_WR_LSB_FIRST ... pass a pointer to a byte | ||
90 | which will return (RD) or assign (WR) the bit justification used to | ||
91 | transfer SPI words. Zero indicates MSB-first; other values indicate | ||
92 | the less common LSB-first encoding. In both cases the specified value | ||
93 | is right-justified in each word, so that unused (TX) or undefined (RX) | ||
94 | bits are in the MSBs. | ||
95 | |||
96 | SPI_IOC_RD_BITS_PER_WORD, SPI_IOC_WR_BITS_PER_WORD ... pass a pointer to | ||
97 | a byte which will return (RD) or assign (WR) the number of bits in | ||
98 | each SPI transfer word. The value zero signifies eight bits. | ||
99 | |||
100 | SPI_IOC_RD_MAX_SPEED_HZ, SPI_IOC_WR_MAX_SPEED_HZ ... pass a pointer to a | ||
101 | u32 which will return (RD) or assign (WR) the maximum SPI transfer | ||
102 | speed, in Hz. The controller can't necessarily assign that specific | ||
103 | clock speed. | ||
104 | |||
105 | NOTES: | ||
106 | |||
107 | - At this time there is no async I/O support; everything is purely | ||
108 | synchronous. | ||
109 | |||
110 | - There's currently no way to report the actual bit rate used to | ||
111 | shift data to/from a given device. | ||
112 | |||
113 | - From userspace, you can't currently change the chip select polarity; | ||
114 | that could corrupt transfers to other devices sharing the SPI bus. | ||
115 | Each SPI device is deselected when it's not in active use, allowing | ||
116 | other drivers to talk to other devices. | ||
117 | |||
118 | - There's a limit on the number of bytes each I/O request can transfer | ||
119 | to the SPI device. It defaults to one page, but that can be changed | ||
120 | using a module parameter. | ||
121 | |||
122 | - Because SPI has no low-level transfer acknowledgement, you usually | ||
123 | won't see any I/O errors when talking to a non-existent device. | ||
124 | |||
125 | |||
126 | FULL DUPLEX CHARACTER DEVICE API | ||
127 | ================================ | ||
128 | |||
129 | See the sample program below for one example showing the use of the full | ||
130 | duplex programming interface. (Although it doesn't perform a full duplex | ||
131 | transfer.) The model is the same as that used in the kernel spi_sync() | ||
132 | request; the individual transfers offer the same capabilities as are | ||
133 | available to kernel drivers (except that it's not asynchronous). | ||
134 | |||
135 | The example shows one half-duplex RPC-style request and response message. | ||
136 | These requests commonly require that the chip not be deselected between | ||
137 | the request and response. Several such requests could be chained into | ||
138 | a single kernel request, even allowing the chip to be deselected after | ||
139 | each response. (Other protocol options include changing the word size | ||
140 | and bitrate for each transfer segment.) | ||
141 | |||
142 | To make a full duplex request, provide both rx_buf and tx_buf for the | ||
143 | same transfer. It's even OK if those are the same buffer. | ||
144 | |||
145 | |||
146 | SAMPLE PROGRAM | ||
147 | ============== | ||
148 | |||
149 | -------------------------------- CUT HERE | ||
150 | #include <stdio.h> | ||
151 | #include <unistd.h> | ||
152 | #include <stdlib.h> | ||
153 | #include <fcntl.h> | ||
154 | #include <string.h> | ||
155 | |||
156 | #include <sys/ioctl.h> | ||
157 | #include <sys/types.h> | ||
158 | #include <sys/stat.h> | ||
159 | |||
160 | #include <linux/types.h> | ||
161 | #include <linux/spi/spidev.h> | ||
162 | |||
163 | |||
164 | static int verbose; | ||
165 | |||
166 | static void do_read(int fd, int len) | ||
167 | { | ||
168 | unsigned char buf[32], *bp; | ||
169 | int status; | ||
170 | |||
171 | /* read at least 2 bytes, no more than 32 */ | ||
172 | if (len < 2) | ||
173 | len = 2; | ||
174 | else if (len > sizeof(buf)) | ||
175 | len = sizeof(buf); | ||
176 | memset(buf, 0, sizeof buf); | ||
177 | |||
178 | status = read(fd, buf, len); | ||
179 | if (status < 0) { | ||
180 | perror("read"); | ||
181 | return; | ||
182 | } | ||
183 | if (status != len) { | ||
184 | fprintf(stderr, "short read\n"); | ||
185 | return; | ||
186 | } | ||
187 | |||
188 | printf("read(%2d, %2d): %02x %02x,", len, status, | ||
189 | buf[0], buf[1]); | ||
190 | status -= 2; | ||
191 | bp = buf + 2; | ||
192 | while (status-- > 0) | ||
193 | printf(" %02x", *bp++); | ||
194 | printf("\n"); | ||
195 | } | ||
196 | |||
197 | static void do_msg(int fd, int len) | ||
198 | { | ||
199 | struct spi_ioc_transfer xfer[2]; | ||
200 | unsigned char buf[32], *bp; | ||
201 | int status; | ||
202 | |||
203 | memset(xfer, 0, sizeof xfer); | ||
204 | memset(buf, 0, sizeof buf); | ||
205 | |||
206 | if (len > sizeof buf) | ||
207 | len = sizeof buf; | ||
208 | |||
209 | buf[0] = 0xaa; | ||
210 | xfer[0].tx_buf = (__u64) buf; | ||
211 | xfer[0].len = 1; | ||
212 | |||
213 | xfer[1].rx_buf = (__u64) buf; | ||
214 | xfer[1].len = len; | ||
215 | |||
216 | status = ioctl(fd, SPI_IOC_MESSAGE(2), xfer); | ||
217 | if (status < 0) { | ||
218 | perror("SPI_IOC_MESSAGE"); | ||
219 | return; | ||
220 | } | ||
221 | |||
222 | printf("response(%2d, %2d): ", len, status); | ||
223 | for (bp = buf; len; len--) | ||
224 | printf(" %02x", *bp++); | ||
225 | printf("\n"); | ||
226 | } | ||
227 | |||
228 | static void dumpstat(const char *name, int fd) | ||
229 | { | ||
230 | __u8 mode, lsb, bits; | ||
231 | __u32 speed; | ||
232 | |||
233 | if (ioctl(fd, SPI_IOC_RD_MODE, &mode) < 0) { | ||
234 | perror("SPI rd_mode"); | ||
235 | return; | ||
236 | } | ||
237 | if (ioctl(fd, SPI_IOC_RD_LSB_FIRST, &lsb) < 0) { | ||
238 | perror("SPI rd_lsb_fist"); | ||
239 | return; | ||
240 | } | ||
241 | if (ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits) < 0) { | ||
242 | perror("SPI bits_per_word"); | ||
243 | return; | ||
244 | } | ||
245 | if (ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed) < 0) { | ||
246 | perror("SPI max_speed_hz"); | ||
247 | return; | ||
248 | } | ||
249 | |||
250 | printf("%s: spi mode %d, %d bits %sper word, %d Hz max\n", | ||
251 | name, mode, bits, lsb ? "(lsb first) " : "", speed); | ||
252 | } | ||
253 | |||
254 | int main(int argc, char **argv) | ||
255 | { | ||
256 | int c; | ||
257 | int readcount = 0; | ||
258 | int msglen = 0; | ||
259 | int fd; | ||
260 | const char *name; | ||
261 | |||
262 | while ((c = getopt(argc, argv, "hm:r:v")) != EOF) { | ||
263 | switch (c) { | ||
264 | case 'm': | ||
265 | msglen = atoi(optarg); | ||
266 | if (msglen < 0) | ||
267 | goto usage; | ||
268 | continue; | ||
269 | case 'r': | ||
270 | readcount = atoi(optarg); | ||
271 | if (readcount < 0) | ||
272 | goto usage; | ||
273 | continue; | ||
274 | case 'v': | ||
275 | verbose++; | ||
276 | continue; | ||
277 | case 'h': | ||
278 | case '?': | ||
279 | usage: | ||
280 | fprintf(stderr, | ||
281 | "usage: %s [-h] [-m N] [-r N] /dev/spidevB.D\n", | ||
282 | argv[0]); | ||
283 | return 1; | ||
284 | } | ||
285 | } | ||
286 | |||
287 | if ((optind + 1) != argc) | ||
288 | goto usage; | ||
289 | name = argv[optind]; | ||
290 | |||
291 | fd = open(name, O_RDWR); | ||
292 | if (fd < 0) { | ||
293 | perror("open"); | ||
294 | return 1; | ||
295 | } | ||
296 | |||
297 | dumpstat(name, fd); | ||
298 | |||
299 | if (msglen) | ||
300 | do_msg(fd, msglen); | ||
301 | |||
302 | if (readcount) | ||
303 | do_read(fd, readcount); | ||
304 | |||
305 | close(fd); | ||
306 | return 0; | ||
307 | } | ||
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 4a012d9acbff..584ed9f74700 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig | |||
@@ -159,6 +159,15 @@ config SPI_AT25 | |||
159 | This driver can also be built as a module. If so, the module | 159 | This driver can also be built as a module. If so, the module |
160 | will be called at25. | 160 | will be called at25. |
161 | 161 | ||
162 | config SPI_SPIDEV | ||
163 | tristate "User mode SPI device driver support" | ||
164 | depends on SPI_MASTER && EXPERIMENTAL | ||
165 | help | ||
166 | This supports user mode SPI protocol drivers. | ||
167 | |||
168 | Note that this application programming interface is EXPERIMENTAL | ||
169 | and hence SUBJECT TO CHANGE WITHOUT NOTICE while it stabilizes. | ||
170 | |||
162 | # | 171 | # |
163 | # Add new SPI protocol masters in alphabetical order above this line | 172 | # Add new SPI protocol masters in alphabetical order above this line |
164 | # | 173 | # |
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index a95ade857a2f..4cc5e99dd59a 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile | |||
@@ -25,6 +25,7 @@ obj-$(CONFIG_SPI_S3C24XX) += spi_s3c24xx.o | |||
25 | 25 | ||
26 | # SPI protocol drivers (device/link on bus) | 26 | # SPI protocol drivers (device/link on bus) |
27 | obj-$(CONFIG_SPI_AT25) += at25.o | 27 | obj-$(CONFIG_SPI_AT25) += at25.o |
28 | obj-$(CONFIG_SPI_SPIDEV) += spidev.o | ||
28 | # ... add above this line ... | 29 | # ... add above this line ... |
29 | 30 | ||
30 | # SPI slave controller drivers (upstream link) | 31 | # SPI slave controller drivers (upstream link) |
diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c new file mode 100644 index 000000000000..c0a6dce800a3 --- /dev/null +++ b/drivers/spi/spidev.c | |||
@@ -0,0 +1,584 @@ | |||
1 | /* | ||
2 | * spidev.c -- simple synchronous userspace interface to SPI devices | ||
3 | * | ||
4 | * Copyright (C) 2006 SWAPP | ||
5 | * Andrea Paterniani <a.paterniani@swapp-eng.it> | ||
6 | * Copyright (C) 2007 David Brownell (simplification, cleanup) | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | */ | ||
22 | |||
23 | #include <linux/init.h> | ||
24 | #include <linux/module.h> | ||
25 | #include <linux/ioctl.h> | ||
26 | #include <linux/fs.h> | ||
27 | #include <linux/device.h> | ||
28 | #include <linux/list.h> | ||
29 | #include <linux/errno.h> | ||
30 | #include <linux/mutex.h> | ||
31 | #include <linux/slab.h> | ||
32 | |||
33 | #include <linux/spi/spi.h> | ||
34 | #include <linux/spi/spidev.h> | ||
35 | |||
36 | #include <asm/uaccess.h> | ||
37 | |||
38 | |||
39 | /* | ||
40 | * This supports acccess to SPI devices using normal userspace I/O calls. | ||
41 | * Note that while traditional UNIX/POSIX I/O semantics are half duplex, | ||
42 | * and often mask message boundaries, full SPI support requires full duplex | ||
43 | * transfers. There are several kinds of of internal message boundaries to | ||
44 | * handle chipselect management and other protocol options. | ||
45 | * | ||
46 | * SPI has a character major number assigned. We allocate minor numbers | ||
47 | * dynamically using a bitmask. You must use hotplug tools, such as udev | ||
48 | * (or mdev with busybox) to create and destroy the /dev/spidevB.C device | ||
49 | * nodes, since there is no fixed association of minor numbers with any | ||
50 | * particular SPI bus or device. | ||
51 | */ | ||
52 | #define SPIDEV_MAJOR 153 /* assigned */ | ||
53 | #define N_SPI_MINORS 32 /* ... up to 256 */ | ||
54 | |||
55 | static unsigned long minors[N_SPI_MINORS / BITS_PER_LONG]; | ||
56 | |||
57 | |||
58 | /* Bit masks for spi_device.mode management */ | ||
59 | #define SPI_MODE_MASK (SPI_CPHA | SPI_CPOL) | ||
60 | |||
61 | |||
62 | struct spidev_data { | ||
63 | struct device dev; | ||
64 | struct spi_device *spi; | ||
65 | struct list_head device_entry; | ||
66 | |||
67 | struct mutex buf_lock; | ||
68 | unsigned users; | ||
69 | u8 *buffer; | ||
70 | }; | ||
71 | |||
72 | static LIST_HEAD(device_list); | ||
73 | static DEFINE_MUTEX(device_list_lock); | ||
74 | |||
75 | static unsigned bufsiz = 4096; | ||
76 | module_param(bufsiz, uint, S_IRUGO); | ||
77 | MODULE_PARM_DESC(bufsiz, "data bytes in biggest supported SPI message"); | ||
78 | |||
79 | /*-------------------------------------------------------------------------*/ | ||
80 | |||
81 | /* Read-only message with current device setup */ | ||
82 | static ssize_t | ||
83 | spidev_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) | ||
84 | { | ||
85 | struct spidev_data *spidev; | ||
86 | struct spi_device *spi; | ||
87 | ssize_t status = 0; | ||
88 | |||
89 | /* chipselect only toggles at start or end of operation */ | ||
90 | if (count > bufsiz) | ||
91 | return -EMSGSIZE; | ||
92 | |||
93 | spidev = filp->private_data; | ||
94 | spi = spidev->spi; | ||
95 | |||
96 | mutex_lock(&spidev->buf_lock); | ||
97 | status = spi_read(spi, spidev->buffer, count); | ||
98 | if (status == 0) { | ||
99 | unsigned long missing; | ||
100 | |||
101 | missing = copy_to_user(buf, spidev->buffer, count); | ||
102 | if (count && missing == count) | ||
103 | status = -EFAULT; | ||
104 | else | ||
105 | status = count - missing; | ||
106 | } | ||
107 | mutex_unlock(&spidev->buf_lock); | ||
108 | |||
109 | return status; | ||
110 | } | ||
111 | |||
112 | /* Write-only message with current device setup */ | ||
113 | static ssize_t | ||
114 | spidev_write(struct file *filp, const char __user *buf, | ||
115 | size_t count, loff_t *f_pos) | ||
116 | { | ||
117 | struct spidev_data *spidev; | ||
118 | struct spi_device *spi; | ||
119 | ssize_t status = 0; | ||
120 | unsigned long missing; | ||
121 | |||
122 | /* chipselect only toggles at start or end of operation */ | ||
123 | if (count > bufsiz) | ||
124 | return -EMSGSIZE; | ||
125 | |||
126 | spidev = filp->private_data; | ||
127 | spi = spidev->spi; | ||
128 | |||
129 | mutex_lock(&spidev->buf_lock); | ||
130 | missing = copy_from_user(spidev->buffer, buf, count); | ||
131 | if (missing == 0) { | ||
132 | status = spi_write(spi, spidev->buffer, count); | ||
133 | if (status == 0) | ||
134 | status = count; | ||
135 | } else | ||
136 | status = -EFAULT; | ||
137 | mutex_unlock(&spidev->buf_lock); | ||
138 | |||
139 | return status; | ||
140 | } | ||
141 | |||
142 | static int spidev_message(struct spidev_data *spidev, | ||
143 | struct spi_ioc_transfer *u_xfers, unsigned n_xfers) | ||
144 | { | ||
145 | struct spi_message msg; | ||
146 | struct spi_transfer *k_xfers; | ||
147 | struct spi_transfer *k_tmp; | ||
148 | struct spi_ioc_transfer *u_tmp; | ||
149 | struct spi_device *spi = spidev->spi; | ||
150 | unsigned n, total; | ||
151 | u8 *buf; | ||
152 | int status = -EFAULT; | ||
153 | |||
154 | spi_message_init(&msg); | ||
155 | k_xfers = kcalloc(n_xfers, sizeof(*k_tmp), GFP_KERNEL); | ||
156 | if (k_xfers == NULL) | ||
157 | return -ENOMEM; | ||
158 | |||
159 | /* Construct spi_message, copying any tx data to bounce buffer. | ||
160 | * We walk the array of user-provided transfers, using each one | ||
161 | * to initialize a kernel version of the same transfer. | ||
162 | */ | ||
163 | mutex_lock(&spidev->buf_lock); | ||
164 | buf = spidev->buffer; | ||
165 | total = 0; | ||
166 | for (n = n_xfers, k_tmp = k_xfers, u_tmp = u_xfers; | ||
167 | n; | ||
168 | n--, k_tmp++, u_tmp++) { | ||
169 | k_tmp->len = u_tmp->len; | ||
170 | |||
171 | if (u_tmp->rx_buf) { | ||
172 | k_tmp->rx_buf = buf; | ||
173 | if (!access_ok(VERIFY_WRITE, u_tmp->rx_buf, u_tmp->len)) | ||
174 | goto done; | ||
175 | } | ||
176 | if (u_tmp->tx_buf) { | ||
177 | k_tmp->tx_buf = buf; | ||
178 | if (copy_from_user(buf, (const u8 __user *)u_tmp->tx_buf, | ||
179 | u_tmp->len)) | ||
180 | goto done; | ||
181 | } | ||
182 | |||
183 | total += k_tmp->len; | ||
184 | if (total > bufsiz) { | ||
185 | status = -EMSGSIZE; | ||
186 | goto done; | ||
187 | } | ||
188 | buf += k_tmp->len; | ||
189 | |||
190 | k_tmp->cs_change = !!u_tmp->cs_change; | ||
191 | k_tmp->bits_per_word = u_tmp->bits_per_word; | ||
192 | k_tmp->delay_usecs = u_tmp->delay_usecs; | ||
193 | k_tmp->speed_hz = u_tmp->speed_hz; | ||
194 | #ifdef VERBOSE | ||
195 | dev_dbg(&spi->dev, | ||
196 | " xfer len %zd %s%s%s%dbits %u usec %uHz\n", | ||
197 | u_tmp->len, | ||
198 | u_tmp->rx_buf ? "rx " : "", | ||
199 | u_tmp->tx_buf ? "tx " : "", | ||
200 | u_tmp->cs_change ? "cs " : "", | ||
201 | u_tmp->bits_per_word ? : spi->bits_per_word, | ||
202 | u_tmp->delay_usecs, | ||
203 | u_tmp->speed_hz ? : spi->max_speed_hz); | ||
204 | #endif | ||
205 | spi_message_add_tail(k_tmp, &msg); | ||
206 | } | ||
207 | |||
208 | status = spi_sync(spi, &msg); | ||
209 | if (status < 0) | ||
210 | goto done; | ||
211 | |||
212 | /* copy any rx data out of bounce buffer */ | ||
213 | buf = spidev->buffer; | ||
214 | for (n = n_xfers, u_tmp = u_xfers; n; n--, u_tmp++) { | ||
215 | if (u_tmp->rx_buf) { | ||
216 | if (__copy_to_user((u8 __user *)u_tmp->rx_buf, buf, | ||
217 | u_tmp->len)) { | ||
218 | status = -EFAULT; | ||
219 | goto done; | ||
220 | } | ||
221 | } | ||
222 | buf += u_tmp->len; | ||
223 | } | ||
224 | status = total; | ||
225 | |||
226 | done: | ||
227 | mutex_unlock(&spidev->buf_lock); | ||
228 | kfree(k_xfers); | ||
229 | return status; | ||
230 | } | ||
231 | |||
232 | static int | ||
233 | spidev_ioctl(struct inode *inode, struct file *filp, | ||
234 | unsigned int cmd, unsigned long arg) | ||
235 | { | ||
236 | int err = 0; | ||
237 | int retval = 0; | ||
238 | struct spidev_data *spidev; | ||
239 | struct spi_device *spi; | ||
240 | u32 tmp; | ||
241 | unsigned n_ioc; | ||
242 | struct spi_ioc_transfer *ioc; | ||
243 | |||
244 | /* Check type and command number */ | ||
245 | if (_IOC_TYPE(cmd) != SPI_IOC_MAGIC) | ||
246 | return -ENOTTY; | ||
247 | |||
248 | /* Check access direction once here; don't repeat below. | ||
249 | * IOC_DIR is from the user perspective, while access_ok is | ||
250 | * from the kernel perspective; so they look reversed. | ||
251 | */ | ||
252 | if (_IOC_DIR(cmd) & _IOC_READ) | ||
253 | err = !access_ok(VERIFY_WRITE, | ||
254 | (void __user *)arg, _IOC_SIZE(cmd)); | ||
255 | if (err == 0 && _IOC_DIR(cmd) & _IOC_WRITE) | ||
256 | err = !access_ok(VERIFY_READ, | ||
257 | (void __user *)arg, _IOC_SIZE(cmd)); | ||
258 | if (err) | ||
259 | return -EFAULT; | ||
260 | |||
261 | spidev = filp->private_data; | ||
262 | spi = spidev->spi; | ||
263 | |||
264 | switch (cmd) { | ||
265 | /* read requests */ | ||
266 | case SPI_IOC_RD_MODE: | ||
267 | retval = __put_user(spi->mode & SPI_MODE_MASK, | ||
268 | (__u8 __user *)arg); | ||
269 | break; | ||
270 | case SPI_IOC_RD_LSB_FIRST: | ||
271 | retval = __put_user((spi->mode & SPI_LSB_FIRST) ? 1 : 0, | ||
272 | (__u8 __user *)arg); | ||
273 | break; | ||
274 | case SPI_IOC_RD_BITS_PER_WORD: | ||
275 | retval = __put_user(spi->bits_per_word, (__u8 __user *)arg); | ||
276 | break; | ||
277 | case SPI_IOC_RD_MAX_SPEED_HZ: | ||
278 | retval = __put_user(spi->max_speed_hz, (__u32 __user *)arg); | ||
279 | break; | ||
280 | |||
281 | /* write requests */ | ||
282 | case SPI_IOC_WR_MODE: | ||
283 | retval = __get_user(tmp, (u8 __user *)arg); | ||
284 | if (retval == 0) { | ||
285 | u8 save = spi->mode; | ||
286 | |||
287 | if (tmp & ~SPI_MODE_MASK) { | ||
288 | retval = -EINVAL; | ||
289 | break; | ||
290 | } | ||
291 | |||
292 | tmp |= spi->mode & ~SPI_MODE_MASK; | ||
293 | spi->mode = (u8)tmp; | ||
294 | retval = spi_setup(spi); | ||
295 | if (retval < 0) | ||
296 | spi->mode = save; | ||
297 | else | ||
298 | dev_dbg(&spi->dev, "spi mode %02x\n", tmp); | ||
299 | } | ||
300 | break; | ||
301 | case SPI_IOC_WR_LSB_FIRST: | ||
302 | retval = __get_user(tmp, (__u8 __user *)arg); | ||
303 | if (retval == 0) { | ||
304 | u8 save = spi->mode; | ||
305 | |||
306 | if (tmp) | ||
307 | spi->mode |= SPI_LSB_FIRST; | ||
308 | else | ||
309 | spi->mode &= ~SPI_LSB_FIRST; | ||
310 | retval = spi_setup(spi); | ||
311 | if (retval < 0) | ||
312 | spi->mode = save; | ||
313 | else | ||
314 | dev_dbg(&spi->dev, "%csb first\n", | ||
315 | tmp ? 'l' : 'm'); | ||
316 | } | ||
317 | break; | ||
318 | case SPI_IOC_WR_BITS_PER_WORD: | ||
319 | retval = __get_user(tmp, (__u8 __user *)arg); | ||
320 | if (retval == 0) { | ||
321 | u8 save = spi->bits_per_word; | ||
322 | |||
323 | spi->bits_per_word = tmp; | ||
324 | retval = spi_setup(spi); | ||
325 | if (retval < 0) | ||
326 | spi->bits_per_word = save; | ||
327 | else | ||
328 | dev_dbg(&spi->dev, "%d bits per word\n", tmp); | ||
329 | } | ||
330 | break; | ||
331 | case SPI_IOC_WR_MAX_SPEED_HZ: | ||
332 | retval = __get_user(tmp, (__u32 __user *)arg); | ||
333 | if (retval == 0) { | ||
334 | u32 save = spi->max_speed_hz; | ||
335 | |||
336 | spi->max_speed_hz = tmp; | ||
337 | retval = spi_setup(spi); | ||
338 | if (retval < 0) | ||
339 | spi->max_speed_hz = save; | ||
340 | else | ||
341 | dev_dbg(&spi->dev, "%d Hz (max)\n", tmp); | ||
342 | } | ||
343 | break; | ||
344 | |||
345 | default: | ||
346 | /* segmented and/or full-duplex I/O request */ | ||
347 | if (_IOC_NR(cmd) != _IOC_NR(SPI_IOC_MESSAGE(0)) | ||
348 | || _IOC_DIR(cmd) != _IOC_WRITE) | ||
349 | return -ENOTTY; | ||
350 | |||
351 | tmp = _IOC_SIZE(cmd); | ||
352 | if ((tmp % sizeof(struct spi_ioc_transfer)) != 0) { | ||
353 | retval = -EINVAL; | ||
354 | break; | ||
355 | } | ||
356 | n_ioc = tmp / sizeof(struct spi_ioc_transfer); | ||
357 | if (n_ioc == 0) | ||
358 | break; | ||
359 | |||
360 | /* copy into scratch area */ | ||
361 | ioc = kmalloc(tmp, GFP_KERNEL); | ||
362 | if (!ioc) { | ||
363 | retval = -ENOMEM; | ||
364 | break; | ||
365 | } | ||
366 | if (__copy_from_user(ioc, (void __user *)arg, tmp)) { | ||
367 | retval = -EFAULT; | ||
368 | break; | ||
369 | } | ||
370 | |||
371 | /* translate to spi_message, execute */ | ||
372 | retval = spidev_message(spidev, ioc, n_ioc); | ||
373 | kfree(ioc); | ||
374 | break; | ||
375 | } | ||
376 | return retval; | ||
377 | } | ||
378 | |||
379 | static int spidev_open(struct inode *inode, struct file *filp) | ||
380 | { | ||
381 | struct spidev_data *spidev; | ||
382 | int status = -ENXIO; | ||
383 | |||
384 | mutex_lock(&device_list_lock); | ||
385 | |||
386 | list_for_each_entry(spidev, &device_list, device_entry) { | ||
387 | if (spidev->dev.devt == inode->i_rdev) { | ||
388 | status = 0; | ||
389 | break; | ||
390 | } | ||
391 | } | ||
392 | if (status == 0) { | ||
393 | if (!spidev->buffer) { | ||
394 | spidev->buffer = kmalloc(bufsiz, GFP_KERNEL); | ||
395 | if (!spidev->buffer) { | ||
396 | dev_dbg(&spidev->spi->dev, "open/ENOMEM\n"); | ||
397 | status = -ENOMEM; | ||
398 | } | ||
399 | } | ||
400 | if (status == 0) { | ||
401 | spidev->users++; | ||
402 | filp->private_data = spidev; | ||
403 | nonseekable_open(inode, filp); | ||
404 | } | ||
405 | } else | ||
406 | pr_debug("spidev: nothing for minor %d\n", iminor(inode)); | ||
407 | |||
408 | mutex_unlock(&device_list_lock); | ||
409 | return status; | ||
410 | } | ||
411 | |||
412 | static int spidev_release(struct inode *inode, struct file *filp) | ||
413 | { | ||
414 | struct spidev_data *spidev; | ||
415 | int status = 0; | ||
416 | |||
417 | mutex_lock(&device_list_lock); | ||
418 | spidev = filp->private_data; | ||
419 | filp->private_data = NULL; | ||
420 | spidev->users--; | ||
421 | if (!spidev->users) { | ||
422 | kfree(spidev->buffer); | ||
423 | spidev->buffer = NULL; | ||
424 | } | ||
425 | mutex_unlock(&device_list_lock); | ||
426 | |||
427 | return status; | ||
428 | } | ||
429 | |||
430 | static struct file_operations spidev_fops = { | ||
431 | .owner = THIS_MODULE, | ||
432 | /* REVISIT switch to aio primitives, so that userspace | ||
433 | * gets more complete API coverage. It'll simplify things | ||
434 | * too, except for the locking. | ||
435 | */ | ||
436 | .write = spidev_write, | ||
437 | .read = spidev_read, | ||
438 | .ioctl = spidev_ioctl, | ||
439 | .open = spidev_open, | ||
440 | .release = spidev_release, | ||
441 | }; | ||
442 | |||
443 | /*-------------------------------------------------------------------------*/ | ||
444 | |||
445 | /* The main reason to have this class is to make mdev/udev create the | ||
446 | * /dev/spidevB.C character device nodes exposing our userspace API. | ||
447 | * It also simplifies memory management. | ||
448 | */ | ||
449 | |||
450 | static void spidev_classdev_release(struct device *dev) | ||
451 | { | ||
452 | struct spidev_data *spidev; | ||
453 | |||
454 | spidev = container_of(dev, struct spidev_data, dev); | ||
455 | kfree(spidev); | ||
456 | } | ||
457 | |||
458 | static struct class spidev_class = { | ||
459 | .name = "spidev", | ||
460 | .owner = THIS_MODULE, | ||
461 | .dev_release = spidev_classdev_release, | ||
462 | }; | ||
463 | |||
464 | /*-------------------------------------------------------------------------*/ | ||
465 | |||
466 | static int spidev_probe(struct spi_device *spi) | ||
467 | { | ||
468 | struct spidev_data *spidev; | ||
469 | int status; | ||
470 | unsigned long minor; | ||
471 | |||
472 | /* Allocate driver data */ | ||
473 | spidev = kzalloc(sizeof(*spidev), GFP_KERNEL); | ||
474 | if (!spidev) | ||
475 | return -ENOMEM; | ||
476 | |||
477 | /* Initialize the driver data */ | ||
478 | spidev->spi = spi; | ||
479 | mutex_init(&spidev->buf_lock); | ||
480 | |||
481 | INIT_LIST_HEAD(&spidev->device_entry); | ||
482 | |||
483 | /* If we can allocate a minor number, hook up this device. | ||
484 | * Reusing minors is fine so long as udev or mdev is working. | ||
485 | */ | ||
486 | mutex_lock(&device_list_lock); | ||
487 | minor = find_first_zero_bit(minors, ARRAY_SIZE(minors)); | ||
488 | if (minor < N_SPI_MINORS) { | ||
489 | spidev->dev.parent = &spi->dev; | ||
490 | spidev->dev.class = &spidev_class; | ||
491 | spidev->dev.devt = MKDEV(SPIDEV_MAJOR, minor); | ||
492 | snprintf(spidev->dev.bus_id, sizeof spidev->dev.bus_id, | ||
493 | "spidev%d.%d", | ||
494 | spi->master->bus_num, spi->chip_select); | ||
495 | status = device_register(&spidev->dev); | ||
496 | } else { | ||
497 | dev_dbg(&spi->dev, "no minor number available!\n"); | ||
498 | status = -ENODEV; | ||
499 | } | ||
500 | if (status == 0) { | ||
501 | set_bit(minor, minors); | ||
502 | dev_set_drvdata(&spi->dev, spidev); | ||
503 | list_add(&spidev->device_entry, &device_list); | ||
504 | } | ||
505 | mutex_unlock(&device_list_lock); | ||
506 | |||
507 | if (status != 0) | ||
508 | kfree(spidev); | ||
509 | |||
510 | return status; | ||
511 | } | ||
512 | |||
513 | static int spidev_remove(struct spi_device *spi) | ||
514 | { | ||
515 | struct spidev_data *spidev = dev_get_drvdata(&spi->dev); | ||
516 | |||
517 | mutex_lock(&device_list_lock); | ||
518 | |||
519 | list_del(&spidev->device_entry); | ||
520 | dev_set_drvdata(&spi->dev, NULL); | ||
521 | clear_bit(MINOR(spidev->dev.devt), minors); | ||
522 | device_unregister(&spidev->dev); | ||
523 | |||
524 | mutex_unlock(&device_list_lock); | ||
525 | |||
526 | return 0; | ||
527 | } | ||
528 | |||
529 | static struct spi_driver spidev_spi = { | ||
530 | .driver = { | ||
531 | .name = "spidev", | ||
532 | .owner = THIS_MODULE, | ||
533 | }, | ||
534 | .probe = spidev_probe, | ||
535 | .remove = __devexit_p(spidev_remove), | ||
536 | |||
537 | /* NOTE: suspend/resume methods are not necessary here. | ||
538 | * We don't do anything except pass the requests to/from | ||
539 | * the underlying controller. The refrigerator handles | ||
540 | * most issues; the controller driver handles the rest. | ||
541 | */ | ||
542 | }; | ||
543 | |||
544 | /*-------------------------------------------------------------------------*/ | ||
545 | |||
546 | static int __init spidev_init(void) | ||
547 | { | ||
548 | int status; | ||
549 | |||
550 | /* Claim our 256 reserved device numbers. Then register a class | ||
551 | * that will key udev/mdev to add/remove /dev nodes. Last, register | ||
552 | * the driver which manages those device numbers. | ||
553 | */ | ||
554 | BUILD_BUG_ON(N_SPI_MINORS > 256); | ||
555 | status = register_chrdev(SPIDEV_MAJOR, "spi", &spidev_fops); | ||
556 | if (status < 0) | ||
557 | return status; | ||
558 | |||
559 | status = class_register(&spidev_class); | ||
560 | if (status < 0) { | ||
561 | unregister_chrdev(SPIDEV_MAJOR, spidev_spi.driver.name); | ||
562 | return status; | ||
563 | } | ||
564 | |||
565 | status = spi_register_driver(&spidev_spi); | ||
566 | if (status < 0) { | ||
567 | class_unregister(&spidev_class); | ||
568 | unregister_chrdev(SPIDEV_MAJOR, spidev_spi.driver.name); | ||
569 | } | ||
570 | return status; | ||
571 | } | ||
572 | module_init(spidev_init); | ||
573 | |||
574 | static void __exit spidev_exit(void) | ||
575 | { | ||
576 | spi_unregister_driver(&spidev_spi); | ||
577 | class_unregister(&spidev_class); | ||
578 | unregister_chrdev(SPIDEV_MAJOR, spidev_spi.driver.name); | ||
579 | } | ||
580 | module_exit(spidev_exit); | ||
581 | |||
582 | MODULE_AUTHOR("Andrea Paterniani, <a.paterniani@swapp-eng.it>"); | ||
583 | MODULE_DESCRIPTION("User mode SPI device interface"); | ||
584 | MODULE_LICENSE("GPL"); | ||
diff --git a/include/linux/Kbuild b/include/linux/Kbuild index 715386142626..ccc6fc157064 100644 --- a/include/linux/Kbuild +++ b/include/linux/Kbuild | |||
@@ -4,6 +4,7 @@ header-y += hdlc/ | |||
4 | header-y += isdn/ | 4 | header-y += isdn/ |
5 | header-y += nfsd/ | 5 | header-y += nfsd/ |
6 | header-y += raid/ | 6 | header-y += raid/ |
7 | header-y += spi/ | ||
7 | header-y += sunrpc/ | 8 | header-y += sunrpc/ |
8 | header-y += tc_act/ | 9 | header-y += tc_act/ |
9 | header-y += netfilter/ | 10 | header-y += netfilter/ |
diff --git a/include/linux/spi/Kbuild b/include/linux/spi/Kbuild new file mode 100644 index 000000000000..d375a082986e --- /dev/null +++ b/include/linux/spi/Kbuild | |||
@@ -0,0 +1 @@ | |||
header-y += spidev.h | |||
diff --git a/include/linux/spi/spidev.h b/include/linux/spi/spidev.h new file mode 100644 index 000000000000..7d700be57490 --- /dev/null +++ b/include/linux/spi/spidev.h | |||
@@ -0,0 +1,124 @@ | |||
1 | /* | ||
2 | * include/linux/spi/spidev.h | ||
3 | * | ||
4 | * Copyright (C) 2006 SWAPP | ||
5 | * Andrea Paterniani <a.paterniani@swapp-eng.it> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | */ | ||
21 | |||
22 | #ifndef SPIDEV_H | ||
23 | #define SPIDEV_H | ||
24 | |||
25 | |||
26 | /* User space versions of kernel symbols for SPI clocking modes, | ||
27 | * matching <linux/spi/spi.h> | ||
28 | */ | ||
29 | |||
30 | #define SPI_CPHA 0x01 | ||
31 | #define SPI_CPOL 0x02 | ||
32 | |||
33 | #define SPI_MODE_0 (0|0) | ||
34 | #define SPI_MODE_1 (0|SPI_CPHA) | ||
35 | #define SPI_MODE_2 (SPI_CPOL|0) | ||
36 | #define SPI_MODE_3 (SPI_CPOL|SPI_CPHA) | ||
37 | |||
38 | |||
39 | /*---------------------------------------------------------------------------*/ | ||
40 | |||
41 | /* IOCTL commands */ | ||
42 | |||
43 | #define SPI_IOC_MAGIC 'k' | ||
44 | |||
45 | /** | ||
46 | * struct spi_ioc_transfer - describes a single SPI transfer | ||
47 | * @tx_buf: Holds pointer to userspace buffer with transmit data, or null. | ||
48 | * If no data is provided, zeroes are shifted out. | ||
49 | * @rx_buf: Holds pointer to userspace buffer for receive data, or null. | ||
50 | * @len: Length of tx and rx buffers, in bytes. | ||
51 | * @speed_hz: Temporary override of the device's bitrate. | ||
52 | * @bits_per_word: Temporary override of the device's wordsize. | ||
53 | * @delay_usecs: If nonzero, how long to delay after the last bit transfer | ||
54 | * before optionally deselecting the device before the next transfer. | ||
55 | * @cs_change: True to deselect device before starting the next transfer. | ||
56 | * | ||
57 | * This structure is mapped directly to the kernel spi_transfer structure; | ||
58 | * the fields have the same meanings, except of course that the pointers | ||
59 | * are in a different address space (and may be of different sizes in some | ||
60 | * cases, such as 32-bit i386 userspace over a 64-bit x86_64 kernel). | ||
61 | * Zero-initialize the structure, including currently unused fields, to | ||
62 | * accomodate potential future updates. | ||
63 | * | ||
64 | * SPI_IOC_MESSAGE gives userspace the equivalent of kernel spi_sync(). | ||
65 | * Pass it an array of related transfers, they'll execute together. | ||
66 | * Each transfer may be half duplex (either direction) or full duplex. | ||
67 | * | ||
68 | * struct spi_ioc_transfer mesg[4]; | ||
69 | * ... | ||
70 | * status = ioctl(fd, SPI_IOC_MESSAGE(4), mesg); | ||
71 | * | ||
72 | * So for example one transfer might send a nine bit command (right aligned | ||
73 | * in a 16-bit word), the next could read a block of 8-bit data before | ||
74 | * terminating that command by temporarily deselecting the chip; the next | ||
75 | * could send a different nine bit command (re-selecting the chip), and the | ||
76 | * last transfer might write some register values. | ||
77 | */ | ||
78 | struct spi_ioc_transfer { | ||
79 | __u64 tx_buf; | ||
80 | __u64 rx_buf; | ||
81 | |||
82 | __u32 len; | ||
83 | __u32 speed_hz; | ||
84 | |||
85 | __u16 delay_usecs; | ||
86 | __u8 bits_per_word; | ||
87 | __u8 cs_change; | ||
88 | __u32 pad; | ||
89 | |||
90 | /* If the contents of 'struct spi_ioc_transfer' ever change | ||
91 | * incompatibly, then the ioctl number (currently 0) must change; | ||
92 | * ioctls with constant size fields get a bit more in the way of | ||
93 | * error checking than ones (like this) where that field varies. | ||
94 | * | ||
95 | * NOTE: struct layout is the same in 64bit and 32bit userspace. | ||
96 | */ | ||
97 | }; | ||
98 | |||
99 | /* not all platforms use <asm-generic/ioctl.h> or _IOC_TYPECHECK() ... */ | ||
100 | #define SPI_MSGSIZE(N) \ | ||
101 | ((((N)*(sizeof (struct spi_ioc_transfer))) < (1 << _IOC_SIZEBITS)) \ | ||
102 | ? ((N)*(sizeof (struct spi_ioc_transfer))) : 0) | ||
103 | #define SPI_IOC_MESSAGE(N) _IOW(SPI_IOC_MAGIC, 0, char[SPI_MSGSIZE(N)]) | ||
104 | |||
105 | |||
106 | /* Read / Write of SPI mode (SPI_MODE_0..SPI_MODE_3) */ | ||
107 | #define SPI_IOC_RD_MODE _IOR(SPI_IOC_MAGIC, 1, __u8) | ||
108 | #define SPI_IOC_WR_MODE _IOW(SPI_IOC_MAGIC, 1, __u8) | ||
109 | |||
110 | /* Read / Write SPI bit justification */ | ||
111 | #define SPI_IOC_RD_LSB_FIRST _IOR(SPI_IOC_MAGIC, 2, __u8) | ||
112 | #define SPI_IOC_WR_LSB_FIRST _IOW(SPI_IOC_MAGIC, 2, __u8) | ||
113 | |||
114 | /* Read / Write SPI device word length (1..N) */ | ||
115 | #define SPI_IOC_RD_BITS_PER_WORD _IOR(SPI_IOC_MAGIC, 3, __u8) | ||
116 | #define SPI_IOC_WR_BITS_PER_WORD _IOW(SPI_IOC_MAGIC, 3, __u8) | ||
117 | |||
118 | /* Read / Write SPI device default max speed hz */ | ||
119 | #define SPI_IOC_RD_MAX_SPEED_HZ _IOR(SPI_IOC_MAGIC, 4, __u32) | ||
120 | #define SPI_IOC_WR_MAX_SPEED_HZ _IOW(SPI_IOC_MAGIC, 4, __u32) | ||
121 | |||
122 | |||
123 | |||
124 | #endif /* SPIDEV_H */ | ||