Version:  2.0.40 2.2.26 2.4.37 3.2 3.3 3.4 3.5 3.6 3.7 3.8 3.9 3.10 3.11 3.12 3.13 3.14 3.15 3.16 3.17 3.18

Linux/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,
766                            dev->regs_end - dev->regs_start + 1);
767 
768         kfree(dev);
769 
770         return 0;
771 }
772 
773 static struct platform_driver vlynq_platform_driver = {
774         .driver.name = "vlynq",
775         .probe = vlynq_probe,
776         .remove = vlynq_remove,
777 };
778 
779 struct bus_type vlynq_bus_type = {
780         .name = "vlynq",
781         .match = vlynq_device_match,
782         .probe = vlynq_device_probe,
783         .remove = vlynq_device_remove,
784 };
785 EXPORT_SYMBOL(vlynq_bus_type);
786 
787 static int vlynq_init(void)
788 {
789         int res = 0;
790 
791         res = bus_register(&vlynq_bus_type);
792         if (res)
793                 goto fail_bus;
794 
795         res = platform_driver_register(&vlynq_platform_driver);
796         if (res)
797                 goto fail_platform;
798 
799         return 0;
800 
801 fail_platform:
802         bus_unregister(&vlynq_bus_type);
803 fail_bus:
804         return res;
805 }
806 
807 static void vlynq_exit(void)
808 {
809         platform_driver_unregister(&vlynq_platform_driver);
810         bus_unregister(&vlynq_bus_type);
811 }
812 
813 module_init(vlynq_init);
814 module_exit(vlynq_exit);
815 

This page was automatically generated by LXR 0.3.1 (source).  •  Linux is a registered trademark of Linus Torvalds  •  Contact us