Lines Matching +full:bk4 +full:- +full:spi
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>
24 #include <linux/spi/spi.h>
25 #include <linux/spi/spidev.h>
31 * This supports access to SPI devices using normal userspace I/O calls.
33 * and often mask message boundaries, full SPI support requires full duplex
37 * SPI has a character major number assigned. We allocate minor numbers
41 * 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.
73 struct spi_device *spi; member
89 MODULE_PARM_DESC(bufsiz, "data bytes in biggest supported SPI message");
91 /*-------------------------------------------------------------------------*/
94 spidev_sync_unlocked(struct spi_device *spi, struct spi_message *message) in spidev_sync_unlocked() argument
98 status = spi_sync(spi, message); in spidev_sync_unlocked()
100 status = message->actual_length; in spidev_sync_unlocked()
109 struct spi_device *spi; in spidev_sync() local
111 mutex_lock(&spidev->spi_lock); in spidev_sync()
112 spi = spidev->spi; in spidev_sync()
114 if (spi == NULL) in spidev_sync()
115 status = -ESHUTDOWN; in spidev_sync()
117 status = spidev_sync_unlocked(spi, message); in spidev_sync()
119 mutex_unlock(&spidev->spi_lock); in spidev_sync()
127 .tx_buf = spidev->tx_buffer, in spidev_sync_write()
129 .speed_hz = spidev->speed_hz, in spidev_sync_write()
142 .rx_buf = spidev->rx_buffer, in spidev_sync_read()
144 .speed_hz = spidev->speed_hz, in spidev_sync_read()
153 /*-------------------------------------------------------------------------*/
155 /* Read-only message with current device setup */
164 return -EMSGSIZE; in spidev_read()
166 spidev = filp->private_data; in spidev_read()
168 mutex_lock(&spidev->buf_lock); in spidev_read()
173 missing = copy_to_user(buf, spidev->rx_buffer, status); in spidev_read()
175 status = -EFAULT; in spidev_read()
177 status = status - missing; in spidev_read()
179 mutex_unlock(&spidev->buf_lock); in spidev_read()
184 /* Write-only message with current device setup */
195 return -EMSGSIZE; in spidev_write()
197 spidev = filp->private_data; in spidev_write()
199 mutex_lock(&spidev->buf_lock); in spidev_write()
200 missing = copy_from_user(spidev->tx_buffer, buf, count); in spidev_write()
204 status = -EFAULT; in spidev_write()
205 mutex_unlock(&spidev->buf_lock); in spidev_write()
219 int status = -EFAULT; in spidev_message()
224 return -ENOMEM; in spidev_message()
227 * We walk the array of user-provided transfers, using each one in spidev_message()
230 tx_buf = spidev->tx_buffer; in spidev_message()
231 rx_buf = spidev->rx_buffer; in spidev_message()
237 n--, k_tmp++, u_tmp++) { in spidev_message()
241 unsigned int len_aligned = ALIGN(u_tmp->len, ARCH_DMA_MINALIGN); in spidev_message()
243 k_tmp->len = u_tmp->len; in spidev_message()
245 total += k_tmp->len; in spidev_message()
251 if (total > INT_MAX || k_tmp->len > INT_MAX) { in spidev_message()
252 status = -EMSGSIZE; in spidev_message()
256 if (u_tmp->rx_buf) { in spidev_message()
260 status = -EMSGSIZE; in spidev_message()
263 k_tmp->rx_buf = rx_buf; in spidev_message()
266 if (u_tmp->tx_buf) { in spidev_message()
270 status = -EMSGSIZE; in spidev_message()
273 k_tmp->tx_buf = tx_buf; in spidev_message()
275 (uintptr_t) u_tmp->tx_buf, in spidev_message()
276 u_tmp->len)) in spidev_message()
281 k_tmp->cs_change = !!u_tmp->cs_change; in spidev_message()
282 k_tmp->tx_nbits = u_tmp->tx_nbits; in spidev_message()
283 k_tmp->rx_nbits = u_tmp->rx_nbits; in spidev_message()
284 k_tmp->bits_per_word = u_tmp->bits_per_word; in spidev_message()
285 k_tmp->delay.value = u_tmp->delay_usecs; in spidev_message()
286 k_tmp->delay.unit = SPI_DELAY_UNIT_USECS; in spidev_message()
287 k_tmp->speed_hz = u_tmp->speed_hz; in spidev_message()
288 k_tmp->word_delay.value = u_tmp->word_delay_usecs; in spidev_message()
289 k_tmp->word_delay.unit = SPI_DELAY_UNIT_USECS; in spidev_message()
290 if (!k_tmp->speed_hz) in spidev_message()
291 k_tmp->speed_hz = spidev->speed_hz; in spidev_message()
293 dev_dbg(&spidev->spi->dev, in spidev_message()
295 k_tmp->len, in spidev_message()
296 k_tmp->rx_buf ? "rx " : "", in spidev_message()
297 k_tmp->tx_buf ? "tx " : "", in spidev_message()
298 k_tmp->cs_change ? "cs " : "", in spidev_message()
299 k_tmp->bits_per_word ? : spidev->spi->bits_per_word, in spidev_message()
300 k_tmp->delay.value, in spidev_message()
301 k_tmp->word_delay.value, in spidev_message()
302 k_tmp->speed_hz ? : spidev->spi->max_speed_hz); in spidev_message()
307 status = spidev_sync_unlocked(spidev->spi, &msg); in spidev_message()
314 n--, k_tmp++, u_tmp++) { in spidev_message()
315 if (u_tmp->rx_buf) { in spidev_message()
317 (uintptr_t) u_tmp->rx_buf, k_tmp->rx_buf, in spidev_message()
318 u_tmp->len)) { in spidev_message()
319 status = -EFAULT; in spidev_message()
341 return ERR_PTR(-ENOTTY); in spidev_get_ioc_message()
345 return ERR_PTR(-EINVAL); in spidev_get_ioc_message()
359 struct spi_device *spi; in spidev_ioctl() local
367 return -ENOTTY; in spidev_ioctl()
372 spidev = filp->private_data; in spidev_ioctl()
373 mutex_lock(&spidev->spi_lock); in spidev_ioctl()
374 spi = spi_dev_get(spidev->spi); in spidev_ioctl()
375 if (spi == NULL) { in spidev_ioctl()
376 mutex_unlock(&spidev->spi_lock); in spidev_ioctl()
377 return -ESHUTDOWN; in spidev_ioctl()
380 ctlr = spi->controller; in spidev_ioctl()
383 * - prevent I/O (from us) so calling spi_setup() is safe; in spidev_ioctl()
384 * - prevent concurrent SPI_IOC_WR_* from morphing in spidev_ioctl()
386 * - SPI_IOC_MESSAGE needs the buffer locked "normally". in spidev_ioctl()
388 mutex_lock(&spidev->buf_lock); in spidev_ioctl()
394 tmp = spi->mode & SPI_MODE_MASK; in spidev_ioctl()
396 if (ctlr->use_gpio_descriptors && spi_get_csgpiod(spi, 0)) in spidev_ioctl()
405 retval = put_user((spi->mode & SPI_LSB_FIRST) ? 1 : 0, in spidev_ioctl()
409 retval = put_user(spi->bits_per_word, (__u8 __user *)arg); in spidev_ioctl()
412 retval = put_user(spidev->speed_hz, (__u32 __user *)arg); in spidev_ioctl()
423 u32 save = spi->mode; in spidev_ioctl()
426 retval = -EINVAL; in spidev_ioctl()
430 if (ctlr->use_gpio_descriptors && spi_get_csgpiod(spi, 0)) in spidev_ioctl()
433 tmp |= spi->mode & ~SPI_MODE_MASK; in spidev_ioctl()
434 spi->mode = tmp & SPI_MODE_USER_MASK; in spidev_ioctl()
435 retval = spi_setup(spi); in spidev_ioctl()
437 spi->mode = save; in spidev_ioctl()
439 dev_dbg(&spi->dev, "spi mode %x\n", tmp); in spidev_ioctl()
445 u32 save = spi->mode; in spidev_ioctl()
448 spi->mode |= SPI_LSB_FIRST; in spidev_ioctl()
450 spi->mode &= ~SPI_LSB_FIRST; in spidev_ioctl()
451 retval = spi_setup(spi); in spidev_ioctl()
453 spi->mode = save; in spidev_ioctl()
455 dev_dbg(&spi->dev, "%csb first\n", in spidev_ioctl()
462 u8 save = spi->bits_per_word; in spidev_ioctl()
464 spi->bits_per_word = tmp; in spidev_ioctl()
465 retval = spi_setup(spi); in spidev_ioctl()
467 spi->bits_per_word = save; in spidev_ioctl()
469 dev_dbg(&spi->dev, "%d bits per word\n", tmp); in spidev_ioctl()
479 retval = -EINVAL; in spidev_ioctl()
483 save = spi->max_speed_hz; in spidev_ioctl()
485 spi->max_speed_hz = tmp; in spidev_ioctl()
486 retval = spi_setup(spi); in spidev_ioctl()
488 spidev->speed_hz = tmp; in spidev_ioctl()
489 dev_dbg(&spi->dev, "%d Hz (max)\n", spidev->speed_hz); in spidev_ioctl()
492 spi->max_speed_hz = save; in spidev_ioctl()
496 /* segmented and/or full-duplex I/O request */ in spidev_ioctl()
513 mutex_unlock(&spidev->buf_lock); in spidev_ioctl()
514 spi_dev_put(spi); in spidev_ioctl()
515 mutex_unlock(&spidev->spi_lock); in spidev_ioctl()
527 struct spi_device *spi; in spidev_compat_ioc_message() local
536 spidev = filp->private_data; in spidev_compat_ioc_message()
537 mutex_lock(&spidev->spi_lock); in spidev_compat_ioc_message()
538 spi = spi_dev_get(spidev->spi); in spidev_compat_ioc_message()
539 if (spi == NULL) { in spidev_compat_ioc_message()
540 mutex_unlock(&spidev->spi_lock); in spidev_compat_ioc_message()
541 return -ESHUTDOWN; in spidev_compat_ioc_message()
545 mutex_lock(&spidev->buf_lock); in spidev_compat_ioc_message()
567 mutex_unlock(&spidev->buf_lock); in spidev_compat_ioc_message()
568 spi_dev_put(spi); in spidev_compat_ioc_message()
569 mutex_unlock(&spidev->spi_lock); in spidev_compat_ioc_message()
590 int status = -ENXIO; in spidev_open()
595 if (iter->devt == inode->i_rdev) { in spidev_open()
607 if (!spidev->tx_buffer) { in spidev_open()
608 spidev->tx_buffer = kmalloc(bufsiz, GFP_KERNEL); in spidev_open()
609 if (!spidev->tx_buffer) { in spidev_open()
610 status = -ENOMEM; in spidev_open()
615 if (!spidev->rx_buffer) { in spidev_open()
616 spidev->rx_buffer = kmalloc(bufsiz, GFP_KERNEL); in spidev_open()
617 if (!spidev->rx_buffer) { in spidev_open()
618 status = -ENOMEM; in spidev_open()
623 spidev->users++; in spidev_open()
624 filp->private_data = spidev; in spidev_open()
631 kfree(spidev->tx_buffer); in spidev_open()
632 spidev->tx_buffer = NULL; in spidev_open()
644 spidev = filp->private_data; in spidev_release()
645 filp->private_data = NULL; in spidev_release()
647 mutex_lock(&spidev->spi_lock); in spidev_release()
649 dofree = (spidev->spi == NULL); in spidev_release()
650 mutex_unlock(&spidev->spi_lock); in spidev_release()
653 spidev->users--; in spidev_release()
654 if (!spidev->users) { in spidev_release()
656 kfree(spidev->tx_buffer); in spidev_release()
657 spidev->tx_buffer = NULL; in spidev_release()
659 kfree(spidev->rx_buffer); in spidev_release()
660 spidev->rx_buffer = NULL; in spidev_release()
665 spidev->speed_hz = spidev->spi->max_speed_hz; in spidev_release()
669 spi_target_abort(spidev->spi); in spidev_release()
690 /*-------------------------------------------------------------------------*/
702 * The spi device ids are expected to match the device names of the
706 { .name = /* cisco */ "spi-petra" },
707 { .name = /* dh */ "dhcom-board" },
708 { .name = /* elgin */ "jg10309-01" },
710 { .name = /* lwn */ "bk4" },
711 { .name = /* lwn */ "bk4-spi" },
713 { .name = /* micron */ "spi-authenta" },
721 MODULE_DEVICE_TABLE(spi, spidev_spi_ids);
733 return -EINVAL; in spidev_of_check()
737 { .compatible = "cisco,spi-petra", .data = &spidev_of_check },
738 { .compatible = "dh,dhcom-board", .data = &spidev_of_check },
739 { .compatible = "elgin,jg10309-01", .data = &spidev_of_check },
741 { .compatible = "lwn,bk4", .data = &spidev_of_check },
742 { .compatible = "lwn,bk4-spi", .data = &spidev_of_check },
744 { .compatible = "micron,spi-authenta", .data = &spidev_of_check },
754 /* Dummy SPI devices not to be used in production systems */
766 * a proper driver instead of poking directly to the SPI bus.
775 /*-------------------------------------------------------------------------*/
777 static int spidev_probe(struct spi_device *spi) in spidev_probe() argument
784 match = device_get_match_data(&spi->dev); in spidev_probe()
786 status = match(&spi->dev); in spidev_probe()
794 return -ENOMEM; in spidev_probe()
797 spidev->spi = spi; in spidev_probe()
798 mutex_init(&spidev->spi_lock); in spidev_probe()
799 mutex_init(&spidev->buf_lock); in spidev_probe()
801 INIT_LIST_HEAD(&spidev->device_entry); in spidev_probe()
811 spidev->devt = MKDEV(SPIDEV_MAJOR, minor); in spidev_probe()
812 dev = device_create(&spidev_class, &spi->dev, spidev->devt, in spidev_probe()
814 spi->controller->bus_num, spi_get_chipselect(spi, 0)); in spidev_probe()
817 dev_dbg(&spi->dev, "no minor number available!\n"); in spidev_probe()
818 status = -ENODEV; in spidev_probe()
822 list_add(&spidev->device_entry, &device_list); in spidev_probe()
826 spidev->speed_hz = spi->max_speed_hz; in spidev_probe()
829 spi_set_drvdata(spi, spidev); in spidev_probe()
836 static void spidev_remove(struct spi_device *spi) in spidev_remove() argument
838 struct spidev_data *spidev = spi_get_drvdata(spi); in spidev_remove()
843 mutex_lock(&spidev->spi_lock); in spidev_remove()
844 spidev->spi = NULL; in spidev_remove()
845 mutex_unlock(&spidev->spi_lock); in spidev_remove()
847 list_del(&spidev->device_entry); in spidev_remove()
848 device_destroy(&spidev_class, spidev->devt); in spidev_remove()
849 clear_bit(MINOR(spidev->devt), minors); in spidev_remove()
850 if (spidev->users == 0) in spidev_remove()
872 /*-------------------------------------------------------------------------*/
882 status = register_chrdev(SPIDEV_MAJOR, "spi", &spidev_fops); in spidev_init()
909 MODULE_AUTHOR("Andrea Paterniani, <a.paterniani@swapp-eng.it>");
910 MODULE_DESCRIPTION("User mode SPI device interface");
912 MODULE_ALIAS("spi:spidev");