0001
0002
0003
0004
0005
0006
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
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
0115 msleep(5);
0116
0117
0118 writel(readl(&dev->local->control) & ~VLYNQ_CTRL_RESET,
0119 &dev->local->control);
0120
0121
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
0258 writel(readl(&dev->local->status), &dev->local->status);
0259 writel(readl(&dev->remote->status), &dev->remote->status);
0260
0261
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
0369
0370
0371
0372
0373
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
0414
0415
0416
0417
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
0451
0452
0453
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
0492
0493
0494
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);