Please revert commit fcb9757333df37cf4a7feccef7ef6f5300643864
Subsystems (2)
Mauro,
Please revert at least the wm8775.c portion of commit fcb9757333df37cf4a7feccef7ef6f5300643864:
It completely trashes baseband line-in audio for PVR-150 cards, and likely does the same for any other ivtv card that has a WM8775 chip.
http://ivtvdriver.org/pipermail/ivtv-users/2010-December/010104.html
http://ivtvdriver.org/pipermail/ivtv-users/2010-December/010102.html
Reported by: David Gesswein <[email protected]>
http://ivtvdriver.org/pipermail/ivtv-devel/2010-December/006619.html
I have also verified with my own PVR-150 that this commit is the cause.
Regards,
Andy
Quoted 9 lines · Andy Walls
Mauro,
Please revert at least the
wm8775.cportion of commitfcb9757333df37cf4a7feccef7ef6f5300643864:It completely trashes baseband line-in audio for PVR-150 cards, and likely does the same for any other ivtv card that has a WM8775 chip.
Confirmed. I manually rolled back most of the changes in that commit for wm8775.c, leaving all other files alone, and the audio is now working correctly for me. I haven't yet narrowed it down to exactly which changes in that file cause the problem. I'll try and do that tomorrow if I have time.
Eric
Quoted 8 lines · Eric Sharkey
Quoted 7 lines · Andy Walls
Mauro,
Please revert at least the
wm8775.cportion of commitfcb9757333df37cf4a7feccef7ef6f5300643864:
Quoted 8 lines
Quoted 2 lines
It completely trashes baseband line-in audio for PVR-150 cards, and likely does the same for any other ivtv card that has a WM8775 chip.
Confirmed. I manually rolled back most of the changes in that commit for
wm8775.c, leaving all other files alone, and the audio is now working correctly for me. I haven't yet narrowed it down to exactly which changes in that file cause the problem. I'll try and do that tomorrow if I have time.
This might help then:
http://dl.ivtvdriver.org/datasheets/audio/WM8775.pdf
I don't have time to look, but I'm hoping it is just the initialization in wm8775_probe().
Without both a PVR-150 card and a Nova-S-plus DVB-S with which to test you are unlikely to get an initialization that works for both the Nova-S Plus and PVR-150. Even if you did, such a configuration would be "fragile" in that it will be hard to tweak in the future for one card without breaking the other. (Code reuse doesn't work out too well for setting up hardware parameters.)
The fix will probably have to use some context sensitive initialization in wm8775_probe(): "Am I being called by ivtv for a PVR-150 or cx88 for a Nova-S plus?"
Which probably means:
1. adding a ".s_config" method to the "wm8775_core_ops" See:
http://git.linuxtv.org/media_tree.git?a=blob;f=Documentation/video4linux/v4l2-framework.txt;h=f22f35c271f38d34fda0c19d8942b536e2fc95d9;hb=staging/for_v2.6.38#l206
http://git.linuxtv.org/media_tree.git?a=blob;f=include/media/v4l2-subdev.h;h=b0316a7cf08d21f2ac68f1dc452894441948c155;hb=staging/for_v2.6.38#l109
http://git.linuxtv.org/media_tree.git?a=blob;f=include/media/v4l2-subdev.h;h=b0316a7cf08d21f2ac68f1dc452894441948c155;hb=staging/for_v2.6.38#l141
2. developing a "struct wm8775_platform_data" type that can be used to indicate the needs for the Nova-S versus the PVR-150 and any other legacy boards that use the wm8775 module
That structure should probably be defined here:
http://git.linuxtv.org/media_tree.git?a=blob;f=include/media/wm8775.h;h=a1c4d417dfa205e8d5c2cf1d4f9d6bbd7a6ec419;hb=staging/for_v2.6.38
3. writing the corresponding "wm8775_s_config" function in wm8775.c to setup the WM8775 based on the arguments passed in the "platform_data". Note that this function may get called at least once initially by the v4l2 infrastructure with "irq" set to 0 and "platform_data" set to NULL.
4. Fixing the wm8775_probe() function to do something sensible, knowing that the .s_config method may get called once by the infrastructure, and/or once again by the cx88 driver or the ivtv driver.
5. Searching through the video drivers to see if any other drivers may use the wm8775 module, and validating that your changes won't break them.
All I see with a quick grep is cx88, ivtv, and pvrusb2
6. Testing with real hardware....
Regards,
Andy
Quoted 36 lines · On Monday, January 03, 2011 23:34:16 Andy Walls wrote:
Quoted 8 lines · Eric Sharkey
Quoted 7 lines · Andy Walls
Mauro,
Please revert at least the
wm8775.cportion of commitfcb9757333df37cf4a7feccef7ef6f5300643864:Quoted 8 lines
Quoted 2 lines
It completely trashes baseband line-in audio for PVR-150 cards, and likely does the same for any other ivtv card that has a WM8775 chip.
Confirmed. I manually rolled back most of the changes in that commit for
wm8775.c, leaving all other files alone, and the audio is now working correctly for me. I haven't yet narrowed it down to exactly which changes in that file cause the problem. I'll try and do that tomorrow if I have time.This might help then:
http://dl.ivtvdriver.org/datasheets/audio/WM8775.pdf
I don't have time to look, but I'm hoping it is just the initialization in
wm8775_probe().Without both a PVR-150 card and a Nova-S-plus DVB-S with which to test you are unlikely to get an initialization that works for both the Nova-S Plus and PVR-150. Even if you did, such a configuration would be "fragile" in that it will be hard to tweak in the future for one card without breaking the other. (Code reuse doesn't work out too well for setting up hardware parameters.)
The fix will probably have to use some context sensitive initialization in
wm8775_probe(): "Am I being called by ivtv for a PVR-150 or cx88 for a Nova-S plus?"
Quoted 7 lines
Which probably means:
1. adding a ".s_config" method to the "
wm8775_core_ops" See:
http://git.linuxtv.org/media_tree.git?a=blob;f=Documentation/video4linux/v4l2-framework.txt;h=f22f35c271f38d34fda0c19d8942b536e2fc95d9;hb=staging/for_v2.6.38#l206
http://git.linuxtv.org/media_tree.git?a=blob;f=include/media/v4l2-subdev.h;h=b0316a7cf08d21f2ac68f1dc452894441948c155;hb=staging/for_v2.6.38#l109
http://git.linuxtv.org/media_tree.git?a=blob;f=include/media/v4l2-subdev.h;h=b0316a7cf08d21f2ac68f1dc452894441948c155;hb=staging/for_v2.6.38#l141
Don't use .s_config! That will be removed soon.
Use platform_data and v4l2_i2c_new_subdev_board instead.
Regards,
Hans
Quoted 35 lines
2. developing a "struct
wm8775_platform_data" type that can be used to indicate the needs for the Nova-S versus the PVR-150 and any other legacy boards that use the wm8775 moduleThat structure should probably be defined here:
http://git.linuxtv.org/media_tree.git?a=blob;f=include/media/wm8775.h;h=a1c4d417dfa205e8d5c2cf1d4f9d6bbd7a6ec419;hb=staging/for_v2.6.383. writing the corresponding "
wm8775_s_config" function inwm8775.cto setup the WM8775 based on the arguments passed in the "platform_data". Note that this function may get called at least once initially by the v4l2 infrastructure with "irq" set to 0 and "platform_data" set to NULL.4. Fixing the
wm8775_probe()function to do something sensible, knowing that the .s_config method may get called once by the infrastructure, and/or once again by the cx88 driver or the ivtv driver.5. Searching through the video drivers to see if any other drivers may use the wm8775 module, and validating that your changes won't break them.
All I see with a quick grep is cx88, ivtv, and pvrusb2
6. Testing with real hardware....
Regards,
Andy
Signature · 1 line
Hans Verkuil - video4linux developer - sponsored by Cisco
Quoted 45 lines · Hans Verkuil
Quoted 36 lines · On Monday, January 03, 2011 23:34:16 Andy Walls wrote:
Quoted 8 lines · Eric Sharkey
Quoted 7 lines · Andy Walls
Mauro,
Please revert at least the
wm8775.cportion of commitfcb9757333df37cf4a7feccef7ef6f5300643864:Quoted 8 lines
Quoted 2 lines
It completely trashes baseband line-in audio for PVR-150 cards, and likely does the same for any other ivtv card that has a WM8775 chip.
Confirmed. I manually rolled back most of the changes in that commit for
wm8775.c, leaving all other files alone, and the audio is now working correctly for me. I haven't yet narrowed it down to exactly which changes in that file cause the problem. I'll try and do that tomorrow if I have time.This might help then:
http://dl.ivtvdriver.org/datasheets/audio/WM8775.pdf
I don't have time to look, but I'm hoping it is just the initialization in
wm8775_probe().Without both a PVR-150 card and a Nova-S-plus DVB-S with which to test you are unlikely to get an initialization that works for both the Nova-S Plus and PVR-150. Even if you did, such a configuration would be "fragile" in that it will be hard to tweak in the future for one card without breaking the other. (Code reuse doesn't work out too well for setting up hardware parameters.)
The fix will probably have to use some context sensitive initialization in
wm8775_probe(): "Am I being called by ivtv for a PVR-150 or cx88 for a Nova-S plus?"Quoted 7 lines
Which probably means:
1. adding a ".s_config" method to the "
wm8775_core_ops" See:
http://git.linuxtv.org/media_tree.git?a=blob;f=Documentation/video4linux/v4l2-framework.txt;h=f22f35c271f38d34fda0c19d8942b536e2fc95d9;hb=staging/for_v2.6.38#l206
http://git.linuxtv.org/media_tree.git?a=blob;f=include/media/v4l2-subdev.h;h=b0316a7cf08d21f2ac68f1dc452894441948c155;hb=staging/for_v2.6.38#l109
http://git.linuxtv.org/media_tree.git?a=blob;f=include/media/v4l2-subdev.h;h=b0316a7cf08d21f2ac68f1dc452894441948c155;hb=staging/for_v2.6.38#l141
Quoted 3 lines
Don't use .s_config! That will be removed soon.
Use
platform_dataandv4l2_i2c_new_subdev_boardinstead.
Gah! Sorry.
I knew that .init had been deprecated. The comments in v4l2_subdev.h indicate that .init is deprecated, but do not do the same for .s_config.
Regards,
Andy
Quoted 9 lines · Andy Walls
Quoted 8 lines · Eric Sharkey
Quoted 7 lines · Andy Walls
Mauro,
Please revert at least the
wm8775.cportion of commitfcb9757333df37cf4a7feccef7ef6f5300643864:
Quoted 8 lines
Quoted 8 lines
Quoted 2 lines
It completely trashes baseband line-in audio for PVR-150 cards, and likely does the same for any other ivtv card that has a WM8775 chip.
Confirmed. I manually rolled back most of the changes in that commit for
wm8775.c, leaving all other files alone, and the audio is now working correctly for me. I haven't yet narrowed it down to exactly which changes in that file cause the problem. I'll try and do that tomorrow if I have time.
Oh dear, you leave the ranch for 5 minutes to a place without email and all hell breaks loose. Didn't anyone think that New Year is a time for holidays?
So, for a minor niggle, which is trivially sorted, you pull almost the whole patch leaving the only bit that causes problems for the Nova-S (for which the patch was intended). The remnant, drivers/media/video/cx88/cx88-cards.c line 970, adds wm8775 baseband audio-in which is horribly distorted without the patch. So I suggest it too is removed.
Now, if someone can direct me to a full hardware description for the PVR-150 and datasheets for the components connected to the wm8775 then I'll endeavour to provide a solution compatible with both. If anyone can loan me a PVR-150 then so much the better, but it's not essential if the full docs are available.
-- Lawrence
Quoted 19 lines · Lawrence Rust
Quoted 9 lines · Andy Walls
Quoted 8 lines · Eric Sharkey
Quoted 7 lines · Andy Walls
Mauro,
Please revert at least the
wm8775.cportion of commitfcb9757333df37cf4a7feccef7ef6f5300643864:Quoted 8 lines
Quoted 8 lines
Quoted 2 lines
It completely trashes baseband line-in audio for PVR-150 cards, and likely does the same for any other ivtv card that has a WM8775 chip.
Confirmed. I manually rolled back most of the changes in that commit for
wm8775.c, leaving all other files alone, and the audio is now working correctly for me. I haven't yet narrowed it down to exactly which changes in that file cause the problem. I'll try and do that tomorrow if I have time.
Quoted 7 lines
Oh dear, you leave the ranch for 5 minutes to a place without email and all hell breaks loose. Didn't anyone think that New Year is a time for holidays?
So, for a minor niggle, which is trivially sorted, you pull almost the whole patch leaving the only bit that causes problems for the Nova-S (for which the patch was intended).
Sorry Lawrence. I didn't have time to review and test the original patch properly when you submitted it. By the time the regression was discovered there was not time for me to fix. (I did have to do work for customers between Christmas and New Year's :( ).
Getting fixes back into stable trees is a royal PITA and has a time lag waiting for the fix to get upstream first. It's better not to let regression slip forward into a kernel release.
If the PVR-150 was some low volume distribution card that no one used or had only been in the kernel for only a few releases, I wouldn't have pushed so hard for the revert.
However the PVR-150 is a very popular card and many units are in service with linux users. It is the 1st choice for analog recording for many users with a MythTV setup. With the transition to DTV in the US, the PVR-150's banseband input is the most useful part of the card in the US.
Quoted 7 lines
The remnant,
drivers/media/video/cx88/cx88-cards.cline 970, adds wm8775 baseband audio-in which is horribly distorted without the patch. So I suggest it too is removed.Now, if someone can direct me to a full hardware description for the PVR-150
http://git.linuxtv.org/media_tree.git?a=blob;f=drivers/media/video/ivtv/ivtv-cards.c;h=87afbbee20636f1e9f1192f8592a35954382bd7f;hb=master#l190
http://www.hauppauge.com/site/support/support_pvr150.html
Quoted 2 lines
and datasheets for the components connected to the wm8775 then I'll endeavour to provide a solution compatible with both.
WM8775:
http://dl.ivtvdriver.org/datasheets/audio/WM8775.pdf
CX2584[0123]:
http://dl.ivtvdriver.org/datasheets/video/cx25840.pdf
CX23416 (old, but the first hit with a Google search):
http://www.google.com/url?sa=t&source=web&cd=1&sqi=2&ved=0CBQQFjAA&url=http%3A%2F%2Fwww.icbank.com%2Ficbank_data%2Fonline_seminar%2Fconexant_060517%2FDatasheet.pdf&rct=j&q=CX23416%20datasheet&ei=GHAoTf31MYWglAeh_bG4AQ&usg=AFQjCNHESSp00ahlEGzxm6I-RXZ7WBMA0w&cad=rja
One of many different analog tuners that can bue used with a PVR-150:
http://dl.ivtvdriver.org/datasheets/tuners/TAPE-H091F_MK3.pdf
Good photographs of the PVR-150MCE board:
http://www.ixbt.com/monitor/images/hauppauge-pvr150/hauppauge-pvr-150-front.jpg
http://www.ixbt.com/monitor/images/hauppauge-pvr150/hauppauge-pvr-150-back.jpg
Approximate layout of the sound path:
+-------------+ +---------------+
| SIF|----------------------->|AFE In8 | +---------+
| Analog | | CX25843 | | CX23416 |
| Tuner | +-----------+ | | | |
| TV AF|------>|AIN1 I2S|--->|I2S In I2S Out|--->|I2S In |
| FM L,R|------>|AIN4 | +---------------+ | |
+-------------+ | WM8775 | | PCI|<--->
| | +---------+
Line In 1 L,R ------->|AIN2 |
Line In 2 L,R ------->|AIN3 |
+-----------+Note that
1. the PVR-500 is essentially two PVR-150's on on card and also uses the WM8775/CX2584x combination but with smaller, probably poorer performing, ananlog tuners. .
2. other cards use the CX2584x with something other than a WM8775 (e.g. a WM8739 with a 74HC4052 analog mux chip)
3. the ivtv driver support use of the CX23416 with other audio decoder chips aside from the CX2584x family, such as MSP34xx or SAA717x chips.
4. the pvrusb2 module is approximately a USB connected version of a PVR-150.
Perturbing the hardware configuration code in the ivtv, cx25840, wm8775 modules has to be done with some care. Otherwise, hardware that has been deployed and in use under linux for a while will break.
Linus is pretty clear on his policy about breaking userspace:
https://lkml.org/lkml/2010/11/19/673
Quoted 3 lines
If anyone
can loan me a PVR-150 then so much the better, but it's not essential if the full docs are available.
It would be cheaper for me to buy it for you than to ship you one from the US:
http://shop.ebay.co.uk/?_from=R40&_trksid=p4295.m570.l1313&_nkw=PVR-150&_sacat=See-All-Categories
They are a lot of these units out there. Used ones are *really* cheap.
Regards,
Andy
Quoted 24 lines · Andy Walls
Quoted 23 lines · Lawrence Rust
Quoted 9 lines · Andy Walls
Quoted 8 lines · Eric Sharkey
Quoted 7 lines · Andy Walls
Mauro,
Please revert at least the
wm8775.cportion of commitfcb9757333df37cf4a7feccef7ef6f5300643864:Quoted 8 lines
Quoted 8 lines
Quoted 2 lines
It completely trashes baseband line-in audio for PVR-150 cards, and likely does the same for any other ivtv card that has a WM8775 chip.
Confirmed. I manually rolled back most of the changes in that commit for
wm8775.c, leaving all other files alone, and the audio is now working correctly for me. I haven't yet narrowed it down to exactly which changes in that file cause the problem. I'll try and do that tomorrow if I have time.Oh dear, you leave the ranch for 5 minutes to a place without email and all hell breaks loose. Didn't anyone think that New Year is a time for holidays?
Quoted 8 lines
Quoted 3 lines
So, for a minor niggle, which is trivially sorted, you pull almost the whole patch leaving the only bit that causes problems for the Nova-S (for which the patch was intended).
Sorry Lawrence. I didn't have time to review and test the original patch properly when you submitted it. By the time the regression was discovered there was not time for me to fix. (I did have to do work for customers between Christmas and New Year's :( ).
You should try harder to take a decent break. It works wonders.
Thanks for the info on the PVR-150. It largely confirmed what I had surmised - that the two cards disagree about serial audio data format. Before my patch, the wm8775 was programmed for Philips mode but the CX25843 on the PVR-150 is setup for Sony I2S mode!! On the Nova-S, the cx23883 is setup (in cx88-tvaudio.c) for Philips mode. The patch changed the wm8775 to Sony I2S mode because the existing setup gave noise, indicative of a mismatch.
It is my belief that either the wm8775 datasheet is wrong or there are inverters on the SCLK lines between the wm8775 and cx25843/23883. It is also plausible that Conexant have it wrong and both their datasheets are wrong.
Anyway, I have revised the patch (attached) so that the wm8775 is kept in Philips mode (to please the PVR-150) and the cx23883 on the Nove-S is now switched to Sony I2S mode (like the PVR-150) and this works fine. The change is trivial, just 2 lines, so they're shouldn't be any other consequences. However, could this affect any other cards?
NB I have only tested this patch on my Nova-S, no other.
-- Lawrence
drivers/media/video/cx88/cx88-alsa.c +86 -12
@@ -40,6 +40,7 @@#include <sound/control.h> #include <sound/initval.h> #include <sound/tlv.h> +#include <media/wm8775.h> #include "cx88.h" #include "cx88-reg.h"
@@ -586,26 +587,47 @@ static int snd_cx88_volume_put(struct snd_kcontrol *kcontrol,int left, right, v, b;int changed =0 ;u32 old; +struct v4l2_control client_ctl; + +/* Pass volume & balance onto any WM8775 */ +if ( value->value.integer.value[0 ] >= value->value.integer.value[1 ]) { + v = value->value.integer.value[0 ] <<10 ; + b = value->value.integer.value[0 ] ? + (0x8000 * value->value.integer.value[1 ]) / value->value.integer.value[0 ] : +0x8000 ; + }else { + v = value->value.integer.value[1 ] <<10 ; + b = value->value.integer.value[1 ] ? +0xffff - (0x8000 * value->value.integer.value[0 ]) / value->value.integer.value[1 ] : +0x8000 ; + } + client_ctl.value = v; + client_ctl.id =V4L2_CID_AUDIO_VOLUME ; +call_hw (core,WM8775_GID , core, s_ctrl, &client_ctl); + + client_ctl.value = b; + client_ctl.id =V4L2_CID_AUDIO_BALANCE ; +call_hw (core,WM8775_GID , core, s_ctrl, &client_ctl); left = value->value.integer.value[0 ] &0x3f ; right = value->value.integer.value[1 ] &0x3f ; b = right - left;if (b <0 ) { - v =0x3f - left; - b = (-b) |0x40 ; + v =0x3f - left; + b = (-b) |0x40 ; }else { - v =0x3f - right; + v =0x3f - right; }/* Do we really know this will always be called with IRQs on? */ spin_lock_irq (&chip->reg_lock); old =cx_read (AUD_VOL_CTL );if (v != (old &0x3f )) { -cx_write (AUD_VOL_CTL , (old & ~0x3f ) | v); - changed =1 ; +cx_swrite (SHADOW_AUD_VOL_CTL ,AUD_VOL_CTL , (old & ~0x3f ) | v); + changed =1 ; } -if (cx_read (AUD_BAL_CTL ) != b) { -cx_write (AUD_BAL_CTL , b); - changed =1 ; +if ((cx_read (AUD_BAL_CTL ) &0x7f ) != b) { +cx_write (AUD_BAL_CTL , b); + changed =1 ; }spin_unlock_irq (&chip->reg_lock);
@@ -618,7 +640,7 @@ static const struct snd_kcontrol_new snd_cx88_volume = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .access =SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, - .name = "Playback Volume", + .name = "Analog-TV Volume", .info = snd_cx88_volume_info, .get = snd_cx88_volume_get, .put = snd_cx88_volume_put,
@@ -649,7 +671,14 @@ static int snd_cx88_switch_put(struct snd_kcontrol *kcontrol, vol =cx_read (AUD_VOL_CTL );if (value->value.integer.value[0 ] != !(vol & bit)) { vol ^= bit; -cx_write (AUD_VOL_CTL , vol); +cx_swrite (SHADOW_AUD_VOL_CTL ,AUD_VOL_CTL , vol); +/* Pass mute onto any WM8775 */ +if ( (1 <<6 ) == bit) { +struct v4l2_control client_ctl; + client_ctl.value =0 != (vol & bit); + client_ctl.id =V4L2_CID_AUDIO_MUTE ; +call_hw (core,WM8775_GID , core, s_ctrl, &client_ctl); + } ret =1 ; }spin_unlock_irq (&chip->reg_lock);
@@ -658,7 +687,7 @@ static int snd_cx88_switch_put(struct snd_kcontrol *kcontrol,static const struct snd_kcontrol_new snd_cx88_dac_switch = { .iface =SNDRV_CTL_ELEM_IFACE_MIXER , - .name ="Playback Switch" , + .name ="Audio-Out Switch" , .info = snd_ctl_boolean_mono_info, .get = snd_cx88_switch_get, .put = snd_cx88_switch_put,
@@ -667,13 +696,49 @@ static const struct snd_kcontrol_new snd_cx88_dac_switch = {static const struct snd_kcontrol_new snd_cx88_source_switch = { .iface =SNDRV_CTL_ELEM_IFACE_MIXER , - .name ="Capture Switch" , + .name ="Analog-TV Switch" , .info = snd_ctl_boolean_mono_info, .get = snd_cx88_switch_get, .put = snd_cx88_switch_put, .private_value = (1 <<6 ), }; +static int snd_cx88_alc_get (struct snd_kcontrol *kcontrol, +struct snd_ctl_elem_value *value) +{ +snd_cx88_card_t *chip =snd_kcontrol_chip (kcontrol); +struct cx88_core *core = chip->core; +struct v4l2_control client_ctl; + + client_ctl.id =V4L2_CID_AUDIO_LOUDNESS ; +call_hw (core,WM8775_GID , core, g_ctrl, &client_ctl); + value->value.integer.value[0 ] = client_ctl.value ?1 :0 ; + +return 0 ; +} + +static int snd_cx88_alc_put (struct snd_kcontrol *kcontrol, +struct snd_ctl_elem_value *value) +{ +snd_cx88_card_t *chip =snd_kcontrol_chip (kcontrol); +struct cx88_core *core = chip->core; +struct v4l2_control client_ctl; + + client_ctl.value =0 != value->value.integer.value[0 ]; + client_ctl.id =V4L2_CID_AUDIO_LOUDNESS ; +call_hw (core,WM8775_GID , core, s_ctrl, &client_ctl); + +return 0 ; +} + +static struct snd_kcontrol_new snd_cx88_alc_switch = { + .iface =SNDRV_CTL_ELEM_IFACE_MIXER , + .name ="Line-In ALC Switch" , + .info = snd_ctl_boolean_mono_info, + .get = snd_cx88_alc_get, + .put = snd_cx88_alc_put, +}; +/**************************************************************************** Basic Flow for Sound Devices ****************************************************************************/
@@ -830,6 +895,15 @@ static int __devinit cx88_audio_initdev(struct pci_dev *pci,if (err <0 ) goto error; +/* If there's a wm8775 then add a Line-In ALC switch */ + {struct v4l2_subdev *sd; +list_for_each_entry (sd, &chip->core->v4l2_dev.subdevs, list) { +if (WM8775_GID == sd->grp_id) { +snd_ctl_add (card,snd_ctl_new1 (&snd_cx88_alc_switch, chip)); +break ; + } + }} +strcpy (card->driver,"CX88x" );sprintf (card->shortname,"Conexant CX%x" , pci->device); sprintf(card->longname, "%s at %#llx",
drivers/media/video/cx88/cx88-video.c +26 -1
@@ -41,6 +41,7 @@#include "cx88.h" #include <media/v4l2-common.h> #include <media/v4l2-ioctl.h> +#include <media/wm8775.h> MODULE_DESCRIPTION ("v4l2 driver module for cx2388x based TV cards" );MODULE_AUTHOR ("Gerd Knorr <[email protected]> [SuSE Labs]" );
@@ -978,6 +979,7 @@ int cx88_set_control(struct cx88_core *core, struct v4l2_control *ctl)const struct cx88_ctrl *c =NULL ;u32 value,mask;int i; +struct v4l2_control client_ctl;for (i =0 ; i <CX8800_CTLS ; i++) {if (cx8800_ctls[i].v.id == ctl->id) {
@@ -991,6 +993,27 @@ int cx88_set_control(struct cx88_core *core, struct v4l2_control *ctl) ctl->value = c->v.minimum;if (ctl->value > c->v.maximum) ctl->value = c->v.maximum; + +/* Pass changes onto any WM8775 */ + client_ctl.id = ctl->id; +switch (ctl->id) { +case V4L2_CID_AUDIO_MUTE : + client_ctl.value = ctl->value; +break ; +case V4L2_CID_AUDIO_VOLUME : + client_ctl.value = (ctl->value) ? + (0x90 + ctl->value) <<8 :0 ; +break ; +case V4L2_CID_AUDIO_BALANCE : + client_ctl.value = ctl->value <<9 ; +break ; +default : + client_ctl.id =0 ; +break ; + } +if (client_ctl.id) +call_hw (core,WM8775_GID , core, s_ctrl, &client_ctl); + mask=c->mask;switch (ctl->id) {case V4L2_CID_AUDIO_BALANCE :
@@ -1537,7 +1560,9 @@ static int radio_queryctrl (struct file *file, void *priv,if (c->id <V4L2_CID_BASE || c->id >=V4L2_CID_LASTP1 )return -EINVAL ; -if (c->id ==V4L2_CID_AUDIO_MUTE ) { +if (c->id ==V4L2_CID_AUDIO_MUTE || + c->id ==V4L2_CID_AUDIO_VOLUME || + c->id ==V4L2_CID_AUDIO_BALANCE ) {for (i =0 ; i <CX8800_CTLS ; i++) {if (cx8800_ctls[i].v.id == c->id)break ;
drivers/media/video/cx88/cx88.h +4 -2
@@ -398,17 +398,19 @@ static inline struct cx88_core *to_core(struct v4l2_device *v4l2_dev) return container_of(v4l2_dev, struct cx88_core, v4l2_dev); } -#define call_all(core, o, f, args...) \ +#define call_hw(core, grpid, o, f, args...) \ do { \ if (!core->i2c_rc) { \ if (core->gate_ctrl) \ core->gate_ctrl(core, 1); \ - v4l2_device_call_all(&core->v4l2_dev, 0, o, f, ##args); \ + v4l2_device_call_all(&core->v4l2_dev, grpid, o, f, ##args); \ if (core->gate_ctrl) \ core->gate_ctrl(core, 0); \ } \ } while (0) +#define call_all(core, o, f, args...) call_hw(core, 0, o, f, ##args) +struct cx8800_dev ;struct cx8802_dev ;
drivers/media/video/wm8775.c +64 -38
177 lines not on this page · raw message
include/media/wm8775.h +3 -0
@@ -32,4 +32,7 @@#define WM8775_AIN3 4#define WM8775_AIN4 8 +/* subdev group ID */ +#define WM8775_GID (1 << 0) +#endif
drivers/media/video/cx88/cx88-tvaudio.c +3 -2
@@ -786,8 +786,9 @@break ;case WW_I2SADC :set_audio_start (core,0x01 ); -/* Slave/Philips/Autobaud */ -cx_write (AUD_I2SINPUTCNTL ,0 ); +/* Slave/Philips/Autobaud +* NB on Nova-S bit1 NPhilipsSony appears to be inverted; 0= Sony, 1=Philips */ +cx_write (AUD_I2SINPUTCNTL ,2 );/* Switch to "I2S ADC mode" */ cx_write (AUD_I2SCNTL ,0x1 );set_audio_finish (core,EN_I2SIN_ENABLE );
Quoted 10 lines · Lawrence Rust
On Sat, 2011-01-08 at 09:22 -0500, Andy Walls wrote:
Thanks for the info on the PVR-150. It largely confirmed what I had surmised - that the two cards disagree about serial audio data format. Before my patch, the wm8775 was programmed for Philips mode but the CX25843 on the PVR-150 is setup for Sony I2S mode!! On the Nova-S, the cx23883 is setup (in
cx88-tvaudio.c) for Philips mode. The patch changed the wm8775 to Sony I2S mode because the existing setup gave noise, indicative of a mismatch.
Quoted 8 lines
It is my belief that either the wm8775 datasheet is wrong or there are inverters on the SCLK lines between the wm8775 and cx25843/23883. It is also plausible that Conexant have it wrong and both their datasheets are wrong.
Anyway, I have revised the patch (attached) so that the wm8775 is kept in Philips mode (to please the PVR-150) and the cx23883 on the Nove-S is now switched to Sony I2S mode (like the PVR-150) and this works fine.
I will try and review and test this coming weekend.
Quoted 2 lines
The change is trivial, just 2 lines, so they're shouldn't be any other consequences. However, could this affect any other cards?
That is the problem with code reuse, for multiple board models, in all the I2C modules. It makes code increasingly more difficult to maintain as more different board models are supported and tested.
But now there is infrastructure in place to pass board specific info down to the I2C v4l2_subdevice drivers. If the wm8775 driver were changed to provide a wm8775-specific platform-data structure for bridge drivers to use, bridge drivers could fill it out and call v4l2_i2c_new_subdev_board() to instantiate the wm8775 device instance specific to the board: Nova-S, PVR-150, or whatever.
See the interaction between the ivtv and cx25840 module in this patch as an example:
https://patchwork.kernel.org/patch/465571/
(Not all of the details are visible in the patch, since some were already there for the .s_config call in cx25840.)
Obviously, the wm8775 module would need code added to take different actions when passed different platform data. However, that the best way to make sure one doesn't accidentally affect other boards.
Quoted 1 line
NB I have only tested this patch on my Nova-S, no other.
I do see one problem with your patch at the moment:
include/media/wm8775.c +0 -0
...
+ sd->grp_id = WM8775_GID; /* subdev group id */
...
include/media/wm8775.h +0 -0
...
+/* subdev group ID */
+#define WM8775_GID (1 << 0)
+
...
The wm8775 module probably should not define WM8775_GID and definitely should not set sd->grp_id. The sd->grp_id is for the bridge driver's use for that v4l2_subdev instance. Some bridge drivers may expect it to be 0 unless they set it themselves. The group ID values should be defined in the bridge driver, and the sd->grp_id field should be set by the bridge driver.
You would want to do that in cx88. See cx23885, ivtv, and cx18 as examples of bridge drivers that use the group id field.
Regards,
Andy
On Mon, 2011-01-10 at 07:39 -0500, Andy Walls wrote:
[snip]
Quoted 21 lines
I do see one problem with your patch at the moment:
include/media/wm8775.c +1
-0+ sd->grp_id =WM8775_GID ;/* subdev group id */ include/media/wm8775.h +3
-0+/* subdev group ID */ +#define WM8775_GID (1 << 0) +The wm8775 module probably should not define
WM8775_GIDand definitely should not setsd->grp_id. Thesd->grp_idis for the bridge driver's use for thatv4l2_subdevinstance. Some bridge drivers may expect it to be 0 unless they set it themselves. The group ID values should be defined in the bridge driver, and thesd->grp_idfield should be set by the bridge driver.
Quoted 2 lines
You would want to do that in cx88. See cx23885, ivtv, and cx18 as examples of bridge drivers that use the group id field.
You know what, life's too short. I've spent far too long on this at the expense of far more interesting projects. Every time I put some effort in someone says just one more thing... I get the message. I'll just keep the patch for my personal use. For those that are interested I'll maintain a copy here:
http://www.softsystem.co.uk/download/patches/nova-2.6.37.patch
-- Lawrence
Quoted 5 lines · Lawrence Rust
On Mon, 2011-01-10 at 07:39 -0500, Andy Walls wrote:
You know what, life's too short. I've spent far too long on this at the expense of far more interesting projects. Every time I put some effort in someone says just one more thing... I get the message.
With all due respect, I don't think that you do.
The message is *not*
"Lawrence we don't won't your patches here , because we're an exclusive club"
nor
"Lawrence, we don't find your time and talent valuable"
All of my comments stem from *one* high level requirement:
Don't break the code for existing boards - especially popular ones for which I have some level of maintenance responsibility.
How you satisfy that requirement is up to you.
Just as you don't have a lot of time to do all the analysis and testing to ensure that requirement is met; I don't have time to clean up every patch that doesn't meet that requirement. The time and effort you don't expend gets pushed off to me or someone else.
I have tried to provide you with constructive criticism and guidance. I will not do your work for you.
Regards,
Andy
Hi Lawrence,
Em 08-01-2011 16:45, Lawrence Rust escreveu:
Quoted 13 lines
Thanks for the info on the PVR-150. It largely confirmed what I had surmised - that the two cards disagree about serial audio data format. Before my patch, the wm8775 was programmed for Philips mode but the CX25843 on the PVR-150 is setup for Sony I2S mode!! On the Nova-S, the cx23883 is setup (in
cx88-tvaudio.c) for Philips mode. The patch changed the wm8775 to Sony I2S mode because the existing setup gave noise, indicative of a mismatch.It is my belief that either the wm8775 datasheet is wrong or there are inverters on the SCLK lines between the wm8775 and cx25843/23883. It is also plausible that Conexant have it wrong and both their datasheets are wrong.
Quoted 7 lines
Anyway, I have revised the patch (attached) so that the wm8775 is kept in Philips mode (to please the PVR-150) and the cx23883 on the Nove-S is now switched to Sony I2S mode (like the PVR-150) and this works fine. The change is trivial, just 2 lines, so they're shouldn't be any other consequences. However, could this affect any other cards?
NB I have only tested this patch on my Nova-S, no other.
As it was pointed, your patch affects other boards with wm8775. In order to avoid it, you need to use platform_data to pass nova_s specific parameters, and be sure that other boards won't be affected by your changes.
As you might not be able to see how this should be written, I modified your patch in a way that, hopefully, it won't affect PVR-150. Please test.
Please notice that I don't have any board with wm8775 handy, so it is compiled-only.
If this patch doesn't break PVR-150 or Nova-S, then I think we can merge it.
There are however two issues:
1) I don't think it is a good idea to keep the I2C group for wm8775 inside
the wm8775 header. Instead, we should move it to some place were people can look on it to avoid duplicated groups. We may instead just get rid of it, as I added tests for wm8775 on all places. So, only if wm8775 is used, the i2c subdev commands will be called.
2) I just added one platform_data info that indicates if the device is anova_s or not. I did it just because I was lazy enough to not go through wm8775 datasheet and add parameters for the parameters that are different. The better is to split it into some more parameters.
If it works for you, please add your Signed-off-by:.
Andy,
please test if this don't break ivtv. If it breaks, please help us to fix, as only you noticed an issue on the previous versions.
-
From: Lawrence Rust <[email protected]>
This patch adds audio DMA capture and ALSA mixer elements for the line input jack of the Hauppauge Nova-S-plus DVB-S PCI card. The Nova-S-plus has a WM8775 ADC that is currently not detected. This patch enables this chip and exports volume, balance mute and ALC elements for ALSA mixer controls.
[[email protected]: Changed the patch to only talk with wm8775 if board info says so. Also, added platform_data support, to avoid changing the behaviour for other boards, and fixed CodingStyle]
drivers/media/video/cx88/cx88-alsa.c +103 -15
@@ -40,6 +40,7 @@#include <sound/control.h> #include <sound/initval.h> #include <sound/tlv.h> +#include <media/wm8775.h> #include "cx88.h" #include "cx88-reg.h"
@@ -577,6 +578,35 @@ static int snd_cx88_volume_get(struct snd_kcontrol *kcontrol,return 0 ; } +static void snd_cx88_wm8775_volume_put (struct snd_kcontrol *kcontrol, +struct snd_ctl_elem_value *value) +{ +snd_cx88_card_t *chip =snd_kcontrol_chip (kcontrol); +struct cx88_core *core = chip->core; +struct v4l2_control client_ctl; +int left = value->value.integer.value[0 ]; +int right = value->value.integer.value[1 ]; +int v, b; + +memset (&client_ctl,0 ,sizeof (client_ctl)); + +/* Pass volume & balance onto any WM8775 */ +if (left >= right) { + v = left <<10 ; + b = left ? (0x8000 * right) / left :0x8000 ; + }else { + v = right <<10 ; + b = right ?0xffff - (0x8000 * left) / right :0x8000 ; + } + client_ctl.value = v; + client_ctl.id =V4L2_CID_AUDIO_VOLUME ; +call_hw (core,WM8775_GID , core, s_ctrl, &client_ctl); + + client_ctl.value = b; + client_ctl.id =V4L2_CID_AUDIO_BALANCE ; +call_hw (core,WM8775_GID , core, s_ctrl, &client_ctl); +} +/* OK - TODO: test it */ static int snd_cx88_volume_put (struct snd_kcontrol *kcontrol,struct snd_ctl_elem_value *value)
@@ -587,25 +617,28 @@ static int snd_cx88_volume_put(struct snd_kcontrol *kcontrol,int changed =0 ;u32 old; +if (core->board.audio_chip ==V4L2_IDENT_WM8775 ) +snd_cx88_wm8775_volume_put (kcontrol, value); + left = value->value.integer.value[0 ] &0x3f ; right = value->value.integer.value[1 ] &0x3f ; b = right - left;if (b <0 ) { - v =0x3f - left; - b = (-b) |0x40 ; + v =0x3f - left; + b = (-b) |0x40 ; }else { - v =0x3f - right; + v =0x3f - right; }/* Do we really know this will always be called with IRQs on? */ spin_lock_irq (&chip->reg_lock); old =cx_read (AUD_VOL_CTL );if (v != (old &0x3f )) { -cx_write (AUD_VOL_CTL , (old & ~0x3f ) | v); - changed =1 ; +cx_swrite (SHADOW_AUD_VOL_CTL ,AUD_VOL_CTL , (old & ~0x3f ) | v); + changed =1 ; } -if (cx_read (AUD_BAL_CTL ) != b) { -cx_write (AUD_BAL_CTL , b); - changed =1 ; +if ((cx_read (AUD_BAL_CTL ) &0x7f ) != b) { +cx_write (AUD_BAL_CTL , b); + changed =1 ; }spin_unlock_irq (&chip->reg_lock);
@@ -618,7 +651,7 @@ static const struct snd_kcontrol_new snd_cx88_volume = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .access =SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, - .name = "Playback Volume", + .name = "Analog-TV Volume", .info = snd_cx88_volume_info, .get = snd_cx88_volume_get, .put = snd_cx88_volume_put,
@@ -649,7 +682,17 @@ static int snd_cx88_switch_put(struct snd_kcontrol *kcontrol, vol =cx_read (AUD_VOL_CTL );if (value->value.integer.value[0 ] != !(vol & bit)) { vol ^= bit; -cx_write (AUD_VOL_CTL , vol); +cx_swrite (SHADOW_AUD_VOL_CTL ,AUD_VOL_CTL , vol); +/* Pass mute onto any WM8775 */ +if ((core->board.audio_chip ==V4L2_IDENT_WM8775 ) && + ((1 <<6 ) == bit)) { +struct v4l2_control client_ctl; + +memset (&client_ctl,0 ,sizeof (client_ctl)); + client_ctl.value =0 != (vol & bit); + client_ctl.id =V4L2_CID_AUDIO_MUTE ; +call_hw (core,WM8775_GID , core, s_ctrl, &client_ctl); + } ret =1 ; }spin_unlock_irq (&chip->reg_lock);
@@ -658,7 +701,7 @@ static int snd_cx88_switch_put(struct snd_kcontrol *kcontrol,static const struct snd_kcontrol_new snd_cx88_dac_switch = { .iface =SNDRV_CTL_ELEM_IFACE_MIXER , - .name ="Playback Switch" , + .name ="Audio-Out Switch" , .info = snd_ctl_boolean_mono_info, .get = snd_cx88_switch_get, .put = snd_cx88_switch_put,
@@ -667,13 +710,51 @@ static const struct snd_kcontrol_new snd_cx88_dac_switch = {static const struct snd_kcontrol_new snd_cx88_source_switch = { .iface =SNDRV_CTL_ELEM_IFACE_MIXER , - .name ="Capture Switch" , + .name ="Analog-TV Switch" , .info = snd_ctl_boolean_mono_info, .get = snd_cx88_switch_get, .put = snd_cx88_switch_put, .private_value = (1 <<6 ), }; +static int snd_cx88_alc_get (struct snd_kcontrol *kcontrol, +struct snd_ctl_elem_value *value) +{ +snd_cx88_card_t *chip =snd_kcontrol_chip (kcontrol); +struct cx88_core *core = chip->core; +struct v4l2_control client_ctl; + +memset (&client_ctl,0 ,sizeof (client_ctl)); + client_ctl.id =V4L2_CID_AUDIO_LOUDNESS ; +call_hw (core,WM8775_GID , core, g_ctrl, &client_ctl); + value->value.integer.value[0 ] = client_ctl.value ?1 :0 ; + +return 0 ; +} + +static int snd_cx88_alc_put (struct snd_kcontrol *kcontrol, +struct snd_ctl_elem_value *value) +{ +snd_cx88_card_t *chip =snd_kcontrol_chip (kcontrol); +struct cx88_core *core = chip->core; +struct v4l2_control client_ctl; + +memset (&client_ctl,0 ,sizeof (client_ctl)); + client_ctl.value =0 != value->value.integer.value[0 ]; + client_ctl.id =V4L2_CID_AUDIO_LOUDNESS ; +call_hw (core,WM8775_GID , core, s_ctrl, &client_ctl); + +return 0 ; +} + +static struct snd_kcontrol_new snd_cx88_alc_switch = { + .iface =SNDRV_CTL_ELEM_IFACE_MIXER , + .name ="Line-In ALC Switch" , + .info = snd_ctl_boolean_mono_info, + .get = snd_cx88_alc_get, + .put = snd_cx88_alc_put, +}; +/**************************************************************************** Basic Flow for Sound Devices ****************************************************************************/
@@ -724,7 +805,8 @@ static void snd_cx88_dev_free(struct snd_card * card)static int devno;static int __devinit snd_cx88_create (struct snd_card *card,struct pci_dev *pci, -snd_cx88_card_t **rchip) +snd_cx88_card_t **rchip, +struct cx88_core **core_ptr) {snd_cx88_card_t *chip;struct cx88_core *core;
@@ -750,7 +832,7 @@ static int __devinit snd_cx88_create(struct snd_card *card,if (!pci_dma_supported (pci,DMA_BIT_MASK (32 ))) {dprintk (0 ,"%s/1: Oops: no 32bit PCI DMA ???\n" ,core->name); err = -EIO ; -cx88_core_put (core,pci); +cx88_core_put (core, pci);return err; }
@@ -786,6 +868,7 @@ static int __devinit snd_cx88_create(struct snd_card *card,snd_card_set_dev (card, &pci->dev); *rchip = chip; + *core_ptr = core;return 0 ; }
@@ -795,6 +878,7 @@ static int __devinit cx88_audio_initdev(struct pci_dev *pci, {struct snd_card *card;snd_cx88_card_t *chip; +struct cx88_core *core;int err;if (devno >=SNDRV_CARDS )
@@ -812,7 +896,7 @@ static int __devinit cx88_audio_initdev(struct pci_dev *pci, card->private_free = snd_cx88_dev_free; - err =snd_cx88_create (card, pci, &chip); + err =snd_cx88_create (card, pci, &chip, &core);if (err <0 ) goto error;
@@ -830,6 +914,10 @@ static int __devinit cx88_audio_initdev(struct pci_dev *pci,if (err <0 ) goto error; +/* If there's a wm8775 then add a Line-In ALC switch */ +if (core->board.audio_chip ==V4L2_IDENT_WM8775 ) +snd_ctl_add (card,snd_ctl_new1 (&snd_cx88_alc_switch, chip)); +strcpy (card->driver,"CX88x" );sprintf (card->shortname,"Conexant CX%x" , pci->device); sprintf(card->longname, "%s at %#llx",
drivers/media/video/cx88/cx88-cards.c +2 -1
@@ -970,7 +970,8 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .audio_chip = V4L2_IDENT_WM8775, + .audio_chip = V4L2_IDENT_WM8775, + .i2sinputcntl = 2, .input = {{ .type = CX88_VMUX_DVB, .vmux = 0,
drivers/media/video/cx88/cx88-tvaudio.c +6 -2
@@ -786,8 +786,12 @@ void cx88_set_tvaudio(struct cx88_core *core)break ;case WW_I2SADC :set_audio_start (core,0x01 ); -/* Slave/Philips/Autobaud */ -cx_write (AUD_I2SINPUTCNTL ,0 ); +/* +* Slave/Philips/Autobaud +* NB on Nova-S bit1 NPhilipsSony appears to be inverted: +* 0= Sony, 1=Philips +*/ +cx_write (AUD_I2SINPUTCNTL , core->board.i2sinputcntl);/* Switch to "I2S ADC mode" */ cx_write (AUD_I2SCNTL ,0x1 );set_audio_finish (core,EN_I2SIN_ENABLE );
drivers/media/video/cx88/cx88-video.c +45 -4
73 lines not on this page · raw message
drivers/media/video/cx88/cx88.h +9 -2
@@ -33,6 +33,7 @@#include <media/cx2341x.h> #include <media/videobuf-dvb.h> #include <media/ir-kbd-i2c.h> +#include <media/wm8775.h> #include "btcx-risc.h" #include "cx88-reg.h"
@@ -273,6 +274,9 @@ struct cx88_board {enum cx88_board_type mpeg;unsigned int audio_chip;int num_frontends; + +/* Used for I2S devices */ +int i2sinputcntl; };struct cx88_subid {
@@ -379,6 +383,7 @@ struct cx88_core {/* I2C remote data */ struct IR_i2c_init_data init_data; +struct wm8775_platform_data wm8775_data;struct mutex lock;/* various v4l controls */
@@ -398,17 +403,19 @@ static inline struct cx88_core *to_core(struct v4l2_device *v4l2_dev) return container_of(v4l2_dev, struct cx88_core, v4l2_dev); } -#define call_all(core, o, f, args...) \ +#define call_hw(core, grpid, o, f, args...) \ do { \ if (!core->i2c_rc) { \ if (core->gate_ctrl) \ core->gate_ctrl(core, 1); \ - v4l2_device_call_all(&core->v4l2_dev, 0, o, f, ##args); \ + v4l2_device_call_all(&core->v4l2_dev, grpid, o, f, ##args); \ if (core->gate_ctrl) \ core->gate_ctrl(core, 0); \ } \ } while (0) +#define call_all(core, o, f, args...) call_hw(core, 0, o, f, ##args) +struct cx8800_dev ;struct cx8802_dev ;
drivers/media/video/wm8775.c +89 -38
202 lines not on this page · raw message
drivers/staging/vme/bridges/Module.symvers deleted +0 -0
include/media/wm8775.h +16 -0
@@ -32,4 +32,20 @@#define WM8775_AIN3 4#define WM8775_AIN4 8 +/* +* subdev group ID +* FIXME: This is not a good place for I2C group ID's. +* We should move it to another place, to be sure that no +* conflicts between different device types will ever happen +*/ +#define WM8775_GID (1 << 0) + +struct wm8775_platform_data { +/* +* FIXME: Instead, we should parametrize the params +* that need different settings between ivtv and Nova-S +*/ +bool is_nova_s; +}; +#endif
Quoted 48 lines · Mauro Carvalho Chehab
Hi Lawrence,
Em 08-01-2011 16:45, Lawrence Rust escreveu:
Quoted 13 lines
Thanks for the info on the PVR-150. It largely confirmed what I had surmised - that the two cards disagree about serial audio data format. Before my patch, the wm8775 was programmed for Philips mode but the CX25843 on the PVR-150 is setup for Sony I2S mode!! On the Nova-S, the cx23883 is setup (in
cx88-tvaudio.c) for Philips mode. The patch changed the wm8775 to Sony I2S mode because the existing setup gave noise, indicative of a mismatch.It is my belief that either the wm8775 datasheet is wrong or there are inverters on the SCLK lines between the wm8775 and cx25843/23883. It is also plausible that Conexant have it wrong and both their datasheets are wrong.
Quoted 7 lines
Anyway, I have revised the patch (attached) so that the wm8775 is kept in Philips mode (to please the PVR-150) and the cx23883 on the Nove-S is now switched to Sony I2S mode (like the PVR-150) and this works fine. The change is trivial, just 2 lines, so they're shouldn't be any other consequences. However, could this affect any other cards?
NB I have only tested this patch on my Nova-S, no other.
As it was pointed, your patch affects other boards with wm8775. In order to avoid it, you need to use
platform_datato passnova_sspecific parameters, and be sure that other boards won't be affected by your changes.As you might not be able to see how this should be written, I modified your patch in a way that, hopefully, it won't affect PVR-150. Please test.
Please notice that I don't have any board with wm8775 handy, so it is compiled-only.
If this patch doesn't break PVR-150 or Nova-S, then I think we can merge it.
There are however two issues:
1) I don't think it is a good idea to keep the I2C group for wm8775 inside
the wm8775 header. Instead, we should move it to some place were people can look on it to avoid duplicated groups. We may instead just get rid of it, as I added tests for wm8775 on all places. So, only if wm8775 is used, the i2c subdev commands will be called.
2) I just added oneplatform_datainfo that indicates if the device is anova_sor not. I did it just because I was lazy enough to not go through wm8775 datasheet and add parameters for the parameters that are different. The better is to split it into some more parameters.
Quoted 5 lines
If it works for you, please add your Signed-off-by:.
Andy,
please test if this don't break ivtv. If it breaks, please help us to fix, as only you noticed an issue on the previous versions.
I'll plan this for Sunday 6 Feb. (I have a wedding to attend on Saturday).
Regards,
Andy
Quoted 657 lines
-
From: Lawrence Rust <[email protected]>
This patch adds audio DMA capture and ALSA mixer elements for the line input jack of the Hauppauge Nova-S-plus DVB-S PCI card. The Nova-S-plus has a WM8775 ADC that is currently not detected. This patch enables this chip and exports volume, balance mute and ALC elements for ALSA mixer controls.
[[email protected]: Changed the patch to only talk with wm8775 if board info says so. Also, added
platform_datasupport, to avoid changing the behaviour for other boards, and fixed CodingStyle]Signed-off-by Mauro Carvalho Chehab <[email protected]>drivers/media/video/cx88/cx88-alsa.c +103
-15@@ -40,6 +40,7 @@#include <sound/control.h> #include <sound/initval.h> #include <sound/tlv.h> +#include <media/wm8775.h> #include "cx88.h" #include "cx88-reg.h" @@ -577,6 +578,35 @@ static int snd_cx88_volume_get(struct snd_kcontrol *kcontrol,return 0 ; } +static void snd_cx88_wm8775_volume_put (struct snd_kcontrol *kcontrol, +struct snd_ctl_elem_value *value) +{ +snd_cx88_card_t *chip =snd_kcontrol_chip (kcontrol); +struct cx88_core *core = chip->core; +struct v4l2_control client_ctl; +int left = value->value.integer.value[0 ]; +int right = value->value.integer.value[1 ]; +int v, b; + +memset (&client_ctl,0 ,sizeof (client_ctl)); + +/* Pass volume & balance onto any WM8775 */ +if (left >= right) { + v = left <<10 ; + b = left ? (0x8000 * right) / left :0x8000 ; + }else { + v = right <<10 ; + b = right ?0xffff - (0x8000 * left) / right :0x8000 ; + } + client_ctl.value = v; + client_ctl.id =V4L2_CID_AUDIO_VOLUME ; +call_hw (core,WM8775_GID , core, s_ctrl, &client_ctl); + + client_ctl.value = b; + client_ctl.id =V4L2_CID_AUDIO_BALANCE ; +call_hw (core,WM8775_GID , core, s_ctrl, &client_ctl); +} +/* OK - TODO: test it */ static int snd_cx88_volume_put (struct snd_kcontrol *kcontrol,struct snd_ctl_elem_value *value)@@ -587,25 +617,28 @@ static int snd_cx88_volume_put(struct snd_kcontrol *kcontrol,int changed =0 ;u32 old; +if (core->board.audio_chip ==V4L2_IDENT_WM8775 ) +snd_cx88_wm8775_volume_put (kcontrol, value); + left = value->value.integer.value[0 ] &0x3f ; right = value->value.integer.value[1 ] &0x3f ; b = right - left;if (b <0 ) { - v =0x3f - left; - b = (-b) |0x40 ; + v =0x3f - left; + b = (-b) |0x40 ; }else { - v =0x3f - right; + v =0x3f - right; }/* Do we really know this will always be called with IRQs on? */ spin_lock_irq (&chip->reg_lock); old =cx_read (AUD_VOL_CTL );if (v != (old &0x3f )) { -cx_write (AUD_VOL_CTL , (old & ~0x3f ) | v); - changed =1 ; +cx_swrite (SHADOW_AUD_VOL_CTL ,AUD_VOL_CTL , (old & ~0x3f ) | v); + changed =1 ; } -if (cx_read (AUD_BAL_CTL ) != b) { -cx_write (AUD_BAL_CTL , b); - changed =1 ; +if ((cx_read (AUD_BAL_CTL ) &0x7f ) != b) { +cx_write (AUD_BAL_CTL , b); + changed =1 ; }spin_unlock_irq (&chip->reg_lock);@@ -618,7 +651,7 @@ static const struct snd_kcontrol_new snd_cx88_volume = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .access =SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, - .name = "Playback Volume", + .name = "Analog-TV Volume", .info = snd_cx88_volume_info, .get = snd_cx88_volume_get, .put = snd_cx88_volume_put,@@ -649,7 +682,17 @@ static int snd_cx88_switch_put(struct snd_kcontrol *kcontrol, vol =cx_read (AUD_VOL_CTL );if (value->value.integer.value[0 ] != !(vol & bit)) { vol ^= bit; -cx_write (AUD_VOL_CTL , vol); +cx_swrite (SHADOW_AUD_VOL_CTL ,AUD_VOL_CTL , vol); +/* Pass mute onto any WM8775 */ +if ((core->board.audio_chip ==V4L2_IDENT_WM8775 ) && + ((1 <<6 ) == bit)) { +struct v4l2_control client_ctl; + +memset (&client_ctl,0 ,sizeof (client_ctl)); + client_ctl.value =0 != (vol & bit); + client_ctl.id =V4L2_CID_AUDIO_MUTE ; +call_hw (core,WM8775_GID , core, s_ctrl, &client_ctl); + } ret =1 ; }spin_unlock_irq (&chip->reg_lock);@@ -658,7 +701,7 @@ static int snd_cx88_switch_put(struct snd_kcontrol *kcontrol,static const struct snd_kcontrol_new snd_cx88_dac_switch = { .iface =SNDRV_CTL_ELEM_IFACE_MIXER , - .name ="Playback Switch" , + .name ="Audio-Out Switch" , .info = snd_ctl_boolean_mono_info, .get = snd_cx88_switch_get, .put = snd_cx88_switch_put,@@ -667,13 +710,51 @@ static const struct snd_kcontrol_new snd_cx88_dac_switch = {static const struct snd_kcontrol_new snd_cx88_source_switch = { .iface =SNDRV_CTL_ELEM_IFACE_MIXER , - .name ="Capture Switch" , + .name ="Analog-TV Switch" , .info = snd_ctl_boolean_mono_info, .get = snd_cx88_switch_get, .put = snd_cx88_switch_put, .private_value = (1 <<6 ), }; +static int snd_cx88_alc_get (struct snd_kcontrol *kcontrol, +struct snd_ctl_elem_value *value) +{ +snd_cx88_card_t *chip =snd_kcontrol_chip (kcontrol); +struct cx88_core *core = chip->core; +struct v4l2_control client_ctl; + +memset (&client_ctl,0 ,sizeof (client_ctl)); + client_ctl.id =V4L2_CID_AUDIO_LOUDNESS ; +call_hw (core,WM8775_GID , core, g_ctrl, &client_ctl); + value->value.integer.value[0 ] = client_ctl.value ?1 :0 ; + +return 0 ; +} + +static int snd_cx88_alc_put (struct snd_kcontrol *kcontrol, +struct snd_ctl_elem_value *value) +{ +snd_cx88_card_t *chip =snd_kcontrol_chip (kcontrol); +struct cx88_core *core = chip->core; +struct v4l2_control client_ctl; + +memset (&client_ctl,0 ,sizeof (client_ctl)); + client_ctl.value =0 != value->value.integer.value[0 ]; + client_ctl.id =V4L2_CID_AUDIO_LOUDNESS ; +call_hw (core,WM8775_GID , core, s_ctrl, &client_ctl); + +return 0 ; +} + +static struct snd_kcontrol_new snd_cx88_alc_switch = { + .iface =SNDRV_CTL_ELEM_IFACE_MIXER , + .name ="Line-In ALC Switch" , + .info = snd_ctl_boolean_mono_info, + .get = snd_cx88_alc_get, + .put = snd_cx88_alc_put, +}; +/**************************************************************************** Basic Flow for Sound Devices ****************************************************************************/ @@ -724,7 +805,8 @@ static void snd_cx88_dev_free(struct snd_card * card)static int devno;static int __devinit snd_cx88_create (struct snd_card *card,struct pci_dev *pci, -snd_cx88_card_t **rchip) +snd_cx88_card_t **rchip, +struct cx88_core **core_ptr) {snd_cx88_card_t *chip;struct cx88_core *core;@@ -750,7 +832,7 @@ static int __devinit snd_cx88_create(struct snd_card *card,if (!pci_dma_supported (pci,DMA_BIT_MASK (32 ))) {dprintk (0 ,"%s/1: Oops: no 32bit PCI DMA ???\n" ,core->name); err = -EIO ; -cx88_core_put (core,pci); +cx88_core_put (core, pci);return err; }@@ -786,6 +868,7 @@ static int __devinit snd_cx88_create(struct snd_card *card,snd_card_set_dev (card, &pci->dev); *rchip = chip; + *core_ptr = core;return 0 ; }@@ -795,6 +878,7 @@ static int __devinit cx88_audio_initdev(struct pci_dev *pci, {struct snd_card *card;snd_cx88_card_t *chip; +struct cx88_core *core;int err;if (devno >=SNDRV_CARDS )@@ -812,7 +896,7 @@ static int __devinit cx88_audio_initdev(struct pci_dev *pci, card->private_free = snd_cx88_dev_free; - err =snd_cx88_create (card, pci, &chip); + err =snd_cx88_create (card, pci, &chip, &core);if (err <0 ) goto error;@@ -830,6 +914,10 @@ static int __devinit cx88_audio_initdev(struct pci_dev *pci,if (err <0 ) goto error; +/* If there's a wm8775 then add a Line-In ALC switch */ +if (core->board.audio_chip ==V4L2_IDENT_WM8775 ) +snd_ctl_add (card,snd_ctl_new1 (&snd_cx88_alc_switch, chip)); +strcpy (card->driver,"CX88x" );sprintf (card->shortname,"Conexant CX%x" , pci->device); sprintf(card->longname, "%s at %#llx",drivers/media/video/cx88/cx88-cards.c +2
-1@@ -970,7 +970,8 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .audio_chip = V4L2_IDENT_WM8775, + .audio_chip = V4L2_IDENT_WM8775, + .i2sinputcntl = 2, .input = {{ .type = CX88_VMUX_DVB, .vmux = 0,drivers/media/video/cx88/cx88-tvaudio.c +6
-2@@ -786,8 +786,12 @@ void cx88_set_tvaudio(struct cx88_core *core)break ;case WW_I2SADC :set_audio_start (core,0x01 ); -/* Slave/Philips/Autobaud */ -cx_write (AUD_I2SINPUTCNTL ,0 ); +/* +* Slave/Philips/Autobaud +* NB on Nova-S bit1 NPhilipsSony appears to be inverted: +* 0= Sony, 1=Philips +*/ +cx_write (AUD_I2SINPUTCNTL , core->board.i2sinputcntl);/* Switch to "I2S ADC mode" */ cx_write (AUD_I2SCNTL ,0x1 );set_audio_finish (core,EN_I2SIN_ENABLE );drivers/media/video/cx88/cx88-video.c +45
-4@@ -40,6 +40,7 @@#include "cx88.h" #include <media/v4l2-common.h> #include <media/v4l2-ioctl.h> +#include <media/wm8775.h> MODULE_DESCRIPTION ("v4l2 driver module for cx2388x based TV cards" );MODULE_AUTHOR ("Gerd Knorr <[email protected]> [SuSE Labs]" );@@ -989,6 +990,32 @@ int cx88_set_control(struct cx88_core *core, struct v4l2_control *ctl) ctl->value = c->v.minimum;if (ctl->value > c->v.maximum) ctl->value = c->v.maximum; + +/* Pass changes onto any WM8775 */ +if (core->board.audio_chip ==V4L2_IDENT_WM8775 ) { +struct v4l2_control client_ctl; +memset (&client_ctl,0 ,sizeof (client_ctl)); + client_ctl.id = ctl->id; + +switch (ctl->id) { +case V4L2_CID_AUDIO_MUTE : + client_ctl.value = ctl->value; +break ; +case V4L2_CID_AUDIO_VOLUME : + client_ctl.value = (ctl->value) ? + (0x90 + ctl->value) <<8 :0 ; +break ; +case V4L2_CID_AUDIO_BALANCE : + client_ctl.value = ctl->value <<9 ; +break ; +default : + client_ctl.id =0 ; +break ; + } +if (client_ctl.id) +call_hw (core,WM8775_GID , core, s_ctrl, &client_ctl); + } + mask=c->mask;switch (ctl->id) {case V4L2_CID_AUDIO_BALANCE :@@ -1526,7 +1553,9 @@ static int radio_queryctrl (struct file *file, void *priv,if (c->id <V4L2_CID_BASE || c->id >=V4L2_CID_LASTP1 )return -EINVAL ; -if (c->id ==V4L2_CID_AUDIO_MUTE ) { +if (c->id ==V4L2_CID_AUDIO_MUTE || + c->id ==V4L2_CID_AUDIO_VOLUME || + c->id ==V4L2_CID_AUDIO_BALANCE ) {for (i =0 ; i <CX8800_CTLS ; i++) {if (cx8800_ctls[i].v.id == c->id)break ;@@ -1856,9 +1885,21 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,/* load and configure helper modules */ -if (core->board.audio_chip ==V4L2_IDENT_WM8775 ) -v4l2_i2c_new_subdev (&core->v4l2_dev, &core->i2c_adap, -"wm8775" ,0x36 >>1 ,NULL ); +if (core->board.audio_chip ==V4L2_IDENT_WM8775 ) { +struct i2c_board_info wm8775_info = { + .type ="wm8775" , + .addr =0x36 >>1 , + .platform_data = &core->wm8775_data, + }; + +if (core->boardnr ==CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1 ) + core->wm8775_data.is_nova_s = true; +else + core->wm8775_data.is_nova_s = false; + +v4l2_i2c_new_subdev_board (&core->v4l2_dev, &core->i2c_adap, + &wm8775_info,NULL ); + }if (core->board.audio_chip ==V4L2_IDENT_TVAUDIO ) {/* This probes for a tda9874 as is used on some drivers/media/video/cx88/cx88.h +9
-2@@ -33,6 +33,7 @@#include <media/cx2341x.h> #include <media/videobuf-dvb.h> #include <media/ir-kbd-i2c.h> +#include <media/wm8775.h> #include "btcx-risc.h" #include "cx88-reg.h" @@ -273,6 +274,9 @@ struct cx88_board {enum cx88_board_type mpeg;unsigned int audio_chip;int num_frontends; + +/* Used for I2S devices */ +int i2sinputcntl; };struct cx88_subid {@@ -379,6 +383,7 @@ struct cx88_core {/* I2C remote data */ struct IR_i2c_init_data init_data; +struct wm8775_platform_data wm8775_data;struct mutex lock;/* various v4l controls */ @@ -398,17 +403,19 @@ static inline struct cx88_core *to_core(struct v4l2_device *v4l2_dev) return container_of(v4l2_dev, struct cx88_core, v4l2_dev); } -#define call_all(core, o, f, args...) \ +#define call_hw(core, grpid, o, f, args...) \ do { \ if (!core->i2c_rc) { \ if (core->gate_ctrl) \ core->gate_ctrl(core, 1); \ - v4l2_device_call_all(&core->v4l2_dev, 0, o, f, ##args); \ + v4l2_device_call_all(&core->v4l2_dev, grpid, o, f, ##args); \ if (core->gate_ctrl) \ core->gate_ctrl(core, 0); \ } \ } while (0) +#define call_all(core, o, f, args...) call_hw(core, 0, o, f, ##args) +struct cx8800_dev ;struct cx8802_dev ;drivers/media/video/wm8775.c +89
-38@@ -35,6 +35,7 @@#include <media/v4l2-device.h> #include <media/v4l2-chip-ident.h> #include <media/v4l2-ctrls.h> +#include <media/wm8775.h> MODULE_DESCRIPTION ("wm8775 driver" );MODULE_AUTHOR ("Ulf Eklund, Hans Verkuil" );@@ -50,10 +51,16 @@ enum { TOT_REGS }; +#define ALC_HOLD 0x85/* R17: use zero cross detection, ALC hold time 42.6 ms */ +#define ALC_EN 0x100/* R17: ALC enable */ +struct wm8775_state {struct v4l2_subdev sd;struct v4l2_ctrl_handler hdl;struct v4l2_ctrl *mute; +struct v4l2_ctrl *vol; +struct v4l2_ctrl *bal; +struct v4l2_ctrl *loud;u8 input;/* Last selected input (0-0xf) */ };@@ -85,6 +92,30 @@ static int wm8775_write(struct v4l2_subdev *sd, int reg, u16 val)return -1 ; } +static void wm8775_set_audio (struct v4l2_subdev *sd,int quietly) +{ +struct wm8775_state *state =to_state (sd); +u8 vol_l, vol_r; +int muted =0 != state->mute->val; +u16 volume = (u16 )state->vol->val; +u16 balance = (u16 )state->bal->val; + +/* normalize ( 65535 to 0 -> 255 to 0 (+24dB to -103dB) ) */ + vol_l = (min (65536 - balance,32768 ) * volume) >>23 ; + vol_r = (min (balance, (u16 )32768 ) * volume) >>23 ; + +/* Mute */ +if (muted || quietly) +wm8775_write (sd,R21 ,0x0c0 | state->input); + +wm8775_write (sd,R14 , vol_l |0x100 );/* 0x100= Left channel ADC zero cross enable */ +wm8775_write (sd,R15 , vol_r |0x100 );/* 0x100= Right channel ADC zero cross enable */ + +/* Un-mute */ +if (!muted) +wm8775_write (sd,R21 , state->input); +} +static int wm8775_s_routing (struct v4l2_subdev *sd,u32 input,u32 output,u32 config) {@@ -102,25 +133,26 @@ static int wm8775_s_routing(struct v4l2_subdev *sd, state->input = input;if (!v4l2_ctrl_g_ctrl (state->mute))return 0 ; -wm8775_write (sd,R21 ,0x0c0 ); -wm8775_write (sd,R14 ,0x1d4 ); -wm8775_write (sd,R15 ,0x1d4 ); -wm8775_write (sd,R21 ,0x100 + state->input); +if (!v4l2_ctrl_g_ctrl (state->vol)) +return 0 ; +if (!v4l2_ctrl_g_ctrl (state->bal)) +return 0 ; +wm8775_set_audio (sd,1 );return 0 ; }static int wm8775_s_ctrl (struct v4l2_ctrl *ctrl) {struct v4l2_subdev *sd =to_sd (ctrl); -struct wm8775_state *state =to_state (sd);switch (ctrl->id) {case V4L2_CID_AUDIO_MUTE : -wm8775_write (sd,R21 ,0x0c0 ); -wm8775_write (sd,R14 ,0x1d4 ); -wm8775_write (sd,R15 ,0x1d4 ); -if (!ctrl->val) -wm8775_write (sd,R21 ,0x100 + state->input); +case V4L2_CID_AUDIO_VOLUME : +case V4L2_CID_AUDIO_BALANCE : +wm8775_set_audio (sd,0 ); +return 0 ; +case V4L2_CID_AUDIO_LOUDNESS : +wm8775_write (sd,R17 , (ctrl->val ?ALC_EN :0 ) |ALC_HOLD );return 0 ; }return -EINVAL ;@@ -144,16 +176,7 @@ static int wm8775_log_status(struct v4l2_subdev *sd)static int wm8775_s_frequency (struct v4l2_subdev *sd,struct v4l2_frequency *freq) { -struct wm8775_state *state =to_state (sd); - -/* If I remove this, then it can happen that I have no -sound the first time I tune from static to a valid channel. -It's difficult to reproduce and is almost certainly related -to the zero cross detect circuit. */ -wm8775_write (sd,R21 ,0x0c0 ); -wm8775_write (sd,R14 ,0x1d4 ); -wm8775_write (sd,R15 ,0x1d4 ); -wm8775_write (sd,R21 ,0x100 + state->input); +wm8775_set_audio (sd,0 );return 0 ; }@@ -203,6 +226,13 @@ static int wm8775_probe(struct i2c_client *client, {struct wm8775_state *state;struct v4l2_subdev *sd; +int err; +bool is_nova_s = false; + +if (client->dev.platform_data) { +struct wm8775_platform_data *data = client->dev.platform_data; + is_nova_s = data->is_nova_s; + }/* Check if the adapter supports the needed features */ if (!i2c_check_functionality (client->adapter,I2C_FUNC_SMBUS_BYTE_DATA ))@@ -216,15 +246,21 @@ static int wm8775_probe(struct i2c_client *client,return -ENOMEM ; sd = &state->sd;v4l2_i2c_subdev_init (sd, client, &wm8775_ops); + sd->grp_id =WM8775_GID ;/* subdev group id */ state->input =2 ; -v4l2_ctrl_handler_init (&state->hdl,1 ); +v4l2_ctrl_handler_init (&state->hdl,4 ); state->mute =v4l2_ctrl_new_std (&state->hdl, &wm8775_ctrl_ops,V4L2_CID_AUDIO_MUTE ,0 ,1 ,1 ,0 ); + state->vol =v4l2_ctrl_new_std (&state->hdl, &wm8775_ctrl_ops, +V4L2_CID_AUDIO_VOLUME ,0 ,65535 , (65535 +99 )/100 ,0xCF00 );/* 0dB*/ + state->bal =v4l2_ctrl_new_std (&state->hdl, &wm8775_ctrl_ops, +V4L2_CID_AUDIO_BALANCE ,0 ,65535 , (65535 +99 )/100 ,32768 ); + state->loud =v4l2_ctrl_new_std (&state->hdl, &wm8775_ctrl_ops, +V4L2_CID_AUDIO_LOUDNESS ,0 ,1 ,1 ,1 ); sd->ctrl_handler = &state->hdl; -if (state->hdl.error) { -int err = state->hdl.error; - + err = state->hdl.error; +if (err) {v4l2_ctrl_handler_free (&state->hdl);kfree (state);return err;@@ -236,29 +272,44 @@ static int wm8775_probe(struct i2c_client *client,wm8775_write (sd,R23 ,0x000 );/* Disable zero cross detect timeout */ wm8775_write (sd,R7 ,0x000 ); -/* Left justified, 24-bit mode */ +/* HPF enable, left justified, 24-bit (Philips) mode */ wm8775_write (sd,R11 ,0x021 );/* Master mode, clock ratio 256fs */ wm8775_write (sd,R12 ,0x102 );/* Powered up */ wm8775_write (sd,R13 ,0x000 ); -/* ADC gain +2.5dB, enable zero cross */ -wm8775_write (sd,R14 ,0x1d4 ); -/* ADC gain +2.5dB, enable zero cross */ -wm8775_write (sd,R15 ,0x1d4 ); -/* ALC Stereo, ALC target level -1dB FS max gain +8dB */ -wm8775_write (sd,R16 ,0x1bf ); -/* Enable gain control, use zero cross detection, -ALC hold time 42.6 ms */ -wm8775_write (sd,R17 ,0x185 ); + +if (!is_nova_s) { +/* ADC gain +2.5dB, enable zero cross */ +wm8775_write (sd,R14 ,0x1d4 ); +/* ADC gain +2.5dB, enable zero cross */ +wm8775_write (sd,R15 ,0x1d4 ); +/* ALC Stereo, ALC target level -1dB FS max gain +8dB */ +wm8775_write (sd,R16 ,0x1bf ); +/* Enable gain control, use zero cross detection, +ALC hold time 42.6 ms */ +wm8775_write (sd,R17 ,0x185 ); + }else { +/* ALC stereo, ALC target level -5dB FS, ALC max gain +8dB */ +wm8775_write (sd,R16 ,0x1bb ); +/* Set ALC mode and hold time */ +wm8775_write (sd,R17 , (state->loud->val ?ALC_EN :0 ) |ALC_HOLD ); + }/* ALC gain ramp up delay 34 s, ALC gain ramp down delay 33 ms */ wm8775_write (sd,R18 ,0x0a2 );/* Enable noise gate, threshold -72dBfs */ wm8775_write (sd,R19 ,0x005 ); -/* Transient window 4ms, lower PGA gain limit -1dB */ -wm8775_write (sd,R20 ,0x07a ); -/* LRBOTH = 1, use input 2. */ -wm8775_write (sd,R21 ,0x102 ); +if (!is_nova_s) { +/* Transient window 4ms, lower PGA gain limit -1dB */ +wm8775_write (sd,R20 ,0x07a ); +/* LRBOTH = 1, use input 2. */ +wm8775_write (sd,R21 ,0x102 ); + }else { +/* Transient window 4ms, ALC min gain -5dB */ +wm8775_write (sd,R20 ,0x0fb ); + +wm8775_set_audio (sd,1 );/* set volume/mute/mux */ + }return 0 ; }drivers/staging/vme/bridges/Module.symvers deleted +0
-0include/media/wm8775.h +16
-1@@ -32,4 +32,20 @@#define WM8775_AIN3 4#define WM8775_AIN4 8 +/* +* subdev group ID +* FIXME: This is not a good place for I2C group ID's. +* We should move it to another place, to be sure that no +* conflicts between different device types will ever happen +*/ +#define WM8775_GID (1 << 0) + +struct wm8775_platform_data { +/* +* FIXME: Instead, we should parametrize the params +* that need different settings between ivtv and Nova-S +*/ +bool is_nova_s; +}; +#endif --To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoted 22 lines · Mauro Carvalho Chehab
Hi Lawrence,
Em 08-01-2011 16:45, Lawrence Rust escreveu:
Quoted 19 lines
Thanks for the info on the PVR-150. It largely confirmed what I had surmised - that the two cards disagree about serial audio data format. Before my patch, the wm8775 was programmed for Philips mode but the CX25843 on the PVR-150 is setup for Sony I2S mode!! On the Nova-S, the cx23883 is setup (in
cx88-tvaudio.c) for Philips mode. The patch changed the wm8775 to Sony I2S mode because the existing setup gave noise, indicative of a mismatch.It is my belief that either the wm8775 datasheet is wrong or there are inverters on the SCLK lines between the wm8775 and cx25843/23883. It is also plausible that Conexant have it wrong and both their datasheets are wrong.
Anyway, I have revised the patch (attached) so that the wm8775 is kept in Philips mode (to please the PVR-150) and the cx23883 on the Nove-S is now switched to Sony I2S mode (like the PVR-150) and this works fine. The change is trivial, just 2 lines, so they're shouldn't be any other consequences. However, could this affect any other cards?
Quoted 8 lines
Quoted 1 line
NB I have only tested this patch on my Nova-S, no other.
As it was pointed, your patch affects other boards with wm8775. In order to avoid it, you need to use
platform_datato passnova_sspecific parameters, and be sure that other boards won't be affected by your changes.As you might not be able to see how this should be written, I modified your patch in a way that, hopefully, it won't affect PVR-150. Please test.
Many thanks for doing this. I appreciate the guidance and effort. I'll test it and report back this weekend.
-- Lawrence
Quoted 22 lines · Mauro Carvalho Chehab
Hi Lawrence,
Em 08-01-2011 16:45, Lawrence Rust escreveu:
Quoted 19 lines
Thanks for the info on the PVR-150. It largely confirmed what I had surmised - that the two cards disagree about serial audio data format. Before my patch, the wm8775 was programmed for Philips mode but the CX25843 on the PVR-150 is setup for Sony I2S mode!! On the Nova-S, the cx23883 is setup (in
cx88-tvaudio.c) for Philips mode. The patch changed the wm8775 to Sony I2S mode because the existing setup gave noise, indicative of a mismatch.It is my belief that either the wm8775 datasheet is wrong or there are inverters on the SCLK lines between the wm8775 and cx25843/23883. It is also plausible that Conexant have it wrong and both their datasheets are wrong.
Anyway, I have revised the patch (attached) so that the wm8775 is kept in Philips mode (to please the PVR-150) and the cx23883 on the Nove-S is now switched to Sony I2S mode (like the PVR-150) and this works fine. The change is trivial, just 2 lines, so they're shouldn't be any other consequences. However, could this affect any other cards?
Quoted 5 lines
Quoted 1 line
NB I have only tested this patch on my Nova-S, no other.
As it was pointed, your patch affects other boards with wm8775. In order to avoid it, you need to use
platform_datato passnova_sspecific parameters, and be sure that other boards won't be affected by your changes.
It's a pity that the setup changes to the wm8775 won't now be seen by any other card because IMHO they improve the audio quality both subjectively and visibly on a 'scope. But I can see why you're anxious to avoid breaking other combinations and your solution is elegant. The existing ALC settings allow too many fast transients to be clipped and the option to switch to manual level control gives ultimate fidelity.
Quoted 2 lines
As you might not be able to see how this should be written, I modified your patch in a way that, hopefully, it won't affect PVR-150. Please test.
Patch applied cleanly to 2.6.37 and tested with Nova-S OK.
Quoted 6 lines
Please notice that I don't have any board with wm8775 handy, so it is compiled-only.
If this patch doesn't break PVR-150 or Nova-S, then I think we can merge it.
Quoted 6 lines
There are however two issues:
1) I don't think it is a good idea to keep the I2C group for wm8775 inside
the wm8775 header. Instead, we should move it to some place were people can look on it to avoid duplicated groups. We may instead just get rid of it, as I added tests for wm8775 on all places. So, only if wm8775 is used, the i2c subdev commands will be called.
It may be prudent to keep the group ID for a while. If we gain confidence that the current changes are non-intrusive to other cards then the improved audio setup and ability to use manual level control may be appealing.
Quoted 4 lines
2) I just added one
platform_datainfo that indicates if the device is anova_sor not. I did it just because I was lazy enough to not go through wm8775 datasheet and add parameters for the parameters that are different. The better is to split it into some more parameters.
In terms of parametrising the changes, I thought the addition of the board.i2sinputcntl field elegantly avoided breaking cx23883 based cards with different I2S peripherals.
Quoted 1 line
If it works for you, please add your Signed-off-by:.
Many thanks for your suggestions and modifications.
Quoted 647 lines
Andy,
please test if this don't break ivtv. If it breaks, please help us to fix, as only you noticed an issue on the previous versions.-
From: Lawrence Rust <[email protected]>
This patch adds audio DMA capture and ALSA mixer elements for the line input jack of the Hauppauge Nova-S-plus DVB-S PCI card. The Nova-S-plus has a WM8775 ADC that is currently not detected. This patch enables this chip and exports volume, balance mute and ALC elements for ALSA mixer controls.
[[email protected]: Changed the patch to only talk with wm8775 if board info says so. Also, added
platform_datasupport, to avoid changing the behaviour for other boards, and fixed CodingStyle]Signed-off-by Mauro Carvalho Chehab <[email protected]>drivers/media/video/cx88/cx88-alsa.c +103
-15@@ -40,6 +40,7 @@#include <sound/control.h> #include <sound/initval.h> #include <sound/tlv.h> +#include <media/wm8775.h> #include "cx88.h" #include "cx88-reg.h" @@ -577,6 +578,35 @@ static int snd_cx88_volume_get(struct snd_kcontrol *kcontrol,return 0 ; } +static void snd_cx88_wm8775_volume_put (struct snd_kcontrol *kcontrol, +struct snd_ctl_elem_value *value) +{ +snd_cx88_card_t *chip =snd_kcontrol_chip (kcontrol); +struct cx88_core *core = chip->core; +struct v4l2_control client_ctl; +int left = value->value.integer.value[0 ]; +int right = value->value.integer.value[1 ]; +int v, b; + +memset (&client_ctl,0 ,sizeof (client_ctl)); + +/* Pass volume & balance onto any WM8775 */ +if (left >= right) { + v = left <<10 ; + b = left ? (0x8000 * right) / left :0x8000 ; + }else { + v = right <<10 ; + b = right ?0xffff - (0x8000 * left) / right :0x8000 ; + } + client_ctl.value = v; + client_ctl.id =V4L2_CID_AUDIO_VOLUME ; +call_hw (core,WM8775_GID , core, s_ctrl, &client_ctl); + + client_ctl.value = b; + client_ctl.id =V4L2_CID_AUDIO_BALANCE ; +call_hw (core,WM8775_GID , core, s_ctrl, &client_ctl); +} +/* OK - TODO: test it */ static int snd_cx88_volume_put (struct snd_kcontrol *kcontrol,struct snd_ctl_elem_value *value)@@ -587,25 +617,28 @@ static int snd_cx88_volume_put(struct snd_kcontrol *kcontrol,int changed =0 ;u32 old; +if (core->board.audio_chip ==V4L2_IDENT_WM8775 ) +snd_cx88_wm8775_volume_put (kcontrol, value); + left = value->value.integer.value[0 ] &0x3f ; right = value->value.integer.value[1 ] &0x3f ; b = right - left;if (b <0 ) { - v =0x3f - left; - b = (-b) |0x40 ; + v =0x3f - left; + b = (-b) |0x40 ; }else { - v =0x3f - right; + v =0x3f - right; }/* Do we really know this will always be called with IRQs on? */ spin_lock_irq (&chip->reg_lock); old =cx_read (AUD_VOL_CTL );if (v != (old &0x3f )) { -cx_write (AUD_VOL_CTL , (old & ~0x3f ) | v); - changed =1 ; +cx_swrite (SHADOW_AUD_VOL_CTL ,AUD_VOL_CTL , (old & ~0x3f ) | v); + changed =1 ; } -if (cx_read (AUD_BAL_CTL ) != b) { -cx_write (AUD_BAL_CTL , b); - changed =1 ; +if ((cx_read (AUD_BAL_CTL ) &0x7f ) != b) { +cx_write (AUD_BAL_CTL , b); + changed =1 ; }spin_unlock_irq (&chip->reg_lock);@@ -618,7 +651,7 @@ static const struct snd_kcontrol_new snd_cx88_volume = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .access =SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, - .name = "Playback Volume", + .name = "Analog-TV Volume", .info = snd_cx88_volume_info, .get = snd_cx88_volume_get, .put = snd_cx88_volume_put,@@ -649,7 +682,17 @@ static int snd_cx88_switch_put(struct snd_kcontrol *kcontrol, vol =cx_read (AUD_VOL_CTL );if (value->value.integer.value[0 ] != !(vol & bit)) { vol ^= bit; -cx_write (AUD_VOL_CTL , vol); +cx_swrite (SHADOW_AUD_VOL_CTL ,AUD_VOL_CTL , vol); +/* Pass mute onto any WM8775 */ +if ((core->board.audio_chip ==V4L2_IDENT_WM8775 ) && + ((1 <<6 ) == bit)) { +struct v4l2_control client_ctl; + +memset (&client_ctl,0 ,sizeof (client_ctl)); + client_ctl.value =0 != (vol & bit); + client_ctl.id =V4L2_CID_AUDIO_MUTE ; +call_hw (core,WM8775_GID , core, s_ctrl, &client_ctl); + } ret =1 ; }spin_unlock_irq (&chip->reg_lock);@@ -658,7 +701,7 @@ static int snd_cx88_switch_put(struct snd_kcontrol *kcontrol,static const struct snd_kcontrol_new snd_cx88_dac_switch = { .iface =SNDRV_CTL_ELEM_IFACE_MIXER , - .name ="Playback Switch" , + .name ="Audio-Out Switch" , .info = snd_ctl_boolean_mono_info, .get = snd_cx88_switch_get, .put = snd_cx88_switch_put,@@ -667,13 +710,51 @@ static const struct snd_kcontrol_new snd_cx88_dac_switch = {static const struct snd_kcontrol_new snd_cx88_source_switch = { .iface =SNDRV_CTL_ELEM_IFACE_MIXER , - .name ="Capture Switch" , + .name ="Analog-TV Switch" , .info = snd_ctl_boolean_mono_info, .get = snd_cx88_switch_get, .put = snd_cx88_switch_put, .private_value = (1 <<6 ), }; +static int snd_cx88_alc_get (struct snd_kcontrol *kcontrol, +struct snd_ctl_elem_value *value) +{ +snd_cx88_card_t *chip =snd_kcontrol_chip (kcontrol); +struct cx88_core *core = chip->core; +struct v4l2_control client_ctl; + +memset (&client_ctl,0 ,sizeof (client_ctl)); + client_ctl.id =V4L2_CID_AUDIO_LOUDNESS ; +call_hw (core,WM8775_GID , core, g_ctrl, &client_ctl); + value->value.integer.value[0 ] = client_ctl.value ?1 :0 ; + +return 0 ; +} + +static int snd_cx88_alc_put (struct snd_kcontrol *kcontrol, +struct snd_ctl_elem_value *value) +{ +snd_cx88_card_t *chip =snd_kcontrol_chip (kcontrol); +struct cx88_core *core = chip->core; +struct v4l2_control client_ctl; + +memset (&client_ctl,0 ,sizeof (client_ctl)); + client_ctl.value =0 != value->value.integer.value[0 ]; + client_ctl.id =V4L2_CID_AUDIO_LOUDNESS ; +call_hw (core,WM8775_GID , core, s_ctrl, &client_ctl); + +return 0 ; +} + +static struct snd_kcontrol_new snd_cx88_alc_switch = { + .iface =SNDRV_CTL_ELEM_IFACE_MIXER , + .name ="Line-In ALC Switch" , + .info = snd_ctl_boolean_mono_info, + .get = snd_cx88_alc_get, + .put = snd_cx88_alc_put, +}; +/**************************************************************************** Basic Flow for Sound Devices ****************************************************************************/ @@ -724,7 +805,8 @@ static void snd_cx88_dev_free(struct snd_card * card)static int devno;static int __devinit snd_cx88_create (struct snd_card *card,struct pci_dev *pci, -snd_cx88_card_t **rchip) +snd_cx88_card_t **rchip, +struct cx88_core **core_ptr) {snd_cx88_card_t *chip;struct cx88_core *core;@@ -750,7 +832,7 @@ static int __devinit snd_cx88_create(struct snd_card *card,if (!pci_dma_supported (pci,DMA_BIT_MASK (32 ))) {dprintk (0 ,"%s/1: Oops: no 32bit PCI DMA ???\n" ,core->name); err = -EIO ; -cx88_core_put (core,pci); +cx88_core_put (core, pci);return err; }@@ -786,6 +868,7 @@ static int __devinit snd_cx88_create(struct snd_card *card,snd_card_set_dev (card, &pci->dev); *rchip = chip; + *core_ptr = core;return 0 ; }@@ -795,6 +878,7 @@ static int __devinit cx88_audio_initdev(struct pci_dev *pci, {struct snd_card *card;snd_cx88_card_t *chip; +struct cx88_core *core;int err;if (devno >=SNDRV_CARDS )@@ -812,7 +896,7 @@ static int __devinit cx88_audio_initdev(struct pci_dev *pci, card->private_free = snd_cx88_dev_free; - err =snd_cx88_create (card, pci, &chip); + err =snd_cx88_create (card, pci, &chip, &core);if (err <0 ) goto error;@@ -830,6 +914,10 @@ static int __devinit cx88_audio_initdev(struct pci_dev *pci,if (err <0 ) goto error; +/* If there's a wm8775 then add a Line-In ALC switch */ +if (core->board.audio_chip ==V4L2_IDENT_WM8775 ) +snd_ctl_add (card,snd_ctl_new1 (&snd_cx88_alc_switch, chip)); +strcpy (card->driver,"CX88x" );sprintf (card->shortname,"Conexant CX%x" , pci->device); sprintf(card->longname, "%s at %#llx",drivers/media/video/cx88/cx88-cards.c +2
-1@@ -970,7 +970,8 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .audio_chip = V4L2_IDENT_WM8775, + .audio_chip = V4L2_IDENT_WM8775, + .i2sinputcntl = 2, .input = {{ .type = CX88_VMUX_DVB, .vmux = 0,drivers/media/video/cx88/cx88-tvaudio.c +6
-2@@ -786,8 +786,12 @@ void cx88_set_tvaudio(struct cx88_core *core)break ;case WW_I2SADC :set_audio_start (core,0x01 ); -/* Slave/Philips/Autobaud */ -cx_write (AUD_I2SINPUTCNTL ,0 ); +/* +* Slave/Philips/Autobaud +* NB on Nova-S bit1 NPhilipsSony appears to be inverted: +* 0= Sony, 1=Philips +*/ +cx_write (AUD_I2SINPUTCNTL , core->board.i2sinputcntl);/* Switch to "I2S ADC mode" */ cx_write (AUD_I2SCNTL ,0x1 );set_audio_finish (core,EN_I2SIN_ENABLE );drivers/media/video/cx88/cx88-video.c +45
-4@@ -40,6 +40,7 @@#include "cx88.h" #include <media/v4l2-common.h> #include <media/v4l2-ioctl.h> +#include <media/wm8775.h> MODULE_DESCRIPTION ("v4l2 driver module for cx2388x based TV cards" );MODULE_AUTHOR ("Gerd Knorr <[email protected]> [SuSE Labs]" );@@ -989,6 +990,32 @@ int cx88_set_control(struct cx88_core *core, struct v4l2_control *ctl) ctl->value = c->v.minimum;if (ctl->value > c->v.maximum) ctl->value = c->v.maximum; + +/* Pass changes onto any WM8775 */ +if (core->board.audio_chip ==V4L2_IDENT_WM8775 ) { +struct v4l2_control client_ctl; +memset (&client_ctl,0 ,sizeof (client_ctl)); + client_ctl.id = ctl->id; + +switch (ctl->id) { +case V4L2_CID_AUDIO_MUTE : + client_ctl.value = ctl->value; +break ; +case V4L2_CID_AUDIO_VOLUME : + client_ctl.value = (ctl->value) ? + (0x90 + ctl->value) <<8 :0 ; +break ; +case V4L2_CID_AUDIO_BALANCE : + client_ctl.value = ctl->value <<9 ; +break ; +default : + client_ctl.id =0 ; +break ; + } +if (client_ctl.id) +call_hw (core,WM8775_GID , core, s_ctrl, &client_ctl); + } + mask=c->mask;switch (ctl->id) {case V4L2_CID_AUDIO_BALANCE :@@ -1526,7 +1553,9 @@ static int radio_queryctrl (struct file *file, void *priv,if (c->id <V4L2_CID_BASE || c->id >=V4L2_CID_LASTP1 )return -EINVAL ; -if (c->id ==V4L2_CID_AUDIO_MUTE ) { +if (c->id ==V4L2_CID_AUDIO_MUTE || + c->id ==V4L2_CID_AUDIO_VOLUME || + c->id ==V4L2_CID_AUDIO_BALANCE ) {for (i =0 ; i <CX8800_CTLS ; i++) {if (cx8800_ctls[i].v.id == c->id)break ;@@ -1856,9 +1885,21 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,/* load and configure helper modules */ -if (core->board.audio_chip ==V4L2_IDENT_WM8775 ) -v4l2_i2c_new_subdev (&core->v4l2_dev, &core->i2c_adap, -"wm8775" ,0x36 >>1 ,NULL ); +if (core->board.audio_chip ==V4L2_IDENT_WM8775 ) { +struct i2c_board_info wm8775_info = { + .type ="wm8775" , + .addr =0x36 >>1 , + .platform_data = &core->wm8775_data, + }; + +if (core->boardnr ==CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1 ) + core->wm8775_data.is_nova_s = true; +else + core->wm8775_data.is_nova_s = false; + +v4l2_i2c_new_subdev_board (&core->v4l2_dev, &core->i2c_adap, + &wm8775_info,NULL ); + }if (core->board.audio_chip ==V4L2_IDENT_TVAUDIO ) {/* This probes for a tda9874 as is used on some drivers/media/video/cx88/cx88.h +9
-2@@ -33,6 +33,7 @@#include <media/cx2341x.h> #include <media/videobuf-dvb.h> #include <media/ir-kbd-i2c.h> +#include <media/wm8775.h> #include "btcx-risc.h" #include "cx88-reg.h" @@ -273,6 +274,9 @@ struct cx88_board {enum cx88_board_type mpeg;unsigned int audio_chip;int num_frontends; + +/* Used for I2S devices */ +int i2sinputcntl; };struct cx88_subid {@@ -379,6 +383,7 @@ struct cx88_core {/* I2C remote data */ struct IR_i2c_init_data init_data; +struct wm8775_platform_data wm8775_data;struct mutex lock;/* various v4l controls */ @@ -398,17 +403,19 @@ static inline struct cx88_core *to_core(struct v4l2_device *v4l2_dev) return container_of(v4l2_dev, struct cx88_core, v4l2_dev); } -#define call_all(core, o, f, args...) \ +#define call_hw(core, grpid, o, f, args...) \ do { \ if (!core->i2c_rc) { \ if (core->gate_ctrl) \ core->gate_ctrl(core, 1); \ - v4l2_device_call_all(&core->v4l2_dev, 0, o, f, ##args); \ + v4l2_device_call_all(&core->v4l2_dev, grpid, o, f, ##args); \ if (core->gate_ctrl) \ core->gate_ctrl(core, 0); \ } \ } while (0) +#define call_all(core, o, f, args...) call_hw(core, 0, o, f, ##args) +struct cx8800_dev ;struct cx8802_dev ;drivers/media/video/wm8775.c +89
-38@@ -35,6 +35,7 @@#include <media/v4l2-device.h> #include <media/v4l2-chip-ident.h> #include <media/v4l2-ctrls.h> +#include <media/wm8775.h> MODULE_DESCRIPTION ("wm8775 driver" );MODULE_AUTHOR ("Ulf Eklund, Hans Verkuil" );@@ -50,10 +51,16 @@ enum { TOT_REGS }; +#define ALC_HOLD 0x85/* R17: use zero cross detection, ALC hold time 42.6 ms */ +#define ALC_EN 0x100/* R17: ALC enable */ +struct wm8775_state {struct v4l2_subdev sd;struct v4l2_ctrl_handler hdl;struct v4l2_ctrl *mute; +struct v4l2_ctrl *vol; +struct v4l2_ctrl *bal; +struct v4l2_ctrl *loud;u8 input;/* Last selected input (0-0xf) */ };@@ -85,6 +92,30 @@ static int wm8775_write(struct v4l2_subdev *sd, int reg, u16 val)return -1 ; } +static void wm8775_set_audio (struct v4l2_subdev *sd,int quietly) +{ +struct wm8775_state *state =to_state (sd); +u8 vol_l, vol_r; +int muted =0 != state->mute->val; +u16 volume = (u16 )state->vol->val; +u16 balance = (u16 )state->bal->val; + +/* normalize ( 65535 to 0 -> 255 to 0 (+24dB to -103dB) ) */ + vol_l = (min (65536 - balance,32768 ) * volume) >>23 ; + vol_r = (min (balance, (u16 )32768 ) * volume) >>23 ; + +/* Mute */ +if (muted || quietly) +wm8775_write (sd,R21 ,0x0c0 | state->input); + +wm8775_write (sd,R14 , vol_l |0x100 );/* 0x100= Left channel ADC zero cross enable */ +wm8775_write (sd,R15 , vol_r |0x100 );/* 0x100= Right channel ADC zero cross enable */ + +/* Un-mute */ +if (!muted) +wm8775_write (sd,R21 , state->input); +} +static int wm8775_s_routing (struct v4l2_subdev *sd,u32 input,u32 output,u32 config) {@@ -102,25 +133,26 @@ static int wm8775_s_routing(struct v4l2_subdev *sd, state->input = input;if (!v4l2_ctrl_g_ctrl (state->mute))return 0 ; -wm8775_write (sd,R21 ,0x0c0 ); -wm8775_write (sd,R14 ,0x1d4 ); -wm8775_write (sd,R15 ,0x1d4 ); -wm8775_write (sd,R21 ,0x100 + state->input); +if (!v4l2_ctrl_g_ctrl (state->vol)) +return 0 ; +if (!v4l2_ctrl_g_ctrl (state->bal)) +return 0 ; +wm8775_set_audio (sd,1 );return 0 ; }static int wm8775_s_ctrl (struct v4l2_ctrl *ctrl) {struct v4l2_subdev *sd =to_sd (ctrl); -struct wm8775_state *state =to_state (sd);switch (ctrl->id) {case V4L2_CID_AUDIO_MUTE : -wm8775_write (sd,R21 ,0x0c0 ); -wm8775_write (sd,R14 ,0x1d4 ); -wm8775_write (sd,R15 ,0x1d4 ); -if (!ctrl->val) -wm8775_write (sd,R21 ,0x100 + state->input); +case V4L2_CID_AUDIO_VOLUME : +case V4L2_CID_AUDIO_BALANCE : +wm8775_set_audio (sd,0 ); +return 0 ; +case V4L2_CID_AUDIO_LOUDNESS : +wm8775_write (sd,R17 , (ctrl->val ?ALC_EN :0 ) |ALC_HOLD );return 0 ; }return -EINVAL ;@@ -144,16 +176,7 @@ static int wm8775_log_status(struct v4l2_subdev *sd)static int wm8775_s_frequency (struct v4l2_subdev *sd,struct v4l2_frequency *freq) { -struct wm8775_state *state =to_state (sd); - -/* If I remove this, then it can happen that I have no -sound the first time I tune from static to a valid channel. -It's difficult to reproduce and is almost certainly related -to the zero cross detect circuit. */ -wm8775_write (sd,R21 ,0x0c0 ); -wm8775_write (sd,R14 ,0x1d4 ); -wm8775_write (sd,R15 ,0x1d4 ); -wm8775_write (sd,R21 ,0x100 + state->input); +wm8775_set_audio (sd,0 );return 0 ; }@@ -203,6 +226,13 @@ static int wm8775_probe(struct i2c_client *client, {struct wm8775_state *state;struct v4l2_subdev *sd; +int err; +bool is_nova_s = false; + +if (client->dev.platform_data) { +struct wm8775_platform_data *data = client->dev.platform_data; + is_nova_s = data->is_nova_s; + }/* Check if the adapter supports the needed features */ if (!i2c_check_functionality (client->adapter,I2C_FUNC_SMBUS_BYTE_DATA ))@@ -216,15 +246,21 @@ static int wm8775_probe(struct i2c_client *client,return -ENOMEM ; sd = &state->sd;v4l2_i2c_subdev_init (sd, client, &wm8775_ops); + sd->grp_id =WM8775_GID ;/* subdev group id */ state->input =2 ; -v4l2_ctrl_handler_init (&state->hdl,1 ); +v4l2_ctrl_handler_init (&state->hdl,4 ); state->mute =v4l2_ctrl_new_std (&state->hdl, &wm8775_ctrl_ops,V4L2_CID_AUDIO_MUTE ,0 ,1 ,1 ,0 ); + state->vol =v4l2_ctrl_new_std (&state->hdl, &wm8775_ctrl_ops, +V4L2_CID_AUDIO_VOLUME ,0 ,65535 , (65535 +99 )/100 ,0xCF00 );/* 0dB*/ + state->bal =v4l2_ctrl_new_std (&state->hdl, &wm8775_ctrl_ops, +V4L2_CID_AUDIO_BALANCE ,0 ,65535 , (65535 +99 )/100 ,32768 ); + state->loud =v4l2_ctrl_new_std (&state->hdl, &wm8775_ctrl_ops, +V4L2_CID_AUDIO_LOUDNESS ,0 ,1 ,1 ,1 ); sd->ctrl_handler = &state->hdl; -if (state->hdl.error) { -int err = state->hdl.error; - + err = state->hdl.error; +if (err) {v4l2_ctrl_handler_free (&state->hdl);kfree (state);return err;@@ -236,29 +272,44 @@ static int wm8775_probe(struct i2c_client *client,wm8775_write (sd,R23 ,0x000 );/* Disable zero cross detect timeout */ wm8775_write (sd,R7 ,0x000 ); -/* Left justified, 24-bit mode */ +/* HPF enable, left justified, 24-bit (Philips) mode */ wm8775_write (sd,R11 ,0x021 );/* Master mode, clock ratio 256fs */ wm8775_write (sd,R12 ,0x102 );/* Powered up */ wm8775_write (sd,R13 ,0x000 ); -/* ADC gain +2.5dB, enable zero cross */ -wm8775_write (sd,R14 ,0x1d4 ); -/* ADC gain +2.5dB, enable zero cross */ -wm8775_write (sd,R15 ,0x1d4 ); -/* ALC Stereo, ALC target level -1dB FS max gain +8dB */ -wm8775_write (sd,R16 ,0x1bf ); -/* Enable gain control, use zero cross detection, -ALC hold time 42.6 ms */ -wm8775_write (sd,R17 ,0x185 ); + +if (!is_nova_s) { +/* ADC gain +2.5dB, enable zero cross */ +wm8775_write (sd,R14 ,0x1d4 ); +/* ADC gain +2.5dB, enable zero cross */ +wm8775_write (sd,R15 ,0x1d4 ); +/* ALC Stereo, ALC target level -1dB FS max gain +8dB */ +wm8775_write (sd,R16 ,0x1bf ); +/* Enable gain control, use zero cross detection, +ALC hold time 42.6 ms */ +wm8775_write (sd,R17 ,0x185 ); + }else { +/* ALC stereo, ALC target level -5dB FS, ALC max gain +8dB */ +wm8775_write (sd,R16 ,0x1bb ); +/* Set ALC mode and hold time */ +wm8775_write (sd,R17 , (state->loud->val ?ALC_EN :0 ) |ALC_HOLD ); + }/* ALC gain ramp up delay 34 s, ALC gain ramp down delay 33 ms */ wm8775_write (sd,R18 ,0x0a2 );/* Enable noise gate, threshold -72dBfs */ wm8775_write (sd,R19 ,0x005 ); -/* Transient window 4ms, lower PGA gain limit -1dB */ -wm8775_write (sd,R20 ,0x07a ); -/* LRBOTH = 1, use input 2. */ -wm8775_write (sd,R21 ,0x102 ); +if (!is_nova_s) { +/* Transient window 4ms, lower PGA gain limit -1dB */ +wm8775_write (sd,R20 ,0x07a ); +/* LRBOTH = 1, use input 2. */ +wm8775_write (sd,R21 ,0x102 ); + }else { +/* Transient window 4ms, ALC min gain -5dB */ +wm8775_write (sd,R20 ,0x0fb ); + +wm8775_set_audio (sd,1 );/* set volume/mute/mux */ + }return 0 ; }drivers/staging/vme/bridges/Module.symvers deleted +0
-0include/media/wm8775.h +7
-0@@ -32,4 +32,20 @@#define WM8775_AIN3 4#define WM8775_AIN4 8 +/* +* subdev group ID +* FIXME: This is not a good place for I2C group ID's. +* We should move it to another place, to be sure that no +* conflicts between different device types will ever happen +*/ +#define WM8775_GID (1 << 0)
include/media/wm8775.h line 51
Quoted 10 lines
include/media/wm8775.h +9
-0+ +struct wm8775_platform_data { +/* +* FIXME: Instead, we should parametrize the params +* that need different settings between ivtv and Nova-S +*/ +bool is_nova_s; +}; +#endif
-- Lawrence
Quoted 48 lines · Mauro Carvalho Chehab
Hi Lawrence,
Em 08-01-2011 16:45, Lawrence Rust escreveu:
Quoted 13 lines
Thanks for the info on the PVR-150. It largely confirmed what I had surmised - that the two cards disagree about serial audio data format. Before my patch, the wm8775 was programmed for Philips mode but the CX25843 on the PVR-150 is setup for Sony I2S mode!! On the Nova-S, the cx23883 is setup (in
cx88-tvaudio.c) for Philips mode. The patch changed the wm8775 to Sony I2S mode because the existing setup gave noise, indicative of a mismatch.It is my belief that either the wm8775 datasheet is wrong or there are inverters on the SCLK lines between the wm8775 and cx25843/23883. It is also plausible that Conexant have it wrong and both their datasheets are wrong.
Quoted 7 lines
Anyway, I have revised the patch (attached) so that the wm8775 is kept in Philips mode (to please the PVR-150) and the cx23883 on the Nove-S is now switched to Sony I2S mode (like the PVR-150) and this works fine. The change is trivial, just 2 lines, so they're shouldn't be any other consequences. However, could this affect any other cards?
NB I have only tested this patch on my Nova-S, no other.
As it was pointed, your patch affects other boards with wm8775. In order to avoid it, you need to use
platform_datato passnova_sspecific parameters, and be sure that other boards won't be affected by your changes.As you might not be able to see how this should be written, I modified your patch in a way that, hopefully, it won't affect PVR-150. Please test.
Please notice that I don't have any board with wm8775 handy, so it is compiled-only.
If this patch doesn't break PVR-150 or Nova-S, then I think we can merge it.
There are however two issues:
1) I don't think it is a good idea to keep the I2C group for wm8775 inside
the wm8775 header. Instead, we should move it to some place were people can look on it to avoid duplicated groups. We may instead just get rid of it, as I added tests for wm8775 on all places. So, only if wm8775 is used, the i2c subdev commands will be called.
2) I just added oneplatform_datainfo that indicates if the device is anova_sor not. I did it just because I was lazy enough to not go through wm8775 datasheet and add parameters for the parameters that are different. The better is to split it into some more parameters.
Quoted 5 lines
If it works for you, please add your Signed-off-by:.
Andy,
please test if this don't break ivtv. If it breaks, please help us to fix, as only you noticed an issue on the previous versions.
Mauro and Lawrence,
I have tested the patch with my PVR-150 (ivtv) and it does not break line in audio, and volume control works as well (mute doesn't work, but that might be an existing ivtv issue). I'm fairly sure the patch will also not break the PVR-USB2 (pvrusb2), but I don't have PVR-USB2 hardware to test.
Since the use of the v4l2_subdev grp_id field is bridge driver private, I have made (only) these changes to the patch:
drivers/media/video/cx88/cx88.h
add WM8775_GID definition
drivers/media/video/cx88/cx88-video.c
add setting sd->grp_id
drivers/media/video/wm8775.c
remove setting sd->grp_id
include/media/wm8775.h
remove WM8775_GID defintion and comment
add pvrusb2 to the platform data comment
Regards,
Andy
--
From: Lawrence Rust <[email protected]>
This patch adds audio DMA capture and ALSA mixer elements for the line input jack of the Hauppauge Nova-S-plus DVB-S PCI card. The Nova-S-plus has a WM8775 ADC that is currently not detected. This patch enables this chip and exports volume, balance mute and ALC elements for ALSA mixer controls.
[[email protected]: Changed the patch to only talk with wm8775 if board info says so. Also, added platform_data support, to avoid changing the behaviour for other boards, and fixed CodingStyle]
[[email protected]: Changed patch to make the WM8775_GID defintion bridge driver private and let the bridge driver set the value of v4l2_subdev.grp_id.]
drivers/media/video/cx88/cx88-alsa.c +103 -15
@@ -40,6 +40,7 @@#include <sound/control.h> #include <sound/initval.h> #include <sound/tlv.h> +#include <media/wm8775.h> #include "cx88.h" #include "cx88-reg.h"
@@ -577,6 +578,35 @@ static int snd_cx88_volume_get(struct snd_kcontrol *kcontrol,return 0 ; } +static void snd_cx88_wm8775_volume_put (struct snd_kcontrol *kcontrol, +struct snd_ctl_elem_value *value) +{ +snd_cx88_card_t *chip =snd_kcontrol_chip (kcontrol); +struct cx88_core *core = chip->core; +struct v4l2_control client_ctl; +int left = value->value.integer.value[0 ]; +int right = value->value.integer.value[1 ]; +int v, b; + +memset (&client_ctl,0 ,sizeof (client_ctl)); + +/* Pass volume & balance onto any WM8775 */ +if (left >= right) { + v = left <<10 ; + b = left ? (0x8000 * right) / left :0x8000 ; + }else { + v = right <<10 ; + b = right ?0xffff - (0x8000 * left) / right :0x8000 ; + } + client_ctl.value = v; + client_ctl.id =V4L2_CID_AUDIO_VOLUME ; +call_hw (core,WM8775_GID , core, s_ctrl, &client_ctl); + + client_ctl.value = b; + client_ctl.id =V4L2_CID_AUDIO_BALANCE ; +call_hw (core,WM8775_GID , core, s_ctrl, &client_ctl); +} +/* OK - TODO: test it */ static int snd_cx88_volume_put (struct snd_kcontrol *kcontrol,struct snd_ctl_elem_value *value)
@@ -587,25 +617,28 @@ static int snd_cx88_volume_put(struct snd_kcontrol *kcontrol,int changed =0 ;u32 old; +if (core->board.audio_chip ==V4L2_IDENT_WM8775 ) +snd_cx88_wm8775_volume_put (kcontrol, value); + left = value->value.integer.value[0 ] &0x3f ; right = value->value.integer.value[1 ] &0x3f ; b = right - left;if (b <0 ) { - v =0x3f - left; - b = (-b) |0x40 ; + v =0x3f - left; + b = (-b) |0x40 ; }else { - v =0x3f - right; + v =0x3f - right; }/* Do we really know this will always be called with IRQs on? */ spin_lock_irq (&chip->reg_lock); old =cx_read (AUD_VOL_CTL );if (v != (old &0x3f )) { -cx_write (AUD_VOL_CTL , (old & ~0x3f ) | v); - changed =1 ; +cx_swrite (SHADOW_AUD_VOL_CTL ,AUD_VOL_CTL , (old & ~0x3f ) | v); + changed =1 ; } -if (cx_read (AUD_BAL_CTL ) != b) { -cx_write (AUD_BAL_CTL , b); - changed =1 ; +if ((cx_read (AUD_BAL_CTL ) &0x7f ) != b) { +cx_write (AUD_BAL_CTL , b); + changed =1 ; }spin_unlock_irq (&chip->reg_lock);
@@ -618,7 +651,7 @@ static const struct snd_kcontrol_new snd_cx88_volume = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .access =SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, - .name = "Playback Volume", + .name = "Analog-TV Volume", .info = snd_cx88_volume_info, .get = snd_cx88_volume_get, .put = snd_cx88_volume_put,
@@ -649,7 +682,17 @@ static int snd_cx88_switch_put(struct snd_kcontrol *kcontrol, vol =cx_read (AUD_VOL_CTL );if (value->value.integer.value[0 ] != !(vol & bit)) { vol ^= bit; -cx_write (AUD_VOL_CTL , vol); +cx_swrite (SHADOW_AUD_VOL_CTL ,AUD_VOL_CTL , vol); +/* Pass mute onto any WM8775 */ +if ((core->board.audio_chip ==V4L2_IDENT_WM8775 ) && + ((1 <<6 ) == bit)) { +struct v4l2_control client_ctl; + +memset (&client_ctl,0 ,sizeof (client_ctl)); + client_ctl.value =0 != (vol & bit); + client_ctl.id =V4L2_CID_AUDIO_MUTE ; +call_hw (core,WM8775_GID , core, s_ctrl, &client_ctl); + } ret =1 ; }spin_unlock_irq (&chip->reg_lock);
@@ -658,7 +701,7 @@ static int snd_cx88_switch_put(struct snd_kcontrol *kcontrol,static const struct snd_kcontrol_new snd_cx88_dac_switch = { .iface =SNDRV_CTL_ELEM_IFACE_MIXER , - .name ="Playback Switch" , + .name ="Audio-Out Switch" , .info = snd_ctl_boolean_mono_info, .get = snd_cx88_switch_get, .put = snd_cx88_switch_put,
@@ -667,13 +710,51 @@ static const struct snd_kcontrol_new snd_cx88_dac_switch = {static const struct snd_kcontrol_new snd_cx88_source_switch = { .iface =SNDRV_CTL_ELEM_IFACE_MIXER , - .name ="Capture Switch" , + .name ="Analog-TV Switch" , .info = snd_ctl_boolean_mono_info, .get = snd_cx88_switch_get, .put = snd_cx88_switch_put, .private_value = (1 <<6 ), }; +static int snd_cx88_alc_get (struct snd_kcontrol *kcontrol, +struct snd_ctl_elem_value *value) +{ +snd_cx88_card_t *chip =snd_kcontrol_chip (kcontrol); +struct cx88_core *core = chip->core; +struct v4l2_control client_ctl; + +memset (&client_ctl,0 ,sizeof (client_ctl)); + client_ctl.id =V4L2_CID_AUDIO_LOUDNESS ; +call_hw (core,WM8775_GID , core, g_ctrl, &client_ctl); + value->value.integer.value[0 ] = client_ctl.value ?1 :0 ; + +return 0 ; +} + +static int snd_cx88_alc_put (struct snd_kcontrol *kcontrol, +struct snd_ctl_elem_value *value) +{ +snd_cx88_card_t *chip =snd_kcontrol_chip (kcontrol); +struct cx88_core *core = chip->core; +struct v4l2_control client_ctl; + +memset (&client_ctl,0 ,sizeof (client_ctl)); + client_ctl.value =0 != value->value.integer.value[0 ]; + client_ctl.id =V4L2_CID_AUDIO_LOUDNESS ; +call_hw (core,WM8775_GID , core, s_ctrl, &client_ctl); + +return 0 ; +} + +static struct snd_kcontrol_new snd_cx88_alc_switch = { + .iface =SNDRV_CTL_ELEM_IFACE_MIXER , + .name ="Line-In ALC Switch" , + .info = snd_ctl_boolean_mono_info, + .get = snd_cx88_alc_get, + .put = snd_cx88_alc_put, +}; +/**************************************************************************** Basic Flow for Sound Devices ****************************************************************************/
@@ -724,7 +805,8 @@ static void snd_cx88_dev_free(struct snd_card * card)static int devno;static int __devinit snd_cx88_create (struct snd_card *card,struct pci_dev *pci, -snd_cx88_card_t **rchip) +snd_cx88_card_t **rchip, +struct cx88_core **core_ptr) {snd_cx88_card_t *chip;struct cx88_core *core;
@@ -750,7 +832,7 @@ static int __devinit snd_cx88_create(struct snd_card *card,if (!pci_dma_supported (pci,DMA_BIT_MASK (32 ))) {dprintk (0 ,"%s/1: Oops: no 32bit PCI DMA ???\n" ,core->name); err = -EIO ; -cx88_core_put (core,pci); +cx88_core_put (core, pci);return err; }
@@ -786,6 +868,7 @@ static int __devinit snd_cx88_create(struct snd_card *card,snd_card_set_dev (card, &pci->dev); *rchip = chip; + *core_ptr = core;return 0 ; }
@@ -795,6 +878,7 @@ static int __devinit cx88_audio_initdev(struct pci_dev *pci, {struct snd_card *card;snd_cx88_card_t *chip; +struct cx88_core *core;int err;if (devno >=SNDRV_CARDS )
@@ -812,7 +896,7 @@ static int __devinit cx88_audio_initdev(struct pci_dev *pci, card->private_free = snd_cx88_dev_free; - err =snd_cx88_create (card, pci, &chip); + err =snd_cx88_create (card, pci, &chip, &core);if (err <0 ) goto error;
@@ -830,6 +914,10 @@ static int __devinit cx88_audio_initdev(struct pci_dev *pci,if (err <0 ) goto error; +/* If there's a wm8775 then add a Line-In ALC switch */ +if (core->board.audio_chip ==V4L2_IDENT_WM8775 ) +snd_ctl_add (card,snd_ctl_new1 (&snd_cx88_alc_switch, chip)); +strcpy (card->driver,"CX88x" );sprintf (card->shortname,"Conexant CX%x" , pci->device); sprintf(card->longname, "%s at %#llx",
drivers/media/video/cx88/cx88-cards.c +2 -1
@@ -970,7 +970,8 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .audio_chip = V4L2_IDENT_WM8775, + .audio_chip = V4L2_IDENT_WM8775, + .i2sinputcntl = 2, .input = {{ .type = CX88_VMUX_DVB, .vmux = 0,
drivers/media/video/cx88/cx88-tvaudio.c +6 -2
@@ -786,8 +786,12 @@ void cx88_set_tvaudio(struct cx88_core *core)break ;case WW_I2SADC :set_audio_start (core,0x01 ); -/* Slave/Philips/Autobaud */ -cx_write (AUD_I2SINPUTCNTL ,0 ); +/* +* Slave/Philips/Autobaud +* NB on Nova-S bit1 NPhilipsSony appears to be inverted: +* 0= Sony, 1=Philips +*/ +cx_write (AUD_I2SINPUTCNTL , core->board.i2sinputcntl);/* Switch to "I2S ADC mode" */ cx_write (AUD_I2SCNTL ,0x1 );set_audio_finish (core,EN_I2SIN_ENABLE );
drivers/media/video/cx88/cx88-video.c +48 -4
76 lines not on this page · raw message
drivers/media/video/cx88/cx88.h +11 -2
@@ -33,6 +33,7 @@#include <media/cx2341x.h> #include <media/videobuf-dvb.h> #include <media/ir-kbd-i2c.h> +#include <media/wm8775.h> #include "btcx-risc.h" #include "cx88-reg.h"
@@ -273,6 +274,9 @@ struct cx88_board {enum cx88_board_type mpeg;unsigned int audio_chip;int num_frontends; + +/* Used for I2S devices */ +int i2sinputcntl; };struct cx88_subid {
@@ -379,6 +383,7 @@ struct cx88_core {/* I2C remote data */ struct IR_i2c_init_data init_data; +struct wm8775_platform_data wm8775_data;struct mutex lock;/* various v4l controls */
@@ -398,17 +403,21 @@ static inline struct cx88_core *to_core(struct v4l2_device *v4l2_dev) return container_of(v4l2_dev, struct cx88_core, v4l2_dev); } -#define call_all(core, o, f, args...) \ +#define WM8775_GID (1 << 0) + +#define call_hw(core, grpid, o, f, args...) \ do { \ if (!core->i2c_rc) { \ if (core->gate_ctrl) \ core->gate_ctrl(core, 1); \ - v4l2_device_call_all(&core->v4l2_dev, 0, o, f, ##args); \ + v4l2_device_call_all(&core->v4l2_dev, grpid, o, f, ##args); \ if (core->gate_ctrl) \ core->gate_ctrl(core, 0); \ } \ } while (0) +#define call_all(core, o, f, args...) call_hw(core, 0, o, f, ##args) +struct cx8800_dev ;struct cx8802_dev ;
drivers/media/video/wm8775.c +88 -38
199 lines not on this page · raw message
include/media/wm8775.h +9 -0
@@ -32,4 +32,13 @@#define WM8775_AIN3 4#define WM8775_AIN4 8 + +struct wm8775_platform_data { +/* +* FIXME: Instead, we should parametrize the params +* that need different settings between ivtv, pvrusb2, and Nova-S +*/ +bool is_nova_s; +}; +#endif