Alsa-devel
Threads by month
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- 22 participants
- 51595 discussions
[alsa-devel] [PATCH] Fix missing stream for second ADC on Realtek ALC260 HDA codec
by Jonathan Woithe 09 Aug '10
by Jonathan Woithe 09 Aug '10
09 Aug '10
Hi all
I discovered tonight that ALSA no longer sets up a stream for the second ADC
provided by the Realtek ALC260 HDA codec. At some point alc_build_pcms()
started using stream_analog_alt_capture when constructing the second ADC
stream, but patch_alc260() was never updated accordingly. I have no idea
when this regression occurred. The trivial patch to patch_alc260() given
below fixes the problem as far as I can tell. The patch is against 2.6.35.
Signed-off-by: Jonathan Woithe <jwoithe(a)physics.adelaide.edu.au>
--- linux-2.6.35-orig/sound/pci/hda/patch_realtek.c 2010-08-02 07:41:14.000000000 +0930
+++ linux-2.6.35/sound/pci/hda/patch_realtek.c 2010-08-08 00:06:19.670695899 +0930
@@ -6863,6 +6863,7 @@
spec->stream_analog_playback = &alc260_pcm_analog_playback;
spec->stream_analog_capture = &alc260_pcm_analog_capture;
+ spec->stream_analog_alt_capture = &alc260_pcm_analog_capture;
spec->stream_digital_playback = &alc260_pcm_digital_playback;
spec->stream_digital_capture = &alc260_pcm_digital_capture;
2
1
Hello,
I have a Gigabyte 890GX-based board with an ALC892 codec.
The optical SPDIF output does not work at all (i.e. no red light on
the cable), and the kernel prints
"ALSA hda_codec.c:407: Too many connections"
messages whenever sound is played (analog works, but I need
digital).
Below are the contents of /proc/asound/card0/codec#0.
Thanks,
Manuel Lauss
Codec: Realtek ALC892
Address: 0
Function Id: 0x1
Vendor Id: 0x10ec0892
Subsystem Id: 0x1458a102
Revision Id: 0x100302
No Modem Function Group found
Default PCM:
rates [0x5f0]: 32000 44100 48000 88200 96000 192000
bits [0xe]: 16 20 24
formats [0x1]: PCM
Default Amp-In caps: N/A
Default Amp-Out caps: N/A
GPIO: io=2, o=0, i=0, unsolicited=1, wake=0
IO[0]: enable=0, dir=0, wake=0, sticky=0, data=0, unsol=0
IO[1]: enable=0, dir=0, wake=0, sticky=0, data=0, unsol=0
Node 0x02 [Audio Output] wcaps 0x41d: Stereo Amp-Out
Control: name="Front Playback Volume", index=0, device=0
ControlAmp: chs=3, dir=Out, idx=0, ofs=0
Device: name="ALC892 Analog", type="Audio", device=0
Amp-Out caps: ofs=0x40, nsteps=0x40, stepsize=0x03, mute=0
Amp-Out vals: [0x40 0x40]
Converter: stream=0, channel=0
PCM:
rates [0x560]: 44100 48000 96000 192000
bits [0xe]: 16 20 24
formats [0x1]: PCM
Power states: D0 D1 D2 D3 EPSS
Power: setting=D0, actual=D0
Node 0x03 [Audio Output] wcaps 0x41d: Stereo Amp-Out
Control: name="Surround Playback Volume", index=0, device=0
ControlAmp: chs=3, dir=Out, idx=0, ofs=0
Amp-Out caps: ofs=0x40, nsteps=0x40, stepsize=0x03, mute=0
Amp-Out vals: [0x40 0x40]
Converter: stream=0, channel=0
PCM:
rates [0x560]: 44100 48000 96000 192000
bits [0xe]: 16 20 24
formats [0x1]: PCM
Power states: D0 D1 D2 D3 EPSS
Power: setting=D0, actual=D0
Node 0x04 [Audio Output] wcaps 0x41d: Stereo Amp-Out
Control: name="Center Playback Volume", index=0, device=0
ControlAmp: chs=1, dir=Out, idx=0, ofs=0
Control: name="LFE Playback Volume", index=0, device=0
ControlAmp: chs=2, dir=Out, idx=0, ofs=0
Amp-Out caps: ofs=0x40, nsteps=0x40, stepsize=0x03, mute=0
Amp-Out vals: [0x40 0x40]
Converter: stream=0, channel=0
PCM:
rates [0x560]: 44100 48000 96000 192000
bits [0xe]: 16 20 24
formats [0x1]: PCM
Power states: D0 D1 D2 D3 EPSS
Power: setting=D0, actual=D0
Node 0x05 [Audio Output] wcaps 0x41d: Stereo Amp-Out
Amp-Out caps: ofs=0x40, nsteps=0x40, stepsize=0x03, mute=0
Amp-Out vals: [0x40 0x40]
Converter: stream=0, channel=0
PCM:
rates [0x560]: 44100 48000 96000 192000
bits [0xe]: 16 20 24
formats [0x1]: PCM
Power states: D0 D1 D2 D3 EPSS
Power: setting=D0, actual=D0
Node 0x06 [Audio Output] wcaps 0x611: Stereo Digital
Control: name="IEC958 Playback Con Mask", index=0, device=0
Control: name="IEC958 Playback Pro Mask", index=0, device=0
Control: name="IEC958 Playback Default", index=0, device=0
Control: name="IEC958 Playback Switch", index=0, device=0
Control: name="IEC958 Default PCM Playback Switch", index=0, device=0
Device: name="ALC892 Digital", type="SPDIF", device=1
Converter: stream=0, channel=0
Digital: Enabled
Digital category: 0x0
PCM:
rates [0x5f0]: 32000 44100 48000 88200 96000 192000
bits [0xe]: 16 20 24
formats [0x1]: PCM
Power states: D0 D1 D2 D3 EPSS
Power: setting=D0, actual=D0
Node 0x07 [Vendor Defined Widget] wcaps 0xf00000: Mono
Node 0x08 [Audio Input] wcaps 0x10051b: Stereo Amp-In
Control: name="Capture Switch", index=1, device=0
Control: name="Capture Volume", index=1, device=0
Amp-In caps: ofs=0x10, nsteps=0x2e, stepsize=0x03, mute=1
Amp-In vals: [0x90 0x90]
Converter: stream=0, channel=0
SDI-Select: 0
PCM:
rates [0x560]: 44100 48000 96000 192000
bits [0xe]: 16 20 24
formats [0x1]: PCM
Power states: D0 D1 D2 D3 EPSS
Power: setting=D0, actual=D0
Connection: 1
0x23
Node 0x09 [Audio Input] wcaps 0x10051b: Stereo Amp-In
Control: name="Capture Switch", index=0, device=0
Control: name="Capture Volume", index=0, device=0
Device: name="ALC892 Analog", type="Audio", device=0
Amp-In caps: ofs=0x10, nsteps=0x2e, stepsize=0x03, mute=1
Amp-In vals: [0x9c 0x9c]
Converter: stream=0, channel=0
SDI-Select: 0
PCM:
rates [0x560]: 44100 48000 96000 192000
bits [0xe]: 16 20 24
formats [0x1]: PCM
Power states: D0 D1 D2 D3 EPSS
Power: setting=D0, actual=D0
Connection: 1
0x22
Node 0x0a [Audio Input] wcaps 0x100711: Stereo Digital
Converter: stream=0, channel=0
SDI-Select: 0
Digital:
Digital category: 0x0
PCM:
rates [0x560]: 44100 48000 96000 192000
bits [0xe]: 16 20 24
formats [0x1]: PCM
Power states: D0 D1 D2 D3 EPSS
Power: setting=D0, actual=D0
Connection: 1
0x1f
Node 0x0b [Audio Mixer] wcaps 0x20010b: Stereo Amp-In
Control: name="Mic Playback Volume", index=0, device=0
ControlAmp: chs=3, dir=In, idx=0, ofs=0
Control: name="Mic Playback Switch", index=0, device=0
ControlAmp: chs=3, dir=In, idx=0, ofs=0
Control: name="Front Mic Playback Volume", index=0, device=0
ControlAmp: chs=3, dir=In, idx=1, ofs=0
Control: name="Front Mic Playback Switch", index=0, device=0
ControlAmp: chs=3, dir=In, idx=1, ofs=0
Control: name="Line Playback Volume", index=0, device=0
ControlAmp: chs=3, dir=In, idx=2, ofs=0
Control: name="Line Playback Switch", index=0, device=0
ControlAmp: chs=3, dir=In, idx=2, ofs=0
Amp-In caps: ofs=0x17, nsteps=0x1f, stepsize=0x05, mute=1
Amp-In vals: [0x80 0x80] [0x80 0x80] [0x80 0x80] [0x80 0x80] [0x80
0x80] [0x80 0x80] [0x80 0x80] [0x80 0x80] [0x80 0x80] [0x80 0x80]
Connection: 10
0x18 0x19 0x1a 0x1b 0x1c 0x1d 0x14 0x15 0x16 0x17
Node 0x0c [Audio Mixer] wcaps 0x20010b: Stereo Amp-In
Control: name="Front Playback Switch", index=0, device=0
ControlAmp: chs=3, dir=In, idx=0, ofs=0
Amp-In caps: ofs=0x00, nsteps=0x00, stepsize=0x00, mute=1
Amp-In vals: [0x00 0x00] [0x00 0x00]
Connection: 2
0x02 0x0b
Node 0x0d [Audio Mixer] wcaps 0x20010b: Stereo Amp-In
Control: name="Surround Playback Switch", index=0, device=0
ControlAmp: chs=3, dir=In, idx=0, ofs=0
Amp-In caps: ofs=0x00, nsteps=0x00, stepsize=0x00, mute=1
Amp-In vals: [0x00 0x00] [0x00 0x00]
Connection: 2
0x03 0x0b
Node 0x0e [Audio Mixer] wcaps 0x20010b: Stereo Amp-In
Control: name="Center Playback Switch", index=0, device=0
ControlAmp: chs=1, dir=In, idx=0, ofs=0
Control: name="LFE Playback Switch", index=0, device=0
ControlAmp: chs=2, dir=In, idx=0, ofs=0
Amp-In caps: ofs=0x00, nsteps=0x00, stepsize=0x00, mute=1
Amp-In vals: [0x00 0x00] [0x00 0x00]
Connection: 2
0x04 0x0b
Node 0x0f [Audio Mixer] wcaps 0x20010b: Stereo Amp-In
Amp-In caps: ofs=0x00, nsteps=0x00, stepsize=0x00, mute=1
Amp-In vals: [0x00 0x00] [0x80 0x80]
Connection: 2
0x05 0x0b
Node 0x10 [Audio Output] wcaps 0x611: Stereo Digital
Converter: stream=0, channel=0
Digital:
Digital category: 0x0
PCM:
rates [0x5f0]: 32000 44100 48000 88200 96000 192000
bits [0xe]: 16 20 24
formats [0x1]: PCM
Power states: D0 D1 D2 D3 EPSS
Power: setting=D0, actual=D0
Node 0x11 [Pin Complex] wcaps 0x400781: Stereo Digital
Pincap 0x00000014: OUT Detect
Pin Default 0x99430140: [Fixed] SPDIF Out at Int ATAPI
Conn = ATAPI, Color = Unknown
DefAssociation = 0x4, Sequence = 0x0
Misc = NO_PRESENCE
Pin-ctls: 0x00:
Unsolicited: tag=00, enabled=0
Power states: D0 D1 D2 D3 EPSS
Power: setting=D0, actual=D0
Connection: 1
0x10
Node 0x12 [Pin Complex] wcaps 0x400401: Stereo
Pincap 0x00000020: IN
Pin Default 0x411111f0: [N/A] Speaker at Ext Rear
Conn = 1/8, Color = Black
DefAssociation = 0xf, Sequence = 0x0
Misc = NO_PRESENCE
Pin-ctls: 0x00:
Power states: D0 D1 D2 D3 EPSS
Power: setting=D0, actual=D0
Node 0x13 [Vendor Defined Widget] wcaps 0xf00000: Mono
Node 0x14 [Pin Complex] wcaps 0x40058d: Stereo Amp-Out
Amp-Out caps: ofs=0x00, nsteps=0x00, stepsize=0x00, mute=1
Amp-Out vals: [0x00 0x00]
Pincap 0x0000003e: IN OUT HP Detect Trigger
Pin Default 0x01014410: [Jack] Line Out at Ext Rear
Conn = 1/8, Color = Green
DefAssociation = 0x1, Sequence = 0x0
Pin-ctls: 0x40: OUT
Unsolicited: tag=00, enabled=0
Power states: D0 D1 D2 D3 EPSS
Power: setting=D0, actual=D0
Connection: 1
0x0c
Node 0x15 [Pin Complex] wcaps 0x40058d: Stereo Amp-Out
Amp-Out caps: ofs=0x00, nsteps=0x00, stepsize=0x00, mute=1
Amp-Out vals: [0x00 0x00]
Pincap 0x00000036: IN OUT Detect Trigger
Pin Default 0x01011412: [Jack] Line Out at Ext Rear
Conn = 1/8, Color = Black
DefAssociation = 0x1, Sequence = 0x2
Pin-ctls: 0x40: OUT
Unsolicited: tag=00, enabled=0
Power states: D0 D1 D2 D3 EPSS
Power: setting=D0, actual=D0
Connection: 1
0x0d
Node 0x16 [Pin Complex] wcaps 0x40058d: Stereo Amp-Out
Amp-Out caps: ofs=0x00, nsteps=0x00, stepsize=0x00, mute=1
Amp-Out vals: [0x00 0x00]
Pincap 0x00000036: IN OUT Detect Trigger
Pin Default 0x01016411: [Jack] Line Out at Ext Rear
Conn = 1/8, Color = Orange
DefAssociation = 0x1, Sequence = 0x1
Pin-ctls: 0x40: OUT
Unsolicited: tag=00, enabled=0
Power states: D0 D1 D2 D3 EPSS
Power: setting=D0, actual=D0
Connection: 1
0x0e
Node 0x17 [Pin Complex] wcaps 0x40058d: Stereo Amp-Out
Amp-Out caps: ofs=0x00, nsteps=0x00, stepsize=0x00, mute=1
Amp-Out vals: [0x00 0x00]
Pincap 0x00000036: IN OUT Detect Trigger
Pin Default 0x01012414: [Jack] Line Out at Ext Rear
Conn = 1/8, Color = Grey
DefAssociation = 0x1, Sequence = 0x4
Pin-ctls: 0x40: OUT
Unsolicited: tag=00, enabled=0
Power states: D0 D1 D2 D3 EPSS
Power: setting=D0, actual=D0
Connection: 1
0x0f
Node 0x18 [Pin Complex] wcaps 0x40058f: Stereo Amp-In Amp-Out
Control: name="Mic Boost", index=0, device=0
ControlAmp: chs=3, dir=In, idx=0, ofs=0
Amp-In caps: ofs=0x00, nsteps=0x03, stepsize=0x27, mute=0
Amp-In vals: [0x00 0x00]
Amp-Out caps: ofs=0x00, nsteps=0x00, stepsize=0x00, mute=1
Amp-Out vals: [0x80 0x80]
Pincap 0x00003736: IN OUT Detect Trigger
Vref caps: HIZ 50 GRD 80 100
Pin Default 0x01a19c50: [Jack] Mic at Ext Rear
Conn = 1/8, Color = Pink
DefAssociation = 0x5, Sequence = 0x0
Pin-ctls: 0x24: IN VREF_80
Unsolicited: tag=00, enabled=0
Power states: D0 D1 D2 D3 EPSS
Power: setting=D0, actual=D0
Connection: 5
0x0c* 0x0d 0x0e 0x0f 0x26
Node 0x19 [Pin Complex] wcaps 0x40058f: Stereo Amp-In Amp-Out
Control: name="Front Mic Boost", index=0, device=0
ControlAmp: chs=3, dir=In, idx=0, ofs=0
Amp-In caps: ofs=0x00, nsteps=0x03, stepsize=0x27, mute=0
Amp-In vals: [0x00 0x00]
Amp-Out caps: ofs=0x00, nsteps=0x00, stepsize=0x00, mute=1
Amp-Out vals: [0x80 0x80]
Pincap 0x0000373e: IN OUT HP Detect Trigger
Vref caps: HIZ 50 GRD 80 100
Pin Default 0x02a19c60: [Jack] Mic at Ext Front
Conn = 1/8, Color = Pink
DefAssociation = 0x6, Sequence = 0x0
Pin-ctls: 0x24: IN VREF_80
Unsolicited: tag=00, enabled=0
Power states: D0 D1 D2 D3 EPSS
Power: setting=D0, actual=D0
Connection: 5
0x0c* 0x0d 0x0e 0x0f 0x26
Node 0x1a [Pin Complex] wcaps 0x40058f: Stereo Amp-In Amp-Out
Amp-In caps: ofs=0x00, nsteps=0x03, stepsize=0x27, mute=0
Amp-In vals: [0x00 0x00]
Amp-Out caps: ofs=0x00, nsteps=0x00, stepsize=0x00, mute=1
Amp-Out vals: [0x80 0x80]
Pincap 0x00003736: IN OUT Detect Trigger
Vref caps: HIZ 50 GRD 80 100
Pin Default 0x0181345f: [Jack] Line In at Ext Rear
Conn = 1/8, Color = Blue
DefAssociation = 0x5, Sequence = 0xf
Pin-ctls: 0x20: IN VREF_HIZ
Unsolicited: tag=00, enabled=0
Power states: D0 D1 D2 D3 EPSS
Power: setting=D0, actual=D0
Connection: 5
0x0c* 0x0d 0x0e 0x0f 0x26
Node 0x1b [Pin Complex] wcaps 0x40058f: Stereo Amp-In Amp-Out
Control: name="Headphone Playback Switch", index=0, device=0
ControlAmp: chs=3, dir=Out, idx=0, ofs=0
Amp-In caps: ofs=0x00, nsteps=0x03, stepsize=0x27, mute=0
Amp-In vals: [0x00 0x00]
Amp-Out caps: ofs=0x00, nsteps=0x00, stepsize=0x00, mute=1
Amp-Out vals: [0x00 0x00]
Pincap 0x0000373e: IN OUT HP Detect Trigger
Vref caps: HIZ 50 GRD 80 100
Pin Default 0x02214c20: [Jack] HP Out at Ext Front
Conn = 1/8, Color = Green
DefAssociation = 0x2, Sequence = 0x0
Pin-ctls: 0xc0: OUT HP VREF_HIZ
Unsolicited: tag=00, enabled=0
Power states: D0 D1 D2 D3 EPSS
Power: setting=D0, actual=D0
Connection: 5
0x0c* 0x0d 0x0e 0x0f 0x26
Node 0x1c [Pin Complex] wcaps 0x400481: Stereo
Pincap 0x00000024: IN Detect
Pin Default 0x593301f0: [N/A] CD at Int ATAPI
Conn = ATAPI, Color = Unknown
DefAssociation = 0xf, Sequence = 0x0
Misc = NO_PRESENCE
Pin-ctls: 0x20: IN
Unsolicited: tag=00, enabled=0
Power states: D0 D1 D2 D3 EPSS
Power: setting=D0, actual=D0
Node 0x1d [Pin Complex] wcaps 0x400400: Mono
Pincap 0x00000020: IN
Pin Default 0x4005e601: [N/A] Line Out at Ext N/A
Conn = Optical, Color = White
DefAssociation = 0x0, Sequence = 0x1
Pin-ctls: 0x00:
Power states: D0 D1 D2 D3 EPSS
Power: setting=D0, actual=D0
Node 0x1e [Pin Complex] wcaps 0x400781: Stereo Digital
Pincap 0x00000014: OUT Detect
Pin Default 0x014b6130: [Jack] SPDIF Out at Ext Rear
Conn = Comb, Color = Orange
DefAssociation = 0x3, Sequence = 0x0
Misc = NO_PRESENCE
Pin-ctls: 0x00:
Unsolicited: tag=00, enabled=0
Power states: D0 D1 D2 D3 EPSS
Power: setting=D0, actual=D0
Connection: 1
0x06
Node 0x1f [Pin Complex] wcaps 0x400681: Stereo Digital
Pincap 0x00000024: IN Detect
Pin Default 0x01cb7170: [Jack] SPDIF In at Ext Rear
Conn = Comb, Color = Yellow
DefAssociation = 0x7, Sequence = 0x0
Misc = NO_PRESENCE
Pin-ctls: 0x00:
Unsolicited: tag=00, enabled=0
Power states: D0 D1 D2 D3 EPSS
Power: setting=D0, actual=D0
Node 0x20 [Vendor Defined Widget] wcaps 0xf00040: Mono
Processing caps: benign=0, ncoeff=24
Node 0x21 [Vendor Defined Widget] wcaps 0xf00000: Mono
Node 0x22 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In
Control: name="Input Source", index=0, device=0
Amp-In caps: ofs=0x00, nsteps=0x00, stepsize=0x00, mute=1
Amp-In vals: [0x00 0x00] [0x80 0x80] [0x80 0x80] [0x80 0x80] [0x80
0x80] [0x80 0x80] [0x80 0x80] [0x80 0x80] [0x80 0x80] [0x80 0x80]
[0x80 0x80] [0x80 0x80]
Connection: 12
0x18 0x19 0x1a 0x1b 0x1c 0x1d 0x14 0x15 0x16 0x17 0x0b 0x12
Node 0x23 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In
Control: name="Input Source", index=1, device=0
Amp-In caps: ofs=0x00, nsteps=0x00, stepsize=0x00, mute=1
Amp-In vals: [0x00 0x00] [0x80 0x80] [0x80 0x80] [0x80 0x80] [0x80
0x80] [0x80 0x80] [0x80 0x80] [0x80 0x80] [0x80 0x80] [0x80 0x80]
[0x80 0x80]
Connection: 11
0x18 0x19 0x1a 0x1b 0x1c 0x1d 0x14 0x15 0x16 0x17 0x0b
Node 0x24 [Vendor Defined Widget] wcaps 0xf00000: Mono
Node 0x25 [Audio Output] wcaps 0x41d: Stereo Amp-Out
Amp-Out caps: ofs=0x40, nsteps=0x40, stepsize=0x03, mute=0
Amp-Out vals: [0x40 0x40]
Converter: stream=0, channel=0
PCM:
rates [0x560]: 44100 48000 96000 192000
bits [0xe]: 16 20 24
formats [0x1]: PCM
Power states: D0 D1 D2 D3 EPSS
Power: setting=D0, actual=D0
Node 0x26 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In
Amp-In caps: ofs=0x00, nsteps=0x00, stepsize=0x00, mute=1
Amp-In vals: [0x00 0x00] [0x80 0x80]
Connection: 2
0x25 0x0b
--
To unsubscribe from this list: send the line "unsubscribe alsa-devel" in
the body of a message to majordomo(a)vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
4
13
[alsa-devel] ASoC: Hiding unused CODEC mixer widgets in the machine driver
by Stuart Longland 08 Aug '10
by Stuart Longland 08 Aug '10
08 Aug '10
Hi all,
Work has continued on the TLV320AIC3204 CODEC driver, and there have
been a number of fixes since the last patch was published. However,
this CODEC is a rather complicated beast to drive, some may find the
controls a little unweildy, and as such, I was wondering if the machine
driver could be used to abstract this for a given target?
It's no use abstracting this in the CODEC, because some may want to
access the functionality I'm trying to hide.
The CODEC we're using has three line inputs; which may be treated as
either three mono differential inputs, or three stereo single-ended
inputs. There are also a couple of common-mode sources that may be
connected. The resistances connecting these is selectable; 10k, 20k or
40k... and as such, it's possible to do some hardware mixing of the
sources inside the CODEC.
At the moment I have each of the inputs to the ADC's PGA ("MICPGA"),
with one control for each possible path... There are two ADCs, so two
PGAs... and the inputs can be connected to either the negative or
positive terminal of the PGA in many cases. That leads to a large
number of controls (the following is from amixer):
Simple mixer control 'Left MICPGA+ Output Mixer IN1L',0
Capabilities: enum
Items: 'not-connected' '10k' '20k' '40k'
Item0: 'not-connected'
Simple mixer control 'Left MICPGA+ Output Mixer IN1R',0
Capabilities: enum
Items: 'not-connected' '10k' '20k' '40k'
Item0: 'not-connected'
Simple mixer control 'Left MICPGA+ Output Mixer IN2L',0
Capabilities: enum
Items: 'not-connected' '10k' '20k' '40k'
Item0: 'not-connected'
Simple mixer control 'Left MICPGA+ Output Mixer IN3L',0
Capabilities: enum
Items: 'not-connected' '10k' '20k' '40k'
Item0: '10k'
Simple mixer control 'Left MICPGA- Output Mixer CM1L',0
Capabilities: enum
Items: 'not-connected' '10k' '20k' '40k'
Item0: 'not-connected'
Simple mixer control 'Left MICPGA- Output Mixer CM2L',0
Capabilities: enum
Items: 'not-connected' '10k' '20k' '40k'
Item0: 'not-connected'
Simple mixer control 'Left MICPGA- Output Mixer IN2R',0
Capabilities: enum
Items: 'not-connected' '10k' '20k' '40k'
Item0: 'not-connected'
Simple mixer control 'Left MICPGA- Output Mixer IN3R',0
Capabilities: enum
Items: 'not-connected' '10k' '20k' '40k'
Item0: '10k'
[...]
Simple mixer control 'Right MICPGA+ Output Mixer IN1R',0
Capabilities: enum
Items: 'not-connected' '10k' '20k' '40k'
Item0: '10k'
Simple mixer control 'Right MICPGA+ Output Mixer IN2L',0
Capabilities: enum
Items: 'not-connected' '10k' '20k' '40k'
Item0: 'not-connected'
Simple mixer control 'Right MICPGA+ Output Mixer IN2R',0
Capabilities: enum
Items: 'not-connected' '10k' '20k' '40k'
Item0: 'not-connected'
Simple mixer control 'Right MICPGA+ Output Mixer IN3R',0
Capabilities: enum
Items: 'not-connected' '10k' '20k' '40k'
Item0: '10k'
Simple mixer control 'Right MICPGA- Output Mixer CM1R',0
Capabilities: enum
Items: 'not-connected' '10k' '20k' '40k'
Item0: 'not-connected'
Simple mixer control 'Right MICPGA- Output Mixer CM2R',0
Capabilities: enum
Items: 'not-connected' '10k' '20k' '40k'
Item0: 'not-connected'
Simple mixer control 'Right MICPGA- Output Mixer IN1L',0
Capabilities: enum
Items: 'not-connected' '10k' '20k' '40k'
Item0: '10k'
Simple mixer control 'Right MICPGA- Output Mixer IN3L',0
Capabilities: enum
Items: 'not-connected' '10k' '20k' '40k'
Item0: '10k'
These controls are useful to a machine driver for implementing controls,
but they're not that friendly to an end user. I was wondering if it was
possible to hide these controls from the userland, but expose them to
the machine driver to be presented to the user in a more meaningful
manner. (i.e. we can have just simple mute switches for IN1 and IN3,
labelling them "handset" and "internal mic" in our device).
Or would I be better defining these controls in the machine driver?
Regards,
--
Stuart Longland (aka Redhatter, VK4MSL) .'''.
Gentoo Linux/MIPS Cobalt and Docs Developer '.'` :
. . . . . . . . . . . . . . . . . . . . . . .'.'
http://dev.gentoo.org/~redhatter :.'
I haven't lost my mind...
...it's backed up on a tape somewhere.
3
5
Hi,
This patch serise fix some problems in smdk64xx board when it use
I2S with wm8580.
o ADC source clock setting is set to use MCLK, It makes that
wm8580 cannot make BCLK and LRCLK for playback and capture.
o When application set some sampling freq. - 8kHz, 11.025kHz,
audio doesn't work correctly with broken sound. Because
wm8580 always set BCLK_RATE and LRCLK_RATE as a default value
, BCLK_RATE - 256fs and LRCLK_RATE - 64 BCLKs per LRCLK. So,
BCLK_RATE and LRCLK_RATE setting on wm8580 is not match to
make these sampling freq. on wm8580 master mode.
So, to solve these problems, this patch apply followings:
o Support ADC source clock setting on wm8580.
o Enable to select BCLK_RATE and LRCLK_RATE value on wm8580.
o Fix smdk-wm8580 machine code to support new features of wm8580.
The following patch series contains:
[PATCH 1/5] ASoC: wm8580: Add to support ADC clock source setting
[PATCH 2/5] ASoC: S3C64XX: Add ADC source clock setting
[PATCH 3/5] ASoC: wm8580: Fix Master Mode BCLK rates names
[PATCH 4/5] ASoC: wm8580: Add to support Master Mode Rates
[PATCH 5/5] ASoC: S3C64XX: Fix to support BCLK, LRCLK rates setting
Thanks,
Claude
4
18
[alsa-devel] mudita24 1.02 -- improved envy24control mixer/router for ice1712-based sound-cards
by Niels Mayer 08 Aug '10
by Niels Mayer 08 Aug '10
08 Aug '10
The "Mudita24" package is a modification of alsa-tools' envy24control:
an application controlling the digital mixer, channel gains and other
hardware settings for sound cards based on the ice1712 chipset (
http://alsa.cybermirror.org/manuals/icensemble/envy24.pdf ). It
also displays a level meter for each input and output channel and
maintains peak level indicators. This utility is preferable to
alsamixer(1) for those with ice1712-based cards: M-Audio Delta 1010,
Delta 1010LT, Delta DiO 2496, Delta 66, Delta 44, Delta 410 and
Audiophile 2496. TerraTec EWS 88MT, EWS 88D, EWX 24/96, DMX 6Fire,
Phase 88. Hoontech SoundTrack DSP 24, SoundTrack DSP 24 Value,
SoundTrack DSP 24 Media 7.1. Event Electronics EZ8. Digigram VX442.
Lionstracs, Mediastaton. Terrasoniq TS 88. Partial support for
Roland/Edirol DA-2496.
Now available, version 1.02:
source: http://nielsmayer.com/envy24control/mudita24-1.0.2.tar.gz
binary: http://nielsmayer.com/envy24control/mudita24-1.0.2.x86_64.tgz
patch: http://nielsmayer.com/envy24control/mudita24-envy24control-0.6-to-1.0.2.pat…
'envy24control' is part of the "alsa-tools" package. For example,
under CCRMA's Fedora repos, it's part of
alsa-tools-1.0.22-1.1.fc12.ccrma.x86_64. This "mudita24" package
updates/replaces the alsa-tools /usr/bin/envy24control application.
The default "./configure ; make ; sudo make install" process on the
source-code leaves a binary in /usr/local/bin/envy24control and places
the man-page in /usr/local/man/man1/envy24control.1 . This means you
can still use the standard alsa-tools version in
/usr/bin/envy24control .
Screenshots (controlling either Terratec DMX6Fire or M-Audio Delta 66):
http://nielsmayer.com/envy24control/Mudita24-102-Monitor-Inputs.png
http://nielsmayer.com/envy24control/Mudita24-102-Monitor-Outputs.png
http://nielsmayer.com/envy24control/Mudita24-102-Patchbay+Router.png
http://nielsmayer.com/envy24control/Mudita24-102-Hardware-Settings.png
http://nielsmayer.com/envy24control/Mudita24-102-Analog-Volume.png
http://nielsmayer.com/envy24control/Mudita24-102-About.png
Changes since recent 1.0.0 and 1.0.1 releases:
* Peak-meter display is in dBFS, corresponding to displayed dBFS
peak-meter value and scale-widget dB labeling.
* Hardware mixer input attenuators provide more precise control to the
0 to -48dB range of adjustment, turning the associated input "off"
when the slider is moved to bottom of the scale. External MIDI control
of the hardware mixer via --midichannel and --midienhanced options
unaffected by this change.
* For M-Audio Delta series, add display of "Delta IEC958 Input Status"
under "Hardware Settings."
* Command line options --no_scale_mark, --channel_group_modulus affect
layout and presence of dB markings for sliders.
--channel_group_modulus allows override of Left/Right grouping of dB
labels for multichannel applications.
* Control of peak-meter coloring via --lights_color and --bg_color
options. Reasonable default colors used when these options are not
set. (1.0.1's use of Gtk skin to provide an automatic color choice
didn't work out that well on some systems.)
* Fixed command-line options --card and --device to allow valid ALSA
card and CTL device names
( https://bugzilla.redhat.com/show_bug.cgi?id=602900 ).
* Profiles created in ~/.envy24control and not "~/envy24control"
( http://bugtrack.alsa-project.org/alsa-bug/view.php?id=4738 ).
Summary of previous updates from envy24control 0.6.0 (GIT HEAD) to "1.0.2":
(1) Implemented "Peak Hold" functionality in meters; reimplemented
meters to do away with inefficient "faux LED" peak-meter display.
(2) Significantly reduced the number of timer interrupts generated by
this program by slowing down all updates to 10 per second --
previously meters updated 25x/second!
(3) All volumes are represented as decibels, including the 0 to -48dB
range of the hardware peak-meters, the 0 -to- -48dB&off attenuation
for all inputs to the digital mixer, the 0 -to- -63dB attenuation of
the analog DAC, and the +18 -to- -63dB attenuation/amplification of
the analog ADC.
(4) All gtk "scale" widgets have dB legends; the "PageUp" "PageDown"
keys allow rapid movement between the marked levels, and "UpArrow" and
"DownArrow" allow fine-adjustment.
Niels
http://nielsmayer.com
PS: Why "mudita24" ? An alternate name to avoid confusion with
"envy24control 0.6.0" until changes in this version propagate
upstream. See http://en.wikipedia.org/wiki/Envy#In_philosophy "In
Buddhism the third of the four divine abidings is mudita, taking joy
in the good fortune of another. This virtue is considered the antidote
to envy and the opposite of schadenfreude."
2
1
From: Cliff Cai <cliff.cai(a)analog.com>
Signed-off-by: Cliff Cai <cliff.cai(a)analog.com>
Signed-off-by: Mike Frysinger <vapier(a)gentoo.org>
---
sound/soc/codecs/Kconfig | 4 +
sound/soc/codecs/Makefile | 2 +
sound/soc/codecs/adau1361.c | 992 +++++++++++++++++++++++++++++++++++++++++++
sound/soc/codecs/adau1361.h | 264 ++++++++++++
4 files changed, 1262 insertions(+), 0 deletions(-)
create mode 100644 sound/soc/codecs/adau1361.c
create mode 100644 sound/soc/codecs/adau1361.h
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index ae01cba..f37d5f4 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -16,6 +16,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_AD193X if SND_SOC_I2C_AND_SPI
select SND_SOC_AD1980 if SND_SOC_AC97_BUS
select SND_SOC_AD73311 if I2C
+ select SND_SOC_ADAU1361 if I2C
select SND_SOC_ADAV80X if SND_SOC_I2C_AND_SPI
select SND_SOC_ADS117X
select SND_SOC_AK4104 if SPI_MASTER
@@ -104,6 +105,9 @@ config SND_SOC_AD1980
config SND_SOC_AD73311
tristate
+config SND_SOC_ADAU1361
+ tristate
+
config SND_SOC_ADAV80X
tristate
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index f5b3d5b..d05b672 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -3,6 +3,7 @@ snd-soc-ad1836-objs := ad1836.o
snd-soc-ad193x-objs := ad193x.o
snd-soc-ad1980-objs := ad1980.o
snd-soc-ad73311-objs := ad73311.o
+snd-soc-adau1361-objs := adau1361.o
snd-soc-adav80x-objs := adav80x.o
snd-soc-ads117x-objs := ads117x.o
snd-soc-ak4104-objs := ak4104.o
@@ -70,6 +71,7 @@ obj-$(CONFIG_SND_SOC_AD1836) += snd-soc-ad1836.o
obj-$(CONFIG_SND_SOC_AD193X) += snd-soc-ad193x.o
obj-$(CONFIG_SND_SOC_AD1980) += snd-soc-ad1980.o
obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o
+obj-$(CONFIG_SND_SOC_ADAU1361) += snd-soc-adau1361.o
obj-$(CONFIG_SND_SOC_ADAV80X) += snd-soc-adav80x.o
obj-$(CONFIG_SND_SOC_ADS117X) += snd-soc-ads117x.o
obj-$(CONFIG_SND_SOC_AK4104) += snd-soc-ak4104.o
diff --git a/sound/soc/codecs/adau1361.c b/sound/soc/codecs/adau1361.c
new file mode 100644
index 0000000..ad78420
--- /dev/null
+++ b/sound/soc/codecs/adau1361.c
@@ -0,0 +1,992 @@
+/*
+ * Driver for ADAU1361 sound codec
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/workqueue.h>
+#include <linux/platform_device.h>
+#include <linux/sysfs.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+
+#include "adau1361.h"
+
+#define AUDIO_NAME "adau1361"
+#define ADAU1361_VERSION "0.1"
+
+#define CAP_MIC 1
+#define CAP_LINE 2
+#define CAPTURE_SOURCE_NUMBER 2
+
+struct snd_soc_codec_device soc_codec_dev_adau1361;
+static struct snd_soc_codec *adau1361_codec;
+/* codec private data */
+struct adau1361_priv {
+ unsigned int sysclk;
+ unsigned int in_source;
+ unsigned int out_route;
+ unsigned int pll_out;
+ struct work_struct resume_work;
+ struct snd_soc_codec codec;
+ int dapm_state_suspend;
+ struct platform_device *pdev;
+ u8 pll_enable;
+ u8 adau1361_pll_reg[6];
+ u8 rate_index;
+ /* dapm */
+ u8 dapm_lineL;
+ u8 dapm_lineR;
+ u8 dapm_hpL;
+ u8 dapm_hpR;
+};
+
+/*
+ * write register cache
+ */
+static inline int adau1361_write_reg_cache(struct snd_soc_codec *codec,
+ unsigned int reg, unsigned int value)
+{
+ u8 *cache = codec->reg_cache;
+
+ if (reg < ADAU_FIRSTREG)
+ reg = reg + ADAU_FIRSTREG;
+
+ if ((reg < ADAU_FIRSTREG) || (reg > ADAU_LASTREG))
+ return -1;
+
+ cache[reg - ADAU_FIRSTREG] = value;
+
+ return 0;
+}
+
+/*
+ * read a multi-byte ADAU1361 register (6byte pll reg)
+ */
+static int adau1361_read_reg_block(struct snd_soc_codec *codec,
+ unsigned int reg, u8 len)
+{
+ u8 buf[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+ u8 addr[2];
+ unsigned int i;
+
+ if (reg < ADAU_FIRSTREG)
+ reg = reg + ADAU_FIRSTREG;
+
+ if ((reg < ADAU_FIRSTREG) || (reg > ADAU_LASTREG))
+ return -EIO;
+
+ addr[0] = (u8)(reg >> 8);
+ addr[1] = (u8)(reg & 0xFF);
+
+ /* write the 2byte read address */
+ if (codec->hw_write(codec->control_data, addr, 2) != 2) {
+ dev_err(codec->dev, "read_reg_byte:address write failed.");
+ return -EIO;
+ }
+
+ if (i2c_master_recv(codec->control_data, buf, len) != len)
+ return -EIO;
+
+ for (i = 0; i < len; i++)
+ adau1361_write_reg_cache(codec, reg+i, (unsigned int)buf[i]);
+
+ return 0;
+}
+
+/*
+ * write a multibyte ADAU1361 register (6byte pll reg)
+ */
+static int adau1361_write_reg_block(struct snd_soc_codec *codec,
+ unsigned int reg, u8 length, u8 *values)
+{
+ int count = length + 2; /*data plus 16bit register address*/
+ u8 buf[8] = {0, 0, 0, 0, 0, 0, 0, 0};
+
+ buf[0] = (u8)(reg >> 8);
+ buf[1] = (u8)(reg & 0xFF);
+
+ if (length > 0)
+ memcpy(&buf[2], values, length);
+
+ if (codec->hw_write(codec->control_data, buf, count) == count)
+ return 0;
+ else {
+ dev_err(codec->dev, "address block write failed.");
+ return -EIO;
+ }
+}
+
+/*
+ * adau1361 controls
+ */
+static int adau1361_mux_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct adau1361_priv *adau1361 = codec->private_data;
+
+ if (adau1361->in_source & CAP_MIC)
+ ucontrol->value.integer.value[0] = 0x0;
+ else
+ ucontrol->value.integer.value[0] = 0x1;
+
+ return 0;
+}
+
+static int adau1361_mux_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct adau1361_priv *adau1361 = codec->private_data;
+ int src = ucontrol->value.integer.value[0];
+ u8 regvalue = 0;
+
+ if (src == 0) {/* Select Mic */
+ adau1361->in_source = CAP_MIC;
+#ifdef ADAU1361_DIG_MIC
+ regvalue = (snd_soc_read(codec, ADAU_ADCCTL0) & 0xFB)|0x4;
+ snd_soc_write(codec, ADAU_ADCCTL0, regvalue);
+#else
+ snd_soc_write(codec, ADAU_RECMBIA, RECMBIA_DISABLE);
+ regvalue = (snd_soc_read(codec, ADAU_RECVLCL)
+ | RECVLC_ENABLE_MASK);
+ snd_soc_write(codec, ADAU_RECVLCL, regvalue);
+ regvalue = (snd_soc_read(codec, ADAU_RECVLCR)
+ | RECVLC_ENABLE_MASK);
+ snd_soc_write(codec, ADAU_RECVLCR, regvalue);
+ snd_soc_write(codec, ADAU_RECMLC1, RECMLC_MIC_0DB);
+ snd_soc_write(codec, ADAU_RECMRC1, RECMLC_MIC_0DB);
+#endif
+ } else if (src == 1) {/* Select Line */
+ adau1361->in_source = CAP_LINE;
+#ifdef ADAU1361_DIG_MIC
+ regvalue = (snd_soc_read(codec, ADAU_ADCCTL0) & 0xFB);
+ snd_soc_write(codec, ADAU_ADCCTL0, regvalue);
+#endif
+ snd_soc_write(codec, ADAU_RECMBIA, RECMBIA_DISABLE);
+ regvalue = (snd_soc_read(codec, ADAU_RECVLCL)
+ & RECVLC_DISABLE_MASK);
+ snd_soc_write(codec, ADAU_RECVLCL, regvalue);
+ regvalue = (snd_soc_read(codec, ADAU_RECVLCR)
+ & RECVLC_DISABLE_MASK);
+ snd_soc_write(codec, ADAU_RECVLCR, regvalue);
+ snd_soc_write(codec, ADAU_RECMLC1, RECMLC_LINE_0DB);
+ snd_soc_write(codec, ADAU_RECMRC1, RECMLC_LINE_0DB);
+ }
+
+ return 0;
+}
+
+static int adau1361_mic_boost_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct adau1361_priv *adau1361 = codec->private_data;
+
+ if (adau1361->in_source & CAP_MIC)
+ ucontrol->value.integer.value[0] =
+ (RECMLC_MIC_20DB ==
+ snd_soc_read(codec, ADAU_RECMLC1));
+ else
+ ucontrol->value.integer.value[0] = 0x0;
+
+ ucontrol->value.integer.value[1] = ucontrol->value.integer.value[0];
+
+ return 0;
+}
+
+static int adau1361_mic_boost_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct adau1361_priv *adau1361 = codec->private_data;
+ int val = ucontrol->value.integer.value[0];
+ u8 regvalue = 0;
+
+ if (adau1361->in_source & CAP_MIC) {
+ regvalue = (val) ? RECMLC_MIC_20DB : RECMLC_MIC_0DB;
+ if (snd_soc_read(codec, ADAU_RECMLC1) != regvalue) {
+ snd_soc_write(codec, ADAU_RECMLC1, regvalue);
+ snd_soc_write(codec, ADAU_RECMRC1, regvalue);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static const char *adau1361_input_select[] = {"Mic", "Line"};
+static const struct soc_enum adau1361_enums[] = {
+ SOC_ENUM_SINGLE(ADAU_RECMLC1, 0, 2, adau1361_input_select),
+};
+
+static const struct snd_kcontrol_new adau1361_snd_controls[] = {
+SOC_DOUBLE_R("Master Playback Volume", ADAU_DACCTL1,
+ ADAU_DACCTL2, 0, 255, 1),
+SOC_DOUBLE_R("Capture Volume", ADAU_ADCCTL1,
+ ADAU_ADCCTL2, 0, 255, 1),
+SOC_DOUBLE_R("Capture Switch", ADAU_RECMLC0,
+ ADAU_RECMRC0, 0, 1, 0),
+SOC_ENUM_EXT("Capture Source", adau1361_enums[0],
+ adau1361_mux_get, adau1361_mux_put),
+SOC_SINGLE_EXT("Mic Boost (+20dB)", ADAU_RECMLC1, 0, 1, 0,
+ adau1361_mic_boost_get, adau1361_mic_boost_put),
+SOC_DOUBLE_R("Headphone Playback Volume", ADAU_PLBHPVL,
+ ADAU_PLBHPVR, 2, 63, 0),
+SOC_DOUBLE_R("Line Playback Volume", ADAU_PLBLOVL,
+ ADAU_PLBLOVR, 2, 63, 0),
+};
+
+/*
+ * _DAPM_
+ */
+
+static int adau1361_mute(struct snd_soc_dai *dai, int mute)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ u8 reg = 0;
+
+ if (mute) {
+ /* mute inputs */
+ reg = (snd_soc_read(codec, ADAU_RECMLC0) & 0xFE) | 0x0;
+ snd_soc_write(codec, ADAU_RECMLC0, reg);
+ reg = (snd_soc_read(codec, ADAU_RECMRC0) & 0xFE) | 0x0;
+ snd_soc_write(codec, ADAU_RECMRC0, reg);
+ /* mute outputs */
+ reg = (snd_soc_read(codec, ADAU_PLBMLC0) & 0xFE) | 0x1;
+ snd_soc_write(codec, ADAU_PLBMLC0, reg);
+ reg = (snd_soc_read(codec, ADAU_PLBMRC0) & 0xFE) | 0x1;
+ snd_soc_write(codec, ADAU_PLBMRC0, reg);
+
+ } else {
+ /* un-mute outputs, according to the spec,
+ we should enable mixer3 and mixer4 here,
+ but it seems that things are converse here.
+ */
+ reg = (snd_soc_read(codec, ADAU_PLBMLC0) & 0xFE) | 0x0;
+ snd_soc_write(codec, ADAU_PLBMLC0, reg);
+ reg = (snd_soc_read(codec, ADAU_PLBMRC0) & 0xFE) | 0x0;
+ snd_soc_write(codec, ADAU_PLBMRC0, reg);
+ /* un-mute inputs */
+ reg = (snd_soc_read(codec, ADAU_RECMLC0) & 0xFE) | 0x1;
+ snd_soc_write(codec, ADAU_RECMLC0, reg);
+ reg = (snd_soc_read(codec, ADAU_RECMRC0) & 0xFE) | 0x1;
+ snd_soc_write(codec, ADAU_RECMRC0, reg);
+ }
+
+ return 0;
+}
+
+/* Left Mixer */
+static const struct snd_kcontrol_new adau1361_left_mixer_controls[] = {
+SOC_DAPM_SINGLE("LineLeft Bypass Switch", ADAU_PLBLOVL, 1, 1, 0),
+SOC_DAPM_SINGLE("HPLeft Bypass Switch", ADAU_PLBHPVL, 1, 1, 0),
+};
+
+/* Right mixer */
+static const struct snd_kcontrol_new adau1361_right_mixer_controls[] = {
+SOC_DAPM_SINGLE("LineRight Bypass Switch", ADAU_PLBLOVR, 1, 1, 0),
+SOC_DAPM_SINGLE("HPRight Bypass Switch", ADAU_PLBHPVR, 1, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget adau1361_dapm_widgets[] = {
+
+SND_SOC_DAPM_MIXER("Left Mixer", ADAU_PLBPWRM, 2, 1, \
+ &adau1361_left_mixer_controls[0], ARRAY_SIZE(adau1361_left_mixer_controls)),
+SND_SOC_DAPM_MIXER("Left Out", ADAU_PLBPWRM, 0, 0, NULL, 0),
+SND_SOC_DAPM_MIXER("Left Line Mixer", ADAU_PLBMLLO, 0, 0, NULL, 0),
+SND_SOC_DAPM_OUTPUT("LOUT"),
+SND_SOC_DAPM_OUTPUT("LHPOUT"),
+
+SND_SOC_DAPM_MIXER("Right Mixer", ADAU_PLBPWRM, 3, 1, \
+ &adau1361_right_mixer_controls[0], ARRAY_SIZE(adau1361_right_mixer_controls)),
+SND_SOC_DAPM_MIXER("Right Out", ADAU_PLBPWRM, 1, 0, NULL, 0),
+SND_SOC_DAPM_MIXER("Right Line Mixer", ADAU_PLBMRLO, 0, 0, NULL, 0),
+SND_SOC_DAPM_OUTPUT("ROUT"),
+SND_SOC_DAPM_OUTPUT("RHPOUT"),
+
+SND_SOC_DAPM_DAC("DAC", "Playback", SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_MIXER("DAC Enable Left", ADAU_DACCTL0, 0, 0, NULL, 0),
+SND_SOC_DAPM_MIXER("DAC Enable Right", ADAU_DACCTL0, 1, 0, NULL, 0),
+SND_SOC_DAPM_MIXER("HP Bias Left", ADAU_PLBPWRM, 6, 1, NULL, 0),
+SND_SOC_DAPM_MIXER("HP Bias Right", ADAU_PLBLRMC, 0, 0, NULL, 0),
+
+SND_SOC_DAPM_ADC("ADC", "Capture", SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_MIXER("ADC Left", ADAU_ADCCTL0, 0, 0, NULL, 0),
+SND_SOC_DAPM_MIXER("ADC Right", ADAU_ADCCTL0, 1, 0, NULL, 0),
+
+#if !defined(ADAU1361_DIG_MIC)
+SND_SOC_DAPM_MICBIAS("Mic Bias", ADAU_RECMBIA, 0, 0),
+SND_SOC_DAPM_MIXER("Left Mic Mixer", ADAU_RECVLCL, 0, 0, NULL, 0),
+SND_SOC_DAPM_MIXER("Right Mic Mixer", ADAU_RECVLCR, 0, 0, NULL, 0),
+#else
+SND_SOC_DAPM_MICBIAS("Mic Bias Left", SND_SOC_NOPM, 1, 0),
+SND_SOC_DAPM_MICBIAS("Mic Bias Right", SND_SOC_NOPM, 1, 0),
+SND_SOC_DAPM_MIXER("Left Mic Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_MIXER("Right Mic Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+#endif
+
+SND_SOC_DAPM_MIXER("Left Input", ADAU_RECPWRM, 1, 1, NULL, 0),
+SND_SOC_DAPM_MIXER("Right Input", ADAU_RECPWRM, 2, 1, NULL, 0),
+
+SND_SOC_DAPM_INPUT("LMICIN"),
+SND_SOC_DAPM_INPUT("RMICIN"),
+SND_SOC_DAPM_INPUT("LLINEIN"),
+SND_SOC_DAPM_INPUT("RLINEIN"),
+};
+
+static const struct snd_soc_dapm_route audio_conns[] = {
+ /* DAC */
+ {"DAC Enable Left", NULL, "DAC"},
+ {"DAC Enable Right", NULL, "DAC"},
+
+ /* mixers */
+ {"Left Mixer", NULL, "DAC Enable Left"},
+ {"Right Mixer", NULL, "DAC Enable Right"},
+
+ /* outputs */
+ {"Left Out", NULL, "Left Mixer"},
+ {"Right Out", NULL, "Right Mixer"},
+
+ /* line Out */
+ {"Left Line Mixer", NULL, "Left Out"},
+ {"Right Line Mixer", NULL, "Right Out"},
+ {"LOUT", "LineLeft Bypass Switch", "Left Line Mixer"},
+ {"ROUT", "LineRight Bypass Switch", "Right Line Mixer"},
+
+ /* headphone out */
+ {"HP Bias Left", NULL, "Left Out"},
+ {"HP Bias Right", NULL, "Right Out"},
+ {"LHPOUT", "HPLeft Bypass Switch", "HP Bias Left"},
+ {"RHPOUT", "HPRight Bypass Switch", "HP Bias Right"},
+
+ /* inputs */
+ {"Left Input", NULL, "LLINEIN"},
+ {"Right Input", NULL, "RLINEIN"},
+ {"ADC Left", NULL, "Left Input"},
+ {"ADC Right", NULL, "Right Input"},
+ {"ADC Left", NULL, "Left Mic Mixer"},
+ {"ADC Right", NULL, "Right Mic Mixer"},
+ {"ADC", NULL, "ADC Left"},
+ {"ADC", NULL, "ADC Right"},
+
+};
+
+static int adau1361_add_widgets(struct snd_soc_codec *codec)
+{
+ snd_soc_dapm_new_controls(codec, adau1361_dapm_widgets,
+ ARRAY_SIZE(adau1361_dapm_widgets));
+
+ snd_soc_dapm_add_routes(codec, audio_conns, ARRAY_SIZE(audio_conns));
+
+ return 0;
+}
+
+/* PLL dividors */
+struct _pll_div {
+ u32 mclk;
+ u32 pll_freq;
+ u16 den;
+ u16 num;
+ u8 param;
+};
+
+static const struct _pll_div clock_dividers[] = {
+ { 12000000, 45158400, 625, 477, /*44.1kHz*/
+ (PLLCTRL_INTPART_R3|PLLCTRL_INPUT_DIV1|PLLCTRL_TYPE_FRAC) },
+ {12000000, 49152000, 125, 12, /*48kHz*/
+ (PLLCTRL_INTPART_R4|PLLCTRL_INPUT_DIV1|PLLCTRL_TYPE_FRAC) },
+ {12288000, 45158400, 40, 27, /*44.1Khz*/
+ (PLLCTRL_INTPART_R3|PLLCTRL_INPUT_DIV1|PLLCTRL_TYPE_FRAC) },
+ {12288000, 49152000, 0, 0, /*48kHz*/
+ (PLLCTRL_INTPART_R4|PLLCTRL_INPUT_DIV1|PLLCTRL_TYPE_INT) },
+};
+
+static inline int get_pll_settings(int mclk, int pll_out)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(clock_dividers); i++) {
+ if (clock_dividers[i].mclk == mclk
+ && clock_dividers[i].pll_freq == pll_out)
+ return i;
+ }
+ return 0;
+}
+
+static int adau1361_pll_init(struct snd_soc_codec *codec)
+{
+ struct adau1361_priv *adau1361 = codec->private_data;
+ u8 *pll_reg = adau1361->adau1361_pll_reg;
+ int ix = 0;
+
+ /* Init ADAU1361 clocking */
+ snd_soc_write(codec, ADAU_CLKCTRL,
+ (CLKCTRL_SRC_PLL | CLKCTRL_FRQ_1024 | CLKCTRL_DISABLE));
+
+ ix = get_pll_settings(adau1361->sysclk, adau1361->pll_out);
+
+ pll_reg[0] = (clock_dividers[ix].den >> 8);
+ pll_reg[1] = (clock_dividers[ix].den & 0xFF);
+ pll_reg[2] = (clock_dividers[ix].num >> 8);
+ pll_reg[3] = (clock_dividers[ix].num & 0xFF);
+ pll_reg[4] = clock_dividers[ix].param;
+ pll_reg[5] = PLLCTRL_DISABLE;
+ adau1361_write_reg_block(codec, ADAU_PLLCTRL, 6, pll_reg);
+
+ adau1361->pll_enable = 0;
+
+ return 0;
+}
+
+static int adau1361_pll_enable(struct snd_soc_codec *codec, int enable)
+{
+ struct adau1361_priv *adau1361 = codec->private_data;
+ u8 *pll_reg = adau1361->adau1361_pll_reg;
+ int counter = 0;
+
+ if (enable) {
+ pll_reg[5] = PLLCTRL_ENABLE;
+ adau1361_write_reg_block(codec, ADAU_PLLCTRL, 6, pll_reg);
+
+ /* wait for PLL lock*/
+ do {
+ ++counter;
+ schedule_timeout_interruptible(msecs_to_jiffies(1));
+ adau1361_read_reg_block(codec, ADAU_PLLCTRL, 6);
+ } while (0 == (snd_soc_read(codec, ADAU_PLLCTRL + 5) & 0x2)
+ && counter < 20);
+ if (counter >= 20)
+ return -1;
+
+ adau1361->pll_enable = 1;
+
+ /* Init ADAU1361 clocking */
+ snd_soc_write(codec, ADAU_CLKCTRL,
+ (CLKCTRL_SRC_PLL | CLKCTRL_FRQ_1024 | CLKCTRL_ENABLE));
+ }
+
+ return 0;
+
+}
+
+static int adau1361_reg_init(struct snd_soc_codec *codec)
+{
+ struct adau1361_mode_register regdata;
+ struct adau1361_mode_register *registers = 0;
+ int i;
+#ifdef ADAU1361_DIG_MIC
+ int mode = 1;
+#else /* analog mic */
+ int mode = 0;
+#endif
+ adau1361_pll_init(codec);
+ adau1361_pll_enable(codec, 1);
+ /* Load deault regsiter settings */
+ for (i = 0; i < RESET_REGISTER_COUNT; ++i) {
+ regdata = adau1361_reset[i];
+ snd_soc_write(codec, regdata.regaddress, regdata.regvalue);
+ }
+ /* Load mode registers */
+ registers = adau1361_mode_registers[mode];
+ for (i = 0; i < MODE_REGISTER_COUNT; ++i) {
+ regdata = registers[i];
+ snd_soc_write(codec, regdata.regaddress, regdata.regvalue);
+ }
+ /* unmute outputs */
+ snd_soc_write(codec, ADAU_PLBHPVL, DAPM_HP_DEF);
+ snd_soc_write(codec, ADAU_PLBHPVR, DAPM_HP_DEF);
+ snd_soc_write(codec, ADAU_PLBLOVL, DAPM_LINE_DEF);
+ snd_soc_write(codec, ADAU_PLBLOVR, DAPM_LINE_DEF);
+
+ return 0;
+}
+
+struct _srate_set {
+ int fs;
+ u8 reg;
+};
+
+static const struct _srate_set srate_iface[] = {
+ {8000, 0x1},
+ {11025, 0x2},
+ {12000, 0x2},
+ {16000, 0x3},
+ {22050, 0x4},
+ {24000, 0x4},
+ {32000, 0x5},
+ {44100, 0x0},
+ {48000, 0x0},
+ {88200, 0x6},
+ {96000, 0x6},
+};
+
+static int adau1361_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_device *socdev = rtd->socdev;
+ struct snd_soc_codec *codec = socdev->card->codec;
+ struct adau1361_priv *adau1361 = codec->private_data;
+ int rate = params_rate(params);
+ int i;
+
+ /* initialize the PLL */
+ if (adau1361_pll_init(codec) != 0)
+ return -EINVAL;
+ for (i = 0; i < ARRAY_SIZE(srate_iface); i++) {
+ if (srate_iface[i].fs == rate) {
+ adau1361->rate_index = i;
+ break;
+ }
+ }
+ return 0;
+}
+
+static int adau1361_pcm_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_device *socdev = rtd->socdev;
+ struct snd_soc_codec *codec = socdev->card->codec;
+ struct adau1361_priv *adau1361 = codec->private_data;
+ u8 reg = 0;
+ int ret = 0;
+
+ reg = srate_iface[adau1361->rate_index].reg;
+ ret = adau1361_pll_enable(codec, 1);
+ if (ret)
+ dev_err(codec->dev, "Failed to initialize PLL");
+
+ reg = (snd_soc_read(codec, ADAU_CONVCT0) & 0xF8) | reg;
+ snd_soc_write(codec, ADAU_CONVCT0, reg);
+
+ return ret;
+}
+
+static void adau1361_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_device *socdev = rtd->socdev;
+ struct snd_soc_codec *codec = socdev->card->codec;
+ u8 reg;
+
+ if (!codec->active) {
+ reg = snd_soc_read(codec, ADAU_CLKCTRL);
+ snd_soc_write(codec, ADAU_CLKCTRL, reg & ~0x1);
+ }
+}
+
+static int adau1361_set_dai_fmt(struct snd_soc_dai *codec_dai,
+ unsigned int fmt)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ u8 reg = 0;
+
+ /* set master/slave audio interface */
+ reg = (snd_soc_read(codec, ADAU_SPRTCT0) & 0xFE);
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM: /*master*/
+ reg |= 0x1;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS: /*slave*/
+ reg &= ~0x1;
+ break;
+ default:
+ return 0;
+ }
+
+ /* interface format */
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ break;
+ /* TODO: support TDM */
+ default:
+ return 0;
+ }
+
+ /* clock inversion */
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ /* TODO: support signal inversions */
+ default:
+ return 0;
+ }
+
+ /* set I2S iface format*/
+ snd_soc_write(codec, ADAU_SPRTCT0, reg);
+ return 0;
+}
+
+/*
+ * Clock after PLL and dividers
+ */
+static int adau1361_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct adau1361_priv *adau1361 = codec->private_data;
+
+ switch (freq) {
+ case 12000000:
+ adau1361->sysclk = freq;
+ return 0;
+ case 12288000:
+ adau1361->sysclk = freq;
+ return 0;
+ }
+
+ /* supported 12MHz MCLK only for now */
+ return -EINVAL;
+}
+
+static int adau1361_set_dai_pll(struct snd_soc_dai *codec_dai,
+ int pll_id, int source, unsigned int freq_in, unsigned int freq_out)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct adau1361_priv *adau1361 = codec->private_data;
+
+ /* fixed MCLK only supported for now */
+ if (adau1361->sysclk != freq_in)
+ return -EINVAL;
+
+ /* Only update pll when freq changes */
+ if (adau1361->pll_enable && adau1361->pll_out == freq_out)
+ return 0;
+
+ switch (freq_out) {
+ case 45158400:
+ adau1361->pll_out = freq_out;
+ break;
+ case 49152000:
+ adau1361->pll_out = freq_out;
+ break;
+ default:
+ dev_err(codec->dev, "adau1361_set_dai_pll: undefined pll freq:%d", freq_out);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+
+static int adau1361_set_bias_level(struct snd_soc_codec *codec,
+ enum snd_soc_bias_level level)
+{
+
+ switch (level) {
+ case SND_SOC_BIAS_ON:
+ break;
+ case SND_SOC_BIAS_PREPARE:
+ break;
+ case SND_SOC_BIAS_STANDBY:
+ snd_soc_write(codec, ADAU_CLKCTRL,
+ (CLKCTRL_SRC_PLL | CLKCTRL_FRQ_1024 | CLKCTRL_DISABLE));
+ break;
+ case SND_SOC_BIAS_OFF:
+ /* everything off, dac mute, inactive */
+ snd_soc_write(codec, ADAU_RECPWRM, RECPWRM_LOW_PWR);
+ snd_soc_write(codec, ADAU_PLBPWRM, PLBPWRM_LOW_PWR);
+ snd_soc_write(codec, ADAU_PLBCTRL, PLBCTRL_POP_OFF);
+ snd_soc_write(codec, ADAU_CLKCTRL,
+ (CLKCTRL_SRC_PLL | CLKCTRL_FRQ_1024 | CLKCTRL_DISABLE));
+ break;
+
+ }
+ codec->bias_level = level;
+ return 0;
+}
+
+#define ADAU1361_RATES (SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_22050 |\
+ SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_88200 |\
+ SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\
+ SNDRV_PCM_RATE_96000)
+
+#define ADAU1361_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_ops adau1361_dai_ops = {
+ .hw_params = adau1361_hw_params,
+ .prepare = adau1361_pcm_prepare,
+ .shutdown = adau1361_shutdown,
+ .digital_mute = adau1361_mute,
+ .set_fmt = adau1361_set_dai_fmt,
+ .set_sysclk = adau1361_set_dai_sysclk,
+ .set_pll = adau1361_set_dai_pll,
+};
+
+struct snd_soc_dai adau1361_dai = {
+ .name = "ADAU1361",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = ADAU1361_RATES,
+ .formats = ADAU1361_FORMATS,
+ },
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = ADAU1361_RATES,
+ .formats = ADAU1361_FORMATS,
+ },
+ .ops = &adau1361_dai_ops,
+};
+EXPORT_SYMBOL_GPL(adau1361_dai);
+
+static int adau1361_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_codec *codec = socdev->card->codec;
+
+ adau1361_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ return 0;
+}
+
+static void adau1361_resume_wq_handler(struct work_struct *work)
+{
+ struct adau1361_priv *adau1361 = container_of(work, struct adau1361_priv, resume_work);
+ struct snd_soc_codec *codec = &adau1361->codec;
+ unsigned int i, v;
+
+ adau1361_pll_init(codec);
+ adau1361_pll_enable(codec, 1);
+
+ /* sync reg_cache with the hardware */
+ for (i = ADAU_FIRSTREG; i <= ADAU_LASTREG; ++i) {
+ /* skip over the 6byte PLL control register */
+ if (i >= ADAU_PLLCTRL && i < ADAU_MICCTRL)
+ continue;
+
+ v = snd_soc_read(codec, i);
+ if (snd_soc_write(codec, i, v) != 0) {
+ dev_err(codec->dev, "ERROR WRITING %.4X AT REG %x\n", v, i);
+ return;
+ }
+ }
+
+ snd_soc_write(codec, ADAU_PLBCTRL, PLBCTRL_POP_ON);
+ snd_soc_write(codec, ADAU_RECPWRM, RECPWRM_RUN_PWR);
+ snd_soc_write(codec, ADAU_PLBPWRM, PLBPWRM_RUN_PWR);
+
+ adau1361_set_bias_level(codec, SND_SOC_BIAS_ON);
+
+}
+
+static int adau1361_resume(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_codec *codec = socdev->card->codec;
+ struct adau1361_priv *adau1361 = codec->private_data;
+
+ adau1361->pdev = pdev;
+ schedule_work(&adau1361->resume_work);
+ return 0;
+}
+
+/*
+ * initialise the adau1361 driver
+ * register the mixer and dsp interfaces with the kernel
+ */
+static int adau1361_register(struct adau1361_priv *adau1361, enum snd_soc_control_type control)
+{
+ struct snd_soc_codec *codec = &adau1361->codec;
+ int ret = 0;
+
+ mutex_init(&codec->mutex);
+ INIT_LIST_HEAD(&codec->dapm_widgets);
+ INIT_LIST_HEAD(&codec->dapm_paths);
+ codec->name = "adau1361";
+ codec->owner = THIS_MODULE;
+ codec->set_bias_level = adau1361_set_bias_level;
+ codec->dai = &adau1361_dai;
+ codec->num_dai = 1;
+ codec->reg_cache_size = ADAU_NUMCACHEREG;
+ codec->reg_cache = kzalloc(ADAU_NUMCACHEREG, GFP_KERNEL);
+ if (codec->reg_cache == NULL)
+ return -ENOMEM;
+
+ ret = snd_soc_codec_set_cache_io(codec, 16, 8, control);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_register_codec(codec);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to register codec: %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_register_dai(&adau1361_dai);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
+ snd_soc_unregister_codec(codec);
+ return ret;
+ }
+
+ return ret;
+}
+
+static void adau1361_unregister(struct adau1361_priv *adau1361)
+{
+ struct snd_soc_codec *codec = &adau1361->codec;
+
+ adau1361_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ kfree(codec->reg_cache);
+ snd_soc_unregister_dai(&adau1361_dai);
+ snd_soc_unregister_codec(codec);
+ kfree(adau1361);
+ adau1361_codec = NULL;
+}
+
+static int adau1361_probe(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_codec *codec;
+ struct adau1361_priv *adau1361;
+ int ret = 0;
+
+ socdev->card->codec = adau1361_codec;
+ codec = adau1361_codec;
+ adau1361 = codec->private_data;
+ adau1361->in_source = CAP_MIC; /*default is mic input*/
+ adau1361->sysclk = ADAU1361_MCLK_RATE;
+ adau1361->pll_out = ADAU1361_PLL_FREQ_48;
+ adau1361->dapm_lineL = DAPM_LINE_DEF;
+ adau1361->dapm_lineR = DAPM_LINE_DEF;
+ adau1361->dapm_hpL = DAPM_HP_DEF;
+ adau1361->dapm_hpR = DAPM_HP_DEF;
+ adau1361->pdev = pdev;
+
+ ret = adau1361_reg_init(codec);
+ if (ret < 0)
+ dev_err(codec->dev, "failed to initialize\n");
+ /* register pcms */
+ ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+ if (ret < 0) {
+ dev_err(codec->dev, "failed to create pcms: %d\n", ret);
+ goto pcm_err;
+ }
+
+ snd_soc_add_controls(codec, adau1361_snd_controls,
+ ARRAY_SIZE(adau1361_snd_controls));
+ adau1361_add_widgets(codec);
+pcm_err:
+ return ret;
+}
+
+/* remove everything here */
+static int adau1361_remove(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+
+ snd_soc_free_pcms(socdev);
+ snd_soc_dapm_free(socdev);
+
+ return 0;
+}
+
+struct snd_soc_codec_device soc_codec_dev_adau1361 = {
+ .probe = adau1361_probe,
+ .remove = adau1361_remove,
+ .suspend = adau1361_suspend,
+ .resume = adau1361_resume,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_adau1361);
+
+
+static __devinit int adau1361_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct adau1361_priv *adau1361;
+ struct snd_soc_codec *codec;
+ int ret = 0;
+
+ adau1361 = kzalloc(sizeof(struct adau1361_priv), GFP_KERNEL);
+ if (adau1361 == NULL)
+ return -ENOMEM;
+ codec = &adau1361->codec;
+ codec->private_data = adau1361;
+ codec->hw_write = (hw_write_t)i2c_master_send;
+
+ i2c_set_clientdata(i2c, adau1361);
+ codec->control_data = i2c;
+
+ codec->dev = &i2c->dev;
+ adau1361_codec = codec;
+
+ INIT_WORK(&adau1361->resume_work, adau1361_resume_wq_handler);
+ ret = adau1361_register(adau1361, SND_SOC_I2C);
+ if (ret < 0)
+ dev_err(&i2c->dev, "failed to initialize\n");
+
+ return ret;
+}
+
+static __devexit int adau1361_i2c_remove(struct i2c_client *client)
+{
+ struct adau1361_priv *adau1361 = i2c_get_clientdata(client);
+ adau1361_unregister(adau1361);
+ return 0;
+}
+
+static const struct i2c_device_id adau1361_i2c_id[] = {
+ { "adau1361", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, adau1361_i2c_id);
+
+/* corgi i2c codec control layer */
+static struct i2c_driver adau1361_i2c_driver = {
+ .driver = {
+ .name = "adau1361",
+ .owner = THIS_MODULE,
+ },
+ .probe = adau1361_i2c_probe,
+ .remove = __devexit_p(adau1361_i2c_remove),
+ .id_table = adau1361_i2c_id,
+};
+
+static int __init adau1361_modinit(void)
+{
+ int ret;
+
+ ret = i2c_add_driver(&adau1361_i2c_driver);
+ if (ret != 0) {
+ printk(KERN_ERR "Failed to register adau1361 I2C driver: %d\n",
+ ret);
+ }
+
+ return ret;
+}
+module_init(adau1361_modinit);
+
+static void __exit adau1361_exit(void)
+{
+ i2c_del_driver(&adau1361_i2c_driver);
+}
+module_exit(adau1361_exit);
+
+MODULE_DESCRIPTION("ASoC ADAU1361 driver");
+MODULE_AUTHOR("Cliff Cai");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/adau1361.h b/sound/soc/codecs/adau1361.h
new file mode 100644
index 0000000..79cf576
--- /dev/null
+++ b/sound/soc/codecs/adau1361.h
@@ -0,0 +1,264 @@
+/*
+ * header file fortone adau1361 sound chip
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+
+#ifndef __ADAU1361_H__
+#define __ADAU1361_H__
+
+struct adau1361_setup_data {
+ unsigned short i2c_bus;
+ unsigned short i2c_address;
+};
+
+struct adau1361_mode_register {
+ u16 regaddress;
+ u16 regvalue;
+};
+
+#define RESET_REGISTER_COUNT 42
+#define MODE_REGISTER_COUNT 8
+
+#define MASTER_MODE 1
+#ifdef MASTER_MODE
+/* IIS mater mode*/
+#define ADAU_SRPT_CTRL0 0x01
+#else
+/* IIS slave mode*/
+#define ADAU_SRPT_CTRL0 0x00
+#endif
+
+/* adau1361_set_dai_sysclk clk_id */
+#define ADAU1361_MCLK_ID 0
+#define ADAU1361_BCLK_ID 0x33
+
+#define ADAU1361_MCLK_RATE 12288000
+
+#define ADAU1361_PLL_FREQ_441 45158400
+#define ADAU1361_PLL_FREQ_48 49152000
+
+
+/* ADAU1361 control registers */
+#define ADAU_FIRSTREG 0x4000
+
+#define ADAU_CLKCTRL 0x4000
+#define ADAU_PLLCTRL 0x4002
+#define ADAU_MICCTRL 0x4008
+#define ADAU_RECPWRM 0x4009
+#define ADAU_RECMLC0 0x400A
+#define ADAU_RECMLC1 0x400B
+#define ADAU_RECMRC0 0x400C
+#define ADAU_RECMRC1 0x400D
+#define ADAU_RECVLCL 0x400E
+#define ADAU_RECVLCR 0x400F
+
+#define ADAU_RECMBIA 0x4010
+#define ADAU_ALCCTR0 0x4011
+#define ADAU_ALCCTR1 0x4012
+#define ADAU_ALCCTR2 0x4013
+#define ADAU_ALCCTR3 0x4014
+#define ADAU_SPRTCT0 0x4015
+#define ADAU_SPRTCT1 0x4016
+#define ADAU_CONVCT0 0x4017
+#define ADAU_CONVCT1 0x4018
+#define ADAU_ADCCTL0 0x4019
+#define ADAU_ADCCTL1 0x401A
+#define ADAU_ADCCTL2 0x401B
+#define ADAU_PLBMLC0 0x401C
+#define ADAU_PLBMLC1 0x401D
+#define ADAU_PLBMRC0 0x401E
+#define ADAU_PLBMRC1 0x401F
+
+#define ADAU_PLBMLLO 0x4020
+#define ADAU_PLBMRLO 0x4021
+#define ADAU_PLBLRMC 0x4022
+#define ADAU_PLBHPVL 0x4023
+#define ADAU_PLBHPVR 0x4024
+#define ADAU_PLBLOVL 0x4025
+#define ADAU_PLBLOVR 0x4026
+#define ADAU_PLBMNOC 0x4027
+#define ADAU_PLBCTRL 0x4028
+#define ADAU_PLBPWRM 0x4029
+
+#define ADAU_DACCTL0 0x402A
+#define ADAU_DACCTL1 0x402B
+#define ADAU_DACCTL2 0x402C
+#define ADAU_SERPAD0 0x402D
+#define ADAU_COMPAD0 0x402F
+#define ADAU_COMPAD1 0x4030
+#define ADAU_MCLKPAD 0x4031
+
+#define ADAU_LASTREG 0x4031
+
+#define ADAU_NUMCACHEREG 44
+
+/* Register field definitions */
+/* Clock Control */
+#define CLKCTRL_SRC_MCLK 0x0
+#define CLKCTRL_SRC_PLL 0x8
+#define CLKCTRL_FRQ_256 0x0
+#define CLKCTRL_FRQ_512 0x2
+#define CLKCTRL_FRQ_768 0x4
+#define CLKCTRL_FRQ_1024 0x6
+#define CLKCTRL_DISABLE 0x0
+#define CLKCTRL_ENABLE 0x1
+
+/* PLL Control -- 6 bytes*/
+/*Bytes 5-6*/
+#define PLLCTRL_DEN_MSB 0x00
+#define PLLCTRL_DEN_LSB 0x00
+/*Bytes 3-4*/
+#define PLLCTRL_NUM_MSB 0x00
+#define PLLCTRL_NUM_LSB 0x00
+/*Byte 2*/
+#define PLLCTRL_INTPART_R2 0x10
+#define PLLCTRL_INTPART_R3 0x18
+#define PLLCTRL_INTPART_R4 0x20
+#define PLLCTRL_INTPART_R5 0x28
+#define PLLCTRL_INTPART_R6 0x30
+#define PLLCTRL_INTPART_R7 0x38
+#define PLLCTRL_INTPART_R8 0x40
+#define PLLCTRL_INPUT_DIV1 0x00
+#define PLLCTRL_INPUT_DIV2 0x02
+#define PLLCTRL_INPUT_DIV3 0x04
+#define PLLCTRL_INPUT_DIV4 0x06
+#define PLLCTRL_TYPE_INT 0x0
+#define PLLCTRL_TYPE_FRAC 0x1
+/*Byte 1*/
+#define PLLCTRL_DISABLE 0x0
+#define PLLCTRL_ENABLE 0x1
+
+/*ADC*/
+#define ADCCTL_DISABLE_MASK 0xFC
+#define ADCCTL_ENABLE_MASK 0x03
+
+/*MIC*/
+#define RECMBIA_DISABLE 0x00
+#define RECMBIA_ENABLE 0x01
+#define RECVLC_DISABLE_MASK 0xFC
+#define RECVLC_ENABLE_MASK 0x03
+
+#define RECMLC_MIC_0DB 0x08
+#define RECMLC_MIC_20DB 0x10
+#define RECMLC_LINE_0DB 0x05
+
+/* PWN MNGMNT */
+#define RECPWRM_LOW_PWR 0x0E
+#define PLBPWRM_LOW_PWR 0x5C
+#define PLBCTRL_POP_LPWR 0x10
+#define PLBCTRL_POP_OFF 0x06
+#define PLBCTRL_POP_ON 0x00
+#define RECPWRM_RUN_PWR 0x00
+#define PLBPWRM_RUN_PWR 0x03
+#define DAPM_LINE_DEF 0xE6
+#define DAPM_HP_DEF 0xE7
+#define PLB_MUTE_MASK 0x03
+
+#define ADAU1361_BITSFRAM_32 0x4000
+#define ADAU1361_BITSFRAM_48 0x8000
+
+/*playback output control*/
+#define ADAU1361_VOLUME_MASK 0xFC
+#define ADAU1361_VOLUME_BITS 0x2
+#define ADAU1361_MUTE_MASK 0x02
+#define ADAU1361_MUTE_BITS 0x1
+#define ADAU1361_ADVOL_MASK 0xff
+
+/*
+ * Reset Mode - ADC capture/DAC playback
+ * (AInput mixers 0db, AOuput mixers 0db, HP out ON)
+*/
+static struct adau1361_mode_register adau1361_reset[RESET_REGISTER_COUNT] = {
+ /* mute outputs */
+ {ADAU_PLBMNOC, 0xE5},
+ {ADAU_PLBHPVL, 0x01},
+ {ADAU_PLBHPVR, 0x01},
+ {ADAU_PLBLOVL, 0x00},
+ {ADAU_PLBLOVR, 0x00},
+ {ADAU_MICCTRL, 0x00},
+ {ADAU_RECPWRM, 0x00},
+ {ADAU_RECMLC0, 0x01},
+ {ADAU_RECMLC1, RECMLC_MIC_0DB},
+ {ADAU_RECMRC0, 0x01},
+ {ADAU_RECMRC1, RECMLC_MIC_0DB},
+ {ADAU_RECVLCL, 0x82},
+ {ADAU_RECVLCR, 0x82},
+ {ADAU_RECMBIA, RECMBIA_DISABLE},
+ {ADAU_ALCCTR0, 0x00},
+ {ADAU_ALCCTR1, 0x00},
+ {ADAU_ALCCTR2, 0x00},
+ {ADAU_ALCCTR3, 0x1F},
+ {ADAU_SPRTCT0, ADAU_SRPT_CTRL0},
+ {ADAU_SPRTCT1, 0x01}, /* 0x01 = 64bclocks frame */
+ {ADAU_CONVCT0, 0x00},
+ {ADAU_CONVCT1, 0x00},
+ {ADAU_ADCCTL0, 0x00},
+ {ADAU_ADCCTL1, 0x00},
+ {ADAU_ADCCTL2, 0x00},
+ {ADAU_PLBMLC0, 0x21},
+ {ADAU_PLBMLC1, 0x00},
+ {ADAU_PLBMRC0, 0x41},
+ {ADAU_PLBMRC1, 0x00},
+ {ADAU_PLBMLLO, 0x03},
+ {ADAU_PLBMRLO, 0x09},
+ {ADAU_PLBLRMC, 0x01},
+ {ADAU_PLBCTRL, 0x00},
+ {ADAU_PLBPWRM, 0x00},
+ {ADAU_DACCTL0, 0x03},
+ {ADAU_DACCTL1, 0x00},
+ {ADAU_DACCTL2, 0x00},
+ {ADAU_SERPAD0, 0xAA},
+ {ADAU_COMPAD0, 0xAA},
+ {ADAU_COMPAD1, 0x00},
+ {ADAU_MCLKPAD, 0x0A},
+};
+
+/*
+ * Default Mode
+ * Analog microphones, ADC capture/DAC playback
+ * (AInput mixers ON, AOuput mixers ON, HP out ON)
+*/
+static struct adau1361_mode_register adau1361_mode0[MODE_REGISTER_COUNT] = {
+ /* mute outputs */
+ {ADAU_PLBHPVL, 0x03},
+ {ADAU_PLBHPVR, 0x03},
+ {ADAU_PLBLOVL, 0x02},
+ {ADAU_PLBLOVR, 0x02},
+ {ADAU_PLBMNOC, 0xE5},
+ /*analog mic*/
+ {ADAU_RECVLCL, 0x42},
+ {ADAU_RECVLCR, 0x42},
+ {ADAU_MICCTRL, 0x00},
+};
+
+/*
+ * Digital Microphone mode,
+ * IIS Master, ADC capture/DAC playback
+ * (AInput mixers OFF, AOuput mixers ON, HP out ON)
+ */
+static struct adau1361_mode_register adau1361_mode1[MODE_REGISTER_COUNT] = {
+ /* mute outputs */
+ {ADAU_PLBHPVL, 0x03},
+ {ADAU_PLBHPVR, 0x03},
+ {ADAU_PLBLOVL, 0x02},
+ {ADAU_PLBLOVR, 0x02},
+ {ADAU_PLBMNOC, 0xE5},
+ /*digital mic*/
+ {ADAU_RECVLCL, 0x00},
+ {ADAU_RECVLCR, 0x00},
+ {ADAU_MICCTRL, 0x20},
+};
+
+static struct adau1361_mode_register *adau1361_mode_registers[] = {
+ adau1361_mode0,
+ adau1361_mode1,
+};
+
+extern struct snd_soc_dai adau1361_dai;
+extern struct snd_soc_codec_device soc_codec_dev_adau1361;
+
+#endif
--
1.7.2
4
17
07 Aug '10
From: Yi Li <yi.li(a)analog.com>
Signed-off-by: Yi Li <yi.li(a)analog.com>
Signed-off-by: Cliff Cai <cliff.cai(a)analog.com>
Signed-off-by: Mike Frysinger <vapier(a)gentoo.org>
---
sound/soc/codecs/Kconfig | 6 +-
sound/soc/codecs/Makefile | 2 +
sound/soc/codecs/adav80x.c | 631 ++++++++++++++++++++++++++++++++++++++++++++
sound/soc/codecs/adav80x.h | 93 +++++++
4 files changed, 731 insertions(+), 1 deletions(-)
create mode 100644 sound/soc/codecs/adav80x.c
create mode 100644 sound/soc/codecs/adav80x.h
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 5db82d2..ae01cba 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -15,8 +15,9 @@ config SND_SOC_ALL_CODECS
select SND_SOC_AD1836 if SPI_MASTER
select SND_SOC_AD193X if SND_SOC_I2C_AND_SPI
select SND_SOC_AD1980 if SND_SOC_AC97_BUS
- select SND_SOC_ADS117X
select SND_SOC_AD73311 if I2C
+ select SND_SOC_ADAV80X if SND_SOC_I2C_AND_SPI
+ select SND_SOC_ADS117X
select SND_SOC_AK4104 if SPI_MASTER
select SND_SOC_AK4535 if I2C
select SND_SOC_AK4642 if I2C
@@ -103,6 +104,9 @@ config SND_SOC_AD1980
config SND_SOC_AD73311
tristate
+config SND_SOC_ADAV80X
+ tristate
+
config SND_SOC_ADS117X
tristate
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 7593eeb..f5b3d5b 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -3,6 +3,7 @@ snd-soc-ad1836-objs := ad1836.o
snd-soc-ad193x-objs := ad193x.o
snd-soc-ad1980-objs := ad1980.o
snd-soc-ad73311-objs := ad73311.o
+snd-soc-adav80x-objs := adav80x.o
snd-soc-ads117x-objs := ads117x.o
snd-soc-ak4104-objs := ak4104.o
snd-soc-ak4535-objs := ak4535.o
@@ -69,6 +70,7 @@ obj-$(CONFIG_SND_SOC_AD1836) += snd-soc-ad1836.o
obj-$(CONFIG_SND_SOC_AD193X) += snd-soc-ad193x.o
obj-$(CONFIG_SND_SOC_AD1980) += snd-soc-ad1980.o
obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o
+obj-$(CONFIG_SND_SOC_ADAV80X) += snd-soc-adav80x.o
obj-$(CONFIG_SND_SOC_ADS117X) += snd-soc-ads117x.o
obj-$(CONFIG_SND_SOC_AK4104) += snd-soc-ak4104.o
obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o
diff --git a/sound/soc/codecs/adav80x.c b/sound/soc/codecs/adav80x.c
new file mode 100644
index 0000000..778473c
--- /dev/null
+++ b/sound/soc/codecs/adav80x.c
@@ -0,0 +1,631 @@
+/*
+ * ADAV80X Audio Codec driver supporting ADAV801, ADAV803
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include <sound/soc-dapm.h>
+#include "adav80x.h"
+
+
+struct adav80x_priv {
+ struct snd_soc_codec codec;
+ u16 reg_cache[ADAV80X_NUM_REGS];
+ int clk_src; /* clock source for ADC, DAC and internal clock */
+};
+
+static struct snd_soc_codec *adav80x_codec;
+struct snd_soc_codec_device soc_codec_dev_adav80x;
+static int adav80x_register(struct adav80x_priv *adav80x, int bus_type);
+static void adav80x_unregister(struct adav80x_priv *adav80x);
+
+static const struct snd_soc_dapm_widget adav80x_dapm_widgets[] = {
+ SND_SOC_DAPM_DAC("DAC", "Playback", ADAV80X_DAC_CTRL1, 7, 1),
+ SND_SOC_DAPM_ADC("ADC", "Capture", ADAV80X_ADC_CTRL1, 5, 1),
+ SND_SOC_DAPM_SUPPLY("PLL_PWR", ADAV80X_PLL_CTRL1, 1, 1, NULL, 0),
+};
+
+static const struct snd_soc_dapm_route audio_paths[] = {
+ { "DAC", NULL, "PLL_PWR" },
+ { "ADC", NULL, "PLL_PWR" },
+};
+
+/*
+ * ADAV80X volume/mute/de-emphasis etc. controls
+ */
+static const char *adav80x_deemp[] = {"None", "44.1kHz", "32kHz", "48kHz"};
+
+static const struct soc_enum adav80x_deemp_enum =
+SOC_ENUM_SINGLE(ADAV80X_DAC_CTRL2, 0, 4, adav80x_deemp);
+
+static const struct snd_kcontrol_new adav80x_snd_controls[] = {
+ /* DAC volume control */
+ SOC_DOUBLE_R("DAC Volume", ADAV80X_DAC_L_VOL,
+ ADAV80X_DAC_R_VOL, 0, 0xFF, 0),
+ /* DAC peak volume detect, read clears it */
+ SOC_DOUBLE_R("DAC Peak Volume", ADAV80X_DAC_L_PEAK_VOL,
+ ADAV80X_DAC_R_PEAK_VOL, 0, 0x3F, 0),
+
+ /* ADC volume control */
+ SOC_DOUBLE_R("ADC Volume", ADAV80X_ADC_L_VOL,
+ ADAV80X_ADC_R_VOL, 0, 0xFF, 0),
+ /* ADC peak volume detect */
+ SOC_DOUBLE_R("ADC Peak Volume", ADAV80X_ADC_L_PEAK_VOL,
+ ADAV80X_ADC_R_PEAK_VOL, 0, 0x3F, 0),
+
+ /* ADC mute */
+ SOC_DOUBLE("ADC Switch", ADAV80X_ADC_CTRL1, 2, 3, 1, 1),
+
+ /* DAC mute */
+ SOC_DOUBLE("DAC Switch", ADAV80X_DAC_CTRL1, 0, 1, 1, 1),
+
+ /* ADC high-pass filter */
+ SOC_SINGLE("ADC High Pass Filter Switch", ADAV80X_ADC_CTRL1, 6, 1, 0),
+
+ /* DAC de-emphasis */
+ SOC_ENUM("Playback Deemphasis", adav80x_deemp_enum),
+};
+
+/*
+ * DAI ops entries
+ */
+
+static int adav80x_set_dai_fmt(struct snd_soc_dai *codec_dai,
+ unsigned int fmt)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ u8 rec_ctl = 0, playback_ctl = 0;
+
+ /* set master/slave audio interface */
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ /* use internal clock 1 */
+ playback_ctl |= 0x10;
+ rec_ctl |= 0x20;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* interface format */
+ /* DAC word length depends on input, ADC need to set word length */
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ playback_ctl |= 0x1;
+ rec_ctl |= 0x1;
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ playback_ctl |= 0x4;
+ rec_ctl |= 0x3;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* clock inversion */
+ /* Use default - seems no polarity setting */
+ /* DAC control reg 1: CHSEL[1:0], POL[1:0] ? */
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ snd_soc_write(codec, ADAV80X_PLAYBACK_CTRL, playback_ctl);
+ snd_soc_write(codec, ADAV80X_REC_CTRL, rec_ctl);
+
+ return 0;
+}
+
+static int adav80x_set_adc_clock(struct snd_soc_codec *codec,
+ int clk_id, unsigned int sample_rate)
+{
+ int reg;
+
+ if (clk_id == ADAV80X_CLK_PLL1) {
+ /* ADC assumes that the MCLK ratre is 256 times the sample rate.
+ We also assumes PLL1 clock rate to be (256 * Fs),
+ So set ADC MCLK divider to be 1 */
+
+ reg = snd_soc_read(codec, ADAV80X_ADC_CTRL1);
+ /* ADC Modulator clock is 6.144MHz Max,
+ need to set devidor properly */
+ if (sample_rate == 96000)
+ reg |= 0x80;
+ else if (sample_rate == 48000)
+ reg &= 0x7F;
+ else
+ /* Unsupported sample rate */
+ return -1;
+
+ snd_soc_write(codec, ADAV80X_ADC_CTRL1, reg);
+ }
+
+ return 0;
+}
+
+static int adav80x_set_dac_clock(struct snd_soc_codec *codec,
+ int clk_id, unsigned int sample_rate)
+{
+ int reg;
+
+ if (clk_id == ADAV80X_CLK_PLL1) {
+ /* PLL1 clock rate is assumed to be 256 * Fs */
+
+ reg = snd_soc_read(codec, ADAV80X_DAC_CTRL2);
+ if (sample_rate == 96000)
+ /* Set the MCLK divider to be MCLK/2,
+ and MCLK = 128 * Fs */
+ reg |= 0x24;
+ else
+ reg &= 0x11;
+
+ snd_soc_write(codec, ADAV80X_DAC_CTRL2, reg);
+ }
+
+ return 0;
+}
+
+static int adav80x_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ int word_len = 0;
+ int rate = params_rate(params);
+
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_device *socdev = rtd->socdev;
+ struct snd_soc_codec *codec = socdev->card->codec;
+ struct adav80x_priv *adav80x = codec->private_data;
+
+ /* bit size */
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ word_len = 3;
+ break;
+ case SNDRV_PCM_FORMAT_S18_3LE:
+ word_len = 2;
+ break;
+ case SNDRV_PCM_FORMAT_S20_3LE:
+ word_len = 1;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ word_len = 0;
+ break;
+ }
+
+
+ /* Playback port does not need to set word length? */
+
+ /* Record Port Control */
+ snd_soc_update_bits(codec, ADAV80X_REC_CTRL, 0x3<<2, word_len<<2);
+
+ /* Set up clock */
+ if (adav80x->clk_src == ADAV80X_CLK_PLL1) {
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ adav80x_set_dac_clock(codec, ADAV80X_CLK_PLL1, rate);
+ else
+ adav80x_set_adc_clock(codec, ADAV80X_CLK_PLL1, rate);
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int adav80x_soc_suspend(struct platform_device *pdev,
+ pm_message_t state)
+{
+ return 0;
+}
+
+static int adav80x_soc_resume(struct platform_device *pdev)
+{
+ return 0;
+}
+#else
+#define adav80x_soc_suspend NULL
+#define adav80x_soc_resume NULL
+#endif
+
+static int adav80x_mute(struct snd_soc_dai *dai, int mute)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ int reg;
+
+ reg = snd_soc_read(codec, ADAV80X_DAC_CTRL1);
+ reg = (mute > 0) ? reg & ~0x3 : reg | 0x3;
+ snd_soc_write(codec, ADAV80X_DAC_CTRL1, reg);
+
+ return 0;
+}
+
+
+static int adav80x_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
+ int source, unsigned int freq_in, unsigned int freq_out)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct adav80x_priv *adav80x = codec->private_data;
+ int reg = 0;
+
+ /* For now, we only enable PLL1 with XIN as source */
+ if (source != ADAV80X_CLK_XIN)
+ return -1;
+
+ if (freq_in && freq_out) {
+ /* XIN - assumes 27MHz */
+ if (freq_in != 27000000)
+ return -1;
+
+ if (pll_id != ADAV80X_CLK_PLL1)
+ return -1;
+
+ /* freq_out = sample_rate * 256 */
+ switch (freq_out) {
+ case 32000:
+ reg = 0x8;
+ break;
+ case 44100:
+ reg = 0xC;
+ break;
+ case 48000:
+ reg = 0x0;
+ break;
+ case 64000:
+ reg = 0x9;
+ break;
+ case 88200:
+ reg = 0xD;
+ break;
+ case 96000:
+ reg = 0x1;
+ break;
+ }
+
+ /* Set PLL1 clock */
+ snd_soc_write(codec, ADAV80X_PLL_CTRL2, reg);
+
+ if (adav80x->clk_src == ADAV80X_CLK_PLL1)
+ return 0;
+ else
+ adav80x->clk_src = ADAV80X_CLK_PLL1;
+
+ /* select XIN as PLL1 clock source */
+ snd_soc_write(codec, ADAV80X_PLL_CLK_SRC, 0x0);
+ /* set PLL1 as clock source for internal clock, DAC, ADC */
+ snd_soc_write(codec, ADAV80X_ICLK_CTRL1, 0x4A);
+ snd_soc_write(codec, ADAV80X_ICLK_CTRL2, 0x10);
+ /* Power on PLL1, power down PLL2, power on XTAL */
+ snd_soc_write(codec, ADAV80X_PLL_CTRL1, 0x8);
+
+ } else {
+ if (adav80x->clk_src == ADAV80X_CLK_XIN)
+ return 0;
+ else
+ adav80x->clk_src = ADAV80X_CLK_XIN;
+
+ /* Turn off PLL, power on XTAL */
+ snd_soc_write(codec, ADAV80X_PLL_CTRL1, 0xC);
+
+ /* DAC, ADC, ICLK clock source - XIN */
+ snd_soc_write(codec, ADAV80X_ICLK_CTRL1, 0x0);
+ snd_soc_write(codec, ADAV80X_ICLK_CTRL2, 0x0);
+ }
+
+ return 0;
+}
+
+static struct snd_soc_dai_ops adav80x_dai_ops = {
+ .hw_params = adav80x_hw_params,
+ .set_fmt = adav80x_set_dai_fmt,
+ .digital_mute = adav80x_mute,
+ .set_pll = adav80x_set_dai_pll,
+};
+
+/* codec DAI instance */
+/* DAC sample rates: 32/44.1/48/96/192kHz, ADC sample reate: 48/96kHz - TBD */
+struct snd_soc_dai adav80x_dai = {
+ .name = "ADAV80X",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_96000,
+ .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE,
+ },
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000,
+ .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE,
+ },
+ .ops = &adav80x_dai_ops,
+};
+EXPORT_SYMBOL_GPL(adav80x_dai);
+
+
+static int adav80x_probe(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_codec *codec;
+ int ret = 0;
+
+ if (adav80x_codec == NULL) {
+ dev_err(&pdev->dev, "Codec device not registered\n");
+ return -ENODEV;
+ }
+
+ socdev->card->codec = adav80x_codec;
+ codec = adav80x_codec;
+
+ /* register pcms */
+ ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+ if (ret < 0) {
+ dev_err(codec->dev, "failed to create pcms: %d\n", ret);
+ goto pcm_err;
+ }
+
+ snd_soc_add_controls(codec, adav80x_snd_controls,
+ ARRAY_SIZE(adav80x_snd_controls));
+ snd_soc_dapm_new_controls(codec, adav80x_dapm_widgets,
+ ARRAY_SIZE(adav80x_dapm_widgets));
+ snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths));
+
+pcm_err:
+ return ret;
+}
+
+/* power down chip */
+static int adav80x_remove(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+
+ snd_soc_free_pcms(socdev);
+ snd_soc_dapm_free(socdev);
+
+ return 0;
+}
+
+struct snd_soc_codec_device soc_codec_dev_adav80x = {
+ .probe = adav80x_probe,
+ .remove = adav80x_remove,
+ .suspend = adav80x_soc_suspend,
+ .resume = adav80x_soc_resume,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_adav80x);
+
+static int adav80x_register(struct adav80x_priv *adav80x, int bus_type)
+{
+ int ret;
+ struct snd_soc_codec *codec = &adav80x->codec;
+
+ if (adav80x_codec) {
+ dev_err(codec->dev, "Another adav80x is registered\n");
+ return -EINVAL;
+ }
+
+ mutex_init(&codec->mutex);
+ codec->private_data = adav80x;
+ codec->reg_cache = adav80x->reg_cache;
+ codec->reg_cache_size = ADAV80X_NUM_REGS;
+ codec->name = "ADAV80X";
+ codec->owner = THIS_MODULE;
+ codec->dai = &adav80x_dai;
+ codec->num_dai = 1;
+
+ INIT_LIST_HEAD(&codec->dapm_widgets);
+ INIT_LIST_HEAD(&codec->dapm_paths);
+
+ adav80x_dai.dev = codec->dev;
+ adav80x_codec = codec;
+
+
+ if (bus_type == SND_SOC_I2C)
+ /* addr(7-bit left shifted 1), data(8bit)*/
+ ret = snd_soc_codec_set_cache_io(codec, 8, 8, bus_type);
+ else
+ /* register format: addr(7bit), data(9bit) */
+ /* set spi bits_per_word to 8 instead of 16,
+ since addr need to be transfer before data */
+ ret = snd_soc_codec_set_cache_io(codec, 7, 9, bus_type);
+ if (ret < 0) {
+ dev_err(codec->dev, "failed to set cache I/O: %d\n",
+ ret);
+ kfree(adav80x);
+ return ret;
+ }
+
+ ret = snd_soc_register_codec(codec);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to register codec: %d\n", ret);
+ kfree(adav80x);
+ return ret;
+ }
+
+ ret = snd_soc_register_dai(&adav80x_dai);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
+ snd_soc_unregister_codec(codec);
+ kfree(adav80x);
+ return ret;
+ }
+
+ /* default setting for adav80x */
+
+ /* Power down SYSCLK output, power down S/PDIF receiver */
+ snd_soc_write(codec, ADAV80X_PLL_OUTE, 0x27);
+
+ /* Disable S/PDIF transmitter */
+ snd_soc_write(codec, ADAV80X_TX_CTRL, 0x0);
+
+ /* Datapath: ADC->record, AUX_IN->SRC->AUX_OUT */
+ snd_soc_write(codec, ADAV80X_DPATH_CTRL1, 0xC4);
+ /* Datapath: playback->DAC, DIR->DIT */
+ snd_soc_write(codec, ADAV80X_DPATH_CTRL2, 0x11);
+
+ /* Soft-mute SRC output */
+ snd_soc_write(codec, ADAV80X_GDELAY_MUTE, 0x80);
+
+ /* DAC: de-emphasis: none, MCLCK divider: 1, MCLK=256xFs */
+ /* snd_soc_write(codec, ADAV80X_DAC_CTRL2, 0x0); */
+ /* Disable DAC zero flag */
+ snd_soc_write(codec, ADAV80X_DAC_CTRL3, 0x6);
+ /* DAC: volume */
+ snd_soc_write(codec, ADAV80X_DAC_L_VOL, 0xFF);
+ snd_soc_write(codec, ADAV80X_DAC_R_VOL, 0xFF);
+
+ /* ADC: power up, unmute adc channles */
+ /* snd_soc_write(codec, ADAV80X_ADC_CTRL1, 0x0); */
+ /* MCLCK divider: 1 */
+ /* snd_soc_write(codec, ADAV80X_ADC_CTRL2, 0x0); */
+ /* ADC: volumn */
+ snd_soc_write(codec, ADAV80X_ADC_L_VOL, 0xFF);
+ snd_soc_write(codec, ADAV80X_ADC_R_VOL, 0xFF);
+
+ /* Disable ALC */
+ snd_soc_write(codec, ADAV80X_ALC_CTRL1, 0x0);
+
+ return 0;
+}
+
+static void adav80x_unregister(struct adav80x_priv *adav80x)
+{
+ snd_soc_unregister_dai(&adav80x_dai);
+ snd_soc_unregister_codec(&adav80x->codec);
+ kfree(adav80x);
+ adav80x_codec = NULL;
+}
+
+static int __devinit adav80x_bus_probe(struct device *dev, void *ctrl_data,
+ int bus_type)
+{
+ struct snd_soc_codec *codec;
+ struct adav80x_priv *adav80x;
+
+ adav80x = kzalloc(sizeof(struct adav80x_priv), GFP_KERNEL);
+ if (adav80x == NULL)
+ return -ENOMEM;
+
+ codec = &adav80x->codec;
+ codec->control_data = ctrl_data;
+ codec->dev = dev;
+
+ dev_set_drvdata(dev, adav80x);
+
+ return adav80x_register(adav80x, bus_type);
+}
+
+int adav80x_bus_remove(struct device *dev)
+{
+ struct adav80x_priv *adav80x = dev_get_drvdata(dev);
+
+ adav80x_unregister(adav80x);
+ return 0;
+}
+
+#if defined(CONFIG_SPI_MASTER)
+static int __devinit adav80x_spi_probe(struct spi_device *spi)
+{
+ return adav80x_bus_probe(&spi->dev, spi, SND_SOC_SPI);
+}
+
+static int __devexit adav80x_spi_remove(struct spi_device *spi)
+{
+ return adav80x_bus_remove(&spi->dev);
+}
+
+static struct spi_driver adav80x_spi_driver = {
+ .driver = {
+ .name = "adav80x",
+ .owner = THIS_MODULE,
+ },
+ .probe = adav80x_spi_probe,
+ .remove = __devexit_p(adav80x_spi_remove),
+};
+#endif
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static const struct i2c_device_id adav80x_id[] = {
+ { "adav803", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, adav80x_id);
+
+static int __devinit adav80x_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ return adav80x_bus_probe(&client->dev, client, SND_SOC_I2C);
+}
+
+static int __devexit adav80x_i2c_remove(struct i2c_client *client)
+{
+ return adav80x_bus_remove(&client->dev);
+}
+
+static struct i2c_driver adav80x_i2c_driver = {
+ .driver = {
+ .name = "adav80x",
+ },
+ .probe = adav80x_i2c_probe,
+ .remove = __devexit_p(adav80x_i2c_remove),
+ .id_table = adav80x_id,
+};
+#endif
+
+static int __init adav80x_init(void)
+{
+ int ret;
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+ ret = i2c_add_driver(&adav80x_i2c_driver);
+ if (ret != 0) {
+ printk(KERN_ERR "Failed to register ADAV80X I2C driver: %d\n",
+ ret);
+ }
+#elif defined(CONFIG_SPI_MASTER)
+ ret = spi_register_driver(&adav80x_spi_driver);
+ if (ret != 0) {
+ printk(KERN_ERR "Failed to register ADAV80X SPI driver: %d\n",
+ ret);
+ }
+#endif
+ return ret;
+}
+module_init(adav80x_init);
+
+static void __exit adav80x_exit(void)
+{
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+ i2c_del_driver(&adav80x_i2c_driver);
+#elif defined(CONFIG_SPI_MASTER)
+ spi_unregister_driver(&adav80x_spi_driver);
+#endif
+}
+module_exit(adav80x_exit);
+
+MODULE_DESCRIPTION("ASoC adav80x driver");
+MODULE_AUTHOR("Yi Li");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/adav80x.h b/sound/soc/codecs/adav80x.h
new file mode 100644
index 0000000..b4a5a4d
--- /dev/null
+++ b/sound/soc/codecs/adav80x.h
@@ -0,0 +1,93 @@
+extern struct snd_soc_dai adav80x_dai;
+extern struct snd_soc_codec_device soc_codec_dev_adav80x;
+
+/* Clock source */
+#define ADAV80X_CLK_XIN 1
+#define ADAV80X_CLK_PLL1 2
+#define ADAV80X_CLK_PLL2 3
+#define ADAV80X_CLK_INTERNAL1 4
+#define ADAV80X_CLK_INTERNAL2 5
+#define ADAV80X_CLK_MCLKI 6
+
+
+#if (CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+/* ADAV80X I2C interface requires left-shifting reg addr for 1-bit */
+#define ADAV80X_NUM_REGS (0x7E<<1)
+
+#define ADAV80X_PLAYBACK_CTRL (0x4<<1)
+#define ADAV80X_AUX_IN_CTRL (0x5<<1)
+#define ADAV80X_REC_CTRL (0x6<<1)
+#define ADAV80X_AUX_OUT_CTRL (0x7<<1)
+#define ADAV80X_GDELAY_MUTE (0x8<<1)
+
+
+#define ADAV80X_TX_CTRL (0xC<<1)
+
+#define ADAV80X_DPATH_CTRL1 (0x62<<1)
+#define ADAV80X_DPATH_CTRL2 (0x63<<1)
+#define ADAV80X_DAC_CTRL1 (0x64<<1)
+#define ADAV80X_DAC_CTRL2 (0x65<<1)
+#define ADAV80X_DAC_CTRL3 (0x66<<1)
+#define ADAV80X_DAC_CTRL4 (0x67<<1)
+#define ADAV80X_DAC_L_VOL (0x68<<1)
+#define ADAV80X_DAC_R_VOL (0x69<<1)
+#define ADAV80X_DAC_L_PEAK_VOL (0x6A<<1)
+#define ADAV80X_DAC_R_PEAK_VOL (0x6B<<1)
+
+
+#define ADAV80X_ADC_CTRL1 (0x6E<<1)
+#define ADAV80X_ADC_CTRL2 (0x6F<<1)
+#define ADAV80X_ADC_L_VOL (0x70<<1)
+#define ADAV80X_ADC_R_VOL (0x71<<1)
+#define ADAV80X_ADC_L_PEAK_VOL (0x72<<1)
+#define ADAV80X_ADC_R_PEAK_VOL (0x73<<1)
+#define ADAV80X_PLL_CTRL1 (0x74<<1)
+#define ADAV80X_PLL_CTRL2 (0x75<<1)
+#define ADAV80X_ICLK_CTRL1 (0x76<<1)
+#define ADAV80X_ICLK_CTRL2 (0x77<<1)
+#define ADAV80X_PLL_CLK_SRC (0x78<<1)
+
+#define ADAV80X_PLL_OUTE (0x7A<<1)
+#define ADAV80X_ALC_CTRL1 (0x7B<<1)
+
+#elif defined(CONFIG_SPI_MASTER)
+/* from 0x0 to 0x7D */
+#define ADAV80X_NUM_REGS 0x7E
+
+#define ADAV80X_PLAYBACK_CTRL 0x4
+#define ADAV80X_AUX_IN_CTRL 0x5
+#define ADAV80X_REC_CTRL 0x6
+#define ADAV80X_AUX_OUT_CTRL 0x7
+#define ADAV80X_GDELAY_MUTE 0x8
+
+
+#define ADAV80X_TX_CTRL 0xC
+
+#define ADAV80X_DPATH_CTRL1 0x62
+#define ADAV80X_DPATH_CTRL2 0x63
+#define ADAV80X_DAC_CTRL1 0x64
+#define ADAV80X_DAC_CTRL2 0x65
+#define ADAV80X_DAC_CTRL3 0x66
+#define ADAV80X_DAC_CTRL4 0x67
+#define ADAV80X_DAC_L_VOL 0x68
+#define ADAV80X_DAC_R_VOL 0x69
+#define ADAV80X_DAC_L_PEAK_VOL 0x6A
+#define ADAV80X_DAC_R_PEAK_VOL 0x6B
+
+
+#define ADAV80X_ADC_CTRL1 0x6E
+#define ADAV80X_ADC_CTRL2 0x6F
+#define ADAV80X_ADC_L_VOL 0x70
+#define ADAV80X_ADC_R_VOL 0x71
+#define ADAV80X_ADC_L_PEAK_VOL 0x72
+#define ADAV80X_ADC_R_PEAK_VOL 0x73
+#define ADAV80X_PLL_CTRL1 0x74
+#define ADAV80X_PLL_CTRL2 0x75
+#define ADAV80X_ICLK_CTRL1 0x76
+#define ADAV80X_ICLK_CTRL2 0x77
+#define ADAV80X_PLL_CLK_SRC 0x78
+
+#define ADAV80X_PLL_OUTE 0x7A
+#define ADAV80X_ALC_CTRL1 0x7B
+
+#endif
--
1.7.2
3
4
Hello Liam, Mark!
The following two patch is for the current multi-comp
branch with twl4030 related fixes.
I have separated them, so they can be squased to the
corresponding commit in multi-comp branch for now.
The changes in short:
- We do not need the header sound/soc/codecs/twl4030.h
anymore, so remove it
- Fix machine drivers with theis header removal
- The codec no longer get's the former setup data, all
configuration is coming from board files via the
platform_data. So change the code accordingly
- Move the twl4030_priv allocation to a proper place
- Codec can shall go OFF instead of STANDBY, so add back
the idle_bias_off flag
- The MFD driver is twl4030-audio
TODO after the multi-comp is merged:
- Rename the mfd driver to twl4030-audio.
Clean up the internal naming within the mfd
This going to touch many files...
One more notice:
The multi-comp branch does not have the
"ASoC: TWL4030: Capture route runtime DAPM ordering fix" commit
yet, and I have tested my changes on top of that, but it should
not be a big problem, when you rebase this driver.
What do you think?
Peter
---
Peter Ujfalusi (2):
ASoC: multi-comp: twl4030: TI CODECs
ASoC: multi-comp: twl4030: TI OMAP Platform
drivers/mfd/twl-core.c | 2 +-
drivers/mfd/twl4030-codec.c | 4 +-
include/linux/i2c/twl.h | 6 +++-
sound/soc/codecs/twl4030.c | 73 ++++++++++++++++++++---------------------
sound/soc/codecs/twl4030.h | 52 -----------------------------
sound/soc/omap/igep0020.c | 1 -
sound/soc/omap/omap2evm.c | 1 -
sound/soc/omap/omap3beagle.c | 1 -
sound/soc/omap/omap3evm.c | 1 -
sound/soc/omap/omap3pandora.c | 1 -
sound/soc/omap/overo.c | 1 -
sound/soc/omap/sdp3430.c | 4 ++-
sound/soc/omap/zoom2.c | 4 ++-
13 files changed, 50 insertions(+), 101 deletions(-)
delete mode 100644 sound/soc/codecs/twl4030.h
--
1.7.2
3
5
07 Aug '10
Hello,
Changes since v1:
- include plat/mcbsp.c in arch/arm/mach-omap1/devices.c
- Runtime port number configuration based on OMAP type (both omap1 and omap2)
Commit message from the first series:
The following series introduces some cleanups for OMAP platforms in
multi-component branch.
- Enable audio for OMAP1 class
- Registers only the available amount of omap-mcbsp-dai devices for OMAP2,3,
and 4
Please do verify, if the chages are correct, especially the number of McBSP
ports on different devices.
Liam: in case you take this, you can squash this to the corresponding commit.
Since I do not have access at the moment to OMAP1 based board, the changes has
not been tested, but at least it should allow the audio (in theory)..
Peter
---
Peter Ujfalusi (3):
ASoC: multi-comp: OMAP McBSP: use macro for platform_device
ASoC: multi-comp: OMAP McBSP: Enable audio on OMAP1 platform
ASoC: multi-comp: OMAP2,3,4 McBSP: register correct number of ports
arch/arm/mach-omap1/devices.c | 26 +++++++++++++++++
arch/arm/mach-omap2/devices.c | 46 ++++++++++++-------------------
arch/arm/plat-omap/include/plat/mcbsp.h | 7 +++++
3 files changed, 51 insertions(+), 28 deletions(-)
--
1.7.2
3
5
[alsa-devel] [PATCH 1/3] ASoC: Remove /s from widget names on SMDK64xx WM8580
by Mark Brown 06 Aug '10
by Mark Brown 06 Aug '10
06 Aug '10
Otherwise debugfs gets upset when we try to create filenames with /
in them.
Signed-off-by: Mark Brown <broonie(a)opensource.wolfsonmicro.com>
---
sound/soc/s3c24xx/smdk64xx_wm8580.c | 18 +++++++++---------
1 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/sound/soc/s3c24xx/smdk64xx_wm8580.c b/sound/soc/s3c24xx/smdk64xx_wm8580.c
index 07e8e51..5853f66 100644
--- a/sound/soc/s3c24xx/smdk64xx_wm8580.c
+++ b/sound/soc/s3c24xx/smdk64xx_wm8580.c
@@ -138,9 +138,9 @@ static struct snd_soc_ops smdk64xx_ops = {
/* SMDK64xx Playback widgets */
static const struct snd_soc_dapm_widget wm8580_dapm_widgets_pbk[] = {
- SND_SOC_DAPM_HP("Front-L/R", NULL),
- SND_SOC_DAPM_HP("Center/Sub", NULL),
- SND_SOC_DAPM_HP("Rear-L/R", NULL),
+ SND_SOC_DAPM_HP("Front", NULL),
+ SND_SOC_DAPM_HP("Center+Sub", NULL),
+ SND_SOC_DAPM_HP("Rear", NULL),
};
/* SMDK64xx Capture widgets */
@@ -162,16 +162,16 @@ static const struct snd_soc_dapm_route audio_map_tx[] = {
/* SMDK-PAIFRX connections */
static const struct snd_soc_dapm_route audio_map_rx[] = {
/* Front Left/Right are fed VOUT1L/R */
- {"Front-L/R", NULL, "VOUT1L"},
- {"Front-L/R", NULL, "VOUT1R"},
+ {"Front", NULL, "VOUT1L"},
+ {"Front", NULL, "VOUT1R"},
/* Center/Sub are fed VOUT2L/R */
- {"Center/Sub", NULL, "VOUT2L"},
- {"Center/Sub", NULL, "VOUT2R"},
+ {"Center+Sub", NULL, "VOUT2L"},
+ {"Center+Sub", NULL, "VOUT2R"},
/* Rear Left/Right are fed VOUT3L/R */
- {"Rear-L/R", NULL, "VOUT3L"},
- {"Rear-L/R", NULL, "VOUT3R"},
+ {"Rear", NULL, "VOUT3L"},
+ {"Rear", NULL, "VOUT3R"},
};
static int smdk64xx_wm8580_init_paiftx(struct snd_soc_codec *codec)
--
1.7.1
2
3