0005-spi-Add-support-for-the-Airoha-EN7523-SoC-SPI-contro.patch 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. --- a/drivers/spi/Kconfig
  2. +++ b/drivers/spi/Kconfig
  3. @@ -307,6 +307,12 @@ config SPI_DLN2
  4. This driver can also be built as a module. If so, the module
  5. will be called spi-dln2.
  6. +config SPI_AIROHA_EN7523
  7. + bool "Airoha EN7523 SPI controller support"
  8. + depends on ARCH_AIROHA
  9. + help
  10. + This enables SPI controller support for the Airoha EN7523 SoC.
  11. +
  12. config SPI_EP93XX
  13. tristate "Cirrus Logic EP93xx SPI controller"
  14. depends on ARCH_EP93XX || COMPILE_TEST
  15. --- a/drivers/spi/Makefile
  16. +++ b/drivers/spi/Makefile
  17. @@ -45,6 +45,7 @@ obj-$(CONFIG_SPI_DW_BT1) += spi-dw-bt1.
  18. obj-$(CONFIG_SPI_DW_MMIO) += spi-dw-mmio.o
  19. obj-$(CONFIG_SPI_DW_PCI) += spi-dw-pci.o
  20. obj-$(CONFIG_SPI_EP93XX) += spi-ep93xx.o
  21. +obj-$(CONFIG_SPI_AIROHA_EN7523) += spi-en7523.o
  22. obj-$(CONFIG_SPI_FALCON) += spi-falcon.o
  23. obj-$(CONFIG_SPI_FSI) += spi-fsi.o
  24. obj-$(CONFIG_SPI_FSL_CPM) += spi-fsl-cpm.o
  25. --- /dev/null
  26. +++ b/drivers/spi/spi-en7523.c
  27. @@ -0,0 +1,313 @@
  28. +// SPDX-License-Identifier: GPL-2.0
  29. +
  30. +#include <linux/module.h>
  31. +#include <linux/platform_device.h>
  32. +#include <linux/mod_devicetable.h>
  33. +#include <linux/spi/spi.h>
  34. +
  35. +
  36. +#define ENSPI_READ_IDLE_EN 0x0004
  37. +#define ENSPI_MTX_MODE_TOG 0x0014
  38. +#define ENSPI_RDCTL_FSM 0x0018
  39. +#define ENSPI_MANUAL_EN 0x0020
  40. +#define ENSPI_MANUAL_OPFIFO_EMPTY 0x0024
  41. +#define ENSPI_MANUAL_OPFIFO_WDATA 0x0028
  42. +#define ENSPI_MANUAL_OPFIFO_FULL 0x002C
  43. +#define ENSPI_MANUAL_OPFIFO_WR 0x0030
  44. +#define ENSPI_MANUAL_DFIFO_FULL 0x0034
  45. +#define ENSPI_MANUAL_DFIFO_WDATA 0x0038
  46. +#define ENSPI_MANUAL_DFIFO_EMPTY 0x003C
  47. +#define ENSPI_MANUAL_DFIFO_RD 0x0040
  48. +#define ENSPI_MANUAL_DFIFO_RDATA 0x0044
  49. +#define ENSPI_IER 0x0090
  50. +#define ENSPI_NFI2SPI_EN 0x0130
  51. +
  52. +// TODO not in spi block
  53. +#define ENSPI_CLOCK_DIVIDER ((void __iomem *)0x1fa201c4)
  54. +
  55. +#define OP_CSH 0x00
  56. +#define OP_CSL 0x01
  57. +#define OP_CK 0x02
  58. +#define OP_OUTS 0x08
  59. +#define OP_OUTD 0x09
  60. +#define OP_OUTQ 0x0A
  61. +#define OP_INS 0x0C
  62. +#define OP_INS0 0x0D
  63. +#define OP_IND 0x0E
  64. +#define OP_INQ 0x0F
  65. +#define OP_OS2IS 0x10
  66. +#define OP_OS2ID 0x11
  67. +#define OP_OS2IQ 0x12
  68. +#define OP_OD2IS 0x13
  69. +#define OP_OD2ID 0x14
  70. +#define OP_OD2IQ 0x15
  71. +#define OP_OQ2IS 0x16
  72. +#define OP_OQ2ID 0x17
  73. +#define OP_OQ2IQ 0x18
  74. +#define OP_OSNIS 0x19
  75. +#define OP_ODNID 0x1A
  76. +
  77. +#define MATRIX_MODE_AUTO 1
  78. +#define CONF_MTX_MODE_AUTO 0
  79. +#define MANUALEN_AUTO 0
  80. +#define MATRIX_MODE_MANUAL 0
  81. +#define CONF_MTX_MODE_MANUAL 9
  82. +#define MANUALEN_MANUAL 1
  83. +
  84. +#define _ENSPI_MAX_XFER 0x1ff
  85. +
  86. +#define REG(x) (iobase + x)
  87. +
  88. +
  89. +static void __iomem *iobase;
  90. +
  91. +
  92. +static void opfifo_write(u32 cmd, u32 len)
  93. +{
  94. + u32 tmp = ((cmd & 0x1f) << 9) | (len & 0x1ff);
  95. +
  96. + writel(tmp, REG(ENSPI_MANUAL_OPFIFO_WDATA));
  97. +
  98. + /* Wait for room in OPFIFO */
  99. + while (readl(REG(ENSPI_MANUAL_OPFIFO_FULL)))
  100. + ;
  101. +
  102. + /* Shift command into OPFIFO */
  103. + writel(1, REG(ENSPI_MANUAL_OPFIFO_WR));
  104. +
  105. + /* Wait for command to finish */
  106. + while (!readl(REG(ENSPI_MANUAL_OPFIFO_EMPTY)))
  107. + ;
  108. +}
  109. +
  110. +static void set_cs(int state)
  111. +{
  112. + if (state)
  113. + opfifo_write(OP_CSH, 1);
  114. + else
  115. + opfifo_write(OP_CSL, 1);
  116. +}
  117. +
  118. +static void manual_begin_cmd(void)
  119. +{
  120. + /* Disable read idle state */
  121. + writel(0, REG(ENSPI_READ_IDLE_EN));
  122. +
  123. + /* Wait for FSM to reach idle state */
  124. + while (readl(REG(ENSPI_RDCTL_FSM)))
  125. + ;
  126. +
  127. + /* Set SPI core to manual mode */
  128. + writel(CONF_MTX_MODE_MANUAL, REG(ENSPI_MTX_MODE_TOG));
  129. + writel(MANUALEN_MANUAL, REG(ENSPI_MANUAL_EN));
  130. +}
  131. +
  132. +static void manual_end_cmd(void)
  133. +{
  134. + /* Set SPI core to auto mode */
  135. + writel(CONF_MTX_MODE_AUTO, REG(ENSPI_MTX_MODE_TOG));
  136. + writel(MANUALEN_AUTO, REG(ENSPI_MANUAL_EN));
  137. +
  138. + /* Enable read idle state */
  139. + writel(1, REG(ENSPI_READ_IDLE_EN));
  140. +}
  141. +
  142. +static void dfifo_read(u8 *buf, int len)
  143. +{
  144. + int i;
  145. +
  146. + for (i = 0; i < len; i++) {
  147. + /* Wait for requested data to show up in DFIFO */
  148. + while (readl(REG(ENSPI_MANUAL_DFIFO_EMPTY)))
  149. + ;
  150. + buf[i] = readl(REG(ENSPI_MANUAL_DFIFO_RDATA));
  151. + /* Queue up next byte */
  152. + writel(1, REG(ENSPI_MANUAL_DFIFO_RD));
  153. + }
  154. +}
  155. +
  156. +static void dfifo_write(const u8 *buf, int len)
  157. +{
  158. + int i;
  159. +
  160. + for (i = 0; i < len; i++) {
  161. + /* Wait for room in DFIFO */
  162. + while (readl(REG(ENSPI_MANUAL_DFIFO_FULL)))
  163. + ;
  164. + writel(buf[i], REG(ENSPI_MANUAL_DFIFO_WDATA));
  165. + }
  166. +}
  167. +
  168. +#if 0
  169. +static void set_spi_clock_speed(int freq_mhz)
  170. +{
  171. + u32 tmp, val;
  172. +
  173. + tmp = readl(ENSPI_CLOCK_DIVIDER);
  174. + tmp &= 0xffff0000;
  175. + writel(tmp, ENSPI_CLOCK_DIVIDER);
  176. +
  177. + val = (400 / (freq_mhz * 2));
  178. + tmp |= (val << 8) | 1;
  179. + writel(tmp, ENSPI_CLOCK_DIVIDER);
  180. +}
  181. +#endif
  182. +
  183. +static void init_hw(void)
  184. +{
  185. + /* Disable manual/auto mode clash interrupt */
  186. + writel(0, REG(ENSPI_IER));
  187. +
  188. + // TODO via clk framework
  189. + // set_spi_clock_speed(50);
  190. +
  191. + /* Disable DMA */
  192. + writel(0, REG(ENSPI_NFI2SPI_EN));
  193. +}
  194. +
  195. +static int xfer_read(struct spi_transfer *xfer)
  196. +{
  197. + int opcode;
  198. + uint8_t *buf = xfer->rx_buf;
  199. +
  200. + switch (xfer->rx_nbits) {
  201. + case SPI_NBITS_SINGLE:
  202. + opcode = OP_INS;
  203. + break;
  204. + case SPI_NBITS_DUAL:
  205. + opcode = OP_IND;
  206. + break;
  207. + case SPI_NBITS_QUAD:
  208. + opcode = OP_INQ;
  209. + break;
  210. + }
  211. +
  212. + opfifo_write(opcode, xfer->len);
  213. + dfifo_read(buf, xfer->len);
  214. +
  215. + return xfer->len;
  216. +}
  217. +
  218. +static int xfer_write(struct spi_transfer *xfer, int next_xfer_is_rx)
  219. +{
  220. + int opcode;
  221. + const uint8_t *buf = xfer->tx_buf;
  222. +
  223. + if (next_xfer_is_rx) {
  224. + /* need to use Ox2Ix opcode to set the core to input afterwards */
  225. + switch (xfer->tx_nbits) {
  226. + case SPI_NBITS_SINGLE:
  227. + opcode = OP_OS2IS;
  228. + break;
  229. + case SPI_NBITS_DUAL:
  230. + opcode = OP_OS2ID;
  231. + break;
  232. + case SPI_NBITS_QUAD:
  233. + opcode = OP_OS2IQ;
  234. + break;
  235. + }
  236. + } else {
  237. + switch (xfer->tx_nbits) {
  238. + case SPI_NBITS_SINGLE:
  239. + opcode = OP_OUTS;
  240. + break;
  241. + case SPI_NBITS_DUAL:
  242. + opcode = OP_OUTD;
  243. + break;
  244. + case SPI_NBITS_QUAD:
  245. + opcode = OP_OUTQ;
  246. + break;
  247. + }
  248. + }
  249. +
  250. + opfifo_write(opcode, xfer->len);
  251. + dfifo_write(buf, xfer->len);
  252. +
  253. + return xfer->len;
  254. +}
  255. +
  256. +size_t max_transfer_size(struct spi_device *spi)
  257. +{
  258. + return _ENSPI_MAX_XFER;
  259. +}
  260. +
  261. +int transfer_one_message(struct spi_controller *ctrl, struct spi_message *msg)
  262. +{
  263. + struct spi_transfer *xfer;
  264. + int next_xfer_is_rx = 0;
  265. +
  266. + manual_begin_cmd();
  267. + set_cs(0);
  268. + list_for_each_entry(xfer, &msg->transfers, transfer_list) {
  269. + if (xfer->tx_buf) {
  270. + if (!list_is_last(&xfer->transfer_list, &msg->transfers)
  271. + && list_next_entry(xfer, transfer_list)->rx_buf != NULL)
  272. + next_xfer_is_rx = 1;
  273. + else
  274. + next_xfer_is_rx = 0;
  275. + msg->actual_length += xfer_write(xfer, next_xfer_is_rx);
  276. + } else if (xfer->rx_buf) {
  277. + msg->actual_length += xfer_read(xfer);
  278. + }
  279. + }
  280. + set_cs(1);
  281. + manual_end_cmd();
  282. +
  283. + msg->status = 0;
  284. + spi_finalize_current_message(ctrl);
  285. +
  286. + return 0;
  287. +}
  288. +
  289. +static int spi_probe(struct platform_device *pdev)
  290. +{
  291. + struct spi_controller *ctrl;
  292. + int err;
  293. +
  294. + ctrl = devm_spi_alloc_master(&pdev->dev, 0);
  295. + if (!ctrl) {
  296. + dev_err(&pdev->dev, "Error allocating SPI controller\n");
  297. + return -ENOMEM;
  298. + }
  299. +
  300. + iobase = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
  301. + if (IS_ERR(iobase)) {
  302. + dev_err(&pdev->dev, "Could not map SPI register address");
  303. + return -ENOMEM;
  304. + }
  305. +
  306. + init_hw();
  307. +
  308. + ctrl->dev.of_node = pdev->dev.of_node;
  309. + ctrl->flags = SPI_CONTROLLER_HALF_DUPLEX;
  310. + ctrl->mode_bits = SPI_RX_DUAL | SPI_TX_DUAL;
  311. + ctrl->max_transfer_size = max_transfer_size;
  312. + ctrl->transfer_one_message = transfer_one_message;
  313. + err = devm_spi_register_controller(&pdev->dev, ctrl);
  314. + if (err) {
  315. + dev_err(&pdev->dev, "Could not register SPI controller\n");
  316. + return -ENODEV;
  317. + }
  318. +
  319. + return 0;
  320. +}
  321. +
  322. +static const struct of_device_id spi_of_ids[] = {
  323. + { .compatible = "airoha,en7523-spi" },
  324. + { /* sentinel */ }
  325. +};
  326. +MODULE_DEVICE_TABLE(of, spi_of_ids);
  327. +
  328. +static struct platform_driver spi_driver = {
  329. + .probe = spi_probe,
  330. + .driver = {
  331. + .name = "airoha-en7523-spi",
  332. + .of_match_table = spi_of_ids,
  333. + },
  334. +};
  335. +
  336. +module_platform_driver(spi_driver);
  337. +
  338. +MODULE_LICENSE("GPL v2");
  339. +MODULE_AUTHOR("Bert Vermeulen <[email protected]>");
  340. +MODULE_DESCRIPTION("Airoha EN7523 SPI driver");