spi-axi-spi-engine.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601
  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 <lars@metafoo.de>
  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. if (xfer->delay_usecs) {
  136. delay = xfer->delay_usecs;
  137. } else {
  138. delay = spi_delay_to_ns(&xfer->delay, xfer);
  139. if (delay < 0)
  140. return;
  141. delay /= 1000;
  142. }
  143. if (delay == 0)
  144. return;
  145. t = DIV_ROUND_UP(delay * spi_clk, (clk_div + 1) * 2);
  146. while (t) {
  147. unsigned int n = min(t, 256U);
  148. spi_engine_program_add_cmd(p, dry, SPI_ENGINE_CMD_SLEEP(n - 1));
  149. t -= n;
  150. }
  151. }
  152. static void spi_engine_gen_cs(struct spi_engine_program *p, bool dry,
  153. struct spi_device *spi, bool assert)
  154. {
  155. unsigned int mask = 0xff;
  156. if (assert)
  157. mask ^= BIT(spi->chip_select);
  158. spi_engine_program_add_cmd(p, dry, SPI_ENGINE_CMD_ASSERT(1, mask));
  159. }
  160. static int spi_engine_compile_message(struct spi_engine *spi_engine,
  161. struct spi_message *msg, bool dry, struct spi_engine_program *p)
  162. {
  163. struct spi_device *spi = msg->spi;
  164. struct spi_transfer *xfer;
  165. int clk_div, new_clk_div;
  166. bool cs_change = true;
  167. clk_div = -1;
  168. spi_engine_program_add_cmd(p, dry,
  169. SPI_ENGINE_CMD_WRITE(SPI_ENGINE_CMD_REG_CONFIG,
  170. spi_engine_get_config(spi)));
  171. list_for_each_entry(xfer, &msg->transfers, transfer_list) {
  172. new_clk_div = spi_engine_get_clk_div(spi_engine, spi, xfer);
  173. if (new_clk_div != clk_div) {
  174. clk_div = new_clk_div;
  175. spi_engine_program_add_cmd(p, dry,
  176. SPI_ENGINE_CMD_WRITE(SPI_ENGINE_CMD_REG_CLK_DIV,
  177. clk_div));
  178. }
  179. if (cs_change)
  180. spi_engine_gen_cs(p, dry, spi, true);
  181. spi_engine_gen_xfer(p, dry, xfer);
  182. spi_engine_gen_sleep(p, dry, spi_engine, clk_div, xfer);
  183. cs_change = xfer->cs_change;
  184. if (list_is_last(&xfer->transfer_list, &msg->transfers))
  185. cs_change = !cs_change;
  186. if (cs_change)
  187. spi_engine_gen_cs(p, dry, spi, false);
  188. }
  189. return 0;
  190. }
  191. static void spi_engine_xfer_next(struct spi_engine *spi_engine,
  192. struct spi_transfer **_xfer)
  193. {
  194. struct spi_message *msg = spi_engine->msg;
  195. struct spi_transfer *xfer = *_xfer;
  196. if (!xfer) {
  197. xfer = list_first_entry(&msg->transfers,
  198. struct spi_transfer, transfer_list);
  199. } else if (list_is_last(&xfer->transfer_list, &msg->transfers)) {
  200. xfer = NULL;
  201. } else {
  202. xfer = list_next_entry(xfer, transfer_list);
  203. }
  204. *_xfer = xfer;
  205. }
  206. static void spi_engine_tx_next(struct spi_engine *spi_engine)
  207. {
  208. struct spi_transfer *xfer = spi_engine->tx_xfer;
  209. do {
  210. spi_engine_xfer_next(spi_engine, &xfer);
  211. } while (xfer && !xfer->tx_buf);
  212. spi_engine->tx_xfer = xfer;
  213. if (xfer) {
  214. spi_engine->tx_length = xfer->len;
  215. spi_engine->tx_buf = xfer->tx_buf;
  216. } else {
  217. spi_engine->tx_buf = NULL;
  218. }
  219. }
  220. static void spi_engine_rx_next(struct spi_engine *spi_engine)
  221. {
  222. struct spi_transfer *xfer = spi_engine->rx_xfer;
  223. do {
  224. spi_engine_xfer_next(spi_engine, &xfer);
  225. } while (xfer && !xfer->rx_buf);
  226. spi_engine->rx_xfer = xfer;
  227. if (xfer) {
  228. spi_engine->rx_length = xfer->len;
  229. spi_engine->rx_buf = xfer->rx_buf;
  230. } else {
  231. spi_engine->rx_buf = NULL;
  232. }
  233. }
  234. static bool spi_engine_write_cmd_fifo(struct spi_engine *spi_engine)
  235. {
  236. void __iomem *addr = spi_engine->base + SPI_ENGINE_REG_CMD_FIFO;
  237. unsigned int n, m, i;
  238. const uint16_t *buf;
  239. n = readl_relaxed(spi_engine->base + SPI_ENGINE_REG_CMD_FIFO_ROOM);
  240. while (n && spi_engine->cmd_length) {
  241. m = min(n, spi_engine->cmd_length);
  242. buf = spi_engine->cmd_buf;
  243. for (i = 0; i < m; i++)
  244. writel_relaxed(buf[i], addr);
  245. spi_engine->cmd_buf += m;
  246. spi_engine->cmd_length -= m;
  247. n -= m;
  248. }
  249. return spi_engine->cmd_length != 0;
  250. }
  251. static bool spi_engine_write_tx_fifo(struct spi_engine *spi_engine)
  252. {
  253. void __iomem *addr = spi_engine->base + SPI_ENGINE_REG_SDO_DATA_FIFO;
  254. unsigned int n, m, i;
  255. const uint8_t *buf;
  256. n = readl_relaxed(spi_engine->base + SPI_ENGINE_REG_SDO_FIFO_ROOM);
  257. while (n && spi_engine->tx_length) {
  258. m = min(n, spi_engine->tx_length);
  259. buf = spi_engine->tx_buf;
  260. for (i = 0; i < m; i++)
  261. writel_relaxed(buf[i], addr);
  262. spi_engine->tx_buf += m;
  263. spi_engine->tx_length -= m;
  264. n -= m;
  265. if (spi_engine->tx_length == 0)
  266. spi_engine_tx_next(spi_engine);
  267. }
  268. return spi_engine->tx_length != 0;
  269. }
  270. static bool spi_engine_read_rx_fifo(struct spi_engine *spi_engine)
  271. {
  272. void __iomem *addr = spi_engine->base + SPI_ENGINE_REG_SDI_DATA_FIFO;
  273. unsigned int n, m, i;
  274. uint8_t *buf;
  275. n = readl_relaxed(spi_engine->base + SPI_ENGINE_REG_SDI_FIFO_LEVEL);
  276. while (n && spi_engine->rx_length) {
  277. m = min(n, spi_engine->rx_length);
  278. buf = spi_engine->rx_buf;
  279. for (i = 0; i < m; i++)
  280. buf[i] = readl_relaxed(addr);
  281. spi_engine->rx_buf += m;
  282. spi_engine->rx_length -= m;
  283. n -= m;
  284. if (spi_engine->rx_length == 0)
  285. spi_engine_rx_next(spi_engine);
  286. }
  287. return spi_engine->rx_length != 0;
  288. }
  289. static irqreturn_t spi_engine_irq(int irq, void *devid)
  290. {
  291. struct spi_master *master = devid;
  292. struct spi_engine *spi_engine = spi_master_get_devdata(master);
  293. unsigned int disable_int = 0;
  294. unsigned int pending;
  295. pending = readl_relaxed(spi_engine->base + SPI_ENGINE_REG_INT_PENDING);
  296. if (pending & SPI_ENGINE_INT_SYNC) {
  297. writel_relaxed(SPI_ENGINE_INT_SYNC,
  298. spi_engine->base + SPI_ENGINE_REG_INT_PENDING);
  299. spi_engine->completed_id = readl_relaxed(
  300. spi_engine->base + SPI_ENGINE_REG_SYNC_ID);
  301. }
  302. spin_lock(&spi_engine->lock);
  303. if (pending & SPI_ENGINE_INT_CMD_ALMOST_EMPTY) {
  304. if (!spi_engine_write_cmd_fifo(spi_engine))
  305. disable_int |= SPI_ENGINE_INT_CMD_ALMOST_EMPTY;
  306. }
  307. if (pending & SPI_ENGINE_INT_SDO_ALMOST_EMPTY) {
  308. if (!spi_engine_write_tx_fifo(spi_engine))
  309. disable_int |= SPI_ENGINE_INT_SDO_ALMOST_EMPTY;
  310. }
  311. if (pending & (SPI_ENGINE_INT_SDI_ALMOST_FULL | SPI_ENGINE_INT_SYNC)) {
  312. if (!spi_engine_read_rx_fifo(spi_engine))
  313. disable_int |= SPI_ENGINE_INT_SDI_ALMOST_FULL;
  314. }
  315. if (pending & SPI_ENGINE_INT_SYNC) {
  316. if (spi_engine->msg &&
  317. spi_engine->completed_id == spi_engine->sync_id) {
  318. struct spi_message *msg = spi_engine->msg;
  319. kfree(spi_engine->p);
  320. msg->status = 0;
  321. msg->actual_length = msg->frame_length;
  322. spi_engine->msg = NULL;
  323. spi_finalize_current_message(master);
  324. disable_int |= SPI_ENGINE_INT_SYNC;
  325. }
  326. }
  327. if (disable_int) {
  328. spi_engine->int_enable &= ~disable_int;
  329. writel_relaxed(spi_engine->int_enable,
  330. spi_engine->base + SPI_ENGINE_REG_INT_ENABLE);
  331. }
  332. spin_unlock(&spi_engine->lock);
  333. return IRQ_HANDLED;
  334. }
  335. static int spi_engine_transfer_one_message(struct spi_master *master,
  336. struct spi_message *msg)
  337. {
  338. struct spi_engine_program p_dry, *p;
  339. struct spi_engine *spi_engine = spi_master_get_devdata(master);
  340. unsigned int int_enable = 0;
  341. unsigned long flags;
  342. size_t size;
  343. p_dry.length = 0;
  344. spi_engine_compile_message(spi_engine, msg, true, &p_dry);
  345. size = sizeof(*p->instructions) * (p_dry.length + 1);
  346. p = kzalloc(sizeof(*p) + size, GFP_KERNEL);
  347. if (!p)
  348. return -ENOMEM;
  349. spi_engine_compile_message(spi_engine, msg, false, p);
  350. spin_lock_irqsave(&spi_engine->lock, flags);
  351. spi_engine->sync_id = (spi_engine->sync_id + 1) & 0xff;
  352. spi_engine_program_add_cmd(p, false,
  353. SPI_ENGINE_CMD_SYNC(spi_engine->sync_id));
  354. spi_engine->msg = msg;
  355. spi_engine->p = p;
  356. spi_engine->cmd_buf = p->instructions;
  357. spi_engine->cmd_length = p->length;
  358. if (spi_engine_write_cmd_fifo(spi_engine))
  359. int_enable |= SPI_ENGINE_INT_CMD_ALMOST_EMPTY;
  360. spi_engine_tx_next(spi_engine);
  361. if (spi_engine_write_tx_fifo(spi_engine))
  362. int_enable |= SPI_ENGINE_INT_SDO_ALMOST_EMPTY;
  363. spi_engine_rx_next(spi_engine);
  364. if (spi_engine->rx_length != 0)
  365. int_enable |= SPI_ENGINE_INT_SDI_ALMOST_FULL;
  366. int_enable |= SPI_ENGINE_INT_SYNC;
  367. writel_relaxed(int_enable,
  368. spi_engine->base + SPI_ENGINE_REG_INT_ENABLE);
  369. spi_engine->int_enable = int_enable;
  370. spin_unlock_irqrestore(&spi_engine->lock, flags);
  371. return 0;
  372. }
  373. static int spi_engine_probe(struct platform_device *pdev)
  374. {
  375. struct spi_engine *spi_engine;
  376. struct spi_master *master;
  377. unsigned int version;
  378. int irq;
  379. int ret;
  380. irq = platform_get_irq(pdev, 0);
  381. if (irq <= 0)
  382. return -ENXIO;
  383. spi_engine = devm_kzalloc(&pdev->dev, sizeof(*spi_engine), GFP_KERNEL);
  384. if (!spi_engine)
  385. return -ENOMEM;
  386. master = spi_alloc_master(&pdev->dev, 0);
  387. if (!master)
  388. return -ENOMEM;
  389. spi_master_set_devdata(master, spi_engine);
  390. spin_lock_init(&spi_engine->lock);
  391. spi_engine->clk = devm_clk_get(&pdev->dev, "s_axi_aclk");
  392. if (IS_ERR(spi_engine->clk)) {
  393. ret = PTR_ERR(spi_engine->clk);
  394. goto err_put_master;
  395. }
  396. spi_engine->ref_clk = devm_clk_get(&pdev->dev, "spi_clk");
  397. if (IS_ERR(spi_engine->ref_clk)) {
  398. ret = PTR_ERR(spi_engine->ref_clk);
  399. goto err_put_master;
  400. }
  401. ret = clk_prepare_enable(spi_engine->clk);
  402. if (ret)
  403. goto err_put_master;
  404. ret = clk_prepare_enable(spi_engine->ref_clk);
  405. if (ret)
  406. goto err_clk_disable;
  407. spi_engine->base = devm_platform_ioremap_resource(pdev, 0);
  408. if (IS_ERR(spi_engine->base)) {
  409. ret = PTR_ERR(spi_engine->base);
  410. goto err_ref_clk_disable;
  411. }
  412. version = readl(spi_engine->base + SPI_ENGINE_REG_VERSION);
  413. if (SPI_ENGINE_VERSION_MAJOR(version) != 1) {
  414. dev_err(&pdev->dev, "Unsupported peripheral version %u.%u.%c\n",
  415. SPI_ENGINE_VERSION_MAJOR(version),
  416. SPI_ENGINE_VERSION_MINOR(version),
  417. SPI_ENGINE_VERSION_PATCH(version));
  418. ret = -ENODEV;
  419. goto err_ref_clk_disable;
  420. }
  421. writel_relaxed(0x00, spi_engine->base + SPI_ENGINE_REG_RESET);
  422. writel_relaxed(0xff, spi_engine->base + SPI_ENGINE_REG_INT_PENDING);
  423. writel_relaxed(0x00, spi_engine->base + SPI_ENGINE_REG_INT_ENABLE);
  424. ret = request_irq(irq, spi_engine_irq, 0, pdev->name, master);
  425. if (ret)
  426. goto err_ref_clk_disable;
  427. master->dev.of_node = pdev->dev.of_node;
  428. master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_3WIRE;
  429. master->bits_per_word_mask = SPI_BPW_MASK(8);
  430. master->max_speed_hz = clk_get_rate(spi_engine->ref_clk) / 2;
  431. master->transfer_one_message = spi_engine_transfer_one_message;
  432. master->num_chipselect = 8;
  433. ret = spi_register_master(master);
  434. if (ret)
  435. goto err_free_irq;
  436. platform_set_drvdata(pdev, master);
  437. return 0;
  438. err_free_irq:
  439. free_irq(irq, master);
  440. err_ref_clk_disable:
  441. clk_disable_unprepare(spi_engine->ref_clk);
  442. err_clk_disable:
  443. clk_disable_unprepare(spi_engine->clk);
  444. err_put_master:
  445. spi_master_put(master);
  446. return ret;
  447. }
  448. static int spi_engine_remove(struct platform_device *pdev)
  449. {
  450. struct spi_master *master = spi_master_get(platform_get_drvdata(pdev));
  451. struct spi_engine *spi_engine = spi_master_get_devdata(master);
  452. int irq = platform_get_irq(pdev, 0);
  453. spi_unregister_master(master);
  454. free_irq(irq, master);
  455. spi_master_put(master);
  456. writel_relaxed(0xff, spi_engine->base + SPI_ENGINE_REG_INT_PENDING);
  457. writel_relaxed(0x00, spi_engine->base + SPI_ENGINE_REG_INT_ENABLE);
  458. writel_relaxed(0x01, spi_engine->base + SPI_ENGINE_REG_RESET);
  459. clk_disable_unprepare(spi_engine->ref_clk);
  460. clk_disable_unprepare(spi_engine->clk);
  461. return 0;
  462. }
  463. static const struct of_device_id spi_engine_match_table[] = {
  464. { .compatible = "adi,axi-spi-engine-1.00.a" },
  465. { },
  466. };
  467. MODULE_DEVICE_TABLE(of, spi_engine_match_table);
  468. static struct platform_driver spi_engine_driver = {
  469. .probe = spi_engine_probe,
  470. .remove = spi_engine_remove,
  471. .driver = {
  472. .name = "spi-engine",
  473. .of_match_table = spi_engine_match_table,
  474. },
  475. };
  476. module_platform_driver(spi_engine_driver);
  477. MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
  478. MODULE_DESCRIPTION("Analog Devices SPI engine peripheral driver");
  479. MODULE_LICENSE("GPL");