blob: dc31944c7d5b144b6cfdcc637999d7eb7ad04b15 [file] [log] [blame]
// 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>
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/videodev2.h>
#include <linux/i2c.h>
#include <linux/delay.h>
#include <linux/math64.h>
#include <media/v4l2-common.h>
#include <media/drv-intf/cx25840.h>
#include "cx25840-core.h"
MODULE_DESCRIPTION("Conexant CX25840 audio/video decoder driver");
MODULE_AUTHOR("Ulf Eklund, Chris Kennedy, Hans Verkuil, Tyler Trafford");
MODULE_LICENSE("GPL");
#define CX25840_VID_INT_STAT_REG 0x410
#define CX25840_VID_INT_STAT_BITS 0x0000ffff
#define CX25840_VID_INT_MASK_BITS 0xffff0000
#define CX25840_VID_INT_MASK_SHFT 16
#define CX25840_VID_INT_MASK_REG 0x412
#define CX23885_AUD_MC_INT_MASK_REG 0x80c
#define CX23885_AUD_MC_INT_STAT_BITS 0xffff0000
#define CX23885_AUD_MC_INT_CTRL_BITS 0x0000ffff
#define CX23885_AUD_MC_INT_STAT_SHFT 16
#define CX25840_AUD_INT_CTRL_REG 0x812
#define CX25840_AUD_INT_STAT_REG 0x813
#define CX23885_PIN_CTRL_IRQ_REG 0x123
#define CX23885_PIN_CTRL_IRQ_IR_STAT 0x40
#define CX23885_PIN_CTRL_IRQ_AUD_STAT 0x20
#define CX23885_PIN_CTRL_IRQ_VID_STAT 0x10
#define CX25840_IR_STATS_REG 0x210
#define CX25840_IR_IRQEN_REG 0x214
static int cx25840_debug;
module_param_named(debug, cx25840_debug, int, 0644);
MODULE_PARM_DESC(debug, "Debugging messages [0=Off (default) 1=On]");
/* ----------------------------------------------------------------------- */
static void cx23888_std_setup(struct i2c_client *client);
int cx25840_write(struct i2c_client *client, u16 addr, u8 value)
{
u8 buffer[3];
buffer[0] = addr >> 8;
buffer[1] = addr & 0xff;
buffer[2] = value;
return i2c_master_send(client, buffer, 3);
}
int cx25840_write4(struct i2c_client *client, u16 addr, u32 value)
{
u8 buffer[6];
buffer[0] = addr >> 8;
buffer[1] = addr & 0xff;
buffer[2] = value & 0xff;
buffer[3] = (value >> 8) & 0xff;
buffer[4] = (value >> 16) & 0xff;
buffer[5] = value >> 24;
return i2c_master_send(client, buffer, 6);
}
u8 cx25840_read(struct i2c_client *client, u16 addr)
{
struct i2c_msg msgs[2];
u8 tx_buf[2], rx_buf[1];
/* Write register address */
tx_buf[0] = addr >> 8;
tx_buf[1] = addr & 0xff;
msgs[0].addr = client->addr;
msgs[0].flags = 0;
msgs[0].len = 2;
msgs[0].buf = (char *)tx_buf;
/* Read data from register */
msgs[1].addr = client->addr;
msgs[1].flags = I2C_M_RD;
msgs[1].len = 1;
msgs[1].buf = (char *)rx_buf;
if (i2c_transfer(client->adapter, msgs, 2) < 2)
return 0;
return rx_buf[0];
}
u32 cx25840_read4(struct i2c_client *client, u16 addr)
{
struct i2c_msg msgs[2];
u8 tx_buf[2], rx_buf[4];
/* Write register address */
tx_buf[0] = addr >> 8;
tx_buf[1] = addr & 0xff;
msgs[0].addr = client->addr;
msgs[0].flags = 0;
msgs[0].len = 2;
msgs[0].buf = (char *)tx_buf;
/* Read data from registers */
msgs[1].addr = client->addr;
msgs[1].flags = I2C_M_RD;
msgs[1].len = 4;
msgs[1].buf = (char *)rx_buf;
if (i2c_transfer(client->adapter, msgs, 2) < 2)
return 0;
return (rx_buf[3] << 24) | (rx_buf[2] << 16) | (rx_buf[1] << 8) |
rx_buf[0];
}
int cx25840_and_or(struct i2c_client *client, u16 addr, unsigned int and_mask,
u8 or_value)
{
return cx25840_write(client, addr,
(cx25840_read(client, addr) & and_mask) |
or_value);
}
int cx25840_and_or4(struct i2c_client *client, u16 addr, u32 and_mask,
u32 or_value)
{
return cx25840_write4(client, addr,
(cx25840_read4(client, addr) & and_mask) |
or_value);
}
/* ----------------------------------------------------------------------- */
static int set_input(struct i2c_client *client,
enum cx25840_video_input vid_input,
enum cx25840_audio_input aud_input);
/* ----------------------------------------------------------------------- */
static int cx23885_s_io_pin_config(struct v4l2_subdev *sd, size_t n,
struct v4l2_subdev_io_pin_config *p)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
int i;
u32 pin_ctrl;
u8 gpio_oe, gpio_data, strength;
pin_ctrl = cx25840_read4(client, 0x120);
gpio_oe = cx25840_read(client, 0x160);
gpio_data = cx25840_read(client, 0x164);
for (i = 0; i < n; i++) {
strength = p[i].strength;
if (strength > CX25840_PIN_DRIVE_FAST)
strength = CX25840_PIN_DRIVE_FAST;
switch (p[i].pin) {
case CX23885_PIN_IRQ_N_GPIO16:
if (p[i].function != CX23885_PAD_IRQ_N) {
/* GPIO16 */
pin_ctrl &= ~(0x1 << 25);
} else {
/* IRQ_N */
if (p[i].flags &
(BIT(V4L2_SUBDEV_IO_PIN_DISABLE) |
BIT(V4L2_SUBDEV_IO_PIN_INPUT))) {
pin_ctrl &= ~(0x1 << 25);
} else {
pin_ctrl |= (0x1 << 25);
}
if (p[i].flags &
BIT(V4L2_SUBDEV_IO_PIN_ACTIVE_LOW)) {
pin_ctrl &= ~(0x1 << 24);
} else {
pin_ctrl |= (0x1 << 24);
}
}
break;
case CX23885_PIN_IR_RX_GPIO19:
if (p[i].function != CX23885_PAD_GPIO19) {
/* IR_RX */
gpio_oe |= (0x1 << 0);
pin_ctrl &= ~(0x3 << 18);
pin_ctrl |= (strength << 18);
} else {
/* GPIO19 */
gpio_oe &= ~(0x1 << 0);
if (p[i].flags & BIT(V4L2_SUBDEV_IO_PIN_SET_VALUE)) {
gpio_data &= ~(0x1 << 0);
gpio_data |= ((p[i].value & 0x1) << 0);
}
pin_ctrl &= ~(0x3 << 12);
pin_ctrl |= (strength << 12);
}
break;
case CX23885_PIN_IR_TX_GPIO20:
if (p[i].function != CX23885_PAD_GPIO20) {
/* IR_TX */
gpio_oe |= (0x1 << 1);
if (p[i].flags & BIT(V4L2_SUBDEV_IO_PIN_DISABLE))
pin_ctrl &= ~(0x1 << 10);
else
pin_ctrl |= (0x1 << 10);
pin_ctrl &= ~(0x3 << 18);
pin_ctrl |= (strength << 18);
} else {
/* GPIO20 */
gpio_oe &= ~(0x1 << 1);
if (p[i].flags & BIT(V4L2_SUBDEV_IO_PIN_SET_VALUE)) {
gpio_data &= ~(0x1 << 1);
gpio_data |= ((p[i].value & 0x1) << 1);
}
pin_ctrl &= ~(0x3 << 12);
pin_ctrl |= (strength << 12);
}
break;
case CX23885_PIN_I2S_SDAT_GPIO21:
if (p[i].function != CX23885_PAD_GPIO21) {
/* I2S_SDAT */
/* TODO: Input or Output config */
gpio_oe |= (0x1 << 2);
pin_ctrl &= ~(0x3 << 22);
pin_ctrl |= (strength << 22);
} else {
/* GPIO21 */
gpio_oe &= ~(0x1 << 2);
if (p[i].flags & BIT(V4L2_SUBDEV_IO_PIN_SET_VALUE)) {
gpio_data &= ~(0x1 << 2);
gpio_data |= ((p[i].value & 0x1) << 2);
}
pin_ctrl &= ~(0x3 << 12);
pin_ctrl |= (strength << 12);
}
break;
case CX23885_PIN_I2S_WCLK_GPIO22:
if (p[i].function != CX23885_PAD_GPIO22) {
/* I2S_WCLK */
/* TODO: Input or Output config */
gpio_oe |= (0x1 << 3);
pin_ctrl &= ~(0x3 << 22);
pin_ctrl |= (strength << 22);
} else {
/* GPIO22 */
gpio_oe &= ~(0x1 << 3);
if (p[i].flags & BIT(V4L2_SUBDEV_IO_PIN_SET_VALUE)) {
gpio_data &= ~(0x1 << 3);
gpio_data |= ((p[i].value & 0x1) << 3);
}
pin_ctrl &= ~(0x3 << 12);
pin_ctrl |= (strength << 12);
}
break;
case CX23885_PIN_I2S_BCLK_GPIO23:
if (p[i].function != CX23885_PAD_GPIO23) {
/* I2S_BCLK */
/* TODO: Input or Output config */
gpio_oe |= (0x1 << 4);
pin_ctrl &= ~(0x3 << 22);
pin_ctrl |= (strength << 22);
} else {
/* GPIO23 */
gpio_oe &= ~(0x1 << 4);
if (p[i].flags & BIT(V4L2_SUBDEV_IO_PIN_SET_VALUE)) {
gpio_data &= ~(0x1 << 4);
gpio_data |= ((p[i].value & 0x1) << 4);
}
pin_ctrl &= ~(0x3 << 12);
pin_ctrl |= (strength << 12);
}
break;
}
}
cx25840_write(client, 0x164, gpio_data);
cx25840_write(client, 0x160, gpio_oe);
cx25840_write4(client, 0x120, pin_ctrl);
return 0;
}
static u8 cx25840_function_to_pad(struct i2c_client *client, u8 function)
{
if (function > CX25840_PAD_VRESET) {
v4l_err(client, "invalid function %u, assuming default\n",
(unsigned int)function);
return 0;
}
return function;
}
static void cx25840_set_invert(u8 *pinctrl3, u8 *voutctrl4, u8 function,
u8 pin, bool invert)
{
switch (function) {
case CX25840_PAD_IRQ_N:
if (invert)
*pinctrl3 &= ~2;
else
*pinctrl3 |= 2;
break;
case CX25840_PAD_ACTIVE:
if (invert)
*voutctrl4 |= BIT(2);
else
*voutctrl4 &= ~BIT(2);
break;
case CX25840_PAD_VACTIVE:
if (invert)
*voutctrl4 |= BIT(5);
else
*voutctrl4 &= ~BIT(5);
break;
case CX25840_PAD_CBFLAG:
if (invert)
*voutctrl4 |= BIT(4);
else
*voutctrl4 &= ~BIT(4);
break;
case CX25840_PAD_VRESET:
if (invert)
*voutctrl4 |= BIT(0);
else
*voutctrl4 &= ~BIT(0);
break;
}
if (function != CX25840_PAD_DEFAULT)
return;
switch (pin) {
case CX25840_PIN_DVALID_PRGM0:
if (invert)
*voutctrl4 |= BIT(6);
else
*voutctrl4 &= ~BIT(6);
break;
case CX25840_PIN_HRESET_PRGM2:
if (invert)
*voutctrl4 |= BIT(1);
else
*voutctrl4 &= ~BIT(1);
break;
}
}
static int cx25840_s_io_pin_config(struct v4l2_subdev *sd, size_t n,
struct v4l2_subdev_io_pin_config *p)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
unsigned int i;
u8 pinctrl[6], pinconf[10], voutctrl4;
for (i = 0; i < 6; i++)
pinctrl[i] = cx25840_read(client, 0x114 + i);
for (i = 0; i < 10; i++)
pinconf[i] = cx25840_read(client, 0x11c + i);
voutctrl4 = cx25840_read(client, 0x407);
for (i = 0; i < n; i++) {
u8 strength = p[i].strength;
if (strength != CX25840_PIN_DRIVE_SLOW &&
strength != CX25840_PIN_DRIVE_MEDIUM &&
strength != CX25840_PIN_DRIVE_FAST) {
v4l_err(client,
"invalid drive speed for pin %u (%u), assuming fast\n",
(unsigned int)p[i].pin,
(unsigned int)strength);
strength = CX25840_PIN_DRIVE_FAST;
}
switch (p[i].pin) {
case CX25840_PIN_DVALID_PRGM0:
if (p[i].flags & BIT(V4L2_SUBDEV_IO_PIN_DISABLE))
pinctrl[0] &= ~BIT(6);
else
pinctrl[0] |= BIT(6);
pinconf[3] &= 0xf0;
pinconf[3] |= cx25840_function_to_pad(client,
p[i].function);
cx25840_set_invert(&pinctrl[3], &voutctrl4,
p[i].function,
CX25840_PIN_DVALID_PRGM0,
p[i].flags &
BIT(V4L2_SUBDEV_IO_PIN_ACTIVE_LOW));
pinctrl[4] &= ~(3 << 2); /* CX25840_PIN_DRIVE_MEDIUM */
switch (strength) {
case CX25840_PIN_DRIVE_SLOW:
pinctrl[4] |= 1 << 2;
break;
case CX25840_PIN_DRIVE_FAST:
pinctrl[4] |= 2 << 2;
break;
}
break;
case CX25840_PIN_HRESET_PRGM2:
if (p[i].flags & BIT(V4L2_SUBDEV_IO_PIN_DISABLE))
pinctrl[1] &= ~BIT(0);
else
pinctrl[1] |= BIT(0);
pinconf[4] &= 0xf0;
pinconf[4] |= cx25840_function_to_pad(client,
p[i].function);
cx25840_set_invert(&pinctrl[3], &voutctrl4,
p[i].function,
CX25840_PIN_HRESET_PRGM2,
p[i].flags &
BIT(V4L2_SUBDEV_IO_PIN_ACTIVE_LOW));
pinctrl[4] &= ~(3 << 2); /* CX25840_PIN_DRIVE_MEDIUM */
switch (strength) {
case CX25840_PIN_DRIVE_SLOW:
pinctrl[4] |= 1 << 2;
break;
case CX25840_PIN_DRIVE_FAST:
pinctrl[4] |= 2 << 2;
break;
}
break;
case CX25840_PIN_PLL_CLK_PRGM7:
if (p[i].flags & BIT(V4L2_SUBDEV_IO_PIN_DISABLE))
pinctrl[2] &= ~BIT(2);
else
pinctrl[2] |= BIT(2);
switch (p[i].function) {
case CX25840_PAD_XTI_X5_DLL:
pinconf[6] = 0;
break;
case CX25840_PAD_AUX_PLL:
pinconf[6] = 1;
break;
case CX25840_PAD_VID_PLL:
pinconf[6] = 5;
break;
case CX25840_PAD_XTI:
pinconf[6] = 2;
break;
default:
pinconf[6] = 3;
pinconf[6] |=
cx25840_function_to_pad(client,
p[i].function)
<< 4;
}
break;
default:
v4l_err(client, "invalid or unsupported pin %u\n",
(unsigned int)p[i].pin);
break;
}
}
cx25840_write(client, 0x407, voutctrl4);
for (i = 0; i < 6; i++)
cx25840_write(client, 0x114 + i, pinctrl[i]);
for (i = 0; i < 10; i++)
cx25840_write(client, 0x11c + i, pinconf[i]);
return 0;
}
static int common_s_io_pin_config(struct v4l2_subdev *sd, size_t n,
struct v4l2_subdev_io_pin_config *pincfg)
{
struct cx25840_state *state = to_state(sd);
if (is_cx2388x(state))
return cx23885_s_io_pin_config(sd, n, pincfg);
else if (is_cx2584x(state))
return cx25840_s_io_pin_config(sd, n, pincfg);
return 0;
}
/* ----------------------------------------------------------------------- */
static void init_dll1(struct i2c_client *client)
{
/*
* This is the Hauppauge sequence used to
* initialize the Delay Lock Loop 1 (ADC DLL).
*/
cx25840_write(client, 0x159, 0x23);
cx25840_write(client, 0x15a, 0x87);
cx25840_write(client, 0x15b, 0x06);
udelay(10);
cx25840_write(client, 0x159, 0xe1);
udelay(10);
cx25840_write(client, 0x15a, 0x86);
cx25840_write(client, 0x159, 0xe0);
cx25840_write(client, 0x159, 0xe1);
cx25840_write(client, 0x15b, 0x10);
}
static void init_dll2(struct i2c_client *client)
{
/*
* This is the Hauppauge sequence used to
* initialize the Delay Lock Loop 2 (ADC DLL).
*/
cx25840_write(client, 0x15d, 0xe3);
cx25840_write(client, 0x15e, 0x86);
cx25840_write(client, 0x15f, 0x06);
udelay(10);
cx25840_write(client, 0x15d, 0xe1);
cx25840_write(client, 0x15d, 0xe0);
cx25840_write(client, 0x15d, 0xe1);
}
static void cx25836_initialize(struct i2c_client *client)
{
/*
*reset configuration is described on page 3-77
* of the CX25836 datasheet
*/
/* 2. */
cx25840_and_or(client, 0x000, ~0x01, 0x01);
cx25840_and_or(client, 0x000, ~0x01, 0x00);
/* 3a. */
cx25840_and_or(client, 0x15a, ~0x70, 0x00);
/* 3b. */
cx25840_and_or(client, 0x15b, ~0x1e, 0x06);
/* 3c. */
cx25840_and_or(client, 0x159, ~0x02, 0x02);
/* 3d. */
udelay(10);
/* 3e. */
cx25840_and_or(client, 0x159, ~0x02, 0x00);
/* 3f. */
cx25840_and_or(client, 0x159, ~0xc0, 0xc0);
/* 3g. */
cx25840_and_or(client, 0x159, ~0x01, 0x00);
cx25840_and_or(client, 0x159, ~0x01, 0x01);
/* 3h. */
cx25840_and_or(client, 0x15b, ~0x1e, 0x10);
}
static void cx25840_work_handler(struct work_struct *work)
{
struct cx25840_state *state = container_of(work, struct cx25840_state, fw_work);
cx25840_loadfw(state->c);
wake_up(&state->fw_wait);
}
#define CX25840_VCONFIG_SET_BIT(state, opt_msk, voc, idx, bit, oneval) \
do { \
if ((state)->vid_config & (opt_msk)) { \
if (((state)->vid_config & (opt_msk)) == \
(oneval)) \
(voc)[idx] |= BIT(bit); \
else \
(voc)[idx] &= ~BIT(bit); \
} \
} while (0)
/* apply current vconfig to hardware regs */
static void cx25840_vconfig_apply(struct i2c_client *client)
{
struct cx25840_state *state = to_state(i2c_get_clientdata(client));
u8 voutctrl[3];
unsigned int i;
for (i = 0; i < 3; i++)
voutctrl[i] = cx25840_read(client, 0x404 + i);
if (state->vid_config & CX25840_VCONFIG_FMT_MASK)
voutctrl[0] &= ~3;
switch (state->vid_config & CX25840_VCONFIG_FMT_MASK) {
case CX25840_VCONFIG_FMT_BT656:
voutctrl[0] |= 1;
break;
case CX25840_VCONFIG_FMT_VIP11:
voutctrl[0] |= 2;
break;
case CX25840_VCONFIG_FMT_VIP2:
voutctrl[0] |= 3;
break;
case CX25840_VCONFIG_FMT_BT601:
/* zero */
default:
break;
}
CX25840_VCONFIG_SET_BIT(state, CX25840_VCONFIG_RES_MASK, voutctrl,
0, 2, CX25840_VCONFIG_RES_10BIT);
CX25840_VCONFIG_SET_BIT(state, CX25840_VCONFIG_VBIRAW_MASK, voutctrl,
0, 3, CX25840_VCONFIG_VBIRAW_ENABLED);
CX25840_VCONFIG_SET_BIT(state, CX25840_VCONFIG_ANCDATA_MASK, voutctrl,
0, 4, CX25840_VCONFIG_ANCDATA_ENABLED);
CX25840_VCONFIG_SET_BIT(state, CX25840_VCONFIG_TASKBIT_MASK, voutctrl,
0, 5, CX25840_VCONFIG_TASKBIT_ONE);
CX25840_VCONFIG_SET_BIT(state, CX25840_VCONFIG_ACTIVE_MASK, voutctrl,
1, 2, CX25840_VCONFIG_ACTIVE_HORIZONTAL);
CX25840_VCONFIG_SET_BIT(state, CX25840_VCONFIG_VALID_MASK, voutctrl,
1, 3, CX25840_VCONFIG_VALID_ANDACTIVE);
CX25840_VCONFIG_SET_BIT(state, CX25840_VCONFIG_HRESETW_MASK, voutctrl,
1, 4, CX25840_VCONFIG_HRESETW_PIXCLK);
if (state->vid_config & CX25840_VCONFIG_CLKGATE_MASK)
voutctrl[1] &= ~(3 << 6);
switch (state->vid_config & CX25840_VCONFIG_CLKGATE_MASK) {
case CX25840_VCONFIG_CLKGATE_VALID:
voutctrl[1] |= 2;
break;
case CX25840_VCONFIG_CLKGATE_VALIDACTIVE:
voutctrl[1] |= 3;
break;
case CX25840_VCONFIG_CLKGATE_NONE:
/* zero */
default:
break;
}
CX25840_VCONFIG_SET_BIT(state, CX25840_VCONFIG_DCMODE_MASK, voutctrl,
2, 0, CX25840_VCONFIG_DCMODE_BYTES);
CX25840_VCONFIG_SET_BIT(state, CX25840_VCONFIG_IDID0S_MASK, voutctrl,
2, 1, CX25840_VCONFIG_IDID0S_LINECNT);
CX25840_VCONFIG_SET_BIT(state, CX25840_VCONFIG_VIPCLAMP_MASK, voutctrl,
2, 4, CX25840_VCONFIG_VIPCLAMP_ENABLED);
for (i = 0; i < 3; i++)
cx25840_write(client, 0x404 + i, voutctrl[i]);
}
static void cx25840_initialize(struct i2c_client *client)
{
DEFINE_WAIT(wait);
struct cx25840_state *state = to_state(i2c_get_clientdata(client));
struct workqueue_struct *q;
/* 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);
}
/* 6. */
cx25840_write(client, 0x115, 0x8c);
cx25840_write(client, 0x116, 0x07);
cx25840_write(client, 0x118, 0x02);
/* 7. */
cx25840_write(client, 0x4a5, 0x80);
cx25840_write(client, 0x4a5, 0x00);
cx25840_write(client, 0x402, 0x00);
/* 8. */
cx25840_and_or(client, 0x401, ~0x18, 0);
cx25840_and_or(client, 0x4a2, ~0x10, 0x10);
/* steps 8c and 8d are done in change_input() */
/* 10. */
cx25840_write(client, 0x8d3, 0x1f);
cx25840_write(client, 0x8e3, 0x03);
cx25840_std_setup(client);
/* 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);
/* stereo preferred */
cx25840_write(client, 0x809, 0x04);
/* AC97 shift */
cx25840_write(client, 0x8cf, 0x0f);
/* (re)set input */
set_input(client, state->vid_input, state->aud_input);
if (state->generic_mode)
cx25840_vconfig_apply(client);
/* start microcontroller */
cx25840_and_or(client, 0x803, ~0x10, 0x10);
}
static void cx23885_initialize(struct i2c_client *client)
{
DEFINE_WAIT(wait);
struct cx25840_state *state = to_state(i2c_get_clientdata(client));
u32 clk_freq = 0;
struct workqueue_struct *q;
/* 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);
/* Internal Reset */
cx25840_and_or(client, 0x102, ~0x01, 0x01);
cx25840_and_or(client, 0x102, ~0x01, 0x00);
/* Stop microcontroller */
cx25840_and_or(client, 0x803, ~0x10, 0x00);
/* DIF in reset? */
cx25840_write(client, 0x398, 0);
/*
* Trust the default xtal, no division
* '885: 28.636363... MHz
* '887: 25.000000 MHz
* '888: 50.000000 MHz
*/
cx25840_write(client, 0x2, 0x76);
/* Power up all the PLL's and DLL */
cx25840_write(client, 0x1, 0x40);
/* Sys PLL */
switch (state->id) {
case CX23888_AV:
/*
* 50.0 MHz * (0xb + 0xe8ba26/0x2000000)/4 = 5 * 28.636363 MHz
* 572.73 MHz before post divide
*/
if (clk_freq == 25000000) {
/* 888/ImpactVCBe or 25Mhz xtal */
; /* nothing to do */
} else {
/* HVR1850 or 50MHz xtal */
cx25840_write(client, 0x2, 0x71);
}
cx25840_write4(client, 0x11c, 0x01d1744c);
cx25840_write4(client, 0x118, 0x00000416);
cx25840_write4(client, 0x404, 0x0010253e);
cx25840_write4(client, 0x42c, 0x42600000);
cx25840_write4(client, 0x44c, 0x161f1000);
break;
case CX23887_AV:
/*
* 25.0 MHz * (0x16 + 0x1d1744c/0x2000000)/4 = 5 * 28.636363 MHz
* 572.73 MHz before post divide
*/
cx25840_write4(client, 0x11c, 0x01d1744c);
cx25840_write4(client, 0x118, 0x00000416);
break;
case CX23885_AV:
default:
/*
* 28.636363 MHz * (0x14 + 0x0/0x2000000)/4 = 5 * 28.636363 MHz
* 572.73 MHz before post divide
*/
cx25840_write4(client, 0x11c, 0x00000000);
cx25840_write4(client, 0x118, 0x00000414);
break;
}
/* Disable DIF bypass */
cx25840_write4(client, 0x33c, 0x00000001);
/* DIF Src phase inc */
cx25840_write4(client, 0x340, 0x0df7df83);
/*
* Vid PLL
* Setup for a BT.656 pixel clock of 13.5 Mpixels/second
*
* 28.636363 MHz * (0xf + 0x02be2c9/0x2000000)/4 = 8 * 13.5 MHz
* 432.0 MHz before post divide
*/
/* HVR1850 */
switch (state->id) {
case CX23888_AV:
if (clk_freq == 25000000) {
/* 888/ImpactVCBe or 25MHz xtal */
cx25840_write4(client, 0x10c, 0x01b6db7b);
cx25840_write4(client, 0x108, 0x00000512);
} else {
/* 888/HVR1250 or 50MHz xtal */
cx25840_write4(client, 0x10c, 0x13333333);
cx25840_write4(client, 0x108, 0x00000515);
}
break;
default:
cx25840_write4(client, 0x10c, 0x002be2c9);
cx25840_write4(client, 0x108, 0x0000040f);
}
/* Luma */
cx25840_write4(client, 0x414, 0x00107d12);
/* Chroma */
if (is_cx23888(state))
cx25840_write4(client, 0x418, 0x1d008282);
else
cx25840_write4(client, 0x420, 0x3d008282);
/*
* Aux PLL
* Initial setup for audio sample clock:
* 48 ksps, 16 bits/sample, x160 multiplier = 122.88 MHz
* Initial I2S output/master clock(?):
* 48 ksps, 16 bits/sample, x16 multiplier = 12.288 MHz
*/
switch (state->id) {
case CX23888_AV:
/*
* 50.0 MHz * (0x7 + 0x0bedfa4/0x2000000)/3 = 122.88 MHz
* 368.64 MHz before post divide
* 122.88 MHz / 0xa = 12.288 MHz
*/
/* HVR1850 or 50MHz xtal or 25MHz xtal */
cx25840_write4(client, 0x114, 0x017dbf48);
cx25840_write4(client, 0x110, 0x000a030e);
break;
case CX23887_AV:
/*
* 25.0 MHz * (0xe + 0x17dbf48/0x2000000)/3 = 122.88 MHz
* 368.64 MHz before post divide
* 122.88 MHz / 0xa = 12.288 MHz
*/
cx25840_write4(client, 0x114, 0x017dbf48);
cx25840_write4(client, 0x110, 0x000a030e);
break;
case CX23885_AV:
default:
/*
* 28.636363 MHz * (0xc + 0x1bf0c9e/0x2000000)/3 = 122.88 MHz
* 368.64 MHz before post divide
* 122.88 MHz / 0xa = 12.288 MHz
*/
cx25840_write4(client, 0x114, 0x01bf0c9e);
cx25840_write4(client, 0x110, 0x000a030c);
break;
}
/* ADC2 input select */
cx25840_write(client, 0x102, 0x10);
/* VIN1 & VIN5 */
cx25840_write(client, 0x103, 0x11);
/* Enable format auto detect */
cx25840_write(client, 0x400, 0);
/* Fast subchroma lock */
/* White crush, Chroma AGC & Chroma Killer enabled */
cx25840_write(client, 0x401, 0xe8);
/* Select AFE clock pad output source */
cx25840_write(client, 0x144, 0x05);
/* 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);
/* (re)set input */
set_input(client, state->vid_input, state->aud_input);
/* start microcontroller */
cx25840_and_or(client, 0x803, ~0x10, 0x10);
/* 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);
/* SRC_COMB_CFG */
if (is_cx23888(state))
cx25840_write4(client, 0x454, 0x6628021F);
else
cx25840_write4(client, 0x478, 0x6628021F);
/* AFE_CLK_OUT_CTRL - Select the clock output source as output */
cx25840_write4(client, 0x144, 0x5);
/* I2C_OUT_CTL - I2S output configuration as
* Master, Sony, Left justified, left sample on WS=1
*/
cx25840_write4(client, 0x918, 0x1a0);
/* AFE_DIAG_CTRL1 */
cx25840_write4(client, 0x134, 0x000a1800);
/* AFE_DIAG_CTRL3 - Inverted Polarity for Audio and Video */
cx25840_write4(client, 0x13c, 0x00310000);
}
/* ----------------------------------------------------------------------- */
static void cx231xx_initialize(struct i2c_client *client)
{
DEFINE_WAIT(wait);
struct cx25840_state *state = to_state(i2c_get_clientdata(client));
struct workqueue_struct *q;
/* Internal Reset */
cx25840_and_or(client, 0x102, ~0x01, 0x01);
cx25840_and_or(client, 0x102, ~0x01, 0x00);
/* Stop microcontroller */
cx25840_and_or(client, 0x803, ~0x10, 0x00);
/* DIF in reset? */
cx25840_write(client, 0x398, 0);
/* Trust the default xtal, no division */
/* This changes for the cx23888 products */
cx25840_write(client, 0x2, 0x76);
/* Bring down the regulator for AUX clk */
cx25840_write(client, 0x1, 0x40);
/* Disable DIF bypass */
cx25840_write4(client, 0x33c, 0x00000001);
/* DIF Src phase inc */
cx25840_write4(client, 0x340, 0x0df7df83);
/* Luma */
cx25840_write4(client, 0x414, 0x00107d12);
/* Chroma */
cx25840_write4(client, 0x420, 0x3d008282);
/* ADC2 input select */
cx25840_write(client, 0x102, 0x10);
/* VIN1 & VIN5 */
cx25840_write(client, 0x103, 0x11);
/* 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);
}
cx25840_std_setup(client);
/* (re)set input */
set_input(client, state->vid_input, state->aud_input);
/* start microcontroller */
cx25840_and_or(client, 0x803, ~0x10, 0x10);
/* CC raw enable */
cx25840_write(client, 0x404, 0x0b);
/* CC on */
cx25840_write(client, 0x42f, 0x66);
cx25840_write4(client, 0x474, 0x1e1e601a);
}
/* ----------------------------------------------------------------------- */
void cx25840_std_setup(struct i2c_client *client)
{
struct cx25840_state *state = to_state(i2c_get_clientdata(client));
v4l2_std_id std = state->std;
int hblank, hactive, burst, vblank, vactive, sc;
int vblank656, src_decimation;
int luma_lpf, uv_lpf, comb;
u32 pll_int, pll_frac, pll_post;
/* datasheet startup, step 8d */
if (std & ~V4L2_STD_NTSC)
cx25840_write(client, 0x49f, 0x11);
else
cx25840_write(client, 0x49f, 0x14);
/* generic mode uses the values that the chip autoconfig would set */
if (std & V4L2_STD_625_50) {
hblank = 132;
hactive = 720;
burst = 93;
if (state->generic_mode) {
vblank = 34;
vactive = 576;
vblank656 = 38;
} else {
vblank = 36;
vactive = 580;
vblank656 = 40;
}
src_decimation = 0x21f;
luma_lpf = 2;
if (std & V4L2_STD_SECAM) {
uv_lpf = 0;
comb = 0;
sc = 0x0a425f;
} else if (std == V4L2_STD_PAL_Nc) {
if (state->generic_mode) {
burst = 95;
luma_lpf = 1;
}
uv_lpf = 1;
comb = 0x20;
sc = 556453;
} else {
uv_lpf = 1;
comb = 0x20;
sc = 688739;
}
} else {
hactive = 720;
hblank = 122;
vactive = 487;
luma_lpf = 1;
uv_lpf = 1;
if (state->generic_mode) {
vblank = 20;
vblank656 = 24;
}
src_decimation = 0x21f;
if (std == V4L2_STD_PAL_60) {
if (!state->generic_mode) {
vblank = 26;
vblank656 = 26;
burst = 0x5b;
} else {
burst = 0x59;
}
luma_lpf = 2;
comb = 0x20;
sc = 688739;
} else if (std == V4L2_STD_PAL_M) {
vblank = 20;
vblank656 = 24;
burst = 0x61;
comb = 0x20;
sc = 555452;
} else {
if (!state->generic_mode) {
vblank = 26;
vblank656 = 26;
}
burst = 0x5b;
comb = 0x66;
sc = 556063;
}
}
/* DEBUG: Displays configured PLL frequency */
if (!is_cx231xx(state)) {
pll_int = cx25840_read(client, 0x108);
pll_frac = cx25840_read4(client, 0x10c) & 0x1ffffff;
pll_post = cx25840_read(client, 0x109);
v4l_dbg(1, cx25840_debug, client,
"PLL regs = int: %u, frac: %u, post: %u\n",
pll_int, pll_frac, pll_post);
if (pll_post) {
int fin, fsc;
int pll = (28636363L * ((((u64)pll_int) << 25L) + pll_frac)) >> 25L;
pll /= pll_post;
v4l_dbg(1, cx25840_debug, client,
"PLL = %d.%06d MHz\n",
pll / 1000000, pll % 1000000);
v4l_dbg(1, cx25840_debug, client,
"PLL/8 = %d.%06d MHz\n",
pll / 8000000, (pll / 8) % 1000000);
fin = ((u64)src_decimation * pll) >> 12;
v4l_dbg(1, cx25840_debug, client,
"ADC Sampling freq = %d.%06d MHz\n",
fin / 1000000, fin % 1000000);
fsc = (((u64)sc) * pll) >> 24L;
v4l_dbg(1, cx25840_debug, client,
"Chroma sub-carrier freq = %d.%06d MHz\n",
fsc / 1000000, fsc % 1000000);
v4l_dbg(1, cx25840_debug, client,
"hblank %i, hactive %i, vblank %i, vactive %i, vblank656 %i, src_dec %i, burst 0x%02x, luma_lpf %i, uv_lpf %i, comb 0x%02x, sc 0x%06x\n",
hblank, hactive, vblank, vactive, vblank656,
src_decimation, burst, luma_lpf, uv_lpf,
comb, sc);
}
}
/* Sets horizontal blanking delay and active lines */
cx25840_write(client, 0x470, hblank);
cx25840_write(client, 0x471,
(((hblank >> 8) & 0x3) | (hactive << 4)) & 0xff);
cx25840_write(client, 0x472, hactive >> 4);
/* Sets burst gate delay */
cx25840_write(client, 0x473, burst);
/* Sets vertical blanking delay and active duration */
cx25840_write(client, 0x474, vblank);
cx25840_write(client, 0x475,
(((vblank >> 8) & 0x3) | (vactive << 4)) & 0xff);
cx25840_write(client, 0x476, vactive >> 4);
cx25840_write(client, 0x477, vblank656);
/* Sets src decimation rate */
cx25840_write(client, 0x478, src_decimation & 0xff);
cx25840_write(client, 0x479, (src_decimation >> 8) & 0xff);
/* Sets Luma and UV Low pass filters */
cx25840_write(client, 0x47a, luma_lpf << 6 | ((uv_lpf << 4) & 0x30));
/* Enables comb filters */
cx25840_write(client, 0x47b, comb);
/* Sets SC Step*/
cx25840_write(client, 0x47c, sc);
cx25840_write(client, 0x47d, (sc >> 8) & 0xff);
cx25840_write(client, 0x47e, (sc >> 16) & 0xff);
/* Sets VBI parameters */
if (std & V4L2_STD_625_50) {
cx25840_write(client, 0x47f, 0x01);
state->vbi_line_offset = 5;
} else {
cx25840_write(client, 0x47f, 0x00);
state->vbi_line_offset = 8;
}
}
/* ----------------------------------------------------------------------- */
static void input_change(struct i2c_client *client)
{
struct cx25840_state *state = to_state(i2c_get_clientdata(client));
v4l2_std_id std = state->std;
/* 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);
} else if (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);
} else if (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);
} else if (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);
} else if (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);
} else if (!(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);
}
}
cx25840_and_or(client, 0x810, ~0x01, 0);
}
static int set_input(struct i2c_client *client,
enum cx25840_video_input vid_input,
enum cx25840_audio_input aud_input)
{
struct cx25840_state *state = to_state(i2c_get_clientdata(client));
u8 is_composite = (vid_input >= CX25840_COMPOSITE1 &&
vid_input <= CX25840_COMPOSITE8);
u8 is_component = (vid_input & CX25840_COMPONENT_ON) ==
CX25840_COMPONENT_ON;
u8 is_dif = (vid_input & CX25840_DIF_ON) ==
CX25840_DIF_ON;
u8 is_svideo = (vid_input & CX25840_SVIDEO_ON) ==
CX25840_SVIDEO_ON;
int luma = vid_input & 0xf0;
int chroma = vid_input & 0xf00;
u8 reg;
u32 val;
v4l_dbg(1, cx25840_debug, client,
"decoder set video input %d, audio input %d\n",
vid_input, aud_input);
if (vid_input >= CX25840_VIN1_CH1) {
v4l_dbg(1, cx25840_debug, client, "vid_input 0x%x\n",
vid_input);
reg = vid_input & 0xff;
is_composite = !is_component &&
((vid_input & CX25840_SVIDEO_ON) != CX25840_SVIDEO_ON);
v4l_dbg(1, cx25840_debug, client, "mux cfg 0x%x comp=%d\n",
reg, is_composite);
} else if (is_composite) {
reg = 0xf0 + (vid_input - CX25840_COMPOSITE1);
} else {
if ((vid_input & ~0xff0) ||
luma < CX25840_SVIDEO_LUMA1 ||
luma > CX25840_SVIDEO_LUMA8 ||
chroma < CX25840_SVIDEO_CHROMA4 ||
chroma > CX25840_SVIDEO_CHROMA8) {
v4l_err(client, "0x%04x is not a valid video input!\n",
vid_input);
return -EINVAL;
}
reg = 0xf0 + ((luma - CX25840_SVIDEO_LUMA1) >> 4);
if (chroma >= CX25840_SVIDEO_CHROMA7) {
reg &= 0x3f;
reg |= (chroma - CX25840_SVIDEO_CHROMA7) >> 2;
} else {
reg &= 0xcf;
reg |= (chroma - CX25840_SVIDEO_CHROMA4) >> 4;
}
}
/* 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);
cx25840_and_or(client, 0x102, ~0x80, 0);
cx25840_write4(client, 0x340, 0xdf7df83);
cx25840_write4(client, 0x104, 0x0704dd80);
cx25840_write4(client, 0x314, 0x22400600);
cx25840_write4(client, 0x318, 0x40002600);
cx25840_write4(client, 0x324, 0x40002600);
cx25840_write4(client, 0x32c, 0x0250e620);
cx25840_write4(client, 0x39c, 0x01FF0B00);
cx25840_write4(client, 0x410, 0xffff0dbf);
cx25840_write4(client, 0x414, 0x00137d03);
if (is_cx23888(state)) {
/* 888 MISC_TIM_CTRL */
cx25840_write4(client, 0x42c, 0x42600000);
/* 888 FIELD_COUNT */
cx25840_write4(client, 0x430, 0x0000039b);
/* 888 VSCALE_CTRL */
cx25840_write4(client, 0x438, 0x00000000);
/* 888 DFE_CTRL1 */
cx25840_write4(client, 0x440, 0xF8E3E824);
/* 888 DFE_CTRL2 */
cx25840_write4(client, 0x444, 0x401040dc);
/* 888 DFE_CTRL3 */
cx25840_write4(client, 0x448, 0xcd3f02a0);
/* 888 PLL_CTRL */
cx25840_write4(client, 0x44c, 0x161f1000);
/* 888 HTL_CTRL */
cx25840_write4(client, 0x450, 0x00000802);
}
cx25840_write4(client, 0x91c, 0x01000000);
cx25840_write4(client, 0x8e0, 0x03063870);
cx25840_write4(client, 0x8d4, 0x7FFF0024);
cx25840_write4(client, 0x8d0, 0x00063073);
cx25840_write4(client, 0x8c8, 0x00010000);
cx25840_write4(client, 0x8cc, 0x00080023);
/* DIF BYPASS */
cx25840_write4(client, 0x33c, 0x2a04c800);
}
/* Reset the DIF */
cx25840_write4(client, 0x398, 0);
}
if (!is_cx2388x(state) && !is_cx231xx(state)) {
/* Set CH_SEL_ADC2 to 1 if input comes from CH3 */
cx25840_and_or(client, 0x102, ~0x2, (reg & 0x80) == 0 ? 2 : 0);
/* Set DUAL_MODE_ADC2 to 1 if input comes from both CH2&CH3 */
if ((reg & 0xc0) != 0xc0 && (reg & 0x30) != 0x30)
cx25840_and_or(client, 0x102, ~0x4, 4);
else
cx25840_and_or(client, 0x102, ~0x4, 0);
} else {
/* Set DUAL_MODE_ADC2 to 1 if component*/
cx25840_and_or(client, 0x102, ~0x4, is_component ? 0x4 : 0x0);
if (is_composite) {
/* ADC2 input select channel 2 */
cx25840_and_or(client, 0x102, ~0x2, 0);
} else if (!is_component) {
/* S-Video */
if (chroma >= CX25840_SVIDEO_CHROMA7) {
/* ADC2 input select channel 3 */
cx25840_and_or(client, 0x102, ~0x2, 2);
} else {
/* ADC2 input select channel 2 */
cx25840_and_or(client, 0x102, ~0x2, 0);
}
}
/* cx23885 / SVIDEO */
if (is_cx2388x(state) && is_svideo) {
#define AFE_CTRL (0x104)
#define MODE_CTRL (0x400)
cx25840_and_or(client, 0x102, ~0x2, 0x2);
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);
}
}
state->vid_input = vid_input;
state->aud_input = aud_input;
cx25840_audio_set_path(client);
input_change(client);
if (is_cx2388x(state)) {
/* Audio channel 1 src : Parallel 1 */
cx25840_write(client, 0x124, 0x03);
/* Select AFE clock pad output source */
cx25840_write(client, 0x144, 0x05);
/* I2S_IN_CTL: I2S_IN_SONY_MODE, LEFT SAMPLE on WS=1 */
cx25840_write(client, 0x914, 0xa0);
/* I2S_OUT_CTL:
* I2S_IN_SONY_MODE, LEFT SAMPLE on WS=1
* I2S_OUT_MASTER_MODE = Master
*/
cx25840_write(client, 0x918, 0xa0);
cx25840_write(client, 0x919, 0x01);
} else if (is_cx231xx(state)) {
/* Audio channel 1 src : Parallel 1 */
cx25840_write(client, 0x124, 0x03);
/* I2S_IN_CTL: I2S_IN_SONY_MODE, LEFT SAMPLE on WS=1 */
cx25840_write(client, 0x914, 0xa0);
/* I2S_OUT_CTL:
* I2S_IN_SONY_MODE, LEFT SAMPLE on WS=1
* I2S_OUT_MASTER_MODE = Master
*/
cx25840_write(client, 0x918, 0xa0);
cx25840_write(client, 0x919, 0x01);
}
if (is_cx2388x(state) &&
((aud_input == CX25840_AUDIO7) || (aud_input == CX25840_AUDIO6))) {
/* Configure audio from LR1 or LR2 input */
cx25840_write4(client, 0x910, 0);
cx25840_write4(client, 0x8d0, 0x63073);
} else if (is_cx2388x(state) && (aud_input == CX25840_AUDIO8)) {
/* Configure audio from tuner/sif input */
cx25840_write4(client, 0x910, 0x12b000c9);
cx25840_write4(client, 0x8d0, 0x1f063870);
}
if (is_cx23888(state)) {
/*
* HVR1850
*
* AUD_IO_CTRL - I2S Input, Parallel1
* - Channel 1 src - Parallel1 (Merlin out)
* - Channel 2 src - Parallel2 (Merlin out)
* - Channel 3 src - Parallel3 (Merlin AC97 out)
* - I2S source and dir - Merlin, output
*/
cx25840_write4(client, 0x124, 0x100);
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);
}
}
return 0;
}
/* ----------------------------------------------------------------------- */
static int set_v4lstd(struct i2c_client *client)
{
struct cx25840_state *state = to_state(i2c_get_clientdata(client));
u8 fmt = 0; /* zero is autodetect */
u8 pal_m = 0;
/* First tests should be against specific std */
if (state->std == V4L2_STD_NTSC_M_JP) {
fmt = 0x2;
} else if (state->std == V4L2_STD_NTSC_443) {
fmt = 0x3;
} else if (state->std == V4L2_STD_PAL_M) {
pal_m = 1;
fmt = 0x5;
} else if (state->std == V4L2_STD_PAL_N) {
fmt = 0x6;
} else if (state->std == V4L2_STD_PAL_Nc) {
fmt = 0x7;
} else if (state->std == V4L2_STD_PAL_60) {
fmt = 0x8;
} else {
/* Then, test against generic ones */
if (state->std & V4L2_STD_NTSC)
fmt = 0x1;
else if (state->std & V4L2_STD_PAL)
fmt = 0x4;
else if (state->std & V4L2_STD_SECAM)
fmt = 0xc;
}
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;
}
/* ----------------------------------------------------------------------- */
static int cx25840_s_ctrl(struct v4l2_ctrl *ctrl)
{
struct v4l2_subdev *sd = to_sd(ctrl);
struct cx25840_state *state = to_state(sd);
struct i2c_client *client = v4l2_get_subdevdata(sd);
switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
cx25840_write(client, 0x414, ctrl->val - 128);
break;
case V4L2_CID_CONTRAST:
cx25840_write(client, 0x415, ctrl->val << 1);
break;
case V4L2_CID_SATURATION:
if (is_cx23888(state)) {
cx25840_write(client, 0x418, ctrl->val << 1);
cx25840_write(client, 0x419, ctrl->val << 1);
} else {
cx25840_write(client, 0x420, ctrl->val << 1);
cx25840_write(client, 0x421, ctrl->val << 1);
}
break;
case V4L2_CID_HUE:
if (is_cx23888(state))
cx25840_write(client, 0x41a, ctrl->val);
else
cx25840_write(client, 0x422, ctrl->val);
break;
default:
return -EINVAL;
}
return 0;
}
/* ----------------------------------------------------------------------- */
static int cx25840_set_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct v4l2_mbus_framefmt *fmt = &format->format;
struct cx25840_state *state = to_state(sd);
struct i2c_client *client = v4l2_get_subdevdata(sd);
u32 hsc, vsc, v_src, h_src, v_add;
int filter;
int is_50hz = !(state->std & V4L2_STD_525_60);
if (format->pad || fmt->code != MEDIA_BUS_FMT_FIXED)
return -EINVAL;
fmt->field = V4L2_FIELD_INTERLACED;
fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
if (is_cx23888(state)) {
v_src = (cx25840_read(client, 0x42a) & 0x3f) << 4;
v_src |= (cx25840_read(client, 0x429) & 0xf0) >> 4;
} else {
v_src = (cx25840_read(client, 0x476) & 0x3f) << 4;
v_src |= (cx25840_read(client, 0x475) & 0xf0) >> 4;
}
if (is_cx23888(state)) {
h_src = (cx25840_read(client, 0x426) & 0x3f) << 4;
h_src |= (cx25840_read(client, 0x425) & 0xf0) >> 4;
} else {
h_src = (cx25840_read(client, 0x472) & 0x3f) << 4;
h_src |= (cx25840_read(client, 0x471) & 0xf0) >> 4;
}
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",
(unsigned int)h_src, (unsigned int)v_src);
/*
* that's the best we can do since the output picture
* size is completely unknown in this case
*/
return -EINVAL;
}
fmt->width = clamp(fmt->width, (h_src + 15) / 16, h_src);
if (v_add * 8 >= v_src)
fmt->height = clamp(fmt->height, (u32)1, v_src - v_add);
else
fmt->height = clamp(fmt->height, (v_src - v_add * 8 + 7) / 8,
v_src - v_add);
if (format->which == V4L2_SUBDEV_FORMAT_TRY)
return 0;
hsc = (h_src * (1 << 20)) / fmt->width - (1 << 20);
vsc = (1 << 16) - (v_src * (1 << 9) / (fmt->height + v_add) - (1 << 9));
vsc &= 0x1fff;
if (fmt->width >= 385)
filter = 0;
else if (fmt->width > 192)
filter = 1;
else if (fmt->width > 96)
filter = 2;
else
filter = 3;
v4l_dbg(1, cx25840_debug, client,
"decoder set size %u x %u with scale %x x %x\n",
(unsigned int)fmt->width, (unsigned int)fmt->height,
(unsigned int)hsc, (unsigned int)vsc);
/* HSCALE=hsc */
if (is_cx23888(state)) {
cx25840_write4(client, 0x434, hsc | (1 << 24));
/* VSCALE=vsc VS_INTRLACE=1 VFILT=filter */
cx25840_write4(client, 0x438, vsc | (1 << 19) | (filter << 16));
} else {
cx25840_write(client, 0x418, hsc & 0xff);
cx25840_write(client, 0x419, (hsc >> 8) & 0xff);
cx25840_write(client, 0x41a, hsc >> 16);
/* VSCALE=vsc */
cx25840_write(client, 0x41c, vsc & 0xff);
cx25840_write(client, 0x41d, vsc >> 8);
/* VS_INTRLACE=1 VFILT=filter */
cx25840_write(client, 0x41e, 0x8 | filter);
}
return 0;
}
/* ----------------------------------------------------------------------- */
static void log_video_status(struct i2c_client *client)
{
static const char *const fmt_strs[] = {
"0x0",
"NTSC-M", "NTSC-J", "NTSC-4.43",
"PAL-BDGHI", "PAL-M", "PAL-N", "PAL-Nc", "PAL-60",
"0x9", "0xA", "0xB",
"SECAM",
"0xD", "0xE", "0xF"
};
struct cx25840_state *state = to_state(i2c_get_clientdata(client));
u8 vidfmt_sel = cx25840_read(client, 0x400) & 0xf;
u8 gen_stat1 = cx25840_read(client, 0x40d);
u8 gen_stat2 = cx25840_read(client, 0x40e);
int vid_input = state->vid_input;
v4l_info(client, "Video signal: %spresent\n",
(gen_stat2 & 0x20) ? "" : "not ");
v4l_info(client, "Detected format: %s\n",
fmt_strs[gen_stat1 & 0xf]);
v4l_info(client, "Specified standard: %s\n",
vidfmt_sel ? fmt_strs[vidfmt_sel] : "automatic detection");
if (vid_input >= CX25840_COMPOSITE1 &&
vid_input <= CX25840_COMPOSITE8) {
v4l_info(client, "Specified video input: Composite %d\n",
vid_input - CX25840_COMPOSITE1 + 1);
} else {
v4l_info(client,
"Specified video input: S-Video (Luma In%d, Chroma In%d)\n",
(vid_input & 0xf0) >> 4, (vid_input & 0xf00) >> 8);
}
v4l_info(client, "Specified audioclock freq: %d Hz\n",
state->audclk_freq);
}
/* ----------------------------------------------------------------------- */
static void log_audio_status(struct i2c_client *client)
{
struct cx25840_state *state = to_state(i2c_get_clientdata(client));
u8 download_ctl = cx25840_read(client, 0x803);
u8 mod_det_stat0 = cx25840_read(client, 0x804);
u8 mod_det_stat1 = cx25840_read(client, 0x805);
u8 audio_config = cx25840_read(client, 0x808);
u8 pref_mode = cx25840_read(client, 0x809);
u8 afc0 = cx25840_read(client, 0x80b);
u8 mute_ctl = cx25840_read(client, 0x8d3);
int aud_input = state->aud_input;
char *p;
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);
}
if (aud_input) {
v4l_info(client, "Specified audio input: Tuner (In%d)\n",
aud_input);
} else {
v4l_info(client, "Specified audio input: External\n");
}
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)
/* apply incoming options to the current vconfig */
static void cx25840_vconfig_add(struct cx25840_state *state, u32 cfg_in)
{
CX25840_VCONFIG_OPTION(state, cfg_in, CX25840_VCONFIG_FMT_MASK);
CX25840_VCONFIG_OPTION(state, cfg_in, CX25840_VCONFIG_RES_MASK);
CX25840_VCONFIG_OPTION(state, cfg_in, CX25840_VCONFIG_VBIRAW_MASK);
CX25840_VCONFIG_OPTION(state, cfg_in, CX25840_VCONFIG_ANCDATA_MASK);
CX25840_VCONFIG_OPTION(state, cfg_in, CX25840_VCONFIG_TASKBIT_MASK);
CX25840_VCONFIG_OPTION(state, cfg_in, CX25840_VCONFIG_ACTIVE_MASK);
CX25840_VCONFIG_OPTION(state, cfg_in, CX25840_VCONFIG_VALID_MASK);
CX25840_VCONFIG_OPTION(state, cfg_in, CX25840_VCONFIG_HRESETW_MASK);
CX25840_VCONFIG_OPTION(state, cfg_in, CX25840_VCONFIG_CLKGATE_MASK);
CX25840_VCONFIG_OPTION(state, cfg_in, CX25840_VCONFIG_DCMODE_MASK);
CX25840_VCONFIG_OPTION(state, cfg_in, CX25840_VCONFIG_IDID0S_MASK);
CX25840_VCONFIG_OPTION(state, cfg_in, CX25840_VCONFIG_VIPCLAMP_MASK);
}
/* ----------------------------------------------------------------------- */
/*
* 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.
*/
static int cx25840_init(struct v4l2_subdev *sd, u32 val)
{
struct cx25840_state *state = to_state(sd);
state->generic_mode = true;
if (is_cx2584x(state)) {
/* set datasheet video output defaults */
state->vid_config = CX25840_VCONFIG_FMT_BT656 |
CX25840_VCONFIG_RES_8BIT |
CX25840_VCONFIG_VBIRAW_DISABLED |
CX25840_VCONFIG_ANCDATA_ENABLED |
CX25840_VCONFIG_TASKBIT_ONE |
CX25840_VCONFIG_ACTIVE_HORIZONTAL |
CX25840_VCONFIG_VALID_NORMAL |
CX25840_VCONFIG_HRESETW_NORMAL |
CX25840_VCONFIG_CLKGATE_NONE |
CX25840_VCONFIG_DCMODE_DWORDS |
CX25840_VCONFIG_IDID0S_NORMAL |
CX25840_VCONFIG_VIPCLAMP_DISABLED;
/* add additional settings */
cx25840_vconfig_add(state, val);
} else {
/* TODO: generic mode needs to be developed for other chips */
WARN_ON(1);
}
return 0;
}
static int cx25840_reset(struct v4l2_subdev *sd, u32 val)
{
struct cx25840_state *state = to_state(sd);
struct i2c_client *client = v4l2_get_subdevdata(sd);
if (is_cx2583x(state))
cx25836_initialize(client);
else if (is_cx2388x(state))
cx23885_initialize(client);
else if (is_cx231xx(state))
cx231xx_initialize(client);
else
cx25840_initialize(client);
state->is_initialized = 1;
return 0;
}
/*
* 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.
*/
static int 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;
}
#ifdef CONFIG_VIDEO_ADV_DEBUG
static int cx25840_g_register(struct v4l2_subdev *sd,
struct v4l2_dbg_register *reg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
reg->size = 1;
reg->val = cx25840_read(client, reg->reg & 0x0fff);
return 0;
}
static int cx25840_s_register(struct v4l2_subdev *sd,
const struct v4l2_dbg_register *reg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
cx25840_write(client, reg->reg & 0x0fff, reg->val & 0xff);
return 0;
}
#endif
static int cx25840_s_audio_stream(struct v4l2_subdev *sd, int enable)
{
struct cx25840_state *state = to_state(sd);
struct i2c_client *client = v4l2_get_subdevdata(sd);
u8 v;
if (is_cx2583x(state) || is_cx2388x(state) || is_cx231xx(state))
return 0;
v4l_dbg(1, cx25840_debug, client, "%s audio output\n",
enable ? "enable" : "disable");
if (enable) {
v = cx25840_read(client, 0x115) | 0x80;
cx25840_write(client, 0x115, v);
v = cx25840_read(client, 0x116) | 0x03;
cx25840_write(client, 0x116, v);
} else {
v = cx25840_read(client, 0x115) & ~(0x80);
cx25840_write(client, 0x115, v);
v = cx25840_read(client, 0x116) & ~(0x03);
cx25840_write(client, 0x116, v);
}
return 0;
}
static int cx25840_s_stream(struct v4l2_subdev *sd, int enable)
{
struct cx25840_state *state = to_state(sd);
struct i2c_client *client = v4l2_get_subdevdata(sd);
u8 v;
v4l_dbg(1, cx25840_debug, client, "%s video output\n",
enable ? "enable" : "disable");
/*
* 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 */
static int cx25840_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
static const v4l2_std_id stds[] = {
/* 0000 */ V4L2_STD_UNKNOWN,
/* 0001 */ V4L2_STD_NTSC_M,
/* 0010 */ V4L2_STD_NTSC_M_JP,
/* 0011 */ V4L2_STD_NTSC_443,
/* 0100 */ V4L2_STD_PAL,
/* 0101 */ V4L2_STD_PAL_M,
/* 0110 */ V4L2_STD_PAL_N,
/* 0111 */ V4L2_STD_PAL_Nc,
/* 1000 */ V4L2_STD_PAL_60,
/* 1001 */ V4L2_STD_UNKNOWN,
/* 1010 */ V4L2_STD_UNKNOWN,
/* 1011 */ V4L2_STD_UNKNOWN,
/* 1100 */ V4L2_STD_SECAM,
/* 1101 */ V4L2_STD_UNKNOWN,
/* 1110 */ V4L2_STD_UNKNOWN,
/* 1111 */ V4L2_STD_UNKNOWN
};
u32 fmt = (cx25840_read4(client, 0x40c) >> 8) & 0xf;
*std = stds[fmt];
v4l_dbg(1, cx25840_debug, client,
"querystd fmt = %x, v4l2_std_id = 0x%x\n",
fmt, (unsigned int)stds[fmt]);
return 0;
}
static int cx25840_g_input_status(struct v4l2_subdev *sd, u32 *status)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
/*
* A limited function that checks for signal status and returns
* the state.
*/
/* Check for status of Horizontal lock (SRC lock isn't reliable) */
if ((cx25840_read4(client, 0x40c) & 0x00010000) == 0)
*status |= V4L2_IN_ST_NO_SIGNAL;
return 0;
}
static int cx25840_g_std(struct v4l2_subdev *sd, v4l2_std_id *std)
{
struct cx25840_state *state = to_state(sd);
*std = state->std;
return 0;
}
static int cx25840_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
{
struct cx25840_state *state = to_state(sd);
struct i2c_client *client = v4l2_get_subdevdata(sd);
if (state->radio == 0 && state->std == std)
return 0;
state->radio = 0;
state->std = std;
return set_v4lstd(client);
}
static int cx25840_s_radio(struct v4l2_subdev *sd)
{
struct cx25840_state *state = to_state(sd);
state->radio = 1;
return 0;
}
static int cx25840_s_video_routing(struct v4l2_subdev *sd,
u32 input, u32 output, u32 config)
{
struct cx25840_state *state = to_state(sd);
struct i2c_client *client = v4l2_get_subdevdata(sd);
if (is_cx23888(state))
cx23888_std_setup(client);
if (is_cx2584x(state) && state->generic_mode && config) {
cx25840_vconfig_add(state, config);
cx25840_vconfig_apply(client);
}
return set_input(client, input, state->aud_input);
}
static int cx25840_s_audio_routing(struct v4l2_subdev *sd,
u32 input, u32 output, u32 config)
{
struct cx25840_state *state = to_state(sd);
struct i2c_client *client = v4l2_get_subdevdata(sd);
if (is_cx23888(state))
cx23888_std_setup(client);
return set_input(client, state->vid_input, input);
}
static int cx25840_s_frequency(struct v4l2_subdev *sd,
const struct v4l2_frequency *freq)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
input_change(client);
return 0;
}
static int cx25840_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
{
struct cx25840_state *state = to_state(sd);
struct i2c_client *client = v4l2_get_subdevdata(sd);
u8 vpres = cx25840_read(client, 0x40e) & 0x20;
u8 mode;
int val = 0;
if (state->radio)
return 0;
vt->signal = vpres ? 0xffff : 0x0;
if (is_cx2583x(state))
return 0;
vt->capability |= V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 |
V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
mode = cx25840_read(client, 0x804);
/* get rxsubchans and audmode */
if ((mode & 0xf) == 1)
val |= V4L2_TUNER_SUB_STEREO;
else
val |= V4L2_TUNER_SUB_MONO;
if (mode == 2 || mode == 4)
val = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
if (mode & 0x10)
val |= V4L2_TUNER_SUB_SAP;
vt->rxsubchans = val;
vt->audmode = state->audmode;
return 0;
}
static int cx25840_s_tuner(struct v4l2_subdev *sd, const struct v4l2_tuner *vt)
{
struct cx25840_state *state = to_state(sd);
struct i2c_client *client = v4l2_get_subdevdata(sd);
if (state->radio || is_cx2583x(state))
return 0;
switch (vt->audmode) {
case V4L2_TUNER_MODE_MONO:
/*
* mono -> mono
* stereo -> mono
* bilingual -> lang1
*/
cx25840_and_or(client, 0x809, ~0xf, 0x00);
break;
case V4L2_TUNER_MODE_STEREO:
case V4L2_TUNER_MODE_LANG1:
/*
* mono -> mono
* stereo -> stereo
* bilingual -> lang1
*/
cx25840_and_or(client, 0x809, ~0xf, 0x04);
break;
case V4L2_TUNER_MODE_LANG1_LANG2:
/*
* mono -> mono
* stereo -> stereo
* bilingual -> lang1/lang2
*/
cx25840_and_or(client, 0x809, ~0xf, 0x07);
break;
case V4L2_TUNER_MODE_LANG2:
/*
* mono -> mono
* stereo -> stereo
* bilingual -> lang2
*/
cx25840_and_or(client, 0x809, ~0xf, 0x01);
break;
default:
return -EINVAL;
}
state->audmode = vt->audmode;
return 0;
}
static int cx25840_log_status(struct v4l2_subdev *sd)
{
struct cx25840_state *state = to_state(sd);
struct i2c_client *client = v4l2_get_subdevdata(sd);
log_video_status(client);
if (!is_cx2583x(state))
log_audio_status(client);
cx25840_ir_log_status(sd);
v4l2_ctrl_handler_log_status(&state->hdl, sd->name);
return 0;
}
static int cx23885_irq_handler(struct v4l2_subdev *sd, u32 status,
bool *handled)
{
struct cx25840_state *state = to_state(sd);
struct i2c_client *c = v4l2_get_subdevdata(sd);
u8 irq_stat, aud_stat, aud_en, ir_stat, ir_en;
u32 vid_stat, aud_mc_stat;
bool block_handled;
int ret = 0;
irq_stat = cx25840_read(c, CX23885_PIN_CTRL_IRQ_REG);
v4l_dbg(2, cx25840_debug, c, "AV Core IRQ status (entry): %s %s %s\n",
irq_stat & CX23885_PIN_CTRL_IRQ_IR_STAT ? "ir" : " ",
irq_stat & CX23885_PIN_CTRL_IRQ_AUD_STAT ? "aud" : " ",
irq_stat & CX23885_PIN_CTRL_IRQ_VID_STAT ? "vid" : " ");
if ((is_cx23885(state) || is_cx23887(state))) {
ir_stat = cx25840_read(c, CX25840_IR_STATS_REG);
ir_en = cx25840_read(c, CX25840_IR_IRQEN_REG);
v4l_dbg(2, cx25840_debug, c,
"AV Core ir IRQ status: %#04x disables: %#04x\n",
ir_stat, ir_en);
if (irq_stat & CX23885_PIN_CTRL_IRQ_IR_STAT) {
block_handled = false;
ret = cx25840_ir_irq_handler(sd,
status, &block_handled);
if (block_handled)
*handled = true;
}
}
aud_stat = cx25840_read(c, CX25840_AUD_INT_STAT_REG);
aud_en = cx25840_read(c, CX25840_AUD_INT_CTRL_REG);
v4l_dbg(2, cx25840_debug, c,
"AV Core audio IRQ status: %#04x disables: %#04x\n",
aud_stat, aud_en);
aud_mc_stat = cx25840_read4(c, CX23885_AUD_MC_INT_MASK_REG);
v4l_dbg(2, cx25840_debug, c,
"AV Core audio MC IRQ status: %#06x enables: %#06x\n",
aud_mc_stat >> CX23885_AUD_MC_INT_STAT_SHFT,
aud_mc_stat & CX23885_AUD_MC_INT_CTRL_BITS);
if (irq_stat & CX23885_PIN_CTRL_IRQ_AUD_STAT) {
if (aud_stat) {
cx25840_write(c, CX25840_AUD_INT_STAT_REG, aud_stat);
*handled = true;
}
}
vid_stat = cx25840_read4(c, CX25840_VID_INT_STAT_REG);
v4l_dbg(2, cx25840_debug, c,
"AV Core video IRQ status: %#06x disables: %#06x\n",
vid_stat & CX25840_VID_INT_STAT_BITS,
vid_stat >> CX25840_VID_INT_MASK_SHFT);
if (irq_stat & CX23885_PIN_CTRL_IRQ_VID_STAT) {
if (vid_stat & CX25840_VID_INT_STAT_BITS) {
cx25840_write4(c, CX25840_VID_INT_STAT_REG, vid_stat);
*handled = true;
}
}
irq_stat = cx25840_read(c, CX23885_PIN_CTRL_IRQ_REG);
v4l_dbg(2, cx25840_debug, c, "AV Core IRQ status (exit): %s %s %s\n",
irq_stat & CX23885_PIN_CTRL_IRQ_IR_STAT ? "ir" : " ",
irq_stat & CX23885_PIN_CTRL_IRQ_AUD_STAT ? "aud" : " ",
irq_stat & CX23885_PIN_CTRL_IRQ_VID_STAT ? "vid" : " ");
return ret;
}
static int cx25840_irq_handler(struct v4l2_subdev *sd, u32 status,
bool *handled)
{
struct cx25840_state *state = to_state(sd);
*handled = false;
/* Only support the CX2388[578] AV Core for now */
if (is_cx2388x(state))
return cx23885_irq_handler(sd, status, handled);
return -ENODEV;
}
/* ----------------------------------------------------------------------- */
#define DIF_PLL_FREQ_WORD (0x300)
#define DIF_BPF_COEFF01 (0x348)
#define DIF_BPF_COEFF23 (0x34c)
#define DIF_BPF_COEFF45 (0x350)
#define DIF_BPF_COEFF67 (0x354)
#define DIF_BPF_COEFF89 (0x358)
#define DIF_BPF_COEFF1011 (0x35c)
#define DIF_BPF_COEFF1213 (0x360)
#define DIF_BPF_COEFF1415 (0x364)
#define DIF_BPF_COEFF1617 (0x368)
#define DIF_BPF_COEFF1819 (0x36c)
#define DIF_BPF_COEFF2021 (0x370)
#define DIF_BPF_COEFF2223 (0x374)
#define DIF_BPF_COEFF2425 (0x378)
#define DIF_BPF_COEFF2627 (0x37c)
#define DIF_BPF_COEFF2829 (0x380)
#define DIF_BPF_COEFF3031 (0x384)
#define DIF_BPF_COEFF3233 (0x388)
#define DIF_BPF_COEFF3435 (0x38c)
#define DIF_BPF_COEFF36 (0x390)
static void cx23885_dif_setup(struct i2c_client *client, u32 ifHz)
{
u64 pll_freq;
u32 pll_freq_word;
v4l_dbg(1, cx25840_debug, client, "%s(%d)\n", __func__, ifHz);
/* Assuming TV */
/* Calculate the PLL frequency word based on the adjusted ifHz */
pll_freq = div_u64((u64)ifHz * 268435456, 50000000);
pll_freq_word = (u32)pll_freq;
cx25840_write4(client, DIF_PLL_FREQ_WORD, pll_freq_word);
/* Round down to the nearest 100KHz */
ifHz = (ifHz / 100000) * 100000;
if (ifHz < 3000000)
ifHz = 3000000;
if (ifHz > 16000000)
ifHz = 16000000;
v4l_dbg(1, cx25840_debug, client, "%s(%d) again\n", __func__, ifHz);
switch (ifHz) {
case 3000000:
cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002);
cx25840_write4(client, DIF_BPF_COEFF23, 0x00080012);
cx25840_write4(client, DIF_BPF_COEFF45, 0x001e0024);
cx25840_write4(client, DIF_BPF_COEFF67, 0x001bfff8);
cx25840_write4(client, DIF_BPF_COEFF89, 0xffb4ff50);
cx25840_write4(client, DIF_BPF_COEFF1011, 0xfed8fe68);
cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe24fe34);
cx25840_write4(client, DIF_BPF_COEFF1415, 0xfebaffc7);
cx25840_write4(client, DIF_BPF_COEFF1617, 0x014d031f);
cx25840_write4(client, DIF_BPF_COEFF1819, 0x04f0065d);
cx25840_write4(client, DIF_BPF_COEFF2021, 0x07010688);
cx25840_write4(client, DIF_BPF_COEFF2223, 0x04c901d6);
cx25840_write4(client, DIF_BPF_COEFF2425, 0xfe00f9d3);
cx25840_write4(client, DIF_BPF_COEFF2627, 0xf600f342);
cx25840_write4(client, DIF_BPF_COEFF2829, 0xf235f337);
cx25840_write4(client, DIF_BPF_COEFF3031, 0xf64efb22);
cx25840_write4(client, DIF_BPF_COEFF3233, 0x0105070f);
cx25840_write4(client, DIF_BPF_COEFF3435, 0x0c460fce);
cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
break;
case 3100000:
cx25840_write4(client, DIF_BPF_COEFF01, 0x00000001);
cx25840_write4(client, DIF_BPF_COEFF23, 0x00070012);
cx25840_write4(client, DIF_BPF_COEFF45, 0x00220032);
cx25840_write4(client, DIF_BPF_COEFF67, 0x00370026);
cx25840_write4(client, DIF_BPF_COEFF89, 0xfff0ff91);
cx25840_write4(client, DIF_BPF_COEFF1011, 0xff0efe7c);
cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe01fdcc);
cx25840_write4(client, DIF_BPF_COEFF1415, 0xfe0afedb);
cx25840_write4(client, DIF_BPF_COEFF1617, 0x00440224);
cx25840_write4(client, DIF_BPF_COEFF1819, 0x0434060c);
cx25840_write4(client, DIF_BPF_COEFF2021, 0x0738074e);
cx25840_write4(client, DIF_BPF_COEFF2223, 0x06090361);
cx25840_write4(client, DIF_BPF_COEFF2425, 0xff99fb39);
cx25840_write4(client, DIF_BPF_COEFF2627, 0xf6fef3b6);
cx25840_write4(client, DIF_BPF_COEFF2829, 0xf21af2a5);
cx25840_write4(client, DIF_BPF_COEFF3031, 0xf573fa33);
cx25840_write4(client, DIF_BPF_COEFF3233, 0x0034067d);
cx25840_write4(client, DIF_BPF_COEFF3435, 0x0bfb0fb9);
cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
break;
case 3200000:
cx25840_write4(client, DIF_BPF_COEFF01, 0x00000000);
cx25840_write4(client, DIF_BPF_COEFF23, 0x0004000e);
cx25840_write4(client, DIF_BPF_COEFF45, 0x00200038);
cx25840_write4(client, DIF_BPF_COEFF67, 0x004c004f);
cx25840_write4(client, DIF_BPF_COEFF89, 0x002fffdf);
cx25840_write4(client, DIF_BPF_COEFF1011, 0xff5cfeb6);
cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe0dfd92);
cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd7ffe03);
cx25840_write4(client, DIF_BPF_COEFF1617, 0xff36010a);
cx25840_write4(client, DIF_BPF_COEFF1819, 0x03410575);
cx25840_write4(client, DIF_BPF_COEFF2021, 0x072607d2);
cx25840_write4(client, DIF_BPF_COEFF2223, 0x071804d5);
cx25840_write4(client, DIF_BPF_COEFF2425, 0x0134fcb7);
cx25840_write4(client, DIF_BPF_COEFF2627, 0xf81ff451);
cx25840_write4(client, DIF_BPF_COEFF2829, 0xf223f22e);
cx25840_write4(client, DIF_BPF_COEFF3031, 0xf4a7f94b);
cx25840_write4(client, DIF_BPF_COEFF3233, 0xff6405e8);
cx25840_write4(client, DIF_BPF_COEFF3435, 0x0bae0fa4);
cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
break;
case 3300000:
cx25840_write4(client, DIF_BPF_COEFF01, 0x0000ffff);
cx25840_write4(client, DIF_BPF_COEFF23, 0x00000008);
cx25840_write4(client, DIF_BPF_COEFF45, 0x001a0036);
cx25840_write4(client, DIF_BPF_COEFF67, 0x0056006d);
cx25840_write4(client, DIF_BPF_COEFF89, 0x00670030);
cx25840_write4(client, DIF_BPF_COEFF1011, 0xffbdff10);
cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe46fd8d);
cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd25fd4f);
cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe35ffe0);
cx25840_write4(client, DIF_BPF_COEFF1819, 0x0224049f);
cx25840_write4(client, DIF_BPF_COEFF2021, 0x06c9080e);
cx25840_write4(client, DIF_BPF_COEFF2223, 0x07ef0627);
cx25840_write4(client, DIF_BPF_COEFF2425, 0x02c9fe45);
cx25840_write4(client, DIF_BPF_COEFF2627, 0xf961f513);
cx25840_write4(client, DIF_BPF_COEFF2829, 0xf250f1d2);
cx25840_write4(client, DIF_BPF_COEFF3031, 0xf3ecf869);
cx25840_write4(client, DIF_BPF_COEFF3233, 0xfe930552);
cx25840_write4(client, DIF_BPF_COEFF3435, 0x0b5f0f8f);
cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
break;
case 3400000:
cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffe);
cx25840_write4(client, DIF_BPF_COEFF23, 0xfffd0001);
cx25840_write4(client, DIF_BPF_COEFF45, 0x000f002c);
cx25840_write4(client, DIF_BPF_COEFF67, 0x0054007d);
cx25840_write4(client, DIF_BPF_COEFF89, 0x0093007c);
cx25840_write4(client, DIF_BPF_COEFF1011, 0x0024ff82);
cx25840_write4(client, DIF_BPF_COEFF1213, 0xfea6fdbb);
cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd03fcca);
cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd51feb9);
cx25840_write4(client, DIF_BPF_COEFF1819, 0x00eb0392);
cx25840_write4(client, DIF_BPF_COEFF2021, 0x06270802);
cx25840_write4(client, DIF_BPF_COEFF2223, 0x08880750);
cx25840_write4(client, DIF_BPF_COEFF2425, 0x044dffdb);
cx25840_write4(client, DIF_BPF_COEFF2627, 0xfabdf5f8);
cx25840_write4(client, DIF_BPF_COEFF2829, 0xf2a0f193);
cx25840_write4(client, DIF_BPF_COEFF3031, 0xf342f78f);
cx25840_write4(client, DIF_BPF_COEFF3233, 0xfdc404b9);
cx25840_write4(client, DIF_BPF_COEFF3435, 0x0b0e0f78);
cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
break;
case 3500000:
cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffd);
cx25840_write4(client, DIF_BPF_COEFF23, 0xfffafff9);
cx25840_write4(client, DIF_BPF_COEFF45, 0x0002001b);
cx25840_write4(client, DIF_BPF_COEFF67, 0x0046007d);
cx25840_write4(client, DIF_BPF_COEFF89, 0x00ad00ba);
cx25840_write4(client, DIF_BPF_COEFF1011, 0x00870000);
cx25840_write4(client, DIF_BPF_COEFF1213, 0xff26fe1a);
cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd1bfc7e);
cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc99fda4);
cx25840_write4(client, DIF_BPF_COEFF1819, 0xffa5025c);
cx25840_write4(client, DIF_BPF_COEFF2021, 0x054507ad);
cx25840_write4(client, DIF_BPF_COEFF2223, 0x08dd0847);
cx25840_write4(client, DIF_BPF_COEFF2425, 0x05b80172);
cx25840_write4(client, DIF_BPF_COEFF2627, 0xfc2ef6ff);
cx25840_write4(client, DIF_BPF_COEFF2829, 0xf313f170);
cx25840_write4(client, DIF_BPF_COEFF3031, 0xf2abf6bd);
cx25840_write4(client, DIF_BPF_COEFF3233, 0xfcf6041f);
cx25840_write4(client, DIF_BPF_COEFF3435, 0x0abc0f61);
cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
break;
case 3600000:
cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffd);
cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8fff3);
cx25840_write4(client, DIF_BPF_COEFF45, 0xfff50006);
cx25840_write4(client, DIF_BPF_COEFF67, 0x002f006c);
cx25840_write4(client, DIF_BPF_COEFF89, 0x00b200e3);
cx25840_write4(client, DIF_BPF_COEFF1011, 0x00dc007e);
cx25840_write4(client, DIF_BPF_COEFF1213, 0xffb9fea0);
cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd6bfc71);
cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc17fcb1);
cx25840_write4(client, DIF_BPF_COEFF1819, 0xfe65010b);
cx25840_write4(client, DIF_BPF_COEFF2021, 0x042d0713);
cx25840_write4(client, DIF_BPF_COEFF2223, 0x08ec0906);
cx25840_write4(client, DIF_BPF_COEFF2425, 0x07020302);
cx25840_write4(client, DIF_BPF_COEFF2627, 0xfdaff823);
cx25840_write4(client, DIF_BPF_COEFF2829, 0xf3a7f16a);
cx25840_write4(client, DIF_BPF_COEFF3031, 0xf228f5f5);
cx25840_write4(client, DIF_BPF_COEFF3233, 0xfc2a0384);
cx25840_write4(client, DIF_BPF_COEFF3435, 0x0a670f4a);
cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
break;
case 3700000:
cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd);
cx25840_write4(client, DIF_BPF_COEFF23, 0xfff7ffef);
cx25840_write4(client, DIF_BPF_COEFF45, 0xffe9fff1);
cx25840_write4(client, DIF_BPF_COEFF67, 0x0010004d);
cx25840_write4(client, DIF_BPF_COEFF89, 0x00a100f2);
cx25840_write4(client, DIF_BPF_COEFF1011, 0x011a00f0);
cx25840_write4(client, DIF_BPF_COEFF1213, 0x0053ff44);
cx25840_write4(client, DIF_BPF_COEFF1415, 0xfdedfca2);
cx25840_write4(client, DIF_BPF_COEFF1617, 0xfbd3fbef);
cx25840_write4(client, DIF_BPF_COEFF1819, 0xfd39ffae);
cx25840_write4(client, DIF_BPF_COEFF2021, 0x02ea0638);
cx25840_write4(client, DIF_BPF_COEFF2223, 0x08b50987);
cx25840_write4(client, DIF_BPF_COEFF2425, 0x08230483);
cx25840_write4(client, DIF_BPF_COEFF2627, 0xff39f960);
cx25840_write4(client, DIF_BPF_COEFF2829, 0xf45bf180);
cx25840_write4(client, DIF_BPF_COEFF3031, 0xf1b8f537);
cx25840_write4(client, DIF_BPF_COEFF3233, 0xfb6102e7);
cx25840_write4(client, DIF_BPF_COEFF3435, 0x0a110f32);
cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
break;
case 3800000:
cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffe);
cx25840_write4(client, DIF_BPF_COEFF23, 0xfff9ffee);
cx25840_write4(client, DIF_BPF_COEFF45, 0xffe1ffdd);
cx25840_write4(client, DIF_BPF_COEFF67, 0xfff00024);
cx25840_write4(client, DIF_BPF_COEFF89, 0x007c00e5);
cx25840_write4(client, DIF_BPF_COEFF1011, 0x013a014a);