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