Mailing List Archive

[REGRESSION: wm8775, ivtv] Please revert commit fcb9757333df37cf4a7feccef7ef6f5300643864
Mauro,

Please revert at least the wm8775.c portion of commit
fcb9757333df37cf4a7feccef7ef6f5300643864:

http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=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.

Reported-by: Eric Sharkey <eric@lisaneric.org>
http://ivtvdriver.org/pipermail/ivtv-users/2010-December/010104.html

Reported-by: Auric <auric@aanet.com.au>
http://ivtvdriver.org/pipermail/ivtv-users/2010-December/010102.html

Reported by: David Gesswein <djg@pdp8online.com>
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



_______________________________________________
ivtv-users mailing list
ivtv-users@ivtvdriver.org
http://ivtvdriver.org/mailman/listinfo/ivtv-users
Re: [REGRESSION: wm8775, ivtv] Please revert commit fcb9757333df37cf4a7feccef7ef6f5300643864 [ In reply to ]
On Fri, Dec 31, 2010 at 7:55 PM, Andy Walls <awalls@md.metrocast.net> wrote:
> Mauro,
>
> Please revert at least the wm8775.c portion of commit
> fcb9757333df37cf4a7feccef7ef6f5300643864:
>
> http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=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.

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

_______________________________________________
ivtv-users mailing list
ivtv-users@ivtvdriver.org
http://ivtvdriver.org/mailman/listinfo/ivtv-users
Re: [REGRESSION: wm8775, ivtv] Please revert commit fcb9757333df37cf4a7feccef7ef6f5300643864 [ In reply to ]
On Sun, 2011-01-02 at 23:00 -0500, Eric Sharkey wrote:
> On Fri, Dec 31, 2010 at 7:55 PM, Andy Walls <awalls@md.metrocast.net> wrote:
> > Mauro,
> >
> > Please revert at least the wm8775.c portion of commit
> > fcb9757333df37cf4a7feccef7ef6f5300643864:
> >
> > http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=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.
>
> 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.

See:
http://git.linuxtv.org/media_tree.git?a=blob;f=Documentation/video4linux/v4l2-framework.txt;h=f22f35c271f38d34fda0c19d8942b536e2fc95d9;hb=staging/for_v2.6.38#l399

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


_______________________________________________
ivtv-users mailing list
ivtv-users@ivtvdriver.org
http://ivtvdriver.org/mailman/listinfo/ivtv-users
Re: [REGRESSION: wm8775, ivtv] Please revert commit fcb9757333df37cf4a7feccef7ef6f5300643864 [ In reply to ]
On Monday, January 03, 2011 23:34:16 Andy Walls wrote:
> On Sun, 2011-01-02 at 23:00 -0500, Eric Sharkey wrote:
> > On Fri, Dec 31, 2010 at 7:55 PM, Andy Walls <awalls@md.metrocast.net> wrote:
> > > Mauro,
> > >
> > > Please revert at least the wm8775.c portion of commit
> > > fcb9757333df37cf4a7feccef7ef6f5300643864:
> > >
> > > http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=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.
> >
> > 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

Don't use .s_config! That will be removed soon.

Use platform_data and v4l2_i2c_new_subdev_board instead.

Regards,

Hans

>
>
> 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.
>
> See:
> http://git.linuxtv.org/media_tree.git?a=blob;f=Documentation/video4linux/v4l2-framework.txt;h=f22f35c271f38d34fda0c19d8942b536e2fc95d9;hb=staging/for_v2.6.38#l399
>
> 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
>
>

--
Hans Verkuil - video4linux developer - sponsored by Cisco

_______________________________________________
ivtv-users mailing list
ivtv-users@ivtvdriver.org
http://ivtvdriver.org/mailman/listinfo/ivtv-users
Re: [REGRESSION: wm8775, ivtv] Please revert commit fcb9757333df37cf4a7feccef7ef6f5300643864 [ In reply to ]
On Tue, 2011-01-04 at 08:10 +0100, Hans Verkuil wrote:
> On Monday, January 03, 2011 23:34:16 Andy Walls wrote:
> > On Sun, 2011-01-02 at 23:00 -0500, Eric Sharkey wrote:
> > > On Fri, Dec 31, 2010 at 7:55 PM, Andy Walls <awalls@md.metrocast.net> wrote:
> > > > Mauro,
> > > >
> > > > Please revert at least the wm8775.c portion of commit
> > > > fcb9757333df37cf4a7feccef7ef6f5300643864:
> > > >
> > > > http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=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.
> > >
> > > 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
>
> Don't use .s_config! That will be removed soon.
>
> Use platform_data and v4l2_i2c_new_subdev_board instead.

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



_______________________________________________
ivtv-users mailing list
ivtv-users@ivtvdriver.org
http://ivtvdriver.org/mailman/listinfo/ivtv-users
Re: [REGRESSION: wm8775, ivtv] Please revert commit fcb9757333df37cf4a7feccef7ef6f5300643864 [ In reply to ]
On Mon, 2011-01-03 at 17:34 -0500, Andy Walls wrote:
> On Sun, 2011-01-02 at 23:00 -0500, Eric Sharkey wrote:
> > On Fri, Dec 31, 2010 at 7:55 PM, Andy Walls <awalls@md.metrocast.net> wrote:
> > > Mauro,
> > >
> > > Please revert at least the wm8775.c portion of commit
> > > fcb9757333df37cf4a7feccef7ef6f5300643864:
> > >
> > > http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=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.
> >
> > 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



_______________________________________________
ivtv-users mailing list
ivtv-users@ivtvdriver.org
http://ivtvdriver.org/mailman/listinfo/ivtv-users
Re: [REGRESSION: wm8775, ivtv] Please revert commit fcb9757333df37cf4a7feccef7ef6f5300643864 [ In reply to ]
On Sat, 2011-01-08 at 13:09 +0100, Lawrence Rust wrote:
> On Mon, 2011-01-03 at 17:34 -0500, Andy Walls wrote:
> > On Sun, 2011-01-02 at 23:00 -0500, Eric Sharkey wrote:
> > > On Fri, Dec 31, 2010 at 7:55 PM, Andy Walls <awalls@md.metrocast.net> wrote:
> > > > Mauro,
> > > >
> > > > Please revert at least the wm8775.c portion of commit
> > > > fcb9757333df37cf4a7feccef7ef6f5300643864:
> > > >
> > > > http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=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.
> > >
> > > 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).

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.

> 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

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


> 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



> 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



_______________________________________________
ivtv-users mailing list
ivtv-users@ivtvdriver.org
http://ivtvdriver.org/mailman/listinfo/ivtv-users
Re: [REGRESSION: wm8775, ivtv] Please revert commit fcb9757333df37cf4a7feccef7ef6f5300643864 [ In reply to ]
On Sat, 2011-01-08 at 09:22 -0500, Andy Walls wrote:
> On Sat, 2011-01-08 at 13:09 +0100, Lawrence Rust wrote:
> > On Mon, 2011-01-03 at 17:34 -0500, Andy Walls wrote:
> > > On Sun, 2011-01-02 at 23:00 -0500, Eric Sharkey wrote:
> > > > On Fri, Dec 31, 2010 at 7:55 PM, Andy Walls <awalls@md.metrocast.net> wrote:
> > > > > Mauro,
> > > > >
> > > > > Please revert at least the wm8775.c portion of commit
> > > > > fcb9757333df37cf4a7feccef7ef6f5300643864:
> > > > >
> > > > > http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=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.
> > > >
> > > > 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).
>
> 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
Re: [REGRESSION: wm8775, ivtv] Please revert commit fcb9757333df37cf4a7feccef7ef6f5300643864 [ In reply to ]
On Sat, 2011-01-08 at 19:45 +0100, Lawrence Rust wrote:
> 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.
>
> 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.


> 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.

> NB I have only tested this patch on my Nova-S, no other.

I do see one problem with your patch at the moment:

diff --git a/include/media/wm8775.c b/include/media/wm8775.c
...
+ sd->grp_id = WM8775_GID; /* subdev group id */
...
diff --git a/include/media/wm8775.h b/include/media/wm8775.h
...
+/* 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


_______________________________________________
ivtv-users mailing list
ivtv-users@ivtvdriver.org
http://ivtvdriver.org/mailman/listinfo/ivtv-users
Re: [REGRESSION: wm8775, ivtv] Please revert commit fcb9757333df37cf4a7feccef7ef6f5300643864 [ In reply to ]
On Mon, 2011-01-10 at 07:39 -0500, Andy Walls wrote:
[snip]
> I do see one problem with your patch at the moment:
>
> diff --git a/include/media/wm8775.c b/include/media/wm8775.c
> ...
> + sd->grp_id = WM8775_GID; /* subdev group id */
> ...
> diff --git a/include/media/wm8775.h b/include/media/wm8775.h
> ...
> +/* 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.

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



_______________________________________________
ivtv-users mailing list
ivtv-users@ivtvdriver.org
http://ivtvdriver.org/mailman/listinfo/ivtv-users
Re: [REGRESSION: wm8775, ivtv] Please revert commit fcb9757333df37cf4a7feccef7ef6f5300643864 [ In reply to ]
On Mon, 2011-01-10 at 13:56 +0100, Lawrence Rust wrote:
> 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


_______________________________________________
ivtv-users mailing list
ivtv-users@ivtvdriver.org
http://ivtvdriver.org/mailman/listinfo/ivtv-users
Re: [REGRESSION: wm8775, ivtv] Please revert commit fcb9757333df37cf4a7feccef7ef6f5300643864 [ In reply to ]
Hi Lawrence,

Em 08-01-2011 16:45, Lawrence Rust escreveu:
> 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.

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 a
nova_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 <lawrence@softsystem.co.uk>

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.

[.mchehab@redhat.com: 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]

Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>

diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c
index 54b7fcd..a2d688e 100644
--- a/drivers/media/video/cx88/cx88-alsa.c
+++ b/drivers/media/video/cx88/cx88-alsa.c
@@ -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",
diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c
index 4e6ee55..6ccbb9c 100644
--- a/drivers/media/video/cx88/cx88-cards.c
+++ b/drivers/media/video/cx88/cx88-cards.c
@@ -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,
diff --git a/drivers/media/video/cx88/cx88-tvaudio.c b/drivers/media/video/cx88/cx88-tvaudio.c
index 08220de..770ec05 100644
--- a/drivers/media/video/cx88/cx88-tvaudio.c
+++ b/drivers/media/video/cx88/cx88-tvaudio.c
@@ -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);
diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c
index 508dabb..0f0aa96 100644
--- a/drivers/media/video/cx88/cx88-video.c
+++ b/drivers/media/video/cx88/cx88-video.c
@@ -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 <kraxel@bytesex.org> [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
diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h
index c9981e7..13bbe95 100644
--- a/drivers/media/video/cx88/cx88.h
+++ b/drivers/media/video/cx88/cx88.h
@@ -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;

diff --git a/drivers/media/video/wm8775.c b/drivers/media/video/wm8775.c
index fe8ef64..8674986 100644
--- a/drivers/media/video/wm8775.c
+++ b/drivers/media/video/wm8775.c
@@ -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;
}

diff --git a/drivers/staging/vme/bridges/Module.symvers b/drivers/staging/vme/bridges/Module.symvers
deleted file mode 100644
index e69de29..0000000
diff --git a/include/media/wm8775.h b/include/media/wm8775.h
index 60739c5..fe6ccd1 100644
--- a/include/media/wm8775.h
+++ b/include/media/wm8775.h
@@ -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


_______________________________________________
ivtv-users mailing list
ivtv-users@ivtvdriver.org
http://ivtvdriver.org/mailman/listinfo/ivtv-users
Re: [REGRESSION: wm8775, ivtv] Please revert commit fcb9757333df37cf4a7feccef7ef6f5300643864 [ In reply to ]
On Tue, 2011-02-01 at 13:49 -0200, Mauro Carvalho Chehab wrote:
> Hi Lawrence,
>
> Em 08-01-2011 16:45, Lawrence Rust escreveu:
> > 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.
>
> 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 a
> nova_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.

I'll plan this for Sunday 6 Feb. (I have a wedding to attend on
Saturday).

Regards,
Andy

> -
>
> From: Lawrence Rust <lawrence@softsystem.co.uk>
>
> 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.
>
> [.mchehab@redhat.com: 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]
>
> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
>
> diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c
> index 54b7fcd..a2d688e 100644
> --- a/drivers/media/video/cx88/cx88-alsa.c
> +++ b/drivers/media/video/cx88/cx88-alsa.c
> @@ -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",
> diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c
> index 4e6ee55..6ccbb9c 100644
> --- a/drivers/media/video/cx88/cx88-cards.c
> +++ b/drivers/media/video/cx88/cx88-cards.c
> @@ -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,
> diff --git a/drivers/media/video/cx88/cx88-tvaudio.c b/drivers/media/video/cx88/cx88-tvaudio.c
> index 08220de..770ec05 100644
> --- a/drivers/media/video/cx88/cx88-tvaudio.c
> +++ b/drivers/media/video/cx88/cx88-tvaudio.c
> @@ -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);
> diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c
> index 508dabb..0f0aa96 100644
> --- a/drivers/media/video/cx88/cx88-video.c
> +++ b/drivers/media/video/cx88/cx88-video.c
> @@ -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 <kraxel@bytesex.org> [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
> diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h
> index c9981e7..13bbe95 100644
> --- a/drivers/media/video/cx88/cx88.h
> +++ b/drivers/media/video/cx88/cx88.h
> @@ -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;
>
> diff --git a/drivers/media/video/wm8775.c b/drivers/media/video/wm8775.c
> index fe8ef64..8674986 100644
> --- a/drivers/media/video/wm8775.c
> +++ b/drivers/media/video/wm8775.c
> @@ -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;
> }
>
> diff --git a/drivers/staging/vme/bridges/Module.symvers b/drivers/staging/vme/bridges/Module.symvers
> deleted file mode 100644
> index e69de29..0000000
> diff --git a/include/media/wm8775.h b/include/media/wm8775.h
> index 60739c5..fe6ccd1 100644
> --- a/include/media/wm8775.h
> +++ b/include/media/wm8775.h
> @@ -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 majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html



_______________________________________________
ivtv-users mailing list
ivtv-users@ivtvdriver.org
http://ivtvdriver.org/mailman/listinfo/ivtv-users
Re: [REGRESSION: wm8775, ivtv] Please revert commit fcb9757333df37cf4a7feccef7ef6f5300643864 [ In reply to ]
On Tue, 2011-02-01 at 13:49 -0200, Mauro Carvalho Chehab wrote:
> Hi Lawrence,
>
> Em 08-01-2011 16:45, Lawrence Rust escreveu:
> > 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.
>
> 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.

Many thanks for doing this. I appreciate the guidance and effort. I'll
test it and report back this weekend.

-- Lawrence



_______________________________________________
ivtv-users mailing list
ivtv-users@ivtvdriver.org
http://ivtvdriver.org/mailman/listinfo/ivtv-users
Re: [REGRESSION: wm8775, ivtv] Please revert commit fcb9757333df37cf4a7feccef7ef6f5300643864 [ In reply to ]
On Tue, 2011-02-01 at 13:49 -0200, Mauro Carvalho Chehab wrote:
> Hi Lawrence,
>
> Em 08-01-2011 16:45, Lawrence Rust escreveu:
> > 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.
>
> 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.

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.

> 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.

> 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.

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.

> 2) I just added one platform_data info that indicates if the device is a
> nova_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.

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.

> If it works for you, please add your Signed-off-by:.

Many thanks for your suggestions and modifications.

Signed-off-by: Lawrence Rust <lvr@softsystem.co.uk>

> 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 <lawrence@softsystem.co.uk>
>
> 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.
>
> [.mchehab@redhat.com: 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]
>
> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
>
> diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c
> index 54b7fcd..a2d688e 100644
> --- a/drivers/media/video/cx88/cx88-alsa.c
> +++ b/drivers/media/video/cx88/cx88-alsa.c
> @@ -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",
> diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c
> index 4e6ee55..6ccbb9c 100644
> --- a/drivers/media/video/cx88/cx88-cards.c
> +++ b/drivers/media/video/cx88/cx88-cards.c
> @@ -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,
> diff --git a/drivers/media/video/cx88/cx88-tvaudio.c b/drivers/media/video/cx88/cx88-tvaudio.c
> index 08220de..770ec05 100644
> --- a/drivers/media/video/cx88/cx88-tvaudio.c
> +++ b/drivers/media/video/cx88/cx88-tvaudio.c
> @@ -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);
> diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c
> index 508dabb..0f0aa96 100644
> --- a/drivers/media/video/cx88/cx88-video.c
> +++ b/drivers/media/video/cx88/cx88-video.c
> @@ -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 <kraxel@bytesex.org> [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
> diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h
> index c9981e7..13bbe95 100644
> --- a/drivers/media/video/cx88/cx88.h
> +++ b/drivers/media/video/cx88/cx88.h
> @@ -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;
>
> diff --git a/drivers/media/video/wm8775.c b/drivers/media/video/wm8775.c
> index fe8ef64..8674986 100644
> --- a/drivers/media/video/wm8775.c
> +++ b/drivers/media/video/wm8775.c
> @@ -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;
> }
>
> diff --git a/drivers/staging/vme/bridges/Module.symvers b/drivers/staging/vme/bridges/Module.symvers
> deleted file mode 100644
> index e69de29..0000000
> diff --git a/include/media/wm8775.h b/include/media/wm8775.h
> index 60739c5..fe6ccd1 100644
> --- a/include/media/wm8775.h
> +++ b/include/media/wm8775.h
> @@ -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
>

-- Lawrence



_______________________________________________
ivtv-users mailing list
ivtv-users@ivtvdriver.org
http://ivtvdriver.org/mailman/listinfo/ivtv-users
Re: [REGRESSION: wm8775, ivtv] Please revert commit fcb9757333df37cf4a7feccef7ef6f5300643864 [ In reply to ]
On Tue, 2011-02-01 at 13:49 -0200, Mauro Carvalho Chehab wrote:
> Hi Lawrence,
>
> Em 08-01-2011 16:45, Lawrence Rust escreveu:
> > 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.
>
> 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 a
> nova_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.

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 <lawrence@softsystem.co.uk>

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.

[.mchehab@redhat.com: 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]

[.awalls@md.metrocast.net: Changed patch to make the WM8775_GID defintion
bridge driver private and let the bridge driver set the value of
v4l2_subdev.grp_id.]

Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Signed-off-by: Andy Walls <awalls@md.metrocast.net>

diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c
index 54b7fcd..a2d688e 100644
--- a/drivers/media/video/cx88/cx88-alsa.c
+++ b/drivers/media/video/cx88/cx88-alsa.c
@@ -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",
diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c
index 4e6ee55..6ccbb9c 100644
--- a/drivers/media/video/cx88/cx88-cards.c
+++ b/drivers/media/video/cx88/cx88-cards.c
@@ -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,
diff --git a/drivers/media/video/cx88/cx88-tvaudio.c b/drivers/media/video/cx88/cx88-tvaudio.c
index 08220de..770ec05 100644
--- a/drivers/media/video/cx88/cx88-tvaudio.c
+++ b/drivers/media/video/cx88/cx88-tvaudio.c
@@ -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);
diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c
index 508dabb..7b03061 100644
--- a/drivers/media/video/cx88/cx88-video.c
+++ b/drivers/media/video/cx88/cx88-video.c
@@ -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 <kraxel@bytesex.org> [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,24 @@ 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,
+ };
+ struct v4l2_subdev *sd;
+
+ if (core->boardnr == CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1)
+ core->wm8775_data.is_nova_s = true;
+ else
+ core->wm8775_data.is_nova_s = false;
+
+ sd = v4l2_i2c_new_subdev_board(&core->v4l2_dev, &core->i2c_adap,
+ &wm8775_info, NULL);
+ if (sd != NULL)
+ sd->grp_id = WM8775_GID;
+ }

if (core->board.audio_chip == V4L2_IDENT_TVAUDIO) {
/* This probes for a tda9874 as is used on some
diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h
index c9981e7..aaf7d12 100644
--- a/drivers/media/video/cx88/cx88.h
+++ b/drivers/media/video/cx88/cx88.h
@@ -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;

diff --git a/drivers/media/video/wm8775.c b/drivers/media/video/wm8775.c
index fe8ef64..9cedb1e 100644
--- a/drivers/media/video/wm8775.c
+++ b/drivers/media/video/wm8775.c
@@ -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))
@@ -218,13 +248,18 @@ static int wm8775_probe(struct i2c_client *client,
v4l2_i2c_subdev_init(sd, client, &wm8775_ops);
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 +271,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;
}

diff --git a/include/media/wm8775.h b/include/media/wm8775.h
index 60739c5..d0e801a 100644
--- a/include/media/wm8775.h
+++ b/include/media/wm8775.h
@@ -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



_______________________________________________
ivtv-users mailing list
ivtv-users@ivtvdriver.org
http://ivtvdriver.org/mailman/listinfo/ivtv-users