1/* 2 * Copyright (C) 2006, 2007 Eugene Konev <ejka@openwrt.org> 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 17 * 18 * Parts of the VLYNQ specification can be found here: 19 * http://www.ti.com/litv/pdf/sprue36a 20 */ 21 22#include <linux/init.h> 23#include <linux/types.h> 24#include <linux/kernel.h> 25#include <linux/string.h> 26#include <linux/device.h> 27#include <linux/module.h> 28#include <linux/errno.h> 29#include <linux/platform_device.h> 30#include <linux/interrupt.h> 31#include <linux/delay.h> 32#include <linux/io.h> 33#include <linux/slab.h> 34#include <linux/irq.h> 35 36#include <linux/vlynq.h> 37 38#define VLYNQ_CTRL_PM_ENABLE 0x80000000 39#define VLYNQ_CTRL_CLOCK_INT 0x00008000 40#define VLYNQ_CTRL_CLOCK_DIV(x) (((x) & 7) << 16) 41#define VLYNQ_CTRL_INT_LOCAL 0x00004000 42#define VLYNQ_CTRL_INT_ENABLE 0x00002000 43#define VLYNQ_CTRL_INT_VECTOR(x) (((x) & 0x1f) << 8) 44#define VLYNQ_CTRL_INT2CFG 0x00000080 45#define VLYNQ_CTRL_RESET 0x00000001 46 47#define VLYNQ_CTRL_CLOCK_MASK (0x7 << 16) 48 49#define VLYNQ_INT_OFFSET 0x00000014 50#define VLYNQ_REMOTE_OFFSET 0x00000080 51 52#define VLYNQ_STATUS_LINK 0x00000001 53#define VLYNQ_STATUS_LERROR 0x00000080 54#define VLYNQ_STATUS_RERROR 0x00000100 55 56#define VINT_ENABLE 0x00000100 57#define VINT_TYPE_EDGE 0x00000080 58#define VINT_LEVEL_LOW 0x00000040 59#define VINT_VECTOR(x) ((x) & 0x1f) 60#define VINT_OFFSET(irq) (8 * ((irq) % 4)) 61 62#define VLYNQ_AUTONEGO_V2 0x00010000 63 64struct vlynq_regs { 65 u32 revision; 66 u32 control; 67 u32 status; 68 u32 int_prio; 69 u32 int_status; 70 u32 int_pending; 71 u32 int_ptr; 72 u32 tx_offset; 73 struct vlynq_mapping rx_mapping[4]; 74 u32 chip; 75 u32 autonego; 76 u32 unused[6]; 77 u32 int_device[8]; 78}; 79 80#ifdef CONFIG_VLYNQ_DEBUG 81static void vlynq_dump_regs(struct vlynq_device *dev) 82{ 83 int i; 84 85 printk(KERN_DEBUG "VLYNQ local=%p remote=%p\n", 86 dev->local, dev->remote); 87 for (i = 0; i < 32; i++) { 88 printk(KERN_DEBUG "VLYNQ: local %d: %08x\n", 89 i + 1, ((u32 *)dev->local)[i]); 90 printk(KERN_DEBUG "VLYNQ: remote %d: %08x\n", 91 i + 1, ((u32 *)dev->remote)[i]); 92 } 93} 94 95static void vlynq_dump_mem(u32 *base, int count) 96{ 97 int i; 98 99 for (i = 0; i < (count + 3) / 4; i++) { 100 if (i % 4 == 0) 101 printk(KERN_DEBUG "\nMEM[0x%04x]:", i * 4); 102 printk(KERN_DEBUG " 0x%08x", *(base + i)); 103 } 104 printk(KERN_DEBUG "\n"); 105} 106#endif 107 108/* Check the VLYNQ link status with a given device */ 109static int vlynq_linked(struct vlynq_device *dev) 110{ 111 int i; 112 113 for (i = 0; i < 100; i++) 114 if (readl(&dev->local->status) & VLYNQ_STATUS_LINK) 115 return 1; 116 else 117 cpu_relax(); 118 119 return 0; 120} 121 122static void vlynq_reset(struct vlynq_device *dev) 123{ 124 writel(readl(&dev->local->control) | VLYNQ_CTRL_RESET, 125 &dev->local->control); 126 127 /* Wait for the devices to finish resetting */ 128 msleep(5); 129 130 /* Remove reset bit */ 131 writel(readl(&dev->local->control) & ~VLYNQ_CTRL_RESET, 132 &dev->local->control); 133 134 /* Give some time for the devices to settle */ 135 msleep(5); 136} 137 138static void vlynq_irq_unmask(struct irq_data *d) 139{ 140 struct vlynq_device *dev = irq_data_get_irq_chip_data(d); 141 int virq; 142 u32 val; 143 144 BUG_ON(!dev); 145 virq = d->irq - dev->irq_start; 146 val = readl(&dev->remote->int_device[virq >> 2]); 147 val |= (VINT_ENABLE | virq) << VINT_OFFSET(virq); 148 writel(val, &dev->remote->int_device[virq >> 2]); 149} 150 151static void vlynq_irq_mask(struct irq_data *d) 152{ 153 struct vlynq_device *dev = irq_data_get_irq_chip_data(d); 154 int virq; 155 u32 val; 156 157 BUG_ON(!dev); 158 virq = d->irq - dev->irq_start; 159 val = readl(&dev->remote->int_device[virq >> 2]); 160 val &= ~(VINT_ENABLE << VINT_OFFSET(virq)); 161 writel(val, &dev->remote->int_device[virq >> 2]); 162} 163 164static int vlynq_irq_type(struct irq_data *d, unsigned int flow_type) 165{ 166 struct vlynq_device *dev = irq_data_get_irq_chip_data(d); 167 int virq; 168 u32 val; 169 170 BUG_ON(!dev); 171 virq = d->irq - dev->irq_start; 172 val = readl(&dev->remote->int_device[virq >> 2]); 173 switch (flow_type & IRQ_TYPE_SENSE_MASK) { 174 case IRQ_TYPE_EDGE_RISING: 175 case IRQ_TYPE_EDGE_FALLING: 176 case IRQ_TYPE_EDGE_BOTH: 177 val |= VINT_TYPE_EDGE << VINT_OFFSET(virq); 178 val &= ~(VINT_LEVEL_LOW << VINT_OFFSET(virq)); 179 break; 180 case IRQ_TYPE_LEVEL_HIGH: 181 val &= ~(VINT_TYPE_EDGE << VINT_OFFSET(virq)); 182 val &= ~(VINT_LEVEL_LOW << VINT_OFFSET(virq)); 183 break; 184 case IRQ_TYPE_LEVEL_LOW: 185 val &= ~(VINT_TYPE_EDGE << VINT_OFFSET(virq)); 186 val |= VINT_LEVEL_LOW << VINT_OFFSET(virq); 187 break; 188 default: 189 return -EINVAL; 190 } 191 writel(val, &dev->remote->int_device[virq >> 2]); 192 return 0; 193} 194 195static void vlynq_local_ack(struct irq_data *d) 196{ 197 struct vlynq_device *dev = irq_data_get_irq_chip_data(d); 198 u32 status = readl(&dev->local->status); 199 200 pr_debug("%s: local status: 0x%08x\n", 201 dev_name(&dev->dev), status); 202 writel(status, &dev->local->status); 203} 204 205static void vlynq_remote_ack(struct irq_data *d) 206{ 207 struct vlynq_device *dev = irq_data_get_irq_chip_data(d); 208 u32 status = readl(&dev->remote->status); 209 210 pr_debug("%s: remote status: 0x%08x\n", 211 dev_name(&dev->dev), status); 212 writel(status, &dev->remote->status); 213} 214 215static irqreturn_t vlynq_irq(int irq, void *dev_id) 216{ 217 struct vlynq_device *dev = dev_id; 218 u32 status; 219 int virq = 0; 220 221 status = readl(&dev->local->int_status); 222 writel(status, &dev->local->int_status); 223 224 if (unlikely(!status)) 225 spurious_interrupt(); 226 227 while (status) { 228 if (status & 1) 229 do_IRQ(dev->irq_start + virq); 230 status >>= 1; 231 virq++; 232 } 233 234 return IRQ_HANDLED; 235} 236 237static struct irq_chip vlynq_irq_chip = { 238 .name = "vlynq", 239 .irq_unmask = vlynq_irq_unmask, 240 .irq_mask = vlynq_irq_mask, 241 .irq_set_type = vlynq_irq_type, 242}; 243 244static struct irq_chip vlynq_local_chip = { 245 .name = "vlynq local error", 246 .irq_unmask = vlynq_irq_unmask, 247 .irq_mask = vlynq_irq_mask, 248 .irq_ack = vlynq_local_ack, 249}; 250 251static struct irq_chip vlynq_remote_chip = { 252 .name = "vlynq local error", 253 .irq_unmask = vlynq_irq_unmask, 254 .irq_mask = vlynq_irq_mask, 255 .irq_ack = vlynq_remote_ack, 256}; 257 258static int vlynq_setup_irq(struct vlynq_device *dev) 259{ 260 u32 val; 261 int i, virq; 262 263 if (dev->local_irq == dev->remote_irq) { 264 printk(KERN_ERR 265 "%s: local vlynq irq should be different from remote\n", 266 dev_name(&dev->dev)); 267 return -EINVAL; 268 } 269 270 /* Clear local and remote error bits */ 271 writel(readl(&dev->local->status), &dev->local->status); 272 writel(readl(&dev->remote->status), &dev->remote->status); 273 274 /* Now setup interrupts */ 275 val = VLYNQ_CTRL_INT_VECTOR(dev->local_irq); 276 val |= VLYNQ_CTRL_INT_ENABLE | VLYNQ_CTRL_INT_LOCAL | 277 VLYNQ_CTRL_INT2CFG; 278 val |= readl(&dev->local->control); 279 writel(VLYNQ_INT_OFFSET, &dev->local->int_ptr); 280 writel(val, &dev->local->control); 281 282 val = VLYNQ_CTRL_INT_VECTOR(dev->remote_irq); 283 val |= VLYNQ_CTRL_INT_ENABLE; 284 val |= readl(&dev->remote->control); 285 writel(VLYNQ_INT_OFFSET, &dev->remote->int_ptr); 286 writel(val, &dev->remote->int_ptr); 287 writel(val, &dev->remote->control); 288 289 for (i = dev->irq_start; i <= dev->irq_end; i++) { 290 virq = i - dev->irq_start; 291 if (virq == dev->local_irq) { 292 irq_set_chip_and_handler(i, &vlynq_local_chip, 293 handle_level_irq); 294 irq_set_chip_data(i, dev); 295 } else if (virq == dev->remote_irq) { 296 irq_set_chip_and_handler(i, &vlynq_remote_chip, 297 handle_level_irq); 298 irq_set_chip_data(i, dev); 299 } else { 300 irq_set_chip_and_handler(i, &vlynq_irq_chip, 301 handle_simple_irq); 302 irq_set_chip_data(i, dev); 303 writel(0, &dev->remote->int_device[virq >> 2]); 304 } 305 } 306 307 if (request_irq(dev->irq, vlynq_irq, IRQF_SHARED, "vlynq", dev)) { 308 printk(KERN_ERR "%s: request_irq failed\n", 309 dev_name(&dev->dev)); 310 return -EAGAIN; 311 } 312 313 return 0; 314} 315 316static void vlynq_device_release(struct device *dev) 317{ 318 struct vlynq_device *vdev = to_vlynq_device(dev); 319 kfree(vdev); 320} 321 322static int vlynq_device_match(struct device *dev, 323 struct device_driver *drv) 324{ 325 struct vlynq_device *vdev = to_vlynq_device(dev); 326 struct vlynq_driver *vdrv = to_vlynq_driver(drv); 327 struct vlynq_device_id *ids = vdrv->id_table; 328 329 while (ids->id) { 330 if (ids->id == vdev->dev_id) { 331 vdev->divisor = ids->divisor; 332 vlynq_set_drvdata(vdev, ids); 333 printk(KERN_INFO "Driver found for VLYNQ " 334 "device: %08x\n", vdev->dev_id); 335 return 1; 336 } 337 printk(KERN_DEBUG "Not using the %08x VLYNQ device's driver" 338 " for VLYNQ device: %08x\n", ids->id, vdev->dev_id); 339 ids++; 340 } 341 return 0; 342} 343 344static int vlynq_device_probe(struct device *dev) 345{ 346 struct vlynq_device *vdev = to_vlynq_device(dev); 347 struct vlynq_driver *drv = to_vlynq_driver(dev->driver); 348 struct vlynq_device_id *id = vlynq_get_drvdata(vdev); 349 int result = -ENODEV; 350 351 if (drv->probe) 352 result = drv->probe(vdev, id); 353 if (result) 354 put_device(dev); 355 return result; 356} 357 358static int vlynq_device_remove(struct device *dev) 359{ 360 struct vlynq_driver *drv = to_vlynq_driver(dev->driver); 361 362 if (drv->remove) 363 drv->remove(to_vlynq_device(dev)); 364 365 return 0; 366} 367 368int __vlynq_register_driver(struct vlynq_driver *driver, struct module *owner) 369{ 370 driver->driver.name = driver->name; 371 driver->driver.bus = &vlynq_bus_type; 372 return driver_register(&driver->driver); 373} 374EXPORT_SYMBOL(__vlynq_register_driver); 375 376void vlynq_unregister_driver(struct vlynq_driver *driver) 377{ 378 driver_unregister(&driver->driver); 379} 380EXPORT_SYMBOL(vlynq_unregister_driver); 381 382/* 383 * A VLYNQ remote device can clock the VLYNQ bus master 384 * using a dedicated clock line. In that case, both the 385 * remove device and the bus master should have the same 386 * serial clock dividers configured. Iterate through the 387 * 8 possible dividers until we actually link with the 388 * device. 389 */ 390static int __vlynq_try_remote(struct vlynq_device *dev) 391{ 392 int i; 393 394 vlynq_reset(dev); 395 for (i = dev->dev_id ? vlynq_rdiv2 : vlynq_rdiv8; dev->dev_id ? 396 i <= vlynq_rdiv8 : i >= vlynq_rdiv2; 397 dev->dev_id ? i++ : i--) { 398 399 if (!vlynq_linked(dev)) 400 break; 401 402 writel((readl(&dev->remote->control) & 403 ~VLYNQ_CTRL_CLOCK_MASK) | 404 VLYNQ_CTRL_CLOCK_INT | 405 VLYNQ_CTRL_CLOCK_DIV(i - vlynq_rdiv1), 406 &dev->remote->control); 407 writel((readl(&dev->local->control) 408 & ~(VLYNQ_CTRL_CLOCK_INT | 409 VLYNQ_CTRL_CLOCK_MASK)) | 410 VLYNQ_CTRL_CLOCK_DIV(i - vlynq_rdiv1), 411 &dev->local->control); 412 413 if (vlynq_linked(dev)) { 414 printk(KERN_DEBUG 415 "%s: using remote clock divisor %d\n", 416 dev_name(&dev->dev), i - vlynq_rdiv1 + 1); 417 dev->divisor = i; 418 return 0; 419 } else { 420 vlynq_reset(dev); 421 } 422 } 423 424 return -ENODEV; 425} 426 427/* 428 * A VLYNQ remote device can be clocked by the VLYNQ bus 429 * master using a dedicated clock line. In that case, only 430 * the bus master configures the serial clock divider. 431 * Iterate through the 8 possible dividers until we 432 * actually get a link with the device. 433 */ 434static int __vlynq_try_local(struct vlynq_device *dev) 435{ 436 int i; 437 438 vlynq_reset(dev); 439 440 for (i = dev->dev_id ? vlynq_ldiv2 : vlynq_ldiv8; dev->dev_id ? 441 i <= vlynq_ldiv8 : i >= vlynq_ldiv2; 442 dev->dev_id ? i++ : i--) { 443 444 writel((readl(&dev->local->control) & 445 ~VLYNQ_CTRL_CLOCK_MASK) | 446 VLYNQ_CTRL_CLOCK_INT | 447 VLYNQ_CTRL_CLOCK_DIV(i - vlynq_ldiv1), 448 &dev->local->control); 449 450 if (vlynq_linked(dev)) { 451 printk(KERN_DEBUG 452 "%s: using local clock divisor %d\n", 453 dev_name(&dev->dev), i - vlynq_ldiv1 + 1); 454 dev->divisor = i; 455 return 0; 456 } else { 457 vlynq_reset(dev); 458 } 459 } 460 461 return -ENODEV; 462} 463 464/* 465 * When using external clocking method, serial clock 466 * is supplied by an external oscillator, therefore we 467 * should mask the local clock bit in the clock control 468 * register for both the bus master and the remote device. 469 */ 470static int __vlynq_try_external(struct vlynq_device *dev) 471{ 472 vlynq_reset(dev); 473 if (!vlynq_linked(dev)) 474 return -ENODEV; 475 476 writel((readl(&dev->remote->control) & 477 ~VLYNQ_CTRL_CLOCK_INT), 478 &dev->remote->control); 479 480 writel((readl(&dev->local->control) & 481 ~VLYNQ_CTRL_CLOCK_INT), 482 &dev->local->control); 483 484 if (vlynq_linked(dev)) { 485 printk(KERN_DEBUG "%s: using external clock\n", 486 dev_name(&dev->dev)); 487 dev->divisor = vlynq_div_external; 488 return 0; 489 } 490 491 return -ENODEV; 492} 493 494static int __vlynq_enable_device(struct vlynq_device *dev) 495{ 496 int result; 497 struct plat_vlynq_ops *ops = dev->dev.platform_data; 498 499 result = ops->on(dev); 500 if (result) 501 return result; 502 503 switch (dev->divisor) { 504 case vlynq_div_external: 505 case vlynq_div_auto: 506 /* When the device is brought from reset it should have clock 507 * generation negotiated by hardware. 508 * Check which device is generating clocks and perform setup 509 * accordingly */ 510 if (vlynq_linked(dev) && readl(&dev->remote->control) & 511 VLYNQ_CTRL_CLOCK_INT) { 512 if (!__vlynq_try_remote(dev) || 513 !__vlynq_try_local(dev) || 514 !__vlynq_try_external(dev)) 515 return 0; 516 } else { 517 if (!__vlynq_try_external(dev) || 518 !__vlynq_try_local(dev) || 519 !__vlynq_try_remote(dev)) 520 return 0; 521 } 522 break; 523 case vlynq_ldiv1: 524 case vlynq_ldiv2: 525 case vlynq_ldiv3: 526 case vlynq_ldiv4: 527 case vlynq_ldiv5: 528 case vlynq_ldiv6: 529 case vlynq_ldiv7: 530 case vlynq_ldiv8: 531 writel(VLYNQ_CTRL_CLOCK_INT | 532 VLYNQ_CTRL_CLOCK_DIV(dev->divisor - 533 vlynq_ldiv1), &dev->local->control); 534 writel(0, &dev->remote->control); 535 if (vlynq_linked(dev)) { 536 printk(KERN_DEBUG 537 "%s: using local clock divisor %d\n", 538 dev_name(&dev->dev), 539 dev->divisor - vlynq_ldiv1 + 1); 540 return 0; 541 } 542 break; 543 case vlynq_rdiv1: 544 case vlynq_rdiv2: 545 case vlynq_rdiv3: 546 case vlynq_rdiv4: 547 case vlynq_rdiv5: 548 case vlynq_rdiv6: 549 case vlynq_rdiv7: 550 case vlynq_rdiv8: 551 writel(0, &dev->local->control); 552 writel(VLYNQ_CTRL_CLOCK_INT | 553 VLYNQ_CTRL_CLOCK_DIV(dev->divisor - 554 vlynq_rdiv1), &dev->remote->control); 555 if (vlynq_linked(dev)) { 556 printk(KERN_DEBUG 557 "%s: using remote clock divisor %d\n", 558 dev_name(&dev->dev), 559 dev->divisor - vlynq_rdiv1 + 1); 560 return 0; 561 } 562 break; 563 } 564 565 ops->off(dev); 566 return -ENODEV; 567} 568 569int vlynq_enable_device(struct vlynq_device *dev) 570{ 571 struct plat_vlynq_ops *ops = dev->dev.platform_data; 572 int result = -ENODEV; 573 574 result = __vlynq_enable_device(dev); 575 if (result) 576 return result; 577 578 result = vlynq_setup_irq(dev); 579 if (result) 580 ops->off(dev); 581 582 dev->enabled = !result; 583 return result; 584} 585EXPORT_SYMBOL(vlynq_enable_device); 586 587 588void vlynq_disable_device(struct vlynq_device *dev) 589{ 590 struct plat_vlynq_ops *ops = dev->dev.platform_data; 591 592 dev->enabled = 0; 593 free_irq(dev->irq, dev); 594 ops->off(dev); 595} 596EXPORT_SYMBOL(vlynq_disable_device); 597 598int vlynq_set_local_mapping(struct vlynq_device *dev, u32 tx_offset, 599 struct vlynq_mapping *mapping) 600{ 601 int i; 602 603 if (!dev->enabled) 604 return -ENXIO; 605 606 writel(tx_offset, &dev->local->tx_offset); 607 for (i = 0; i < 4; i++) { 608 writel(mapping[i].offset, &dev->local->rx_mapping[i].offset); 609 writel(mapping[i].size, &dev->local->rx_mapping[i].size); 610 } 611 return 0; 612} 613EXPORT_SYMBOL(vlynq_set_local_mapping); 614 615int vlynq_set_remote_mapping(struct vlynq_device *dev, u32 tx_offset, 616 struct vlynq_mapping *mapping) 617{ 618 int i; 619 620 if (!dev->enabled) 621 return -ENXIO; 622 623 writel(tx_offset, &dev->remote->tx_offset); 624 for (i = 0; i < 4; i++) { 625 writel(mapping[i].offset, &dev->remote->rx_mapping[i].offset); 626 writel(mapping[i].size, &dev->remote->rx_mapping[i].size); 627 } 628 return 0; 629} 630EXPORT_SYMBOL(vlynq_set_remote_mapping); 631 632int vlynq_set_local_irq(struct vlynq_device *dev, int virq) 633{ 634 int irq = dev->irq_start + virq; 635 if (dev->enabled) 636 return -EBUSY; 637 638 if ((irq < dev->irq_start) || (irq > dev->irq_end)) 639 return -EINVAL; 640 641 if (virq == dev->remote_irq) 642 return -EINVAL; 643 644 dev->local_irq = virq; 645 646 return 0; 647} 648EXPORT_SYMBOL(vlynq_set_local_irq); 649 650int vlynq_set_remote_irq(struct vlynq_device *dev, int virq) 651{ 652 int irq = dev->irq_start + virq; 653 if (dev->enabled) 654 return -EBUSY; 655 656 if ((irq < dev->irq_start) || (irq > dev->irq_end)) 657 return -EINVAL; 658 659 if (virq == dev->local_irq) 660 return -EINVAL; 661 662 dev->remote_irq = virq; 663 664 return 0; 665} 666EXPORT_SYMBOL(vlynq_set_remote_irq); 667 668static int vlynq_probe(struct platform_device *pdev) 669{ 670 struct vlynq_device *dev; 671 struct resource *regs_res, *mem_res, *irq_res; 672 int len, result; 673 674 regs_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs"); 675 if (!regs_res) 676 return -ENODEV; 677 678 mem_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mem"); 679 if (!mem_res) 680 return -ENODEV; 681 682 irq_res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "devirq"); 683 if (!irq_res) 684 return -ENODEV; 685 686 dev = kzalloc(sizeof(*dev), GFP_KERNEL); 687 if (!dev) { 688 printk(KERN_ERR 689 "vlynq: failed to allocate device structure\n"); 690 return -ENOMEM; 691 } 692 693 dev->id = pdev->id; 694 dev->dev.bus = &vlynq_bus_type; 695 dev->dev.parent = &pdev->dev; 696 dev_set_name(&dev->dev, "vlynq%d", dev->id); 697 dev->dev.platform_data = pdev->dev.platform_data; 698 dev->dev.release = vlynq_device_release; 699 700 dev->regs_start = regs_res->start; 701 dev->regs_end = regs_res->end; 702 dev->mem_start = mem_res->start; 703 dev->mem_end = mem_res->end; 704 705 len = resource_size(regs_res); 706 if (!request_mem_region(regs_res->start, len, dev_name(&dev->dev))) { 707 printk(KERN_ERR "%s: Can't request vlynq registers\n", 708 dev_name(&dev->dev)); 709 result = -ENXIO; 710 goto fail_request; 711 } 712 713 dev->local = ioremap(regs_res->start, len); 714 if (!dev->local) { 715 printk(KERN_ERR "%s: Can't remap vlynq registers\n", 716 dev_name(&dev->dev)); 717 result = -ENXIO; 718 goto fail_remap; 719 } 720 721 dev->remote = (struct vlynq_regs *)((void *)dev->local + 722 VLYNQ_REMOTE_OFFSET); 723 724 dev->irq = platform_get_irq_byname(pdev, "irq"); 725 dev->irq_start = irq_res->start; 726 dev->irq_end = irq_res->end; 727 dev->local_irq = dev->irq_end - dev->irq_start; 728 dev->remote_irq = dev->local_irq - 1; 729 730 if (device_register(&dev->dev)) 731 goto fail_register; 732 platform_set_drvdata(pdev, dev); 733 734 printk(KERN_INFO "%s: regs 0x%p, irq %d, mem 0x%p\n", 735 dev_name(&dev->dev), (void *)dev->regs_start, dev->irq, 736 (void *)dev->mem_start); 737 738 dev->dev_id = 0; 739 dev->divisor = vlynq_div_auto; 740 result = __vlynq_enable_device(dev); 741 if (result == 0) { 742 dev->dev_id = readl(&dev->remote->chip); 743 ((struct plat_vlynq_ops *)(dev->dev.platform_data))->off(dev); 744 } 745 if (dev->dev_id) 746 printk(KERN_INFO "Found a VLYNQ device: %08x\n", dev->dev_id); 747 748 return 0; 749 750fail_register: 751 iounmap(dev->local); 752fail_remap: 753fail_request: 754 release_mem_region(regs_res->start, len); 755 kfree(dev); 756 return result; 757} 758 759static int vlynq_remove(struct platform_device *pdev) 760{ 761 struct vlynq_device *dev = platform_get_drvdata(pdev); 762 763 device_unregister(&dev->dev); 764 iounmap(dev->local); 765 release_mem_region(dev->regs_start, dev->regs_end - dev->regs_start); 766 767 kfree(dev); 768 769 return 0; 770} 771 772static struct platform_driver vlynq_platform_driver = { 773 .driver.name = "vlynq", 774 .probe = vlynq_probe, 775 .remove = __devexit_p(vlynq_remove), 776}; 777 778struct bus_type vlynq_bus_type = { 779 .name = "vlynq", 780 .match = vlynq_device_match, 781 .probe = vlynq_device_probe, 782 .remove = vlynq_device_remove, 783}; 784EXPORT_SYMBOL(vlynq_bus_type); 785 786static int __devinit vlynq_init(void) 787{ 788 int res = 0; 789 790 res = bus_register(&vlynq_bus_type); 791 if (res) 792 goto fail_bus; 793 794 res = platform_driver_register(&vlynq_platform_driver); 795 if (res) 796 goto fail_platform; 797 798 return 0; 799 800fail_platform: 801 bus_unregister(&vlynq_bus_type); 802fail_bus: 803 return res; 804} 805 806static void __devexit vlynq_exit(void) 807{ 808 platform_driver_unregister(&vlynq_platform_driver); 809 bus_unregister(&vlynq_bus_type); 810} 811 812module_init(vlynq_init); 813module_exit(vlynq_exit); 814