.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * Simple synchronous userspace interface to SPI devices |
---|
3 | 4 | * |
---|
4 | 5 | * Copyright (C) 2006 SWAPP |
---|
5 | 6 | * Andrea Paterniani <a.paterniani@swapp-eng.it> |
---|
6 | 7 | * 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 | 8 | */ |
---|
18 | 9 | |
---|
19 | 10 | #include <linux/init.h> |
---|
.. | .. |
---|
71 | 62 | #define SPI_MODE_MASK (SPI_CPHA | SPI_CPOL | SPI_CS_HIGH \ |
---|
72 | 63 | | SPI_LSB_FIRST | SPI_3WIRE | SPI_LOOP \ |
---|
73 | 64 | | SPI_NO_CS | SPI_READY | SPI_TX_DUAL \ |
---|
74 | | - | SPI_TX_QUAD | SPI_RX_DUAL | SPI_RX_QUAD) |
---|
| 65 | + | SPI_TX_QUAD | SPI_TX_OCTAL | SPI_RX_DUAL \ |
---|
| 66 | + | SPI_RX_QUAD | SPI_RX_OCTAL) |
---|
75 | 67 | |
---|
76 | 68 | struct spidev_data { |
---|
77 | 69 | dev_t devt; |
---|
.. | .. |
---|
154 | 146 | spidev_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) |
---|
155 | 147 | { |
---|
156 | 148 | struct spidev_data *spidev; |
---|
157 | | - ssize_t status = 0; |
---|
| 149 | + ssize_t status; |
---|
158 | 150 | |
---|
159 | 151 | /* chipselect only toggles at start or end of operation */ |
---|
160 | 152 | if (count > bufsiz) |
---|
.. | .. |
---|
184 | 176 | size_t count, loff_t *f_pos) |
---|
185 | 177 | { |
---|
186 | 178 | struct spidev_data *spidev; |
---|
187 | | - ssize_t status = 0; |
---|
| 179 | + ssize_t status; |
---|
188 | 180 | unsigned long missing; |
---|
189 | 181 | |
---|
190 | 182 | /* chipselect only toggles at start or end of operation */ |
---|
.. | .. |
---|
279 | 271 | k_tmp->tx_nbits = u_tmp->tx_nbits; |
---|
280 | 272 | k_tmp->rx_nbits = u_tmp->rx_nbits; |
---|
281 | 273 | k_tmp->bits_per_word = u_tmp->bits_per_word; |
---|
282 | | - k_tmp->delay_usecs = u_tmp->delay_usecs; |
---|
| 274 | + k_tmp->delay.value = u_tmp->delay_usecs; |
---|
| 275 | + k_tmp->delay.unit = SPI_DELAY_UNIT_USECS; |
---|
283 | 276 | k_tmp->speed_hz = u_tmp->speed_hz; |
---|
| 277 | + k_tmp->word_delay.value = u_tmp->word_delay_usecs; |
---|
| 278 | + k_tmp->word_delay.unit = SPI_DELAY_UNIT_USECS; |
---|
284 | 279 | if (!k_tmp->speed_hz) |
---|
285 | 280 | k_tmp->speed_hz = spidev->speed_hz; |
---|
286 | 281 | #ifdef VERBOSE |
---|
287 | 282 | dev_dbg(&spidev->spi->dev, |
---|
288 | | - " xfer len %u %s%s%s%dbits %u usec %uHz\n", |
---|
289 | | - u_tmp->len, |
---|
290 | | - u_tmp->rx_buf ? "rx " : "", |
---|
291 | | - u_tmp->tx_buf ? "tx " : "", |
---|
292 | | - u_tmp->cs_change ? "cs " : "", |
---|
293 | | - u_tmp->bits_per_word ? : spidev->spi->bits_per_word, |
---|
294 | | - u_tmp->delay_usecs, |
---|
295 | | - u_tmp->speed_hz ? : spidev->spi->max_speed_hz); |
---|
| 283 | + " xfer len %u %s%s%s%dbits %u usec %u usec %uHz\n", |
---|
| 284 | + k_tmp->len, |
---|
| 285 | + k_tmp->rx_buf ? "rx " : "", |
---|
| 286 | + k_tmp->tx_buf ? "tx " : "", |
---|
| 287 | + k_tmp->cs_change ? "cs " : "", |
---|
| 288 | + k_tmp->bits_per_word ? : spidev->spi->bits_per_word, |
---|
| 289 | + k_tmp->delay.value, |
---|
| 290 | + k_tmp->word_delay.value, |
---|
| 291 | + k_tmp->speed_hz ? : spidev->spi->max_speed_hz); |
---|
296 | 292 | #endif |
---|
297 | 293 | spi_message_add_tail(k_tmp, &msg); |
---|
298 | 294 | } |
---|
.. | .. |
---|
380 | 376 | switch (cmd) { |
---|
381 | 377 | /* read requests */ |
---|
382 | 378 | case SPI_IOC_RD_MODE: |
---|
383 | | - retval = put_user(spi->mode & SPI_MODE_MASK, |
---|
384 | | - (__u8 __user *)arg); |
---|
385 | | - break; |
---|
386 | 379 | case SPI_IOC_RD_MODE32: |
---|
387 | | - retval = put_user(spi->mode & SPI_MODE_MASK, |
---|
388 | | - (__u32 __user *)arg); |
---|
| 380 | + tmp = spi->mode; |
---|
| 381 | + |
---|
| 382 | + { |
---|
| 383 | + struct spi_controller *ctlr = spi->controller; |
---|
| 384 | + |
---|
| 385 | + if (ctlr->use_gpio_descriptors && ctlr->cs_gpiods && |
---|
| 386 | + ctlr->cs_gpiods[spi->chip_select]) |
---|
| 387 | + tmp &= ~SPI_CS_HIGH; |
---|
| 388 | + } |
---|
| 389 | + |
---|
| 390 | + if (cmd == SPI_IOC_RD_MODE) |
---|
| 391 | + retval = put_user(tmp & SPI_MODE_MASK, |
---|
| 392 | + (__u8 __user *)arg); |
---|
| 393 | + else |
---|
| 394 | + retval = put_user(tmp & SPI_MODE_MASK, |
---|
| 395 | + (__u32 __user *)arg); |
---|
389 | 396 | break; |
---|
390 | 397 | case SPI_IOC_RD_LSB_FIRST: |
---|
391 | 398 | retval = put_user((spi->mode & SPI_LSB_FIRST) ? 1 : 0, |
---|
.. | .. |
---|
406 | 413 | else |
---|
407 | 414 | retval = get_user(tmp, (u32 __user *)arg); |
---|
408 | 415 | if (retval == 0) { |
---|
| 416 | + struct spi_controller *ctlr = spi->controller; |
---|
409 | 417 | u32 save = spi->mode; |
---|
410 | 418 | |
---|
411 | 419 | if (tmp & ~SPI_MODE_MASK) { |
---|
412 | 420 | retval = -EINVAL; |
---|
413 | 421 | break; |
---|
414 | 422 | } |
---|
| 423 | + |
---|
| 424 | + if (ctlr->use_gpio_descriptors && ctlr->cs_gpiods && |
---|
| 425 | + ctlr->cs_gpiods[spi->chip_select]) |
---|
| 426 | + tmp |= SPI_CS_HIGH; |
---|
415 | 427 | |
---|
416 | 428 | tmp |= spi->mode & ~SPI_MODE_MASK; |
---|
417 | 429 | spi->mode = (u16)tmp; |
---|
.. | .. |
---|
459 | 471 | |
---|
460 | 472 | spi->max_speed_hz = tmp; |
---|
461 | 473 | retval = spi_setup(spi); |
---|
462 | | - if (retval >= 0) |
---|
| 474 | + if (retval == 0) { |
---|
463 | 475 | spidev->speed_hz = tmp; |
---|
464 | | - else |
---|
465 | | - dev_dbg(&spi->dev, "%d Hz (max)\n", tmp); |
---|
| 476 | + dev_dbg(&spi->dev, "%d Hz (max)\n", |
---|
| 477 | + spidev->speed_hz); |
---|
| 478 | + } |
---|
466 | 479 | spi->max_speed_hz = save; |
---|
467 | 480 | } |
---|
468 | 481 | break; |
---|
.. | .. |
---|
579 | 592 | if (!spidev->tx_buffer) { |
---|
580 | 593 | spidev->tx_buffer = kmalloc(bufsiz, GFP_KERNEL); |
---|
581 | 594 | if (!spidev->tx_buffer) { |
---|
582 | | - dev_dbg(&spidev->spi->dev, "open/ENOMEM\n"); |
---|
583 | 595 | status = -ENOMEM; |
---|
584 | 596 | goto err_find_dev; |
---|
585 | 597 | } |
---|
.. | .. |
---|
588 | 600 | if (!spidev->rx_buffer) { |
---|
589 | 601 | spidev->rx_buffer = kmalloc(bufsiz, GFP_KERNEL); |
---|
590 | 602 | if (!spidev->rx_buffer) { |
---|
591 | | - dev_dbg(&spidev->spi->dev, "open/ENOMEM\n"); |
---|
592 | 603 | status = -ENOMEM; |
---|
593 | 604 | goto err_alloc_rx_buf; |
---|
594 | 605 | } |
---|
.. | .. |
---|
596 | 607 | |
---|
597 | 608 | spidev->users++; |
---|
598 | 609 | filp->private_data = spidev; |
---|
599 | | - nonseekable_open(inode, filp); |
---|
| 610 | + stream_open(inode, filp); |
---|
600 | 611 | |
---|
601 | 612 | mutex_unlock(&device_list_lock); |
---|
602 | 613 | return 0; |
---|
.. | .. |
---|
677 | 688 | { .compatible = "lineartechnology,ltc2488" }, |
---|
678 | 689 | { .compatible = "ge,achc" }, |
---|
679 | 690 | { .compatible = "semtech,sx1301" }, |
---|
| 691 | + { .compatible = "lwn,bk4" }, |
---|
| 692 | + { .compatible = "dh,dhcom-board" }, |
---|
| 693 | + { .compatible = "menlo,m53cpld" }, |
---|
680 | 694 | { .compatible = "rockchip,spidev" }, |
---|
681 | 695 | {}, |
---|
682 | 696 | }; |
---|