aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mfd
diff options
context:
space:
mode:
authorTony Lindgren <tony@atomide.com>2010-03-01 17:19:05 -0500
committerTony Lindgren <tony@atomide.com>2010-03-01 17:19:05 -0500
commitd702d12167a2c05a346f49aac7a311d597762495 (patch)
treebaae42c299cce34d6df24b5d01f8b1d0b481bd9a /drivers/mfd
parent9418c65f9bd861d0f7e39aab9cfb3aa6f2275d11 (diff)
parentac0f6f927db539e03e1f3f61bcd4ed57d5cde7a9 (diff)
Merge with mainline to remove plat-omap/Kconfig conflict
Conflicts: arch/arm/plat-omap/Kconfig
Diffstat (limited to 'drivers/mfd')
-rw-r--r--drivers/mfd/Kconfig10
-rw-r--r--drivers/mfd/Makefile3
-rw-r--r--drivers/mfd/timberdale.c727
-rw-r--r--drivers/mfd/timberdale.h130
-rw-r--r--drivers/mfd/twl-core.c18
5 files changed, 884 insertions, 4 deletions
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 1380e1c44e4b..b670d10d5c92 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 && GPIOLIB
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..1ed44d283803
--- /dev/null
+++ b/drivers/mfd/timberdale.c
@@ -0,0 +1,727 @@
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 <media/timb_radio.h>
41
42#include "timberdale.h"
43
44#define DRIVER_NAME "timberdale"
45
46struct timberdale_device {
47 resource_size_t ctl_mapbase;
48 unsigned char __iomem *ctl_membase;
49 struct {
50 u32 major;
51 u32 minor;
52 u32 config;
53 } fw;
54};
55
56/*--------------------------------------------------------------------------*/
57
58static struct tsc2007_platform_data timberdale_tsc2007_platform_data = {
59 .model = 2003,
60 .x_plate_ohms = 100
61};
62
63static struct i2c_board_info timberdale_i2c_board_info[] = {
64 {
65 I2C_BOARD_INFO("tsc2007", 0x48),
66 .platform_data = &timberdale_tsc2007_platform_data,
67 .irq = IRQ_TIMBERDALE_TSC_INT
68 },
69};
70
71static __devinitdata struct ocores_i2c_platform_data
72timberdale_ocores_platform_data = {
73 .regstep = 4,
74 .clock_khz = 62500,
75 .devices = timberdale_i2c_board_info,
76 .num_devices = ARRAY_SIZE(timberdale_i2c_board_info)
77};
78
79const static __devinitconst struct resource timberdale_ocores_resources[] = {
80 {
81 .start = OCORESOFFSET,
82 .end = OCORESEND,
83 .flags = IORESOURCE_MEM,
84 },
85 {
86 .start = IRQ_TIMBERDALE_I2C,
87 .end = IRQ_TIMBERDALE_I2C,
88 .flags = IORESOURCE_IRQ,
89 },
90};
91
92const struct max7301_platform_data timberdale_max7301_platform_data = {
93 .base = 200
94};
95
96const struct mc33880_platform_data timberdale_mc33880_platform_data = {
97 .base = 100
98};
99
100static struct spi_board_info timberdale_spi_16bit_board_info[] = {
101 {
102 .modalias = "max7301",
103 .max_speed_hz = 26000,
104 .chip_select = 2,
105 .mode = SPI_MODE_0,
106 .platform_data = &timberdale_max7301_platform_data
107 },
108};
109
110static struct spi_board_info timberdale_spi_8bit_board_info[] = {
111 {
112 .modalias = "mc33880",
113 .max_speed_hz = 4000,
114 .chip_select = 1,
115 .mode = SPI_MODE_1,
116 .platform_data = &timberdale_mc33880_platform_data
117 },
118};
119
120static __devinitdata struct xspi_platform_data timberdale_xspi_platform_data = {
121 .num_chipselect = 3,
122 .little_endian = true,
123 /* bits per word and devices will be filled in runtime depending
124 * on the HW config
125 */
126};
127
128const static __devinitconst struct resource timberdale_spi_resources[] = {
129 {
130 .start = SPIOFFSET,
131 .end = SPIEND,
132 .flags = IORESOURCE_MEM,
133 },
134 {
135 .start = IRQ_TIMBERDALE_SPI,
136 .end = IRQ_TIMBERDALE_SPI,
137 .flags = IORESOURCE_IRQ,
138 },
139};
140
141const static __devinitconst struct resource timberdale_eth_resources[] = {
142 {
143 .start = ETHOFFSET,
144 .end = ETHEND,
145 .flags = IORESOURCE_MEM,
146 },
147 {
148 .start = IRQ_TIMBERDALE_ETHSW_IF,
149 .end = IRQ_TIMBERDALE_ETHSW_IF,
150 .flags = IORESOURCE_IRQ,
151 },
152};
153
154static __devinitdata struct timbgpio_platform_data
155 timberdale_gpio_platform_data = {
156 .gpio_base = 0,
157 .nr_pins = GPIO_NR_PINS,
158 .irq_base = 200,
159};
160
161const static __devinitconst struct resource timberdale_gpio_resources[] = {
162 {
163 .start = GPIOOFFSET,
164 .end = GPIOEND,
165 .flags = IORESOURCE_MEM,
166 },
167 {
168 .start = IRQ_TIMBERDALE_GPIO,
169 .end = IRQ_TIMBERDALE_GPIO,
170 .flags = IORESOURCE_IRQ,
171 },
172};
173
174const static __devinitconst struct resource timberdale_mlogicore_resources[] = {
175 {
176 .start = MLCOREOFFSET,
177 .end = MLCOREEND,
178 .flags = IORESOURCE_MEM,
179 },
180 {
181 .start = IRQ_TIMBERDALE_MLCORE,
182 .end = IRQ_TIMBERDALE_MLCORE,
183 .flags = IORESOURCE_IRQ,
184 },
185 {
186 .start = IRQ_TIMBERDALE_MLCORE_BUF,
187 .end = IRQ_TIMBERDALE_MLCORE_BUF,
188 .flags = IORESOURCE_IRQ,
189 },
190};
191
192const static __devinitconst struct resource timberdale_uart_resources[] = {
193 {
194 .start = UARTOFFSET,
195 .end = UARTEND,
196 .flags = IORESOURCE_MEM,
197 },
198 {
199 .start = IRQ_TIMBERDALE_UART,
200 .end = IRQ_TIMBERDALE_UART,
201 .flags = IORESOURCE_IRQ,
202 },
203};
204
205const static __devinitconst struct resource timberdale_uartlite_resources[] = {
206 {
207 .start = UARTLITEOFFSET,
208 .end = UARTLITEEND,
209 .flags = IORESOURCE_MEM,
210 },
211 {
212 .start = IRQ_TIMBERDALE_UARTLITE,
213 .end = IRQ_TIMBERDALE_UARTLITE,
214 .flags = IORESOURCE_IRQ,
215 },
216};
217
218const static __devinitconst struct resource timberdale_radio_resources[] = {
219 {
220 .start = RDSOFFSET,
221 .end = RDSEND,
222 .flags = IORESOURCE_MEM,
223 },
224 {
225 .start = IRQ_TIMBERDALE_RDS,
226 .end = IRQ_TIMBERDALE_RDS,
227 .flags = IORESOURCE_IRQ,
228 },
229};
230
231static __devinitdata struct i2c_board_info timberdale_tef6868_i2c_board_info = {
232 I2C_BOARD_INFO("tef6862", 0x60)
233};
234
235static __devinitdata struct i2c_board_info timberdale_saa7706_i2c_board_info = {
236 I2C_BOARD_INFO("saa7706h", 0x1C)
237};
238
239static __devinitdata struct timb_radio_platform_data
240 timberdale_radio_platform_data = {
241 .i2c_adapter = 0,
242 .tuner = {
243 .module_name = "tef6862",
244 .info = &timberdale_tef6868_i2c_board_info
245 },
246 .dsp = {
247 .module_name = "saa7706h",
248 .info = &timberdale_saa7706_i2c_board_info
249 }
250};
251
252const static __devinitconst struct resource timberdale_dma_resources[] = {
253 {
254 .start = DMAOFFSET,
255 .end = DMAEND,
256 .flags = IORESOURCE_MEM,
257 },
258 {
259 .start = IRQ_TIMBERDALE_DMA,
260 .end = IRQ_TIMBERDALE_DMA,
261 .flags = IORESOURCE_IRQ,
262 },
263};
264
265static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg0[] = {
266 {
267 .name = "timb-uart",
268 .num_resources = ARRAY_SIZE(timberdale_uart_resources),
269 .resources = timberdale_uart_resources,
270 },
271 {
272 .name = "timb-gpio",
273 .num_resources = ARRAY_SIZE(timberdale_gpio_resources),
274 .resources = timberdale_gpio_resources,
275 .platform_data = &timberdale_gpio_platform_data,
276 .data_size = sizeof(timberdale_gpio_platform_data),
277 },
278 {
279 .name = "timb-radio",
280 .num_resources = ARRAY_SIZE(timberdale_radio_resources),
281 .resources = timberdale_radio_resources,
282 .platform_data = &timberdale_radio_platform_data,
283 .data_size = sizeof(timberdale_radio_platform_data),
284 },
285 {
286 .name = "xilinx_spi",
287 .num_resources = ARRAY_SIZE(timberdale_spi_resources),
288 .resources = timberdale_spi_resources,
289 .platform_data = &timberdale_xspi_platform_data,
290 .data_size = sizeof(timberdale_xspi_platform_data),
291 },
292 {
293 .name = "ks8842",
294 .num_resources = ARRAY_SIZE(timberdale_eth_resources),
295 .resources = timberdale_eth_resources,
296 },
297 {
298 .name = "timb-dma",
299 .num_resources = ARRAY_SIZE(timberdale_dma_resources),
300 .resources = timberdale_dma_resources,
301 },
302};
303
304static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg1[] = {
305 {
306 .name = "timb-uart",
307 .num_resources = ARRAY_SIZE(timberdale_uart_resources),
308 .resources = timberdale_uart_resources,
309 },
310 {
311 .name = "uartlite",
312 .num_resources = ARRAY_SIZE(timberdale_uartlite_resources),
313 .resources = timberdale_uartlite_resources,
314 },
315 {
316 .name = "timb-gpio",
317 .num_resources = ARRAY_SIZE(timberdale_gpio_resources),
318 .resources = timberdale_gpio_resources,
319 .platform_data = &timberdale_gpio_platform_data,
320 .data_size = sizeof(timberdale_gpio_platform_data),
321 },
322 {
323 .name = "timb-mlogicore",
324 .num_resources = ARRAY_SIZE(timberdale_mlogicore_resources),
325 .resources = timberdale_mlogicore_resources,
326 },
327 {
328 .name = "timb-radio",
329 .num_resources = ARRAY_SIZE(timberdale_radio_resources),
330 .resources = timberdale_radio_resources,
331 .platform_data = &timberdale_radio_platform_data,
332 .data_size = sizeof(timberdale_radio_platform_data),
333 },
334 {
335 .name = "xilinx_spi",
336 .num_resources = ARRAY_SIZE(timberdale_spi_resources),
337 .resources = timberdale_spi_resources,
338 .platform_data = &timberdale_xspi_platform_data,
339 .data_size = sizeof(timberdale_xspi_platform_data),
340 },
341 {
342 .name = "ks8842",
343 .num_resources = ARRAY_SIZE(timberdale_eth_resources),
344 .resources = timberdale_eth_resources,
345 },
346 {
347 .name = "timb-dma",
348 .num_resources = ARRAY_SIZE(timberdale_dma_resources),
349 .resources = timberdale_dma_resources,
350 },
351};
352
353static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg2[] = {
354 {
355 .name = "timb-uart",
356 .num_resources = ARRAY_SIZE(timberdale_uart_resources),
357 .resources = timberdale_uart_resources,
358 },
359 {
360 .name = "timb-gpio",
361 .num_resources = ARRAY_SIZE(timberdale_gpio_resources),
362 .resources = timberdale_gpio_resources,
363 .platform_data = &timberdale_gpio_platform_data,
364 .data_size = sizeof(timberdale_gpio_platform_data),
365 },
366 {
367 .name = "timb-radio",
368 .num_resources = ARRAY_SIZE(timberdale_radio_resources),
369 .resources = timberdale_radio_resources,
370 .platform_data = &timberdale_radio_platform_data,
371 .data_size = sizeof(timberdale_radio_platform_data),
372 },
373 {
374 .name = "xilinx_spi",
375 .num_resources = ARRAY_SIZE(timberdale_spi_resources),
376 .resources = timberdale_spi_resources,
377 .platform_data = &timberdale_xspi_platform_data,
378 .data_size = sizeof(timberdale_xspi_platform_data),
379 },
380 {
381 .name = "timb-dma",
382 .num_resources = ARRAY_SIZE(timberdale_dma_resources),
383 .resources = timberdale_dma_resources,
384 },
385};
386
387static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg3[] = {
388 {
389 .name = "timb-uart",
390 .num_resources = ARRAY_SIZE(timberdale_uart_resources),
391 .resources = timberdale_uart_resources,
392 },
393 {
394 .name = "ocores-i2c",
395 .num_resources = ARRAY_SIZE(timberdale_ocores_resources),
396 .resources = timberdale_ocores_resources,
397 .platform_data = &timberdale_ocores_platform_data,
398 .data_size = sizeof(timberdale_ocores_platform_data),
399 },
400 {
401 .name = "timb-gpio",
402 .num_resources = ARRAY_SIZE(timberdale_gpio_resources),
403 .resources = timberdale_gpio_resources,
404 .platform_data = &timberdale_gpio_platform_data,
405 .data_size = sizeof(timberdale_gpio_platform_data),
406 },
407 {
408 .name = "timb-radio",
409 .num_resources = ARRAY_SIZE(timberdale_radio_resources),
410 .resources = timberdale_radio_resources,
411 .platform_data = &timberdale_radio_platform_data,
412 .data_size = sizeof(timberdale_radio_platform_data),
413 },
414 {
415 .name = "xilinx_spi",
416 .num_resources = ARRAY_SIZE(timberdale_spi_resources),
417 .resources = timberdale_spi_resources,
418 .platform_data = &timberdale_xspi_platform_data,
419 .data_size = sizeof(timberdale_xspi_platform_data),
420 },
421 {
422 .name = "ks8842",
423 .num_resources = ARRAY_SIZE(timberdale_eth_resources),
424 .resources = timberdale_eth_resources,
425 },
426 {
427 .name = "timb-dma",
428 .num_resources = ARRAY_SIZE(timberdale_dma_resources),
429 .resources = timberdale_dma_resources,
430 },
431};
432
433static const __devinitconst struct resource timberdale_sdhc_resources[] = {
434 /* located in bar 1 and bar 2 */
435 {
436 .start = SDHC0OFFSET,
437 .end = SDHC0END,
438 .flags = IORESOURCE_MEM,
439 },
440 {
441 .start = IRQ_TIMBERDALE_SDHC,
442 .end = IRQ_TIMBERDALE_SDHC,
443 .flags = IORESOURCE_IRQ,
444 },
445};
446
447static __devinitdata struct mfd_cell timberdale_cells_bar1[] = {
448 {
449 .name = "sdhci",
450 .num_resources = ARRAY_SIZE(timberdale_sdhc_resources),
451 .resources = timberdale_sdhc_resources,
452 },
453};
454
455static __devinitdata struct mfd_cell timberdale_cells_bar2[] = {
456 {
457 .name = "sdhci",
458 .num_resources = ARRAY_SIZE(timberdale_sdhc_resources),
459 .resources = timberdale_sdhc_resources,
460 },
461};
462
463static ssize_t show_fw_ver(struct device *dev, struct device_attribute *attr,
464 char *buf)
465{
466 struct pci_dev *pdev = to_pci_dev(dev);
467 struct timberdale_device *priv = pci_get_drvdata(pdev);
468
469 return sprintf(buf, "%d.%d.%d\n", priv->fw.major, priv->fw.minor,
470 priv->fw.config);
471}
472
473static DEVICE_ATTR(fw_ver, S_IRUGO, show_fw_ver, NULL);
474
475/*--------------------------------------------------------------------------*/
476
477static int __devinit timb_probe(struct pci_dev *dev,
478 const struct pci_device_id *id)
479{
480 struct timberdale_device *priv;
481 int err, i;
482 resource_size_t mapbase;
483 struct msix_entry *msix_entries = NULL;
484 u8 ip_setup;
485
486 priv = kzalloc(sizeof(*priv), GFP_KERNEL);
487 if (!priv)
488 return -ENOMEM;
489
490 pci_set_drvdata(dev, priv);
491
492 err = pci_enable_device(dev);
493 if (err)
494 goto err_enable;
495
496 mapbase = pci_resource_start(dev, 0);
497 if (!mapbase) {
498 dev_err(&dev->dev, "No resource\n");
499 goto err_start;
500 }
501
502 /* create a resource for the PCI master register */
503 priv->ctl_mapbase = mapbase + CHIPCTLOFFSET;
504 if (!request_mem_region(priv->ctl_mapbase, CHIPCTLSIZE, "timb-ctl")) {
505 dev_err(&dev->dev, "Failed to request ctl mem\n");
506 goto err_request;
507 }
508
509 priv->ctl_membase = ioremap(priv->ctl_mapbase, CHIPCTLSIZE);
510 if (!priv->ctl_membase) {
511 dev_err(&dev->dev, "ioremap failed for ctl mem\n");
512 goto err_ioremap;
513 }
514
515 /* read the HW config */
516 priv->fw.major = ioread32(priv->ctl_membase + TIMB_REV_MAJOR);
517 priv->fw.minor = ioread32(priv->ctl_membase + TIMB_REV_MINOR);
518 priv->fw.config = ioread32(priv->ctl_membase + TIMB_HW_CONFIG);
519
520 if (priv->fw.major > TIMB_SUPPORTED_MAJOR) {
521 dev_err(&dev->dev, "The driver supports an older "
522 "version of the FPGA, please update the driver to "
523 "support %d.%d\n", priv->fw.major, priv->fw.minor);
524 goto err_ioremap;
525 }
526 if (priv->fw.major < TIMB_SUPPORTED_MAJOR ||
527 priv->fw.minor < TIMB_REQUIRED_MINOR) {
528 dev_err(&dev->dev, "The FPGA image is too old (%d.%d), "
529 "please upgrade the FPGA to at least: %d.%d\n",
530 priv->fw.major, priv->fw.minor,
531 TIMB_SUPPORTED_MAJOR, TIMB_REQUIRED_MINOR);
532 goto err_ioremap;
533 }
534
535 msix_entries = kzalloc(TIMBERDALE_NR_IRQS * sizeof(*msix_entries),
536 GFP_KERNEL);
537 if (!msix_entries)
538 goto err_ioremap;
539
540 for (i = 0; i < TIMBERDALE_NR_IRQS; i++)
541 msix_entries[i].entry = i;
542
543 err = pci_enable_msix(dev, msix_entries, TIMBERDALE_NR_IRQS);
544 if (err) {
545 dev_err(&dev->dev,
546 "MSI-X init failed: %d, expected entries: %d\n",
547 err, TIMBERDALE_NR_IRQS);
548 goto err_msix;
549 }
550
551 err = device_create_file(&dev->dev, &dev_attr_fw_ver);
552 if (err)
553 goto err_create_file;
554
555 /* Reset all FPGA PLB peripherals */
556 iowrite32(0x1, priv->ctl_membase + TIMB_SW_RST);
557
558 /* update IRQ offsets in I2C board info */
559 for (i = 0; i < ARRAY_SIZE(timberdale_i2c_board_info); i++)
560 timberdale_i2c_board_info[i].irq =
561 msix_entries[timberdale_i2c_board_info[i].irq].vector;
562
563 /* Update the SPI configuration depending on the HW (8 or 16 bit) */
564 if (priv->fw.config & TIMB_HW_CONFIG_SPI_8BIT) {
565 timberdale_xspi_platform_data.bits_per_word = 8;
566 timberdale_xspi_platform_data.devices =
567 timberdale_spi_8bit_board_info;
568 timberdale_xspi_platform_data.num_devices =
569 ARRAY_SIZE(timberdale_spi_8bit_board_info);
570 } else {
571 timberdale_xspi_platform_data.bits_per_word = 16;
572 timberdale_xspi_platform_data.devices =
573 timberdale_spi_16bit_board_info;
574 timberdale_xspi_platform_data.num_devices =
575 ARRAY_SIZE(timberdale_spi_16bit_board_info);
576 }
577
578 ip_setup = priv->fw.config & TIMB_HW_VER_MASK;
579 switch (ip_setup) {
580 case TIMB_HW_VER0:
581 err = mfd_add_devices(&dev->dev, -1,
582 timberdale_cells_bar0_cfg0,
583 ARRAY_SIZE(timberdale_cells_bar0_cfg0),
584 &dev->resource[0], msix_entries[0].vector);
585 break;
586 case TIMB_HW_VER1:
587 err = mfd_add_devices(&dev->dev, -1,
588 timberdale_cells_bar0_cfg1,
589 ARRAY_SIZE(timberdale_cells_bar0_cfg1),
590 &dev->resource[0], msix_entries[0].vector);
591 break;
592 case TIMB_HW_VER2:
593 err = mfd_add_devices(&dev->dev, -1,
594 timberdale_cells_bar0_cfg2,
595 ARRAY_SIZE(timberdale_cells_bar0_cfg2),
596 &dev->resource[0], msix_entries[0].vector);
597 break;
598 case TIMB_HW_VER3:
599 err = mfd_add_devices(&dev->dev, -1,
600 timberdale_cells_bar0_cfg3,
601 ARRAY_SIZE(timberdale_cells_bar0_cfg3),
602 &dev->resource[0], msix_entries[0].vector);
603 break;
604 default:
605 dev_err(&dev->dev, "Uknown IP setup: %d.%d.%d\n",
606 priv->fw.major, priv->fw.minor, ip_setup);
607 err = -ENODEV;
608 goto err_mfd;
609 break;
610 }
611
612 if (err) {
613 dev_err(&dev->dev, "mfd_add_devices failed: %d\n", err);
614 goto err_mfd;
615 }
616
617 err = mfd_add_devices(&dev->dev, 0,
618 timberdale_cells_bar1, ARRAY_SIZE(timberdale_cells_bar1),
619 &dev->resource[1], msix_entries[0].vector);
620 if (err) {
621 dev_err(&dev->dev, "mfd_add_devices failed: %d\n", err);
622 goto err_mfd2;
623 }
624
625 /* only version 0 and 3 have the iNand routed to SDHCI */
626 if (((priv->fw.config & TIMB_HW_VER_MASK) == TIMB_HW_VER0) ||
627 ((priv->fw.config & TIMB_HW_VER_MASK) == TIMB_HW_VER3)) {
628 err = mfd_add_devices(&dev->dev, 1, timberdale_cells_bar2,
629 ARRAY_SIZE(timberdale_cells_bar2),
630 &dev->resource[2], msix_entries[0].vector);
631 if (err) {
632 dev_err(&dev->dev, "mfd_add_devices failed: %d\n", err);
633 goto err_mfd2;
634 }
635 }
636
637 kfree(msix_entries);
638
639 dev_info(&dev->dev,
640 "Found Timberdale Card. Rev: %d.%d, HW config: 0x%02x\n",
641 priv->fw.major, priv->fw.minor, priv->fw.config);
642
643 return 0;
644
645err_mfd2:
646 mfd_remove_devices(&dev->dev);
647err_mfd:
648 device_remove_file(&dev->dev, &dev_attr_fw_ver);
649err_create_file:
650 pci_disable_msix(dev);
651err_msix:
652 iounmap(priv->ctl_membase);
653err_ioremap:
654 release_mem_region(priv->ctl_mapbase, CHIPCTLSIZE);
655err_request:
656 pci_set_drvdata(dev, NULL);
657err_start:
658 pci_disable_device(dev);
659err_enable:
660 kfree(msix_entries);
661 kfree(priv);
662 pci_set_drvdata(dev, NULL);
663 return -ENODEV;
664}
665
666static void __devexit timb_remove(struct pci_dev *dev)
667{
668 struct timberdale_device *priv = pci_get_drvdata(dev);
669
670 mfd_remove_devices(&dev->dev);
671
672 device_remove_file(&dev->dev, &dev_attr_fw_ver);
673
674 iounmap(priv->ctl_membase);
675 release_mem_region(priv->ctl_mapbase, CHIPCTLSIZE);
676
677 pci_disable_msix(dev);
678 pci_disable_device(dev);
679 pci_set_drvdata(dev, NULL);
680 kfree(priv);
681}
682
683static struct pci_device_id timberdale_pci_tbl[] = {
684 { PCI_DEVICE(PCI_VENDOR_ID_TIMB, PCI_DEVICE_ID_TIMB) },
685 { 0 }
686};
687MODULE_DEVICE_TABLE(pci, timberdale_pci_tbl);
688
689static struct pci_driver timberdale_pci_driver = {
690 .name = DRIVER_NAME,
691 .id_table = timberdale_pci_tbl,
692 .probe = timb_probe,
693 .remove = __devexit_p(timb_remove),
694};
695
696static int __init timberdale_init(void)
697{
698 int err;
699
700 err = pci_register_driver(&timberdale_pci_driver);
701 if (err < 0) {
702 printk(KERN_ERR
703 "Failed to register PCI driver for %s device.\n",
704 timberdale_pci_driver.name);
705 return -ENODEV;
706 }
707
708 printk(KERN_INFO "Driver for %s has been successfully registered.\n",
709 timberdale_pci_driver.name);
710
711 return 0;
712}
713
714static void __exit timberdale_exit(void)
715{
716 pci_unregister_driver(&timberdale_pci_driver);
717
718 printk(KERN_INFO "Driver for %s has been successfully unregistered.\n",
719 timberdale_pci_driver.name);
720}
721
722module_init(timberdale_init);
723module_exit(timberdale_exit);
724
725MODULE_AUTHOR("Mocean Laboratories <info@mocean-labs.com>");
726MODULE_VERSION(DRV_VERSION);
727MODULE_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
diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c
index 2a7606534196..19a930d06241 100644
--- a/drivers/mfd/twl-core.c
+++ b/drivers/mfd/twl-core.c
@@ -115,7 +115,8 @@
115#define twl_has_watchdog() false 115#define twl_has_watchdog() false
116#endif 116#endif
117 117
118#if defined(CONFIG_TWL4030_CODEC) || defined(CONFIG_TWL4030_CODEC_MODULE) 118#if defined(CONFIG_TWL4030_CODEC) || defined(CONFIG_TWL4030_CODEC_MODULE) ||\
119 defined(CONFIG_SND_SOC_TWL6030) || defined(CONFIG_SND_SOC_TWL6030_MODULE)
119#define twl_has_codec() true 120#define twl_has_codec() true
120#else 121#else
121#define twl_has_codec() false 122#define twl_has_codec() false
@@ -711,8 +712,19 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
711 return PTR_ERR(child); 712 return PTR_ERR(child);
712 } 713 }
713 714
714 if (twl_has_codec() && pdata->codec) { 715 if (twl_has_codec() && pdata->codec && twl_class_is_4030()) {
715 child = add_child(1, "twl4030_codec", 716 sub_chip_id = twl_map[TWL_MODULE_AUDIO_VOICE].sid;
717 child = add_child(sub_chip_id, "twl4030_codec",
718 pdata->codec, sizeof(*pdata->codec),
719 false, 0, 0);
720 if (IS_ERR(child))
721 return PTR_ERR(child);
722 }
723
724 /* Phoenix*/
725 if (twl_has_codec() && pdata->codec && twl_class_is_6030()) {
726 sub_chip_id = twl_map[TWL_MODULE_AUDIO_VOICE].sid;
727 child = add_child(sub_chip_id, "twl6030_codec",
716 pdata->codec, sizeof(*pdata->codec), 728 pdata->codec, sizeof(*pdata->codec),
717 false, 0, 0); 729 false, 0, 0);
718 if (IS_ERR(child)) 730 if (IS_ERR(child))