|
@@ -44,7 +44,7 @@
|
|
|
#include <linux/slab.h>
|
|
|
#include <linux/i2c.h>
|
|
|
#include <linux/videodev2.h>
|
|
|
-#include <media/v4l2-common.h>
|
|
|
+#include <media/v4l2-device.h>
|
|
|
#include <media/v4l2-chip-ident.h>
|
|
|
#include <media/v4l2-i2c-drv-legacy.h>
|
|
|
#include <media/saa7115.h>
|
|
@@ -70,6 +70,7 @@ static unsigned short normal_i2c[] = {
|
|
|
I2C_CLIENT_INSMOD;
|
|
|
|
|
|
struct saa711x_state {
|
|
|
+ struct v4l2_subdev sd;
|
|
|
v4l2_std_id std;
|
|
|
int input;
|
|
|
int output;
|
|
@@ -89,10 +90,17 @@ struct saa711x_state {
|
|
|
u8 apll;
|
|
|
};
|
|
|
|
|
|
+static inline struct saa711x_state *to_state(struct v4l2_subdev *sd)
|
|
|
+{
|
|
|
+ return container_of(sd, struct saa711x_state, sd);
|
|
|
+}
|
|
|
+
|
|
|
/* ----------------------------------------------------------------------- */
|
|
|
|
|
|
-static inline int saa711x_write(struct i2c_client *client, u8 reg, u8 value)
|
|
|
+static inline int saa711x_write(struct v4l2_subdev *sd, u8 reg, u8 value)
|
|
|
{
|
|
|
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
|
|
|
+
|
|
|
return i2c_smbus_write_byte_data(client, reg, value);
|
|
|
}
|
|
|
|
|
@@ -128,9 +136,9 @@ static int saa711x_has_reg(const int id, const u8 reg)
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
-static int saa711x_writeregs(struct i2c_client *client, const unsigned char *regs)
|
|
|
+static int saa711x_writeregs(struct v4l2_subdev *sd, const unsigned char *regs)
|
|
|
{
|
|
|
- struct saa711x_state *state = i2c_get_clientdata(client);
|
|
|
+ struct saa711x_state *state = to_state(sd);
|
|
|
unsigned char reg, data;
|
|
|
|
|
|
while (*regs != 0x00) {
|
|
@@ -139,18 +147,20 @@ static int saa711x_writeregs(struct i2c_client *client, const unsigned char *reg
|
|
|
|
|
|
/* According with datasheets, reserved regs should be
|
|
|
filled with 0 - seems better not to touch on they */
|
|
|
- if (saa711x_has_reg(state->ident,reg)) {
|
|
|
- if (saa711x_write(client, reg, data) < 0)
|
|
|
+ if (saa711x_has_reg(state->ident, reg)) {
|
|
|
+ if (saa711x_write(sd, reg, data) < 0)
|
|
|
return -1;
|
|
|
} else {
|
|
|
- v4l_dbg(1, debug, client, "tried to access reserved reg 0x%02x\n", reg);
|
|
|
+ v4l2_dbg(1, debug, sd, "tried to access reserved reg 0x%02x\n", reg);
|
|
|
}
|
|
|
}
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static inline int saa711x_read(struct i2c_client *client, u8 reg)
|
|
|
+static inline int saa711x_read(struct v4l2_subdev *sd, u8 reg)
|
|
|
{
|
|
|
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
|
|
|
+
|
|
|
return i2c_smbus_read_byte_data(client, reg);
|
|
|
}
|
|
|
|
|
@@ -601,7 +611,7 @@ static int saa711x_odd_parity(u8 c)
|
|
|
return c & 1;
|
|
|
}
|
|
|
|
|
|
-static int saa711x_decode_vps(u8 * dst, u8 * p)
|
|
|
+static int saa711x_decode_vps(u8 *dst, u8 *p)
|
|
|
{
|
|
|
static const u8 biphase_tbl[] = {
|
|
|
0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
|
|
@@ -648,7 +658,7 @@ static int saa711x_decode_vps(u8 * dst, u8 * p)
|
|
|
return err & 0xf0;
|
|
|
}
|
|
|
|
|
|
-static int saa711x_decode_wss(u8 * p)
|
|
|
+static int saa711x_decode_wss(u8 *p)
|
|
|
{
|
|
|
static const int wss_bits[8] = {
|
|
|
0, 0, 0, 1, 0, 1, 1, 1
|
|
@@ -675,9 +685,9 @@ static int saa711x_decode_wss(u8 * p)
|
|
|
return wss;
|
|
|
}
|
|
|
|
|
|
-static int saa711x_set_audio_clock_freq(struct i2c_client *client, u32 freq)
|
|
|
+static int saa711x_s_clock_freq(struct v4l2_subdev *sd, u32 freq)
|
|
|
{
|
|
|
- struct saa711x_state *state = i2c_get_clientdata(client);
|
|
|
+ struct saa711x_state *state = to_state(sd);
|
|
|
u32 acpf;
|
|
|
u32 acni;
|
|
|
u32 hz;
|
|
@@ -685,10 +695,10 @@ static int saa711x_set_audio_clock_freq(struct i2c_client *client, u32 freq)
|
|
|
u8 acc = 0; /* reg 0x3a, audio clock control */
|
|
|
|
|
|
/* Checks for chips that don't have audio clock (saa7111, saa7113) */
|
|
|
- if (!saa711x_has_reg(state->ident,R_30_AUD_MAST_CLK_CYCLES_PER_FIELD))
|
|
|
+ if (!saa711x_has_reg(state->ident, R_30_AUD_MAST_CLK_CYCLES_PER_FIELD))
|
|
|
return 0;
|
|
|
|
|
|
- v4l_dbg(1, debug, client, "set audio clock freq: %d\n", freq);
|
|
|
+ v4l2_dbg(1, debug, sd, "set audio clock freq: %d\n", freq);
|
|
|
|
|
|
/* sanity check */
|
|
|
if (freq < 32000 || freq > 48000)
|
|
@@ -715,66 +725,66 @@ static int saa711x_set_audio_clock_freq(struct i2c_client *client, u32 freq)
|
|
|
if (state->apll)
|
|
|
acc |= 0x08;
|
|
|
|
|
|
- saa711x_write(client, R_38_CLK_RATIO_AMXCLK_TO_ASCLK, 0x03);
|
|
|
- saa711x_write(client, R_39_CLK_RATIO_ASCLK_TO_ALRCLK, 0x10);
|
|
|
- saa711x_write(client, R_3A_AUD_CLK_GEN_BASIC_SETUP, acc);
|
|
|
+ saa711x_write(sd, R_38_CLK_RATIO_AMXCLK_TO_ASCLK, 0x03);
|
|
|
+ saa711x_write(sd, R_39_CLK_RATIO_ASCLK_TO_ALRCLK, 0x10);
|
|
|
+ saa711x_write(sd, R_3A_AUD_CLK_GEN_BASIC_SETUP, acc);
|
|
|
|
|
|
- saa711x_write(client, R_30_AUD_MAST_CLK_CYCLES_PER_FIELD, acpf & 0xff);
|
|
|
- saa711x_write(client, R_30_AUD_MAST_CLK_CYCLES_PER_FIELD+1,
|
|
|
+ saa711x_write(sd, R_30_AUD_MAST_CLK_CYCLES_PER_FIELD, acpf & 0xff);
|
|
|
+ saa711x_write(sd, R_30_AUD_MAST_CLK_CYCLES_PER_FIELD+1,
|
|
|
(acpf >> 8) & 0xff);
|
|
|
- saa711x_write(client, R_30_AUD_MAST_CLK_CYCLES_PER_FIELD+2,
|
|
|
+ saa711x_write(sd, R_30_AUD_MAST_CLK_CYCLES_PER_FIELD+2,
|
|
|
(acpf >> 16) & 0x03);
|
|
|
|
|
|
- saa711x_write(client, R_34_AUD_MAST_CLK_NOMINAL_INC, acni & 0xff);
|
|
|
- saa711x_write(client, R_34_AUD_MAST_CLK_NOMINAL_INC+1, (acni >> 8) & 0xff);
|
|
|
- saa711x_write(client, R_34_AUD_MAST_CLK_NOMINAL_INC+2, (acni >> 16) & 0x3f);
|
|
|
+ saa711x_write(sd, R_34_AUD_MAST_CLK_NOMINAL_INC, acni & 0xff);
|
|
|
+ saa711x_write(sd, R_34_AUD_MAST_CLK_NOMINAL_INC+1, (acni >> 8) & 0xff);
|
|
|
+ saa711x_write(sd, R_34_AUD_MAST_CLK_NOMINAL_INC+2, (acni >> 16) & 0x3f);
|
|
|
state->audclk_freq = freq;
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static int saa711x_set_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
|
|
|
+static int saa711x_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
|
|
|
{
|
|
|
- struct saa711x_state *state = i2c_get_clientdata(client);
|
|
|
+ struct saa711x_state *state = to_state(sd);
|
|
|
|
|
|
switch (ctrl->id) {
|
|
|
case V4L2_CID_BRIGHTNESS:
|
|
|
if (ctrl->value < 0 || ctrl->value > 255) {
|
|
|
- v4l_err(client, "invalid brightness setting %d\n", ctrl->value);
|
|
|
+ v4l2_err(sd, "invalid brightness setting %d\n", ctrl->value);
|
|
|
return -ERANGE;
|
|
|
}
|
|
|
|
|
|
state->bright = ctrl->value;
|
|
|
- saa711x_write(client, R_0A_LUMA_BRIGHT_CNTL, state->bright);
|
|
|
+ saa711x_write(sd, R_0A_LUMA_BRIGHT_CNTL, state->bright);
|
|
|
break;
|
|
|
|
|
|
case V4L2_CID_CONTRAST:
|
|
|
if (ctrl->value < 0 || ctrl->value > 127) {
|
|
|
- v4l_err(client, "invalid contrast setting %d\n", ctrl->value);
|
|
|
+ v4l2_err(sd, "invalid contrast setting %d\n", ctrl->value);
|
|
|
return -ERANGE;
|
|
|
}
|
|
|
|
|
|
state->contrast = ctrl->value;
|
|
|
- saa711x_write(client, R_0B_LUMA_CONTRAST_CNTL, state->contrast);
|
|
|
+ saa711x_write(sd, R_0B_LUMA_CONTRAST_CNTL, state->contrast);
|
|
|
break;
|
|
|
|
|
|
case V4L2_CID_SATURATION:
|
|
|
if (ctrl->value < 0 || ctrl->value > 127) {
|
|
|
- v4l_err(client, "invalid saturation setting %d\n", ctrl->value);
|
|
|
+ v4l2_err(sd, "invalid saturation setting %d\n", ctrl->value);
|
|
|
return -ERANGE;
|
|
|
}
|
|
|
|
|
|
state->sat = ctrl->value;
|
|
|
- saa711x_write(client, R_0C_CHROMA_SAT_CNTL, state->sat);
|
|
|
+ saa711x_write(sd, R_0C_CHROMA_SAT_CNTL, state->sat);
|
|
|
break;
|
|
|
|
|
|
case V4L2_CID_HUE:
|
|
|
if (ctrl->value < -127 || ctrl->value > 127) {
|
|
|
- v4l_err(client, "invalid hue setting %d\n", ctrl->value);
|
|
|
+ v4l2_err(sd, "invalid hue setting %d\n", ctrl->value);
|
|
|
return -ERANGE;
|
|
|
}
|
|
|
|
|
|
state->hue = ctrl->value;
|
|
|
- saa711x_write(client, R_0D_CHROMA_HUE_CNTL, state->hue);
|
|
|
+ saa711x_write(sd, R_0D_CHROMA_HUE_CNTL, state->hue);
|
|
|
break;
|
|
|
|
|
|
default:
|
|
@@ -784,9 +794,9 @@ static int saa711x_set_v4lctrl(struct i2c_client *client, struct v4l2_control *c
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static int saa711x_get_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
|
|
|
+static int saa711x_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
|
|
|
{
|
|
|
- struct saa711x_state *state = i2c_get_clientdata(client);
|
|
|
+ struct saa711x_state *state = to_state(sd);
|
|
|
|
|
|
switch (ctrl->id) {
|
|
|
case V4L2_CID_BRIGHTNESS:
|
|
@@ -808,16 +818,16 @@ static int saa711x_get_v4lctrl(struct i2c_client *client, struct v4l2_control *c
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static int saa711x_set_size(struct i2c_client *client, int width, int height)
|
|
|
+static int saa711x_set_size(struct v4l2_subdev *sd, int width, int height)
|
|
|
{
|
|
|
- struct saa711x_state *state = i2c_get_clientdata(client);
|
|
|
+ struct saa711x_state *state = to_state(sd);
|
|
|
int HPSC, HFSC;
|
|
|
int VSCY;
|
|
|
int res;
|
|
|
int is_50hz = state->std & V4L2_STD_625_50;
|
|
|
int Vsrc = is_50hz ? 576 : 480;
|
|
|
|
|
|
- v4l_dbg(1, debug, client, "decoder set size to %ix%i\n",width,height);
|
|
|
+ v4l2_dbg(1, debug, sd, "decoder set size to %ix%i\n", width, height);
|
|
|
|
|
|
/* FIXME need better bounds checking here */
|
|
|
if ((width < 1) || (width > 1440))
|
|
@@ -825,7 +835,7 @@ static int saa711x_set_size(struct i2c_client *client, int width, int height)
|
|
|
if ((height < 1) || (height > Vsrc))
|
|
|
return -EINVAL;
|
|
|
|
|
|
- if (!saa711x_has_reg(state->ident,R_D0_B_HORIZ_PRESCALING)) {
|
|
|
+ if (!saa711x_has_reg(state->ident, R_D0_B_HORIZ_PRESCALING)) {
|
|
|
/* Decoder only supports 720 columns and 480 or 576 lines */
|
|
|
if (width != 720)
|
|
|
return -EINVAL;
|
|
@@ -843,22 +853,22 @@ static int saa711x_set_size(struct i2c_client *client, int width, int height)
|
|
|
/* Set output width/height */
|
|
|
/* width */
|
|
|
|
|
|
- saa711x_write(client, R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH,
|
|
|
+ saa711x_write(sd, R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH,
|
|
|
(u8) (width & 0xff));
|
|
|
- saa711x_write(client, R_CD_B_HORIZ_OUTPUT_WINDOW_LENGTH_MSB,
|
|
|
+ saa711x_write(sd, R_CD_B_HORIZ_OUTPUT_WINDOW_LENGTH_MSB,
|
|
|
(u8) ((width >> 8) & 0xff));
|
|
|
|
|
|
/* Vertical Scaling uses height/2 */
|
|
|
- res=height/2;
|
|
|
+ res = height / 2;
|
|
|
|
|
|
/* On 60Hz, it is using a higher Vertical Output Size */
|
|
|
if (!is_50hz)
|
|
|
res += (VRES_60HZ - 480) >> 1;
|
|
|
|
|
|
/* height */
|
|
|
- saa711x_write(client, R_CE_B_VERT_OUTPUT_WINDOW_LENGTH,
|
|
|
+ saa711x_write(sd, R_CE_B_VERT_OUTPUT_WINDOW_LENGTH,
|
|
|
(u8) (res & 0xff));
|
|
|
- saa711x_write(client, R_CF_B_VERT_OUTPUT_WINDOW_LENGTH_MSB,
|
|
|
+ saa711x_write(sd, R_CF_B_VERT_OUTPUT_WINDOW_LENGTH_MSB,
|
|
|
(u8) ((res >> 8) & 0xff));
|
|
|
|
|
|
/* Scaling settings */
|
|
@@ -869,54 +879,54 @@ static int saa711x_set_size(struct i2c_client *client, int width, int height)
|
|
|
HFSC = (int)((1024 * 720) / (HPSC * width));
|
|
|
/* FIXME hardcodes to "Task B"
|
|
|
* write H prescaler integer */
|
|
|
- saa711x_write(client, R_D0_B_HORIZ_PRESCALING,
|
|
|
+ saa711x_write(sd, R_D0_B_HORIZ_PRESCALING,
|
|
|
(u8) (HPSC & 0x3f));
|
|
|
|
|
|
- v4l_dbg(1, debug, client, "Hpsc: 0x%05x, Hfsc: 0x%05x\n", HPSC, HFSC);
|
|
|
+ v4l2_dbg(1, debug, sd, "Hpsc: 0x%05x, Hfsc: 0x%05x\n", HPSC, HFSC);
|
|
|
/* write H fine-scaling (luminance) */
|
|
|
- saa711x_write(client, R_D8_B_HORIZ_LUMA_SCALING_INC,
|
|
|
+ saa711x_write(sd, R_D8_B_HORIZ_LUMA_SCALING_INC,
|
|
|
(u8) (HFSC & 0xff));
|
|
|
- saa711x_write(client, R_D9_B_HORIZ_LUMA_SCALING_INC_MSB,
|
|
|
+ saa711x_write(sd, R_D9_B_HORIZ_LUMA_SCALING_INC_MSB,
|
|
|
(u8) ((HFSC >> 8) & 0xff));
|
|
|
/* write H fine-scaling (chrominance)
|
|
|
* must be lum/2, so i'll just bitshift :) */
|
|
|
- saa711x_write(client, R_DC_B_HORIZ_CHROMA_SCALING,
|
|
|
+ saa711x_write(sd, R_DC_B_HORIZ_CHROMA_SCALING,
|
|
|
(u8) ((HFSC >> 1) & 0xff));
|
|
|
- saa711x_write(client, R_DD_B_HORIZ_CHROMA_SCALING_MSB,
|
|
|
+ saa711x_write(sd, R_DD_B_HORIZ_CHROMA_SCALING_MSB,
|
|
|
(u8) ((HFSC >> 9) & 0xff));
|
|
|
|
|
|
VSCY = (int)((1024 * Vsrc) / height);
|
|
|
- v4l_dbg(1, debug, client, "Vsrc: %d, Vscy: 0x%05x\n", Vsrc, VSCY);
|
|
|
+ v4l2_dbg(1, debug, sd, "Vsrc: %d, Vscy: 0x%05x\n", Vsrc, VSCY);
|
|
|
|
|
|
/* Correct Contrast and Luminance */
|
|
|
- saa711x_write(client, R_D5_B_LUMA_CONTRAST_CNTL,
|
|
|
+ saa711x_write(sd, R_D5_B_LUMA_CONTRAST_CNTL,
|
|
|
(u8) (64 * 1024 / VSCY));
|
|
|
- saa711x_write(client, R_D6_B_CHROMA_SATURATION_CNTL,
|
|
|
+ saa711x_write(sd, R_D6_B_CHROMA_SATURATION_CNTL,
|
|
|
(u8) (64 * 1024 / VSCY));
|
|
|
|
|
|
/* write V fine-scaling (luminance) */
|
|
|
- saa711x_write(client, R_E0_B_VERT_LUMA_SCALING_INC,
|
|
|
+ saa711x_write(sd, R_E0_B_VERT_LUMA_SCALING_INC,
|
|
|
(u8) (VSCY & 0xff));
|
|
|
- saa711x_write(client, R_E1_B_VERT_LUMA_SCALING_INC_MSB,
|
|
|
+ saa711x_write(sd, R_E1_B_VERT_LUMA_SCALING_INC_MSB,
|
|
|
(u8) ((VSCY >> 8) & 0xff));
|
|
|
/* write V fine-scaling (chrominance) */
|
|
|
- saa711x_write(client, R_E2_B_VERT_CHROMA_SCALING_INC,
|
|
|
+ saa711x_write(sd, R_E2_B_VERT_CHROMA_SCALING_INC,
|
|
|
(u8) (VSCY & 0xff));
|
|
|
- saa711x_write(client, R_E3_B_VERT_CHROMA_SCALING_INC_MSB,
|
|
|
+ saa711x_write(sd, R_E3_B_VERT_CHROMA_SCALING_INC_MSB,
|
|
|
(u8) ((VSCY >> 8) & 0xff));
|
|
|
|
|
|
- saa711x_writeregs(client, saa7115_cfg_reset_scaler);
|
|
|
+ saa711x_writeregs(sd, saa7115_cfg_reset_scaler);
|
|
|
|
|
|
/* Activates task "B" */
|
|
|
- saa711x_write(client, R_80_GLOBAL_CNTL_1,
|
|
|
- saa711x_read(client,R_80_GLOBAL_CNTL_1) | 0x20);
|
|
|
+ saa711x_write(sd, R_80_GLOBAL_CNTL_1,
|
|
|
+ saa711x_read(sd, R_80_GLOBAL_CNTL_1) | 0x20);
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static void saa711x_set_v4lstd(struct i2c_client *client, v4l2_std_id std)
|
|
|
+static void saa711x_set_v4lstd(struct v4l2_subdev *sd, v4l2_std_id std)
|
|
|
{
|
|
|
- struct saa711x_state *state = i2c_get_clientdata(client);
|
|
|
+ struct saa711x_state *state = to_state(sd);
|
|
|
|
|
|
/* Prevent unnecessary standard changes. During a standard
|
|
|
change the I-Port is temporarily disabled. Any devices
|
|
@@ -932,13 +942,13 @@ static void saa711x_set_v4lstd(struct i2c_client *client, v4l2_std_id std)
|
|
|
|
|
|
// This works for NTSC-M, SECAM-L and the 50Hz PAL variants.
|
|
|
if (std & V4L2_STD_525_60) {
|
|
|
- v4l_dbg(1, debug, client, "decoder set standard 60 Hz\n");
|
|
|
- saa711x_writeregs(client, saa7115_cfg_60hz_video);
|
|
|
- saa711x_set_size(client, 720, 480);
|
|
|
+ v4l2_dbg(1, debug, sd, "decoder set standard 60 Hz\n");
|
|
|
+ saa711x_writeregs(sd, saa7115_cfg_60hz_video);
|
|
|
+ saa711x_set_size(sd, 720, 480);
|
|
|
} else {
|
|
|
- v4l_dbg(1, debug, client, "decoder set standard 50 Hz\n");
|
|
|
- saa711x_writeregs(client, saa7115_cfg_50hz_video);
|
|
|
- saa711x_set_size(client, 720, 576);
|
|
|
+ v4l2_dbg(1, debug, sd, "decoder set standard 50 Hz\n");
|
|
|
+ saa711x_writeregs(sd, saa7115_cfg_50hz_video);
|
|
|
+ saa711x_set_size(sd, 720, 576);
|
|
|
}
|
|
|
|
|
|
/* Register 0E - Bits D6-D4 on NO-AUTO mode
|
|
@@ -952,7 +962,7 @@ static void saa711x_set_v4lstd(struct i2c_client *client, v4l2_std_id std)
|
|
|
*/
|
|
|
if (state->ident == V4L2_IDENT_SAA7111 ||
|
|
|
state->ident == V4L2_IDENT_SAA7113) {
|
|
|
- u8 reg = saa711x_read(client, R_0E_CHROMA_CNTL_1) & 0x8f;
|
|
|
+ u8 reg = saa711x_read(sd, R_0E_CHROMA_CNTL_1) & 0x8f;
|
|
|
|
|
|
if (std == V4L2_STD_PAL_M) {
|
|
|
reg |= 0x30;
|
|
@@ -965,87 +975,31 @@ static void saa711x_set_v4lstd(struct i2c_client *client, v4l2_std_id std)
|
|
|
} else if (std & V4L2_STD_SECAM) {
|
|
|
reg |= 0x50;
|
|
|
}
|
|
|
- saa711x_write(client, R_0E_CHROMA_CNTL_1, reg);
|
|
|
+ saa711x_write(sd, R_0E_CHROMA_CNTL_1, reg);
|
|
|
} else {
|
|
|
/* restart task B if needed */
|
|
|
- int taskb = saa711x_read(client, R_80_GLOBAL_CNTL_1) & 0x10;
|
|
|
+ int taskb = saa711x_read(sd, R_80_GLOBAL_CNTL_1) & 0x10;
|
|
|
|
|
|
if (taskb && state->ident == V4L2_IDENT_SAA7114) {
|
|
|
- saa711x_writeregs(client, saa7115_cfg_vbi_on);
|
|
|
+ saa711x_writeregs(sd, saa7115_cfg_vbi_on);
|
|
|
}
|
|
|
|
|
|
/* switch audio mode too! */
|
|
|
- saa711x_set_audio_clock_freq(client, state->audclk_freq);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-static v4l2_std_id saa711x_get_v4lstd(struct i2c_client *client)
|
|
|
-{
|
|
|
- struct saa711x_state *state = i2c_get_clientdata(client);
|
|
|
-
|
|
|
- return state->std;
|
|
|
-}
|
|
|
-
|
|
|
-static void saa711x_log_status(struct i2c_client *client)
|
|
|
-{
|
|
|
- struct saa711x_state *state = i2c_get_clientdata(client);
|
|
|
- int reg1e, reg1f;
|
|
|
- int signalOk;
|
|
|
- int vcr;
|
|
|
-
|
|
|
- v4l_info(client, "Audio frequency: %d Hz\n", state->audclk_freq);
|
|
|
- if (state->ident != V4L2_IDENT_SAA7115) {
|
|
|
- /* status for the saa7114 */
|
|
|
- reg1f = saa711x_read(client, R_1F_STATUS_BYTE_2_VD_DEC);
|
|
|
- signalOk = (reg1f & 0xc1) == 0x81;
|
|
|
- v4l_info(client, "Video signal: %s\n", signalOk ? "ok" : "bad");
|
|
|
- v4l_info(client, "Frequency: %s\n", (reg1f & 0x20) ? "60 Hz" : "50 Hz");
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- /* status for the saa7115 */
|
|
|
- reg1e = saa711x_read(client, R_1E_STATUS_BYTE_1_VD_DEC);
|
|
|
- reg1f = saa711x_read(client, R_1F_STATUS_BYTE_2_VD_DEC);
|
|
|
-
|
|
|
- signalOk = (reg1f & 0xc1) == 0x81 && (reg1e & 0xc0) == 0x80;
|
|
|
- vcr = !(reg1f & 0x10);
|
|
|
-
|
|
|
- if (state->input >= 6) {
|
|
|
- v4l_info(client, "Input: S-Video %d\n", state->input - 6);
|
|
|
- } else {
|
|
|
- v4l_info(client, "Input: Composite %d\n", state->input);
|
|
|
+ saa711x_s_clock_freq(sd, state->audclk_freq);
|
|
|
}
|
|
|
- v4l_info(client, "Video signal: %s\n", signalOk ? (vcr ? "VCR" : "broadcast/DVD") : "bad");
|
|
|
- v4l_info(client, "Frequency: %s\n", (reg1f & 0x20) ? "60 Hz" : "50 Hz");
|
|
|
-
|
|
|
- switch (reg1e & 0x03) {
|
|
|
- case 1:
|
|
|
- v4l_info(client, "Detected format: NTSC\n");
|
|
|
- break;
|
|
|
- case 2:
|
|
|
- v4l_info(client, "Detected format: PAL\n");
|
|
|
- break;
|
|
|
- case 3:
|
|
|
- v4l_info(client, "Detected format: SECAM\n");
|
|
|
- break;
|
|
|
- default:
|
|
|
- v4l_info(client, "Detected format: BW/No color\n");
|
|
|
- break;
|
|
|
- }
|
|
|
- v4l_info(client, "Width, Height: %d, %d\n", state->width, state->height);
|
|
|
}
|
|
|
|
|
|
/* setup the sliced VBI lcr registers according to the sliced VBI format */
|
|
|
-static void saa711x_set_lcr(struct i2c_client *client, struct v4l2_sliced_vbi_format *fmt)
|
|
|
+static void saa711x_set_lcr(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *fmt)
|
|
|
{
|
|
|
- struct saa711x_state *state = i2c_get_clientdata(client);
|
|
|
+ struct saa711x_state *state = to_state(sd);
|
|
|
int is_50hz = (state->std & V4L2_STD_625_50);
|
|
|
u8 lcr[24];
|
|
|
int i, x;
|
|
|
|
|
|
#if 1
|
|
|
/* saa7113/7114/7118 VBI support are experimental */
|
|
|
- if (!saa711x_has_reg(state->ident,R_41_LCR_BASE))
|
|
|
+ if (!saa711x_has_reg(state->ident, R_41_LCR_BASE))
|
|
|
return;
|
|
|
|
|
|
#else
|
|
@@ -1109,16 +1063,16 @@ static void saa711x_set_lcr(struct i2c_client *client, struct v4l2_sliced_vbi_fo
|
|
|
|
|
|
/* write the lcr registers */
|
|
|
for (i = 2; i <= 23; i++) {
|
|
|
- saa711x_write(client, i - 2 + R_41_LCR_BASE, lcr[i]);
|
|
|
+ saa711x_write(sd, i - 2 + R_41_LCR_BASE, lcr[i]);
|
|
|
}
|
|
|
|
|
|
/* enable/disable raw VBI capturing */
|
|
|
- saa711x_writeregs(client, fmt == NULL ?
|
|
|
+ saa711x_writeregs(sd, fmt == NULL ?
|
|
|
saa7115_cfg_vbi_on :
|
|
|
saa7115_cfg_vbi_off);
|
|
|
}
|
|
|
|
|
|
-static int saa711x_get_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
|
|
|
+static int saa711x_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
|
|
|
{
|
|
|
static u16 lcr2vbi[] = {
|
|
|
0, V4L2_SLICED_TELETEXT_B, 0, /* 1 */
|
|
@@ -1134,10 +1088,10 @@ static int saa711x_get_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt
|
|
|
return -EINVAL;
|
|
|
memset(sliced, 0, sizeof(*sliced));
|
|
|
/* done if using raw VBI */
|
|
|
- if (saa711x_read(client, R_80_GLOBAL_CNTL_1) & 0x10)
|
|
|
+ if (saa711x_read(sd, R_80_GLOBAL_CNTL_1) & 0x10)
|
|
|
return 0;
|
|
|
for (i = 2; i <= 23; i++) {
|
|
|
- u8 v = saa711x_read(client, i - 2 + R_41_LCR_BASE);
|
|
|
+ u8 v = saa711x_read(sd, i - 2 + R_41_LCR_BASE);
|
|
|
|
|
|
sliced->service_lines[0][i] = lcr2vbi[v >> 4];
|
|
|
sliced->service_lines[1][i] = lcr2vbi[v & 0xf];
|
|
@@ -1147,20 +1101,20 @@ static int saa711x_get_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static int saa711x_set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
|
|
|
+static int saa711x_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
|
|
|
{
|
|
|
if (fmt->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {
|
|
|
- saa711x_set_lcr(client, &fmt->fmt.sliced);
|
|
|
+ saa711x_set_lcr(sd, &fmt->fmt.sliced);
|
|
|
return 0;
|
|
|
}
|
|
|
if (fmt->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
|
|
|
- saa711x_set_lcr(client, NULL);
|
|
|
+ saa711x_set_lcr(sd, NULL);
|
|
|
return 0;
|
|
|
}
|
|
|
if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
|
|
|
return -EINVAL;
|
|
|
|
|
|
- return saa711x_set_size(client,fmt->fmt.pix.width,fmt->fmt.pix.height);
|
|
|
+ return saa711x_set_size(sd, fmt->fmt.pix.width, fmt->fmt.pix.height);
|
|
|
}
|
|
|
|
|
|
/* Decode the sliced VBI data stream as created by the saa7115.
|
|
@@ -1169,13 +1123,12 @@ static int saa711x_set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt
|
|
|
The current implementation uses SAV/EAV codes and not the ancillary data
|
|
|
headers. The vbi->p pointer points to the R_5E_SDID byte right after the SAV
|
|
|
code. */
|
|
|
-static void saa711x_decode_vbi_line(struct i2c_client *client,
|
|
|
- struct v4l2_decode_vbi_line *vbi)
|
|
|
+static int saa711x_decode_vbi_line(struct v4l2_subdev *sd, struct v4l2_decode_vbi_line *vbi)
|
|
|
{
|
|
|
+ struct saa711x_state *state = to_state(sd);
|
|
|
static const char vbi_no_data_pattern[] = {
|
|
|
0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0
|
|
|
};
|
|
|
- struct saa711x_state *state = i2c_get_clientdata(client);
|
|
|
u8 *p = vbi->p;
|
|
|
u32 wss;
|
|
|
int id1, id2; /* the ID1 and ID2 bytes from the internal header */
|
|
@@ -1202,7 +1155,7 @@ static void saa711x_decode_vbi_line(struct i2c_client *client,
|
|
|
/* If the VBI slicer does not detect any signal it will fill up
|
|
|
the payload buffer with 0xa0 bytes. */
|
|
|
if (!memcmp(p, vbi_no_data_pattern, sizeof(vbi_no_data_pattern)))
|
|
|
- return;
|
|
|
+ return 0;
|
|
|
|
|
|
/* decode payloads */
|
|
|
switch (id2) {
|
|
@@ -1211,275 +1164,352 @@ static void saa711x_decode_vbi_line(struct i2c_client *client,
|
|
|
break;
|
|
|
case 4:
|
|
|
if (!saa711x_odd_parity(p[0]) || !saa711x_odd_parity(p[1]))
|
|
|
- return;
|
|
|
+ return 0;
|
|
|
vbi->type = V4L2_SLICED_CAPTION_525;
|
|
|
break;
|
|
|
case 5:
|
|
|
wss = saa711x_decode_wss(p);
|
|
|
if (wss == -1)
|
|
|
- return;
|
|
|
+ return 0;
|
|
|
p[0] = wss & 0xff;
|
|
|
p[1] = wss >> 8;
|
|
|
vbi->type = V4L2_SLICED_WSS_625;
|
|
|
break;
|
|
|
case 7:
|
|
|
if (saa711x_decode_vps(p, p) != 0)
|
|
|
- return;
|
|
|
+ return 0;
|
|
|
vbi->type = V4L2_SLICED_VPS;
|
|
|
break;
|
|
|
default:
|
|
|
- return;
|
|
|
+ break;
|
|
|
}
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
/* ============ SAA7115 AUDIO settings (end) ============= */
|
|
|
|
|
|
-static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *arg)
|
|
|
+static int saa711x_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
|
|
|
{
|
|
|
- struct saa711x_state *state = i2c_get_clientdata(client);
|
|
|
+ struct saa711x_state *state = to_state(sd);
|
|
|
+ int status;
|
|
|
|
|
|
- /* ioctls to allow direct access to the saa7115 registers for testing */
|
|
|
- switch (cmd) {
|
|
|
- case VIDIOC_S_FMT:
|
|
|
- return saa711x_set_v4lfmt(client, (struct v4l2_format *)arg);
|
|
|
+ if (state->radio)
|
|
|
+ return 0;
|
|
|
+ status = saa711x_read(sd, R_1F_STATUS_BYTE_2_VD_DEC);
|
|
|
|
|
|
- case VIDIOC_G_FMT:
|
|
|
- return saa711x_get_v4lfmt(client, (struct v4l2_format *)arg);
|
|
|
+ v4l2_dbg(1, debug, sd, "status: 0x%02x\n", status);
|
|
|
+ vt->signal = ((status & (1 << 6)) == 0) ? 0xffff : 0x0;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
|
|
|
- case VIDIOC_INT_AUDIO_CLOCK_FREQ:
|
|
|
- return saa711x_set_audio_clock_freq(client, *(u32 *)arg);
|
|
|
+static int saa711x_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
|
|
|
+{
|
|
|
+ switch (qc->id) {
|
|
|
+ case V4L2_CID_BRIGHTNESS:
|
|
|
+ case V4L2_CID_CONTRAST:
|
|
|
+ case V4L2_CID_SATURATION:
|
|
|
+ case V4L2_CID_HUE:
|
|
|
+ return v4l2_ctrl_query_fill_std(qc);
|
|
|
+ default:
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
- case VIDIOC_G_TUNER:
|
|
|
- {
|
|
|
- struct v4l2_tuner *vt = arg;
|
|
|
- int status;
|
|
|
+static int saa711x_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
|
|
|
+{
|
|
|
+ struct saa711x_state *state = to_state(sd);
|
|
|
|
|
|
- if (state->radio)
|
|
|
- break;
|
|
|
- status = saa711x_read(client, R_1F_STATUS_BYTE_2_VD_DEC);
|
|
|
+ state->radio = 0;
|
|
|
+ saa711x_set_v4lstd(sd, std);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
|
|
|
- v4l_dbg(1, debug, client, "status: 0x%02x\n", status);
|
|
|
- vt->signal = ((status & (1 << 6)) == 0) ? 0xffff : 0x0;
|
|
|
- break;
|
|
|
- }
|
|
|
+static int saa711x_s_radio(struct v4l2_subdev *sd)
|
|
|
+{
|
|
|
+ struct saa711x_state *state = to_state(sd);
|
|
|
|
|
|
- case VIDIOC_LOG_STATUS:
|
|
|
- saa711x_log_status(client);
|
|
|
- break;
|
|
|
+ state->radio = 1;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
|
|
|
- case VIDIOC_G_CTRL:
|
|
|
- return saa711x_get_v4lctrl(client, (struct v4l2_control *)arg);
|
|
|
+static int saa711x_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
|
|
|
+{
|
|
|
+ struct saa711x_state *state = to_state(sd);
|
|
|
+ u32 input = route->input;
|
|
|
+ u8 mask = (state->ident == V4L2_IDENT_SAA7111) ? 0xf8 : 0xf0;
|
|
|
+
|
|
|
+ v4l2_dbg(1, debug, sd, "decoder set input %d output %d\n", route->input, route->output);
|
|
|
+ /* saa7111/3 does not have these inputs */
|
|
|
+ if ((state->ident == V4L2_IDENT_SAA7113 ||
|
|
|
+ state->ident == V4L2_IDENT_SAA7111) &&
|
|
|
+ (route->input == SAA7115_COMPOSITE4 ||
|
|
|
+ route->input == SAA7115_COMPOSITE5)) {
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+ if (route->input > SAA7115_SVIDEO3)
|
|
|
+ return -EINVAL;
|
|
|
+ if (route->output > SAA7115_IPORT_ON)
|
|
|
+ return -EINVAL;
|
|
|
+ if (state->input == route->input && state->output == route->output)
|
|
|
+ return 0;
|
|
|
+ v4l2_dbg(1, debug, sd, "now setting %s input %s output\n",
|
|
|
+ (route->input >= SAA7115_SVIDEO0) ? "S-Video" : "Composite",
|
|
|
+ (route->output == SAA7115_IPORT_ON) ? "iport on" : "iport off");
|
|
|
+ state->input = route->input;
|
|
|
+
|
|
|
+ /* saa7111 has slightly different input numbering */
|
|
|
+ if (state->ident == V4L2_IDENT_SAA7111) {
|
|
|
+ if (input >= SAA7115_COMPOSITE4)
|
|
|
+ input -= 2;
|
|
|
+ /* saa7111 specific */
|
|
|
+ saa711x_write(sd, R_10_CHROMA_CNTL_2,
|
|
|
+ (saa711x_read(sd, R_10_CHROMA_CNTL_2) & 0x3f) |
|
|
|
+ ((route->output & 0xc0) ^ 0x40));
|
|
|
+ saa711x_write(sd, R_13_RT_X_PORT_OUT_CNTL,
|
|
|
+ (saa711x_read(sd, R_13_RT_X_PORT_OUT_CNTL) & 0xf0) |
|
|
|
+ ((route->output & 2) ? 0x0a : 0));
|
|
|
+ }
|
|
|
|
|
|
- case VIDIOC_S_CTRL:
|
|
|
- return saa711x_set_v4lctrl(client, (struct v4l2_control *)arg);
|
|
|
+ /* select mode */
|
|
|
+ saa711x_write(sd, R_02_INPUT_CNTL_1,
|
|
|
+ (saa711x_read(sd, R_02_INPUT_CNTL_1) & mask) |
|
|
|
+ input);
|
|
|
|
|
|
- case VIDIOC_QUERYCTRL:
|
|
|
- {
|
|
|
- struct v4l2_queryctrl *qc = arg;
|
|
|
+ /* bypass chrominance trap for S-Video modes */
|
|
|
+ saa711x_write(sd, R_09_LUMA_CNTL,
|
|
|
+ (saa711x_read(sd, R_09_LUMA_CNTL) & 0x7f) |
|
|
|
+ (state->input >= SAA7115_SVIDEO0 ? 0x80 : 0x0));
|
|
|
|
|
|
- switch (qc->id) {
|
|
|
- case V4L2_CID_BRIGHTNESS:
|
|
|
- case V4L2_CID_CONTRAST:
|
|
|
- case V4L2_CID_SATURATION:
|
|
|
- case V4L2_CID_HUE:
|
|
|
- return v4l2_ctrl_query_fill_std(qc);
|
|
|
- default:
|
|
|
- return -EINVAL;
|
|
|
- }
|
|
|
+ state->output = route->output;
|
|
|
+ if (state->ident == V4L2_IDENT_SAA7114 ||
|
|
|
+ state->ident == V4L2_IDENT_SAA7115) {
|
|
|
+ saa711x_write(sd, R_83_X_PORT_I_O_ENA_AND_OUT_CLK,
|
|
|
+ (saa711x_read(sd, R_83_X_PORT_I_O_ENA_AND_OUT_CLK) & 0xfe) |
|
|
|
+ (state->output & 0x01));
|
|
|
}
|
|
|
+ return 0;
|
|
|
+}
|
|
|
|
|
|
- case VIDIOC_G_STD:
|
|
|
- *(v4l2_std_id *)arg = saa711x_get_v4lstd(client);
|
|
|
- break;
|
|
|
+static int saa711x_s_gpio(struct v4l2_subdev *sd, u32 val)
|
|
|
+{
|
|
|
+ struct saa711x_state *state = to_state(sd);
|
|
|
|
|
|
- case VIDIOC_S_STD:
|
|
|
- state->radio = 0;
|
|
|
- saa711x_set_v4lstd(client, *(v4l2_std_id *)arg);
|
|
|
- break;
|
|
|
+ if (state->ident != V4L2_IDENT_SAA7111)
|
|
|
+ return -EINVAL;
|
|
|
+ saa711x_write(sd, 0x11, (saa711x_read(sd, 0x11) & 0x7f) |
|
|
|
+ (val ? 0x80 : 0));
|
|
|
+ return 0;
|
|
|
+}
|
|
|
|
|
|
- case AUDC_SET_RADIO:
|
|
|
- state->radio = 1;
|
|
|
- break;
|
|
|
+static int saa711x_s_stream(struct v4l2_subdev *sd, int enable)
|
|
|
+{
|
|
|
+ struct saa711x_state *state = to_state(sd);
|
|
|
|
|
|
- case VIDIOC_INT_G_VIDEO_ROUTING:
|
|
|
- {
|
|
|
- struct v4l2_routing *route = arg;
|
|
|
+ v4l2_dbg(1, debug, sd, "%s output\n",
|
|
|
+ enable ? "enable" : "disable");
|
|
|
|
|
|
- route->input = state->input;
|
|
|
- route->output = state->output;
|
|
|
- break;
|
|
|
+ if (state->enable != enable) {
|
|
|
+ state->enable = enable;
|
|
|
+ saa711x_write(sd, R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED,
|
|
|
+ state->enable);
|
|
|
}
|
|
|
+ return 0;
|
|
|
+}
|
|
|
|
|
|
- case VIDIOC_INT_S_VIDEO_ROUTING:
|
|
|
- {
|
|
|
- struct v4l2_routing *route = arg;
|
|
|
- u32 input = route->input;
|
|
|
- u8 mask = (state->ident == V4L2_IDENT_SAA7111) ? 0xf8 : 0xf0;
|
|
|
-
|
|
|
- v4l_dbg(1, debug, client, "decoder set input %d output %d\n", route->input, route->output);
|
|
|
- /* saa7111/3 does not have these inputs */
|
|
|
- if ((state->ident == V4L2_IDENT_SAA7113 ||
|
|
|
- state->ident == V4L2_IDENT_SAA7111) &&
|
|
|
- (route->input == SAA7115_COMPOSITE4 ||
|
|
|
- route->input == SAA7115_COMPOSITE5)) {
|
|
|
- return -EINVAL;
|
|
|
- }
|
|
|
- if (route->input > SAA7115_SVIDEO3)
|
|
|
- return -EINVAL;
|
|
|
- if (route->output > SAA7115_IPORT_ON)
|
|
|
- return -EINVAL;
|
|
|
- if (state->input == route->input && state->output == route->output)
|
|
|
- break;
|
|
|
- v4l_dbg(1, debug, client, "now setting %s input %s output\n",
|
|
|
- (route->input >= SAA7115_SVIDEO0) ? "S-Video" : "Composite", (route->output == SAA7115_IPORT_ON) ? "iport on" : "iport off");
|
|
|
- state->input = route->input;
|
|
|
-
|
|
|
- /* saa7111 has slightly different input numbering */
|
|
|
- if (state->ident == V4L2_IDENT_SAA7111) {
|
|
|
- if (input >= SAA7115_COMPOSITE4)
|
|
|
- input -= 2;
|
|
|
- /* saa7111 specific */
|
|
|
- saa711x_write(client, R_10_CHROMA_CNTL_2,
|
|
|
- (saa711x_read(client, R_10_CHROMA_CNTL_2) & 0x3f) |
|
|
|
- ((route->output & 0xc0) ^ 0x40));
|
|
|
- saa711x_write(client, R_13_RT_X_PORT_OUT_CNTL,
|
|
|
- (saa711x_read(client, R_13_RT_X_PORT_OUT_CNTL) & 0xf0) |
|
|
|
- ((route->output & 2) ? 0x0a : 0));
|
|
|
- }
|
|
|
+static int saa711x_s_crystal_freq(struct v4l2_subdev *sd, struct v4l2_crystal_freq *freq)
|
|
|
+{
|
|
|
+ struct saa711x_state *state = to_state(sd);
|
|
|
|
|
|
- /* select mode */
|
|
|
- saa711x_write(client, R_02_INPUT_CNTL_1,
|
|
|
- (saa711x_read(client, R_02_INPUT_CNTL_1) & mask) |
|
|
|
- input);
|
|
|
+ if (freq->freq != SAA7115_FREQ_32_11_MHZ &&
|
|
|
+ freq->freq != SAA7115_FREQ_24_576_MHZ)
|
|
|
+ return -EINVAL;
|
|
|
+ state->crystal_freq = freq->freq;
|
|
|
+ state->cgcdiv = (freq->flags & SAA7115_FREQ_FL_CGCDIV) ? 3 : 4;
|
|
|
+ state->ucgc = (freq->flags & SAA7115_FREQ_FL_UCGC) ? 1 : 0;
|
|
|
+ state->apll = (freq->flags & SAA7115_FREQ_FL_APLL) ? 1 : 0;
|
|
|
+ saa711x_s_clock_freq(sd, state->audclk_freq);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
|
|
|
- /* bypass chrominance trap for S-Video modes */
|
|
|
- saa711x_write(client, R_09_LUMA_CNTL,
|
|
|
- (saa711x_read(client, R_09_LUMA_CNTL) & 0x7f) |
|
|
|
- (state->input >= SAA7115_SVIDEO0 ? 0x80 : 0x0));
|
|
|
+static int saa711x_reset(struct v4l2_subdev *sd, u32 val)
|
|
|
+{
|
|
|
+ v4l2_dbg(1, debug, sd, "decoder RESET\n");
|
|
|
+ saa711x_writeregs(sd, saa7115_cfg_reset_scaler);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
|
|
|
- state->output = route->output;
|
|
|
- if (state->ident == V4L2_IDENT_SAA7114 ||
|
|
|
- state->ident == V4L2_IDENT_SAA7115) {
|
|
|
- saa711x_write(client, R_83_X_PORT_I_O_ENA_AND_OUT_CLK,
|
|
|
- (saa711x_read(client, R_83_X_PORT_I_O_ENA_AND_OUT_CLK) & 0xfe) |
|
|
|
- (state->output & 0x01));
|
|
|
+static int saa711x_g_vbi_data(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_data *data)
|
|
|
+{
|
|
|
+ /* Note: the internal field ID is inverted for NTSC,
|
|
|
+ so data->field 0 maps to the saa7115 even field,
|
|
|
+ whereas for PAL it maps to the saa7115 odd field. */
|
|
|
+ switch (data->id) {
|
|
|
+ case V4L2_SLICED_WSS_625:
|
|
|
+ if (saa711x_read(sd, 0x6b) & 0xc0)
|
|
|
+ return -EIO;
|
|
|
+ data->data[0] = saa711x_read(sd, 0x6c);
|
|
|
+ data->data[1] = saa711x_read(sd, 0x6d);
|
|
|
+ return 0;
|
|
|
+ case V4L2_SLICED_CAPTION_525:
|
|
|
+ if (data->field == 0) {
|
|
|
+ /* CC */
|
|
|
+ if (saa711x_read(sd, 0x66) & 0x30)
|
|
|
+ return -EIO;
|
|
|
+ data->data[0] = saa711x_read(sd, 0x69);
|
|
|
+ data->data[1] = saa711x_read(sd, 0x6a);
|
|
|
+ return 0;
|
|
|
}
|
|
|
- break;
|
|
|
+ /* XDS */
|
|
|
+ if (saa711x_read(sd, 0x66) & 0xc0)
|
|
|
+ return -EIO;
|
|
|
+ data->data[0] = saa711x_read(sd, 0x67);
|
|
|
+ data->data[1] = saa711x_read(sd, 0x68);
|
|
|
+ return 0;
|
|
|
+ default:
|
|
|
+ return -EINVAL;
|
|
|
}
|
|
|
+}
|
|
|
|
|
|
- case VIDIOC_STREAMON:
|
|
|
- case VIDIOC_STREAMOFF:
|
|
|
- v4l_dbg(1, debug, client, "%s output\n",
|
|
|
- (cmd == VIDIOC_STREAMON) ? "enable" : "disable");
|
|
|
-
|
|
|
- if (state->enable != (cmd == VIDIOC_STREAMON)) {
|
|
|
- state->enable = (cmd == VIDIOC_STREAMON);
|
|
|
- saa711x_write(client,
|
|
|
- R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED,
|
|
|
- state->enable);
|
|
|
- }
|
|
|
- break;
|
|
|
+#ifdef CONFIG_VIDEO_ADV_DEBUG
|
|
|
+static int saa711x_g_register(struct v4l2_subdev *sd, struct v4l2_register *reg)
|
|
|
+{
|
|
|
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
|
|
|
|
|
|
- case VIDIOC_INT_S_CRYSTAL_FREQ:
|
|
|
- {
|
|
|
- struct v4l2_crystal_freq *freq = arg;
|
|
|
+ if (!v4l2_chip_match_i2c_client(client,
|
|
|
+ reg->match_type, reg->match_chip))
|
|
|
+ return -EINVAL;
|
|
|
+ if (!capable(CAP_SYS_ADMIN))
|
|
|
+ return -EPERM;
|
|
|
+ reg->val = saa711x_read(sd, reg->reg & 0xff);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
|
|
|
- if (freq->freq != SAA7115_FREQ_32_11_MHZ &&
|
|
|
- freq->freq != SAA7115_FREQ_24_576_MHZ)
|
|
|
- return -EINVAL;
|
|
|
- state->crystal_freq = freq->freq;
|
|
|
- state->cgcdiv = (freq->flags & SAA7115_FREQ_FL_CGCDIV) ? 3 : 4;
|
|
|
- state->ucgc = (freq->flags & SAA7115_FREQ_FL_UCGC) ? 1 : 0;
|
|
|
- state->apll = (freq->flags & SAA7115_FREQ_FL_APLL) ? 1 : 0;
|
|
|
- saa711x_set_audio_clock_freq(client, state->audclk_freq);
|
|
|
- break;
|
|
|
- }
|
|
|
+static int saa711x_s_register(struct v4l2_subdev *sd, struct v4l2_register *reg)
|
|
|
+{
|
|
|
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
|
|
|
|
|
|
- case VIDIOC_INT_DECODE_VBI_LINE:
|
|
|
- saa711x_decode_vbi_line(client, arg);
|
|
|
- break;
|
|
|
+ if (!v4l2_chip_match_i2c_client(client,
|
|
|
+ reg->match_type, reg->match_chip))
|
|
|
+ return -EINVAL;
|
|
|
+ if (!capable(CAP_SYS_ADMIN))
|
|
|
+ return -EPERM;
|
|
|
+ saa711x_write(sd, reg->reg & 0xff, reg->val & 0xff);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+#endif
|
|
|
|
|
|
- case VIDIOC_INT_RESET:
|
|
|
- v4l_dbg(1, debug, client, "decoder RESET\n");
|
|
|
- saa711x_writeregs(client, saa7115_cfg_reset_scaler);
|
|
|
- break;
|
|
|
+static int saa711x_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_chip_ident *chip)
|
|
|
+{
|
|
|
+ struct saa711x_state *state = to_state(sd);
|
|
|
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
|
|
|
|
|
|
- case VIDIOC_INT_S_GPIO:
|
|
|
- if (state->ident != V4L2_IDENT_SAA7111)
|
|
|
- return -EINVAL;
|
|
|
- saa711x_write(client, 0x11, (saa711x_read(client, 0x11) & 0x7f) |
|
|
|
- (*(u32 *)arg ? 0x80 : 0));
|
|
|
- break;
|
|
|
+ return v4l2_chip_ident_i2c_client(client, chip, state->ident, 0);
|
|
|
+}
|
|
|
|
|
|
- case VIDIOC_INT_G_VBI_DATA:
|
|
|
- {
|
|
|
- struct v4l2_sliced_vbi_data *data = arg;
|
|
|
+static int saa711x_log_status(struct v4l2_subdev *sd)
|
|
|
+{
|
|
|
+ struct saa711x_state *state = to_state(sd);
|
|
|
+ int reg1e, reg1f;
|
|
|
+ int signalOk;
|
|
|
+ int vcr;
|
|
|
|
|
|
- /* Note: the internal field ID is inverted for NTSC,
|
|
|
- so data->field 0 maps to the saa7115 even field,
|
|
|
- whereas for PAL it maps to the saa7115 odd field. */
|
|
|
- switch (data->id) {
|
|
|
- case V4L2_SLICED_WSS_625:
|
|
|
- if (saa711x_read(client, 0x6b) & 0xc0)
|
|
|
- return -EIO;
|
|
|
- data->data[0] = saa711x_read(client, 0x6c);
|
|
|
- data->data[1] = saa711x_read(client, 0x6d);
|
|
|
- return 0;
|
|
|
- case V4L2_SLICED_CAPTION_525:
|
|
|
- if (data->field == 0) {
|
|
|
- /* CC */
|
|
|
- if (saa711x_read(client, 0x66) & 0x30)
|
|
|
- return -EIO;
|
|
|
- data->data[0] = saa711x_read(client, 0x69);
|
|
|
- data->data[1] = saa711x_read(client, 0x6a);
|
|
|
- return 0;
|
|
|
- }
|
|
|
- /* XDS */
|
|
|
- if (saa711x_read(client, 0x66) & 0xc0)
|
|
|
- return -EIO;
|
|
|
- data->data[0] = saa711x_read(client, 0x67);
|
|
|
- data->data[1] = saa711x_read(client, 0x68);
|
|
|
- return 0;
|
|
|
- default:
|
|
|
- return -EINVAL;
|
|
|
- }
|
|
|
- break;
|
|
|
+ v4l2_info(sd, "Audio frequency: %d Hz\n", state->audclk_freq);
|
|
|
+ if (state->ident != V4L2_IDENT_SAA7115) {
|
|
|
+ /* status for the saa7114 */
|
|
|
+ reg1f = saa711x_read(sd, R_1F_STATUS_BYTE_2_VD_DEC);
|
|
|
+ signalOk = (reg1f & 0xc1) == 0x81;
|
|
|
+ v4l2_info(sd, "Video signal: %s\n", signalOk ? "ok" : "bad");
|
|
|
+ v4l2_info(sd, "Frequency: %s\n", (reg1f & 0x20) ? "60 Hz" : "50 Hz");
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
-#ifdef CONFIG_VIDEO_ADV_DEBUG
|
|
|
- case VIDIOC_DBG_G_REGISTER:
|
|
|
- case VIDIOC_DBG_S_REGISTER:
|
|
|
- {
|
|
|
- struct v4l2_register *reg = arg;
|
|
|
+ /* status for the saa7115 */
|
|
|
+ reg1e = saa711x_read(sd, R_1E_STATUS_BYTE_1_VD_DEC);
|
|
|
+ reg1f = saa711x_read(sd, R_1F_STATUS_BYTE_2_VD_DEC);
|
|
|
|
|
|
- if (!v4l2_chip_match_i2c_client(client, reg->match_type, reg->match_chip))
|
|
|
- return -EINVAL;
|
|
|
- if (!capable(CAP_SYS_ADMIN))
|
|
|
- return -EPERM;
|
|
|
- if (cmd == VIDIOC_DBG_G_REGISTER)
|
|
|
- reg->val = saa711x_read(client, reg->reg & 0xff);
|
|
|
- else
|
|
|
- saa711x_write(client, reg->reg & 0xff, reg->val & 0xff);
|
|
|
- break;
|
|
|
- }
|
|
|
-#endif
|
|
|
+ signalOk = (reg1f & 0xc1) == 0x81 && (reg1e & 0xc0) == 0x80;
|
|
|
+ vcr = !(reg1f & 0x10);
|
|
|
|
|
|
- case VIDIOC_G_CHIP_IDENT:
|
|
|
- return v4l2_chip_ident_i2c_client(client, arg, state->ident, 0);
|
|
|
+ if (state->input >= 6)
|
|
|
+ v4l2_info(sd, "Input: S-Video %d\n", state->input - 6);
|
|
|
+ else
|
|
|
+ v4l2_info(sd, "Input: Composite %d\n", state->input);
|
|
|
+ v4l2_info(sd, "Video signal: %s\n", signalOk ? (vcr ? "VCR" : "broadcast/DVD") : "bad");
|
|
|
+ v4l2_info(sd, "Frequency: %s\n", (reg1f & 0x20) ? "60 Hz" : "50 Hz");
|
|
|
|
|
|
+ switch (reg1e & 0x03) {
|
|
|
+ case 1:
|
|
|
+ v4l2_info(sd, "Detected format: NTSC\n");
|
|
|
+ break;
|
|
|
+ case 2:
|
|
|
+ v4l2_info(sd, "Detected format: PAL\n");
|
|
|
+ break;
|
|
|
+ case 3:
|
|
|
+ v4l2_info(sd, "Detected format: SECAM\n");
|
|
|
+ break;
|
|
|
default:
|
|
|
- return -EINVAL;
|
|
|
+ v4l2_info(sd, "Detected format: BW/No color\n");
|
|
|
+ break;
|
|
|
}
|
|
|
-
|
|
|
+ v4l2_info(sd, "Width, Height: %d, %d\n", state->width, state->height);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static int saa711x_command(struct i2c_client *client, unsigned cmd, void *arg)
|
|
|
+{
|
|
|
+ return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
|
|
|
+}
|
|
|
+
|
|
|
+/* ----------------------------------------------------------------------- */
|
|
|
+
|
|
|
+static const struct v4l2_subdev_core_ops saa711x_core_ops = {
|
|
|
+ .log_status = saa711x_log_status,
|
|
|
+ .g_chip_ident = saa711x_g_chip_ident,
|
|
|
+ .g_ctrl = saa711x_g_ctrl,
|
|
|
+ .s_ctrl = saa711x_s_ctrl,
|
|
|
+ .queryctrl = saa711x_queryctrl,
|
|
|
+ .reset = saa711x_reset,
|
|
|
+ .s_gpio = saa711x_s_gpio,
|
|
|
+#ifdef CONFIG_VIDEO_ADV_DEBUG
|
|
|
+ .g_register = saa711x_g_register,
|
|
|
+ .s_register = saa711x_s_register,
|
|
|
+#endif
|
|
|
+};
|
|
|
+
|
|
|
+static const struct v4l2_subdev_tuner_ops saa711x_tuner_ops = {
|
|
|
+ .s_std = saa711x_s_std,
|
|
|
+ .s_radio = saa711x_s_radio,
|
|
|
+ .g_tuner = saa711x_g_tuner,
|
|
|
+};
|
|
|
+
|
|
|
+static const struct v4l2_subdev_audio_ops saa711x_audio_ops = {
|
|
|
+ .s_clock_freq = saa711x_s_clock_freq,
|
|
|
+};
|
|
|
+
|
|
|
+static const struct v4l2_subdev_video_ops saa711x_video_ops = {
|
|
|
+ .s_routing = saa711x_s_routing,
|
|
|
+ .s_crystal_freq = saa711x_s_crystal_freq,
|
|
|
+ .g_fmt = saa711x_g_fmt,
|
|
|
+ .s_fmt = saa711x_s_fmt,
|
|
|
+ .g_vbi_data = saa711x_g_vbi_data,
|
|
|
+ .decode_vbi_line = saa711x_decode_vbi_line,
|
|
|
+ .s_stream = saa711x_s_stream,
|
|
|
+};
|
|
|
+
|
|
|
+static const struct v4l2_subdev_ops saa711x_ops = {
|
|
|
+ .core = &saa711x_core_ops,
|
|
|
+ .tuner = &saa711x_tuner_ops,
|
|
|
+ .audio = &saa711x_audio_ops,
|
|
|
+ .video = &saa711x_video_ops,
|
|
|
+};
|
|
|
+
|
|
|
/* ----------------------------------------------------------------------- */
|
|
|
|
|
|
-static int saa7115_probe(struct i2c_client *client,
|
|
|
+static int saa711x_probe(struct i2c_client *client,
|
|
|
const struct i2c_device_id *id)
|
|
|
{
|
|
|
struct saa711x_state *state;
|
|
|
+ struct v4l2_subdev *sd;
|
|
|
int i;
|
|
|
char name[17];
|
|
|
char chip_id;
|
|
@@ -1490,8 +1520,8 @@ static int saa7115_probe(struct i2c_client *client,
|
|
|
return -EIO;
|
|
|
|
|
|
for (i = 0; i < 0x0f; i++) {
|
|
|
- saa711x_write(client, 0, i);
|
|
|
- name[i] = (saa711x_read(client, 0) & 0x0f) + '0';
|
|
|
+ i2c_smbus_write_byte_data(client, 0, i);
|
|
|
+ name[i] = (i2c_smbus_read_byte_data(client, 0) & 0x0f) + '0';
|
|
|
if (name[i] > '9')
|
|
|
name[i] += 'a' - '9' - 1;
|
|
|
}
|
|
@@ -1518,7 +1548,8 @@ static int saa7115_probe(struct i2c_client *client,
|
|
|
state = kzalloc(sizeof(struct saa711x_state), GFP_KERNEL);
|
|
|
if (state == NULL)
|
|
|
return -ENOMEM;
|
|
|
- i2c_set_clientdata(client, state);
|
|
|
+ sd = &state->sd;
|
|
|
+ v4l2_i2c_subdev_init(sd, client, &saa711x_ops);
|
|
|
state->input = -1;
|
|
|
state->output = SAA7115_IPORT_ON;
|
|
|
state->enable = 1;
|
|
@@ -1545,41 +1576,45 @@ static int saa7115_probe(struct i2c_client *client,
|
|
|
break;
|
|
|
default:
|
|
|
state->ident = V4L2_IDENT_SAA7111;
|
|
|
- v4l_info(client, "WARNING: Chip is not known - Falling back to saa7111\n");
|
|
|
+ v4l2_info(sd, "WARNING: Chip is not known - Falling back to saa7111\n");
|
|
|
|
|
|
}
|
|
|
|
|
|
state->audclk_freq = 48000;
|
|
|
|
|
|
- v4l_dbg(1, debug, client, "writing init values\n");
|
|
|
+ v4l2_dbg(1, debug, sd, "writing init values\n");
|
|
|
|
|
|
/* init to 60hz/48khz */
|
|
|
state->crystal_freq = SAA7115_FREQ_24_576_MHZ;
|
|
|
switch (state->ident) {
|
|
|
case V4L2_IDENT_SAA7111:
|
|
|
- saa711x_writeregs(client, saa7111_init);
|
|
|
+ saa711x_writeregs(sd, saa7111_init);
|
|
|
break;
|
|
|
case V4L2_IDENT_SAA7113:
|
|
|
- saa711x_writeregs(client, saa7113_init);
|
|
|
+ saa711x_writeregs(sd, saa7113_init);
|
|
|
break;
|
|
|
default:
|
|
|
state->crystal_freq = SAA7115_FREQ_32_11_MHZ;
|
|
|
- saa711x_writeregs(client, saa7115_init_auto_input);
|
|
|
+ saa711x_writeregs(sd, saa7115_init_auto_input);
|
|
|
}
|
|
|
if (state->ident != V4L2_IDENT_SAA7111)
|
|
|
- saa711x_writeregs(client, saa7115_init_misc);
|
|
|
- saa711x_set_v4lstd(client, V4L2_STD_NTSC);
|
|
|
+ saa711x_writeregs(sd, saa7115_init_misc);
|
|
|
+ saa711x_set_v4lstd(sd, V4L2_STD_NTSC);
|
|
|
|
|
|
- v4l_dbg(1, debug, client, "status: (1E) 0x%02x, (1F) 0x%02x\n",
|
|
|
- saa711x_read(client, R_1E_STATUS_BYTE_1_VD_DEC), saa711x_read(client, R_1F_STATUS_BYTE_2_VD_DEC));
|
|
|
+ v4l2_dbg(1, debug, sd, "status: (1E) 0x%02x, (1F) 0x%02x\n",
|
|
|
+ saa711x_read(sd, R_1E_STATUS_BYTE_1_VD_DEC),
|
|
|
+ saa711x_read(sd, R_1F_STATUS_BYTE_2_VD_DEC));
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
/* ----------------------------------------------------------------------- */
|
|
|
|
|
|
-static int saa7115_remove(struct i2c_client *client)
|
|
|
+static int saa711x_remove(struct i2c_client *client)
|
|
|
{
|
|
|
- kfree(i2c_get_clientdata(client));
|
|
|
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
|
|
|
+
|
|
|
+ v4l2_device_unregister_subdev(sd);
|
|
|
+ kfree(to_state(sd));
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -1597,9 +1632,9 @@ MODULE_DEVICE_TABLE(i2c, saa7115_id);
|
|
|
static struct v4l2_i2c_driver_data v4l2_i2c_data = {
|
|
|
.name = "saa7115",
|
|
|
.driverid = I2C_DRIVERID_SAA711X,
|
|
|
- .command = saa7115_command,
|
|
|
- .probe = saa7115_probe,
|
|
|
- .remove = saa7115_remove,
|
|
|
+ .command = saa711x_command,
|
|
|
+ .probe = saa711x_probe,
|
|
|
+ .remove = saa711x_remove,
|
|
|
.legacy_class = I2C_CLASS_TV_ANALOG | I2C_CLASS_TV_DIGITAL,
|
|
|
.id_table = saa7115_id,
|
|
|
};
|