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

V4L/DVB (9829): tuner: convert to v4l2_subdev.

Signed-off-by: default avatarHans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 27760fc4
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
#include <linux/videodev.h> #include <linux/videodev.h>
#include <media/tuner.h> #include <media/tuner.h>
#include <media/tuner-types.h> #include <media/tuner-types.h>
#include <media/v4l2-common.h> #include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h> #include <media/v4l2-ioctl.h>
#include <media/v4l2-i2c-drv-legacy.h> #include <media/v4l2-i2c-drv-legacy.h>
#include "mt20xx.h" #include "mt20xx.h"
...@@ -78,6 +78,7 @@ struct tuner { ...@@ -78,6 +78,7 @@ struct tuner {
/* device */ /* device */
struct dvb_frontend fe; struct dvb_frontend fe;
struct i2c_client *i2c; struct i2c_client *i2c;
struct v4l2_subdev sd;
struct list_head list; struct list_head list;
unsigned int using_v4l2:1; unsigned int using_v4l2:1;
...@@ -95,6 +96,11 @@ struct tuner { ...@@ -95,6 +96,11 @@ struct tuner {
const char *name; const char *name;
}; };
static inline struct tuner *to_tuner(struct v4l2_subdev *sd)
{
return container_of(sd, struct tuner, sd);
}
/* standard i2c insmod options */ /* standard i2c insmod options */
static unsigned short normal_i2c[] = { static unsigned short normal_i2c[] = {
#if defined(CONFIG_MEDIA_TUNER_TEA5761) || (defined(CONFIG_MEDIA_TUNER_TEA5761_MODULE) && defined(MODULE)) #if defined(CONFIG_MEDIA_TUNER_TEA5761) || (defined(CONFIG_MEDIA_TUNER_TEA5761_MODULE) && defined(MODULE))
...@@ -213,7 +219,7 @@ static int fe_set_config(struct dvb_frontend *fe, void *priv_cfg) ...@@ -213,7 +219,7 @@ static int fe_set_config(struct dvb_frontend *fe, void *priv_cfg)
static void tuner_status(struct dvb_frontend *fe); static void tuner_status(struct dvb_frontend *fe);
static struct analog_demod_ops tuner_core_ops = { static struct analog_demod_ops tuner_analog_ops = {
.set_params = fe_set_params, .set_params = fe_set_params,
.standby = fe_standby, .standby = fe_standby,
.has_signal = fe_has_signal, .has_signal = fe_has_signal,
...@@ -224,7 +230,7 @@ static struct analog_demod_ops tuner_core_ops = { ...@@ -224,7 +230,7 @@ static struct analog_demod_ops tuner_core_ops = {
/* Set tuner frequency, freq in Units of 62.5kHz = 1/16MHz */ /* Set tuner frequency, freq in Units of 62.5kHz = 1/16MHz */
static void set_tv_freq(struct i2c_client *c, unsigned int freq) static void set_tv_freq(struct i2c_client *c, unsigned int freq)
{ {
struct tuner *t = i2c_get_clientdata(c); struct tuner *t = to_tuner(i2c_get_clientdata(c));
struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
struct analog_parameters params = { struct analog_parameters params = {
...@@ -259,7 +265,7 @@ static void set_tv_freq(struct i2c_client *c, unsigned int freq) ...@@ -259,7 +265,7 @@ static void set_tv_freq(struct i2c_client *c, unsigned int freq)
static void set_radio_freq(struct i2c_client *c, unsigned int freq) static void set_radio_freq(struct i2c_client *c, unsigned int freq)
{ {
struct tuner *t = i2c_get_clientdata(c); struct tuner *t = to_tuner(i2c_get_clientdata(c));
struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
struct analog_parameters params = { struct analog_parameters params = {
...@@ -294,7 +300,7 @@ static void set_radio_freq(struct i2c_client *c, unsigned int freq) ...@@ -294,7 +300,7 @@ static void set_radio_freq(struct i2c_client *c, unsigned int freq)
static void set_freq(struct i2c_client *c, unsigned long freq) static void set_freq(struct i2c_client *c, unsigned long freq)
{ {
struct tuner *t = i2c_get_clientdata(c); struct tuner *t = to_tuner(i2c_get_clientdata(c));
switch (t->mode) { switch (t->mode) {
case V4L2_TUNER_RADIO: case V4L2_TUNER_RADIO:
...@@ -347,7 +353,7 @@ static void set_type(struct i2c_client *c, unsigned int type, ...@@ -347,7 +353,7 @@ static void set_type(struct i2c_client *c, unsigned int type,
unsigned int new_mode_mask, unsigned int new_config, unsigned int new_mode_mask, unsigned int new_config,
int (*tuner_callback) (void *dev, int component, int cmd, int arg)) int (*tuner_callback) (void *dev, int component, int cmd, int arg))
{ {
struct tuner *t = i2c_get_clientdata(c); struct tuner *t = to_tuner(i2c_get_clientdata(c));
struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
unsigned char buffer[4]; unsigned char buffer[4];
...@@ -470,7 +476,7 @@ static void set_type(struct i2c_client *c, unsigned int type, ...@@ -470,7 +476,7 @@ static void set_type(struct i2c_client *c, unsigned int type,
t->name = fe_tuner_ops->info.name; t->name = fe_tuner_ops->info.name;
t->fe.analog_demod_priv = t; t->fe.analog_demod_priv = t;
memcpy(analog_ops, &tuner_core_ops, memcpy(analog_ops, &tuner_analog_ops,
sizeof(struct analog_demod_ops)); sizeof(struct analog_demod_ops));
} else { } else {
...@@ -515,7 +521,7 @@ attach_failed: ...@@ -515,7 +521,7 @@ attach_failed:
static void set_addr(struct i2c_client *c, struct tuner_setup *tun_setup) static void set_addr(struct i2c_client *c, struct tuner_setup *tun_setup)
{ {
struct tuner *t = i2c_get_clientdata(c); struct tuner *t = to_tuner(i2c_get_clientdata(c));
if ( (t->type == UNSET && ((tun_setup->addr == ADDR_UNSET) && if ( (t->type == UNSET && ((tun_setup->addr == ADDR_UNSET) &&
(t->mode_mask & tun_setup->mode_mask))) || (t->mode_mask & tun_setup->mode_mask))) ||
...@@ -748,43 +754,56 @@ static inline int check_v4l2(struct tuner *t) ...@@ -748,43 +754,56 @@ static inline int check_v4l2(struct tuner *t)
return 0; return 0;
} }
static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) static int tuner_s_type_addr(struct v4l2_subdev *sd, struct tuner_setup *type)
{ {
struct tuner *t = i2c_get_clientdata(client); struct tuner *t = to_tuner(sd);
struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; struct i2c_client *client = v4l2_get_subdevdata(sd);
struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
if (tuner_debug > 1) { tuner_dbg("Calling set_type_addr for type=%d, addr=0x%02x, mode=0x%02x, config=0x%02x\n",
v4l_i2c_print_ioctl(client,cmd); type->type,
printk("\n"); type->addr,
} type->mode_mask,
type->config);
set_addr(client, type);
return 0;
}
static int tuner_s_radio(struct v4l2_subdev *sd)
{
struct tuner *t = to_tuner(sd);
struct i2c_client *client = v4l2_get_subdevdata(sd);
switch (cmd) {
/* --- configuration --- */
case TUNER_SET_TYPE_ADDR:
tuner_dbg ("Calling set_type_addr for type=%d, addr=0x%02x, mode=0x%02x, config=0x%02x\n",
((struct tuner_setup *)arg)->type,
((struct tuner_setup *)arg)->addr,
((struct tuner_setup *)arg)->mode_mask,
((struct tuner_setup *)arg)->config);
set_addr(client, (struct tuner_setup *)arg);
break;
case AUDC_SET_RADIO:
if (set_mode(client, t, V4L2_TUNER_RADIO, "AUDC_SET_RADIO") if (set_mode(client, t, V4L2_TUNER_RADIO, "AUDC_SET_RADIO")
== -EINVAL) == -EINVAL)
return 0; return 0;
if (t->radio_freq) if (t->radio_freq)
set_freq(client, t->radio_freq); set_freq(client, t->radio_freq);
break; return 0;
case TUNER_SET_STANDBY: }
static int tuner_s_standby(struct v4l2_subdev *sd, u32 standby)
{
struct tuner *t = to_tuner(sd);
struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
if (check_mode(t, "TUNER_SET_STANDBY") == -EINVAL) if (check_mode(t, "TUNER_SET_STANDBY") == -EINVAL)
return 0; return 0;
t->mode = T_STANDBY; t->mode = T_STANDBY;
if (analog_ops->standby) if (analog_ops->standby)
analog_ops->standby(&t->fe); analog_ops->standby(&t->fe);
break; return 0;
}
#ifdef CONFIG_VIDEO_ALLOW_V4L1 #ifdef CONFIG_VIDEO_ALLOW_V4L1
static int tuner_ioctl(struct v4l2_subdev *sd, int cmd, void *arg)
{
struct tuner *t = to_tuner(sd);
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
switch (cmd) {
case VIDIOCSAUDIO: case VIDIOCSAUDIO:
if (check_mode(t, "VIDIOCSAUDIO") == -EINVAL) if (check_mode(t, "VIDIOCSAUDIO") == -EINVAL)
return 0; return 0;
...@@ -897,56 +916,67 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) ...@@ -897,56 +916,67 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
} }
return 0; return 0;
} }
}
return -ENOIOCTLCMD;
}
#endif #endif
case TUNER_SET_CONFIG:
{ static int tuner_s_config(struct v4l2_subdev *sd, const struct v4l2_priv_tun_config *cfg)
struct v4l2_priv_tun_config *cfg = arg; {
struct tuner *t = to_tuner(sd);
struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
if (t->type != cfg->tuner) if (t->type != cfg->tuner)
break; return 0;
if (analog_ops->set_config) { if (analog_ops->set_config) {
analog_ops->set_config(&t->fe, cfg->priv); analog_ops->set_config(&t->fe, cfg->priv);
break; return 0;
} }
tuner_dbg("Tuner frontend module has no way to set config\n"); tuner_dbg("Tuner frontend module has no way to set config\n");
break; return 0;
} }
/* --- v4l ioctls --- */
/* take care: bttv does userspace copying, we'll get a /* --- v4l ioctls --- */
/* take care: bttv does userspace copying, we'll get a
kernel pointer here... */ kernel pointer here... */
case VIDIOC_S_STD: static int tuner_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
{ {
v4l2_std_id *id = arg; struct tuner *t = to_tuner(sd);
struct i2c_client *client = v4l2_get_subdevdata(sd);
if (set_mode (client, t, V4L2_TUNER_ANALOG_TV, "VIDIOC_S_STD") if (set_mode(client, t, V4L2_TUNER_ANALOG_TV, "VIDIOC_S_STD")
== -EINVAL) == -EINVAL)
return 0; return 0;
switch_v4l2(); switch_v4l2();
t->std = *id; t->std = std;
tuner_fixup_std(t); tuner_fixup_std(t);
if (t->tv_freq) if (t->tv_freq)
set_freq(client, t->tv_freq); set_freq(client, t->tv_freq);
break; return 0;
} }
case VIDIOC_S_FREQUENCY:
{
struct v4l2_frequency *f = arg;
if (set_mode (client, t, f->type, "VIDIOC_S_FREQUENCY") static int tuner_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f)
{
struct tuner *t = to_tuner(sd);
struct i2c_client *client = v4l2_get_subdevdata(sd);
if (set_mode(client, t, f->type, "VIDIOC_S_FREQUENCY")
== -EINVAL) == -EINVAL)
return 0; return 0;
switch_v4l2(); switch_v4l2();
set_freq(client,f->frequency); set_freq(client, f->frequency);
break; return 0;
} }
case VIDIOC_G_FREQUENCY:
{ static int tuner_g_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f)
struct v4l2_frequency *f = arg; {
struct tuner *t = to_tuner(sd);
struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
if (check_mode(t, "VIDIOC_G_FREQUENCY") == -EINVAL) if (check_mode(t, "VIDIOC_G_FREQUENCY") == -EINVAL)
return 0; return 0;
...@@ -959,62 +989,67 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) ...@@ -959,62 +989,67 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
f->frequency = (V4L2_TUNER_RADIO == t->mode) ? f->frequency = (V4L2_TUNER_RADIO == t->mode) ?
(abs_freq * 2 + 125/2) / 125 : (abs_freq * 2 + 125/2) / 125 :
(abs_freq + 62500/2) / 62500; (abs_freq + 62500/2) / 62500;
break; return 0;
} }
f->frequency = (V4L2_TUNER_RADIO == t->mode) ? f->frequency = (V4L2_TUNER_RADIO == t->mode) ?
t->radio_freq : t->tv_freq; t->radio_freq : t->tv_freq;
break; return 0;
} }
case VIDIOC_G_TUNER:
{ static int tuner_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
struct v4l2_tuner *tuner = arg; {
struct tuner *t = to_tuner(sd);
struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
if (check_mode(t, "VIDIOC_G_TUNER") == -EINVAL) if (check_mode(t, "VIDIOC_G_TUNER") == -EINVAL)
return 0; return 0;
switch_v4l2(); switch_v4l2();
tuner->type = t->mode; vt->type = t->mode;
if (analog_ops->get_afc) if (analog_ops->get_afc)
tuner->afc = analog_ops->get_afc(&t->fe); vt->afc = analog_ops->get_afc(&t->fe);
if (t->mode == V4L2_TUNER_ANALOG_TV) if (t->mode == V4L2_TUNER_ANALOG_TV)
tuner->capability |= V4L2_TUNER_CAP_NORM; vt->capability |= V4L2_TUNER_CAP_NORM;
if (t->mode != V4L2_TUNER_RADIO) { if (t->mode != V4L2_TUNER_RADIO) {
tuner->rangelow = tv_range[0] * 16; vt->rangelow = tv_range[0] * 16;
tuner->rangehigh = tv_range[1] * 16; vt->rangehigh = tv_range[1] * 16;
break; return 0;
} }
/* radio mode */ /* radio mode */
tuner->rxsubchans = vt->rxsubchans =
V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
if (fe_tuner_ops->get_status) { if (fe_tuner_ops->get_status) {
u32 tuner_status; u32 tuner_status;
fe_tuner_ops->get_status(&t->fe, &tuner_status); fe_tuner_ops->get_status(&t->fe, &tuner_status);
tuner->rxsubchans = vt->rxsubchans =
(tuner_status & TUNER_STATUS_STEREO) ? (tuner_status & TUNER_STATUS_STEREO) ?
V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_STEREO :
V4L2_TUNER_SUB_MONO; V4L2_TUNER_SUB_MONO;
} else { } else {
if (analog_ops->is_stereo) { if (analog_ops->is_stereo) {
tuner->rxsubchans = vt->rxsubchans =
analog_ops->is_stereo(&t->fe) ? analog_ops->is_stereo(&t->fe) ?
V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_STEREO :
V4L2_TUNER_SUB_MONO; V4L2_TUNER_SUB_MONO;
} }
} }
if (analog_ops->has_signal) if (analog_ops->has_signal)
tuner->signal = analog_ops->has_signal(&t->fe); vt->signal = analog_ops->has_signal(&t->fe);
tuner->capability |= vt->capability |=
V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO; V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
tuner->audmode = t->audmode; vt->audmode = t->audmode;
tuner->rangelow = radio_range[0] * 16000; vt->rangelow = radio_range[0] * 16000;
tuner->rangehigh = radio_range[1] * 16000; vt->rangehigh = radio_range[1] * 16000;
break; return 0;
} }
case VIDIOC_S_TUNER:
{ static int tuner_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
struct v4l2_tuner *tuner = arg; {
struct tuner *t = to_tuner(sd);
struct i2c_client *client = v4l2_get_subdevdata(sd);
if (check_mode(t, "VIDIOC_S_TUNER") == -EINVAL) if (check_mode(t, "VIDIOC_S_TUNER") == -EINVAL)
return 0; return 0;
...@@ -1023,23 +1058,30 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) ...@@ -1023,23 +1058,30 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
/* do nothing unless we're a radio tuner */ /* do nothing unless we're a radio tuner */
if (t->mode != V4L2_TUNER_RADIO) if (t->mode != V4L2_TUNER_RADIO)
break; return 0;
t->audmode = tuner->audmode; t->audmode = vt->audmode;
set_radio_freq(client, t->radio_freq); set_radio_freq(client, t->radio_freq);
break; return 0;
} }
case VIDIOC_LOG_STATUS:
static int tuner_log_status(struct v4l2_subdev *sd)
{
struct tuner *t = to_tuner(sd);
struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
if (analog_ops->tuner_status) if (analog_ops->tuner_status)
analog_ops->tuner_status(&t->fe); analog_ops->tuner_status(&t->fe);
break;
}
return 0; return 0;
} }
static int tuner_command(struct i2c_client *client, unsigned cmd, void *arg)
{
return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
}
static int tuner_suspend(struct i2c_client *c, pm_message_t state) static int tuner_suspend(struct i2c_client *c, pm_message_t state)
{ {
struct tuner *t = i2c_get_clientdata(c); struct tuner *t = to_tuner(i2c_get_clientdata(c));
tuner_dbg("suspend\n"); tuner_dbg("suspend\n");
/* FIXME: power down ??? */ /* FIXME: power down ??? */
...@@ -1048,7 +1090,7 @@ static int tuner_suspend(struct i2c_client *c, pm_message_t state) ...@@ -1048,7 +1090,7 @@ static int tuner_suspend(struct i2c_client *c, pm_message_t state)
static int tuner_resume(struct i2c_client *c) static int tuner_resume(struct i2c_client *c)
{ {
struct tuner *t = i2c_get_clientdata(c); struct tuner *t = to_tuner(i2c_get_clientdata(c));
tuner_dbg("resume\n"); tuner_dbg("resume\n");
if (V4L2_TUNER_RADIO == t->mode) { if (V4L2_TUNER_RADIO == t->mode) {
...@@ -1061,6 +1103,30 @@ static int tuner_resume(struct i2c_client *c) ...@@ -1061,6 +1103,30 @@ static int tuner_resume(struct i2c_client *c)
return 0; return 0;
} }
/* ----------------------------------------------------------------------- */
static const struct v4l2_subdev_core_ops tuner_core_ops = {
.log_status = tuner_log_status,
.s_standby = tuner_s_standby,
.ioctl = tuner_ioctl,
};
static const struct v4l2_subdev_tuner_ops tuner_tuner_ops = {
.s_std = tuner_s_std,
.s_radio = tuner_s_radio,
.g_tuner = tuner_g_tuner,
.s_tuner = tuner_s_tuner,
.s_frequency = tuner_s_frequency,
.g_frequency = tuner_g_frequency,
.s_type_addr = tuner_s_type_addr,
.s_config = tuner_s_config,
};
static const struct v4l2_subdev_ops tuner_ops = {
.core = &tuner_core_ops,
.tuner = &tuner_tuner_ops,
};
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
static LIST_HEAD(tuner_list); static LIST_HEAD(tuner_list);
...@@ -1109,9 +1175,9 @@ static int tuner_probe(struct i2c_client *client, ...@@ -1109,9 +1175,9 @@ static int tuner_probe(struct i2c_client *client,
t = kzalloc(sizeof(struct tuner), GFP_KERNEL); t = kzalloc(sizeof(struct tuner), GFP_KERNEL);
if (NULL == t) if (NULL == t)
return -ENOMEM; return -ENOMEM;
v4l2_i2c_subdev_init(&t->sd, client, &tuner_ops);
t->i2c = client; t->i2c = client;
t->name = "(tuner unset)"; t->name = "(tuner unset)";
i2c_set_clientdata(client, t);
t->type = UNSET; t->type = UNSET;
t->audmode = V4L2_TUNER_MODE_STEREO; t->audmode = V4L2_TUNER_MODE_STEREO;
t->mode_mask = T_UNINITIALIZED; t->mode_mask = T_UNINITIALIZED;
...@@ -1261,8 +1327,9 @@ static int tuner_legacy_probe(struct i2c_adapter *adap) ...@@ -1261,8 +1327,9 @@ static int tuner_legacy_probe(struct i2c_adapter *adap)
static int tuner_remove(struct i2c_client *client) static int tuner_remove(struct i2c_client *client)
{ {
struct tuner *t = i2c_get_clientdata(client); struct tuner *t = to_tuner(i2c_get_clientdata(client));
v4l2_device_unregister_subdev(&t->sd);
tuner_detach(&t->fe); tuner_detach(&t->fe);
t->fe.analog_demod_priv = NULL; t->fe.analog_demod_priv = NULL;
......
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