spi-oc-tiny.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * OpenCores tiny SPI master 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_master_get_devdata(sdev->master);
  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_CPOL | SPI_CPHA);
  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. #include <linux/of_gpio.h>
  164. static int tiny_spi_of_probe(struct platform_device *pdev)
  165. {
  166. struct tiny_spi *hw = platform_get_drvdata(pdev);
  167. struct device_node *np = pdev->dev.of_node;
  168. u32 val;
  169. if (!np)
  170. return 0;
  171. hw->bitbang.master->dev.of_node = pdev->dev.of_node;
  172. if (!of_property_read_u32(np, "clock-frequency", &val))
  173. hw->freq = val;
  174. if (!of_property_read_u32(np, "baud-width", &val))
  175. hw->baudwidth = val;
  176. return 0;
  177. }
  178. #else /* !CONFIG_OF */
  179. static int tiny_spi_of_probe(struct platform_device *pdev)
  180. {
  181. return 0;
  182. }
  183. #endif /* CONFIG_OF */
  184. static int tiny_spi_probe(struct platform_device *pdev)
  185. {
  186. struct tiny_spi_platform_data *platp = dev_get_platdata(&pdev->dev);
  187. struct tiny_spi *hw;
  188. struct spi_master *master;
  189. int err = -ENODEV;
  190. master = spi_alloc_master(&pdev->dev, sizeof(struct tiny_spi));
  191. if (!master)
  192. return err;
  193. /* setup the master state. */
  194. master->bus_num = pdev->id;
  195. master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
  196. master->setup = tiny_spi_setup;
  197. master->use_gpio_descriptors = true;
  198. hw = spi_master_get_devdata(master);
  199. platform_set_drvdata(pdev, hw);
  200. /* setup the state for the bitbang driver */
  201. hw->bitbang.master = master;
  202. hw->bitbang.setup_transfer = tiny_spi_setup_transfer;
  203. hw->bitbang.txrx_bufs = tiny_spi_txrx_bufs;
  204. /* find and map our resources */
  205. hw->base = devm_platform_ioremap_resource(pdev, 0);
  206. if (IS_ERR(hw->base)) {
  207. err = PTR_ERR(hw->base);
  208. goto exit;
  209. }
  210. /* irq is optional */
  211. hw->irq = platform_get_irq(pdev, 0);
  212. if (hw->irq >= 0) {
  213. init_completion(&hw->done);
  214. err = devm_request_irq(&pdev->dev, hw->irq, tiny_spi_irq, 0,
  215. pdev->name, hw);
  216. if (err)
  217. goto exit;
  218. }
  219. /* find platform data */
  220. if (platp) {
  221. hw->freq = platp->freq;
  222. hw->baudwidth = platp->baudwidth;
  223. } else {
  224. err = tiny_spi_of_probe(pdev);
  225. if (err)
  226. goto exit;
  227. }
  228. /* register our spi controller */
  229. err = spi_bitbang_start(&hw->bitbang);
  230. if (err)
  231. goto exit;
  232. dev_info(&pdev->dev, "base %p, irq %d\n", hw->base, hw->irq);
  233. return 0;
  234. exit:
  235. spi_master_put(master);
  236. return err;
  237. }
  238. static int tiny_spi_remove(struct platform_device *pdev)
  239. {
  240. struct tiny_spi *hw = platform_get_drvdata(pdev);
  241. struct spi_master *master = hw->bitbang.master;
  242. spi_bitbang_stop(&hw->bitbang);
  243. spi_master_put(master);
  244. return 0;
  245. }
  246. #ifdef CONFIG_OF
  247. static const struct of_device_id tiny_spi_match[] = {
  248. { .compatible = "opencores,tiny-spi-rtlsvn2", },
  249. {},
  250. };
  251. MODULE_DEVICE_TABLE(of, tiny_spi_match);
  252. #endif /* CONFIG_OF */
  253. static struct platform_driver tiny_spi_driver = {
  254. .probe = tiny_spi_probe,
  255. .remove = tiny_spi_remove,
  256. .driver = {
  257. .name = DRV_NAME,
  258. .pm = NULL,
  259. .of_match_table = of_match_ptr(tiny_spi_match),
  260. },
  261. };
  262. module_platform_driver(tiny_spi_driver);
  263. MODULE_DESCRIPTION("OpenCores tiny SPI driver");
  264. MODULE_AUTHOR("Thomas Chou <thomas@wytron.com.tw>");
  265. MODULE_LICENSE("GPL");
  266. MODULE_ALIAS("platform:" DRV_NAME);