Re: [PATCH 7/9] MFD: Added Timberdale driver

From: Samuel Ortiz
Date: Mon Jun 15 2009 - 06:09:25 EST


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@xxxxxxxxxxxxxxx>
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@xxxxxxxxxxxxxxx>");
> +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/
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/