Merge commits 'ca6a42586fae' and 'c286c419c784' into perf/urgent
[pandora-kernel.git] / drivers / vlynq / vlynq.c
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
64 struct 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
81 static 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
95 static 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 */
109 static 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
122 static 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
138 static 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
151 static 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
164 static 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
195 static 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
205 static 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
215 static 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
237 static 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
244 static 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
251 static 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
258 static 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
316 static void vlynq_device_release(struct device *dev)
317 {
318         struct vlynq_device *vdev = to_vlynq_device(dev);
319         kfree(vdev);
320 }
321
322 static 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
344 static 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
358 static 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
368 int __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 }
374 EXPORT_SYMBOL(__vlynq_register_driver);
375
376 void vlynq_unregister_driver(struct vlynq_driver *driver)
377 {
378         driver_unregister(&driver->driver);
379 }
380 EXPORT_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  */
390 static 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  */
434 static 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  */
470 static 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
494 static 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
569 int 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 }
585 EXPORT_SYMBOL(vlynq_enable_device);
586
587
588 void 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 }
596 EXPORT_SYMBOL(vlynq_disable_device);
597
598 int 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 }
613 EXPORT_SYMBOL(vlynq_set_local_mapping);
614
615 int 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 }
630 EXPORT_SYMBOL(vlynq_set_remote_mapping);
631
632 int 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 }
648 EXPORT_SYMBOL(vlynq_set_local_irq);
649
650 int 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 }
666 EXPORT_SYMBOL(vlynq_set_remote_irq);
667
668 static 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
750 fail_register:
751         iounmap(dev->local);
752 fail_remap:
753 fail_request:
754         release_mem_region(regs_res->start, len);
755         kfree(dev);
756         return result;
757 }
758
759 static 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
772 static struct platform_driver vlynq_platform_driver = {
773         .driver.name = "vlynq",
774         .probe = vlynq_probe,
775         .remove = __devexit_p(vlynq_remove),
776 };
777
778 struct bus_type vlynq_bus_type = {
779         .name = "vlynq",
780         .match = vlynq_device_match,
781         .probe = vlynq_device_probe,
782         .remove = vlynq_device_remove,
783 };
784 EXPORT_SYMBOL(vlynq_bus_type);
785
786 static 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
800 fail_platform:
801         bus_unregister(&vlynq_bus_type);
802 fail_bus:
803         return res;
804 }
805
806 static void __devexit vlynq_exit(void)
807 {
808         platform_driver_unregister(&vlynq_platform_driver);
809         bus_unregister(&vlynq_bus_type);
810 }
811
812 module_init(vlynq_init);
813 module_exit(vlynq_exit);