root/drivers/vlynq/vlynq.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. vlynq_dump_regs
  2. vlynq_dump_mem
  3. vlynq_linked
  4. vlynq_reset
  5. vlynq_irq_unmask
  6. vlynq_irq_mask
  7. vlynq_irq_type
  8. vlynq_local_ack
  9. vlynq_remote_ack
  10. vlynq_irq
  11. vlynq_setup_irq
  12. vlynq_device_release
  13. vlynq_device_match
  14. vlynq_device_probe
  15. vlynq_device_remove
  16. __vlynq_register_driver
  17. vlynq_unregister_driver
  18. __vlynq_try_remote
  19. __vlynq_try_local
  20. __vlynq_try_external
  21. __vlynq_enable_device
  22. vlynq_enable_device
  23. vlynq_disable_device
  24. vlynq_set_local_mapping
  25. vlynq_set_remote_mapping
  26. vlynq_set_local_irq
  27. vlynq_set_remote_irq
  28. vlynq_probe
  29. vlynq_remove
  30. vlynq_init
  31. vlynq_exit

   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 
  51 struct 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
  68 static 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 
  82 static 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 */
  96 static 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 
 109 static 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 
 125 static 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 
 138 static 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 
 151 static 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 
 182 static 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 
 192 static 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 
 202 static 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 
 224 static 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 
 231 static 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 
 238 static 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 
 245 static 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 
 303 static void vlynq_device_release(struct device *dev)
 304 {
 305         struct vlynq_device *vdev = to_vlynq_device(dev);
 306         kfree(vdev);
 307 }
 308 
 309 static 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 
 331 static 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 
 345 static 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 
 355 int __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 }
 361 EXPORT_SYMBOL(__vlynq_register_driver);
 362 
 363 void vlynq_unregister_driver(struct vlynq_driver *driver)
 364 {
 365         driver_unregister(&driver->driver);
 366 }
 367 EXPORT_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  */
 377 static 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  */
 421 static 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  */
 457 static 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 
 481 static 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 
 556 int 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 }
 572 EXPORT_SYMBOL(vlynq_enable_device);
 573 
 574 
 575 void 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 }
 583 EXPORT_SYMBOL(vlynq_disable_device);
 584 
 585 int 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 }
 600 EXPORT_SYMBOL(vlynq_set_local_mapping);
 601 
 602 int 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 }
 617 EXPORT_SYMBOL(vlynq_set_remote_mapping);
 618 
 619 int 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 }
 635 EXPORT_SYMBOL(vlynq_set_local_irq);
 636 
 637 int 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 }
 653 EXPORT_SYMBOL(vlynq_set_remote_irq);
 654 
 655 static 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 
 737 fail_register:
 738         iounmap(dev->local);
 739 fail_remap:
 740 fail_request:
 741         release_mem_region(regs_res->start, len);
 742         kfree(dev);
 743         return result;
 744 }
 745 
 746 static 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 
 760 static struct platform_driver vlynq_platform_driver = {
 761         .driver.name = "vlynq",
 762         .probe = vlynq_probe,
 763         .remove = vlynq_remove,
 764 };
 765 
 766 struct bus_type vlynq_bus_type = {
 767         .name = "vlynq",
 768         .match = vlynq_device_match,
 769         .probe = vlynq_device_probe,
 770         .remove = vlynq_device_remove,
 771 };
 772 EXPORT_SYMBOL(vlynq_bus_type);
 773 
 774 static 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 
 788 fail_platform:
 789         bus_unregister(&vlynq_bus_type);
 790 fail_bus:
 791         return res;
 792 }
 793 
 794 static void vlynq_exit(void)
 795 {
 796         platform_driver_unregister(&vlynq_platform_driver);
 797         bus_unregister(&vlynq_bus_type);
 798 }
 799 
 800 module_init(vlynq_init);
 801 module_exit(vlynq_exit);

/* [<][>][^][v][top][bottom][index][help] */