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