stk1160: Let the driver setup the device's internal AC97 codec
Subsystems (2)
v4 cover stk1160: Let the driver setup the device's internal AC97 codec
This patchset is a result of my attempt to fix a bug (https://bugzilla.kernel.org/show_bug.cgi?id=180071) that eventually turned out to be caused by a missing quirk in snd-usb-audio. My idea was to remove the AC97 interface and setup the codec using the same values and in the same order as the Windows driver does, hoping there might be some "magic" sequence that would make the sound work the way it should. Although this didn't help to fix the problem, I found these changes to be useful nevertheless.
IMHO, having all of the AC97 codec's channels exposed to userspace is confusing since most of them have no meaning for this device anyway. Changing these values in alsamixer has either no effect at all or may even reduce the sound quality since it can actually increase the line-in DC offset (slightly).
In addition, having to re-select the correct capture channel everytime the device has been plugged in is annoying. At least on my systems the mixer setup is only saved if the device is plugged in during shutdown/reboot. I also get error messages in my kernel log when I unplug the device because some process (probably the AC97 driver) ist trying to read from the device after it has been removed. Either way the device should work out-of-the-box without the need for the user to manually setup channels.
The first patch in the set therefore removes the 'stk1160-mixer' and lets the driver setup the AC97 codec using the same values as the Windows driver. Although some of the values seem to be defaults I let the driver set them either way, just to be sure.
The second patch adds a check to determine whether the device is strapped to use the internal 8-bit ADC or an external chip, or whether audio is disabled altogether. There's currently no check in place to determine whether the device uses AC-link or I2S, but then again I haven't heard of any of these devices actually using an I2S chip. If the device uses the internal ADC the AC97 setup can be skipped. I implemented the check inside stk1160-ac97. It could just as well be in stk1160-core but this way just seemed cleaner. If at some point the need arises to check other power-on strap values, it might make sense to refactor this then.
The third patch addresses an issue when reading from the AC97 chip too soon, resulting in corrupt data.
Changes from version 3:
* Removed module param
* Implemented polling read/write bits
Marcel Hasler (3):
stk1160: Remove stk1160-mixer and setup internal AC97 codec automatically.
stk1160: Check whether to use AC97 codec.
stk1160: Wait for completion of transfers to and from AC97 codec.
drivers/media/usb/stk1160/Kconfig | 10 +- drivers/media/usb/stk1160/Makefile | 4 +- drivers/media/usb/stk1160/stk1160-ac97.c | 183 +++++++++++++++++-------------- drivers/media/usb/stk1160/stk1160-core.c | 8 +- drivers/media/usb/stk1160/stk1160-reg.h | 10 ++ drivers/media/usb/stk1160/stk1160.h | 11 +- 6 files changed, 116 insertions(+), 110 deletions(-)
Signature · 1 line
2.10.2
PATCH v4 1/3 stk1160: Remove stk1160-mixer and setup internal AC97 codec automatically.
Exposing all the channels of the device's internal AC97 codec to userspace is unnecessary and confusing. Instead the driver should setup the codec with proper values. This patch removes the mixer and sets up the codec using optimal values, i.e. the same values set by the Windows driver. This also makes the device work out-of-the-box, without the need for the user to reconfigure the device every time it's plugged in.
--- drivers/media/usb/stk1160/Kconfig | 10 +-- drivers/media/usb/stk1160/Makefile | 4 +- drivers/media/usb/stk1160/stk1160-ac97.c | 126 +++++++++++-------------------- drivers/media/usb/stk1160/stk1160-core.c | 5 +- drivers/media/usb/stk1160/stk1160.h | 9 +-- 5 files changed, 50 insertions(+), 104 deletions(-)
drivers/media/usb/stk1160/Kconfig +1 -9
@@ -8,17 +8,9 @@ config VIDEO_STK1160_COMMON To compile this driver as a module, choose M here: the module will be called stk1160 -config VIDEO_STK1160_AC97 - bool "STK1160 AC97 codec support" - depends on VIDEO_STK1160_COMMON && SND - - ---help--- - Enables AC97 codec support for stk1160 driver. - config VIDEO_STK1160 tristate - depends on (!VIDEO_STK1160_AC97 || (SND='n') || SND) && VIDEO_STK1160_COMMON + depends on VIDEO_STK1160_COMMON default y select VIDEOBUF2_VMALLOC select VIDEO_SAA711X - select SND_AC97_CODEC if SND
drivers/media/usb/stk1160/Makefile +1 -3
@@ -1,10 +1,8 @@ -obj-stk1160-ac97-$(CONFIG_VIDEO_STK1160_AC97) := stk1160-ac97.o - stk1160-y := stk1160-core.o \ stk1160-v4l.o \ stk1160-video.o \ stk1160-i2c.o \ - $(obj-stk1160-ac97-y) + stk1160-ac97.o obj-$(CONFIG_VIDEO_STK1160) += stk1160.o
drivers/media/usb/stk1160/stk1160-ac97.c +46 -80
162 lines not on this page · raw message
drivers/media/usb/stk1160/stk1160-core.c +1 -4
@@ -373,7 +373,7 @@ static int stk1160_probe(struct usb_interface *interface,/* select default input */ stk1160_select_input (dev); -stk1160_ac97_register (dev); +stk1160_ac97_setup (dev); rc =stk1160_video_register (dev);if (rc <0 )
@@ -411,9 +411,6 @@ static void stk1160_disconnect(struct usb_interface *interface)/* Here is the only place where isoc get released */ stk1160_uninit_isoc (dev); -/* ac97 unregister needs to be done before usb_device is cleared */ -stk1160_ac97_unregister (dev); -stk1160_clear_queue (dev);video_unregister_device (&dev->vdev);
drivers/media/usb/stk1160/stk1160.h +1 -8
@@ -197,11 +197,4 @@ int stk1160_read_reg_req_len(struct stk1160 *dev, u8 req, u16 reg,void stk1160_select_input (struct stk1160 *dev);/* Provided by stk1160-ac97.c */ -#ifdef CONFIG_VIDEO_STK1160_AC97 -int stk1160_ac97_register (struct stk1160 *dev); -int stk1160_ac97_unregister (struct stk1160 *dev); -#else -static inline int stk1160_ac97_register (struct stk1160 *dev) {return 0 ; } -static inline int stk1160_ac97_unregister (struct stk1160 *dev) {return 0 ; } -#endif - +void stk1160_ac97_setup (struct stk1160 *dev);
Signature · 1 line
2.10.2
PATCH v4 2/3 stk1160: Check whether to use AC97 codec.
In reply to Marcel HaslerSome STK1160-based devices use the chip's internal 8-bit ADC. This is configured through a strap pin. The value of this and other pins can be read through the POSVA register. If the internal ADC is used, or if audio is disabled altogether, there's no point trying to setup the AC97 codec.
--- drivers/media/usb/stk1160/stk1160-ac97.c | 26 ++++++++++++++++++++++++++ drivers/media/usb/stk1160/stk1160-core.c | 3 +-- drivers/media/usb/stk1160/stk1160-reg.h | 8 ++++++++ 3 files changed, 35 insertions(+), 2 deletions(-)
drivers/media/usb/stk1160/stk1160-ac97.c +26 -0
@@ -91,8 +91,34 @@ void stk1160_ac97_dump_regs(struct stk1160 *dev) }#endif +int stk1160_has_audio (struct stk1160 *dev) +{ +u8 value; + +stk1160_read_reg (dev,STK1160_POSV_L , &value); +return !(value &STK1160_POSV_L_ACDOUT ); +} + +int stk1160_has_ac97 (struct stk1160 *dev) +{ +u8 value; + +stk1160_read_reg (dev,STK1160_POSV_L , &value); +return !(value &STK1160_POSV_L_ACSYNC ); +} +void stk1160_ac97_setup (struct stk1160 *dev) { +if (!stk1160_has_audio (dev)) { +stk1160_info ("Device doesn't support audio, skipping AC97 setup." ); +return ; + } + +if (!stk1160_has_ac97 (dev)) { +stk1160_info ("Device uses internal 8-bit ADC, skipping AC97 setup." ); +return ; + } +/* Two-step reset AC97 interface and hardware codec */ stk1160_write_reg (dev,STK1160_AC97CTL_0 ,0x94 );stk1160_write_reg (dev,STK1160_AC97CTL_0 ,0x8c );
drivers/media/usb/stk1160/stk1160-core.c +1 -2
@@ -20,8 +20,7 @@* * TODO: * -* 1. (Try to) detect if we must register ac97 mixer -* 2. Support stream at lower speed: lower frame rate or lower frame size. +* 1. Support stream at lower speed: lower frame rate or lower frame size. * */
drivers/media/usb/stk1160/stk1160-reg.h +8 -0
@@ -26,6 +26,14 @@/* Remote Wakup Control */ #define STK1160_RMCTL 0x00c +/* Power-on Strapping Data */ +#define STK1160_POSVA 0x010 +#define STK1160_POSV_L 0x010 +#define STK1160_POSV_M 0x011 +#define STK1160_POSV_H 0x012 +#define STK1160_POSV_L_ACDOUT BIT(3) +#define STK1160_POSV_L_ACSYNC BIT(2) +/* * Decoder Control Register: * This byte controls capture start/stop
Signature · 1 line
2.10.2
PATCH v4 3/3 stk1160: Wait for completion of transfers to and from AC97 codec.
In reply to Marcel HaslerThe STK1160 needs some time to transfer data to and from the AC97 codec. The transfer completion is indicated by command read/write bits in the chip's audio control register. The driver should poll these bits and wait until they have been cleared by hardware before trying to retrive the results of a read operation or setting a new write command.
--- drivers/media/usb/stk1160/stk1160-ac97.c | 39 +++++++++++++++++++++++++------- drivers/media/usb/stk1160/stk1160-reg.h | 2 ++ drivers/media/usb/stk1160/stk1160.h | 2 ++ 3 files changed, 35 insertions(+), 8 deletions(-)
drivers/media/usb/stk1160/stk1160-ac97.c +31 -8
@@ -23,9 +23,30 @@* */ +#include <linux/delay.h> +#include "stk1160.h" #include "stk1160-reg.h" +static int stk1160_ac97_wait_transfer_complete (struct stk1160 *dev) +{ +unsigned long timeout = jiffies +msecs_to_jiffies (STK1160_AC97_TIMEOUT ); +u8 value; + +/* Wait for AC97 transfer to complete */ +while (time_is_after_jiffies (timeout)) { +stk1160_read_reg (dev,STK1160_AC97CTL_0 , &value); + +if (!(value & (STK1160_AC97CTL_0_CR |STK1160_AC97CTL_0_CW ))) +return 0 ; + +usleep_range (50 ,100 ); + } + +stk1160_err ("AC97 transfer took too long, this should never happen!" ); +return -EBUSY ; +} +static void stk1160_write_ac97 (struct stk1160 *dev,u16 reg,u16 value) {/* Set codec register address */
@@ -35,11 +56,11 @@ static void stk1160_write_ac97(struct stk1160 *dev, u16 reg, u16 value)stk1160_write_reg (dev,STK1160_AC97_CMD , value &0xff );stk1160_write_reg (dev,STK1160_AC97_CMD +1 , (value &0xff00 ) >>8 ); -/* -* Set command write bit to initiate write operation. -* The bit will be cleared when transfer is done. -*/ +/* Set command write bit to initiate write operation */ stk1160_write_reg (dev,STK1160_AC97CTL_0 ,0x8c ); + +/* Wait for command write bit to be cleared */ +stk1160_ac97_wait_transfer_complete (dev); }#ifdef DEBUG
@@ -51,12 +72,14 @@ static u16 stk1160_read_ac97(struct stk1160 *dev, u16 reg)/* Set codec register address */ stk1160_write_reg (dev,STK1160_AC97_ADDR , reg); -/* -* Set command read bit to initiate read operation. -* The bit will be cleared when transfer is done. -*/ +/* Set command read bit to initiate read operation */ stk1160_write_reg (dev,STK1160_AC97CTL_0 ,0x8b ); +/* Wait for command read bit to be cleared */ +if (stk1160_ac97_wait_transfer_complete (dev) <0 ) { +return 0 ; + } +/* Retrieve register value */ stk1160_read_reg (dev,STK1160_AC97_CMD , &vall);stk1160_read_reg (dev,STK1160_AC97_CMD +1 , &valh);
drivers/media/usb/stk1160/stk1160-reg.h +2 -0
@@ -122,6 +122,8 @@/* AC97 Audio Control */ #define STK1160_AC97CTL_0 0x500#define STK1160_AC97CTL_1 0x504 +#define STK1160_AC97CTL_0_CR BIT(1) +#define STK1160_AC97CTL_0_CW BIT(2)/* Use [0:6] bits of register 0x504 to set codec command address */ #define STK1160_AC97_ADDR 0x504
drivers/media/usb/stk1160/stk1160.h +2 -0
@@ -50,6 +50,8 @@#define STK1160_MAX_INPUT 4#define STK1160_SVIDEO_INPUT 4 +#define STK1160_AC97_TIMEOUT 50 +#define STK1160_I2C_TIMEOUT 100/* TODO: Print helpers
Signature · 1 line
2.10.2
Quoted 12 lines · Marcel Hasler
This patchset is a result of my attempt to fix a bug (https://bugzilla.kernel.org/show_bug.cgi?id=180071) that eventually turned out to be caused by a missing quirk in snd-usb-audio. My idea was to remove the AC97 interface and setup the codec using the same values and in the same order as the Windows driver does, hoping there might be some "magic" sequence that would make the sound work the way it should. Although this didn't help to fix the problem, I found these changes to be useful nevertheless.
IMHO, having all of the AC97 codec's channels exposed to userspace is confusing since most of them have no meaning for this device anyway. Changing these values in alsamixer has either no effect at all or may even reduce the sound quality since it can actually increase the line-in DC offset (slightly).
In addition, having to re-select the correct capture channel everytime the device has been plugged in is annoying. At least on my systems the mixer setup is only saved if the device is plugged in during shutdown/reboot. I also get error messages in my kernel log when I unplug the device because some process (probably the AC97 driver) ist trying to read from the device after it has been removed. Either way the device should work out-of-the-box without the need for the user to manually setup channels.
The first patch in the set therefore removes the 'stk1160-mixer' and lets the driver setup the AC97 codec using the same values as the Windows driver. Although some of the values seem to be defaults I let the driver set them either way, just to be sure.
The second patch adds a check to determine whether the device is strapped to use the internal 8-bit ADC or an external chip, or whether audio is disabled altogether. There's currently no check in place to determine whether the device uses AC-link or I2S, but then again I haven't heard of any of these devices actually using an I2S chip. If the device uses the internal ADC the AC97 setup can be skipped. I implemented the check inside stk1160-ac97. It could just as well be in stk1160-core but this way just seemed cleaner. If at some point the need arises to check other power-on strap values, it might make sense to refactor this then.
The third patch addresses an issue when reading from the AC97 chip too soon, resulting in corrupt data.
Quoted 9 lines
Changes from version 3:
* Removed module param
* Implemented polling read/write bitsMarcel Hasler (3):
stk1160: Remove stk1160-mixer and setup internal AC97 codec automatically.
stk1160: Check whether to use AC97 codec.
stk1160: Wait for completion of transfers to and from AC97 codec.
For the whole set:
Signature · 2 lines
Ezequiel García, VanguardiaSur www.vanguardiasur.com.ar