xref: /openbmc/linux/drivers/mfd/timberdale.c (revision 5588bd59)
18edbede9SRichard Röjfors /*
28edbede9SRichard Röjfors  * timberdale.c timberdale FPGA MFD driver
38edbede9SRichard Röjfors  * Copyright (c) 2009 Intel Corporation
48edbede9SRichard Röjfors  *
58edbede9SRichard Röjfors  * This program is free software; you can redistribute it and/or modify
68edbede9SRichard Röjfors  * it under the terms of the GNU General Public License version 2 as
78edbede9SRichard Röjfors  * published by the Free Software Foundation.
88edbede9SRichard Röjfors  *
98edbede9SRichard Röjfors  * This program is distributed in the hope that it will be useful,
108edbede9SRichard Röjfors  * but WITHOUT ANY WARRANTY; without even the implied warranty of
118edbede9SRichard Röjfors  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
128edbede9SRichard Röjfors  * GNU General Public License for more details.
138edbede9SRichard Röjfors  *
148edbede9SRichard Röjfors  * You should have received a copy of the GNU General Public License
158edbede9SRichard Röjfors  * along with this program; if not, write to the Free Software
168edbede9SRichard Röjfors  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
178edbede9SRichard Röjfors  */
188edbede9SRichard Röjfors 
198edbede9SRichard Röjfors /* Supports:
208edbede9SRichard Röjfors  * Timberdale FPGA
218edbede9SRichard Röjfors  */
228edbede9SRichard Röjfors 
238edbede9SRichard Röjfors #include <linux/kernel.h>
248edbede9SRichard Röjfors #include <linux/module.h>
258edbede9SRichard Röjfors #include <linux/pci.h>
268edbede9SRichard Röjfors #include <linux/msi.h>
278edbede9SRichard Röjfors #include <linux/mfd/core.h>
285a0e3ad6STejun Heo #include <linux/slab.h>
298edbede9SRichard Röjfors 
308edbede9SRichard Röjfors #include <linux/timb_gpio.h>
318edbede9SRichard Röjfors 
328edbede9SRichard Röjfors #include <linux/i2c.h>
338edbede9SRichard Röjfors #include <linux/i2c-ocores.h>
34d84027bcSRichard Röjfors #include <linux/i2c-xiic.h>
358edbede9SRichard Röjfors 
368edbede9SRichard Röjfors #include <linux/spi/spi.h>
378edbede9SRichard Röjfors #include <linux/spi/xilinx_spi.h>
388edbede9SRichard Röjfors #include <linux/spi/max7301.h>
398edbede9SRichard Röjfors #include <linux/spi/mc33880.h>
408edbede9SRichard Röjfors 
418fd70815SWolfram Sang #include <linux/platform_data/tsc2007.h>
42eb4b0ec7SMauro Carvalho Chehab #include <linux/platform_data/media/timb_radio.h>
43eb4b0ec7SMauro Carvalho Chehab #include <linux/platform_data/media/timb_video.h>
44071193ffSRichard Röjfors 
45dc64f30fSRichard Röjfors #include <linux/timb_dma.h>
46dc64f30fSRichard Röjfors 
476901ffd9SRichard Röjfors #include <linux/ks8842.h>
486901ffd9SRichard Röjfors 
498edbede9SRichard Röjfors #include "timberdale.h"
508edbede9SRichard Röjfors 
518edbede9SRichard Röjfors #define DRIVER_NAME "timberdale"
528edbede9SRichard Röjfors 
538edbede9SRichard Röjfors struct timberdale_device {
548edbede9SRichard Röjfors 	resource_size_t		ctl_mapbase;
558edbede9SRichard Röjfors 	unsigned char __iomem   *ctl_membase;
568edbede9SRichard Röjfors 	struct {
578edbede9SRichard Röjfors 		u32 major;
588edbede9SRichard Röjfors 		u32 minor;
598edbede9SRichard Röjfors 		u32 config;
608edbede9SRichard Röjfors 	} fw;
618edbede9SRichard Röjfors };
628edbede9SRichard Röjfors 
638edbede9SRichard Röjfors /*--------------------------------------------------------------------------*/
648edbede9SRichard Röjfors 
658edbede9SRichard Röjfors static struct tsc2007_platform_data timberdale_tsc2007_platform_data = {
668edbede9SRichard Röjfors 	.model = 2003,
678edbede9SRichard Röjfors 	.x_plate_ohms = 100
688edbede9SRichard Röjfors };
698edbede9SRichard Röjfors 
708edbede9SRichard Röjfors static struct i2c_board_info timberdale_i2c_board_info[] = {
718edbede9SRichard Röjfors 	{
728edbede9SRichard Röjfors 		I2C_BOARD_INFO("tsc2007", 0x48),
738edbede9SRichard Röjfors 		.platform_data = &timberdale_tsc2007_platform_data,
748edbede9SRichard Röjfors 		.irq = IRQ_TIMBERDALE_TSC_INT
758edbede9SRichard Röjfors 	},
768edbede9SRichard Röjfors };
778edbede9SRichard Röjfors 
78a9e9ce4cSBill Pemberton static struct xiic_i2c_platform_data
79d84027bcSRichard Röjfors timberdale_xiic_platform_data = {
80d84027bcSRichard Röjfors 	.devices = timberdale_i2c_board_info,
81d84027bcSRichard Röjfors 	.num_devices = ARRAY_SIZE(timberdale_i2c_board_info)
82d84027bcSRichard Röjfors };
83d84027bcSRichard Röjfors 
84a9e9ce4cSBill Pemberton static struct ocores_i2c_platform_data
858edbede9SRichard Röjfors timberdale_ocores_platform_data = {
86d739a464SJayachandran C 	.reg_shift = 2,
878edbede9SRichard Röjfors 	.clock_khz = 62500,
888edbede9SRichard Röjfors 	.devices = timberdale_i2c_board_info,
898edbede9SRichard Röjfors 	.num_devices = ARRAY_SIZE(timberdale_i2c_board_info)
908edbede9SRichard Röjfors };
918edbede9SRichard Röjfors 
92a73e5df1SBill Pemberton static const struct resource timberdale_xiic_resources[] = {
93d84027bcSRichard Röjfors 	{
94d84027bcSRichard Röjfors 		.start	= XIICOFFSET,
95d84027bcSRichard Röjfors 		.end	= XIICEND,
96d84027bcSRichard Röjfors 		.flags	= IORESOURCE_MEM,
97d84027bcSRichard Röjfors 	},
98d84027bcSRichard Röjfors 	{
99d84027bcSRichard Röjfors 		.start	= IRQ_TIMBERDALE_I2C,
100d84027bcSRichard Röjfors 		.end	= IRQ_TIMBERDALE_I2C,
101d84027bcSRichard Röjfors 		.flags	= IORESOURCE_IRQ,
102d84027bcSRichard Röjfors 	},
103d84027bcSRichard Röjfors };
104d84027bcSRichard Röjfors 
105a73e5df1SBill Pemberton static const struct resource timberdale_ocores_resources[] = {
1068edbede9SRichard Röjfors 	{
1078edbede9SRichard Röjfors 		.start	= OCORESOFFSET,
1088edbede9SRichard Röjfors 		.end	= OCORESEND,
1098edbede9SRichard Röjfors 		.flags	= IORESOURCE_MEM,
1108edbede9SRichard Röjfors 	},
1118edbede9SRichard Röjfors 	{
1128edbede9SRichard Röjfors 		.start 	= IRQ_TIMBERDALE_I2C,
1138edbede9SRichard Röjfors 		.end	= IRQ_TIMBERDALE_I2C,
1148edbede9SRichard Röjfors 		.flags	= IORESOURCE_IRQ,
1158edbede9SRichard Röjfors 	},
1168edbede9SRichard Röjfors };
1178edbede9SRichard Röjfors 
1184eaf4157SSachin Kamat static const struct max7301_platform_data timberdale_max7301_platform_data = {
1198edbede9SRichard Röjfors 	.base = 200
1208edbede9SRichard Röjfors };
1218edbede9SRichard Röjfors 
1224eaf4157SSachin Kamat static const struct mc33880_platform_data timberdale_mc33880_platform_data = {
1238edbede9SRichard Röjfors 	.base = 100
1248edbede9SRichard Röjfors };
1258edbede9SRichard Röjfors 
1268edbede9SRichard Röjfors static struct spi_board_info timberdale_spi_16bit_board_info[] = {
1278edbede9SRichard Röjfors 	{
1288edbede9SRichard Röjfors 		.modalias = "max7301",
1298edbede9SRichard Röjfors 		.max_speed_hz = 26000,
1308edbede9SRichard Röjfors 		.chip_select = 2,
1318edbede9SRichard Röjfors 		.mode = SPI_MODE_0,
1328edbede9SRichard Röjfors 		.platform_data = &timberdale_max7301_platform_data
1338edbede9SRichard Röjfors 	},
1348edbede9SRichard Röjfors };
1358edbede9SRichard Röjfors 
1368edbede9SRichard Röjfors static struct spi_board_info timberdale_spi_8bit_board_info[] = {
1378edbede9SRichard Röjfors 	{
1388edbede9SRichard Röjfors 		.modalias = "mc33880",
1398edbede9SRichard Röjfors 		.max_speed_hz = 4000,
1408edbede9SRichard Röjfors 		.chip_select = 1,
1418edbede9SRichard Röjfors 		.mode = SPI_MODE_1,
1428edbede9SRichard Röjfors 		.platform_data = &timberdale_mc33880_platform_data
1438edbede9SRichard Röjfors 	},
1448edbede9SRichard Röjfors };
1458edbede9SRichard Röjfors 
146a9e9ce4cSBill Pemberton static struct xspi_platform_data timberdale_xspi_platform_data = {
1478edbede9SRichard Röjfors 	.num_chipselect = 3,
1488edbede9SRichard Röjfors 	/* bits per word and devices will be filled in runtime depending
1498edbede9SRichard Röjfors 	 * on the HW config
1508edbede9SRichard Röjfors 	 */
1518edbede9SRichard Röjfors };
1528edbede9SRichard Röjfors 
153a73e5df1SBill Pemberton static const struct resource timberdale_spi_resources[] = {
1548edbede9SRichard Röjfors 	{
1558edbede9SRichard Röjfors 		.start 	= SPIOFFSET,
1568edbede9SRichard Röjfors 		.end	= SPIEND,
1578edbede9SRichard Röjfors 		.flags	= IORESOURCE_MEM,
1588edbede9SRichard Röjfors 	},
1598edbede9SRichard Röjfors 	{
1608edbede9SRichard Röjfors 		.start	= IRQ_TIMBERDALE_SPI,
1618edbede9SRichard Röjfors 		.end	= IRQ_TIMBERDALE_SPI,
1628edbede9SRichard Röjfors 		.flags	= IORESOURCE_IRQ,
1638edbede9SRichard Röjfors 	},
1648edbede9SRichard Röjfors };
1658edbede9SRichard Röjfors 
166a9e9ce4cSBill Pemberton static struct ks8842_platform_data
1676901ffd9SRichard Röjfors 	timberdale_ks8842_platform_data = {
1686901ffd9SRichard Röjfors 	.rx_dma_channel = DMA_ETH_RX,
1696901ffd9SRichard Röjfors 	.tx_dma_channel = DMA_ETH_TX
1706901ffd9SRichard Röjfors };
1716901ffd9SRichard Röjfors 
172a73e5df1SBill Pemberton static const struct resource timberdale_eth_resources[] = {
1738edbede9SRichard Röjfors 	{
1748edbede9SRichard Röjfors 		.start	= ETHOFFSET,
1758edbede9SRichard Röjfors 		.end	= ETHEND,
1768edbede9SRichard Röjfors 		.flags	= IORESOURCE_MEM,
1778edbede9SRichard Röjfors 	},
1788edbede9SRichard Röjfors 	{
1798edbede9SRichard Röjfors 		.start	= IRQ_TIMBERDALE_ETHSW_IF,
1808edbede9SRichard Röjfors 		.end	= IRQ_TIMBERDALE_ETHSW_IF,
1818edbede9SRichard Röjfors 		.flags	= IORESOURCE_IRQ,
1828edbede9SRichard Röjfors 	},
1838edbede9SRichard Röjfors };
1848edbede9SRichard Röjfors 
185a9e9ce4cSBill Pemberton static struct timbgpio_platform_data
1868edbede9SRichard Röjfors 	timberdale_gpio_platform_data = {
1878edbede9SRichard Röjfors 	.gpio_base = 0,
1888edbede9SRichard Röjfors 	.nr_pins = GPIO_NR_PINS,
1898edbede9SRichard Röjfors 	.irq_base = 200,
1908edbede9SRichard Röjfors };
1918edbede9SRichard Röjfors 
192a73e5df1SBill Pemberton static const struct resource timberdale_gpio_resources[] = {
1938edbede9SRichard Röjfors 	{
1948edbede9SRichard Röjfors 		.start	= GPIOOFFSET,
1958edbede9SRichard Röjfors 		.end	= GPIOEND,
1968edbede9SRichard Röjfors 		.flags	= IORESOURCE_MEM,
1978edbede9SRichard Röjfors 	},
1988edbede9SRichard Röjfors 	{
1998edbede9SRichard Röjfors 		.start	= IRQ_TIMBERDALE_GPIO,
2008edbede9SRichard Röjfors 		.end	= IRQ_TIMBERDALE_GPIO,
2018edbede9SRichard Röjfors 		.flags	= IORESOURCE_IRQ,
2028edbede9SRichard Röjfors 	},
2038edbede9SRichard Röjfors };
2048edbede9SRichard Röjfors 
205a73e5df1SBill Pemberton static const struct resource timberdale_mlogicore_resources[] = {
2068edbede9SRichard Röjfors 	{
2078edbede9SRichard Röjfors 		.start	= MLCOREOFFSET,
2088edbede9SRichard Röjfors 		.end	= MLCOREEND,
2098edbede9SRichard Röjfors 		.flags	= IORESOURCE_MEM,
2108edbede9SRichard Röjfors 	},
2118edbede9SRichard Röjfors 	{
2128edbede9SRichard Röjfors 		.start	= IRQ_TIMBERDALE_MLCORE,
2138edbede9SRichard Röjfors 		.end	= IRQ_TIMBERDALE_MLCORE,
2148edbede9SRichard Röjfors 		.flags	= IORESOURCE_IRQ,
2158edbede9SRichard Röjfors 	},
2168edbede9SRichard Röjfors 	{
2178edbede9SRichard Röjfors 		.start	= IRQ_TIMBERDALE_MLCORE_BUF,
2188edbede9SRichard Röjfors 		.end	= IRQ_TIMBERDALE_MLCORE_BUF,
2198edbede9SRichard Röjfors 		.flags	= IORESOURCE_IRQ,
2208edbede9SRichard Röjfors 	},
2218edbede9SRichard Röjfors };
2228edbede9SRichard Röjfors 
223a73e5df1SBill Pemberton static const struct resource timberdale_uart_resources[] = {
2248edbede9SRichard Röjfors 	{
2258edbede9SRichard Röjfors 		.start	= UARTOFFSET,
2268edbede9SRichard Röjfors 		.end	= UARTEND,
2278edbede9SRichard Röjfors 		.flags	= IORESOURCE_MEM,
2288edbede9SRichard Röjfors 	},
2298edbede9SRichard Röjfors 	{
2308edbede9SRichard Röjfors 		.start	= IRQ_TIMBERDALE_UART,
2318edbede9SRichard Röjfors 		.end	= IRQ_TIMBERDALE_UART,
2328edbede9SRichard Röjfors 		.flags	= IORESOURCE_IRQ,
2338edbede9SRichard Röjfors 	},
2348edbede9SRichard Röjfors };
2358edbede9SRichard Röjfors 
236a73e5df1SBill Pemberton static const struct resource timberdale_uartlite_resources[] = {
2378edbede9SRichard Röjfors 	{
2388edbede9SRichard Röjfors 		.start	= UARTLITEOFFSET,
2398edbede9SRichard Röjfors 		.end	= UARTLITEEND,
2408edbede9SRichard Röjfors 		.flags	= IORESOURCE_MEM,
2418edbede9SRichard Röjfors 	},
2428edbede9SRichard Röjfors 	{
2438edbede9SRichard Röjfors 		.start	= IRQ_TIMBERDALE_UARTLITE,
2448edbede9SRichard Röjfors 		.end	= IRQ_TIMBERDALE_UARTLITE,
2458edbede9SRichard Röjfors 		.flags	= IORESOURCE_IRQ,
2468edbede9SRichard Röjfors 	},
2478edbede9SRichard Röjfors };
2488edbede9SRichard Röjfors 
249a9e9ce4cSBill Pemberton static struct i2c_board_info timberdale_adv7180_i2c_board_info = {
250c091575cSRichard Röjfors 	/* Requires jumper JP9 to be off */
251c091575cSRichard Röjfors 	I2C_BOARD_INFO("adv7180", 0x42 >> 1),
252c091575cSRichard Röjfors 	.irq = IRQ_TIMBERDALE_ADV7180
253c091575cSRichard Röjfors };
254c091575cSRichard Röjfors 
255a9e9ce4cSBill Pemberton static struct timb_video_platform_data
256c091575cSRichard Röjfors 	timberdale_video_platform_data = {
257c091575cSRichard Röjfors 	.dma_channel = DMA_VIDEO_RX,
258c091575cSRichard Röjfors 	.i2c_adapter = 0,
259c091575cSRichard Röjfors 	.encoder = {
260c091575cSRichard Röjfors 		.info = &timberdale_adv7180_i2c_board_info
261c091575cSRichard Röjfors 	}
262c091575cSRichard Röjfors };
263c091575cSRichard Röjfors 
264a73e5df1SBill Pemberton static const struct resource
265c091575cSRichard Röjfors timberdale_radio_resources[] = {
266071193ffSRichard Röjfors 	{
267071193ffSRichard Röjfors 		.start	= RDSOFFSET,
268071193ffSRichard Röjfors 		.end	= RDSEND,
269071193ffSRichard Röjfors 		.flags	= IORESOURCE_MEM,
270071193ffSRichard Röjfors 	},
271071193ffSRichard Röjfors 	{
272071193ffSRichard Röjfors 		.start	= IRQ_TIMBERDALE_RDS,
273071193ffSRichard Röjfors 		.end	= IRQ_TIMBERDALE_RDS,
274071193ffSRichard Röjfors 		.flags	= IORESOURCE_IRQ,
275071193ffSRichard Röjfors 	},
276071193ffSRichard Röjfors };
277071193ffSRichard Röjfors 
278a9e9ce4cSBill Pemberton static struct i2c_board_info timberdale_tef6868_i2c_board_info = {
279071193ffSRichard Röjfors 	I2C_BOARD_INFO("tef6862", 0x60)
280071193ffSRichard Röjfors };
281071193ffSRichard Röjfors 
282a9e9ce4cSBill Pemberton static struct i2c_board_info timberdale_saa7706_i2c_board_info = {
283071193ffSRichard Röjfors 	I2C_BOARD_INFO("saa7706h", 0x1C)
284071193ffSRichard Röjfors };
285071193ffSRichard Röjfors 
286a9e9ce4cSBill Pemberton static struct timb_radio_platform_data
287071193ffSRichard Röjfors 	timberdale_radio_platform_data = {
288071193ffSRichard Röjfors 	.i2c_adapter = 0,
2899cd49719SRichard Röjfors 	.tuner = &timberdale_tef6868_i2c_board_info,
2909cd49719SRichard Röjfors 	.dsp = &timberdale_saa7706_i2c_board_info
291071193ffSRichard Röjfors };
292071193ffSRichard Röjfors 
293a73e5df1SBill Pemberton static const struct resource timberdale_video_resources[] = {
294c091575cSRichard Röjfors 	{
295c091575cSRichard Röjfors 		.start	= LOGIWOFFSET,
296c091575cSRichard Röjfors 		.end	= LOGIWEND,
297c091575cSRichard Röjfors 		.flags	= IORESOURCE_MEM,
298c091575cSRichard Röjfors 	},
299c091575cSRichard Röjfors 	/*
300c091575cSRichard Röjfors 	note that the "frame buffer" is located in DMA area
301c091575cSRichard Röjfors 	starting at 0x1200000
302c091575cSRichard Röjfors 	*/
303c091575cSRichard Röjfors };
304c091575cSRichard Röjfors 
305a9e9ce4cSBill Pemberton static struct timb_dma_platform_data timb_dma_platform_data = {
306dc64f30fSRichard Röjfors 	.nr_channels = 10,
307dc64f30fSRichard Röjfors 	.channels = {
308dc64f30fSRichard Röjfors 		{
309dc64f30fSRichard Röjfors 			/* UART RX */
310dc64f30fSRichard Röjfors 			.rx = true,
311dc64f30fSRichard Röjfors 			.descriptors = 2,
312dc64f30fSRichard Röjfors 			.descriptor_elements = 1
313dc64f30fSRichard Röjfors 		},
314dc64f30fSRichard Röjfors 		{
315dc64f30fSRichard Röjfors 			/* UART TX */
316dc64f30fSRichard Röjfors 			.rx = false,
317dc64f30fSRichard Röjfors 			.descriptors = 2,
318dc64f30fSRichard Röjfors 			.descriptor_elements = 1
319dc64f30fSRichard Röjfors 		},
320dc64f30fSRichard Röjfors 		{
321dc64f30fSRichard Röjfors 			/* MLB RX */
322dc64f30fSRichard Röjfors 			.rx = true,
323dc64f30fSRichard Röjfors 			.descriptors = 2,
324dc64f30fSRichard Röjfors 			.descriptor_elements = 1
325dc64f30fSRichard Röjfors 		},
326dc64f30fSRichard Röjfors 		{
327dc64f30fSRichard Röjfors 			/* MLB TX */
328dc64f30fSRichard Röjfors 			.rx = false,
329dc64f30fSRichard Röjfors 			.descriptors = 2,
330dc64f30fSRichard Röjfors 			.descriptor_elements = 1
331dc64f30fSRichard Röjfors 		},
332dc64f30fSRichard Röjfors 		{
333dc64f30fSRichard Röjfors 			/* Video RX */
334dc64f30fSRichard Röjfors 			.rx = true,
335dc64f30fSRichard Röjfors 			.bytes_per_line = 1440,
336dc64f30fSRichard Röjfors 			.descriptors = 2,
337dc64f30fSRichard Röjfors 			.descriptor_elements = 16
338dc64f30fSRichard Röjfors 		},
339dc64f30fSRichard Röjfors 		{
340dc64f30fSRichard Röjfors 			/* Video framedrop */
341dc64f30fSRichard Röjfors 		},
342dc64f30fSRichard Röjfors 		{
343dc64f30fSRichard Röjfors 			/* SDHCI RX */
344dc64f30fSRichard Röjfors 			.rx = true,
345dc64f30fSRichard Röjfors 		},
346dc64f30fSRichard Röjfors 		{
347dc64f30fSRichard Röjfors 			/* SDHCI TX */
348dc64f30fSRichard Röjfors 		},
349dc64f30fSRichard Röjfors 		{
350dc64f30fSRichard Röjfors 			/* ETH RX */
351dc64f30fSRichard Röjfors 			.rx = true,
352dc64f30fSRichard Röjfors 			.descriptors = 2,
353dc64f30fSRichard Röjfors 			.descriptor_elements = 1
354dc64f30fSRichard Röjfors 		},
355dc64f30fSRichard Röjfors 		{
356dc64f30fSRichard Röjfors 			/* ETH TX */
357dc64f30fSRichard Röjfors 			.rx = false,
358dc64f30fSRichard Röjfors 			.descriptors = 2,
359dc64f30fSRichard Röjfors 			.descriptor_elements = 1
360dc64f30fSRichard Röjfors 		},
361dc64f30fSRichard Röjfors 	}
362dc64f30fSRichard Röjfors };
363dc64f30fSRichard Röjfors 
364a73e5df1SBill Pemberton static const struct resource timberdale_dma_resources[] = {
3658edbede9SRichard Röjfors 	{
3668edbede9SRichard Röjfors 		.start	= DMAOFFSET,
3678edbede9SRichard Röjfors 		.end	= DMAEND,
3688edbede9SRichard Röjfors 		.flags	= IORESOURCE_MEM,
3698edbede9SRichard Röjfors 	},
3708edbede9SRichard Röjfors 	{
3718edbede9SRichard Röjfors 		.start	= IRQ_TIMBERDALE_DMA,
3728edbede9SRichard Röjfors 		.end	= IRQ_TIMBERDALE_DMA,
3738edbede9SRichard Röjfors 		.flags	= IORESOURCE_IRQ,
3748edbede9SRichard Röjfors 	},
3758edbede9SRichard Röjfors };
3768edbede9SRichard Röjfors 
3775ac98553SGeert Uytterhoeven static const struct mfd_cell timberdale_cells_bar0_cfg0[] = {
3788edbede9SRichard Röjfors 	{
379dc64f30fSRichard Röjfors 		.name = "timb-dma",
380dc64f30fSRichard Röjfors 		.num_resources = ARRAY_SIZE(timberdale_dma_resources),
381dc64f30fSRichard Röjfors 		.resources = timberdale_dma_resources,
3823271d382SSamuel Ortiz 		.platform_data = &timb_dma_platform_data,
3833271d382SSamuel Ortiz 		.pdata_size = sizeof(timb_dma_platform_data),
384dc64f30fSRichard Röjfors 	},
385dc64f30fSRichard Röjfors 	{
3868edbede9SRichard Röjfors 		.name = "timb-uart",
3878edbede9SRichard Röjfors 		.num_resources = ARRAY_SIZE(timberdale_uart_resources),
3888edbede9SRichard Röjfors 		.resources = timberdale_uart_resources,
3898edbede9SRichard Röjfors 	},
3908edbede9SRichard Röjfors 	{
391d84027bcSRichard Röjfors 		.name = "xiic-i2c",
392d84027bcSRichard Röjfors 		.num_resources = ARRAY_SIZE(timberdale_xiic_resources),
393d84027bcSRichard Röjfors 		.resources = timberdale_xiic_resources,
3943271d382SSamuel Ortiz 		.platform_data = &timberdale_xiic_platform_data,
3953271d382SSamuel Ortiz 		.pdata_size = sizeof(timberdale_xiic_platform_data),
396d84027bcSRichard Röjfors 	},
397d84027bcSRichard Röjfors 	{
3988edbede9SRichard Röjfors 		.name = "timb-gpio",
3998edbede9SRichard Röjfors 		.num_resources = ARRAY_SIZE(timberdale_gpio_resources),
4008edbede9SRichard Röjfors 		.resources = timberdale_gpio_resources,
4013271d382SSamuel Ortiz 		.platform_data = &timberdale_gpio_platform_data,
4023271d382SSamuel Ortiz 		.pdata_size = sizeof(timberdale_gpio_platform_data),
4038edbede9SRichard Röjfors 	},
4048edbede9SRichard Röjfors 	{
405c091575cSRichard Röjfors 		.name = "timb-video",
406c091575cSRichard Röjfors 		.num_resources = ARRAY_SIZE(timberdale_video_resources),
407c091575cSRichard Röjfors 		.resources = timberdale_video_resources,
4083271d382SSamuel Ortiz 		.platform_data = &timberdale_video_platform_data,
4093271d382SSamuel Ortiz 		.pdata_size = sizeof(timberdale_video_platform_data),
410c091575cSRichard Röjfors 	},
411c091575cSRichard Röjfors 	{
412071193ffSRichard Röjfors 		.name = "timb-radio",
413071193ffSRichard Röjfors 		.num_resources = ARRAY_SIZE(timberdale_radio_resources),
414071193ffSRichard Röjfors 		.resources = timberdale_radio_resources,
4153271d382SSamuel Ortiz 		.platform_data = &timberdale_radio_platform_data,
4163271d382SSamuel Ortiz 		.pdata_size = sizeof(timberdale_radio_platform_data),
417071193ffSRichard Röjfors 	},
418071193ffSRichard Röjfors 	{
4198edbede9SRichard Röjfors 		.name = "xilinx_spi",
4208edbede9SRichard Röjfors 		.num_resources = ARRAY_SIZE(timberdale_spi_resources),
4218edbede9SRichard Röjfors 		.resources = timberdale_spi_resources,
4223271d382SSamuel Ortiz 		.platform_data = &timberdale_xspi_platform_data,
4233271d382SSamuel Ortiz 		.pdata_size = sizeof(timberdale_xspi_platform_data),
4248edbede9SRichard Röjfors 	},
4258edbede9SRichard Röjfors 	{
4268edbede9SRichard Röjfors 		.name = "ks8842",
4278edbede9SRichard Röjfors 		.num_resources = ARRAY_SIZE(timberdale_eth_resources),
4288edbede9SRichard Röjfors 		.resources = timberdale_eth_resources,
4293271d382SSamuel Ortiz 		.platform_data = &timberdale_ks8842_platform_data,
4303271d382SSamuel Ortiz 		.pdata_size = sizeof(timberdale_ks8842_platform_data),
4318edbede9SRichard Röjfors 	},
432dc64f30fSRichard Röjfors };
433dc64f30fSRichard Röjfors 
4345ac98553SGeert Uytterhoeven static const struct mfd_cell timberdale_cells_bar0_cfg1[] = {
4358edbede9SRichard Röjfors 	{
4368edbede9SRichard Röjfors 		.name = "timb-dma",
4378edbede9SRichard Röjfors 		.num_resources = ARRAY_SIZE(timberdale_dma_resources),
4388edbede9SRichard Röjfors 		.resources = timberdale_dma_resources,
4393271d382SSamuel Ortiz 		.platform_data = &timb_dma_platform_data,
4403271d382SSamuel Ortiz 		.pdata_size = sizeof(timb_dma_platform_data),
4418edbede9SRichard Röjfors 	},
4428edbede9SRichard Röjfors 	{
4438edbede9SRichard Röjfors 		.name = "timb-uart",
4448edbede9SRichard Röjfors 		.num_resources = ARRAY_SIZE(timberdale_uart_resources),
4458edbede9SRichard Röjfors 		.resources = timberdale_uart_resources,
4468edbede9SRichard Röjfors 	},
4478edbede9SRichard Röjfors 	{
4488edbede9SRichard Röjfors 		.name = "uartlite",
4498edbede9SRichard Röjfors 		.num_resources = ARRAY_SIZE(timberdale_uartlite_resources),
4508edbede9SRichard Röjfors 		.resources = timberdale_uartlite_resources,
4518edbede9SRichard Röjfors 	},
4528edbede9SRichard Röjfors 	{
453d84027bcSRichard Röjfors 		.name = "xiic-i2c",
454d84027bcSRichard Röjfors 		.num_resources = ARRAY_SIZE(timberdale_xiic_resources),
455d84027bcSRichard Röjfors 		.resources = timberdale_xiic_resources,
4563271d382SSamuel Ortiz 		.platform_data = &timberdale_xiic_platform_data,
4573271d382SSamuel Ortiz 		.pdata_size = sizeof(timberdale_xiic_platform_data),
458d84027bcSRichard Röjfors 	},
459d84027bcSRichard Röjfors 	{
4608edbede9SRichard Röjfors 		.name = "timb-gpio",
4618edbede9SRichard Röjfors 		.num_resources = ARRAY_SIZE(timberdale_gpio_resources),
4628edbede9SRichard Röjfors 		.resources = timberdale_gpio_resources,
4633271d382SSamuel Ortiz 		.platform_data = &timberdale_gpio_platform_data,
4643271d382SSamuel Ortiz 		.pdata_size = sizeof(timberdale_gpio_platform_data),
4658edbede9SRichard Röjfors 	},
4668edbede9SRichard Röjfors 	{
4678edbede9SRichard Röjfors 		.name = "timb-mlogicore",
4688edbede9SRichard Röjfors 		.num_resources = ARRAY_SIZE(timberdale_mlogicore_resources),
4698edbede9SRichard Röjfors 		.resources = timberdale_mlogicore_resources,
4708edbede9SRichard Röjfors 	},
4718edbede9SRichard Röjfors 	{
472c091575cSRichard Röjfors 		.name = "timb-video",
473c091575cSRichard Röjfors 		.num_resources = ARRAY_SIZE(timberdale_video_resources),
474c091575cSRichard Röjfors 		.resources = timberdale_video_resources,
4753271d382SSamuel Ortiz 		.platform_data = &timberdale_video_platform_data,
4763271d382SSamuel Ortiz 		.pdata_size = sizeof(timberdale_video_platform_data),
477c091575cSRichard Röjfors 	},
478c091575cSRichard Röjfors 	{
479071193ffSRichard Röjfors 		.name = "timb-radio",
480071193ffSRichard Röjfors 		.num_resources = ARRAY_SIZE(timberdale_radio_resources),
481071193ffSRichard Röjfors 		.resources = timberdale_radio_resources,
4823271d382SSamuel Ortiz 		.platform_data = &timberdale_radio_platform_data,
4833271d382SSamuel Ortiz 		.pdata_size = sizeof(timberdale_radio_platform_data),
484071193ffSRichard Röjfors 	},
485071193ffSRichard Röjfors 	{
4868edbede9SRichard Röjfors 		.name = "xilinx_spi",
4878edbede9SRichard Röjfors 		.num_resources = ARRAY_SIZE(timberdale_spi_resources),
4888edbede9SRichard Röjfors 		.resources = timberdale_spi_resources,
4893271d382SSamuel Ortiz 		.platform_data = &timberdale_xspi_platform_data,
4903271d382SSamuel Ortiz 		.pdata_size = sizeof(timberdale_xspi_platform_data),
4918edbede9SRichard Röjfors 	},
4928edbede9SRichard Röjfors 	{
4938edbede9SRichard Röjfors 		.name = "ks8842",
4948edbede9SRichard Röjfors 		.num_resources = ARRAY_SIZE(timberdale_eth_resources),
4958edbede9SRichard Röjfors 		.resources = timberdale_eth_resources,
4963271d382SSamuel Ortiz 		.platform_data = &timberdale_ks8842_platform_data,
4973271d382SSamuel Ortiz 		.pdata_size = sizeof(timberdale_ks8842_platform_data),
4988edbede9SRichard Röjfors 	},
499dc64f30fSRichard Röjfors };
500dc64f30fSRichard Röjfors 
5015ac98553SGeert Uytterhoeven static const struct mfd_cell timberdale_cells_bar0_cfg2[] = {
5028edbede9SRichard Röjfors 	{
5038edbede9SRichard Röjfors 		.name = "timb-dma",
5048edbede9SRichard Röjfors 		.num_resources = ARRAY_SIZE(timberdale_dma_resources),
5058edbede9SRichard Röjfors 		.resources = timberdale_dma_resources,
5063271d382SSamuel Ortiz 		.platform_data = &timb_dma_platform_data,
5073271d382SSamuel Ortiz 		.pdata_size = sizeof(timb_dma_platform_data),
5088edbede9SRichard Röjfors 	},
5098edbede9SRichard Röjfors 	{
5108edbede9SRichard Röjfors 		.name = "timb-uart",
5118edbede9SRichard Röjfors 		.num_resources = ARRAY_SIZE(timberdale_uart_resources),
5128edbede9SRichard Röjfors 		.resources = timberdale_uart_resources,
5138edbede9SRichard Röjfors 	},
5148edbede9SRichard Röjfors 	{
515d84027bcSRichard Röjfors 		.name = "xiic-i2c",
516d84027bcSRichard Röjfors 		.num_resources = ARRAY_SIZE(timberdale_xiic_resources),
517d84027bcSRichard Röjfors 		.resources = timberdale_xiic_resources,
5183271d382SSamuel Ortiz 		.platform_data = &timberdale_xiic_platform_data,
5193271d382SSamuel Ortiz 		.pdata_size = sizeof(timberdale_xiic_platform_data),
520d84027bcSRichard Röjfors 	},
521d84027bcSRichard Röjfors 	{
5228edbede9SRichard Röjfors 		.name = "timb-gpio",
5238edbede9SRichard Röjfors 		.num_resources = ARRAY_SIZE(timberdale_gpio_resources),
5248edbede9SRichard Röjfors 		.resources = timberdale_gpio_resources,
5253271d382SSamuel Ortiz 		.platform_data = &timberdale_gpio_platform_data,
5263271d382SSamuel Ortiz 		.pdata_size = sizeof(timberdale_gpio_platform_data),
5278edbede9SRichard Röjfors 	},
5288edbede9SRichard Röjfors 	{
529c091575cSRichard Röjfors 		.name = "timb-video",
530c091575cSRichard Röjfors 		.num_resources = ARRAY_SIZE(timberdale_video_resources),
531c091575cSRichard Röjfors 		.resources = timberdale_video_resources,
5323271d382SSamuel Ortiz 		.platform_data = &timberdale_video_platform_data,
5333271d382SSamuel Ortiz 		.pdata_size = sizeof(timberdale_video_platform_data),
534c091575cSRichard Röjfors 	},
535c091575cSRichard Röjfors 	{
536071193ffSRichard Röjfors 		.name = "timb-radio",
537071193ffSRichard Röjfors 		.num_resources = ARRAY_SIZE(timberdale_radio_resources),
538071193ffSRichard Röjfors 		.resources = timberdale_radio_resources,
5393271d382SSamuel Ortiz 		.platform_data = &timberdale_radio_platform_data,
5403271d382SSamuel Ortiz 		.pdata_size = sizeof(timberdale_radio_platform_data),
541071193ffSRichard Röjfors 	},
542071193ffSRichard Röjfors 	{
5438edbede9SRichard Röjfors 		.name = "xilinx_spi",
5448edbede9SRichard Röjfors 		.num_resources = ARRAY_SIZE(timberdale_spi_resources),
5458edbede9SRichard Röjfors 		.resources = timberdale_spi_resources,
5463271d382SSamuel Ortiz 		.platform_data = &timberdale_xspi_platform_data,
5473271d382SSamuel Ortiz 		.pdata_size = sizeof(timberdale_xspi_platform_data),
5488edbede9SRichard Röjfors 	},
549dc64f30fSRichard Röjfors };
550dc64f30fSRichard Röjfors 
5515ac98553SGeert Uytterhoeven static const struct mfd_cell timberdale_cells_bar0_cfg3[] = {
5528edbede9SRichard Röjfors 	{
5538edbede9SRichard Röjfors 		.name = "timb-dma",
5548edbede9SRichard Röjfors 		.num_resources = ARRAY_SIZE(timberdale_dma_resources),
5558edbede9SRichard Röjfors 		.resources = timberdale_dma_resources,
5563271d382SSamuel Ortiz 		.platform_data = &timb_dma_platform_data,
5573271d382SSamuel Ortiz 		.pdata_size = sizeof(timb_dma_platform_data),
5588edbede9SRichard Röjfors 	},
5598edbede9SRichard Röjfors 	{
5608edbede9SRichard Röjfors 		.name = "timb-uart",
5618edbede9SRichard Röjfors 		.num_resources = ARRAY_SIZE(timberdale_uart_resources),
5628edbede9SRichard Röjfors 		.resources = timberdale_uart_resources,
5638edbede9SRichard Röjfors 	},
5648edbede9SRichard Röjfors 	{
5658edbede9SRichard Röjfors 		.name = "ocores-i2c",
5668edbede9SRichard Röjfors 		.num_resources = ARRAY_SIZE(timberdale_ocores_resources),
5678edbede9SRichard Röjfors 		.resources = timberdale_ocores_resources,
5683271d382SSamuel Ortiz 		.platform_data = &timberdale_ocores_platform_data,
5693271d382SSamuel Ortiz 		.pdata_size = sizeof(timberdale_ocores_platform_data),
5708edbede9SRichard Röjfors 	},
5718edbede9SRichard Röjfors 	{
5728edbede9SRichard Röjfors 		.name = "timb-gpio",
5738edbede9SRichard Röjfors 		.num_resources = ARRAY_SIZE(timberdale_gpio_resources),
5748edbede9SRichard Röjfors 		.resources = timberdale_gpio_resources,
5753271d382SSamuel Ortiz 		.platform_data = &timberdale_gpio_platform_data,
5763271d382SSamuel Ortiz 		.pdata_size = sizeof(timberdale_gpio_platform_data),
5778edbede9SRichard Röjfors 	},
5788edbede9SRichard Röjfors 	{
579c091575cSRichard Röjfors 		.name = "timb-video",
580c091575cSRichard Röjfors 		.num_resources = ARRAY_SIZE(timberdale_video_resources),
581c091575cSRichard Röjfors 		.resources = timberdale_video_resources,
5823271d382SSamuel Ortiz 		.platform_data = &timberdale_video_platform_data,
5833271d382SSamuel Ortiz 		.pdata_size = sizeof(timberdale_video_platform_data),
584c091575cSRichard Röjfors 	},
585c091575cSRichard Röjfors 	{
586071193ffSRichard Röjfors 		.name = "timb-radio",
587071193ffSRichard Röjfors 		.num_resources = ARRAY_SIZE(timberdale_radio_resources),
588071193ffSRichard Röjfors 		.resources = timberdale_radio_resources,
5893271d382SSamuel Ortiz 		.platform_data = &timberdale_radio_platform_data,
5903271d382SSamuel Ortiz 		.pdata_size = sizeof(timberdale_radio_platform_data),
591071193ffSRichard Röjfors 	},
592071193ffSRichard Röjfors 	{
5938edbede9SRichard Röjfors 		.name = "xilinx_spi",
5948edbede9SRichard Röjfors 		.num_resources = ARRAY_SIZE(timberdale_spi_resources),
5958edbede9SRichard Röjfors 		.resources = timberdale_spi_resources,
5963271d382SSamuel Ortiz 		.platform_data = &timberdale_xspi_platform_data,
5973271d382SSamuel Ortiz 		.pdata_size = sizeof(timberdale_xspi_platform_data),
5988edbede9SRichard Röjfors 	},
5998edbede9SRichard Röjfors 	{
6008edbede9SRichard Röjfors 		.name = "ks8842",
6018edbede9SRichard Röjfors 		.num_resources = ARRAY_SIZE(timberdale_eth_resources),
6028edbede9SRichard Röjfors 		.resources = timberdale_eth_resources,
6033271d382SSamuel Ortiz 		.platform_data = &timberdale_ks8842_platform_data,
6043271d382SSamuel Ortiz 		.pdata_size = sizeof(timberdale_ks8842_platform_data),
6058edbede9SRichard Röjfors 	},
6068edbede9SRichard Röjfors };
6078edbede9SRichard Röjfors 
608a73e5df1SBill Pemberton static const struct resource timberdale_sdhc_resources[] = {
6098edbede9SRichard Röjfors 	/* located in bar 1 and bar 2 */
6108edbede9SRichard Röjfors 	{
6118edbede9SRichard Röjfors 		.start	= SDHC0OFFSET,
6128edbede9SRichard Röjfors 		.end	= SDHC0END,
6138edbede9SRichard Röjfors 		.flags	= IORESOURCE_MEM,
6148edbede9SRichard Röjfors 	},
6158edbede9SRichard Röjfors 	{
6168edbede9SRichard Röjfors 		.start	= IRQ_TIMBERDALE_SDHC,
6178edbede9SRichard Röjfors 		.end	= IRQ_TIMBERDALE_SDHC,
6188edbede9SRichard Röjfors 		.flags	= IORESOURCE_IRQ,
6198edbede9SRichard Röjfors 	},
6208edbede9SRichard Röjfors };
6218edbede9SRichard Röjfors 
6225ac98553SGeert Uytterhoeven static const struct mfd_cell timberdale_cells_bar1[] = {
6238edbede9SRichard Röjfors 	{
6248edbede9SRichard Röjfors 		.name = "sdhci",
6258edbede9SRichard Röjfors 		.num_resources = ARRAY_SIZE(timberdale_sdhc_resources),
6268edbede9SRichard Röjfors 		.resources = timberdale_sdhc_resources,
6278edbede9SRichard Röjfors 	},
6288edbede9SRichard Röjfors };
6298edbede9SRichard Röjfors 
6305ac98553SGeert Uytterhoeven static const struct mfd_cell timberdale_cells_bar2[] = {
6318edbede9SRichard Röjfors 	{
6328edbede9SRichard Röjfors 		.name = "sdhci",
6338edbede9SRichard Röjfors 		.num_resources = ARRAY_SIZE(timberdale_sdhc_resources),
6348edbede9SRichard Röjfors 		.resources = timberdale_sdhc_resources,
6358edbede9SRichard Röjfors 	},
6368edbede9SRichard Röjfors };
6378edbede9SRichard Röjfors 
6388edbede9SRichard Röjfors static ssize_t show_fw_ver(struct device *dev, struct device_attribute *attr,
6398edbede9SRichard Röjfors 	char *buf)
6408edbede9SRichard Röjfors {
6418edbede9SRichard Röjfors 	struct pci_dev *pdev = to_pci_dev(dev);
6428edbede9SRichard Röjfors 	struct timberdale_device *priv = pci_get_drvdata(pdev);
6438edbede9SRichard Röjfors 
6448edbede9SRichard Röjfors 	return sprintf(buf, "%d.%d.%d\n", priv->fw.major, priv->fw.minor,
6458edbede9SRichard Röjfors 		priv->fw.config);
6468edbede9SRichard Röjfors }
6478edbede9SRichard Röjfors 
6488edbede9SRichard Röjfors static DEVICE_ATTR(fw_ver, S_IRUGO, show_fw_ver, NULL);
6498edbede9SRichard Röjfors 
6508edbede9SRichard Röjfors /*--------------------------------------------------------------------------*/
6518edbede9SRichard Röjfors 
652f791be49SBill Pemberton static int timb_probe(struct pci_dev *dev,
6538edbede9SRichard Röjfors 	const struct pci_device_id *id)
6548edbede9SRichard Röjfors {
6558edbede9SRichard Röjfors 	struct timberdale_device *priv;
6568edbede9SRichard Röjfors 	int err, i;
6578edbede9SRichard Röjfors 	resource_size_t mapbase;
6588edbede9SRichard Röjfors 	struct msix_entry *msix_entries = NULL;
6598edbede9SRichard Röjfors 	u8 ip_setup;
6608edbede9SRichard Röjfors 
6618edbede9SRichard Röjfors 	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
6628edbede9SRichard Röjfors 	if (!priv)
6638edbede9SRichard Röjfors 		return -ENOMEM;
6648edbede9SRichard Röjfors 
6658edbede9SRichard Röjfors 	pci_set_drvdata(dev, priv);
6668edbede9SRichard Röjfors 
6678edbede9SRichard Röjfors 	err = pci_enable_device(dev);
6688edbede9SRichard Röjfors 	if (err)
6698edbede9SRichard Röjfors 		goto err_enable;
6708edbede9SRichard Röjfors 
6718edbede9SRichard Röjfors 	mapbase = pci_resource_start(dev, 0);
6728edbede9SRichard Röjfors 	if (!mapbase) {
6738edbede9SRichard Röjfors 		dev_err(&dev->dev, "No resource\n");
6748edbede9SRichard Röjfors 		goto err_start;
6758edbede9SRichard Röjfors 	}
6768edbede9SRichard Röjfors 
6778edbede9SRichard Röjfors 	/* create a resource for the PCI master register */
6788edbede9SRichard Röjfors 	priv->ctl_mapbase = mapbase + CHIPCTLOFFSET;
6798edbede9SRichard Röjfors 	if (!request_mem_region(priv->ctl_mapbase, CHIPCTLSIZE, "timb-ctl")) {
6808edbede9SRichard Röjfors 		dev_err(&dev->dev, "Failed to request ctl mem\n");
6817902fe8cSJingoo Han 		goto err_start;
6828edbede9SRichard Röjfors 	}
6838edbede9SRichard Röjfors 
6848edbede9SRichard Röjfors 	priv->ctl_membase = ioremap(priv->ctl_mapbase, CHIPCTLSIZE);
6858edbede9SRichard Röjfors 	if (!priv->ctl_membase) {
6868edbede9SRichard Röjfors 		dev_err(&dev->dev, "ioremap failed for ctl mem\n");
6878edbede9SRichard Röjfors 		goto err_ioremap;
6888edbede9SRichard Röjfors 	}
6898edbede9SRichard Röjfors 
6908edbede9SRichard Röjfors 	/* read the HW config */
6918edbede9SRichard Röjfors 	priv->fw.major = ioread32(priv->ctl_membase + TIMB_REV_MAJOR);
6928edbede9SRichard Röjfors 	priv->fw.minor = ioread32(priv->ctl_membase + TIMB_REV_MINOR);
6938edbede9SRichard Röjfors 	priv->fw.config = ioread32(priv->ctl_membase + TIMB_HW_CONFIG);
6948edbede9SRichard Röjfors 
6958edbede9SRichard Röjfors 	if (priv->fw.major > TIMB_SUPPORTED_MAJOR) {
6968edbede9SRichard Röjfors 		dev_err(&dev->dev, "The driver supports an older "
6978edbede9SRichard Röjfors 			"version of the FPGA, please update the driver to "
6988edbede9SRichard Röjfors 			"support %d.%d\n", priv->fw.major, priv->fw.minor);
699981c65a9SJulia Lawall 		goto err_config;
7008edbede9SRichard Röjfors 	}
7018edbede9SRichard Röjfors 	if (priv->fw.major < TIMB_SUPPORTED_MAJOR ||
7028edbede9SRichard Röjfors 		priv->fw.minor < TIMB_REQUIRED_MINOR) {
7038edbede9SRichard Röjfors 		dev_err(&dev->dev, "The FPGA image is too old (%d.%d), "
7048edbede9SRichard Röjfors 			"please upgrade the FPGA to at least: %d.%d\n",
7058edbede9SRichard Röjfors 			priv->fw.major, priv->fw.minor,
7068edbede9SRichard Röjfors 			TIMB_SUPPORTED_MAJOR, TIMB_REQUIRED_MINOR);
707981c65a9SJulia Lawall 		goto err_config;
7088edbede9SRichard Röjfors 	}
7098edbede9SRichard Röjfors 
7108edbede9SRichard Röjfors 	msix_entries = kzalloc(TIMBERDALE_NR_IRQS * sizeof(*msix_entries),
7118edbede9SRichard Röjfors 		GFP_KERNEL);
7128edbede9SRichard Röjfors 	if (!msix_entries)
713981c65a9SJulia Lawall 		goto err_config;
7148edbede9SRichard Röjfors 
7158edbede9SRichard Röjfors 	for (i = 0; i < TIMBERDALE_NR_IRQS; i++)
7168edbede9SRichard Röjfors 		msix_entries[i].entry = i;
7178edbede9SRichard Röjfors 
718471212d9SAlexander Gordeev 	err = pci_enable_msix_exact(dev, msix_entries, TIMBERDALE_NR_IRQS);
7198edbede9SRichard Röjfors 	if (err) {
7208edbede9SRichard Röjfors 		dev_err(&dev->dev,
7218edbede9SRichard Röjfors 			"MSI-X init failed: %d, expected entries: %d\n",
7228edbede9SRichard Röjfors 			err, TIMBERDALE_NR_IRQS);
7238edbede9SRichard Röjfors 		goto err_msix;
7248edbede9SRichard Röjfors 	}
7258edbede9SRichard Röjfors 
7268edbede9SRichard Röjfors 	err = device_create_file(&dev->dev, &dev_attr_fw_ver);
7278edbede9SRichard Röjfors 	if (err)
7288edbede9SRichard Röjfors 		goto err_create_file;
7298edbede9SRichard Röjfors 
7308edbede9SRichard Röjfors 	/* Reset all FPGA PLB peripherals */
7318edbede9SRichard Röjfors 	iowrite32(0x1, priv->ctl_membase + TIMB_SW_RST);
7328edbede9SRichard Röjfors 
7338edbede9SRichard Röjfors 	/* update IRQ offsets in I2C board info */
7348edbede9SRichard Röjfors 	for (i = 0; i < ARRAY_SIZE(timberdale_i2c_board_info); i++)
7358edbede9SRichard Röjfors 		timberdale_i2c_board_info[i].irq =
7368edbede9SRichard Röjfors 			msix_entries[timberdale_i2c_board_info[i].irq].vector;
7378edbede9SRichard Röjfors 
7388edbede9SRichard Röjfors 	/* Update the SPI configuration depending on the HW (8 or 16 bit) */
7398edbede9SRichard Röjfors 	if (priv->fw.config & TIMB_HW_CONFIG_SPI_8BIT) {
7408edbede9SRichard Röjfors 		timberdale_xspi_platform_data.bits_per_word = 8;
7418edbede9SRichard Röjfors 		timberdale_xspi_platform_data.devices =
7428edbede9SRichard Röjfors 			timberdale_spi_8bit_board_info;
7438edbede9SRichard Röjfors 		timberdale_xspi_platform_data.num_devices =
7448edbede9SRichard Röjfors 			ARRAY_SIZE(timberdale_spi_8bit_board_info);
7458edbede9SRichard Röjfors 	} else {
7468edbede9SRichard Röjfors 		timberdale_xspi_platform_data.bits_per_word = 16;
7478edbede9SRichard Röjfors 		timberdale_xspi_platform_data.devices =
7488edbede9SRichard Röjfors 			timberdale_spi_16bit_board_info;
7498edbede9SRichard Röjfors 		timberdale_xspi_platform_data.num_devices =
7508edbede9SRichard Röjfors 			ARRAY_SIZE(timberdale_spi_16bit_board_info);
7518edbede9SRichard Röjfors 	}
7528edbede9SRichard Röjfors 
7538edbede9SRichard Röjfors 	ip_setup = priv->fw.config & TIMB_HW_VER_MASK;
7548edbede9SRichard Röjfors 	switch (ip_setup) {
7558edbede9SRichard Röjfors 	case TIMB_HW_VER0:
7568edbede9SRichard Röjfors 		err = mfd_add_devices(&dev->dev, -1,
7578edbede9SRichard Röjfors 			timberdale_cells_bar0_cfg0,
7588edbede9SRichard Röjfors 			ARRAY_SIZE(timberdale_cells_bar0_cfg0),
7590848c94fSMark Brown 			&dev->resource[0], msix_entries[0].vector, NULL);
7608edbede9SRichard Röjfors 		break;
7618edbede9SRichard Röjfors 	case TIMB_HW_VER1:
7628edbede9SRichard Röjfors 		err = mfd_add_devices(&dev->dev, -1,
7638edbede9SRichard Röjfors 			timberdale_cells_bar0_cfg1,
7648edbede9SRichard Röjfors 			ARRAY_SIZE(timberdale_cells_bar0_cfg1),
7650848c94fSMark Brown 			&dev->resource[0], msix_entries[0].vector, NULL);
7668edbede9SRichard Röjfors 		break;
7678edbede9SRichard Röjfors 	case TIMB_HW_VER2:
7688edbede9SRichard Röjfors 		err = mfd_add_devices(&dev->dev, -1,
7698edbede9SRichard Röjfors 			timberdale_cells_bar0_cfg2,
7708edbede9SRichard Röjfors 			ARRAY_SIZE(timberdale_cells_bar0_cfg2),
7710848c94fSMark Brown 			&dev->resource[0], msix_entries[0].vector, NULL);
7728edbede9SRichard Röjfors 		break;
7738edbede9SRichard Röjfors 	case TIMB_HW_VER3:
7748edbede9SRichard Röjfors 		err = mfd_add_devices(&dev->dev, -1,
7758edbede9SRichard Röjfors 			timberdale_cells_bar0_cfg3,
7768edbede9SRichard Röjfors 			ARRAY_SIZE(timberdale_cells_bar0_cfg3),
7770848c94fSMark Brown 			&dev->resource[0], msix_entries[0].vector, NULL);
7788edbede9SRichard Röjfors 		break;
7798edbede9SRichard Röjfors 	default:
7805588bd59SColin Ian King 		dev_err(&dev->dev, "Unknown IP setup: %d.%d.%d\n",
7818edbede9SRichard Röjfors 			priv->fw.major, priv->fw.minor, ip_setup);
7828edbede9SRichard Röjfors 		err = -ENODEV;
7838edbede9SRichard Röjfors 		goto err_mfd;
7848edbede9SRichard Röjfors 	}
7858edbede9SRichard Röjfors 
7868edbede9SRichard Röjfors 	if (err) {
7878edbede9SRichard Röjfors 		dev_err(&dev->dev, "mfd_add_devices failed: %d\n", err);
7888edbede9SRichard Röjfors 		goto err_mfd;
7898edbede9SRichard Röjfors 	}
7908edbede9SRichard Röjfors 
7918edbede9SRichard Röjfors 	err = mfd_add_devices(&dev->dev, 0,
7928edbede9SRichard Röjfors 		timberdale_cells_bar1, ARRAY_SIZE(timberdale_cells_bar1),
7930848c94fSMark Brown 		&dev->resource[1], msix_entries[0].vector, NULL);
7948edbede9SRichard Röjfors 	if (err) {
7958edbede9SRichard Röjfors 		dev_err(&dev->dev, "mfd_add_devices failed: %d\n", err);
7968edbede9SRichard Röjfors 		goto err_mfd2;
7978edbede9SRichard Röjfors 	}
7988edbede9SRichard Röjfors 
7998edbede9SRichard Röjfors 	/* only version 0 and 3 have the iNand routed to SDHCI */
8008edbede9SRichard Röjfors 	if (((priv->fw.config & TIMB_HW_VER_MASK) == TIMB_HW_VER0) ||
8018edbede9SRichard Röjfors 		((priv->fw.config & TIMB_HW_VER_MASK) == TIMB_HW_VER3)) {
8028edbede9SRichard Röjfors 		err = mfd_add_devices(&dev->dev, 1, timberdale_cells_bar2,
8038edbede9SRichard Röjfors 			ARRAY_SIZE(timberdale_cells_bar2),
8040848c94fSMark Brown 			&dev->resource[2], msix_entries[0].vector, NULL);
8058edbede9SRichard Röjfors 		if (err) {
8068edbede9SRichard Röjfors 			dev_err(&dev->dev, "mfd_add_devices failed: %d\n", err);
8078edbede9SRichard Röjfors 			goto err_mfd2;
8088edbede9SRichard Röjfors 		}
8098edbede9SRichard Röjfors 	}
8108edbede9SRichard Röjfors 
8118edbede9SRichard Röjfors 	kfree(msix_entries);
8128edbede9SRichard Röjfors 
8138edbede9SRichard Röjfors 	dev_info(&dev->dev,
8148edbede9SRichard Röjfors 		"Found Timberdale Card. Rev: %d.%d, HW config: 0x%02x\n",
8158edbede9SRichard Röjfors 		priv->fw.major, priv->fw.minor, priv->fw.config);
8168edbede9SRichard Röjfors 
8178edbede9SRichard Röjfors 	return 0;
8188edbede9SRichard Röjfors 
8198edbede9SRichard Röjfors err_mfd2:
8208edbede9SRichard Röjfors 	mfd_remove_devices(&dev->dev);
8218edbede9SRichard Röjfors err_mfd:
8228edbede9SRichard Röjfors 	device_remove_file(&dev->dev, &dev_attr_fw_ver);
8238edbede9SRichard Röjfors err_create_file:
8248edbede9SRichard Röjfors 	pci_disable_msix(dev);
8258edbede9SRichard Röjfors err_msix:
826981c65a9SJulia Lawall 	kfree(msix_entries);
827981c65a9SJulia Lawall err_config:
8288edbede9SRichard Röjfors 	iounmap(priv->ctl_membase);
8298edbede9SRichard Röjfors err_ioremap:
8308edbede9SRichard Röjfors 	release_mem_region(priv->ctl_mapbase, CHIPCTLSIZE);
8318edbede9SRichard Röjfors err_start:
8328edbede9SRichard Röjfors 	pci_disable_device(dev);
8338edbede9SRichard Röjfors err_enable:
8348edbede9SRichard Röjfors 	kfree(priv);
8358edbede9SRichard Röjfors 	return -ENODEV;
8368edbede9SRichard Röjfors }
8378edbede9SRichard Röjfors 
8384740f73fSBill Pemberton static void timb_remove(struct pci_dev *dev)
8398edbede9SRichard Röjfors {
8408edbede9SRichard Röjfors 	struct timberdale_device *priv = pci_get_drvdata(dev);
8418edbede9SRichard Röjfors 
8428edbede9SRichard Röjfors 	mfd_remove_devices(&dev->dev);
8438edbede9SRichard Röjfors 
8448edbede9SRichard Röjfors 	device_remove_file(&dev->dev, &dev_attr_fw_ver);
8458edbede9SRichard Röjfors 
8468edbede9SRichard Röjfors 	iounmap(priv->ctl_membase);
8478edbede9SRichard Röjfors 	release_mem_region(priv->ctl_mapbase, CHIPCTLSIZE);
8488edbede9SRichard Röjfors 
8498edbede9SRichard Röjfors 	pci_disable_msix(dev);
8508edbede9SRichard Röjfors 	pci_disable_device(dev);
8518edbede9SRichard Röjfors 	kfree(priv);
8528edbede9SRichard Röjfors }
8538edbede9SRichard Röjfors 
85436fcd06cSJingoo Han static const struct pci_device_id timberdale_pci_tbl[] = {
8558edbede9SRichard Röjfors 	{ PCI_DEVICE(PCI_VENDOR_ID_TIMB, PCI_DEVICE_ID_TIMB) },
8568edbede9SRichard Röjfors 	{ 0 }
8578edbede9SRichard Röjfors };
8588edbede9SRichard Röjfors MODULE_DEVICE_TABLE(pci, timberdale_pci_tbl);
8598edbede9SRichard Röjfors 
8608edbede9SRichard Röjfors static struct pci_driver timberdale_pci_driver = {
8618edbede9SRichard Röjfors 	.name = DRIVER_NAME,
8628edbede9SRichard Röjfors 	.id_table = timberdale_pci_tbl,
8638edbede9SRichard Röjfors 	.probe = timb_probe,
86484449216SBill Pemberton 	.remove = timb_remove,
8658edbede9SRichard Röjfors };
8668edbede9SRichard Röjfors 
8670afb00e3SSachin Kamat module_pci_driver(timberdale_pci_driver);
8688edbede9SRichard Röjfors 
8698edbede9SRichard Röjfors MODULE_AUTHOR("Mocean Laboratories <info@mocean-labs.com>");
8708edbede9SRichard Röjfors MODULE_VERSION(DRV_VERSION);
8718edbede9SRichard Röjfors MODULE_LICENSE("GPL v2");
872