spi-oc-tiny.c 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * OpenCores tiny SPI host driver
  4. *
  5. * https://opencores.org/project,tiny_spi
  6. *
  7. * Copyright (C) 2011 Thomas Chou <thomas@wytron.com.tw>
  8. *
  9. * Based on spi_s3c24xx.c, which is:
  10. * Copyright (c) 2006 Ben Dooks
  11. * Copyright (c) 2006 Simtec Electronics
  12. * Ben Dooks <ben@simtec.co.uk>
  13. */
  14. #include <linux/interrupt.h>
  15. #include <linux/errno.h>
  16. #include <linux/module.h>
  17. #include <linux/platform_device.h>
  18. #include <linux/spi/spi.h>
  19. #include <linux/spi/spi_bitbang.h>
  20. #include <linux/spi/spi_oc_tiny.h>
  21. #include <linux/io.h>
  22. #include <linux/of.h>
  23. #define DRV_NAME "spi_oc_tiny"
  24. #define TINY_SPI_RXDATA 0
  25. #define TINY_SPI_TXDATA 4
  26. #define TINY_SPI_STATUS 8
  27. #define TINY_SPI_CONTROL 12
  28. #define TINY_SPI_BAUD 16
  29. #define TINY_SPI_STATUS_TXE 0x1
  30. #define TINY_SPI_STATUS_TXR 0x2
  31. struct tiny_spi {
  32. /* bitbang has to be first */
  33. struct spi_bitbang bitbang;
  34. struct completion done;
  35. void __iomem *base;
  36. int irq;
  37. unsigned int freq;
  38. unsigned int baudwidth;
  39. unsigned int baud;
  40. unsigned int speed_hz;
  41. unsigned int mode;
  42. unsigned int len;
  43. unsigned int txc, rxc;
  44. const u8 *txp;
  45. u8 *rxp;
  46. };
  47. static inline struct tiny_spi *tiny_spi_to_hw(struct spi_device *sdev)
  48. {
  49. return spi_controller_get_devdata(sdev->controller);
  50. }
  51. static unsigned int tiny_spi_baud(struct spi_device *spi, unsigned int hz)
  52. {
  53. struct tiny_spi *hw = tiny_spi_to_hw(spi);
  54. return min(DIV_ROUND_UP(hw->freq, hz * 2), (1U << hw->baudwidth)) - 1;
  55. }
  56. static int tiny_spi_setup_transfer(struct spi_device *spi,
  57. struct spi_transfer *t)
  58. {
  59. struct tiny_spi *hw = tiny_spi_to_hw(spi);
  60. unsigned int baud = hw->baud;
  61. if (t) {
  62. if (t->speed_hz && t->speed_hz != hw->speed_hz)
  63. baud = tiny_spi_baud(spi, t->speed_hz);
  64. }
  65. writel(baud, hw->base + TINY_SPI_BAUD);
  66. writel(hw->mode, hw->base + TINY_SPI_CONTROL);
  67. return 0;
  68. }
  69. static int tiny_spi_setup(struct spi_device *spi)
  70. {
  71. struct tiny_spi *hw = tiny_spi_to_hw(spi);
  72. if (spi->max_speed_hz != hw->speed_hz) {
  73. hw->speed_hz = spi->max_speed_hz;
  74. hw->baud = tiny_spi_baud(spi, hw->speed_hz);
  75. }
  76. hw->mode = spi->mode & SPI_MODE_X_MASK;
  77. return 0;
  78. }
  79. static inline void tiny_spi_wait_txr(struct tiny_spi *hw)
  80. {
  81. while (!(readb(hw->base + TINY_SPI_STATUS) &
  82. TINY_SPI_STATUS_TXR))
  83. cpu_relax();
  84. }
  85. static inline void tiny_spi_wait_txe(struct tiny_spi *hw)
  86. {
  87. while (!(readb(hw->base + TINY_SPI_STATUS) &
  88. TINY_SPI_STATUS_TXE))
  89. cpu_relax();
  90. }
  91. static int tiny_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
  92. {
  93. struct tiny_spi *hw = tiny_spi_to_hw(spi);
  94. const u8 *txp = t->tx_buf;
  95. u8 *rxp = t->rx_buf;
  96. unsigned int i;
  97. if (hw->irq >= 0) {
  98. /* use interrupt driven data transfer */
  99. hw->len = t->len;
  100. hw->txp = t->tx_buf;
  101. hw->rxp = t->rx_buf;
  102. hw->txc = 0;
  103. hw->rxc = 0;
  104. /* send the first byte */
  105. if (t->len > 1) {
  106. writeb(hw->txp ? *hw->txp++ : 0,
  107. hw->base + TINY_SPI_TXDATA);
  108. hw->txc++;
  109. writeb(hw->txp ? *hw->txp++ : 0,
  110. hw->base + TINY_SPI_TXDATA);
  111. hw->txc++;
  112. writeb(TINY_SPI_STATUS_TXR, hw->base + TINY_SPI_STATUS);
  113. } else {
  114. writeb(hw->txp ? *hw->txp++ : 0,
  115. hw->base + TINY_SPI_TXDATA);
  116. hw->txc++;
  117. writeb(TINY_SPI_STATUS_TXE, hw->base + TINY_SPI_STATUS);
  118. }
  119. wait_for_completion(&hw->done);
  120. } else {
  121. /* we need to tighten the transfer loop */
  122. writeb(txp ? *txp++ : 0, hw->base + TINY_SPI_TXDATA);
  123. for (i = 1; i < t->len; i++) {
  124. writeb(txp ? *txp++ : 0, hw->base + TINY_SPI_TXDATA);
  125. if (rxp || (i != t->len - 1))
  126. tiny_spi_wait_txr(hw);
  127. if (rxp)
  128. *rxp++ = readb(hw->base + TINY_SPI_TXDATA);
  129. }
  130. tiny_spi_wait_txe(hw);
  131. if (rxp)
  132. *rxp++ = readb(hw->base + TINY_SPI_RXDATA);
  133. }
  134. return t->len;
  135. }
  136. static irqreturn_t tiny_spi_irq(int irq, void *dev)
  137. {
  138. struct tiny_spi *hw = dev;
  139. writeb(0, hw->base + TINY_SPI_STATUS);
  140. if (hw->rxc + 1 == hw->len) {
  141. if (hw->rxp)
  142. *hw->rxp++ = readb(hw->base + TINY_SPI_RXDATA);
  143. hw->rxc++;
  144. complete(&hw->done);
  145. } else {
  146. if (hw->rxp)
  147. *hw->rxp++ = readb(hw->base + TINY_SPI_TXDATA);
  148. hw->rxc++;
  149. if (hw->txc < hw->len) {
  150. writeb(hw->txp ? *hw->txp++ : 0,
  151. hw->base + TINY_SPI_TXDATA);
  152. hw->txc++;
  153. writeb(TINY_SPI_STATUS_TXR,
  154. hw->base + TINY_SPI_STATUS);
  155. } else {
  156. writeb(TINY_SPI_STATUS_TXE,
  157. hw->base + TINY_SPI_STATUS);
  158. }
  159. }
  160. return IRQ_HANDLED;
  161. }
  162. #ifdef CONFIG_OF
  163. static int tiny_spi_of_probe(struct platform_device *pdev)
  164. {
  165. struct tiny_spi *hw = platform_get_drvdata(pdev);
  166. struct device_node *np = pdev->dev.of_node;
  167. u32 val;
  168. if (!np)
  169. return 0;
  170. hw->bitbang.ctlr->dev.of_node = pdev->dev.of_node;
  171. if (!of_property_read_u32(np, "clock-frequency", &val))
  172. hw->freq = val;
  173. if (!of_property_read_u32(np, "baud-width", &val))
  174. hw->baudwidth = val;
  175. return 0;
  176. }
  177. #else /* !CONFIG_OF */
  178. static int tiny_spi_of_probe(struct platform_device *pdev)
  179. {
  180. return 0;
  181. }
  182. #endif /* CONFIG_OF */
  183. static int tiny_spi_probe(struct platform_device *pdev)
  184. {
  185. struct tiny_spi_platform_data *platp = dev_get_platdata(&pdev->dev);
  186. struct tiny_spi *hw;
  187. struct spi_controller *host;
  188. int err = -ENODEV;
  189. host = spi_alloc_host(&pdev->dev, sizeof(struct tiny_spi));
  190. if (!host)
  191. return err;
  192. /* setup the host state. */
  193. host->bus_num = pdev->id;
  194. host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
  195. host->setup = tiny_spi_setup;
  196. host->use_gpio_descriptors = true;
  197. hw = spi_controller_get_devdata(host);
  198. platform_set_drvdata(pdev, hw);
  199. /* setup the state for the bitbang driver */
  200. hw->bitbang.ctlr = host;
  201. hw->bitbang.setup_transfer = tiny_spi_setup_transfer;
  202. hw->bitbang.txrx_bufs = tiny_spi_txrx_bufs;
  203. /* find and map our resources */
  204. hw->base = devm_platform_ioremap_resource(pdev, 0);
  205. if (IS_ERR(hw->base)) {
  206. err = PTR_ERR(hw->base);
  207. goto exit;
  208. }
  209. /* irq is optional */
  210. hw->irq = platform_get_irq(pdev, 0);
  211. if (hw->irq >= 0) {
  212. init_completion(&hw->done);
  213. err = devm_request_irq(&pdev->dev, hw->irq, tiny_spi_irq, 0,
  214. pdev->name, hw);
  215. if (err)
  216. goto exit;
  217. }
  218. /* find platform data */
  219. if (platp) {
  220. hw->freq = platp->freq;
  221. hw->baudwidth = platp->baudwidth;
  222. } else {
  223. err = tiny_spi_of_probe(pdev);
  224. if (err)
  225. goto exit;
  226. }
  227. /* register our spi controller */
  228. err = spi_bitbang_start(&hw->bitbang);
  229. if (err)
  230. goto exit;
  231. dev_info(&pdev->dev, "base %p, irq %d\n", hw->base, hw->irq);
  232. return 0;
  233. exit:
  234. spi_controller_put(host);
  235. return err;
  236. }
  237. static void tiny_spi_remove(struct platform_device *pdev)
  238. {
  239. struct tiny_spi *hw = platform_get_drvdata(pdev);
  240. struct spi_controller *host = hw->bitbang.ctlr;
  241. spi_bitbang_stop(&hw->bitbang);
  242. spi_controller_put(host);
  243. }
  244. #ifdef CONFIG_OF
  245. static const struct of_device_id tiny_spi_match[] = {
  246. { .compatible = "opencores,tiny-spi-rtlsvn2", },
  247. {},
  248. };
  249. MODULE_DEVICE_TABLE(of, tiny_spi_match);
  250. #endif /* CONFIG_OF */
  251. static struct platform_driver tiny_spi_driver = {
  252. .probe = tiny_spi_probe,
  253. .remove_new = tiny_spi_remove,
  254. .driver = {
  255. .name = DRV_NAME,
  256. .pm = NULL,
  257. .of_match_table = of_match_ptr(tiny_spi_match),
  258. },
  259. };
  260. module_platform_driver(tiny_spi_driver);
  261. MODULE_DESCRIPTION("OpenCores tiny SPI driver");
  262. MODULE_AUTHOR("Thomas Chou <thomas@wytron.com.tw>");
  263. MODULE_LICENSE("GPL");
  264. MODULE_ALIAS("platform:" DRV_NAME);