// SPDX-License-Identifier: GPL-2.0-or-later /* cx25840 - Conexant CX25840 audio/video decoder driver * * Copyright (C) 2004 Ulf Eklund * * Based on the saa7115 driver and on the first version of Chris Kennedy's * cx25840 driver. * * Changes by Tyler Trafford <tatrafford@comcast.net> * - cleanup/rewrite for V4L2 API (2005) * * VBI support by Hans Verkuil <hverkuil@xs4all.nl>. * * NTSC sliced VBI support by Christopher Neufeld <television@cneufeld.ca> * with additional fixes by Hans Verkuil <hverkuil@xs4all.nl>. * * CX23885 support by Steven Toth <stoth@linuxtv.org>. * * CX2388[578] IRQ handling, IO Pin mux configuration and other small fixes are * Copyright (C) 2010 Andy Walls <awalls@md.metrocast.net> * * CX23888 DIF support for the HVR1850 * Copyright (C) 2011 Steven Toth <stoth@kernellabs.com> * * CX2584x pin to pad mapping and output format configuration support are * Copyright (C) 2011 Maciej S. Szmigiero <mail@maciej.szmigiero.name>
*/
if (is_cx2388x(state)) return cx23885_s_io_pin_config(sd, n, pincfg); elseif (is_cx2584x(state)) return cx25840_s_io_pin_config(sd, n, pincfg); return 0;
}
/* datasheet startup in numbered steps, refer to page 3-77 */ /* 2. */
cx25840_and_or(client, 0x803, ~0x10, 0x00); /* * The default of this register should be 4, but I get 0 instead. * Set this register to 4 manually.
*/
cx25840_write(client, 0x000, 0x04); /* 3. */
init_dll1(client);
init_dll2(client);
cx25840_write(client, 0x136, 0x0a); /* 4. */
cx25840_write(client, 0x13c, 0x01);
cx25840_write(client, 0x13c, 0x00); /* 5. */ /* * Do the firmware load in a work handler to prevent. * Otherwise the kernel is blocked waiting for the * bit-banging i2c interface to finish uploading the * firmware.
*/
INIT_WORK(&state->fw_work, cx25840_work_handler);
init_waitqueue_head(&state->fw_wait);
q = create_singlethread_workqueue("cx25840_fw"); if (q) {
prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE);
queue_work(q, &state->fw_work);
schedule();
finish_wait(&state->fw_wait, &wait);
destroy_workqueue(q);
}
/* trial and error says these are needed to get audio */
cx25840_write(client, 0x914, 0xa0);
cx25840_write(client, 0x918, 0xa0);
cx25840_write(client, 0x919, 0x01);
/* cx23885 sets hostdata to clk_freq pointer */ if (v4l2_get_subdev_hostdata(&state->sd))
clk_freq = *((u32 *)v4l2_get_subdev_hostdata(&state->sd));
/* * Come out of digital power down * The CX23888, at least, needs this, otherwise registers aside from * 0x0-0x2 can't be read or written.
*/
cx25840_write(client, 0x000, 0);
/* Drive GPIO2 direction and values for HVR1700 * where an onboard mux selects the output of demodulator * vs the 417. Failure to set this results in no DTV. * It's safe to set this across all Hauppauge boards * currently, regardless of the board type.
*/
cx25840_write(client, 0x160, 0x1d);
cx25840_write(client, 0x164, 0x00);
/* * Do the firmware load in a work handler to prevent. * Otherwise the kernel is blocked waiting for the * bit-banging i2c interface to finish uploading the * firmware.
*/
INIT_WORK(&state->fw_work, cx25840_work_handler);
init_waitqueue_head(&state->fw_wait);
q = create_singlethread_workqueue("cx25840_fw"); if (q) {
prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE);
queue_work(q, &state->fw_work);
schedule();
finish_wait(&state->fw_wait, &wait);
destroy_workqueue(q);
}
/* * Call the cx23888 specific std setup func, we no longer rely on * the generic cx24840 func.
*/ if (is_cx23888(state))
cx23888_std_setup(client); else
cx25840_std_setup(client);
/* Disable and clear video interrupts - we don't use them */
cx25840_write4(client, CX25840_VID_INT_STAT_REG, 0xffffffff);
/* Disable and clear audio interrupts - we don't use them */
cx25840_write(client, CX25840_AUD_INT_CTRL_REG, 0xff);
cx25840_write(client, CX25840_AUD_INT_STAT_REG, 0xff);
/* CC raw enable */
/* * - VIP 1.1 control codes - 10bit, blue field enable. * - enable raw data during vertical blanking. * - enable ancillary Data insertion for 656 or VIP.
*/
cx25840_write4(client, 0x404, 0x0010253e);
/* CC on - VBI_LINE_CTRL3, FLD_VBI_MD_LINE12 */
cx25840_write(client, state->vbi_regs_offset + 0x42f, 0x66);
/* HVR-1250 / HVR1850 DIF related */ /* Power everything up */
cx25840_write4(client, 0x130, 0x0);
/* Enable format auto detect */
cx25840_write(client, 0x400, 0); /* Fast subchroma lock */ /* White crush, Chroma AGC & Chroma Killer enabled */
cx25840_write(client, 0x401, 0xe8);
/* * Do the firmware load in a work handler to prevent. * Otherwise the kernel is blocked waiting for the * bit-banging i2c interface to finish uploading the * firmware.
*/
INIT_WORK(&state->fw_work, cx25840_work_handler);
init_waitqueue_head(&state->fw_wait);
q = create_singlethread_workqueue("cx25840_fw"); if (q) {
prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE);
queue_work(q, &state->fw_work);
schedule();
finish_wait(&state->fw_wait, &wait);
destroy_workqueue(q);
}
/* Follow step 8c and 8d of section 3.16 in the cx25840 datasheet */ if (std & V4L2_STD_SECAM) {
cx25840_write(client, 0x402, 0);
} else {
cx25840_write(client, 0x402, 0x04);
cx25840_write(client, 0x49f,
(std & V4L2_STD_NTSC) ? 0x14 : 0x11);
}
cx25840_and_or(client, 0x401, ~0x60, 0);
cx25840_and_or(client, 0x401, ~0x60, 0x60);
/* Don't write into audio registers on cx2583x chips */ if (is_cx2583x(state)) return;
cx25840_and_or(client, 0x810, ~0x01, 1);
if (state->radio) {
cx25840_write(client, 0x808, 0xf9);
cx25840_write(client, 0x80b, 0x00);
} elseif (std & V4L2_STD_525_60) { /* * Certain Hauppauge PVR150 models have a hardware bug * that causes audio to drop out. For these models the * audio standard must be set explicitly. * To be precise: it affects cards with tuner models * 85, 99 and 112 (model numbers from tveeprom).
*/ int hw_fix = state->pvr150_workaround;
if (std == V4L2_STD_NTSC_M_JP) { /* Japan uses EIAJ audio standard */
cx25840_write(client, 0x808, hw_fix ? 0x2f : 0xf7);
} elseif (std == V4L2_STD_NTSC_M_KR) { /* South Korea uses A2 audio standard */
cx25840_write(client, 0x808, hw_fix ? 0x3f : 0xf8);
} else { /* Others use the BTSC audio standard */
cx25840_write(client, 0x808, hw_fix ? 0x1f : 0xf6);
}
cx25840_write(client, 0x80b, 0x00);
} elseif (std & V4L2_STD_PAL) { /* Autodetect audio standard and audio system */
cx25840_write(client, 0x808, 0xff); /* * Since system PAL-L is pretty much non-existent and * not used by any public broadcast network, force * 6.5 MHz carrier to be interpreted as System DK, * this avoids DK audio detection instability
*/
cx25840_write(client, 0x80b, 0x00);
} elseif (std & V4L2_STD_SECAM) { /* Autodetect audio standard and audio system */
cx25840_write(client, 0x808, 0xff); /* * If only one of SECAM-DK / SECAM-L is required, then force * 6.5MHz carrier, else autodetect it
*/ if ((std & V4L2_STD_SECAM_DK) &&
!(std & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC))) { /* 6.5 MHz carrier to be interpreted as System DK */
cx25840_write(client, 0x80b, 0x00);
} elseif (!(std & V4L2_STD_SECAM_DK) &&
(std & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC))) { /* 6.5 MHz carrier to be interpreted as System L */
cx25840_write(client, 0x80b, 0x08);
} else { /* 6.5 MHz carrier to be autodetected */
cx25840_write(client, 0x80b, 0x10);
}
}
/* The caller has previously prepared the correct routing * configuration in reg (for the cx23885) so we have no * need to attempt to flip bits for earlier av decoders.
*/ if (!is_cx2388x(state) && !is_cx231xx(state)) { switch (aud_input) { case CX25840_AUDIO_SERIAL: /* do nothing, use serial audio input */ break; case CX25840_AUDIO4:
reg &= ~0x30; break; case CX25840_AUDIO5:
reg &= ~0x30;
reg |= 0x10; break; case CX25840_AUDIO6:
reg &= ~0x30;
reg |= 0x20; break; case CX25840_AUDIO7:
reg &= ~0xc0; break; case CX25840_AUDIO8:
reg &= ~0xc0;
reg |= 0x40; break; default:
v4l_err(client, "0x%04x is not a valid audio input!\n",
aud_input); return -EINVAL;
}
}
cx25840_write(client, 0x103, reg);
/* Set INPUT_MODE to Composite, S-Video or Component */ if (is_component)
cx25840_and_or(client, 0x401, ~0x6, 0x6); else
cx25840_and_or(client, 0x401, ~0x6, is_composite ? 0 : 0x02);
if (is_cx2388x(state)) { /* Enable or disable the DIF for tuner use */ if (is_dif) {
cx25840_and_or(client, 0x102, ~0x80, 0x80);
/* Set of defaults for NTSC and PAL */
cx25840_write4(client, 0x31c, 0xc2262600);
cx25840_write4(client, 0x320, 0xc2262600);
/* 18271 IF - Nobody else yet uses a different * tuner with the DIF, so these are reasonable * assumptions (HVR1250 and HVR1850 specific).
*/
cx25840_write4(client, 0x318, 0xda262600);
cx25840_write4(client, 0x33c, 0x2a24c800);
cx25840_write4(client, 0x104, 0x0704dd00);
} else {
cx25840_write4(client, 0x300, 0x015c28f5);
val = cx25840_read4(client, MODE_CTRL);
val &= 0xFFFFF9FF;
/* YC */
val |= 0x00000200;
val &= ~0x2000;
cx25840_write4(client, MODE_CTRL, val);
val = cx25840_read4(client, AFE_CTRL);
/* Chroma in select */
val |= 0x00001000;
val &= 0xfffffe7f; /* Clear VGA_SEL_CH2 and VGA_SEL_CH3 (bits 7 and 8). * This sets them to use video rather than audio. * Only one of the two will be in use.
*/
cx25840_write4(client, AFE_CTRL, val);
} else {
cx25840_and_or(client, 0x102, ~0x2, 0);
}
}
if (!is_dif) { /* * Stop microcontroller if we don't need it * to avoid audio popping on svideo/composite use.
*/
cx25840_and_or(client, 0x803, ~0x10, 0x00);
}
}
v4l_dbg(1, cx25840_debug, client, "changing video std to fmt %i\n", fmt);
/* * Follow step 9 of section 3.16 in the cx25840 datasheet. * Without this PAL may display a vertical ghosting effect. * This happens for example with the Yuan MPC622.
*/ if (fmt >= 4 && fmt < 8) { /* Set format to NTSC-M */
cx25840_and_or(client, 0x400, ~0xf, 1); /* Turn off LCOMB */
cx25840_and_or(client, 0x47b, ~6, 0);
}
cx25840_and_or(client, 0x400, ~0xf, fmt);
cx25840_and_or(client, 0x403, ~0x3, pal_m); if (is_cx23888(state))
cx23888_std_setup(client); else
cx25840_std_setup(client); if (!is_cx2583x(state))
input_change(client); return 0;
}
if (!state->generic_mode) {
v_add = is_50hz ? 4 : 7;
/* * cx23888 in 525-line mode is programmed for 486 active lines * while other chips use 487 active lines. * * See reg 0x428 bits [21:12] in cx23888_std_setup() vs * vactive in cx25840_std_setup().
*/ if (is_cx23888(state) && !is_50hz)
v_add--;
} else {
v_add = 0;
}
if (h_src == 0 ||
v_src <= v_add) {
v4l_err(client, "chip reported picture size (%u x %u) is far too small\n",
(unsignedint)h_src, (unsignedint)v_src); /* * that's the best we can do since the output picture * size is completely unknown in this case
*/ return -EINVAL;
}
v4l_dbg(1, cx25840_debug, client, "decoder set size %u x %u with scale %x x %x\n",
(unsignedint)fmt->width, (unsignedint)fmt->height,
(unsignedint)hsc, (unsignedint)vsc);
switch (mod_det_stat0) { case 0x00:
p = "mono"; break; case 0x01:
p = "stereo"; break; case 0x02:
p = "dual"; break; case 0x04:
p = "tri"; break; case 0x10:
p = "mono with SAP"; break; case 0x11:
p = "stereo with SAP"; break; case 0x12:
p = "dual with SAP"; break; case 0x14:
p = "tri with SAP"; break; case 0xfe:
p = "forced mode"; break; default:
p = "not defined";
}
v4l_info(client, "Detected audio mode: %s\n", p);
switch (mod_det_stat1) { case 0x00:
p = "not defined"; break; case 0x01:
p = "EIAJ"; break; case 0x02:
p = "A2-M"; break; case 0x03:
p = "A2-BG"; break; case 0x04:
p = "A2-DK1"; break; case 0x05:
p = "A2-DK2"; break; case 0x06:
p = "A2-DK3"; break; case 0x07:
p = "A1 (6.0 MHz FM Mono)"; break; case 0x08:
p = "AM-L"; break; case 0x09:
p = "NICAM-BG"; break; case 0x0a:
p = "NICAM-DK"; break; case 0x0b:
p = "NICAM-I"; break; case 0x0c:
p = "NICAM-L"; break; case 0x0d:
p = "BTSC/EIAJ/A2-M Mono (4.5 MHz FMMono)"; break; case 0x0e:
p = "IF FM Radio"; break; case 0x0f:
p = "BTSC"; break; case 0x10:
p = "high-deviation FM"; break; case 0x11:
p = "very high-deviation FM"; break; case 0xfd:
p = "unknown audio standard"; break; case 0xfe:
p = "forced audio standard"; break; case 0xff:
p = "no detected audio standard"; break; default:
p = "not defined";
}
v4l_info(client, "Detected audio standard: %s\n", p);
v4l_info(client, "Audio microcontroller: %s\n",
(download_ctl & 0x10) ?
((mute_ctl & 0x2) ? "detecting" : "running") : "stopped");
switch (audio_config >> 4) { case 0x00:
p = "undefined"; break; case 0x01:
p = "BTSC"; break; case 0x02:
p = "EIAJ"; break; case 0x03:
p = "A2-M"; break; case 0x04:
p = "A2-BG"; break; case 0x05:
p = "A2-DK1"; break; case 0x06:
p = "A2-DK2"; break; case 0x07:
p = "A2-DK3"; break; case 0x08:
p = "A1 (6.0 MHz FM Mono)"; break; case 0x09:
p = "AM-L"; break; case 0x0a:
p = "NICAM-BG"; break; case 0x0b:
p = "NICAM-DK"; break; case 0x0c:
p = "NICAM-I"; break; case 0x0d:
p = "NICAM-L"; break; case 0x0e:
p = "FM radio"; break; case 0x0f:
p = "automatic detection"; break; default:
p = "undefined";
}
v4l_info(client, "Configured audio standard: %s\n", p);
if ((audio_config >> 4) < 0xF) { switch (audio_config & 0xF) { case 0x00:
p = "MONO1 (LANGUAGE A/Mono L+R channel for BTSC, EIAJ, A2)"; break; case 0x01:
p = "MONO2 (LANGUAGE B)"; break; case 0x02:
p = "MONO3 (STEREO forced MONO)"; break; case 0x03:
p = "MONO4 (NICAM ANALOG-Language C/Analog Fallback)"; break; case 0x04:
p = "STEREO"; break; case 0x05:
p = "DUAL1 (AB)"; break; case 0x06:
p = "DUAL2 (AC) (FM)"; break; case 0x07:
p = "DUAL3 (BC) (FM)"; break; case 0x08:
p = "DUAL4 (AC) (AM)"; break; case 0x09:
p = "DUAL5 (BC) (AM)"; break; case 0x0a:
p = "SAP"; break; default:
p = "undefined";
}
v4l_info(client, "Configured audio mode: %s\n", p);
} else { switch (audio_config & 0xF) { case 0x00:
p = "BG"; break; case 0x01:
p = "DK1"; break; case 0x02:
p = "DK2"; break; case 0x03:
p = "DK3"; break; case 0x04:
p = "I"; break; case 0x05:
p = "L"; break; case 0x06:
p = "BTSC"; break; case 0x07:
p = "EIAJ"; break; case 0x08:
p = "A2-M"; break; case 0x09:
p = "FM Radio"; break; case 0x0f:
p = "automatic standard and mode detection"; break; default:
p = "undefined";
}
v4l_info(client, "Configured audio system: %s\n", p);
}
switch (pref_mode & 0xf) { case 0:
p = "mono/language A"; break; case 1:
p = "language B"; break; case 2:
p = "language C"; break; case 3:
p = "analog fallback"; break; case 4:
p = "stereo"; break; case 5:
p = "language AC"; break; case 6:
p = "language BC"; break; case 7:
p = "language AB"; break; default:
p = "undefined";
}
v4l_info(client, "Preferred audio mode: %s\n", p);
if ((audio_config & 0xf) == 0xf) { switch ((afc0 >> 3) & 0x3) { case 0:
p = "system DK"; break; case 1:
p = "system L"; break; case 2:
p = "autodetect"; break; default:
p = "undefined";
}
v4l_info(client, "Selected 65 MHz format: %s\n", p);
switch (afc0 & 0x7) { case 0:
p = "chroma"; break; case 1:
p = "BTSC"; break; case 2:
p = "EIAJ"; break; case 3:
p = "A2-M"; break; case 4:
p = "autodetect"; break; default:
p = "undefined";
}
v4l_info(client, "Selected 45 MHz format: %s\n", p);
}
}
#define CX25840_VCONFIG_OPTION(state, cfg_in, opt_msk) \ do { \ if ((cfg_in) & (opt_msk)) { \
(state)->vid_config &= ~(opt_msk); \
(state)->vid_config |= (cfg_in) & (opt_msk); \
} \
} while (0)
/* * Initializes the device in the generic mode. * For cx2584x chips also adds additional video output settings provided * in @val parameter (CX25840_VCONFIG_*). * * The generic mode disables some of the ivtv-related hacks in this driver. * For cx2584x chips it also enables setting video output configuration while * setting it according to datasheet defaults by default.
*/ staticint cx25840_init(struct v4l2_subdev *sd, u32 val)
{ struct cx25840_state *state = to_state(sd);
/* * This load_fw operation must be called to load the driver's firmware. * This will load the firmware on the first invocation (further ones are NOP). * Without this the audio standard detection will fail and you will * only get mono. * Alternatively, you can call the reset operation instead of this one. * * Since loading the firmware is often problematic when the driver is * compiled into the kernel I recommend postponing calling this function * until the first open of the video device. Another reason for * postponing it is that loading this firmware takes a long time (seconds) * due to the slow i2c bus speed. So it will speed up the boot process if * you can avoid loading the fw as long as the video device isn't used.
*/ staticint cx25840_load_fw(struct v4l2_subdev *sd)
{ struct cx25840_state *state = to_state(sd);
if (!state->is_initialized) { /* initialize and load firmware */
cx25840_reset(sd, 0);
} return 0;
}
/* * It's not clear what should be done for these devices. * The original code used the same addresses as for the cx25840, but * those addresses do something else entirely on the cx2388x and * cx231xx. Since it never did anything in the first place, just do * nothing.
*/ if (is_cx2388x(state) || is_cx231xx(state)) return 0;
if (enable) {
v = cx25840_read(client, 0x115) | 0x0c;
cx25840_write(client, 0x115, v);
v = cx25840_read(client, 0x116) | 0x04;
cx25840_write(client, 0x116, v);
} else {
v = cx25840_read(client, 0x115) & ~(0x0c);
cx25840_write(client, 0x115, v);
v = cx25840_read(client, 0x116) & ~(0x04);
cx25840_write(client, 0x116, v);
} return 0;
}
/* Query the current detected video format */ staticint cx25840_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
{ struct i2c_client *client = v4l2_get_subdevdata(sd);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.