Lines Matching +full:spi +full:- +full:rx +full:- +full:delay +full:- +full:us

1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Simple synchronous userspace interface to SPI devices
6 * Andrea Paterniani <a.paterniani@swapp-eng.it>
25 #include <linux/spi/spi.h>
26 #include <linux/spi/spidev.h>
32 * This supports access to SPI devices using normal userspace I/O calls.
34 * and often mask message boundaries, full SPI support requires full duplex
38 * SPI has a character major number assigned. We allocate minor numbers
42 * particular SPI bus or device.
54 * - CS_HIGH ... this device will be active when it shouldn't be
55 * - 3WIRE ... when active, it won't behave as it should
56 * - NO_CS ... there will be no explicit message boundaries; this
58 * - READY ... transfers may proceed when they shouldn't.
71 struct spi_device *spi; member
74 /* TX/RX buffers are NULL unless this device is open (users > 0) */
87 MODULE_PARM_DESC(bufsiz, "data bytes in biggest supported SPI message");
89 /*-------------------------------------------------------------------------*/
95 struct spi_device *spi; in spidev_sync() local
97 spin_lock_irq(&spidev->spi_lock); in spidev_sync()
98 spi = spidev->spi; in spidev_sync()
99 spin_unlock_irq(&spidev->spi_lock); in spidev_sync()
101 if (spi == NULL) in spidev_sync()
102 status = -ESHUTDOWN; in spidev_sync()
104 status = spi_sync(spi, message); in spidev_sync()
107 status = message->actual_length; in spidev_sync()
116 .tx_buf = spidev->tx_buffer, in spidev_sync_write()
118 .speed_hz = spidev->speed_hz, in spidev_sync_write()
131 .rx_buf = spidev->rx_buffer, in spidev_sync_read()
133 .speed_hz = spidev->speed_hz, in spidev_sync_read()
142 /*-------------------------------------------------------------------------*/
144 /* Read-only message with current device setup */
153 return -EMSGSIZE; in spidev_read()
155 spidev = filp->private_data; in spidev_read()
157 mutex_lock(&spidev->buf_lock); in spidev_read()
162 missing = copy_to_user(buf, spidev->rx_buffer, status); in spidev_read()
164 status = -EFAULT; in spidev_read()
166 status = status - missing; in spidev_read()
168 mutex_unlock(&spidev->buf_lock); in spidev_read()
173 /* Write-only message with current device setup */
184 return -EMSGSIZE; in spidev_write()
186 spidev = filp->private_data; in spidev_write()
188 mutex_lock(&spidev->buf_lock); in spidev_write()
189 missing = copy_from_user(spidev->tx_buffer, buf, count); in spidev_write()
193 status = -EFAULT; in spidev_write()
194 mutex_unlock(&spidev->buf_lock); in spidev_write()
208 int status = -EFAULT; in spidev_message()
213 return -ENOMEM; in spidev_message()
216 * We walk the array of user-provided transfers, using each one in spidev_message()
219 tx_buf = spidev->tx_buffer; in spidev_message()
220 rx_buf = spidev->rx_buffer; in spidev_message()
226 n--, k_tmp++, u_tmp++) { in spidev_message()
230 unsigned int len_aligned = ALIGN(u_tmp->len, ARCH_KMALLOC_MINALIGN); in spidev_message()
232 k_tmp->len = u_tmp->len; in spidev_message()
234 total += k_tmp->len; in spidev_message()
240 if (total > INT_MAX || k_tmp->len > INT_MAX) { in spidev_message()
241 status = -EMSGSIZE; in spidev_message()
245 if (u_tmp->rx_buf) { in spidev_message()
246 /* this transfer needs space in RX bounce buffer */ in spidev_message()
249 status = -EMSGSIZE; in spidev_message()
252 k_tmp->rx_buf = rx_buf; in spidev_message()
255 if (u_tmp->tx_buf) { in spidev_message()
259 status = -EMSGSIZE; in spidev_message()
262 k_tmp->tx_buf = tx_buf; in spidev_message()
264 (uintptr_t) u_tmp->tx_buf, in spidev_message()
265 u_tmp->len)) in spidev_message()
270 k_tmp->cs_change = !!u_tmp->cs_change; in spidev_message()
271 k_tmp->tx_nbits = u_tmp->tx_nbits; in spidev_message()
272 k_tmp->rx_nbits = u_tmp->rx_nbits; in spidev_message()
273 k_tmp->bits_per_word = u_tmp->bits_per_word; in spidev_message()
274 k_tmp->delay.value = u_tmp->delay_usecs; in spidev_message()
275 k_tmp->delay.unit = SPI_DELAY_UNIT_USECS; in spidev_message()
276 k_tmp->speed_hz = u_tmp->speed_hz; in spidev_message()
277 k_tmp->word_delay.value = u_tmp->word_delay_usecs; in spidev_message()
278 k_tmp->word_delay.unit = SPI_DELAY_UNIT_USECS; in spidev_message()
279 if (!k_tmp->speed_hz) in spidev_message()
280 k_tmp->speed_hz = spidev->speed_hz; in spidev_message()
282 dev_dbg(&spidev->spi->dev, in spidev_message()
284 k_tmp->len, in spidev_message()
285 k_tmp->rx_buf ? "rx " : "", in spidev_message()
286 k_tmp->tx_buf ? "tx " : "", in spidev_message()
287 k_tmp->cs_change ? "cs " : "", in spidev_message()
288 k_tmp->bits_per_word ? : spidev->spi->bits_per_word, in spidev_message()
289 k_tmp->delay.value, in spidev_message()
290 k_tmp->word_delay.value, in spidev_message()
291 k_tmp->speed_hz ? : spidev->spi->max_speed_hz); in spidev_message()
300 /* copy any rx data out of bounce buffer */ in spidev_message()
303 n--, k_tmp++, u_tmp++) { in spidev_message()
304 if (u_tmp->rx_buf) { in spidev_message()
306 (uintptr_t) u_tmp->rx_buf, k_tmp->rx_buf, in spidev_message()
307 u_tmp->len)) { in spidev_message()
308 status = -EFAULT; in spidev_message()
330 return ERR_PTR(-ENOTTY); in spidev_get_ioc_message()
334 return ERR_PTR(-EINVAL); in spidev_get_ioc_message()
348 struct spi_device *spi; in spidev_ioctl() local
355 return -ENOTTY; in spidev_ioctl()
360 spidev = filp->private_data; in spidev_ioctl()
361 spin_lock_irq(&spidev->spi_lock); in spidev_ioctl()
362 spi = spi_dev_get(spidev->spi); in spidev_ioctl()
363 spin_unlock_irq(&spidev->spi_lock); in spidev_ioctl()
365 if (spi == NULL) in spidev_ioctl()
366 return -ESHUTDOWN; in spidev_ioctl()
369 * - prevent I/O (from us) so calling spi_setup() is safe; in spidev_ioctl()
370 * - prevent concurrent SPI_IOC_WR_* from morphing in spidev_ioctl()
372 * - SPI_IOC_MESSAGE needs the buffer locked "normally". in spidev_ioctl()
374 mutex_lock(&spidev->buf_lock); in spidev_ioctl()
379 retval = put_user(spi->mode & SPI_MODE_MASK, in spidev_ioctl()
383 retval = put_user(spi->mode & SPI_MODE_MASK, in spidev_ioctl()
387 retval = put_user((spi->mode & SPI_LSB_FIRST) ? 1 : 0, in spidev_ioctl()
391 retval = put_user(spi->bits_per_word, (__u8 __user *)arg); in spidev_ioctl()
394 retval = put_user(spidev->speed_hz, (__u32 __user *)arg); in spidev_ioctl()
405 struct spi_controller *ctlr = spi->controller; in spidev_ioctl()
406 u32 save = spi->mode; in spidev_ioctl()
409 retval = -EINVAL; in spidev_ioctl()
413 if (ctlr->use_gpio_descriptors && ctlr->cs_gpiods && in spidev_ioctl()
414 ctlr->cs_gpiods[spi->chip_select]) in spidev_ioctl()
417 tmp |= spi->mode & ~SPI_MODE_MASK; in spidev_ioctl()
418 spi->mode = (u16)tmp; in spidev_ioctl()
419 retval = spi_setup(spi); in spidev_ioctl()
421 spi->mode = save; in spidev_ioctl()
423 dev_dbg(&spi->dev, "spi mode %x\n", tmp); in spidev_ioctl()
429 u32 save = spi->mode; in spidev_ioctl()
432 spi->mode |= SPI_LSB_FIRST; in spidev_ioctl()
434 spi->mode &= ~SPI_LSB_FIRST; in spidev_ioctl()
435 retval = spi_setup(spi); in spidev_ioctl()
437 spi->mode = save; in spidev_ioctl()
439 dev_dbg(&spi->dev, "%csb first\n", in spidev_ioctl()
446 u8 save = spi->bits_per_word; in spidev_ioctl()
448 spi->bits_per_word = tmp; in spidev_ioctl()
449 retval = spi_setup(spi); in spidev_ioctl()
451 spi->bits_per_word = save; in spidev_ioctl()
453 dev_dbg(&spi->dev, "%d bits per word\n", tmp); in spidev_ioctl()
459 u32 save = spi->max_speed_hz; in spidev_ioctl()
461 spi->max_speed_hz = tmp; in spidev_ioctl()
462 retval = spi_setup(spi); in spidev_ioctl()
464 spidev->speed_hz = tmp; in spidev_ioctl()
465 dev_dbg(&spi->dev, "%d Hz (max)\n", in spidev_ioctl()
466 spidev->speed_hz); in spidev_ioctl()
468 spi->max_speed_hz = save; in spidev_ioctl()
473 /* segmented and/or full-duplex I/O request */ in spidev_ioctl()
490 mutex_unlock(&spidev->buf_lock); in spidev_ioctl()
491 spi_dev_put(spi); in spidev_ioctl()
503 struct spi_device *spi; in spidev_compat_ioc_message() local
512 spidev = filp->private_data; in spidev_compat_ioc_message()
513 spin_lock_irq(&spidev->spi_lock); in spidev_compat_ioc_message()
514 spi = spi_dev_get(spidev->spi); in spidev_compat_ioc_message()
515 spin_unlock_irq(&spidev->spi_lock); in spidev_compat_ioc_message()
517 if (spi == NULL) in spidev_compat_ioc_message()
518 return -ESHUTDOWN; in spidev_compat_ioc_message()
521 mutex_lock(&spidev->buf_lock); in spidev_compat_ioc_message()
543 mutex_unlock(&spidev->buf_lock); in spidev_compat_ioc_message()
544 spi_dev_put(spi); in spidev_compat_ioc_message()
565 int status = -ENXIO; in spidev_open()
570 if (spidev->devt == inode->i_rdev) { in spidev_open()
581 if (!spidev->tx_buffer) { in spidev_open()
582 spidev->tx_buffer = kmalloc(bufsiz, GFP_KERNEL); in spidev_open()
583 if (!spidev->tx_buffer) { in spidev_open()
584 dev_dbg(&spidev->spi->dev, "open/ENOMEM\n"); in spidev_open()
585 status = -ENOMEM; in spidev_open()
590 if (!spidev->rx_buffer) { in spidev_open()
591 spidev->rx_buffer = kmalloc(bufsiz, GFP_KERNEL); in spidev_open()
592 if (!spidev->rx_buffer) { in spidev_open()
593 dev_dbg(&spidev->spi->dev, "open/ENOMEM\n"); in spidev_open()
594 status = -ENOMEM; in spidev_open()
599 spidev->users++; in spidev_open()
600 filp->private_data = spidev; in spidev_open()
607 kfree(spidev->tx_buffer); in spidev_open()
608 spidev->tx_buffer = NULL; in spidev_open()
620 spidev = filp->private_data; in spidev_release()
621 filp->private_data = NULL; in spidev_release()
623 spin_lock_irq(&spidev->spi_lock); in spidev_release()
625 dofree = (spidev->spi == NULL); in spidev_release()
626 spin_unlock_irq(&spidev->spi_lock); in spidev_release()
629 spidev->users--; in spidev_release()
630 if (!spidev->users) { in spidev_release()
632 kfree(spidev->tx_buffer); in spidev_release()
633 spidev->tx_buffer = NULL; in spidev_release()
635 kfree(spidev->rx_buffer); in spidev_release()
636 spidev->rx_buffer = NULL; in spidev_release()
641 spidev->speed_hz = spidev->spi->max_speed_hz; in spidev_release()
645 spi_slave_abort(spidev->spi); in spidev_release()
667 /*-------------------------------------------------------------------------*/
683 { .compatible = "dh,dhcom-board" },
692 /* Dummy SPI devices not to be used in production systems */
700 * a proper driver instead of poking directly to the SPI bus.
709 static void spidev_probe_acpi(struct spi_device *spi) in spidev_probe_acpi() argument
713 if (!has_acpi_companion(&spi->dev)) in spidev_probe_acpi()
716 id = acpi_match_device(spidev_acpi_ids, &spi->dev); in spidev_probe_acpi()
720 if (id->driver_data == SPIDEV_ACPI_DUMMY) in spidev_probe_acpi()
721 dev_warn(&spi->dev, "do not use this driver in production systems!\n"); in spidev_probe_acpi()
724 static inline void spidev_probe_acpi(struct spi_device *spi) {} in spidev_probe_acpi() argument
727 /*-------------------------------------------------------------------------*/
729 static int spidev_probe(struct spi_device *spi) in spidev_probe() argument
740 WARN(spi->dev.of_node && in spidev_probe()
741 of_device_is_compatible(spi->dev.of_node, "spidev"), in spidev_probe()
742 "%pOF: buggy DT: spidev listed directly in DT\n", spi->dev.of_node); in spidev_probe()
744 spidev_probe_acpi(spi); in spidev_probe()
749 return -ENOMEM; in spidev_probe()
752 spidev->spi = spi; in spidev_probe()
753 spin_lock_init(&spidev->spi_lock); in spidev_probe()
754 mutex_init(&spidev->buf_lock); in spidev_probe()
756 INIT_LIST_HEAD(&spidev->device_entry); in spidev_probe()
766 spidev->devt = MKDEV(SPIDEV_MAJOR, minor); in spidev_probe()
767 dev = device_create(spidev_class, &spi->dev, spidev->devt, in spidev_probe()
769 spi->master->bus_num, spi->chip_select); in spidev_probe()
772 dev_dbg(&spi->dev, "no minor number available!\n"); in spidev_probe()
773 status = -ENODEV; in spidev_probe()
777 list_add(&spidev->device_entry, &device_list); in spidev_probe()
781 spidev->speed_hz = spi->max_speed_hz; in spidev_probe()
784 spi_set_drvdata(spi, spidev); in spidev_probe()
791 static int spidev_remove(struct spi_device *spi) in spidev_remove() argument
793 struct spidev_data *spidev = spi_get_drvdata(spi); in spidev_remove()
798 spin_lock_irq(&spidev->spi_lock); in spidev_remove()
799 spidev->spi = NULL; in spidev_remove()
800 spin_unlock_irq(&spidev->spi_lock); in spidev_remove()
802 list_del(&spidev->device_entry); in spidev_remove()
803 device_destroy(spidev_class, spidev->devt); in spidev_remove()
804 clear_bit(MINOR(spidev->devt), minors); in spidev_remove()
805 if (spidev->users == 0) in spidev_remove()
828 /*-------------------------------------------------------------------------*/
839 status = register_chrdev(SPIDEV_MAJOR, "spi", &spidev_fops); in spidev_init()
866 MODULE_AUTHOR("Andrea Paterniani, <a.paterniani@swapp-eng.it>");
867 MODULE_DESCRIPTION("User mode SPI device interface");
869 MODULE_ALIAS("spi:spidev");