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