Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Copyright (C) 2006, 2007 Eugene Konev <ejka@openwrt.org>
0004  *
0005  * Parts of the VLYNQ specification can be found here:
0006  * http://www.ti.com/litv/pdf/sprue36a
0007  */
0008 
0009 #include <linux/init.h>
0010 #include <linux/types.h>
0011 #include <linux/kernel.h>
0012 #include <linux/string.h>
0013 #include <linux/device.h>
0014 #include <linux/module.h>
0015 #include <linux/errno.h>
0016 #include <linux/platform_device.h>
0017 #include <linux/interrupt.h>
0018 #include <linux/delay.h>
0019 #include <linux/io.h>
0020 #include <linux/slab.h>
0021 #include <linux/irq.h>
0022 
0023 #include <linux/vlynq.h>
0024 
0025 #define VLYNQ_CTRL_PM_ENABLE        0x80000000
0026 #define VLYNQ_CTRL_CLOCK_INT        0x00008000
0027 #define VLYNQ_CTRL_CLOCK_DIV(x)     (((x) & 7) << 16)
0028 #define VLYNQ_CTRL_INT_LOCAL        0x00004000
0029 #define VLYNQ_CTRL_INT_ENABLE       0x00002000
0030 #define VLYNQ_CTRL_INT_VECTOR(x)    (((x) & 0x1f) << 8)
0031 #define VLYNQ_CTRL_INT2CFG      0x00000080
0032 #define VLYNQ_CTRL_RESET        0x00000001
0033 
0034 #define VLYNQ_CTRL_CLOCK_MASK          (0x7 << 16)
0035 
0036 #define VLYNQ_INT_OFFSET        0x00000014
0037 #define VLYNQ_REMOTE_OFFSET     0x00000080
0038 
0039 #define VLYNQ_STATUS_LINK       0x00000001
0040 #define VLYNQ_STATUS_LERROR     0x00000080
0041 #define VLYNQ_STATUS_RERROR     0x00000100
0042 
0043 #define VINT_ENABLE         0x00000100
0044 #define VINT_TYPE_EDGE          0x00000080
0045 #define VINT_LEVEL_LOW          0x00000040
0046 #define VINT_VECTOR(x)          ((x) & 0x1f)
0047 #define VINT_OFFSET(irq)        (8 * ((irq) % 4))
0048 
0049 #define VLYNQ_AUTONEGO_V2       0x00010000
0050 
0051 struct vlynq_regs {
0052     u32 revision;
0053     u32 control;
0054     u32 status;
0055     u32 int_prio;
0056     u32 int_status;
0057     u32 int_pending;
0058     u32 int_ptr;
0059     u32 tx_offset;
0060     struct vlynq_mapping rx_mapping[4];
0061     u32 chip;
0062     u32 autonego;
0063     u32 unused[6];
0064     u32 int_device[8];
0065 };
0066 
0067 #ifdef CONFIG_VLYNQ_DEBUG
0068 static void vlynq_dump_regs(struct vlynq_device *dev)
0069 {
0070     int i;
0071 
0072     printk(KERN_DEBUG "VLYNQ local=%p remote=%p\n",
0073             dev->local, dev->remote);
0074     for (i = 0; i < 32; i++) {
0075         printk(KERN_DEBUG "VLYNQ: local %d: %08x\n",
0076             i + 1, ((u32 *)dev->local)[i]);
0077         printk(KERN_DEBUG "VLYNQ: remote %d: %08x\n",
0078             i + 1, ((u32 *)dev->remote)[i]);
0079     }
0080 }
0081 
0082 static void vlynq_dump_mem(u32 *base, int count)
0083 {
0084     int i;
0085 
0086     for (i = 0; i < (count + 3) / 4; i++) {
0087         if (i % 4 == 0)
0088             printk(KERN_DEBUG "\nMEM[0x%04x]:", i * 4);
0089         printk(KERN_DEBUG " 0x%08x", *(base + i));
0090     }
0091     printk(KERN_DEBUG "\n");
0092 }
0093 #endif
0094 
0095 /* Check the VLYNQ link status with a given device */
0096 static int vlynq_linked(struct vlynq_device *dev)
0097 {
0098     int i;
0099 
0100     for (i = 0; i < 100; i++)
0101         if (readl(&dev->local->status) & VLYNQ_STATUS_LINK)
0102             return 1;
0103         else
0104             cpu_relax();
0105 
0106     return 0;
0107 }
0108 
0109 static void vlynq_reset(struct vlynq_device *dev)
0110 {
0111     writel(readl(&dev->local->control) | VLYNQ_CTRL_RESET,
0112             &dev->local->control);
0113 
0114     /* Wait for the devices to finish resetting */
0115     msleep(5);
0116 
0117     /* Remove reset bit */
0118     writel(readl(&dev->local->control) & ~VLYNQ_CTRL_RESET,
0119             &dev->local->control);
0120 
0121     /* Give some time for the devices to settle */
0122     msleep(5);
0123 }
0124 
0125 static void vlynq_irq_unmask(struct irq_data *d)
0126 {
0127     struct vlynq_device *dev = irq_data_get_irq_chip_data(d);
0128     int virq;
0129     u32 val;
0130 
0131     BUG_ON(!dev);
0132     virq = d->irq - dev->irq_start;
0133     val = readl(&dev->remote->int_device[virq >> 2]);
0134     val |= (VINT_ENABLE | virq) << VINT_OFFSET(virq);
0135     writel(val, &dev->remote->int_device[virq >> 2]);
0136 }
0137 
0138 static void vlynq_irq_mask(struct irq_data *d)
0139 {
0140     struct vlynq_device *dev = irq_data_get_irq_chip_data(d);
0141     int virq;
0142     u32 val;
0143 
0144     BUG_ON(!dev);
0145     virq = d->irq - dev->irq_start;
0146     val = readl(&dev->remote->int_device[virq >> 2]);
0147     val &= ~(VINT_ENABLE << VINT_OFFSET(virq));
0148     writel(val, &dev->remote->int_device[virq >> 2]);
0149 }
0150 
0151 static int vlynq_irq_type(struct irq_data *d, unsigned int flow_type)
0152 {
0153     struct vlynq_device *dev = irq_data_get_irq_chip_data(d);
0154     int virq;
0155     u32 val;
0156 
0157     BUG_ON(!dev);
0158     virq = d->irq - dev->irq_start;
0159     val = readl(&dev->remote->int_device[virq >> 2]);
0160     switch (flow_type & IRQ_TYPE_SENSE_MASK) {
0161     case IRQ_TYPE_EDGE_RISING:
0162     case IRQ_TYPE_EDGE_FALLING:
0163     case IRQ_TYPE_EDGE_BOTH:
0164         val |= VINT_TYPE_EDGE << VINT_OFFSET(virq);
0165         val &= ~(VINT_LEVEL_LOW << VINT_OFFSET(virq));
0166         break;
0167     case IRQ_TYPE_LEVEL_HIGH:
0168         val &= ~(VINT_TYPE_EDGE << VINT_OFFSET(virq));
0169         val &= ~(VINT_LEVEL_LOW << VINT_OFFSET(virq));
0170         break;
0171     case IRQ_TYPE_LEVEL_LOW:
0172         val &= ~(VINT_TYPE_EDGE << VINT_OFFSET(virq));
0173         val |= VINT_LEVEL_LOW << VINT_OFFSET(virq);
0174         break;
0175     default:
0176         return -EINVAL;
0177     }
0178     writel(val, &dev->remote->int_device[virq >> 2]);
0179     return 0;
0180 }
0181 
0182 static void vlynq_local_ack(struct irq_data *d)
0183 {
0184     struct vlynq_device *dev = irq_data_get_irq_chip_data(d);
0185     u32 status = readl(&dev->local->status);
0186 
0187     pr_debug("%s: local status: 0x%08x\n",
0188                dev_name(&dev->dev), status);
0189     writel(status, &dev->local->status);
0190 }
0191 
0192 static void vlynq_remote_ack(struct irq_data *d)
0193 {
0194     struct vlynq_device *dev = irq_data_get_irq_chip_data(d);
0195     u32 status = readl(&dev->remote->status);
0196 
0197     pr_debug("%s: remote status: 0x%08x\n",
0198                dev_name(&dev->dev), status);
0199     writel(status, &dev->remote->status);
0200 }
0201 
0202 static irqreturn_t vlynq_irq(int irq, void *dev_id)
0203 {
0204     struct vlynq_device *dev = dev_id;
0205     u32 status;
0206     int virq = 0;
0207 
0208     status = readl(&dev->local->int_status);
0209     writel(status, &dev->local->int_status);
0210 
0211     if (unlikely(!status))
0212         spurious_interrupt();
0213 
0214     while (status) {
0215         if (status & 1)
0216             do_IRQ(dev->irq_start + virq);
0217         status >>= 1;
0218         virq++;
0219     }
0220 
0221     return IRQ_HANDLED;
0222 }
0223 
0224 static struct irq_chip vlynq_irq_chip = {
0225     .name = "vlynq",
0226     .irq_unmask = vlynq_irq_unmask,
0227     .irq_mask = vlynq_irq_mask,
0228     .irq_set_type = vlynq_irq_type,
0229 };
0230 
0231 static struct irq_chip vlynq_local_chip = {
0232     .name = "vlynq local error",
0233     .irq_unmask = vlynq_irq_unmask,
0234     .irq_mask = vlynq_irq_mask,
0235     .irq_ack = vlynq_local_ack,
0236 };
0237 
0238 static struct irq_chip vlynq_remote_chip = {
0239     .name = "vlynq local error",
0240     .irq_unmask = vlynq_irq_unmask,
0241     .irq_mask = vlynq_irq_mask,
0242     .irq_ack = vlynq_remote_ack,
0243 };
0244 
0245 static int vlynq_setup_irq(struct vlynq_device *dev)
0246 {
0247     u32 val;
0248     int i, virq;
0249 
0250     if (dev->local_irq == dev->remote_irq) {
0251         printk(KERN_ERR
0252                "%s: local vlynq irq should be different from remote\n",
0253                dev_name(&dev->dev));
0254         return -EINVAL;
0255     }
0256 
0257     /* Clear local and remote error bits */
0258     writel(readl(&dev->local->status), &dev->local->status);
0259     writel(readl(&dev->remote->status), &dev->remote->status);
0260 
0261     /* Now setup interrupts */
0262     val = VLYNQ_CTRL_INT_VECTOR(dev->local_irq);
0263     val |= VLYNQ_CTRL_INT_ENABLE | VLYNQ_CTRL_INT_LOCAL |
0264         VLYNQ_CTRL_INT2CFG;
0265     val |= readl(&dev->local->control);
0266     writel(VLYNQ_INT_OFFSET, &dev->local->int_ptr);
0267     writel(val, &dev->local->control);
0268 
0269     val = VLYNQ_CTRL_INT_VECTOR(dev->remote_irq);
0270     val |= VLYNQ_CTRL_INT_ENABLE;
0271     val |= readl(&dev->remote->control);
0272     writel(VLYNQ_INT_OFFSET, &dev->remote->int_ptr);
0273     writel(val, &dev->remote->int_ptr);
0274     writel(val, &dev->remote->control);
0275 
0276     for (i = dev->irq_start; i <= dev->irq_end; i++) {
0277         virq = i - dev->irq_start;
0278         if (virq == dev->local_irq) {
0279             irq_set_chip_and_handler(i, &vlynq_local_chip,
0280                          handle_level_irq);
0281             irq_set_chip_data(i, dev);
0282         } else if (virq == dev->remote_irq) {
0283             irq_set_chip_and_handler(i, &vlynq_remote_chip,
0284                          handle_level_irq);
0285             irq_set_chip_data(i, dev);
0286         } else {
0287             irq_set_chip_and_handler(i, &vlynq_irq_chip,
0288                          handle_simple_irq);
0289             irq_set_chip_data(i, dev);
0290             writel(0, &dev->remote->int_device[virq >> 2]);
0291         }
0292     }
0293 
0294     if (request_irq(dev->irq, vlynq_irq, IRQF_SHARED, "vlynq", dev)) {
0295         printk(KERN_ERR "%s: request_irq failed\n",
0296                     dev_name(&dev->dev));
0297         return -EAGAIN;
0298     }
0299 
0300     return 0;
0301 }
0302 
0303 static void vlynq_device_release(struct device *dev)
0304 {
0305     struct vlynq_device *vdev = to_vlynq_device(dev);
0306     kfree(vdev);
0307 }
0308 
0309 static int vlynq_device_match(struct device *dev,
0310                   struct device_driver *drv)
0311 {
0312     struct vlynq_device *vdev = to_vlynq_device(dev);
0313     struct vlynq_driver *vdrv = to_vlynq_driver(drv);
0314     struct vlynq_device_id *ids = vdrv->id_table;
0315 
0316     while (ids->id) {
0317         if (ids->id == vdev->dev_id) {
0318             vdev->divisor = ids->divisor;
0319             vlynq_set_drvdata(vdev, ids);
0320             printk(KERN_INFO "Driver found for VLYNQ "
0321                 "device: %08x\n", vdev->dev_id);
0322             return 1;
0323         }
0324         printk(KERN_DEBUG "Not using the %08x VLYNQ device's driver"
0325             " for VLYNQ device: %08x\n", ids->id, vdev->dev_id);
0326         ids++;
0327     }
0328     return 0;
0329 }
0330 
0331 static int vlynq_device_probe(struct device *dev)
0332 {
0333     struct vlynq_device *vdev = to_vlynq_device(dev);
0334     struct vlynq_driver *drv = to_vlynq_driver(dev->driver);
0335     struct vlynq_device_id *id = vlynq_get_drvdata(vdev);
0336     int result = -ENODEV;
0337 
0338     if (drv->probe)
0339         result = drv->probe(vdev, id);
0340     if (result)
0341         put_device(dev);
0342     return result;
0343 }
0344 
0345 static void vlynq_device_remove(struct device *dev)
0346 {
0347     struct vlynq_driver *drv = to_vlynq_driver(dev->driver);
0348 
0349     if (drv->remove)
0350         drv->remove(to_vlynq_device(dev));
0351 }
0352 
0353 int __vlynq_register_driver(struct vlynq_driver *driver, struct module *owner)
0354 {
0355     driver->driver.name = driver->name;
0356     driver->driver.bus = &vlynq_bus_type;
0357     return driver_register(&driver->driver);
0358 }
0359 EXPORT_SYMBOL(__vlynq_register_driver);
0360 
0361 void vlynq_unregister_driver(struct vlynq_driver *driver)
0362 {
0363     driver_unregister(&driver->driver);
0364 }
0365 EXPORT_SYMBOL(vlynq_unregister_driver);
0366 
0367 /*
0368  * A VLYNQ remote device can clock the VLYNQ bus master
0369  * using a dedicated clock line. In that case, both the
0370  * remove device and the bus master should have the same
0371  * serial clock dividers configured. Iterate through the
0372  * 8 possible dividers until we actually link with the
0373  * device.
0374  */
0375 static int __vlynq_try_remote(struct vlynq_device *dev)
0376 {
0377     int i;
0378 
0379     vlynq_reset(dev);
0380     for (i = dev->dev_id ? vlynq_rdiv2 : vlynq_rdiv8; dev->dev_id ?
0381             i <= vlynq_rdiv8 : i >= vlynq_rdiv2;
0382         dev->dev_id ? i++ : i--) {
0383 
0384         if (!vlynq_linked(dev))
0385             break;
0386 
0387         writel((readl(&dev->remote->control) &
0388                 ~VLYNQ_CTRL_CLOCK_MASK) |
0389                 VLYNQ_CTRL_CLOCK_INT |
0390                 VLYNQ_CTRL_CLOCK_DIV(i - vlynq_rdiv1),
0391                 &dev->remote->control);
0392         writel((readl(&dev->local->control)
0393                 & ~(VLYNQ_CTRL_CLOCK_INT |
0394                 VLYNQ_CTRL_CLOCK_MASK)) |
0395                 VLYNQ_CTRL_CLOCK_DIV(i - vlynq_rdiv1),
0396                 &dev->local->control);
0397 
0398         if (vlynq_linked(dev)) {
0399             printk(KERN_DEBUG
0400                 "%s: using remote clock divisor %d\n",
0401                 dev_name(&dev->dev), i - vlynq_rdiv1 + 1);
0402             dev->divisor = i;
0403             return 0;
0404         } else {
0405             vlynq_reset(dev);
0406         }
0407     }
0408 
0409     return -ENODEV;
0410 }
0411 
0412 /*
0413  * A VLYNQ remote device can be clocked by the VLYNQ bus
0414  * master using a dedicated clock line. In that case, only
0415  * the bus master configures the serial clock divider.
0416  * Iterate through the 8 possible dividers until we
0417  * actually get a link with the device.
0418  */
0419 static int __vlynq_try_local(struct vlynq_device *dev)
0420 {
0421     int i;
0422 
0423     vlynq_reset(dev);
0424 
0425     for (i = dev->dev_id ? vlynq_ldiv2 : vlynq_ldiv8; dev->dev_id ?
0426             i <= vlynq_ldiv8 : i >= vlynq_ldiv2;
0427         dev->dev_id ? i++ : i--) {
0428 
0429         writel((readl(&dev->local->control) &
0430                 ~VLYNQ_CTRL_CLOCK_MASK) |
0431                 VLYNQ_CTRL_CLOCK_INT |
0432                 VLYNQ_CTRL_CLOCK_DIV(i - vlynq_ldiv1),
0433                 &dev->local->control);
0434 
0435         if (vlynq_linked(dev)) {
0436             printk(KERN_DEBUG
0437                 "%s: using local clock divisor %d\n",
0438                 dev_name(&dev->dev), i - vlynq_ldiv1 + 1);
0439             dev->divisor = i;
0440             return 0;
0441         } else {
0442             vlynq_reset(dev);
0443         }
0444     }
0445 
0446     return -ENODEV;
0447 }
0448 
0449 /*
0450  * When using external clocking method, serial clock
0451  * is supplied by an external oscillator, therefore we
0452  * should mask the local clock bit in the clock control
0453  * register for both the bus master and the remote device.
0454  */
0455 static int __vlynq_try_external(struct vlynq_device *dev)
0456 {
0457     vlynq_reset(dev);
0458     if (!vlynq_linked(dev))
0459         return -ENODEV;
0460 
0461     writel((readl(&dev->remote->control) &
0462             ~VLYNQ_CTRL_CLOCK_INT),
0463             &dev->remote->control);
0464 
0465     writel((readl(&dev->local->control) &
0466             ~VLYNQ_CTRL_CLOCK_INT),
0467             &dev->local->control);
0468 
0469     if (vlynq_linked(dev)) {
0470         printk(KERN_DEBUG "%s: using external clock\n",
0471             dev_name(&dev->dev));
0472             dev->divisor = vlynq_div_external;
0473         return 0;
0474     }
0475 
0476     return -ENODEV;
0477 }
0478 
0479 static int __vlynq_enable_device(struct vlynq_device *dev)
0480 {
0481     int result;
0482     struct plat_vlynq_ops *ops = dev->dev.platform_data;
0483 
0484     result = ops->on(dev);
0485     if (result)
0486         return result;
0487 
0488     switch (dev->divisor) {
0489     case vlynq_div_external:
0490     case vlynq_div_auto:
0491         /* When the device is brought from reset it should have clock
0492          * generation negotiated by hardware.
0493          * Check which device is generating clocks and perform setup
0494          * accordingly */
0495         if (vlynq_linked(dev) && readl(&dev->remote->control) &
0496            VLYNQ_CTRL_CLOCK_INT) {
0497             if (!__vlynq_try_remote(dev) ||
0498                 !__vlynq_try_local(dev)  ||
0499                 !__vlynq_try_external(dev))
0500                 return 0;
0501         } else {
0502             if (!__vlynq_try_external(dev) ||
0503                 !__vlynq_try_local(dev)    ||
0504                 !__vlynq_try_remote(dev))
0505                 return 0;
0506         }
0507         break;
0508     case vlynq_ldiv1:
0509     case vlynq_ldiv2:
0510     case vlynq_ldiv3:
0511     case vlynq_ldiv4:
0512     case vlynq_ldiv5:
0513     case vlynq_ldiv6:
0514     case vlynq_ldiv7:
0515     case vlynq_ldiv8:
0516         writel(VLYNQ_CTRL_CLOCK_INT |
0517             VLYNQ_CTRL_CLOCK_DIV(dev->divisor -
0518             vlynq_ldiv1), &dev->local->control);
0519         writel(0, &dev->remote->control);
0520         if (vlynq_linked(dev)) {
0521             printk(KERN_DEBUG
0522                 "%s: using local clock divisor %d\n",
0523                 dev_name(&dev->dev),
0524                 dev->divisor - vlynq_ldiv1 + 1);
0525             return 0;
0526         }
0527         break;
0528     case vlynq_rdiv1:
0529     case vlynq_rdiv2:
0530     case vlynq_rdiv3:
0531     case vlynq_rdiv4:
0532     case vlynq_rdiv5:
0533     case vlynq_rdiv6:
0534     case vlynq_rdiv7:
0535     case vlynq_rdiv8:
0536         writel(0, &dev->local->control);
0537         writel(VLYNQ_CTRL_CLOCK_INT |
0538             VLYNQ_CTRL_CLOCK_DIV(dev->divisor -
0539             vlynq_rdiv1), &dev->remote->control);
0540         if (vlynq_linked(dev)) {
0541             printk(KERN_DEBUG
0542                 "%s: using remote clock divisor %d\n",
0543                 dev_name(&dev->dev),
0544                 dev->divisor - vlynq_rdiv1 + 1);
0545             return 0;
0546         }
0547         break;
0548     }
0549 
0550     ops->off(dev);
0551     return -ENODEV;
0552 }
0553 
0554 int vlynq_enable_device(struct vlynq_device *dev)
0555 {
0556     struct plat_vlynq_ops *ops = dev->dev.platform_data;
0557     int result = -ENODEV;
0558 
0559     result = __vlynq_enable_device(dev);
0560     if (result)
0561         return result;
0562 
0563     result = vlynq_setup_irq(dev);
0564     if (result)
0565         ops->off(dev);
0566 
0567     dev->enabled = !result;
0568     return result;
0569 }
0570 EXPORT_SYMBOL(vlynq_enable_device);
0571 
0572 
0573 void vlynq_disable_device(struct vlynq_device *dev)
0574 {
0575     struct plat_vlynq_ops *ops = dev->dev.platform_data;
0576 
0577     dev->enabled = 0;
0578     free_irq(dev->irq, dev);
0579     ops->off(dev);
0580 }
0581 EXPORT_SYMBOL(vlynq_disable_device);
0582 
0583 int vlynq_set_local_mapping(struct vlynq_device *dev, u32 tx_offset,
0584                 struct vlynq_mapping *mapping)
0585 {
0586     int i;
0587 
0588     if (!dev->enabled)
0589         return -ENXIO;
0590 
0591     writel(tx_offset, &dev->local->tx_offset);
0592     for (i = 0; i < 4; i++) {
0593         writel(mapping[i].offset, &dev->local->rx_mapping[i].offset);
0594         writel(mapping[i].size, &dev->local->rx_mapping[i].size);
0595     }
0596     return 0;
0597 }
0598 EXPORT_SYMBOL(vlynq_set_local_mapping);
0599 
0600 int vlynq_set_remote_mapping(struct vlynq_device *dev, u32 tx_offset,
0601                  struct vlynq_mapping *mapping)
0602 {
0603     int i;
0604 
0605     if (!dev->enabled)
0606         return -ENXIO;
0607 
0608     writel(tx_offset, &dev->remote->tx_offset);
0609     for (i = 0; i < 4; i++) {
0610         writel(mapping[i].offset, &dev->remote->rx_mapping[i].offset);
0611         writel(mapping[i].size, &dev->remote->rx_mapping[i].size);
0612     }
0613     return 0;
0614 }
0615 EXPORT_SYMBOL(vlynq_set_remote_mapping);
0616 
0617 int vlynq_set_local_irq(struct vlynq_device *dev, int virq)
0618 {
0619     int irq = dev->irq_start + virq;
0620     if (dev->enabled)
0621         return -EBUSY;
0622 
0623     if ((irq < dev->irq_start) || (irq > dev->irq_end))
0624         return -EINVAL;
0625 
0626     if (virq == dev->remote_irq)
0627         return -EINVAL;
0628 
0629     dev->local_irq = virq;
0630 
0631     return 0;
0632 }
0633 EXPORT_SYMBOL(vlynq_set_local_irq);
0634 
0635 int vlynq_set_remote_irq(struct vlynq_device *dev, int virq)
0636 {
0637     int irq = dev->irq_start + virq;
0638     if (dev->enabled)
0639         return -EBUSY;
0640 
0641     if ((irq < dev->irq_start) || (irq > dev->irq_end))
0642         return -EINVAL;
0643 
0644     if (virq == dev->local_irq)
0645         return -EINVAL;
0646 
0647     dev->remote_irq = virq;
0648 
0649     return 0;
0650 }
0651 EXPORT_SYMBOL(vlynq_set_remote_irq);
0652 
0653 static int vlynq_probe(struct platform_device *pdev)
0654 {
0655     struct vlynq_device *dev;
0656     struct resource *regs_res, *mem_res, *irq_res;
0657     int len, result;
0658 
0659     regs_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
0660     if (!regs_res)
0661         return -ENODEV;
0662 
0663     mem_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mem");
0664     if (!mem_res)
0665         return -ENODEV;
0666 
0667     irq_res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "devirq");
0668     if (!irq_res)
0669         return -ENODEV;
0670 
0671     dev = kzalloc(sizeof(*dev), GFP_KERNEL);
0672     if (!dev) {
0673         printk(KERN_ERR
0674                "vlynq: failed to allocate device structure\n");
0675         return -ENOMEM;
0676     }
0677 
0678     dev->id = pdev->id;
0679     dev->dev.bus = &vlynq_bus_type;
0680     dev->dev.parent = &pdev->dev;
0681     dev_set_name(&dev->dev, "vlynq%d", dev->id);
0682     dev->dev.platform_data = pdev->dev.platform_data;
0683     dev->dev.release = vlynq_device_release;
0684 
0685     dev->regs_start = regs_res->start;
0686     dev->regs_end = regs_res->end;
0687     dev->mem_start = mem_res->start;
0688     dev->mem_end = mem_res->end;
0689 
0690     len = resource_size(regs_res);
0691     if (!request_mem_region(regs_res->start, len, dev_name(&dev->dev))) {
0692         printk(KERN_ERR "%s: Can't request vlynq registers\n",
0693                dev_name(&dev->dev));
0694         result = -ENXIO;
0695         goto fail_request;
0696     }
0697 
0698     dev->local = ioremap(regs_res->start, len);
0699     if (!dev->local) {
0700         printk(KERN_ERR "%s: Can't remap vlynq registers\n",
0701                dev_name(&dev->dev));
0702         result = -ENXIO;
0703         goto fail_remap;
0704     }
0705 
0706     dev->remote = (struct vlynq_regs *)((void *)dev->local +
0707                         VLYNQ_REMOTE_OFFSET);
0708 
0709     dev->irq = platform_get_irq_byname(pdev, "irq");
0710     dev->irq_start = irq_res->start;
0711     dev->irq_end = irq_res->end;
0712     dev->local_irq = dev->irq_end - dev->irq_start;
0713     dev->remote_irq = dev->local_irq - 1;
0714 
0715     if (device_register(&dev->dev))
0716         goto fail_register;
0717     platform_set_drvdata(pdev, dev);
0718 
0719     printk(KERN_INFO "%s: regs 0x%p, irq %d, mem 0x%p\n",
0720            dev_name(&dev->dev), (void *)dev->regs_start, dev->irq,
0721            (void *)dev->mem_start);
0722 
0723     dev->dev_id = 0;
0724     dev->divisor = vlynq_div_auto;
0725     result = __vlynq_enable_device(dev);
0726     if (result == 0) {
0727         dev->dev_id = readl(&dev->remote->chip);
0728         ((struct plat_vlynq_ops *)(dev->dev.platform_data))->off(dev);
0729     }
0730     if (dev->dev_id)
0731         printk(KERN_INFO "Found a VLYNQ device: %08x\n", dev->dev_id);
0732 
0733     return 0;
0734 
0735 fail_register:
0736     iounmap(dev->local);
0737 fail_remap:
0738 fail_request:
0739     release_mem_region(regs_res->start, len);
0740     kfree(dev);
0741     return result;
0742 }
0743 
0744 static int vlynq_remove(struct platform_device *pdev)
0745 {
0746     struct vlynq_device *dev = platform_get_drvdata(pdev);
0747 
0748     device_unregister(&dev->dev);
0749     iounmap(dev->local);
0750     release_mem_region(dev->regs_start,
0751                dev->regs_end - dev->regs_start + 1);
0752 
0753     kfree(dev);
0754 
0755     return 0;
0756 }
0757 
0758 static struct platform_driver vlynq_platform_driver = {
0759     .driver.name = "vlynq",
0760     .probe = vlynq_probe,
0761     .remove = vlynq_remove,
0762 };
0763 
0764 struct bus_type vlynq_bus_type = {
0765     .name = "vlynq",
0766     .match = vlynq_device_match,
0767     .probe = vlynq_device_probe,
0768     .remove = vlynq_device_remove,
0769 };
0770 EXPORT_SYMBOL(vlynq_bus_type);
0771 
0772 static int vlynq_init(void)
0773 {
0774     int res = 0;
0775 
0776     res = bus_register(&vlynq_bus_type);
0777     if (res)
0778         goto fail_bus;
0779 
0780     res = platform_driver_register(&vlynq_platform_driver);
0781     if (res)
0782         goto fail_platform;
0783 
0784     return 0;
0785 
0786 fail_platform:
0787     bus_unregister(&vlynq_bus_type);
0788 fail_bus:
0789     return res;
0790 }
0791 
0792 static void vlynq_exit(void)
0793 {
0794     platform_driver_unregister(&vlynq_platform_driver);
0795     bus_unregister(&vlynq_bus_type);
0796 }
0797 
0798 module_init(vlynq_init);
0799 module_exit(vlynq_exit);