brintos

brintos / linux-shallow public Read only

0
0
Text · 11.9 KiB · a207672 Raw
499 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3    hexium_orion.c - v4l2 driver for the Hexium Orion frame grabber cards4 5    Visit http://www.mihu.de/linux/saa7146/ and follow the link6    to "hexium" for further details about this card.7 8    Copyright (C) 2003 Michael Hunold <michael@mihu.de>9 10*/11 12#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt13 14#define DEBUG_VARIABLE debug15 16#include <media/drv-intf/saa7146_vv.h>17#include <linux/module.h>18#include <linux/kernel.h>19 20static int debug;21module_param(debug, int, 0);22MODULE_PARM_DESC(debug, "debug verbosity");23 24/* global variables */25static int hexium_num;26 27#define HEXIUM_HV_PCI6_ORION		128#define HEXIUM_ORION_1SVHS_3BNC		229#define HEXIUM_ORION_4BNC		330 31#define HEXIUM_STD (V4L2_STD_PAL | V4L2_STD_SECAM | V4L2_STD_NTSC)32#define HEXIUM_INPUTS	933static struct v4l2_input hexium_inputs[HEXIUM_INPUTS] = {34	{ 0, "CVBS 1",	V4L2_INPUT_TYPE_CAMERA,	0, 0, HEXIUM_STD, 0, V4L2_IN_CAP_STD },35	{ 1, "CVBS 2",	V4L2_INPUT_TYPE_CAMERA,	0, 0, HEXIUM_STD, 0, V4L2_IN_CAP_STD },36	{ 2, "CVBS 3",	V4L2_INPUT_TYPE_CAMERA,	0, 0, HEXIUM_STD, 0, V4L2_IN_CAP_STD },37	{ 3, "CVBS 4",	V4L2_INPUT_TYPE_CAMERA,	0, 0, HEXIUM_STD, 0, V4L2_IN_CAP_STD },38	{ 4, "CVBS 5",	V4L2_INPUT_TYPE_CAMERA,	0, 0, HEXIUM_STD, 0, V4L2_IN_CAP_STD },39	{ 5, "CVBS 6",	V4L2_INPUT_TYPE_CAMERA,	0, 0, HEXIUM_STD, 0, V4L2_IN_CAP_STD },40	{ 6, "Y/C 1",	V4L2_INPUT_TYPE_CAMERA,	0, 0, HEXIUM_STD, 0, V4L2_IN_CAP_STD },41	{ 7, "Y/C 2",	V4L2_INPUT_TYPE_CAMERA,	0, 0, HEXIUM_STD, 0, V4L2_IN_CAP_STD },42	{ 8, "Y/C 3",	V4L2_INPUT_TYPE_CAMERA,	0, 0, HEXIUM_STD, 0, V4L2_IN_CAP_STD },43};44 45#define HEXIUM_AUDIOS	046 47struct hexium_data48{49	s8 adr;50	u8 byte;51};52 53struct hexium54{55	int type;56	struct video_device	video_dev;57	struct i2c_adapter	i2c_adapter;58 59	int cur_input;	/* current input */60};61 62/* Philips SAA7110 decoder default registers */63static u8 hexium_saa7110[53]={64/*00*/ 0x4C,0x3C,0x0D,0xEF,0xBD,0xF0,0x00,0x00,65/*08*/ 0xF8,0xF8,0x60,0x60,0x40,0x86,0x18,0x90,66/*10*/ 0x00,0x2C,0x40,0x46,0x42,0x1A,0xFF,0xDA,67/*18*/ 0xF0,0x8B,0x00,0x00,0x00,0x00,0x00,0x00,68/*20*/ 0xD9,0x17,0x40,0x41,0x80,0x41,0x80,0x4F,69/*28*/ 0xFE,0x01,0x0F,0x0F,0x03,0x01,0x81,0x03,70/*30*/ 0x44,0x75,0x01,0x8C,0x0371};72 73static struct {74	struct hexium_data data[8];75} hexium_input_select[] = {76{77	{ /* cvbs 1 */78		{ 0x06, 0x00 },79		{ 0x20, 0xD9 },80		{ 0x21, 0x17 }, // 0x16,81		{ 0x22, 0x40 },82		{ 0x2C, 0x03 },83		{ 0x30, 0x44 },84		{ 0x31, 0x75 }, // ??85		{ 0x21, 0x16 }, // 0x03,86	}87}, {88	{ /* cvbs 2 */89		{ 0x06, 0x00 },90		{ 0x20, 0x78 },91		{ 0x21, 0x07 }, // 0x03,92		{ 0x22, 0xD2 },93		{ 0x2C, 0x83 },94		{ 0x30, 0x60 },95		{ 0x31, 0xB5 }, // ?96		{ 0x21, 0x03 },97	}98}, {99	{ /* cvbs 3 */100		{ 0x06, 0x00 },101		{ 0x20, 0xBA },102		{ 0x21, 0x07 }, // 0x05,103		{ 0x22, 0x91 },104		{ 0x2C, 0x03 },105		{ 0x30, 0x60 },106		{ 0x31, 0xB5 }, // ??107		{ 0x21, 0x05 }, // 0x03,108	}109}, {110	{ /* cvbs 4 */111		{ 0x06, 0x00 },112		{ 0x20, 0xD8 },113		{ 0x21, 0x17 }, // 0x16,114		{ 0x22, 0x40 },115		{ 0x2C, 0x03 },116		{ 0x30, 0x44 },117		{ 0x31, 0x75 }, // ??118		{ 0x21, 0x16 }, // 0x03,119	}120}, {121	{ /* cvbs 5 */122		{ 0x06, 0x00 },123		{ 0x20, 0xB8 },124		{ 0x21, 0x07 }, // 0x05,125		{ 0x22, 0x91 },126		{ 0x2C, 0x03 },127		{ 0x30, 0x60 },128		{ 0x31, 0xB5 }, // ??129		{ 0x21, 0x05 }, // 0x03,130	}131}, {132	{ /* cvbs 6 */133		{ 0x06, 0x00 },134		{ 0x20, 0x7C },135		{ 0x21, 0x07 }, // 0x03136		{ 0x22, 0xD2 },137		{ 0x2C, 0x83 },138		{ 0x30, 0x60 },139		{ 0x31, 0xB5 }, // ??140		{ 0x21, 0x03 },141	}142}, {143	{ /* y/c 1 */144		{ 0x06, 0x80 },145		{ 0x20, 0x59 },146		{ 0x21, 0x17 },147		{ 0x22, 0x42 },148		{ 0x2C, 0xA3 },149		{ 0x30, 0x44 },150		{ 0x31, 0x75 },151		{ 0x21, 0x12 },152	}153}, {154	{ /* y/c 2 */155		{ 0x06, 0x80 },156		{ 0x20, 0x9A },157		{ 0x21, 0x17 },158		{ 0x22, 0xB1 },159		{ 0x2C, 0x13 },160		{ 0x30, 0x60 },161		{ 0x31, 0xB5 },162		{ 0x21, 0x14 },163	}164}, {165	{ /* y/c 3 */166		{ 0x06, 0x80 },167		{ 0x20, 0x3C },168		{ 0x21, 0x27 },169		{ 0x22, 0xC1 },170		{ 0x2C, 0x23 },171		{ 0x30, 0x44 },172		{ 0x31, 0x75 },173		{ 0x21, 0x21 },174	}175}176};177 178static struct saa7146_standard hexium_standards[] = {179	{180		.name	= "PAL",	.id	= V4L2_STD_PAL,181		.v_offset	= 16,	.v_field	= 288,182		.h_offset	= 1,	.h_pixels	= 680,183		.v_max_out	= 576,	.h_max_out	= 768,184	}, {185		.name	= "NTSC",	.id	= V4L2_STD_NTSC,186		.v_offset	= 16,	.v_field	= 240,187		.h_offset	= 1,	.h_pixels	= 640,188		.v_max_out	= 480,	.h_max_out	= 640,189	}, {190		.name	= "SECAM",	.id	= V4L2_STD_SECAM,191		.v_offset	= 16,	.v_field	= 288,192		.h_offset	= 1,	.h_pixels	= 720,193		.v_max_out	= 576,	.h_max_out	= 768,194	}195};196 197/* this is only called for old HV-PCI6/Orion cards198   without eeprom */199static int hexium_probe(struct saa7146_dev *dev)200{201	struct hexium *hexium = NULL;202	union i2c_smbus_data data;203	int err = 0;204 205	DEB_EE("\n");206 207	/* there are no hexium orion cards with revision 0 saa7146s */208	if (0 == dev->revision) {209		return -EFAULT;210	}211 212	hexium = kzalloc(sizeof(*hexium), GFP_KERNEL);213	if (!hexium)214		return -ENOMEM;215 216	/* enable i2c-port pins */217	saa7146_write(dev, MC1, (MASK_08 | MASK_24 | MASK_10 | MASK_26));218 219	saa7146_write(dev, DD1_INIT, 0x01000100);220	saa7146_write(dev, DD1_STREAM_B, 0x00000000);221	saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));222 223	strscpy(hexium->i2c_adapter.name, "hexium orion",224		sizeof(hexium->i2c_adapter.name));225	saa7146_i2c_adapter_prepare(dev, &hexium->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480);226	if (i2c_add_adapter(&hexium->i2c_adapter) < 0) {227		DEB_S("cannot register i2c-device. skipping.\n");228		kfree(hexium);229		return -EFAULT;230	}231 232	/* set SAA7110 control GPIO 0 */233	saa7146_setgpio(dev, 0, SAA7146_GPIO_OUTHI);234	/*  set HWControl GPIO number 2 */235	saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI);236 237	mdelay(10);238 239	/* detect newer Hexium Orion cards by subsystem ids */240	if (0x17c8 == dev->pci->subsystem_vendor && 0x0101 == dev->pci->subsystem_device) {241		pr_info("device is a Hexium Orion w/ 1 SVHS + 3 BNC inputs\n");242		/* we store the pointer in our private data field */243		dev->ext_priv = hexium;244		hexium->type = HEXIUM_ORION_1SVHS_3BNC;245		return 0;246	}247 248	if (0x17c8 == dev->pci->subsystem_vendor && 0x2101 == dev->pci->subsystem_device) {249		pr_info("device is a Hexium Orion w/ 4 BNC inputs\n");250		/* we store the pointer in our private data field */251		dev->ext_priv = hexium;252		hexium->type = HEXIUM_ORION_4BNC;253		return 0;254	}255 256	/* check if this is an old hexium Orion card by looking at257	   a saa7110 at address 0x4e */258	err = i2c_smbus_xfer(&hexium->i2c_adapter, 0x4e, 0, I2C_SMBUS_READ,259			     0x00, I2C_SMBUS_BYTE_DATA, &data);260	if (err == 0) {261		pr_info("device is a Hexium HV-PCI6/Orion (old)\n");262		/* we store the pointer in our private data field */263		dev->ext_priv = hexium;264		hexium->type = HEXIUM_HV_PCI6_ORION;265		return 0;266	}267 268	i2c_del_adapter(&hexium->i2c_adapter);269	kfree(hexium);270	return -EFAULT;271}272 273/* bring hardware to a sane state. this has to be done, just in case someone274   wants to capture from this device before it has been properly initialized.275   the capture engine would badly fail, because no valid signal arrives on the276   saa7146, thus leading to timeouts and stuff. */277static int hexium_init_done(struct saa7146_dev *dev)278{279	struct hexium *hexium = (struct hexium *) dev->ext_priv;280	union i2c_smbus_data data;281	int i = 0;282 283	DEB_D("hexium_init_done called\n");284 285	/* initialize the helper ics to useful values */286	for (i = 0; i < sizeof(hexium_saa7110); i++) {287		data.byte = hexium_saa7110[i];288		if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x4e, 0, I2C_SMBUS_WRITE, i, I2C_SMBUS_BYTE_DATA, &data)) {289			pr_err("failed for address 0x%02x\n", i);290		}291	}292 293	return 0;294}295 296static int hexium_set_input(struct hexium *hexium, int input)297{298	union i2c_smbus_data data;299	int i = 0;300 301	DEB_D("\n");302 303	for (i = 0; i < 8; i++) {304		int adr = hexium_input_select[input].data[i].adr;305		data.byte = hexium_input_select[input].data[i].byte;306		if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x4e, 0, I2C_SMBUS_WRITE, adr, I2C_SMBUS_BYTE_DATA, &data)) {307			return -1;308		}309		pr_debug("%d: 0x%02x => 0x%02x\n", input, adr, data.byte);310	}311 312	return 0;313}314 315static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)316{317	DEB_EE("VIDIOC_ENUMINPUT %d\n", i->index);318 319	if (i->index >= HEXIUM_INPUTS)320		return -EINVAL;321 322	memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input));323 324	DEB_D("v4l2_ioctl: VIDIOC_ENUMINPUT %d\n", i->index);325	return 0;326}327 328static int vidioc_g_input(struct file *file, void *fh, unsigned int *input)329{330	struct saa7146_dev *dev = video_drvdata(file);331	struct hexium *hexium = (struct hexium *) dev->ext_priv;332 333	*input = hexium->cur_input;334 335	DEB_D("VIDIOC_G_INPUT: %d\n", *input);336	return 0;337}338 339static int vidioc_s_input(struct file *file, void *fh, unsigned int input)340{341	struct saa7146_dev *dev = video_drvdata(file);342	struct hexium *hexium = (struct hexium *) dev->ext_priv;343 344	if (input >= HEXIUM_INPUTS)345		return -EINVAL;346 347	hexium->cur_input = input;348	hexium_set_input(hexium, input);349 350	return 0;351}352 353static struct saa7146_ext_vv vv_data;354 355/* this function only gets called when the probing was successful */356static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)357{358	struct hexium *hexium = (struct hexium *) dev->ext_priv;359	int ret;360 361	DEB_EE("\n");362 363	ret = saa7146_vv_init(dev, &vv_data);364	if (ret) {365		pr_err("Error in saa7146_vv_init()\n");366		return ret;367	}368 369	vv_data.vid_ops.vidioc_enum_input = vidioc_enum_input;370	vv_data.vid_ops.vidioc_g_input = vidioc_g_input;371	vv_data.vid_ops.vidioc_s_input = vidioc_s_input;372	if (0 != saa7146_register_device(&hexium->video_dev, dev, "hexium orion", VFL_TYPE_VIDEO)) {373		pr_err("cannot register capture v4l2 device. skipping.\n");374		return -1;375	}376 377	pr_err("found 'hexium orion' frame grabber-%d\n", hexium_num);378	hexium_num++;379 380	/* the rest */381	hexium->cur_input = 0;382	hexium_init_done(dev);383	hexium_set_input(hexium, 0);384 385	return 0;386}387 388static int hexium_detach(struct saa7146_dev *dev)389{390	struct hexium *hexium = (struct hexium *) dev->ext_priv;391 392	DEB_EE("dev:%p\n", dev);393 394	saa7146_unregister_device(&hexium->video_dev, dev);395	saa7146_vv_release(dev);396 397	hexium_num--;398 399	i2c_del_adapter(&hexium->i2c_adapter);400	kfree(hexium);401	return 0;402}403 404static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *std)405{406	return 0;407}408 409static struct saa7146_extension extension;410 411static struct saa7146_pci_extension_data hexium_hv_pci6 = {412	.ext_priv = "Hexium HV-PCI6 / Orion",413	.ext = &extension,414};415 416static struct saa7146_pci_extension_data hexium_orion_1svhs_3bnc = {417	.ext_priv = "Hexium HV-PCI6 / Orion (1 SVHS/3 BNC)",418	.ext = &extension,419};420 421static struct saa7146_pci_extension_data hexium_orion_4bnc = {422	.ext_priv = "Hexium HV-PCI6 / Orion (4 BNC)",423	.ext = &extension,424};425 426static const struct pci_device_id pci_tbl[] = {427	{428	 .vendor = PCI_VENDOR_ID_PHILIPS,429	 .device = PCI_DEVICE_ID_PHILIPS_SAA7146,430	 .subvendor = 0x0000,431	 .subdevice = 0x0000,432	 .driver_data = (unsigned long) &hexium_hv_pci6,433	 },434	{435	 .vendor = PCI_VENDOR_ID_PHILIPS,436	 .device = PCI_DEVICE_ID_PHILIPS_SAA7146,437	 .subvendor = 0x17c8,438	 .subdevice = 0x0101,439	 .driver_data = (unsigned long) &hexium_orion_1svhs_3bnc,440	 },441	{442	 .vendor = PCI_VENDOR_ID_PHILIPS,443	 .device = PCI_DEVICE_ID_PHILIPS_SAA7146,444	 .subvendor = 0x17c8,445	 .subdevice = 0x2101,446	 .driver_data = (unsigned long) &hexium_orion_4bnc,447	 },448	{449	 .vendor = 0,450	 }451};452 453MODULE_DEVICE_TABLE(pci, pci_tbl);454 455static struct saa7146_ext_vv vv_data = {456	.inputs = HEXIUM_INPUTS,457	.capabilities = 0,458	.stds = &hexium_standards[0],459	.num_stds = ARRAY_SIZE(hexium_standards),460	.std_callback = &std_callback,461};462 463static struct saa7146_extension extension = {464	.name = "hexium HV-PCI6 Orion",465	.flags = 0,		// SAA7146_USE_I2C_IRQ,466 467	.pci_tbl = &pci_tbl[0],468	.module = THIS_MODULE,469 470	.probe = hexium_probe,471	.attach = hexium_attach,472	.detach = hexium_detach,473 474	.irq_mask = 0,475	.irq_func = NULL,476};477 478static int __init hexium_init_module(void)479{480	if (0 != saa7146_register_extension(&extension)) {481		DEB_S("failed to register extension\n");482		return -ENODEV;483	}484 485	return 0;486}487 488static void __exit hexium_cleanup_module(void)489{490	saa7146_unregister_extension(&extension);491}492 493module_init(hexium_init_module);494module_exit(hexium_cleanup_module);495 496MODULE_DESCRIPTION("video4linux-2 driver for Hexium Orion frame grabber cards");497MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");498MODULE_LICENSE("GPL");499