diff options
Diffstat (limited to 'drivers')
45 files changed, 10182 insertions, 0 deletions
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 7dda5d54716..fe743aa7f64 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -748,6 +748,8 @@ source "drivers/media/video/au0828/Kconfig" source "drivers/media/video/ivtv/Kconfig" +source "drivers/media/video/cx18/Kconfig" + config VIDEO_M32R_AR tristate "AR devices" depends on M32R && VIDEO_V4L1 diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 560dc32d4cb..a352c6e31f0 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -124,6 +124,7 @@ obj-$(CONFIG_USB_VICAM) += usbvideo/ obj-$(CONFIG_USB_QUICKCAM_MESSENGER) += usbvideo/ obj-$(CONFIG_VIDEO_IVTV) += ivtv/ +obj-$(CONFIG_VIDEO_CX18) += cx18/ obj-$(CONFIG_VIDEO_VIVI) += vivi.o obj-$(CONFIG_VIDEO_CX23885) += cx23885/ diff --git a/drivers/media/video/cx18/Kconfig b/drivers/media/video/cx18/Kconfig new file mode 100644 index 00000000000..be654a27bd3 --- /dev/null +++ b/drivers/media/video/cx18/Kconfig @@ -0,0 +1,20 @@ +config VIDEO_CX18 + tristate "Conexant cx23418 MPEG encoder support" + depends on VIDEO_V4L2 && DVB_CORE && PCI && I2C && EXPERIMENTAL + select I2C_ALGOBIT + select FW_LOADER + select VIDEO_IR + select VIDEO_TUNER + select VIDEO_TVEEPROM + select VIDEO_CX2341X + select VIDEO_CS5345 + select DVB_S5H1409 + ---help--- + This is a video4linux driver for Conexant cx23418 based + PCI combo video recorder devices. + + This is used in devices such as the Hauppauge HVR-1600 + cards. + + To compile this driver as a module, choose M here: the + module will be called cx18. diff --git a/drivers/media/video/cx18/Makefile b/drivers/media/video/cx18/Makefile new file mode 100644 index 00000000000..b23d2e26120 --- /dev/null +++ b/drivers/media/video/cx18/Makefile @@ -0,0 +1,11 @@ +cx18-objs := cx18-driver.o cx18-cards.o cx18-i2c.o cx18-firmware.o cx18-gpio.o \ + cx18-queue.o cx18-streams.o cx18-fileops.o cx18-ioctl.o cx18-controls.o \ + cx18-mailbox.o cx18-vbi.o cx18-audio.o cx18-video.o cx18-irq.o \ + cx18-av-core.o cx18-av-audio.o cx18-av-firmware.o cx18-av-vbi.o cx18-scb.o \ + cx18-dvb.o + +obj-$(CONFIG_VIDEO_CX18) += cx18.o + +EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core +EXTRA_CFLAGS += -Idrivers/media/dvb/frontends +EXTRA_CFLAGS += -Idrivers/media/common/tuners diff --git a/drivers/media/video/cx18/cx18-audio.c b/drivers/media/video/cx18/cx18-audio.c new file mode 100644 index 00000000000..1adc404d955 --- /dev/null +++ b/drivers/media/video/cx18/cx18-audio.c @@ -0,0 +1,73 @@ +/* + * cx18 audio-related functions + * + * Derived from ivtv-audio.c + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + */ + +#include "cx18-driver.h" +#include "cx18-i2c.h" +#include "cx18-cards.h" +#include "cx18-audio.h" + +/* Selects the audio input and output according to the current + settings. */ +int cx18_audio_set_io(struct cx18 *cx) +{ + struct v4l2_routing route; + u32 audio_input; + int mux_input; + + /* Determine which input to use */ + if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) { + audio_input = cx->card->radio_input.audio_input; + mux_input = cx->card->radio_input.muxer_input; + } else { + audio_input = + cx->card->audio_inputs[cx->audio_input].audio_input; + mux_input = + cx->card->audio_inputs[cx->audio_input].muxer_input; + } + + /* handle muxer chips */ + route.input = mux_input; + route.output = 0; + cx18_i2c_hw(cx, cx->card->hw_muxer, VIDIOC_INT_S_AUDIO_ROUTING, &route); + + route.input = audio_input; + return cx18_i2c_hw(cx, cx->card->hw_audio_ctrl, + VIDIOC_INT_S_AUDIO_ROUTING, &route); +} + +void cx18_audio_set_route(struct cx18 *cx, struct v4l2_routing *route) +{ + cx18_i2c_hw(cx, cx->card->hw_audio_ctrl, + VIDIOC_INT_S_AUDIO_ROUTING, route); +} + +void cx18_audio_set_audio_clock_freq(struct cx18 *cx, u8 freq) +{ + static u32 freqs[3] = { 44100, 48000, 32000 }; + + /* The audio clock of the digitizer must match the codec sample + rate otherwise you get some very strange effects. */ + if (freq > 2) + return; + cx18_call_i2c_clients(cx, VIDIOC_INT_AUDIO_CLOCK_FREQ, &freqs[freq]); +} diff --git a/drivers/media/video/cx18/cx18-audio.h b/drivers/media/video/cx18/cx18-audio.h new file mode 100644 index 00000000000..cb569a69379 --- /dev/null +++ b/drivers/media/video/cx18/cx18-audio.h @@ -0,0 +1,26 @@ +/* + * cx18 audio-related functions + * + * Derived from ivtv-audio.c + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + */ + +int cx18_audio_set_io(struct cx18 *cx); +void cx18_audio_set_route(struct cx18 *cx, struct v4l2_routing *route); +void cx18_audio_set_audio_clock_freq(struct cx18 *cx, u8 freq); diff --git a/drivers/media/video/cx18/cx18-av-audio.c b/drivers/media/video/cx18/cx18-av-audio.c new file mode 100644 index 00000000000..2dc3a5dd170 --- /dev/null +++ b/drivers/media/video/cx18/cx18-av-audio.c @@ -0,0 +1,361 @@ +/* + * cx18 ADEC audio functions + * + * Derived from cx25840-audio.c + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "cx18-driver.h" + +static int set_audclk_freq(struct cx18 *cx, u32 freq) +{ + struct cx18_av_state *state = &cx->av_state; + + if (freq != 32000 && freq != 44100 && freq != 48000) + return -EINVAL; + + /* common for all inputs and rates */ + /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x10 */ + cx18_av_write(cx, 0x127, 0x50); + + if (state->aud_input != CX18_AV_AUDIO_SERIAL) { + switch (freq) { + case 32000: + /* VID_PLL and AUX_PLL */ + cx18_av_write4(cx, 0x108, 0x1006040f); + + /* AUX_PLL_FRAC */ + cx18_av_write4(cx, 0x110, 0x01bb39ee); + + /* src3/4/6_ctl = 0x0801f77f */ + cx18_av_write4(cx, 0x900, 0x0801f77f); + cx18_av_write4(cx, 0x904, 0x0801f77f); + cx18_av_write4(cx, 0x90c, 0x0801f77f); + break; + + case 44100: + /* VID_PLL and AUX_PLL */ + cx18_av_write4(cx, 0x108, 0x1009040f); + + /* AUX_PLL_FRAC */ + cx18_av_write4(cx, 0x110, 0x00ec6bd6); + + /* src3/4/6_ctl = 0x08016d59 */ + cx18_av_write4(cx, 0x900, 0x08016d59); + cx18_av_write4(cx, 0x904, 0x08016d59); + cx18_av_write4(cx, 0x90c, 0x08016d59); + break; + + case 48000: + /* VID_PLL and AUX_PLL */ + cx18_av_write4(cx, 0x108, 0x100a040f); + + /* AUX_PLL_FRAC */ + cx18_av_write4(cx, 0x110, 0x0098d6e5); + + /* src3/4/6_ctl = 0x08014faa */ + cx18_av_write4(cx, 0x900, 0x08014faa); + cx18_av_write4(cx, 0x904, 0x08014faa); + cx18_av_write4(cx, 0x90c, 0x08014faa); + break; + } + } else { + switch (freq) { + case 32000: + /* VID_PLL and AUX_PLL */ + cx18_av_write4(cx, 0x108, 0x1e08040f); + + /* AUX_PLL_FRAC */ + cx18_av_write4(cx, 0x110, 0x012a0869); + + /* src1_ctl = 0x08010000 */ + cx18_av_write4(cx, 0x8f8, 0x08010000); + + /* src3/4/6_ctl = 0x08020000 */ + cx18_av_write4(cx, 0x900, 0x08020000); + cx18_av_write4(cx, 0x904, 0x08020000); + cx18_av_write4(cx, 0x90c, 0x08020000); + + /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x14 */ + cx18_av_write(cx, 0x127, 0x54); + break; + + case 44100: + /* VID_PLL and AUX_PLL */ + cx18_av_write4(cx, 0x108, 0x1809040f); + + /* AUX_PLL_FRAC */ + cx18_av_write4(cx, 0x110, 0x00ec6bd6); + + /* src1_ctl = 0x08010000 */ + cx18_av_write4(cx, 0x8f8, 0x080160cd); + + /* src3/4/6_ctl = 0x08020000 */ + cx18_av_write4(cx, 0x900, 0x08017385); + cx18_av_write4(cx, 0x904, 0x08017385); + cx18_av_write4(cx, 0x90c, 0x08017385); + break; + + case 48000: + /* VID_PLL and AUX_PLL */ + cx18_av_write4(cx, 0x108, 0x180a040f); + + /* AUX_PLL_FRAC */ + cx18_av_write4(cx, 0x110, 0x0098d6e5); + + /* src1_ctl = 0x08010000 */ + cx18_av_write4(cx, 0x8f8, 0x08018000); + + /* src3/4/6_ctl = 0x08020000 */ + cx18_av_write4(cx, 0x900, 0x08015555); + cx18_av_write4(cx, 0x904, 0x08015555); + cx18_av_write4(cx, 0x90c, 0x08015555); + break; + } + } + + state->audclk_freq = freq; + + return 0; +} + +void cx18_av_audio_set_path(struct cx18 *cx) +{ + struct cx18_av_state *state = &cx->av_state; + + /* stop microcontroller */ + cx18_av_and_or(cx, 0x803, ~0x10, 0); + + /* assert soft reset */ + cx18_av_and_or(cx, 0x810, ~0x1, 0x01); + + /* Mute everything to prevent the PFFT! */ + cx18_av_write(cx, 0x8d3, 0x1f); + + if (state->aud_input == CX18_AV_AUDIO_SERIAL) { + /* Set Path1 to Serial Audio Input */ + cx18_av_write4(cx, 0x8d0, 0x01011012); + + /* The microcontroller should not be started for the + * non-tuner inputs: autodetection is specific for + * TV audio. */ + } else { + /* Set Path1 to Analog Demod Main Channel */ + cx18_av_write4(cx, 0x8d0, 0x1f063870); + } + + set_audclk_freq(cx, state->audclk_freq); + + /* deassert soft reset */ + cx18_av_and_or(cx, 0x810, ~0x1, 0x00); + + if (state->aud_input != CX18_AV_AUDIO_SERIAL) { + /* When the microcontroller detects the + * audio format, it will unmute the lines */ + cx18_av_and_or(cx, 0x803, ~0x10, 0x10); + } +} + +static int get_volume(struct cx18 *cx) +{ + /* Volume runs +18dB to -96dB in 1/2dB steps + * change to fit the msp3400 -114dB to +12dB range */ + + /* check PATH1_VOLUME */ + int vol = 228 - cx18_av_read(cx, 0x8d4); + vol = (vol / 2) + 23; + return vol << 9; +} + +static void set_volume(struct cx18 *cx, int volume) +{ + /* First convert the volume to msp3400 values (0-127) */ + int vol = volume >> 9; + /* now scale it up to cx18_av values + * -114dB to -96dB maps to 0 + * this should be 19, but in my testing that was 4dB too loud */ + if (vol <= 23) + vol = 0; + else + vol -= 23; + + /* PATH1_VOLUME */ + cx18_av_write(cx, 0x8d4, 228 - (vol * 2)); +} + +static int get_bass(struct cx18 *cx) +{ + /* bass is 49 steps +12dB to -12dB */ + + /* check PATH1_EQ_BASS_VOL */ + int bass = cx18_av_read(cx, 0x8d9) & 0x3f; + bass = (((48 - bass) * 0xffff) + 47) / 48; + return bass; +} + +static void set_bass(struct cx18 *cx, int bass) +{ + /* PATH1_EQ_BASS_VOL */ + cx18_av_and_or(cx, 0x8d9, ~0x3f, 48 - (bass * 48 / 0xffff)); +} + +static int get_treble(struct cx18 *cx) +{ + /* treble is 49 steps +12dB to -12dB */ + + /* check PATH1_EQ_TREBLE_VOL */ + int treble = cx18_av_read(cx, 0x8db) & 0x3f; + treble = (((48 - treble) * 0xffff) + 47) / 48; + return treble; +} + +static void set_treble(struct cx18 *cx, int treble) +{ + /* PATH1_EQ_TREBLE_VOL */ + cx18_av_and_or(cx, 0x8db, ~0x3f, 48 - (treble * 48 / 0xffff)); +} + +static int get_balance(struct cx18 *cx) +{ + /* balance is 7 bit, 0 to -96dB */ + + /* check PATH1_BAL_LEVEL */ + int balance = cx18_av_read(cx, 0x8d5) & 0x7f; + /* check PATH1_BAL_LEFT */ + if ((cx18_av_read(cx, 0x8d5) & 0x80) == 0) + balance = 0x80 - balance; + else + balance = 0x80 + balance; + return balance << 8; +} + +static void set_balance(struct cx18 *cx, int balance) +{ + int bal = balance >> 8; + if (bal > 0x80) { + /* PATH1_BAL_LEFT */ + cx18_av_and_or(cx, 0x8d5, 0x7f, 0x80); + /* PATH1_BAL_LEVEL */ + cx18_av_and_or(cx, 0x8d5, ~0x7f, bal & 0x7f); + } else { + /* PATH1_BAL_LEFT */ + cx18_av_and_or(cx, 0x8d5, 0x7f, 0x00); + /* PATH1_BAL_LEVEL */ + cx18_av_and_or(cx, 0x8d5, ~0x7f, 0x80 - bal); + } +} + +static int get_mute(struct cx18 *cx) +{ + /* check SRC1_MUTE_EN */ + return cx18_av_read(cx, 0x8d3) & 0x2 ? 1 : 0; +} + +static void set_mute(struct cx18 *cx, int mute) +{ + struct cx18_av_state *state = &cx->av_state; + + if (state->aud_input != CX18_AV_AUDIO_SERIAL) { + /* Must turn off microcontroller in order to mute sound. + * Not sure if this is the best method, but it does work. + * If the microcontroller is running, then it will undo any + * changes to the mute register. */ + if (mute) { + /* disable microcontroller */ + cx18_av_and_or(cx, 0x803, ~0x10, 0x00); + cx18_av_write(cx, 0x8d3, 0x1f); + } else { + /* enable microcontroller */ + cx18_av_and_or(cx, 0x803, ~0x10, 0x10); + } + } else { + /* SRC1_MUTE_EN */ + cx18_av_and_or(cx, 0x8d3, ~0x2, mute ? 0x02 : 0x00); + } +} + +int cx18_av_audio(struct cx18 *cx, unsigned int cmd, void *arg) +{ + struct cx18_av_state *state = &cx->av_state; + struct v4l2_control *ctrl = arg; + int retval; + + switch (cmd) { + case VIDIOC_INT_AUDIO_CLOCK_FREQ: + if (state->aud_input != CX18_AV_AUDIO_SERIAL) { + cx18_av_and_or(cx, 0x803, ~0x10, 0); + cx18_av_write(cx, 0x8d3, 0x1f); + } + cx18_av_and_or(cx, 0x810, ~0x1, 1); + retval = set_audclk_freq(cx, *(u32 *)arg); + cx18_av_and_or(cx, 0x810, ~0x1, 0); + if (state->aud_input != CX18_AV_AUDIO_SERIAL) + cx18_av_and_or(cx, 0x803, ~0x10, 0x10); + return retval; + + case VIDIOC_G_CTRL: + switch (ctrl->id) { + case V4L2_CID_AUDIO_VOLUME: + ctrl->value = get_volume(cx); + break; + case V4L2_CID_AUDIO_BASS: + ctrl->value = get_bass(cx); + break; + case V4L2_CID_AUDIO_TREBLE: + ctrl->value = get_treble(cx); + break; + case V4L2_CID_AUDIO_BALANCE: + ctrl->value = get_balance(cx); + break; + case V4L2_CID_AUDIO_MUTE: + ctrl->value = get_mute(cx); + break; + default: + return -EINVAL; + } + break; + + case VIDIOC_S_CTRL: + switch (ctrl->id) { + case V4L2_CID_AUDIO_VOLUME: + set_volume(cx, ctrl->value); + break; + case V4L2_CID_AUDIO_BASS: + set_bass(cx, ctrl->value); + break; + case V4L2_CID_AUDIO_TREBLE: + set_treble(cx, ctrl->value); + break; + case V4L2_CID_AUDIO_BALANCE: + set_balance(cx, ctrl->value); + break; + case V4L2_CID_AUDIO_MUTE: + set_mute(cx, ctrl->value); + break; + default: + return -EINVAL; + } + break; + + default: + return -EINVAL; + } + + return 0; +} diff --git a/drivers/media/video/cx18/cx18-av-core.c b/drivers/media/video/cx18/cx18-av-core.c new file mode 100644 index 00000000000..66864904c99 --- /dev/null +++ b/drivers/media/video/cx18/cx18-av-core.c @@ -0,0 +1,879 @@ +/* + * cx18 ADEC audio functions + * + * Derived from cx25840-core.c + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "cx18-driver.h" + +int cx18_av_write(struct cx18 *cx, u16 addr, u8 value) +{ + u32 x = readl(cx->reg_mem + 0xc40000 + (addr & ~3)); + u32 mask = 0xff; + int shift = (addr & 3) * 8; + + x = (x & ~(mask << shift)) | ((u32)value << shift); + writel(x, cx->reg_mem + 0xc40000 + (addr & ~3)); + return 0; +} + +int cx18_av_write4(struct cx18 *cx, u16 addr, u32 value) +{ + writel(value, cx->reg_mem + 0xc40000 + addr); + return 0; +} + +u8 cx18_av_read(struct cx18 *cx, u16 addr) +{ + u32 x = readl(cx->reg_mem + 0xc40000 + (addr & ~3)); + int shift = (addr & 3) * 8; + + return (x >> shift) & 0xff; +} + +u32 cx18_av_read4(struct cx18 *cx, u16 addr) +{ + return readl(cx->reg_mem + 0xc40000 + addr); +} + +int cx18_av_and_or(struct cx18 *cx, u16 addr, unsigned and_mask, + u8 or_value) +{ + return cx18_av_write(cx, addr, + (cx18_av_read(cx, addr) & and_mask) | + or_value); +} + +int cx18_av_and_or4(struct cx18 *cx, u16 addr, u32 and_mask, + u32 or_value) +{ + return cx18_av_write4(cx, addr, + (cx18_av_read4(cx, addr) & and_mask) | + or_value); +} + +/* ----------------------------------------------------------------------- */ + +static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input, + enum cx18_av_audio_input aud_input); +static void log_audio_status(struct cx18 *cx); +static void log_video_status(struct cx18 *cx); + +/* ----------------------------------------------------------------------- */ + +static void cx18_av_initialize(struct cx18 *cx) +{ + u32 v; + + cx18_av_loadfw(cx); + /* Stop 8051 code execution */ + cx18_av_write4(cx, CXADEC_DL_CTL, 0x03000000); + + /* initallize the PLL by toggling sleep bit */ + v = cx18_av_read4(cx, CXADEC_HOST_REG1); + /* enable sleep mode */ + cx18_av_write4(cx, CXADEC_HOST_REG1, v | 1); + /* disable sleep mode */ + cx18_av_write4(cx, CXADEC_HOST_REG1, v & 0xfffe); + + /* initialize DLLs */ + v = cx18_av_read4(cx, CXADEC_DLL1_DIAG_CTRL) & 0xE1FFFEFF; + /* disable FLD */ + cx18_av_write4(cx, CXADEC_DLL1_DIAG_CTRL, v); + /* enable FLD */ + cx18_av_write4(cx, CXADEC_DLL1_DIAG_CTRL, v | 0x10000100); + + v = cx18_av_read4(cx, CXADEC_DLL2_DIAG_CTRL) & 0xE1FFFEFF; + /* disable FLD */ + cx18_av_write4(cx, CXADEC_DLL2_DIAG_CTRL, v); + /* enable FLD */ + cx18_av_write4(cx, CXADEC_DLL2_DIAG_CTRL, v | 0x06000100); + + /* set analog bias currents. Set Vreg to 1.20V. */ + cx18_av_write4(cx, CXADEC_AFE_DIAG_CTRL1, 0x000A1802); + + v = cx18_av_read4(cx, CXADEC_AFE_DIAG_CTRL3) | 1; + /* enable TUNE_FIL_RST */ + cx18_av_write4(cx, CXADEC_AFE_DIAG_CTRL3, v); + /* disable TUNE_FIL_RST */ + cx18_av_write4(cx, CXADEC_AFE_DIAG_CTRL3, v & 0xFFFFFFFE); + + /* enable 656 output */ + cx18_av_and_or4(cx, CXADEC_PIN_CTRL1, ~0, 0x040C00); + + /* video output drive strength */ + cx18_av_and_or4(cx, CXADEC_PIN_CTRL2, ~0, 0x2); + + /* reset video */ + cx18_av_write4(cx, CXADEC_SOFT_RST_CTRL, 0x8000); + cx18_av_write4(cx, CXADEC_SOFT_RST_CTRL, 0); + + /* set video to auto-detect */ + /* Clear bits 11-12 to enable slow locking mode. Set autodetect mode */ + /* set the comb notch = 1 */ + cx18_av_and_or4(cx, CXADEC_MODE_CTRL, 0xFFF7E7F0, 0x02040800); + + /* Enable wtw_en in CRUSH_CTRL (Set bit 22) */ + /* Enable maj_sel in CRUSH_CTRL (Set bit 20) */ + cx18_av_and_or4(cx, CXADEC_CRUSH_CTRL, ~0, 0x00500000); + + /* Set VGA_TRACK_RANGE to 0x20 */ + cx18_av_and_or4(cx, CXADEC_DFE_CTRL2, 0xFFFF00FF, 0x00002000); + + /* Enable VBI capture */ + cx18_av_write4(cx, CXADEC_OUT_CTRL1, 0x4010253F); + /* cx18_av_write4(cx, CXADEC_OUT_CTRL1, 0x4010253E); */ + + /* Set the video input. + The setting in MODE_CTRL gets lost when we do the above setup */ + /* EncSetSignalStd(dwDevNum, pEnc->dwSigStd); */ + /* EncSetVideoInput(dwDevNum, pEnc->VidIndSelection); */ + + v = cx18_av_read4(cx, CXADEC_AFE_CTRL); + v &= 0xFFFBFFFF; /* turn OFF bit 18 for droop_comp_ch1 */ + v &= 0xFFFF7FFF; /* turn OFF bit 9 for clamp_sel_ch1 */ + v &= 0xFFFFFFFE; /* turn OFF bit 0 for 12db_ch1 */ + /* v |= 0x00000001;*/ /* turn ON bit 0 for 12db_ch1 */ + cx18_av_write4(cx, CXADEC_AFE_CTRL, v); + +/* if(dwEnable && dw3DCombAvailable) { */ +/* CxDevWrReg(CXADEC_SRC_COMB_CFG, 0x7728021F); */ +/* } else { */ +/* CxDevWrReg(CXADEC_SRC_COMB_CFG, 0x6628021F); */ +/* } */ + cx18_av_write4(cx, CXADEC_SRC_COMB_CFG, 0x6628021F); +} + +/* ----------------------------------------------------------------------- */ + +static void input_change(struct cx18 *cx) +{ + struct cx18_av_state *state = &cx->av_state; + v4l2_std_id std = state->std; + + /* Follow step 8c and 8d of section 3.16 in the cx18_av datasheet */ + if (std & V4L2_STD_SECAM) + cx18_av_write(cx, 0x402, 0); + else { + cx18_av_write(cx, 0x402, 0x04); + cx18_av_write(cx, 0x49f, (std & V4L2_STD_NTSC) ? 0x14 : 0x11); + } + cx18_av_and_or(cx, 0x401, ~0x60, 0); + cx18_av_and_or(cx, 0x401, ~0x60, 0x60); + + if (std & V4L2_STD_525_60) { + if (std == V4L2_STD_NTSC_M_JP) { + /* Japan uses EIAJ audio standard */ + cx18_av_write(cx, 0x808, 0xf7); + } else if (std == V4L2_STD_NTSC_M_KR) { + /* South Korea uses A2 audio standard */ + cx18_av_write(cx, 0x808, 0xf8); + } else { + /* Others use the BTSC audio standard */ + cx18_av_write(cx, 0x808, 0xf6); + } + cx18_av_write(cx, 0x80b, 0x00); + } else if (std & V4L2_STD_PAL) { + /* Follow tuner change procedure for PAL */ + cx18_av_write(cx, 0x808, 0xff); + cx18_av_write(cx, 0x80b, 0x03); + } else if (std & V4L2_STD_SECAM) { + /* Select autodetect for SECAM */ + cx18_av_write(cx, 0x808, 0xff); + cx18_av_write(cx, 0x80b, 0x03); + } + + if (cx18_av_read(cx, 0x803) & 0x10) { + /* restart audio decoder microcontroller */ + cx18_av_and_or(cx, 0x803, ~0x10, 0x00); + cx18_av_and_or(cx, 0x803, ~0x10, 0x10); + } +} + +static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input, + enum cx18_av_audio_input aud_input) +{ + struct cx18_av_state *state = &cx->av_state; + u8 is_composite = (vid_input >= CX18_AV_COMPOSITE1 && + vid_input <= CX18_AV_COMPOSITE8); + u8 reg; + + CX18_DEBUG_INFO("decoder set video input %d, audio input %d\n", + vid_input, aud_input); + |