Commit 61391e04 authored by Tim Kaiser's avatar Tim Kaiser Committed by Mauro Carvalho Chehab

V4L/DVB (4219): Av7110: analog sound output of DVB-C rev 2.3

Added support for the msp34x5 audio dac. Analog sound output of
Technotrend DVB-C 2300 (aka Hauppauge Nexus-CA) works now.
Signed-off-by: default avatarTim Kaiser <timkaiser@t-online.de>
Signed-off-by: default avatarMarco Schluessler <marco@lordzodiac.de>
Signed-off-by: default avatarOliver Endriss <o.endriss@gmx.de>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@infradead.org>
parent 4a4edcca
...@@ -152,13 +152,9 @@ static void init_av7110_av(struct av7110 *av7110) ...@@ -152,13 +152,9 @@ static void init_av7110_av(struct av7110 *av7110)
/* remaining inits according to card and frontend type */ /* remaining inits according to card and frontend type */
av7110->analog_tuner_flags = 0; av7110->analog_tuner_flags = 0;
av7110->current_input = 0; av7110->current_input = 0;
if (dev->pci->subsystem_vendor == 0x13c2 && dev->pci->subsystem_device == 0x000a) { if (dev->pci->subsystem_vendor == 0x13c2 && dev->pci->subsystem_device == 0x000a)
printk("dvb-ttpci: MSP3415 audio DAC @ card %d\n",
av7110->dvb_adapter.num);
av7110->adac_type = DVB_ADAC_MSP34x5;
av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, ADSwitch, 1, 0); // SPDIF on av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, ADSwitch, 1, 0); // SPDIF on
} if (i2c_writereg(av7110, 0x20, 0x00, 0x00) == 1) {
else if (i2c_writereg(av7110, 0x20, 0x00, 0x00) == 1) {
printk ("dvb-ttpci: Crystal audio DAC @ card %d detected\n", printk ("dvb-ttpci: Crystal audio DAC @ card %d detected\n",
av7110->dvb_adapter.num); av7110->dvb_adapter.num);
av7110->adac_type = DVB_ADAC_CRYSTAL; av7110->adac_type = DVB_ADAC_CRYSTAL;
......
...@@ -318,7 +318,17 @@ int av7110_set_volume(struct av7110 *av7110, int volleft, int volright) ...@@ -318,7 +318,17 @@ int av7110_set_volume(struct av7110 *av7110, int volleft, int volright)
msp_writereg(av7110, MSP_WR_DSP, 0x0000, val); /* loudspeaker */ msp_writereg(av7110, MSP_WR_DSP, 0x0000, val); /* loudspeaker */
msp_writereg(av7110, MSP_WR_DSP, 0x0006, val); /* headphonesr */ msp_writereg(av7110, MSP_WR_DSP, 0x0006, val); /* headphonesr */
return 0; return 0;
case DVB_ADAC_MSP34x5:
vol = (volleft > volright) ? volleft : volright;
val = (vol * 0x73 / 255) << 8;
if (vol > 0)
balance = ((volright - volleft) * 127) / vol;
msp_writereg(av7110, MSP_WR_DSP, 0x0001, balance << 8);
msp_writereg(av7110, MSP_WR_DSP, 0x0000, val); /* loudspeaker */
return 0;
} }
return 0; return 0;
} }
...@@ -1267,23 +1277,32 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file, ...@@ -1267,23 +1277,32 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file,
switch(av7110->audiostate.channel_select) { switch(av7110->audiostate.channel_select) {
case AUDIO_STEREO: case AUDIO_STEREO:
ret = audcom(av7110, AUDIO_CMD_STEREO); ret = audcom(av7110, AUDIO_CMD_STEREO);
if (!ret) if (!ret) {
if (av7110->adac_type == DVB_ADAC_CRYSTAL) if (av7110->adac_type == DVB_ADAC_CRYSTAL)
i2c_writereg(av7110, 0x20, 0x02, 0x49); i2c_writereg(av7110, 0x20, 0x02, 0x49);
else if (av7110->adac_type == DVB_ADAC_MSP34x5)
msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0220);
}
break; break;
case AUDIO_MONO_LEFT: case AUDIO_MONO_LEFT:
ret = audcom(av7110, AUDIO_CMD_MONO_L); ret = audcom(av7110, AUDIO_CMD_MONO_L);
if (!ret) if (!ret) {
if (av7110->adac_type == DVB_ADAC_CRYSTAL) if (av7110->adac_type == DVB_ADAC_CRYSTAL)
i2c_writereg(av7110, 0x20, 0x02, 0x4a); i2c_writereg(av7110, 0x20, 0x02, 0x4a);
else if (av7110->adac_type == DVB_ADAC_MSP34x5)
msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0200);
}
break; break;
case AUDIO_MONO_RIGHT: case AUDIO_MONO_RIGHT:
ret = audcom(av7110, AUDIO_CMD_MONO_R); ret = audcom(av7110, AUDIO_CMD_MONO_R);
if (!ret) if (!ret) {
if (av7110->adac_type == DVB_ADAC_CRYSTAL) if (av7110->adac_type == DVB_ADAC_CRYSTAL)
i2c_writereg(av7110, 0x20, 0x02, 0x45); i2c_writereg(av7110, 0x20, 0x02, 0x45);
else if (av7110->adac_type == DVB_ADAC_MSP34x5)
msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0210);
}
break; break;
default: default:
......
...@@ -42,7 +42,18 @@ ...@@ -42,7 +42,18 @@
int msp_writereg(struct av7110 *av7110, u8 dev, u16 reg, u16 val) int msp_writereg(struct av7110 *av7110, u8 dev, u16 reg, u16 val)
{ {
u8 msg[5] = { dev, reg >> 8, reg & 0xff, val >> 8 , val & 0xff }; u8 msg[5] = { dev, reg >> 8, reg & 0xff, val >> 8 , val & 0xff };
struct i2c_msg msgs = { .flags = 0, .addr = 0x40, .len = 5, .buf = msg }; struct i2c_msg msgs = { .flags = 0, .len = 5, .buf = msg };
switch (av7110->adac_type) {
case DVB_ADAC_MSP34x0:
msgs.addr = 0x40;
break;
case DVB_ADAC_MSP34x5:
msgs.addr = 0x42;
break;
default:
return 0;
}
if (i2c_transfer(&av7110->i2c_adap, &msgs, 1) != 1) { if (i2c_transfer(&av7110->i2c_adap, &msgs, 1) != 1) {
dprintk(1, "dvb-ttpci: failed @ card %d, %u = %u\n", dprintk(1, "dvb-ttpci: failed @ card %d, %u = %u\n",
...@@ -57,10 +68,23 @@ static int msp_readreg(struct av7110 *av7110, u8 dev, u16 reg, u16 *val) ...@@ -57,10 +68,23 @@ static int msp_readreg(struct av7110 *av7110, u8 dev, u16 reg, u16 *val)
u8 msg1[3] = { dev, reg >> 8, reg & 0xff }; u8 msg1[3] = { dev, reg >> 8, reg & 0xff };
u8 msg2[2]; u8 msg2[2];
struct i2c_msg msgs[2] = { struct i2c_msg msgs[2] = {
{ .flags = 0, .addr = 0x40, .len = 3, .buf = msg1 }, { .flags = 0 , .len = 3, .buf = msg1 },
{ .flags = I2C_M_RD, .addr = 0x40, .len = 2, .buf = msg2 } { .flags = I2C_M_RD, .len = 2, .buf = msg2 }
}; };
switch (av7110->adac_type) {
case DVB_ADAC_MSP34x0:
msgs[0].addr = 0x40;
msgs[1].addr = 0x40;
break;
case DVB_ADAC_MSP34x5:
msgs[0].addr = 0x42;
msgs[1].addr = 0x42;
break;
default:
return 0;
}
if (i2c_transfer(&av7110->i2c_adap, &msgs[0], 2) != 2) { if (i2c_transfer(&av7110->i2c_adap, &msgs[0], 2) != 2) {
dprintk(1, "dvb-ttpci: failed @ card %d, %u\n", dprintk(1, "dvb-ttpci: failed @ card %d, %u\n",
av7110->dvb_adapter.num, reg); av7110->dvb_adapter.num, reg);
...@@ -678,17 +702,23 @@ int av7110_init_analog_module(struct av7110 *av7110) ...@@ -678,17 +702,23 @@ int av7110_init_analog_module(struct av7110 *av7110)
{ {
u16 version1, version2; u16 version1, version2;
if (i2c_writereg(av7110, 0x80, 0x0, 0x80) != 1 if (i2c_writereg(av7110, 0x80, 0x0, 0x80) == 1 &&
|| i2c_writereg(av7110, 0x80, 0x0, 0) != 1) i2c_writereg(av7110, 0x80, 0x0, 0) == 1) {
printk("dvb-ttpci: DVB-C analog module @ card %d detected, initializing MSP3400\n",
av7110->dvb_adapter.num);
av7110->adac_type = DVB_ADAC_MSP34x0;
} else if (i2c_writereg(av7110, 0x84, 0x0, 0x80) == 1 &&
i2c_writereg(av7110, 0x84, 0x0, 0) == 1) {
printk("dvb-ttpci: DVB-C analog module @ card %d detected, initializing MSP3415\n",
av7110->dvb_adapter.num);
av7110->adac_type = DVB_ADAC_MSP34x5;
} else
return -ENODEV; return -ENODEV;
printk("dvb-ttpci: DVB-C analog module @ card %d detected, initializing MSP3400\n",
av7110->dvb_adapter.num);
av7110->adac_type = DVB_ADAC_MSP34x0;
msleep(100); // the probing above resets the msp... msleep(100); // the probing above resets the msp...
msp_readreg(av7110, MSP_RD_DSP, 0x001e, &version1); msp_readreg(av7110, MSP_RD_DSP, 0x001e, &version1);
msp_readreg(av7110, MSP_RD_DSP, 0x001f, &version2); msp_readreg(av7110, MSP_RD_DSP, 0x001f, &version2);
dprintk(1, "dvb-ttpci: @ card %d MSP3400 version 0x%04x 0x%04x\n", dprintk(1, "dvb-ttpci: @ card %d MSP34xx version 0x%04x 0x%04x\n",
av7110->dvb_adapter.num, version1, version2); av7110->dvb_adapter.num, version1, version2);
msp_writereg(av7110, MSP_WR_DSP, 0x0013, 0x0c00); msp_writereg(av7110, MSP_WR_DSP, 0x0013, 0x0c00);
msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x7f00); // loudspeaker + headphone msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x7f00); // loudspeaker + headphone
...@@ -697,7 +727,7 @@ int av7110_init_analog_module(struct av7110 *av7110) ...@@ -697,7 +727,7 @@ int av7110_init_analog_module(struct av7110 *av7110)
msp_writereg(av7110, MSP_WR_DSP, 0x0004, 0x7f00); // loudspeaker volume msp_writereg(av7110, MSP_WR_DSP, 0x0004, 0x7f00); // loudspeaker volume
msp_writereg(av7110, MSP_WR_DSP, 0x000a, 0x0220); // SCART 1 source msp_writereg(av7110, MSP_WR_DSP, 0x000a, 0x0220); // SCART 1 source
msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0x7f00); // SCART 1 volume msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0x7f00); // SCART 1 volume
msp_writereg(av7110, MSP_WR_DSP, 0x000d, 0x4800); // prescale SCART msp_writereg(av7110, MSP_WR_DSP, 0x000d, 0x1900); // prescale SCART
if (i2c_writereg(av7110, 0x48, 0x01, 0x00)!=1) { if (i2c_writereg(av7110, 0x48, 0x01, 0x00)!=1) {
INFO(("saa7113 not accessible.\n")); INFO(("saa7113 not accessible.\n"));
......
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