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