2 * timberdale.c timberdale FPGA MFD driver
3 * Copyright (c) 2009 Intel Corporation
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.
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.
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.
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>
30 #include <linux/timb_gpio.h>
32 #include <linux/i2c.h>
33 #include <linux/i2c-ocores.h>
34 #include <linux/i2c-xiic.h>
35 #include <linux/i2c/tsc2007.h>
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>
42 #include <media/timb_radio.h>
43 #include <media/timb_video.h>
45 #include <linux/timb_dma.h>
47 #include <linux/ks8842.h>
49 #include "timberdale.h"
51 #define DRIVER_NAME "timberdale"
53 struct timberdale_device
{
54 resource_size_t ctl_mapbase
;
55 unsigned char __iomem
*ctl_membase
;
63 /*--------------------------------------------------------------------------*/
65 static struct tsc2007_platform_data timberdale_tsc2007_platform_data
= {
70 static struct i2c_board_info timberdale_i2c_board_info
[] = {
72 I2C_BOARD_INFO("tsc2007", 0x48),
73 .platform_data
= &timberdale_tsc2007_platform_data
,
74 .irq
= IRQ_TIMBERDALE_TSC_INT
78 static struct xiic_i2c_platform_data
79 timberdale_xiic_platform_data
= {
80 .devices
= timberdale_i2c_board_info
,
81 .num_devices
= ARRAY_SIZE(timberdale_i2c_board_info
)
84 static struct ocores_i2c_platform_data
85 timberdale_ocores_platform_data
= {
88 .devices
= timberdale_i2c_board_info
,
89 .num_devices
= ARRAY_SIZE(timberdale_i2c_board_info
)
92 static const struct resource timberdale_xiic_resources
[] = {
96 .flags
= IORESOURCE_MEM
,
99 .start
= IRQ_TIMBERDALE_I2C
,
100 .end
= IRQ_TIMBERDALE_I2C
,
101 .flags
= IORESOURCE_IRQ
,
105 static const struct resource timberdale_ocores_resources
[] = {
107 .start
= OCORESOFFSET
,
109 .flags
= IORESOURCE_MEM
,
112 .start
= IRQ_TIMBERDALE_I2C
,
113 .end
= IRQ_TIMBERDALE_I2C
,
114 .flags
= IORESOURCE_IRQ
,
118 static const struct max7301_platform_data timberdale_max7301_platform_data
= {
122 static const struct mc33880_platform_data timberdale_mc33880_platform_data
= {
126 static struct spi_board_info timberdale_spi_16bit_board_info
[] = {
128 .modalias
= "max7301",
129 .max_speed_hz
= 26000,
132 .platform_data
= &timberdale_max7301_platform_data
136 static struct spi_board_info timberdale_spi_8bit_board_info
[] = {
138 .modalias
= "mc33880",
139 .max_speed_hz
= 4000,
142 .platform_data
= &timberdale_mc33880_platform_data
146 static struct xspi_platform_data timberdale_xspi_platform_data
= {
148 /* bits per word and devices will be filled in runtime depending
153 static const struct resource timberdale_spi_resources
[] = {
157 .flags
= IORESOURCE_MEM
,
160 .start
= IRQ_TIMBERDALE_SPI
,
161 .end
= IRQ_TIMBERDALE_SPI
,
162 .flags
= IORESOURCE_IRQ
,
166 static struct ks8842_platform_data
167 timberdale_ks8842_platform_data
= {
168 .rx_dma_channel
= DMA_ETH_RX
,
169 .tx_dma_channel
= DMA_ETH_TX
172 static const struct resource timberdale_eth_resources
[] = {
176 .flags
= IORESOURCE_MEM
,
179 .start
= IRQ_TIMBERDALE_ETHSW_IF
,
180 .end
= IRQ_TIMBERDALE_ETHSW_IF
,
181 .flags
= IORESOURCE_IRQ
,
185 static struct timbgpio_platform_data
186 timberdale_gpio_platform_data
= {
188 .nr_pins
= GPIO_NR_PINS
,
192 static const struct resource timberdale_gpio_resources
[] = {
196 .flags
= IORESOURCE_MEM
,
199 .start
= IRQ_TIMBERDALE_GPIO
,
200 .end
= IRQ_TIMBERDALE_GPIO
,
201 .flags
= IORESOURCE_IRQ
,
205 static const struct resource timberdale_mlogicore_resources
[] = {
207 .start
= MLCOREOFFSET
,
209 .flags
= IORESOURCE_MEM
,
212 .start
= IRQ_TIMBERDALE_MLCORE
,
213 .end
= IRQ_TIMBERDALE_MLCORE
,
214 .flags
= IORESOURCE_IRQ
,
217 .start
= IRQ_TIMBERDALE_MLCORE_BUF
,
218 .end
= IRQ_TIMBERDALE_MLCORE_BUF
,
219 .flags
= IORESOURCE_IRQ
,
223 static const struct resource timberdale_uart_resources
[] = {
227 .flags
= IORESOURCE_MEM
,
230 .start
= IRQ_TIMBERDALE_UART
,
231 .end
= IRQ_TIMBERDALE_UART
,
232 .flags
= IORESOURCE_IRQ
,
236 static const struct resource timberdale_uartlite_resources
[] = {
238 .start
= UARTLITEOFFSET
,
240 .flags
= IORESOURCE_MEM
,
243 .start
= IRQ_TIMBERDALE_UARTLITE
,
244 .end
= IRQ_TIMBERDALE_UARTLITE
,
245 .flags
= IORESOURCE_IRQ
,
249 static struct i2c_board_info timberdale_adv7180_i2c_board_info
= {
250 /* Requires jumper JP9 to be off */
251 I2C_BOARD_INFO("adv7180", 0x42 >> 1),
252 .irq
= IRQ_TIMBERDALE_ADV7180
255 static struct timb_video_platform_data
256 timberdale_video_platform_data
= {
257 .dma_channel
= DMA_VIDEO_RX
,
260 .info
= &timberdale_adv7180_i2c_board_info
264 static const struct resource
265 timberdale_radio_resources
[] = {
269 .flags
= IORESOURCE_MEM
,
272 .start
= IRQ_TIMBERDALE_RDS
,
273 .end
= IRQ_TIMBERDALE_RDS
,
274 .flags
= IORESOURCE_IRQ
,
278 static struct i2c_board_info timberdale_tef6868_i2c_board_info
= {
279 I2C_BOARD_INFO("tef6862", 0x60)
282 static struct i2c_board_info timberdale_saa7706_i2c_board_info
= {
283 I2C_BOARD_INFO("saa7706h", 0x1C)
286 static struct timb_radio_platform_data
287 timberdale_radio_platform_data
= {
289 .tuner
= &timberdale_tef6868_i2c_board_info
,
290 .dsp
= &timberdale_saa7706_i2c_board_info
293 static const struct resource timberdale_video_resources
[] = {
295 .start
= LOGIWOFFSET
,
297 .flags
= IORESOURCE_MEM
,
300 note that the "frame buffer" is located in DMA area
301 starting at 0x1200000
305 static struct timb_dma_platform_data timb_dma_platform_data
= {
312 .descriptor_elements
= 1
318 .descriptor_elements
= 1
324 .descriptor_elements
= 1
330 .descriptor_elements
= 1
335 .bytes_per_line
= 1440,
337 .descriptor_elements
= 16
340 /* Video framedrop */
353 .descriptor_elements
= 1
359 .descriptor_elements
= 1
364 static const struct resource timberdale_dma_resources
[] = {
368 .flags
= IORESOURCE_MEM
,
371 .start
= IRQ_TIMBERDALE_DMA
,
372 .end
= IRQ_TIMBERDALE_DMA
,
373 .flags
= IORESOURCE_IRQ
,
377 static const struct mfd_cell timberdale_cells_bar0_cfg0
[] = {
380 .num_resources
= ARRAY_SIZE(timberdale_dma_resources
),
381 .resources
= timberdale_dma_resources
,
382 .platform_data
= &timb_dma_platform_data
,
383 .pdata_size
= sizeof(timb_dma_platform_data
),
387 .num_resources
= ARRAY_SIZE(timberdale_uart_resources
),
388 .resources
= timberdale_uart_resources
,
392 .num_resources
= ARRAY_SIZE(timberdale_xiic_resources
),
393 .resources
= timberdale_xiic_resources
,
394 .platform_data
= &timberdale_xiic_platform_data
,
395 .pdata_size
= sizeof(timberdale_xiic_platform_data
),
399 .num_resources
= ARRAY_SIZE(timberdale_gpio_resources
),
400 .resources
= timberdale_gpio_resources
,
401 .platform_data
= &timberdale_gpio_platform_data
,
402 .pdata_size
= sizeof(timberdale_gpio_platform_data
),
405 .name
= "timb-video",
406 .num_resources
= ARRAY_SIZE(timberdale_video_resources
),
407 .resources
= timberdale_video_resources
,
408 .platform_data
= &timberdale_video_platform_data
,
409 .pdata_size
= sizeof(timberdale_video_platform_data
),
412 .name
= "timb-radio",
413 .num_resources
= ARRAY_SIZE(timberdale_radio_resources
),
414 .resources
= timberdale_radio_resources
,
415 .platform_data
= &timberdale_radio_platform_data
,
416 .pdata_size
= sizeof(timberdale_radio_platform_data
),
419 .name
= "xilinx_spi",
420 .num_resources
= ARRAY_SIZE(timberdale_spi_resources
),
421 .resources
= timberdale_spi_resources
,
422 .platform_data
= &timberdale_xspi_platform_data
,
423 .pdata_size
= sizeof(timberdale_xspi_platform_data
),
427 .num_resources
= ARRAY_SIZE(timberdale_eth_resources
),
428 .resources
= timberdale_eth_resources
,
429 .platform_data
= &timberdale_ks8842_platform_data
,
430 .pdata_size
= sizeof(timberdale_ks8842_platform_data
),
434 static const struct mfd_cell timberdale_cells_bar0_cfg1
[] = {
437 .num_resources
= ARRAY_SIZE(timberdale_dma_resources
),
438 .resources
= timberdale_dma_resources
,
439 .platform_data
= &timb_dma_platform_data
,
440 .pdata_size
= sizeof(timb_dma_platform_data
),
444 .num_resources
= ARRAY_SIZE(timberdale_uart_resources
),
445 .resources
= timberdale_uart_resources
,
449 .num_resources
= ARRAY_SIZE(timberdale_uartlite_resources
),
450 .resources
= timberdale_uartlite_resources
,
454 .num_resources
= ARRAY_SIZE(timberdale_xiic_resources
),
455 .resources
= timberdale_xiic_resources
,
456 .platform_data
= &timberdale_xiic_platform_data
,
457 .pdata_size
= sizeof(timberdale_xiic_platform_data
),
461 .num_resources
= ARRAY_SIZE(timberdale_gpio_resources
),
462 .resources
= timberdale_gpio_resources
,
463 .platform_data
= &timberdale_gpio_platform_data
,
464 .pdata_size
= sizeof(timberdale_gpio_platform_data
),
467 .name
= "timb-mlogicore",
468 .num_resources
= ARRAY_SIZE(timberdale_mlogicore_resources
),
469 .resources
= timberdale_mlogicore_resources
,
472 .name
= "timb-video",
473 .num_resources
= ARRAY_SIZE(timberdale_video_resources
),
474 .resources
= timberdale_video_resources
,
475 .platform_data
= &timberdale_video_platform_data
,
476 .pdata_size
= sizeof(timberdale_video_platform_data
),
479 .name
= "timb-radio",
480 .num_resources
= ARRAY_SIZE(timberdale_radio_resources
),
481 .resources
= timberdale_radio_resources
,
482 .platform_data
= &timberdale_radio_platform_data
,
483 .pdata_size
= sizeof(timberdale_radio_platform_data
),
486 .name
= "xilinx_spi",
487 .num_resources
= ARRAY_SIZE(timberdale_spi_resources
),
488 .resources
= timberdale_spi_resources
,
489 .platform_data
= &timberdale_xspi_platform_data
,
490 .pdata_size
= sizeof(timberdale_xspi_platform_data
),
494 .num_resources
= ARRAY_SIZE(timberdale_eth_resources
),
495 .resources
= timberdale_eth_resources
,
496 .platform_data
= &timberdale_ks8842_platform_data
,
497 .pdata_size
= sizeof(timberdale_ks8842_platform_data
),
501 static const struct mfd_cell timberdale_cells_bar0_cfg2
[] = {
504 .num_resources
= ARRAY_SIZE(timberdale_dma_resources
),
505 .resources
= timberdale_dma_resources
,
506 .platform_data
= &timb_dma_platform_data
,
507 .pdata_size
= sizeof(timb_dma_platform_data
),
511 .num_resources
= ARRAY_SIZE(timberdale_uart_resources
),
512 .resources
= timberdale_uart_resources
,
516 .num_resources
= ARRAY_SIZE(timberdale_xiic_resources
),
517 .resources
= timberdale_xiic_resources
,
518 .platform_data
= &timberdale_xiic_platform_data
,
519 .pdata_size
= sizeof(timberdale_xiic_platform_data
),
523 .num_resources
= ARRAY_SIZE(timberdale_gpio_resources
),
524 .resources
= timberdale_gpio_resources
,
525 .platform_data
= &timberdale_gpio_platform_data
,
526 .pdata_size
= sizeof(timberdale_gpio_platform_data
),
529 .name
= "timb-video",
530 .num_resources
= ARRAY_SIZE(timberdale_video_resources
),
531 .resources
= timberdale_video_resources
,
532 .platform_data
= &timberdale_video_platform_data
,
533 .pdata_size
= sizeof(timberdale_video_platform_data
),
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 .pdata_size
= sizeof(timberdale_radio_platform_data
),
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 .pdata_size
= sizeof(timberdale_xspi_platform_data
),
551 static const struct mfd_cell timberdale_cells_bar0_cfg3
[] = {
554 .num_resources
= ARRAY_SIZE(timberdale_dma_resources
),
555 .resources
= timberdale_dma_resources
,
556 .platform_data
= &timb_dma_platform_data
,
557 .pdata_size
= sizeof(timb_dma_platform_data
),
561 .num_resources
= ARRAY_SIZE(timberdale_uart_resources
),
562 .resources
= timberdale_uart_resources
,
565 .name
= "ocores-i2c",
566 .num_resources
= ARRAY_SIZE(timberdale_ocores_resources
),
567 .resources
= timberdale_ocores_resources
,
568 .platform_data
= &timberdale_ocores_platform_data
,
569 .pdata_size
= sizeof(timberdale_ocores_platform_data
),
573 .num_resources
= ARRAY_SIZE(timberdale_gpio_resources
),
574 .resources
= timberdale_gpio_resources
,
575 .platform_data
= &timberdale_gpio_platform_data
,
576 .pdata_size
= sizeof(timberdale_gpio_platform_data
),
579 .name
= "timb-video",
580 .num_resources
= ARRAY_SIZE(timberdale_video_resources
),
581 .resources
= timberdale_video_resources
,
582 .platform_data
= &timberdale_video_platform_data
,
583 .pdata_size
= sizeof(timberdale_video_platform_data
),
586 .name
= "timb-radio",
587 .num_resources
= ARRAY_SIZE(timberdale_radio_resources
),
588 .resources
= timberdale_radio_resources
,
589 .platform_data
= &timberdale_radio_platform_data
,
590 .pdata_size
= sizeof(timberdale_radio_platform_data
),
593 .name
= "xilinx_spi",
594 .num_resources
= ARRAY_SIZE(timberdale_spi_resources
),
595 .resources
= timberdale_spi_resources
,
596 .platform_data
= &timberdale_xspi_platform_data
,
597 .pdata_size
= sizeof(timberdale_xspi_platform_data
),
601 .num_resources
= ARRAY_SIZE(timberdale_eth_resources
),
602 .resources
= timberdale_eth_resources
,
603 .platform_data
= &timberdale_ks8842_platform_data
,
604 .pdata_size
= sizeof(timberdale_ks8842_platform_data
),
608 static const struct resource timberdale_sdhc_resources
[] = {
609 /* located in bar 1 and bar 2 */
611 .start
= SDHC0OFFSET
,
613 .flags
= IORESOURCE_MEM
,
616 .start
= IRQ_TIMBERDALE_SDHC
,
617 .end
= IRQ_TIMBERDALE_SDHC
,
618 .flags
= IORESOURCE_IRQ
,
622 static const struct mfd_cell timberdale_cells_bar1
[] = {
625 .num_resources
= ARRAY_SIZE(timberdale_sdhc_resources
),
626 .resources
= timberdale_sdhc_resources
,
630 static const struct mfd_cell timberdale_cells_bar2
[] = {
633 .num_resources
= ARRAY_SIZE(timberdale_sdhc_resources
),
634 .resources
= timberdale_sdhc_resources
,
638 static ssize_t
show_fw_ver(struct device
*dev
, struct device_attribute
*attr
,
641 struct pci_dev
*pdev
= to_pci_dev(dev
);
642 struct timberdale_device
*priv
= pci_get_drvdata(pdev
);
644 return sprintf(buf
, "%d.%d.%d\n", priv
->fw
.major
, priv
->fw
.minor
,
648 static DEVICE_ATTR(fw_ver
, S_IRUGO
, show_fw_ver
, NULL
);
650 /*--------------------------------------------------------------------------*/
652 static int timb_probe(struct pci_dev
*dev
,
653 const struct pci_device_id
*id
)
655 struct timberdale_device
*priv
;
657 resource_size_t mapbase
;
658 struct msix_entry
*msix_entries
= NULL
;
661 priv
= kzalloc(sizeof(*priv
), GFP_KERNEL
);
665 pci_set_drvdata(dev
, priv
);
667 err
= pci_enable_device(dev
);
671 mapbase
= pci_resource_start(dev
, 0);
673 dev_err(&dev
->dev
, "No resource\n");
677 /* create a resource for the PCI master register */
678 priv
->ctl_mapbase
= mapbase
+ CHIPCTLOFFSET
;
679 if (!request_mem_region(priv
->ctl_mapbase
, CHIPCTLSIZE
, "timb-ctl")) {
680 dev_err(&dev
->dev
, "Failed to request ctl mem\n");
684 priv
->ctl_membase
= ioremap(priv
->ctl_mapbase
, CHIPCTLSIZE
);
685 if (!priv
->ctl_membase
) {
686 dev_err(&dev
->dev
, "ioremap failed for ctl mem\n");
690 /* read the HW config */
691 priv
->fw
.major
= ioread32(priv
->ctl_membase
+ TIMB_REV_MAJOR
);
692 priv
->fw
.minor
= ioread32(priv
->ctl_membase
+ TIMB_REV_MINOR
);
693 priv
->fw
.config
= ioread32(priv
->ctl_membase
+ TIMB_HW_CONFIG
);
695 if (priv
->fw
.major
> TIMB_SUPPORTED_MAJOR
) {
696 dev_err(&dev
->dev
, "The driver supports an older "
697 "version of the FPGA, please update the driver to "
698 "support %d.%d\n", priv
->fw
.major
, priv
->fw
.minor
);
701 if (priv
->fw
.major
< TIMB_SUPPORTED_MAJOR
||
702 priv
->fw
.minor
< TIMB_REQUIRED_MINOR
) {
703 dev_err(&dev
->dev
, "The FPGA image is too old (%d.%d), "
704 "please upgrade the FPGA to at least: %d.%d\n",
705 priv
->fw
.major
, priv
->fw
.minor
,
706 TIMB_SUPPORTED_MAJOR
, TIMB_REQUIRED_MINOR
);
710 msix_entries
= kzalloc(TIMBERDALE_NR_IRQS
* sizeof(*msix_entries
),
715 for (i
= 0; i
< TIMBERDALE_NR_IRQS
; i
++)
716 msix_entries
[i
].entry
= i
;
718 err
= pci_enable_msix_exact(dev
, msix_entries
, TIMBERDALE_NR_IRQS
);
721 "MSI-X init failed: %d, expected entries: %d\n",
722 err
, TIMBERDALE_NR_IRQS
);
726 err
= device_create_file(&dev
->dev
, &dev_attr_fw_ver
);
728 goto err_create_file
;
730 /* Reset all FPGA PLB peripherals */
731 iowrite32(0x1, priv
->ctl_membase
+ TIMB_SW_RST
);
733 /* update IRQ offsets in I2C board info */
734 for (i
= 0; i
< ARRAY_SIZE(timberdale_i2c_board_info
); i
++)
735 timberdale_i2c_board_info
[i
].irq
=
736 msix_entries
[timberdale_i2c_board_info
[i
].irq
].vector
;
738 /* Update the SPI configuration depending on the HW (8 or 16 bit) */
739 if (priv
->fw
.config
& TIMB_HW_CONFIG_SPI_8BIT
) {
740 timberdale_xspi_platform_data
.bits_per_word
= 8;
741 timberdale_xspi_platform_data
.devices
=
742 timberdale_spi_8bit_board_info
;
743 timberdale_xspi_platform_data
.num_devices
=
744 ARRAY_SIZE(timberdale_spi_8bit_board_info
);
746 timberdale_xspi_platform_data
.bits_per_word
= 16;
747 timberdale_xspi_platform_data
.devices
=
748 timberdale_spi_16bit_board_info
;
749 timberdale_xspi_platform_data
.num_devices
=
750 ARRAY_SIZE(timberdale_spi_16bit_board_info
);
753 ip_setup
= priv
->fw
.config
& TIMB_HW_VER_MASK
;
756 err
= mfd_add_devices(&dev
->dev
, -1,
757 timberdale_cells_bar0_cfg0
,
758 ARRAY_SIZE(timberdale_cells_bar0_cfg0
),
759 &dev
->resource
[0], msix_entries
[0].vector
, NULL
);
762 err
= mfd_add_devices(&dev
->dev
, -1,
763 timberdale_cells_bar0_cfg1
,
764 ARRAY_SIZE(timberdale_cells_bar0_cfg1
),
765 &dev
->resource
[0], msix_entries
[0].vector
, NULL
);
768 err
= mfd_add_devices(&dev
->dev
, -1,
769 timberdale_cells_bar0_cfg2
,
770 ARRAY_SIZE(timberdale_cells_bar0_cfg2
),
771 &dev
->resource
[0], msix_entries
[0].vector
, NULL
);
774 err
= mfd_add_devices(&dev
->dev
, -1,
775 timberdale_cells_bar0_cfg3
,
776 ARRAY_SIZE(timberdale_cells_bar0_cfg3
),
777 &dev
->resource
[0], msix_entries
[0].vector
, NULL
);
780 dev_err(&dev
->dev
, "Uknown IP setup: %d.%d.%d\n",
781 priv
->fw
.major
, priv
->fw
.minor
, ip_setup
);
787 dev_err(&dev
->dev
, "mfd_add_devices failed: %d\n", err
);
791 err
= mfd_add_devices(&dev
->dev
, 0,
792 timberdale_cells_bar1
, ARRAY_SIZE(timberdale_cells_bar1
),
793 &dev
->resource
[1], msix_entries
[0].vector
, NULL
);
795 dev_err(&dev
->dev
, "mfd_add_devices failed: %d\n", err
);
799 /* only version 0 and 3 have the iNand routed to SDHCI */
800 if (((priv
->fw
.config
& TIMB_HW_VER_MASK
) == TIMB_HW_VER0
) ||
801 ((priv
->fw
.config
& TIMB_HW_VER_MASK
) == TIMB_HW_VER3
)) {
802 err
= mfd_add_devices(&dev
->dev
, 1, timberdale_cells_bar2
,
803 ARRAY_SIZE(timberdale_cells_bar2
),
804 &dev
->resource
[2], msix_entries
[0].vector
, NULL
);
806 dev_err(&dev
->dev
, "mfd_add_devices failed: %d\n", err
);
814 "Found Timberdale Card. Rev: %d.%d, HW config: 0x%02x\n",
815 priv
->fw
.major
, priv
->fw
.minor
, priv
->fw
.config
);
820 mfd_remove_devices(&dev
->dev
);
822 device_remove_file(&dev
->dev
, &dev_attr_fw_ver
);
824 pci_disable_msix(dev
);
828 iounmap(priv
->ctl_membase
);
830 release_mem_region(priv
->ctl_mapbase
, CHIPCTLSIZE
);
832 pci_disable_device(dev
);
838 static void timb_remove(struct pci_dev
*dev
)
840 struct timberdale_device
*priv
= pci_get_drvdata(dev
);
842 mfd_remove_devices(&dev
->dev
);
844 device_remove_file(&dev
->dev
, &dev_attr_fw_ver
);
846 iounmap(priv
->ctl_membase
);
847 release_mem_region(priv
->ctl_mapbase
, CHIPCTLSIZE
);
849 pci_disable_msix(dev
);
850 pci_disable_device(dev
);
854 static const struct pci_device_id timberdale_pci_tbl
[] = {
855 { PCI_DEVICE(PCI_VENDOR_ID_TIMB
, PCI_DEVICE_ID_TIMB
) },
858 MODULE_DEVICE_TABLE(pci
, timberdale_pci_tbl
);
860 static struct pci_driver timberdale_pci_driver
= {
862 .id_table
= timberdale_pci_tbl
,
864 .remove
= timb_remove
,
867 module_pci_driver(timberdale_pci_driver
);
869 MODULE_AUTHOR("Mocean Laboratories <info@mocean-labs.com>");
870 MODULE_VERSION(DRV_VERSION
);
871 MODULE_LICENSE("GPL v2");