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