drm/rockchip: Don't change hdmi reference clock rate
[drm/drm-misc.git] / drivers / media / pci / saa7146 / hexium_gemini.c
blob40b35098f3ead1d63378d05beb2ccddf3977a2da
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 hexium_gemini.c - v4l2 driver for Hexium Gemini frame grabber cards
5 Visit http://www.mihu.de/linux/saa7146/ and follow the link
6 to "hexium" for further details about this card.
8 Copyright (C) 2003 Michael Hunold <michael@mihu.de>
12 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
14 #define DEBUG_VARIABLE debug
16 #include <media/drv-intf/saa7146_vv.h>
17 #include <linux/module.h>
18 #include <linux/kernel.h>
20 static int debug;
21 module_param(debug, int, 0);
22 MODULE_PARM_DESC(debug, "debug verbosity");
24 /* global variables */
25 static int hexium_num;
27 #define HEXIUM_GEMINI 4
28 #define HEXIUM_GEMINI_DUAL 5
30 #define HEXIUM_STD (V4L2_STD_PAL | V4L2_STD_SECAM | V4L2_STD_NTSC)
31 #define HEXIUM_INPUTS 9
32 static struct v4l2_input hexium_inputs[HEXIUM_INPUTS] = {
33 { 0, "CVBS 1", V4L2_INPUT_TYPE_CAMERA, 0, 0, HEXIUM_STD, 0, V4L2_IN_CAP_STD },
34 { 1, "CVBS 2", V4L2_INPUT_TYPE_CAMERA, 0, 0, HEXIUM_STD, 0, V4L2_IN_CAP_STD },
35 { 2, "CVBS 3", V4L2_INPUT_TYPE_CAMERA, 0, 0, HEXIUM_STD, 0, V4L2_IN_CAP_STD },
36 { 3, "CVBS 4", V4L2_INPUT_TYPE_CAMERA, 0, 0, HEXIUM_STD, 0, V4L2_IN_CAP_STD },
37 { 4, "CVBS 5", V4L2_INPUT_TYPE_CAMERA, 0, 0, HEXIUM_STD, 0, V4L2_IN_CAP_STD },
38 { 5, "CVBS 6", V4L2_INPUT_TYPE_CAMERA, 0, 0, HEXIUM_STD, 0, V4L2_IN_CAP_STD },
39 { 6, "Y/C 1", V4L2_INPUT_TYPE_CAMERA, 0, 0, HEXIUM_STD, 0, V4L2_IN_CAP_STD },
40 { 7, "Y/C 2", V4L2_INPUT_TYPE_CAMERA, 0, 0, HEXIUM_STD, 0, V4L2_IN_CAP_STD },
41 { 8, "Y/C 3", V4L2_INPUT_TYPE_CAMERA, 0, 0, HEXIUM_STD, 0, V4L2_IN_CAP_STD },
44 #define HEXIUM_AUDIOS 0
46 struct hexium_data
48 s8 adr;
49 u8 byte;
52 #define HEXIUM_GEMINI_V_1_0 1
53 #define HEXIUM_GEMINI_DUAL_V_1_0 2
55 struct hexium
57 int type;
59 struct video_device video_dev;
60 struct i2c_adapter i2c_adapter;
62 int cur_input; /* current input */
63 v4l2_std_id cur_std; /* current standard */
66 /* Samsung KS0127B decoder default registers */
67 static u8 hexium_ks0127b[0x100]={
68 /*00*/ 0x00,0x52,0x30,0x40,0x01,0x0C,0x2A,0x10,
69 /*08*/ 0x00,0x00,0x00,0x60,0x00,0x00,0x0F,0x06,
70 /*10*/ 0x00,0x00,0xE4,0xC0,0x00,0x00,0x00,0x00,
71 /*18*/ 0x14,0x9B,0xFE,0xFF,0xFC,0xFF,0x03,0x22,
72 /*20*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
73 /*28*/ 0x00,0x00,0x00,0x00,0x00,0x2C,0x9B,0x00,
74 /*30*/ 0x00,0x00,0x10,0x80,0x80,0x10,0x80,0x80,
75 /*38*/ 0x01,0x04,0x00,0x00,0x00,0x29,0xC0,0x00,
76 /*40*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
77 /*48*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
78 /*50*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
79 /*58*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
80 /*60*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
81 /*68*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
82 /*70*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
83 /*78*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
84 /*80*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
85 /*88*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
86 /*90*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
87 /*98*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
88 /*A0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
89 /*A8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
90 /*B0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
91 /*B8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
92 /*C0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
93 /*C8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
94 /*D0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
95 /*D8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
96 /*E0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
97 /*E8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
98 /*F0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
99 /*F8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
102 static struct hexium_data hexium_pal[] = {
103 { 0x01, 0x52 }, { 0x12, 0x64 }, { 0x2D, 0x2C }, { 0x2E, 0x9B }, { -1 , 0xFF }
106 static struct hexium_data hexium_ntsc[] = {
107 { 0x01, 0x53 }, { 0x12, 0x04 }, { 0x2D, 0x23 }, { 0x2E, 0x81 }, { -1 , 0xFF }
110 static struct hexium_data hexium_secam[] = {
111 { 0x01, 0x52 }, { 0x12, 0x64 }, { 0x2D, 0x2C }, { 0x2E, 0x9B }, { -1 , 0xFF }
114 static struct hexium_data hexium_input_select[] = {
115 { 0x02, 0x60 },
116 { 0x02, 0x64 },
117 { 0x02, 0x61 },
118 { 0x02, 0x65 },
119 { 0x02, 0x62 },
120 { 0x02, 0x66 },
121 { 0x02, 0x68 },
122 { 0x02, 0x69 },
123 { 0x02, 0x6A },
126 /* fixme: h_offset = 0 for Hexium Gemini *Dual*, which
127 are currently *not* supported*/
128 static struct saa7146_standard hexium_standards[] = {
130 .name = "PAL", .id = V4L2_STD_PAL,
131 .v_offset = 28, .v_field = 288,
132 .h_offset = 1, .h_pixels = 680,
133 .v_max_out = 576, .h_max_out = 768,
134 }, {
135 .name = "NTSC", .id = V4L2_STD_NTSC,
136 .v_offset = 28, .v_field = 240,
137 .h_offset = 1, .h_pixels = 640,
138 .v_max_out = 480, .h_max_out = 640,
139 }, {
140 .name = "SECAM", .id = V4L2_STD_SECAM,
141 .v_offset = 28, .v_field = 288,
142 .h_offset = 1, .h_pixels = 720,
143 .v_max_out = 576, .h_max_out = 768,
147 /* bring hardware to a sane state. this has to be done, just in case someone
148 wants to capture from this device before it has been properly initialized.
149 the capture engine would badly fail, because no valid signal arrives on the
150 saa7146, thus leading to timeouts and stuff. */
151 static int hexium_init_done(struct saa7146_dev *dev)
153 struct hexium *hexium = (struct hexium *) dev->ext_priv;
154 union i2c_smbus_data data;
155 int i = 0;
157 DEB_D("hexium_init_done called\n");
159 /* initialize the helper ics to useful values */
160 for (i = 0; i < sizeof(hexium_ks0127b); i++) {
161 data.byte = hexium_ks0127b[i];
162 if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x6c, 0, I2C_SMBUS_WRITE, i, I2C_SMBUS_BYTE_DATA, &data)) {
163 pr_err("hexium_init_done() failed for address 0x%02x\n",
168 return 0;
171 static int hexium_set_input(struct hexium *hexium, int input)
173 union i2c_smbus_data data;
175 DEB_D("\n");
177 data.byte = hexium_input_select[input].byte;
178 if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x6c, 0, I2C_SMBUS_WRITE, hexium_input_select[input].adr, I2C_SMBUS_BYTE_DATA, &data)) {
179 return -1;
182 return 0;
185 static int hexium_set_standard(struct hexium *hexium, struct hexium_data *vdec)
187 union i2c_smbus_data data;
188 int i = 0;
190 DEB_D("\n");
192 while (vdec[i].adr != -1) {
193 data.byte = vdec[i].byte;
194 if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x6c, 0, I2C_SMBUS_WRITE, vdec[i].adr, I2C_SMBUS_BYTE_DATA, &data)) {
195 pr_err("hexium_init_done: hexium_set_standard() failed for address 0x%02x\n",
197 return -1;
199 i++;
201 return 0;
204 static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
206 DEB_EE("VIDIOC_ENUMINPUT %d\n", i->index);
208 if (i->index >= HEXIUM_INPUTS)
209 return -EINVAL;
211 memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input));
213 DEB_D("v4l2_ioctl: VIDIOC_ENUMINPUT %d\n", i->index);
214 return 0;
217 static int vidioc_g_input(struct file *file, void *fh, unsigned int *input)
219 struct saa7146_dev *dev = video_drvdata(file);
220 struct hexium *hexium = (struct hexium *) dev->ext_priv;
222 *input = hexium->cur_input;
224 DEB_D("VIDIOC_G_INPUT: %d\n", *input);
225 return 0;
228 static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
230 struct saa7146_dev *dev = video_drvdata(file);
231 struct hexium *hexium = (struct hexium *) dev->ext_priv;
233 DEB_EE("VIDIOC_S_INPUT %d\n", input);
235 if (input >= HEXIUM_INPUTS)
236 return -EINVAL;
238 hexium->cur_input = input;
239 hexium_set_input(hexium, input);
240 return 0;
243 static struct saa7146_ext_vv vv_data;
245 /* this function only gets called when the probing was successful */
246 static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
248 struct hexium *hexium;
249 int ret;
251 DEB_EE("\n");
253 hexium = kzalloc(sizeof(*hexium), GFP_KERNEL);
254 if (!hexium)
255 return -ENOMEM;
257 dev->ext_priv = hexium;
259 /* enable i2c-port pins */
260 saa7146_write(dev, MC1, (MASK_08 | MASK_24 | MASK_10 | MASK_26));
262 strscpy(hexium->i2c_adapter.name, "hexium gemini",
263 sizeof(hexium->i2c_adapter.name));
264 saa7146_i2c_adapter_prepare(dev, &hexium->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480);
265 if (i2c_add_adapter(&hexium->i2c_adapter) < 0) {
266 DEB_S("cannot register i2c-device. skipping.\n");
267 kfree(hexium);
268 return -EFAULT;
271 /* set HWControl GPIO number 2 */
272 saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI);
274 saa7146_write(dev, DD1_INIT, 0x07000700);
275 saa7146_write(dev, DD1_STREAM_B, 0x00000000);
276 saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
278 /* the rest */
279 hexium->cur_input = 0;
280 hexium_init_done(dev);
282 hexium_set_standard(hexium, hexium_pal);
283 hexium->cur_std = V4L2_STD_PAL;
285 hexium_set_input(hexium, 0);
286 hexium->cur_input = 0;
288 ret = saa7146_vv_init(dev, &vv_data);
289 if (ret) {
290 i2c_del_adapter(&hexium->i2c_adapter);
291 kfree(hexium);
292 return ret;
295 vv_data.vid_ops.vidioc_enum_input = vidioc_enum_input;
296 vv_data.vid_ops.vidioc_g_input = vidioc_g_input;
297 vv_data.vid_ops.vidioc_s_input = vidioc_s_input;
298 ret = saa7146_register_device(&hexium->video_dev, dev, "hexium gemini", VFL_TYPE_VIDEO);
299 if (ret < 0) {
300 pr_err("cannot register capture v4l2 device. skipping.\n");
301 saa7146_vv_release(dev);
302 i2c_del_adapter(&hexium->i2c_adapter);
303 kfree(hexium);
304 return ret;
307 pr_info("found 'hexium gemini' frame grabber-%d\n", hexium_num);
308 hexium_num++;
310 return 0;
313 static int hexium_detach(struct saa7146_dev *dev)
315 struct hexium *hexium = (struct hexium *) dev->ext_priv;
317 DEB_EE("dev:%p\n", dev);
319 saa7146_unregister_device(&hexium->video_dev, dev);
320 saa7146_vv_release(dev);
322 hexium_num--;
324 i2c_del_adapter(&hexium->i2c_adapter);
325 kfree(hexium);
326 return 0;
329 static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *std)
331 struct hexium *hexium = (struct hexium *) dev->ext_priv;
333 if (V4L2_STD_PAL == std->id) {
334 hexium_set_standard(hexium, hexium_pal);
335 hexium->cur_std = V4L2_STD_PAL;
336 return 0;
337 } else if (V4L2_STD_NTSC == std->id) {
338 hexium_set_standard(hexium, hexium_ntsc);
339 hexium->cur_std = V4L2_STD_NTSC;
340 return 0;
341 } else if (V4L2_STD_SECAM == std->id) {
342 hexium_set_standard(hexium, hexium_secam);
343 hexium->cur_std = V4L2_STD_SECAM;
344 return 0;
347 return -1;
350 static struct saa7146_extension hexium_extension;
352 static struct saa7146_pci_extension_data hexium_gemini_4bnc = {
353 .ext_priv = "Hexium Gemini (4 BNC)",
354 .ext = &hexium_extension,
357 static struct saa7146_pci_extension_data hexium_gemini_dual_4bnc = {
358 .ext_priv = "Hexium Gemini Dual (4 BNC)",
359 .ext = &hexium_extension,
362 static const struct pci_device_id pci_tbl[] = {
364 .vendor = PCI_VENDOR_ID_PHILIPS,
365 .device = PCI_DEVICE_ID_PHILIPS_SAA7146,
366 .subvendor = 0x17c8,
367 .subdevice = 0x2401,
368 .driver_data = (unsigned long) &hexium_gemini_4bnc,
371 .vendor = PCI_VENDOR_ID_PHILIPS,
372 .device = PCI_DEVICE_ID_PHILIPS_SAA7146,
373 .subvendor = 0x17c8,
374 .subdevice = 0x2402,
375 .driver_data = (unsigned long) &hexium_gemini_dual_4bnc,
378 .vendor = 0,
382 MODULE_DEVICE_TABLE(pci, pci_tbl);
384 static struct saa7146_ext_vv vv_data = {
385 .inputs = HEXIUM_INPUTS,
386 .capabilities = 0,
387 .stds = &hexium_standards[0],
388 .num_stds = ARRAY_SIZE(hexium_standards),
389 .std_callback = &std_callback,
392 static struct saa7146_extension hexium_extension = {
393 .name = "hexium gemini",
394 .flags = SAA7146_USE_I2C_IRQ,
396 .pci_tbl = &pci_tbl[0],
397 .module = THIS_MODULE,
399 .attach = hexium_attach,
400 .detach = hexium_detach,
402 .irq_mask = 0,
403 .irq_func = NULL,
406 static int __init hexium_init_module(void)
408 if (0 != saa7146_register_extension(&hexium_extension)) {
409 DEB_S("failed to register extension\n");
410 return -ENODEV;
413 return 0;
416 static void __exit hexium_cleanup_module(void)
418 saa7146_unregister_extension(&hexium_extension);
421 module_init(hexium_init_module);
422 module_exit(hexium_cleanup_module);
424 MODULE_DESCRIPTION("video4linux-2 driver for Hexium Gemini frame grabber cards");
425 MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
426 MODULE_LICENSE("GPL");