--- a/drivers/vlynq/vlynq.c +++ b/drivers/vlynq/vlynq.c @@ -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 @@ -25,7 +28,6 @@ #include #include #include -#include #include #include @@ -73,15 +75,11 @@ struct vlynq_regs { 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_regs(struct vlynq 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 @@ int vlynq_linked(struct vlynq_device *de 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 @@ static void vlynq_irq_unmask(unsigned in 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 @@ static void vlynq_irq_mask(unsigned int 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 @@ static int vlynq_irq_type(unsigned int i 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 @@ static int vlynq_irq_type(unsigned int i 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 @@ static irqreturn_t vlynq_irq(int irq, vo 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 @@ static int vlynq_setup_irq(struct vlynq_ 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 @@ static int vlynq_setup_irq(struct vlynq_ 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 @@ static int vlynq_device_match(struct dev 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 @@ static int vlynq_device_probe(struct dev 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_probe(struct dev 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 @@ void vlynq_unregister_driver(struct vlyn } 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 @@ static int __vlynq_try_remote(struct vly 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 @@ static int __vlynq_try_remote(struct vly 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 @@ static int __vlynq_try_local(struct vlyn 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 @@ static int __vlynq_enable_device(struct 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 @@ static int __vlynq_enable_device(struct 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 @@ int vlynq_set_local_mapping(struct vlynq 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 @@ int vlynq_set_remote_mapping(struct vlyn 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 @@ static int vlynq_probe(struct platform_d 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 @@ static int vlynq_probe(struct platform_d 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 @@ static int vlynq_probe(struct platform_d 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 @@ static int vlynq_probe(struct platform_d 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)