Merge branch 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[cascardo/linux.git] / drivers / staging / media / tw686x-kh / tw686x-kh-core.c
1 /*
2  * Copyright (C) 2015 Industrial Research Institute for Automation
3  * and Measurements PIAP
4  *
5  * Written by Krzysztof Ha?asa.
6  *
7  * This program is free software; you can redistribute it and/or modify it
8  * under the terms of version 2 of the GNU General Public License
9  * as published by the Free Software Foundation.
10  */
11
12 #include <linux/init.h>
13 #include <linux/interrupt.h>
14 #include <linux/kernel.h>
15 #include <linux/module.h>
16 #include <linux/slab.h>
17 #include "tw686x-kh.h"
18 #include "tw686x-kh-regs.h"
19
20 static irqreturn_t tw686x_irq(int irq, void *dev_id)
21 {
22         struct tw686x_dev *dev = (struct tw686x_dev *)dev_id;
23         u32 int_status = reg_read(dev, INT_STATUS); /* cleared on read */
24         unsigned long flags;
25         unsigned int handled = 0;
26
27         if (int_status) {
28                 spin_lock_irqsave(&dev->irq_lock, flags);
29                 dev->dma_requests |= int_status;
30                 spin_unlock_irqrestore(&dev->irq_lock, flags);
31
32                 if (int_status & 0xFF0000FF)
33                         handled = tw686x_kh_video_irq(dev);
34         }
35
36         return IRQ_RETVAL(handled);
37 }
38
39 static int tw686x_probe(struct pci_dev *pci_dev,
40                         const struct pci_device_id *pci_id)
41 {
42         struct tw686x_dev *dev;
43         int err;
44
45         dev = devm_kzalloc(&pci_dev->dev, sizeof(*dev) +
46                            (pci_id->driver_data & TYPE_MAX_CHANNELS) *
47                            sizeof(dev->video_channels[0]), GFP_KERNEL);
48         if (!dev)
49                 return -ENOMEM;
50
51         sprintf(dev->name, "TW%04X", pci_dev->device);
52         dev->type = pci_id->driver_data;
53
54         pr_info("%s: PCI %s, IRQ %d, MMIO 0x%lx\n", dev->name,
55                 pci_name(pci_dev), pci_dev->irq,
56                 (unsigned long)pci_resource_start(pci_dev, 0));
57
58         dev->pci_dev = pci_dev;
59         if (pcim_enable_device(pci_dev))
60                 return -EIO;
61
62         pci_set_master(pci_dev);
63
64         if (pci_set_dma_mask(pci_dev, DMA_BIT_MASK(32))) {
65                 pr_err("%s: 32-bit PCI DMA not supported\n", dev->name);
66                 return -EIO;
67         }
68
69         err = pci_request_regions(pci_dev, dev->name);
70         if (err < 0) {
71                 pr_err("%s: Unable to get MMIO region\n", dev->name);
72                 return err;
73         }
74
75         dev->mmio = pci_ioremap_bar(pci_dev, 0);
76         if (!dev->mmio) {
77                 pr_err("%s: Unable to remap MMIO region\n", dev->name);
78                 return -EIO;
79         }
80
81         reg_write(dev, SYS_SOFT_RST, 0x0F); /* Reset all subsystems */
82         mdelay(1);
83
84         reg_write(dev, SRST[0], 0x3F);
85         if (max_channels(dev) > 4)
86                 reg_write(dev, SRST[1], 0x3F);
87         reg_write(dev, DMA_CMD, 0);
88         reg_write(dev, DMA_CHANNEL_ENABLE, 0);
89         reg_write(dev, DMA_CHANNEL_TIMEOUT, 0x3EFF0FF0);
90         reg_write(dev, DMA_TIMER_INTERVAL, 0x38000);
91         reg_write(dev, DMA_CONFIG, 0xFFFFFF04);
92
93         spin_lock_init(&dev->irq_lock);
94
95         err = devm_request_irq(&pci_dev->dev, pci_dev->irq, tw686x_irq,
96                                IRQF_SHARED, dev->name, dev);
97         if (err < 0) {
98                 pr_err("%s: Unable to get IRQ\n", dev->name);
99                 return err;
100         }
101
102         err = tw686x_kh_video_init(dev);
103         if (err)
104                 return err;
105
106         pci_set_drvdata(pci_dev, dev);
107         return 0;
108 }
109
110 static void tw686x_remove(struct pci_dev *pci_dev)
111 {
112         struct tw686x_dev *dev = pci_get_drvdata(pci_dev);
113
114         tw686x_kh_video_free(dev);
115 }
116
117 /* driver_data is number of A/V channels */
118 static const struct pci_device_id tw686x_pci_tbl[] = {
119         {PCI_DEVICE(0x1797, 0x6864), .driver_data = 4},
120         /* not tested */
121         {PCI_DEVICE(0x1797, 0x6865), .driver_data = 4 | TYPE_SECOND_GEN},
122         /* TW6868 supports 8 A/V channels with an external TW2865 chip -
123            not supported by the driver */
124         {PCI_DEVICE(0x1797, 0x6868), .driver_data = 4}, /* not tested */
125         {PCI_DEVICE(0x1797, 0x6869), .driver_data = 8 | TYPE_SECOND_GEN},
126         {}
127 };
128
129 static struct pci_driver tw686x_pci_driver = {
130         .name = "tw686x-kh",
131         .id_table = tw686x_pci_tbl,
132         .probe = tw686x_probe,
133         .remove = tw686x_remove,
134 };
135
136 MODULE_DESCRIPTION("Driver for video frame grabber cards based on Intersil/Techwell TW686[4589]");
137 MODULE_AUTHOR("Krzysztof Halasa");
138 MODULE_LICENSE("GPL v2");
139 MODULE_DEVICE_TABLE(pci, tw686x_pci_tbl);
140 module_pci_driver(tw686x_pci_driver);