root/drivers/mfd/timberdale.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. show_fw_ver
  2. timb_probe
  3. timb_remove

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

/* [<][>][^][v][top][bottom][index][help] */