Commit 3c86cf7a authored by Hans Verkuil's avatar Hans Verkuil Committed by Mauro Carvalho Chehab

V4L/DVB (12215): saa6588: conform to the final RDS spec.

Signed-off-by: default avatarHans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 6a052c84
...@@ -40,7 +40,7 @@ ...@@ -40,7 +40,7 @@
/* insmod options */ /* insmod options */
static unsigned int debug; static unsigned int debug;
static unsigned int xtal; static unsigned int xtal;
static unsigned int rbds; static unsigned int mmbs;
static unsigned int plvl; static unsigned int plvl;
static unsigned int bufblocks = 100; static unsigned int bufblocks = 100;
...@@ -48,8 +48,8 @@ module_param(debug, int, 0644); ...@@ -48,8 +48,8 @@ module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "enable debug messages"); MODULE_PARM_DESC(debug, "enable debug messages");
module_param(xtal, int, 0); module_param(xtal, int, 0);
MODULE_PARM_DESC(xtal, "select oscillator frequency (0..3), default 0"); MODULE_PARM_DESC(xtal, "select oscillator frequency (0..3), default 0");
module_param(rbds, int, 0); module_param(mmbs, int, 0);
MODULE_PARM_DESC(rbds, "select mode, 0=RDS, 1=RBDS, default 0"); MODULE_PARM_DESC(mmbs, "enable MMBS mode: 0=off (default), 1=on");
module_param(plvl, int, 0); module_param(plvl, int, 0);
MODULE_PARM_DESC(plvl, "select pause level (0..3), default 0"); MODULE_PARM_DESC(plvl, "select pause level (0..3), default 0");
module_param(bufblocks, int, 0); module_param(bufblocks, int, 0);
...@@ -78,6 +78,7 @@ struct saa6588 { ...@@ -78,6 +78,7 @@ struct saa6588 {
unsigned char last_blocknum; unsigned char last_blocknum;
wait_queue_head_t read_queue; wait_queue_head_t read_queue;
int data_available_for_read; int data_available_for_read;
u8 sync;
}; };
static inline struct saa6588 *to_saa6588(struct v4l2_subdev *sd) static inline struct saa6588 *to_saa6588(struct v4l2_subdev *sd)
...@@ -261,13 +262,16 @@ static void saa6588_i2c_poll(struct saa6588 *s) ...@@ -261,13 +262,16 @@ static void saa6588_i2c_poll(struct saa6588 *s)
unsigned char tmp; unsigned char tmp;
/* Although we only need 3 bytes, we have to read at least 6. /* Although we only need 3 bytes, we have to read at least 6.
SAA6588 returns garbage otherwise */ SAA6588 returns garbage otherwise. */
if (6 != i2c_master_recv(client, &tmpbuf[0], 6)) { if (6 != i2c_master_recv(client, &tmpbuf[0], 6)) {
if (debug > 1) if (debug > 1)
dprintk(PREFIX "read error!\n"); dprintk(PREFIX "read error!\n");
return; return;
} }
s->sync = tmpbuf[0] & 0x10;
if (!s->sync)
return;
blocknum = tmpbuf[0] >> 5; blocknum = tmpbuf[0] >> 5;
if (blocknum == s->last_blocknum) { if (blocknum == s->last_blocknum) {
if (debug > 3) if (debug > 3)
...@@ -286,9 +290,8 @@ static void saa6588_i2c_poll(struct saa6588 *s) ...@@ -286,9 +290,8 @@ static void saa6588_i2c_poll(struct saa6588 *s)
occurred during reception of this block. occurred during reception of this block.
Bit 6: Corrected bit. Indicates that an error was Bit 6: Corrected bit. Indicates that an error was
corrected for this data block. corrected for this data block.
Bits 5-3: Received Offset. Indicates the offset received Bits 5-3: Same as bits 0-2.
by the sync system. Bits 2-0: Block number.
Bits 2-0: Offset Name. Indicates the offset applied to this data.
SAA6588 byte order is Status-MSB-LSB, so we have to swap the SAA6588 byte order is Status-MSB-LSB, so we have to swap the
first and the last of the 3 bytes block. first and the last of the 3 bytes block.
...@@ -298,12 +301,21 @@ static void saa6588_i2c_poll(struct saa6588 *s) ...@@ -298,12 +301,21 @@ static void saa6588_i2c_poll(struct saa6588 *s)
tmpbuf[2] = tmpbuf[0]; tmpbuf[2] = tmpbuf[0];
tmpbuf[0] = tmp; tmpbuf[0] = tmp;
/* Map 'Invalid block E' to 'Invalid Block' */
if (blocknum == 6)
blocknum = V4L2_RDS_BLOCK_INVALID;
/* And if are not in mmbs mode, then 'Block E' is also mapped
to 'Invalid Block'. As far as I can tell MMBS is discontinued,
and if there is ever a need to support E blocks, then please
contact the linux-media mailinglist. */
else if (!mmbs && blocknum == 5)
blocknum = V4L2_RDS_BLOCK_INVALID;
tmp = blocknum; tmp = blocknum;
tmp |= blocknum << 3; /* Received offset == Offset Name (OK ?) */ tmp |= blocknum << 3; /* Received offset == Offset Name (OK ?) */
if ((tmpbuf[2] & 0x03) == 0x03) if ((tmpbuf[2] & 0x03) == 0x03)
tmp |= 0x80; /* uncorrectable error */ tmp |= V4L2_RDS_BLOCK_ERROR; /* uncorrectable error */
else if ((tmpbuf[2] & 0x03) != 0x00) else if ((tmpbuf[2] & 0x03) != 0x00)
tmp |= 0x40; /* corrected error */ tmp |= V4L2_RDS_BLOCK_CORRECTED; /* corrected error */
tmpbuf[2] = tmp; /* Is this enough ? Should we also check other bits ? */ tmpbuf[2] = tmp; /* Is this enough ? Should we also check other bits ? */
spin_lock_irqsave(&s->lock, flags); spin_lock_irqsave(&s->lock, flags);
...@@ -321,14 +333,14 @@ static void saa6588_work(struct work_struct *work) ...@@ -321,14 +333,14 @@ static void saa6588_work(struct work_struct *work)
schedule_delayed_work(&s->work, msecs_to_jiffies(20)); schedule_delayed_work(&s->work, msecs_to_jiffies(20));
} }
static int saa6588_configure(struct saa6588 *s) static void saa6588_configure(struct saa6588 *s)
{ {
struct i2c_client *client = v4l2_get_subdevdata(&s->sd); struct i2c_client *client = v4l2_get_subdevdata(&s->sd);
unsigned char buf[3]; unsigned char buf[3];
int rc; int rc;
buf[0] = cSyncRestart; buf[0] = cSyncRestart;
if (rbds) if (mmbs)
buf[0] |= cProcessingModeRBDS; buf[0] |= cProcessingModeRBDS;
buf[1] = cFlywheelDefault; buf[1] = cFlywheelDefault;
...@@ -374,8 +386,6 @@ static int saa6588_configure(struct saa6588 *s) ...@@ -374,8 +386,6 @@ static int saa6588_configure(struct saa6588 *s)
rc = i2c_master_send(client, buf, 3); rc = i2c_master_send(client, buf, 3);
if (rc != 3) if (rc != 3)
printk(PREFIX "i2c i/o error: rc == %d (should be 3)\n", rc); printk(PREFIX "i2c i/o error: rc == %d (should be 3)\n", rc);
return 0;
} }
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
...@@ -416,6 +426,24 @@ static long saa6588_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) ...@@ -416,6 +426,24 @@ static long saa6588_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
return 0; return 0;
} }
static int saa6588_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
{
struct saa6588 *s = to_saa6588(sd);
vt->capability |= V4L2_TUNER_CAP_RDS;
if (s->sync)
vt->rxsubchans |= V4L2_TUNER_SUB_RDS;
return 0;
}
static int saa6588_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
{
struct saa6588 *s = to_saa6588(sd);
saa6588_configure(s);
return 0;
}
static int saa6588_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) static int saa6588_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
{ {
struct i2c_client *client = v4l2_get_subdevdata(sd); struct i2c_client *client = v4l2_get_subdevdata(sd);
...@@ -430,8 +458,14 @@ static const struct v4l2_subdev_core_ops saa6588_core_ops = { ...@@ -430,8 +458,14 @@ static const struct v4l2_subdev_core_ops saa6588_core_ops = {
.ioctl = saa6588_ioctl, .ioctl = saa6588_ioctl,
}; };
static const struct v4l2_subdev_tuner_ops saa6588_tuner_ops = {
.g_tuner = saa6588_g_tuner,
.s_tuner = saa6588_s_tuner,
};
static const struct v4l2_subdev_ops saa6588_ops = { static const struct v4l2_subdev_ops saa6588_ops = {
.core = &saa6588_core_ops, .core = &saa6588_core_ops,
.tuner = &saa6588_tuner_ops,
}; };
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment