0007-spi-add-rb4xx-cpld-driver.patch 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525
  1. diff -Nur linux-4.1.6.orig/arch/mips/include/asm/mach-ath79/rb4xx_cpld.h linux-4.1.6/arch/mips/include/asm/mach-ath79/rb4xx_cpld.h
  2. --- linux-4.1.6.orig/arch/mips/include/asm/mach-ath79/rb4xx_cpld.h 1970-01-01 01:00:00.000000000 +0100
  3. +++ linux-4.1.6/arch/mips/include/asm/mach-ath79/rb4xx_cpld.h 2015-09-13 19:28:51.200198278 +0200
  4. @@ -0,0 +1,48 @@
  5. +/*
  6. + * SPI driver definitions for the CPLD chip on the Mikrotik RB4xx boards
  7. + *
  8. + * Copyright (C) 2010 Gabor Juhos <juhosg@openwrt.org>
  9. + *
  10. + * This file was based on the patches for Linux 2.6.27.39 published by
  11. + * MikroTik for their RouterBoard 4xx series devices.
  12. + *
  13. + * This program is free software; you can redistribute it and/or modify it
  14. + * under the terms of the GNU General Public License version 2 as published
  15. + * by the Free Software Foundation.
  16. + */
  17. +
  18. +#define CPLD_GPIO_nLED1 0
  19. +#define CPLD_GPIO_nLED2 1
  20. +#define CPLD_GPIO_nLED3 2
  21. +#define CPLD_GPIO_nLED4 3
  22. +#define CPLD_GPIO_FAN 4
  23. +#define CPLD_GPIO_ALE 5
  24. +#define CPLD_GPIO_CLE 6
  25. +#define CPLD_GPIO_nCE 7
  26. +#define CPLD_GPIO_nLED5 8
  27. +
  28. +#define CPLD_NUM_GPIOS 9
  29. +
  30. +#define CPLD_CFG_nLED1 BIT(CPLD_GPIO_nLED1)
  31. +#define CPLD_CFG_nLED2 BIT(CPLD_GPIO_nLED2)
  32. +#define CPLD_CFG_nLED3 BIT(CPLD_GPIO_nLED3)
  33. +#define CPLD_CFG_nLED4 BIT(CPLD_GPIO_nLED4)
  34. +#define CPLD_CFG_FAN BIT(CPLD_GPIO_FAN)
  35. +#define CPLD_CFG_ALE BIT(CPLD_GPIO_ALE)
  36. +#define CPLD_CFG_CLE BIT(CPLD_GPIO_CLE)
  37. +#define CPLD_CFG_nCE BIT(CPLD_GPIO_nCE)
  38. +#define CPLD_CFG_nLED5 BIT(CPLD_GPIO_nLED5)
  39. +
  40. +struct rb4xx_cpld_platform_data {
  41. + unsigned gpio_base;
  42. +};
  43. +
  44. +extern int rb4xx_cpld_change_cfg(unsigned mask, unsigned value);
  45. +extern int rb4xx_cpld_read(unsigned char *rx_buf,
  46. + const unsigned char *verify_buf,
  47. + unsigned cnt);
  48. +extern int rb4xx_cpld_read_from(unsigned addr,
  49. + unsigned char *rx_buf,
  50. + const unsigned char *verify_buf,
  51. + unsigned cnt);
  52. +extern int rb4xx_cpld_write(const unsigned char *buf, unsigned count);
  53. diff -Nur linux-4.1.6.orig/drivers/spi/Kconfig linux-4.1.6/drivers/spi/Kconfig
  54. --- linux-4.1.6.orig/drivers/spi/Kconfig 2015-08-17 05:52:51.000000000 +0200
  55. +++ linux-4.1.6/drivers/spi/Kconfig 2015-09-13 19:28:51.200198278 +0200
  56. @@ -661,6 +661,13 @@
  57. sysfs interface, with each line presented as a kind of GPIO
  58. exposing both switch control and diagnostic feedback.
  59. +config SPI_RB4XX_CPLD
  60. + tristate "MikroTik RB4XX CPLD driver"
  61. + depends on ATH79_MACH_RB4XX
  62. + help
  63. + SPI driver for the Xilinx CPLD chip present on the
  64. + MikroTik RB4xx boards.
  65. +
  66. #
  67. # Add new SPI protocol masters in alphabetical order above this line
  68. #
  69. diff -Nur linux-4.1.6.orig/drivers/spi/Makefile linux-4.1.6/drivers/spi/Makefile
  70. --- linux-4.1.6.orig/drivers/spi/Makefile 2015-08-17 05:52:51.000000000 +0200
  71. +++ linux-4.1.6/drivers/spi/Makefile 2015-09-13 19:29:38.934613144 +0200
  72. @@ -65,6 +65,7 @@
  73. obj-$(CONFIG_SPI_PXA2XX) += spi-pxa2xx-platform.o
  74. obj-$(CONFIG_SPI_PXA2XX_PCI) += spi-pxa2xx-pci.o
  75. obj-$(CONFIG_SPI_QUP) += spi-qup.o
  76. +obj-$(CONFIG_SPI_RB4XX_CPLD) += spi-rb4xx-cpld.o
  77. obj-$(CONFIG_SPI_ROCKCHIP) += spi-rockchip.o
  78. obj-$(CONFIG_SPI_RSPI) += spi-rspi.o
  79. obj-$(CONFIG_SPI_S3C24XX) += spi-s3c24xx-hw.o
  80. diff -Nur linux-4.1.6.orig/drivers/spi/spi-rb4xx-cpld.c linux-4.1.6/drivers/spi/spi-rb4xx-cpld.c
  81. --- linux-4.1.6.orig/drivers/spi/spi-rb4xx-cpld.c 1970-01-01 01:00:00.000000000 +0100
  82. +++ linux-4.1.6/drivers/spi/spi-rb4xx-cpld.c 2015-09-13 19:28:51.200198278 +0200
  83. @@ -0,0 +1,441 @@
  84. +/*
  85. + * SPI driver for the CPLD chip on the Mikrotik RB4xx boards
  86. + *
  87. + * Copyright (C) 2010 Gabor Juhos <juhosg@openwrt.org>
  88. + *
  89. + * This file was based on the patches for Linux 2.6.27.39 published by
  90. + * MikroTik for their RouterBoard 4xx series devices.
  91. + *
  92. + * This program is free software; you can redistribute it and/or modify it
  93. + * under the terms of the GNU General Public License version 2 as published
  94. + * by the Free Software Foundation.
  95. + */
  96. +
  97. +#include <linux/types.h>
  98. +#include <linux/kernel.h>
  99. +#include <linux/module.h>
  100. +#include <linux/init.h>
  101. +#include <linux/module.h>
  102. +#include <linux/device.h>
  103. +#include <linux/bitops.h>
  104. +#include <linux/spi/spi.h>
  105. +#include <linux/gpio.h>
  106. +#include <linux/slab.h>
  107. +
  108. +#include <asm/mach-ath79/rb4xx_cpld.h>
  109. +
  110. +#define DRV_NAME "spi-rb4xx-cpld"
  111. +#define DRV_DESC "RB4xx CPLD driver"
  112. +#define DRV_VERSION "0.1.0"
  113. +
  114. +#define CPLD_CMD_WRITE_NAND 0x08 /* send cmd, n x send data, send indle */
  115. +#define CPLD_CMD_WRITE_CFG 0x09 /* send cmd, n x send cfg */
  116. +#define CPLD_CMD_READ_NAND 0x0a /* send cmd, send idle, n x read data */
  117. +#define CPLD_CMD_READ_FAST 0x0b /* send cmd, 4 x idle, n x read data */
  118. +#define CPLD_CMD_LED5_ON 0x0c /* send cmd */
  119. +#define CPLD_CMD_LED5_OFF 0x0d /* send cmd */
  120. +
  121. +struct rb4xx_cpld {
  122. + struct spi_device *spi;
  123. + struct mutex lock;
  124. + struct gpio_chip chip;
  125. + unsigned int config;
  126. +};
  127. +
  128. +static struct rb4xx_cpld *rb4xx_cpld;
  129. +
  130. +static inline struct rb4xx_cpld *gpio_to_cpld(struct gpio_chip *chip)
  131. +{
  132. + return container_of(chip, struct rb4xx_cpld, chip);
  133. +}
  134. +
  135. +static int rb4xx_cpld_write_cmd(struct rb4xx_cpld *cpld, unsigned char cmd)
  136. +{
  137. + struct spi_transfer t[1];
  138. + struct spi_message m;
  139. + unsigned char tx_buf[1];
  140. + int err;
  141. +
  142. + spi_message_init(&m);
  143. + memset(&t, 0, sizeof(t));
  144. +
  145. + t[0].tx_buf = tx_buf;
  146. + t[0].len = sizeof(tx_buf);
  147. + spi_message_add_tail(&t[0], &m);
  148. +
  149. + tx_buf[0] = cmd;
  150. +
  151. + err = spi_sync(cpld->spi, &m);
  152. + return err;
  153. +}
  154. +
  155. +static int rb4xx_cpld_write_cfg(struct rb4xx_cpld *cpld, unsigned char config)
  156. +{
  157. + struct spi_transfer t[1];
  158. + struct spi_message m;
  159. + unsigned char cmd[2];
  160. + int err;
  161. +
  162. + spi_message_init(&m);
  163. + memset(&t, 0, sizeof(t));
  164. +
  165. + t[0].tx_buf = cmd;
  166. + t[0].len = sizeof(cmd);
  167. + spi_message_add_tail(&t[0], &m);
  168. +
  169. + cmd[0] = CPLD_CMD_WRITE_CFG;
  170. + cmd[1] = config;
  171. +
  172. + err = spi_sync(cpld->spi, &m);
  173. + return err;
  174. +}
  175. +
  176. +static int __rb4xx_cpld_change_cfg(struct rb4xx_cpld *cpld, unsigned mask,
  177. + unsigned value)
  178. +{
  179. + unsigned int config;
  180. + int err;
  181. +
  182. + config = cpld->config & ~mask;
  183. + config |= value;
  184. +
  185. + if ((cpld->config ^ config) & 0xff) {
  186. + err = rb4xx_cpld_write_cfg(cpld, config);
  187. + if (err)
  188. + return err;
  189. + }
  190. +
  191. + if ((cpld->config ^ config) & CPLD_CFG_nLED5) {
  192. + err = rb4xx_cpld_write_cmd(cpld, (value) ? CPLD_CMD_LED5_ON :
  193. + CPLD_CMD_LED5_OFF);
  194. + if (err)
  195. + return err;
  196. + }
  197. +
  198. + cpld->config = config;
  199. + return 0;
  200. +}
  201. +
  202. +int rb4xx_cpld_change_cfg(unsigned mask, unsigned value)
  203. +{
  204. + int ret;
  205. +
  206. + if (rb4xx_cpld == NULL)
  207. + return -ENODEV;
  208. +
  209. + mutex_lock(&rb4xx_cpld->lock);
  210. + ret = __rb4xx_cpld_change_cfg(rb4xx_cpld, mask, value);
  211. + mutex_unlock(&rb4xx_cpld->lock);
  212. +
  213. + return ret;
  214. +}
  215. +EXPORT_SYMBOL_GPL(rb4xx_cpld_change_cfg);
  216. +
  217. +int rb4xx_cpld_read_from(unsigned addr, unsigned char *rx_buf,
  218. + const unsigned char *verify_buf, unsigned count)
  219. +{
  220. + const unsigned char cmd[5] = {
  221. + CPLD_CMD_READ_FAST,
  222. + (addr >> 16) & 0xff,
  223. + (addr >> 8) & 0xff,
  224. + addr & 0xff,
  225. + 0
  226. + };
  227. + struct spi_transfer t[2] = {
  228. + {
  229. + .tx_buf = &cmd,
  230. + .len = 5,
  231. + },
  232. + {
  233. + .tx_buf = verify_buf,
  234. + .rx_buf = rx_buf,
  235. + .len = count,
  236. + .verify = (verify_buf != NULL),
  237. + },
  238. + };
  239. + struct spi_message m;
  240. +
  241. + if (rb4xx_cpld == NULL)
  242. + return -ENODEV;
  243. +
  244. + spi_message_init(&m);
  245. + m.fast_read = 1;
  246. + spi_message_add_tail(&t[0], &m);
  247. + spi_message_add_tail(&t[1], &m);
  248. + return spi_sync(rb4xx_cpld->spi, &m);
  249. +}
  250. +EXPORT_SYMBOL_GPL(rb4xx_cpld_read_from);
  251. +
  252. +#if 0
  253. +int rb4xx_cpld_read(unsigned char *buf, unsigned char *verify_buf,
  254. + unsigned count)
  255. +{
  256. + struct spi_transfer t[2];
  257. + struct spi_message m;
  258. + unsigned char cmd[2];
  259. +
  260. + if (rb4xx_cpld == NULL)
  261. + return -ENODEV;
  262. +
  263. + spi_message_init(&m);
  264. + memset(&t, 0, sizeof(t));
  265. +
  266. + /* send command */
  267. + t[0].tx_buf = cmd;
  268. + t[0].len = sizeof(cmd);
  269. + spi_message_add_tail(&t[0], &m);
  270. +
  271. + cmd[0] = CPLD_CMD_READ_NAND;
  272. + cmd[1] = 0;
  273. +
  274. + /* read data */
  275. + t[1].rx_buf = buf;
  276. + t[1].len = count;
  277. + spi_message_add_tail(&t[1], &m);
  278. +
  279. + return spi_sync(rb4xx_cpld->spi, &m);
  280. +}
  281. +#else
  282. +int rb4xx_cpld_read(unsigned char *rx_buf, const unsigned char *verify_buf,
  283. + unsigned count)
  284. +{
  285. + static const unsigned char cmd[2] = { CPLD_CMD_READ_NAND, 0 };
  286. + struct spi_transfer t[2] = {
  287. + {
  288. + .tx_buf = &cmd,
  289. + .len = 2,
  290. + }, {
  291. + .tx_buf = verify_buf,
  292. + .rx_buf = rx_buf,
  293. + .len = count,
  294. + .verify = (verify_buf != NULL),
  295. + },
  296. + };
  297. + struct spi_message m;
  298. +
  299. + if (rb4xx_cpld == NULL)
  300. + return -ENODEV;
  301. +
  302. + spi_message_init(&m);
  303. + spi_message_add_tail(&t[0], &m);
  304. + spi_message_add_tail(&t[1], &m);
  305. + return spi_sync(rb4xx_cpld->spi, &m);
  306. +}
  307. +#endif
  308. +EXPORT_SYMBOL_GPL(rb4xx_cpld_read);
  309. +
  310. +int rb4xx_cpld_write(const unsigned char *buf, unsigned count)
  311. +{
  312. +#if 0
  313. + struct spi_transfer t[3];
  314. + struct spi_message m;
  315. + unsigned char cmd[1];
  316. +
  317. + if (rb4xx_cpld == NULL)
  318. + return -ENODEV;
  319. +
  320. + memset(&t, 0, sizeof(t));
  321. + spi_message_init(&m);
  322. +
  323. + /* send command */
  324. + t[0].tx_buf = cmd;
  325. + t[0].len = sizeof(cmd);
  326. + spi_message_add_tail(&t[0], &m);
  327. +
  328. + cmd[0] = CPLD_CMD_WRITE_NAND;
  329. +
  330. + /* write data */
  331. + t[1].tx_buf = buf;
  332. + t[1].len = count;
  333. + spi_message_add_tail(&t[1], &m);
  334. +
  335. + /* send idle */
  336. + t[2].len = 1;
  337. + spi_message_add_tail(&t[2], &m);
  338. +
  339. + return spi_sync(rb4xx_cpld->spi, &m);
  340. +#else
  341. + static const unsigned char cmd = CPLD_CMD_WRITE_NAND;
  342. + struct spi_transfer t[3] = {
  343. + {
  344. + .tx_buf = &cmd,
  345. + .len = 1,
  346. + }, {
  347. + .tx_buf = buf,
  348. + .len = count,
  349. + .fast_write = 1,
  350. + }, {
  351. + .len = 1,
  352. + .fast_write = 1,
  353. + },
  354. + };
  355. + struct spi_message m;
  356. +
  357. + if (rb4xx_cpld == NULL)
  358. + return -ENODEV;
  359. +
  360. + spi_message_init(&m);
  361. + spi_message_add_tail(&t[0], &m);
  362. + spi_message_add_tail(&t[1], &m);
  363. + spi_message_add_tail(&t[2], &m);
  364. + return spi_sync(rb4xx_cpld->spi, &m);
  365. +#endif
  366. +}
  367. +EXPORT_SYMBOL_GPL(rb4xx_cpld_write);
  368. +
  369. +static int rb4xx_cpld_gpio_get(struct gpio_chip *chip, unsigned offset)
  370. +{
  371. + struct rb4xx_cpld *cpld = gpio_to_cpld(chip);
  372. + int ret;
  373. +
  374. + mutex_lock(&cpld->lock);
  375. + ret = (cpld->config >> offset) & 1;
  376. + mutex_unlock(&cpld->lock);
  377. +
  378. + return ret;
  379. +}
  380. +
  381. +static void rb4xx_cpld_gpio_set(struct gpio_chip *chip, unsigned offset,
  382. + int value)
  383. +{
  384. + struct rb4xx_cpld *cpld = gpio_to_cpld(chip);
  385. +
  386. + mutex_lock(&cpld->lock);
  387. + __rb4xx_cpld_change_cfg(cpld, (1 << offset), !!value << offset);
  388. + mutex_unlock(&cpld->lock);
  389. +}
  390. +
  391. +static int rb4xx_cpld_gpio_direction_input(struct gpio_chip *chip,
  392. + unsigned offset)
  393. +{
  394. + return -EOPNOTSUPP;
  395. +}
  396. +
  397. +static int rb4xx_cpld_gpio_direction_output(struct gpio_chip *chip,
  398. + unsigned offset,
  399. + int value)
  400. +{
  401. + struct rb4xx_cpld *cpld = gpio_to_cpld(chip);
  402. + int ret;
  403. +
  404. + mutex_lock(&cpld->lock);
  405. + ret = __rb4xx_cpld_change_cfg(cpld, (1 << offset), !!value << offset);
  406. + mutex_unlock(&cpld->lock);
  407. +
  408. + return ret;
  409. +}
  410. +
  411. +static int rb4xx_cpld_gpio_init(struct rb4xx_cpld *cpld, unsigned int base)
  412. +{
  413. + int err;
  414. +
  415. + /* init config */
  416. + cpld->config = CPLD_CFG_nLED1 | CPLD_CFG_nLED2 | CPLD_CFG_nLED3 |
  417. + CPLD_CFG_nLED4 | CPLD_CFG_nCE;
  418. + rb4xx_cpld_write_cfg(cpld, cpld->config);
  419. +
  420. + /* setup GPIO chip */
  421. + cpld->chip.label = DRV_NAME;
  422. +
  423. + cpld->chip.get = rb4xx_cpld_gpio_get;
  424. + cpld->chip.set = rb4xx_cpld_gpio_set;
  425. + cpld->chip.direction_input = rb4xx_cpld_gpio_direction_input;
  426. + cpld->chip.direction_output = rb4xx_cpld_gpio_direction_output;
  427. +
  428. + cpld->chip.base = base;
  429. + cpld->chip.ngpio = CPLD_NUM_GPIOS;
  430. + cpld->chip.can_sleep = 1;
  431. + cpld->chip.dev = &cpld->spi->dev;
  432. + cpld->chip.owner = THIS_MODULE;
  433. +
  434. + err = gpiochip_add(&cpld->chip);
  435. + if (err)
  436. + dev_err(&cpld->spi->dev, "adding GPIO chip failed, err=%d\n",
  437. + err);
  438. +
  439. + return err;
  440. +}
  441. +
  442. +static int rb4xx_cpld_probe(struct spi_device *spi)
  443. +{
  444. + struct rb4xx_cpld *cpld;
  445. + struct rb4xx_cpld_platform_data *pdata;
  446. + int err;
  447. +
  448. + pdata = spi->dev.platform_data;
  449. + if (!pdata) {
  450. + dev_dbg(&spi->dev, "no platform data\n");
  451. + return -EINVAL;
  452. + }
  453. +
  454. + cpld = kzalloc(sizeof(*cpld), GFP_KERNEL);
  455. + if (!cpld) {
  456. + dev_err(&spi->dev, "no memory for private data\n");
  457. + return -ENOMEM;
  458. + }
  459. +
  460. + mutex_init(&cpld->lock);
  461. + cpld->spi = spi_dev_get(spi);
  462. + dev_set_drvdata(&spi->dev, cpld);
  463. +
  464. + spi->mode = SPI_MODE_0;
  465. + spi->bits_per_word = 8;
  466. + err = spi_setup(spi);
  467. + if (err) {
  468. + dev_err(&spi->dev, "spi_setup failed, err=%d\n", err);
  469. + goto err_drvdata;
  470. + }
  471. +
  472. + err = rb4xx_cpld_gpio_init(cpld, pdata->gpio_base);
  473. + if (err)
  474. + goto err_drvdata;
  475. +
  476. + rb4xx_cpld = cpld;
  477. +
  478. + return 0;
  479. +
  480. +err_drvdata:
  481. + dev_set_drvdata(&spi->dev, NULL);
  482. + kfree(cpld);
  483. +
  484. + return err;
  485. +}
  486. +
  487. +static int rb4xx_cpld_remove(struct spi_device *spi)
  488. +{
  489. + struct rb4xx_cpld *cpld;
  490. +
  491. + rb4xx_cpld = NULL;
  492. + cpld = dev_get_drvdata(&spi->dev);
  493. + dev_set_drvdata(&spi->dev, NULL);
  494. + kfree(cpld);
  495. +
  496. + return 0;
  497. +}
  498. +
  499. +static struct spi_driver rb4xx_cpld_driver = {
  500. + .driver = {
  501. + .name = DRV_NAME,
  502. + .bus = &spi_bus_type,
  503. + .owner = THIS_MODULE,
  504. + },
  505. + .probe = rb4xx_cpld_probe,
  506. + .remove = rb4xx_cpld_remove,
  507. +};
  508. +
  509. +static int __init rb4xx_cpld_init(void)
  510. +{
  511. + return spi_register_driver(&rb4xx_cpld_driver);
  512. +}
  513. +module_init(rb4xx_cpld_init);
  514. +
  515. +static void __exit rb4xx_cpld_exit(void)
  516. +{
  517. + spi_unregister_driver(&rb4xx_cpld_driver);
  518. +}
  519. +module_exit(rb4xx_cpld_exit);
  520. +
  521. +MODULE_DESCRIPTION(DRV_DESC);
  522. +MODULE_VERSION(DRV_VERSION);
  523. +MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
  524. +MODULE_LICENSE("GPL v2");