spi-axi-spi-engine.c 15 KB

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