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

Archive Download this file



interactive