summaryrefslogtreecommitdiff
path: root/target/linux/ar7/files/arch/mips
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/ar7/files/arch/mips')
-rw-r--r--target/linux/ar7/files/arch/mips/ar7/Makefile6
-rw-r--r--target/linux/ar7/files/arch/mips/ar7/platform.c2
-rw-r--r--target/linux/ar7/files/arch/mips/ar7/vlynq-pci.c436
-rw-r--r--target/linux/ar7/files/arch/mips/ar7/vlynq.c653
4 files changed, 2 insertions, 1095 deletions
diff --git a/target/linux/ar7/files/arch/mips/ar7/Makefile b/target/linux/ar7/files/arch/mips/ar7/Makefile
index bd1095739c..7435e44b39 100644
--- a/target/linux/ar7/files/arch/mips/ar7/Makefile
+++ b/target/linux/ar7/files/arch/mips/ar7/Makefile
@@ -7,8 +7,4 @@ obj-y := \
time.o \
platform.o \
gpio.o \
- clock.o \
- vlynq.o
-
-obj-$(CONFIG_PCI) += \
- vlynq-pci.o
+ clock.o
diff --git a/target/linux/ar7/files/arch/mips/ar7/platform.c b/target/linux/ar7/files/arch/mips/ar7/platform.c
index f3a9372d88..8f410babe7 100644
--- a/target/linux/ar7/files/arch/mips/ar7/platform.c
+++ b/target/linux/ar7/files/arch/mips/ar7/platform.c
@@ -29,6 +29,7 @@
#include <linux/ioport.h>
#include <linux/io.h>
#include <linux/version.h>
+#include <linux/vlynq.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
#include <linux/leds.h>
#endif
@@ -37,7 +38,6 @@
#include <asm/ar7/ar7.h>
#include <asm/ar7/gpio.h>
#include <asm/ar7/prom.h>
-#include <asm/ar7/vlynq.h>
struct plat_vlynq_data {
struct plat_vlynq_ops ops;
diff --git a/target/linux/ar7/files/arch/mips/ar7/vlynq-pci.c b/target/linux/ar7/files/arch/mips/ar7/vlynq-pci.c
deleted file mode 100644
index 7a640dbef7..0000000000
--- a/target/linux/ar7/files/arch/mips/ar7/vlynq-pci.c
+++ /dev/null
@@ -1,436 +0,0 @@
-/*
- * Copyright (C) 2006, 2007 OpenWrt.org
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/irq.h>
-#include <asm/ar7/vlynq.h>
-
-#define VLYNQ_PCI_SLOTS 2
-
-struct vlynq_reg_config {
- u32 offset;
- u32 value;
-};
-
-struct vlynq_pci_config {
- u32 chip_id;
- char name[32];
- struct vlynq_mapping rx_mapping[4];
- int irq;
- int irq_type;
- u32 chip;
- u32 class;
- int num_regs;
- struct vlynq_reg_config regs[10];
-};
-
-struct vlynq_pci_private {
- u32 latency;
- u32 cache_line;
- u32 command;
- u32 sz_mask;
- struct vlynq_pci_config *config;
-};
-
-static struct vlynq_pci_config known_devices[] = {
- {
- .chip_id = 0x00000009, .name = "TI TNETW1130",
- .rx_mapping = {
- { .size = 0x22000, .offset = 0xf0000000 },
- { .size = 0x40000, .offset = 0xc0000000 },
- { .size = 0x0, .offset = 0x0 },
- { .size = 0x0, .offset = 0x0 },
- },
- .irq = 0, .chip = 0x9066104c,
- .irq_type = IRQ_TYPE_EDGE_RISING,
- .class = PCI_CLASS_NETWORK_OTHER,
- .num_regs = 5,
- .regs = {
- {
- .offset = 0x790,
- .value = (0xd0000000 - PHYS_OFFSET)
- },
- {
- .offset = 0x794,
- .value = (0xd0000000 - PHYS_OFFSET)
- },
- { .offset = 0x740, .value = 0 },
- { .offset = 0x744, .value = 0x00010000 },
- { .offset = 0x764, .value = 0x00010000 },
- },
- },
- {
- .chip_id = 0x00000029, .name = "TI TNETW1350",
- .rx_mapping = {
- { .size = 0x100000, .offset = 0x00300000 },
- { .size = 0x80000, .offset = 0x00000000 },
- { .size = 0x0, .offset = 0x0 },
- { .size = 0x0, .offset = 0x0 },
- },
- .irq = 0, .chip = 0x9066104c,
- .irq_type = IRQ_TYPE_EDGE_RISING,
- .class = PCI_CLASS_NETWORK_OTHER,
- .num_regs = 5,
- .regs = {
- {
- .offset = 0x790,
- .value = (0x60000000 - PHYS_OFFSET)
- },
- {
- .offset = 0x794,
- .value = (0x60000000 - PHYS_OFFSET)
- },
- { .offset = 0x740, .value = 0 },
- { .offset = 0x744, .value = 0x00010000 },
- { .offset = 0x764, .value = 0x00010000 },
- },
- },
-};
-
-static struct vlynq_device *slots[VLYNQ_PCI_SLOTS] = { NULL, };
-
-static struct resource vlynq_io_resource = {
- .start = 0x00000000,
- .end = 0x00000000,
- .name = "pci IO space",
- .flags = IORESOURCE_IO
-};
-
-static struct resource vlynq_mem_resource = {
- .start = 0x00000000,
- .end = 0x00000000,
- .name = "pci memory space",
- .flags = IORESOURCE_MEM
-};
-
-static inline u32 vlynq_get_mapped(struct vlynq_device *dev, int res)
-{
- int i;
- struct vlynq_pci_private *priv = dev->priv;
- u32 ret = dev->mem_start;
- if (!priv->config->rx_mapping[res].size) return 0;
- for (i = 0; i < res; i++)
- ret += priv->config->rx_mapping[i].size;
-
- return ret;
-}
-
-static inline u32 vlynq_read(u32 val, int size)
-{
- switch (size) {
- case 1:
- return *(u8 *)&val;
- case 2:
- return *(u16 *)&val;
- }
- return val;
-}
-
-static int vlynq_config_read(struct pci_bus *bus, unsigned int devfn,
- int where, int size, u32 *val)
-{
- struct vlynq_device *dev;
- struct vlynq_pci_private *priv;
- int resno, slot = PCI_SLOT(devfn);
-
- if ((size == 2) && (where & 1))
- return PCIBIOS_BAD_REGISTER_NUMBER;
- else if ((size == 4) && (where & 3))
- return PCIBIOS_BAD_REGISTER_NUMBER;
-
- if (slot >= VLYNQ_PCI_SLOTS)
- return PCIBIOS_DEVICE_NOT_FOUND;
-
- dev = slots[slot];
-
- if (!dev || (PCI_FUNC(devfn) > 0))
- return PCIBIOS_DEVICE_NOT_FOUND;
-
- priv = dev->priv;
-
- switch (where) {
- case PCI_VENDOR_ID:
- *val = vlynq_read(priv->config->chip, size);
- break;
- case PCI_DEVICE_ID:
- *val = priv->config->chip & 0xffff;
- case PCI_COMMAND:
- *val = priv->command;
- case PCI_STATUS:
-/* *val = PCI_STATUS_CAP_LIST;*/
- *val = 0;
- break;
- case PCI_CLASS_REVISION:
- *val = priv->config->class;
- break;
- case PCI_LATENCY_TIMER:
- *val = priv->latency;
- break;
- case PCI_HEADER_TYPE:
- *val = PCI_HEADER_TYPE_NORMAL;
- break;
- case PCI_CACHE_LINE_SIZE:
- *val = priv->cache_line;
- break;
- case PCI_BASE_ADDRESS_0:
- case PCI_BASE_ADDRESS_1:
- case PCI_BASE_ADDRESS_2:
- case PCI_BASE_ADDRESS_3:
- resno = (where - PCI_BASE_ADDRESS_0) >> 2;
- if (priv->sz_mask & (1 << resno)) {
- priv->sz_mask &= ~(1 << resno);
- *val = priv->config->rx_mapping[resno].size;
- } else {
- *val = vlynq_get_mapped(dev, resno);
- }
- break;
- case PCI_BASE_ADDRESS_4:
- case PCI_BASE_ADDRESS_5:
- case PCI_SUBSYSTEM_VENDOR_ID:
- case PCI_SUBSYSTEM_ID:
- case PCI_ROM_ADDRESS:
- case PCI_INTERRUPT_LINE:
- case PCI_CARDBUS_CIS:
- case PCI_CAPABILITY_LIST:
- *val = 0;
- break;
- case PCI_INTERRUPT_PIN:
- *val = 1;
- break;
- default:
- printk(KERN_NOTICE "%s: Read of unknown register 0x%x "
- "(size %d)\n", dev->dev.bus_id, where, size);
- return PCIBIOS_BAD_REGISTER_NUMBER;
- }
- return PCIBIOS_SUCCESSFUL;
-}
-
-static int vlynq_config_write(struct pci_bus *bus, unsigned int devfn,
- int where, int size, u32 val)
-{
- struct vlynq_device *dev;
- struct vlynq_pci_private *priv;
- int resno, slot = PCI_SLOT(devfn);
-
- if ((size == 2) && (where & 1))
- return PCIBIOS_BAD_REGISTER_NUMBER;
- else if ((size == 4) && (where & 3))
- return PCIBIOS_BAD_REGISTER_NUMBER;
-
- if (slot >= VLYNQ_PCI_SLOTS)
- return PCIBIOS_DEVICE_NOT_FOUND;
-
- dev = slots[slot];
-
- if (!dev || (PCI_FUNC(devfn) > 0))
- return PCIBIOS_DEVICE_NOT_FOUND;
-
- priv = dev->priv;
-
- switch (where) {
- case PCI_VENDOR_ID:
- case PCI_DEVICE_ID:
- case PCI_STATUS:
- case PCI_CLASS_REVISION:
- case PCI_HEADER_TYPE:
- case PCI_CACHE_LINE_SIZE:
- case PCI_SUBSYSTEM_VENDOR_ID:
- case PCI_SUBSYSTEM_ID:
- case PCI_INTERRUPT_LINE:
- case PCI_INTERRUPT_PIN:
- case PCI_CARDBUS_CIS:
- case PCI_CAPABILITY_LIST:
- return PCIBIOS_FUNC_NOT_SUPPORTED;
- case PCI_COMMAND:
- priv->command = val;
- case PCI_LATENCY_TIMER:
- priv->latency = val;
- break;
- case PCI_BASE_ADDRESS_0:
- case PCI_BASE_ADDRESS_1:
- case PCI_BASE_ADDRESS_2:
- case PCI_BASE_ADDRESS_3:
- if (val == 0xffffffff) {
- resno = (where - PCI_BASE_ADDRESS_0) >> 2;
- priv->sz_mask |= (1 << resno);
- break;
- }
- case PCI_BASE_ADDRESS_4:
- case PCI_BASE_ADDRESS_5:
- case PCI_ROM_ADDRESS:
- break;
- default:
- printk(KERN_NOTICE "%s: Write to unknown register 0x%x "
- "(size %d) value=0x%x\n", dev->dev.bus_id, where, size,
- val);
- return PCIBIOS_BAD_REGISTER_NUMBER;
- }
- return PCIBIOS_SUCCESSFUL;
-}
-
-static struct pci_ops vlynq_pci_ops = {
- vlynq_config_read,
- vlynq_config_write
-};
-
-static struct pci_controller vlynq_controller = {
- .pci_ops = &vlynq_pci_ops,
- .io_resource = &vlynq_io_resource,
- .mem_resource = &vlynq_mem_resource,
-};
-
-static int vlynq_pci_probe(struct vlynq_device *dev)
-{
- int result, i;
- u32 chip_id, addr;
- struct vlynq_pci_private *priv;
- struct vlynq_mapping mapping[4] = { { 0, }, };
- struct vlynq_pci_config *config = NULL;
-
- result = vlynq_set_local_irq(dev, 31);
- if (result)
- return result;
-
- result = vlynq_set_remote_irq(dev, 30);
- if (result)
- return result;
-
- dev->divisor = vlynq_div_auto;
- result = vlynq_device_enable(dev);
- if (result)
- return result;
-
- chip_id = vlynq_remote_id(dev);
- for (i = 0; i < ARRAY_SIZE(known_devices); i++)
- if (chip_id == known_devices[i].chip_id)
- config = &known_devices[i];
-
- if (!config) {
- printk(KERN_DEBUG "vlynq-pci: skipping unknown device "
- "%04x:%04x at %s\n", chip_id >> 16,
- chip_id & 0xffff, dev->dev.bus_id);
- result = -ENODEV;
- goto fail;
- }
-
- printk(KERN_NOTICE "vlynq-pci: attaching device %s at %s\n",
- config->name, dev->dev.bus_id);
-
- priv = kzalloc(sizeof(*priv), GFP_KERNEL);
- if (!priv) {
- printk(KERN_ERR "%s: failed to allocate private data\n",
- dev->dev.bus_id);
- result = -ENOMEM;
- goto fail;
- }
-
- priv->latency = 64;
- priv->cache_line = 32;
- priv->config = config;
-
- mapping[0].offset = ARCH_PFN_OFFSET << PAGE_SHIFT;
- mapping[0].size = 0x02000000;
- vlynq_set_local_mapping(dev, dev->mem_start, mapping);
- vlynq_set_remote_mapping(dev, 0, config->rx_mapping);
-
- set_irq_type(vlynq_virq_to_irq(dev, config->irq), config->irq_type);
-
- addr = (u32)ioremap_nocache(dev->mem_start, 0x10000);
- if (!addr) {
- printk(KERN_ERR "%s: failed to remap io memory\n",
- dev->dev.bus_id);
- result = -ENXIO;
- goto fail;
- }
-
- for (i = 0; i < config->num_regs; i++)
- iowrite32(config->regs[i].value,
- (u32 *)(addr + config->regs[i].offset));
-
- dev->priv = priv;
- for (i = 0; i < VLYNQ_PCI_SLOTS; i++) {
- if (!slots[i]) {
- slots[i] = dev;
- break;
- }
- }
-
- return 0;
-
-fail:
- vlynq_device_disable(dev);
-
- return result;
-}
-
-static int vlynq_pci_remove(struct vlynq_device *dev)
-{
- int i;
- struct vlynq_pci_private *priv = dev->priv;
-
- for (i = 0; i < VLYNQ_PCI_SLOTS; i++)
- if (slots[i] == dev)
- slots[i] = NULL;
-
- vlynq_device_disable(dev);
- kfree(priv);
-
- return 0;
-}
-
-static struct vlynq_driver vlynq_pci = {
- .name = "PCI over VLYNQ emulation",
- .probe = vlynq_pci_probe,
- .remove = vlynq_pci_remove,
-};
-
-int vlynq_pci_init(void)
-{
- int res;
- res = vlynq_register_driver(&vlynq_pci);
- if (res)
- return res;
-
- register_pci_controller(&vlynq_controller);
-
- return 0;
-}
-
-int pcibios_map_irq(struct pci_dev *pdev, u8 slot, u8 pin)
-{
- struct vlynq_device *dev;
- struct vlynq_pci_private *priv;
-
- dev = slots[slot];
-
- if (!dev)
- return 0;
-
- priv = dev->priv;
-
- return vlynq_virq_to_irq(dev, priv->config->irq);
-}
-
-/* Do platform specific device initialization at pci_enable_device() time */
-int pcibios_plat_dev_init(struct pci_dev *dev)
-{
- return 0;
-}
diff --git a/target/linux/ar7/files/arch/mips/ar7/vlynq.c b/target/linux/ar7/files/arch/mips/ar7/vlynq.c
deleted file mode 100644
index 4c0a86dbaf..0000000000
--- a/target/linux/ar7/files/arch/mips/ar7/vlynq.c
+++ /dev/null
@@ -1,653 +0,0 @@
-/*
- * Copyright (C) 2006, 2007 OpenWrt.org
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/device.h>
-#include <linux/errno.h>
-#include <linux/platform_device.h>
-#include <linux/interrupt.h>
-#include <linux/device.h>
-#include <linux/io.h>
-
-#include <asm/ar7/vlynq.h>
-
-#define PER_DEVICE_IRQS 32
-
-#define VLYNQ_CTRL_PM_ENABLE 0x80000000
-#define VLYNQ_CTRL_CLOCK_INT 0x00008000
-#define VLYNQ_CTRL_CLOCK_DIV(x) (((x) & 7) << 16)
-#define VLYNQ_CTRL_INT_LOCAL 0x00004000
-#define VLYNQ_CTRL_INT_ENABLE 0x00002000
-#define VLYNQ_CTRL_INT_VECTOR(x) (((x) & 0x1f) << 8)
-#define VLYNQ_CTRL_INT2CFG 0x00000080
-#define VLYNQ_CTRL_RESET 0x00000001
-
-#define VLYNQ_INT_OFFSET 0x00000014
-#define VLYNQ_REMOTE_OFFSET 0x00000080
-
-#define VLYNQ_STATUS_LINK 0x00000001
-#define VLYNQ_STATUS_LERROR 0x00000080
-#define VLYNQ_STATUS_RERROR 0x00000100
-
-#define VINT_ENABLE 0x00000100
-#define VINT_TYPE_EDGE 0x00000080
-#define VINT_LEVEL_LOW 0x00000040
-#define VINT_VECTOR(x) ((x) & 0x1f)
-#define VINT_OFFSET(irq) (8 * ((irq) % 4))
-
-#define VLYNQ_AUTONEGO_V2 0x00010000
-
-struct vlynq_regs {
- u32 revision;
- u32 control;
- u32 status;
- u32 int_prio;
- u32 int_status;
- u32 int_pending;
- u32 int_ptr;
- u32 tx_offset;
- struct vlynq_mapping rx_mapping[4];
- u32 chip;
- u32 autonego;
- u32 unused[6];
- u32 int_device[8];
-} __attribute__ ((packed));
-
-#define vlynq_reg_read(reg) readl(&(reg))
-#define vlynq_reg_write(reg, val) writel(val, &(reg))
-
-#ifdef VLYNQ_DEBUG
-static void vlynq_dump_regs(struct vlynq_device *dev)
-{
- int i;
- printk(KERN_DEBUG "VLYNQ local=%p remote=%p\n",
- dev->local, dev->remote);
- for (i = 0; i < 32; i++) {
- printk(KERN_DEBUG "VLYNQ: local %d: %08x\n",
- i + 1, ((u32 *)dev->local)[i]);
- printk(KERN_DEBUG "VLYNQ: remote %d: %08x\n",
- i + 1, ((u32 *)dev->remote)[i]);
- }
-}
-
-static void vlynq_dump_mem(u32 *base, int count)
-{
- int i;
- for (i = 0; i < (count + 3) / 4; i++) {
- if (i % 4 == 0) printk(KERN_DEBUG "\nMEM[0x%04x]:", i * 4);
- printk(KERN_DEBUG " 0x%08x", *(base + i));
- }
- printk(KERN_DEBUG "\n");
-}
-#endif
-
-int vlynq_linked(struct vlynq_device *dev)
-{
- int i;
-
- for (i = 0; i < 100; i++)
- if (vlynq_reg_read(dev->local->status) & VLYNQ_STATUS_LINK)
- return 1;
- else
- cpu_relax();
-
- return 0;
-}
-
-static void vlynq_irq_unmask(unsigned int irq)
-{
- u32 val;
- struct vlynq_device *dev = get_irq_chip_data(irq);
- int virq;
-
- BUG_ON(!dev);
- virq = irq - dev->irq_start;
- val = vlynq_reg_read(dev->remote->int_device[virq >> 2]);
- val |= (VINT_ENABLE | virq) << VINT_OFFSET(virq);
- vlynq_reg_write(dev->remote->int_device[virq >> 2], val);
-}
-
-static void vlynq_irq_mask(unsigned int irq)
-{
- u32 val;
- struct vlynq_device *dev = get_irq_chip_data(irq);
- int virq;
-
- BUG_ON(!dev);
- virq = irq - dev->irq_start;
- val = vlynq_reg_read(dev->remote->int_device[virq >> 2]);
- val &= ~(VINT_ENABLE << VINT_OFFSET(virq));
- vlynq_reg_write(dev->remote->int_device[virq >> 2], val);
-}
-
-static int vlynq_irq_type(unsigned int irq, unsigned int flow_type)
-{
- u32 val;
- struct vlynq_device *dev = get_irq_chip_data(irq);
- int virq;
-
- BUG_ON(!dev);
- virq = irq - dev->irq_start;
- val = vlynq_reg_read(dev->remote->int_device[virq >> 2]);
- switch (flow_type & IRQ_TYPE_SENSE_MASK) {
- case IRQ_TYPE_EDGE_RISING:
- case IRQ_TYPE_EDGE_FALLING:
- case IRQ_TYPE_EDGE_BOTH:
- val |= VINT_TYPE_EDGE << VINT_OFFSET(virq);
- val &= ~(VINT_LEVEL_LOW << VINT_OFFSET(virq));
- break;
- case IRQ_TYPE_LEVEL_HIGH:
- val &= ~(VINT_TYPE_EDGE << VINT_OFFSET(virq));
- val &= ~(VINT_LEVEL_LOW << VINT_OFFSET(virq));
- break;
- case IRQ_TYPE_LEVEL_LOW:
- val &= ~(VINT_TYPE_EDGE << VINT_OFFSET(virq));
- val |= VINT_LEVEL_LOW << VINT_OFFSET(virq);
- break;
- default:
- return -EINVAL;
- }
- vlynq_reg_write(dev->remote->int_device[virq >> 2], val);
- return 0;
-}
-
-static void vlynq_local_ack(unsigned int irq)
-{
- struct vlynq_device *dev = get_irq_chip_data(irq);
- u32 status = vlynq_reg_read(dev->local->status);
- if (printk_ratelimit())
- printk(KERN_DEBUG "%s: local status: 0x%08x\n",
- dev->dev.bus_id, status);
- vlynq_reg_write(dev->local->status, status);
-}
-
-static void vlynq_remote_ack(unsigned int irq)
-{
- struct vlynq_device *dev = get_irq_chip_data(irq);
- u32 status = vlynq_reg_read(dev->remote->status);
- if (printk_ratelimit())
- printk(KERN_DEBUG "%s: remote status: 0x%08x\n",
- dev->dev.bus_id, status);
- vlynq_reg_write(dev->remote->status, status);
-}
-
-#warning FIXME: process one irq per call
-static irqreturn_t vlynq_irq(int irq, void *dev_id)
-{
- struct vlynq_device *dev = dev_id;
- u32 status;
- int virq = 0;
-
- status = vlynq_reg_read(dev->local->int_status);
- vlynq_reg_write(dev->local->int_status, status);
-
- if (unlikely(!status))
- spurious_interrupt();
-
- while (status) {
- if (status & 1)
- do_IRQ(dev->irq_start + virq);
- status >>= 1;
- virq++;
- }
-
- return IRQ_HANDLED;
-}
-
-static struct irq_chip vlynq_irq_chip = {
- .name = "vlynq",
- .unmask = vlynq_irq_unmask,
- .mask = vlynq_irq_mask,
- .set_type = vlynq_irq_type,
-};
-
-static struct irq_chip vlynq_local_chip = {
- .name = "vlynq local error",
- .unmask = vlynq_irq_unmask,
- .mask = vlynq_irq_mask,
- .ack = vlynq_local_ack,
-};
-
-static struct irq_chip vlynq_remote_chip = {
- .name = "vlynq local error",
- .unmask = vlynq_irq_unmask,
- .mask = vlynq_irq_mask,
- .ack = vlynq_remote_ack,
-};
-
-static int vlynq_setup_irq(struct vlynq_device *dev)
-{
- u32 val;
- int i;
-
- if (dev->local_irq == dev->remote_irq) {
- printk(KERN_ERR
- "%s: local vlynq irq should be different from remote\n",
- dev->dev.bus_id);
- return -EINVAL;
- }
-
- /* Clear local and remote error bits */
- vlynq_reg_write(dev->local->status, vlynq_reg_read(dev->local->status));
- vlynq_reg_write(dev->remote->status,
- vlynq_reg_read(dev->remote->status));
-
- /* Now setup interrupts */
- val = VLYNQ_CTRL_INT_VECTOR(dev->local_irq);
- val |= VLYNQ_CTRL_INT_ENABLE | VLYNQ_CTRL_INT_LOCAL |
- VLYNQ_CTRL_INT2CFG;
- val |= vlynq_reg_read(dev->local->control);
- vlynq_reg_write(dev->local->int_ptr, VLYNQ_INT_OFFSET);
- vlynq_reg_write(dev->local->control, val);
-
- val = VLYNQ_CTRL_INT_VECTOR(dev->remote_irq);
- val |= VLYNQ_CTRL_INT_ENABLE;
- val |= vlynq_reg_read(dev->remote->control);
- vlynq_reg_write(dev->remote->int_ptr, VLYNQ_INT_OFFSET);
- vlynq_reg_write(dev->remote->control, val);
-
- for (i = 0; i < PER_DEVICE_IRQS; i++) {
- if (i == dev->local_irq) {
- set_irq_chip_and_handler(dev->irq_start + i,
- &vlynq_local_chip,
- handle_level_irq);
- set_irq_chip_data(dev->irq_start + i, dev);
- } else if (i == dev->remote_irq) {
- set_irq_chip_and_handler(dev->irq_start + i,
- &vlynq_remote_chip,
- handle_level_irq);
- set_irq_chip_data(dev->irq_start + i, dev);
- } else {
- set_irq_chip_and_handler(dev->irq_start + i,
- &vlynq_irq_chip,
- handle_simple_irq);
- set_irq_chip_data(dev->irq_start + i, dev);
- vlynq_reg_write(dev->remote->int_device[i >> 2], 0);
- }
- }
-
- if (request_irq(dev->irq, vlynq_irq, IRQF_SHARED, "vlynq", dev)) {
- printk(KERN_ERR "%s: request_irq failed\n", dev->dev.bus_id);
- return -EAGAIN;
- }
-
- return 0;
-}
-
-static void vlynq_free_irq(struct vlynq_device *dev)
-{
- free_irq(dev->irq, dev);
-}
-
-static void vlynq_device_release(struct device *dev)
-{
- struct vlynq_device *vdev = to_vlynq_device(dev);
- kfree(vdev);
-}
-
-static int vlynq_device_probe(struct device *dev)
-{
- struct vlynq_driver *drv = to_vlynq_driver(dev->driver);
- if (drv->probe)
- return drv->probe(to_vlynq_device(dev));
- return 0;
-}
-
-static int vlynq_device_remove(struct device *dev)
-{
- struct vlynq_driver *drv = to_vlynq_driver(dev->driver);
- if (drv->remove)
- return drv->remove(to_vlynq_device(dev));
- return 0;
-}
-
-int __vlynq_register_driver(struct vlynq_driver *driver, struct module *owner)
-{
- driver->driver.name = driver->name;
- driver->driver.bus = &vlynq_bus_type;
- return driver_register(&driver->driver);
-}
-EXPORT_SYMBOL(__vlynq_register_driver);
-
-void vlynq_unregister_driver(struct vlynq_driver *driver)
-{
- driver_unregister(&driver->driver);
-}
-EXPORT_SYMBOL(vlynq_unregister_driver);
-
-int vlynq_device_enable(struct vlynq_device *dev)
-{
- int i, result;
- struct plat_vlynq_ops *ops = dev->dev.platform_data;
-
- result = ops->on(dev);
- if (result)
- return result;
-
- switch (dev->divisor) {
- case vlynq_div_auto:
- /* First try locally supplied clock */
- vlynq_reg_write(dev->remote->control, 0);
- for (i = vlynq_ldiv1; i <= vlynq_ldiv8; i++) {
- vlynq_reg_write(dev->local->control,
- VLYNQ_CTRL_CLOCK_INT |
- VLYNQ_CTRL_CLOCK_DIV(i - vlynq_ldiv1));
- if (vlynq_linked(dev)) {
- printk(KERN_DEBUG
- "%s: using local clock divisor %d\n",
- dev->dev.bus_id, i - vlynq_ldiv1 + 1);
- return vlynq_setup_irq(dev);
- }
- }
- /* Then remotely supplied clock */
- vlynq_reg_write(dev->local->control, 0);
- for (i = vlynq_rdiv1; i <= vlynq_rdiv8; i++) {
- vlynq_reg_write(dev->remote->control,
- VLYNQ_CTRL_CLOCK_INT |
- VLYNQ_CTRL_CLOCK_DIV(i - vlynq_rdiv1));
- if (vlynq_linked(dev)) {
- printk(KERN_DEBUG
- "%s: using remote clock divisor %d\n",
- dev->dev.bus_id, i - vlynq_rdiv1 + 1);
- return vlynq_setup_irq(dev);
- }
- }
- /* At last, externally supplied clock */
- vlynq_reg_write(dev->remote->control, 0);
- if (vlynq_linked(dev)) {
- printk(KERN_DEBUG "%s: using external clock\n",
- dev->dev.bus_id);
- return vlynq_setup_irq(dev);
- }
- break;
- case vlynq_ldiv1: case vlynq_ldiv2: case vlynq_ldiv3: case vlynq_ldiv4:
- case vlynq_ldiv5: case vlynq_ldiv6: case vlynq_ldiv7: case vlynq_ldiv8:
- vlynq_reg_write(dev->remote->control, 0);
- vlynq_reg_write(dev->local->control,
- VLYNQ_CTRL_CLOCK_INT |
- VLYNQ_CTRL_CLOCK_DIV(dev->divisor -
- vlynq_ldiv1));
- if (vlynq_linked(dev)) {
- printk(KERN_DEBUG
- "%s: using local clock divisor %d\n",
- dev->dev.bus_id, dev->divisor - vlynq_ldiv1 + 1);
- return vlynq_setup_irq(dev);
- }
- break;
- case vlynq_rdiv1: case vlynq_rdiv2: case vlynq_rdiv3: case vlynq_rdiv4:
- case vlynq_rdiv5: case vlynq_rdiv6: case vlynq_rdiv7: case vlynq_rdiv8:
- vlynq_reg_write(dev->local->control, 0);
- vlynq_reg_write(dev->remote->control,
- VLYNQ_CTRL_CLOCK_INT |
- VLYNQ_CTRL_CLOCK_DIV(dev->divisor -
- vlynq_rdiv1));
- if (vlynq_linked(dev)) {
- printk(KERN_DEBUG
- "%s: using remote clock divisor %d\n",
- dev->dev.bus_id, dev->divisor - vlynq_rdiv1 + 1);
- return vlynq_setup_irq(dev);
- }
- break;
- case vlynq_div_external:
- vlynq_reg_write(dev->local->control, 0);
- vlynq_reg_write(dev->remote->control, 0);
- if (vlynq_linked(dev)) {
- printk(KERN_DEBUG "%s: using external clock\n",
- dev->dev.bus_id);
- return vlynq_setup_irq(dev);
- }
- break;
- }
-
- return -ENODEV;
-}
-
-void vlynq_device_disable(struct vlynq_device *dev)
-{
- struct plat_vlynq_ops *ops = dev->dev.platform_data;
-
- vlynq_free_irq(dev);
- ops->off(dev);
-}
-
-u32 vlynq_remote_id(struct vlynq_device *dev)
-{
- return vlynq_reg_read(dev->remote->chip);
-}
-
-void vlynq_set_local_mapping(struct vlynq_device *dev, u32 tx_offset,
- struct vlynq_mapping *mapping)
-{
- int i;
-
- vlynq_reg_write(dev->local->tx_offset, tx_offset);
- for (i = 0; i < 4; i++) {
- vlynq_reg_write(dev->local->rx_mapping[i].offset,
- mapping[i].offset);
- vlynq_reg_write(dev->local->rx_mapping[i].size,
- mapping[i].size);
- }
-}
-
-void vlynq_set_remote_mapping(struct vlynq_device *dev, u32 tx_offset,
- struct vlynq_mapping *mapping)
-{
- int i;
-
- vlynq_reg_write(dev->remote->tx_offset, tx_offset);
- for (i = 0; i < 4; i++) {
- vlynq_reg_write(dev->remote->rx_mapping[i].offset,
- mapping[i].offset);
- vlynq_reg_write(dev->remote->rx_mapping[i].size,
- mapping[i].size);
- }
-}
-
-int vlynq_virq_to_irq(struct vlynq_device *dev, int virq)
-{
- if ((virq < 0) || (virq >= PER_DEVICE_IRQS))
- return -EINVAL;
-
- return dev->irq_start + virq;
-}
-
-int vlynq_irq_to_virq(struct vlynq_device *dev, int irq)
-{
- if ((irq < dev->irq_start) || (irq >= dev->irq_start + PER_DEVICE_IRQS))
- return -EINVAL;
-
- return irq - dev->irq_start;
-}
-
-int vlynq_set_local_irq(struct vlynq_device *dev, int virq)
-{
- if ((virq < 0) || (virq >= PER_DEVICE_IRQS))
- return -EINVAL;
-
- if (virq == dev->remote_irq)
- return -EINVAL;
-
- dev->local_irq = virq;
-
- return 0;
-}
-
-int vlynq_set_remote_irq(struct vlynq_device *dev, int virq)
-{
- if ((virq < 0) || (virq >= PER_DEVICE_IRQS))
- return -EINVAL;
-
- if (virq == dev->local_irq)
- return -EINVAL;
-
- dev->remote_irq = virq;
-
- return 0;
-}
-
-static int vlynq_probe(struct platform_device *pdev)
-{
- struct vlynq_device *dev;
- struct resource *regs_res, *mem_res, *irq_res;
- int len, result;
-
- if (strcmp(pdev->name, "vlynq"))
- return -ENODEV;
-
- regs_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
- if (!regs_res)
- return -ENODEV;
-
- mem_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mem");
- if (!mem_res)
- return -ENODEV;
-
- irq_res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "devirq");
- if (!irq_res)
- return -ENODEV;
-
- dev = kzalloc(sizeof(*dev), GFP_KERNEL);
- if (!dev) {
- printk(KERN_ERR
- "vlynq: failed to allocate device structure\n");
- return -ENOMEM;
- }
-
- dev->id = pdev->id;
- dev->dev.bus = &vlynq_bus_type;
- dev->dev.parent = &pdev->dev;
- snprintf(dev->dev.bus_id, BUS_ID_SIZE, "vlynq%d", dev->id);
- dev->dev.bus_id[BUS_ID_SIZE - 1] = 0;
- dev->dev.platform_data = pdev->dev.platform_data;
- dev->dev.release = vlynq_device_release;
-
- dev->regs_start = regs_res->start;
- dev->regs_end = regs_res->end;
- dev->mem_start = mem_res->start;
- dev->mem_end = mem_res->end;
-
- len = regs_res->end - regs_res->start;
- if (!request_mem_region(regs_res->start, len, dev->dev.bus_id)) {
- printk(KERN_ERR "%s: Can't request vlynq registers\n",
- dev->dev.bus_id);
- result = -ENXIO;
- goto fail_request;
- }
-
- dev->local = ioremap(regs_res->start, len);
- if (!dev->local) {
- printk(KERN_ERR "%s: Can't remap vlynq registers\n",
- dev->dev.bus_id);
- result = -ENXIO;
- goto fail_remap;
- }
-
- dev->remote = (struct vlynq_regs *)((u32)dev->local +
- VLYNQ_REMOTE_OFFSET);
-
- dev->irq = platform_get_irq_byname(pdev, "irq");
- dev->irq_start = irq_res->start;
- dev->irq_end = irq_res->end;
- dev->local_irq = 31;
- dev->remote_irq = 30;
-
- if (device_register(&dev->dev))
- goto fail_register;
- platform_set_drvdata(pdev, dev);
-
- printk(KERN_INFO "%s: regs 0x%p, irq %d, mem 0x%p\n",
- dev->dev.bus_id, (void *)dev->regs_start, dev->irq,
- (void *)dev->mem_start);
-
- return 0;
-
-fail_register:
- iounmap(dev->local);
-fail_remap:
-fail_request:
- release_mem_region(regs_res->start, len);
- kfree(dev);
- return result;
-}
-
-static int vlynq_remove(struct platform_device *pdev)
-{
- struct vlynq_device *dev = platform_get_drvdata(pdev);
-
- device_unregister(&dev->dev);
- iounmap(dev->local);
- release_mem_region(dev->regs_start, dev->regs_end - dev->regs_start);
-
- kfree(dev);
-
- return 0;
-}
-
-static struct platform_driver vlynq_driver = {
- .driver.name = "vlynq",
- .probe = vlynq_probe,
- .remove = vlynq_remove,
-};
-
-struct bus_type vlynq_bus_type = {
- .name = "vlynq",
- .probe = vlynq_device_probe,
- .remove = vlynq_device_remove,
-};
-EXPORT_SYMBOL(vlynq_bus_type);
-
-#ifdef CONFIG_PCI
-extern void vlynq_pci_init(void);
-#endif
-static int __init vlynq_init(void)
-{
- int res = 0;
-
- res = bus_register(&vlynq_bus_type);
- if (res)
- goto fail_bus;
-
- res = platform_driver_register(&vlynq_driver);
- if (res)
- goto fail_platform;
-
-#ifdef CONFIG_PCI
- vlynq_pci_init();
-#endif
-
- return 0;
-
-fail_platform:
- bus_unregister(&vlynq_bus_type);
-fail_bus:
- return res;
-}
-
-/* Add this back when vlynq-pci crap is gone */
-#if 0
-static void __devexit vlynq_exit(void)
-{
- platform_driver_unregister(&vlynq_driver);
- bus_unregister(&vlynq_bus_type);
-}
-#endif
-
-subsys_initcall(vlynq_init);