timberdale.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * timberdale.c timberdale FPGA MFD driver
  4. * Copyright (c) 2009 Intel Corporation
  5. */
  6. /* Supports:
  7. * Timberdale FPGA
  8. */
  9. #include <linux/kernel.h>
  10. #include <linux/module.h>
  11. #include <linux/pci.h>
  12. #include <linux/msi.h>
  13. #include <linux/mfd/core.h>
  14. #include <linux/slab.h>
  15. #include <linux/timb_gpio.h>
  16. #include <linux/i2c.h>
  17. #include <linux/platform_data/i2c-ocores.h>
  18. #include <linux/platform_data/i2c-xiic.h>
  19. #include <linux/spi/spi.h>
  20. #include <linux/spi/xilinx_spi.h>
  21. #include <linux/spi/max7301.h>
  22. #include <linux/spi/mc33880.h>
  23. #include <linux/platform_data/tsc2007.h>
  24. #include <linux/platform_data/media/timb_radio.h>
  25. #include <linux/platform_data/media/timb_video.h>
  26. #include <linux/timb_dma.h>
  27. #include <linux/ks8842.h>
  28. #include "timberdale.h"
  29. #define DRIVER_NAME "timberdale"
  30. struct timberdale_device {
  31. resource_size_t ctl_mapbase;
  32. unsigned char __iomem *ctl_membase;
  33. struct {
  34. u32 major;
  35. u32 minor;
  36. u32 config;
  37. } fw;
  38. };
  39. /*--------------------------------------------------------------------------*/
  40. static struct tsc2007_platform_data timberdale_tsc2007_platform_data = {
  41. .model = 2003,
  42. .x_plate_ohms = 100
  43. };
  44. static struct i2c_board_info timberdale_i2c_board_info[] = {
  45. {
  46. I2C_BOARD_INFO("tsc2007", 0x48),
  47. .platform_data = &timberdale_tsc2007_platform_data,
  48. .irq = IRQ_TIMBERDALE_TSC_INT
  49. },
  50. };
  51. static struct xiic_i2c_platform_data
  52. timberdale_xiic_platform_data = {
  53. .devices = timberdale_i2c_board_info,
  54. .num_devices = ARRAY_SIZE(timberdale_i2c_board_info)
  55. };
  56. static struct ocores_i2c_platform_data
  57. timberdale_ocores_platform_data = {
  58. .reg_shift = 2,
  59. .clock_khz = 62500,
  60. .devices = timberdale_i2c_board_info,
  61. .num_devices = ARRAY_SIZE(timberdale_i2c_board_info)
  62. };
  63. static const struct resource timberdale_xiic_resources[] = {
  64. {
  65. .start = XIICOFFSET,
  66. .end = XIICEND,
  67. .flags = IORESOURCE_MEM,
  68. },
  69. {
  70. .start = IRQ_TIMBERDALE_I2C,
  71. .end = IRQ_TIMBERDALE_I2C,
  72. .flags = IORESOURCE_IRQ,
  73. },
  74. };
  75. static const struct resource timberdale_ocores_resources[] = {
  76. {
  77. .start = OCORESOFFSET,
  78. .end = OCORESEND,
  79. .flags = IORESOURCE_MEM,
  80. },
  81. {
  82. .start = IRQ_TIMBERDALE_I2C,
  83. .end = IRQ_TIMBERDALE_I2C,
  84. .flags = IORESOURCE_IRQ,
  85. },
  86. };
  87. static const struct max7301_platform_data timberdale_max7301_platform_data = {
  88. .base = 200
  89. };
  90. static const struct mc33880_platform_data timberdale_mc33880_platform_data = {
  91. .base = 100
  92. };
  93. static struct spi_board_info timberdale_spi_16bit_board_info[] = {
  94. {
  95. .modalias = "max7301",
  96. .max_speed_hz = 26000,
  97. .chip_select = 2,
  98. .mode = SPI_MODE_0,
  99. .platform_data = &timberdale_max7301_platform_data
  100. },
  101. };
  102. static struct spi_board_info timberdale_spi_8bit_board_info[] = {
  103. {
  104. .modalias = "mc33880",
  105. .max_speed_hz = 4000,
  106. .chip_select = 1,
  107. .mode = SPI_MODE_1,
  108. .platform_data = &timberdale_mc33880_platform_data
  109. },
  110. };
  111. static struct xspi_platform_data timberdale_xspi_platform_data = {
  112. .num_chipselect = 3,
  113. /* bits per word and devices will be filled in runtime depending
  114. * on the HW config
  115. */
  116. };
  117. static const struct resource timberdale_spi_resources[] = {
  118. {
  119. .start = SPIOFFSET,
  120. .end = SPIEND,
  121. .flags = IORESOURCE_MEM,
  122. },
  123. {
  124. .start = IRQ_TIMBERDALE_SPI,
  125. .end = IRQ_TIMBERDALE_SPI,
  126. .flags = IORESOURCE_IRQ,
  127. },
  128. };
  129. static struct ks8842_platform_data
  130. timberdale_ks8842_platform_data = {
  131. .rx_dma_channel = DMA_ETH_RX,
  132. .tx_dma_channel = DMA_ETH_TX
  133. };
  134. static const struct resource timberdale_eth_resources[] = {
  135. {
  136. .start = ETHOFFSET,
  137. .end = ETHEND,
  138. .flags = IORESOURCE_MEM,
  139. },
  140. {
  141. .start = IRQ_TIMBERDALE_ETHSW_IF,
  142. .end = IRQ_TIMBERDALE_ETHSW_IF,
  143. .flags = IORESOURCE_IRQ,
  144. },
  145. };
  146. static struct timbgpio_platform_data
  147. timberdale_gpio_platform_data = {
  148. .gpio_base = 0,
  149. .nr_pins = GPIO_NR_PINS,
  150. .irq_base = 200,
  151. };
  152. static const struct resource timberdale_gpio_resources[] = {
  153. {
  154. .start = GPIOOFFSET,
  155. .end = GPIOEND,
  156. .flags = IORESOURCE_MEM,
  157. },
  158. {
  159. .start = IRQ_TIMBERDALE_GPIO,
  160. .end = IRQ_TIMBERDALE_GPIO,
  161. .flags = IORESOURCE_IRQ,
  162. },
  163. };
  164. static const struct resource timberdale_mlogicore_resources[] = {
  165. {
  166. .start = MLCOREOFFSET,
  167. .end = MLCOREEND,
  168. .flags = IORESOURCE_MEM,
  169. },
  170. {
  171. .start = IRQ_TIMBERDALE_MLCORE,
  172. .end = IRQ_TIMBERDALE_MLCORE,
  173. .flags = IORESOURCE_IRQ,
  174. },
  175. {
  176. .start = IRQ_TIMBERDALE_MLCORE_BUF,
  177. .end = IRQ_TIMBERDALE_MLCORE_BUF,
  178. .flags = IORESOURCE_IRQ,
  179. },
  180. };
  181. static const struct resource timberdale_uart_resources[] = {
  182. {
  183. .start = UARTOFFSET,
  184. .end = UARTEND,
  185. .flags = IORESOURCE_MEM,
  186. },
  187. {
  188. .start = IRQ_TIMBERDALE_UART,
  189. .end = IRQ_TIMBERDALE_UART,
  190. .flags = IORESOURCE_IRQ,
  191. },
  192. };
  193. static const struct resource timberdale_uartlite_resources[] = {
  194. {
  195. .start = UARTLITEOFFSET,
  196. .end = UARTLITEEND,
  197. .flags = IORESOURCE_MEM,
  198. },
  199. {
  200. .start = IRQ_TIMBERDALE_UARTLITE,
  201. .end = IRQ_TIMBERDALE_UARTLITE,
  202. .flags = IORESOURCE_IRQ,
  203. },
  204. };
  205. static struct i2c_board_info timberdale_adv7180_i2c_board_info = {
  206. /* Requires jumper JP9 to be off */
  207. I2C_BOARD_INFO("adv7180", 0x42 >> 1),
  208. .irq = IRQ_TIMBERDALE_ADV7180
  209. };
  210. static struct timb_video_platform_data
  211. timberdale_video_platform_data = {
  212. .dma_channel = DMA_VIDEO_RX,
  213. .i2c_adapter = 0,
  214. .encoder = {
  215. .info = &timberdale_adv7180_i2c_board_info
  216. }
  217. };
  218. static const struct resource
  219. timberdale_radio_resources[] = {
  220. {
  221. .start = RDSOFFSET,
  222. .end = RDSEND,
  223. .flags = IORESOURCE_MEM,
  224. },
  225. {
  226. .start = IRQ_TIMBERDALE_RDS,
  227. .end = IRQ_TIMBERDALE_RDS,
  228. .flags = IORESOURCE_IRQ,
  229. },
  230. };
  231. static struct i2c_board_info timberdale_tef6868_i2c_board_info = {
  232. I2C_BOARD_INFO("tef6862", 0x60)
  233. };
  234. static struct i2c_board_info timberdale_saa7706_i2c_board_info = {
  235. I2C_BOARD_INFO("saa7706h", 0x1C)
  236. };
  237. static struct timb_radio_platform_data
  238. timberdale_radio_platform_data = {
  239. .i2c_adapter = 0,
  240. .tuner = &timberdale_tef6868_i2c_board_info,
  241. .dsp = &timberdale_saa7706_i2c_board_info
  242. };
  243. static const struct resource timberdale_video_resources[] = {
  244. {
  245. .start = LOGIWOFFSET,
  246. .end = LOGIWEND,
  247. .flags = IORESOURCE_MEM,
  248. },
  249. /*
  250. note that the "frame buffer" is located in DMA area
  251. starting at 0x1200000
  252. */
  253. };
  254. static struct timb_dma_platform_data timb_dma_platform_data = {
  255. .nr_channels = 10,
  256. .channels = {
  257. {
  258. /* UART RX */
  259. .rx = true,
  260. .descriptors = 2,
  261. .descriptor_elements = 1
  262. },
  263. {
  264. /* UART TX */
  265. .rx = false,
  266. .descriptors = 2,
  267. .descriptor_elements = 1
  268. },
  269. {
  270. /* MLB RX */
  271. .rx = true,
  272. .descriptors = 2,
  273. .descriptor_elements = 1
  274. },
  275. {
  276. /* MLB TX */
  277. .rx = false,
  278. .descriptors = 2,
  279. .descriptor_elements = 1
  280. },
  281. {
  282. /* Video RX */
  283. .rx = true,
  284. .bytes_per_line = 1440,
  285. .descriptors = 2,
  286. .descriptor_elements = 16
  287. },
  288. {
  289. /* Video framedrop */
  290. },
  291. {
  292. /* SDHCI RX */
  293. .rx = true,
  294. },
  295. {
  296. /* SDHCI TX */
  297. },
  298. {
  299. /* ETH RX */
  300. .rx = true,
  301. .descriptors = 2,
  302. .descriptor_elements = 1
  303. },
  304. {
  305. /* ETH TX */
  306. .rx = false,
  307. .descriptors = 2,
  308. .descriptor_elements = 1
  309. },
  310. }
  311. };
  312. static const struct resource timberdale_dma_resources[] = {
  313. {
  314. .start = DMAOFFSET,
  315. .end = DMAEND,
  316. .flags = IORESOURCE_MEM,
  317. },
  318. {
  319. .start = IRQ_TIMBERDALE_DMA,
  320. .end = IRQ_TIMBERDALE_DMA,
  321. .flags = IORESOURCE_IRQ,
  322. },
  323. };
  324. static const struct mfd_cell timberdale_cells_bar0_cfg0[] = {
  325. {
  326. .name = "timb-dma",
  327. .num_resources = ARRAY_SIZE(timberdale_dma_resources),
  328. .resources = timberdale_dma_resources,
  329. .platform_data = &timb_dma_platform_data,
  330. .pdata_size = sizeof(timb_dma_platform_data),
  331. },
  332. {
  333. .name = "timb-uart",
  334. .num_resources = ARRAY_SIZE(timberdale_uart_resources),
  335. .resources = timberdale_uart_resources,
  336. },
  337. {
  338. .name = "xiic-i2c",
  339. .num_resources = ARRAY_SIZE(timberdale_xiic_resources),
  340. .resources = timberdale_xiic_resources,
  341. .platform_data = &timberdale_xiic_platform_data,
  342. .pdata_size = sizeof(timberdale_xiic_platform_data),
  343. },
  344. {
  345. .name = "timb-gpio",
  346. .num_resources = ARRAY_SIZE(timberdale_gpio_resources),
  347. .resources = timberdale_gpio_resources,
  348. .platform_data = &timberdale_gpio_platform_data,
  349. .pdata_size = sizeof(timberdale_gpio_platform_data),
  350. },
  351. {
  352. .name = "timb-video",
  353. .num_resources = ARRAY_SIZE(timberdale_video_resources),
  354. .resources = timberdale_video_resources,
  355. .platform_data = &timberdale_video_platform_data,
  356. .pdata_size = sizeof(timberdale_video_platform_data),
  357. },
  358. {
  359. .name = "timb-radio",
  360. .num_resources = ARRAY_SIZE(timberdale_radio_resources),
  361. .resources = timberdale_radio_resources,
  362. .platform_data = &timberdale_radio_platform_data,
  363. .pdata_size = sizeof(timberdale_radio_platform_data),
  364. },
  365. {
  366. .name = "xilinx_spi",
  367. .num_resources = ARRAY_SIZE(timberdale_spi_resources),
  368. .resources = timberdale_spi_resources,
  369. .platform_data = &timberdale_xspi_platform_data,
  370. .pdata_size = sizeof(timberdale_xspi_platform_data),
  371. },
  372. {
  373. .name = "ks8842",
  374. .num_resources = ARRAY_SIZE(timberdale_eth_resources),
  375. .resources = timberdale_eth_resources,
  376. .platform_data = &timberdale_ks8842_platform_data,
  377. .pdata_size = sizeof(timberdale_ks8842_platform_data),
  378. },
  379. };
  380. static const struct mfd_cell timberdale_cells_bar0_cfg1[] = {
  381. {
  382. .name = "timb-dma",
  383. .num_resources = ARRAY_SIZE(timberdale_dma_resources),
  384. .resources = timberdale_dma_resources,
  385. .platform_data = &timb_dma_platform_data,
  386. .pdata_size = sizeof(timb_dma_platform_data),
  387. },
  388. {
  389. .name = "timb-uart",
  390. .num_resources = ARRAY_SIZE(timberdale_uart_resources),
  391. .resources = timberdale_uart_resources,
  392. },
  393. {
  394. .name = "uartlite",
  395. .num_resources = ARRAY_SIZE(timberdale_uartlite_resources),
  396. .resources = timberdale_uartlite_resources,
  397. },
  398. {
  399. .name = "xiic-i2c",
  400. .num_resources = ARRAY_SIZE(timberdale_xiic_resources),
  401. .resources = timberdale_xiic_resources,
  402. .platform_data = &timberdale_xiic_platform_data,
  403. .pdata_size = sizeof(timberdale_xiic_platform_data),
  404. },
  405. {
  406. .name = "timb-gpio",
  407. .num_resources = ARRAY_SIZE(timberdale_gpio_resources),
  408. .resources = timberdale_gpio_resources,
  409. .platform_data = &timberdale_gpio_platform_data,
  410. .pdata_size = sizeof(timberdale_gpio_platform_data),
  411. },
  412. {
  413. .name = "timb-mlogicore",
  414. .num_resources = ARRAY_SIZE(timberdale_mlogicore_resources),
  415. .resources = timberdale_mlogicore_resources,
  416. },
  417. {
  418. .name = "timb-video",
  419. .num_resources = ARRAY_SIZE(timberdale_video_resources),
  420. .resources = timberdale_video_resources,
  421. .platform_data = &timberdale_video_platform_data,
  422. .pdata_size = sizeof(timberdale_video_platform_data),
  423. },
  424. {
  425. .name = "timb-radio",
  426. .num_resources = ARRAY_SIZE(timberdale_radio_resources),
  427. .resources = timberdale_radio_resources,
  428. .platform_data = &timberdale_radio_platform_data,
  429. .pdata_size = sizeof(timberdale_radio_platform_data),
  430. },
  431. {
  432. .name = "xilinx_spi",
  433. .num_resources = ARRAY_SIZE(timberdale_spi_resources),
  434. .resources = timberdale_spi_resources,
  435. .platform_data = &timberdale_xspi_platform_data,
  436. .pdata_size = sizeof(timberdale_xspi_platform_data),
  437. },
  438. {
  439. .name = "ks8842",
  440. .num_resources = ARRAY_SIZE(timberdale_eth_resources),
  441. .resources = timberdale_eth_resources,
  442. .platform_data = &timberdale_ks8842_platform_data,
  443. .pdata_size = sizeof(timberdale_ks8842_platform_data),
  444. },
  445. };
  446. static const struct mfd_cell timberdale_cells_bar0_cfg2[] = {
  447. {
  448. .name = "timb-dma",
  449. .num_resources = ARRAY_SIZE(timberdale_dma_resources),
  450. .resources = timberdale_dma_resources,
  451. .platform_data = &timb_dma_platform_data,
  452. .pdata_size = sizeof(timb_dma_platform_data),
  453. },
  454. {
  455. .name = "timb-uart",
  456. .num_resources = ARRAY_SIZE(timberdale_uart_resources),
  457. .resources = timberdale_uart_resources,
  458. },
  459. {
  460. .name = "xiic-i2c",
  461. .num_resources = ARRAY_SIZE(timberdale_xiic_resources),
  462. .resources = timberdale_xiic_resources,
  463. .platform_data = &timberdale_xiic_platform_data,
  464. .pdata_size = sizeof(timberdale_xiic_platform_data),
  465. },
  466. {
  467. .name = "timb-gpio",
  468. .num_resources = ARRAY_SIZE(timberdale_gpio_resources),
  469. .resources = timberdale_gpio_resources,
  470. .platform_data = &timberdale_gpio_platform_data,
  471. .pdata_size = sizeof(timberdale_gpio_platform_data),
  472. },
  473. {
  474. .name = "timb-video",
  475. .num_resources = ARRAY_SIZE(timberdale_video_resources),
  476. .resources = timberdale_video_resources,
  477. .platform_data = &timberdale_video_platform_data,
  478. .pdata_size = sizeof(timberdale_video_platform_data),
  479. },
  480. {
  481. .name = "timb-radio",
  482. .num_resources = ARRAY_SIZE(timberdale_radio_resources),
  483. .resources = timberdale_radio_resources,
  484. .platform_data = &timberdale_radio_platform_data,
  485. .pdata_size = sizeof(timberdale_radio_platform_data),
  486. },
  487. {
  488. .name = "xilinx_spi",
  489. .num_resources = ARRAY_SIZE(timberdale_spi_resources),
  490. .resources = timberdale_spi_resources,
  491. .platform_data = &timberdale_xspi_platform_data,
  492. .pdata_size = sizeof(timberdale_xspi_platform_data),
  493. },
  494. };
  495. static const struct mfd_cell timberdale_cells_bar0_cfg3[] = {
  496. {
  497. .name = "timb-dma",
  498. .num_resources = ARRAY_SIZE(timberdale_dma_resources),
  499. .resources = timberdale_dma_resources,
  500. .platform_data = &timb_dma_platform_data,
  501. .pdata_size = sizeof(timb_dma_platform_data),
  502. },
  503. {
  504. .name = "timb-uart",
  505. .num_resources = ARRAY_SIZE(timberdale_uart_resources),
  506. .resources = timberdale_uart_resources,
  507. },
  508. {
  509. .name = "ocores-i2c",
  510. .num_resources = ARRAY_SIZE(timberdale_ocores_resources),
  511. .resources = timberdale_ocores_resources,
  512. .platform_data = &timberdale_ocores_platform_data,
  513. .pdata_size = sizeof(timberdale_ocores_platform_data),
  514. },
  515. {
  516. .name = "timb-gpio",
  517. .num_resources = ARRAY_SIZE(timberdale_gpio_resources),
  518. .resources = timberdale_gpio_resources,
  519. .platform_data = &timberdale_gpio_platform_data,
  520. .pdata_size = sizeof(timberdale_gpio_platform_data),
  521. },
  522. {
  523. .name = "timb-video",
  524. .num_resources = ARRAY_SIZE(timberdale_video_resources),
  525. .resources = timberdale_video_resources,
  526. .platform_data = &timberdale_video_platform_data,
  527. .pdata_size = sizeof(timberdale_video_platform_data),
  528. },
  529. {
  530. .name = "timb-radio",
  531. .num_resources = ARRAY_SIZE(timberdale_radio_resources),
  532. .resources = timberdale_radio_resources,
  533. .platform_data = &timberdale_radio_platform_data,
  534. .pdata_size = sizeof(timberdale_radio_platform_data),
  535. },
  536. {
  537. .name = "xilinx_spi",
  538. .num_resources = ARRAY_SIZE(timberdale_spi_resources),
  539. .resources = timberdale_spi_resources,
  540. .platform_data = &timberdale_xspi_platform_data,
  541. .pdata_size = sizeof(timberdale_xspi_platform_data),
  542. },
  543. {
  544. .name = "ks8842",
  545. .num_resources = ARRAY_SIZE(timberdale_eth_resources),
  546. .resources = timberdale_eth_resources,
  547. .platform_data = &timberdale_ks8842_platform_data,
  548. .pdata_size = sizeof(timberdale_ks8842_platform_data),
  549. },
  550. };
  551. static const struct resource timberdale_sdhc_resources[] = {
  552. /* located in bar 1 and bar 2 */
  553. {
  554. .start = SDHC0OFFSET,
  555. .end = SDHC0END,
  556. .flags = IORESOURCE_MEM,
  557. },
  558. {
  559. .start = IRQ_TIMBERDALE_SDHC,
  560. .end = IRQ_TIMBERDALE_SDHC,
  561. .flags = IORESOURCE_IRQ,
  562. },
  563. };
  564. static const struct mfd_cell timberdale_cells_bar1[] = {
  565. {
  566. .name = "sdhci",
  567. .num_resources = ARRAY_SIZE(timberdale_sdhc_resources),
  568. .resources = timberdale_sdhc_resources,
  569. },
  570. };
  571. static const struct mfd_cell timberdale_cells_bar2[] = {
  572. {
  573. .name = "sdhci",
  574. .num_resources = ARRAY_SIZE(timberdale_sdhc_resources),
  575. .resources = timberdale_sdhc_resources,
  576. },
  577. };
  578. static ssize_t show_fw_ver(struct device *dev, struct device_attribute *attr,
  579. char *buf)
  580. {
  581. struct timberdale_device *priv = dev_get_drvdata(dev);
  582. return sprintf(buf, "%d.%d.%d\n", priv->fw.major, priv->fw.minor,
  583. priv->fw.config);
  584. }
  585. static DEVICE_ATTR(fw_ver, S_IRUGO, show_fw_ver, NULL);
  586. /*--------------------------------------------------------------------------*/
  587. static int timb_probe(struct pci_dev *dev,
  588. const struct pci_device_id *id)
  589. {
  590. struct timberdale_device *priv;
  591. int err, i;
  592. resource_size_t mapbase;
  593. struct msix_entry *msix_entries = NULL;
  594. u8 ip_setup;
  595. priv = kzalloc(sizeof(*priv), GFP_KERNEL);
  596. if (!priv)
  597. return -ENOMEM;
  598. pci_set_drvdata(dev, priv);
  599. err = pci_enable_device(dev);
  600. if (err)
  601. goto err_enable;
  602. mapbase = pci_resource_start(dev, 0);
  603. if (!mapbase) {
  604. dev_err(&dev->dev, "No resource\n");
  605. goto err_start;
  606. }
  607. /* create a resource for the PCI master register */
  608. priv->ctl_mapbase = mapbase + CHIPCTLOFFSET;
  609. if (!request_mem_region(priv->ctl_mapbase, CHIPCTLSIZE, "timb-ctl")) {
  610. dev_err(&dev->dev, "Failed to request ctl mem\n");
  611. goto err_start;
  612. }
  613. priv->ctl_membase = ioremap(priv->ctl_mapbase, CHIPCTLSIZE);
  614. if (!priv->ctl_membase) {
  615. dev_err(&dev->dev, "ioremap failed for ctl mem\n");
  616. goto err_ioremap;
  617. }
  618. /* read the HW config */
  619. priv->fw.major = ioread32(priv->ctl_membase + TIMB_REV_MAJOR);
  620. priv->fw.minor = ioread32(priv->ctl_membase + TIMB_REV_MINOR);
  621. priv->fw.config = ioread32(priv->ctl_membase + TIMB_HW_CONFIG);
  622. if (priv->fw.major > TIMB_SUPPORTED_MAJOR) {
  623. dev_err(&dev->dev, "The driver supports an older "
  624. "version of the FPGA, please update the driver to "
  625. "support %d.%d\n", priv->fw.major, priv->fw.minor);
  626. goto err_config;
  627. }
  628. if (priv->fw.major < TIMB_SUPPORTED_MAJOR ||
  629. priv->fw.minor < TIMB_REQUIRED_MINOR) {
  630. dev_err(&dev->dev, "The FPGA image is too old (%d.%d), "
  631. "please upgrade the FPGA to at least: %d.%d\n",
  632. priv->fw.major, priv->fw.minor,
  633. TIMB_SUPPORTED_MAJOR, TIMB_REQUIRED_MINOR);
  634. goto err_config;
  635. }
  636. msix_entries = kcalloc(TIMBERDALE_NR_IRQS, sizeof(*msix_entries),
  637. GFP_KERNEL);
  638. if (!msix_entries)
  639. goto err_config;
  640. for (i = 0; i < TIMBERDALE_NR_IRQS; i++)
  641. msix_entries[i].entry = i;
  642. err = pci_enable_msix_exact(dev, msix_entries, TIMBERDALE_NR_IRQS);
  643. if (err) {
  644. dev_err(&dev->dev,
  645. "MSI-X init failed: %d, expected entries: %d\n",
  646. err, TIMBERDALE_NR_IRQS);
  647. goto err_msix;
  648. }
  649. err = device_create_file(&dev->dev, &dev_attr_fw_ver);
  650. if (err)
  651. goto err_create_file;
  652. /* Reset all FPGA PLB peripherals */
  653. iowrite32(0x1, priv->ctl_membase + TIMB_SW_RST);
  654. /* update IRQ offsets in I2C board info */
  655. for (i = 0; i < ARRAY_SIZE(timberdale_i2c_board_info); i++)
  656. timberdale_i2c_board_info[i].irq =
  657. msix_entries[timberdale_i2c_board_info[i].irq].vector;
  658. /* Update the SPI configuration depending on the HW (8 or 16 bit) */
  659. if (priv->fw.config & TIMB_HW_CONFIG_SPI_8BIT) {
  660. timberdale_xspi_platform_data.bits_per_word = 8;
  661. timberdale_xspi_platform_data.devices =
  662. timberdale_spi_8bit_board_info;
  663. timberdale_xspi_platform_data.num_devices =
  664. ARRAY_SIZE(timberdale_spi_8bit_board_info);
  665. } else {
  666. timberdale_xspi_platform_data.bits_per_word = 16;
  667. timberdale_xspi_platform_data.devices =
  668. timberdale_spi_16bit_board_info;
  669. timberdale_xspi_platform_data.num_devices =
  670. ARRAY_SIZE(timberdale_spi_16bit_board_info);
  671. }
  672. ip_setup = priv->fw.config & TIMB_HW_VER_MASK;
  673. switch (ip_setup) {
  674. case TIMB_HW_VER0:
  675. err = mfd_add_devices(&dev->dev, -1,
  676. timberdale_cells_bar0_cfg0,
  677. ARRAY_SIZE(timberdale_cells_bar0_cfg0),
  678. &dev->resource[0], msix_entries[0].vector, NULL);
  679. break;
  680. case TIMB_HW_VER1:
  681. err = mfd_add_devices(&dev->dev, -1,
  682. timberdale_cells_bar0_cfg1,
  683. ARRAY_SIZE(timberdale_cells_bar0_cfg1),
  684. &dev->resource[0], msix_entries[0].vector, NULL);
  685. break;
  686. case TIMB_HW_VER2:
  687. err = mfd_add_devices(&dev->dev, -1,
  688. timberdale_cells_bar0_cfg2,
  689. ARRAY_SIZE(timberdale_cells_bar0_cfg2),
  690. &dev->resource[0], msix_entries[0].vector, NULL);
  691. break;
  692. case TIMB_HW_VER3:
  693. err = mfd_add_devices(&dev->dev, -1,
  694. timberdale_cells_bar0_cfg3,
  695. ARRAY_SIZE(timberdale_cells_bar0_cfg3),
  696. &dev->resource[0], msix_entries[0].vector, NULL);
  697. break;
  698. default:
  699. dev_err(&dev->dev, "Unknown IP setup: %d.%d.%d\n",
  700. priv->fw.major, priv->fw.minor, ip_setup);
  701. err = -ENODEV;
  702. goto err_mfd;
  703. }
  704. if (err) {
  705. dev_err(&dev->dev, "mfd_add_devices failed: %d\n", err);
  706. goto err_mfd;
  707. }
  708. err = mfd_add_devices(&dev->dev, 0,
  709. timberdale_cells_bar1, ARRAY_SIZE(timberdale_cells_bar1),
  710. &dev->resource[1], msix_entries[0].vector, NULL);
  711. if (err) {
  712. dev_err(&dev->dev, "mfd_add_devices failed: %d\n", err);
  713. goto err_mfd2;
  714. }
  715. /* only version 0 and 3 have the iNand routed to SDHCI */
  716. if (((priv->fw.config & TIMB_HW_VER_MASK) == TIMB_HW_VER0) ||
  717. ((priv->fw.config & TIMB_HW_VER_MASK) == TIMB_HW_VER3)) {
  718. err = mfd_add_devices(&dev->dev, 1, timberdale_cells_bar2,
  719. ARRAY_SIZE(timberdale_cells_bar2),
  720. &dev->resource[2], msix_entries[0].vector, NULL);
  721. if (err) {
  722. dev_err(&dev->dev, "mfd_add_devices failed: %d\n", err);
  723. goto err_mfd2;
  724. }
  725. }
  726. kfree(msix_entries);
  727. dev_info(&dev->dev,
  728. "Found Timberdale Card. Rev: %d.%d, HW config: 0x%02x\n",
  729. priv->fw.major, priv->fw.minor, priv->fw.config);
  730. return 0;
  731. err_mfd2:
  732. mfd_remove_devices(&dev->dev);
  733. err_mfd:
  734. device_remove_file(&dev->dev, &dev_attr_fw_ver);
  735. err_create_file:
  736. pci_disable_msix(dev);
  737. err_msix:
  738. kfree(msix_entries);
  739. err_config:
  740. iounmap(priv->ctl_membase);
  741. err_ioremap:
  742. release_mem_region(priv->ctl_mapbase, CHIPCTLSIZE);
  743. err_start:
  744. pci_disable_device(dev);
  745. err_enable:
  746. kfree(priv);
  747. return -ENODEV;
  748. }
  749. static void timb_remove(struct pci_dev *dev)
  750. {
  751. struct timberdale_device *priv = pci_get_drvdata(dev);
  752. mfd_remove_devices(&dev->dev);
  753. device_remove_file(&dev->dev, &dev_attr_fw_ver);
  754. iounmap(priv->ctl_membase);
  755. release_mem_region(priv->ctl_mapbase, CHIPCTLSIZE);
  756. pci_disable_msix(dev);
  757. pci_disable_device(dev);
  758. kfree(priv);
  759. }
  760. static const struct pci_device_id timberdale_pci_tbl[] = {
  761. { PCI_DEVICE(PCI_VENDOR_ID_TIMB, PCI_DEVICE_ID_TIMB) },
  762. { 0 }
  763. };
  764. MODULE_DEVICE_TABLE(pci, timberdale_pci_tbl);
  765. static struct pci_driver timberdale_pci_driver = {
  766. .name = DRIVER_NAME,
  767. .id_table = timberdale_pci_tbl,
  768. .probe = timb_probe,
  769. .remove = timb_remove,
  770. };
  771. module_pci_driver(timberdale_pci_driver);
  772. MODULE_AUTHOR("Mocean Laboratories <info@mocean-labs.com>");
  773. MODULE_VERSION(DRV_VERSION);
  774. MODULE_LICENSE("GPL v2");