162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * timberdale.c timberdale FPGA MFD driver 462306a36Sopenharmony_ci * Copyright (c) 2009 Intel Corporation 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci/* Supports: 862306a36Sopenharmony_ci * Timberdale FPGA 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/kernel.h> 1262306a36Sopenharmony_ci#include <linux/module.h> 1362306a36Sopenharmony_ci#include <linux/pci.h> 1462306a36Sopenharmony_ci#include <linux/mfd/core.h> 1562306a36Sopenharmony_ci#include <linux/slab.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include <linux/timb_gpio.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include <linux/i2c.h> 2062306a36Sopenharmony_ci#include <linux/platform_data/i2c-ocores.h> 2162306a36Sopenharmony_ci#include <linux/platform_data/i2c-xiic.h> 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#include <linux/spi/spi.h> 2462306a36Sopenharmony_ci#include <linux/spi/xilinx_spi.h> 2562306a36Sopenharmony_ci#include <linux/spi/max7301.h> 2662306a36Sopenharmony_ci#include <linux/spi/mc33880.h> 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci#include <linux/platform_data/tsc2007.h> 2962306a36Sopenharmony_ci#include <linux/platform_data/media/timb_radio.h> 3062306a36Sopenharmony_ci#include <linux/platform_data/media/timb_video.h> 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#include <linux/timb_dma.h> 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci#include <linux/ks8842.h> 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci#include "timberdale.h" 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci#define DRIVER_NAME "timberdale" 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistruct timberdale_device { 4162306a36Sopenharmony_ci resource_size_t ctl_mapbase; 4262306a36Sopenharmony_ci unsigned char __iomem *ctl_membase; 4362306a36Sopenharmony_ci struct { 4462306a36Sopenharmony_ci u32 major; 4562306a36Sopenharmony_ci u32 minor; 4662306a36Sopenharmony_ci u32 config; 4762306a36Sopenharmony_ci } fw; 4862306a36Sopenharmony_ci}; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci/*--------------------------------------------------------------------------*/ 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_cistatic struct tsc2007_platform_data timberdale_tsc2007_platform_data = { 5362306a36Sopenharmony_ci .model = 2003, 5462306a36Sopenharmony_ci .x_plate_ohms = 100 5562306a36Sopenharmony_ci}; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_cistatic struct i2c_board_info timberdale_i2c_board_info[] = { 5862306a36Sopenharmony_ci { 5962306a36Sopenharmony_ci I2C_BOARD_INFO("tsc2007", 0x48), 6062306a36Sopenharmony_ci .platform_data = &timberdale_tsc2007_platform_data, 6162306a36Sopenharmony_ci .irq = IRQ_TIMBERDALE_TSC_INT 6262306a36Sopenharmony_ci }, 6362306a36Sopenharmony_ci}; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_cistatic struct xiic_i2c_platform_data 6662306a36Sopenharmony_citimberdale_xiic_platform_data = { 6762306a36Sopenharmony_ci .devices = timberdale_i2c_board_info, 6862306a36Sopenharmony_ci .num_devices = ARRAY_SIZE(timberdale_i2c_board_info) 6962306a36Sopenharmony_ci}; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cistatic struct ocores_i2c_platform_data 7262306a36Sopenharmony_citimberdale_ocores_platform_data = { 7362306a36Sopenharmony_ci .reg_shift = 2, 7462306a36Sopenharmony_ci .clock_khz = 62500, 7562306a36Sopenharmony_ci .devices = timberdale_i2c_board_info, 7662306a36Sopenharmony_ci .num_devices = ARRAY_SIZE(timberdale_i2c_board_info) 7762306a36Sopenharmony_ci}; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_cistatic const struct resource timberdale_xiic_resources[] = { 8062306a36Sopenharmony_ci { 8162306a36Sopenharmony_ci .start = XIICOFFSET, 8262306a36Sopenharmony_ci .end = XIICEND, 8362306a36Sopenharmony_ci .flags = IORESOURCE_MEM, 8462306a36Sopenharmony_ci }, 8562306a36Sopenharmony_ci { 8662306a36Sopenharmony_ci .start = IRQ_TIMBERDALE_I2C, 8762306a36Sopenharmony_ci .end = IRQ_TIMBERDALE_I2C, 8862306a36Sopenharmony_ci .flags = IORESOURCE_IRQ, 8962306a36Sopenharmony_ci }, 9062306a36Sopenharmony_ci}; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_cistatic const struct resource timberdale_ocores_resources[] = { 9362306a36Sopenharmony_ci { 9462306a36Sopenharmony_ci .start = OCORESOFFSET, 9562306a36Sopenharmony_ci .end = OCORESEND, 9662306a36Sopenharmony_ci .flags = IORESOURCE_MEM, 9762306a36Sopenharmony_ci }, 9862306a36Sopenharmony_ci { 9962306a36Sopenharmony_ci .start = IRQ_TIMBERDALE_I2C, 10062306a36Sopenharmony_ci .end = IRQ_TIMBERDALE_I2C, 10162306a36Sopenharmony_ci .flags = IORESOURCE_IRQ, 10262306a36Sopenharmony_ci }, 10362306a36Sopenharmony_ci}; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_cistatic const struct max7301_platform_data timberdale_max7301_platform_data = { 10662306a36Sopenharmony_ci .base = 200 10762306a36Sopenharmony_ci}; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_cistatic const struct mc33880_platform_data timberdale_mc33880_platform_data = { 11062306a36Sopenharmony_ci .base = 100 11162306a36Sopenharmony_ci}; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_cistatic struct spi_board_info timberdale_spi_16bit_board_info[] = { 11462306a36Sopenharmony_ci { 11562306a36Sopenharmony_ci .modalias = "max7301", 11662306a36Sopenharmony_ci .max_speed_hz = 26000, 11762306a36Sopenharmony_ci .chip_select = 2, 11862306a36Sopenharmony_ci .mode = SPI_MODE_0, 11962306a36Sopenharmony_ci .platform_data = &timberdale_max7301_platform_data 12062306a36Sopenharmony_ci }, 12162306a36Sopenharmony_ci}; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_cistatic struct spi_board_info timberdale_spi_8bit_board_info[] = { 12462306a36Sopenharmony_ci { 12562306a36Sopenharmony_ci .modalias = "mc33880", 12662306a36Sopenharmony_ci .max_speed_hz = 4000, 12762306a36Sopenharmony_ci .chip_select = 1, 12862306a36Sopenharmony_ci .mode = SPI_MODE_1, 12962306a36Sopenharmony_ci .platform_data = &timberdale_mc33880_platform_data 13062306a36Sopenharmony_ci }, 13162306a36Sopenharmony_ci}; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_cistatic struct xspi_platform_data timberdale_xspi_platform_data = { 13462306a36Sopenharmony_ci .num_chipselect = 3, 13562306a36Sopenharmony_ci /* bits per word and devices will be filled in runtime depending 13662306a36Sopenharmony_ci * on the HW config 13762306a36Sopenharmony_ci */ 13862306a36Sopenharmony_ci}; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_cistatic const struct resource timberdale_spi_resources[] = { 14162306a36Sopenharmony_ci { 14262306a36Sopenharmony_ci .start = SPIOFFSET, 14362306a36Sopenharmony_ci .end = SPIEND, 14462306a36Sopenharmony_ci .flags = IORESOURCE_MEM, 14562306a36Sopenharmony_ci }, 14662306a36Sopenharmony_ci { 14762306a36Sopenharmony_ci .start = IRQ_TIMBERDALE_SPI, 14862306a36Sopenharmony_ci .end = IRQ_TIMBERDALE_SPI, 14962306a36Sopenharmony_ci .flags = IORESOURCE_IRQ, 15062306a36Sopenharmony_ci }, 15162306a36Sopenharmony_ci}; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_cistatic struct ks8842_platform_data 15462306a36Sopenharmony_ci timberdale_ks8842_platform_data = { 15562306a36Sopenharmony_ci .rx_dma_channel = DMA_ETH_RX, 15662306a36Sopenharmony_ci .tx_dma_channel = DMA_ETH_TX 15762306a36Sopenharmony_ci}; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_cistatic const struct resource timberdale_eth_resources[] = { 16062306a36Sopenharmony_ci { 16162306a36Sopenharmony_ci .start = ETHOFFSET, 16262306a36Sopenharmony_ci .end = ETHEND, 16362306a36Sopenharmony_ci .flags = IORESOURCE_MEM, 16462306a36Sopenharmony_ci }, 16562306a36Sopenharmony_ci { 16662306a36Sopenharmony_ci .start = IRQ_TIMBERDALE_ETHSW_IF, 16762306a36Sopenharmony_ci .end = IRQ_TIMBERDALE_ETHSW_IF, 16862306a36Sopenharmony_ci .flags = IORESOURCE_IRQ, 16962306a36Sopenharmony_ci }, 17062306a36Sopenharmony_ci}; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_cistatic struct timbgpio_platform_data 17362306a36Sopenharmony_ci timberdale_gpio_platform_data = { 17462306a36Sopenharmony_ci .gpio_base = 0, 17562306a36Sopenharmony_ci .nr_pins = GPIO_NR_PINS, 17662306a36Sopenharmony_ci .irq_base = 200, 17762306a36Sopenharmony_ci}; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_cistatic const struct resource timberdale_gpio_resources[] = { 18062306a36Sopenharmony_ci { 18162306a36Sopenharmony_ci .start = GPIOOFFSET, 18262306a36Sopenharmony_ci .end = GPIOEND, 18362306a36Sopenharmony_ci .flags = IORESOURCE_MEM, 18462306a36Sopenharmony_ci }, 18562306a36Sopenharmony_ci { 18662306a36Sopenharmony_ci .start = IRQ_TIMBERDALE_GPIO, 18762306a36Sopenharmony_ci .end = IRQ_TIMBERDALE_GPIO, 18862306a36Sopenharmony_ci .flags = IORESOURCE_IRQ, 18962306a36Sopenharmony_ci }, 19062306a36Sopenharmony_ci}; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_cistatic const struct resource timberdale_mlogicore_resources[] = { 19362306a36Sopenharmony_ci { 19462306a36Sopenharmony_ci .start = MLCOREOFFSET, 19562306a36Sopenharmony_ci .end = MLCOREEND, 19662306a36Sopenharmony_ci .flags = IORESOURCE_MEM, 19762306a36Sopenharmony_ci }, 19862306a36Sopenharmony_ci { 19962306a36Sopenharmony_ci .start = IRQ_TIMBERDALE_MLCORE, 20062306a36Sopenharmony_ci .end = IRQ_TIMBERDALE_MLCORE, 20162306a36Sopenharmony_ci .flags = IORESOURCE_IRQ, 20262306a36Sopenharmony_ci }, 20362306a36Sopenharmony_ci { 20462306a36Sopenharmony_ci .start = IRQ_TIMBERDALE_MLCORE_BUF, 20562306a36Sopenharmony_ci .end = IRQ_TIMBERDALE_MLCORE_BUF, 20662306a36Sopenharmony_ci .flags = IORESOURCE_IRQ, 20762306a36Sopenharmony_ci }, 20862306a36Sopenharmony_ci}; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_cistatic const struct resource timberdale_uart_resources[] = { 21162306a36Sopenharmony_ci { 21262306a36Sopenharmony_ci .start = UARTOFFSET, 21362306a36Sopenharmony_ci .end = UARTEND, 21462306a36Sopenharmony_ci .flags = IORESOURCE_MEM, 21562306a36Sopenharmony_ci }, 21662306a36Sopenharmony_ci { 21762306a36Sopenharmony_ci .start = IRQ_TIMBERDALE_UART, 21862306a36Sopenharmony_ci .end = IRQ_TIMBERDALE_UART, 21962306a36Sopenharmony_ci .flags = IORESOURCE_IRQ, 22062306a36Sopenharmony_ci }, 22162306a36Sopenharmony_ci}; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_cistatic const struct resource timberdale_uartlite_resources[] = { 22462306a36Sopenharmony_ci { 22562306a36Sopenharmony_ci .start = UARTLITEOFFSET, 22662306a36Sopenharmony_ci .end = UARTLITEEND, 22762306a36Sopenharmony_ci .flags = IORESOURCE_MEM, 22862306a36Sopenharmony_ci }, 22962306a36Sopenharmony_ci { 23062306a36Sopenharmony_ci .start = IRQ_TIMBERDALE_UARTLITE, 23162306a36Sopenharmony_ci .end = IRQ_TIMBERDALE_UARTLITE, 23262306a36Sopenharmony_ci .flags = IORESOURCE_IRQ, 23362306a36Sopenharmony_ci }, 23462306a36Sopenharmony_ci}; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_cistatic struct i2c_board_info timberdale_adv7180_i2c_board_info = { 23762306a36Sopenharmony_ci /* Requires jumper JP9 to be off */ 23862306a36Sopenharmony_ci I2C_BOARD_INFO("adv7180", 0x42 >> 1), 23962306a36Sopenharmony_ci .irq = IRQ_TIMBERDALE_ADV7180 24062306a36Sopenharmony_ci}; 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_cistatic struct timb_video_platform_data 24362306a36Sopenharmony_ci timberdale_video_platform_data = { 24462306a36Sopenharmony_ci .dma_channel = DMA_VIDEO_RX, 24562306a36Sopenharmony_ci .i2c_adapter = 0, 24662306a36Sopenharmony_ci .encoder = { 24762306a36Sopenharmony_ci .info = &timberdale_adv7180_i2c_board_info 24862306a36Sopenharmony_ci } 24962306a36Sopenharmony_ci}; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_cistatic const struct resource 25262306a36Sopenharmony_citimberdale_radio_resources[] = { 25362306a36Sopenharmony_ci { 25462306a36Sopenharmony_ci .start = RDSOFFSET, 25562306a36Sopenharmony_ci .end = RDSEND, 25662306a36Sopenharmony_ci .flags = IORESOURCE_MEM, 25762306a36Sopenharmony_ci }, 25862306a36Sopenharmony_ci { 25962306a36Sopenharmony_ci .start = IRQ_TIMBERDALE_RDS, 26062306a36Sopenharmony_ci .end = IRQ_TIMBERDALE_RDS, 26162306a36Sopenharmony_ci .flags = IORESOURCE_IRQ, 26262306a36Sopenharmony_ci }, 26362306a36Sopenharmony_ci}; 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_cistatic struct i2c_board_info timberdale_tef6868_i2c_board_info = { 26662306a36Sopenharmony_ci I2C_BOARD_INFO("tef6862", 0x60) 26762306a36Sopenharmony_ci}; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_cistatic struct i2c_board_info timberdale_saa7706_i2c_board_info = { 27062306a36Sopenharmony_ci I2C_BOARD_INFO("saa7706h", 0x1C) 27162306a36Sopenharmony_ci}; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_cistatic struct timb_radio_platform_data 27462306a36Sopenharmony_ci timberdale_radio_platform_data = { 27562306a36Sopenharmony_ci .i2c_adapter = 0, 27662306a36Sopenharmony_ci .tuner = &timberdale_tef6868_i2c_board_info, 27762306a36Sopenharmony_ci .dsp = &timberdale_saa7706_i2c_board_info 27862306a36Sopenharmony_ci}; 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_cistatic const struct resource timberdale_video_resources[] = { 28162306a36Sopenharmony_ci { 28262306a36Sopenharmony_ci .start = LOGIWOFFSET, 28362306a36Sopenharmony_ci .end = LOGIWEND, 28462306a36Sopenharmony_ci .flags = IORESOURCE_MEM, 28562306a36Sopenharmony_ci }, 28662306a36Sopenharmony_ci /* 28762306a36Sopenharmony_ci note that the "frame buffer" is located in DMA area 28862306a36Sopenharmony_ci starting at 0x1200000 28962306a36Sopenharmony_ci */ 29062306a36Sopenharmony_ci}; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_cistatic struct timb_dma_platform_data timb_dma_platform_data = { 29362306a36Sopenharmony_ci .nr_channels = 10, 29462306a36Sopenharmony_ci .channels = { 29562306a36Sopenharmony_ci { 29662306a36Sopenharmony_ci /* UART RX */ 29762306a36Sopenharmony_ci .rx = true, 29862306a36Sopenharmony_ci .descriptors = 2, 29962306a36Sopenharmony_ci .descriptor_elements = 1 30062306a36Sopenharmony_ci }, 30162306a36Sopenharmony_ci { 30262306a36Sopenharmony_ci /* UART TX */ 30362306a36Sopenharmony_ci .rx = false, 30462306a36Sopenharmony_ci .descriptors = 2, 30562306a36Sopenharmony_ci .descriptor_elements = 1 30662306a36Sopenharmony_ci }, 30762306a36Sopenharmony_ci { 30862306a36Sopenharmony_ci /* MLB RX */ 30962306a36Sopenharmony_ci .rx = true, 31062306a36Sopenharmony_ci .descriptors = 2, 31162306a36Sopenharmony_ci .descriptor_elements = 1 31262306a36Sopenharmony_ci }, 31362306a36Sopenharmony_ci { 31462306a36Sopenharmony_ci /* MLB TX */ 31562306a36Sopenharmony_ci .rx = false, 31662306a36Sopenharmony_ci .descriptors = 2, 31762306a36Sopenharmony_ci .descriptor_elements = 1 31862306a36Sopenharmony_ci }, 31962306a36Sopenharmony_ci { 32062306a36Sopenharmony_ci /* Video RX */ 32162306a36Sopenharmony_ci .rx = true, 32262306a36Sopenharmony_ci .bytes_per_line = 1440, 32362306a36Sopenharmony_ci .descriptors = 2, 32462306a36Sopenharmony_ci .descriptor_elements = 16 32562306a36Sopenharmony_ci }, 32662306a36Sopenharmony_ci { 32762306a36Sopenharmony_ci /* Video framedrop */ 32862306a36Sopenharmony_ci }, 32962306a36Sopenharmony_ci { 33062306a36Sopenharmony_ci /* SDHCI RX */ 33162306a36Sopenharmony_ci .rx = true, 33262306a36Sopenharmony_ci }, 33362306a36Sopenharmony_ci { 33462306a36Sopenharmony_ci /* SDHCI TX */ 33562306a36Sopenharmony_ci }, 33662306a36Sopenharmony_ci { 33762306a36Sopenharmony_ci /* ETH RX */ 33862306a36Sopenharmony_ci .rx = true, 33962306a36Sopenharmony_ci .descriptors = 2, 34062306a36Sopenharmony_ci .descriptor_elements = 1 34162306a36Sopenharmony_ci }, 34262306a36Sopenharmony_ci { 34362306a36Sopenharmony_ci /* ETH TX */ 34462306a36Sopenharmony_ci .rx = false, 34562306a36Sopenharmony_ci .descriptors = 2, 34662306a36Sopenharmony_ci .descriptor_elements = 1 34762306a36Sopenharmony_ci }, 34862306a36Sopenharmony_ci } 34962306a36Sopenharmony_ci}; 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_cistatic const struct resource timberdale_dma_resources[] = { 35262306a36Sopenharmony_ci { 35362306a36Sopenharmony_ci .start = DMAOFFSET, 35462306a36Sopenharmony_ci .end = DMAEND, 35562306a36Sopenharmony_ci .flags = IORESOURCE_MEM, 35662306a36Sopenharmony_ci }, 35762306a36Sopenharmony_ci { 35862306a36Sopenharmony_ci .start = IRQ_TIMBERDALE_DMA, 35962306a36Sopenharmony_ci .end = IRQ_TIMBERDALE_DMA, 36062306a36Sopenharmony_ci .flags = IORESOURCE_IRQ, 36162306a36Sopenharmony_ci }, 36262306a36Sopenharmony_ci}; 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_cistatic const struct mfd_cell timberdale_cells_bar0_cfg0[] = { 36562306a36Sopenharmony_ci { 36662306a36Sopenharmony_ci .name = "timb-dma", 36762306a36Sopenharmony_ci .num_resources = ARRAY_SIZE(timberdale_dma_resources), 36862306a36Sopenharmony_ci .resources = timberdale_dma_resources, 36962306a36Sopenharmony_ci .platform_data = &timb_dma_platform_data, 37062306a36Sopenharmony_ci .pdata_size = sizeof(timb_dma_platform_data), 37162306a36Sopenharmony_ci }, 37262306a36Sopenharmony_ci { 37362306a36Sopenharmony_ci .name = "timb-uart", 37462306a36Sopenharmony_ci .num_resources = ARRAY_SIZE(timberdale_uart_resources), 37562306a36Sopenharmony_ci .resources = timberdale_uart_resources, 37662306a36Sopenharmony_ci }, 37762306a36Sopenharmony_ci { 37862306a36Sopenharmony_ci .name = "xiic-i2c", 37962306a36Sopenharmony_ci .num_resources = ARRAY_SIZE(timberdale_xiic_resources), 38062306a36Sopenharmony_ci .resources = timberdale_xiic_resources, 38162306a36Sopenharmony_ci .platform_data = &timberdale_xiic_platform_data, 38262306a36Sopenharmony_ci .pdata_size = sizeof(timberdale_xiic_platform_data), 38362306a36Sopenharmony_ci }, 38462306a36Sopenharmony_ci { 38562306a36Sopenharmony_ci .name = "timb-gpio", 38662306a36Sopenharmony_ci .num_resources = ARRAY_SIZE(timberdale_gpio_resources), 38762306a36Sopenharmony_ci .resources = timberdale_gpio_resources, 38862306a36Sopenharmony_ci .platform_data = &timberdale_gpio_platform_data, 38962306a36Sopenharmony_ci .pdata_size = sizeof(timberdale_gpio_platform_data), 39062306a36Sopenharmony_ci }, 39162306a36Sopenharmony_ci { 39262306a36Sopenharmony_ci .name = "timb-video", 39362306a36Sopenharmony_ci .num_resources = ARRAY_SIZE(timberdale_video_resources), 39462306a36Sopenharmony_ci .resources = timberdale_video_resources, 39562306a36Sopenharmony_ci .platform_data = &timberdale_video_platform_data, 39662306a36Sopenharmony_ci .pdata_size = sizeof(timberdale_video_platform_data), 39762306a36Sopenharmony_ci }, 39862306a36Sopenharmony_ci { 39962306a36Sopenharmony_ci .name = "timb-radio", 40062306a36Sopenharmony_ci .num_resources = ARRAY_SIZE(timberdale_radio_resources), 40162306a36Sopenharmony_ci .resources = timberdale_radio_resources, 40262306a36Sopenharmony_ci .platform_data = &timberdale_radio_platform_data, 40362306a36Sopenharmony_ci .pdata_size = sizeof(timberdale_radio_platform_data), 40462306a36Sopenharmony_ci }, 40562306a36Sopenharmony_ci { 40662306a36Sopenharmony_ci .name = "xilinx_spi", 40762306a36Sopenharmony_ci .num_resources = ARRAY_SIZE(timberdale_spi_resources), 40862306a36Sopenharmony_ci .resources = timberdale_spi_resources, 40962306a36Sopenharmony_ci .platform_data = &timberdale_xspi_platform_data, 41062306a36Sopenharmony_ci .pdata_size = sizeof(timberdale_xspi_platform_data), 41162306a36Sopenharmony_ci }, 41262306a36Sopenharmony_ci { 41362306a36Sopenharmony_ci .name = "ks8842", 41462306a36Sopenharmony_ci .num_resources = ARRAY_SIZE(timberdale_eth_resources), 41562306a36Sopenharmony_ci .resources = timberdale_eth_resources, 41662306a36Sopenharmony_ci .platform_data = &timberdale_ks8842_platform_data, 41762306a36Sopenharmony_ci .pdata_size = sizeof(timberdale_ks8842_platform_data), 41862306a36Sopenharmony_ci }, 41962306a36Sopenharmony_ci}; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_cistatic const struct mfd_cell timberdale_cells_bar0_cfg1[] = { 42262306a36Sopenharmony_ci { 42362306a36Sopenharmony_ci .name = "timb-dma", 42462306a36Sopenharmony_ci .num_resources = ARRAY_SIZE(timberdale_dma_resources), 42562306a36Sopenharmony_ci .resources = timberdale_dma_resources, 42662306a36Sopenharmony_ci .platform_data = &timb_dma_platform_data, 42762306a36Sopenharmony_ci .pdata_size = sizeof(timb_dma_platform_data), 42862306a36Sopenharmony_ci }, 42962306a36Sopenharmony_ci { 43062306a36Sopenharmony_ci .name = "timb-uart", 43162306a36Sopenharmony_ci .num_resources = ARRAY_SIZE(timberdale_uart_resources), 43262306a36Sopenharmony_ci .resources = timberdale_uart_resources, 43362306a36Sopenharmony_ci }, 43462306a36Sopenharmony_ci { 43562306a36Sopenharmony_ci .name = "uartlite", 43662306a36Sopenharmony_ci .num_resources = ARRAY_SIZE(timberdale_uartlite_resources), 43762306a36Sopenharmony_ci .resources = timberdale_uartlite_resources, 43862306a36Sopenharmony_ci }, 43962306a36Sopenharmony_ci { 44062306a36Sopenharmony_ci .name = "xiic-i2c", 44162306a36Sopenharmony_ci .num_resources = ARRAY_SIZE(timberdale_xiic_resources), 44262306a36Sopenharmony_ci .resources = timberdale_xiic_resources, 44362306a36Sopenharmony_ci .platform_data = &timberdale_xiic_platform_data, 44462306a36Sopenharmony_ci .pdata_size = sizeof(timberdale_xiic_platform_data), 44562306a36Sopenharmony_ci }, 44662306a36Sopenharmony_ci { 44762306a36Sopenharmony_ci .name = "timb-gpio", 44862306a36Sopenharmony_ci .num_resources = ARRAY_SIZE(timberdale_gpio_resources), 44962306a36Sopenharmony_ci .resources = timberdale_gpio_resources, 45062306a36Sopenharmony_ci .platform_data = &timberdale_gpio_platform_data, 45162306a36Sopenharmony_ci .pdata_size = sizeof(timberdale_gpio_platform_data), 45262306a36Sopenharmony_ci }, 45362306a36Sopenharmony_ci { 45462306a36Sopenharmony_ci .name = "timb-mlogicore", 45562306a36Sopenharmony_ci .num_resources = ARRAY_SIZE(timberdale_mlogicore_resources), 45662306a36Sopenharmony_ci .resources = timberdale_mlogicore_resources, 45762306a36Sopenharmony_ci }, 45862306a36Sopenharmony_ci { 45962306a36Sopenharmony_ci .name = "timb-video", 46062306a36Sopenharmony_ci .num_resources = ARRAY_SIZE(timberdale_video_resources), 46162306a36Sopenharmony_ci .resources = timberdale_video_resources, 46262306a36Sopenharmony_ci .platform_data = &timberdale_video_platform_data, 46362306a36Sopenharmony_ci .pdata_size = sizeof(timberdale_video_platform_data), 46462306a36Sopenharmony_ci }, 46562306a36Sopenharmony_ci { 46662306a36Sopenharmony_ci .name = "timb-radio", 46762306a36Sopenharmony_ci .num_resources = ARRAY_SIZE(timberdale_radio_resources), 46862306a36Sopenharmony_ci .resources = timberdale_radio_resources, 46962306a36Sopenharmony_ci .platform_data = &timberdale_radio_platform_data, 47062306a36Sopenharmony_ci .pdata_size = sizeof(timberdale_radio_platform_data), 47162306a36Sopenharmony_ci }, 47262306a36Sopenharmony_ci { 47362306a36Sopenharmony_ci .name = "xilinx_spi", 47462306a36Sopenharmony_ci .num_resources = ARRAY_SIZE(timberdale_spi_resources), 47562306a36Sopenharmony_ci .resources = timberdale_spi_resources, 47662306a36Sopenharmony_ci .platform_data = &timberdale_xspi_platform_data, 47762306a36Sopenharmony_ci .pdata_size = sizeof(timberdale_xspi_platform_data), 47862306a36Sopenharmony_ci }, 47962306a36Sopenharmony_ci { 48062306a36Sopenharmony_ci .name = "ks8842", 48162306a36Sopenharmony_ci .num_resources = ARRAY_SIZE(timberdale_eth_resources), 48262306a36Sopenharmony_ci .resources = timberdale_eth_resources, 48362306a36Sopenharmony_ci .platform_data = &timberdale_ks8842_platform_data, 48462306a36Sopenharmony_ci .pdata_size = sizeof(timberdale_ks8842_platform_data), 48562306a36Sopenharmony_ci }, 48662306a36Sopenharmony_ci}; 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_cistatic const struct mfd_cell timberdale_cells_bar0_cfg2[] = { 48962306a36Sopenharmony_ci { 49062306a36Sopenharmony_ci .name = "timb-dma", 49162306a36Sopenharmony_ci .num_resources = ARRAY_SIZE(timberdale_dma_resources), 49262306a36Sopenharmony_ci .resources = timberdale_dma_resources, 49362306a36Sopenharmony_ci .platform_data = &timb_dma_platform_data, 49462306a36Sopenharmony_ci .pdata_size = sizeof(timb_dma_platform_data), 49562306a36Sopenharmony_ci }, 49662306a36Sopenharmony_ci { 49762306a36Sopenharmony_ci .name = "timb-uart", 49862306a36Sopenharmony_ci .num_resources = ARRAY_SIZE(timberdale_uart_resources), 49962306a36Sopenharmony_ci .resources = timberdale_uart_resources, 50062306a36Sopenharmony_ci }, 50162306a36Sopenharmony_ci { 50262306a36Sopenharmony_ci .name = "xiic-i2c", 50362306a36Sopenharmony_ci .num_resources = ARRAY_SIZE(timberdale_xiic_resources), 50462306a36Sopenharmony_ci .resources = timberdale_xiic_resources, 50562306a36Sopenharmony_ci .platform_data = &timberdale_xiic_platform_data, 50662306a36Sopenharmony_ci .pdata_size = sizeof(timberdale_xiic_platform_data), 50762306a36Sopenharmony_ci }, 50862306a36Sopenharmony_ci { 50962306a36Sopenharmony_ci .name = "timb-gpio", 51062306a36Sopenharmony_ci .num_resources = ARRAY_SIZE(timberdale_gpio_resources), 51162306a36Sopenharmony_ci .resources = timberdale_gpio_resources, 51262306a36Sopenharmony_ci .platform_data = &timberdale_gpio_platform_data, 51362306a36Sopenharmony_ci .pdata_size = sizeof(timberdale_gpio_platform_data), 51462306a36Sopenharmony_ci }, 51562306a36Sopenharmony_ci { 51662306a36Sopenharmony_ci .name = "timb-video", 51762306a36Sopenharmony_ci .num_resources = ARRAY_SIZE(timberdale_video_resources), 51862306a36Sopenharmony_ci .resources = timberdale_video_resources, 51962306a36Sopenharmony_ci .platform_data = &timberdale_video_platform_data, 52062306a36Sopenharmony_ci .pdata_size = sizeof(timberdale_video_platform_data), 52162306a36Sopenharmony_ci }, 52262306a36Sopenharmony_ci { 52362306a36Sopenharmony_ci .name = "timb-radio", 52462306a36Sopenharmony_ci .num_resources = ARRAY_SIZE(timberdale_radio_resources), 52562306a36Sopenharmony_ci .resources = timberdale_radio_resources, 52662306a36Sopenharmony_ci .platform_data = &timberdale_radio_platform_data, 52762306a36Sopenharmony_ci .pdata_size = sizeof(timberdale_radio_platform_data), 52862306a36Sopenharmony_ci }, 52962306a36Sopenharmony_ci { 53062306a36Sopenharmony_ci .name = "xilinx_spi", 53162306a36Sopenharmony_ci .num_resources = ARRAY_SIZE(timberdale_spi_resources), 53262306a36Sopenharmony_ci .resources = timberdale_spi_resources, 53362306a36Sopenharmony_ci .platform_data = &timberdale_xspi_platform_data, 53462306a36Sopenharmony_ci .pdata_size = sizeof(timberdale_xspi_platform_data), 53562306a36Sopenharmony_ci }, 53662306a36Sopenharmony_ci}; 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_cistatic const struct mfd_cell timberdale_cells_bar0_cfg3[] = { 53962306a36Sopenharmony_ci { 54062306a36Sopenharmony_ci .name = "timb-dma", 54162306a36Sopenharmony_ci .num_resources = ARRAY_SIZE(timberdale_dma_resources), 54262306a36Sopenharmony_ci .resources = timberdale_dma_resources, 54362306a36Sopenharmony_ci .platform_data = &timb_dma_platform_data, 54462306a36Sopenharmony_ci .pdata_size = sizeof(timb_dma_platform_data), 54562306a36Sopenharmony_ci }, 54662306a36Sopenharmony_ci { 54762306a36Sopenharmony_ci .name = "timb-uart", 54862306a36Sopenharmony_ci .num_resources = ARRAY_SIZE(timberdale_uart_resources), 54962306a36Sopenharmony_ci .resources = timberdale_uart_resources, 55062306a36Sopenharmony_ci }, 55162306a36Sopenharmony_ci { 55262306a36Sopenharmony_ci .name = "ocores-i2c", 55362306a36Sopenharmony_ci .num_resources = ARRAY_SIZE(timberdale_ocores_resources), 55462306a36Sopenharmony_ci .resources = timberdale_ocores_resources, 55562306a36Sopenharmony_ci .platform_data = &timberdale_ocores_platform_data, 55662306a36Sopenharmony_ci .pdata_size = sizeof(timberdale_ocores_platform_data), 55762306a36Sopenharmony_ci }, 55862306a36Sopenharmony_ci { 55962306a36Sopenharmony_ci .name = "timb-gpio", 56062306a36Sopenharmony_ci .num_resources = ARRAY_SIZE(timberdale_gpio_resources), 56162306a36Sopenharmony_ci .resources = timberdale_gpio_resources, 56262306a36Sopenharmony_ci .platform_data = &timberdale_gpio_platform_data, 56362306a36Sopenharmony_ci .pdata_size = sizeof(timberdale_gpio_platform_data), 56462306a36Sopenharmony_ci }, 56562306a36Sopenharmony_ci { 56662306a36Sopenharmony_ci .name = "timb-video", 56762306a36Sopenharmony_ci .num_resources = ARRAY_SIZE(timberdale_video_resources), 56862306a36Sopenharmony_ci .resources = timberdale_video_resources, 56962306a36Sopenharmony_ci .platform_data = &timberdale_video_platform_data, 57062306a36Sopenharmony_ci .pdata_size = sizeof(timberdale_video_platform_data), 57162306a36Sopenharmony_ci }, 57262306a36Sopenharmony_ci { 57362306a36Sopenharmony_ci .name = "timb-radio", 57462306a36Sopenharmony_ci .num_resources = ARRAY_SIZE(timberdale_radio_resources), 57562306a36Sopenharmony_ci .resources = timberdale_radio_resources, 57662306a36Sopenharmony_ci .platform_data = &timberdale_radio_platform_data, 57762306a36Sopenharmony_ci .pdata_size = sizeof(timberdale_radio_platform_data), 57862306a36Sopenharmony_ci }, 57962306a36Sopenharmony_ci { 58062306a36Sopenharmony_ci .name = "xilinx_spi", 58162306a36Sopenharmony_ci .num_resources = ARRAY_SIZE(timberdale_spi_resources), 58262306a36Sopenharmony_ci .resources = timberdale_spi_resources, 58362306a36Sopenharmony_ci .platform_data = &timberdale_xspi_platform_data, 58462306a36Sopenharmony_ci .pdata_size = sizeof(timberdale_xspi_platform_data), 58562306a36Sopenharmony_ci }, 58662306a36Sopenharmony_ci { 58762306a36Sopenharmony_ci .name = "ks8842", 58862306a36Sopenharmony_ci .num_resources = ARRAY_SIZE(timberdale_eth_resources), 58962306a36Sopenharmony_ci .resources = timberdale_eth_resources, 59062306a36Sopenharmony_ci .platform_data = &timberdale_ks8842_platform_data, 59162306a36Sopenharmony_ci .pdata_size = sizeof(timberdale_ks8842_platform_data), 59262306a36Sopenharmony_ci }, 59362306a36Sopenharmony_ci}; 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_cistatic const struct resource timberdale_sdhc_resources[] = { 59662306a36Sopenharmony_ci /* located in bar 1 and bar 2 */ 59762306a36Sopenharmony_ci { 59862306a36Sopenharmony_ci .start = SDHC0OFFSET, 59962306a36Sopenharmony_ci .end = SDHC0END, 60062306a36Sopenharmony_ci .flags = IORESOURCE_MEM, 60162306a36Sopenharmony_ci }, 60262306a36Sopenharmony_ci { 60362306a36Sopenharmony_ci .start = IRQ_TIMBERDALE_SDHC, 60462306a36Sopenharmony_ci .end = IRQ_TIMBERDALE_SDHC, 60562306a36Sopenharmony_ci .flags = IORESOURCE_IRQ, 60662306a36Sopenharmony_ci }, 60762306a36Sopenharmony_ci}; 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_cistatic const struct mfd_cell timberdale_cells_bar1[] = { 61062306a36Sopenharmony_ci { 61162306a36Sopenharmony_ci .name = "sdhci", 61262306a36Sopenharmony_ci .num_resources = ARRAY_SIZE(timberdale_sdhc_resources), 61362306a36Sopenharmony_ci .resources = timberdale_sdhc_resources, 61462306a36Sopenharmony_ci }, 61562306a36Sopenharmony_ci}; 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_cistatic const struct mfd_cell timberdale_cells_bar2[] = { 61862306a36Sopenharmony_ci { 61962306a36Sopenharmony_ci .name = "sdhci", 62062306a36Sopenharmony_ci .num_resources = ARRAY_SIZE(timberdale_sdhc_resources), 62162306a36Sopenharmony_ci .resources = timberdale_sdhc_resources, 62262306a36Sopenharmony_ci }, 62362306a36Sopenharmony_ci}; 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_cistatic ssize_t fw_ver_show(struct device *dev, 62662306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 62762306a36Sopenharmony_ci{ 62862306a36Sopenharmony_ci struct timberdale_device *priv = dev_get_drvdata(dev); 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci return sprintf(buf, "%d.%d.%d\n", priv->fw.major, priv->fw.minor, 63162306a36Sopenharmony_ci priv->fw.config); 63262306a36Sopenharmony_ci} 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_cistatic DEVICE_ATTR_RO(fw_ver); 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci/*--------------------------------------------------------------------------*/ 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_cistatic int timb_probe(struct pci_dev *dev, 63962306a36Sopenharmony_ci const struct pci_device_id *id) 64062306a36Sopenharmony_ci{ 64162306a36Sopenharmony_ci struct timberdale_device *priv; 64262306a36Sopenharmony_ci int err, i; 64362306a36Sopenharmony_ci resource_size_t mapbase; 64462306a36Sopenharmony_ci struct msix_entry *msix_entries = NULL; 64562306a36Sopenharmony_ci u8 ip_setup; 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci priv = kzalloc(sizeof(*priv), GFP_KERNEL); 64862306a36Sopenharmony_ci if (!priv) 64962306a36Sopenharmony_ci return -ENOMEM; 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci pci_set_drvdata(dev, priv); 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci err = pci_enable_device(dev); 65462306a36Sopenharmony_ci if (err) 65562306a36Sopenharmony_ci goto err_enable; 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci mapbase = pci_resource_start(dev, 0); 65862306a36Sopenharmony_ci if (!mapbase) { 65962306a36Sopenharmony_ci dev_err(&dev->dev, "No resource\n"); 66062306a36Sopenharmony_ci goto err_start; 66162306a36Sopenharmony_ci } 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci /* create a resource for the PCI master register */ 66462306a36Sopenharmony_ci priv->ctl_mapbase = mapbase + CHIPCTLOFFSET; 66562306a36Sopenharmony_ci if (!request_mem_region(priv->ctl_mapbase, CHIPCTLSIZE, "timb-ctl")) { 66662306a36Sopenharmony_ci dev_err(&dev->dev, "Failed to request ctl mem\n"); 66762306a36Sopenharmony_ci goto err_start; 66862306a36Sopenharmony_ci } 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci priv->ctl_membase = ioremap(priv->ctl_mapbase, CHIPCTLSIZE); 67162306a36Sopenharmony_ci if (!priv->ctl_membase) { 67262306a36Sopenharmony_ci dev_err(&dev->dev, "ioremap failed for ctl mem\n"); 67362306a36Sopenharmony_ci goto err_ioremap; 67462306a36Sopenharmony_ci } 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci /* read the HW config */ 67762306a36Sopenharmony_ci priv->fw.major = ioread32(priv->ctl_membase + TIMB_REV_MAJOR); 67862306a36Sopenharmony_ci priv->fw.minor = ioread32(priv->ctl_membase + TIMB_REV_MINOR); 67962306a36Sopenharmony_ci priv->fw.config = ioread32(priv->ctl_membase + TIMB_HW_CONFIG); 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci if (priv->fw.major > TIMB_SUPPORTED_MAJOR) { 68262306a36Sopenharmony_ci dev_err(&dev->dev, "The driver supports an older " 68362306a36Sopenharmony_ci "version of the FPGA, please update the driver to " 68462306a36Sopenharmony_ci "support %d.%d\n", priv->fw.major, priv->fw.minor); 68562306a36Sopenharmony_ci goto err_config; 68662306a36Sopenharmony_ci } 68762306a36Sopenharmony_ci if (priv->fw.major < TIMB_SUPPORTED_MAJOR || 68862306a36Sopenharmony_ci priv->fw.minor < TIMB_REQUIRED_MINOR) { 68962306a36Sopenharmony_ci dev_err(&dev->dev, "The FPGA image is too old (%d.%d), " 69062306a36Sopenharmony_ci "please upgrade the FPGA to at least: %d.%d\n", 69162306a36Sopenharmony_ci priv->fw.major, priv->fw.minor, 69262306a36Sopenharmony_ci TIMB_SUPPORTED_MAJOR, TIMB_REQUIRED_MINOR); 69362306a36Sopenharmony_ci goto err_config; 69462306a36Sopenharmony_ci } 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci msix_entries = kcalloc(TIMBERDALE_NR_IRQS, sizeof(*msix_entries), 69762306a36Sopenharmony_ci GFP_KERNEL); 69862306a36Sopenharmony_ci if (!msix_entries) 69962306a36Sopenharmony_ci goto err_config; 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci for (i = 0; i < TIMBERDALE_NR_IRQS; i++) 70262306a36Sopenharmony_ci msix_entries[i].entry = i; 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci err = pci_enable_msix_exact(dev, msix_entries, TIMBERDALE_NR_IRQS); 70562306a36Sopenharmony_ci if (err) { 70662306a36Sopenharmony_ci dev_err(&dev->dev, 70762306a36Sopenharmony_ci "MSI-X init failed: %d, expected entries: %d\n", 70862306a36Sopenharmony_ci err, TIMBERDALE_NR_IRQS); 70962306a36Sopenharmony_ci goto err_msix; 71062306a36Sopenharmony_ci } 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci err = device_create_file(&dev->dev, &dev_attr_fw_ver); 71362306a36Sopenharmony_ci if (err) 71462306a36Sopenharmony_ci goto err_create_file; 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci /* Reset all FPGA PLB peripherals */ 71762306a36Sopenharmony_ci iowrite32(0x1, priv->ctl_membase + TIMB_SW_RST); 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci /* update IRQ offsets in I2C board info */ 72062306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(timberdale_i2c_board_info); i++) 72162306a36Sopenharmony_ci timberdale_i2c_board_info[i].irq = 72262306a36Sopenharmony_ci msix_entries[timberdale_i2c_board_info[i].irq].vector; 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci /* Update the SPI configuration depending on the HW (8 or 16 bit) */ 72562306a36Sopenharmony_ci if (priv->fw.config & TIMB_HW_CONFIG_SPI_8BIT) { 72662306a36Sopenharmony_ci timberdale_xspi_platform_data.bits_per_word = 8; 72762306a36Sopenharmony_ci timberdale_xspi_platform_data.devices = 72862306a36Sopenharmony_ci timberdale_spi_8bit_board_info; 72962306a36Sopenharmony_ci timberdale_xspi_platform_data.num_devices = 73062306a36Sopenharmony_ci ARRAY_SIZE(timberdale_spi_8bit_board_info); 73162306a36Sopenharmony_ci } else { 73262306a36Sopenharmony_ci timberdale_xspi_platform_data.bits_per_word = 16; 73362306a36Sopenharmony_ci timberdale_xspi_platform_data.devices = 73462306a36Sopenharmony_ci timberdale_spi_16bit_board_info; 73562306a36Sopenharmony_ci timberdale_xspi_platform_data.num_devices = 73662306a36Sopenharmony_ci ARRAY_SIZE(timberdale_spi_16bit_board_info); 73762306a36Sopenharmony_ci } 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci ip_setup = priv->fw.config & TIMB_HW_VER_MASK; 74062306a36Sopenharmony_ci switch (ip_setup) { 74162306a36Sopenharmony_ci case TIMB_HW_VER0: 74262306a36Sopenharmony_ci err = mfd_add_devices(&dev->dev, -1, 74362306a36Sopenharmony_ci timberdale_cells_bar0_cfg0, 74462306a36Sopenharmony_ci ARRAY_SIZE(timberdale_cells_bar0_cfg0), 74562306a36Sopenharmony_ci &dev->resource[0], msix_entries[0].vector, NULL); 74662306a36Sopenharmony_ci break; 74762306a36Sopenharmony_ci case TIMB_HW_VER1: 74862306a36Sopenharmony_ci err = mfd_add_devices(&dev->dev, -1, 74962306a36Sopenharmony_ci timberdale_cells_bar0_cfg1, 75062306a36Sopenharmony_ci ARRAY_SIZE(timberdale_cells_bar0_cfg1), 75162306a36Sopenharmony_ci &dev->resource[0], msix_entries[0].vector, NULL); 75262306a36Sopenharmony_ci break; 75362306a36Sopenharmony_ci case TIMB_HW_VER2: 75462306a36Sopenharmony_ci err = mfd_add_devices(&dev->dev, -1, 75562306a36Sopenharmony_ci timberdale_cells_bar0_cfg2, 75662306a36Sopenharmony_ci ARRAY_SIZE(timberdale_cells_bar0_cfg2), 75762306a36Sopenharmony_ci &dev->resource[0], msix_entries[0].vector, NULL); 75862306a36Sopenharmony_ci break; 75962306a36Sopenharmony_ci case TIMB_HW_VER3: 76062306a36Sopenharmony_ci err = mfd_add_devices(&dev->dev, -1, 76162306a36Sopenharmony_ci timberdale_cells_bar0_cfg3, 76262306a36Sopenharmony_ci ARRAY_SIZE(timberdale_cells_bar0_cfg3), 76362306a36Sopenharmony_ci &dev->resource[0], msix_entries[0].vector, NULL); 76462306a36Sopenharmony_ci break; 76562306a36Sopenharmony_ci default: 76662306a36Sopenharmony_ci dev_err(&dev->dev, "Unknown IP setup: %d.%d.%d\n", 76762306a36Sopenharmony_ci priv->fw.major, priv->fw.minor, ip_setup); 76862306a36Sopenharmony_ci err = -ENODEV; 76962306a36Sopenharmony_ci goto err_mfd; 77062306a36Sopenharmony_ci } 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci if (err) { 77362306a36Sopenharmony_ci dev_err(&dev->dev, "mfd_add_devices failed: %d\n", err); 77462306a36Sopenharmony_ci goto err_mfd; 77562306a36Sopenharmony_ci } 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci err = mfd_add_devices(&dev->dev, 0, 77862306a36Sopenharmony_ci timberdale_cells_bar1, ARRAY_SIZE(timberdale_cells_bar1), 77962306a36Sopenharmony_ci &dev->resource[1], msix_entries[0].vector, NULL); 78062306a36Sopenharmony_ci if (err) { 78162306a36Sopenharmony_ci dev_err(&dev->dev, "mfd_add_devices failed: %d\n", err); 78262306a36Sopenharmony_ci goto err_mfd2; 78362306a36Sopenharmony_ci } 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci /* only version 0 and 3 have the iNand routed to SDHCI */ 78662306a36Sopenharmony_ci if (((priv->fw.config & TIMB_HW_VER_MASK) == TIMB_HW_VER0) || 78762306a36Sopenharmony_ci ((priv->fw.config & TIMB_HW_VER_MASK) == TIMB_HW_VER3)) { 78862306a36Sopenharmony_ci err = mfd_add_devices(&dev->dev, 1, timberdale_cells_bar2, 78962306a36Sopenharmony_ci ARRAY_SIZE(timberdale_cells_bar2), 79062306a36Sopenharmony_ci &dev->resource[2], msix_entries[0].vector, NULL); 79162306a36Sopenharmony_ci if (err) { 79262306a36Sopenharmony_ci dev_err(&dev->dev, "mfd_add_devices failed: %d\n", err); 79362306a36Sopenharmony_ci goto err_mfd2; 79462306a36Sopenharmony_ci } 79562306a36Sopenharmony_ci } 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci kfree(msix_entries); 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci dev_info(&dev->dev, 80062306a36Sopenharmony_ci "Found Timberdale Card. Rev: %d.%d, HW config: 0x%02x\n", 80162306a36Sopenharmony_ci priv->fw.major, priv->fw.minor, priv->fw.config); 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci return 0; 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_cierr_mfd2: 80662306a36Sopenharmony_ci mfd_remove_devices(&dev->dev); 80762306a36Sopenharmony_cierr_mfd: 80862306a36Sopenharmony_ci device_remove_file(&dev->dev, &dev_attr_fw_ver); 80962306a36Sopenharmony_cierr_create_file: 81062306a36Sopenharmony_ci pci_disable_msix(dev); 81162306a36Sopenharmony_cierr_msix: 81262306a36Sopenharmony_ci kfree(msix_entries); 81362306a36Sopenharmony_cierr_config: 81462306a36Sopenharmony_ci iounmap(priv->ctl_membase); 81562306a36Sopenharmony_cierr_ioremap: 81662306a36Sopenharmony_ci release_mem_region(priv->ctl_mapbase, CHIPCTLSIZE); 81762306a36Sopenharmony_cierr_start: 81862306a36Sopenharmony_ci pci_disable_device(dev); 81962306a36Sopenharmony_cierr_enable: 82062306a36Sopenharmony_ci kfree(priv); 82162306a36Sopenharmony_ci return -ENODEV; 82262306a36Sopenharmony_ci} 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_cistatic void timb_remove(struct pci_dev *dev) 82562306a36Sopenharmony_ci{ 82662306a36Sopenharmony_ci struct timberdale_device *priv = pci_get_drvdata(dev); 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci mfd_remove_devices(&dev->dev); 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_ci device_remove_file(&dev->dev, &dev_attr_fw_ver); 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci iounmap(priv->ctl_membase); 83362306a36Sopenharmony_ci release_mem_region(priv->ctl_mapbase, CHIPCTLSIZE); 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci pci_disable_msix(dev); 83662306a36Sopenharmony_ci pci_disable_device(dev); 83762306a36Sopenharmony_ci kfree(priv); 83862306a36Sopenharmony_ci} 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_cistatic const struct pci_device_id timberdale_pci_tbl[] = { 84162306a36Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_TIMB, PCI_DEVICE_ID_TIMB) }, 84262306a36Sopenharmony_ci { 0 } 84362306a36Sopenharmony_ci}; 84462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, timberdale_pci_tbl); 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_cistatic struct pci_driver timberdale_pci_driver = { 84762306a36Sopenharmony_ci .name = DRIVER_NAME, 84862306a36Sopenharmony_ci .id_table = timberdale_pci_tbl, 84962306a36Sopenharmony_ci .probe = timb_probe, 85062306a36Sopenharmony_ci .remove = timb_remove, 85162306a36Sopenharmony_ci}; 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_cimodule_pci_driver(timberdale_pci_driver); 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ciMODULE_AUTHOR("Mocean Laboratories <info@mocean-labs.com>"); 85662306a36Sopenharmony_ciMODULE_VERSION(DRV_VERSION); 85762306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 858