Commit bb10ca17 authored by Tony Lindgren's avatar Tony Lindgren

Revert "radio-tea5761: Update driver"

This reverts commit 5728b4a3.

This patch causes oops on n810 which does not have this chip.
Signed-off-by: default avatarTony Lindgren <tony@atomide.com>
parent 6604ac6c
...@@ -341,7 +341,6 @@ config RADIO_ZOLTRIX_PORT ...@@ -341,7 +341,6 @@ config RADIO_ZOLTRIX_PORT
config RADIO_TEA5761 config RADIO_TEA5761
tristate "Philips Semiconductors TEA5761 I2C FM Radio" tristate "Philips Semiconductors TEA5761 I2C FM Radio"
depends on MEDIA_TUNER_TEA5761
help help
Choose Y here if you have one of these AM/FM radio cards. Choose Y here if you have one of these AM/FM radio cards.
......
...@@ -25,5 +25,3 @@ obj-$(CONFIG_USB_DSBR) += dsbr100.o ...@@ -25,5 +25,3 @@ obj-$(CONFIG_USB_DSBR) += dsbr100.o
obj-$(CONFIG_USB_SI470X) += radio-si470x.o obj-$(CONFIG_USB_SI470X) += radio-si470x.o
EXTRA_CFLAGS += -Isound EXTRA_CFLAGS += -Isound
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/
EXTRA_CFLAGS += -Idrivers/media/common/tuners/
...@@ -23,29 +23,79 @@ ...@@ -23,29 +23,79 @@
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <media/v4l2-common.h> #include <media/v4l2-common.h>
#include <media/tuner.h>
#include "dvb_frontend.h"
#include "tea5761.h"
#define DRIVER_NAME "tea5761" #define DRIVER_NAME "tea5761"
#define TEA5761_VERSION KERNEL_VERSION(0, 0, 1) #define TEA5761_VERSION KERNEL_VERSION(0, 0, 1)
#define TEA5761_I2C_ADDR 0x10
#define TEA5761_MANID 0x002b
#define TEA5761_CHIPID 0x5761
#define TEA5761_INTREG_BLMSK 0x0001
#define TEA5761_INTREG_FRRMSK 0x0002
#define TEA5761_INTREG_LEVMSK 0x0008
#define TEA5761_INTREG_IFMSK 0x0010
#define TEA5761_INTREG_BLMFLAG 0x0100
#define TEA5761_INTREG_FRRFLAG 0x0200
#define TEA5761_INTREG_LEVFLAG 0x0800
#define TEA5761_INTREG_IFFLAG 0x1000
#define TEA5761_FRQSET_SUD 0x8000
#define TEA5761_FRQSET_SM 0x4000
#define TEA5761_TNCTRL_PUPD0 0x4000
#define TEA5761_TNCTRL_BLIM 0x2000
#define TEA5761_TNCTRL_SWPM 0x1000
#define TEA5761_TNCTRL_IFCTC 0x0800
#define TEA5761_TNCTRL_AFM 0x0400
#define TEA5761_TNCTRL_SMUTE 0x0200
#define TEA5761_TNCTRL_SNC 0x0100
#define TEA5761_TNCTRL_MU 0x0080
#define TEA5761_TNCTRL_SSL1 0x0040
#define TEA5761_TNCTRL_SSL0 0x0020
#define TEA5761_TNCTRL_HLSI 0x0010
#define TEA5761_TNCTRL_MST 0x0008
#define TEA5761_TNCTRL_SWP 0x0004
#define TEA5761_TNCTRL_DTC 0x0002
#define TEA5761_TNCTRL_AHLSI 0x0001
#define TEA5761_TUNCHK_LEVEL(x) (((x) & 0x00F0) >> 4)
#define TEA5761_TUNCHK_IFCNT(x) (((x) & 0xFE00) >> 9)
#define TEA5761_TUNCHK_TUNTO 0x0100
#define TEA5761_TUNCHK_LD 0x0008
#define TEA5761_TUNCHK_STEREO 0x0004
#define TEA5761_TESTREG_TRIGFR 0x0800
#define TEA5761_FREQ_LOW 87500 #define TEA5761_FREQ_LOW 87500
#define TEA5761_FREQ_HIGH 108000 #define TEA5761_FREQ_HIGH 108000
struct tea5761_regs {
u16 intreg;
u16 frqset;
u16 tnctrl;
u16 frqchk;
u16 tunchk;
u16 testreg;
u16 manid;
u16 chipid;
} __attribute__ ((packed));
struct tea5761_write_regs {
u8 intreg;
u16 frqset;
u16 tnctrl;
u16 testreg;
} __attribute__ ((packed));
struct tea5761_device { struct tea5761_device {
struct video_device *video_dev; struct video_device *video_dev;
struct device *dev; struct i2c_client *i2c_dev;
struct dvb_frontend fe; struct tea5761_regs regs;
/* To control number of users access (.users field) */
struct mutex mutex; struct mutex mutex;
int users; int users;
unsigned int freq;
u16 audmode;
u8 mute;
u8 power;
}; };
static struct tea5761_device tea5761; static struct tea5761_device tea5761;
...@@ -53,286 +103,267 @@ static struct tea5761_device tea5761; ...@@ -53,286 +103,267 @@ static struct tea5761_device tea5761;
static struct i2c_driver tea5761_driver; static struct i2c_driver tea5761_driver;
static int radio_nr = -1; static int radio_nr = -1;
static void tea5761_power_up(struct tea5761_device *tea) static int tea5761_read_regs(struct tea5761_device *tea)
{ {
struct dvb_frontend *fe = &tea->fe; int rc, i;
struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops; u16 *p = (u16 *) &tea->regs;
struct i2c_client *client = tea->i2c_dev;
rc = i2c_master_recv(client, (void*) &tea->regs, sizeof(tea->regs));
for (i = 0; i < 8; i++) {
p[i] = __be16_to_cpu(p[i]);
}
dev_dbg(&client->dev,
"chip state: %04x %04x %04x %04x %04x %04x %04x %04x\n",
p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
if (rc < 0)
dev_err(&client->dev, "read\n");
if (fe_tuner_ops->init) return rc;
fe_tuner_ops->init(fe);
tea->power = 1;
} }
static void tea5761_power_down(struct tea5761_device *tea) static void tea5761_write_regs(struct tea5761_device *tea)
{ {
struct dvb_frontend *fe = &tea->fe; struct tea5761_write_regs wr;
struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops; struct tea5761_regs *r = &tea->regs;
struct i2c_client *client = tea->i2c_dev;
u8 *p = (u8 *) r;
wr.intreg = r->intreg & 0xff;
wr.frqset = __cpu_to_be16(r->frqset);
wr.tnctrl = __cpu_to_be16(r->tnctrl);
wr.testreg = __cpu_to_be16(r->testreg);
dev_dbg(&client->dev,
"writing state: %02x %02x %02x %02x %02x %02x %02x\n",
p[0], p[1], p[2], p[3], p[4], p[5], p[6]);
if (i2c_master_send(client, (void *) &wr, sizeof(wr)) < 0)
dev_err(&client->dev, "write\n");
}
if (fe_tuner_ops->sleep) static void tea5761_power_up(struct tea5761_device *tea)
fe_tuner_ops->sleep(fe); {
tea->power = 0; struct tea5761_regs *r = &tea->regs;
if (!(r->tnctrl & TEA5761_TNCTRL_PUPD0)) {
r->tnctrl &= ~(TEA5761_TNCTRL_AFM | TEA5761_TNCTRL_MU |
TEA5761_TNCTRL_HLSI);
r->testreg |= TEA5761_TESTREG_TRIGFR;
r->tnctrl |= TEA5761_TNCTRL_PUPD0;
return tea5761_write_regs(tea);
}
} }
static void tea5761_set_freq(struct tea5761_device *tea, unsigned int freq) static void tea5761_power_down(struct tea5761_device *tea)
{ {
struct dvb_frontend *fe = &tea->fe; struct tea5761_regs *r = &tea->regs;
struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops;
struct analog_parameters params = { if (r->tnctrl & TEA5761_TNCTRL_PUPD0) {
.mode = V4L2_TUNER_RADIO, r->tnctrl &= ~TEA5761_TNCTRL_PUPD0;
.audmode = tea->audmode, return tea5761_write_regs(tea);
.frequency = freq,
};
if (NULL == fe_tuner_ops->set_analog_params) {
dev_warn(tea->dev,
"Tuner frontend module has no way to set frequency\n");
return;
} }
if (!fe_tuner_ops->set_analog_params(fe, &params)) }
tea->freq = freq;
static void tea5761_set_freq(struct tea5761_device *tea, int freq)
{
struct tea5761_regs *r = &tea->regs;
if (r->tnctrl & TEA5761_TNCTRL_HLSI)
r->frqset = (freq + 225000) / 8192;
else
r->frqset = (freq - 225000) / 8192;
} }
static int tea5761_get_freq(struct tea5761_device *tea) static int tea5761_get_freq(struct tea5761_device *tea)
{ {
struct dvb_frontend *fe = &tea->fe; struct tea5761_regs *r = &tea->regs;
struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops;
u32 freq;
if (fe_tuner_ops->get_frequency) { if (r->tnctrl & TEA5761_TNCTRL_HLSI)
fe_tuner_ops->get_frequency(fe, &freq); return (r->frqchk * 8192) - 225000;
return freq * 2 / 125; else
} return (r->frqchk * 8192) + 225000;
}
return -ENODEV; static void tea5761_tune(struct tea5761_device *tea, int freq)
{
tea5761_set_freq(tea, freq);
tea5761_write_regs(tea);
} }
static void tea5761_set_audout_mode(struct tea5761_device *tea, int audmode) static void tea5761_set_audout_mode(struct tea5761_device *tea, int audmode)
{ {
struct dvb_frontend *fe = &tea->fe; struct tea5761_regs *r = &tea->regs;
struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops; int tnctrl = r->tnctrl;
struct analog_parameters params = {
.mode = V4L2_TUNER_RADIO, if (audmode == V4L2_TUNER_MODE_MONO)
.frequency = tea->freq, r->tnctrl |= TEA5761_TNCTRL_MST;
.audmode = audmode, else
}; r->tnctrl &= ~TEA5761_TNCTRL_MST;
if (tnctrl != r->tnctrl)
if (NULL == fe_tuner_ops->set_analog_params) { tea5761_write_regs(tea);
dev_warn(tea->dev,
"Tuner frontend module has no way to set frequency\n");
return;
}
if (!fe_tuner_ops->set_analog_params(fe, &params))
tea->audmode = audmode;
} }
static int tea5761_get_audout_mode(struct tea5761_device *tea) static int tea5761_get_audout_mode(struct tea5761_device *tea)
{ {
return tea->audmode; struct tea5761_regs *r = &tea->regs;
if (r->tnctrl & TEA5761_TNCTRL_MST)
return V4L2_TUNER_MODE_MONO;
else
return V4L2_TUNER_MODE_STEREO;
} }
static void tea5761_mute(struct tea5761_device *tea, int on) static void tea5761_mute(struct tea5761_device *tea, int on)
{ {
struct dvb_frontend *fe = &tea->fe; struct tea5761_regs *r = &tea->regs;
struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops; int tnctrl = r->tnctrl;
struct analog_parameters params = {
.mode = on ? T_STANDBY : V4L2_TUNER_RADIO, if (on)
.frequency = tea->freq, r->tnctrl |= TEA5761_TNCTRL_MU;
.audmode = tea->audmode, else
}; r->tnctrl &= ~TEA5761_TNCTRL_MU;
if (tnctrl != r->tnctrl)
if (NULL == fe_tuner_ops->set_analog_params) { tea5761_write_regs(tea);
dev_warn(tea->dev,
"Tuner frontend module has no way to set frequency\n");
return;
}
if (!fe_tuner_ops->set_analog_params(fe, &params))
tea->mute = on;
} }
static int tea5761_is_muted(struct tea5761_device *tea) static int tea5761_is_muted(struct tea5761_device *tea)
{ {
return tea->mute; return tea->regs.tnctrl & TEA5761_TNCTRL_MU;
} }
static int tea5761_vidioc_querycap(struct file *file, void *priv, static int tea5761_do_ioctl(struct inode *inode, struct file *file,
struct v4l2_capability *c) unsigned int cmd, void *arg)
{ {
struct tea5761_device *tea = file->private_data; struct tea5761_device *tea = file->private_data;
struct video_device *dev = tea->video_dev; struct video_device *dev = tea->video_dev;
struct i2c_client *client = tea->i2c_dev;
memset(c, 0, sizeof(*c)); struct tea5761_regs *r = &tea->regs;
strlcpy(c->driver, dev->dev->driver->name, sizeof(*c->driver));
strlcpy(c->card, dev->name, sizeof(c->card)); union {
snprintf(c->bus_info, sizeof(c->bus_info), "I2C:%s", struct v4l2_capability c;
struct v4l2_tuner t;
struct v4l2_frequency f;
struct v4l2_queryctrl qc;
struct v4l2_control ct;
} *u = arg;
tea5761_read_regs(tea);
switch (cmd) {
case VIDIOC_QUERYCAP:
dev_dbg(&client->dev, "VIDIOC_QUERYCAP\n");
memset(&u->c, 0, sizeof(u->c));
strlcpy(u->c.driver, dev->dev->driver->name,
sizeof(u->c.driver));
strlcpy(u->c.card, dev->name, sizeof(u->c.card));
snprintf(u->c.bus_info, sizeof(u->c.bus_info), "I2C:%s",
dev->dev->bus_id); dev->dev->bus_id);
c->version = TEA5761_VERSION; u->c.version = TEA5761_VERSION;
c->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; u->c.capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
break;
return 0;
}
static int tea5761_vidioc_g_tuner(struct file *file, void *priv,
struct v4l2_tuner *t)
{
struct tea5761_device *tea = file->private_data;
struct dvb_frontend *fe = &tea->fe;
u16 strength = 0;
case VIDIOC_G_TUNER:
/* Only one tuner chip */ /* Only one tuner chip */
if (t->index != 0) dev_dbg(&client->dev, "VIDIOC_G_TUNER\n");
if (u->t.index != 0)
return -EINVAL; return -EINVAL;
memset(t, 0, sizeof(*t)); memset(&u->t, 0, sizeof(u->t));
t->type = V4L2_TUNER_RADIO; u->t.type = V4L2_TUNER_RADIO;
strlcpy(t->name, "FM", sizeof(t->name)); strlcpy(u->t.name, "FM", sizeof(u->t.name));
/* Frequency in 62.5Hz units */ /* Freq in 62.5Hz units */
t->rangelow = TEA5761_FREQ_LOW * 16; u->t.rangelow = TEA5761_FREQ_LOW * 16;
t->rangehigh = TEA5761_FREQ_HIGH * 16; u->t.rangehigh = TEA5761_FREQ_HIGH * 16;
t->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO; u->t.capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
if (r->tunchk & TEA5761_TUNCHK_STEREO)
t->audmode = tea5761_get_audout_mode(tea); u->t.rxsubchans = V4L2_TUNER_SUB_STEREO;
if (t->audmode == V4L2_TUNER_MODE_STEREO) u->t.audmode = tea5761_get_audout_mode(tea);
t->rxsubchans = V4L2_TUNER_SUB_STEREO; u->t.signal = TEA5761_TUNCHK_LEVEL(r->tunchk) * 0xffff / 0xf;
u->t.afc = TEA5761_TUNCHK_IFCNT(r->tunchk);
if (fe->ops.tuner_ops.get_rf_strength) break;
fe->ops.tuner_ops.get_rf_strength(fe, &strength);
t->signal = strength; case VIDIOC_S_TUNER:
/* Only tuner nro 0 can be selected. */
return 0; dev_dbg(&client->dev, "VIDIOC_S_TUNER\n");
} if (u->t.index != 0)
static int tea5761_vidioc_s_tuner(struct file *file, void *priv,
struct v4l2_tuner *t)
{
struct tea5761_device *tea = file->private_data;
/* Only tuner number 0 can be selected. */
if (t->index != 0)
return -EINVAL; return -EINVAL;
tea5761_set_audout_mode(tea, t->audmode); tea5761_set_audout_mode(tea, u->t.audmode);
break;
return 0;
} case VIDIOC_G_FREQUENCY:
dev_dbg(&client->dev, "VIDIOC_G_FREQUENCY\n");
static int tea5761_vidioc_g_frequency(struct file *file, void *priv, memset(&u->f, 0, sizeof(u->f));
struct v4l2_frequency *f) u->f.type = V4L2_TUNER_RADIO;
{ if (r->tnctrl & TEA5761_TNCTRL_PUPD0)
struct tea5761_device *tea = file->private_data; u->f.frequency = (tea5761_get_freq(tea) * 2) / 125;
memset(f, 0, sizeof(*f));
f->type = V4L2_TUNER_RADIO;
if (tea->power)
f->frequency = (tea5761_get_freq(tea) * 2) / 125;
else else
f->frequency = 0; u->f.frequency = 0;
break;
return 0; case VIDIOC_S_FREQUENCY:
} dev_dbg(&client->dev, "VIDIOC_S_FREQUENCY %u\n",
u->f.frequency);
static int tea5761_vidioc_s_frequency(struct file *file, void *priv, if (u->f.tuner != 0)
struct v4l2_frequency *f)
{
struct tea5761_device *tea = file->private_data;
if (f->tuner != 0)
return -EINVAL; return -EINVAL;
if (f->frequency == 0) { if (u->f.frequency == 0) {
/* We special case this as a power down /* We special case this as a power down
* control. */ * control. */
tea5761_power_down(tea); tea5761_power_down(tea);
return 0; break;
} }
if (f->frequency < 16 * TEA5761_FREQ_LOW) if (u->f.frequency < 16 * TEA5761_FREQ_LOW)
return -EINVAL; return -EINVAL;
if (f->frequency > 16 * TEA5761_FREQ_HIGH) if (u->f.frequency > 16 * TEA5761_FREQ_HIGH)
return -EINVAL; return -EINVAL;
tea5761_power_up(tea); tea5761_power_up(tea);
tea5761_set_freq(tea, f->frequency); tea5761_tune(tea, (u->f.frequency * 125) / 2);
break;
return 0; case VIDIOC_QUERYCTRL:
} dev_dbg(&client->dev, "VIDIOC_QUERYCTRL %d\n", u->qc.id);
if (u->qc.id != V4L2_CID_AUDIO_MUTE)
static int tea5761_vidioc_queryctrl(struct file *file, void *priv,
struct v4l2_queryctrl *qc)
{
if (qc->id != V4L2_CID_AUDIO_MUTE)
return -EINVAL; return -EINVAL;
strlcpy(qc->name, "Mute", sizeof(qc->name)); strlcpy(u->qc.name, "Mute", sizeof(u->qc.name));
qc->minimum = 0; u->qc.minimum = 0;
qc->maximum = 1; u->qc.maximum = 1;
qc->step = 1; u->qc.step = 1;
qc->default_value = 0; u->qc.default_value = 0;
qc->type = V4L2_CTRL_TYPE_BOOLEAN; u->qc.type = V4L2_CTRL_TYPE_BOOLEAN;
break;
return 0;
} case VIDIOC_G_CTRL:
dev_dbg(&client->dev, "VIDIOC_G_CTRL %d\n", u->ct.id);
static int tea5761_vidioc_g_ctrl(struct file *file, void *priv, if (u->ct.id != V4L2_CID_AUDIO_MUTE)
struct v4l2_control *ct)
{
struct tea5761_device *tea = file->private_data;
if (ct->id != V4L2_CID_AUDIO_MUTE)
return -EINVAL; return -EINVAL;
if (tea->power) if (r->tnctrl & TEA5761_TNCTRL_PUPD0)
ct->value = tea5761_is_muted(tea) ? 1 : 0; u->ct.value = tea5761_is_muted(tea) ? 1 : 0;
else else
ct->value = 0; u->ct.value = 0;
break;
return 0;
}
static int tea5761_vidioc_s_ctrl(struct file *file, void *priv, case VIDIOC_S_CTRL:
struct v4l2_control *ct) dev_dbg(&client->dev, "VIDIOC_S_CTRL %d\n", u->ct.id);
{ if (u->ct.id != V4L2_CID_AUDIO_MUTE)
struct tea5761_device *tea = file->private_data;
if (ct->id != V4L2_CID_AUDIO_MUTE)
return -EINVAL; return -EINVAL;
tea5761_mute(tea, ct->value); tea5761_mute(tea, u->ct.value);
break;
return 0;
}
static int tea5761_vidioc_g_audio(struct file *file, void *priv,
struct v4l2_audio *audio)
{
struct tea5761_device *tea = file->private_data;
strlcpy(audio->name, "FM Radio", ARRAY_SIZE(audio->name));
audio->mode = tea->audmode;
return 0;
}
static int tea5761_vidioc_s_audio(struct file *file, void *priv,
struct v4l2_audio *audio)
{
struct tea5761_device *tea = file->private_data;
tea5761_set_audout_mode(tea, audio->mode);
return 0; default:
} return -ENOIOCTLCMD;
}
static int tea5761_vidioc_g_input(struct file *filp, void *priv,
unsigned int *i)
{
*i = 0;
return 0; return 0;
} }
static int tea5761_vidioc_s_input(struct file *filp, void *priv, unsigned int i) static int tea5761_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{ {
if (i) return video_usercopy(inode, file, cmd, arg, tea5761_do_ioctl);
return -EINVAL;
return 0;
} }
static int tea5761_open(struct inode *inode, struct file *file) static int tea5761_open(struct inode *inode, struct file *file)
{ {
int minor = iminor(file->f_dentry->d_inode); int minor = iminor(file->f_dentry->d_inode);
...@@ -370,32 +401,16 @@ static struct file_operations tea5761_fops = { ...@@ -370,32 +401,16 @@ static struct file_operations tea5761_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.open = tea5761_open, .open = tea5761_open,
.release = tea5761_release, .release = tea5761_release,
.ioctl = tea5761_ioctl,
.llseek = no_llseek, .llseek = no_llseek,
.ioctl = video_ioctl2,
.compat_ioctl = v4l_compat_ioctl32,
}; };
/*
* tea5761_viddev_tamples - video device interface
*/
static struct video_device tea5761_video_device = { static struct video_device tea5761_video_device = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.name = "TEA5761 FM-Radio", .name = "TEA5761 FM-Radio",
.type = VID_TYPE_TUNER, .type = VID_TYPE_TUNER,
.release = video_device_release,
.fops = &tea5761_fops, .fops = &tea5761_fops,
.vidioc_querycap = tea5761_vidioc_querycap, .release = video_device_release
.vidioc_g_tuner = tea5761_vidioc_g_tuner,
.vidioc_s_tuner = tea5761_vidioc_s_tuner,
.vidioc_g_frequency = tea5761_vidioc_g_frequency,
.vidioc_s_frequency = tea5761_vidioc_s_frequency,
.vidioc_queryctrl = tea5761_vidioc_queryctrl,
.vidioc_g_ctrl = tea5761_vidioc_g_ctrl,
.vidioc_s_ctrl = tea5761_vidioc_s_ctrl,
.vidioc_g_audio = tea5761_vidioc_g_audio,
.vidioc_s_audio = tea5761_vidioc_s_audio,
.vidioc_g_input = tea5761_vidioc_g_input,
.vidioc_s_input = tea5761_vidioc_s_input,
}; };
static int tea5761_i2c_driver_probe(struct i2c_client *client, static int tea5761_i2c_driver_probe(struct i2c_client *client,
...@@ -407,24 +422,12 @@ static int tea5761_i2c_driver_probe(struct i2c_client *client, ...@@ -407,24 +422,12 @@ static int tea5761_i2c_driver_probe(struct i2c_client *client,
mutex_init(&tea->mutex); mutex_init(&tea->mutex);
/* Tuner attach */ tea->i2c_dev = client;
if (!dvb_attach(tea5761_attach, &tea->fe, client->adapter,
client->addr)) {
dev_err(&client->dev, "Could not attach tuner\n");
err = -ENODEV;
goto exit;
}
/* initialize and power off the chip */
tea5761_power_up(tea);
tea5761_set_audout_mode(tea, V4L2_TUNER_MODE_STEREO);
tea5761_mute(tea, 0);
tea5761_power_down(tea);
/* V4L initialization */ /* V4L initialization */
video_dev = video_device_alloc(); video_dev = video_device_alloc();
if (video_dev == NULL) { if (video_dev == NULL) {
dev_err(&client->dev, "Could not allocate memory\n"); dev_err(&client->dev, "couldn't allocate memory\n");
err = -ENOMEM; err = -ENOMEM;
goto exit; goto exit;
} }
...@@ -433,15 +436,25 @@ static int tea5761_i2c_driver_probe(struct i2c_client *client, ...@@ -433,15 +436,25 @@ static int tea5761_i2c_driver_probe(struct i2c_client *client,
*video_dev = tea5761_video_device; *video_dev = tea5761_video_device;
video_dev->dev = &client->dev; video_dev->dev = &client->dev;
i2c_set_clientdata(client, video_dev); i2c_set_clientdata(client, video_dev);
tea->video_dev = video_dev;
tea->dev = &client->dev; /* initialize and power off the chip */
tea5761_read_regs(tea);
tea5761_set_audout_mode(tea, V4L2_TUNER_MODE_STEREO);
tea5761_mute(tea, 0);
tea5761_power_down(tea);
tea5761.video_dev = video_dev;
tea5761.i2c_dev = client;
err = video_register_device(video_dev, VFL_TYPE_RADIO, radio_nr); err = video_register_device(video_dev, VFL_TYPE_RADIO, radio_nr);
if (err) { if (err) {
dev_err(&client->dev, "Could not register video device\n"); dev_err(&client->dev, "couldn't register video device\n");
goto err_video_alloc; goto err_video_alloc;
} }
dev_info(&client->dev, "tea5761 (version %d) detected\n",
(tea->regs.manid >> 12) & 0xf);
return 0; return 0;
err_video_alloc: err_video_alloc:
...@@ -477,7 +490,14 @@ static struct i2c_driver tea5761_driver = { ...@@ -477,7 +490,14 @@ static struct i2c_driver tea5761_driver = {
static int __init tea5761_init(void) static int __init tea5761_init(void)
{ {
return i2c_add_driver(&tea5761_driver); int res;
if ((res = i2c_add_driver(&tea5761_driver))) {
printk(KERN_ERR DRIVER_NAME ": driver registration failed\n");
return res;
}
return 0;
} }
static void __exit tea5761_exit(void) static void __exit tea5761_exit(void)
......
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