aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Röjfors <richard.rojfors@pelagicore.com>2010-02-04 06:18:52 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2010-02-26 13:10:56 -0500
commit8edbede9ebf5959ec9951175a239925225440f5f (patch)
tree8389065970e63b4ab4ed1530126c3c252c731535
parentd44d1f3bfaef71ce27b4fd2284ec528b52617977 (diff)
V4L/DVB: mfd: Add support for the timberdale FPGA
The timberdale FPGA is found on the Intel in-Vehicle Infotainment reference board russelville. The driver is a PCI driver which chunks up the I/O memory and distributes interrupts to a number of platform devices for each IP inside the FPGA. Signed-off-by: Richard Röjfors <richard.rojfors@pelagicore.com> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r--drivers/mfd/Kconfig10
-rw-r--r--drivers/mfd/Makefile3
-rw-r--r--drivers/mfd/timberdale.c663
-rw-r--r--drivers/mfd/timberdale.h130
4 files changed, 805 insertions, 1 deletions
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 87829789243e..eb22deeecb1a 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -348,6 +348,16 @@ config AB4500_CORE
348 read/write functions for the devices to get access to this chip. 348 read/write functions for the devices to get access to this chip.
349 This chip embeds various other multimedia funtionalities as well. 349 This chip embeds various other multimedia funtionalities as well.
350 350
351config MFD_TIMBERDALE
352 tristate "Support for the Timberdale FPGA"
353 select MFD_CORE
354 depends on PCI
355 ---help---
356 This is the core driver for the timberdale FPGA. This device is a
357 multifunction device which exposes numerous platform devices.
358
359 The timberdale FPGA can be found on the Intel Atom development board
360 for in-vehicle infontainment, called Russellville.
351endmenu 361endmenu
352 362
353menu "Multimedia Capabilities Port drivers" 363menu "Multimedia Capabilities Port drivers"
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index e09eb4870db6..78295d6a75f7 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -54,5 +54,6 @@ obj-$(CONFIG_PCF50633_GPIO) += pcf50633-gpio.o
54obj-$(CONFIG_AB3100_CORE) += ab3100-core.o 54obj-$(CONFIG_AB3100_CORE) += ab3100-core.o
55obj-$(CONFIG_AB3100_OTP) += ab3100-otp.o 55obj-$(CONFIG_AB3100_OTP) += ab3100-otp.o
56obj-$(CONFIG_AB4500_CORE) += ab4500-core.o 56obj-$(CONFIG_AB4500_CORE) += ab4500-core.o
57obj-$(CONFIG_MFD_TIMBERDALE) += timberdale.o
57obj-$(CONFIG_MFD_88PM8607) += 88pm8607.o 58obj-$(CONFIG_MFD_88PM8607) += 88pm8607.o
58obj-$(CONFIG_PMIC_ADP5520) += adp5520.o \ No newline at end of file 59obj-$(CONFIG_PMIC_ADP5520) += adp5520.o
diff --git a/drivers/mfd/timberdale.c b/drivers/mfd/timberdale.c
new file mode 100644
index 000000000000..603cf069ad24
--- /dev/null
+++ b/drivers/mfd/timberdale.c
@@ -0,0 +1,663 @@
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
29#include <linux/timb_gpio.h>
30
31#include <linux/i2c.h>
32#include <linux/i2c-ocores.h>
33#include <linux/i2c/tsc2007.h>
34
35#include <linux/spi/spi.h>
36#include <linux/spi/xilinx_spi.h>
37#include <linux/spi/max7301.h>
38#include <linux/spi/mc33880.h>
39
40#include "timberdale.h"
41
42#define DRIVER_NAME "timberdale"
43
44struct timberdale_device {
45 resource_size_t ctl_mapbase;
46 unsigned char __iomem *ctl_membase;
47 struct {
48 u32 major;
49 u32 minor;
50 u32 config;
51 } fw;
52};
53
54/*--------------------------------------------------------------------------*/
55
56static struct tsc2007_platform_data timberdale_tsc2007_platform_data = {
57 .model = 2003,
58 .x_plate_ohms = 100
59};
60
61static struct i2c_board_info timberdale_i2c_board_info[] = {
62 {
63 I2C_BOARD_INFO("tsc2007", 0x48),
64 .platform_data = &timberdale_tsc2007_platform_data,
65 .irq = IRQ_TIMBERDALE_TSC_INT
66 },
67};
68
69static __devinitdata struct ocores_i2c_platform_data
70timberdale_ocores_platform_data = {
71 .regstep = 4,
72 .clock_khz = 62500,
73 .devices = timberdale_i2c_board_info,
74 .num_devices = ARRAY_SIZE(timberdale_i2c_board_info)
75};
76
77const static __devinitconst struct resource timberdale_ocores_resources[] = {
78 {
79 .start = OCORESOFFSET,
80 .end = OCORESEND,
81 .flags = IORESOURCE_MEM,
82 },
83 {
84 .start = IRQ_TIMBERDALE_I2C,
85 .end = IRQ_TIMBERDALE_I2C,
86 .flags = IORESOURCE_IRQ,
87 },
88};
89
90const struct max7301_platform_data timberdale_max7301_platform_data = {
91 .base = 200
92};
93
94const struct mc33880_platform_data timberdale_mc33880_platform_data = {
95 .base = 100
96};
97
98static struct spi_board_info timberdale_spi_16bit_board_info[] = {
99 {
100 .modalias = "max7301",
101 .max_speed_hz = 26000,
102 .chip_select = 2,
103 .mode = SPI_MODE_0,
104 .platform_data = &timberdale_max7301_platform_data
105 },
106};
107
108static struct spi_board_info timberdale_spi_8bit_board_info[] = {
109 {
110 .modalias = "mc33880",
111 .max_speed_hz = 4000,
112 .chip_select = 1,
113 .mode = SPI_MODE_1,
114 .platform_data = &timberdale_mc33880_platform_data
115 },
116};
117
118static __devinitdata struct xspi_platform_data timberdale_xspi_platform_data = {
119 .num_chipselect = 3,
120 .little_endian = true,
121 /* bits per word and devices will be filled in runtime depending
122 * on the HW config
123 */
124};
125
126const static __devinitconst struct resource timberdale_spi_resources[] = {
127 {
128 .start = SPIOFFSET,
129 .end = SPIEND,
130 .flags = IORESOURCE_MEM,
131 },
132 {
133 .start = IRQ_TIMBERDALE_SPI,
134 .end = IRQ_TIMBERDALE_SPI,
135 .flags = IORESOURCE_IRQ,
136 },
137};
138
139const static __devinitconst struct resource timberdale_eth_resources[] = {
140 {
141 .start = ETHOFFSET,
142 .end = ETHEND,
143 .flags = IORESOURCE_MEM,
144 },
145 {
146 .start = IRQ_TIMBERDALE_ETHSW_IF,
147 .end = IRQ_TIMBERDALE_ETHSW_IF,
148 .flags = IORESOURCE_IRQ,
149 },
150};
151
152static __devinitdata struct timbgpio_platform_data
153 timberdale_gpio_platform_data = {
154 .gpio_base = 0,
155 .nr_pins = GPIO_NR_PINS,
156 .irq_base = 200,
157};
158
159const static __devinitconst struct resource timberdale_gpio_resources[] = {
160 {
161 .start = GPIOOFFSET,
162 .end = GPIOEND,
163 .flags = IORESOURCE_MEM,
164 },
165 {
166 .start = IRQ_TIMBERDALE_GPIO,
167 .end = IRQ_TIMBERDALE_GPIO,
168 .flags = IORESOURCE_IRQ,
169 },
170};
171
172const static __devinitconst struct resource timberdale_mlogicore_resources[] = {
173 {
174 .start = MLCOREOFFSET,
175 .end = MLCOREEND,
176 .flags = IORESOURCE_MEM,
177 },
178 {
179 .start = IRQ_TIMBERDALE_MLCORE,
180 .end = IRQ_TIMBERDALE_MLCORE,
181 .flags = IORESOURCE_IRQ,
182 },
183 {
184 .start = IRQ_TIMBERDALE_MLCORE_BUF,
185 .end = IRQ_TIMBERDALE_MLCORE_BUF,
186 .flags = IORESOURCE_IRQ,
187 },
188};
189
190const static __devinitconst struct resource timberdale_uart_resources[] = {
191 {
192 .start = UARTOFFSET,
193 .end = UARTEND,
194 .flags = IORESOURCE_MEM,
195 },
196 {
197 .start = IRQ_TIMBERDALE_UART,
198 .end = IRQ_TIMBERDALE_UART,
199 .flags = IORESOURCE_IRQ,
200 },
201};
202
203const static __devinitconst struct resource timberdale_uartlite_resources[] = {
204 {
205 .start = UARTLITEOFFSET,
206 .end = UARTLITEEND,
207 .flags = IORESOURCE_MEM,
208 },
209 {
210 .start = IRQ_TIMBERDALE_UARTLITE,
211 .end = IRQ_TIMBERDALE_UARTLITE,
212 .flags = IORESOURCE_IRQ,
213 },
214};
215
216const static __devinitconst struct resource timberdale_dma_resources[] = {
217 {
218 .start = DMAOFFSET,
219 .end = DMAEND,
220 .flags = IORESOURCE_MEM,
221 },
222 {
223 .start = IRQ_TIMBERDALE_DMA,
224 .end = IRQ_TIMBERDALE_DMA,
225 .flags = IORESOURCE_IRQ,
226 },
227};
228
229static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg0[] = {
230 {
231 .name = "timb-uart",
232 .num_resources = ARRAY_SIZE(timberdale_uart_resources),
233 .resources = timberdale_uart_resources,
234 },
235 {
236 .name = "timb-gpio",
237 .num_resources = ARRAY_SIZE(timberdale_gpio_resources),
238 .resources = timberdale_gpio_resources,
239 .platform_data = &timberdale_gpio_platform_data,
240 .data_size = sizeof(timberdale_gpio_platform_data),
241 },
242 {
243 .name = "xilinx_spi",
244 .num_resources = ARRAY_SIZE(timberdale_spi_resources),
245 .resources = timberdale_spi_resources,
246 .platform_data = &timberdale_xspi_platform_data,
247 .data_size = sizeof(timberdale_xspi_platform_data),
248 },
249 {
250 .name = "ks8842",
251 .num_resources = ARRAY_SIZE(timberdale_eth_resources),
252 .resources = timberdale_eth_resources,
253 },
254 {
255 .name = "timb-dma",
256 .num_resources = ARRAY_SIZE(timberdale_dma_resources),
257 .resources = timberdale_dma_resources,
258 },
259};
260
261static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg1[] = {
262 {
263 .name = "timb-uart",
264 .num_resources = ARRAY_SIZE(timberdale_uart_resources),
265 .resources = timberdale_uart_resources,
266 },
267 {
268 .name = "uartlite",
269 .num_resources = ARRAY_SIZE(timberdale_uartlite_resources),
270 .resources = timberdale_uartlite_resources,
271 },
272 {
273 .name = "timb-gpio",
274 .num_resources = ARRAY_SIZE(timberdale_gpio_resources),
275 .resources = timberdale_gpio_resources,
276 .platform_data = &timberdale_gpio_platform_data,
277 .data_size = sizeof(timberdale_gpio_platform_data),
278 },
279 {
280 .name = "timb-mlogicore",
281 .num_resources = ARRAY_SIZE(timberdale_mlogicore_resources),
282 .resources = timberdale_mlogicore_resources,
283 },
284 {
285 .name = "xilinx_spi",
286 .num_resources = ARRAY_SIZE(timberdale_spi_resources),
287 .resources = timberdale_spi_resources,
288 .platform_data = &timberdale_xspi_platform_data,
289 .data_size = sizeof(timberdale_xspi_platform_data),
290 },
291 {
292 .name = "ks8842",
293 .num_resources = ARRAY_SIZE(timberdale_eth_resources),
294 .resources = timberdale_eth_resources,
295 },
296 {
297 .name = "timb-dma",
298 .num_resources = ARRAY_SIZE(timberdale_dma_resources),
299 .resources = timberdale_dma_resources,
300 },
301};
302
303static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg2[] = {
304 {
305 .name = "timb-uart",
306 .num_resources = ARRAY_SIZE(timberdale_uart_resources),
307 .resources = timberdale_uart_resources,
308 },
309 {
310 .name = "timb-gpio",
311 .num_resources = ARRAY_SIZE(timberdale_gpio_resources),
312 .resources = timberdale_gpio_resources,
313 .platform_data = &timberdale_gpio_platform_data,
314 .data_size = sizeof(timberdale_gpio_platform_data),
315 },
316 {
317 .name = "xilinx_spi",
318 .num_resources = ARRAY_SIZE(timberdale_spi_resources),
319 .resources = timberdale_spi_resources,
320 .platform_data = &timberdale_xspi_platform_data,
321 .data_size = sizeof(timberdale_xspi_platform_data),
322 },
323 {
324 .name = "timb-dma",
325 .num_resources = ARRAY_SIZE(timberdale_dma_resources),
326 .resources = timberdale_dma_resources,
327 },
328};
329
330static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg3[] = {
331 {
332 .name = "timb-uart",
333 .num_resources = ARRAY_SIZE(timberdale_uart_resources),
334 .resources = timberdale_uart_resources,
335 },
336 {
337 .name = "ocores-i2c",
338 .num_resources = ARRAY_SIZE(timberdale_ocores_resources),
339 .resources = timberdale_ocores_resources,
340 .platform_data = &timberdale_ocores_platform_data,
341 .data_size = sizeof(timberdale_ocores_platform_data),
342 },
343 {
344 .name = "timb-gpio",
345 .num_resources = ARRAY_SIZE(timberdale_gpio_resources),
346 .resources = timberdale_gpio_resources,
347 .platform_data = &timberdale_gpio_platform_data,
348 .data_size = sizeof(timberdale_gpio_platform_data),
349 },
350 {
351 .name = "xilinx_spi",
352 .num_resources = ARRAY_SIZE(timberdale_spi_resources),
353 .resources = timberdale_spi_resources,
354 .platform_data = &timberdale_xspi_platform_data,
355 .data_size = sizeof(timberdale_xspi_platform_data),
356 },
357 {
358 .name = "ks8842",
359 .num_resources = ARRAY_SIZE(timberdale_eth_resources),
360 .resources = timberdale_eth_resources,
361 },
362 {
363 .name = "timb-dma",
364 .num_resources = ARRAY_SIZE(timberdale_dma_resources),
365 .resources = timberdale_dma_resources,
366 },
367};
368
369static const __devinitconst struct resource timberdale_sdhc_resources[] = {
370 /* located in bar 1 and bar 2 */
371 {
372 .start = SDHC0OFFSET,
373 .end = SDHC0END,
374 .flags = IORESOURCE_MEM,
375 },
376 {
377 .start = IRQ_TIMBERDALE_SDHC,
378 .end = IRQ_TIMBERDALE_SDHC,
379 .flags = IORESOURCE_IRQ,
380 },
381};
382
383static __devinitdata struct mfd_cell timberdale_cells_bar1[] = {
384 {
385 .name = "sdhci",
386 .num_resources = ARRAY_SIZE(timberdale_sdhc_resources),
387 .resources = timberdale_sdhc_resources,
388 },
389};
390
391static __devinitdata struct mfd_cell timberdale_cells_bar2[] = {
392 {
393 .name = "sdhci",
394 .num_resources = ARRAY_SIZE(timberdale_sdhc_resources),
395 .resources = timberdale_sdhc_resources,
396 },
397};
398
399static ssize_t show_fw_ver(struct device *dev, struct device_attribute *attr,
400 char *buf)
401{
402 struct pci_dev *pdev = to_pci_dev(dev);
403 struct timberdale_device *priv = pci_get_drvdata(pdev);
404
405 return sprintf(buf, "%d.%d.%d\n", priv->fw.major, priv->fw.minor,
406 priv->fw.config);
407}
408
409static DEVICE_ATTR(fw_ver, S_IRUGO, show_fw_ver, NULL);
410
411/*--------------------------------------------------------------------------*/
412
413static int __devinit timb_probe(struct pci_dev *dev,
414 const struct pci_device_id *id)
415{
416 struct timberdale_device *priv;
417 int err, i;
418 resource_size_t mapbase;
419 struct msix_entry *msix_entries = NULL;
420 u8 ip_setup;
421
422 priv = kzalloc(sizeof(*priv), GFP_KERNEL);
423 if (!priv)
424 return -ENOMEM;
425
426 pci_set_drvdata(dev, priv);
427
428 err = pci_enable_device(dev);
429 if (err)
430 goto err_enable;
431
432 mapbase = pci_resource_start(dev, 0);
433 if (!mapbase) {
434 dev_err(&dev->dev, "No resource\n");
435 goto err_start;
436 }
437
438 /* create a resource for the PCI master register */
439 priv->ctl_mapbase = mapbase + CHIPCTLOFFSET;
440 if (!request_mem_region(priv->ctl_mapbase, CHIPCTLSIZE, "timb-ctl")) {
441 dev_err(&dev->dev, "Failed to request ctl mem\n");
442 goto err_request;
443 }
444
445 priv->ctl_membase = ioremap(priv->ctl_mapbase, CHIPCTLSIZE);
446 if (!priv->ctl_membase) {
447 dev_err(&dev->dev, "ioremap failed for ctl mem\n");
448 goto err_ioremap;
449 }
450
451 /* read the HW config */
452 priv->fw.major = ioread32(priv->ctl_membase + TIMB_REV_MAJOR);
453 priv->fw.minor = ioread32(priv->ctl_membase + TIMB_REV_MINOR);
454 priv->fw.config = ioread32(priv->ctl_membase + TIMB_HW_CONFIG);
455
456 if (priv->fw.major > TIMB_SUPPORTED_MAJOR) {
457 dev_err(&dev->dev, "The driver supports an older "
458 "version of the FPGA, please update the driver to "
459 "support %d.%d\n", priv->fw.major, priv->fw.minor);
460 goto err_ioremap;
461 }
462 if (priv->fw.major < TIMB_SUPPORTED_MAJOR ||
463 priv->fw.minor < TIMB_REQUIRED_MINOR) {
464 dev_err(&dev->dev, "The FPGA image is too old (%d.%d), "
465 "please upgrade the FPGA to at least: %d.%d\n",
466 priv->fw.major, priv->fw.minor,
467 TIMB_SUPPORTED_MAJOR, TIMB_REQUIRED_MINOR);
468 goto err_ioremap;
469 }
470
471 msix_entries = kzalloc(TIMBERDALE_NR_IRQS * sizeof(*msix_entries),
472 GFP_KERNEL);
473 if (!msix_entries)
474 goto err_ioremap;
475
476 for (i = 0; i < TIMBERDALE_NR_IRQS; i++)
477 msix_entries[i].entry = i;
478
479 err = pci_enable_msix(dev, msix_entries, TIMBERDALE_NR_IRQS);
480 if (err) {
481 dev_err(&dev->dev,
482 "MSI-X init failed: %d, expected entries: %d\n",
483 err, TIMBERDALE_NR_IRQS);
484 goto err_msix;
485 }
486
487 err = device_create_file(&dev->dev, &dev_attr_fw_ver);
488 if (err)
489 goto err_create_file;
490
491 /* Reset all FPGA PLB peripherals */
492 iowrite32(0x1, priv->ctl_membase + TIMB_SW_RST);
493
494 /* update IRQ offsets in I2C board info */
495 for (i = 0; i < ARRAY_SIZE(timberdale_i2c_board_info); i++)
496 timberdale_i2c_board_info[i].irq =
497 msix_entries[timberdale_i2c_board_info[i].irq].vector;
498
499 /* Update the SPI configuration depending on the HW (8 or 16 bit) */
500 if (priv->fw.config & TIMB_HW_CONFIG_SPI_8BIT) {
501 timberdale_xspi_platform_data.bits_per_word = 8;
502 timberdale_xspi_platform_data.devices =
503 timberdale_spi_8bit_board_info;
504 timberdale_xspi_platform_data.num_devices =
505 ARRAY_SIZE(timberdale_spi_8bit_board_info);
506 } else {
507 timberdale_xspi_platform_data.bits_per_word = 16;
508 timberdale_xspi_platform_data.devices =
509 timberdale_spi_16bit_board_info;
510 timberdale_xspi_platform_data.num_devices =
511 ARRAY_SIZE(timberdale_spi_16bit_board_info);
512 }
513
514 ip_setup = priv->fw.config & TIMB_HW_VER_MASK;
515 switch (ip_setup) {
516 case TIMB_HW_VER0:
517 err = mfd_add_devices(&dev->dev, -1,
518 timberdale_cells_bar0_cfg0,
519 ARRAY_SIZE(timberdale_cells_bar0_cfg0),
520 &dev->resource[0], msix_entries[0].vector);
521 break;
522 case TIMB_HW_VER1:
523 err = mfd_add_devices(&dev->dev, -1,
524 timberdale_cells_bar0_cfg1,
525 ARRAY_SIZE(timberdale_cells_bar0_cfg1),
526 &dev->resource[0], msix_entries[0].vector);
527 break;
528 case TIMB_HW_VER2:
529 err = mfd_add_devices(&dev->dev, -1,
530 timberdale_cells_bar0_cfg2,
531 ARRAY_SIZE(timberdale_cells_bar0_cfg2),
532 &dev->resource[0], msix_entries[0].vector);
533 break;
534 case TIMB_HW_VER3:
535 err = mfd_add_devices(&dev->dev, -1,
536 timberdale_cells_bar0_cfg3,
537 ARRAY_SIZE(timberdale_cells_bar0_cfg3),
538 &dev->resource[0], msix_entries[0].vector);
539 break;
540 default:
541 dev_err(&dev->dev, "Uknown IP setup: %d.%d.%d\n",
542 priv->fw.major, priv->fw.minor, ip_setup);
543 err = -ENODEV;
544 goto err_mfd;
545 break;
546 }
547
548 if (err) {
549 dev_err(&dev->dev, "mfd_add_devices failed: %d\n", err);
550 goto err_mfd;
551 }
552
553 err = mfd_add_devices(&dev->dev, 0,
554 timberdale_cells_bar1, ARRAY_SIZE(timberdale_cells_bar1),
555 &dev->resource[1], msix_entries[0].vector);
556 if (err) {
557 dev_err(&dev->dev, "mfd_add_devices failed: %d\n", err);
558 goto err_mfd2;
559 }
560
561 /* only version 0 and 3 have the iNand routed to SDHCI */
562 if (((priv->fw.config & TIMB_HW_VER_MASK) == TIMB_HW_VER0) ||
563 ((priv->fw.config & TIMB_HW_VER_MASK) == TIMB_HW_VER3)) {
564 err = mfd_add_devices(&dev->dev, 1, timberdale_cells_bar2,
565 ARRAY_SIZE(timberdale_cells_bar2),
566 &dev->resource[2], msix_entries[0].vector);
567 if (err) {
568 dev_err(&dev->dev, "mfd_add_devices failed: %d\n", err);
569 goto err_mfd2;
570 }
571 }
572
573 kfree(msix_entries);
574
575 dev_info(&dev->dev,
576 "Found Timberdale Card. Rev: %d.%d, HW config: 0x%02x\n",
577 priv->fw.major, priv->fw.minor, priv->fw.config);
578
579 return 0;
580
581err_mfd2:
582 mfd_remove_devices(&dev->dev);
583err_mfd:
584 device_remove_file(&dev->dev, &dev_attr_fw_ver);
585err_create_file:
586 pci_disable_msix(dev);
587err_msix:
588 iounmap(priv->ctl_membase);
589err_ioremap:
590 release_mem_region(priv->ctl_mapbase, CHIPCTLSIZE);
591err_request:
592 pci_set_drvdata(dev, NULL);
593err_start:
594 pci_disable_device(dev);
595err_enable:
596 kfree(msix_entries);
597 kfree(priv);
598 pci_set_drvdata(dev, NULL);
599 return -ENODEV;
600}
601
602static void __devexit timb_remove(struct pci_dev *dev)
603{
604 struct timberdale_device *priv = pci_get_drvdata(dev);
605
606 mfd_remove_devices(&dev->dev);
607
608 device_remove_file(&dev->dev, &dev_attr_fw_ver);
609
610 iounmap(priv->ctl_membase);
611 release_mem_region(priv->ctl_mapbase, CHIPCTLSIZE);
612
613 pci_disable_msix(dev);
614 pci_disable_device(dev);
615 pci_set_drvdata(dev, NULL);
616 kfree(priv);
617}
618
619static struct pci_device_id timberdale_pci_tbl[] = {
620 { PCI_DEVICE(PCI_VENDOR_ID_TIMB, PCI_DEVICE_ID_TIMB) },
621 { 0 }
622};
623MODULE_DEVICE_TABLE(pci, timberdale_pci_tbl);
624
625static struct pci_driver timberdale_pci_driver = {
626 .name = DRIVER_NAME,
627 .id_table = timberdale_pci_tbl,
628 .probe = timb_probe,
629 .remove = __devexit_p(timb_remove),
630};
631
632static int __init timberdale_init(void)
633{
634 int err;
635
636 err = pci_register_driver(&timberdale_pci_driver);
637 if (err < 0) {
638 printk(KERN_ERR
639 "Failed to register PCI driver for %s device.\n",
640 timberdale_pci_driver.name);
641 return -ENODEV;
642 }
643
644 printk(KERN_INFO "Driver for %s has been successfully registered.\n",
645 timberdale_pci_driver.name);
646
647 return 0;
648}
649
650static void __exit timberdale_exit(void)
651{
652 pci_unregister_driver(&timberdale_pci_driver);
653
654 printk(KERN_INFO "Driver for %s has been successfully unregistered.\n",
655 timberdale_pci_driver.name);
656}
657
658module_init(timberdale_init);
659module_exit(timberdale_exit);
660
661MODULE_AUTHOR("Mocean Laboratories <info@mocean-labs.com>");
662MODULE_VERSION(DRV_VERSION);
663MODULE_LICENSE("GPL v2");
diff --git a/drivers/mfd/timberdale.h b/drivers/mfd/timberdale.h
new file mode 100644
index 000000000000..8d27ffabc25d
--- /dev/null
+++ b/drivers/mfd/timberdale.h
@@ -0,0 +1,130 @@
1/*
2 * timberdale.h timberdale FPGA MFD driver defines
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#ifndef MFD_TIMBERDALE_H
24#define MFD_TIMBERDALE_H
25
26#define DRV_VERSION "0.1"
27
28/* This driver only support versions >= 3.8 and < 4.0 */
29#define TIMB_SUPPORTED_MAJOR 3
30
31/* This driver only support minor >= 8 */
32#define TIMB_REQUIRED_MINOR 8
33
34/* Registers of the control area */
35#define TIMB_REV_MAJOR 0x00
36#define TIMB_REV_MINOR 0x04
37#define TIMB_HW_CONFIG 0x08
38#define TIMB_SW_RST 0x40
39
40/* bits in the TIMB_HW_CONFIG register */
41#define TIMB_HW_CONFIG_SPI_8BIT 0x80
42
43#define TIMB_HW_VER_MASK 0x0f
44#define TIMB_HW_VER0 0x00
45#define TIMB_HW_VER1 0x01
46#define TIMB_HW_VER2 0x02
47#define TIMB_HW_VER3 0x03
48
49#define OCORESOFFSET 0x0
50#define OCORESEND 0x1f
51
52#define SPIOFFSET 0x80
53#define SPIEND 0xff
54
55#define UARTLITEOFFSET 0x100
56#define UARTLITEEND 0x10f
57
58#define RDSOFFSET 0x180
59#define RDSEND 0x183
60
61#define ETHOFFSET 0x300
62#define ETHEND 0x3ff
63
64#define GPIOOFFSET 0x400
65#define GPIOEND 0x7ff
66
67#define CHIPCTLOFFSET 0x800
68#define CHIPCTLEND 0x8ff
69#define CHIPCTLSIZE (CHIPCTLEND - CHIPCTLOFFSET)
70
71#define INTCOFFSET 0xc00
72#define INTCEND 0xfff
73#define INTCSIZE (INTCEND - INTCOFFSET)
74
75#define MOSTOFFSET 0x1000
76#define MOSTEND 0x13ff
77
78#define UARTOFFSET 0x1400
79#define UARTEND 0x17ff
80
81#define XIICOFFSET 0x1800
82#define XIICEND 0x19ff
83
84#define I2SOFFSET 0x1C00
85#define I2SEND 0x1fff
86
87#define LOGIWOFFSET 0x30000
88#define LOGIWEND 0x37fff
89
90#define MLCOREOFFSET 0x40000
91#define MLCOREEND 0x43fff
92
93#define DMAOFFSET 0x01000000
94#define DMAEND 0x013fffff
95
96/* SDHC0 is placed in PCI bar 1 */
97#define SDHC0OFFSET 0x00
98#define SDHC0END 0xff
99
100/* SDHC1 is placed in PCI bar 2 */
101#define SDHC1OFFSET 0x00
102#define SDHC1END 0xff
103
104#define PCI_VENDOR_ID_TIMB 0x10ee
105#define PCI_DEVICE_ID_TIMB 0xa123
106
107#define IRQ_TIMBERDALE_INIC 0
108#define IRQ_TIMBERDALE_MLB 1
109#define IRQ_TIMBERDALE_GPIO 2
110#define IRQ_TIMBERDALE_I2C 3
111#define IRQ_TIMBERDALE_UART 4
112#define IRQ_TIMBERDALE_DMA 5
113#define IRQ_TIMBERDALE_I2S 6
114#define IRQ_TIMBERDALE_TSC_INT 7
115#define IRQ_TIMBERDALE_SDHC 8
116#define IRQ_TIMBERDALE_ADV7180 9
117#define IRQ_TIMBERDALE_ETHSW_IF 10
118#define IRQ_TIMBERDALE_SPI 11
119#define IRQ_TIMBERDALE_UARTLITE 12
120#define IRQ_TIMBERDALE_MLCORE 13
121#define IRQ_TIMBERDALE_MLCORE_BUF 14
122#define IRQ_TIMBERDALE_RDS 15
123#define TIMBERDALE_NR_IRQS 16
124
125#define GPIO_PIN_ASCB 8
126#define GPIO_PIN_INIC_RST 14
127#define GPIO_PIN_BT_RST 15
128#define GPIO_NR_PINS 16
129
130#endif