This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Linux/AM5728: tw2964 + VIP Issues

Part Number: AM5728
Other Parts Discussed in Thread: TVP5158, TVP5150

Tool/software: Linux

Hello, I am using the Linux Processor SDK for AM57x v05.02.00.10

I am developing a driver for tw2964 video decoder. As a basic example, I took the tvp5150 and tvp5158 drivers.

I connected the tw2964 to the P9 connector of the TMDSEVM572X kit. See the diagram.

TVP connects to AM5728 as follows:

tw2964 (vd1(0)) <=> am5728 (vin3a_d0)

tw2964 (vd1(1)) <=> am5728 (vin3a_d1)

tw2964 (vd1(2)) <=> am5728 (vin3a_d2)

tw2964 (vd1(3)) <=> am5728 (vin3a_d3)

tw2964 (vd1(4)) <=> am5728 (vin3a_d4)

tw2964 (vd1(5)) <=> am5728 (vin3a_d5)

tw2964 (vd1(6)) <=> am5728 (vin3a_d6)

tw2964 (vd1(7)) <=> am5728 (vin3a_d7)

tw2964 (clkp0) <=> am5728 (vin3a_clko)

Now tw2964 driver successfully works in EMBEDDED_SYNC_SINGLE_YUV422 mode for one vip (vin3a). But I need to do EMBEDDED_SYNC_2X_MULTIPLEXED_YUV422 for two separate vip.

I've read http://wiki.tiprocessors.com/index.php/Processor_SDK_VIP_Driver#Video_Input_Port. Аnd now I have serious concerns about work EMBEDDED_SYNC_2X_MULTIPLEXED_YUV422 and EMBEDDED_SYNC_4X_MULTIPLEXED_YUV422

Therefore, I had 3 questions:

1. Is the vip.c driver able to work in pixel interleaved method mode aka EMBEDDED_SYNC_2X_MULTIPLEXED_YUV422 or EMBEDDED_SYNC_4X_MULTIPLEXED_YUV422?

2. How to implement multichannel single subdevice to work with different vip in EMBEDDED_SYNC_SINGLE_YUV422 mode (some examples)?

Before I ask last questions, I will tell that do not working in EMBEDDED_SYNC_2X_MULTIPLEXED_YUV422 mode for vin3a.

[   93.802177] tw2964: start probe
[   93.802360] tw2964 4-0029: GPIO lookup for consumer reset
[   93.802367] tw2964 4-0029: using device tree for GPIO lookup
[   93.802401] of_get_named_gpiod_flags: parsed 'reset-gpios' property of node '/ocp/i2c@4807c000/tw2964@29[0]' - status (0)
[   93.802736] tw2964: tw2964_init()
[   93.802742] tw2964: tw2964_kzalloc()
[   93.802765] tw2964: tw2964_parse_dt()
[   93.802775] tw2964 4-0029: tw2964: v4l2_i2c_subdev_init()
[   93.802937] tw2964 4-0029: tw2964: read adr'0xfe' dat'0x0'
[   93.803195] tw2964 4-0029: tw2964: read adr'0xff' dat'0xe8'
[   93.803204] tw2964 4-0029: tw2964 dev_id=0x001d (0.232) chip found @ 0x29 (OMAP I2C adapter)
[   93.812281] tw2964 4-0029: tw2964 detected.
[   93.816531] tw2964 4-0029: tw2964: tw2964_detect_version()
[   93.816559] tw2964 4-0029: tw2964: v4l2_ctrl_handler_init()
[   93.816876] tw2964: read adr'0x3e' dat'0x97'
[   93.816884] tw2964 4-0029: tw2964: tw2964_read_std()
[   93.816889] tw2964: write_all_regs()-size_of_mass_regs-'120'
[   93.817042] tw2964: [#0]write_all_regs()ret'0',regs'0x1',data'0x0'
[   93.817278] tw2964: [#2]write_all_regs()ret'0',regs'0x11',data'0x0'
[   93.817386] tw2964: [#4]write_all_regs()ret'0',regs'0x21',data'0x0'
[   93.817491] tw2964: [#6]write_all_regs()ret'0',regs'0x31',data'0x0'
[   93.817609] tw2964: [#8]write_all_regs()ret'0',regs'0x2',data'0x64'
[   93.817716] tw2964: [#10]write_all_regs()ret'0',regs'0x12',data'0x64'
[   93.821152] tw2964: [#12]write_all_regs()ret'0',regs'0x22',data'0x64'
[   93.821263] tw2964: [#14]write_all_regs()ret'0',regs'0x32',data'0x64'
[   93.821370] tw2964: [#16]write_all_regs()ret'0',regs'0x3',data'0x11'
[   93.821478] tw2964: [#18]write_all_regs()ret'0',regs'0x13',data'0x11'
[   93.821583] tw2964: [#20]write_all_regs()ret'0',regs'0x23',data'0x11'
[   93.821688] tw2964: [#22]write_all_regs()ret'0',regs'0x33',data'0x11'
[   93.821792] tw2964: [#24]write_all_regs()ret'0',regs'0x4',data'0x80'
[   93.821907] tw2964: [#26]write_all_regs()ret'0',regs'0x14',data'0x80'
[   93.822012] tw2964: [#28]write_all_regs()ret'0',regs'0x24',data'0x80'
[   93.822116] tw2964: [#30]write_all_regs()ret'0',regs'0x34',data'0x80'
[   93.822220] tw2964: [#32]write_all_regs()ret'0',regs'0x5',data'0x80'
[   93.822334] tw2964: [#34]write_all_regs()ret'0',regs'0x15',data'0x80'
[   93.822440] tw2964: [#36]write_all_regs()ret'0',regs'0x25',data'0x80'
[   93.822543] tw2964: [#38]write_all_regs()ret'0',regs'0x35',data'0x80'
[   93.822646] tw2964: [#40]write_all_regs()ret'0',regs'0x6',data'0x0'
[   93.822754] tw2964: [#42]write_all_regs()ret'0',regs'0x16',data'0x0'
[   93.822859] tw2964: [#44]write_all_regs()ret'0',regs'0x26',data'0x0'
[   93.822962] tw2964: [#46]write_all_regs()ret'0',regs'0x36',data'0x0'
[   93.823066] tw2964: [#48]write_all_regs()ret'0',regs'0x7',data'0x12'
[   93.823171] tw2964: [#50]write_all_regs()ret'0',regs'0x17',data'0x12'
[   93.823276] tw2964: [#52]write_all_regs()ret'0',regs'0x27',data'0x12'
[   93.823380] tw2964: [#54]write_all_regs()ret'0',regs'0x37',data'0x12'
[   93.823515] tw2964: [#56]write_all_regs()ret'0',regs'0x8',data'0x12'
[   93.823624] tw2964: [#58]write_all_regs()ret'0',regs'0x18',data'0x12'
[   93.823728] tw2964: [#60]write_all_regs()ret'0',regs'0x28',data'0x12'
[   93.823832] tw2964: [#62]write_all_regs()ret'0',regs'0x38',data'0x12'
[   93.823945] tw2964: [#64]write_all_regs()ret'0',regs'0x9',data'0x20'
[   93.824050] tw2964: [#66]write_all_regs()ret'0',regs'0x19',data'0x20'
[   93.824153] tw2964: [#68]write_all_regs()ret'0',regs'0x29',data'0x20'
[   93.824257] tw2964: [#70]write_all_regs()ret'0',regs'0x39',data'0x20'
[   93.824364] tw2964: [#72]write_all_regs()ret'0',regs'0xa',data'0xa'
[   93.824470] tw2964: [#74]write_all_regs()ret'0',regs'0x1a',data'0xa'
[   93.824574] tw2964: [#76]write_all_regs()ret'0',regs'0x2a',data'0xa'
[   93.824679] tw2964: [#78]write_all_regs()ret'0',regs'0x3a',data'0xa'
[   93.824783] tw2964: [#80]write_all_regs()ret'0',regs'0xb',data'0xd0'
[   93.824892] tw2964: [#82]write_all_regs()ret'0',regs'0x1b',data'0xd0'
[   93.824996] tw2964: [#84]write_all_regs()ret'0',regs'0x2b',data'0xd0'
[   93.825100] tw2964: [#86]write_all_regs()ret'0',regs'0x3b',data'0xd0'
[   93.825204] tw2964: [#88]write_all_regs()ret'0',regs'0xe',data'0x7'
[   93.825309] tw2964: [#90]write_all_regs()ret'0',regs'0x1e',data'0x7'
[   93.825413] tw2964: [#92]write_all_regs()ret'0',regs'0x2e',data'0x7'
[   93.825538] tw2964: [#94]write_all_regs()ret'0',regs'0x3e',data'0x7'
[   93.825641] tw2964: [#96]write_all_regs()ret'0',regs'0xf',data'0x7f'
[   93.825745] tw2964: [#98]write_all_regs()ret'0',regs'0x1f',data'0x7f'
[   93.825850] tw2964: [#100]write_all_regs()ret'0',regs'0x2f',data'0x7f'
[   93.825960] tw2964: [#102]write_all_regs()ret'0',regs'0x3f',data'0x7f'
[   93.826068] tw2964: [#104]write_all_regs()ret'0',regs'0xa0',data'0x8'
[   93.826173] tw2964: [#106]write_all_regs()ret'0',regs'0xb0',data'0x8'
[   93.826282] tw2964: [#108]write_all_regs()ret'0',regs'0xc0',data'0x8'
[   93.826390] tw2964: [#110]write_all_regs()ret'0',regs'0xd0',data'0x8'
[   93.826494] tw2964: [#112]write_all_regs()ret'0',regs'0xa4',data'0x9c'
[   93.826599] tw2964: [#114]write_all_regs()ret'0',regs'0xb4',data'0x9c'
[   93.826722] tw2964: [#116]write_all_regs()ret'0',regs'0xc4',data'0x9c'
[   93.826827] tw2964: [#118]write_all_regs()ret'0',regs'0xd4',data'0x9c'
[   93.826831] tw2964: write_all_regs()-size_of_mass_regs-'260'
[   93.826935] tw2964: [#0]write_all_regs()ret'0',regs'0x4f',data'0x0'
[   93.827040] tw2964: [#2]write_all_regs()ret'0',regs'0x50',data'0x0'
[   93.827143] tw2964: [#4]write_all_regs()ret'0',regs'0x51',data'0x0'
[   93.827246] tw2964: [#6]write_all_regs()ret'0',regs'0x52',data'0x0'
[   93.827353] tw2964: [#8]write_all_regs()ret'0',regs'0x54',data'0x7'
[   93.827457] tw2964: [#10]write_all_regs()ret'0',regs'0x55',data'0x0'
[   93.827561] tw2964: [#12]write_all_regs()ret'0',regs'0x56',data'0x0'
[   93.827691] tw2964: [#14]write_all_regs()ret'0',regs'0x57',data'0x90'
[   93.827797] tw2964: [#16]write_all_regs()ret'0',regs'0x58',data'0x90'
[   93.827901] tw2964: [#18]write_all_regs()ret'0',regs'0x59',data'0x90'
[   93.828004] tw2964: [#20]write_all_regs()ret'0',regs'0x5a',data'0x90'
[   93.828114] tw2964: [#22]write_all_regs()ret'0',regs'0x5b',data'0x0'
[   93.828219] tw2964: [#24]write_all_regs()ret'0',regs'0x5c',data'0x0'
[   93.828324] tw2964: [#26]write_all_regs()ret'0',regs'0x5d',data'0xe0'
[   93.828427] tw2964: [#28]write_all_regs()ret'0',regs'0x5e',data'0xe0'
[   93.828536] tw2964: [#30]write_all_regs()ret'0',regs'0x5f',data'0xe0'
[   93.828645] tw2964: [#32]write_all_regs()ret'0',regs'0x60',data'0x26'
[   93.828751] tw2964: [#34]write_all_regs()ret'0',regs'0x61',data'0x1f'
[   93.828855] tw2964: [#36]write_all_regs()ret'0',regs'0x62',data'0x0'
[   93.828960] tw2964: [#38]write_all_regs()ret'0',regs'0x63',data'0x10'
[   93.829064] tw2964: [#40]write_all_regs()ret'0',regs'0x64',data'0x32'
[   93.829168] tw2964: [#42]write_all_regs()ret'0',regs'0x65',data'0x0'
[   93.829272] tw2964: [#44]write_all_regs()ret'0',regs'0x67',data'0x80'
[   93.829377] tw2964: [#46]write_all_regs()ret'0',regs'0x68',data'0x0'
[   93.829481] tw2964: [#48]write_all_regs()ret'0',regs'0x69',data'0x0'
[   93.829584] tw2964: [#50]write_all_regs()ret'0',regs'0x6a',data'0x0'
[   93.829698] tw2964: [#52]write_all_regs()ret'0',regs'0x6b',data'0x0'
[   93.829803] tw2964: [#54]write_all_regs()ret'0',regs'0x6c',data'0x0'
[   93.829908] tw2964: [#56]write_all_regs()ret'0',regs'0x6d',data'0x28'
[   93.830012] tw2964: [#58]write_all_regs()ret'0',regs'0x6e',data'0x38'
[   93.830116] tw2964: [#60]write_all_regs()ret'0',regs'0x70',data'0x8'
[   93.831468] tw2964: [#62]write_all_regs()ret'0',regs'0x71',data'0x40'
[   93.831575] tw2964: [#64]write_all_regs()ret'0',regs'0x72',data'0x28'
[   93.831679] tw2964: [#66]write_all_regs()ret'0',regs'0x73',data'0x0'
[   93.831781] tw2964: [#68]write_all_regs()ret'0',regs'0x74',data'0x0'
[   93.831885] tw2964: [#70]write_all_regs()ret'0',regs'0x75',data'0x0'
[   93.831987] tw2964: [#72]write_all_regs()ret'0',regs'0x76',data'0x0'
[   93.832090] tw2964: [#74]write_all_regs()ret'0',regs'0x7b',data'0x15'
[   93.832192] tw2964: [#76]write_all_regs()ret'0',regs'0x7c',data'0x15'
[   93.832294] tw2964: [#78]write_all_regs()ret'0',regs'0x7d',data'0xe4'
[   93.832402] tw2964: [#80]write_all_regs()ret'0',regs'0x7e',data'0xa3'
[   93.832508] tw2964: [#82]write_all_regs()ret'0',regs'0x7f',data'0x66'
[   93.832610] tw2964: [#84]write_all_regs()ret'0',regs'0x80',data'0x0'
[   93.832712] tw2964: [#86]write_all_regs()ret'0',regs'0x81',data'0x2'
[   93.832814] tw2964: [#88]write_all_regs()ret'0',regs'0x82',data'0x0'
[   93.832917] tw2964: [#90]write_all_regs()ret'0',regs'0x83',data'0xcc'
[   93.833019] tw2964: [#92]write_all_regs()ret'0',regs'0x84',data'0x0'
[   93.833121] tw2964: [#94]write_all_regs()ret'0',regs'0x85',data'0x30'
[   93.833223] tw2964: [#96]write_all_regs()ret'0',regs'0x86',data'0x44'
[   93.833325] tw2964: [#98]write_all_regs()ret'0',regs'0x87',data'0x50'
[   93.833427] tw2964: [#100]write_all_regs()ret'0',regs'0x88',data'0x42'
[   93.833529] tw2964: [#102]write_all_regs()ret'0',regs'0x89',data'0x0'
[   93.833631] tw2964: [#104]write_all_regs()ret'0',regs'0x8a',data'0xd8'
[   93.833733] tw2964: [#106]write_all_regs()ret'0',regs'0x8b',data'0xbc'
[   93.833835] tw2964: [#108]write_all_regs()ret'0',regs'0x8c',data'0xb8'
[   93.833937] tw2964: [#110]write_all_regs()ret'0',regs'0x8d',data'0x44'
[   93.834039] tw2964: [#112]write_all_regs()ret'0',regs'0x8e',data'0x36'
[   93.834141] tw2964: [#114]write_all_regs()ret'0',regs'0x8f',data'0x0'
[   93.834244] tw2964: [#116]write_all_regs()ret'0',regs'0x90',data'0x0'
[   93.834345] tw2964: [#118]write_all_regs()ret'0',regs'0x91',data'0x78'
[   93.834447] tw2964: [#120]write_all_regs()ret'0',regs'0x92',data'0x44'
[   93.834550] tw2964: [#122]write_all_regs()ret'0',regs'0x93',data'0x30'
[   93.834654] tw2964: [#124]write_all_regs()ret'0',regs'0x94',data'0x14'
[   93.834756] tw2964: [#126]write_all_regs()ret'0',regs'0x95',data'0xa5'
[   93.834859] tw2964: [#128]write_all_regs()ret'0',regs'0x96',data'0xe0'
[   93.834961] tw2964: [#130]write_all_regs()ret'0',regs'0x97',data'0x5'
[   93.835064] tw2964: [#132]write_all_regs()ret'0',regs'0x98',data'0x0'
[   93.835166] tw2964: [#134]write_all_regs()ret'0',regs'0x99',data'0x13'
[   93.835268] tw2964: [#136]write_all_regs()ret'0',regs'0x9a',data'0x1f'
[   93.835369] tw2964: [#138]write_all_regs()ret'0',regs'0x9b',data'0x44'
[   93.835471] tw2964: [#140]write_all_regs()ret'0',regs'0x9c',data'0x20'
[   93.835573] tw2964: [#142]write_all_regs()ret'0',regs'0x9e',data'0x42'
[   93.835681] tw2964: [#144]write_all_regs()ret'0',regs'0x9f',data'0x0'
[   93.835786] tw2964: [#146]write_all_regs()ret'0',regs'0xaa',data'0x0'
[   93.835888] tw2964: [#148]write_all_regs()ret'0',regs'0xab',data'0xf0'
[   93.835990] tw2964: [#150]write_all_regs()ret'0',regs'0xac',data'0xf0'
[   93.836093] tw2964: [#152]write_all_regs()ret'0',regs'0xad',data'0xf0'
[   93.836195] tw2964: [#154]write_all_regs()ret'0',regs'0xae',data'0xf0'
[   93.836296] tw2964: [#156]write_all_regs()ret'0',regs'0xaf',data'0x0'
[   93.836398] tw2964: [#158]write_all_regs()ret'0',regs'0xb0',data'0x0'
[   93.836500] tw2964: [#160]write_all_regs()ret'0',regs'0xb1',data'0x0'
[   93.836602] tw2964: [#162]write_all_regs()ret'0',regs'0xb2',data'0x0'
[   93.836704] tw2964: [#164]write_all_regs()ret'0',regs'0xb3',data'0x0'
[   93.836807] tw2964: [#166]write_all_regs()ret'0',regs'0xb4',data'0x0'
[   93.836908] tw2964: [#168]write_all_regs()ret'0',regs'0xb5',data'0x0'
[   93.837010] tw2964: [#170]write_all_regs()ret'0',regs'0xb6',data'0x0'
[   93.837112] tw2964: [#172]write_all_regs()ret'0',regs'0xb7',data'0x0'
[   93.837215] tw2964: [#174]write_all_regs()ret'0',regs'0xc8',data'0x0'
[   93.837316] tw2964: [#176]write_all_regs()ret'0',regs'0xc9',data'0x0'
[   93.837417] tw2964: [#178]write_all_regs()ret'0',regs'0xca',data'0x0'
[   93.837519] tw2964: [#180]write_all_regs()ret'0',regs'0xcb',data'0x0'
[   93.837622] tw2964: [#182]write_all_regs()ret'0',regs'0xcc',data'0x39'
[   93.837723] tw2964: [#184]write_all_regs()ret'0',regs'0xcd',data'0xe4'
[   93.837826] tw2964: [#186]write_all_regs()ret'0',regs'0xce',data'0x0'
[   93.837927] tw2964: [#188]write_all_regs()ret'0',regs'0xcf',data'0x0'
[   93.838029] tw2964: [#190]write_all_regs()ret'0',regs'0xd0',data'0x66'
[   93.838137] tw2964: [#192]write_all_regs()ret'0',regs'0xd1',data'0x66'
[   93.838241] tw2964: [#194]write_all_regs()ret'0',regs'0xd2',data'0x0'
[   93.838346] tw2964: [#196]write_all_regs()ret'0',regs'0xd3',data'0x10'
[   93.838449] tw2964: [#198]write_all_regs()ret'0',regs'0xd4',data'0x32'
[   93.838553] tw2964: [#200]write_all_regs()ret'0',regs'0xd5',data'0x54'
[   93.838656] tw2964: [#202]write_all_regs()ret'0',regs'0xd6',data'0x76'
[   93.838762] tw2964: [#204]write_all_regs()ret'0',regs'0xd7',data'0x98'
[   93.838868] tw2964: [#206]write_all_regs()ret'0',regs'0xd8',data'0xba'
[   93.838976] tw2964: [#208]write_all_regs()ret'0',regs'0xd9',data'0xdc'
[   93.839083] tw2964: [#210]write_all_regs()ret'0',regs'0xda',data'0xfe'
[   93.839190] tw2964: [#212]write_all_regs()ret'0',regs'0xdb',data'0xc2'
[   93.839293] tw2964: [#214]write_all_regs()ret'0',regs'0xdc',data'0x10'
[   93.839397] tw2964: [#216]write_all_regs()ret'0',regs'0xdd',data'0x0'
[   93.839500] tw2964: [#218]write_all_regs()ret'0',regs'0xde',data'0x0'
[   93.839604] tw2964: [#220]write_all_regs()ret'0',regs'0xdf',data'0x80'
[   93.839707] tw2964: [#222]write_all_regs()ret'0',regs'0xe0',data'0x1f'
[   93.839810] tw2964: [#224]write_all_regs()ret'0',regs'0xe1',data'0xf0'
[   93.839913] tw2964: [#226]write_all_regs()ret'0',regs'0xe2',data'0x33'
[   93.840018] tw2964: [#228]write_all_regs()ret'0',regs'0xe3',data'0x33'
[   93.840121] tw2964: [#230]write_all_regs()ret'0',regs'0xf0',data'0x23'
[   93.840226] tw2964: [#232]write_all_regs()ret'0',regs'0xf1',data'0x48'
[   93.840329] tw2964: [#234]write_all_regs()ret'0',regs'0xf2',data'0x7'
[   93.840433] tw2964: [#236]write_all_regs()ret'0',regs'0xf3',data'0x0'
[   93.840536] tw2964: [#238]write_all_regs()ret'0',regs'0xf4',data'0x1'
[   93.840640] tw2964: [#240]write_all_regs()ret'0',regs'0xf5',data'0x0'
[   93.840742] tw2964: [#242]write_all_regs()ret'0',regs'0xf6',data'0x0'
[   93.841796] tw2964: [#244]write_all_regs()ret'0',regs'0xf7',data'0x20'
[   93.841906] tw2964: [#246]write_all_regs()ret'0',regs'0xf8',data'0xc4'
[   93.842010] tw2964: [#248]write_all_regs()ret'0',regs'0xf9',data'0x40'
[   93.842114] tw2964: [#250]write_all_regs()ret'0',regs'0xfa',data'0x0'
[   93.842217] tw2964: [#252]write_all_regs()ret'0',regs'0xfb',data'0xf'
[   93.842322] tw2964: [#254]write_all_regs()ret'0',regs'0xfc',data'0xff'
[   93.842426] tw2964: [#256]write_all_regs()ret'0',regs'0xfd',data'0x0'
[   93.842529] tw2964: [#258]write_all_regs()ret'0',regs'0xfe',data'0x0'
[   93.842537] tw2964 4-0029: Selecting video route: route input=0 tw2964 input=0
[   93.842542] tw2964 4-0029: tw2964: writing adr'0x85' dat'0x30'
[   93.842788] tw2964 4-0029: tw2964: read adr'0x85' dat'0x30'
[   93.842793] tw2964 4-0029: TW2964_REG_SHCOR960:=0x30
[   93.842900] tw2964: write adr'0x33' dat'0x1'
[   93.843004] tw2964: write adr'0x34' dat'0x80'
[   93.843108] tw2964: write adr'0x35' dat'0x80'
[   93.843216] tw2964: write adr'0x32' dat'0x64'
[   93.843322] tw2964: write adr'0x31' dat'0x0'
[   93.843429] tw2964: write adr'0x36' dat'0x0'
[   93.843435] tw2964 4-0029: Set video std register to 1.
[   93.843537] tw2964: write adr'0x3e' dat'0x1'
[   93.843542] tw2964 4-0029: Set video std register to 1.
[   93.843646] tw2964: write adr'0x3e' dat'0x1'
[   93.843651] tw2964 4-0029: tw2964: tw2964_reset()
[   93.843662] vin3a: Port A: Using subdev tw2964 4-0029 for capture
[   93.849783] vin3a: subdev tw2964 4-0029: code: 2006 idx: 0
[   93.859783] tw2964 4-0029: tw2964: v4l2_async_register_subdev()
[   93.859936] tw2964 4-0029: tw2964: read adr'0xfa' dat'0x0'
[   93.860087] tw2964 4-0029: tw2964: read adr'0xca' dat'0x0'
[   93.860232] tw2964 4-0029: tw2964: read adr'0xcd' dat'0xe4'
[   93.860379] tw2964 4-0029: tw2964: read adr'0xcc' dat'0x39'
[   93.860385] tw2964 4-0029: tw2964: writing adr'0xcd' dat'0xe8'
[   93.860496] tw2964 4-0029: tw2964: writing adr'0xcc' dat'0x3d'
[   93.860601] tw2964 4-0029: tw2964: writing adr'0xfa' dat'0x45'
[   93.860711] tw2964 4-0029: tw2964: writing adr'0xca' dat'0x5'
[   93.861129] tw2964 4-0029: tw2964: read adr'0xfa' dat'0x45'
[   93.861279] tw2964 4-0029: tw2964: read adr'0xca' dat'0x5'
[   93.861432] tw2964 4-0029: tw2964: read adr'0xcd' dat'0xe8'
[   93.861584] tw2964 4-0029: tw2964: read adr'0xcc' dat'0x3d'
[   93.861589] tw2964 4-0029: TW2964_REG_CLKOCTL:=0x45
[   93.861593] tw2964 4-0029: TW2964_REG_CHMD:=0x5
[   93.861598] tw2964 4-0029: TTW2964_REG_MAINCH:=0xe8
[   93.861603] tw2964 4-0029: TW2964_REG_SELCH:=0x3d
[   93.861607] tw2964 4-0029: begin etx_driver_init()
[   93.861613] tw2964: Major = 239 Minor = 0 
[   93.861726] tw2964: device driver insert...Done!!!
[   93.861731] tw2964 4-0029: end etx_driver_init()
[   93.861735] tw2964 4-0029: Standard: 50 Hz
[   93.865863] tw2964 4-0029: Channel: 0
[   93.869537] tw2964 4-0029: Input: 0
[   93.873258] tw2964 4-0029: Standard: 50 Hz
[   93.877368] tw2964 4-0029: Channel: 0
[   93.881071] tw2964 4-0029: Input: 0
[   93.884747] tw2964 4-0029: tw2964: read adr'0x0' dat'0x13'
[   93.884896] tw2964 4-0029: tw2964: read adr'0x1' dat'0x0'
[   93.885041] tw2964 4-0029: tw2964: read adr'0x2' dat'0x64'
[   93.885185] tw2964 4-0029: tw2964: read adr'0x3' dat'0x11'
[   93.885339] tw2964 4-0029: tw2964: read adr'0x4' dat'0x80'
[   93.885491] tw2964 4-0029: tw2964: read adr'0x5' dat'0x80'
[   93.885632] tw2964 4-0029: tw2964: read adr'0x6' dat'0x0'
[   93.885784] tw2964 4-0029: tw2964: read adr'0x7' dat'0x12'
[   93.885928] tw2964 4-0029: tw2964: read adr'0x8' dat'0x12'
[   93.886070] tw2964 4-0029: tw2964: read adr'0x9' dat'0x20'
[   93.886211] tw2964 4-0029: tw2964: read adr'0xa' dat'0xa'
[   93.886355] tw2964 4-0029: tw2964: read adr'0xb' dat'0xd0'
[   93.886514] tw2964 4-0029: tw2964: read adr'0xc' dat'0x0'
[   93.886685] tw2964 4-0029: tw2964: read adr'0xd' dat'0x0'
[   93.886829] tw2964 4-0029: tw2964: read adr'0xe' dat'0x97'
[   93.886975] tw2964 4-0029: tw2964: read adr'0xf' dat'0x7f'
[   93.887150] tw2964 4-0029: tw2964: read adr'0x10' dat'0x87'
[   93.887293] tw2964 4-0029: tw2964: read adr'0x11' dat'0x0'
[   93.887441] tw2964 4-0029: tw2964: read adr'0x12' dat'0x64'
[   93.887588] tw2964 4-0029: tw2964: read adr'0x13' dat'0x11'
[   93.887733] tw2964 4-0029: tw2964: read adr'0x14' dat'0x80'
[   93.887879] tw2964 4-0029: tw2964: read adr'0x15' dat'0x80'
[   93.888019] tw2964 4-0029: tw2964: read adr'0x16' dat'0x0'
[   93.888162] tw2964 4-0029: tw2964: read adr'0x17' dat'0x12'
[   93.888309] tw2964 4-0029: tw2964: read adr'0x18' dat'0x12'
[   93.888450] tw2964 4-0029: tw2964: read adr'0x19' dat'0x20'
[   93.888627] tw2964 4-0029: tw2964: read adr'0x1a' dat'0xa'
[   93.888812] tw2964 4-0029: tw2964: read adr'0x1b' dat'0xd0'
[   93.889013] tw2964 4-0029: tw2964: read adr'0x1c' dat'0x50'
[   93.889185] tw2964 4-0029: tw2964: read adr'0x1d' dat'0x0'
[   93.889356] tw2964 4-0029: tw2964: read adr'0x1e' dat'0x97'
[   93.889552] tw2964 4-0029: tw2964: read adr'0x1f' dat'0x7f'
[   93.889706] tw2964 4-0029: tw2964: read adr'0x20' dat'0x87'
[   93.889863] tw2964 4-0029: tw2964: read adr'0x21' dat'0x0'
[   93.890047] tw2964 4-0029: tw2964: read adr'0x22' dat'0x64'
[   93.890228] tw2964 4-0029: tw2964: read adr'0x23' dat'0x11'
[   93.890398] tw2964 4-0029: tw2964: read adr'0x24' dat'0x80'
[   93.890556] tw2964 4-0029: tw2964: read adr'0x25' dat'0x80'
[   93.890717] tw2964 4-0029: tw2964: read adr'0x26' dat'0x0'
[   93.890895] tw2964 4-0029: tw2964: read adr'0x27' dat'0x12'
[   93.891065] tw2964 4-0029: tw2964: read adr'0x28' dat'0x12'
[   93.891244] tw2964 4-0029: tw2964: read adr'0x29' dat'0x20'
[   93.891416] tw2964 4-0029: tw2964: read adr'0x2a' dat'0xa'
[   93.891604] tw2964 4-0029: tw2964: read adr'0x2b' dat'0xd0'
[   93.891768] tw2964 4-0029: tw2964: read adr'0x2c' dat'0x50'
[   93.891931] tw2964 4-0029: tw2964: read adr'0x2d' dat'0x0'
[   93.892093] tw2964 4-0029: tw2964: read adr'0x2e' dat'0x97'
[   93.892274] tw2964 4-0029: tw2964: read adr'0x2f' dat'0x7f'
[   93.892432] tw2964 4-0029: tw2964: read adr'0x30' dat'0x87'
[   93.892591] tw2964 4-0029: tw2964: read adr'0x31' dat'0x0'
[   93.892791] tw2964 4-0029: tw2964: read adr'0x32' dat'0x64'
[   93.892952] tw2964 4-0029: tw2964: read adr'0x33' dat'0x1'
[   93.893512] tw2964 4-0029: tw2964: read adr'0x34' dat'0x80'
[   93.893672] tw2964 4-0029: tw2964: read adr'0x35' dat'0x80'
[   93.893837] tw2964 4-0029: tw2964: read adr'0x36' dat'0x0'
[   93.894002] tw2964 4-0029: tw2964: read adr'0x37' dat'0x12'
[   93.894161] tw2964 4-0029: tw2964: read adr'0x38' dat'0x12'
[   93.894356] tw2964 4-0029: tw2964: read adr'0x39' dat'0x20'
[   93.894538] tw2964 4-0029: tw2964: read adr'0x3a' dat'0xa'
[   93.894716] tw2964 4-0029: tw2964: read adr'0x3b' dat'0xd0'
[   93.894893] tw2964 4-0029: tw2964: read adr'0x3c' dat'0x50'
[   93.895053] tw2964 4-0029: tw2964: read adr'0x3d' dat'0x0'
[   93.895206] tw2964 4-0029: tw2964: read adr'0x3e' dat'0x11'
[   93.895398] tw2964 4-0029: tw2964: read adr'0x3f' dat'0x7f'
[   93.895579] tw2964 4-0029: tw2964: read adr'0x40' dat'0x0'
[   93.895735] tw2964 4-0029: tw2964: read adr'0x41' dat'0x40'
[   93.895951] tw2964 4-0029: tw2964: read adr'0x42' dat'0x90'
[   93.896116] tw2964 4-0029: tw2964: read adr'0x43' dat'0x8'
[   93.896298] tw2964 4-0029: tw2964: read adr'0x44' dat'0x0'
[   93.896468] tw2964 4-0029: tw2964: read adr'0x45' dat'0x38'
[   93.896643] tw2964 4-0029: tw2964: read adr'0x46' dat'0x80'
[   93.896802] tw2964 4-0029: tw2964: read adr'0x47' dat'0x80'
[   93.896960] tw2964 4-0029: tw2964: read adr'0x48' dat'0x80'
[   93.897115] tw2964 4-0029: tw2964: read adr'0x49' dat'0x80'
[   93.897294] tw2964 4-0029: tw2964: read adr'0x4a' dat'0xb'
[   93.897456] tw2964 4-0029: tw2964: read adr'0x4b' dat'0x30'
[   93.897626] tw2964 4-0029: tw2964: read adr'0x4c' dat'0x0'
[   93.897782] tw2964 4-0029: tw2964: read adr'0x4d' dat'0x0'
[   93.897992] tw2964 4-0029: tw2964: read adr'0x4e' dat'0x0'
[   93.898172] tw2964 4-0029: tw2964: read adr'0x4f' dat'0x0'
[   93.898355] tw2964 4-0029: tw2964: read adr'0x50' dat'0x0'
[   93.898531] tw2964 4-0029: tw2964: read adr'0x51' dat'0x0'
[   93.898746] tw2964 4-0029: tw2964: read adr'0x52' dat'0x0'
[   93.898907] tw2964 4-0029: tw2964: read adr'0x53' dat'0x0'
[   93.899056] tw2964 4-0029: tw2964: read adr'0x54' dat'0x7'
[   93.899222] tw2964 4-0029: tw2964: read adr'0x55' dat'0x0'
[   93.899379] tw2964 4-0029: tw2964: read adr'0x56' dat'0x0'
[   93.899555] tw2964 4-0029: tw2964: read adr'0x57' dat'0x90'
[   93.899712] tw2964 4-0029: tw2964: read adr'0x58' dat'0x90'
[   93.899866] tw2964 4-0029: tw2964: read adr'0x59' dat'0x90'
[   93.900010] tw2964 4-0029: tw2964: read adr'0x5a' dat'0x90'
[   93.900155] tw2964 4-0029: tw2964: read adr'0x5b' dat'0x0'
[   93.900307] tw2964 4-0029: tw2964: read adr'0x5c' dat'0x0'
[   93.900452] tw2964 4-0029: tw2964: read adr'0x5d' dat'0xe0'
[   93.900611] tw2964 4-0029: tw2964: read adr'0x5e' dat'0xe0'
[   93.900756] tw2964 4-0029: tw2964: read adr'0x5f' dat'0xe0'
[   93.900952] tw2964 4-0029: tw2964: read adr'0x60' dat'0x26'
[   93.901103] tw2964 4-0029: tw2964: read adr'0x61' dat'0x1f'
[   93.901266] tw2964 4-0029: tw2964: read adr'0x62' dat'0x0'
[   93.901430] tw2964 4-0029: tw2964: read adr'0x63' dat'0x10'
[   93.901608] tw2964 4-0029: tw2964: read adr'0x64' dat'0x32'
[   93.901761] tw2964 4-0029: tw2964: read adr'0x65' dat'0x0'
[   93.901915] tw2964 4-0029: tw2964: read adr'0x66' dat'0x0'
[   93.902067] tw2964 4-0029: tw2964: read adr'0x67' dat'0x80'
[   93.902234] tw2964 4-0029: tw2964: read adr'0x68' dat'0x0'
[   93.902350] tw2964 4-0029: width = 704, height = 280
[   93.902391] tw2964 4-0029: tw2964: read adr'0x69' dat'0x0'
[   93.902551] tw2964 4-0029: tw2964: read adr'0x6a' dat'0x0'
[   93.902765] tw2964 4-0029: tw2964: read adr'0x6b' dat'0x0'
[   93.902912] tw2964 4-0029: tw2964: read adr'0x6c' dat'0x0'
[   93.904570] tw2964 4-0029: tw2964: read adr'0x6d' dat'0x28'
[   93.904723] tw2964 4-0029: tw2964: read adr'0x6e' dat'0x38'
[   93.905482] tw2964 4-0029: tw2964: read adr'0x6f' dat'0x0'
[   93.905633] tw2964 4-0029: tw2964: read adr'0x70' dat'0x8'
[   93.905784] tw2964 4-0029: tw2964: read adr'0x71' dat'0x40'
[   93.905941] tw2964 4-0029: tw2964: read adr'0x72' dat'0x28'
[   93.906132] tw2964 4-0029: tw2964: read adr'0x73' dat'0x0'
[   93.906310] tw2964 4-0029: tw2964: read adr'0x74' dat'0x0'
[   93.906464] tw2964 4-0029: tw2964: read adr'0x75' dat'0x0'
[   93.906619] tw2964 4-0029: tw2964: read adr'0x76' dat'0x0'
[   93.906783] tw2964 4-0029: tw2964: read adr'0x77' dat'0x0'
[   93.906934] tw2964 4-0029: tw2964: read adr'0x78' dat'0x0'
[   93.907104] tw2964 4-0029: tw2964: read adr'0x79' dat'0x0'
[   93.907258] tw2964 4-0029: tw2964: read adr'0x7a' dat'0x0'
[   93.907421] tw2964 4-0029: tw2964: read adr'0x7b' dat'0x15'
[   93.907582] tw2964 4-0029: tw2964: read adr'0x7c' dat'0x15'
[   93.907733] tw2964 4-0029: tw2964: read adr'0x7d' dat'0xe4'
[   93.907893] tw2964 4-0029: tw2964: read adr'0x7e' dat'0xa3'
[   93.908045] tw2964 4-0029: tw2964: read adr'0x7f' dat'0x66'
[   93.908254] tw2964 4-0029: tw2964: read adr'0x80' dat'0x0'
[   93.908409] tw2964 4-0029: tw2964: read adr'0x81' dat'0x2'
[   93.908578] tw2964 4-0029: tw2964: read adr'0x82' dat'0x0'
[   93.908725] tw2964 4-0029: tw2964: read adr'0x83' dat'0xcc'
[   93.908915] tw2964 4-0029: tw2964: read adr'0x84' dat'0x0'
[   93.908969] tw2964 4-0029: width = 704, height = 280
[   93.909065] tw2964 4-0029: tw2964: read adr'0x85' dat'0x30'
[   93.909241] tw2964 4-0029: tw2964: read adr'0x86' dat'0x44'
[   93.909394] tw2964 4-0029: tw2964: read adr'0x87' dat'0x50'
[   93.909544] tw2964 4-0029: tw2964: read adr'0x88' dat'0x42'
[   93.909725] tw2964 4-0029: tw2964: read adr'0x89' dat'0x0'
[   93.909877] tw2964 4-0029: tw2964: read adr'0x8a' dat'0xd8'
[   93.910061] tw2964 4-0029: tw2964: read adr'0x8b' dat'0xbc'
[   93.910265] tw2964 4-0029: tw2964: read adr'0x8c' dat'0xb8'
[   93.910414] tw2964 4-0029: tw2964: read adr'0x8d' dat'0x44'
[   93.910560] tw2964 4-0029: tw2964: read adr'0x8e' dat'0x36'
[   93.910825] tw2964 4-0029: tw2964: read adr'0x8f' dat'0x0'
[   93.912326] tw2964 4-0029: tw2964: read adr'0x90' dat'0x0'
[   93.912473] tw2964 4-0029: tw2964: read adr'0x91' dat'0x78'
[   93.912624] tw2964 4-0029: tw2964: read adr'0x92' dat'0x44'
[   93.913186] tw2964 4-0029: tw2964: read adr'0x93' dat'0x30'
[   93.914569] tw2964 4-0029: tw2964: read adr'0x94' dat'0x14'
[   93.915228] tw2964 4-0029: tw2964: read adr'0x95' dat'0xa5'
[   93.915377] tw2964 4-0029: tw2964: read adr'0x96' dat'0xe0'
[   93.915522] tw2964 4-0029: tw2964: read adr'0x97' dat'0x5'
[   93.915662] tw2964 4-0029: tw2964: read adr'0x98' dat'0x0'
[   93.915809] tw2964 4-0029: tw2964: read adr'0x99' dat'0x13'
[   93.915952] tw2964 4-0029: tw2964: read adr'0x9a' dat'0x1f'
[   93.916098] tw2964 4-0029: tw2964: read adr'0x9b' dat'0x44'
[   93.916238] tw2964 4-0029: tw2964: read adr'0x9c' dat'0x20'
[   93.916379] tw2964 4-0029: tw2964: read adr'0x9d' dat'0x0'
[   93.916521] tw2964 4-0029: tw2964: read adr'0x9e' dat'0x42'
[   93.916665] tw2964 4-0029: tw2964: read adr'0x9f' dat'0x0'
[   93.916807] tw2964 4-0029: tw2964: read adr'0xa0' dat'0x8'
[   93.917049] tw2964 4-0029: tw2964: read adr'0xa1' dat'0x8'
[   93.917192] tw2964 4-0029: tw2964: read adr'0xa2' dat'0x8'
[   93.917334] tw2964 4-0029: tw2964: read adr'0xa3' dat'0x8'
[   93.917477] tw2964 4-0029: tw2964: read adr'0xa4' dat'0x1c'
[   93.917619] tw2964 4-0029: tw2964: read adr'0xa5' dat'0x1a'
[   93.917760] tw2964 4-0029: tw2964: read adr'0xa6' dat'0x1a'
[   93.917907] tw2964 4-0029: tw2964: read adr'0xa7' dat'0x1a'
[   93.918048] tw2964 4-0029: tw2964: read adr'0xa8' dat'0x0'
[   93.918206] tw2964 4-0029: tw2964: read adr'0xa9' dat'0x0'
[   93.918351] tw2964 4-0029: tw2964: read adr'0xaa' dat'0x0'
[   93.918497] tw2964 4-0029: tw2964: read adr'0xab' dat'0xf0'
[   93.918642] tw2964 4-0029: tw2964: read adr'0xac' dat'0xf0'
[   93.918785] tw2964 4-0029: tw2964: read adr'0xad' dat'0xf0'
[   93.918927] tw2964 4-0029: tw2964: read adr'0xae' dat'0xf0'
[   93.919072] tw2964 4-0029: tw2964: read adr'0xaf' dat'0x0'
[   93.919214] tw2964 4-0029: tw2964: read adr'0xb0' dat'0x0'
[   93.919359] tw2964 4-0029: tw2964: read adr'0xb1' dat'0x0'
[   93.919505] tw2964 4-0029: tw2964: read adr'0xb2' dat'0x0'
[   93.919648] tw2964 4-0029: tw2964: read adr'0xb3' dat'0x0'
[   93.919791] tw2964 4-0029: tw2964: read adr'0xb4' dat'0x0'
[   93.919933] tw2964 4-0029: tw2964: read adr'0xb5' dat'0x0'
[   93.920078] tw2964 4-0029: tw2964: read adr'0xb6' dat'0x0'
[   93.920220] tw2964 4-0029: tw2964: read adr'0xb7' dat'0x0'
[   93.920362] tw2964 4-0029: tw2964: read adr'0xb8' dat'0x0'
[   93.920509] tw2964 4-0029: tw2964: read adr'0xb9' dat'0x0'
[   93.920657] tw2964 4-0029: tw2964: read adr'0xba' dat'0x0'
[   93.920820] tw2964 4-0029: tw2964: read adr'0xbb' dat'0x0'
[   93.920980] tw2964 4-0029: tw2964: read adr'0xbc' dat'0x0'
[   93.921131] tw2964 4-0029: tw2964: read adr'0xbd' dat'0x0'
[   93.921276] tw2964 4-0029: tw2964: read adr'0xbe' dat'0x0'
[   93.921433] tw2964 4-0029: tw2964: read adr'0xbf' dat'0x0'
[   93.921579] tw2964 4-0029: tw2964: read adr'0xc0' dat'0x0'
[   93.921725] tw2964 4-0029: tw2964: read adr'0xc1' dat'0x0'
[   93.921873] tw2964 4-0029: tw2964: read adr'0xc2' dat'0x0'
[   93.922016] tw2964 4-0029: tw2964: read adr'0xc3' dat'0x0'
[   93.922163] tw2964 4-0029: tw2964: read adr'0xc4' dat'0x0'
[   93.922304] tw2964 4-0029: tw2964: read adr'0xc5' dat'0x0'
[   93.922448] tw2964 4-0029: tw2964: read adr'0xc6' dat'0x0'
[   93.922591] tw2964 4-0029: tw2964: read adr'0xc7' dat'0x0'
[   93.922737] tw2964 4-0029: tw2964: read adr'0xc8' dat'0x88'
[   93.922884] tw2964 4-0029: tw2964: read adr'0xc9' dat'0x88'
[   93.923026] tw2964 4-0029: tw2964: read adr'0xca' dat'0x5'
[   93.923172] tw2964 4-0029: tw2964: read adr'0xcb' dat'0x0'
[   93.923313] tw2964 4-0029: tw2964: read adr'0xcc' dat'0x3d'
[   93.923459] tw2964 4-0029: tw2964: read adr'0xcd' dat'0xe8'
[   93.923612] tw2964 4-0029: tw2964: read adr'0xce' dat'0x0'
[   93.923759] tw2964 4-0029: tw2964: read adr'0xcf' dat'0x0'
[   93.923905] tw2964 4-0029: tw2964: read adr'0xd0' dat'0x66'
[   93.924050] tw2964 4-0029: tw2964: read adr'0xd1' dat'0x66'
[   93.924194] tw2964 4-0029: tw2964: read adr'0xd2' dat'0x0'
[   93.924336] tw2964 4-0029: tw2964: read adr'0xd3' dat'0x10'
[   93.924478] tw2964 4-0029: tw2964: read adr'0xd4' dat'0x32'
[   93.924619] tw2964 4-0029: tw2964: read adr'0xd5' dat'0x54'
[   93.924760] tw2964 4-0029: tw2964: read adr'0xd6' dat'0x76'
[   93.924905] tw2964 4-0029: tw2964: read adr'0xd7' dat'0x98'
[   93.925048] tw2964 4-0029: tw2964: read adr'0xd8' dat'0xba'
[   93.925197] tw2964 4-0029: tw2964: read adr'0xd9' dat'0xdc'
[   93.925339] tw2964 4-0029: tw2964: read adr'0xda' dat'0xfe'
[   93.925483] tw2964 4-0029: tw2964: read adr'0xdb' dat'0xc2'
[   93.925625] tw2964 4-0029: tw2964: read adr'0xdc' dat'0x10'
[   93.925771] tw2964 4-0029: tw2964: read adr'0xdd' dat'0x0'
[   93.925914] tw2964 4-0029: tw2964: read adr'0xde' dat'0x0'
[   93.926060] tw2964 4-0029: tw2964: read adr'0xdf' dat'0x80'
[   93.926216] tw2964 4-0029: tw2964: read adr'0xe0' dat'0x1f'
[   93.926361] tw2964 4-0029: tw2964: read adr'0xe1' dat'0xf0'
[   93.926503] tw2964 4-0029: tw2964: read adr'0xe2' dat'0x33'
[   93.926645] tw2964 4-0029: tw2964: read adr'0xe3' dat'0x33'
[   93.926786] tw2964 4-0029: tw2964: read adr'0xe4' dat'0x0'
[   93.926927] tw2964 4-0029: tw2964: read adr'0xe5' dat'0x0'
[   93.927068] tw2964 4-0029: tw2964: read adr'0xe6' dat'0x0'
[   93.927211] tw2964 4-0029: tw2964: read adr'0xe7' dat'0x0'
[   93.927359] tw2964 4-0029: tw2964: read adr'0xe8' dat'0x0'
[   93.927500] tw2964 4-0029: tw2964: read adr'0xe9' dat'0x0'
[   93.927645] tw2964 4-0029: tw2964: read adr'0xea' dat'0x0'
[   93.927789] tw2964 4-0029: tw2964: read adr'0xeb' dat'0x0'
[   93.927931] tw2964 4-0029: tw2964: read adr'0xec' dat'0x0'
[   93.928077] tw2964 4-0029: tw2964: read adr'0xed' dat'0x0'
[   93.928219] tw2964 4-0029: tw2964: read adr'0xee' dat'0x0'
[   93.928365] tw2964 4-0029: tw2964: read adr'0xef' dat'0x0'
[   93.928506] tw2964 4-0029: tw2964: read adr'0xf0' dat'0x23'
[   93.928647] tw2964 4-0029: tw2964: read adr'0xf1' dat'0x48'
[   93.928789] tw2964 4-0029: tw2964: read adr'0xf2' dat'0x7'
[   93.928931] tw2964 4-0029: tw2964: read adr'0xf3' dat'0x0'
[   93.929089] tw2964 4-0029: tw2964: read adr'0xf4' dat'0x1'
[   93.929236] tw2964 4-0029: tw2964: read adr'0xf5' dat'0x0'
[   93.929379] tw2964 4-0029: tw2964: read adr'0xf6' dat'0x0'
[   93.929526] tw2964 4-0029: tw2964: read adr'0xf7' dat'0x20'
[   93.929667] tw2964 4-0029: tw2964: read adr'0xf8' dat'0xc4'
[   93.929808] tw2964 4-0029: tw2964: read adr'0xf9' dat'0x40'
[   93.929951] tw2964 4-0029: tw2964: read adr'0xfa' dat'0x45'
[   93.930097] tw2964 4-0029: tw2964: read adr'0xfb' dat'0xf'
[   93.930244] tw2964 4-0029: tw2964: read adr'0xfc' dat'0xff'
[   93.930385] tw2964 4-0029: tw2964: read adr'0xfd' dat'0x1'
[   93.930527] tw2964 4-0029: tw2964: read adr'0xfe' dat'0x0'
[   93.930669] tw2964 4-0029: tw2964: read adr'0xff' dat'0xe8'
- log tw2964 after modprobe tw2964.ko

[   93.843657] vin3a: vip_async_bound
[   93.843662] vin3a: Port A: Using subdev tw2964 4-0029 for capture
[   93.849783] vin3a: subdev tw2964 4-0029: code: 2006 idx: 0
[   93.849788] vin3a: matched fourcc: UYVY: code: 2006 idx: 0
[   93.849792] vin3a: matched fourcc: YUYV: code: 2006 idx: 1
[   93.849796] vin3a: matched fourcc: VYUY: code: 2006 idx: 2
[   93.849799] vin3a: matched fourcc: YVYU: code: 2006 idx: 3
[   93.849954] vin3a-0: device registered as video1
[   93.855023] vin3a: vip_create_streams[channel-0]: bus_type = V4L2_MBUS_BT656
[   93.855123] vin3a-0: device registered as video2
[   93.859759] vin3a: vip_create_streams[channel-1]: bus_type = V4L2_MBUS_BT656
[   93.859776] vin3a: vip_async_complete
[   93.902336] vin3a-0: vip_open
[   93.902356] vin3a: vip_init_port: g_mbus_fmt subdev mbus_code: 2006 fourcc:UYVY size: 704x280
[   93.902366] vin3a: calc_format_size: fourcc:UYVY size: 704x280 bpl:1408 img_size:394240
[   93.902388] vin3a-0: init_stream fourcc:UYVY size: 704x280 bpl:1408 img_size:394240
[   93.902395] vin3a-0: init_stream vpdma data type: 0x27
[   93.902413] vin3a-0: vip_init_stream: stream instance 0xc0bb1438edfb6000
[   93.902652] vin3a-0: vip_release
[   93.902659] vin3a-0: vip_release_stream: stream instance 0x00000010edfb6000
[   93.902664] vin3a: vip_release_port: port instance 0xeda74c00edaa1410
[   93.908956] vin3a-0: vip_open
[   93.909143] vin3a: vip_init_port: g_mbus_fmt subdev mbus_code: 2006 fourcc:UYVY size: 704x280
[   93.909153] vin3a: calc_format_size: fourcc:UYVY size: 704x280 bpl:1408 img_size:394240
[   93.909158] vin3a-0: init_stream fourcc:UYVY size: 704x280 bpl:1408 img_size:394240
[   93.909162] vin3a-0: init_stream vpdma data type: 0x27
[   93.909167] vin3a-0: vip_init_stream: stream instance 0xc0bb1438edfb5000
[   93.909879] vin3a-0: vip_release
[   93.909885] vin3a-0: vip_release_stream: stream instance 0x00000010edfb5000
[   93.909907] vin3a: vip_release_port: port instance 0xed9d4300edaa1410
-log vip after modprobe tw2964

gst-launch-1.0 v4l2src device=/dev/video2 io-mode=4 ! 'video/x-raw,format=(string)YUY2, width=(int)704, height=(int)280' ! vpe num-input-buffers=8 ! queue ! waylandsink use-drm=true
6840.gstreamer.log - log after gst-launch
 
But no video (Oscillograms of data and clock frequency of 54 MHz are normal):

cat /proc/interrupts | grep vi
102: 0 0 CBAR 352 Level vin3
103: 0 0 CBAR 393 Level vin4

PS. 10 minutes later, one frame of the distorted video and 1 interrupt appeared on the screen.

When trying to start the second channel (the first is already running)

gst-launch-1.0 v4l2src device=/dev/video2 io-mode=4 ! 'video/x-raw,format=(string)YUY2, width=(int)704, height=(int)280' ! vpe num-input-buffers=8 ! queue ! waylandsink use-drm=true
Setting pipeline to PAUSED ...
Pipeline is live and does not need PREROLL ...
Setting pipeline to PLAYING ...
New clock: GstSystemClock
ERROR: from element /GstPipeline:pipeline0/GstV4l2Src:v4l2src0: Device '/dev/video2' is busy
Additional debug info:
../../../gst-plugins-good-1.12.2/sys/v4l2/gstv4l2object.c(3595): gst_v4l2_object_set_format_full (): /GstPipeline:pipeline0/GstV4l2Src:v4l2src0:
Call to S_FMT failed for YUYV @ 704x280: Device or resource busy
Execution ended after 0:00:00.015667890
Setting pipeline to PAUSED ...
Setting pipeline to READY ...
Setting pipeline to NULL ...
Freeing pipeline ...

gstreamer_2.log - log after second gst-launch

Same experiment for yavta

root@am57xx-evm:~# echo '\n' | yavta -c100 -p -F/home/root/1.yuv --skip 2 -t 1/30 -f YUYV -s 704x280 /dev/video1
Device /dev/video1 opened.
Device `vip' on `platform:vip2:vin3a:stream0' is a video output (without mplanes) device.
Video format set: YUYV (56595559) 704x280 (stride 1408) field none buffer size 394240
Video format: YUYV (56595559) 704x280 (stride 1408) field none buffer size 394240
Current frame rate: 1/30
Setting frame rate to: 1/30
Frame rate set: 1/30
8 buffers requested.
length: 394240 offset: 0 timestamp type/source: mono/EoF
Buffer 0/0 mapped at address 0xb6d55000.
length: 394240 offset: 397312 timestamp type/source: mono/EoF
Buffer 1/0 mapped at address 0xb6cf4000.
length: 394240 offset: 794624 timestamp type/source: mono/EoF
Buffer 2/0 mapped at address 0xb6c93000.
length: 394240 offset: 1191936 timestamp type/source: mono/EoF
Buffer 3/0 mapped at address 0xb6c32000.
length: 394240 offset: 1589248 timestamp type/source: mono/EoF
Buffer 4/0 mapped at address 0xb6bd1000.
length: 394240 offset: 1986560 timestamp type/source: mono/EoF
Buffer 5/0 mapped at address 0xb6b70000.
length: 394240 offset: 2383872 timestamp type/source: mono/EoF
Buffer 6/0 mapped at address 0xb6b0f000.
length: 394240 offset: 2781184 timestamp type/source: mono/EoF
Buffer 7/0 mapped at address 0xb6aae000.
Press enter to start capture

[  213.203392] vin3a-0: vip_open
[  213.203414] tw2964 4-0029: width = 704, height = 280
[  213.203422] vin3a: vip_init_port: g_mbus_fmt subdev mbus_code: 2006 fourcc:UYVY size: 704x280
[  213.203433] vin3a: calc_format_size: fourcc:UYVY size: 704x280 bpl:1408 img_size:394240
[  213.203439] vin3a-0: init_stream fourcc:UYVY size: 704x280 bpl:1408 img_size:394240
[  213.203444] vin3a-0: init_stream vpdma data type: 0x27
[  213.203450] vin3a-0: vip_init_stream: stream instance 0xc0bb1438ecd04000
[  213.203634] vin3a-0: s_fmt input fourcc:YUYV size: 704x280 bpl:0 img_size:0
[  213.203641] vin3a-0: try_fmt fourcc:YUYV size: 704x280
[  213.203650] vin3a-0: try_fmt loop:0 fourcc:YUYV size: 704x280
[  213.203656] vin3a-0: try_fmt loop:0 found new larger: 704x280
[  213.203662] vin3a-0: try_fmt loop:0 found at least larger: 704x280
[  213.203667] vin3a-0: try_fmt loop:0 found new best: 704x280
[  213.203672] vin3a-0: try_fmt loop:0 found direct match: 704x280
[  213.203678] vin3a: calc_format_size: fourcc:YUYV size: 704x280 bpl:1408 img_size:394240
[  213.203684] vin3a-0: s_fmt try_fmt fourcc:YUYV size: 704x280 bpl:1408 img_size:394240
[  213.203690] vin3a-0: s_fmt fourcc:YUYV size: 704x280 bpl:1408 img_size:394240
[  213.203695] vin3a-0: s_fmt pix_to_mbus mbus_code: 2006 size: 704x280
[  213.203703] tw2964 4-0029: width = 704, height = 280
[  213.203709] vin3a-0: s_fmt subdev fmt mbus_code: 2006 size: 704x280
[  213.203714] vin3a-0: s_fmt vpdma data type: 0x07
[  213.203770] vin3a-0: g_fmt fourcc:YUYV code: 2006 size: 704x280 bpl:1408 img_size:394240
[  213.203775] vin3a-0: g_fmt vpdma data type: 0x07
[  213.203934] vin3a-0: get 8 buffer(s) of size 394240 each.
[  213.207641] vin3: vip_set_slice_path:
[  213.207650] vin3: vip_set_slice_path: DATA_PATH_SELECT(0000010C): 80008000
[  213.207654] vin3: vip_set_slice_path:
[  213.207660] vin3: vip_set_slice_path: DATA_PATH_SELECT(0000010C): 40008000
[  213.207932] vin3: vip_setup_parser: EMBEDDED_SYNC_2X_MULTIPLEXED_YUV422
[  213.207937] vin3: vip_setup_parser: VIP_PIXCLK_EDGE_POLARITY=0
[  213.208124] tw2964 4-0029: tw2964: read adr'0x65' dat'0x0'
[  213.208132] tw2964 4-0029: tw2964: writing adr'0x65' dat'0x0'
[  213.208246] vin3a-0: vip_load_vpdma_list_fifo: start_dma vb2 buf idx:0
[  213.209369] vin3a-0: vip_load_vpdma_list_fifo: start_dma vb2 buf idx:1
-log after first yavta

When trying to start the second channel (the first is already running)

 root@am57xx-evm:~# echo '\n' | yavta -c100 -p -F/home/root/1.yuv --skip 2 -t 1/30 -f YUYV -s 704x280 /dev/video2

Device /dev/video2 opened.
Device `vip' on `platform:vip2:vin3a:stream0' is a video output (without mplanes) device.
Video format set: YUYV (56595559) 704x280 (stride 1408) field none buffer size 394240
Video format: YUYV (56595559) 704x280 (stride 1408) field none buffer size 394240
Current frame rate: 1/30
Setting frame rate to: 1/30
Frame rate set: 1/30
8 buffers requested.
length: 394240 offset: 0 timestamp type/source: mono/EoF
Buffer 0/0 mapped at address 0xb6e33000.
length: 394240 offset: 397312 timestamp type/source: mono/EoF
Buffer 1/0 mapped at address 0xb6dd2000.
length: 394240 offset: 794624 timestamp type/source: mono/EoF
Buffer 2/0 mapped at address 0xb6d71000.
length: 394240 offset: 1191936 timestamp type/source: mono/EoF
Buffer 3/0 mapped at address 0xb6d10000.
length: 394240 offset: 1589248 timestamp type/source: mono/EoF
Buffer 4/0 mapped at address 0xb6caf000.
length: 394240 offset: 1986560 timestamp type/source: mono/EoF
Buffer 5/0 mapped at address 0xb6c4e000.
length: 394240 offset: 2383872 timestamp type/source: mono/EoF
Buffer 6/0 mapped at address 0xb6bed000.
length: 394240 offset: 2781184 timestamp type/source: mono/EoF
Buffer 7/0 mapped at address 0xb6b8c000.
Press enter to start capture
Unable to start streaming: Device or resource busy (16).
8 buffers released.

[  357.042092] vin3a-0: vip_open
[  357.042109] vin3a: calc_format_size: fourcc:YUYV size: 704x280 bpl:1408 img_size:394240
[  357.042117] vin3a-0: init_stream fourcc:YUYV size: 704x280 bpl:1408 img_size:394240
[  357.042123] vin3a-0: init_stream vpdma data type: 0x07
[  357.042132] vin3a-0: vip_init_stream: stream instance 0xc0bb1438ecd06000
[  357.042338] vin3a-0: s_fmt input fourcc:YUYV size: 704x280 bpl:0 img_size:0
[  357.042347] vin3a-0: try_fmt fourcc:YUYV size: 704x280
[  357.042358] vin3a-0: try_fmt loop:0 fourcc:YUYV size: 704x280
[  357.042365] vin3a-0: try_fmt loop:0 found new larger: 704x280
[  357.042371] vin3a-0: try_fmt loop:0 found at least larger: 704x280
[  357.042377] vin3a-0: try_fmt loop:0 found new best: 704x280
[  357.042383] vin3a-0: try_fmt loop:0 found direct match: 704x280
[  357.042390] vin3a: calc_format_size: fourcc:YUYV size: 704x280 bpl:1408 img_size:394240
[  357.042397] vin3a-0: s_fmt try_fmt fourcc:YUYV size: 704x280 bpl:1408 img_size:394240
[  357.042404] vin3a-0: s_fmt fourcc:YUYV size: 704x280 bpl:1408 img_size:394240
[  357.042412] vin3a-0: s_fmt pix_to_mbus mbus_code: 2006 size: 704x280
[  357.042423] tw2964 4-0029: width = 704, height = 280
[  357.042429] vin3a-0: s_fmt subdev fmt mbus_code: 2006 size: 704x280
[  357.042435] vin3a-0: s_fmt vpdma data type: 0x07
[  357.042503] vin3a-0: g_fmt fourcc:YUYV code: 2006 size: 704x280 bpl:1408 img_size:394240
[  357.042508] vin3a-0: g_fmt vpdma data type: 0x07
[  357.042694] vin3a-0: get 8 buffer(s) of size 394240 each.
[  357.046848] vin3: vip_set_slice_path:
[  357.046858] vin3: vip_set_slice_path: DATA_PATH_SELECT(0000010C): 80008000
[  357.046863] vin3: vip_set_slice_path:
[  357.046870] vin3: vip_set_slice_path: DATA_PATH_SELECT(0000010C): 40008000
[  357.047147] vin3: vip_setup_parser: EMBEDDED_SYNC_2X_MULTIPLEXED_YUV422
[  357.047153] vin3: vip_setup_parser: VIP_PIXCLK_EDGE_POLARITY=0
[  357.047356] tw2964 4-0029: tw2964: read adr'0x65' dat'0x0'
[  357.047364] tw2964 4-0029: tw2964: writing adr'0x65' dat'0x0'
[  357.047484] vin3a-0: vip_load_vpdma_list_fifo: start_dma vb2 buf idx:0
[  357.607609] vin3a-0: Timed out loading VPDMA list fifo
[  357.612795] ------------[ cut here ]------------
[  357.617446] WARNING: CPU: 0 PID: 1269 at drivers/media/v4l2-core/videobuf2-core.c:1347 vb2_start_streaming+0xdc/0x158
[  357.628278] Modules linked in: tw2964(O) sha512_generic sha512_arm sha256_generic sha1_generic sha1_arm_neon sha1_arm md5 cbc aes_arm_bs crypto_simd cryptd xfrm_user xfrm4_tunnel ipcomp xfrm_ipcomp esp4 ah4 af_key xfrm_algo bc_example(O) pru_rproc xhci_plat_hcd xhci_hcd pruss_intc rpmsg_rpc rpmsg_proto dwc3 udc_core pruss snd_soc_simple_card snd_soc_simple_card_utils snd_soc_omap_hdmi_audio pvrsrvkm(O) omap_aes_driver ahci_platform libahci_platform pruss_soc_bus libahci omap_sham libata omap_wdt scsi_mod phy_omap_usb2 ti_vip(O) ti_vpe ti_sc ti_csc ti_vpdma dwc3_omap rtc_omap extcon_palmas rtc_palmas pixcir_i2c_ts v4l2_fwnode snd_soc_tlv320aic3x at24 omap_des rtc_ds1307 des_generic crypto_engine omap_crypto omap_remoteproc virtio_rpmsg_bus rpmsg_core remoteproc sch_fq_codel uio_module_drv(O) uio ftdi_sio
[  357.700108]  usbserial usbcore usb_common gdbserverproxy(O) cryptodev(O) cmemk(O)
[  357.707960] CPU: 0 PID: 1269 Comm: yavta Tainted: G           O    4.14.79-gbde58ab01e #1
[  357.716176] Hardware name: Generic DRA74X (Flattened Device Tree)
[  357.722294] Backtrace: 
[  357.724762] [<c020b4dc>] (dump_backtrace) from [<c020b7c0>] (show_stack+0x18/0x1c)
[  357.732366]  r7:00000009 r6:60050013 r5:00000000 r4:c1053d90
[  357.738056] [<c020b7a8>] (show_stack) from [<c0932528>] (dump_stack+0x90/0xa4)
[  357.745314] [<c0932498>] (dump_stack) from [<c022b9cc>] (__warn+0xec/0x104)
[  357.752307]  r7:00000009 r6:c0c0f3d4 r5:00000000 r4:00000000
[  357.757993] [<c022b8e0>] (__warn) from [<c022ba9c>] (warn_slowpath_null+0x28/0x30)
[  357.765597]  r9:00000000 r8:00000012 r7:c0719424 r6:ecd06ae8 r5:ecd0688c r4:fffffff0
[  357.773379] [<c022ba74>] (warn_slowpath_null) from [<c072d94c>] (vb2_start_streaming+0xdc/0x158)
[  357.782208] [<c072d870>] (vb2_start_streaming) from [<c072f7a8>] (vb2_core_streamon+0x130/0x178)
[  357.791031]  r7:c0719424 r6:eda6a800 r5:00000000 r4:ecd0688c
[  357.796719] [<c072f678>] (vb2_core_streamon) from [<c0731fec>] (vb2_streamon+0x38/0x58)
[  357.804756]  r5:ed9b6e40 r4:00000001
[  357.808348] [<c0731fb4>] (vb2_streamon) from [<c0732050>] (vb2_ioctl_streamon+0x44/0x48)
[  357.816480] [<c073200c>] (vb2_ioctl_streamon) from [<c0719448>] (v4l_streamon+0x24/0x28)
[  357.824604]  r5:40045612 r4:c073200c
[  357.828200] [<c0719424>] (v4l_streamon) from [<c071bdd4>] (__video_do_ioctl+0x30c/0x314)
[  357.836324]  r5:40045612 r4:00000001
[  357.839920] [<c071bac8>] (__video_do_ioctl) from [<c071b688>] (video_usercopy+0x78/0x49c)
[  357.848132]  r10:00000000 r9:00000000 r8:edc7be28 r7:00000000 r6:00000004 r5:00000001
[  357.855995]  r4:40045612
[  357.858544] [<c071b610>] (video_usercopy) from [<c071bac4>] (video_ioctl2+0x18/0x1c)
[  357.866321]  r10:ec242b90 r9:edc7a000 r8:ed210974 r7:be9bc604 r6:40045612 r5:ed9b6e40
[  357.874183]  r4:eda6a800
[  357.876730] [<c071baac>] (video_ioctl2) from [<c0717d0c>] (v4l2_ioctl+0x84/0xe0)
[  357.884164] [<c0717c88>] (v4l2_ioctl) from [<c034ed3c>] (do_vfs_ioctl+0xa8/0x790)
[  357.891680]  r9:edc7a000 r8:00000003 r7:40045612 r6:00000003 r5:ed9b6e40 r4:be9bc604
[  357.899461] [<c034ec94>] (do_vfs_ioctl) from [<c034f460>] (SyS_ioctl+0x3c/0x60)
[  357.906803]  r10:00000036 r9:edc7a000 r8:be9bc604 r7:40045612 r6:00000003 r5:ed9b6e40
[  357.914665]  r4:ed9b6e40
[  357.917213] [<c034f424>] (SyS_ioctl) from [<c0207c40>] (ret_fast_syscall+0x0/0x4c)
[  357.924817]  r9:edc7a000 r8:c0207e44 r7:00000036 r6:00000001 r5:00000000 r4:00000008
[  357.933837] ---[ end trace f15c45b46cdb50b2 ]---
[  357.939747] vin3a-0: vip_release
[  357.939757] vin3a-0: vip_release_stream: stream instance 0x00000008ecd06000
-log after second yavta

I studied the following links but did not find solutions in them:

https://e2e.ti.com/support/processors/f/791/p/640197/2368318?pi320966=3#pi320966=1

https://e2e.ti.com/support/processors/f/791/t/555591?AM572x-VIN4a-V4L2-interface-with-TVP5158-analog-video-decoder

https://e2e.ti.com/support/processors/f/791/p/758945/2811324?tisearch=e2e-sitesearch&keymatch=PCM1774

Therefore, I had a third question.

3. How to make vip.c work simultaneously for different video channels?

PS. link to tvp5158 driver  (http://review.omapzoom.org/#/c/37708/)

  • Hi Oleg,

    I will get back to you on above queries soon.

    Regards,
    Manisha
  • Hi, Manisha.

    Looking forward to your reply.

    Just in case i give my source code:

    0871.vip.h8156.vip.c7367.tw2964_reg.h

    ///-------------------------------------------------------------------------------------------------------------------------------------
    // Copyright (C) 2019 by DeVdistress.
    //
    // This program is free software; you can redistribute it and/or modify
    // it under the terms of the GNU General Public License (Version 2) as
    // published by the Free Software Foundation.
    //
    // This program is distributed in the hope that it will be useful,
    // but WITHOUT ANY WARRANTY; without even the implied warranty of
    // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    // GNU General Public License for more details.
    //
    ///-------------------------------------------------------------------------------------------------------------------------------------
    // PS. by DeVdistress: minimum requirements for implemented driver functions for the v4l2 system
    ///-------------------------------------------------------------------------------------------------------------------------------------
    // http://software-dl.ti.com/processor-sdk-linux/esd/docs/05_02_00_10/linux/Foundational_Components_Kernel_Drivers.html#vip
    // V4L2 asynchronous subdevice registration
    //
    // Each camera device that VIP driver communicates to is modelled as a V4L2 subdevice.
    // In the probe sequence, VIP and camera drivers are probed at different time.
    // V4L2 async subdevice binding helps to bind the VIP device and the camera device together.
    // VIP driver looks for the camera entries in the endpoints and registers (v4l2_async_notifier_register)
    // a callback if any of the requested devices become available.
    // vip_async_bound implements the priority based binding which allows to have multiple cameras muxed against same video port.
    // The device tree order determines which of these gets picked up by the driver.
    // Note that the V4L2 g/s_input ioctls are not supported, userspace won’t be able to select specific camera with these ioctls.
    //
    // Of course the target subdevice driver also needs to support the asynchronous registration framework.
    // On top of this the subdevice driver must implements the following ioctls for the handshake with the VIP driver to work properly:
    //
    // get_fmt()
    // set_fmt()
    // enum_mbus_code()
    // enum_frame_sizes()
    // s_stream()
    ///-------------------------------------------------------------------------------------------------------------------------------------
    #include <linux/module.h>
    #include <linux/init.h>
    #include <linux/i2c.h>
    #include <linux/videodev2.h>
    #include <linux/ioctl.h>
    #include <linux/slab.h>
    #include <media/v4l2-async.h>
    #include <media/v4l2-subdev.h>
    #include <media/v4l2-device.h>
    #include <media/v4l2-ctrls.h>
    #include <media/v4l2-fwnode.h>
    #include <media/v4l2-mc.h>
    #include <linux/gpio/consumer.h>
    #include <linux/delay.h>
    #include <linux/of_graph.h>
    #include <linux/kernel.h>
    
    // for create device through udev
    #include <linux/device.h>
    #include <linux/kdev_t.h>
    
    // for file operation
    #include <linux/fs.h>
    #include <linux/cdev.h>
    #include <linux/ioctl.h>
    
    // kmalloc()
    #include<linux/slab.h>
    
    // copy_to/from_user()
    #include<linux/uaccess.h>
    
    #include "tw2964_reg.h"
    
    #define SET_MAIN_CHAIN_FROM_IOCTL	_IOW()
    
    #define TW2804_REG_AUTOGAIN			0x02
    #define TW2804_REG_HUE				0x0f
    #define TW2804_REG_SATURATION		0x10
    #define TW2804_REG_CONTRAST			0x11
    #define TW2804_REG_BRIGHTNESS		0x12
    #define TW2804_REG_COLOR_KILLER		0x14
    #define TW2804_REG_GAIN				0x3c
    #define TW2804_REG_CHROMA_GAIN		0x3d
    #define TW2804_REG_BLUE_BALANCE		0x3e
    #define TW2804_REG_RED_BALANCE		0x3f
    
    MODULE_LICENSE("GPL");
    MODULE_DESCRIPTION("TW2964 V4L2 i2c video decoder driver");
    MODULE_AUTHOR("DeVdistress");
    MODULE_VERSION("0.1");
    
    // number of video in time-multiplexing
    // should be 1 <= x <= 4
    #undef		HOW_MUCH_VIDEO_IN_TIME_MULTIPLEXING
    #define		HOW_MUCH_VIDEO_IN_TIME_MULTIPLEXING		(2)
    
    #undef		HOW_MUCH_SEPARATE_VIP_VIDEO
    #define		HOW_MUCH_SEPARATE_VIP_VIDEO				(2)
    
    // attempt to forward my ioctl
    #undef		NEED_USE_TW2964_IOCTL
    #define		NEED_USE_TW2964_IOCTL					(1)
    
    // allocated space for udev and fops
    #define		SIZE_FOR_MY_UDEV_DATA					(1024)
    
    #if (4 < HOW_MUCH_VIDEO_IN_TIME_MULTIPLEXING) || (1 > HOW_MUCH_VIDEO_IN_TIME_MULTIPLEXING)
    	#error Incorrect value of macros HOW_MUCH_VIDEO_IN_TIME_MULTIPLEXING in tw2964.c
    #endif
    
    #define my_dev_info(dev, fmt, arg...)	dev_dbg_lvl(dev, 1, debug, fmt, ##arg)
    #define my_simple_info(fmt, arg...)		if (debug > 1) printk( KERN_DEBUG "tw2964: " fmt, ##arg )
    
    // Definition of fast work with bits in the necessary registers
    #ifndef SET_B
    	#define SET_B(x) 	|= (1<<(x)) // in_x SET_B(5); "set"		bit5 в in_x
    #endif // SET_B(x)
    
    #ifndef	CLR_B
    	#define CLR_B(x) 	&=~(1<<(x)) // in_y CLR_B(2); "clear"	bit2 в in_y
    #endif // CLR_B(x)
    
    #ifndef	INV_B
    	#define INV_B(x) 	^=(1<<(x))  // in_z INV_B(6); "invert"	bit6 в in_z
    #endif // INV_B(x)
    
    // DeVdistress attempt to create driver in driver
    // we will use udev, cdev, file_operation and ioctl
    #if defined(NEED_USE_TW2964_IOCTL) && (NEED_USE_TW2964_IOCTL)
    					dev_t 		dev = 0;
    	static struct 	class 		*dev_class		= NULL;
    	static struct 	cdev 		etx_cdev;
    					uint8_t 	*kernel_buffer	= NULL;
    	static const    size_t 		mem_size = (size_t)SIZE_FOR_MY_UDEV_DATA;
    
    	// for rolling data between udev driver and i2c subdevice
    	static struct 	tw2964 		*drv_tw2964 = NULL;
    	static struct 	i2c_client	*i2c_client = NULL;
    	static struct 	v4l2_subdev	*drv_sd		= NULL;
    
    	// essentially the second init
    	// so it will be embedded in the initial tw2964_probe init
    	// static int __init etx_driver_init (void);
    	static int etx_driver_init(void);
    
    	// essentially the second deinite,
    	// so it will be embedded in the original deinit tw2964_remove
    	// static void __exit etx_driver_exit (void);
    	static void etx_driver_exit(void);
    
    	static int etx_open(struct inode *inode, struct file *file);
    	static int etx_release(struct inode *inode, struct file *file);
    	static ssize_t etx_read(struct file *filp, char __user *buf, size_t len,loff_t * off);
    	static ssize_t etx_write(struct file *filp, const char *buf, size_t len, loff_t * off);
    	static long etx_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
    
    	static struct file_operations fops =
    	{
    	        .owner          = THIS_MODULE,
    	        .read           = etx_read,
    	        .write          = etx_write,
    	        .open           = etx_open,
    	        .unlocked_ioctl = etx_ioctl,
    	        .release        = etx_release,
    	};
    #endif
    
    //DeVdistress
    #if(0)
    	static int debug;
    	module_param(debug, int, 0644);
    	MODULE_PARM_DESC(debug, "Debug level (0-2)");
    #else
    	static int debug = 2;
    #endif
    
    struct tw2964 {
    	struct v4l2_subdev sd;
    #ifdef CONFIG_MEDIA_CONTROLLER
    	struct media_pad pads[DEMOD_NUM_PADS];
    	struct media_entity input_ent[TW2964_INPUT_NUM];
    	struct media_pad input_pad[TW2964_INPUT_NUM];
    #endif
    	struct v4l2_ctrl_handler hdl;
    	// store resolution
    	struct v4l2_rect rect;
    	u8	channel	[HOW_MUCH_VIDEO_IN_TIME_MULTIPLEXING];
    	u8	input; // input type for the multiplexer is the same for all 4 inputs
    	int	enable;// power on state is the same for all 4 inputs
    
    	// strategy is as follows:
    	// I will throw the external ioctl that cur_chan will expose,
    	// this channel will be the main one for reading the states of the microcircuit
    	// this is due to the fact that it is not yet clear how a specific channel
    	// a lot of channel device comes from vip-a or v4l2
    	// most likely not like !!!
    	int32_t  cur_chan;
    
    	// Current set standard
    	// ToDo: it is not yet clear how the channel number will live in the v4l2 system
    	v4l2_std_id norm[TW2964_INPUT_NUM];
    
    	// left for compatibility with tvp5150, delete if possible
    	enum v4l2_mbus_type mbus_type;
    
    	u8 dev_id;
    	u8 rev_id;
    };
    
    // @brief Default values as suggested at tw2964 datasheet
    static const u8 global_registers[] = {
    	TW2964_REG_TESTOUTSEL,			0x00,
    	TW2964_REG_VDFREQ,				0x00,
    	TW2964_REG_FBITINV,				0x00,
    	TW2964_REG_ANADACTEST,			0x00,
    	TW2964_REG_ASAVE,				0x07,
    	TW2964_REG_AAFLPF,				0x00,
    	TW2964_REG_HASYNC,				0x00,
    	TW2964_REG_HBLEN1,				0x90,
    	TW2964_REG_HBLEN2,				0x90,
    	TW2964_REG_HBLEN3,				0x90,
    	TW2964_REG_HBLEN4,				0x90,
    	TW2964_REG_CKDS,				0x00,
    	TW2964_REG_BGCTL,				0x00,
    	TW2964_REG_CH2MISC2,			0xE0,
    	TW2964_REG_CH3MISC2,			0xE0,
    	TW2964_REG_CH4MISC2,			0xE0,
    	TW2964_REG_VCO,					0x26,
    	TW2964_REG_XTIMD,				0x1F,
    	TW2964_REG_MPPOE,				0x00,
    	TW2964_REG_CH21NUM,				0x10,
    	TW2964_REG_CH43NUM,				0x32,
    	TW2964_REG_VDOEB,				0x00,
    	TW2964_REG_HZST,				0x80,
    	TW2964_REG_HZOOM_HI,			0x00,
    	TW2964_REG_HZOOM1_LOW,			0x00,
    	TW2964_REG_HZOOM2_LOW,			0x00,
    	TW2964_REG_HZOOM3_LOW,			0x00,
    	TW2964_REG_HZOOM4_LOW,			0x00,
    	TW2964_REG_D1_NMGAIN,			0x28,
    	TW2964_REG_PCLAMP720,			0x38,
    	TW2964_REG_ACLKPOL,				0x08,
    	TW2964_REG_AINCTL,				0x40,
    	TW2964_REG_MRATIOMD,			0x28,
    	TW2964_REG_A5NUM,				0x00,
    	TW2964_REG_A5DETST,				0x00,
    	TW2964_REG_AADC5OFS_H,			0x00,
    	TW2964_REG_AADC5OFS_L,			0x00,
    //	TW2964_REG_AUD5ADC_H,			0x00,	( read only )
    //	TW2964_REG_AUD5ADC_L,			0x00,	( read only )
    //	TW2964_REG_ADJAADC5_H,			0x00,	( read only )
    //	TW2964_REG_ADJAADC5_L,			0x00,	( read only )
    	TW2964_REG_I2SO_RSEL,			0x15,
    	TW2964_REG_I2SO_LSEL,			0x15,
    	TW2964_REG_RECSEL5,				0xE4,
    	TW2964_REG_ADATMI2S,			0xA3,
    	TW2964_REG_AIGAIN5,				0x66,
    	TW2964_REG_SRST,				0x00,
    	TW2964_REG_ACNTL,				0x02,
    	TW2964_REG_ACNTL2,				0x00,
    	TW2964_REG_CNTRL1,				0xCC,
    	TW2964_REG_CKHY,				0x00,
    	TW2964_REG_SHCOR960,			0x30,
    	TW2964_REG_CORING,				0x44,
    	TW2964_REG_CLMPG,				0x50,
    	TW2964_REG_IAGC,				0x42,
    	TW2964_REG_AIN5MD,				0x00,
    	TW2964_REG_PEAKWT,				0xD8,
    	TW2964_REG_CLMPL,				0xBC,
    	TW2964_REG_SYNCT,				0xB8,
    	TW2964_REG_MISSCNT,				0x44,
    	TW2964_REG_PCLAMP960,			0x36,
    	TW2964_REG_VCNTL1,				0x00,
    	TW2964_REG_VCNTL2,				0x00,
    	TW2964_REG_CKILL,				0x78,
    	TW2964_REG_VTL,					0x44,
    	TW2964_REG_LDLY,				0x30,
    	TW2964_REG_MISC1,				0x14,
    	TW2964_REG_CBW,					0xA5,
    	TW2964_REG_MISC2,				0xE0,
    	TW2964_REG_CLMD,				0x05,
    	TW2964_REG_HSLOWCTL,			0x00,
    	TW2964_REG_HSBEGIN,				0x13,
    	TW2964_REG_HSEND,				0x1F,
    	TW2964_REG_OVSDLY,				0x44,
    	TW2964_REG_OVSEND,				0x20,
    	TW2964_REG_NOVID,				0x42,
    	TW2964_REG_CLKODEL,				0x00,
    	TW2964_REG_AGCEN,				0x00,
    	TW2964_REG_AGCGAIN1,			0xF0,
    	TW2964_REG_AGCGAIN2,			0xF0,
    	TW2964_REG_AGCGAIN3,			0xF0,
    	TW2964_REG_AGCGAIN4,			0xF0,
    	TW2964_REG_VSHP21,				0x00,
    	TW2964_REG_VSHP43,				0x00,
    	TW2964_REG_CH8IDEN,				0x00,
    	TW2964_REG_VDLOSSOE,			0x00,
    	TW2964_REG_AADCOFS_H,			0x00,
    	TW2964_REG_AADC1OFS_L,			0x00,
    	TW2964_REG_AADC2OFS_L,			0x00,
    	TW2964_REG_AADC3OFS_L,			0x00,
    	TW2964_REG_AADC4OFS_L,			0x00,
    //	TW2964_REG_AUDADC_H,			0x00,	( read only )
    //	TW2964_REG_AUD1ADC_L,			0x00,	( read only )
    //	TW2964_REG_AUD2ADC_L,			0x00,	( read only )
    //	TW2964_REG_AUD3ADC_L,			0x00,	( read only )
    //	TW2964_REG_AUD4ADC_L,			0x00,	( read only )
    //	TW2964_REG_ADJAADC_H,			0x00,	( read only )
    //	TW2964_REG_ADJAADC1_L,			0x00,	( read only )
    //	TW2964_REG_ADJAADC2_L,			0x00,	( read only )
    //	TW2964_REG_ADJAADC3_L,			0x00,	( read only )
    //	TW2964_REG_ADJAADC4_L,			0x00,	( read only )
    	TW2964_REG_MPP21,				0x00,
    	TW2964_REG_MPP43,				0x00,
    	TW2964_REG_CHMD,				0x00,
    	TW2964_REG_POLMPP,				0x00,
    	TW2964_REG_SELCH,				0x39,
    	TW2964_REG_MAINCH,				0xE4,
    	TW2964_REG_ANAPWDN,				0x00,
    	TW2964_REG_SMD,					0x00,
    	TW2964_REG_AIGAIN21,			0x66,
    	TW2964_REG_AIGAIN43,			0x66,
    	TW2964_REG_R_MULTCH,			0x00,
    	TW2964_REG_R_SEQ10,				0x10,
    	TW2964_REG_R_SEQ32,				0x32,
    	TW2964_REG_R_SEQ54,				0x54,
    	TW2964_REG_R_SEQ76,				0x76,
    	TW2964_REG_R_SEQ98,				0x98,
    	TW2964_REG_R_SEQBA,				0xBA,
    	TW2964_REG_R_SEQDC,				0xDC,
    	TW2964_REG_R_SEQFE,				0xFE,
    	TW2964_REG_AMASTER,				0xC2,
    	TW2964_REG_MIX_MUTE,			0x10,
    	TW2964_REG_MIX_RATIO21,			0x00,
    	TW2964_REG_MIX_RATIO43,			0x00,
    	TW2964_REG_MIX_RATIOP,			0x80,
    	TW2964_REG_MIX_OUTSEL,			0x1F,
    	TW2964_REG_ADET,				0xF0,
    	TW2964_REG_ADET_TH21,			0x33,
    	TW2964_REG_ADET_TH43,			0x33,
    	TW2964_REG_ACKI_L,				0x23,
    	TW2964_REG_ACKI_M,				0x48,
    	TW2964_REG_ACKI_H,				0x07,
    	TW2964_REG_ACKN_L,				0x00,
    	TW2964_REG_ACKN_M,				0x01,
    	TW2964_REG_ACKN_H,				0x00,
    	TW2964_REG_SDIV,				0x00,
    	TW2964_REG_LRDIV,				0x20,
    	TW2964_REG_ACCNTL,				0xC4,
    	TW2964_REG_VMISC,				0x40,
    	TW2964_REG_CLKOCTL,				0x00,
    	TW2964_REG_AVDET_MODE,			0x0F,
    	TW2964_REG_AVDET_ENA,			0xFF,
    	TW2964_REG_AVDET_STATE,			0x00,
    	TW2964_REG_TEST,				0x00,
    //	TW2964_REG_DEV_ID,				0x00,	( read only )
    };
    
    // @brief Default values as suggested at tw2964 datasheet
    static const u8 channel_registers[] = {
    //	( TW2964_REG_VIDSTAT ),			0x00,		/// TW2964_REG_VIDSTAT (read only)
    //	( TW2964_REG_VIDSTAT + 0x10),	0x00,
    //	( TW2964_REG_VIDSTAT + 0x20),	0x00,
    //	( TW2964_REG_VIDSTAT + 0x30),	0x00,
    	( TW2964_REG_BRIGHT ),			0x00,		/// TW2964_REG_BRIGHT
    	( TW2964_REG_BRIGHT + 0x10),	0x00,
    	( TW2964_REG_BRIGHT + 0x20),	0x00,
    	( TW2964_REG_BRIGHT + 0x30),	0x00,
    	( TW2964_REG_CONTRAST ),		0x64,		/// TW2964_REG_CONTRAST
    	( TW2964_REG_CONTRAST + 0x10),	0x64,
    	( TW2964_REG_CONTRAST + 0x20),	0x64,
    	( TW2964_REG_CONTRAST + 0x30),	0x64,
    	( TW2964_REG_SHARPNESS ),		0x11,		/// TW2964_REG_SHARPNESS
    	( TW2964_REG_SHARPNESS + 0x10),	0x11,
    	( TW2964_REG_SHARPNESS + 0x20),	0x11,
    	( TW2964_REG_SHARPNESS + 0x30),	0x11,
    	( TW2964_REG_SAT_U ),			0x80,		/// TW2964_REG_SAT_U
    	( TW2964_REG_SAT_U + 0x10),		0x80,
    	( TW2964_REG_SAT_U + 0x20),		0x80,
    	( TW2964_REG_SAT_U + 0x30),		0x80,
    	( TW2964_REG_SAT_V ),			0x80,		/// TW2964_REG_SAT_V
    	( TW2964_REG_SAT_V + 0x10),		0x80,
    	( TW2964_REG_SAT_V + 0x20),		0x80,
    	( TW2964_REG_SAT_V + 0x30),		0x80,
    	( TW2964_REG_HUE ),				0x00,		/// TW2964_REG_HUE
    	( TW2964_REG_HUE + 0x10),		0x00,
    	( TW2964_REG_HUE + 0x20),		0x00,
    	( TW2964_REG_HUE + 0x30),		0x00,
    	( TW2964_REG_CROP_HI ),			0x12,		/// TW2964_REG_CROP_HI
    	( TW2964_REG_CROP_HI + 0x10),	0x12,
    	( TW2964_REG_CROP_HI + 0x20),	0x12,
    	( TW2964_REG_CROP_HI + 0x30),	0x12,
    	( TW2964_REG_VDELAY_LO ),		0x12,		/// TW2964_REG_VDELAY_LO
    	( TW2964_REG_VDELAY_LO + 0x10),	0x12,
    	( TW2964_REG_VDELAY_LO + 0x20),	0x12,
    	( TW2964_REG_VDELAY_LO + 0x30),	0x12,
    	( TW2964_REG_VACTIVE_LO ),		0x20,		/// TW2964_REG_VACTIVE_LO
    	( TW2964_REG_VACTIVE_LO + 0x10),0x20,
    	( TW2964_REG_VACTIVE_LO + 0x20),0x20,
    	( TW2964_REG_VACTIVE_LO + 0x30),0x20,
    	( TW2964_REG_HDELAY_LO ),		0x0A,		/// TW2964_REG_HDELAY_LO
    	( TW2964_REG_HDELAY_LO + 0x10),	0x0A,
    	( TW2964_REG_HDELAY_LO + 0x20),	0x0A,
    	( TW2964_REG_HDELAY_LO + 0x30),	0x0A,
    	( TW2964_REG_HACTIVE_LO ),		0xD0,		/// TW2964_REG_HACTIVE_LO
    	( TW2964_REG_HACTIVE_LO + 0x10),0xD0,
    	( TW2964_REG_HACTIVE_LO + 0x20),0xD0,
    	( TW2964_REG_HACTIVE_LO + 0x30),0xD0,
    //	( TW2964_REG_MVSN ),			0x00,		/// TW2964_REG_MVSN (read only)
    //	( TW2964_REG_MVSN + 0x10),		0x00,
    //	( TW2964_REG_MVSN + 0x20),		0x00,
    //	( TW2964_REG_MVSN + 0x30),		0x00,
    //	( TW2964_REG_STATUS2 ),			0x00,		/// TW2964_REG_STATUS2 (read only)
    //	( TW2964_REG_STATUS2 + 0x10),	0x00,
    //	( TW2964_REG_STATUS2 + 0x20),	0x00,
    //	( TW2964_REG_STATUS2 + 0x30),	0x00,
    	( TW2964_REG_SDT ),				0x07,		/// TW2964_REG_SDT
    	( TW2964_REG_SDT + 0x10),		0x07,
    	( TW2964_REG_SDT + 0x20),		0x07,
    	( TW2964_REG_SDT + 0x30),		0x07,
    	( TW2964_REG_SDTR ),			0x7F,		/// TW2964_REG_SDTR
    	( TW2964_REG_SDTR + 0x10),		0x7F,
    	( TW2964_REG_SDTR + 0x20),		0x7F,
    	( TW2964_REG_SDTR + 0x30),		0x7F,
    	( TW2964_REG_NT50 ),			0x08,		/// TW2964_REG_NT50
    	( TW2964_REG_NT50 + 0x10),		0x08,
    	( TW2964_REG_NT50 + 0x20),		0x08,
    	( TW2964_REG_NT50 + 0x30),		0x08,
    	( TW2964_REG_IDCNTL ),			0x9C,		/// TW2964_REG_IDCNTL (заточил под PAL ID, non default)
    	( TW2964_REG_IDCNTL + 0x10),	0x9C,
    	( TW2964_REG_IDCNTL + 0x20),	0x9C,
    	( TW2964_REG_IDCNTL + 0x30),	0x9C,
    //	( TW2964_REG_HREF ),			0x00,		/// TW2964_REG_HREF (read only)
    //	( TW2964_REG_HREF + 0x10),		0x00,
    //	( TW2964_REG_HREF + 0x20),		0x00,
    //	( TW2964_REG_HREF + 0x30),		0x00,
    };
    
    // attempt to register the driver in the driver and forward ioctl
    #if defined(NEED_USE_TW2964_IOCTL) && (NEED_USE_TW2964_IOCTL)
    
    	// total function for working with files by fops
    	static int etx_open(struct inode *inode, struct file *file)
    	{
    			// Creating Physical memory
    			if((kernel_buffer = kmalloc(mem_size , GFP_KERNEL)) == 0)
    			{
    				my_simple_info("Cannot allocate memory in kernel\n");
    				return -1;
    			}
    
    			my_simple_info("Device File Opened...!!!\n");
    			return 0;
    	}
    	// total function for working with files by fops
    	static int etx_release(struct inode *inode, struct file *file)
    	{
    			kfree(kernel_buffer);
    			my_simple_info("Device File Closed...!!!\n");
    			return 0;
    	}
    	// total function for working with files by fops
    	static ssize_t etx_read(struct file *filp, char __user *buf, size_t len, loff_t *off)
    	{
    		my_simple_info("Read Function\n");
    
    		if(kernel_buffer)
    		{
    			unsigned long res = copy_to_user(buf, kernel_buffer, mem_size);
    
    			if(!res)
    			{
    				my_simple_info("Data Read : Done!\n");
    			}
    			else
    			{
    				my_simple_info("Data Read Err: not done copy_to_user err!\n");
    			}
    
    			return mem_size;
    		}
    		else
    		{
    			my_simple_info("Err kernel_buffer is null, unable copy_to_user()\n");
    		}
    
    		return 0;
    	}
    	// total function for working with files by fops
    	static ssize_t etx_write(struct file *filp, const char __user *buf, size_t len, loff_t *off)
    	{
    		my_simple_info("Write function\n");
    
    		if(kernel_buffer)
    		{
    			unsigned long res = 0;
    
    			memset(kernel_buffer, 0,  mem_size);
    			res = copy_from_user(kernel_buffer, buf, len);
    
    			if(!res)
    			{
    				my_simple_info("Data Write : done! -%s", kernel_buffer);
    			}
    			else
    			{
    				my_simple_info("Data Write Err: not done copy_from_user err!\n");
    			}
    
    			return len;
    		}
    		else
    		{
    			my_simple_info("Err kernel_buffer is null, unable copy_from_user()\n");
    		}
    
    		return 0;
    	}
    
    	// work with ioctl
    	static long etx_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
    	{
    		unsigned long res = 0;
    
    		 switch(cmd)
    		 {
    			case SET_MAIN_CHANNEL_TW2964:
    			{
    				if(drv_tw2964)
    				{
    					res = copy_from_user(&drv_tw2964->cur_chan ,(int32_t*) arg, sizeof(drv_tw2964->cur_chan));
    
    					if(!res)
    					{
    						my_simple_info("set main channel value = %d\n", drv_tw2964->cur_chan);
    					}
    					else
    					{
    						my_simple_info("Err copy_from_user()\n");
    					}
    				}
    				else
    				{
    					my_simple_info("error from ioctl, drv_tw2964 is null\n");
    				}
    			}
    				break;
    
    			case GET_MAIN_CHANNEL_TW2964:
    			{
    				if(drv_tw2964)
    				{
    					res = copy_to_user((int32_t*) arg, &drv_tw2964->cur_chan, sizeof(&drv_tw2964->cur_chan));
    
    					if(!res)
    					{
    						my_simple_info("get main channel value = %d\n", drv_tw2964->cur_chan);
    					}
    					else
    					{
    						my_simple_info("Err copy_to_user()\n");
    					}
    				}
    				else
    				{
    					my_simple_info("error from ioctl, drv_tw2964 is null\n");
    				}
    			}
    				break;
    
    			case GET_VIDEO_DETECT_FROM_INPUT_TW2964:
    				my_simple_info("get video detect from input channel\n");
    				break;
    		}
    		return 0;
    	}
    
    	// if it was a standalone driver, and this is part of i2c
    	// as a matter of fact it is the second init,
    	// so it will be embedded in the initial tw2964_probe init
    	// static int __init etx_driver_init (void)
    	static int etx_driver_init(void)
    	{
    			// Allocating Major number
    			if((alloc_chrdev_region(&dev, 0, 1, "tw2964")) < 0)
    			{
    				my_simple_info("Err cannot allocate major number\n");
    				return -1;
    			}
    			my_simple_info("Major = %d Minor = %d \n", MAJOR(dev), MINOR(dev));
    
    			// Creating cdev structure
    			cdev_init(&etx_cdev, &fops);
    
    			// Adding character device to the system
    			if((cdev_add(&etx_cdev, dev, 1)) < 0)
    			{
    				my_simple_info("Err cannot add the device to the system\n");
    				goto r_class;
    			}
    
    			// Creating struct class
    			if((dev_class = class_create(THIS_MODULE, "tw2964_class")) == NULL)
    			{
    				my_simple_info("Err cannot create the struct class\n");
    				goto r_class;
    			}
    
    			// Creating device
    			// this name been in udev system (e.g. /dev/tw2964)
    			if((device_create(dev_class, NULL, dev, NULL, "tw2964")) == NULL)
    			{
    				my_simple_info("Err cannot create the Device 1\n");
    				goto r_device;
    			}
    
    			my_simple_info("device driver insert...Done!!!\n");
    
    			return 0;
    
    	r_device:
    			class_destroy(dev_class);
    	r_class:
    			unregister_chrdev_region(dev, 1);
    			return -1;
    	}
    
    	// if it was a standalone driver, and this is part of i2c
    	// essentially the second deinite,
    	// so it will be embedded in the original deinit tw2964_remove
    	// void __exit etx_driver_exit (void)
    	void etx_driver_exit(void)
    	{
    			device_destroy	(dev_class, dev);
    			class_destroy	(dev_class);
    			cdev_del		(&etx_cdev);
    			unregister_chrdev_region(dev, 1);
    			my_simple_info("device driver remove...Done!!!\n");
    	}
    
    //	module_init(etx_driver_init);
    //	module_exit(etx_driver_exit);
    #endif
    
    static int tw2964_read_from_i2c(struct v4l2_subdev *sd, unsigned char addr);
    static int tw2964_write_to_i2c(struct v4l2_subdev *sd, unsigned char addr, unsigned char value);
    static int tw2964_reset(struct v4l2_subdev *sd, u32 val);
    
    // @brief channel number validation
    static inline u8 verif_chan(u8 chan)
    {
    	return (chan>(TW2964_INPUT_NUM-1))?3:(TW2964_INPUT_NUM-1);
    }
    
    //------------------------------------------------------------------------------
    /// @brief search for special registers separate for channels (not common or shared)
    static inline int find_reg_separate_by_channel(u8 reg)
    {
    	u8 res = 0, i = 0;
    
    	for (; i <= 0x0F; ++i)
    	{
    		if (i == reg)
    		{
    			res = 1;
    			break;
    		}
    	}
    
    	if (res)
    		return 1;
    	else if (reg == 0xA0 || reg == 0xA4 || reg == 0xC4)
    		return 2;
    	else
    		return 0;
    }
    
    // @brief casting and finding the address of the beginning of the tw2964 structure
    static inline struct tw2964 *to_tw2964(struct v4l2_subdev *sd)
    {
    	// through the pointer sd we find the address on the whole structure tw2964
    	// How does it work:
    	// recognizes the sd field offset inside the tw2964 structure
    	// and compensate in the passed sd pointer
    	return container_of(sd, struct tw2964, sd);
    }
    
    // @brief casting and finding the address of the beginning of the tw2964 structure
    static inline struct tw2964 *to_state_from_ctrl(struct v4l2_ctrl *ctrl)
    {
    	// through the pointer ctrl-> handler we find the address on the whole structure tw2964
    	// How does it work:
    	// learns the offset of the hdl field inside the tw2964 structure
    	// and compensate in the passed pointer ctrl-> handler
    	return container_of(ctrl->handler, struct tw2964, hdl);
    }
    
    #ifdef MAKE_TW2964_REG_ADD_WITH_CHAN
    	#undef MAKE_TW2964_REG_ADD_WITH_CHAN
    #endif
    #define MAKE_TW2964_REG_ADD_WITH_CHAN	if ( res == 1) 						\
    										{									\
    											reg = (reg | (channel << 4));	\
    										}									\
    										else if (res == 2)					\
    										{									\
    											reg += channel;					\
    										}
    
    // on/off output clk
    static void tw2964_enable_output_clk(struct v4l2_subdev *sd, u8 on_or_off)
    {
    	int val[4]  = { 0, 0, 0, 0};
    
    	// read the value of the mic. (it is considered that at this stage micr. is stitched by default)
    	val[0] = tw2964_read_from_i2c(sd, TW2964_REG_CLKOCTL);
    	if (val[0] < 0)
    		goto err;
    
    	val[1] = tw2964_read_from_i2c(sd, TW2964_REG_CHMD);
    	if (val[1] < 0)
    		goto err;
    
    
    	val[2] = tw2964_read_from_i2c(sd, TW2964_REG_MAINCH);
    	if (val[2] < 0)
    		goto err;
    
    
    	val[3] = tw2964_read_from_i2c(sd, TW2964_REG_SELCH);
    	if (val[3] < 0)
    		goto err;
    
    	// turn on or turn off the main clock resolution
    	if(on_or_off)
    		val[0] SET_B(CLKOCTL_OE);
    	else
    		val[0] CLR_B(CLKOCTL_OE);
    
    	// clear the lower 4 bits
    	val[0]  &= ~((int)0x0F);
    	val[1]  &= ~((int)0x0F);
    
    	// depending on the requested number of multiplex video request the output frequency
    	// if HOW_MUCH_VIDEO_IN_TIME_MULTIPLEXING == 2, то 54
    	if ((HOW_MUCH_VIDEO_IN_TIME_MULTIPLEXING > 1) && (HOW_MUCH_VIDEO_IN_TIME_MULTIPLEXING < 4))
    	{
    		// очистим 3 и 2 бит;
    		val[2]  &= ~((int)0x0C);
    		val[3]  &= ~((int)0x0C);
    
    		val[0]  |= ((1 << CLKOCTL_CLKPO_MD)	| (1 << CLKOCTL_CLKNO_MD));
    		val[1] 	|= ((1 << CHMD_CHMD1)		| (1 << CHMD_CHMD2));
    		val[2] 	|= ( 2 << MAINCH_MAINCH2);
    		val[3]	|= ( 3 << SELCH_SELCH2);
    
    		tw2964_write_to_i2c(sd, TW2964_REG_MAINCH,	val[2]);
    		tw2964_write_to_i2c(sd, TW2964_REG_SELCH,	val[3]);
    	}// if HOW_MUCH_VIDEO_IN_TIME_MULTIPLEXING == 4, то 108
    	else if (HOW_MUCH_VIDEO_IN_TIME_MULTIPLEXING >= 4)
    	{
    		val[0]  |= ((2 << CLKOCTL_CLKPO_MD) | (2 << CLKOCTL_CLKNO_MD));
    		val[1] 	|= (2 << CHMD_CHMD1);
    	}
    
    	tw2964_write_to_i2c(sd, TW2964_REG_CLKOCTL, val[0]);
    	tw2964_write_to_i2c(sd, TW2964_REG_CHMD,	val[1]);
    
    	if ((val[0] < 0) || (val[1] < 0) || (val[2] < 0) || (val[3] < 0))
    		goto err;
    
    	// read the value of the mic.
    	val[0] = tw2964_read_from_i2c(sd, TW2964_REG_CLKOCTL);
    	if (val[0] < 0)
    		goto err;
    
    	val[1] = tw2964_read_from_i2c(sd, TW2964_REG_CHMD);
    	if (val[1] < 0)
    		goto err;
    
    	val[2] = tw2964_read_from_i2c(sd, TW2964_REG_MAINCH);
    	if (val[2] < 0)
    		goto err;
    
    	val[3] = tw2964_read_from_i2c(sd, TW2964_REG_SELCH);
    	if (val[3] < 0)
    		goto err;
    
    	dev_dbg_lvl(sd->dev, 1, debug, "TW2964_REG_CLKOCTL:=%#x\n"	,val[0]);
    	dev_dbg_lvl(sd->dev, 1, debug, "TW2964_REG_CHMD:=%#x\n"		,val[1]);
    	dev_dbg_lvl(sd->dev, 1, debug, "TTW2964_REG_MAINCH:=%#x\n"	,val[2]);
    	dev_dbg_lvl(sd->dev, 1, debug, "TW2964_REG_SELCH:=%#x\n"	,val[3]);
    
    	return;
    
    err:
    	{
    		int tik = 0;
    
    		for(; tik<ARRAY_SIZE(val); ++tik)
    			dev_err(sd->dev, "%s: failed with error = %d\n", __func__, val[tik]);
    	}
    };
    
    // select multiplex input (A or B) for all input groups (from 1 to 4)
    static void tw2964_selmux(struct v4l2_subdev *sd)
    {
    	struct tw2964 *decoder = to_tw2964(sd);
    	int input = TW2964_VIN_A;
    	int val;
    
    //DeVdistress
    #if(1)
    	switch (decoder->input)
    	{
    	case TW2964_VIN_A:
    		break;
    	case TW2964_VIN_B:
    		input = TW2964_VIN_B;
    		break;
    
    	default:
    		break;
    	}
    #endif
    
    	dev_dbg_lvl(sd->dev, 1, debug, "Selecting video route: route input=%i tw2964 input=%i\n",
    			decoder->input, input);
    
    	// if asked to enter B
    	if(input == TW2964_VIN_B)
    	{
    		// read the value of the mic. (it is considered that at this stage micr. is stitched by default)
    		val = tw2964_read_from_i2c(sd, TW2964_REG_SHCOR960);
    		if (val < 0)
    			goto err;
    
    		// set the input B
    		val |= ((1<<SHCOR960_VIN4) | (1<<SHCOR960_VIN3) | (1<<SHCOR960_VIN2) | (1<<SHCOR960_VIN1));
    
    		tw2964_write_to_i2c(sd, TW2964_REG_SHCOR960, val);
    	}
    	else
    	{
    		// flashing default
    		val = (0x03<<SHCOR960_SHCOR960);
    		tw2964_write_to_i2c(sd, TW2964_REG_SHCOR960, val);
    	}
    
    	// read for log output
    	val = tw2964_read_from_i2c(sd, TW2964_REG_SHCOR960);
    
    	if (val < 0)
    		goto err;
    	else
    		dev_dbg_lvl(sd->dev, 1, debug, "TW2964_REG_SHCOR960:=%#x\n",val);
    
    	return;
    
    err:
    	dev_err(sd->dev, "%s: failed with error = %d\n", __func__, val);
    };
    
    //------------------------------------------------------------------------------
    /// @brief reading in tw2964 on i2c special registers, separate for channels
    static s32 read_reg(struct i2c_client *client, u8 reg, u8 channel)
    {
    	int ret = 0;
    	u8 res = find_reg_separate_by_channel(reg);
    
    	MAKE_TW2964_REG_ADD_WITH_CHAN
    
    	ret = i2c_smbus_read_byte_data(client, reg);
    
    	my_simple_info("read adr'%#02x' dat'%#02x'\n", reg, (u8)ret);
    
    	return (s32)ret;
    }
    
    //------------------------------------------------------------------------------
    /// @brief writing in tw2964 on i2c special registers, separate for channels
    static int write_reg(struct i2c_client *client, u8 reg, u8 value, u8 channel)
    {
    	u8 res = find_reg_separate_by_channel(reg);
    	int ret;
    
    	MAKE_TW2964_REG_ADD_WITH_CHAN
    
    	ret = i2c_smbus_write_byte_data(client, reg, value);
    
    	if (ret < 0)
    				return ret;
    
    	my_simple_info("write adr'%#02x' dat'%#02x'\n", reg, value);
    
    	return ret;
    }
    
    //------------------------------------------------------------------------------
    /// @brief write to tw2964 i2c ALL REGISTERS
    static int write_all_regs(struct i2c_client *client, const u8 *regs, size_t size_of_mass_regs)
    {
    	int ret;
    	int i;
    
    	my_simple_info( "write_all_regs()-size_of_mass_regs-'%u'\n", size_of_mass_regs);
    
    	for (i = 0; i < size_of_mass_regs; i += 2)
    	{
    		ret = i2c_smbus_write_byte_data(client, regs[i], regs[i + 1]);
    		my_simple_info( "[#%u]write_all_regs()ret'%i',regs'%#02x',data'%#02x'\n", i, ret, regs[i], regs[i + 1]);
    
    		if (ret < 0)
    			return ret;
    	}
    	return 0;
    }
    
    //------------------------------------------------------------------------------
    /// @brief reading from tw2964 on i2c (by analogy with tvp5150)
    static int tw2964_read_from_i2c(struct v4l2_subdev *sd, unsigned char addr)
    {
    	struct i2c_client *c = v4l2_get_subdevdata(sd);
    	int rc;
    
    	rc = i2c_smbus_read_byte_data(c, addr);
    	if (rc < 0)
    	{
    		dev_err(sd->dev, "i2c i/o error: rc == %d\n", rc);
    		return rc;
    	}
    
    	dev_dbg_lvl(sd->dev, 2, debug, "tw2964: read adr'%#02x' dat'%#02x'\n", addr, rc);
    
    	return rc;
    }
    
    //------------------------------------------------------------------------------
    /// @brief write to tw2964 on i2c (by analogy with tvp5150)
    static int tw2964_write_to_i2c(struct v4l2_subdev *sd, unsigned char addr, unsigned char value)
    {
    	struct i2c_client *c = v4l2_get_subdevdata(sd);
    	int rc;
    
    	dev_dbg_lvl(sd->dev, 2, debug, "tw2964: writing adr'%#02x' dat'%#02x'\n", addr, value);
    
    	rc = i2c_smbus_write_byte_data(c, addr, value);
    	if (rc < 0)
    		dev_err(sd->dev, "i2c i/o error: rc == %d\n", rc);
    
    	return rc;
    }
    
    //------------------------------------------------------------------------------
    /// @brief write tw2964 default value in accordance with pdf
    static int tw2964_write_inittab(struct v4l2_subdev *sd)
    {
    	struct i2c_client *client = v4l2_get_subdevdata(sd);
    	int ret = 0;
    
    	ret = write_all_regs(client, channel_registers, (size_t)ARRAY_SIZE(channel_registers));
    	if (ret < 0)
    		return ret;
    
    	ret = write_all_regs(client, global_registers, (size_t)ARRAY_SIZE(global_registers));
    
    	return ret;
    }
    
    // output to debag info content of all registers
    static int tw2964_log_status(struct v4l2_subdev *sd)
    {
    	struct tw2964 *state = to_tw2964(sd);
    	int i = 0, ret = 0, tik = 0;
    
    	for(; tik < HOW_MUCH_VIDEO_IN_TIME_MULTIPLEXING; ++tik)
    	{
    		v4l2_info(sd, "Standard: %s\n",
    					state->norm[verif_chan(state->channel[tik])] & V4L2_STD_525_60 ? "60 Hz" : "50 Hz");
    			v4l2_info(sd, "Channel: %d\n", state->channel[tik]);
    			v4l2_info(sd, "Input: %d\n", state->input);
    	}
    
    	for (; i <= 255; ++i)
    	{
    		ret = tw2964_read_from_i2c(sd, i);
    		if (ret < 0)
    			return ret;
    	}
    
    	return 0;
    }
    
    // main control functions
    static int tw2964_s_ctrl(struct v4l2_ctrl *ctrl)
    {
    	struct tw2964 *state = to_state_from_ctrl(ctrl);
    	struct i2c_client *client = v4l2_get_subdevdata(&state->sd);
    	s32 reg;
    	int res = 0;
    
    	switch (ctrl->id)
    	{
    		case V4L2_CID_SHARPNESS:
    			// chop off fat, mask
    			reg = ((s32)0x0F & ctrl->val);
    			res = write_reg(client, TW2964_REG_SHARPNESS,	reg, 		verif_chan(state->cur_chan));
    			return res;
    
    		case V4L2_CID_BLUE_BALANCE:
    			res = write_reg(client, TW2964_REG_SAT_U,		ctrl->val,	verif_chan(state->cur_chan));
    			return res;
    
    		case V4L2_CID_RED_BALANCE:
    			res = write_reg(client, TW2964_REG_SAT_V,		ctrl->val,	verif_chan(state->cur_chan));
    			return res;
    
    		case V4L2_CID_BRIGHTNESS:
    			res = write_reg(client, TW2964_REG_BRIGHT,		ctrl->val,	verif_chan(state->cur_chan));
    			return res;
    
    		case V4L2_CID_CONTRAST:
    			res = write_reg(client, TW2964_REG_CONTRAST,	ctrl->val,	verif_chan(state->cur_chan));
    			return res;
    
    		case V4L2_CID_HUE:
    			res = write_reg(client, TW2964_REG_HUE,			ctrl->val,	verif_chan(state->cur_chan));
    			return res;
    
    		default:
    			return -EINVAL;
    	}
    
    	return res;
    }
    
    // These volatile controls are needed because all four channels share
    // these controls. So a change made to them through one channel would
    // require another channel to be updated.
    //
    // Normally this would have been done in a different way, but since the one
    // board that uses this driver sees this single chip as if it was on four
    // different i2c adapters (each adapter belonging to a separate instance of
    // the same USB driver) there is no reliable method that I have found to let
    // the instances know about each other.
    // So implementing these global registers as volatile is the best we can do.
    static int tw2964_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
    {
    	struct tw2964		*state	= to_state_from_ctrl(ctrl);
    	struct i2c_client	*client	= v4l2_get_subdevdata(&state->sd);
    	s32 reg;
    
    	switch (ctrl->id)
    	{
    		case V4L2_CID_SHARPNESS:
    			reg = read_reg(client, TW2964_REG_SHARPNESS,		verif_chan(state->cur_chan));
    			// chop off fat, mask
    			ctrl->val = (s32)0x0F & reg;
    			break;
    
    		case V4L2_CID_BLUE_BALANCE:
    			ctrl->val = read_reg(client, TW2964_REG_SAT_U,		verif_chan(state->cur_chan));
    			break;
    
    		case V4L2_CID_RED_BALANCE:
    			ctrl->val = read_reg(client, TW2964_REG_SAT_V,		verif_chan(state->cur_chan));
    			break;
    
    		case V4L2_CID_BRIGHTNESS:
    			ctrl->val = read_reg(client, TW2964_REG_BRIGHT,		verif_chan(state->cur_chan));
    			break;
    
    		case V4L2_CID_CONTRAST:
    			ctrl->val = read_reg(client, TW2964_REG_CONTRAST,	verif_chan(state->cur_chan));
    			break;
    
    		case V4L2_CID_HUE:
    			ctrl->val = read_reg(client, TW2964_REG_HUE,        verif_chan(state->cur_chan));
    			break;
    	}
    
    	return 0;
    }
    
    // standard definition
    // measurement is performed on the first (0th channel)
    static v4l2_std_id tw2964_read_std(struct v4l2_subdev *sd)
    {
    	struct tw2964 		*state = to_tw2964(sd);
    	struct i2c_client	*client	= v4l2_get_subdevdata(sd);
    	s32 reg;
    	u8  reg_8 = 0;
    
    	reg = read_reg(client, TW2964_REG_SDT, verif_chan(state->cur_chan));
    
    	reg &= 0xFF;
    	reg_8 = (u8)reg;
    
    	// if you have not yet decided on the standard
    	if( reg_8 & (u8)(1<<SDT_DETSTUS))
    		return V4L2_STD_UNKNOWN;
    
    	reg_8 = reg_8 >> SDT_STDNOW;
    
    	switch (reg_8 & 0x0F)
    	{
    		case SDT_NTSC:
    			return V4L2_STD_NTSC;
    
    		case SDT_PAL:
    			return V4L2_STD_PAL;
    
    		case SDT_SECAM:
    			return V4L2_STD_SECAM;
    
    		case SDT_NTSC_4:
    			return V4L2_STD_NTSC_443;
    
    		case SDT_PAL_M:
    			return V4L2_STD_PAL_M;
    
    		case SDT_PAL_C_N:
    			return V4L2_STD_PAL_N | V4L2_STD_PAL_Nc;
    
    		case SDT_PAL_60:
    			return V4L2_STD_PAL_60;
    
    		default:
    			return V4L2_STD_UNKNOWN;
    	}
    }
    
    static int tw2964_set_std(struct v4l2_subdev *sd, v4l2_std_id std)
    {
    	struct tw2964 		*state  = to_tw2964(sd);
    	struct i2c_client	*client = v4l2_get_subdevdata(sd);
    	int fmt = 0, tik = 0;
    
    	// ToDo: thin point is not clear yet
    	// how the channel is formed
    	state->norm[verif_chan(state->cur_chan)] = std;
    
    //DeVdistress
    #if(1)
    	if (std == V4L2_STD_NTSC_443)
    	{
    		fmt = SDT_NTSC_4;
    	}
    	else if (std == V4L2_STD_PAL_M)
    	{
    		fmt = SDT_PAL_M;
    	}
    	else if (std == V4L2_STD_PAL_N || std == V4L2_STD_PAL_Nc)
    	{
    		fmt = SDT_PAL_C_N;
    	}
    	else if (std & V4L2_STD_NTSC)
    	{
    		fmt = SDT_NTSC;
    	}
    	else if (std & V4L2_STD_PAL)
    	{
    		fmt = SDT_PAL;
    	}
    	else if (std & V4L2_STD_SECAM)
    	{
    		fmt = SDT_SECAM;
    	}
    	else
    	{
    		fmt = SDT_PAL;
    	}
    #else
    	fmt = VIDEO_STD_PAL_BDGHIN_BIT;
    #endif
    
    
    	fmt &= 0x07;
    
    	// set the standard for all channels according to the main channel
    	for(tik = 0; tik < HOW_MUCH_VIDEO_IN_TIME_MULTIPLEXING; ++tik)
    	{
    		//reg = read_reg(client, TW2964_REG_SDT, verif_chan(tik));
    		dev_dbg_lvl(sd->dev, 1, debug, "Set video std register to %d.\n", fmt);
    		write_reg(client, TW2964_REG_SDT, fmt, verif_chan(tik));
    	}
    
    	return 0;
    }
    
    static int tw2964_s_std(struct v4l2_subdev *sd, v4l2_std_id norm)
    {
    	struct tw2964 *decoder = to_tw2964(sd);
    
    	// norm <=> std
    	if (decoder->norm[verif_chan(decoder->cur_chan)] == norm)
    		return 0;
    
    	/* Change cropping height limits */
    	if (norm & V4L2_STD_525_60)
    		decoder->rect.height = TW2964_V_MAX_525_60;
    	else
    		decoder->rect.height = TW2964_V_MAX_OTHERS;
    
    
    	return tw2964_set_std(sd, norm);
    }
    
    static int tw2964_s_stream(struct v4l2_subdev *sd, int enable)
    {
    	int val, tik = 0;
    
    	// Enable or disable the video output signals
    	val = tw2964_read_from_i2c(sd, TW2964_REG_VDOEB);
    	if (val < 0)
    		return val;
    
    	for(; tik < HOW_MUCH_SEPARATE_VIP_VIDEO; ++tik)
    	{
    		if (enable)
    			val CLR_B(tik);
    		else
    			val SET_B(tik);
    	}
    
    	tw2964_write_to_i2c(sd, TW2964_REG_VDOEB, val);
    
    	return 0;
    }
    
    // I use it purely for debugging the channel number
    static int tw2964_s_video_routing(struct v4l2_subdev *sd, u32 input, u32 output, u32 config)
    {
    	struct tw2964 *dec = to_tw2964(sd);
    	struct i2c_client *client = v4l2_get_subdevdata(sd);
    
    	if (config && config - 1 != dec->cur_chan)
    	{
    		if (config > 4)
    		{
    			dev_err(&client->dev,
    				"channel %d is not between 1 and 4!\n", config);
    			return -EINVAL;
    		}
    
    		dec->cur_chan = config - 1;
    		dev_dbg(&client->dev, "initializing TW2964 channel %d\n",
    			dec->cur_chan);
    	}
    
    	if (input > 1)
    		return -EINVAL;
    
    	return 0;
    }
    
    static int tw2964_g_mbus_config(struct v4l2_subdev *sd,
    				 struct v4l2_mbus_config *cfg)
    {
    	struct tw2964 *decoder = to_tw2964(sd);
    
    	cfg->type = decoder->mbus_type;
    	cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_PCLK_SAMPLE_RISING
    		   | V4L2_MBUS_FIELD_EVEN_LOW | V4L2_MBUS_DATA_ACTIVE_HIGH;
    
    	return 0;
    }
    
    // throw the output video format
    static int tw2964_enum_mbus_code(	struct v4l2_subdev *sd,
    									struct v4l2_subdev_pad_config *cfg,
    									struct v4l2_subdev_mbus_code_enum *code)
    {
    	if (code->pad || code->index)
    		return -EINVAL;
    
    	code->code = MEDIA_BUS_FMT_UYVY8_2X8;
    	return 0;
    }
    
    // throw the size of the output image
    static int tw2964_enum_frame_size(	struct v4l2_subdev *sd,
    									struct v4l2_subdev_pad_config *cfg,
    									struct v4l2_subdev_frame_size_enum *fse)
    {
    	struct tw2964 *decoder = to_tw2964(sd);
    
    	if (fse->index >= 8 || fse->code != MEDIA_BUS_FMT_UYVY8_2X8)
    		return -EINVAL;
    
    	fse->code = MEDIA_BUS_FMT_UYVY8_2X8;
    	//DeVdistress
    #if(1)
    	fse->min_width = decoder->rect.width;
    	fse->max_width = decoder->rect.width;
    #else
    	fse->min_width = 700;
    	fse->max_width = 700;
    #endif
    
    	fse->min_height = decoder->rect.height / 2;
    	fse->max_height = decoder->rect.height / 2;
    
    	return 0;
    }
    
    // a kind of point of installation and reading the size of the image and the type of output
    static int tw2964_fill_fmt(	struct v4l2_subdev *sd,
    							struct v4l2_subdev_pad_config *cfg,
    							struct v4l2_subdev_format *format)
    {
    	struct v4l2_mbus_framefmt *f;
    	struct tw2964 *decoder = to_tw2964(sd);
    
    	//DeVdistress
    #if(0)
    	if (!format || (format->pad != DEMOD_PAD_VID_OUT))
    		return -EINVAL;
    #else
    	if (!format || format->pad)
    		return -EINVAL;
    #endif
    
    	f = &format->format;
    
    	//DeVdistress
    #if(1)
    	f->width  = decoder->rect.width;
    #else
    	f->width  = 700;
    #endif
    
    	f->height = decoder->rect.height / 2;
    
    	f->code = MEDIA_BUS_FMT_UYVY8_2X8;
    	f->field = V4L2_FIELD_ALTERNATE;
    	f->colorspace = V4L2_COLORSPACE_SMPTE170M;
    
    	dev_dbg_lvl(sd->dev, 1, debug, "width = %d, height = %d\n", f->width,
    			f->height);
    
    	return 0;
    }
    
    //---------------------------------------------------------------------------------
    // tw2964 link setup
    // tore off from tvp5150
    #if(0)
    	#ifdef CONFIG_MEDIA_CONTROLLER
    	static int tw2964_link_setup(struct media_entity *entity,
    					  const struct media_pad *local,
    					  const struct media_pad *remote, u32 flags)
    	{
    		// restore address to sd
    		struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
    		// restore the address to tw2964
    		struct tw2964 *decoder = to_tw2964(sd);
    		int i;
    
    		for (i = 0; i < TW2964_INPUT_NUM; i++)
    		{
    			if (remote->entity == &decoder->input_ent[i])
    				break;
    		}
    
    		// Do nothing for entities that are not input connectors
    		if (i == TW2964_INPUT_NUM)
    			return 0;
    
    		decoder->input = i;
    
    		tw2964_selmux(sd);
    
    		return 0;
    	}
    
    	static const struct media_entity_operations tw2964_sd_media_ops = {
    		.link_setup = tw2964_link_setup,
    	};
    	#endif
    
    	//---------------------------------------------------------------------------------
    	// register tw2964 in v4l2 as subdevice
    	// tore off from tvp5150
    	static int tw2964_registered(struct v4l2_subdev *sd)
    	{
    	// this macro is defined in the kernel build system
    	#ifdef CONFIG_MEDIA_CONTROLLER
    		struct tw2964 *decoder = to_tw2964(sd);
    		int ret = 0;
    		int i;
    
    		for (i = 0; i < TW2964_INPUT_NUM; i++)
    		{
    			struct media_entity *input = &decoder->input_ent[i];
    			struct media_pad *pad = &decoder->input_pad[i];
    
    			if (!input->name)
    				continue;
    
    			decoder->input_pad[i].flags = MEDIA_PAD_FL_SOURCE;
    
    			// initialize pad (binding pad to input)
    			ret = media_entity_pads_init(input, 1, pad);
    			if (ret < 0)
    				return ret;
    
    			// initialize the media device (binding input to device)
    			ret = media_device_register_entity(sd->v4l2_dev->mdev, input);
    			if (ret < 0)
    				return ret;
    
    			// create a link between input (source) and sd-> entity (sink)
    			ret = media_create_pad_link(input, 0, &sd->entity,
    							DEMOD_PAD_IF_INPUT, 0);
    			if (ret < 0)
    			{
    				media_device_unregister_entity(input);
    				return ret;
    			}
    		}
    	#endif
    
    		return 0;
    	}
    #endif
    
    //---------------------------------------------------------------------------------
    // register callback functions aka endpoints for work with v4l2
    
    static const struct v4l2_ctrl_ops tw2964_ctrl_ops = {
    	.g_volatile_ctrl 	= tw2964_g_volatile_ctrl,	//is realized	// ??? in tvp5150 is absent, i think that it is not necessary
    	.s_ctrl 			= tw2964_s_ctrl,			//is realized
    };
    
    // 2
    static const struct v4l2_subdev_video_ops tw2964_video_ops = {
    	.s_std 				= tw2964_s_std,				//is realized
    	.s_stream 			= tw2964_s_stream,			//is realized	// ToDo: important, need to implement!!!
    	.s_routing 			= tw2964_s_video_routing,	//is realized	// ToDo: channel number debugging
    	.g_mbus_config 		= tw2964_g_mbus_config,		//is realized	//I made by analogy with tvp5150	// a piece of shit, i think that it is not necessary
    };
    
    // 1
    static const struct v4l2_subdev_core_ops tw2964_core_ops = {
    	.log_status 		= tw2964_log_status,						// ToDo: add all registers output
    	.reset      		= tw2964_reset,				//is realized	// ToDo: do it by analogy tvp5150
    };
    
    // 3
    // Attention is very important !!!
    static const struct v4l2_subdev_pad_ops tw2964_pad_ops = {
    	.enum_mbus_code 	= tw2964_enum_mbus_code,	//is realized	// ToDo: important, need to implement!!!
    	.enum_frame_size 	= tw2964_enum_frame_size,	//is realized	// ToDo: important, need to implement!!!
    	.set_fmt 			= tw2964_fill_fmt,			//is realized	// ToDo: important, need to implement!!!
    	.get_fmt 			= tw2964_fill_fmt,			//is realized	// ToDo: important, need to implement!!!
    //	.get_selection 		= tw2964_get_selection,						// for video crop, a piece of shit, i think that it is not necessary
    //	.set_selection 		= tw2964_set_selection,						// for video crop, a piece of shit, i think that it is not necessary
    };
    
    // a piece of shit, i think that it is not necessary
    //static const struct v4l2_subdev_tuner_ops tw2964_tuner_ops = {
    //	.g_tuner = tw2964_g_tuner,
    //};
    
    // a piece of shit, i think that it is not necessary
    //static const struct v4l2_subdev_vbi_ops tw2964_vbi_ops = {
    //	.g_sliced_vbi_cap 	= tw2964_g_sliced_vbi_cap,
    //	.g_sliced_fmt 		= tw2964_g_sliced_fmt,
    //	.s_sliced_fmt 		= tw2964_s_sliced_fmt,
    //	.s_raw_fmt 			= tw2964_s_raw_fmt,
    //};
    
    //---------------------------------------------------------------------------------
    // register all structure's with callback functions aka endpoints for work with v4l2
    static const struct v4l2_subdev_ops tw2964_ops = {
    	.core 				= &tw2964_core_ops,						// 1
    	.video 				= &tw2964_video_ops,					// 2
    //	.tuner 				= &tw2964_tuner_ops,					// a piece of shit, i think that it is not necessary
    //	.vbi 				= &tw2964_vbi_ops,						// a piece of shit, i think that it is not necessary
    	.pad 				= &tw2964_pad_ops,						// 3
    };
    
    #if(0)
    	static const struct v4l2_subdev_internal_ops tw2964_internal_ops = {
    		.registered = tw2964_registered,				//is realized
    	};
    #endif
    
    static int tw2964_detect_version(struct tw2964 *core)
    {
    	struct v4l2_subdev *sd = &core->sd;
    	struct i2c_client *c = v4l2_get_subdevdata(sd);
    	unsigned int i;
    	u8 regs[2];
    	int res;
    
    	for (i = 0; i < 2; i++)
    	{
    		res = tw2964_read_from_i2c(sd, TW2964_REG_TEST + i);
    		if (res < 0)
    			return res;
    		regs[i] = res;
    	}
    
    	core->dev_id = ((regs[0] & 0xC0)>>1) | ((regs[1] & 0xF8)>>3);
    	core->rev_id = (regs[1] & 0x01);
    
    	dev_info(sd->dev, "tw2964 dev_id=0x%04x (%u.%u) chip found @ 0x%02x (%s)\n",
    		  core->dev_id, regs[0], regs[1], c->addr,
    		  c->adapter->name);
    
    	if (core->dev_id == 0x1D && core->rev_id == 0x00)
    	{
    		dev_info(sd->dev, "tw2964 detected.\n");
    	}
    	else
    	{
    		dev_info(sd->dev, "*** unknown tw%04x chip detected.\n",
    			  core->dev_id);
    	}
    
    	return 0;
    }
    
    // hardware reset
    static int tw2964_init(struct i2c_client *client)
    {
    	struct gpio_desc *reset_gpio;
    
    //  tw2964 not have power down pin
    //
    //	struct gpio_desc *pdn_gpio;
    //
    //	pdn_gpio = devm_gpiod_get_optional(&client->dev, "pdn", GPIOD_OUT_HIGH);
    //
    //	// null pointer check
    //	if (IS_ERR(pdn_gpio))
    //		return PTR_ERR(pdn_gpio);
    //
    //	if (pdn_gpio) {
    //		gpiod_set_value_cansleep(pdn_gpio, 0);
    //		// Delay time between power supplies active and reset
    //		msleep(20);
    //	}
    
    	// look for the leg declared in dts as reset
    	// here it is not very clear, at the foot the active state is declared 0 in dts
    	// and here high ???
    	// if dts installations are more priority, then this function simply removes the pull cut and sets HIGH
    	// ToDo: check !!! Because in general, it is not clear what and how to reset (for now, as in tvp5150)
    	reset_gpio = devm_gpiod_get_optional(&client->dev, "reset", GPIOD_OUT_HIGH);
    	// null pointer check
    	if (IS_ERR(reset_gpio))
    		return PTR_ERR(reset_gpio);
    
    	if (reset_gpio)
    	{
    		// RESETB pulse duration */
    		// atmoic delay
    		ndelay(500);
    		gpiod_set_value_cansleep(reset_gpio, 0);
    		// Delay time between end of reset to I2C active, non atomic delay
    		usleep_range(200, 250);
    	}
    
    	return 0;
    }
    
    // software reset
    static int tw2964_reset(struct v4l2_subdev *sd, u32 val)
    {
    	struct tw2964 *decoder = to_tw2964(sd);
    
    	// initializes all registers tw2964 to its default values
    	tw2964_write_inittab(sd);
    
    	// selects decoder input for input 1 .. to 4
    	tw2964_selmux(sd);
    
    	// initialize image preferences
    	v4l2_ctrl_handler_setup(&decoder->hdl);
    
    	tw2964_set_std(sd, decoder->norm[decoder->cur_chan]);
    
    	return 0;
    };
    
    // ToDo: apparently this function is not necessary, in the future to cut off
    static int tw2964_parse_dt(struct tw2964 *decoder, struct device_node *np)
    {
    	struct v4l2_fwnode_endpoint bus_cfg;
    	struct device_node *ep;
    #ifdef CONFIG_MEDIA_CONTROLLER
     #if(0)
    	struct device_node *connectors, *child;
    	struct media_entity *input;
    	const char *name;
    	u32 input_type;
      #endif
    #endif
    	unsigned int flags;
    	int ret = 0;
    
    	ep = of_graph_get_next_endpoint(np, NULL);
    	if (!ep)
    		return -EINVAL;
    
    	ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), &bus_cfg);
    	if (ret)
    		goto err;
    
    	flags = bus_cfg.bus.parallel.flags;
    
    	// in my case, the tire is always BT.656
    //	if ( bus_cfg.bus_type != V4L2_MBUS_PARALLEL )
    //	{
    //		ret = -EINVAL;
    //		goto err;
    //		bus_cfg.bus_type = V4L2_MBUS_PARALLEL;
    //	}
    //	decoder->mbus_type = bus_cfg.bus_type;
    
    	decoder->mbus_type = V4L2_MBUS_BT656 ;
    
    // disabled because I don’t know why
    // ripped off from tvp5150, it didn't work there!
    #if(0)
    	#ifdef CONFIG_MEDIA_CONTROLLER
    		connectors = of_get_child_by_name(np, "connectors");
    
    		if (!connectors)
    			goto err;
    
    		for_each_available_child_of_node(connectors, child) {
    			ret = of_property_read_u32(child, "input", &input_type);
    			if (ret) {
    				dev_err(decoder->sd.dev,
    					 "missing type property in node %s\n",
    					 child->name);
    				goto err_connector;
    			}
    
    			if (input_type >= TW2964_INPUT_NUM) {
    				ret = -EINVAL;
    				goto err_connector;
    			}
    
    			input = &decoder->input_ent[input_type];
    
    			/* Each input connector can only be defined once */
    			if (input->name) {
    				dev_err(decoder->sd.dev,
    					 "input %s with same type already exists\n",
    					 input->name);
    				ret = -EINVAL;
    				goto err_connector;
    			}
    
    			switch (input_type) {
    			case TVP5150_COMPOSITE0:
    			case TVP5150_COMPOSITE1:
    				input->function = MEDIA_ENT_F_CONN_COMPOSITE;
    				break;
    			case TVP5150_SVIDEO:
    				input->function = MEDIA_ENT_F_CONN_SVIDEO;
    				break;
    			}
    
    			input->flags = MEDIA_ENT_FL_CONNECTOR;
    
    			ret = of_property_read_string(child, "label", &name);
    			if (ret < 0) {
    				dev_err(decoder->sd.dev,
    					 "missing label property in node %s\n",
    					 child->name);
    				goto err_connector;
    			}
    
    			input->name = name;
    		}
    
    	err_connector:
    		of_node_put(connectors);
    	#endif
    #endif
    err:
    	of_node_put(ep);
    	return ret;
    }
    
    // This func. call after modprobe
    static int tw2964_probe(struct i2c_client *client,
    			    const struct i2c_device_id *id)
    {
    	struct i2c_adapter	*adapter = client->adapter;
    	struct tw2964 		*state;
    	struct v4l2_subdev	*sd;
    	struct device_node	*np = client->dev.of_node;
    	int res;
    	int tik;
    
    	my_simple_info("start probe\n");
    
    	// Check if the adapter supports the needed features
    	// Check whether your I2C bus controller of the SoC supports the functionality
    	// needed by your device, using the i2c_check_functionality function
    	if (!i2c_check_functionality(adapter,
    	     I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
    		return -EIO;
    
    	// init tw2964, remove the reset
    	// we drag by pin declared in DTS
    	res = tw2964_init(client);
    	if (res)
    		return res;
    
    	my_simple_info("tw2964_init()\n");
    
    	// allocate space for struct tw2964
    	state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL);
    	if (state == NULL)
    		return -ENOMEM;
    
    	// simplify writing
    	sd = &state->sd;
    
    	my_simple_info("tw2964_kzalloc()\n");
    
    	// parsing device tree
    	// almost rudimentary func, while I left it, maybe I don’t understand something
    	if (IS_ENABLED(CONFIG_OF) && np)
    	{
    		res = tw2964_parse_dt(state, np);
    		if (res)
    		{
    			dev_err(sd->dev, "DT parsing error: %d\n", res);
    			return res;
    		}
    
    		my_simple_info("tw2964_parse_dt()\n");
    	}
    
    	// registration of all callbacks in the v4l2 system
    	// this is where the sd-> dev-> init_name pops up
    	v4l2_i2c_subdev_init(sd, client, &tw2964_ops);
    
    	my_dev_info(sd->dev, "tw2964: v4l2_i2c_subdev_init()\n");
    
    	// set 0 channel (numbering from 0)
    	state->cur_chan = 0;
    	// set the standard
    	for(tik = 0; tik < HOW_MUCH_VIDEO_IN_TIME_MULTIPLEXING; ++tik)
    		state->norm[tik] = V4L2_STD_PAL;
    
    	// left by analogy with tw2964
    	// set this flag if this subdev needs a device node
    	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
    
    	// set the properties of media_pad - am device tw2964
    	// cut off from tvp5150
    #if(0)
    	// left by analogy with tw2964
    	sd->internal_ops = &tw2964_internal_ops;
    
    	#if defined(CONFIG_MEDIA_CONTROLLER)
    		state->pads[DEMOD_PAD_IF_INPUT].flags = MEDIA_PAD_FL_SINK;
    		state->pads[DEMOD_PAD_VID_OUT].flags = MEDIA_PAD_FL_SOURCE;
    		state->pads[DEMOD_PAD_VBI_OUT].flags = MEDIA_PAD_FL_SOURCE;
    
    		sd->entity.function = MEDIA_ENT_F_ATV_DECODER;
    
    		res = media_entity_pads_init(&sd->entity, DEMOD_NUM_PADS, state->pads);
    		if (res < 0)
    			return res;
    
    		my_dev_info(sd->dev, "tw2964: media_entity_pads_init()\n");
    
    		sd->entity.ops = &tw2964_sd_media_ops;
    	#endif
    #endif
    
    	// find the device
    	res = tw2964_detect_version(state);
    	if (res < 0)
    		return res;
    
    	my_dev_info(sd->dev, "tw2964: tw2964_detect_version()\n");
    
    	//for(tik = 0; tik < (state->channel + 1); ++tik)
    	//		state->norm[tik] = V4L2_STD_ALL;	// Default is autodetect
    
    	state->input = TW2964_VIN_A;
    
    	state->enable = true;
    
    	// registration of func. controling
    	// registrate func. control
    	v4l2_ctrl_handler_init(&state->hdl, 6);
    	v4l2_ctrl_new_std(&state->hdl, &tw2964_ctrl_ops, V4L2_CID_SHARPNESS,	0,		15,		1, 1	);
    	v4l2_ctrl_new_std(&state->hdl, &tw2964_ctrl_ops, V4L2_CID_BLUE_BALANCE, 0,		200,	1, 128	);
    	v4l2_ctrl_new_std(&state->hdl, &tw2964_ctrl_ops, V4L2_CID_RED_BALANCE,	0,		200,	1, 128	);
    	v4l2_ctrl_new_std(&state->hdl, &tw2964_ctrl_ops, V4L2_CID_CONTRAST,		0,		255,	1, 100	);
    	v4l2_ctrl_new_std(&state->hdl, &tw2964_ctrl_ops, V4L2_CID_BRIGHTNESS,	-128,	127,	1, 0	);
    	v4l2_ctrl_new_std(&state->hdl, &tw2964_ctrl_ops, V4L2_CID_HUE,			-90,	90,		1, 0	);
    
    	// if an error has occurred, then an alert !!!
    	sd->ctrl_handler = &state->hdl;
    	if (state->hdl.error)
    	{
    		res = state->hdl.error;
    		goto err;
    	}
    
    	my_dev_info(sd->dev, "tw2964: v4l2_ctrl_handler_init()\n");
    
    	// Default is no cropping
    	state->rect.top = 0;
    
    	// determine the resolution according to the standard
    #if(1)
    	if (tw2964_read_std(sd) & V4L2_STD_525_60)
    		state->rect.height = TW2964_V_MAX_525_60;
    	else
    		state->rect.height = TW2964_V_MAX_OTHERS;
    #else
    	state->rect.height = TW2964_V_MAX_OTHERS;
    #endif
    
    	state->rect.left = 0;
    	state->rect.width = TW2964_H_MAX;
    
    	my_dev_info(sd->dev, "tw2964: tw2964_read_std()\n");
    
    	// Calls v4l2_ctrl_handler_setup()
    	tw2964_reset(sd, 0);
    
    	my_dev_info(sd->dev, "tw2964: tw2964_reset()\n");
    
    	// requirements from Ti
    	res = v4l2_async_register_subdev(sd);
    	if (res < 0)
    		goto err;
    
    	my_dev_info(sd->dev, "tw2964: v4l2_async_register_subdev()\n");
    
    	tw2964_enable_output_clk(sd, 1);
    
    	//-------------------------------------------------------------------------
    	// move pointers to control critical sections and internal data
    	drv_sd		= sd;
    	i2c_client	= v4l2_get_subdevdata(sd);
    	drv_tw2964  = to_tw2964(sd);
    
    	my_dev_info(sd->dev, "begin etx_driver_init()\n");
    
    	// initiating the second part of the driver, as the udev device
    	etx_driver_init();
    
    	my_dev_info(sd->dev, "end etx_driver_init()\n");
    	//-------------------------------------------------------------------------
    
    	if (debug > 1)
    		tw2964_log_status(sd);
    	return 0;
    
    	// in case of an error we release memory
    err:
    	v4l2_ctrl_handler_free(&state->hdl);
    	return res;
    }
    
    static int tw2964_remove(struct i2c_client *client)
    {
    	struct v4l2_subdev *sd = i2c_get_clientdata(client);
    	struct tw2964 *state = to_tw2964(sd);
    
    	dev_dbg_lvl(sd->dev, 1, debug,
    		"tw2964.c: removing tw2964 adapter on address 0x%x\n",
    		client->addr << 1);
    
    	// remove the second part of the driver, as udev device
    	etx_driver_exit();
    
    	// in the case of work as async
    	v4l2_async_unregister_subdev(sd);
    	v4l2_ctrl_handler_free(&state->hdl);
    	return 0;
    }
    
    static const struct i2c_device_id tw2964_id[] =
    {
    	{ "tw2964", 0 },
    	{ }
    };
    // created tw2964_id structure should be exported to user space,
    // so that hotplugging and module loading systems (sysfs, udev, etc.) can find out
    // What devices does this module work with. This task is solved by the MODULE_DEVICE_TABLE macro.
    MODULE_DEVICE_TABLE(i2c, tw2964_id);
    
    // for parsing in dts file
    #if IS_ENABLED(CONFIG_OF)
    static const struct of_device_id tw2964_of_match[] = {
    	{ .compatible = "techwell,tw2964", },
    	{ /* sentinel */ },
    };
    MODULE_DEVICE_TABLE(of, tw2964_of_match);
    #endif
    
    static struct i2c_driver tw2964_driver =
    {
    	.driver =
    	{
    		.of_match_table = of_match_ptr(tw2964_of_match),
    		.name	= "tw2964",
    	},
    	.probe		= tw2964_probe,
    	.remove		= tw2964_remove,
    	.id_table	= tw2964_id,
    };
    // Registration of functions of loading, unloading, etc.
    // id_table is needed for non-DT based probing of I2C devices
    module_i2c_driver(tw2964_driver);
    

  • manisha said:
    Hi Oleg,

    I will get back to you on above queries soon.

    Regards,
    Manisha

    Hello, Ti. I am already waiting for your reply 7 days. When can you answer?

  • Hi Oleg,

    Thank you for your patience and I apologize for the delay in my response. I will get back to you before end of this week.

    Regards,
    Manisha
  • Hi Oleg,

    Thank you for your patience. We analysed your log and find that vpdma list is hung. One of the possible reason could be that vpdma engine is waiting for frame sync marker to be seen.

    Multi-channel capture use case is not tested by the driver. This is unsupported use case by us but I have seen other customers having some success with it.

    The issue could be coming from the tw2964 driver or from within VIP driver. Unfortunately we don't support this use case and also we don't have the hardware setup at our end to connect to multi-channel input and do further investigation.

    Regards,
    Manisha
  •  Hi Manisha. I apologize for the delay in my response.

    manisha said:
    I have seen other customers having some success with it.

    Where can I read about experience other customers who have some success with vip in multi-channel capture use case?

    I want to repeat an important question. 

    Is the vip.c driver able to work in pixel interleaved method mode aka EMBEDDED_SYNC_2X_MULTIPLEXED_YUV422 or EMBEDDED_SYNC_4X_MULTIPLEXED_YUV422?

    manisha said:
    Unfortunately we don't support this use case and also we don't have the hardware setup at our end to connect to multi-channel input and do further investigation.

    If now to abstract from tw2964 and focus on driver vip.c

    How about tvp5158 driver (http://review.omapzoom.org/#/c/37708/) and http://wiki.tiprocessors.com/index.php/Processor_SDK_VIP_Driver#Video_Input_Port ?

    Has it been tested?

    If you look at the startup logs first channel (5556.gstreamer.log) second channel ( 6862.gstreamer_2.log) and first channel (

    [  213.203392] vin3a-0: vip_open
    [  213.203414] tw2964 4-0029: width = 704, height = 280
    [  213.203422] vin3a: vip_init_port: g_mbus_fmt subdev mbus_code: 2006 fourcc:UYVY size: 704x280
    [  213.203433] vin3a: calc_format_size: fourcc:UYVY size: 704x280 bpl:1408 img_size:394240
    [  213.203439] vin3a-0: init_stream fourcc:UYVY size: 704x280 bpl:1408 img_size:394240
    [  213.203444] vin3a-0: init_stream vpdma data type: 0x27
    [  213.203450] vin3a-0: vip_init_stream: stream instance 0xc0bb1438ecd04000
    [  213.203634] vin3a-0: s_fmt input fourcc:YUYV size: 704x280 bpl:0 img_size:0
    [  213.203641] vin3a-0: try_fmt fourcc:YUYV size: 704x280
    [  213.203650] vin3a-0: try_fmt loop:0 fourcc:YUYV size: 704x280
    [  213.203656] vin3a-0: try_fmt loop:0 found new larger: 704x280
    [  213.203662] vin3a-0: try_fmt loop:0 found at least larger: 704x280
    [  213.203667] vin3a-0: try_fmt loop:0 found new best: 704x280
    [  213.203672] vin3a-0: try_fmt loop:0 found direct match: 704x280
    [  213.203678] vin3a: calc_format_size: fourcc:YUYV size: 704x280 bpl:1408 img_size:394240
    [  213.203684] vin3a-0: s_fmt try_fmt fourcc:YUYV size: 704x280 bpl:1408 img_size:394240
    [  213.203690] vin3a-0: s_fmt fourcc:YUYV size: 704x280 bpl:1408 img_size:394240
    [  213.203695] vin3a-0: s_fmt pix_to_mbus mbus_code: 2006 size: 704x280
    [  213.203703] tw2964 4-0029: width = 704, height = 280
    [  213.203709] vin3a-0: s_fmt subdev fmt mbus_code: 2006 size: 704x280
    [  213.203714] vin3a-0: s_fmt vpdma data type: 0x07
    [  213.203770] vin3a-0: g_fmt fourcc:YUYV code: 2006 size: 704x280 bpl:1408 img_size:394240
    [  213.203775] vin3a-0: g_fmt vpdma data type: 0x07
    [  213.203934] vin3a-0: get 8 buffer(s) of size 394240 each.
    [  213.207641] vin3: vip_set_slice_path:
    [  213.207650] vin3: vip_set_slice_path: DATA_PATH_SELECT(0000010C): 80008000
    [  213.207654] vin3: vip_set_slice_path:
    [  213.207660] vin3: vip_set_slice_path: DATA_PATH_SELECT(0000010C): 40008000
    [  213.207932] vin3: vip_setup_parser: EMBEDDED_SYNC_2X_MULTIPLEXED_YUV422
    [  213.207937] vin3: vip_setup_parser: VIP_PIXCLK_EDGE_POLARITY=0
    [  213.208124] tw2964 4-0029: tw2964: read adr'0x65' dat'0x0'
    [  213.208132] tw2964 4-0029: tw2964: writing adr'0x65' dat'0x0'
    [  213.208246] vin3a-0: vip_load_vpdma_list_fifo: start_dma vb2 buf idx:0
    [  213.209369] vin3a-0: vip_load_vpdma_list_fifo: start_dma vb2 buf idx:1
    
    ) second channel (
    [  357.042092] vin3a-0: vip_open
    [  357.042109] vin3a: calc_format_size: fourcc:YUYV size: 704x280 bpl:1408 img_size:394240
    [  357.042117] vin3a-0: init_stream fourcc:YUYV size: 704x280 bpl:1408 img_size:394240
    [  357.042123] vin3a-0: init_stream vpdma data type: 0x07
    [  357.042132] vin3a-0: vip_init_stream: stream instance 0xc0bb1438ecd06000
    [  357.042338] vin3a-0: s_fmt input fourcc:YUYV size: 704x280 bpl:0 img_size:0
    [  357.042347] vin3a-0: try_fmt fourcc:YUYV size: 704x280
    [  357.042358] vin3a-0: try_fmt loop:0 fourcc:YUYV size: 704x280
    [  357.042365] vin3a-0: try_fmt loop:0 found new larger: 704x280
    [  357.042371] vin3a-0: try_fmt loop:0 found at least larger: 704x280
    [  357.042377] vin3a-0: try_fmt loop:0 found new best: 704x280
    [  357.042383] vin3a-0: try_fmt loop:0 found direct match: 704x280
    [  357.042390] vin3a: calc_format_size: fourcc:YUYV size: 704x280 bpl:1408 img_size:394240
    [  357.042397] vin3a-0: s_fmt try_fmt fourcc:YUYV size: 704x280 bpl:1408 img_size:394240
    [  357.042404] vin3a-0: s_fmt fourcc:YUYV size: 704x280 bpl:1408 img_size:394240
    [  357.042412] vin3a-0: s_fmt pix_to_mbus mbus_code: 2006 size: 704x280
    [  357.042423] tw2964 4-0029: width = 704, height = 280
    [  357.042429] vin3a-0: s_fmt subdev fmt mbus_code: 2006 size: 704x280
    [  357.042435] vin3a-0: s_fmt vpdma data type: 0x07
    [  357.042503] vin3a-0: g_fmt fourcc:YUYV code: 2006 size: 704x280 bpl:1408 img_size:394240
    [  357.042508] vin3a-0: g_fmt vpdma data type: 0x07
    [  357.042694] vin3a-0: get 8 buffer(s) of size 394240 each.
    [  357.046848] vin3: vip_set_slice_path:
    [  357.046858] vin3: vip_set_slice_path: DATA_PATH_SELECT(0000010C): 80008000
    [  357.046863] vin3: vip_set_slice_path:
    [  357.046870] vin3: vip_set_slice_path: DATA_PATH_SELECT(0000010C): 40008000
    [  357.047147] vin3: vip_setup_parser: EMBEDDED_SYNC_2X_MULTIPLEXED_YUV422
    [  357.047153] vin3: vip_setup_parser: VIP_PIXCLK_EDGE_POLARITY=0
    [  357.047356] tw2964 4-0029: tw2964: read adr'0x65' dat'0x0'
    [  357.047364] tw2964 4-0029: tw2964: writing adr'0x65' dat'0x0'
    [  357.047484] vin3a-0: vip_load_vpdma_list_fifo: start_dma vb2 buf idx:0
    [  357.607609] vin3a-0: Timed out loading VPDMA list fifo
    [  357.612795] ------------[ cut here ]------------
    [  357.617446] WARNING: CPU: 0 PID: 1269 at drivers/media/v4l2-core/videobuf2-core.c:1347 vb2_start_streaming+0xdc/0x158
    [  357.628278] Modules linked in: tw2964(O) sha512_generic sha512_arm sha256_generic sha1_generic sha1_arm_neon sha1_arm md5 cbc aes_arm_bs crypto_simd cryptd xfrm_user xfrm4_tunnel ipcomp xfrm_ipcomp esp4 ah4 af_key xfrm_algo bc_example(O) pru_rproc xhci_plat_hcd xhci_hcd pruss_intc rpmsg_rpc rpmsg_proto dwc3 udc_core pruss snd_soc_simple_card snd_soc_simple_card_utils snd_soc_omap_hdmi_audio pvrsrvkm(O) omap_aes_driver ahci_platform libahci_platform pruss_soc_bus libahci omap_sham libata omap_wdt scsi_mod phy_omap_usb2 ti_vip(O) ti_vpe ti_sc ti_csc ti_vpdma dwc3_omap rtc_omap extcon_palmas rtc_palmas pixcir_i2c_ts v4l2_fwnode snd_soc_tlv320aic3x at24 omap_des rtc_ds1307 des_generic crypto_engine omap_crypto omap_remoteproc virtio_rpmsg_bus rpmsg_core remoteproc sch_fq_codel uio_module_drv(O) uio ftdi_sio
    [  357.700108]  usbserial usbcore usb_common gdbserverproxy(O) cryptodev(O) cmemk(O)
    [  357.707960] CPU: 0 PID: 1269 Comm: yavta Tainted: G           O    4.14.79-gbde58ab01e #1
    [  357.716176] Hardware name: Generic DRA74X (Flattened Device Tree)
    [  357.722294] Backtrace: 
    [  357.724762] [<c020b4dc>] (dump_backtrace) from [<c020b7c0>] (show_stack+0x18/0x1c)
    [  357.732366]  r7:00000009 r6:60050013 r5:00000000 r4:c1053d90
    [  357.738056] [<c020b7a8>] (show_stack) from [<c0932528>] (dump_stack+0x90/0xa4)
    [  357.745314] [<c0932498>] (dump_stack) from [<c022b9cc>] (__warn+0xec/0x104)
    [  357.752307]  r7:00000009 r6:c0c0f3d4 r5:00000000 r4:00000000
    [  357.757993] [<c022b8e0>] (__warn) from [<c022ba9c>] (warn_slowpath_null+0x28/0x30)
    [  357.765597]  r9:00000000 r8:00000012 r7:c0719424 r6:ecd06ae8 r5:ecd0688c r4:fffffff0
    [  357.773379] [<c022ba74>] (warn_slowpath_null) from [<c072d94c>] (vb2_start_streaming+0xdc/0x158)
    [  357.782208] [<c072d870>] (vb2_start_streaming) from [<c072f7a8>] (vb2_core_streamon+0x130/0x178)
    [  357.791031]  r7:c0719424 r6:eda6a800 r5:00000000 r4:ecd0688c
    [  357.796719] [<c072f678>] (vb2_core_streamon) from [<c0731fec>] (vb2_streamon+0x38/0x58)
    [  357.804756]  r5:ed9b6e40 r4:00000001
    [  357.808348] [<c0731fb4>] (vb2_streamon) from [<c0732050>] (vb2_ioctl_streamon+0x44/0x48)
    [  357.816480] [<c073200c>] (vb2_ioctl_streamon) from [<c0719448>] (v4l_streamon+0x24/0x28)
    [  357.824604]  r5:40045612 r4:c073200c
    [  357.828200] [<c0719424>] (v4l_streamon) from [<c071bdd4>] (__video_do_ioctl+0x30c/0x314)
    [  357.836324]  r5:40045612 r4:00000001
    [  357.839920] [<c071bac8>] (__video_do_ioctl) from [<c071b688>] (video_usercopy+0x78/0x49c)
    [  357.848132]  r10:00000000 r9:00000000 r8:edc7be28 r7:00000000 r6:00000004 r5:00000001
    [  357.855995]  r4:40045612
    [  357.858544] [<c071b610>] (video_usercopy) from [<c071bac4>] (video_ioctl2+0x18/0x1c)
    [  357.866321]  r10:ec242b90 r9:edc7a000 r8:ed210974 r7:be9bc604 r6:40045612 r5:ed9b6e40
    [  357.874183]  r4:eda6a800
    [  357.876730] [<c071baac>] (video_ioctl2) from [<c0717d0c>] (v4l2_ioctl+0x84/0xe0)
    [  357.884164] [<c0717c88>] (v4l2_ioctl) from [<c034ed3c>] (do_vfs_ioctl+0xa8/0x790)
    [  357.891680]  r9:edc7a000 r8:00000003 r7:40045612 r6:00000003 r5:ed9b6e40 r4:be9bc604
    [  357.899461] [<c034ec94>] (do_vfs_ioctl) from [<c034f460>] (SyS_ioctl+0x3c/0x60)
    [  357.906803]  r10:00000036 r9:edc7a000 r8:be9bc604 r7:40045612 r6:00000003 r5:ed9b6e40
    [  357.914665]  r4:ed9b6e40
    [  357.917213] [<c034f424>] (SyS_ioctl) from [<c0207c40>] (ret_fast_syscall+0x0/0x4c)
    [  357.924817]  r9:edc7a000 r8:c0207e44 r7:00000036 r6:00000001 r5:00000000 r4:00000008
    [  357.933837] ---[ end trace f15c45b46cdb50b2 ]---
    [  357.939747] vin3a-0: vip_release
    [  357.939757] vin3a-0: vip_release_stream: stream instance 0x00000008ecd06000
    
    )

    then you can see:

    for gstreamer:

    first channel:

    [ 365.937177] vin3a-0: vip_load_vpdma_list_fifo: start_dma vb2 buf idx:0
    [ 365.938297] vin3a-0: vip_load_vpdma_list_fifo: start_dma vb2 buf idx:1

    second channel:

    [ 1967.758900] vin3a-0: vip_s_fmt_vid_cap queue busy
    [ 1967.781254] vin3a-0: vip_release

    for yavta:

    first channel:

    [ 213.208246] vin3a-0: vip_load_vpdma_list_fifo: start_dma vb2 buf idx:0
    [ 213.209369] vin3a-0: vip_load_vpdma_list_fifo: start_dma vb2 buf idx:1

    second channel:

    [ 357.047484] vin3a-0: vip_load_vpdma_list_fifo: start_dma vb2 buf idx:0
    [ 357.607609] vin3a-0: Timed out loading VPDMA list fifo

    In the example with yavta, In the example with yavta, it is especially clear that the same vpdma channels open for the first and second video channel. 

    Is vpdma work normal?

    Why for each channel immediately open two dma?

  • Hi Manisha, i am still waiting for your reply

  • It is a pity that I did not receive your answer.
    But your previous answer gave me an idea.
    And I managed to implement a multi-channel driver, but only in mode EMBEDDED_SYNC_SINGLE_YUV422 (different channels of vip's).
    I will give my sources for helping other developers:

    https://e2e.ti.com/cfs-file/__key/communityserver-discussions-components-files/791/3666.src.7z ( The important point is the correct spelling of cam-tw2964.dtso, for the correct parsing channel numbers )

    I consider the problem solved.

    I have one question left: Is the vip.c driver able to work in pixel interleaved method mode aka EMBEDDED_SYNC_2X_MULTIPLEXED_YUV422 or EMBEDDED_SYNC_4X_MULTIPLEXED_YUV422?