All of lore.kernel.org
 help / color / mirror / Atom feed
From: Samuel Ortiz <sameo@linux.intel.com>
To: "Richard Röjfors" <richard.rojfors.ext@mocean-labs.com>,
	"Andrew Morton" <akpm@linux-foundation.org>
Cc: linux-kernel@vger.kernel.org
Subject: Re: [PATCH 7/9] MFD: Added Timberdale driver
Date: Mon, 15 Jun 2009 12:11:19 +0200	[thread overview]
Message-ID: <20090615101116.GB4094@sortiz.org> (raw)
In-Reply-To: <4A292099.2020306@mocean-labs.com>

Hi Richard,

On Fri, Jun 05, 2009 at 03:41:45PM +0200, Richard Röjfors wrote:
> MFD driver for the Timberdale FPGA The FPGA can be found on the
> Intel Atom development board, Russellville for in-vechicle infotainment
> 
> The FPGA is connected via PCIe
> 
> The driver basically exposes a lot of platform devices for the
> different IPs within the FPGA, and doing IRQ multiplexing
> 
> Signed-off-by: Richard Röjfors <richard.rojfors.ext@mocean-labs.com>
patch #4 of this serie is an mfd driver too, so I guess I should have been
cc'ed on it too.
So, if I understand this thread correctly, we should proceed like that:

1) Richard comes up with an updated xilinx patch (patch #2).
2) Andrew sends all patches but patch 7 to the relevant maintainers.
3) When all patches but 7 are in Linus tree, I take patch 7 and include it in
my pull request to Linus.

Andrew, does that make sense to you? Do you want me to take patch #4 as well?

Cheers,
Samuel.


> ---
> Index: linux-2.6.30-rc7/drivers/mfd/Kconfig
> ===================================================================
> --- linux-2.6.30-rc7/drivers/mfd/Kconfig	(revision 861)
> +++ linux-2.6.30-rc7/drivers/mfd/Kconfig	(working copy)
> @@ -241,6 +241,16 @@
>  	 Say yes here if you want to include support GPIO for pins on
>  	 the PCF50633 chip.
> 
> +config MFD_TIMBERDALE
> +	bool "Support for the Timberdale FPGA"
> +	select MFD_CORE
> +	---help---
> +	This is the core driver for the timberdale FPGA. This device is a
> +	multifunctioanl device which may provide numerous interfaces.
> +
> +	The timberdale FPGA can be found on the Intel Atom development board
> +	for automotive in-vehicle infontainment board called Russellville.
> +
>  config MFD_TIMBERDALE_DMA
>  	tristate "Support for timberdale DMA"
>  	depends on MFD_TIMBERDALE
> Index: linux-2.6.30-rc7/drivers/mfd/timberdale.c
> ===================================================================
> --- linux-2.6.30-rc7/drivers/mfd/timberdale.c	(revision 0)
> +++ linux-2.6.30-rc7/drivers/mfd/timberdale.c	(revision 888)
> @@ -0,0 +1,686 @@
> +/*
> + * timberdale.c timberdale FPGA mfd shim driver
> + * Copyright (c) 2009 Intel Corporation
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
> + */
> +
> +/* Supports:
> + * Timberdale FPGA
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/pci.h>
> +#include <linux/msi.h>
> +#include <linux/init.h>
> +#include <linux/interrupt.h>
> +#include <linux/platform_device.h>
> +#include <linux/mfd/core.h>
> +#include <linux/irq.h>
> +
> +#include <linux/i2c.h>
> +#include <linux/i2c-ocores.h>
> +#include <linux/i2c/tsc2007.h>
> +
> +#include <linux/spi/spi.h>
> +#include <linux/spi/xilinx_spi.h>
> +#include <linux/spi/max7301.h>
> +#include <linux/spi/mc33880.h>
> +
> +#include <media/timb_video.h>
> +
> +#include "timberdale.h"
> +
> +struct timberdale_device {
> +	resource_size_t		intc_mapbase;
> +	resource_size_t		ctl_mapbase;
> +	unsigned char __iomem   *intc_membase;
> +	unsigned char __iomem   *ctl_membase;
> +	int			irq_base;
> +	u32			irq_ack_mask;
> +	/* locking from interrupts while modifiying registers */
> +	spinlock_t		lock;
> +};
> +
> +/*--------------------------------------------------------------------------*/
> +
> +struct tsc2007_platform_data timberdale_tsc2007_platform_data = {
> +	.model = 2003,
> +	.x_plate_ohms = 100
> +};
> +
> +struct i2c_board_info timberdale_i2c_board_info[] = {
> +	{
> +		I2C_BOARD_INFO("tsc2003", 0x48),
> +		.platform_data = &timberdale_tsc2007_platform_data,
> +		.irq = IRQ_TIMBERDALE_TSC_INT
> +	},
> +	{
> +		/* Requires jumper JP9 to be off */
> +		I2C_BOARD_INFO("adv7180", 0x42 >> 1),
> +		.irq = IRQ_TIMBERDALE_ADV7180
> +	}
> +};
> +
> +static __devinitdata struct ocores_i2c_platform_data
> +timberdale_i2c_platform_data = {
> +	.regstep = 4,
> +	.clock_khz = 62500,
> +	.devices = timberdale_i2c_board_info,
> +	.num_devices = ARRAY_SIZE(timberdale_i2c_board_info)
> +};
> +
> +const static __devinitconst struct resource timberdale_i2c_resources[] = {
> +	{
> +		.start	= I2COFFSET,
> +		.end	= I2CEND,
> +		.flags	= IORESOURCE_MEM,
> +	},
> +	{
> +		.start 	= IRQ_TIMBERDALE_I2C,
> +		.end	= IRQ_TIMBERDALE_I2C,
> +		.flags	= IORESOURCE_IRQ,
> +	},
> +};
> +
> +const struct max7301_platform_data timberdale_max7301_platform_data = {
> +	.base = -1
> +};
> +
> +const struct mc33880_platform_data timberdale_mc33880_platform_data = {
> +	.base = -1
> +};
> +
> +struct spi_board_info timberdale_spi_16bit_board_info[] = {
> +	{
> +		.modalias = "max7301",
> +		.max_speed_hz = 26000,
> +		.chip_select = 2,
> +		.mode = SPI_MODE_0,
> +		.platform_data = &timberdale_max7301_platform_data
> +	},
> +};
> +
> +struct spi_board_info timberdale_spi_8bit_board_info[] = {
> +	{
> +		.modalias = "mc33880",
> +		.max_speed_hz = 4000,
> +		.chip_select = 1,
> +		.mode = SPI_MODE_1,
> +		.platform_data = &timberdale_mc33880_platform_data
> +	},
> +};
> +
> +static __devinitdata struct xspi_platform_data timberdale_xspi_platform_data = {
> +	.bus_num = -1,
> +	/* Current(2009-03-06) revision of
> +	 * Timberdale we can handle 3 chip selects
> +	 */
> +	.num_chipselect = 3,
> +	.model = XILINX_SPI_MODEL_DS570,
> +	/* bits per word and devices will be filled in runtime depending
> +	 * on the HW config
> +	 */
> +};
> +
> +const static __devinitconst struct resource timberdale_spi_resources[] = {
> +	{
> +		.start 	= SPIOFFSET,
> +		.end	= SPIEND,
> +		.flags	= IORESOURCE_MEM,
> +	},
> +	{
> +		.start	= IRQ_TIMBERDALE_SPI,
> +		.end	= IRQ_TIMBERDALE_SPI,
> +		.flags	= IORESOURCE_IRQ,
> +	},
> +};
> +
> +const static __devinitconst struct resource timberdale_eth_resources[] = {
> +	{
> +		.start	= ETHOFFSET,
> +		.end	= ETHEND,
> +		.flags	= IORESOURCE_MEM,
> +	},
> +	{
> +		.start	= IRQ_TIMBERDALE_ETHSW_IF,
> +		.end	= IRQ_TIMBERDALE_ETHSW_IF,
> +		.flags	= IORESOURCE_IRQ,
> +	},
> +};
> +
> +const static __devinitconst struct resource timberdale_gpio_resources[] = {
> +	{
> +		.start	= GPIOOFFSET,
> +		.end	= GPIOEND,
> +		.flags	= IORESOURCE_MEM,
> +	},
> +	{
> +		.start	= IRQ_TIMBERDALE_GPIO,
> +		.end	= IRQ_TIMBERDALE_GPIO,
> +		.flags	= IORESOURCE_IRQ,
> +	},
> +};
> +
> +const static __devinitconst struct resource timberdale_most_resources[] = {
> +	{
> +		.start	= MOSTOFFSET,
> +		.end	= MOSTEND,
> +		.flags	= IORESOURCE_MEM,
> +	},
> +	{
> +		.start	= IRQ_TIMBERDALE_MLB,
> +		.end	= IRQ_TIMBERDALE_MLB,
> +		.flags	= IORESOURCE_IRQ,
> +	},
> +};
> +
> +const static __devinitconst struct resource timberdale_uart_resources[] = {
> +	{
> +		.start	= UARTOFFSET,
> +		.end	= UARTEND,
> +		.flags	= IORESOURCE_MEM,
> +	},
> +	{
> +		.start	= IRQ_TIMBERDALE_UART,
> +		.end	= IRQ_TIMBERDALE_UART,
> +		.flags	= IORESOURCE_IRQ,
> +	},
> +};
> +
> +const static __devinitconst struct resource timberdale_i2s_resources[] = {
> +	{
> +		.start	= I2SOFFSET,
> +		.end	= I2SEND,
> +		.flags	= IORESOURCE_MEM,
> +	},
> +	{
> +		.start	= IRQ_TIMBERDALE_I2S,
> +		.end	= IRQ_TIMBERDALE_I2S,
> +		.flags	= IORESOURCE_IRQ,
> +	},
> +};
> +
> +static __devinitdata struct timb_video_platform_data
> +	timberdale_video_platform_data = {
> +	.i2c_adapter = 0,
> +	.encoder = "adv7180"
> +};
> +
> +const static __devinitconst struct resource timberdale_video_resources[] = {
> +	{
> +		.start	= LOGIWOFFSET,
> +		.end	= LOGIWEND,
> +		.flags	= IORESOURCE_MEM,
> +	},
> +	/*
> +	note that the "frame buffer" is located in DMA area
> +	starting at 0x1200000
> +	*/
> +};
> +
> +const static __devinitconst struct resource timberdale_dma_resources[] = {
> +	{
> +		.start	= DMAOFFSET,
> +		.end	= DMAEND,
> +		.flags	= IORESOURCE_MEM,
> +	},
> +	{
> +		.start	= IRQ_TIMBERDALE_DMA,
> +		.end	= IRQ_TIMBERDALE_DMA,
> +		.flags	= IORESOURCE_IRQ,
> +	},
> +};
> +
> +static __devinitdata struct mfd_cell timberdale_cells_bar0[] = {
> +	{
> +		.name = "timb-uart",
> +		.num_resources = ARRAY_SIZE(timberdale_uart_resources),
> +		.resources = timberdale_uart_resources,
> +	},
> +	{
> +		.name = "ocores-i2c",
> +		.num_resources = ARRAY_SIZE(timberdale_i2c_resources),
> +		.resources = timberdale_i2c_resources,
> +		.platform_data = &timberdale_i2c_platform_data,
> +		.data_size = sizeof(timberdale_i2c_platform_data),
> +	},
> +	{
> +		.name = "timb-gpio",
> +		.num_resources = ARRAY_SIZE(timberdale_gpio_resources),
> +		.resources = timberdale_gpio_resources,
> +	},
> +	{
> +		.name = "timb-i2s",
> +		.num_resources = ARRAY_SIZE(timberdale_i2s_resources),
> +		.resources = timberdale_i2s_resources,
> +	},
> +	{
> +		.name = "timb-most",
> +		.num_resources = ARRAY_SIZE(timberdale_most_resources),
> +		.resources = timberdale_most_resources,
> +	},
> +	{
> +		.name = "timb-video",
> +		.num_resources = ARRAY_SIZE(timberdale_video_resources),
> +		.resources = timberdale_video_resources,
> +		.platform_data = &timberdale_video_platform_data,
> +		.data_size = sizeof(timberdale_video_platform_data),
> +	},
> +	{
> +		.name = "xilinx_spi",
> +		.num_resources = ARRAY_SIZE(timberdale_spi_resources),
> +		.resources = timberdale_spi_resources,
> +		.platform_data = &timberdale_xspi_platform_data,
> +		.data_size = sizeof(timberdale_xspi_platform_data),
> +	},
> +	{
> +		.name = "ks8842",
> +		.num_resources = ARRAY_SIZE(timberdale_eth_resources),
> +		.resources = timberdale_eth_resources,
> +	},
> +	{
> +		.name = "timb-dma",
> +		.num_resources = ARRAY_SIZE(timberdale_dma_resources),
> +		.resources = timberdale_dma_resources,
> +	},
> +};
> +
> +static const __devinitconst struct resource timberdale_sdhc_resources[] = {
> +	/* located in bar 1 and bar 2 */
> +	{
> +		.start	= SDHC0OFFSET,
> +		.end	= SDHC0END,
> +		.flags	= IORESOURCE_MEM,
> +	},
> +	{
> +		.start	= IRQ_TIMBERDALE_SDHC,
> +		.end	= IRQ_TIMBERDALE_SDHC,
> +		.flags	= IORESOURCE_IRQ,
> +	},
> +};
> +
> +static __devinitdata struct mfd_cell timberdale_cells_bar1[] = {
> +	{
> +		.name = "sdhci",
> +		.num_resources = ARRAY_SIZE(timberdale_sdhc_resources),
> +		.resources = timberdale_sdhc_resources,
> +	},
> +};
> +
> +static __devinitdata struct mfd_cell timberdale_cells_bar2[] = {
> +	{
> +		.name = "sdhci",
> +		.num_resources = ARRAY_SIZE(timberdale_sdhc_resources),
> +		.resources = timberdale_sdhc_resources,
> +	},
> +};
> +
> +/*--------------------------------------------------------------------------*/
> +
> +
> +/* Handle the timberdale interrupt mux */
> +static void timberdale_irq(unsigned int irq, struct irq_desc *desc)
> +{
> +	struct timberdale_device *priv = get_irq_data(irq);
> +	unsigned int i, ipr;
> +
> +	desc->chip->ack(irq);
> +
> +	while ((ipr = ioread32(priv->intc_membase + IPR))) {
> +		for (i = 0; i < TIMBERDALE_NR_IRQS; i++)
> +			if (ipr & (1 << i)) {
> +				priv->irq_ack_mask = 0;
> +				generic_handle_irq(priv->irq_base + i);
> +				if (priv->irq_ack_mask)
> +					iowrite32(priv->irq_ack_mask,
> +						priv->intc_membase + IAR);
> +			}
> +	}
> +}
> +
> +static void timberdale_irq_mask(unsigned int irq)
> +{
> +	struct timberdale_device *priv = get_irq_chip_data(irq);
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&priv->lock, flags);
> +	iowrite32(1 << (irq - priv->irq_base), priv->intc_membase + CIE);
> +	spin_unlock_irqrestore(&priv->lock, flags);
> +}
> +
> +static void timberdale_irq_unmask(unsigned int irq)
> +{
> +	struct timberdale_device *priv = get_irq_chip_data(irq);
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&priv->lock, flags);
> +	iowrite32(1 << (irq - priv->irq_base), priv->intc_membase + SIE);
> +	spin_unlock_irqrestore(&priv->lock, flags);
> +}
> +
> +static void timberdale_irq_ack(unsigned int irq)
> +{
> +	struct timberdale_device *priv = get_irq_chip_data(irq);
> +	unsigned long flags;
> +	u32 ack_mask = 1 << (irq - priv->irq_base);
> +
> +	spin_lock_irqsave(&priv->lock, flags);
> +	/* if edge triggered, ack directly. Otherwhise ack in the end of
> +	 * irq handler
> +	 */
> +	if (ack_mask & IRQ_TIMBERDALE_EDGE_MASK)
> +		iowrite32(ack_mask, priv->intc_membase + IAR);
> +	else
> +		priv->irq_ack_mask |= ack_mask;
> +	spin_unlock_irqrestore(&priv->lock, flags);
> +}
> +
> +static struct irq_chip timberdale_chip = {
> +	.name		= "timberdale",
> +	.ack		= timberdale_irq_ack,
> +	.mask		= timberdale_irq_mask,
> +	.unmask		= timberdale_irq_unmask,
> +	.disable	= timberdale_irq_mask,
> +	.enable		= timberdale_irq_unmask,
> +};
> +
> +/*--------------------------------------------------------------------------*/
> +
> +/* Install the IRQ handler */
> +static void timberdale_attach_irq(struct pci_dev *dev)
> +{
> +	struct timberdale_device *priv = pci_get_drvdata(dev);
> +	unsigned int irq, irq_base;
> +
> +	irq_base = priv->irq_base;
> +	for (irq = irq_base; irq < irq_base + TIMBERDALE_NR_IRQS; irq++) {
> +		set_irq_chip_and_handler_name(irq, &timberdale_chip,
> +			handle_edge_irq, "mux");
> +
> +		set_irq_chip_data(irq, priv);
> +
> +#ifdef CONFIG_ARM
> +		set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
> +#endif
> +	}
> +
> +	set_irq_data(dev->irq, priv);
> +	set_irq_chained_handler(dev->irq, timberdale_irq);
> +}
> +
> +static void timberdale_detach_irq(struct pci_dev *dev)
> +{
> +	struct timberdale_device *priv = pci_get_drvdata(dev);
> +	unsigned int irq, irq_base;
> +
> +	irq_base = priv->irq_base;
> +
> +	set_irq_chained_handler(dev->irq, NULL);
> +	set_irq_data(dev->irq, NULL);
> +
> +	for (irq = irq_base; irq < irq_base + TIMBERDALE_NR_IRQS; irq++) {
> +#ifdef CONFIG_ARM
> +		set_irq_flags(irq, 0);
> +#endif
> +		set_irq_chip(irq, NULL);
> +		set_irq_chip_data(irq, NULL);
> +	}
> +}
> +
> +static int irq_range_free(int irq_start, int num_irq)
> +{
> +	int i;
> +
> +	for (i = 0; i < num_irq; i++)
> +		if (get_irq_chip(irq_start + i) != &no_irq_chip)
> +			return 0;
> +
> +	return 1;
> +}
> +
> +static int __devinit timb_probe(struct pci_dev *dev,
> +	const struct pci_device_id *id)
> +{
> +	struct timberdale_device *priv;
> +	int err, i;
> +	resource_size_t mapbase;
> +	u32 hw_config;
> +
> +	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
> +	if (!priv)
> +		return -ENOMEM;
> +
> +	spin_lock_init(&priv->lock);
> +	pci_set_drvdata(dev, priv);
> +
> +	err = pci_enable_device(dev);
> +	if (err)
> +		goto err_enable;
> +
> +	mapbase = pci_resource_start(dev, 0);
> +	if (!mapbase) {
> +		printk(KERN_ERR "timberdale: No resource\n");
> +		goto err_start;
> +	}
> +
> +	/* create a resource for the Interrupt controller registers */
> +	priv->intc_mapbase = mapbase + INTCOFFSET;
> +	if (!request_mem_region(priv->intc_mapbase, INTCSIZE, "timb-intc")) {
> +		printk(KERN_ERR "timberdale: Failed to request intc mem\n");
> +		goto err_request;
> +	}
> +
> +	/* create a resource for the PCI master register */
> +	priv->ctl_mapbase = mapbase + CHIPCTLOFFSET;
> +	if (!request_mem_region(priv->ctl_mapbase, CHIPCTLSIZE, "timb-intc")) {
> +		printk(KERN_ERR "timberdale: Failed to request ctl mem\n");
> +		goto err_request_ctl;
> +	}
> +
> +	priv->intc_membase = ioremap(priv->intc_mapbase, INTCSIZE);
> +	if (!priv->intc_membase) {
> +		printk(KERN_ALERT "timberdale: Map error, intc\n");
> +		goto err_ioremap;
> +	}
> +
> +	priv->ctl_membase = ioremap(priv->ctl_mapbase, CHIPCTLSIZE);
> +	if (!priv->ctl_membase) {
> +		printk(KERN_ALERT "timberdale: Map error, ctl\n");
> +		goto err_ioremap_ctl;
> +	}
> +
> +	err = pci_enable_msi(dev);
> +	if (err) {
> +		printk(KERN_WARNING "timberdale: MSI init failed: %d\n", err);
> +		goto err_msi;
> +	}
> +
> +	/* Reset all FPGA PLB peripherals */
> +	iowrite32(0x1, priv->ctl_membase + MAYSVILLERST);
> +
> +	/* read the HW config */
> +	hw_config = ioread32(priv->ctl_membase + TIMB_HW_CONFIG);
> +
> +	/* at this stage the FPGA does not generate a
> +	 * unique interrupt per function, to emulate real interrupts
> +	 * we assign them a faked interrupt which we issue in the
> +	 * interrupt handler. For now just hard code a base number
> +	 */
> +	priv->irq_base = NR_IRQS - TIMBERDALE_NR_IRQS - 1;
> +	while (priv->irq_base >= 0)
> +		if (irq_range_free(priv->irq_base, TIMBERDALE_NR_IRQS))
> +			break;
> +		else
> +			priv->irq_base -= TIMBERDALE_NR_IRQS;
> +
> +	if (priv->irq_base < 0)
> +		goto err_msi;
> +
> +	timberdale_attach_irq(dev);
> +
> +	/* update IRQ offsets in I2C board info */
> +	for (i = 0; i < ARRAY_SIZE(timberdale_i2c_board_info); i++)
> +		timberdale_i2c_board_info[i].irq += priv->irq_base;
> +
> +	/* Update the SPI configuration depending on the HW (8 or 16 bit) */
> +	if (hw_config & TIMB_HW_CONFIG_SPI_8BIT) {
> +		timberdale_xspi_platform_data.bits_per_word = 8;
> +		timberdale_xspi_platform_data.devices =
> +			timberdale_spi_8bit_board_info;
> +		timberdale_xspi_platform_data.num_devices =
> +			ARRAY_SIZE(timberdale_spi_8bit_board_info);
> +	} else {
> +		timberdale_xspi_platform_data.bits_per_word = 16;
> +		timberdale_xspi_platform_data.devices =
> +			timberdale_spi_16bit_board_info;
> +		timberdale_xspi_platform_data.num_devices =
> +			ARRAY_SIZE(timberdale_spi_16bit_board_info);
> +	}
> +
> +	err = mfd_add_devices(&dev->dev, 0,
> +		timberdale_cells_bar0, ARRAY_SIZE(timberdale_cells_bar0),
> +		&dev->resource[0], priv->irq_base);
> +	if (err) {
> +		printk(KERN_WARNING
> +			"timberdale: mfd_add_devices failed: %d\n", err);
> +		goto err_mfd;
> +	}
> +
> +	err = mfd_add_devices(&dev->dev, 1,
> +		timberdale_cells_bar1, ARRAY_SIZE(timberdale_cells_bar1),
> +		&dev->resource[1], priv->irq_base);
> +	if (err) {
> +		printk(KERN_WARNING
> +			"timberdale: mfd_add_devices failed: %d\n", err);
> +		goto err_mfd2;
> +	}
> +
> +	err = mfd_add_devices(&dev->dev, 2,
> +		timberdale_cells_bar2, ARRAY_SIZE(timberdale_cells_bar2),
> +		&dev->resource[2], priv->irq_base);
> +	if (err) {
> +		printk(KERN_WARNING
> +			"timberdale: mfd_add_devices failed: %d\n", err);
> +		goto err_mfd2;
> +	}
> +
> +	printk(KERN_INFO
> +		"Found Timberdale Card. Rev: %d.%d, HW config: 0x%02x\n",
> +		ioread32(priv->ctl_membase + TIMB_REV_MAJOR),
> +		ioread32(priv->ctl_membase + TIMB_REV_MINOR), hw_config);
> +
> +	/* Enable interrupts and wire the hardware interrupts */
> +	iowrite32(0x3, priv->intc_membase + MER);
> +
> +	return 0;
> +
> +err_mfd2:
> +	mfd_remove_devices(&dev->dev);
> +err_mfd:
> +	timberdale_detach_irq(dev);
> +	pci_disable_msi(dev);
> +err_msi:
> +	iounmap(priv->ctl_membase);
> +err_ioremap_ctl:
> +	iounmap(priv->intc_membase);
> +err_ioremap:
> +	release_mem_region(priv->ctl_mapbase, CHIPCTLSIZE);
> +err_request_ctl:
> +	release_mem_region(priv->intc_mapbase, INTCSIZE);
> +err_request:
> +	pci_set_drvdata(dev, NULL);
> +err_start:
> +	pci_disable_device(dev);
> +err_enable:
> +	kfree(priv);
> +	pci_set_drvdata(dev, NULL);
> +	return -ENODEV;
> +}
> +
> +static void __devexit timb_remove(struct pci_dev *dev)
> +{
> +	/* clean up any allocated resources and stuff here.
> +	 * like call release_region();
> +	 */
> +	struct timberdale_device *priv;
> +
> +	priv = pci_get_drvdata(dev);
> +
> +	mfd_remove_devices(&dev->dev);
> +
> +	timberdale_detach_irq(dev);
> +
> +	iowrite32(0xffffffff, priv->intc_membase + IAR);
> +	iowrite32(0, priv->intc_membase + MER);
> +	iowrite32(0, priv->intc_membase + IER);
> +
> +	iounmap(priv->ctl_membase);
> +	iounmap(priv->intc_membase);
> +	release_mem_region(priv->ctl_mapbase, CHIPCTLSIZE);
> +	release_mem_region(priv->intc_mapbase, INTCSIZE);
> +
> +	pci_disable_msi(dev);
> +	pci_disable_device(dev);
> +	pci_set_drvdata(dev, NULL);
> +	kfree(priv);
> +}
> +
> +static struct pci_device_id timberdale_pci_tbl[] = {
> +	{ PCI_DEVICE(PCI_VENDOR_ID_TIMB, PCI_DEVICE_ID_TIMB) },
> +	{ 0 }
> +};
> +MODULE_DEVICE_TABLE(pci, timberdale_pci_tbl);
> +
> +static struct pci_driver timberdale_pci_driver = {
> +	.name = "timberdale",
> +	.id_table = timberdale_pci_tbl,
> +	.probe = timb_probe,
> +	.remove = timb_remove,
> +};
> +
> +static int __init timberdale_init(void)
> +{
> +	int err;
> +
> +	err = pci_register_driver(&timberdale_pci_driver);
> +	if (err < 0) {
> +		printk(KERN_ERR
> +			"Failed to register PCI driver for %s device.\n",
> +			timberdale_pci_driver.name);
> +		return -ENODEV;
> +	}
> +
> +	printk(KERN_INFO "Driver for %s has been successfully registered.\n",
> +		timberdale_pci_driver.name);
> +
> +	return 0;
> +}
> +
> +static void __exit timberdale_exit(void)
> +{
> +	pci_unregister_driver(&timberdale_pci_driver);
> +
> +	printk(KERN_INFO "Driver for %s has been successfully unregistered.\n",
> +				timberdale_pci_driver.name);
> +}
> +
> +module_init(timberdale_init);
> +module_exit(timberdale_exit);
> +
> +MODULE_AUTHOR("Mocean Laboratories <info@mocean-labs.com>");
> +MODULE_VERSION(DRV_VERSION);
> +MODULE_LICENSE("GPL v2");
> +
> Index: linux-2.6.30-rc7/drivers/mfd/timberdale.h
> ===================================================================
> --- linux-2.6.30-rc7/drivers/mfd/timberdale.h	(revision 0)
> +++ linux-2.6.30-rc7/drivers/mfd/timberdale.h	(revision 864)
> @@ -0,0 +1,123 @@
> +/*
> + * timberdale.h timberdale FPGA mfd shim driver defines
> + * Copyright (c) 2009 Intel Corporation
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
> + */
> +
> +/* Supports:
> + * Timberdale FPGA
> + */
> +
> +#ifndef MFD_TIMBERDALE_H
> +#define MFD_TIMBERDALE_H
> +
> +/* Registers of the interrupt controller */
> +#define ISR		0x00
> +#define IPR		0x04
> +#define IER		0x08
> +#define IAR		0x0c
> +#define SIE		0x10
> +#define CIE		0x14
> +#define MER		0x1c
> +
> +/* Registers of the control area */
> +#define TIMB_REV_MAJOR	0x00
> +#define TIMB_REV_MINOR	0x04
> +#define TIMB_HW_CONFIG	0x08
> +#define MAYSVILLERST	0x40
> +
> +/* bits in the TIMB_HW_CONFIG register */
> +#define TIMB_HW_CONFIG_SPI_8BIT	0x80
> +
> +#define I2COFFSET	0x0
> +#define I2CEND		0x1f
> +
> +#define SPIOFFSET	0x80
> +#define SPIEND		0xff
> +
> +#define ETHOFFSET	0x300
> +#define ETHEND		0x3ff
> +
> +#define GPIOOFFSET	0x400
> +#define GPIOEND		0x7ff
> +
> +#define CHIPCTLOFFSET	0x800
> +#define CHIPCTLEND	0x8ff
> +#define CHIPCTLSIZE	(CHIPCTLEND - CHIPCTLOFFSET)
> +
> +#define INTCOFFSET	0xc00
> +#define INTCEND		0xfff
> +#define INTCSIZE	(INTCEND - INTCOFFSET)
> +
> +#define MOSTOFFSET	0x1000
> +#define MOSTEND		0x13ff
> +
> +#define UARTOFFSET	0x1400
> +#define UARTEND		0x17ff
> +
> +#define I2SOFFSET	0x1C00
> +#define I2SEND		0x1fff
> +
> +#define LOGIWOFFSET	0x30000
> +#define LOGIWEND	0x37fff
> +
> +#define DMAOFFSET	0x01000000
> +#define DMAEND		0x013fffff
> +
> +/* SDHC0 is placed in PCI bar 1 */
> +#define SDHC0OFFSET	0x00
> +#define SDHC0END	0xff
> +
> +/* SDHC1 is placed in PCI bar 2 */
> +#define SDHC1OFFSET	0x00
> +#define SDHC1END	0xff
> +
> +#define PCI_VENDOR_ID_TIMB	0x10ee
> +#define PCI_DEVICE_ID_TIMB	0xa123
> +#define DRV_VERSION		"0.1"
> +
> +
> +#define IRQ_TIMBERDALE_INIC	0
> +#define IRQ_TIMBERDALE_MLB	1
> +#define IRQ_TIMBERDALE_GPIO	2
> +#define IRQ_TIMBERDALE_I2C	3
> +#define IRQ_TIMBERDALE_UART	4
> +#define IRQ_TIMBERDALE_DMA	5
> +#define IRQ_TIMBERDALE_I2S	6
> +#define IRQ_TIMBERDALE_TSC_INT	7
> +#define IRQ_TIMBERDALE_SDHC	8
> +#define IRQ_TIMBERDALE_ADV7180	9
> +#define IRQ_TIMBERDALE_ETHSW_IF	10
> +#define IRQ_TIMBERDALE_SPI	11
> +
> +#define TIMBERDALE_NR_IRQS	12
> +
> +/* Some of the interrupts are level triggered, some are edge triggered */
> +#define IRQ_TIMBERDALE_EDGE_MASK ((1 << IRQ_TIMBERDALE_ADV7180) | \
> +	(1 << IRQ_TIMBERDALE_TSC_INT) | \
> +	(1 << IRQ_TIMBERDALE_MLB) | (1 << IRQ_TIMBERDALE_INIC))
> +
> +#define IRQ_TIMBERDALE_LEVEL_MASK ((1 << IRQ_TIMBERDALE_SPI) | \
> +	(1 << IRQ_TIMBERDALE_ETHSW_IF) | (1 << IRQ_TIMBERDALE_SDHC) | \
> +	(1 << IRQ_TIMBERDALE_I2S) | (1 << IRQ_TIMBERDALE_UART) | \
> +	(1 << IRQ_TIMBERDALE_I2C) | (1 << IRQ_TIMBERDALE_GPIO) | \
> +	(1 << IRQ_TIMBERDALE_DMA))
> +
> +#define GPIO_PIN_INIC_RST	14
> +#define GPIO_PIN_BT_RST		15
> +
> +
> +#endif
> +
> Index: linux-2.6.30-rc7/drivers/mfd/Makefile
> ===================================================================
> --- linux-2.6.30-rc7/drivers/mfd/Makefile	(revision 861)
> +++ linux-2.6.30-rc7/drivers/mfd/Makefile	(working copy)
> @@ -42,4 +42,5 @@
>  obj-$(CONFIG_PCF50633_ADC)	+= pcf50633-adc.o
>  obj-$(CONFIG_PCF50633_GPIO)	+= pcf50633-gpio.o
> 
> +obj-$(CONFIG_MFD_TIMBERDALE)		+= timberdale.o
>  obj-$(CONFIG_MFD_TIMBERDALE_DMA)	+= timbdma.o
> 

-- 
Intel Open Source Technology Centre
http://oss.intel.com/

  reply	other threads:[~2009-06-15 10:09 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-06-05 13:41 [PATCH 7/9] MFD: Added Timberdale driver Richard Röjfors
2009-06-15 10:11 ` Samuel Ortiz [this message]
2009-06-15 15:56   ` Andrew Morton
2009-06-16  9:21     ` Samuel Ortiz

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20090615101116.GB4094@sortiz.org \
    --to=sameo@linux.intel.com \
    --cc=akpm@linux-foundation.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=richard.rojfors.ext@mocean-labs.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.