2 * Copyright (C) 2015 Industrial Research Institute for Automation
3 * and Measurements PIAP
5 * Written by Krzysztof Ha?asa.
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.
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"
20 static irqreturn_t
tw686x_irq(int irq
, void *dev_id
)
22 struct tw686x_dev
*dev
= (struct tw686x_dev
*)dev_id
;
23 u32 int_status
= reg_read(dev
, INT_STATUS
); /* cleared on read */
25 unsigned int handled
= 0;
28 spin_lock_irqsave(&dev
->irq_lock
, flags
);
29 dev
->dma_requests
|= int_status
;
30 spin_unlock_irqrestore(&dev
->irq_lock
, flags
);
32 if (int_status
& 0xFF0000FF)
33 handled
= tw686x_kh_video_irq(dev
);
36 return IRQ_RETVAL(handled
);
39 static int tw686x_probe(struct pci_dev
*pci_dev
,
40 const struct pci_device_id
*pci_id
)
42 struct tw686x_dev
*dev
;
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
);
51 sprintf(dev
->name
, "TW%04X", pci_dev
->device
);
52 dev
->type
= pci_id
->driver_data
;
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));
58 dev
->pci_dev
= pci_dev
;
59 if (pcim_enable_device(pci_dev
))
62 pci_set_master(pci_dev
);
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
);
69 err
= pci_request_regions(pci_dev
, dev
->name
);
71 pr_err("%s: Unable to get MMIO region\n", dev
->name
);
75 dev
->mmio
= pci_ioremap_bar(pci_dev
, 0);
77 pr_err("%s: Unable to remap MMIO region\n", dev
->name
);
81 reg_write(dev
, SYS_SOFT_RST
, 0x0F); /* Reset all subsystems */
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);
93 spin_lock_init(&dev
->irq_lock
);
95 err
= devm_request_irq(&pci_dev
->dev
, pci_dev
->irq
, tw686x_irq
,
96 IRQF_SHARED
, dev
->name
, dev
);
98 pr_err("%s: Unable to get IRQ\n", dev
->name
);
102 err
= tw686x_kh_video_init(dev
);
106 pci_set_drvdata(pci_dev
, dev
);
110 static void tw686x_remove(struct pci_dev
*pci_dev
)
112 struct tw686x_dev
*dev
= pci_get_drvdata(pci_dev
);
114 tw686x_kh_video_free(dev
);
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},
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
},
129 static struct pci_driver tw686x_pci_driver
= {
131 .id_table
= tw686x_pci_tbl
,
132 .probe
= tw686x_probe
,
133 .remove
= tw686x_remove
,
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
);