diff options
Diffstat (limited to 'target/linux/ar7/patches-2.6.30/131-vlynq_fixes.patch')
-rw-r--r-- | target/linux/ar7/patches-2.6.30/131-vlynq_fixes.patch | 548 |
1 files changed, 548 insertions, 0 deletions
diff --git a/target/linux/ar7/patches-2.6.30/131-vlynq_fixes.patch b/target/linux/ar7/patches-2.6.30/131-vlynq_fixes.patch new file mode 100644 index 0000000000..f68ae4c70e --- /dev/null +++ b/target/linux/ar7/patches-2.6.30/131-vlynq_fixes.patch @@ -0,0 +1,548 @@ +--- a/drivers/vlynq/vlynq.c 2009-05-31 20:41:57.000000000 +0200 ++++ b/drivers/vlynq/vlynq.c 2009-07-28 21:27:52.000000000 +0200 +@@ -14,6 +14,9 @@ + * 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 ++ * ++ * Parts of the VLYNQ specification can be found here: ++ * http://www.ti.com/litv/pdf/sprue36a + */ + + #include <linux/init.h> +@@ -25,7 +28,6 @@ + #include <linux/errno.h> + #include <linux/platform_device.h> + #include <linux/interrupt.h> +-#include <linux/device.h> + #include <linux/delay.h> + #include <linux/io.h> + +@@ -73,15 +75,11 @@ + u32 int_device[8]; + }; + +-#define vlynq_reg_read(reg) readl(&(reg)) +-#define vlynq_reg_write(reg, val) writel(val, &(reg)) +- +-static int __vlynq_enable_device(struct vlynq_device *dev); +- +-#ifdef VLYNQ_DEBUG ++#ifdef CONFIG_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++) { +@@ -95,20 +93,23 @@ + 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); ++ 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) ++/* Check the VLYNQ link status with a given device */ ++static 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) ++ if (readl(&dev->local->status) & VLYNQ_STATUS_LINK) + return 1; + else + cpu_relax(); +@@ -118,17 +119,15 @@ + + static void vlynq_reset(struct vlynq_device *dev) + { +- vlynq_reg_write(dev->local->control, +- vlynq_reg_read(dev->local->control) | +- VLYNQ_CTRL_RESET); ++ writel(readl(&dev->local->control) | VLYNQ_CTRL_RESET, ++ &dev->local->control); + + /* Wait for the devices to finish resetting */ + msleep(5); + + /* Remove reset bit */ +- vlynq_reg_write(dev->local->control, +- vlynq_reg_read(dev->local->control) & +- ~VLYNQ_CTRL_RESET); ++ writel(readl(&dev->local->control) & ~VLYNQ_CTRL_RESET, ++ &dev->local->control); + + /* Give some time for the devices to settle */ + msleep(5); +@@ -142,9 +141,9 @@ + + BUG_ON(!dev); + virq = irq - dev->irq_start; +- val = vlynq_reg_read(dev->remote->int_device[virq >> 2]); ++ val = readl(&dev->remote->int_device[virq >> 2]); + val |= (VINT_ENABLE | virq) << VINT_OFFSET(virq); +- vlynq_reg_write(dev->remote->int_device[virq >> 2], val); ++ writel(val, &dev->remote->int_device[virq >> 2]); + } + + static void vlynq_irq_mask(unsigned int irq) +@@ -155,9 +154,9 @@ + + BUG_ON(!dev); + virq = irq - dev->irq_start; +- val = vlynq_reg_read(dev->remote->int_device[virq >> 2]); ++ val = readl(&dev->remote->int_device[virq >> 2]); + val &= ~(VINT_ENABLE << VINT_OFFSET(virq)); +- vlynq_reg_write(dev->remote->int_device[virq >> 2], val); ++ writel(val, &dev->remote->int_device[virq >> 2]); + } + + static int vlynq_irq_type(unsigned int irq, unsigned int flow_type) +@@ -168,7 +167,7 @@ + + BUG_ON(!dev); + virq = irq - dev->irq_start; +- val = vlynq_reg_read(dev->remote->int_device[virq >> 2]); ++ val = readl(&dev->remote->int_device[virq >> 2]); + switch (flow_type & IRQ_TYPE_SENSE_MASK) { + case IRQ_TYPE_EDGE_RISING: + case IRQ_TYPE_EDGE_FALLING: +@@ -187,28 +186,30 @@ + default: + return -EINVAL; + } +- vlynq_reg_write(dev->remote->int_device[virq >> 2], val); ++ writel(val, &dev->remote->int_device[virq >> 2]); + 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); ++ ++ u32 status = readl(&dev->local->status); ++ ++ pr_debug("%s: local status: 0x%08x\n", ++ dev_name(&dev->dev), status); ++ writel(status, &dev->local->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); ++ ++ u32 status = readl(&dev->remote->status); ++ ++ pr_debug("%s: remote status: 0x%08x\n", ++ dev_name(&dev->dev), status); ++ writel(status, &dev->remote->status); + } + + static irqreturn_t vlynq_irq(int irq, void *dev_id) +@@ -217,8 +218,8 @@ + u32 status; + int virq = 0; + +- status = vlynq_reg_read(dev->local->int_status); +- vlynq_reg_write(dev->local->int_status, status); ++ status = readl(&dev->local->int_status); ++ writel(status, &dev->local->int_status); + + if (unlikely(!status)) + spurious_interrupt(); +@@ -262,28 +263,28 @@ + if (dev->local_irq == dev->remote_irq) { + printk(KERN_ERR + "%s: local vlynq irq should be different from remote\n", +- dev->dev.bus_id); ++ dev_name(&dev->dev)); + 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)); ++ writel(readl(&dev->local->status), &dev->local->status); ++ writel(readl(&dev->remote->status), &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 |= readl(&dev->local->control); ++ writel(VLYNQ_INT_OFFSET, &dev->local->int_ptr); ++ writel(val, &dev->local->control); + + 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); ++ val |= readl(&dev->remote->control); ++ writel(VLYNQ_INT_OFFSET, &dev->remote->int_ptr); ++ writel(val, &dev->remote->int_ptr); ++ writel(val, &dev->remote->control); + + for (i = dev->irq_start; i <= dev->irq_end; i++) { + virq = i - dev->irq_start; +@@ -299,12 +300,13 @@ + set_irq_chip_and_handler(i, &vlynq_irq_chip, + handle_simple_irq); + set_irq_chip_data(i, dev); +- vlynq_reg_write(dev->remote->int_device[virq >> 2], 0); ++ writel(0, &dev->remote->int_device[virq >> 2]); + } + } + + if (request_irq(dev->irq, vlynq_irq, IRQF_SHARED, "vlynq", dev)) { +- printk(KERN_ERR "%s: request_irq failed\n", dev->dev.bus_id); ++ printk(KERN_ERR "%s: request_irq failed\n", ++ dev_name(&dev->dev)); + return -EAGAIN; + } + +@@ -328,11 +330,11 @@ + if (ids->id == vdev->dev_id) { + vdev->divisor = ids->divisor; + vlynq_set_drvdata(vdev, ids); +- printk(KERN_INFO "Driver found for VLYNQ " \ ++ printk(KERN_INFO "Driver found for VLYNQ " + "device: %08x\n", vdev->dev_id); + return 1; + } +- printk(KERN_DEBUG "Not using the %08x VLYNQ device's driver" \ ++ printk(KERN_DEBUG "Not using the %08x VLYNQ device's driver" + " for VLYNQ device: %08x\n", ids->id, vdev->dev_id); + ids++; + } +@@ -346,8 +348,7 @@ + struct vlynq_device_id *id = vlynq_get_drvdata(vdev); + int result = -ENODEV; + +- get_device(dev); +- if (drv && drv->probe) ++ if (drv->probe) + result = drv->probe(vdev, id); + if (result) + put_device(dev); +@@ -357,9 +358,10 @@ + static int vlynq_device_remove(struct device *dev) + { + struct vlynq_driver *drv = to_vlynq_driver(dev->driver); +- if (drv && drv->remove) ++ ++ if (drv->remove) + drv->remove(to_vlynq_device(dev)); +- put_device(dev); ++ + return 0; + } + +@@ -377,6 +379,14 @@ + } + EXPORT_SYMBOL(vlynq_unregister_driver); + ++/* ++ * A VLYNQ remote device can clock the VLYNQ bus master ++ * using a dedicated clock line. In that case, both the ++ * remove device and the bus master should have the same ++ * serial clock dividers configured. Iterate through the ++ * 8 possible dividers until we actually link with the ++ * device. ++ */ + static int __vlynq_try_remote(struct vlynq_device *dev) + { + int i; +@@ -389,21 +399,21 @@ + if (!vlynq_linked(dev)) + break; + +- vlynq_reg_write(dev->remote->control, +- (vlynq_reg_read(dev->remote->control) & ++ writel((readl(&dev->remote->control) & + ~VLYNQ_CTRL_CLOCK_MASK) | + VLYNQ_CTRL_CLOCK_INT | +- VLYNQ_CTRL_CLOCK_DIV(i - vlynq_rdiv1)); +- vlynq_reg_write(dev->local->control, +- ((vlynq_reg_read(dev->local->control) ++ VLYNQ_CTRL_CLOCK_DIV(i - vlynq_rdiv1), ++ &dev->remote->control); ++ writel((readl(&dev->local->control) + & ~(VLYNQ_CTRL_CLOCK_INT | + VLYNQ_CTRL_CLOCK_MASK)) | +- VLYNQ_CTRL_CLOCK_DIV(i - vlynq_rdiv1))); ++ VLYNQ_CTRL_CLOCK_DIV(i - vlynq_rdiv1), ++ &dev->local->control); + + if (vlynq_linked(dev)) { + printk(KERN_DEBUG + "%s: using remote clock divisor %d\n", +- dev->dev.bus_id, i - vlynq_rdiv1 + 1); ++ dev_name(&dev->dev), i - vlynq_rdiv1 + 1); + dev->divisor = i; + return 0; + } else { +@@ -414,26 +424,33 @@ + return -ENODEV; + } + ++/* ++ * A VLYNQ remote device can be clocked by the VLYNQ bus ++ * master using a dedicated clock line. In that case, only ++ * the bus master configures the serial clock divider. ++ * Iterate through the 8 possible dividers until we ++ * actually get a link with the device. ++ */ + static int __vlynq_try_local(struct vlynq_device *dev) + { + int i; +- ++ + vlynq_reset(dev); + + for (i = dev->dev_id ? vlynq_ldiv2 : vlynq_ldiv8; dev->dev_id ? + i <= vlynq_ldiv8 : i >= vlynq_ldiv2; + dev->dev_id ? i++ : i--) { + +- vlynq_reg_write(dev->local->control, +- (vlynq_reg_read(dev->local->control) & ++ writel((readl(&dev->local->control) & + ~VLYNQ_CTRL_CLOCK_MASK) | + VLYNQ_CTRL_CLOCK_INT | +- VLYNQ_CTRL_CLOCK_DIV(i - vlynq_ldiv1)); ++ VLYNQ_CTRL_CLOCK_DIV(i - vlynq_ldiv1), ++ &dev->local->control); + + if (vlynq_linked(dev)) { + printk(KERN_DEBUG + "%s: using local clock divisor %d\n", +- dev->dev.bus_id, i - vlynq_ldiv1 + 1); ++ dev_name(&dev->dev), i - vlynq_ldiv1 + 1); + dev->divisor = i; + return 0; + } else { +@@ -444,27 +461,33 @@ + return -ENODEV; + } + ++/* ++ * When using external clocking method, serial clock ++ * is supplied by an external oscillator, therefore we ++ * should mask the local clock bit in the clock control ++ * register for both the bus master and the remote device. ++ */ + static int __vlynq_try_external(struct vlynq_device *dev) + { + vlynq_reset(dev); + if (!vlynq_linked(dev)) + return -ENODEV; + +- vlynq_reg_write(dev->remote->control, +- (vlynq_reg_read(dev->remote->control) & +- ~VLYNQ_CTRL_CLOCK_INT)); +- +- vlynq_reg_write(dev->local->control, +- (vlynq_reg_read(dev->local->control) & +- ~VLYNQ_CTRL_CLOCK_INT)); ++ writel((readl(&dev->remote->control) & ++ ~VLYNQ_CTRL_CLOCK_INT), ++ &dev->remote->control); ++ ++ writel((readl(&dev->local->control) & ++ ~VLYNQ_CTRL_CLOCK_INT), ++ &dev->local->control); + + if (vlynq_linked(dev)) { + printk(KERN_DEBUG "%s: using external clock\n", +- dev->dev.bus_id); ++ dev_name(&dev->dev)); + dev->divisor = vlynq_div_external; + return 0; + } +- ++ + return -ENODEV; + } + +@@ -481,10 +504,10 @@ + case vlynq_div_external: + case vlynq_div_auto: + /* When the device is brought from reset it should have clock +- generation negotiated by hardware. +- Check which device is generating clocks and perform setup +- accordingly */ +- if (vlynq_linked(dev) && vlynq_reg_read(dev->remote->control) & ++ * generation negotiated by hardware. ++ * Check which device is generating clocks and perform setup ++ * accordingly */ ++ if (vlynq_linked(dev) && readl(&dev->remote->control) & + VLYNQ_CTRL_CLOCK_INT) { + if (!__vlynq_try_remote(dev) || + !__vlynq_try_local(dev) || +@@ -497,31 +520,43 @@ + return 0; + } + 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->local->control, +- VLYNQ_CTRL_CLOCK_INT | +- VLYNQ_CTRL_CLOCK_DIV(dev->divisor - +- vlynq_ldiv1)); +- vlynq_reg_write(dev->remote->control, 0); ++ case vlynq_ldiv1: ++ case vlynq_ldiv2: ++ case vlynq_ldiv3: ++ case vlynq_ldiv4: ++ case vlynq_ldiv5: ++ case vlynq_ldiv6: ++ case vlynq_ldiv7: ++ case vlynq_ldiv8: ++ writel(VLYNQ_CTRL_CLOCK_INT | ++ VLYNQ_CTRL_CLOCK_DIV(dev->divisor - ++ vlynq_ldiv1), &dev->local->control); ++ writel(0, &dev->remote->control); + if (vlynq_linked(dev)) { + printk(KERN_DEBUG +- "%s: using local clock divisor %d\n", +- dev->dev.bus_id, dev->divisor - vlynq_ldiv1 + 1); ++ "%s: using local clock divisor %d\n", ++ dev_name(&dev->dev), ++ dev->divisor - vlynq_ldiv1 + 1); + return 0; + } + 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)); ++ case vlynq_rdiv1: ++ case vlynq_rdiv2: ++ case vlynq_rdiv3: ++ case vlynq_rdiv4: ++ case vlynq_rdiv5: ++ case vlynq_rdiv6: ++ case vlynq_rdiv7: ++ case vlynq_rdiv8: ++ writel(0, &dev->local->control); ++ writel(VLYNQ_CTRL_CLOCK_INT | ++ VLYNQ_CTRL_CLOCK_DIV(dev->divisor - ++ vlynq_rdiv1), &dev->remote->control); + if (vlynq_linked(dev)) { + printk(KERN_DEBUG +- "%s: using remote clock divisor %d\n", +- dev->dev.bus_id, dev->divisor - vlynq_rdiv1 + 1); ++ "%s: using remote clock divisor %d\n", ++ dev_name(&dev->dev), ++ dev->divisor - vlynq_rdiv1 + 1); + return 0; + } + break; +@@ -568,12 +603,10 @@ + if (!dev->enabled) + return -ENXIO; + +- vlynq_reg_write(dev->local->tx_offset, tx_offset); ++ writel(tx_offset, &dev->local->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); ++ writel(mapping[i].offset, &dev->local->rx_mapping[i].offset); ++ writel(mapping[i].size, &dev->local->rx_mapping[i].size); + } + return 0; + } +@@ -587,12 +620,10 @@ + if (!dev->enabled) + return -ENXIO; + +- vlynq_reg_write(dev->remote->tx_offset, tx_offset); ++ writel(tx_offset, &dev->remote->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); ++ writel(mapping[i].offset, &dev->remote->rx_mapping[i].offset); ++ writel(mapping[i].size, &dev->remote->rx_mapping[i].size); + } + return 0; + } +@@ -662,8 +693,7 @@ + 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_set_name(&dev->dev, "vlynq%d", dev->id); + dev->dev.platform_data = pdev->dev.platform_data; + dev->dev.release = vlynq_device_release; + +@@ -673,9 +703,9 @@ + 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)) { ++ if (!request_mem_region(regs_res->start, len, dev_name(&dev->dev))) { + printk(KERN_ERR "%s: Can't request vlynq registers\n", +- dev->dev.bus_id); ++ dev_name(&dev->dev)); + result = -ENXIO; + goto fail_request; + } +@@ -683,7 +713,7 @@ + dev->local = ioremap(regs_res->start, len); + if (!dev->local) { + printk(KERN_ERR "%s: Can't remap vlynq registers\n", +- dev->dev.bus_id); ++ dev_name(&dev->dev)); + result = -ENXIO; + goto fail_remap; + } +@@ -702,14 +732,14 @@ + 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, ++ dev_name(&dev->dev), (void *)dev->regs_start, dev->irq, + (void *)dev->mem_start); + + dev->dev_id = 0; + dev->divisor = vlynq_div_auto; + result = __vlynq_enable_device(dev); + if (result == 0) { +- dev->dev_id = vlynq_reg_read(dev->remote->chip); ++ dev->dev_id = readl(&dev->remote->chip); + ((struct plat_vlynq_ops *)(dev->dev.platform_data))->off(dev); + } + if (dev->dev_id) |