// 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 0 x410
#define CX25840_VID_INT_STAT_BITS 0 x0000ffff
#define CX25840_VID_INT_MASK_BITS 0 xffff0000
#define CX25840_VID_INT_MASK_SHFT 16
#define CX25840_VID_INT_MASK_REG 0 x412
#define CX23885_AUD_MC_INT_MASK_REG 0 x80c
#define CX23885_AUD_MC_INT_STAT_BITS 0 xffff0000
#define CX23885_AUD_MC_INT_CTRL_BITS 0 x0000ffff
#define CX23885_AUD_MC_INT_STAT_SHFT 16
#define CX25840_AUD_INT_CTRL_REG 0 x812
#define CX25840_AUD_INT_STAT_REG 0 x813
#define CX23885_PIN_CTRL_IRQ_REG 0 x123
#define CX23885_PIN_CTRL_IRQ_IR_STAT 0 x40
#define CX23885_PIN_CTRL_IRQ_AUD_STAT 0 x20
#define CX23885_PIN_CTRL_IRQ_VID_STAT 0 x10
#define CX25840_IR_STATS_REG 0 x210
#define CX25840_IR_IRQEN_REG 0 x214
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 & 0 xff;
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 & 0 xff;
buffer[2 ] = value & 0 xff;
buffer[3 ] = (value >> 8 ) & 0 xff;
buffer[4 ] = (value >> 16 ) & 0 xff;
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 & 0 xff;
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 & 0 xff;
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, 0 x120);
gpio_oe = cx25840_read(client, 0 x160);
gpio_data = cx25840_read(client, 0 x164);
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 &= ~(0 x1 << 25 );
} else {
/* IRQ_N */
if (p[i].flags &
(BIT(V4L2_SUBDEV_IO_PIN_DISABLE) |
BIT(V4L2_SUBDEV_IO_PIN_INPUT))) {
pin_ctrl &= ~(0 x1 << 25 );
} else {
pin_ctrl |= (0 x1 << 25 );
}
if (p[i].flags &
BIT(V4L2_SUBDEV_IO_PIN_ACTIVE_LOW)) {
pin_ctrl &= ~(0 x1 << 24 );
} else {
pin_ctrl |= (0 x1 << 24 );
}
}
break ;
case CX23885_PIN_IR_RX_GPIO19:
if (p[i].function != CX23885_PAD_GPIO19) {
/* IR_RX */
gpio_oe |= (0 x1 << 0 );
pin_ctrl &= ~(0 x3 << 18 );
pin_ctrl |= (strength << 18 );
} else {
/* GPIO19 */
gpio_oe &= ~(0 x1 << 0 );
if (p[i].flags & BIT(V4L2_SUBDEV_IO_PIN_SET_VALUE)) {
gpio_data &= ~(0 x1 << 0 );
gpio_data |= ((p[i].value & 0 x1) << 0 );
}
pin_ctrl &= ~(0 x3 << 12 );
pin_ctrl |= (strength << 12 );
}
break ;
case CX23885_PIN_IR_TX_GPIO20:
if (p[i].function != CX23885_PAD_GPIO20) {
/* IR_TX */
gpio_oe |= (0 x1 << 1 );
if (p[i].flags & BIT(V4L2_SUBDEV_IO_PIN_DISABLE))
pin_ctrl &= ~(0 x1 << 10 );
else
pin_ctrl |= (0 x1 << 10 );
pin_ctrl &= ~(0 x3 << 18 );
pin_ctrl |= (strength << 18 );
} else {
/* GPIO20 */
gpio_oe &= ~(0 x1 << 1 );
if (p[i].flags & BIT(V4L2_SUBDEV_IO_PIN_SET_VALUE)) {
gpio_data &= ~(0 x1 << 1 );
gpio_data |= ((p[i].value & 0 x1) << 1 );
}
pin_ctrl &= ~(0 x3 << 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 |= (0 x1 << 2 );
pin_ctrl &= ~(0 x3 << 22 );
pin_ctrl |= (strength << 22 );
} else {
/* GPIO21 */
gpio_oe &= ~(0 x1 << 2 );
if (p[i].flags & BIT(V4L2_SUBDEV_IO_PIN_SET_VALUE)) {
gpio_data &= ~(0 x1 << 2 );
gpio_data |= ((p[i].value & 0 x1) << 2 );
}
pin_ctrl &= ~(0 x3 << 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 |= (0 x1 << 3 );
pin_ctrl &= ~(0 x3 << 22 );
pin_ctrl |= (strength << 22 );
} else {
/* GPIO22 */
gpio_oe &= ~(0 x1 << 3 );
if (p[i].flags & BIT(V4L2_SUBDEV_IO_PIN_SET_VALUE)) {
gpio_data &= ~(0 x1 << 3 );
gpio_data |= ((p[i].value & 0 x1) << 3 );
}
pin_ctrl &= ~(0 x3 << 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 |= (0 x1 << 4 );
pin_ctrl &= ~(0 x3 << 22 );
pin_ctrl |= (strength << 22 );
} else {
/* GPIO23 */
gpio_oe &= ~(0 x1 << 4 );
if (p[i].flags & BIT(V4L2_SUBDEV_IO_PIN_SET_VALUE)) {
gpio_data &= ~(0 x1 << 4 );
gpio_data |= ((p[i].value & 0 x1) << 4 );
}
pin_ctrl &= ~(0 x3 << 12 );
pin_ctrl |= (strength << 12 );
}
break ;
}
}
cx25840_write(client, 0 x164, gpio_data);
cx25840_write(client, 0 x160, gpio_oe);
cx25840_write4(client, 0 x120, 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, 0 x114 + i);
for (i = 0 ; i < 10 ; i++)
pinconf[i] = cx25840_read(client, 0 x11c + i);
voutctrl4 = cx25840_read(client, 0 x407);
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 ] &= 0 xf0;
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 ] &= 0 xf0;
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, 0 x407, voutctrl4);
for (i = 0 ; i < 6 ; i++)
cx25840_write(client, 0 x114 + i, pinctrl[i]);
for (i = 0 ; i < 10 ; i++)
cx25840_write(client, 0 x11c + 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, 0 x159, 0 x23);
cx25840_write(client, 0 x15a, 0 x87);
cx25840_write(client, 0 x15b, 0 x06);
udelay(10 );
cx25840_write(client, 0 x159, 0 xe1);
udelay(10 );
cx25840_write(client, 0 x15a, 0 x86);
cx25840_write(client, 0 x159, 0 xe0);
cx25840_write(client, 0 x159, 0 xe1);
cx25840_write(client, 0 x15b, 0 x10);
}
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, 0 x15d, 0 xe3);
cx25840_write(client, 0 x15e, 0 x86);
cx25840_write(client, 0 x15f, 0 x06);
udelay(10 );
cx25840_write(client, 0 x15d, 0 xe1);
cx25840_write(client, 0 x15d, 0 xe0);
cx25840_write(client, 0 x15d, 0 xe1);
}
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, 0 x000, ~0 x01, 0 x01);
cx25840_and_or(client, 0 x000, ~0 x01, 0 x00);
/* 3a. */
cx25840_and_or(client, 0 x15a, ~0 x70, 0 x00);
/* 3b. */
cx25840_and_or(client, 0 x15b, ~0 x1e, 0 x06);
/* 3c. */
cx25840_and_or(client, 0 x159, ~0 x02, 0 x02);
/* 3d. */
udelay(10 );
/* 3e. */
cx25840_and_or(client, 0 x159, ~0 x02, 0 x00);
/* 3f. */
cx25840_and_or(client, 0 x159, ~0 xc0, 0 xc0);
/* 3g. */
cx25840_and_or(client, 0 x159, ~0 x01, 0 x00);
cx25840_and_or(client, 0 x159, ~0 x01, 0 x01);
/* 3h. */
cx25840_and_or(client, 0 x15b, ~0 x1e, 0 x10);
}
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, 0 x404 + 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, 0 x404 + 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, 0 x803, ~0 x10, 0 x00);
/*
* The default of this register should be 4, but I get 0 instead.
* Set this register to 4 manually.
*/
cx25840_write(client, 0 x000, 0 x04);
/* 3. */
init_dll1(client);
init_dll2(client);
cx25840_write(client, 0 x136, 0 x0a);
/* 4. */
cx25840_write(client, 0 x13c, 0 x01);
cx25840_write(client, 0 x13c, 0 x00);
/* 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, 0 x115, 0 x8c);
cx25840_write(client, 0 x116, 0 x07);
cx25840_write(client, 0 x118, 0 x02);
/* 7. */
cx25840_write(client, 0 x4a5, 0 x80);
cx25840_write(client, 0 x4a5, 0 x00);
cx25840_write(client, 0 x402, 0 x00);
/* 8. */
cx25840_and_or(client, 0 x401, ~0 x18, 0 );
cx25840_and_or(client, 0 x4a2, ~0 x10, 0 x10);
/* steps 8c and 8d are done in change_input() */
/* 10. */
cx25840_write(client, 0 x8d3, 0 x1f);
cx25840_write(client, 0 x8e3, 0 x03);
cx25840_std_setup(client);
/* trial and error says these are needed to get audio */
cx25840_write(client, 0 x914, 0 xa0);
cx25840_write(client, 0 x918, 0 xa0);
cx25840_write(client, 0 x919, 0 x01);
/* stereo preferred */
cx25840_write(client, 0 x809, 0 x04);
/* AC97 shift */
cx25840_write(client, 0 x8cf, 0 x0f);
/* (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, 0 x803, ~0 x10, 0 x10);
}
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, 0 x000, 0 );
/* Internal Reset */
cx25840_and_or(client, 0 x102, ~0 x01, 0 x01);
cx25840_and_or(client, 0 x102, ~0 x01, 0 x00);
/* Stop microcontroller */
cx25840_and_or(client, 0 x803, ~0 x10, 0 x00);
/* DIF in reset? */
cx25840_write(client, 0 x398, 0 );
/*
* Trust the default xtal, no division
* '885: 28.636363... MHz
* '887: 25.000000 MHz
* '888: 50.000000 MHz
*/
cx25840_write(client, 0 x2, 0 x76);
/* Power up all the PLL's and DLL */
cx25840_write(client, 0 x1, 0 x40);
/* 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, 0 x2, 0 x71);
}
cx25840_write4(client, 0 x11c, 0 x01d1744c);
cx25840_write4(client, 0 x118, 0 x00000416);
cx25840_write4(client, 0 x404, 0 x0010253e);
cx25840_write4(client, 0 x42c, 0 x42600000);
cx25840_write4(client, 0 x44c, 0 x161f1000);
break ;
case CX23887_AV:
/*
* 25.0 MHz * (0x16 + 0x1d1744c/0x2000000)/4 = 5 * 28.636363 MHz
* 572.73 MHz before post divide
*/
cx25840_write4(client, 0 x11c, 0 x01d1744c);
cx25840_write4(client, 0 x118, 0 x00000416);
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, 0 x11c, 0 x00000000);
cx25840_write4(client, 0 x118, 0 x00000414);
break ;
}
/* Disable DIF bypass */
cx25840_write4(client, 0 x33c, 0 x00000001);
/* DIF Src phase inc */
cx25840_write4(client, 0 x340, 0 x0df7df83);
/*
* 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, 0 x10c, 0 x01b6db7b);
cx25840_write4(client, 0 x108, 0 x00000512);
} else {
/* 888/HVR1250 or 50MHz xtal */
cx25840_write4(client, 0 x10c, 0 x13333333);
cx25840_write4(client, 0 x108, 0 x00000515);
}
break ;
default :
cx25840_write4(client, 0 x10c, 0 x002be2c9);
cx25840_write4(client, 0 x108, 0 x0000040f);
}
/* Luma */
cx25840_write4(client, 0 x414, 0 x00107d12);
/* Chroma */
if (is_cx23888(state))
cx25840_write4(client, 0 x418, 0 x1d008282);
else
cx25840_write4(client, 0 x420, 0 x3d008282);
/*
* 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, 0 x114, 0 x017dbf48);
cx25840_write4(client, 0 x110, 0 x000a030e);
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, 0 x114, 0 x017dbf48);
cx25840_write4(client, 0 x110, 0 x000a030e);
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, 0 x114, 0 x01bf0c9e);
cx25840_write4(client, 0 x110, 0 x000a030c);
break ;
}
/* ADC2 input select */
cx25840_write(client, 0 x102, 0 x10);
/* VIN1 & VIN5 */
cx25840_write(client, 0 x103, 0 x11);
/* Enable format auto detect */
cx25840_write(client, 0 x400, 0 );
/* Fast subchroma lock */
/* White crush, Chroma AGC & Chroma Killer enabled */
cx25840_write(client, 0 x401, 0 xe8);
/* Select AFE clock pad output source */
cx25840_write(client, 0 x144, 0 x05);
/* 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, 0 x160, 0 x1d);
cx25840_write(client, 0 x164, 0 x00);
/*
* 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, 0 x803, ~0 x10, 0 x10);
/* Disable and clear video interrupts - we don't use them */
cx25840_write4(client, CX25840_VID_INT_STAT_REG, 0 xffffffff);
/* Disable and clear audio interrupts - we don't use them */
cx25840_write(client, CX25840_AUD_INT_CTRL_REG, 0 xff);
cx25840_write(client, CX25840_AUD_INT_STAT_REG, 0 xff);
/* 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, 0 x404, 0 x0010253e);
/* CC on - VBI_LINE_CTRL3, FLD_VBI_MD_LINE12 */
cx25840_write(client, state->vbi_regs_offset + 0 x42f, 0 x66);
/* HVR-1250 / HVR1850 DIF related */
/* Power everything up */
cx25840_write4(client, 0 x130, 0 x0);
/* SRC_COMB_CFG */
if (is_cx23888(state))
cx25840_write4(client, 0 x454, 0 x6628021F);
else
cx25840_write4(client, 0 x478, 0 x6628021F);
/* AFE_CLK_OUT_CTRL - Select the clock output source as output */
cx25840_write4(client, 0 x144, 0 x5);
/* I2C_OUT_CTL - I2S output configuration as
* Master, Sony, Left justified, left sample on WS=1
*/
cx25840_write4(client, 0 x918, 0 x1a0);
/* AFE_DIAG_CTRL1 */
cx25840_write4(client, 0 x134, 0 x000a1800);
/* AFE_DIAG_CTRL3 - Inverted Polarity for Audio and Video */
cx25840_write4(client, 0 x13c, 0 x00310000);
}
/* ----------------------------------------------------------------------- */
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, 0 x102, ~0 x01, 0 x01);
cx25840_and_or(client, 0 x102, ~0 x01, 0 x00);
/* Stop microcontroller */
cx25840_and_or(client, 0 x803, ~0 x10, 0 x00);
/* DIF in reset? */
cx25840_write(client, 0 x398, 0 );
/* Trust the default xtal, no division */
/* This changes for the cx23888 products */
cx25840_write(client, 0 x2, 0 x76);
/* Bring down the regulator for AUX clk */
cx25840_write(client, 0 x1, 0 x40);
/* Disable DIF bypass */
cx25840_write4(client, 0 x33c, 0 x00000001);
/* DIF Src phase inc */
cx25840_write4(client, 0 x340, 0 x0df7df83);
/* Luma */
cx25840_write4(client, 0 x414, 0 x00107d12);
/* Chroma */
cx25840_write4(client, 0 x420, 0 x3d008282);
/* ADC2 input select */
cx25840_write(client, 0 x102, 0 x10);
/* VIN1 & VIN5 */
cx25840_write(client, 0 x103, 0 x11);
/* Enable format auto detect */
cx25840_write(client, 0 x400, 0 );
/* Fast subchroma lock */
/* White crush, Chroma AGC & Chroma Killer enabled */
cx25840_write(client, 0 x401, 0 xe8);
/*
* 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, 0 x803, ~0 x10, 0 x10);
/* CC raw enable */
cx25840_write(client, 0 x404, 0 x0b);
/* CC on */
cx25840_write(client, 0 x42f, 0 x66);
cx25840_write4(client, 0 x474, 0 x1e1e601a);
}
/* ----------------------------------------------------------------------- */
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, 0 x49f, 0 x11);
else
cx25840_write(client, 0 x49f, 0 x14);
/* 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 = 0 x21f;
luma_lpf = 2 ;
if (std & V4L2_STD_SECAM) {
uv_lpf = 0 ;
comb = 0 ;
sc = 0 x0a425f;
} else if (std == V4L2_STD_PAL_Nc) {
if (state->generic_mode) {
burst = 95 ;
luma_lpf = 1 ;
}
uv_lpf = 1 ;
comb = 0 x20;
sc = 556453 ;
} else {
uv_lpf = 1 ;
comb = 0 x20;
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 = 0 x21f;
if (std == V4L2_STD_PAL_60) {
if (!state->generic_mode) {
vblank = 26 ;
vblank656 = 26 ;
burst = 0 x5b;
} else {
burst = 0 x59;
}
luma_lpf = 2 ;
comb = 0 x20;
sc = 688739 ;
} else if (std == V4L2_STD_PAL_M) {
vblank = 20 ;
vblank656 = 24 ;
burst = 0 x61;
comb = 0 x20;
sc = 555452 ;
} else {
if (!state->generic_mode) {
vblank = 26 ;
vblank656 = 26 ;
}
burst = 0 x5b;
comb = 0 x66;
sc = 556063 ;
}
}
/* DEBUG: Displays configured PLL frequency */
if (!is_cx231xx(state)) {
pll_int = cx25840_read(client, 0 x108);
pll_frac = cx25840_read4(client, 0 x10c) & 0 x1ffffff;
pll_post = cx25840_read(client, 0 x109);
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 = (28636363 L * ((((u64)pll_int) << 25 L) + pll_frac)) >> 25 L;
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) >> 24 L;
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, 0 x470, hblank);
cx25840_write(client, 0 x471,
(((hblank >> 8 ) & 0 x3) | (hactive << 4 )) & 0 xff);
cx25840_write(client, 0 x472, hactive >> 4 );
/* Sets burst gate delay */
cx25840_write(client, 0 x473, burst);
/* Sets vertical blanking delay and active duration */
cx25840_write(client, 0 x474, vblank);
cx25840_write(client, 0 x475,
(((vblank >> 8 ) & 0 x3) | (vactive << 4 )) & 0 xff);
cx25840_write(client, 0 x476, vactive >> 4 );
cx25840_write(client, 0 x477, vblank656);
/* Sets src decimation rate */
cx25840_write(client, 0 x478, src_decimation & 0 xff);
cx25840_write(client, 0 x479, (src_decimation >> 8 ) & 0 xff);
/* Sets Luma and UV Low pass filters */
cx25840_write(client, 0 x47a, luma_lpf << 6 | ((uv_lpf << 4 ) & 0 x30));
/* Enables comb filters */
cx25840_write(client, 0 x47b, comb);
/* Sets SC Step*/
cx25840_write(client, 0 x47c, sc);
cx25840_write(client, 0 x47d, (sc >> 8 ) & 0 xff);
cx25840_write(client, 0 x47e, (sc >> 16 ) & 0 xff);
/* Sets VBI parameters */
if (std & V4L2_STD_625_50) {
cx25840_write(client, 0 x47f, 0 x01);
state->vbi_line_offset = 5 ;
} else {
cx25840_write(client, 0 x47f, 0 x00);
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, 0 x402, 0 );
} else {
cx25840_write(client, 0 x402, 0 x04);
cx25840_write(client, 0 x49f,
(std & V4L2_STD_NTSC) ? 0 x14 : 0 x11);
}
cx25840_and_or(client, 0 x401, ~0 x60, 0 );
cx25840_and_or(client, 0 x401, ~0 x60, 0 x60);
/* Don't write into audio registers on cx2583x chips */
if (is_cx2583x(state))
return ;
cx25840_and_or(client, 0 x810, ~0 x01, 1 );
if (state->radio) {
cx25840_write(client, 0 x808, 0 xf9);
cx25840_write(client, 0 x80b, 0 x00);
} 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, 0 x808, hw_fix ? 0 x2f : 0 xf7);
} else if (std == V4L2_STD_NTSC_M_KR) {
/* South Korea uses A2 audio standard */
cx25840_write(client, 0 x808, hw_fix ? 0 x3f : 0 xf8);
} else {
/* Others use the BTSC audio standard */
cx25840_write(client, 0 x808, hw_fix ? 0 x1f : 0 xf6);
}
cx25840_write(client, 0 x80b, 0 x00);
} else if (std & V4L2_STD_PAL) {
/* Autodetect audio standard and audio system */
cx25840_write(client, 0 x808, 0 xff);
/*
* 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, 0 x80b, 0 x00);
} else if (std & V4L2_STD_SECAM) {
/* Autodetect audio standard and audio system */
cx25840_write(client, 0 x808, 0 xff);
/*
* 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, 0 x80b, 0 x00);
} 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, 0 x80b, 0 x08);
} else {
/* 6.5 MHz carrier to be autodetected */
cx25840_write(client, 0 x80b, 0 x10);
}
}
cx25840_and_or(client, 0 x810, ~0 x01, 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 & 0 xf0;
int chroma = vid_input & 0 xf00;
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 & 0 xff;
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 = 0 xf0 + (vid_input - CX25840_COMPOSITE1);
} else {
if ((vid_input & ~0 xff0) ||
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 = 0 xf0 + ((luma - CX25840_SVIDEO_LUMA1) >> 4 );
if (chroma >= CX25840_SVIDEO_CHROMA7) {
reg &= 0 x3f;
reg |= (chroma - CX25840_SVIDEO_CHROMA7) >> 2 ;
} else {
reg &= 0 xcf;
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 &= ~0 x30;
break ;
case CX25840_AUDIO5:
reg &= ~0 x30;
reg |= 0 x10;
break ;
case CX25840_AUDIO6:
reg &= ~0 x30;
reg |= 0 x20;
break ;
case CX25840_AUDIO7:
reg &= ~0 xc0;
break ;
case CX25840_AUDIO8:
reg &= ~0 xc0;
reg |= 0 x40;
break ;
default :
v4l_err(client, "0x%04x is not a valid audio input!\n" ,
aud_input);
return -EINVAL;
}
}
cx25840_write(client, 0 x103, reg);
/* Set INPUT_MODE to Composite, S-Video or Component */
if (is_component)
cx25840_and_or(client, 0 x401, ~0 x6, 0 x6);
else
cx25840_and_or(client, 0 x401, ~0 x6, is_composite ? 0 : 0 x02);
if (is_cx2388x(state)) {
/* Enable or disable the DIF for tuner use */
if (is_dif) {
cx25840_and_or(client, 0 x102, ~0 x80, 0 x80);
/* Set of defaults for NTSC and PAL */
cx25840_write4(client, 0 x31c, 0 xc2262600);
cx25840_write4(client, 0 x320, 0 xc2262600);
/* 18271 IF - Nobody else yet uses a different
* tuner with the DIF, so these are reasonable
* assumptions (HVR1250 and HVR1850 specific).
*/
cx25840_write4(client, 0 x318, 0 xda262600);
cx25840_write4(client, 0 x33c, 0 x2a24c800);
cx25840_write4(client, 0 x104, 0 x0704dd00);
} else {
cx25840_write4(client, 0 x300, 0 x015c28f5);
cx25840_and_or(client, 0 x102, ~0 x80, 0 );
cx25840_write4(client, 0 x340, 0 xdf7df83);
cx25840_write4(client, 0 x104, 0 x0704dd80);
cx25840_write4(client, 0 x314, 0 x22400600);
cx25840_write4(client, 0 x318, 0 x40002600);
cx25840_write4(client, 0 x324, 0 x40002600);
cx25840_write4(client, 0 x32c, 0 x0250e620);
cx25840_write4(client, 0 x39c, 0 x01FF0B00);
cx25840_write4(client, 0 x410, 0 xffff0dbf);
cx25840_write4(client, 0 x414, 0 x00137d03);
if (is_cx23888(state)) {
/* 888 MISC_TIM_CTRL */
cx25840_write4(client, 0 x42c, 0 x42600000);
/* 888 FIELD_COUNT */
cx25840_write4(client, 0 x430, 0 x0000039b);
/* 888 VSCALE_CTRL */
cx25840_write4(client, 0 x438, 0 x00000000);
/* 888 DFE_CTRL1 */
cx25840_write4(client, 0 x440, 0 xF8E3E824);
/* 888 DFE_CTRL2 */
cx25840_write4(client, 0 x444, 0 x401040dc);
/* 888 DFE_CTRL3 */
cx25840_write4(client, 0 x448, 0 xcd3f02a0);
/* 888 PLL_CTRL */
cx25840_write4(client, 0 x44c, 0 x161f1000);
/* 888 HTL_CTRL */
cx25840_write4(client, 0 x450, 0 x00000802);
}
cx25840_write4(client, 0 x91c, 0 x01000000);
cx25840_write4(client, 0 x8e0, 0 x03063870);
cx25840_write4(client, 0 x8d4, 0 x7FFF0024);
cx25840_write4(client, 0 x8d0, 0 x00063073);
cx25840_write4(client, 0 x8c8, 0 x00010000);
cx25840_write4(client, 0 x8cc, 0 x00080023);
/* DIF BYPASS */
cx25840_write4(client, 0 x33c, 0 x2a04c800);
}
/* Reset the DIF */
cx25840_write4(client, 0 x398, 0 );
}
if (!is_cx2388x(state) && !is_cx231xx(state)) {
/* Set CH_SEL_ADC2 to 1 if input comes from CH3 */
cx25840_and_or(client, 0 x102, ~0 x2, (reg & 0 x80) == 0 ? 2 : 0 );
/* Set DUAL_MODE_ADC2 to 1 if input comes from both CH2&CH3 */
if ((reg & 0 xc0) != 0 xc0 && (reg & 0 x30) != 0 x30)
cx25840_and_or(client, 0 x102, ~0 x4, 4 );
else
cx25840_and_or(client, 0 x102, ~0 x4, 0 );
} else {
/* Set DUAL_MODE_ADC2 to 1 if component*/
cx25840_and_or(client, 0 x102, ~0 x4, is_component ? 0 x4 : 0 x0);
if (is_composite) {
/* ADC2 input select channel 2 */
cx25840_and_or(client, 0 x102, ~0 x2, 0 );
} else if (!is_component) {
/* S-Video */
if (chroma >= CX25840_SVIDEO_CHROMA7) {
/* ADC2 input select channel 3 */
cx25840_and_or(client, 0 x102, ~0 x2, 2 );
} else {
/* ADC2 input select channel 2 */
cx25840_and_or(client, 0 x102, ~0 x2, 0 );
}
}
/* cx23885 / SVIDEO */
if (is_cx2388x(state) && is_svideo) {
#define AFE_CTRL (0 x104)
#define MODE_CTRL (0 x400)
cx25840_and_or(client, 0 x102, ~0 x2, 0 x2);
val = cx25840_read4(client, MODE_CTRL);
val &= 0 xFFFFF9FF;
/* YC */
val |= 0 x00000200;
val &= ~0 x2000;
cx25840_write4(client, MODE_CTRL, val);
val = cx25840_read4(client, AFE_CTRL);
/* Chroma in select */
val |= 0 x00001000;
val &= 0 xfffffe7f;
/* 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, 0 x102, ~0 x2, 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, 0 x124, 0 x03);
/* Select AFE clock pad output source */
cx25840_write(client, 0 x144, 0 x05);
/* I2S_IN_CTL: I2S_IN_SONY_MODE, LEFT SAMPLE on WS=1 */
cx25840_write(client, 0 x914, 0 xa0);
/* I2S_OUT_CTL:
* I2S_IN_SONY_MODE, LEFT SAMPLE on WS=1
* I2S_OUT_MASTER_MODE = Master
*/
cx25840_write(client, 0 x918, 0 xa0);
cx25840_write(client, 0 x919, 0 x01);
} else if (is_cx231xx(state)) {
/* Audio channel 1 src : Parallel 1 */
cx25840_write(client, 0 x124, 0 x03);
/* I2S_IN_CTL: I2S_IN_SONY_MODE, LEFT SAMPLE on WS=1 */
cx25840_write(client, 0 x914, 0 xa0);
/* I2S_OUT_CTL:
* I2S_IN_SONY_MODE, LEFT SAMPLE on WS=1
* I2S_OUT_MASTER_MODE = Master
*/
cx25840_write(client, 0 x918, 0 xa0);
cx25840_write(client, 0 x919, 0 x01);
}
if (is_cx2388x(state) &&
((aud_input == CX25840_AUDIO7) || (aud_input == CX25840_AUDIO6))) {
/* Configure audio from LR1 or LR2 input */
cx25840_write4(client, 0 x910, 0 );
cx25840_write4(client, 0 x8d0, 0 x63073);
} else if (is_cx2388x(state) && (aud_input == CX25840_AUDIO8)) {
/* Configure audio from tuner/sif input */
cx25840_write4(client, 0 x910, 0 x12b000c9);
cx25840_write4(client, 0 x8d0, 0 x1f063870);
}
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, 0 x124, 0 x100);
if (!is_dif) {
/*
* Stop microcontroller if we don't need it
* to avoid audio popping on svideo/composite use.
*/
cx25840_and_or(client, 0 x803, ~0 x10, 0 x00);
}
}
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 = 0 x2;
} else if (state->std == V4L2_STD_NTSC_443) {
fmt = 0 x3;
} else if (state->std == V4L2_STD_PAL_M) {
pal_m = 1 ;
fmt = 0 x5;
} else if (state->std == V4L2_STD_PAL_N) {
fmt = 0 x6;
} else if (state->std == V4L2_STD_PAL_Nc) {
fmt = 0 x7;
} else if (state->std == V4L2_STD_PAL_60) {
fmt = 0 x8;
} else {
/* Then, test against generic ones */
if (state->std & V4L2_STD_NTSC)
fmt = 0 x1;
else if (state->std & V4L2_STD_PAL)
fmt = 0 x4;
else if (state->std & V4L2_STD_SECAM)
fmt = 0 xc;
}
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, 0 x400, ~0 xf, 1 );
/* Turn off LCOMB */
cx25840_and_or(client, 0 x47b, ~6 , 0 );
}
cx25840_and_or(client, 0 x400, ~0 xf, fmt);
cx25840_and_or(client, 0 x403, ~0 x3, 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, 0 x414, ctrl->val - 128 );
break ;
case V4L2_CID_CONTRAST:
cx25840_write(client, 0 x415, ctrl->val << 1 );
break ;
case V4L2_CID_SATURATION:
if (is_cx23888(state)) {
cx25840_write(client, 0 x418, ctrl->val << 1 );
cx25840_write(client, 0 x419, ctrl->val << 1 );
} else {
cx25840_write(client, 0 x420, ctrl->val << 1 );
cx25840_write(client, 0 x421, ctrl->val << 1 );
}
break ;
case V4L2_CID_HUE:
if (is_cx23888(state))
cx25840_write(client, 0 x41a, ctrl->val);
else
cx25840_write(client, 0 x422, 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, 0 x42a) & 0 x3f) << 4 ;
v_src |= (cx25840_read(client, 0 x429) & 0 xf0) >> 4 ;
} else {
v_src = (cx25840_read(client, 0 x476) & 0 x3f) << 4 ;
v_src |= (cx25840_read(client, 0 x475) & 0 xf0) >> 4 ;
}
if (is_cx23888(state)) {
h_src = (cx25840_read(client, 0 x426) & 0 x3f) << 4 ;
h_src |= (cx25840_read(client, 0 x425) & 0 xf0) >> 4 ;
} else {
h_src = (cx25840_read(client, 0 x472) & 0 x3f) << 4 ;
h_src |= (cx25840_read(client, 0 x471) & 0 xf0) >> 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 &= 0 x1fff;
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, 0 x434, hsc | (1 << 24 ));
/* VSCALE=vsc VS_INTRLACE=1 VFILT=filter */
cx25840_write4(client, 0 x438, vsc | (1 << 19 ) | (filter << 16 ));
} else {
cx25840_write(client, 0 x418, hsc & 0 xff);
cx25840_write(client, 0 x419, (hsc >> 8 ) & 0 xff);
cx25840_write(client, 0 x41a, hsc >> 16 );
/* VSCALE=vsc */
cx25840_write(client, 0 x41c, vsc & 0 xff);
cx25840_write(client, 0 x41d, vsc >> 8 );
/* VS_INTRLACE=1 VFILT=filter */
cx25840_write(client, 0 x41e, 0 x8 | 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, 0 x400) & 0 xf;
u8 gen_stat1 = cx25840_read(client, 0 x40d);
u8 gen_stat2 = cx25840_read(client, 0 x40e);
int vid_input = state->vid_input;
v4l_info(client, "Video signal: %spresent\n" ,
(gen_stat2 & 0 x20) ? "" : "not " );
v4l_info(client, "Detected format: %s\n" ,
fmt_strs[gen_stat1 & 0 xf]);
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 & 0 xf0) >> 4 , (vid_input & 0 xf00) >> 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, 0 x803);
u8 mod_det_stat0 = cx25840_read(client, 0 x804);
u8 mod_det_stat1 = cx25840_read(client, 0 x805);
u8 audio_config = cx25840_read(client, 0 x808);
u8 pref_mode = cx25840_read(client, 0 x809);
u8 afc0 = cx25840_read(client, 0 x80b);
u8 mute_ctl = cx25840_read(client, 0 x8d3);
int aud_input = state->aud_input;
char *p;
switch (mod_det_stat0) {
case 0 x00:
p = "mono" ;
break ;
case 0 x01:
p = "stereo" ;
break ;
case 0 x02:
p = "dual" ;
break ;
case 0 x04:
p = "tri" ;
break ;
case 0 x10:
p = "mono with SAP" ;
break ;
case 0 x11:
p = "stereo with SAP" ;
break ;
case 0 x12:
p = "dual with SAP" ;
break ;
case 0 x14:
p = "tri with SAP" ;
break ;
case 0 xfe:
p = "forced mode" ;
break ;
default :
p = "not defined" ;
}
v4l_info(client, "Detected audio mode: %s\n" , p);
switch (mod_det_stat1) {
case 0 x00:
p = "not defined" ;
break ;
case 0 x01:
p = "EIAJ" ;
break ;
case 0 x02:
p = "A2-M" ;
break ;
case 0 x03:
p = "A2-BG" ;
break ;
case 0 x04:
p = "A2-DK1" ;
break ;
case 0 x05:
p = "A2-DK2" ;
break ;
case 0 x06:
p = "A2-DK3" ;
break ;
case 0 x07:
p = "A1 (6.0 MHz FM Mono)" ;
break ;
case 0 x08:
p = "AM-L" ;
break ;
case 0 x09:
p = "NICAM-BG" ;
break ;
case 0 x0a:
p = "NICAM-DK" ;
break ;
case 0 x0b:
p = "NICAM-I" ;
break ;
case 0 x0c:
p = "NICAM-L" ;
break ;
case 0 x0d:
p = "BTSC/EIAJ/A2-M Mono (4.5 MHz FMMono)" ;
break ;
case 0 x0e:
p = "IF FM Radio" ;
break ;
case 0 x0f:
p = "BTSC" ;
break ;
case 0 x10:
p = "high-deviation FM" ;
break ;
case 0 x11:
p = "very high-deviation FM" ;
break ;
case 0 xfd:
p = "unknown audio standard" ;
break ;
case 0 xfe:
p = "forced audio standard" ;
break ;
case 0 xff:
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 & 0 x10) ?
((mute_ctl & 0 x2) ? "detecting" : "running" ) : "stopped" );
switch (audio_config >> 4 ) {
case 0 x00:
p = "undefined" ;
break ;
case 0 x01:
p = "BTSC" ;
break ;
case 0 x02:
p = "EIAJ" ;
break ;
case 0 x03:
p = "A2-M" ;
break ;
case 0 x04:
p = "A2-BG" ;
break ;
case 0 x05:
p = "A2-DK1" ;
break ;
case 0 x06:
p = "A2-DK2" ;
break ;
case 0 x07:
p = "A2-DK3" ;
break ;
case 0 x08:
p = "A1 (6.0 MHz FM Mono)" ;
break ;
case 0 x09:
p = "AM-L" ;
break ;
case 0 x0a:
p = "NICAM-BG" ;
break ;
case 0 x0b:
p = "NICAM-DK" ;
break ;
case 0 x0c:
p = "NICAM-I" ;
break ;
case 0 x0d:
p = "NICAM-L" ;
break ;
case 0 x0e:
p = "FM radio" ;
break ;
case 0 x0f:
p = "automatic detection" ;
break ;
default :
p = "undefined" ;
}
v4l_info(client, "Configured audio standard: %s\n" , p);
if ((audio_config >> 4 ) < 0 xF) {
switch (audio_config & 0 xF) {
case 0 x00:
p = "MONO1 (LANGUAGE A/Mono L+R channel for BTSC, EIAJ, A2)" ;
break ;
case 0 x01:
p = "MONO2 (LANGUAGE B)" ;
break ;
case 0 x02:
p = "MONO3 (STEREO forced MONO)" ;
break ;
case 0 x03:
p = "MONO4 (NICAM ANALOG-Language C/Analog Fallback)" ;
break ;
case 0 x04:
p = "STEREO" ;
break ;
case 0 x05:
p = "DUAL1 (AB)" ;
break ;
case 0 x06:
p = "DUAL2 (AC) (FM)" ;
break ;
case 0 x07:
p = "DUAL3 (BC) (FM)" ;
break ;
case 0 x08:
p = "DUAL4 (AC) (AM)" ;
break ;
case 0 x09:
p = "DUAL5 (BC) (AM)" ;
break ;
case 0 x0a:
p = "SAP" ;
break ;
default :
p = "undefined" ;
}
v4l_info(client, "Configured audio mode: %s\n" , p);
} else {
switch (audio_config & 0 xF) {
case 0 x00:
p = "BG" ;
break ;
case 0 x01:
p = "DK1" ;
break ;
case 0 x02:
p = "DK2" ;
break ;
case 0 x03:
p = "DK3" ;
break ;
case 0 x04:
p = "I" ;
break ;
case 0 x05:
p = "L" ;
break ;
case 0 x06:
p = "BTSC" ;
break ;
case 0 x07:
p = "EIAJ" ;
break ;
case 0 x08:
p = "A2-M" ;
break ;
case 0 x09:
p = "FM Radio" ;
break ;
case 0 x0f:
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 & 0 xf) {
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 & 0 xf) == 0 xf) {
switch ((afc0 >> 3 ) & 0 x3) {
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 & 0 x7) {
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 & 0 x0fff);
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 & 0 x0fff, reg->val & 0 xff);
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, 0 x115) | 0 x80;
cx25840_write(client, 0 x115, v);
v = cx25840_read(client, 0 x116) | 0 x03;
cx25840_write(client, 0 x116, v);
} else {
v = cx25840_read(client, 0 x115) & ~(0 x80);
cx25840_write(client, 0 x115, v);
v = cx25840_read(client, 0 x116) & ~(0 x03);
cx25840_write(client, 0 x116, 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, 0 x115) | 0 x0c;
cx25840_write(client, 0 x115, v);
v = cx25840_read(client, 0 x116) | 0 x04;
cx25840_write(client, 0 x116, v);
} else {
v = cx25840_read(client, 0 x115) & ~(0 x0c);
cx25840_write(client, 0 x115, v);
v = cx25840_read(client, 0 x116) & ~(0 x04);
cx25840_write(client, 0 x116, 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, 0 x40c) >> 8 ) & 0 xf;
*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, 0 x40c) & 0 x00010000) == 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, 0 x40e) & 0 x20;
u8 mode;
int val = 0 ;
if (state->radio)
return 0 ;
vt->signal = vpres ? 0 xffff : 0 x0;
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, 0 x804);
/* get rxsubchans and audmode */
if ((mode & 0 xf) == 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 & 0 x10)
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, 0 x809, ~0 xf, 0 x00);
break ;
case V4L2_TUNER_MODE_STEREO:
case V4L2_TUNER_MODE_LANG1:
/*
* mono -> mono
* stereo -> stereo
* bilingual -> lang1
*/
cx25840_and_or(client, 0 x809, ~0 xf, 0 x04);
break ;
case V4L2_TUNER_MODE_LANG1_LANG2:
/*
* mono -> mono
* stereo -> stereo
* bilingual -> lang1/lang2
*/
cx25840_and_or(client, 0 x809, ~0 xf, 0 x07);
break ;
case V4L2_TUNER_MODE_LANG2:
/*
* mono -> mono
* stereo -> stereo
* bilingual -> lang2
*/
cx25840_and_or(client, 0 x809, ~0 xf, 0 x01);
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 (0 x300)
#define DIF_BPF_COEFF01 (0 x348)
#define DIF_BPF_COEFF23 (0 x34c)
#define DIF_BPF_COEFF45 (0 x350)
#define DIF_BPF_COEFF67 (0 x354)
#define DIF_BPF_COEFF89 (0 x358)
#define DIF_BPF_COEFF1011 (0 x35c)
#define DIF_BPF_COEFF1213 (0 x360)
#define DIF_BPF_COEFF1415 (0 x364)
#define DIF_BPF_COEFF1617 (0 x368)
#define DIF_BPF_COEFF1819 (0 x36c)
#define DIF_BPF_COEFF2021 (0 x370)
#define DIF_BPF_COEFF2223 (0 x374)
#define DIF_BPF_COEFF2425 (0 x378)
#define DIF_BPF_COEFF2627 (0 x37c)
#define DIF_BPF_COEFF2829 (0 x380)
#define DIF_BPF_COEFF3031 (0 x384)
#define DIF_BPF_COEFF3233 (0 x388)
#define DIF_BPF_COEFF3435 (0 x38c)
#define DIF_BPF_COEFF36 (0 x390)
static const u32 ifhz_coeffs[][19 ] = {
{ // 3.0 MHz
0 x00000002, 0 x00080012, 0 x001e0024, 0 x001bfff8,
0 xffb4ff50, 0 xfed8fe68, 0 xfe24fe34, 0 xfebaffc7,
0 x014d031f, 0 x04f0065d, 0 x07010688, 0 x04c901d6,
0 xfe00f9d3, 0 xf600f342, 0 xf235f337, 0 xf64efb22,
0 x0105070f, 0 x0c460fce, 0 x110d0000,
}, { // 3.1 MHz
0 x00000001, 0 x00070012, 0 x00220032, 0 x00370026,
0 xfff0ff91, 0 xff0efe7c, 0 xfe01fdcc, 0 xfe0afedb,
0 x00440224, 0 x0434060c, 0 x0738074e, 0 x06090361,
0 xff99fb39, 0 xf6fef3b6, 0 xf21af2a5, 0 xf573fa33,
0 x0034067d, 0 x0bfb0fb9, 0 x110d0000,
}, { // 3.2 MHz
0 x00000000, 0 x0004000e, 0 x00200038, 0 x004c004f,
0 x002fffdf, 0 xff5cfeb6, 0 xfe0dfd92, 0 xfd7ffe03,
0 xff36010a, 0 x03410575, 0 x072607d2, 0 x071804d5,
0 x0134fcb7, 0 xf81ff451, 0 xf223f22e, 0 xf4a7f94b,
0 xff6405e8, 0 x0bae0fa4, 0 x110d0000,
}, { // 3.3 MHz
0 x0000ffff, 0 x00000008, 0 x001a0036, 0 x0056006d,
0 x00670030, 0 xffbdff10, 0 xfe46fd8d, 0 xfd25fd4f,
0 xfe35ffe0, 0 x0224049f, 0 x06c9080e, 0 x07ef0627,
0 x02c9fe45, 0 xf961f513, 0 xf250f1d2, 0 xf3ecf869,
0 xfe930552, 0 x0b5f0f8f, 0 x110d0000,
}, { // 3.4 MHz
0 xfffffffe, 0 xfffd0001, 0 x000f002c, 0 x0054007d,
0 x0093007c, 0 x0024ff82, 0 xfea6fdbb, 0 xfd03fcca,
0 xfd51feb9, 0 x00eb0392, 0 x06270802, 0 x08880750,
0 x044dffdb, 0 xfabdf5f8, 0 xf2a0f193, 0 xf342f78f,
0 xfdc404b9, 0 x0b0e0f78, 0 x110d0000,
}, { // 3.5 MHz
0 xfffffffd, 0 xfffafff9, 0 x0002001b, 0 x0046007d,
0 x00ad00ba, 0 x00870000, 0 xff26fe1a, 0 xfd1bfc7e,
0 xfc99fda4, 0 xffa5025c, 0 x054507ad, 0 x08dd0847,
0 x05b80172, 0 xfc2ef6ff, 0 xf313f170, 0 xf2abf6bd,
0 xfcf6041f, 0 x0abc0f61, 0 x110d0000,
}, { // 3.6 MHz
0 xfffffffd, 0 xfff8fff3, 0 xfff50006, 0 x002f006c,
0 x00b200e3, 0 x00dc007e, 0 xffb9fea0, 0 xfd6bfc71,
0 xfc17fcb1, 0 xfe65010b, 0 x042d0713, 0 x08ec0906,
0 x07020302, 0 xfdaff823, 0 xf3a7f16a, 0 xf228f5f5,
0 xfc2a0384, 0 x0a670f4a, 0 x110d0000,
}, { // 3.7 MHz
0 x0000fffd, 0 xfff7ffef, 0 xffe9fff1, 0 x0010004d,
0 x00a100f2, 0 x011a00f0, 0 x0053ff44, 0 xfdedfca2,
0 xfbd3fbef, 0 xfd39ffae, 0 x02ea0638, 0 x08b50987,
0 x08230483, 0 xff39f960, 0 xf45bf180, 0 xf1b8f537,
0 xfb6102e7, 0 x0a110f32, 0 x110d0000,
}, { // 3.8 MHz
0 x0000fffe, 0 xfff9ffee, 0 xffe1ffdd, 0 xfff00024,
0 x007c00e5, 0 x013a014a, 0 x00e6fff8, 0 xfe98fd0f,
0 xfbd3fb67, 0 xfc32fe54, 0 x01880525, 0 x083909c7,
0 x091505ee, 0 x00c7fab3, 0 xf52df1b4, 0 xf15df484,
0 xfa9b0249, 0 x09ba0f19, 0 x110d0000,
}, { // 3.9 MHz
0 x00000000, 0 xfffbfff0, 0 xffdeffcf, 0 xffd1fff6,
0 x004800be, 0 x01390184, 0 x016300ac, 0 xff5efdb1,
0 xfc17fb23, 0 xfb5cfd0d, 0 x001703e4, 0 x077b09c4,
0 x09d2073c, 0 x0251fc18, 0 xf61cf203, 0 xf118f3dc,
0 xf9d801aa, 0 x09600eff, 0 x110d0000,
}, { // 4.0 MHz
0 x00000001, 0 xfffefff4, 0 xffe1ffc8, 0 xffbaffca,
0 x000b0082, 0 x01170198, 0 x01c10152, 0 x0030fe7b,
0 xfc99fb24, 0 xfac3fbe9, 0 xfea5027f, 0 x0683097f,
0 x0a560867, 0 x03d2fd89, 0 xf723f26f, 0 xf0e8f341,
0 xf919010a, 0 x09060ee5, 0 x110d0000,
}, { // 4.1 MHz
0 x00010002, 0 x0002fffb, 0 xffe8ffca, 0 xffacffa4,
0 xffcd0036, 0 x00d70184, 0 x01f601dc, 0 x00ffff60,
0 xfd51fb6d, 0 xfa6efaf5, 0 xfd410103, 0 x055708f9,
0 x0a9e0969, 0 x0543ff02, 0 xf842f2f5, 0 xf0cef2b2,
0 xf85e006b, 0 x08aa0ecb, 0 x110d0000,
}, { // 4.2 MHz
0 x00010003, 0 x00050003, 0 xfff3ffd3, 0 xffaaff8b,
0 xff95ffe5, 0 x0080014a, 0 x01fe023f, 0 x01ba0050,
0 xfe35fbf8, 0 xfa62fa3b, 0 xfbf9ff7e, 0 x04010836,
0 x0aa90a3d, 0 x069f007f, 0 xf975f395, 0 xf0cbf231,
0 xf7a9ffcb, 0 x084c0eaf, 0 x110d0000,
}, { // 4.3 MHz
0 x00010003, 0 x0008000a, 0 x0000ffe4, 0 xffb4ff81,
0 xff6aff96, 0 x001c00f0, 0 x01d70271, 0 x0254013b,
0 xff36fcbd, 0 xfa9ff9c5, 0 xfadbfdfe, 0 x028c073b,
0 x0a750adf, 0 x07e101fa, 0 xfab8f44e, 0 xf0ddf1be,
0 xf6f9ff2b, 0 x07ed0e94, 0 x110d0000,
}, { // 4.4 MHz
0 x00000003, 0 x0009000f, 0 x000efff8, 0 xffc9ff87,
0 xff52ff54, 0 xffb5007e, 0 x01860270, 0 x02c00210,
0 x0044fdb2, 0 xfb22f997, 0 xf9f2fc90, 0 x0102060f,
0 x0a050b4c, 0 x0902036e, 0 xfc0af51e, 0 xf106f15a,
0 xf64efe8b, 0 x078d0e77, 0 x110d0000,
}, { // 4.5 MHz
0 x00000002, 0 x00080012, 0 x0019000e, 0 xffe5ff9e,
0 xff4fff25, 0 xff560000, 0 x0112023b, 0 x02f702c0,
0 x014dfec8, 0 xfbe5f9b3, 0 xf947fb41, 0 xff7004b9,
0 x095a0b81, 0 x0a0004d8, 0 xfd65f603, 0 xf144f104,
0 xf5aafdec, 0 x072b0e5a, 0 x110d0000,
}, { // 4.6 MHz
0 x00000001, 0 x00060012, 0 x00200022, 0 x0005ffc1,
0 xff61ff10, 0 xff09ff82, 0 x008601d7, 0 x02f50340,
0 x0241fff0, 0 xfcddfa19, 0 xf8e2fa1e, 0 xfde30343,
0 x08790b7f, 0 x0ad50631, 0 xfec7f6fc, 0 xf198f0bd,
0 xf50dfd4e, 0 x06c90e3d, 0 x110d0000,
}, { // 4.7 MHz
0 x0000ffff, 0 x0003000f, 0 x00220030, 0 x0025ffed,
0 xff87ff15, 0 xfed6ff10, 0 xffed014c, 0 x02b90386,
0 x03110119, 0 xfdfefac4, 0 xf8c6f92f, 0 xfc6701b7,
0 x07670b44, 0 x0b7e0776, 0 x002df807, 0 xf200f086,
0 xf477fcb1, 0 x06650e1e, 0 x110d0000,
}, { // 4.8 MHz
0 xfffffffe, 0 xffff0009, 0 x001e0038, 0 x003f001b,
0 xffbcff36, 0 xfec2feb6, 0 xff5600a5, 0 x0248038d,
0 x03b00232, 0 xff39fbab, 0 xf8f4f87f, 0 xfb060020,
0 x062a0ad2, 0 x0bf908a3, 0 x0192f922, 0 xf27df05e,
0 xf3e8fc14, 0 x06000e00, 0 x110d0000,
}, { // 4.9 MHz
0 xfffffffd, 0 xfffc0002, 0 x00160037, 0 x00510046,
0 xfff9ff6d, 0 xfed0fe7c, 0 xfecefff0, 0 x01aa0356,
0 x0413032b, 0 x007ffcc5, 0 xf96cf812, 0 xf9cefe87,
0 x04c90a2c, 0 x0c4309b4, 0 x02f3fa4a, 0 xf30ef046,
0 xf361fb7a, 0 x059b0de0, 0 x110d0000,
}, { // 5.0 MHz
0 xfffffffd, 0 xfff9fffa, 0 x000a002d, 0 x00570067,
0 x0037ffb5, 0 xfefffe68, 0 xfe62ff3d, 0 x00ec02e3,
0 x043503f6, 0 x01befe05, 0 xfa27f7ee, 0 xf8c6fcf8,
0 x034c0954, 0 x0c5c0aa4, 0 x044cfb7e, 0 xf3b1f03f,
0 xf2e2fae1, 0 x05340dc0, 0 x110d0000,
}, { // 5.1 MHz
0 x0000fffd, 0 xfff8fff4, 0 xfffd001e, 0 x0051007b,
0 x006e0006, 0 xff48fe7c, 0 xfe1bfe9a, 0 x001d023e,
0 x04130488, 0 x02e6ff5b, 0 xfb1ef812, 0 xf7f7fb7f,
0 x01bc084e, 0 x0c430b72, 0 x059afcba, 0 xf467f046,
0 xf26cfa4a, 0 x04cd0da0, 0 x110d0000,
}, { // 5.2 MHz
0 x0000fffe, 0 xfff8ffef, 0 xfff00009, 0 x003f007f,
0 x00980056, 0 xffa5feb6, 0 xfe00fe15, 0 xff4b0170,
0 x03b004d7, 0 x03e800b9, 0 xfc48f87f, 0 xf768fa23,
0 x0022071f, 0 x0bf90c1b, 0 x06dafdfd, 0 xf52df05e,
0 xf1fef9b5, 0 x04640d7f, 0 x110d0000,
}, { // 5.3 MHz
0 x0000ffff, 0 xfff9ffee, 0 xffe6fff3, 0 x00250072,
0 x00af009c, 0 x000cff10, 0 xfe13fdb8, 0 xfe870089,
0 x031104e1, 0 x04b8020f, 0 xfd98f92f, 0 xf71df8f0,
0 xfe8805ce, 0 x0b7e0c9c, 0 x0808ff44, 0 xf603f086,
0 xf19af922, 0 x03fb0d5e, 0 x110d0000,
}, { // 5.4 MHz
0 x00000001, 0 xfffcffef, 0 xffe0ffe0, 0 x00050056,
0 x00b000d1, 0 x0071ff82, 0 xfe53fd8c, 0 xfddfff99,
0 x024104a3, 0 x054a034d, 0 xff01fa1e, 0 xf717f7ed,
0 xfcf50461, 0 x0ad50cf4, 0 x0921008d, 0 xf6e7f0bd,
0 xf13ff891, 0 x03920d3b, 0 x110d0000,
}, { // 5.5 MHz
0 x00010002, 0 xfffffff3, 0 xffdeffd1, 0 xffe5002f,
0 x009c00ed, 0 x00cb0000, 0 xfebafd94, 0 xfd61feb0,
0 x014d0422, 0 x05970464, 0 x0074fb41, 0 xf759f721,
0 xfb7502de, 0 x0a000d21, 0 x0a2201d4, 0 xf7d9f104,
0 xf0edf804, 0 x03280d19, 0 x110d0000,
}, { // 5.6 MHz
0 x00010003, 0 x0003fffa, 0 xffe3ffc9, 0 xffc90002,
0 x007500ef, 0 x010e007e, 0 xff3dfdcf, 0 xfd16fddd,
0 x00440365, 0 x059b0548, 0 x01e3fc90, 0 xf7dff691,
0 xfa0f014d, 0 x09020d23, 0 x0b0a0318, 0 xf8d7f15a,
0 xf0a5f779, 0 x02bd0cf6, 0 x110d0000,
}, { // 5.7 MHz
0 x00010003, 0 x00060001, 0 xffecffc9, 0 xffb4ffd4,
0 x004000d5, 0 x013600f0, 0 xffd3fe39, 0 xfd04fd31,
0 xff360277, 0 x055605ef, 0 x033efdfe, 0 xf8a5f642,
0 xf8cbffb6, 0 x07e10cfb, 0 x0bd50456, 0 xf9dff1be,
0 xf067f6f2, 0 x02520cd2, 0 x110d0000,
}, { // 5.8 MHz
0 x00000003, 0 x00080009, 0 xfff8ffd2, 0 xffaaffac,
0 x000200a3, 0 x013c014a, 0 x006dfec9, 0 xfd2bfcb7,
0 xfe350165, 0 x04cb0651, 0 x0477ff7e, 0 xf9a5f635,
0 xf7b1fe20, 0 x069f0ca8, 0 x0c81058b, 0 xfaf0f231,
0 xf033f66d, 0 x01e60cae, 0 x110d0000,
}, { // 5.9 MHz
0 x00000002, 0 x0009000e, 0 x0005ffe1, 0 xffacff90,
0 xffc5005f, 0 x01210184, 0 x00fcff72, 0 xfd8afc77,
0 xfd51003f, 0 x04020669, 0 x05830103, 0 xfad7f66b,
0 xf6c8fc93, 0 x05430c2b, 0 x0d0d06b5, 0 xfc08f2b2,
0 xf00af5ec, 0 x017b0c89, 0 x110d0000,
}, { // 6.0 MHz
0 x00000001, 0 x00070012, 0 x0012fff5, 0 xffbaff82,
0 xff8e000f, 0 x00e80198, 0 x01750028, 0 xfe18fc75,
0 xfc99ff15, 0 x03050636, 0 x0656027f, 0 xfc32f6e2,
0 xf614fb17, 0 x03d20b87, 0 x0d7707d2, 0 xfd26f341,
0 xefeaf56f, 0 x010f0c64, 0 x110d0000,
}, { // 6.1 MHz
0 xffff0000, 0 x00050012, 0 x001c000b, 0 xffd1ff84,
0 xff66ffbe, 0 x00960184, 0 x01cd00da, 0 xfeccfcb2,
0 xfc17fdf9, 0 x01e005bc, 0 x06e703e4, 0 xfdabf798,
0 xf599f9b3, 0 x02510abd, 0 x0dbf08df, 0 xfe48f3dc,
0 xefd5f4f6, 0 x00a20c3e, 0 x110d0000,
}, { // 6.2 MHz
0 xfffffffe, 0 x0002000f, 0 x0021001f, 0 xfff0ff97,
0 xff50ff74, 0 x0034014a, 0 x01fa0179, 0 xff97fd2a,
0 xfbd3fcfa, 0 x00a304fe, 0 x07310525, 0 xff37f886,
0 xf55cf86e, 0 x00c709d0, 0 x0de209db, 0 xff6df484,
0 xefcbf481, 0 x00360c18, 0 x110d0000,
}, { // 6.3 MHz
0 xfffffffd, 0 xfffe000a, 0 x0021002f, 0 x0010ffb8,
0 xff50ff3b, 0 xffcc00f0, 0 x01fa01fa, 0 x0069fdd4,
0 xfbd3fc26, 0 xff5d0407, 0 x07310638, 0 x00c9f9a8,
0 xf55cf74e, 0 xff3908c3, 0 x0de20ac3, 0 x0093f537,
0 xefcbf410, 0 xffca0bf2, 0 x110d0000,
}, { // 6.4 MHz
0 xfffffffd, 0 xfffb0003, 0 x001c0037, 0 x002fffe2,
0 xff66ff17, 0 xff6a007e, 0 x01cd0251, 0 x0134fea5,
0 xfc17fb8b, 0 xfe2002e0, 0 x06e70713, 0 x0255faf5,
0 xf599f658, 0 xfdaf0799, 0 x0dbf0b96, 0 x01b8f5f5,
0 xefd5f3a3, 0 xff5e0bca, 0 x110d0000,
}, { // 6.5 MHz
0 x0000fffd, 0 xfff9fffb, 0 x00120037, 0 x00460010,
0 xff8eff0f, 0 xff180000, 0 x01750276, 0 x01e8ff8d,
0 xfc99fb31, 0 xfcfb0198, 0 x065607ad, 0 x03cefc64,
0 xf614f592, 0 xfc2e0656, 0 x0d770c52, 0 x02daf6bd,
0 xefeaf33b, 0 xfef10ba3, 0 x110d0000,
}, { // 6.6 MHz
0 x0000fffe, 0 xfff7fff5, 0 x0005002f, 0 x0054003c,
0 xffc5ff22, 0 xfedfff82, 0 x00fc0267, 0 x0276007e,
0 xfd51fb1c, 0 xfbfe003e, 0 x05830802, 0 x0529fdec,
0 xf6c8f4fe, 0 xfabd04ff, 0 x0d0d0cf6, 0 x03f8f78f,
0 xf00af2d7, 0 xfe850b7b, 0 x110d0000,
}, { // 6.7 MHz
0 x0000ffff, 0 xfff8fff0, 0 xfff80020, 0 x00560060,
0 x0002ff4e, 0 xfec4ff10, 0 x006d0225, 0 x02d50166,
0 xfe35fb4e, 0 xfb35fee1, 0 x0477080e, 0 x065bff82,
0 xf7b1f4a0, 0 xf9610397, 0 x0c810d80, 0 x0510f869,
0 xf033f278, 0 xfe1a0b52, 0 x110d0000,
}, { // 6.8 MHz
0 x00010000, 0 xfffaffee, 0 xffec000c, 0 x004c0078,
0 x0040ff8e, 0 xfecafeb6, 0 xffd301b6, 0 x02fc0235,
0 xff36fbc5, 0 xfaaafd90, 0 x033e07d2, 0 x075b011b,
0 xf8cbf47a, 0 xf81f0224, 0 x0bd50def, 0 x0621f94b,
0 xf067f21e, 0 xfdae0b29, 0 x110d0000,
}, { // 6.9 MHz
0 x00010001, 0 xfffdffef, 0 xffe3fff6, 0 x0037007f,
0 x0075ffdc, 0 xfef2fe7c, 0 xff3d0122, 0 x02ea02dd,
0 x0044fc79, 0 xfa65fc5d, 0 x01e3074e, 0 x082102ad,
0 xfa0ff48c, 0 xf6fe00a9, 0 x0b0a0e43, 0 x0729fa33,
0 xf0a5f1c9, 0 xfd430b00, 0 x110d0000,
}, { // 7.0 MHz
0 x00010002, 0 x0001fff3, 0 xffdeffe2, 0 x001b0076,
0 x009c002d, 0 xff35fe68, 0 xfeba0076, 0 x029f0352,
0 x014dfd60, 0 xfa69fb53, 0 x00740688, 0 x08a7042d,
0 xfb75f4d6, 0 xf600ff2d, 0 x0a220e7a, 0 x0827fb22,
0 xf0edf17a, 0 xfcd80ad6, 0 x110d0000,
}, { // 7.1 MHz
0 x00000003, 0 x0004fff9, 0 xffe0ffd2, 0 xfffb005e,
0 x00b0007a, 0 xff8ffe7c, 0 xfe53ffc1, 0 x0221038c,
0 x0241fe6e, 0 xfab6fa80, 0 xff010587, 0 x08e90590,
0 xfcf5f556, 0 xf52bfdb3, 0 x09210e95, 0 x0919fc15,
0 xf13ff12f, 0 xfc6e0aab, 0 x110d0000,
}, { // 7.2 MHz
0 x00000003, 0 x00070000, 0 xffe6ffc9, 0 xffdb0039,
0 x00af00b8, 0 xfff4feb6, 0 xfe13ff10, 0 x01790388,
0 x0311ff92, 0 xfb48f9ed, 0 xfd980453, 0 x08e306cd,
0 xfe88f60a, 0 xf482fc40, 0 x08080e93, 0 x09fdfd0c,
0 xf19af0ea, 0 xfc050a81, 0 x110d0000,
}, { // 7.3 MHz
0 x00000002, 0 x00080008, 0 xfff0ffc9, 0 xffc1000d,
0 x009800e2, 0 x005bff10, 0 xfe00fe74, 0 x00b50345,
0 x03b000bc, 0 xfc18f9a1, 0 xfc4802f9, 0 x089807dc,
0 x0022f6f0, 0 xf407fada, 0 x06da0e74, 0 x0ad3fe06,
0 xf1fef0ab, 0 xfb9c0a55, 0 x110d0000,
}, { // 7.4 MHz
0 x00000001, 0 x0008000e, 0 xfffdffd0, 0 xffafffdf,
0 x006e00f2, 0 x00b8ff82, 0 xfe1bfdf8, 0 xffe302c8,
0 x041301dc, 0 xfd1af99e, 0 xfb1e0183, 0 x080908b5,
0 x01bcf801, 0 xf3bdf985, 0 x059a0e38, 0 x0b99ff03,
0 xf26cf071, 0 xfb330a2a, 0 x110d0000,
}, { // 7.5 MHz
0 xffff0000, 0 x00070011, 0 x000affdf, 0 xffa9ffb5,
0 x003700e6, 0 x01010000, 0 xfe62fda8, 0 xff140219,
0 x043502e1, 0 xfe42f9e6, 0 xfa270000, 0 x073a0953,
0 x034cf939, 0 xf3a4f845, 0 x044c0de1, 0 x0c4f0000,
0 xf2e2f03c, 0 xfacc09fe, 0 x110d0000,
}, { // 7.6 MHz
0 xffffffff, 0 x00040012, 0 x0016fff3, 0 xffafff95,
0 xfff900c0, 0 x0130007e, 0 xfecefd89, 0 xfe560146,
0 x041303bc, 0 xff81fa76, 0 xf96cfe7d, 0 x063209b1,
0 x04c9fa93, 0 xf3bdf71e, 0 x02f30d6e, 0 x0cf200fd,
0 xf361f00e, 0 xfa6509d1, 0 x110d0000,
}, { // 7.7 MHz
0 xfffffffe, 0 x00010010, 0 x001e0008, 0 xffc1ff84,
0 xffbc0084, 0 x013e00f0, 0 xff56fd9f, 0 xfdb8005c,
0 x03b00460, 0 x00c7fb45, 0 xf8f4fd07, 0 x04fa09ce,
0 x062afc07, 0 xf407f614, 0 x01920ce0, 0 x0d8301fa,
0 xf3e8efe5, 0 xfa0009a4, 0 x110d0000,
}, { // 7.8 MHz
0 x0000fffd, 0 xfffd000b, 0 x0022001d, 0 xffdbff82,
0 xff870039, 0 x012a014a, 0 xffedfde7, 0 xfd47ff6b,
0 x031104c6, 0 x0202fc4c, 0 xf8c6fbad, 0 x039909a7,
0 x0767fd8e, 0 xf482f52b, 0 x002d0c39, 0 x0e0002f4,
0 xf477efc2, 0 xf99b0977, 0 x110d0000,
}, { // 7.9 MHz
0 x0000fffd, 0 xfffa0004, 0 x0020002d, 0 xfffbff91,
0 xff61ffe8, 0 x00f70184, 0 x0086fe5c, 0 xfd0bfe85,
0 x024104e5, 0 x0323fd7d, 0 xf8e2fa79, 0 x021d093f,
0 x0879ff22, 0 xf52bf465, 0 xfec70b79, 0 x0e6803eb,
0 xf50defa5, 0 xf937094a, 0 x110d0000,
}, { // 8.0 MHz
0 x0000fffe, 0 xfff8fffd, 0 x00190036, 0 x001bffaf,
0 xff4fff99, 0 x00aa0198, 0 x0112fef3, 0 xfd09fdb9,
0 x014d04be, 0 x041bfecc, 0 xf947f978, 0 x00900897,
0 x095a00b9, 0 xf600f3c5, 0 xfd650aa3, 0 x0ebc04de,
0 xf5aaef8e, 0 xf8d5091c, 0 x110d0000,
}, { // 8.1 MHz
0 x0000ffff, 0 xfff7fff6, 0 x000e0038, 0 x0037ffd7,
0 xff52ff56, 0 x004b0184, 0 x0186ffa1, 0 xfd40fd16,
0 x00440452, 0 x04de0029, 0 xf9f2f8b2, 0 xfefe07b5,
0 x0a05024d, 0 xf6fef34d, 0 xfc0a09b8, 0 x0efa05cd,
0 xf64eef7d, 0 xf87308ed, 0 x110d0000,
}, { // 8.2 MHz
0 x00010000, 0 xfff8fff0, 0 x00000031, 0 x004c0005,
0 xff6aff27, 0 xffe4014a, 0 x01d70057, 0 xfdacfca6,
0 xff3603a7, 0 x05610184, 0 xfadbf82e, 0 xfd74069f,
0 x0a7503d6, 0 xf81ff2ff, 0 xfab808b9, 0 x0f2306b5,
0 xf6f9ef72, 0 xf81308bf, 0 x110d0000,
}, { // 8.3 MHz
0 x00010001, 0 xfffbffee, 0 xfff30022, 0 x00560032,
0 xff95ff10, 0 xff8000f0, 0 x01fe0106, 0 xfe46fc71,
0 xfe3502c7, 0 x059e02ce, 0 xfbf9f7f2, 0 xfbff055b,
0 x0aa9054c, 0 xf961f2db, 0 xf97507aa, 0 x0f350797,
0 xf7a9ef6d, 0 xf7b40890, 0 x110d0000,
}, { // 8.4 MHz
0 x00010002, 0 xfffeffee, 0 xffe8000f, 0 x00540058,
0 xffcdff14, 0 xff29007e, 0 x01f6019e, 0 xff01fc7c,
0 xfd5101bf, 0 x059203f6, 0 xfd41f7fe, 0 xfaa903f3,
0 x0a9e06a9, 0 xfabdf2e2, 0 xf842068b, 0 x0f320871,
0 xf85eef6e, 0 xf7560860, 0 x110d0000,
}, { // 8.5 MHz
0 x00000003, 0 x0002fff2, 0 xffe1fff9, 0 x00460073,
0 x000bff34, 0 xfee90000, 0 x01c10215, 0 xffd0fcc5,
0 xfc99009d, 0 x053d04f1, 0 xfea5f853, 0 xf97d0270,
0 x0a5607e4, 0 xfc2ef314, 0 xf723055f, 0 x0f180943,
0 xf919ef75, 0 xf6fa0830, 0 x110d0000,
}, { // 8.6 MHz
0 x00000003, 0 x0005fff8, 0 xffdeffe4, 0 x002f007f,
0 x0048ff6b, 0 xfec7ff82, 0 x0163025f, 0 x00a2fd47,
0 xfc17ff73, 0 x04a405b2, 0 x0017f8ed, 0 xf88500dc,
0 x09d208f9, 0 xfdaff370, 0 xf61c0429, 0 x0ee80a0b,
0 xf9d8ef82, 0 xf6a00800, 0 x110d0000,
}, { // 8.7 MHz
0 x00000003, 0 x0007ffff, 0 xffe1ffd4, 0 x0010007a,
0 x007cffb2, 0 xfec6ff10, 0 x00e60277, 0 x0168fdf9,
0 xfbd3fe50, 0 x03ce0631, 0 x0188f9c8, 0 xf7c7ff43,
0 x091509e3, 0 xff39f3f6, 0 xf52d02ea, 0 x0ea30ac9,
0 xfa9bef95, 0 xf64607d0, 0 x110d0000,
}, { // 8.8 MHz
0 x00000002, 0 x00090007, 0 xffe9ffca, 0 xfff00065,
0 x00a10003, 0 xfee6feb6, 0 x0053025b, 0 x0213fed0,
0 xfbd3fd46, 0 x02c70668, 0 x02eafadb, 0 xf74bfdae,
0 x08230a9c, 0 x00c7f4a3, 0 xf45b01a6, 0 x0e480b7c,
0 xfb61efae, 0 xf5ef079f, 0 x110d0000,
}, { // 8.9 MHz
0 xffff0000, 0 x0008000d, 0 xfff5ffc8, 0 xffd10043,
0 x00b20053, 0 xff24fe7c, 0 xffb9020c, 0 x0295ffbb,
0 xfc17fc64, 0 x019b0654, 0 x042dfc1c, 0 xf714fc2a,
0 x07020b21, 0 x0251f575, 0 xf3a7005e, 0 x0dd80c24,
0 xfc2aefcd, 0 xf599076e, 0 x110d0000,
}, { // 9.0 MHz
0 xffffffff, 0 x00060011, 0 x0002ffcf, 0 xffba0018,
0 x00ad009a, 0 xff79fe68, 0 xff260192, 0 x02e500ab,
0 xfc99fbb6, 0 x005b05f7, 0 x0545fd81, 0 xf723fabf,
0 x05b80b70, 0 x03d2f669, 0 xf313ff15, 0 x0d550cbf,
0 xfcf6eff2, 0 xf544073d, 0 x110d0000,
}, { // 9.1 MHz
0 xfffffffe, 0 x00030012, 0 x000fffdd, 0 xffacffea,
0 x009300cf, 0 xffdcfe7c, 0 xfea600f7, 0 x02fd0190,
0 xfd51fb46, 0 xff150554, 0 x0627fefd, 0 xf778f978,
0 x044d0b87, 0 x0543f77d, 0 xf2a0fdcf, 0 x0cbe0d4e,
0 xfdc4f01d, 0 xf4f2070b, 0 x110d0000,
}, { // 9.2 MHz
0 x0000fffd, 0 x00000010, 0 x001afff0, 0 xffaaffbf,
0 x006700ed, 0 x0043feb6, 0 xfe460047, 0 x02db0258,
0 xfe35fb1b, 0 xfddc0473, 0 x06c90082, 0 xf811f85e,
0 x02c90b66, 0 x069ff8ad, 0 xf250fc8d, 0 x0c140dcf,
0 xfe93f04d, 0 xf4a106d9, 0 x110d0000,
}, { // 9.3 MHz
0 x0000fffd, 0 xfffc000c, 0 x00200006, 0 xffb4ff9c,
0 x002f00ef, 0 x00a4ff10, 0 xfe0dff92, 0 x028102f7,
0 xff36fb37, 0 xfcbf035e, 0 x07260202, 0 xf8e8f778,
0 x01340b0d, 0 x07e1f9f4, 0 xf223fb51, 0 x0b590e42,
0 xff64f083, 0 xf45206a7, 0 x110d0000,
}, { // 9.4 MHz
0 x0000fffd, 0 xfff90005, 0 x0022001a, 0 xffc9ff86,
0 xfff000d7, 0 x00f2ff82, 0 xfe01fee5, 0 x01f60362,
0 x0044fb99, 0 xfbcc0222, 0 x07380370, 0 xf9f7f6cc,
0 xff990a7e, 0 x0902fb50, 0 xf21afa1f, 0 x0a8d0ea6,
0 x0034f0bf, 0 xf4050675, 0 x110d0000,
}, { // 9.5 MHz
0 x0000fffe, 0 xfff8fffe, 0 x001e002b, 0 xffe5ff81,
0 xffb400a5, 0 x01280000, 0 xfe24fe50, 0 x01460390,
0 x014dfc3a, 0 xfb1000ce, 0 x070104bf, 0 xfb37f65f,
0 xfe0009bc, 0 x0a00fcbb, 0 xf235f8f8, 0 x09b20efc,
0 x0105f101, 0 xf3ba0642, 0 x110d0000,
}, { // 9.6 MHz
0 x0001ffff, 0 xfff8fff7, 0 x00150036, 0 x0005ff8c,
0 xff810061, 0 x013d007e, 0 xfe71fddf, 0 x007c0380,
0 x0241fd13, 0 xfa94ff70, 0 x068005e2, 0 xfc9bf633,
0 xfc7308ca, 0 x0ad5fe30, 0 xf274f7e0, 0 x08c90f43,
0 x01d4f147, 0 xf371060f, 0 x110d0000,
}, { // 9.7 MHz
0 x00010001, 0 xfff9fff1, 0 x00090038, 0 x0025ffa7,
0 xff5e0012, 0 x013200f0, 0 xfee3fd9b, 0 xffaa0331,
0 x0311fe15, 0 xfa60fe18, 0 x05bd06d1, 0 xfe1bf64a,
0 xfafa07ae, 0 x0b7effab, 0 xf2d5f6d7, 0 x07d30f7a,
0 x02a3f194, 0 xf32905dc, 0 x110d0000,
}, { // 9.8 MHz
0 x00010002, 0 xfffcffee, 0 xfffb0032, 0 x003fffcd,
0 xff4effc1, 0 x0106014a, 0 xff6efd8a, 0 xfedd02aa,
0 x03b0ff34, 0 xfa74fcd7, 0 x04bf0781, 0 xffaaf6a3,
0 xf99e066b, 0 x0bf90128, 0 xf359f5e1, 0 x06d20fa2,
0 x0370f1e5, 0 xf2e405a8, 0 x110d0000,
}, { // 9.9 MHz
0 x00000003, 0 xffffffee, 0 xffef0024, 0 x0051fffa,
0 xff54ff77, 0 x00be0184, 0 x0006fdad, 0 xfe2701f3,
0 x0413005e, 0 xfad1fbba, 0 x039007ee, 0 x013bf73d,
0 xf868050a, 0 x0c4302a1, 0 xf3fdf4fe, 0 x05c70fba,
0 x043bf23c, 0 xf2a10575, 0 x110d0000,
}, { // 10.0 MHz
0 x00000003, 0 x0003fff1, 0 xffe50011, 0 x00570027,
0 xff70ff3c, 0 x00620198, 0 x009efe01, 0 xfd95011a,
0 x04350183, 0 xfb71fad0, 0 x023c0812, 0 x02c3f811,
0 xf75e0390, 0 x0c5c0411, 0 xf4c1f432, 0 x04b30fc1,
0 x0503f297, 0 xf2610541, 0 x110d0000,
}, { // 10.1 MHz
0 x00000003, 0 x0006fff7, 0 xffdffffc, 0 x00510050,
0 xff9dff18, 0 xfffc0184, 0 x0128fe80, 0 xfd32002e,
0 x04130292, 0 xfc4dfa21, 0 x00d107ee, 0 x0435f91c,
0 xf6850205, 0 x0c430573, 0 xf5a1f37d, 0 x03990fba,
0 x05c7f2f8, 0 xf222050d, 0 x110d0000,
}, { // 10.2 MHz
0 x00000002, 0 x0008fffe, 0 xffdfffe7, 0 x003f006e,
0 xffd6ff0f, 0 xff96014a, 0 x0197ff1f, 0 xfd05ff3e,
0 x03b0037c, 0 xfd59f9b7, 0 xff5d0781, 0 x0585fa56,
0 xf5e4006f, 0 x0bf906c4, 0 xf69df2e0, 0 x02790fa2,
0 x0688f35d, 0 xf1e604d8, 0 x110d0000,
}, { // 10.3 MHz
0 xffff0001, 0 x00090005, 0 xffe4ffd6, 0 x0025007e,
0 x0014ff20, 0 xff3c00f0, 0 x01e1ffd0, 0 xfd12fe5c,
0 x03110433, 0 xfe88f996, 0 xfdf106d1, 0 x06aafbb7,
0 xf57efed8, 0 x0b7e07ff, 0 xf7b0f25e, 0 x01560f7a,
0 x0745f3c7, 0 xf1ac04a4, 0 x110d0000,
}, { // 10.4 MHz
0 xffffffff, 0 x0008000c, 0 xffedffcb, 0 x0005007d,
0 x0050ff4c, 0 xfef6007e, 0 x01ff0086, 0 xfd58fd97,
0 x024104ad, 0 xffcaf9c0, 0 xfc9905e2, 0 x079afd35,
0 xf555fd46, 0 x0ad50920, 0 xf8d9f1f6, 0 x00310f43,
0 x07fdf435, 0 xf174046f, 0 x110d0000,
}, { // 10.5 MHz
0 xfffffffe, 0 x00050011, 0 xfffaffc8, 0 xffe5006b,
0 x0082ff8c, 0 xfecc0000, 0 x01f00130, 0 xfdd2fcfc,
0 x014d04e3, 0 x010efa32, 0 xfb6404bf, 0 x084efec5,
0 xf569fbc2, 0 x0a000a23, 0 xfa15f1ab, 0 xff0b0efc,
0 x08b0f4a7, 0 xf13f043a, 0 x110d0000,
}, { // 10.6 MHz
0 x0000fffd, 0 x00020012, 0 x0007ffcd, 0 xffc9004c,
0 x00a4ffd9, 0 xfec3ff82, 0 x01b401c1, 0 xfe76fc97,
0 x004404d2, 0 x0245fae8, 0 xfa5f0370, 0 x08c1005f,
0 xf5bcfa52, 0 x09020b04, 0 xfb60f17b, 0 xfde70ea6,
0 x095df51e, 0 xf10c0405, 0 x110d0000,
}, { // 10.7 MHz
0 x0000fffd, 0 xffff0011, 0 x0014ffdb, 0 xffb40023,
0 x00b2002a, 0 xfedbff10, 0 x0150022d, 0 xff38fc6f,
0 xff36047b, 0 x035efbda, 0 xf9940202, 0 x08ee01f5,
0 xf649f8fe, 0 x07e10bc2, 0 xfcb6f169, 0 xfcc60e42,
0 x0a04f599, 0 xf0db03d0, 0 x110d0000,
}, { // 10.8 MHz
0 x0000fffd, 0 xfffb000d, 0 x001dffed, 0 xffaafff5,
0 x00aa0077, 0 xff13feb6, 0 x00ce026b, 0 x000afc85,
0 xfe3503e3, 0 x044cfcfb, 0 xf90c0082, 0 x08d5037f,
0 xf710f7cc, 0 x069f0c59, 0 xfe16f173, 0 xfbaa0dcf,
0 x0aa5f617, 0 xf0ad039b, 0 x110d0000,
}, { // 10.9 MHz
0 x0000fffe, 0 xfff90006, 0 x00210003, 0 xffacffc8,
0 x008e00b6, 0 xff63fe7c, 0 x003a0275, 0 x00dafcda,
0 xfd510313, 0 x0501fe40, 0 xf8cbfefd, 0 x087604f0,
0 xf80af6c2, 0 x05430cc8, 0 xff7af19a, 0 xfa940d4e,
0 x0b3ff699, 0 xf0810365, 0 x110d0000,
}, { // 11.0 MHz
0 x0001ffff, 0 xfff8ffff, 0 x00210018, 0 xffbaffa3,
0 x006000e1, 0 xffc4fe68, 0 xffa0024b, 0 x019afd66,
0 xfc990216, 0 x0575ff99, 0 xf8d4fd81, 0 x07d40640,
0 xf932f5e6, 0 x03d20d0d, 0 x00dff1de, 0 xf9860cbf,
0 x0bd1f71e, 0 xf058032f, 0 x110d0000,
}, { // 11.1 MHz
0 x00010000, 0 xfff8fff8, 0 x001b0029, 0 xffd1ff8a,
0 x002600f2, 0 x002cfe7c, 0 xff0f01f0, 0 x023bfe20,
0 xfc1700fa, 0 x05a200f7, 0 xf927fc1c, 0 x06f40765,
0 xfa82f53b, 0 x02510d27, 0 x0243f23d, 0 xf8810c24,
0 x0c5cf7a7, 0 xf03102fa, 0 x110d0000,
}, { // 11.2 MHz
0 x00010002, 0 xfffafff2, 0 x00110035, 0 xfff0ff81,
0 xffe700e7, 0 x008ffeb6, 0 xfe94016d, 0 x02b0fefb,
0 xfbd3ffd1, 0 x05850249, 0 xf9c1fadb, 0 x05de0858,
0 xfbf2f4c4, 0 x00c70d17, 0 x03a0f2b8, 0 xf7870b7c,
0 x0cdff833, 0 xf00d02c4, 0 x110d0000,
}, { // 11.3 MHz
0 x00000003, 0 xfffdffee, 0 x00040038, 0 x0010ff88,
0 xffac00c2, 0 x00e2ff10, 0 xfe3900cb, 0 x02f1ffe9,
0 xfbd3feaa, 0 x05210381, 0 xfa9cf9c8, 0 x04990912,
0 xfd7af484, 0 xff390cdb, 0 x04f4f34d, 0 xf69a0ac9,
0 x0d5af8c1, 0 xefec028e, 0 x110d0000,
}, { // 11.4 MHz
0 x00000003, 0 x0000ffee, 0 xfff60033, 0 x002fff9f,
0 xff7b0087, 0 x011eff82, 0 xfe080018, 0 x02f900d8,
0 xfc17fd96, 0 x04790490, 0 xfbadf8ed, 0 x032f098e,
0 xff10f47d, 0 xfdaf0c75, 0 x063cf3fc, 0 xf5ba0a0b,
0 x0dccf952, 0 xefcd0258, 0 x110d0000,
}, { // 11.5 MHz
0 x00000003, 0 x0004fff1, 0 xffea0026, 0 x0046ffc3,
0 xff5a003c, 0 x013b0000, 0 xfe04ff63, 0 x02c801b8,
0 xfc99fca6, 0 x0397056a, 0 xfcecf853, 0 x01ad09c9,
0 x00acf4ad, 0 xfc2e0be7, 0 x0773f4c2, 0 xf4e90943,
0 x0e35f9e6, 0 xefb10221, 0 x110d0000,
}, { // 11.6 MHz
0 x00000002, 0 x0007fff6, 0 xffe20014, 0 x0054ffee,
0 xff4effeb, 0 x0137007e, 0 xfe2efebb, 0 x0260027a,
0 xfd51fbe6, 0 x02870605, 0 xfe4af7fe, 0 x001d09c1,
0 x0243f515, 0 xfabd0b32, 0 x0897f59e, 0 xf4280871,
0 x0e95fa7c, 0 xef9701eb, 0 x110d0000,
}, { // 11.7 MHz
0 xffff0001, 0 x0008fffd, 0 xffdeffff, 0 x0056001d,
0 xff57ff9c, 0 x011300f0, 0 xfe82fe2e, 0 x01ca0310,
0 xfe35fb62, 0 x0155065a, 0 xffbaf7f2, 0 xfe8c0977,
0 x03cef5b2, 0 xf9610a58, 0 x09a5f68f, 0 xf3790797,
0 x0eebfb14, 0 xef8001b5, 0 x110d0000,
}, { // 11.8 MHz
0 xffff0000, 0 x00080004, 0 xffe0ffe9, 0 x004c0047,
0 xff75ff58, 0 x00d1014a, 0 xfef9fdc8, 0 x0111036f,
0 xff36fb21, 0 x00120665, 0 x012df82e, 0 xfd0708ec,
0 x0542f682, 0 xf81f095c, 0 x0a9af792, 0 xf2db06b5,
0 x0f38fbad, 0 xef6c017e, 0 x110d0000,
}, { // 11.9 MHz
0 xffffffff, 0 x0007000b, 0 xffe7ffd8, 0 x00370068,
0 xffa4ff28, 0 x00790184, 0 xff87fd91, 0 x00430392,
0 x0044fb26, 0 xfece0626, 0 x0294f8b2, 0 xfb990825,
0 x0698f77f, 0 xf6fe0842, 0 x0b73f8a7, 0 xf25105cd,
0 x0f7bfc48, 0 xef5a0148, 0 x110d0000,
}, { // 12.0 MHz
0 x0000fffe, 0 x00050010, 0 xfff2ffcc, 0 x001b007b,
0 xffdfff10, 0 x00140198, 0 x0020fd8e, 0 xff710375,
0 x014dfb73, 0 xfd9a059f, 0 x03e0f978, 0 xfa4e0726,
0 x07c8f8a7, 0 xf600070c, 0 x0c2ff9c9, 0 xf1db04de,
0 x0fb4fce5, 0 xef4b0111, 0 x110d0000,
}, { // 12.1 MHz
0 x0000fffd, 0 x00010012, 0 xffffffc8, 0 xfffb007e,
0 x001dff14, 0 xffad0184, 0 x00b7fdbe, 0 xfea9031b,
0 x0241fc01, 0 xfc8504d6, 0 x0504fa79, 0 xf93005f6,
0 x08caf9f2, 0 xf52b05c0, 0 x0ccbfaf9, 0 xf17903eb,
0 x0fe3fd83, 0 xef3f00db, 0 x110d0000,
}, { // 12.2 MHz
0 x0000fffd, 0 xfffe0011, 0 x000cffcc, 0 xffdb0071,
0 x0058ff32, 0 xff4f014a, 0 x013cfe1f, 0 xfdfb028a,
0 x0311fcc9, 0 xfb9d03d6, 0 x05f4fbad, 0 xf848049d,
0 x0999fb5b, 0 xf4820461, 0 x0d46fc32, 0 xf12d02f4,
0 x1007fe21, 0 xef3600a4, 0 x110d0000,
}, { // 12.3 MHz
0 x0000fffe, 0 xfffa000e, 0 x0017ffd9, 0 xffc10055,
0 x0088ff68, 0 xff0400f0, 0 x01a6fea7, 0 xfd7501cc,
0 x03b0fdc0, 0 xfaef02a8, 0 x06a7fd07, 0 xf79d0326,
0 x0a31fcda, 0 xf40702f3, 0 x0d9ffd72, 0 xf0f601fa,
0 x1021fec0, 0 xef2f006d, 0 x110d0000,
}, { // 12.4 MHz
0 x0001ffff, 0 xfff80007, 0 x001fffeb, 0 xffaf002d,
0 x00a8ffb0, 0 xfed3007e, 0 x01e9ff4c, 0 xfd2000ee,
0 x0413fed8, 0 xfa82015c, 0 x0715fe7d, 0 xf7340198,
0 x0a8dfe69, 0 xf3bd017c, 0 x0dd5feb8, 0 xf0d500fd,
0 x1031ff60, 0 xef2b0037, 0 x110d0000,
}, { // 12.5 MHz
0 x00010000, 0 xfff70000, 0 x00220000, 0 xffa90000,
0 x00b30000, 0 xfec20000, 0 x02000000, 0 xfd030000,
0 x04350000, 0 xfa5e0000, 0 x073b0000, 0 xf7110000,
0 x0aac0000, 0 xf3a40000, 0 x0de70000, 0 xf0c90000,
0 x10360000, 0 xef290000, 0 x110d0000,
}, { // 12.6 MHz
0 x00010001, 0 xfff8fff9, 0 x001f0015, 0 xffafffd3,
0 x00a80050, 0 xfed3ff82, 0 x01e900b4, 0 xfd20ff12,
0 x04130128, 0 xfa82fea4, 0 x07150183, 0 xf734fe68,
0 x0a8d0197, 0 xf3bdfe84, 0 x0dd50148, 0 xf0d5ff03,
0 x103100a0, 0 xef2bffc9, 0 x110d0000,
}, { // 12.7 MHz
0 x00000002, 0 xfffafff2, 0 x00170027, 0 xffc1ffab,
0 x00880098, 0 xff04ff10, 0 x01a60159, 0 xfd75fe34,
0 x03b00240, 0 xfaeffd58, 0 x06a702f9, 0 xf79dfcda,
0 x0a310326, 0 xf407fd0d, 0 x0d9f028e, 0 xf0f6fe06,
0 x10210140, 0 xef2fff93, 0 x110d0000,
}, { // 12.8 MHz
0 x00000003, 0 xfffeffef, 0 x000c0034, 0 xffdbff8f,
0 x005800ce, 0 xff4ffeb6, 0 x013c01e1, 0 xfdfbfd76,
0 x03110337, 0 xfb9dfc2a, 0 x05f40453, 0 xf848fb63,
0 x099904a5, 0 xf482fb9f, 0 x0d4603ce, 0 xf12dfd0c,
0 x100701df, 0 xef36ff5c, 0 x110d0000,
}, { // 12.9 MHz
0 x00000003, 0 x0001ffee, 0 xffff0038, 0 xfffbff82,
0 x001d00ec, 0 xffadfe7c, 0 x00b70242, 0 xfea9fce5,
0 x024103ff, 0 xfc85fb2a, 0 x05040587, 0 xf930fa0a,
0 x08ca060e, 0 xf52bfa40, 0 x0ccb0507, 0 xf179fc15,
0 x0fe3027d, 0 xef3fff25, 0 x110d0000,
}, { // 13.0 MHz
0 x00000002, 0 x0005fff0, 0 xfff20034, 0 x001bff85,
0 xffdf00f0, 0 x0014fe68, 0 x00200272, 0 xff71fc8b,
0 x014d048d, 0 xfd9afa61, 0 x03e00688, 0 xfa4ef8da,
0 x07c80759, 0 xf600f8f4, 0 x0c2f0637, 0 xf1dbfb22,
0 x0fb4031b, 0 xef4bfeef, 0 x110d0000,
}, { // 13.1 MHz
0 xffff0001, 0 x0007fff5, 0 xffe70028, 0 x0037ff98,
0 xffa400d8, 0 x0079fe7c, 0 xff87026f, 0 x0043fc6e,
0 x004404da, 0 xfecef9da, 0 x0294074e, 0 xfb99f7db,
0 x06980881, 0 xf6fef7be, 0 x0b730759, 0 xf251fa33,
0 x0f7b03b8, 0 xef5afeb8, 0 x110d0000,
}, { // 13.2 MHz
0 xffff0000, 0 x0008fffc, 0 xffe00017, 0 x004cffb9,
0 xff7500a8, 0 x00d1feb6, 0 xfef90238, 0 x0111fc91,
0 xff3604df, 0 x0012f99b, 0 x012d07d2, 0 xfd07f714,
0 x0542097e, 0 xf81ff6a4, 0 x0a9a086e, 0 xf2dbf94b,
0 x0f380453, 0 xef6cfe82, 0 x110d0000,
}, { // 13.3 MHz
0 xffffffff, 0 x00080003, 0 xffde0001, 0 x0056ffe3,
0 xff570064, 0 x0113ff10, 0 xfe8201d2, 0 x01cafcf0,
0 xfe35049e, 0 x0155f9a6, 0 xffba080e, 0 xfe8cf689,
0 x03ce0a4e, 0 xf961f5a8, 0 x09a50971, 0 xf379f869,
0 x0eeb04ec, 0 xef80fe4b, 0 x110d0000,
}, { // 13.4 MHz
0 x0000fffe, 0 x0007000a, 0 xffe2ffec, 0 x00540012,
0 xff4e0015, 0 x0137ff82, 0 xfe2e0145, 0 x0260fd86,
0 xfd51041a, 0 x0287f9fb, 0 xfe4a0802, 0 x001df63f,
0 x02430aeb, 0 xfabdf4ce, 0 x08970a62, 0 xf428f78f,
0 x0e950584, 0 xef97fe15, 0 x110d0000,
}, { // 13.5 MHz
0 x0000fffd, 0 x0004000f, 0 xffeaffda, 0 x0046003d,
0 xff5affc4, 0 x013b0000, 0 xfe04009d, 0 x02c8fe48,
0 xfc99035a, 0 x0397fa96, 0 xfcec07ad, 0 x01adf637,
0 x00ac0b53, 0 xfc2ef419, 0 x07730b3e, 0 xf4e9f6bd,
0 x0e35061a, 0 xefb1fddf, 0 x110d0000,
}, { // 13.6 MHz
0 x0000fffd, 0 x00000012, 0 xfff6ffcd, 0 x002f0061,
0 xff7bff79, 0 x011e007e, 0 xfe08ffe8, 0 x02f9ff28,
0 xfc17026a, 0 x0479fb70, 0 xfbad0713, 0 x032ff672,
0 xff100b83, 0 xfdaff38b, 0 x063c0c04, 0 xf5baf5f5,
0 x0dcc06ae, 0 xefcdfda8, 0 x110d0000,
}, { // 13.7 MHz
0 x0000fffd, 0 xfffd0012, 0 x0004ffc8, 0 x00100078,
0 xffacff3e, 0 x00e200f0, 0 xfe39ff35, 0 x02f10017,
0 xfbd30156, 0 x0521fc7f, 0 xfa9c0638, 0 x0499f6ee,
0 xfd7a0b7c, 0 xff39f325, 0 x04f40cb3, 0 xf69af537,
0 x0d5a073f, 0 xefecfd72, 0 x110d0000,
}, { // 13.8 MHz
0 x0001fffe, 0 xfffa000e, 0 x0011ffcb, 0 xfff0007f,
0 xffe7ff19, 0 x008f014a, 0 xfe94fe93, 0 x02b00105,
0 xfbd3002f, 0 x0585fdb7, 0 xf9c10525, 0 x05def7a8,
0 xfbf20b3c, 0 x00c7f2e9, 0 x03a00d48, 0 xf787f484,
0 x0cdf07cd, 0 xf00dfd3c, 0 x110d0000,
}, { // 13.9 MHz
0 x00010000, 0 xfff80008, 0 x001bffd7, 0 xffd10076,
0 x0026ff0e, 0 x002c0184, 0 xff0ffe10, 0 x023b01e0,
0 xfc17ff06, 0 x05a2ff09, 0 xf92703e4, 0 x06f4f89b,
0 xfa820ac5, 0 x0251f2d9, 0 x02430dc3, 0 xf881f3dc,
0 x0c5c0859, 0 xf031fd06, 0 x110d0000,
}, { // 14.0 MHz
0 x00010001, 0 xfff80001, 0 x0021ffe8, 0 xffba005d,
0 x0060ff1f, 0 xffc40198, 0 xffa0fdb5, 0 x019a029a,
0 xfc99fdea, 0 x05750067, 0 xf8d4027f, 0 x07d4f9c0,
0 xf9320a1a, 0 x03d2f2f3, 0 x00df0e22, 0 xf986f341,
0 x0bd108e2, 0 xf058fcd1, 0 x110d0000,
}, { // 14.1 MHz
0 x00000002, 0 xfff9fffa, 0 x0021fffd, 0 xffac0038,
0 x008eff4a, 0 xff630184, 0 x003afd8b, 0 x00da0326,
0 xfd51fced, 0 x050101c0, 0 xf8cb0103, 0 x0876fb10,
0 xf80a093e, 0 x0543f338, 0 xff7a0e66, 0 xfa94f2b2,
0 x0b3f0967, 0 xf081fc9b, 0 x110d0000,
}, { // 14.2 MHz
0 x00000003, 0 xfffbfff3, 0 x001d0013, 0 xffaa000b,
0 x00aaff89, 0 xff13014a, 0 x00cefd95, 0 x000a037b,
0 xfe35fc1d, 0 x044c0305, 0 xf90cff7e, 0 x08d5fc81,
0 xf7100834, 0 x069ff3a7, 0 xfe160e8d, 0 xfbaaf231,
0 x0aa509e9, 0 xf0adfc65, 0 x110d0000,
}, { // 14.3 MHz
0 x00000003, 0 xffffffef, 0 x00140025, 0 xffb4ffdd,
0 x00b2ffd6, 0 xfedb00f0, 0 x0150fdd3, 0 xff380391,
0 xff36fb85, 0 x035e0426, 0 xf994fdfe, 0 x08eefe0b,
0 xf6490702, 0 x07e1f43e, 0 xfcb60e97, 0 xfcc6f1be,
0 x0a040a67, 0 xf0dbfc30, 0 x110d0000,
}, { // 14.4 MHz
0 x00000003, 0 x0002ffee, 0 x00070033, 0 xffc9ffb4,
0 x00a40027, 0 xfec3007e, 0 x01b4fe3f, 0 xfe760369,
0 x0044fb2e, 0 x02450518, 0 xfa5ffc90, 0 x08c1ffa1,
0 xf5bc05ae, 0 x0902f4fc, 0 xfb600e85, 0 xfde7f15a,
0 x095d0ae2, 0 xf10cfbfb, 0 x110d0000,
}, { // 14.5 MHz
0 xffff0002, 0 x0005ffef, 0 xfffa0038, 0 xffe5ff95,
0 x00820074, 0 xfecc0000, 0 x01f0fed0, 0 xfdd20304,
0 x014dfb1d, 0 x010e05ce, 0 xfb64fb41, 0 x084e013b,
0 xf569043e, 0 x0a00f5dd, 0 xfa150e55, 0 xff0bf104,
0 x08b00b59, 0 xf13ffbc6, 0 x110d0000,
}, { // 14.6 MHz
0 xffff0001, 0 x0008fff4, 0 xffed0035, 0 x0005ff83,
0 x005000b4, 0 xfef6ff82, 0 x01ffff7a, 0 xfd580269,
0 x0241fb53, 0 xffca0640, 0 xfc99fa1e, 0 x079a02cb,
0 xf55502ba, 0 x0ad5f6e0, 0 xf8d90e0a, 0 x0031f0bd,
0 x07fd0bcb, 0 xf174fb91, 0 x110d0000,
}, { // 14.7 MHz
0 xffffffff, 0 x0009fffb, 0 xffe4002a, 0 x0025ff82,
0 x001400e0, 0 xff3cff10, 0 x01e10030, 0 xfd1201a4,
0 x0311fbcd, 0 xfe88066a, 0 xfdf1f92f, 0 x06aa0449,
0 xf57e0128, 0 x0b7ef801, 0 xf7b00da2, 0 x0156f086,
0 x07450c39, 0 xf1acfb5c, 0 x110d0000,
}, { // 14.8 MHz
0 x0000fffe, 0 x00080002, 0 xffdf0019, 0 x003fff92,
0 xffd600f1, 0 xff96feb6, 0 x019700e1, 0 xfd0500c2,
0 x03b0fc84, 0 xfd590649, 0 xff5df87f, 0 x058505aa,
0 xf5e4ff91, 0 x0bf9f93c, 0 xf69d0d20, 0 x0279f05e,
0 x06880ca3, 0 xf1e6fb28, 0 x110d0000,
}, { // 14.9 MHz
0 x0000fffd, 0 x00060009, 0 xffdf0004, 0 x0051ffb0,
0 xff9d00e8, 0 xfffcfe7c, 0 x01280180, 0 xfd32ffd2,
0 x0413fd6e, 0 xfc4d05df, 0 x00d1f812, 0 x043506e4,
0 xf685fdfb, 0 x0c43fa8d, 0 xf5a10c83, 0 x0399f046,
0 x05c70d08, 0 xf222faf3, 0 x110d0000,
}, { // 15.0 MHz
0 x0000fffd, 0 x0003000f, 0 xffe5ffef, 0 x0057ffd9,
0 xff7000c4, 0 x0062fe68, 0 x009e01ff, 0 xfd95fee6,
0 x0435fe7d, 0 xfb710530, 0 x023cf7ee, 0 x02c307ef,
0 xf75efc70, 0 x0c5cfbef, 0 xf4c10bce, 0 x04b3f03f,
0 x05030d69, 0 xf261fabf, 0 x110d0000,
}, { // 15.1 MHz
0 x0000fffd, 0 xffff0012, 0 xffefffdc, 0 x00510006,
0 xff540089, 0 x00befe7c, 0 x00060253, 0 xfe27fe0d,
0 x0413ffa2, 0 xfad10446, 0 x0390f812, 0 x013b08c3,
0 xf868faf6, 0 x0c43fd5f, 0 xf3fd0b02, 0 x05c7f046,
0 x043b0dc4, 0 xf2a1fa8b, 0 x110d0000,
}, { // 15.2 MHz
0 x0001fffe, 0 xfffc0012, 0 xfffbffce, 0 x003f0033,
0 xff4e003f, 0 x0106feb6, 0 xff6e0276, 0 xfeddfd56,
0 x03b000cc, 0 xfa740329, 0 x04bff87f, 0 xffaa095d,
0 xf99ef995, 0 x0bf9fed8, 0 xf3590a1f, 0 x06d2f05e,
0 x03700e1b, 0 xf2e4fa58, 0 x110d0000,
}, { // 15.3 MHz
0 x0001ffff, 0 xfff9000f, 0 x0009ffc8, 0 x00250059,
0 xff5effee, 0 x0132ff10, 0 xfee30265, 0 xffaafccf,
0 x031101eb, 0 xfa6001e8, 0 x05bdf92f, 0 xfe1b09b6,
0 xfafaf852, 0 x0b7e0055, 0 xf2d50929, 0 x07d3f086,
0 x02a30e6c, 0 xf329fa24, 0 x110d0000,
}, { // 15.4 MHz
0 x00010001, 0 xfff80009, 0 x0015ffca, 0 x00050074,
0 xff81ff9f, 0 x013dff82, 0 xfe710221, 0 x007cfc80,
0 x024102ed, 0 xfa940090, 0 x0680fa1e, 0 xfc9b09cd,
0 xfc73f736, 0 x0ad501d0, 0 xf2740820, 0 x08c9f0bd,
0 x01d40eb9, 0 xf371f9f1, 0 x110d0000,
}, { // 15.5 MHz
0 x00000002, 0 xfff80002, 0 x001effd5, 0 xffe5007f,
0 xffb4ff5b, 0 x01280000, 0 xfe2401b0, 0 x0146fc70,
0 x014d03c6, 0 xfb10ff32, 0 x0701fb41, 0 xfb3709a1,
0 xfe00f644, 0 x0a000345, 0 xf2350708, 0 x09b2f104,
0 x01050eff, 0 xf3baf9be, 0 x110d0000,
}, { // 15.6 MHz
0 x00000003, 0 xfff9fffb, 0 x0022ffe6, 0 xffc9007a,
0 xfff0ff29, 0 x00f2007e, 0 xfe01011b, 0 x01f6fc9e,
0 x00440467, 0 xfbccfdde, 0 x0738fc90, 0 xf9f70934,
0 xff99f582, 0 x090204b0, 0 xf21a05e1, 0 x0a8df15a,
0 x00340f41, 0 xf405f98b, 0 x110d0000,
}, { // 15.7 MHz
0 x00000003, 0 xfffcfff4, 0 x0020fffa, 0 xffb40064,
0 x002fff11, 0 x00a400f0, 0 xfe0d006e, 0 x0281fd09,
0 xff3604c9, 0 xfcbffca2, 0 x0726fdfe, 0 xf8e80888,
0 x0134f4f3, 0 x07e1060c, 0 xf22304af, 0 x0b59f1be,
0 xff640f7d, 0 xf452f959, 0 x110d0000,
}, { // 15.8 MHz
0 x00000003, 0 x0000fff0, 0 x001a0010, 0 xffaa0041,
0 x0067ff13, 0 x0043014a, 0 xfe46ffb9, 0 x02dbfda8,
0 xfe3504e5, 0 xfddcfb8d, 0 x06c9ff7e, 0 xf81107a2,
0 x02c9f49a, 0 x069f0753, 0 xf2500373, 0 x0c14f231,
0 xfe930fb3, 0 xf4a1f927, 0 x110d0000,
}, { // 15.9 MHz
0 xffff0002, 0 x0003ffee, 0 x000f0023, 0 xffac0016,
0 x0093ff31, 0 xffdc0184, 0 xfea6ff09, 0 x02fdfe70,
0 xfd5104ba, 0 xff15faac, 0 x06270103, 0 xf7780688,
0 x044df479, 0 x05430883, 0 xf2a00231, 0 x0cbef2b2,
0 xfdc40fe3, 0 xf4f2f8f5, 0 x110d0000,
}, { // 16.0 MHz
0 xffff0001, 0 x0006ffef, 0 x00020031, 0 xffbaffe8,
0 x00adff66, 0 xff790198, 0 xff26fe6e, 0 x02e5ff55,
0 xfc99044a, 0 x005bfa09, 0 x0545027f, 0 xf7230541,
0 x05b8f490, 0 x03d20997, 0 xf31300eb, 0 x0d55f341,
0 xfcf6100e, 0 xf544f8c3, 0 x110d0000,
}
};
static void cx23885_dif_setup(struct i2c_client *client, u32 ifHz)
{
u64 pll_freq;
u32 pll_freq_word;
const u32 *coeffs;
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);
coeffs = ifhz_coeffs[(ifHz - 3000000 ) / 100000 ];
cx25840_write4(client, DIF_BPF_COEFF01, coeffs[0 ]);
cx25840_write4(client, DIF_BPF_COEFF23, coeffs[1 ]);
cx25840_write4(client, DIF_BPF_COEFF45, coeffs[2 ]);
cx25840_write4(client, DIF_BPF_COEFF67, coeffs[3 ]);
cx25840_write4(client, DIF_BPF_COEFF89, coeffs[4 ]);
cx25840_write4(client, DIF_BPF_COEFF1011, coeffs[5 ]);
cx25840_write4(client, DIF_BPF_COEFF1213, coeffs[6 ]);
cx25840_write4(client, DIF_BPF_COEFF1415, coeffs[7 ]);
cx25840_write4(client, DIF_BPF_COEFF1617, coeffs[8 ]);
cx25840_write4(client, DIF_BPF_COEFF1819, coeffs[9 ]);
cx25840_write4(client, DIF_BPF_COEFF2021, coeffs[10 ]);
cx25840_write4(client, DIF_BPF_COEFF2223, coeffs[11 ]);
cx25840_write4(client, DIF_BPF_COEFF2425, coeffs[12 ]);
cx25840_write4(client, DIF_BPF_COEFF2627, coeffs[13 ]);
cx25840_write4(client, DIF_BPF_COEFF2829, coeffs[14 ]);
cx25840_write4(client, DIF_BPF_COEFF3031, coeffs[15 ]);
cx25840_write4(client, DIF_BPF_COEFF3233, coeffs[16 ]);
cx25840_write4(client, DIF_BPF_COEFF3435, coeffs[17 ]);
cx25840_write4(client, DIF_BPF_COEFF36, coeffs[18 ]);
}
static void cx23888_std_setup(struct i2c_client *client)
{
struct cx25840_state *state = to_state(i2c_get_clientdata(client));
v4l2_std_id std = state->std;
u32 ifHz;
cx25840_write4(client, 0 x478, 0 x6628021F);
cx25840_write4(client, 0 x400, 0 x0);
cx25840_write4(client, 0 x4b4, 0 x20524030);
cx25840_write4(client, 0 x47c, 0 x010a8263);
if (std & V4L2_STD_525_60) {
v4l_dbg(1 , cx25840_debug, client, "%s() Selecting NTSC" ,
__func__);
/* Horiz / vert timing */
cx25840_write4(client, 0 x428, 0 x1e1e601a);
cx25840_write4(client, 0 x424, 0 x5b2d007a);
/* DIF NTSC */
cx25840_write4(client, 0 x304, 0 x6503bc0c);
cx25840_write4(client, 0 x308, 0 xbd038c85);
cx25840_write4(client, 0 x30c, 0 x1db4640a);
cx25840_write4(client, 0 x310, 0 x00008800);
cx25840_write4(client, 0 x314, 0 x44400400);
cx25840_write4(client, 0 x32c, 0 x0c800800);
cx25840_write4(client, 0 x330, 0 x27000100);
cx25840_write4(client, 0 x334, 0 x1f296e1f);
cx25840_write4(client, 0 x338, 0 x009f50c1);
cx25840_write4(client, 0 x340, 0 x1befbf06);
cx25840_write4(client, 0 x344, 0 x000035e8);
/* DIF I/F */
ifHz = 5400000 ;
} else {
v4l_dbg(1 , cx25840_debug, client, "%s() Selecting PAL-BG" ,
__func__);
/* Horiz / vert timing */
cx25840_write4(client, 0 x428, 0 x28244024);
cx25840_write4(client, 0 x424, 0 x5d2d0084);
/* DIF */
cx25840_write4(client, 0 x304, 0 x6503bc0c);
cx25840_write4(client, 0 x308, 0 xbd038c85);
cx25840_write4(client, 0 x30c, 0 x1db4640a);
cx25840_write4(client, 0 x310, 0 x00008800);
cx25840_write4(client, 0 x314, 0 x44400600);
cx25840_write4(client, 0 x32c, 0 x0c800800);
cx25840_write4(client, 0 x330, 0 x27000100);
cx25840_write4(client, 0 x334, 0 x213530ec);
cx25840_write4(client, 0 x338, 0 x00a65ba8);
cx25840_write4(client, 0 x340, 0 x1befbf06);
cx25840_write4(client, 0 x344, 0 x000035e8);
/* DIF I/F */
ifHz = 6000000 ;
}
cx23885_dif_setup(client, ifHz);
/* Explicitly ensure the inputs are reconfigured after
* a standard change.
*/
set_input(client, state->vid_input, state->aud_input);
}
/* ----------------------------------------------------------------------- */
static const struct v4l2_ctrl_ops cx25840_ctrl_ops = {
.s_ctrl = cx25840_s_ctrl,
};
static const struct v4l2_subdev_core_ops cx25840_core_ops = {
.log_status = cx25840_log_status,
.reset = cx25840_reset,
/* calling the (optional) init op will turn on the generic mode */
.init = cx25840_init,
.load_fw = cx25840_load_fw,
.s_io_pin_config = common_s_io_pin_config,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.g_register = cx25840_g_register,
.s_register = cx25840_s_register,
#endif
.interrupt_service_routine = cx25840_irq_handler,
};
static const struct v4l2_subdev_tuner_ops cx25840_tuner_ops = {
.s_frequency = cx25840_s_frequency,
.s_radio = cx25840_s_radio,
.g_tuner = cx25840_g_tuner,
.s_tuner = cx25840_s_tuner,
};
static const struct v4l2_subdev_audio_ops cx25840_audio_ops = {
.s_clock_freq = cx25840_s_clock_freq,
.s_routing = cx25840_s_audio_routing,
.s_stream = cx25840_s_audio_stream,
};
static const struct v4l2_subdev_video_ops cx25840_video_ops = {
.g_std = cx25840_g_std,
.s_std = cx25840_s_std,
.querystd = cx25840_querystd,
.s_routing = cx25840_s_video_routing,
.s_stream = cx25840_s_stream,
.g_input_status = cx25840_g_input_status,
};
static const struct v4l2_subdev_vbi_ops cx25840_vbi_ops = {
.decode_vbi_line = cx25840_decode_vbi_line,
.s_raw_fmt = cx25840_s_raw_fmt,
.s_sliced_fmt = cx25840_s_sliced_fmt,
.g_sliced_fmt = cx25840_g_sliced_fmt,
};
static const struct v4l2_subdev_pad_ops cx25840_pad_ops = {
.set_fmt = cx25840_set_fmt,
};
static const struct v4l2_subdev_ops cx25840_ops = {
.core = &cx25840_core_ops,
.tuner = &cx25840_tuner_ops,
.audio = &cx25840_audio_ops,
.video = &cx25840_video_ops,
.vbi = &cx25840_vbi_ops,
.pad = &cx25840_pad_ops,
.ir = &cx25840_ir_ops,
};
/* ----------------------------------------------------------------------- */
static u32 get_cx2388x_ident(struct i2c_client *client)
{
u32 ret;
/* Come out of digital power down */
cx25840_write(client, 0 x000, 0 );
/*
* Detecting whether the part is cx23885/7/8 is more
* difficult than it needs to be. No ID register. Instead we
* probe certain registers indicated in the datasheets to look
* for specific defaults that differ between the silicon designs.
*/
/* It's either 885/7 if the IR Tx Clk Divider register exists */
if (cx25840_read4(client, 0 x204) & 0 xffff) {
/*
* CX23885 returns bogus repetitive byte values for the DIF,
* which doesn't exist for it. (Ex. 8a8a8a8a or 31313131)
*/
ret = cx25840_read4(client, 0 x300);
if (((ret & 0 xffff0000) >> 16 ) == (ret & 0 xffff)) {
/* No DIF */
ret = CX23885_AV;
} else {
/*
* CX23887 has a broken DIF, but the registers
* appear valid (but unused), good enough to detect.
*/
ret = CX23887_AV;
}
} else if (cx25840_read4(client, 0 x300) & 0 x0fffffff) {
/* DIF PLL Freq Word reg exists; chip must be a CX23888 */
ret = CX23888_AV;
} else {
v4l_err(client, "Unable to detect h/w, assuming cx23887\n" );
ret = CX23887_AV;
}
/* Back into digital power down */
cx25840_write(client, 0 x000, 2 );
return ret;
}
static int cx25840_probe(struct i2c_client *client)
{
struct cx25840_state *state;
struct v4l2_subdev *sd;
int default_volume;
u32 id;
u16 device_id;
#if defined (CONFIG_MEDIA_CONTROLLER)
int ret;
#endif
/* Check if the adapter supports the needed features */
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -EIO;
v4l_dbg(1 , cx25840_debug, client,
"detecting cx25840 client on address 0x%x\n" ,
client->addr << 1 );
device_id = cx25840_read(client, 0 x101) << 8 ;
device_id |= cx25840_read(client, 0 x100);
v4l_dbg(1 , cx25840_debug, client, "device_id = 0x%04x\n" , device_id);
/*
* The high byte of the device ID should be
* 0x83 for the cx2583x and 0x84 for the cx2584x
*/
if ((device_id & 0 xff00) == 0 x8300) {
id = CX25836 + ((device_id >> 4 ) & 0 xf) - 6 ;
} else if ((device_id & 0 xff00) == 0 x8400) {
id = CX25840 + ((device_id >> 4 ) & 0 xf);
} else if (device_id == 0 x0000) {
id = get_cx2388x_ident(client);
} else if ((device_id & 0 xfff0) == 0 x5A30) {
/* The CX23100 (0x5A3C = 23100) doesn't have an A/V decoder */
id = CX2310X_AV;
} else if ((device_id & 0 xff) == (device_id >> 8 )) {
v4l_err(client,
"likely a confused/unresponsive cx2388[578] A/V decoder found @ 0x%x (%s)\n" ,
client->addr << 1 , client->adapter->name);
v4l_err(client,
"A method to reset it from the cx25840 driver software is not known at this time\n" );
return -ENODEV;
} else {
v4l_dbg(1 , cx25840_debug, client, "cx25840 not found\n" );
return -ENODEV;
}
state = devm_kzalloc(&client->dev, sizeof (*state), GFP_KERNEL);
if (!state)
return -ENOMEM;
sd = &state->sd;
v4l2_i2c_subdev_init(sd, client, &cx25840_ops);
#if defined (CONFIG_MEDIA_CONTROLLER)
/*
* TODO: add media controller support for analog video inputs like
* composite, svideo, etc.
* A real input pad for this analog demod would be like:
* ___________
* TUNER --------> | |
* | |
* SVIDEO .......> | cx25840 |
* | |
* COMPOSITE1 ...> |_________|
*
* However, at least for now, there's no much gain on modelling
* those extra inputs. So, let's add it only when needed.
*/
state->pads[CX25840_PAD_INPUT].flags = MEDIA_PAD_FL_SINK;
state->pads[CX25840_PAD_INPUT].sig_type = PAD_SIGNAL_ANALOG;
state->pads[CX25840_PAD_VID_OUT].flags = MEDIA_PAD_FL_SOURCE;
state->pads[CX25840_PAD_VID_OUT].sig_type = PAD_SIGNAL_DV;
sd->entity.function = MEDIA_ENT_F_ATV_DECODER;
ret = media_entity_pads_init(&sd->entity, ARRAY_SIZE(state->pads),
state->pads);
if (ret < 0 ) {
v4l_info(client, "failed to initialize media entity!\n" );
return ret;
}
#endif
switch (id) {
case CX23885_AV:
v4l_info(client, "cx23885 A/V decoder found @ 0x%x (%s)\n" ,
client->addr << 1 , client->adapter->name);
break ;
case CX23887_AV:
v4l_info(client, "cx23887 A/V decoder found @ 0x%x (%s)\n" ,
client->addr << 1 , client->adapter->name);
break ;
case CX23888_AV:
v4l_info(client, "cx23888 A/V decoder found @ 0x%x (%s)\n" ,
client->addr << 1 , client->adapter->name);
break ;
case CX2310X_AV:
v4l_info(client, "cx%d A/V decoder found @ 0x%x (%s)\n" ,
device_id, client->addr << 1 , client->adapter->name);
break ;
case CX25840:
case CX25841:
case CX25842:
case CX25843:
/*
* Note: revision '(device_id & 0x0f) == 2' was never built.
* The marking skips from 0x1 == 22 to 0x3 == 23.
*/
v4l_info(client, "cx25%3x-2%x found @ 0x%x (%s)\n" ,
(device_id & 0 xfff0) >> 4 ,
(device_id & 0 x0f) < 3 ? (device_id & 0 x0f) + 1
: (device_id & 0 x0f),
client->addr << 1 , client->adapter->name);
break ;
case CX25836:
case CX25837:
default :
v4l_info(client, "cx25%3x-%x found @ 0x%x (%s)\n" ,
(device_id & 0 xfff0) >> 4 , device_id & 0 x0f,
client->addr << 1 , client->adapter->name);
break ;
}
state->c = client;
state->vid_input = CX25840_COMPOSITE7;
state->aud_input = CX25840_AUDIO8;
state->audclk_freq = 48000 ;
state->audmode = V4L2_TUNER_MODE_LANG1;
state->vbi_line_offset = 8 ;
state->id = id;
state->rev = device_id;
state->vbi_regs_offset = id == CX23888_AV ? 0 x500 - 0 x424 : 0 ;
state->std = V4L2_STD_NTSC_M;
v4l2_ctrl_handler_init(&state->hdl, 9 );
v4l2_ctrl_new_std(&state->hdl, &cx25840_ctrl_ops,
V4L2_CID_BRIGHTNESS, 0 , 255 , 1 , 128 );
v4l2_ctrl_new_std(&state->hdl, &cx25840_ctrl_ops,
V4L2_CID_CONTRAST, 0 , 127 , 1 , 64 );
v4l2_ctrl_new_std(&state->hdl, &cx25840_ctrl_ops,
V4L2_CID_SATURATION, 0 , 127 , 1 , 64 );
v4l2_ctrl_new_std(&state->hdl, &cx25840_ctrl_ops,
V4L2_CID_HUE, -128 , 127 , 1 , 0 );
if (!is_cx2583x(state)) {
default_volume = cx25840_read(client, 0 x8d4);
/*
* Enforce the legacy PVR-350/MSP3400 to PVR-150/CX25843 volume
* scale mapping limits to avoid -ERANGE errors when
* initializing the volume control
*/
if (default_volume > 228 ) {
/* Bottom out at -96 dB, v4l2 vol range 0x2e00-0x2fff */
default_volume = 228 ;
cx25840_write(client, 0 x8d4, 228 );
} else if (default_volume < 20 ) {
/* Top out at + 8 dB, v4l2 vol range 0xfe00-0xffff */
default_volume = 20 ;
cx25840_write(client, 0 x8d4, 20 );
}
default_volume = (((228 - default_volume) >> 1 ) + 23 ) << 9 ;
state->volume = v4l2_ctrl_new_std(&state->hdl,
&cx25840_audio_ctrl_ops,
V4L2_CID_AUDIO_VOLUME,
0 , 65535 , 65535 / 100 ,
default_volume);
state->mute = v4l2_ctrl_new_std(&state->hdl,
&cx25840_audio_ctrl_ops,
V4L2_CID_AUDIO_MUTE,
0 , 1 , 1 , 0 );
v4l2_ctrl_new_std(&state->hdl, &cx25840_audio_ctrl_ops,
V4L2_CID_AUDIO_BALANCE,
0 , 65535 , 65535 / 100 , 32768 );
v4l2_ctrl_new_std(&state->hdl, &cx25840_audio_ctrl_ops,
V4L2_CID_AUDIO_BASS,
0 , 65535 , 65535 / 100 , 32768 );
v4l2_ctrl_new_std(&state->hdl, &cx25840_audio_ctrl_ops,
V4L2_CID_AUDIO_TREBLE,
0 , 65535 , 65535 / 100 , 32768 );
}
sd->ctrl_handler = &state->hdl;
if (state->hdl.error) {
int err = state->hdl.error;
v4l2_ctrl_handler_free(&state->hdl);
return err;
}
if (!is_cx2583x(state))
v4l2_ctrl_cluster(2 , &state->volume);
v4l2_ctrl_handler_setup(&state->hdl);
if (client->dev.platform_data) {
struct cx25840_platform_data *pdata = client->dev.platform_data;
state->pvr150_workaround = pdata->pvr150_workaround;
}
cx25840_ir_probe(sd);
return 0 ;
}
static void cx25840_remove(struct i2c_client *client)
{
struct v4l2_subdev *sd = i2c_get_clientdata(client);
struct cx25840_state *state = to_state(sd);
cx25840_ir_remove(sd);
v4l2_device_unregister_subdev(sd);
v4l2_ctrl_handler_free(&state->hdl);
}
static const struct i2c_device_id cx25840_id[] = {
{ "cx25840" },
{ }
};
MODULE_DEVICE_TABLE(i2c, cx25840_id);
static struct i2c_driver cx25840_driver = {
.driver = {
.name = "cx25840" ,
},
.probe = cx25840_probe,
.remove = cx25840_remove,
.id_table = cx25840_id,
};
module_i2c_driver(cx25840_driver);
Messung V0.5 in Prozent C=95 H=90 G=92
¤ Dauer der Verarbeitung: 0.52 Sekunden
(vorverarbeitet am 2026-06-07)
¤
*© Formatika GbR, Deutschland