spi-axi-spi-engine.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * SPI-Engine SPI controller driver
  4. * Copyright 2015 Analog Devices Inc.
  5. * Author: Lars-Peter Clausen <[email protected]>
  6. */
  7. #include <linux/clk.h>
  8. #include <linux/interrupt.h>
  9. #include <linux/io.h>
  10. #include <linux/of.h>
  11. #include <linux/module.h>
  12. #include <linux/platform_device.h>
  13. #include <linux/spi/spi.h>
  14. #define SPI_ENGINE_VERSION_MAJOR(x) ((x >> 16) & 0xff)
  15. #define SPI_ENGINE_VERSION_MINOR(x) ((x >> 8) & 0xff)
  16. #define SPI_ENGINE_VERSION_PATCH(x) (x & 0xff)
  17. #define SPI_ENGINE_REG_VERSION 0x00
  18. #define SPI_ENGINE_REG_RESET 0x40
  19. #define SPI_ENGINE_REG_INT_ENABLE 0x80
  20. #define SPI_ENGINE_REG_INT_PENDING 0x84
  21. #define SPI_ENGINE_REG_INT_SOURCE 0x88
  22. #define SPI_ENGINE_REG_SYNC_ID 0xc0
  23. #define SPI_ENGINE_REG_CMD_FIFO_ROOM 0xd0
  24. #define SPI_ENGINE_REG_SDO_FIFO_ROOM 0xd4
  25. #define SPI_ENGINE_REG_SDI_FIFO_LEVEL 0xd8
  26. #define SPI_ENGINE_REG_CMD_FIFO 0xe0
  27. #define SPI_ENGINE_REG_SDO_DATA_FIFO 0xe4
  28. #define SPI_ENGINE_REG_SDI_DATA_FIFO 0xe8
  29. #define SPI_ENGINE_REG_SDI_DATA_FIFO_PEEK 0xec
  30. #define SPI_ENGINE_INT_CMD_ALMOST_EMPTY BIT(0)
  31. #define SPI_ENGINE_INT_SDO_ALMOST_EMPTY BIT(1)
  32. #define SPI_ENGINE_INT_SDI_ALMOST_FULL BIT(2)
  33. #define SPI_ENGINE_INT_SYNC BIT(3)
  34. #define SPI_ENGINE_CONFIG_CPHA BIT(0)
  35. #define SPI_ENGINE_CONFIG_CPOL BIT(1)
  36. #define SPI_ENGINE_CONFIG_3WIRE BIT(2)
  37. #define SPI_ENGINE_INST_TRANSFER 0x0
  38. #define SPI_ENGINE_INST_ASSERT 0x1
  39. #define SPI_ENGINE_INST_WRITE 0x2
  40. #define SPI_ENGINE_INST_MISC 0x3
  41. #define SPI_ENGINE_CMD_REG_CLK_DIV 0x0
  42. #define SPI_ENGINE_CMD_REG_CONFIG 0x1
  43. #define SPI_ENGINE_MISC_SYNC 0x0
  44. #define SPI_ENGINE_MISC_SLEEP 0x1
  45. #define SPI_ENGINE_TRANSFER_WRITE 0x1
  46. #define SPI_ENGINE_TRANSFER_READ 0x2
  47. #define SPI_ENGINE_CMD(inst, arg1, arg2) \
  48. (((inst) << 12) | ((arg1) << 8) | (arg2))
  49. #define SPI_ENGINE_CMD_TRANSFER(flags, n) \
  50. SPI_ENGINE_CMD(SPI_ENGINE_INST_TRANSFER, (flags), (n))
  51. #define SPI_ENGINE_CMD_ASSERT(delay, cs) \
  52. SPI_ENGINE_CMD(SPI_ENGINE_INST_ASSERT, (delay), (cs))
  53. #define SPI_ENGINE_CMD_WRITE(reg, val) \
  54. SPI_ENGINE_CMD(SPI_ENGINE_INST_WRITE, (reg), (val))
  55. #define SPI_ENGINE_CMD_SLEEP(delay) \
  56. SPI_ENGINE_CMD(SPI_ENGINE_INST_MISC, SPI_ENGINE_MISC_SLEEP, (delay))
  57. #define SPI_ENGINE_CMD_SYNC(id) \
  58. SPI_ENGINE_CMD(SPI_ENGINE_INST_MISC, SPI_ENGINE_MISC_SYNC, (id))
  59. struct spi_engine_program {
  60. unsigned int length;
  61. uint16_t instructions[];
  62. };
  63. struct spi_engine {
  64. struct clk *clk;
  65. struct clk *ref_clk;
  66. spinlock_t lock;
  67. void __iomem *base;
  68. struct spi_message *msg;
  69. struct spi_engine_program *p;
  70. unsigned cmd_length;
  71. const uint16_t *cmd_buf;
  72. struct spi_transfer *tx_xfer;
  73. unsigned int tx_length;
  74. const uint8_t *tx_buf;
  75. struct spi_transfer *rx_xfer;
  76. unsigned int rx_length;
  77. uint8_t *rx_buf;
  78. unsigned int sync_id;
  79. unsigned int completed_id;
  80. unsigned int int_enable;
  81. };
  82. static void spi_engine_program_add_cmd(struct spi_engine_program *p,
  83. bool dry, uint16_t cmd)
  84. {
  85. if (!dry)
  86. p->instructions[p->length] = cmd;
  87. p->length++;
  88. }
  89. static unsigned int spi_engine_get_config(struct spi_device *spi)
  90. {
  91. unsigned int config = 0;
  92. if (spi->mode & SPI_CPOL)
  93. config |= SPI_ENGINE_CONFIG_CPOL;
  94. if (spi->mode & SPI_CPHA)
  95. config |= SPI_ENGINE_CONFIG_CPHA;
  96. if (spi->mode & SPI_3WIRE)
  97. config |= SPI_ENGINE_CONFIG_3WIRE;
  98. return config;
  99. }
  100. static unsigned int spi_engine_get_clk_div(struct spi_engine *spi_engine,
  101. struct spi_device *spi, struct spi_transfer *xfer)
  102. {
  103. unsigned int clk_div;
  104. clk_div = DIV_ROUND_UP(clk_get_rate(spi_engine->ref_clk),
  105. xfer->speed_hz * 2);
  106. if (clk_div > 255)
  107. clk_div = 255;
  108. else if (clk_div > 0)
  109. clk_div -= 1;
  110. return clk_div;
  111. }
  112. static void spi_engine_gen_xfer(struct spi_engine_program *p, bool dry,
  113. struct spi_transfer *xfer)
  114. {
  115. unsigned int len = xfer->len;
  116. while (len) {
  117. unsigned int n = min(len, 256U);
  118. unsigned int flags = 0;
  119. if (xfer->tx_buf)
  120. flags |= SPI_ENGINE_TRANSFER_WRITE;
  121. if (xfer->rx_buf)
  122. flags |= SPI_ENGINE_TRANSFER_READ;
  123. spi_engine_program_add_cmd(p, dry,
  124. SPI_ENGINE_CMD_TRANSFER(flags, n - 1));
  125. len -= n;
  126. }
  127. }
  128. static void spi_engine_gen_sleep(struct spi_engine_program *p, bool dry,
  129. struct spi_engine *spi_engine, unsigned int clk_div,
  130. struct spi_transfer *xfer)
  131. {
  132. unsigned int spi_clk = clk_get_rate(spi_engine->ref_clk);
  133. unsigned int t;
  134. int delay;
  135. delay = spi_delay_to_ns(&xfer->delay, xfer);
  136. if (delay < 0)
  137. return;
  138. delay /= 1000;
  139. if (delay == 0)
  140. return;
  141. t = DIV_ROUND_UP(delay * spi_clk, (clk_div + 1) * 2);
  142. while (t) {
  143. unsigned int n = min(t, 256U);
  144. spi_engine_program_add_cmd(p, dry, SPI_ENGINE_CMD_SLEEP(n - 1));
  145. t -= n;
  146. }
  147. }
  148. static void spi_engine_gen_cs(struct spi_engine_program *p, bool dry,
  149. struct spi_device *spi, bool assert)
  150. {
  151. unsigned int mask = 0xff;
  152. if (assert)
  153. mask ^= BIT(spi->chip_select);
  154. spi_engine_program_add_cmd(p, dry, SPI_ENGINE_CMD_ASSERT(1, mask));
  155. }
  156. static int spi_engine_compile_message(struct spi_engine *spi_engine,
  157. struct spi_message *msg, bool dry, struct spi_engine_program *p)
  158. {
  159. struct spi_device *spi = msg->spi;
  160. struct spi_transfer *xfer;
  161. int clk_div, new_clk_div;
  162. bool cs_change = true;
  163. clk_div = -1;
  164. spi_engine_program_add_cmd(p, dry,
  165. SPI_ENGINE_CMD_WRITE(SPI_ENGINE_CMD_REG_CONFIG,
  166. spi_engine_get_config(spi)));
  167. list_for_each_entry(xfer, &msg->transfers, transfer_list) {
  168. new_clk_div = spi_engine_get_clk_div(spi_engine, spi, xfer);
  169. if (new_clk_div != clk_div) {
  170. clk_div = new_clk_div;
  171. spi_engine_program_add_cmd(p, dry,
  172. SPI_ENGINE_CMD_WRITE(SPI_ENGINE_CMD_REG_CLK_DIV,
  173. clk_div));
  174. }
  175. if (cs_change)
  176. spi_engine_gen_cs(p, dry, spi, true);
  177. spi_engine_gen_xfer(p, dry, xfer);
  178. spi_engine_gen_sleep(p, dry, spi_engine, clk_div, xfer);
  179. cs_change = xfer->cs_change;
  180. if (list_is_last(&xfer->transfer_list, &msg->transfers))
  181. cs_change = !cs_change;
  182. if (cs_change)
  183. spi_engine_gen_cs(p, dry, spi, false);
  184. }
  185. return 0;
  186. }
  187. static void spi_engine_xfer_next(struct spi_engine *spi_engine,
  188. struct spi_transfer **_xfer)
  189. {
  190. struct spi_message *msg = spi_engine->msg;
  191. struct spi_transfer *xfer = *_xfer;
  192. if (!xfer) {
  193. xfer = list_first_entry(&msg->transfers,
  194. struct spi_transfer, transfer_list);
  195. } else if (list_is_last(&xfer->transfer_list, &msg->transfers)) {
  196. xfer = NULL;
  197. } else {
  198. xfer = list_next_entry(xfer, transfer_list);
  199. }
  200. *_xfer = xfer;
  201. }
  202. static void spi_engine_tx_next(struct spi_engine *spi_engine)
  203. {
  204. struct spi_transfer *xfer = spi_engine->tx_xfer;
  205. do {
  206. spi_engine_xfer_next(spi_engine, &xfer);
  207. } while (xfer && !xfer->tx_buf);
  208. spi_engine->tx_xfer = xfer;
  209. if (xfer) {
  210. spi_engine->tx_length = xfer->len;
  211. spi_engine->tx_buf = xfer->tx_buf;
  212. } else {
  213. spi_engine->tx_buf = NULL;
  214. }
  215. }
  216. static void spi_engine_rx_next(struct spi_engine *spi_engine)
  217. {
  218. struct spi_transfer *xfer = spi_engine->rx_xfer;
  219. do {
  220. spi_engine_xfer_next(spi_engine, &xfer);
  221. } while (xfer && !xfer->rx_buf);
  222. spi_engine->rx_xfer = xfer;
  223. if (xfer) {
  224. spi_engine->rx_length = xfer->len;
  225. spi_engine->rx_buf = xfer->rx_buf;
  226. } else {
  227. spi_engine->rx_buf = NULL;
  228. }
  229. }
  230. static bool spi_engine_write_cmd_fifo(struct spi_engine *spi_engine)
  231. {
  232. void __iomem *addr = spi_engine->base + SPI_ENGINE_REG_CMD_FIFO;
  233. unsigned int n, m, i;
  234. const uint16_t *buf;
  235. n = readl_relaxed(spi_engine->base + SPI_ENGINE_REG_CMD_FIFO_ROOM);
  236. while (n && spi_engine->cmd_length) {
  237. m = min(n, spi_engine->cmd_length);
  238. buf = spi_engine->cmd_buf;
  239. for (i = 0; i < m; i++)
  240. writel_relaxed(buf[i], addr);
  241. spi_engine->cmd_buf += m;
  242. spi_engine->cmd_length -= m;
  243. n -= m;
  244. }
  245. return spi_engine->cmd_length != 0;
  246. }
  247. static bool spi_engine_write_tx_fifo(struct spi_engine *spi_engine)
  248. {
  249. void __iomem *addr = spi_engine->base + SPI_ENGINE_REG_SDO_DATA_FIFO;
  250. unsigned int n, m, i;
  251. const uint8_t *buf;
  252. n = readl_relaxed(spi_engine->base + SPI_ENGINE_REG_SDO_FIFO_ROOM);
  253. while (n && spi_engine->tx_length) {
  254. m = min(n, spi_engine->tx_length);
  255. buf = spi_engine->tx_buf;
  256. for (i = 0; i < m; i++)
  257. writel_relaxed(buf[i], addr);
  258. spi_engine->tx_buf += m;
  259. spi_engine->tx_length -= m;
  260. n -= m;
  261. if (spi_engine->tx_length == 0)
  262. spi_engine_tx_next(spi_engine);
  263. }
  264. return spi_engine->tx_length != 0;
  265. }
  266. static bool spi_engine_read_rx_fifo(struct spi_engine *spi_engine)
  267. {
  268. void __iomem *addr = spi_engine->base + SPI_ENGINE_REG_SDI_DATA_FIFO;
  269. unsigned int n, m, i;
  270. uint8_t *buf;
  271. n = readl_relaxed(spi_engine->base + SPI_ENGINE_REG_SDI_FIFO_LEVEL);
  272. while (n && spi_engine->rx_length) {
  273. m = min(n, spi_engine->rx_length);
  274. buf = spi_engine->rx_buf;
  275. for (i = 0; i < m; i++)
  276. buf[i] = readl_relaxed(addr);
  277. spi_engine->rx_buf += m;
  278. spi_engine->rx_length -= m;
  279. n -= m;
  280. if (spi_engine->rx_length == 0)
  281. spi_engine_rx_next(spi_engine);
  282. }
  283. return spi_engine->rx_length != 0;
  284. }
  285. static irqreturn_t spi_engine_irq(int irq, void *devid)
  286. {
  287. struct spi_master *master = devid;
  288. struct spi_engine *spi_engine = spi_master_get_devdata(master);
  289. unsigned int disable_int = 0;
  290. unsigned int pending;
  291. pending = readl_relaxed(spi_engine->base + SPI_ENGINE_REG_INT_PENDING);
  292. if (pending & SPI_ENGINE_INT_SYNC) {
  293. writel_relaxed(SPI_ENGINE_INT_SYNC,
  294. spi_engine->base + SPI_ENGINE_REG_INT_PENDING);
  295. spi_engine->completed_id = readl_relaxed(
  296. spi_engine->base + SPI_ENGINE_REG_SYNC_ID);
  297. }
  298. spin_lock(&spi_engine->lock);
  299. if (pending & SPI_ENGINE_INT_CMD_ALMOST_EMPTY) {
  300. if (!spi_engine_write_cmd_fifo(spi_engine))
  301. disable_int |= SPI_ENGINE_INT_CMD_ALMOST_EMPTY;
  302. }
  303. if (pending & SPI_ENGINE_INT_SDO_ALMOST_EMPTY) {
  304. if (!spi_engine_write_tx_fifo(spi_engine))
  305. disable_int |= SPI_ENGINE_INT_SDO_ALMOST_EMPTY;
  306. }
  307. if (pending & (SPI_ENGINE_INT_SDI_ALMOST_FULL | SPI_ENGINE_INT_SYNC)) {
  308. if (!spi_engine_read_rx_fifo(spi_engine))
  309. disable_int |= SPI_ENGINE_INT_SDI_ALMOST_FULL;
  310. }
  311. if (pending & SPI_ENGINE_INT_SYNC) {
  312. if (spi_engine->msg &&
  313. spi_engine->completed_id == spi_engine->sync_id) {
  314. struct spi_message *msg = spi_engine->msg;
  315. kfree(spi_engine->p);
  316. msg->status = 0;
  317. msg->actual_length = msg->frame_length;
  318. spi_engine->msg = NULL;
  319. spi_finalize_current_message(master);
  320. disable_int |= SPI_ENGINE_INT_SYNC;
  321. }
  322. }
  323. if (disable_int) {
  324. spi_engine->int_enable &= ~disable_int;
  325. writel_relaxed(spi_engine->int_enable,
  326. spi_engine->base + SPI_ENGINE_REG_INT_ENABLE);
  327. }
  328. spin_unlock(&spi_engine->lock);
  329. return IRQ_HANDLED;
  330. }
  331. static int spi_engine_transfer_one_message(struct spi_master *master,
  332. struct spi_message *msg)
  333. {
  334. struct spi_engine_program p_dry, *p;
  335. struct spi_engine *spi_engine = spi_master_get_devdata(master);
  336. unsigned int int_enable = 0;
  337. unsigned long flags;
  338. size_t size;
  339. p_dry.length = 0;
  340. spi_engine_compile_message(spi_engine, msg, true, &p_dry);
  341. size = sizeof(*p->instructions) * (p_dry.length + 1);
  342. p = kzalloc(sizeof(*p) + size, GFP_KERNEL);
  343. if (!p)
  344. return -ENOMEM;
  345. spi_engine_compile_message(spi_engine, msg, false, p);
  346. spin_lock_irqsave(&spi_engine->lock, flags);
  347. spi_engine->sync_id = (spi_engine->sync_id + 1) & 0xff;
  348. spi_engine_program_add_cmd(p, false,
  349. SPI_ENGINE_CMD_SYNC(spi_engine->sync_id));
  350. spi_engine->msg = msg;
  351. spi_engine->p = p;
  352. spi_engine->cmd_buf = p->instructions;
  353. spi_engine->cmd_length = p->length;
  354. if (spi_engine_write_cmd_fifo(spi_engine))
  355. int_enable |= SPI_ENGINE_INT_CMD_ALMOST_EMPTY;
  356. spi_engine_tx_next(spi_engine);
  357. if (spi_engine_write_tx_fifo(spi_engine))
  358. int_enable |= SPI_ENGINE_INT_SDO_ALMOST_EMPTY;
  359. spi_engine_rx_next(spi_engine);
  360. if (spi_engine->rx_length != 0)
  361. int_enable |= SPI_ENGINE_INT_SDI_ALMOST_FULL;
  362. int_enable |= SPI_ENGINE_INT_SYNC;
  363. writel_relaxed(int_enable,
  364. spi_engine->base + SPI_ENGINE_REG_INT_ENABLE);
  365. spi_engine->int_enable = int_enable;
  366. spin_unlock_irqrestore(&spi_engine->lock, flags);
  367. return 0;
  368. }
  369. static int spi_engine_probe(struct platform_device *pdev)
  370. {
  371. struct spi_engine *spi_engine;
  372. struct spi_master *master;
  373. unsigned int version;
  374. int irq;
  375. int ret;
  376. irq = platform_get_irq(pdev, 0);
  377. if (irq <= 0)
  378. return -ENXIO;
  379. spi_engine = devm_kzalloc(&pdev->dev, sizeof(*spi_engine), GFP_KERNEL);
  380. if (!spi_engine)
  381. return -ENOMEM;
  382. master = spi_alloc_master(&pdev->dev, 0);
  383. if (!master)
  384. return -ENOMEM;
  385. spi_master_set_devdata(master, spi_engine);
  386. spin_lock_init(&spi_engine->lock);
  387. spi_engine->clk = devm_clk_get(&pdev->dev, "s_axi_aclk");
  388. if (IS_ERR(spi_engine->clk)) {
  389. ret = PTR_ERR(spi_engine->clk);
  390. goto err_put_master;
  391. }
  392. spi_engine->ref_clk = devm_clk_get(&pdev->dev, "spi_clk");
  393. if (IS_ERR(spi_engine->ref_clk)) {
  394. ret = PTR_ERR(spi_engine->ref_clk);
  395. goto err_put_master;
  396. }
  397. ret = clk_prepare_enable(spi_engine->clk);
  398. if (ret)
  399. goto err_put_master;
  400. ret = clk_prepare_enable(spi_engine->ref_clk);
  401. if (ret)
  402. goto err_clk_disable;
  403. spi_engine->base = devm_platform_ioremap_resource(pdev, 0);
  404. if (IS_ERR(spi_engine->base)) {
  405. ret = PTR_ERR(spi_engine->base);
  406. goto err_ref_clk_disable;
  407. }
  408. version = readl(spi_engine->base + SPI_ENGINE_REG_VERSION);
  409. if (SPI_ENGINE_VERSION_MAJOR(version) != 1) {
  410. dev_err(&pdev->dev, "Unsupported peripheral version %u.%u.%c\n",
  411. SPI_ENGINE_VERSION_MAJOR(version),
  412. SPI_ENGINE_VERSION_MINOR(version),
  413. SPI_ENGINE_VERSION_PATCH(version));
  414. ret = -ENODEV;
  415. goto err_ref_clk_disable;
  416. }
  417. writel_relaxed(0x00, spi_engine->base + SPI_ENGINE_REG_RESET);
  418. writel_relaxed(0xff, spi_engine->base + SPI_ENGINE_REG_INT_PENDING);
  419. writel_relaxed(0x00, spi_engine->base + SPI_ENGINE_REG_INT_ENABLE);
  420. ret = request_irq(irq, spi_engine_irq, 0, pdev->name, master);
  421. if (ret)
  422. goto err_ref_clk_disable;
  423. master->dev.of_node = pdev->dev.of_node;
  424. master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_3WIRE;
  425. master->bits_per_word_mask = SPI_BPW_MASK(8);
  426. master->max_speed_hz = clk_get_rate(spi_engine->ref_clk) / 2;
  427. master->transfer_one_message = spi_engine_transfer_one_message;
  428. master->num_chipselect = 8;
  429. ret = spi_register_master(master);
  430. if (ret)
  431. goto err_free_irq;
  432. platform_set_drvdata(pdev, master);
  433. return 0;
  434. err_free_irq:
  435. free_irq(irq, master);
  436. err_ref_clk_disable:
  437. clk_disable_unprepare(spi_engine->ref_clk);
  438. err_clk_disable:
  439. clk_disable_unprepare(spi_engine->clk);
  440. err_put_master:
  441. spi_master_put(master);
  442. return ret;
  443. }
  444. static int spi_engine_remove(struct platform_device *pdev)
  445. {
  446. struct spi_master *master = spi_master_get(platform_get_drvdata(pdev));
  447. struct spi_engine *spi_engine = spi_master_get_devdata(master);
  448. int irq = platform_get_irq(pdev, 0);
  449. spi_unregister_master(master);
  450. free_irq(irq, master);
  451. spi_master_put(master);
  452. writel_relaxed(0xff, spi_engine->base + SPI_ENGINE_REG_INT_PENDING);
  453. writel_relaxed(0x00, spi_engine->base + SPI_ENGINE_REG_INT_ENABLE);
  454. writel_relaxed(0x01, spi_engine->base + SPI_ENGINE_REG_RESET);
  455. clk_disable_unprepare(spi_engine->ref_clk);
  456. clk_disable_unprepare(spi_engine->clk);
  457. return 0;
  458. }
  459. static const struct of_device_id spi_engine_match_table[] = {
  460. { .compatible = "adi,axi-spi-engine-1.00.a" },
  461. { },
  462. };
  463. MODULE_DEVICE_TABLE(of, spi_engine_match_table);
  464. static struct platform_driver spi_engine_driver = {
  465. .probe = spi_engine_probe,
  466. .remove = spi_engine_remove,
  467. .driver = {
  468. .name = "spi-engine",
  469. .of_match_table = spi_engine_match_table,
  470. },
  471. };
  472. module_platform_driver(spi_engine_driver);
  473. MODULE_AUTHOR("Lars-Peter Clausen <[email protected]>");
  474. MODULE_DESCRIPTION("Analog Devices SPI engine peripheral driver");
  475. MODULE_LICENSE("GPL");