Alsa-devel
Threads by month
- ----- 2025 -----
- 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
- 7 participants
- 51268 discussions
Hello all,
I've been trying to make Zoom R16 multi track recorder / audio interface /
control surface working with Linux without any success. I've tried this quirk,
but it usually just hang the unit:
{
/* ZOOM R16 in USB 2.0 mode */
USB_DEVICE(0x1686, 0x00dd),
.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
.ifnum = QUIRK_ANY_INTERFACE,
.type = QUIRK_COMPOSITE,
.data = (const struct snd_usb_audio_quirk[]) {
{
.ifnum = 0,
.type = QUIRK_AUDIO_STANDARD_INTERFACE
},
{
.ifnum = 1,
.type = QUIRK_AUDIO_STANDARD_INTERFACE
},
{
.ifnum = 2,
.type = QUIRK_AUDIO_STANDARD_INTERFACE
},
{
.ifnum = 3,
.type = QUIRK_MIDI_STANDARD_INTERFACE
},
{
.ifnum = -1
},
}
}
},
This one doesn't freeze it, but it neither works. No sound with playback.
{
/* ZOOM R16 in USB 2.0 mode */
USB_DEVICE(0x1686, 0x00dd),
.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
.ifnum = QUIRK_ANY_INTERFACE,
.type = QUIRK_COMPOSITE,
.data = (const struct snd_usb_audio_quirk[]) {
{
.ifnum = 0,
.type = QUIRK_AUDIO_STANDARD_INTERFACE,
},
{
.ifnum = 1,
.type = QUIRK_AUDIO_FIXED_ENDPOINT,
.data = &(const struct audioformat) {
.formats = SNDRV_PCM_FMTBIT_S24_3LE,
.channels = 2,
.iface = 1,
.altsetting = 1,
.altset_idx = 1,
.attributes =
UAC_EP_CS_ATTR_SAMPLE_RATE,
.endpoint = 0x03,
.ep_attr = 0x01,
.maxpacksize = 0x6c,
.rates = SNDRV_PCM_RATE_44100 |
SNDRV_PCM_RATE_48000 |
SNDRV_PCM_RATE_88200 |
SNDRV_PCM_RATE_96000,
.rate_min = 44100,
.rate_max = 96000,
.nr_rates = 4,
.rate_table = (unsigned int[]) {
44100, 48000, 88200, 96000
}
}
},
{
.ifnum = 2,
.type = QUIRK_AUDIO_STANDARD_INTERFACE
},
{
.ifnum = 3,
.type = QUIRK_MIDI_STANDARD_INTERFACE
},
{
.ifnum = -1
},
}
}
},
I attached the lsusb -v output. There are couple usb snoop logs.
1) The other, not so great OS plays new device found sound @ 96 kHz:
https://sites.google.com/site/zoomr16linux/technical-information/usbsnoop.l…
2) Short (0.15 sec) .wav @ 44.1 kHz:
https://sites.google.com/site/zoomr16linux/technical-information/usbsnoop2.…
https://sites.google.com/site/zoomr16linux/technical-information/short.wav?…
It would be fun to get this device working with Linux. I'd appreciate a lot
if someone could help me out.
Regards,
Jani
1
1
Hi, quick question for the list. Has MIDI support been implemented
for the hda-intel codec, specifically the sigmatel codec. I tried
playing a MIDI file the other day, and could see the levels bouncing
around, but no sound whatsoever. Basically, does the driver not
support it, or am I doing something wrong?
Thanks,
Nick
--
"Life is not measured by the number of breaths we take, but by the
moments that take our breath away."
3
5
Hi,
I have some trouble with stereo audio through the atmal ssc interface
based on at91-ssc.c.
Unfortunately left and right channels were swapped periodically.
In my environment the codec supplies the BLCK and LRC clocks and
the SSC is configured to transmit one sample on both edges of the LRC clock.
But I guess the audio frames will always start with a frame of the left
channel
while the LRC clock is in an undefined state.
How does normally the audio driver detect when a left and when a right
channel
frame should be send and with which it should start ?
Thanks in advance for your help.
Regards,
Patrick
--
Dipl.-Inf. (FH) Patrick Ziegler
University Of Applied Sciences
Kaiserslautern
Amerikastrasse 1
D-66482 Zweibruecken
Germany
Phone: +49 631 3724 5526
Mail: patrick.ziegler(a)fh-kl.de
http://www.fh-kl.de
http://www.fh-kl.de/fachbereiche/imst/iuk-knowhow.html
3
4

25 Oct '10
Hi,
it seems something in 2.6.36 broke sound for snd-hda-intel with ad198x codecs
(reproducible with Lenovo 3000 N100 laptop, AD1986A codec and with HP Compaq
6910p, AD1981 codec). I have no problems with 2.6.35 kernel.
Sound works right after power on, but after reboot or even driver reload it
does not work until power cycle, of course controls are unmuted. Under "does
not work" I mean that aplay plays nothing, but gives no errors. What info
would be usefull to debug this issue?
Regards
Vasily
2
3
I would like to make sure that all programs that use the sound driver
I wrote are required to use 512 frames per period. Is there a
snd_pcm_hw_constraint function that will allow me to do this? If not,
is this possible another way?
Thanks,
Adam
Adam Rosenberg
Software Engineer
Alcorn McBride Inc.
3300 South Hiawassee
Building 105
Orlando, FL 32835
(407) 296 - 5800 ext. 5490
3
5
From: Jassi Brar <jassi.brar(a)samsung.com>
Hi,
Submitting revised patch series.
Patches 11 through 16 apply to Kgene's tree, rest apply to
Mark Brown's.
Since v1:
a) Use case 16 in set_bfs and default for error
b) Better code comments.
c) Use switch case in i2sv2_i2s_set_clkdiv
d) Use SNDRV_PCM_RATE_8000_96000
e) MAX_I2S -> SAMSUNG_I2S_SECOFF
f) Local namespace cleanup with i2s driver.
------------
Here come patches overhauling the Samsung ASoC support.
The AC97, PCM, SPDIF and ASoC-DMA related code has merely undergone
cosmetic changes - symbol, device & driver renaming and file moving.
A new I2S controller driver has been added to manage Samsung SoCs since
S3C64XX. Older driver has been changed only as is necessary.
Regarding I2S, I have left the s3c24xx series untouched because the
controllers are too different to run by a common driver. S3C2412's I2S
does have some similarities, but not important enough to warrant impact
on new driver design.
The new I2S driver has been designed around the notion of features/quirks.
The newer SoCs have revised version of I2S_0(usually) than previous ones.
So, I2S block is 'specified' in the platform code and the driver works on
that configuration.
For now, Secondary I2S DAI works only with System-DMAC. I2S-Internal DMA
and SRAM will be enabled later.
Testing:-
Simple testing of 5.1 channel and hardware mixing seems to work (though
there seems to be some issue with symmetric_rates in soc-core.c which
would be tried to fix later as saperate issue).
I would appreciate any test-results for GONI and SMARTQ.
I suggest the patches 13,14,16 & 17 go via Kgene's Tree, and the rest via ASoC
tree due to tight dependencies.
1). ASoC: Samsung: Remove redundant AQUILA driver
2). ASoC: Samsung: Rename DMA device
3). ARM: Samsung: Define common audio-dma device
4). ASoC: Samsung: Rename ASoC DMA driver
5). ASoC: Samsung: Rename AC97 platform device
6). ASoC: Samsung: Rename AC97 driver
7). ASoC: Samsung: Rename PCM driver
8). ASoC: Samsung: Generalize DMA driver namespace
9). ASoC: Samsung: Rename s3c64xx I2S device
10). ASoC: Samsung: Add common I2S driver
11). ARM: S3C64XX: I2S: Upgrade platform device
12). ARM: S5P6440: I2S: Upgrade platform device
13). ARM: S5P6442: I2S: Upgrade platform device
14). ARM: S5PC100: I2S: Upgrade platform device
15). ARM: S5PV210: I2S: Upgrade platform device
16). ARM: S5PV310: Add audio platform devices
17). ASoC: SMARTQ: Move to use new I2S driver
18). ASoC: GONI: Move to use new I2S driver
19). ASoC: SMDK64XX: Move to use new I2S driver
20). ASoC: S3C64XX: Remove obsoleted I2S drivers
21). ASoC: SMDK64XX: Rename for other platforms
22). ASoC: SMDK_WM8580: Enable for SMDKC100
23). ASoC: Samsung: Generalize Kconfig symbols
24). ASoC: Samsung: Rename from s3c24xx to samsung
Thanks,
Jassi
3
30
Hi,
I suddenly noticed that sound is not working on 2.6.36; there's no
error, or warning, everything seems to be working, but there's no
sound coming out.
I tried the rc's and AFAICR it was working fine, maybe I changed the
config, but everything seems to be ok. I went back to the rc's and
still couldn't get them to work. 2.6.35.7 works though.
I'm attaching the config.
--
Felipe Contreras
1
0
So I've discovered that my sound card has a "PCM Playback Volume"
control, but changing that control does not alter the volume. This is
not only confusing but also a problem for PulseAudio. (PA merges this
control into it's overall volume, and so when the user moves PA's volume
control, in some ranges nothing happens.)
Interestingly enough, this control does not come from the HDA parser, it
is added by alsactl at boot time...! (Through alsa-lib's
snd_ctl_elem_add_integer, which does an snd_ctl_ioctl.)
So the question is, why is alsactl creating volume controls, and why is
userspace allowed to add controls in the first place, if the kernel
can't use them for anything anyway? That doesn't make sense to me.
This a generic problem, but sound card info, if that matters, is
available here:
https://launchpad.net/bugs/625149
Codec: http://launchpadlibrarian.net/54478760/Card0.Codecs.codec.0.txt
--
David Henningsson, Canonical Ltd.
http://launchpad.net/~diwic
9
73

[alsa-devel] [PATCH - snd-usb-audio 1/1] Creative USB X-Fi volume knob support
by emailmandar@gmail.com 24 Oct '10
by emailmandar@gmail.com 24 Oct '10
24 Oct '10
From: Mandar Joshi <emailmandar(a)gmail.com>
Adds an entry for Creative USB X-Fi to the rc_config array in mixer_quirks.c to allow use of volume knob on the device.
The action of the volume knob is received by lirc when its using the alsa_usb driver.
Signed-off-by: Mandar Joshi <emailmandar(a)gmail.com>
diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c
index e7df1e5..53ce1d2 100644
--- a/sound/usb/mixer_quirks.c
+++ b/sound/usb/mixer_quirks.c
@@ -61,6 +61,7 @@ static const struct rc_config {
{ USB_ID(0x041e, 0x3020), 2, 1, 6, 6, 18, 0x0013 }, /* Audigy 2 NX */
{ USB_ID(0x041e, 0x3040), 2, 2, 6, 6, 2, 0x6e91 }, /* Live! 24-bit */
{ USB_ID(0x041e, 0x3048), 2, 2, 6, 6, 2, 0x6e91 }, /* Toshiba SB0500 */
+ { USB_ID(0x041e, 0x3042), 0, 1, 1, 1, 1, 0x000d }, /* Usb X-Fi */
};
static void snd_usb_soundblaster_remote_complete(struct urb *urb)
--
1.7.1
2
1

Re: [alsa-devel] [PATCH] ALSA: HDA: Enable internal mic on Dell E6410 and Dell E6510
by Takashi Iwai 24 Oct '10
by Takashi Iwai 24 Oct '10
24 Oct '10
At Thu, 21 Oct 2010 17:09:49 +0200,
Diego Elio Pettenò wrote:
>
> From: David Henningsson <david.henningsson(a)canonical.com>
>
> (Ported on top of 2.6.36)
>
> BugLink: http://launchpad.net/bugs/628961
> BugLink: http://launchpad.net/bugs/605047
>
> CC: Diego Elio Pettenò <flameeyes(a)gmail.com>
I'd need sign-offs of you and David.
Could you guys give them?
Takashi
> ---
> sound/pci/hda/patch_sigmatel.c | 13 +++++++++++++
> 1 files changed, 13 insertions(+), 0 deletions(-)
>
> diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
> index c16c5ba..be79c3c 100644
> --- a/sound/pci/hda/patch_sigmatel.c
> +++ b/sound/pci/hda/patch_sigmatel.c
> @@ -1633,6 +1633,13 @@ static unsigned int dell_s14_pin_configs[10] = {
> 0x40f000f0, 0x40f000f0,
> };
>
> +/* Deliberately turn off 0x0f (Dock Mic) to make it choose Int Mic instead */
> +static unsigned int dell_e6410_pin_configs[10] = {
> + 0x04a11020, 0x0421101f, 0x400000f0, 0x90170110,
> + 0x23011050, 0x40f000f0, 0x400000f0, 0x90a60130,
> + 0x40f000f0, 0x40f000f0,
> +};
> +
> static unsigned int hp_dv7_4000_pin_configs[10] = {
> 0x03a12050, 0x0321201f, 0x40f000f0, 0x90170110,
> 0x40f000f0, 0x40f000f0, 0x90170110, 0xd5a30140,
> @@ -1643,6 +1650,7 @@ static unsigned int *stac92hd83xxx_brd_tbl[STAC_92HD83XXX_MODELS] = {
> [STAC_92HD83XXX_REF] = ref92hd83xxx_pin_configs,
> [STAC_92HD83XXX_PWR_REF] = ref92hd83xxx_pin_configs,
> [STAC_DELL_S14] = dell_s14_pin_configs,
> + [STAC_DELL_E6410] = dell_e6410_pin_configs,
> [STAC_HP_DV7_4000] = hp_dv7_4000_pin_configs,
> };
>
> @@ -1651,6 +1659,7 @@ static const char *stac92hd83xxx_models[STAC_92HD83XXX_MODELS] = {
> [STAC_92HD83XXX_REF] = "ref",
> [STAC_92HD83XXX_PWR_REF] = "mic-ref",
> [STAC_DELL_S14] = "dell-s14",
> + [STAC_DELL_E6410] = "dell-e6410",
> [STAC_92HD83XXX_HP] = "hp",
> [STAC_HP_DV7_4000] = "hp-dv7-4000",
> };
> @@ -1663,6 +1672,10 @@ static struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = {
> "DFI LanParty", STAC_92HD83XXX_REF),
> SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02ba,
> "unknown Dell", STAC_DELL_S14),
> + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x040a,
> + "Dell E6410", STAC_DELL_E6410),
> + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x040b,
> + "Dell E6510", STAC_DELL_E6410),
> SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xff00, 0x3600,
> "HP", STAC_92HD83XXX_HP),
> {} /* terminator */
> --
> 1.7.3.1
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo(a)vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
>
2
1
> Hmm, there is no feature unit in this dump, so the volume is most
> probably set with an vendor-specific USB request. Unless the Windows
> driver does something similar than PulseAudio and handles the volume
> level control in software (iow, modify each sample before sending it to
> the hardware) rather than setting any actual hardware volume level.
Daniel, you are right, Its the driver thing.
Feb 2009, I was dealing this the same issue and
James Courtier-Dutton from this list pointed out that the device has no
hardware based mixer controls which is why alsamixer does not find anything.
He suggested using SoftVol.
I've been using dmix and Softvol for volume control whenever I need it.
This is the ~/.asoundrc I use http://mndar.phpnet.us/usbxfi/files/asoundrc.log
The device has a volume knob. I had left the issue of the volume knob
alone until a few days back..
I was about the post this when I came across the query from Matti Picus.
This is how it works.
The volume knob sends an interrupt via endpoint 0x83 containing 0xC0
0x00 whenever it is
rotated clockwise,anti-clockwise or pressed.
After this a control message is sent to the device to retrieve which
of the 3 actions it was.
The control packet sent is 0xa1 0x85 0x00 0x00 0x00 0x00 0x04 0x00
We get a 1 byte response.
0x0F for anti-clockwise rotation. 0x0D for press and 0x10 for
clockwise rotation.
I've tested this using a simple kernel module to handle just the
volume knob and it works fine.
The quick little code I've written does the above, then sets a sysfs
attribute and sends a kobject_uevent.
Udev rules execute a command depending on the value of this sysfs
attribute. (Having some issues here but anyway...)
Since the volume is entirely a software thing, I figure this might be
a good way of letting userspace know about the volume knob.
Using softvol we can have a Master volume control and then we can use
a command like amixer in udev rules to change the volume.
Or since events are passed to HAL, something could be done there.
I do not know much about the usbaudio driver but does this seem like
something that can be done from within the usbaudio driver ?
-Mandar Joshi
1
2
Some final updates prior to the ALSA pull request.
Thanks
Liam
---
The following changes since commit ad5e4655f9a920b1cc13972e0389eaf9e0ba10b3:
ASoC: remove duplicated include for nuc900 (2010-10-05 19:26:00 -0700)
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/lrg/asoc-2.6.git for-2.6.37
Jarkko Nikula (1):
ASoC: omap: Remove needless prints from machine drivers
Peter Ujfalusi (3):
ASoC: tlv320dac33: Control for line output gain
ASoC: tpa6130a2: Error handling for broken chip
ASoC: tlv320dac33: Use usleep_range for delays
sound/soc/codecs/tlv320dac33.c | 28 ++++++++++++++++++++++++----
sound/soc/codecs/tpa6130a2.c | 28 ++++++++++++++++++++++------
sound/soc/omap/am3517evm.c | 4 +---
sound/soc/omap/igep0020.c | 4 +---
sound/soc/omap/omap2evm.c | 4 +---
sound/soc/omap/omap3beagle.c | 4 +---
sound/soc/omap/omap3evm.c | 4 +---
sound/soc/omap/sdp3430.c | 4 +---
sound/soc/omap/sdp4430.c | 4 +---
sound/soc/omap/zoom2.c | 4 +---
10 files changed, 54 insertions(+), 34 deletions(-)
2
1

[alsa-devel] [PATCH 0/2] ASoC: twl4030/tlv320dac33: convert to use usleep_range
by Peter Ujfalusi 23 Oct '10
by Peter Ujfalusi 23 Oct '10
23 Oct '10
Hello,
remove the long busy loop delays from the drivers, and replace it with
more civilized usleep_range or in case of twl4030 msleep (when the
needed delay is really long)
---
Peter Ujfalusi (2):
ASoC: tlv320dac33: Use usleep_range for delays
ASoC: TWL4030: Use usleep_range when appropriate
sound/soc/codecs/tlv320dac33.c | 10 ++++++----
sound/soc/codecs/twl4030.c | 33 ++++++++++++++++++++++++++-------
2 files changed, 32 insertions(+), 11 deletions(-)
--
1.7.3.1
3
5
The following changes since commit c429ffbe038a649d121e6cecba5cf66777f39370:
ASoC: WM8580: Remove useless assignment (2010-10-19 03:07:10 -0700)
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound-2.6.git for-2.6.37
Dimitris Papastamos (2):
ASoC: soc-core: Fix codec->name memory leak
ASoC: max98088: Staticise m98088_eq_band
sound/soc/codecs/max98088.c | 2 +-
sound/soc/soc-core.c | 1 +
2 files changed, 2 insertions(+), 1 deletions(-)
2
3

Re: [alsa-devel] [PATCH - ca0106 1/6] ALSA: ca0106 - add Sound Blaster 5.1vx info.
by Takashi Iwai 23 Oct '10
by Takashi Iwai 23 Oct '10
23 Oct '10
At Sat, 23 Oct 2010 17:18:10 +1100,
Andy Owen wrote:
>
> On Thu, 2010-10-21 at 23:16 +0200, Takashi Iwai wrote:
> > Thanks for patches.
> > All changes look good in your patches, but could you give more
> > changelog for clarifying a bit more details what the patch is
> > actually for?
>
> Sure.
>
> Before I send another round of patches, could I just check that sending
> to patch(a)alsa-project.org and cc-ing alsa-devel(a)alsa-project.org is
> correct. I seem to be the only person double spamming like this, which
> I'm doing just because the wiki says to:
>
> http://www.alsa-project.org/main/index.php/GIT_Server#Occasional_Developers
>
> (and if the wiki is out of date, and someone feels like editing it to be
> right, then that will save me from having to make an account :)
It's fine that you put it to Cc. Or you can put my address directly to
Cc. Otherwise I'll have to look down to alsa-devel ML folder, and
the posts are even sometimes delayed due to non-subscribers
filtering...
thanks,
Takashi
1
0
Hi all,
I have a problem running the RME MADIface card at 192 kHz. At that
speed the number of channels for the card is reduced to 16. I can set
the sampling rate to 192 kHz using:
# amixer -c 1 cset numid=2 9
numid=2,iface=MIXER,name='Sample Clock Source'
; type=ENUMERATED,access=rw------,values=1,items=10
; Item #0 'AutoSync'
; Item #1 'Internal 32.0 kHz'
; Item #2 'Internal 44.1 kHz'
; Item #3 'Internal 48.0 kHz'
; Item #4 'Internal 64.0 kHz'
; Item #5 'Internal 88.2 kHz'
; Item #6 'Internal 96.0 kHz'
; Item #7 'Internal 128.0 kHz'
; Item #8 'Internal 176.4 kHz'
; Item #9 'Internal 192.0 kHz'
: values=9
but when I try to read data at 192 kHz I always get a :
Invalid argument
from
the snd_pcm_hw_params_set_channels(...)
and
snd_pcm_hw_params(...)
functions when I try to set the number of channels. The
snd_pcm_hw_params_get_channels_max(...)
snd_pcm_hw_params_get_channels_min(...)
functions also seems to return the wrong number of max and min number
of channels.
And, jackd will not start using 192 kHz. See the thread here:
http://www.rme-audio.de/forum/viewtopic.php?id=9169
What is needed to get this card running at 192 kHz?
Regards,
/Fredrik
--
Fredrik Lingvall, PhD
E-mail: fl(a)ifi.uio.no, fredrik.lingvall(a)gmail.com
Web: http://folk.uio.no/fl/
3
6

[alsa-devel] [PATCH - ca0106 1/6] ALSA: ca0106 - add Sound Blaster 5.1vx info.
by Andy Owen 23 Oct '10
by Andy Owen 23 Oct '10
23 Oct '10
Signed-off-by: Andy Owen <andy-alsa(a)ultra-premium.com>
diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c
index 8e69620..6dc9a5d 100644
--- a/sound/pci/ca0106/ca0106_main.c
+++ b/sound/pci/ca0106/ca0106_main.c
@@ -239,6 +239,16 @@ static struct snd_ca0106_details ca0106_chip_details[] = {
.gpio_type = 1,
.i2c_adc = 1,
.spi_dac = 1 } ,
+ /* Sound Blaster 5.1vx
+ * Tested: Playback on front, rear, center/lfe speakers
+ * Not-Tested: Capture
+ */
+ { .serial = 0x10041102,
+ .name = "Sound Blaster 5.1vx [SB1070]",
+ .gpio_type = 1,
+ .i2c_adc = 0,
+ .spi_dac = 1
+ } ,
/* MSI K8N Diamond Motherboard with onboard SB Live 24bit without AC97 */
/* SB0438
* CTRL:CA0106-DAT
--
1.7.3.1.127.g1bb28
2
7

22 Oct '10
On 10/21/2010 12:01 AM, akpm(a)linux-foundation.org wrote:
> The mm-of-the-moment snapshot 2010-10-20-15-01 has been uploaded to
Hi, I've lost sound with my intel hda (sigmatel) in this release
(regression against mmotm 2010-10-13-17-13).
All outputs were silented at level 0 after reboot, but even after
setting them non-zero in alsamixer -D hw, no sound can be heard by:
mplayer -ao alsa:device=hw /usr/share/sounds/alsa/Front_Center.wav
I don't knwo if it's related, but aplay complains like (even if I pass
-c 2):
aplay -D hw /usr/share/sounds/alsa/Front_Center.wav
Playing WAVE '/usr/share/sounds/alsa/Front_Center.wav' : Signed 16 bit
Little Endian, Rate 48000 Hz, Mono
aplay: set_params:1065: Channels count non available
alsa-info:
http://www.alsa-project.org/db/?f=a7a09703bcc8c43386c87a984e513ce35fc91ca4
regards,
--
js
5
27

22 Oct '10
Hello,
I have a sound problem with an HP DV8 (HP Pavilion DV8-1290-ez).
I have two sound cards 01:00.1 Audio device: nVidia Corporation High
Definition Audio Controller (rev a1) and 00:1b.0 Audio device: Intel
Corporation 5 Series/3400 Series Chipset High Definition Audio (rev 05)
the sound works properly with the internal speakers of the laptop, but
nothing comes from external speakers.
Here are the dtails of my laptop config :
http://www.alsa-project.org/db/?f=de70b54ecd18f28494b08e05d865779b9776686b
I think i have no sound with mic in amsn or skype.
Waiting for your response.
With my best regards.
Jacques Disner
LA CAVE A POLYTE SA
Jacques Disner
Vigneron-Encaveur
5 Rue de la Place
CH-1955 Chamoson
Tel : +41 (79) 220 35 11
Fax : +41 (27) 306 26 56
Site Internet : http://www.polyte.ch
E-Mail : info(a)polyte.ch
1
0

[alsa-devel] [PATCH] ALSA: HDA: Correctly apply position_fix quirks for ATI and VIA controllers
by David Henningsson 22 Oct '10
by David Henningsson 22 Oct '10
22 Oct '10
Position_fix quirks for specific machines now override the default
position_fix behavior for all HDA controllers.
BugLink: http://launchpad.net/bugs/465942
BugLink: http://launchpad.net/bugs/580749
BugLink: http://launchpad.net/bugs/587546
Signed-off-by: David Henningsson <david.henningsson(a)canonical.com>
--
David Henningsson, Canonical Ltd.
http://launchpad.net/~diwic
3
4
From: Jassi Brar <jassi.brar(a)samsung.com>
The I2S controllers since S3C64XX are incremental revisions, with
a new feature added to the last one. The programming i/f doesn't
conflict between these revisions, so it is possible to have one
common driver that could manage various versions of I2S (v3, 4 & 5)
Signed-off-by: Jassi Brar <jassi.brar(a)samsung.com>
---
arch/arm/plat-samsung/include/plat/audio.h | 24 +
sound/soc/s3c24xx/Kconfig | 3 +
sound/soc/s3c24xx/Makefile | 2 +
sound/soc/s3c24xx/i2s.c | 1251 ++++++++++++++++++++++++++++
sound/soc/s3c24xx/i2s.h | 29 +
5 files changed, 1309 insertions(+), 0 deletions(-)
create mode 100644 sound/soc/s3c24xx/i2s.c
create mode 100644 sound/soc/s3c24xx/i2s.h
diff --git a/arch/arm/plat-samsung/include/plat/audio.h b/arch/arm/plat-samsung/include/plat/audio.h
index e32f9ed..b72ad03 100644
--- a/arch/arm/plat-samsung/include/plat/audio.h
+++ b/arch/arm/plat-samsung/include/plat/audio.h
@@ -16,10 +16,34 @@
#define S3C64XX_AC97_GPE 1
extern void s3c64xx_ac97_setup_gpio(int);
+struct samsung_i2s {
+/* If the Primary DAI has 5.1 Channels */
+#define QUIRK_PRI_6CHAN (1 << 0)
+/* If the I2S block has a Stereo Overlay Channel */
+#define QUIRK_SEC_DAI (1 << 1)
+/*
+ * If the I2S block has no internal prescalar or MUX (I2SMOD[10] bit)
+ * The Machine driver must provide suitably set clock to the I2S block.
+ */
+#define QUIRK_NO_MUXPSR (1 << 2)
+#define QUIRK_NEED_RSTCLR (1 << 3)
+ /* Quirks of the I2S controller */
+ u32 quirks;
+
+ /*
+ * Array of clock names that can be used to generate I2S signals.
+ * Also corresponds to clocks of I2SMOD[10]
+ */
+ const char **src_clk;
+};
+
/**
* struct s3c_audio_pdata - common platform data for audio device drivers
* @cfg_gpio: Callback function to setup mux'ed pins in I2S/PCM/AC97 mode
*/
struct s3c_audio_pdata {
int (*cfg_gpio)(struct platform_device *);
+ union {
+ struct samsung_i2s i2s;
+ } type;
};
diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig
index 6efdf65..20fe288 100644
--- a/sound/soc/s3c24xx/Kconfig
+++ b/sound/soc/s3c24xx/Kconfig
@@ -40,6 +40,9 @@ config SND_S5P_SOC_SPDIF
tristate
select SND_SOC_SPDIF
+config SND_SAMSUNG_I2S
+ tristate
+
config SND_S3C24XX_SOC_NEO1973_WM8753
tristate "SoC I2S Audio support for NEO1973 - WM8753"
depends on SND_S3C24XX_SOC && MACH_NEO1973_GTA01
diff --git a/sound/soc/s3c24xx/Makefile b/sound/soc/s3c24xx/Makefile
index 93de2a0..1d6fc07 100644
--- a/sound/soc/s3c24xx/Makefile
+++ b/sound/soc/s3c24xx/Makefile
@@ -8,6 +8,7 @@ snd-soc-s3c64xx-i2s-v4-objs := s3c64xx-i2s-v4.o
snd-soc-s3c-i2s-v2-objs := s3c-i2s-v2.o
snd-soc-samsung-spdif-objs := spdif.o
snd-soc-pcm-objs := pcm.o
+snd-soc-i2s-objs := i2s.o
obj-$(CONFIG_SND_S3C24XX_SOC) += snd-soc-s3c24xx.o
obj-$(CONFIG_SND_S3C24XX_SOC_I2S) += snd-soc-s3c24xx-i2s.o
@@ -18,6 +19,7 @@ obj-$(CONFIG_SND_S3C64XX_SOC_I2S_V4) += snd-soc-s3c64xx-i2s-v4.o
obj-$(CONFIG_SND_S3C_I2SV2_SOC) += snd-soc-s3c-i2s-v2.o
obj-$(CONFIG_SND_S5P_SOC_SPDIF) += snd-soc-samsung-spdif.o
obj-$(CONFIG_SND_S3C_SOC_PCM) += snd-soc-pcm.o
+obj-$(CONFIG_SND_SAMSUNG_I2S) += snd-soc-i2s.o
# S3C24XX Machine Support
snd-soc-jive-wm8750-objs := jive_wm8750.o
diff --git a/sound/soc/s3c24xx/i2s.c b/sound/soc/s3c24xx/i2s.c
new file mode 100644
index 0000000..6869f51
--- /dev/null
+++ b/sound/soc/s3c24xx/i2s.c
@@ -0,0 +1,1251 @@
+/* sound/soc/s3c24xx/i2s.c
+ *
+ * ALSA SoC Audio Layer - Samsung I2S Controller driver
+ *
+ * Copyright (c) 2010 Samsung Electronics Co. Ltd.
+ * Jaswinder Singh <jassi.brar(a)samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include <plat/audio.h>
+
+#include "dma.h"
+#include "i2s.h"
+
+#define I2SCON 0x0
+#define I2SMOD 0x4
+#define I2SFIC 0x8
+#define I2SPSR 0xc
+#define I2STXD 0x10
+#define I2SRXD 0x14
+#define I2SFICS 0x18
+#define I2STXDS 0x1c
+
+#define CON_RSTCLR (1 << 31)
+#define CON_FRXOFSTATUS (1 << 26)
+#define CON_FRXORINTEN (1 << 25)
+#define CON_FTXSURSTAT (1 << 24)
+#define CON_FTXSURINTEN (1 << 23)
+#define CON_TXSDMA_PAUSE (1 << 20)
+#define CON_TXSDMA_ACTIVE (1 << 18)
+
+#define CON_FTXURSTATUS (1 << 17)
+#define CON_FTXURINTEN (1 << 16)
+#define CON_TXFIFO2_EMPTY (1 << 15)
+#define CON_TXFIFO1_EMPTY (1 << 14)
+#define CON_TXFIFO2_FULL (1 << 13)
+#define CON_TXFIFO1_FULL (1 << 12)
+
+#define CON_LRINDEX (1 << 11)
+#define CON_TXFIFO_EMPTY (1 << 10)
+#define CON_RXFIFO_EMPTY (1 << 9)
+#define CON_TXFIFO_FULL (1 << 8)
+#define CON_RXFIFO_FULL (1 << 7)
+#define CON_TXDMA_PAUSE (1 << 6)
+#define CON_RXDMA_PAUSE (1 << 5)
+#define CON_TXCH_PAUSE (1 << 4)
+#define CON_RXCH_PAUSE (1 << 3)
+#define CON_TXDMA_ACTIVE (1 << 2)
+#define CON_RXDMA_ACTIVE (1 << 1)
+#define CON_ACTIVE (1 << 0)
+
+#define MOD_OPCLK_CDCLK_OUT (0 << 30)
+#define MOD_OPCLK_CDCLK_IN (1 << 30)
+#define MOD_OPCLK_BCLK_OUT (2 << 30)
+#define MOD_OPCLK_PCLK (3 << 30)
+#define MOD_OPCLK_MASK (3 << 30)
+#define MOD_TXS_IDMA (1 << 28) /* Sec_TXFIFO use I-DMA */
+
+#define MOD_BLCS_SHIFT 26
+#define MOD_BLCS_16BIT (0 << MOD_BLCS_SHIFT)
+#define MOD_BLCS_8BIT (1 << MOD_BLCS_SHIFT)
+#define MOD_BLCS_24BIT (2 << MOD_BLCS_SHIFT)
+#define MOD_BLCS_MASK (3 << MOD_BLCS_SHIFT)
+#define MOD_BLCP_SHIFT 24
+#define MOD_BLCP_16BIT (0 << MOD_BLCP_SHIFT)
+#define MOD_BLCP_8BIT (1 << MOD_BLCP_SHIFT)
+#define MOD_BLCP_24BIT (2 << MOD_BLCP_SHIFT)
+#define MOD_BLCP_MASK (3 << MOD_BLCP_SHIFT)
+
+#define MOD_C2DD_HHALF (1 << 21) /* Discard Higher-half */
+#define MOD_C2DD_LHALF (1 << 20) /* Discard Lower-half */
+#define MOD_C1DD_HHALF (1 << 19)
+#define MOD_C1DD_LHALF (1 << 18)
+#define MOD_DC2_EN (1 << 17)
+#define MOD_DC1_EN (1 << 16)
+#define MOD_BLC_16BIT (0 << 13)
+#define MOD_BLC_8BIT (1 << 13)
+#define MOD_BLC_24BIT (2 << 13)
+#define MOD_BLC_MASK (3 << 13)
+
+#define MOD_IMS_SYSMUX (1 << 10)
+#define MOD_SLAVE (1 << 11)
+#define MOD_TXONLY (0 << 8)
+#define MOD_RXONLY (1 << 8)
+#define MOD_TXRX (2 << 8)
+#define MOD_MASK (3 << 8)
+#define MOD_LR_LLOW (0 << 7)
+#define MOD_LR_RLOW (1 << 7)
+#define MOD_SDF_IIS (0 << 5)
+#define MOD_SDF_MSB (1 << 5)
+#define MOD_SDF_LSB (2 << 5)
+#define MOD_SDF_MASK (3 << 5)
+#define MOD_RCLK_256FS (0 << 3)
+#define MOD_RCLK_512FS (1 << 3)
+#define MOD_RCLK_384FS (2 << 3)
+#define MOD_RCLK_768FS (3 << 3)
+#define MOD_RCLK_MASK (3 << 3)
+#define MOD_BCLK_32FS (0 << 1)
+#define MOD_BCLK_48FS (1 << 1)
+#define MOD_BCLK_16FS (2 << 1)
+#define MOD_BCLK_24FS (3 << 1)
+#define MOD_BCLK_MASK (3 << 1)
+#define MOD_8BIT (1 << 0)
+
+#define MOD_CDCLKCON (1 << 12)
+
+#define PSR_PSREN (1 << 15)
+
+#define FIC_TX2COUNT(x) (((x) >> 24) & 0xf)
+#define FIC_TX1COUNT(x) (((x) >> 16) & 0xf)
+
+#define FIC_TXFLUSH (1 << 15)
+#define FIC_RXFLUSH (1 << 7)
+#define FIC_TXCOUNT(x) (((x) >> 8) & 0xf)
+#define FIC_RXCOUNT(x) (((x) >> 0) & 0xf)
+#define FICS_TXCOUNT(x) (((x) >> 8) & 0x7f)
+
+#define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t)
+
+struct i2s_dai {
+ /* Platform device for this DAI */
+ struct platform_device *pdev;
+ /* IOREMAP'd SFRs */
+ void __iomem *addr;
+ /* Physical base address of SFRs */
+ u32 base;
+ /* Rate of RCLK source clock */
+ unsigned long rclk_srcrate;
+ /* Frame Clock */
+ unsigned frmclk;
+ /*
+ * Specifically requested RCLK,BCLK by MACHINE Driver.
+ * 0 indicates CPU driver is free to choose any value.
+ */
+ unsigned rfs, bfs;
+ /* I2S Controller's core clock */
+ struct clk *clk;
+ /* Clock for generating I2S signals */
+ struct clk *op_clk;
+ /* Array of clock names for op_clk */
+ const char **src_clk;
+ /* Pointer to the Primary_Fifo if this is Sec_Fifo, NULL otherwise */
+ struct i2s_dai *pri_dai;
+ /* Pointer to the Secondary_Fifo if it has one, NULL otherwise */
+ struct i2s_dai *sec_dai;
+#define DAI_OPENED (1 << 0) /* Dai is opened */
+#define DAI_MANAGER (1 << 1) /* Dai is the manager */
+ unsigned mode;
+ /* Driver for this DAI */
+ struct snd_soc_dai_driver s3c_i2s_drv;
+ /* DMA parameters */
+ struct s3c_dma_params dma_playback;
+ struct s3c_dma_params dma_capture;
+ u32 quirks;
+ u32 suspend_i2smod;
+ u32 suspend_i2scon;
+ u32 suspend_i2spsr;
+};
+
+/* Lock for cross i/f checks */
+static DEFINE_SPINLOCK(lock);
+
+/* If this is the 'overlay' stereo DAI */
+static inline bool is_secondary(struct i2s_dai *i2s)
+{
+ return i2s->pri_dai ? true : false;
+}
+
+/* If operating in SoC-Slave mode */
+static inline bool is_slave(struct i2s_dai *i2s)
+{
+ return (readl(i2s->addr + I2SMOD) & MOD_SLAVE) ? true : false;
+}
+
+/* If this interface of the controller is transmitting data */
+static inline bool tx_active(struct i2s_dai *i2s)
+{
+ u32 active;
+
+ if (!i2s)
+ return false;
+
+ active = readl(i2s->addr + I2SMOD);
+
+ if (is_secondary(i2s))
+ active &= CON_TXSDMA_ACTIVE;
+ else
+ active &= CON_TXDMA_ACTIVE;
+
+ return active ? true : false;
+}
+
+/* If the other interface of the controller is transmitting data */
+static inline bool other_tx_active(struct i2s_dai *i2s)
+{
+ struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
+
+ return tx_active(other);
+}
+
+/* If any interface of the controller is transmitting data */
+static inline bool any_tx_active(struct i2s_dai *i2s)
+{
+ return tx_active(i2s) || other_tx_active(i2s);
+}
+
+/* If this interface of the controller is receiving data */
+static inline bool rx_active(struct i2s_dai *i2s)
+{
+ u32 active;
+
+ if (!i2s)
+ return false;
+
+ active = readl(i2s->addr + I2SMOD) & CON_RXDMA_ACTIVE;
+
+ return active ? true : false;
+}
+
+/* If the other interface of the controller is receiving data */
+static inline bool other_rx_active(struct i2s_dai *i2s)
+{
+ struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
+
+ return rx_active(other);
+}
+
+/* If any interface of the controller is receiving data */
+static inline bool any_rx_active(struct i2s_dai *i2s)
+{
+ return rx_active(i2s) || other_rx_active(i2s);
+}
+
+/* If the other DAI is transmitting or receiving data */
+static inline bool other_active(struct i2s_dai *i2s)
+{
+ return other_rx_active(i2s) || other_tx_active(i2s);
+}
+
+/* If this DAI is transmitting or receiving data */
+static inline bool this_active(struct i2s_dai *i2s)
+{
+ return tx_active(i2s) || rx_active(i2s);
+}
+
+/* If the controller is active anyway */
+static inline bool any_active(struct i2s_dai *i2s)
+{
+ return this_active(i2s) || other_active(i2s);
+}
+
+static inline struct i2s_dai *to_info(struct snd_soc_dai *dai)
+{
+ return snd_soc_dai_get_drvdata(dai);
+}
+
+static inline bool is_opened(struct i2s_dai *i2s)
+{
+ if (i2s && (i2s->mode & DAI_OPENED))
+ return true;
+ else
+ return false;
+}
+
+static inline bool is_manager(struct i2s_dai *i2s)
+{
+ if (is_opened(i2s) && (i2s->mode & DAI_MANAGER))
+ return true;
+ else
+ return false;
+}
+
+/* Read RCLK of I2S (in multiples of LRCLK) */
+static inline unsigned get_rfs(struct i2s_dai *i2s)
+{
+ u32 rfs = (readl(i2s->addr + I2SMOD) >> 3) & 0x3;
+
+ switch (rfs) {
+ case 3: return 768;
+ case 2: return 384;
+ case 1: return 512;
+ default: return 256;
+ }
+}
+
+/* Write RCLK of I2S (in multiples of LRCLK) */
+static inline void set_rfs(struct i2s_dai *i2s, unsigned rfs)
+{
+ u32 mod = readl(i2s->addr + I2SMOD);
+
+ mod &= ~MOD_RCLK_MASK;
+
+ switch (rfs) {
+ case 768:
+ mod |= MOD_RCLK_768FS;
+ break;
+ case 512:
+ mod |= MOD_RCLK_512FS;
+ break;
+ case 384:
+ mod |= MOD_RCLK_384FS;
+ break;
+ default:
+ mod |= MOD_RCLK_256FS;
+ break;
+ }
+
+ writel(mod, i2s->addr + I2SMOD);
+}
+
+/* Read Bit-Clock of I2S (in multiples of LRCLK) */
+static inline unsigned get_bfs(struct i2s_dai *i2s)
+{
+ u32 bfs = (readl(i2s->addr + I2SMOD) >> 1) & 0x3;
+
+ switch (bfs) {
+ case 3: return 24;
+ case 2: return 16;
+ case 1: return 48;
+ default: return 32;
+ }
+}
+
+/* Write Bit-Clock of I2S (in multiples of LRCLK) */
+static inline void set_bfs(struct i2s_dai *i2s, unsigned bfs)
+{
+ u32 mod = readl(i2s->addr + I2SMOD);
+
+ mod &= ~MOD_BCLK_MASK;
+
+ switch (bfs) {
+ case 48:
+ mod |= MOD_BCLK_48FS;
+ break;
+ case 32:
+ mod |= MOD_BCLK_32FS;
+ break;
+ case 24:
+ mod |= MOD_BCLK_24FS;
+ break;
+ default:
+ mod |= MOD_BCLK_16FS;
+ break;
+ }
+
+ writel(mod, i2s->addr + I2SMOD);
+}
+
+/* Sample-Size */
+static inline int get_blc(struct i2s_dai *i2s)
+{
+ int blc = readl(i2s->addr + I2SMOD);
+
+ blc = (blc >> 13) & 0x3;
+
+ switch (blc) {
+ case 2: return 24;
+ case 1: return 8;
+ default: return 16;
+ }
+}
+
+/* TX Channel Control */
+static void s3c_i2sv2_txctrl(struct i2s_dai *i2s, int on)
+{
+ void __iomem *addr = i2s->addr;
+ u32 con = readl(addr + I2SCON);
+ u32 mod = readl(addr + I2SMOD) & ~MOD_MASK;
+
+ if (on) {
+ con |= CON_ACTIVE;
+ con &= ~CON_TXCH_PAUSE;
+
+ if (is_secondary(i2s)) {
+ con |= CON_TXSDMA_ACTIVE;
+ con &= ~CON_TXSDMA_PAUSE;
+ } else {
+ con |= CON_TXDMA_ACTIVE;
+ con &= ~CON_TXDMA_PAUSE;
+ }
+
+ if (any_rx_active(i2s))
+ mod |= MOD_TXRX;
+ else
+ mod |= MOD_TXONLY;
+ } else {
+ if (is_secondary(i2s)) {
+ con |= CON_TXSDMA_PAUSE;
+ con &= ~CON_TXSDMA_ACTIVE;
+ } else {
+ con |= CON_TXDMA_PAUSE;
+ con &= ~CON_TXDMA_ACTIVE;
+ }
+
+ if (other_tx_active(i2s)) {
+ writel(con, addr + I2SCON);
+ return;
+ }
+
+ con |= CON_TXCH_PAUSE;
+
+ if (any_rx_active(i2s))
+ mod |= MOD_RXONLY;
+ else
+ con &= ~CON_ACTIVE;
+ }
+
+ writel(mod, addr + I2SMOD);
+ writel(con, addr + I2SCON);
+}
+
+/* RX Channel Control */
+static void s3c_i2sv2_rxctrl(struct i2s_dai *i2s, int on)
+{
+ void __iomem *addr = i2s->addr;
+ u32 con = readl(addr + I2SCON);
+ u32 mod = readl(addr + I2SMOD) & ~MOD_MASK;
+
+ if (on) {
+ con |= CON_RXDMA_ACTIVE | CON_ACTIVE;
+ con &= ~(CON_RXDMA_PAUSE | CON_RXCH_PAUSE);
+
+ if (any_tx_active(i2s))
+ mod |= MOD_TXRX;
+ else
+ mod |= MOD_RXONLY;
+ } else {
+ con |= CON_RXDMA_PAUSE | CON_RXCH_PAUSE;
+ con &= ~CON_RXDMA_ACTIVE;
+
+ if (any_tx_active(i2s))
+ mod |= MOD_TXONLY;
+ else
+ con &= ~CON_ACTIVE;
+ }
+
+ writel(mod, addr + I2SMOD);
+ writel(con, addr + I2SCON);
+}
+
+/* Flush FIFO of an interface */
+static inline void s3c_i2sv2_fifo(struct i2s_dai *i2s, u32 flush)
+{
+ void __iomem *fic;
+ u32 val;
+
+ if (!i2s)
+ return;
+
+ if (is_secondary(i2s))
+ fic = i2s->addr + I2SFICS;
+ else
+ fic = i2s->addr + I2SFIC;
+
+ /* Flush the FIFO */
+ writel(readl(fic) | flush, fic);
+
+ /* Be patient */
+ val = msecs_to_loops(1) / 1000; /* 1 usec */
+ while (--val)
+ cpu_relax();
+
+ writel(readl(fic) & ~flush, fic);
+}
+
+static int s3c_i2sv2_set_sysclk(struct snd_soc_dai *dai,
+ int clk_id, unsigned int rfs, int dir)
+{
+ struct i2s_dai *i2s = to_info(dai);
+ struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
+ u32 mod = readl(i2s->addr + I2SMOD);
+
+ switch (clk_id) {
+ case SAMSUNG_I2S_CDCLK:
+ /* Shouldn't matter in GATING(CLOCK_IN) mode */
+ if (dir == SND_SOC_CLOCK_IN)
+ rfs = 0;
+
+ if ((rfs && other->rfs && (other->rfs != rfs)) ||
+ (any_active(i2s) &&
+ (((dir == SND_SOC_CLOCK_IN)
+ && !(mod & MOD_CDCLKCON)) ||
+ ((dir == SND_SOC_CLOCK_OUT)
+ && (mod & MOD_CDCLKCON))))) {
+ dev_err(&i2s->pdev->dev,
+ "%s:%d Other DAI busy\n", __func__, __LINE__);
+ return -EAGAIN;
+ }
+
+ if (dir == SND_SOC_CLOCK_IN)
+ mod |= MOD_CDCLKCON;
+ else
+ mod &= ~MOD_CDCLKCON;
+
+ i2s->rfs = rfs;
+ break;
+
+ case SAMSUNG_I2S_RCLKSRC_0: /* clock corrsponding to IISMOD[10] := 0 */
+ case SAMSUNG_I2S_RCLKSRC_1: /* clock corrsponding to IISMOD[10] := 1 */
+ if ((i2s->quirks & QUIRK_NO_MUXPSR)
+ || (clk_id == SAMSUNG_I2S_RCLKSRC_0))
+ clk_id = 0;
+ else
+ clk_id = 1;
+
+ if (!any_active(i2s)) {
+ if (i2s->op_clk) {
+ if ((clk_id && !(mod & MOD_IMS_SYSMUX)) ||
+ (!clk_id && (mod & MOD_IMS_SYSMUX))) {
+ clk_disable(i2s->op_clk);
+ clk_put(i2s->op_clk);
+ } else {
+ return 0;
+ }
+ }
+
+ i2s->op_clk = clk_get(&i2s->pdev->dev,
+ i2s->src_clk[clk_id]);
+ clk_enable(i2s->op_clk);
+ i2s->rclk_srcrate = clk_get_rate(i2s->op_clk);
+
+ /* Over-ride the other's */
+ if (other) {
+ other->op_clk = i2s->op_clk;
+ other->rclk_srcrate = i2s->rclk_srcrate;
+ }
+ } else if ((!clk_id && (mod & MOD_IMS_SYSMUX))
+ || (clk_id && !(mod & MOD_IMS_SYSMUX))) {
+ dev_err(&i2s->pdev->dev,
+ "%s:%d Other DAI busy\n", __func__, __LINE__);
+ return -EAGAIN;
+ } else {
+ /* Call can't be on the active DAI */
+ i2s->op_clk = other->op_clk;
+ i2s->rclk_srcrate = other->rclk_srcrate;
+ return 0;
+ }
+
+ if (clk_id == 0)
+ mod &= ~MOD_IMS_SYSMUX;
+ else
+ mod |= MOD_IMS_SYSMUX;
+ break;
+
+ default:
+ dev_err(&i2s->pdev->dev, "We don't serve that!\n");
+ return -EINVAL;
+ }
+
+ writel(mod, i2s->addr + I2SMOD);
+
+ return 0;
+}
+
+static int i2sv2_i2s_set_fmt(struct snd_soc_dai *dai,
+ unsigned int fmt)
+{
+ struct i2s_dai *i2s = to_info(dai);
+ u32 mod = readl(i2s->addr + I2SMOD);
+ u32 tmp = 0;
+
+ /* Format is priority */
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_RIGHT_J:
+ tmp |= MOD_LR_RLOW;
+ tmp |= MOD_SDF_MSB;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ tmp |= MOD_LR_RLOW;
+ tmp |= MOD_SDF_LSB;
+ break;
+ case SND_SOC_DAIFMT_I2S:
+ tmp |= MOD_SDF_IIS;
+ break;
+ default:
+ dev_err(&i2s->pdev->dev, "Format not supported\n");
+ return -EINVAL;
+ }
+
+ /* Allow LRCLK-inverted version of the supported formats */
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ if (tmp & MOD_LR_RLOW)
+ tmp &= ~MOD_LR_RLOW;
+ else
+ tmp |= MOD_LR_RLOW;
+ break;
+ default:
+ dev_err(&i2s->pdev->dev, "Polarity not supported\n");
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ tmp |= MOD_SLAVE;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ /* Set default source clock in Master mode */
+ if (i2s->rclk_srcrate == 0)
+ s3c_i2sv2_set_sysclk(dai, SAMSUNG_I2S_RCLKSRC_0,
+ 0, SND_SOC_CLOCK_IN);
+ break;
+ default:
+ dev_err(&i2s->pdev->dev, "master/slave format not supported\n");
+ return -EINVAL;
+ }
+
+ if (any_active(i2s) &&
+ ((mod & (MOD_SDF_MASK | MOD_LR_RLOW
+ | MOD_SLAVE)) != tmp)) {
+ dev_err(&i2s->pdev->dev,
+ "%s:%d Other DAI busy\n", __func__, __LINE__);
+ return -EAGAIN;
+ }
+
+ mod &= ~(MOD_SDF_MASK | MOD_LR_RLOW | MOD_SLAVE);
+ mod |= tmp;
+ writel(mod, i2s->addr + I2SMOD);
+
+ return 0;
+}
+
+static int s3c_i2sv2_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+ struct i2s_dai *i2s = to_info(dai);
+ u32 mod = readl(i2s->addr + I2SMOD);
+
+ if (!is_secondary(i2s))
+ mod &= ~(MOD_DC2_EN | MOD_DC1_EN);
+
+ switch (params_channels(params)) {
+ case 6:
+ mod |= MOD_DC2_EN;
+ case 4:
+ mod |= MOD_DC1_EN;
+ break;
+ case 2:
+ break;
+ default:
+ dev_err(&i2s->pdev->dev, "%d channels not supported\n",
+ params_channels(params));
+ return -EINVAL;
+ }
+
+ if (is_secondary(i2s))
+ mod &= ~MOD_BLCS_MASK;
+ else
+ mod &= ~MOD_BLCP_MASK;
+
+ if (is_manager(i2s))
+ mod &= ~MOD_BLC_MASK;
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S8:
+ if (is_secondary(i2s))
+ mod |= MOD_BLCS_8BIT;
+ else
+ mod |= MOD_BLCP_8BIT;
+ if (is_manager(i2s))
+ mod |= MOD_BLC_8BIT;
+ break;
+ case SNDRV_PCM_FORMAT_S16_LE:
+ if (is_secondary(i2s))
+ mod |= MOD_BLCS_16BIT;
+ else
+ mod |= MOD_BLCP_16BIT;
+ if (is_manager(i2s))
+ mod |= MOD_BLC_16BIT;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ if (is_secondary(i2s))
+ mod |= MOD_BLCS_24BIT;
+ else
+ mod |= MOD_BLCP_24BIT;
+ if (is_manager(i2s))
+ mod |= MOD_BLC_24BIT;
+ break;
+ default:
+ dev_err(&i2s->pdev->dev, "Format(%d) not supported\n",
+ params_format(params));
+ return -EINVAL;
+ }
+ writel(mod, i2s->addr + I2SMOD);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ snd_soc_dai_set_dma_data(dai, substream,
+ (void *)&i2s->dma_playback);
+ else
+ snd_soc_dai_set_dma_data(dai, substream,
+ (void *)&i2s->dma_capture);
+
+ i2s->frmclk = params_rate(params);
+
+ return 0;
+}
+
+/* We set constraints on the substream acc to the version of I2S */
+static int s3c_i2sv2_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct i2s_dai *i2s = to_info(dai);
+ struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
+ unsigned long flags;
+
+ spin_lock_irqsave(&lock, flags);
+
+ i2s->mode |= DAI_OPENED;
+
+ if (is_manager(other))
+ i2s->mode &= ~DAI_MANAGER;
+ else
+ i2s->mode |= DAI_MANAGER;
+
+ /* Enforce set_sysclk in Master mode */
+ i2s->rclk_srcrate = 0;
+
+ spin_unlock_irqrestore(&lock, flags);
+
+ return 0;
+}
+
+static void s3c_i2sv2_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct i2s_dai *i2s = to_info(dai);
+ struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
+ unsigned long flags;
+
+ spin_lock_irqsave(&lock, flags);
+
+ i2s->mode &= ~DAI_OPENED;
+ i2s->mode &= ~DAI_MANAGER;
+
+ if (is_opened(other))
+ other->mode |= DAI_MANAGER;
+
+ /* Reset any constraint on RFS and BFS */
+ i2s->rfs = 0;
+ i2s->bfs = 0;
+
+ spin_unlock_irqrestore(&lock, flags);
+
+ /* Gate CDCLK by default */
+ if (!is_opened(other))
+ s3c_i2sv2_set_sysclk(dai, SAMSUNG_I2S_CDCLK,
+ 0, SND_SOC_CLOCK_IN);
+}
+
+static int config_setup(struct i2s_dai *i2s)
+{
+ struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
+ unsigned rfs, bfs, blc;
+ u32 psr;
+
+ blc = get_blc(i2s);
+
+ bfs = i2s->bfs;
+
+ if (!bfs && other)
+ bfs = other->bfs;
+
+ /* Select least possible multiple(2) if no constraint set */
+ if (!bfs)
+ bfs = blc * 2;
+
+ rfs = i2s->rfs;
+
+ if (!rfs && other)
+ rfs = other->rfs;
+
+ if ((rfs == 256 || rfs == 512) && (blc == 24)) {
+ dev_err(&i2s->pdev->dev,
+ "%d-RFS not supported for 24-blc\n", rfs);
+ return -EINVAL;
+ }
+
+ if (!rfs) {
+ if (bfs == 16 || bfs == 32)
+ rfs = 256;
+ else
+ rfs = 384;
+ }
+
+ /* If already setup and running */
+ if (any_active(i2s) && (get_rfs(i2s) != rfs || get_bfs(i2s) != bfs)) {
+ dev_err(&i2s->pdev->dev,
+ "%s:%d Other DAI busy\n", __func__, __LINE__);
+ return -EAGAIN;
+ }
+
+ /* We don't care about BFS in Slave mode */
+ if (is_slave(i2s))
+ return 0;
+
+ set_bfs(i2s, bfs);
+ set_rfs(i2s, rfs);
+
+ if (!(i2s->quirks & QUIRK_NO_MUXPSR)) {
+ psr = i2s->rclk_srcrate / i2s->frmclk / rfs;
+ writel(((psr - 1) << 8) | PSR_PSREN, i2s->addr + I2SPSR);
+ dev_dbg(&i2s->pdev->dev,
+ "RCLK_SRC=%luHz PSR=%u, RCLK=%dfs, BCLK=%dfs\n",
+ i2s->rclk_srcrate, psr, rfs, bfs);
+ }
+
+ return 0;
+}
+
+static int i2sv2_i2s_trigger(struct snd_pcm_substream *substream,
+ int cmd, struct snd_soc_dai *dai)
+{
+ int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct i2s_dai *i2s = to_info(rtd->cpu_dai);
+ unsigned long flags;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ local_irq_save(flags);
+
+ if (capture)
+ s3c_i2sv2_fifo(i2s, FIC_RXFLUSH);
+ else
+ s3c_i2sv2_fifo(i2s, FIC_TXFLUSH);
+
+ if (config_setup(i2s)) {
+ local_irq_restore(flags);
+ return -EINVAL;
+ }
+
+ if (capture)
+ s3c_i2sv2_rxctrl(i2s, 1);
+ else
+ s3c_i2sv2_txctrl(i2s, 1);
+
+ local_irq_restore(flags);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ local_irq_save(flags);
+
+ if (capture)
+ s3c_i2sv2_rxctrl(i2s, 0);
+ else
+ s3c_i2sv2_txctrl(i2s, 0);
+
+ local_irq_restore(flags);
+ break;
+ }
+
+ return 0;
+}
+
+static int i2sv2_i2s_set_clkdiv(struct snd_soc_dai *dai,
+ int div_id, int div)
+{
+ struct i2s_dai *i2s = to_info(dai);
+ struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
+
+ if (div_id == SAMSUNG_I2S_DIV_BCLK) {
+ if ((any_active(i2s) && div && (get_bfs(i2s) != div))
+ || (other && other->bfs && (other->bfs != div))) {
+ dev_err(&i2s->pdev->dev,
+ "%s:%d Other DAI busy\n", __func__, __LINE__);
+ return -EAGAIN;
+ }
+ i2s->bfs = div;
+ } else {
+ dev_err(&i2s->pdev->dev,
+ "Invalid clock divider(%d)\n", div_id);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static snd_pcm_sframes_t
+i2sv2_i2s_delay(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
+{
+ struct i2s_dai *i2s = to_info(dai);
+ u32 reg = readl(i2s->addr + I2SFIC);
+ snd_pcm_sframes_t delay;
+
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ delay = FIC_RXCOUNT(reg);
+ else if (is_secondary(i2s))
+ delay = FICS_TXCOUNT(readl(i2s->addr + I2SFICS));
+ else
+ delay = FIC_TXCOUNT(reg);
+
+ return delay;
+}
+
+#ifdef CONFIG_PM
+static int i2sv2_i2s_suspend(struct snd_soc_dai *dai)
+{
+ struct i2s_dai *i2s = to_info(dai);
+
+ if (dai->active) {
+ i2s->suspend_i2smod = readl(i2s->addr + I2SMOD);
+ i2s->suspend_i2scon = readl(i2s->addr + I2SCON);
+ i2s->suspend_i2spsr = readl(i2s->addr + I2SPSR);
+ }
+
+ return 0;
+}
+
+static int i2sv2_i2s_resume(struct snd_soc_dai *dai)
+{
+ struct i2s_dai *i2s = to_info(dai);
+
+ if (dai->active) {
+ writel(i2s->suspend_i2scon, i2s->addr + I2SCON);
+ writel(i2s->suspend_i2smod, i2s->addr + I2SMOD);
+ writel(i2s->suspend_i2spsr, i2s->addr + I2SPSR);
+ }
+
+ return 0;
+}
+#else
+#define i2sv2_i2s_suspend NULL
+#define i2sv2_i2s_resume NULL
+#endif
+
+static int samsung_i2s_dai_probe(struct snd_soc_dai *dai)
+{
+ struct i2s_dai *i2s = to_info(dai);
+ struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
+
+ if (other && other->clk) /* If this is probe on secondary */
+ goto probe_exit;
+
+ i2s->addr = ioremap(i2s->base, 0x100);
+ if (i2s->addr == NULL) {
+ dev_err(&i2s->pdev->dev, "cannot ioremap registers\n");
+ return -ENXIO;
+ }
+
+ i2s->clk = clk_get(&i2s->pdev->dev, "iis");
+ if (IS_ERR(i2s->clk)) {
+ dev_err(&i2s->pdev->dev, "failed to get i2s_clock\n");
+ iounmap(i2s->addr);
+ return -ENOENT;
+ }
+ clk_enable(i2s->clk);
+
+ if (other) {
+ other->addr = i2s->addr;
+ other->clk = i2s->clk;
+ }
+
+ if (i2s->quirks & QUIRK_NEED_RSTCLR)
+ writel(CON_RSTCLR, i2s->addr + I2SCON);
+
+probe_exit:
+ /* Reset any constraint on RFS and BFS */
+ i2s->rfs = 0;
+ i2s->bfs = 0;
+ s3c_i2sv2_txctrl(i2s, 0);
+ s3c_i2sv2_rxctrl(i2s, 0);
+ s3c_i2sv2_fifo(i2s, FIC_TXFLUSH);
+ s3c_i2sv2_fifo(other, FIC_TXFLUSH);
+ s3c_i2sv2_fifo(i2s, FIC_RXFLUSH);
+
+ /* Gate CDCLK by default */
+ if (!is_opened(other))
+ s3c_i2sv2_set_sysclk(dai, SAMSUNG_I2S_CDCLK,
+ 0, SND_SOC_CLOCK_IN);
+
+ return 0;
+}
+
+static int samsung_i2s_dai_remove(struct snd_soc_dai *dai)
+{
+ struct i2s_dai *i2s = snd_soc_dai_get_drvdata(dai);
+ struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
+
+ if (!other || !other->clk) {
+
+ if (i2s->quirks & QUIRK_NEED_RSTCLR)
+ writel(0, i2s->addr + I2SCON);
+
+ clk_disable(i2s->clk);
+ clk_put(i2s->clk);
+
+ iounmap(i2s->addr);
+ }
+
+ i2s->clk = NULL;
+
+ return 0;
+}
+
+static struct snd_soc_dai_ops samsung_i2s_dai_ops = {
+ .trigger = i2sv2_i2s_trigger,
+ .hw_params = s3c_i2sv2_hw_params,
+ .set_fmt = i2sv2_i2s_set_fmt,
+ .set_clkdiv = i2sv2_i2s_set_clkdiv,
+ .set_sysclk = s3c_i2sv2_set_sysclk,
+ .startup = s3c_i2sv2_startup,
+ .shutdown = s3c_i2sv2_shutdown,
+ .delay = i2sv2_i2s_delay,
+};
+
+#define SAMSUNG_I2S_RATES \
+ (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \
+ SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
+ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
+
+#define SAMSUNG_I2S_FMTS \
+ (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |\
+ SNDRV_PCM_FMTBIT_S24_LE)
+
+static __devinit
+struct i2s_dai *s3c_alloc_dai(struct platform_device *pdev, bool sec)
+{
+ struct i2s_dai *i2s;
+
+ i2s = kzalloc(sizeof(struct i2s_dai), GFP_KERNEL);
+ if (i2s == NULL)
+ return NULL;
+
+ i2s->pdev = pdev;
+ i2s->pri_dai = NULL;
+ i2s->sec_dai = NULL;
+ i2s->s3c_i2s_drv.symmetric_rates = 1;
+ i2s->s3c_i2s_drv.probe = samsung_i2s_dai_probe;
+ i2s->s3c_i2s_drv.remove = samsung_i2s_dai_remove;
+ i2s->s3c_i2s_drv.ops = &samsung_i2s_dai_ops;
+ i2s->s3c_i2s_drv.suspend = i2sv2_i2s_suspend;
+ i2s->s3c_i2s_drv.resume = i2sv2_i2s_resume;
+ i2s->s3c_i2s_drv.playback.channels_min = 2;
+ i2s->s3c_i2s_drv.playback.channels_max = 2;
+ i2s->s3c_i2s_drv.playback.rates = SAMSUNG_I2S_RATES;
+ i2s->s3c_i2s_drv.playback.formats = SAMSUNG_I2S_FMTS;
+
+ if (!sec) {
+ i2s->s3c_i2s_drv.capture.channels_min = 2;
+ i2s->s3c_i2s_drv.capture.channels_max = 2;
+ i2s->s3c_i2s_drv.capture.rates = SAMSUNG_I2S_RATES;
+ i2s->s3c_i2s_drv.capture.formats = SAMSUNG_I2S_FMTS;
+ } else { /* Create a new platform_device for Secondary */
+ i2s->pdev = platform_device_register_resndata(NULL,
+ pdev->name, pdev->id + MAX_I2S,
+ NULL, 0, NULL, 0);
+ if (IS_ERR(i2s->pdev)) {
+ kfree(i2s);
+ return NULL;
+ }
+ }
+
+ /* Pre-assign snd_soc_dai_set_drvdata */
+ dev_set_drvdata(&i2s->pdev->dev, i2s);
+
+ return i2s;
+}
+
+static __devinit int samsung_i2s_probe(struct platform_device *pdev)
+{
+ u32 dma_pl_chan, dma_cp_chan, dma_pl_sec_chan;
+ struct i2s_dai *pri_dai, *sec_dai = NULL;
+ struct s3c_audio_pdata *i2s_pdata;
+ struct samsung_i2s *i2s_cfg;
+ struct resource *res;
+ u32 regs_base, quirks;
+ int ret = 0;
+
+ /* Call during Seconday interface registration */
+ if (pdev->id >= MAX_I2S) {
+ sec_dai = dev_get_drvdata(&pdev->dev);
+ snd_soc_register_dai(&sec_dai->pdev->dev,
+ &sec_dai->s3c_i2s_drv);
+ return 0;
+ }
+
+ i2s_pdata = pdev->dev.platform_data;
+ if (i2s_pdata == NULL) {
+ dev_err(&pdev->dev, "Can't work without s3c_audio_pdata\n");
+ return -EINVAL;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "Unable to get I2S-TX dma resource\n");
+ return -ENXIO;
+ }
+ dma_pl_chan = res->start;
+
+ res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+ if (!res) {
+ dev_err(&pdev->dev, "Unable to get I2S-RX dma resource\n");
+ return -ENXIO;
+ }
+ dma_cp_chan = res->start;
+
+ res = platform_get_resource(pdev, IORESOURCE_DMA, 2);
+ if (res)
+ dma_pl_sec_chan = res->start;
+ else
+ dma_pl_sec_chan = 0;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "Unable to get I2S SFR address\n");
+ return -ENXIO;
+ }
+
+ if (!request_mem_region(res->start, resource_size(res),
+ "samsung-i2s")) {
+ dev_err(&pdev->dev, "Unable to request SFR region\n");
+ return -EBUSY;
+ }
+ regs_base = res->start;
+
+ i2s_cfg = &i2s_pdata->type.i2s;
+ quirks = i2s_cfg->quirks;
+
+ pri_dai = s3c_alloc_dai(pdev, false);
+ if (!pri_dai) {
+ dev_err(&pdev->dev, "Unable to alloc I2S_pri\n");
+ ret = -ENOMEM;
+ goto err1;
+ }
+
+ pri_dai->dma_playback.dma_addr = regs_base + I2STXD;
+ pri_dai->dma_capture.dma_addr = regs_base + I2SRXD;
+ pri_dai->dma_playback.client =
+ (struct s3c2410_dma_client *)&pri_dai->dma_playback;
+ pri_dai->dma_capture.client =
+ (struct s3c2410_dma_client *)&pri_dai->dma_capture;
+ pri_dai->dma_playback.channel = dma_pl_chan;
+ pri_dai->dma_capture.channel = dma_cp_chan;
+ pri_dai->src_clk = i2s_cfg->src_clk;
+ pri_dai->dma_playback.dma_size = 4;
+ pri_dai->dma_capture.dma_size = 4;
+ pri_dai->base = regs_base;
+ pri_dai->quirks = quirks;
+
+ if (quirks & QUIRK_PRI_6CHAN)
+ pri_dai->s3c_i2s_drv.playback.channels_max = 6;
+
+ if (quirks & QUIRK_SEC_DAI) {
+ sec_dai = s3c_alloc_dai(pdev, true);
+ if (!sec_dai) {
+ dev_err(&pdev->dev, "Unable to alloc I2S_sec\n");
+ ret = -ENOMEM;
+ goto err2;
+ }
+ sec_dai->dma_playback.dma_addr = regs_base + I2STXDS;
+ sec_dai->dma_playback.client =
+ (struct s3c2410_dma_client *)&sec_dai->dma_playback;
+ /* Use iDMA always if SysDMA not provided */
+ sec_dai->dma_playback.channel = dma_pl_sec_chan ? : -1;
+ sec_dai->src_clk = i2s_cfg->src_clk;
+ sec_dai->dma_playback.dma_size = 4;
+ sec_dai->base = regs_base;
+ sec_dai->quirks = quirks;
+ sec_dai->pri_dai = pri_dai;
+ pri_dai->sec_dai = sec_dai;
+ }
+
+ if (i2s_pdata->cfg_gpio && i2s_pdata->cfg_gpio(pdev)) {
+ dev_err(&pdev->dev, "Unable to configure gpio\n");
+ ret = -EINVAL;
+ goto err3;
+ }
+
+ snd_soc_register_dai(&pri_dai->pdev->dev, &pri_dai->s3c_i2s_drv);
+
+ return 0;
+err3:
+ kfree(sec_dai);
+err2:
+ kfree(pri_dai);
+err1:
+ release_mem_region(regs_base, resource_size(res));
+
+ return ret;
+}
+
+static __devexit int samsung_i2s_remove(struct platform_device *pdev)
+{
+ struct i2s_dai *i2s, *other;
+
+ i2s = dev_get_drvdata(&pdev->dev);
+ other = i2s->pri_dai ? : i2s->sec_dai;
+
+ if (other) {
+ other->pri_dai = NULL;
+ other->sec_dai = NULL;
+ } else {
+ struct resource *res;
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res)
+ release_mem_region(res->start, resource_size(res));
+ }
+
+ i2s->pri_dai = NULL;
+ i2s->sec_dai = NULL;
+
+ kfree(i2s);
+
+ snd_soc_unregister_dai(&pdev->dev);
+
+ return 0;
+}
+
+static struct platform_driver samsung_i2s_driver = {
+ .probe = samsung_i2s_probe,
+ .remove = samsung_i2s_remove,
+ .driver = {
+ .name = "samsung-i2s",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init samsung_i2s_init(void)
+{
+ return platform_driver_register(&samsung_i2s_driver);
+}
+module_init(samsung_i2s_init);
+
+static void __exit samsung_i2s_exit(void)
+{
+ platform_driver_unregister(&samsung_i2s_driver);
+}
+module_exit(samsung_i2s_exit);
+
+/* Module information */
+MODULE_AUTHOR("Jaswinder Singh, <jassi.brar(a)samsung.com>");
+MODULE_DESCRIPTION("Samsung I2S Interface");
+MODULE_ALIAS("platform:samsung-i2s");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/i2s.h b/sound/soc/s3c24xx/i2s.h
new file mode 100644
index 0000000..77b7965
--- /dev/null
+++ b/sound/soc/s3c24xx/i2s.h
@@ -0,0 +1,29 @@
+/* sound/soc/s3c24xx/i2s.h
+ *
+ * ALSA SoC Audio Layer - Samsung I2S Controller driver
+ *
+ * Copyright (c) 2010 Samsung Electronics Co. Ltd.
+ * Jaswinder Singh <jassi.brar(a)samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __SND_SOC_SAMSUNG_I2S_H
+#define __SND_SOC_SAMSUNG_I2S_H
+
+/*
+ * Maximum number of I2S blocks that any SoC can have.
+ * The secondary interface of a CPU dai(if there exists any),
+ * is indexed at [cpu-dai's ID + MAX_I2S]
+ */
+#define MAX_I2S 4
+
+#define SAMSUNG_I2S_DIV_BCLK 1
+
+#define SAMSUNG_I2S_RCLKSRC_0 0
+#define SAMSUNG_I2S_RCLKSRC_1 1
+#define SAMSUNG_I2S_CDCLK 2
+
+#endif /* __SND_SOC_SAMSUNG_I2S_H */
--
1.6.2.5
2
7

[alsa-devel] hda-intel (ALC889) - sound loops/repeats continuously, and general brokenness
by Juliano F. Ravasi 22 Oct '10
by Juliano F. Ravasi 22 Oct '10
22 Oct '10
Hello ALSA devs,
(Cc'ing alsa-devel since looks like it can be a driver problem/bug, but
still unsure. Need some expert advice.)
I'm experiencing a lot of problems reproducing audio with an HD Audio
"card" integrated on an Intel DX58SO mainboard. It happens only on this
card, everything is Ok with another (USB) card.
The most visible problem is that `aplay` plays only a small fragment of
audio (less than one second), then hangs and the card keeps reproducing
that fragment continuously in a loop, until killed with Ctrl-C. `aplay
-N` progresses, but each fragment repeats 3 times.
Doing an strace on `aplay`, it hangs here while repeating the audio
fragment:
...
semop(294912, {{0, 0, 0}, {0, 1, SEM_UNDO}}, 2) = 0
semop(294912, {{0, -1, SEM_UNDO|IPC_NOWAIT}}, 1) = 0
ioctl(4, 0x4122, 0x3) = 0
ioctl(4, 0x4122, 0) = 0
ioctl(4, 0x4122, 0xe4) = 0
poll([{fd=3, events=POLLIN|POLLERR|POLLNVAL}], 1, -1) = 1 ([{fd=3,
revents=POLLIN}])
ioctl(4, 0x4122, 0x3) = 0
ioctl(4, 0x4122, 0xe4) = 0
ioctl(4, 0x4122, 0x1) = 0
read(3,
"\6\0\0\0\1\210\377\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\210\377\377"...,
128) = 64
read(3, 0x7fff890f6810, 128) = -1 EAGAIN (Resource
temporarily unavailable)
poll([{fd=3, events=POLLIN|POLLERR|POLLNVAL}], 1, -1^C <unfinished ...>
Descriptor 3 is /dev/snd/timer ... Perhaps time stops progressing for
the driver? `aplay -N` continues a little here because this poll() call
timeouts after 1000ms, but this still repeats each fragment 3 times.
Other audio software (mplayer, amarok) can play audio almost normally,
except when you pause. When paused, the same behavior happens: the last
fragment of sound before pausing keeps repeating continuously until
unpaused.
When the song finishes, the application (tested with mplayer) also
hangs, the last fragment keeps repeating while the process is blocked here:
ioctl(0, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 opost isig -icanon -echo
...}) = 0
ioctl(0, SNDCTL_TMR_START or TCSETS, {B38400 opost isig icanon echo
...}) = 0
ioctl(0, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 opost isig icanon echo
...}) = 0
ioctl(6, 0x4144^C <unfinished ...>
Descriptor 6 is /dev/snd/pcmC0D0p , and 0x4144 is SNDRV_PCM_IOCTL_DRAIN
ioctl in sound/asound.h. Sometimes mplayer timeouts and reports:
[AO_ALSA] alsa-lib: pcm_hw.c:616:(snd_pcm_hw_drain)
SNDRV_PCM_IOCTL_DRAIN failed (-5): Input/output error
I'm at a loss here. I have already read the sound/alsa/HD-Audio.txt and
tried many of the tweaks described there, but with no luck.
Any help is greatly appreciated.
System information:
http://www.alsa-project.org/db/?f=4ab249b0f301ff20260d7388432e624aa65092d6
Best regards,
Juliano.
--
Juliano F. Ravasi ·· http://juliano.info/
5105 46CC B2B7 F0CD 5F47 E740 72CA 54F4 DF37 9E96
3
3
Hi,
I have question concerning ALSA Core snd_pcm_control_ioctl function.
I have noticed that the IOCTL fails if it's called for a device with substream_count = 0, since I'm implementing a PCM device that supports Record and does not support Playback, the IOCTL fails when called for the Playback stream. I would propose, in such case, to return that the stream has 0 playback substreams instead of failing.
Thanks in advance for your help,
Regards,
Selma.
---------------------------------------------------------------------
Intel Corporation SAS (French simplified joint stock company)
Registered headquarters: "Les Montalets"- 2, rue de Paris,
92196 Meudon Cedex, France
Registration Number: 302 456 199 R.C.S. NANTERRE
Capital: 4,572,000 Euros
This e-mail and any attachments may contain confidential material for
the sole use of the intended recipient(s). Any review or distribution
by others is strictly prohibited. If you are not the intended
recipient, please contact the sender and delete all copies.
2
1
From: Jassi Brar <jassi.brar(a)samsung.com>
Hi,
Here come patches overhauling the Samsung ASoC support.
The AC97, PCM, SPDIF and ASoC-DMA related code has merely undergone
cosmetic changes - symbol, device & driver renaming and file moving.
A new I2S controller driver has been added to manage Samsung SoCs since
S3C64XX. Older driver has been changed only as is necessary.
Regarding I2S, I have left the s3c24xx series untouched because the
controllers are too different to run by a common driver. S3C2412's I2S
does have some similarities, but not important enough to warrant impact
on new driver design.
The new I2S driver has been designed around the notion of features/quirks.
The newer SoCs have revised version of I2S_0(usually) than previous ones.
So, I2S block is 'specified' in the platform code and the driver works on
that configuration.
For now, Secondary I2S DAI works only with System-DMAC. I2S-Internal DMA
and SRAM will be enabled later.
Testing:-
Simple testing of 5.1 channel and hardware mixing seems to work (though
there seems to be some issue with symmetric_rates in soc-core.c which
would be tried to fix later as saperate issue).
I would appreciate any test-results for GONI and SMARTQ.
I suggest the patches 13,14,16 & 17 go via Kgene's Tree, and the rest via ASoC
tree due to tight dependencies.
1). ASoC: WM8580: Remove useless assignment
2). ASoC: Samsung: Remove redundant AQUILA driver
3). ASoC: Samsung: Rename DMA device
4). ARM: Samsung: Define common audio-dma device
5). ASoC: Samsung: Rename ASoC DMA driver
6). ASoC: Samsung: Rename AC97 platform device
7). ASoC: Samsung: Rename AC97 driver
8). ASoC: Samsung: Rename PCM driver
9). ASoC: Samsung: Generalize DMA driver namespace
10). ASoC: Samsung: Rename s3c64xx I2S device
11). ASoC: Samsung: Add common I2S driver
12). ARM: S3C64XX: I2S: Upgrade platform device
13). ARM: S5P6440: I2S: Upgrade platform device
14). ARM: S5P6442: I2S: Upgrade platform device
15). ARM: S5PC100: I2S: Upgrade platform device
16). ARM: S5PV210: I2S: Upgrade platform device
17). ARM: S5PV310: Add audio platform devices
18). ASoC: SMARTQ: Move to use new I2S driver
19). ASoC: GONI: Move to use new I2S driver
20). ASoC: SMDK64XX: Move to use new I2S driver
21). ASoC: S3C64XX: Remove obsoleted I2S drivers
22). ASoC: SMDK64XX: Rename for other platforms
23). ASoC: SMDK_WM8580: Enable for SMDKC100
24). ASoC: Samsung: Generalize Kconfig symbols
25). ASoC: Samsung: Rename from s3c24xx to samsung
Thanks,
Jassi
4
6
Hi guys.
Is it possible to somehow mandate the
use of a PCM plugin? For example, the
PC-Speaker.conf defines the use of softvol
plugin for "default" and "front" devices.
It is still possible for the software to bypass
it by the use of "hw", and some software
does exactly that.
Is it possible to somehow make some
plugin a mandatory?
6
23

22 Oct '10
when running a kernel built using mx3_defconfig, I get an error message
because wm1133-ev1 tries to alloc soc-audio even if not running on an
iMX31ads :
sysfs: cannot create duplicate filename '/devices/platform/soc-audio'
.../...
kobject_add_internal failed for soc-audio with -EEXIST, don't try to register things with the same name in the same directory.
This patch fix this problem.
Signed-off-by: Eric Bénard <eric(a)eukrea.com>
Cc: Liam Girdwood <lrg(a)slimlogic.co.uk>
Cc: Mark Brown <broonie(a)opensource.wolfsonmicro.com>
---
sound/soc/imx/wm1133-ev1.c | 5 +++++
1 files changed, 5 insertions(+), 0 deletions(-)
diff --git a/sound/soc/imx/wm1133-ev1.c b/sound/soc/imx/wm1133-ev1.c
index a6e7d94..ef37440 100644
--- a/sound/soc/imx/wm1133-ev1.c
+++ b/sound/soc/imx/wm1133-ev1.c
@@ -20,6 +20,7 @@
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
+#include <asm/mach-types.h>
#include <mach/audmux.h>
@@ -269,6 +270,10 @@ static int __init wm1133_ev1_audio_init(void)
int ret;
unsigned int ptcr, pdcr;
+ if (!machine_is_mx31ads())
+ /* return happy. We might run on a totally different machine */
+ return 0;
+
/* SSI0 mastered by port 5 */
ptcr = MXC_AUDMUX_V2_PTCR_SYN |
MXC_AUDMUX_V2_PTCR_TFSDIR |
--
1.7.0.4
2
3
I have been looking into UCM lately and have been tasked with looking
into possible inclusion in Ubuntu Natty 11.04 timeframe, for arm mainly,
but more systems may be possible depending on the scope of the project.
Unfortunately there isn't much info online other than a few brief
blurbs. Reading the patch logs gives me a little more insight, but a
timeline would really be nice.
--
Tobin Davis
Perhaps the biggest disappointments were the ones you expected anyway.
3
3
The following changes since commit f6765502f8daae3d237a394889276c8987f3e299:
Revert "ASoC: Add max98088 CODEC driver" (2010-10-18 06:01:33 +0100)
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound-2.6.git for-next
These have all been in -next for a few days, note that this isn't
for-2.6.37 - I may update with any extra fixes after sending this.
Jarkko Nikula (1):
ASoC: Fix I2C component device id number creation
Jassi Brar (1):
ASoC: WM8580: Remove useless assignment
Julia Lawall (1):
ASoC: davinci-mcasp.c: Return error code in failure
Mark Brown (1):
ASoC: Restore MAX98088 CODEC driver
include/sound/max98088.h | 50 +
sound/soc/codecs/Kconfig | 4 +
sound/soc/codecs/Makefile | 2 +
sound/soc/codecs/max98088.c | 2097 +++++++++++++++++++++++++++++++++++++
sound/soc/codecs/max98088.h | 193 ++++
sound/soc/codecs/wm8580.c | 4 -
sound/soc/davinci/davinci-mcasp.c | 2 +
sound/soc/soc-core.c | 2 +-
8 files changed, 2349 insertions(+), 5 deletions(-)
create mode 100644 include/sound/max98088.h
create mode 100644 sound/soc/codecs/max98088.c
create mode 100644 sound/soc/codecs/max98088.h
2
1

22 Oct '10
Correct/Implement handling of broken chip.
Fail the i2c_prope if the communication with the chip
fails.
Signed-off-by: Peter Ujfalusi <peter.ujfalusi(a)nokia.com>
---
sound/soc/codecs/tpa6130a2.c | 28 ++++++++++++++++++++++------
1 files changed, 22 insertions(+), 6 deletions(-)
diff --git a/sound/soc/codecs/tpa6130a2.c b/sound/soc/codecs/tpa6130a2.c
index 99b70e5..329acc1 100644
--- a/sound/soc/codecs/tpa6130a2.c
+++ b/sound/soc/codecs/tpa6130a2.c
@@ -98,16 +98,21 @@ static u8 tpa6130a2_read(int reg)
return data->regs[reg];
}
-static void tpa6130a2_initialize(void)
+static int tpa6130a2_initialize(void)
{
struct tpa6130a2_data *data;
- int i;
+ int i, ret = 0;
BUG_ON(tpa6130a2_client == NULL);
data = i2c_get_clientdata(tpa6130a2_client);
- for (i = 1; i < TPA6130A2_REG_VERSION; i++)
- tpa6130a2_i2c_write(i, data->regs[i]);
+ for (i = 1; i < TPA6130A2_REG_VERSION; i++) {
+ ret = tpa6130a2_i2c_write(i, data->regs[i]);
+ if (ret < 0)
+ break;
+ }
+
+ return ret;
}
static int tpa6130a2_power(int power)
@@ -133,7 +138,16 @@ static int tpa6130a2_power(int power)
}
data->power_state = 1;
- tpa6130a2_initialize();
+ ret = tpa6130a2_initialize();
+ if (ret < 0) {
+ dev_err(&tpa6130a2_client->dev,
+ "Failed to initialize chip\n");
+ if (data->power_gpio >= 0)
+ gpio_set_value(data->power_gpio, 0);
+ regulator_disable(data->supply);
+ data->power_state = 0;
+ goto exit;
+ }
/* Clear SWS */
val = tpa6130a2_read(TPA6130A2_REG_CONTROL);
@@ -375,7 +389,9 @@ int tpa6130a2_add_controls(struct snd_soc_codec *codec)
{
struct tpa6130a2_data *data;
- BUG_ON(tpa6130a2_client == NULL);
+ if (tpa6130a2_client == NULL)
+ return -ENODEV;
+
data = i2c_get_clientdata(tpa6130a2_client);
snd_soc_dapm_new_controls(codec, tpa6130a2_dapm_widgets,
--
1.7.3.1
3
2

[alsa-devel] [patch v4 0/2] ASoC: alc562[123] / HP t5325 support - try 4
by Arnaud Patard 21 Oct '10
by Arnaud Patard 21 Oct '10
21 Oct '10
Hi,
It's a quick resend of previous patchset but this time workqueue parts really
removed. It should be the last try to get it merge (well, I hope).
thanks,
Arnaud
3
4

21 Oct '10
Op 19-10-10 09:30, Jassi Brar schreef:
> I forgot to CC you on the patches.
>
> --------
>
> Hi,
>
> Here come patches overhauling the Samsung ASoC support.
>
> The AC97, PCM, SPDIF and ASoC-DMA related code has merely undergone
> cosmetic changes - symbol, device & driver renaming and file moving.
>
> A new I2S controller driver has been added to manage Samsung SoCs since
> S3C64XX. Older driver has been changed only as is necessary.
> Regarding I2S, I have left the s3c24xx series untouched because the
> controllers are too different to run by a common driver. S3C2412's I2S
> does have some similarities, but not important enough to warrant impact
> on new driver design.
> The new I2S driver has been designed around the notion of features/quirks.
> The newer SoCs have revised version of I2S_0(usually) than previous ones.
> So, I2S block is 'specified' in the platform code and the driver works on
> that configuration.
> For now, Secondary I2S DAI works only with System-DMAC. I2S-Internal DMA
> and SRAM will be enabled later.
>
> Testing:-
> Simple testing of 5.1 channel and hardware mixing seems to work (though
> there seems to be some issue with symmetric_rates in soc-core.c which
> would be tried to fix later as saperate issue).
> I would appreciate any test-results for GONI and SMARTQ.
>
> I suggest the patches 13,14,16 & 17 go via Kgene's Tree, and the rest via ASoC
> tree due to tight dependencies.
>
> 1). ASoC: WM8580: Remove useless assignment
> 2). ASoC: Samsung: Remove redundant AQUILA driver
> 3). ASoC: Samsung: Rename DMA device
> 4). ARM: Samsung: Define common audio-dma device
> 5). ASoC: Samsung: Rename ASoC DMA driver
> 6). ASoC: Samsung: Rename AC97 platform device
> 7). ASoC: Samsung: Rename AC97 driver
> 8). ASoC: Samsung: Rename PCM driver
> 9). ASoC: Samsung: Generalize DMA driver namespace
> 10). ASoC: Samsung: Rename s3c64xx I2S device
> 11). ASoC: Samsung: Add common I2S driver
> 12). ARM: S3C64XX: I2S: Upgrade platform device
> 13). ARM: S5P6440: I2S: Upgrade platform device
> 14). ARM: S5P6442: I2S: Upgrade platform device
> 15). ARM: S5PC100: I2S: Upgrade platform device
> 16). ARM: S5PV210: I2S: Upgrade platform device
> 17). ARM: S5PV310: Add audio platform devices
> 18). ASoC: SMARTQ: Move to use new I2S driver
> 19). ASoC: GONI: Move to use new I2S driver
> 20). ASoC: SMDK64XX: Move to use new I2S driver
> 21). ASoC: S3C64XX: Remove obsoleted I2S drivers
> 22). ASoC: SMDK64XX: Rename for other platforms
> 23). ASoC: SMDK_WM8580: Enable for SMDKC100
> 24). ASoC: Samsung: Generalize Kconfig symbols
> 25). ASoC: Samsung: Rename from s3c24xx to samsung
These don't seem to apply on Linus' latest release
(f6f94e2ab1b33f0082ac22d71f66385a60d8157f)?
Also, do you have a git tree I can pull to test these?
--
Maurus Cuelenaere
2
1

21 Oct '10
Ensure that the codec->name is freed when unregistering the codec.
Signed-off-by: Dimitris Papastamos <dp(a)opensource.wolfsonmicro.com>
---
sound/soc/soc-core.c | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 862b1af..70d9a73 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -3299,6 +3299,7 @@ found:
if (codec->reg_cache)
kfree(codec->reg_cache);
+ kfree(codec->name);
kfree(codec);
}
EXPORT_SYMBOL_GPL(snd_soc_unregister_codec);
--
1.7.3.1
3
2

21 Oct '10
This function is not exported and it does not seem to be called from
anywhere else therefore it should be static.
Signed-off-by: Dimitris Papastamos <dp(a)opensource.wolfsonmicro.com>
---
sound/soc/codecs/max98088.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c
index 4186b27..e7a40d1 100644
--- a/sound/soc/codecs/max98088.c
+++ b/sound/soc/codecs/max98088.c
@@ -613,7 +613,7 @@ static int max98088_volatile_register(unsigned int reg)
/*
* Load equalizer DSP coefficient configurations registers
*/
-void m98088_eq_band(struct snd_soc_codec *codec, unsigned int dai,
+static void m98088_eq_band(struct snd_soc_codec *codec, unsigned int dai,
unsigned int band, u16 *coefs)
{
unsigned int eq_reg;
--
1.7.3.1
3
2
Announcement:
A new version of the funny game "Catch-the-slider" aka
Alsamixer-Qt4 0.5.1 is now available at
http://xwmw.org/alsamixer-qt4/
http://sourceforge.net/projects/alsamixer-qt4/files/
This is mostly a GUI polishing release over 0.5.0 which seemed
to be reasonable stable.
Changes
GUI:
* Adaptive cursor shape (on mouse over events)
* Sliders labels: Context menus work
* Sliders labels: Tool tips show up
* Sliders labels: Label emphasis on mouse over
* Slider snapping animation on more occassions
* Rubberband graphics for the slider snapping animation
* General slider optimisations
* Fix for slider draging did not end on a focusOut event
ALSA:
The following events which were ignored before
now trigger a mixer refresh/reload
* SND_CTL_EVENT_MASK_ADD
* SND_CTL_EVENT_MASK_INFO
* SND_CTL_EVENT_MASK_REMOVE
* SND_CTL_EVENT_MASK_TLV
Regards,
Sebastian Holtermann
1
0

[alsa-devel] [patch v3 0/2] ASoC: alc562[123] / HP t5325 support - try 3
by Arnaud Patard 21 Oct '10
by Arnaud Patard 21 Oct '10
21 Oct '10
Hi,
It's an other try to get alc562[123] and HP t5325 support merged into ASoC tree.
There was not a lot of changes except on places where I got comments (except on
the depop stuff). I've also removed the patch on
arch/arm/mach-kirkwood/t5325-setup.c which will go through an other route later.
Arnaud
2
3
Hello ALSA people,
How do you use the ALSA API to mute the MICROPHONE?
How do you use the ALSA API to mute the SPEAKER?
How do you reduce the playback latency or delay? I am reading my audio and I
notice that there is a delay ... or some kind of latency. I want the audio
played as soon as it is read or something close to that.
Thanks,
X
2
3

[alsa-devel] [PATCH 10/22] pcmcia: introduce autoconfiguration feature
by Dominik Brodowski 21 Oct '10
by Dominik Brodowski 21 Oct '10
21 Oct '10
Introduce an autoconfiguration feature to set certain values in
pcmcia_loop_config(), instead of copying the same code over and over
in each PCMCIA driver. At first, introduce the following options:
CONF_AUTO_CHECK_VCC check or matching Vcc entry
CONF_AUTO_SET_VPP set Vpp
CONF_AUTO_AUDIO enable the speaker line
CC: netdev(a)vger.kernel.org
CC: linux-wireless(a)vger.kernel.org
CC: linux-ide(a)vger.kernel.org
CC: linux-usb(a)vger.kernel.org
CC: laforge(a)gnumonks.org
CC: linux-mtd(a)lists.infradead.org
CC: alsa-devel(a)alsa-project.org
CC: linux-serial(a)vger.kernel.org
CC: Jiri Kosina <jkosina(a)suse.cz>
CC: linux-scsi(a)vger.kernel.org
Acked-by: Gustavo F. Padovan <padovan(a)profusion.mobi> (for drivers/bluetooth)
Tested-by: Wolfram Sang <w.sang(a)pengutronix.de>
Signed-off-by: Dominik Brodowski <linux(a)dominikbrodowski.net>
---
drivers/ata/pata_pcmcia.c | 23 +----
drivers/bluetooth/bt3c_cs.c | 7 +-
drivers/bluetooth/btuart_cs.c | 7 +-
drivers/bluetooth/dtl1_cs.c | 1 -
drivers/char/pcmcia/cm4000_cs.c | 1 -
drivers/char/pcmcia/cm4040_cs.c | 1 -
drivers/char/pcmcia/ipwireless/main.c | 1 -
drivers/char/pcmcia/synclink_cs.c | 1 -
drivers/ide/ide-cs.c | 23 +----
drivers/isdn/hardware/avm/avm_cs.c | 1 -
drivers/isdn/hisax/avma1_cs.c | 1 -
drivers/isdn/hisax/elsa_cs.c | 1 -
drivers/isdn/hisax/sedlbauer_cs.c | 25 +-----
drivers/isdn/hisax/teles_cs.c | 1 -
drivers/net/pcmcia/axnet_cs.c | 1 -
drivers/net/pcmcia/fmvj18x_cs.c | 1 -
drivers/net/pcmcia/pcnet_cs.c | 1 -
drivers/net/pcmcia/smc91c92_cs.c | 2 -
drivers/net/pcmcia/xirc2ps_cs.c | 5 +-
drivers/net/wireless/airo_cs.c | 17 +---
drivers/net/wireless/atmel_cs.c | 17 +---
drivers/net/wireless/hostap/hostap_cs.c | 27 +-----
drivers/net/wireless/libertas/if_cs.c | 1 -
drivers/net/wireless/orinoco/orinoco_cs.c | 31 +------
drivers/net/wireless/orinoco/spectrum_cs.c | 24 +----
drivers/parport/parport_cs.c | 1 -
drivers/pcmcia/pcmcia_cis.c | 36 ++++++-
drivers/scsi/pcmcia/aha152x_stub.c | 1 -
drivers/scsi/pcmcia/fdomain_stub.c | 1 -
drivers/scsi/pcmcia/nsp_cs.c | 110 ++++++++-------------
drivers/scsi/pcmcia/qlogic_stub.c | 1 -
drivers/scsi/pcmcia/sym53c500_cs.c | 1 -
drivers/serial/serial_cs.c | 10 +--
drivers/staging/comedi/drivers/cb_das16_cs.c | 1 -
drivers/staging/comedi/drivers/das08_cs.c | 1 -
drivers/staging/comedi/drivers/ni_daq_700.c | 10 +--
drivers/staging/comedi/drivers/ni_daq_dio24.c | 10 +--
drivers/staging/comedi/drivers/ni_labpc_cs.c | 11 +--
drivers/staging/comedi/drivers/ni_mio_cs.c | 1 -
drivers/staging/comedi/drivers/quatech_daqp_cs.c | 1 -
drivers/telephony/ixj_pcmcia.c | 1 -
drivers/usb/host/sl811_cs.c | 24 +----
include/pcmcia/ds.h | 7 +-
43 files changed, 120 insertions(+), 329 deletions(-)
diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c
index 76da55d..954f43c 100644
--- a/drivers/ata/pata_pcmcia.c
+++ b/drivers/ata/pata_pcmcia.c
@@ -169,34 +169,16 @@ static struct ata_port_operations pcmcia_8bit_port_ops = {
struct pcmcia_config_check {
unsigned long ctl_base;
- int skip_vcc;
int is_kme;
};
static int pcmcia_check_one_config(struct pcmcia_device *pdev,
cistpl_cftable_entry_t *cfg,
cistpl_cftable_entry_t *dflt,
- unsigned int vcc,
void *priv_data)
{
struct pcmcia_config_check *stk = priv_data;
- /* Check for matching Vcc, unless we're desperate */
- if (!stk->skip_vcc) {
- if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
- if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000)
- return -ENODEV;
- } else if (dflt->vcc.present & (1 << CISTPL_POWER_VNOM)) {
- if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM] / 10000)
- return -ENODEV;
- }
- }
-
- if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM))
- pdev->vpp = cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
- else if (dflt->vpp1.present & (1 << CISTPL_POWER_VNOM))
- pdev->vpp = dflt->vpp1.param[CISTPL_POWER_VNOM] / 10000;
-
if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
pdev->io_lines = io->flags & CISTPL_IO_LINES_MASK;
@@ -249,6 +231,7 @@ static int pcmcia_init_one(struct pcmcia_device *pdev)
pdev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
pdev->resource[1]->flags |= IO_DATA_PATH_WIDTH_8;
pdev->config_flags |= CONF_ENABLE_IRQ;
+ pdev->config_flags |= CONF_AUTO_SET_VPP | CONF_AUTO_CHECK_VCC;
/* See if we have a manufacturer identifier. Use it to set is_kme for
vendor quirks */
@@ -262,10 +245,10 @@ static int pcmcia_init_one(struct pcmcia_device *pdev)
if (!stk)
goto out1;
stk->is_kme = is_kme;
- stk->skip_vcc = io_base = ctl_base = 0;
+ io_base = ctl_base = 0;
if (pcmcia_loop_config(pdev, pcmcia_check_one_config, stk)) {
- stk->skip_vcc = 1;
+ pdev->config_flags &= ~CONF_AUTO_CHECK_VCC;
if (pcmcia_loop_config(pdev, pcmcia_check_one_config, stk))
goto failed; /* No suitable config found */
}
diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c
index 3db9588..97338a3 100644
--- a/drivers/bluetooth/bt3c_cs.c
+++ b/drivers/bluetooth/bt3c_cs.c
@@ -659,7 +659,7 @@ static int bt3c_probe(struct pcmcia_device *link)
link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
link->resource[0]->end = 8;
- link->config_flags |= CONF_ENABLE_IRQ;
+ link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_VPP;
return bt3c_config(link);
}
@@ -676,15 +676,11 @@ static void bt3c_detach(struct pcmcia_device *link)
static int bt3c_check_config(struct pcmcia_device *p_dev,
cistpl_cftable_entry_t *cf,
cistpl_cftable_entry_t *dflt,
- unsigned int vcc,
void *priv_data)
{
unsigned long try = (unsigned long) priv_data;
-
p_dev->io_lines = (try == 0) ? 16 : cf->io.flags & CISTPL_IO_LINES_MASK;
- if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM))
- p_dev->vpp = cf->vpp1.param[CISTPL_POWER_VNOM] / 10000;
if ((cf->io.nwin > 0) && (cf->io.win[0].len == 8) &&
(cf->io.win[0].base != 0)) {
p_dev->resource[0]->start = cf->io.win[0].base;
@@ -697,7 +693,6 @@ static int bt3c_check_config(struct pcmcia_device *p_dev,
static int bt3c_check_config_notpicky(struct pcmcia_device *p_dev,
cistpl_cftable_entry_t *cf,
cistpl_cftable_entry_t *dflt,
- unsigned int vcc,
void *priv_data)
{
static unsigned int base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
diff --git a/drivers/bluetooth/btuart_cs.c b/drivers/bluetooth/btuart_cs.c
index c5c4359..8a6864f 100644
--- a/drivers/bluetooth/btuart_cs.c
+++ b/drivers/bluetooth/btuart_cs.c
@@ -588,7 +588,7 @@ static int btuart_probe(struct pcmcia_device *link)
link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
link->resource[0]->end = 8;
- link->config_flags |= CONF_ENABLE_IRQ;
+ link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_VPP;
return btuart_config(link);
}
@@ -605,15 +605,11 @@ static void btuart_detach(struct pcmcia_device *link)
static int btuart_check_config(struct pcmcia_device *p_dev,
cistpl_cftable_entry_t *cf,
cistpl_cftable_entry_t *dflt,
- unsigned int vcc,
void *priv_data)
{
int *try = priv_data;
-
p_dev->io_lines = (try == 0) ? 16 : cf->io.flags & CISTPL_IO_LINES_MASK;
- if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM))
- p_dev->vpp = cf->vpp1.param[CISTPL_POWER_VNOM] / 10000;
if ((cf->io.nwin > 0) && (cf->io.win[0].len == 8) &&
(cf->io.win[0].base != 0)) {
p_dev->resource[0]->start = cf->io.win[0].base;
@@ -626,7 +622,6 @@ static int btuart_check_config(struct pcmcia_device *p_dev,
static int btuart_check_config_notpicky(struct pcmcia_device *p_dev,
cistpl_cftable_entry_t *cf,
cistpl_cftable_entry_t *dflt,
- unsigned int vcc,
void *priv_data)
{
static unsigned int base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
diff --git a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c
index 38206df..4620cc3 100644
--- a/drivers/bluetooth/dtl1_cs.c
+++ b/drivers/bluetooth/dtl1_cs.c
@@ -592,7 +592,6 @@ static void dtl1_detach(struct pcmcia_device *link)
static int dtl1_confcheck(struct pcmcia_device *p_dev,
cistpl_cftable_entry_t *cf,
cistpl_cftable_entry_t *dflt,
- unsigned int vcc,
void *priv_data)
{
if ((cf->io.nwin != 1) || (cf->io.win[0].len <= 8))
diff --git a/drivers/char/pcmcia/cm4000_cs.c b/drivers/char/pcmcia/cm4000_cs.c
index 75caa8c..0b2f3b9 100644
--- a/drivers/char/pcmcia/cm4000_cs.c
+++ b/drivers/char/pcmcia/cm4000_cs.c
@@ -1744,7 +1744,6 @@ static void cmm_cm4000_release(struct pcmcia_device * link)
static int cm4000_config_check(struct pcmcia_device *p_dev,
cistpl_cftable_entry_t *cfg,
cistpl_cftable_entry_t *dflt,
- unsigned int vcc,
void *priv_data)
{
if (!cfg->io.nwin)
diff --git a/drivers/char/pcmcia/cm4040_cs.c b/drivers/char/pcmcia/cm4040_cs.c
index 0c87b80..acf88d5 100644
--- a/drivers/char/pcmcia/cm4040_cs.c
+++ b/drivers/char/pcmcia/cm4040_cs.c
@@ -518,7 +518,6 @@ static void cm4040_reader_release(struct pcmcia_device *link)
static int cm4040_config_check(struct pcmcia_device *p_dev,
cistpl_cftable_entry_t *cfg,
cistpl_cftable_entry_t *dflt,
- unsigned int vcc,
void *priv_data)
{
int rc;
diff --git a/drivers/char/pcmcia/ipwireless/main.c b/drivers/char/pcmcia/ipwireless/main.c
index cd21b2b..1b7f092 100644
--- a/drivers/char/pcmcia/ipwireless/main.c
+++ b/drivers/char/pcmcia/ipwireless/main.c
@@ -78,7 +78,6 @@ static void signalled_reboot_callback(void *callback_data)
static int ipwireless_probe(struct pcmcia_device *p_dev,
cistpl_cftable_entry_t *cfg,
cistpl_cftable_entry_t *dflt,
- unsigned int vcc,
void *priv_data)
{
struct ipw_dev *ipw = priv_data;
diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
index 99feaed..c701434 100644
--- a/drivers/char/pcmcia/synclink_cs.c
+++ b/drivers/char/pcmcia/synclink_cs.c
@@ -564,7 +564,6 @@ static int mgslpc_probe(struct pcmcia_device *link)
static int mgslpc_ioprobe(struct pcmcia_device *p_dev,
cistpl_cftable_entry_t *cfg,
cistpl_cftable_entry_t *dflt,
- unsigned int vcc,
void *priv_data)
{
if (!cfg->io.nwin)
diff --git a/drivers/ide/ide-cs.c b/drivers/ide/ide-cs.c
index 87ad049..25b8a10 100644
--- a/drivers/ide/ide-cs.c
+++ b/drivers/ide/ide-cs.c
@@ -99,6 +99,7 @@ static int ide_probe(struct pcmcia_device *link)
link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
link->resource[1]->flags |= IO_DATA_PATH_WIDTH_8;
link->config_flags |= CONF_ENABLE_IRQ;
+ link->config_flags |= CONF_AUTO_SET_VPP | CONF_AUTO_CHECK_VCC;
return ide_config(link);
} /* ide_attach */
@@ -195,34 +196,16 @@ out_release:
struct pcmcia_config_check {
unsigned long ctl_base;
- int skip_vcc;
int is_kme;
};
static int pcmcia_check_one_config(struct pcmcia_device *pdev,
cistpl_cftable_entry_t *cfg,
cistpl_cftable_entry_t *dflt,
- unsigned int vcc,
void *priv_data)
{
struct pcmcia_config_check *stk = priv_data;
- /* Check for matching Vcc, unless we're desperate */
- if (!stk->skip_vcc) {
- if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
- if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000)
- return -ENODEV;
- } else if (dflt->vcc.present & (1 << CISTPL_POWER_VNOM)) {
- if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM] / 10000)
- return -ENODEV;
- }
- }
-
- if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM))
- pdev->vpp = cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
- else if (dflt->vpp1.present & (1 << CISTPL_POWER_VNOM))
- pdev->vpp = dflt->vpp1.param[CISTPL_POWER_VNOM] / 10000;
-
if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
pdev->io_lines = io->flags & CISTPL_IO_LINES_MASK;
@@ -271,10 +254,10 @@ static int ide_config(struct pcmcia_device *link)
if (!stk)
goto err_mem;
stk->is_kme = is_kme;
- stk->skip_vcc = io_base = ctl_base = 0;
+ io_base = ctl_base = 0;
if (pcmcia_loop_config(link, pcmcia_check_one_config, stk)) {
- stk->skip_vcc = 1;
+ link->config_flags &= ~CONF_AUTO_CHECK_VCC;
if (pcmcia_loop_config(link, pcmcia_check_one_config, stk))
goto failed; /* No suitable config found */
}
diff --git a/drivers/isdn/hardware/avm/avm_cs.c b/drivers/isdn/hardware/avm/avm_cs.c
index 6ea5cd2..9dbab9c 100644
--- a/drivers/isdn/hardware/avm/avm_cs.c
+++ b/drivers/isdn/hardware/avm/avm_cs.c
@@ -110,7 +110,6 @@ static void avmcs_detach(struct pcmcia_device *link)
static int avmcs_configcheck(struct pcmcia_device *p_dev,
cistpl_cftable_entry_t *cf,
cistpl_cftable_entry_t *dflt,
- unsigned int vcc,
void *priv_data)
{
if (cf->io.nwin <= 0)
diff --git a/drivers/isdn/hisax/avma1_cs.c b/drivers/isdn/hisax/avma1_cs.c
index 5dd47ad..2f2b000 100644
--- a/drivers/isdn/hisax/avma1_cs.c
+++ b/drivers/isdn/hisax/avma1_cs.c
@@ -117,7 +117,6 @@ static void __devexit avma1cs_detach(struct pcmcia_device *link)
static int avma1cs_configcheck(struct pcmcia_device *p_dev,
cistpl_cftable_entry_t *cf,
cistpl_cftable_entry_t *dflt,
- unsigned int vcc,
void *priv_data)
{
if (cf->io.nwin <= 0)
diff --git a/drivers/isdn/hisax/elsa_cs.c b/drivers/isdn/hisax/elsa_cs.c
index 368c8a2..0a65280 100644
--- a/drivers/isdn/hisax/elsa_cs.c
+++ b/drivers/isdn/hisax/elsa_cs.c
@@ -163,7 +163,6 @@ static void __devexit elsa_cs_detach(struct pcmcia_device *link)
static int elsa_cs_configcheck(struct pcmcia_device *p_dev,
cistpl_cftable_entry_t *cf,
cistpl_cftable_entry_t *dflt,
- unsigned int vcc,
void *priv_data)
{
int j;
diff --git a/drivers/isdn/hisax/sedlbauer_cs.c b/drivers/isdn/hisax/sedlbauer_cs.c
index 791e23a..b69eccf 100644
--- a/drivers/isdn/hisax/sedlbauer_cs.c
+++ b/drivers/isdn/hisax/sedlbauer_cs.c
@@ -164,33 +164,11 @@ static void __devexit sedlbauer_detach(struct pcmcia_device *link)
static int sedlbauer_config_check(struct pcmcia_device *p_dev,
cistpl_cftable_entry_t *cfg,
cistpl_cftable_entry_t *dflt,
- unsigned int vcc,
void *priv_data)
{
if (cfg->index == 0)
return -ENODEV;
- /* Does this card need audio output? */
- if (cfg->flags & CISTPL_CFTABLE_AUDIO)
- p_dev->config_flags |= CONF_ENABLE_SPKR;
-
- /* Use power settings for Vcc and Vpp if present */
- /* Note that the CIS values need to be rescaled */
- if (cfg->vcc.present & (1<<CISTPL_POWER_VNOM)) {
- if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM]/10000)
- return -ENODEV;
- } else if (dflt->vcc.present & (1<<CISTPL_POWER_VNOM)) {
- if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM]/10000)
- return -ENODEV;
- }
-
- if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM))
- p_dev->vpp = cfg->vpp1.param[CISTPL_POWER_VNOM]/10000;
- else if (dflt->vpp1.present & (1<<CISTPL_POWER_VNOM))
- p_dev->vpp = dflt->vpp1.param[CISTPL_POWER_VNOM]/10000;
-
- p_dev->config_flags |= CONF_ENABLE_IRQ;
-
/* IO window settings */
p_dev->resource[0]->end = p_dev->resource[1]->end = 0;
if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
@@ -223,6 +201,9 @@ static int __devinit sedlbauer_config(struct pcmcia_device *link)
dev_dbg(&link->dev, "sedlbauer_config(0x%p)\n", link);
+ link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_CHECK_VCC |
+ CONF_AUTO_SET_VPP | CONF_AUTO_AUDIO;
+
/*
In this loop, we scan the CIS for configuration table entries,
each of which describes a valid card configuration, including
diff --git a/drivers/isdn/hisax/teles_cs.c b/drivers/isdn/hisax/teles_cs.c
index 2ae71e3..6605480 100644
--- a/drivers/isdn/hisax/teles_cs.c
+++ b/drivers/isdn/hisax/teles_cs.c
@@ -145,7 +145,6 @@ static void __devexit teles_detach(struct pcmcia_device *link)
static int teles_cs_configcheck(struct pcmcia_device *p_dev,
cistpl_cftable_entry_t *cf,
cistpl_cftable_entry_t *dflt,
- unsigned int vcc,
void *priv_data)
{
int j;
diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c
index f361d28..17f1040 100644
--- a/drivers/net/pcmcia/axnet_cs.c
+++ b/drivers/net/pcmcia/axnet_cs.c
@@ -287,7 +287,6 @@ static int try_io_port(struct pcmcia_device *link)
static int axnet_configcheck(struct pcmcia_device *p_dev,
cistpl_cftable_entry_t *cfg,
cistpl_cftable_entry_t *dflt,
- unsigned int vcc,
void *priv_data)
{
int i;
diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c
index f6865ad..c1479e3 100644
--- a/drivers/net/pcmcia/fmvj18x_cs.c
+++ b/drivers/net/pcmcia/fmvj18x_cs.c
@@ -322,7 +322,6 @@ static int ungermann_try_io_port(struct pcmcia_device *link)
static int fmvj18x_ioprobe(struct pcmcia_device *p_dev,
cistpl_cftable_entry_t *cfg,
cistpl_cftable_entry_t *dflt,
- unsigned int vcc,
void *priv_data)
{
return 0; /* strange, but that's what the code did already before... */
diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c
index 4a3b6a4..12b028c 100644
--- a/drivers/net/pcmcia/pcnet_cs.c
+++ b/drivers/net/pcmcia/pcnet_cs.c
@@ -503,7 +503,6 @@ static int try_io_port(struct pcmcia_device *link)
static int pcnet_confcheck(struct pcmcia_device *p_dev,
cistpl_cftable_entry_t *cfg,
cistpl_cftable_entry_t *dflt,
- unsigned int vcc,
void *priv_data)
{
int *priv = priv_data;
diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c
index 8c16ba6..e127d2b 100644
--- a/drivers/net/pcmcia/smc91c92_cs.c
+++ b/drivers/net/pcmcia/smc91c92_cs.c
@@ -420,7 +420,6 @@ static int mhz_3288_power(struct pcmcia_device *link)
static int mhz_mfc_config_check(struct pcmcia_device *p_dev,
cistpl_cftable_entry_t *cf,
cistpl_cftable_entry_t *dflt,
- unsigned int vcc,
void *priv_data)
{
int k;
@@ -590,7 +589,6 @@ static int mot_setup(struct pcmcia_device *link)
static int smc_configcheck(struct pcmcia_device *p_dev,
cistpl_cftable_entry_t *cf,
cistpl_cftable_entry_t *dflt,
- unsigned int vcc,
void *priv_data)
{
p_dev->resource[0]->start = cf->io.win[0].base;
diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c
index 7a4a99b..2bc2eb8 100644
--- a/drivers/net/pcmcia/xirc2ps_cs.c
+++ b/drivers/net/pcmcia/xirc2ps_cs.c
@@ -668,7 +668,6 @@ static int
xirc2ps_config_modem(struct pcmcia_device *p_dev,
cistpl_cftable_entry_t *cf,
cistpl_cftable_entry_t *dflt,
- unsigned int vcc,
void *priv_data)
{
unsigned int ioaddr;
@@ -688,7 +687,6 @@ static int
xirc2ps_config_check(struct pcmcia_device *p_dev,
cistpl_cftable_entry_t *cf,
cistpl_cftable_entry_t *dflt,
- unsigned int vcc,
void *priv_data)
{
int *pass = priv_data;
@@ -826,7 +824,8 @@ xirc2ps_config(struct pcmcia_device * link)
* the Mako if (on the first pass) the COR bit 5 is set.
*/
for (pass=0; pass < 2; pass++)
- if (!pcmcia_loop_config(link, xirc2ps_config_check, &pass))
+ if (!pcmcia_loop_config(link, xirc2ps_config_check,
+ &pass))
goto port_found;
/* if special option:
* try to configure as Ethernet only.
diff --git a/drivers/net/wireless/airo_cs.c b/drivers/net/wireless/airo_cs.c
index 5939d0c..63bf662 100644
--- a/drivers/net/wireless/airo_cs.c
+++ b/drivers/net/wireless/airo_cs.c
@@ -140,25 +140,11 @@ static void airo_detach(struct pcmcia_device *link)
static int airo_cs_config_check(struct pcmcia_device *p_dev,
cistpl_cftable_entry_t *cfg,
cistpl_cftable_entry_t *dflt,
- unsigned int vcc,
void *priv_data)
{
if (cfg->index == 0)
return -ENODEV;
- /* Does this card need audio output? */
- if (cfg->flags & CISTPL_CFTABLE_AUDIO)
- p_dev->config_flags |= CONF_ENABLE_SPKR;
-
- /* Use power settings for Vcc and Vpp if present */
- /* Note that the CIS values need to be rescaled */
- if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM))
- p_dev->vpp = cfg->vpp1.param[CISTPL_POWER_VNOM]/10000;
- else if (dflt->vpp1.present & (1<<CISTPL_POWER_VNOM))
- p_dev->vpp = dflt->vpp1.param[CISTPL_POWER_VNOM]/10000;
-
- p_dev->config_flags |= CONF_ENABLE_IRQ;
-
/* IO window settings */
p_dev->resource[0]->end = p_dev->resource[1]->end = 0;
if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
@@ -193,6 +179,9 @@ static int airo_config(struct pcmcia_device *link)
dev_dbg(&link->dev, "airo_config\n");
+ link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_VPP |
+ CONF_AUTO_AUDIO;
+
/*
* In this loop, we scan the CIS for configuration table
* entries, each of which describes a valid card
diff --git a/drivers/net/wireless/atmel_cs.c b/drivers/net/wireless/atmel_cs.c
index 080266e..812decd 100644
--- a/drivers/net/wireless/atmel_cs.c
+++ b/drivers/net/wireless/atmel_cs.c
@@ -157,25 +157,11 @@ static int card_present(void *arg)
static int atmel_config_check(struct pcmcia_device *p_dev,
cistpl_cftable_entry_t *cfg,
cistpl_cftable_entry_t *dflt,
- unsigned int vcc,
void *priv_data)
{
if (cfg->index == 0)
return -ENODEV;
- /* Does this card need audio output? */
- if (cfg->flags & CISTPL_CFTABLE_AUDIO)
- p_dev->config_flags |= CONF_ENABLE_SPKR;
-
- /* Use power settings for Vcc and Vpp if present */
- /* Note that the CIS values need to be rescaled */
- if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM))
- p_dev->vpp = cfg->vpp1.param[CISTPL_POWER_VNOM]/10000;
- else if (dflt->vpp1.present & (1<<CISTPL_POWER_VNOM))
- p_dev->vpp = dflt->vpp1.param[CISTPL_POWER_VNOM]/10000;
-
- p_dev->config_flags |= CONF_ENABLE_IRQ;
-
/* IO window settings */
p_dev->resource[0]->end = p_dev->resource[1]->end = 0;
if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
@@ -207,6 +193,9 @@ static int atmel_config(struct pcmcia_device *link)
dev_dbg(&link->dev, "atmel_config\n");
+ link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_VPP |
+ CONF_AUTO_AUDIO;
+
/*
In this loop, we scan the CIS for configuration table entries,
each of which describes a valid card configuration, including
diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c
index 5b0b582..d4f19af 100644
--- a/drivers/net/wireless/hostap/hostap_cs.c
+++ b/drivers/net/wireless/hostap/hostap_cs.c
@@ -472,7 +472,6 @@ static void prism2_detach(struct pcmcia_device *link)
static int prism2_config_check(struct pcmcia_device *p_dev,
cistpl_cftable_entry_t *cfg,
cistpl_cftable_entry_t *dflt,
- unsigned int vcc,
void *priv_data)
{
if (cfg->index == 0)
@@ -481,28 +480,6 @@ static int prism2_config_check(struct pcmcia_device *p_dev,
PDEBUG(DEBUG_EXTRA, "Checking CFTABLE_ENTRY 0x%02X "
"(default 0x%02X)\n", cfg->index, dflt->index);
- /* Does this card need audio output? */
- if (cfg->flags & CISTPL_CFTABLE_AUDIO)
- p_dev->config_flags |= CONF_ENABLE_SPKR;
-
- /* Use power settings for Vcc and Vpp if present */
- /* Note that the CIS values need to be rescaled */
- if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
- if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM] /
- 10000 && !ignore_cis_vcc) {
- PDEBUG(DEBUG_EXTRA, " Vcc mismatch - skipping"
- " this entry\n");
- return -ENODEV;
- }
- } else if (dflt->vcc.present & (1 << CISTPL_POWER_VNOM)) {
- if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM] /
- 10000 && !ignore_cis_vcc) {
- PDEBUG(DEBUG_EXTRA, " Vcc (default) mismatch "
- "- skipping this entry\n");
- return -ENODEV;
- }
- }
-
if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM))
p_dev->vpp = cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
else if (dflt->vpp1.present & (1 << CISTPL_POWER_VNOM))
@@ -553,6 +530,10 @@ static int prism2_config(struct pcmcia_device *link)
}
/* Look for an appropriate configuration table entry in the CIS */
+ link->config_flags |= CONF_AUTO_SET_VPP | CONF_AUTO_AUDIO |
+ CONF_AUTO_CHECK_VCC;
+ if (ignore_cis_vcc)
+ link->config_flags &= ~CONF_AUTO_CHECK_VCC;
ret = pcmcia_loop_config(link, prism2_config_check, NULL);
if (ret) {
if (!ignore_cis_vcc)
diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c
index 6020c19..031f3e6 100644
--- a/drivers/net/wireless/libertas/if_cs.c
+++ b/drivers/net/wireless/libertas/if_cs.c
@@ -797,7 +797,6 @@ static void if_cs_release(struct pcmcia_device *p_dev)
static int if_cs_ioprobe(struct pcmcia_device *p_dev,
cistpl_cftable_entry_t *cfg,
cistpl_cftable_entry_t *dflt,
- unsigned int vcc,
void *priv_data)
{
p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
diff --git a/drivers/net/wireless/orinoco/orinoco_cs.c b/drivers/net/wireless/orinoco/orinoco_cs.c
index 00316a1..b921738 100644
--- a/drivers/net/wireless/orinoco/orinoco_cs.c
+++ b/drivers/net/wireless/orinoco/orinoco_cs.c
@@ -145,39 +145,11 @@ static void orinoco_cs_detach(struct pcmcia_device *link)
static int orinoco_cs_config_check(struct pcmcia_device *p_dev,
cistpl_cftable_entry_t *cfg,
cistpl_cftable_entry_t *dflt,
- unsigned int vcc,
void *priv_data)
{
if (cfg->index == 0)
goto next_entry;
- /* Use power settings for Vcc and Vpp if present */
- /* Note that the CIS values need to be rescaled */
- if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
- if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) {
- DEBUG(2, "%s: Vcc mismatch (vcc = %d, CIS = %d)\n",
- __func__, vcc,
- cfg->vcc.param[CISTPL_POWER_VNOM] / 10000);
- if (!ignore_cis_vcc)
- goto next_entry;
- }
- } else if (dflt->vcc.present & (1 << CISTPL_POWER_VNOM)) {
- if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM] / 10000) {
- DEBUG(2, "%s: Vcc mismatch (vcc = %d, CIS = %d)\n",
- __func__, vcc,
- dflt->vcc.param[CISTPL_POWER_VNOM] / 10000);
- if (!ignore_cis_vcc)
- goto next_entry;
- }
- }
-
- if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM))
- p_dev->vpp =
- cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
- else if (dflt->vpp1.present & (1 << CISTPL_POWER_VNOM))
- p_dev->vpp =
- dflt->vpp1.param[CISTPL_POWER_VNOM] / 10000;
-
/* Do we need to allocate an interrupt? */
p_dev->config_flags |= CONF_ENABLE_IRQ;
@@ -230,6 +202,9 @@ orinoco_cs_config(struct pcmcia_device *link)
* and most client drivers will only use the CIS to fill in
* implementation-defined details.
*/
+ link->config_flags |= CONF_AUTO_SET_VPP | CONF_AUTO_CHECK_VCC;
+ if (ignore_cis_vcc)
+ link->config_flags &= ~CONF_AUTO_CHECK_VCC;
ret = pcmcia_loop_config(link, orinoco_cs_config_check, NULL);
if (ret) {
if (!ignore_cis_vcc)
diff --git a/drivers/net/wireless/orinoco/spectrum_cs.c b/drivers/net/wireless/orinoco/spectrum_cs.c
index ca2c6c0..f462c78 100644
--- a/drivers/net/wireless/orinoco/spectrum_cs.c
+++ b/drivers/net/wireless/orinoco/spectrum_cs.c
@@ -207,32 +207,11 @@ static void spectrum_cs_detach(struct pcmcia_device *link)
static int spectrum_cs_config_check(struct pcmcia_device *p_dev,
cistpl_cftable_entry_t *cfg,
cistpl_cftable_entry_t *dflt,
- unsigned int vcc,
void *priv_data)
{
if (cfg->index == 0)
goto next_entry;
- /* Use power settings for Vcc and Vpp if present */
- /* Note that the CIS values need to be rescaled */
- if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
- if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) {
- DEBUG(2, "%s: Vcc mismatch (vcc = %d, CIS = %d)\n",
- __func__, vcc,
- cfg->vcc.param[CISTPL_POWER_VNOM] / 10000);
- if (!ignore_cis_vcc)
- goto next_entry;
- }
- } else if (dflt->vcc.present & (1 << CISTPL_POWER_VNOM)) {
- if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM] / 10000) {
- DEBUG(2, "%s: Vcc mismatch (vcc = %d, CIS = %d)\n",
- __func__, vcc,
- dflt->vcc.param[CISTPL_POWER_VNOM] / 10000);
- if (!ignore_cis_vcc)
- goto next_entry;
- }
- }
-
if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM))
p_dev->vpp =
cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
@@ -292,6 +271,9 @@ spectrum_cs_config(struct pcmcia_device *link)
* and most client drivers will only use the CIS to fill in
* implementation-defined details.
*/
+ link->config_flags |= CONF_AUTO_SET_VPP | CONF_AUTO_CHECK_VCC;
+ if (ignore_cis_vcc)
+ link->config_flags &= ~CONF_AUTO_CHECK_VCC;
ret = pcmcia_loop_config(link, spectrum_cs_config_check, NULL);
if (ret) {
if (!ignore_cis_vcc)
diff --git a/drivers/parport/parport_cs.c b/drivers/parport/parport_cs.c
index 63b3d3c..8c2a473 100644
--- a/drivers/parport/parport_cs.c
+++ b/drivers/parport/parport_cs.c
@@ -136,7 +136,6 @@ static void parport_detach(struct pcmcia_device *link)
static int parport_config_check(struct pcmcia_device *p_dev,
cistpl_cftable_entry_t *cfg,
cistpl_cftable_entry_t *dflt,
- unsigned int vcc,
void *priv_data)
{
if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
diff --git a/drivers/pcmcia/pcmcia_cis.c b/drivers/pcmcia/pcmcia_cis.c
index ce8b94a..160da06 100644
--- a/drivers/pcmcia/pcmcia_cis.c
+++ b/drivers/pcmcia/pcmcia_cis.c
@@ -131,7 +131,6 @@ struct pcmcia_cfg_mem {
int (*conf_check) (struct pcmcia_device *p_dev,
cistpl_cftable_entry_t *cfg,
cistpl_cftable_entry_t *dflt,
- unsigned int vcc,
void *priv_data);
cisparse_t parse;
cistpl_cftable_entry_t dflt;
@@ -146,16 +145,46 @@ struct pcmcia_cfg_mem {
*/
static int pcmcia_do_loop_config(tuple_t *tuple, cisparse_t *parse, void *priv)
{
- cistpl_cftable_entry_t *cfg = &parse->cftable_entry;
struct pcmcia_cfg_mem *cfg_mem = priv;
+ struct pcmcia_device *p_dev = cfg_mem->p_dev;
+ cistpl_cftable_entry_t *cfg = &parse->cftable_entry;
+ cistpl_cftable_entry_t *dflt = &cfg_mem->dflt;
+ unsigned int flags = p_dev->config_flags;
+ unsigned int vcc = p_dev->socket->socket.Vcc;
+
+ dev_dbg(&p_dev->dev, "testing configuration %x, autoconf %x\n",
+ cfg->index, flags);
/* default values */
cfg_mem->p_dev->config_index = cfg->index;
if (cfg->flags & CISTPL_CFTABLE_DEFAULT)
cfg_mem->dflt = *cfg;
+ /* check for matching Vcc? */
+ if (flags & CONF_AUTO_CHECK_VCC) {
+ if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
+ if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000)
+ return -ENODEV;
+ } else if (dflt->vcc.present & (1 << CISTPL_POWER_VNOM)) {
+ if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM] / 10000)
+ return -ENODEV;
+ }
+ }
+
+ /* set Vpp? */
+ if (flags & CONF_AUTO_SET_VPP) {
+ if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM))
+ p_dev->vpp = cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
+ else if (dflt->vpp1.present & (1 << CISTPL_POWER_VNOM))
+ p_dev->vpp =
+ dflt->vpp1.param[CISTPL_POWER_VNOM] / 10000;
+ }
+
+ /* enable audio? */
+ if ((flags & CONF_AUTO_AUDIO) && (cfg->flags & CISTPL_CFTABLE_AUDIO))
+ p_dev->config_flags |= CONF_ENABLE_SPKR;
+
return cfg_mem->conf_check(cfg_mem->p_dev, cfg, &cfg_mem->dflt,
- cfg_mem->p_dev->socket->socket.Vcc,
cfg_mem->priv_data);
}
@@ -176,7 +205,6 @@ int pcmcia_loop_config(struct pcmcia_device *p_dev,
int (*conf_check) (struct pcmcia_device *p_dev,
cistpl_cftable_entry_t *cfg,
cistpl_cftable_entry_t *dflt,
- unsigned int vcc,
void *priv_data),
void *priv_data)
{
diff --git a/drivers/scsi/pcmcia/aha152x_stub.c b/drivers/scsi/pcmcia/aha152x_stub.c
index e1f7485..0b5fc2f 100644
--- a/drivers/scsi/pcmcia/aha152x_stub.c
+++ b/drivers/scsi/pcmcia/aha152x_stub.c
@@ -124,7 +124,6 @@ static void aha152x_detach(struct pcmcia_device *link)
static int aha152x_config_check(struct pcmcia_device *p_dev,
cistpl_cftable_entry_t *cfg,
cistpl_cftable_entry_t *dflt,
- unsigned int vcc,
void *priv_data)
{
p_dev->io_lines = 10;
diff --git a/drivers/scsi/pcmcia/fdomain_stub.c b/drivers/scsi/pcmcia/fdomain_stub.c
index ae263b1..3b9f311 100644
--- a/drivers/scsi/pcmcia/fdomain_stub.c
+++ b/drivers/scsi/pcmcia/fdomain_stub.c
@@ -106,7 +106,6 @@ static void fdomain_detach(struct pcmcia_device *link)
static int fdomain_config_check(struct pcmcia_device *p_dev,
cistpl_cftable_entry_t *cfg,
cistpl_cftable_entry_t *dflt,
- unsigned int vcc,
void *priv_data)
{
p_dev->io_lines = 10;
diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c
index d0546c0..344d499 100644
--- a/drivers/scsi/pcmcia/nsp_cs.c
+++ b/drivers/scsi/pcmcia/nsp_cs.c
@@ -1597,7 +1597,6 @@ static void nsp_cs_detach(struct pcmcia_device *link)
static int nsp_cs_config_check(struct pcmcia_device *p_dev,
cistpl_cftable_entry_t *cfg,
cistpl_cftable_entry_t *dflt,
- unsigned int vcc,
void *priv_data)
{
nsp_hw_data *data = priv_data;
@@ -1605,77 +1604,49 @@ static int nsp_cs_config_check(struct pcmcia_device *p_dev,
if (cfg->index == 0)
return -ENODEV;
- /* Does this card need audio output? */
- if (cfg->flags & CISTPL_CFTABLE_AUDIO)
- p_dev->config_flags |= CONF_ENABLE_SPKR;
-
- /* Use power settings for Vcc and Vpp if present */
- /* Note that the CIS values need to be rescaled */
- if (cfg->vcc.present & (1<<CISTPL_POWER_VNOM)) {
- if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM]/10000)
- return -ENODEV;
- else if (dflt->vcc.present & (1<<CISTPL_POWER_VNOM)) {
- if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM]/10000)
- return -ENODEV;
- }
-
- if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) {
- p_dev->vpp =
- cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
- } else if (dflt->vpp1.present & (1 << CISTPL_POWER_VNOM)) {
- p_dev->vpp =
- dflt->vpp1.param[CISTPL_POWER_VNOM] / 10000;
- }
-
- /* Do we need to allocate an interrupt? */
- p_dev->config_flags |= CONF_ENABLE_IRQ;
-
- /* IO window settings */
- p_dev->resource[0]->end = p_dev->resource[1]->end = 0;
- if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
- cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
- p_dev->io_lines = io->flags & CISTPL_IO_LINES_MASK;
- p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
- p_dev->resource[0]->flags |=
- pcmcia_io_cfg_data_width(io->flags);
- p_dev->resource[0]->start = io->win[0].base;
- p_dev->resource[0]->end = io->win[0].len;
- if (io->nwin > 1) {
- p_dev->resource[1]->flags =
- p_dev->resource[0]->flags;
- p_dev->resource[1]->start = io->win[1].base;
- p_dev->resource[1]->end = io->win[1].len;
- }
- /* This reserves IO space but doesn't actually enable it */
- if (pcmcia_request_io(p_dev) != 0)
- goto next_entry;
+ /* IO window settings */
+ p_dev->resource[0]->end = p_dev->resource[1]->end = 0;
+ if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
+ cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
+ p_dev->io_lines = io->flags & CISTPL_IO_LINES_MASK;
+ p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
+ p_dev->resource[0]->flags |=
+ pcmcia_io_cfg_data_width(io->flags);
+ p_dev->resource[0]->start = io->win[0].base;
+ p_dev->resource[0]->end = io->win[0].len;
+ if (io->nwin > 1) {
+ p_dev->resource[1]->flags = p_dev->resource[0]->flags;
+ p_dev->resource[1]->start = io->win[1].base;
+ p_dev->resource[1]->end = io->win[1].len;
}
+ /* This reserves IO space but doesn't actually enable it */
+ if (pcmcia_request_io(p_dev) != 0)
+ goto next_entry;
+ }
- if ((cfg->mem.nwin > 0) || (dflt->mem.nwin > 0)) {
- cistpl_mem_t *mem =
- (cfg->mem.nwin) ? &cfg->mem : &dflt->mem;
- p_dev->resource[2]->flags |= (WIN_DATA_WIDTH_16 |
- WIN_MEMORY_TYPE_CM |
- WIN_ENABLE);
- p_dev->resource[2]->start = mem->win[0].host_addr;
- p_dev->resource[2]->end = mem->win[0].len;
- if (p_dev->resource[2]->end < 0x1000)
- p_dev->resource[2]->end = 0x1000;
- if (pcmcia_request_window(p_dev, p_dev->resource[2],
- 0) != 0)
- goto next_entry;
- if (pcmcia_map_mem_page(p_dev, p_dev->resource[2],
- mem->win[0].card_addr) != 0)
- goto next_entry;
-
- data->MmioAddress = (unsigned long)
- ioremap_nocache(p_dev->resource[2]->start,
+ if ((cfg->mem.nwin > 0) || (dflt->mem.nwin > 0)) {
+ cistpl_mem_t *mem =
+ (cfg->mem.nwin) ? &cfg->mem : &dflt->mem;
+ p_dev->resource[2]->flags |= (WIN_DATA_WIDTH_16 |
+ WIN_MEMORY_TYPE_CM |
+ WIN_ENABLE);
+ p_dev->resource[2]->start = mem->win[0].host_addr;
+ p_dev->resource[2]->end = mem->win[0].len;
+ if (p_dev->resource[2]->end < 0x1000)
+ p_dev->resource[2]->end = 0x1000;
+ if (pcmcia_request_window(p_dev, p_dev->resource[2], 0) != 0)
+ goto next_entry;
+ if (pcmcia_map_mem_page(p_dev, p_dev->resource[2],
+ mem->win[0].card_addr) != 0)
+ goto next_entry;
+
+ data->MmioAddress = (unsigned long)
+ ioremap_nocache(p_dev->resource[2]->start,
resource_size(p_dev->resource[2]));
- data->MmioLength = resource_size(p_dev->resource[2]);
- }
- /* If we got this far, we're cool! */
- return 0;
+ data->MmioLength = resource_size(p_dev->resource[2]);
}
+ /* If we got this far, we're cool! */
+ return 0;
next_entry:
nsp_dbg(NSP_DEBUG_INIT, "next");
@@ -1692,6 +1663,9 @@ static int nsp_cs_config(struct pcmcia_device *link)
nsp_dbg(NSP_DEBUG_INIT, "in");
+ link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_CHECK_VCC |
+ CONF_AUTO_SET_VPP | CONF_AUTO_AUDIO;
+
ret = pcmcia_loop_config(link, nsp_cs_config_check, data);
if (ret)
goto cs_failed;
diff --git a/drivers/scsi/pcmcia/qlogic_stub.c b/drivers/scsi/pcmcia/qlogic_stub.c
index 7d3f49c..468fd12 100644
--- a/drivers/scsi/pcmcia/qlogic_stub.c
+++ b/drivers/scsi/pcmcia/qlogic_stub.c
@@ -179,7 +179,6 @@ static void qlogic_detach(struct pcmcia_device *link)
static int qlogic_config_check(struct pcmcia_device *p_dev,
cistpl_cftable_entry_t *cfg,
cistpl_cftable_entry_t *dflt,
- unsigned int vcc,
void *priv_data)
{
p_dev->io_lines = 10;
diff --git a/drivers/scsi/pcmcia/sym53c500_cs.c b/drivers/scsi/pcmcia/sym53c500_cs.c
index 600630e..7a0bb9a 100644
--- a/drivers/scsi/pcmcia/sym53c500_cs.c
+++ b/drivers/scsi/pcmcia/sym53c500_cs.c
@@ -686,7 +686,6 @@ static struct scsi_host_template sym53c500_driver_template = {
static int SYM53C500_config_check(struct pcmcia_device *p_dev,
cistpl_cftable_entry_t *cfg,
cistpl_cftable_entry_t *dflt,
- unsigned int vcc,
void *priv_data)
{
p_dev->io_lines = 10;
diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c
index 47b1869..a796a93 100644
--- a/drivers/serial/serial_cs.c
+++ b/drivers/serial/serial_cs.c
@@ -427,16 +427,11 @@ static int pfc_config(struct pcmcia_device *p_dev)
static int simple_config_check(struct pcmcia_device *p_dev,
cistpl_cftable_entry_t *cf,
cistpl_cftable_entry_t *dflt,
- unsigned int vcc,
void *priv_data)
{
static const int size_table[2] = { 8, 16 };
int *try = priv_data;
- if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM))
- p_dev->vpp =
- cf->vpp1.param[CISTPL_POWER_VNOM] / 10000;
-
p_dev->io_lines = ((*try & 0x1) == 0) ?
16 : cf->io.flags & CISTPL_IO_LINES_MASK;
@@ -452,7 +447,6 @@ static int simple_config_check(struct pcmcia_device *p_dev,
static int simple_config_check_notpicky(struct pcmcia_device *p_dev,
cistpl_cftable_entry_t *cf,
cistpl_cftable_entry_t *dflt,
- unsigned int vcc,
void *priv_data)
{
static const unsigned int base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
@@ -479,6 +473,7 @@ static int simple_config(struct pcmcia_device *link)
/* First pass: look for a config entry that looks normal.
* Two tries: without IO aliases, then with aliases */
+ link->config_flags |= CONF_AUTO_SET_VPP;
for (try = 0; try < 4; try++)
if (!pcmcia_loop_config(link, simple_config_check, &try))
goto found_port;
@@ -511,7 +506,6 @@ found_port:
static int multi_config_check(struct pcmcia_device *p_dev,
cistpl_cftable_entry_t *cf,
cistpl_cftable_entry_t *dflt,
- unsigned int vcc,
void *priv_data)
{
int *base2 = priv_data;
@@ -532,7 +526,6 @@ static int multi_config_check(struct pcmcia_device *p_dev,
static int multi_config_check_notpicky(struct pcmcia_device *p_dev,
cistpl_cftable_entry_t *cf,
cistpl_cftable_entry_t *dflt,
- unsigned int vcc,
void *priv_data)
{
int *base2 = priv_data;
@@ -621,7 +614,6 @@ static int multi_config(struct pcmcia_device *link)
static int serial_check_for_multi(struct pcmcia_device *p_dev,
cistpl_cftable_entry_t *cf,
cistpl_cftable_entry_t *dflt,
- unsigned int vcc,
void *priv_data)
{
struct serial_info *info = p_dev->priv;
diff --git a/drivers/staging/comedi/drivers/cb_das16_cs.c b/drivers/staging/comedi/drivers/cb_das16_cs.c
index ee91c89..678fbf6 100644
--- a/drivers/staging/comedi/drivers/cb_das16_cs.c
+++ b/drivers/staging/comedi/drivers/cb_das16_cs.c
@@ -712,7 +712,6 @@ static void das16cs_pcmcia_detach(struct pcmcia_device *link)
static int das16cs_pcmcia_config_loop(struct pcmcia_device *p_dev,
cistpl_cftable_entry_t *cfg,
cistpl_cftable_entry_t *dflt,
- unsigned int vcc,
void *priv_data)
{
if (cfg->index == 0)
diff --git a/drivers/staging/comedi/drivers/das08_cs.c b/drivers/staging/comedi/drivers/das08_cs.c
index f8f3de5..12a96b7 100644
--- a/drivers/staging/comedi/drivers/das08_cs.c
+++ b/drivers/staging/comedi/drivers/das08_cs.c
@@ -194,7 +194,6 @@ static void das08_pcmcia_detach(struct pcmcia_device *link)
static int das08_pcmcia_config_loop(struct pcmcia_device *p_dev,
cistpl_cftable_entry_t *cfg,
cistpl_cftable_entry_t *dflt,
- unsigned int vcc,
void *priv_data)
{
if (cfg->index == 0)
diff --git a/drivers/staging/comedi/drivers/ni_daq_700.c b/drivers/staging/comedi/drivers/ni_daq_700.c
index 803683b..f22dc0f 100644
--- a/drivers/staging/comedi/drivers/ni_daq_700.c
+++ b/drivers/staging/comedi/drivers/ni_daq_700.c
@@ -532,19 +532,11 @@ static void dio700_cs_detach(struct pcmcia_device *link)
static int dio700_pcmcia_config_loop(struct pcmcia_device *p_dev,
cistpl_cftable_entry_t *cfg,
cistpl_cftable_entry_t *dflt,
- unsigned int vcc,
void *priv_data)
{
if (cfg->index == 0)
return -ENODEV;
- /* Does this card need audio output? */
- if (cfg->flags & CISTPL_CFTABLE_AUDIO)
- p_dev->config_flags |= CONF_ENABLE_SPKR;
-
- /* Do we need to allocate an interrupt? */
- p_dev->config_flags |= CONF_ENABLE_IRQ;
-
/* IO window settings */
p_dev->resource[0]->end = p_dev->resource[1]->end = 0;
if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
@@ -578,6 +570,8 @@ static void dio700_config(struct pcmcia_device *link)
dev_dbg(&link->dev, "dio700_config\n");
+ link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_AUDIO;
+
ret = pcmcia_loop_config(link, dio700_pcmcia_config_loop, NULL);
if (ret) {
dev_warn(&link->dev, "no configuration found\n");
diff --git a/drivers/staging/comedi/drivers/ni_daq_dio24.c b/drivers/staging/comedi/drivers/ni_daq_dio24.c
index 6512f7a..6dc2b06 100644
--- a/drivers/staging/comedi/drivers/ni_daq_dio24.c
+++ b/drivers/staging/comedi/drivers/ni_daq_dio24.c
@@ -284,19 +284,11 @@ static void dio24_cs_detach(struct pcmcia_device *link)
static int dio24_pcmcia_config_loop(struct pcmcia_device *p_dev,
cistpl_cftable_entry_t *cfg,
cistpl_cftable_entry_t *dflt,
- unsigned int vcc,
void *priv_data)
{
if (cfg->index == 0)
return -ENODEV;
- /* Does this card need audio output? */
- if (cfg->flags & CISTPL_CFTABLE_AUDIO)
- p_dev->config_flags |= CONF_ENABLE_SPKR;
-
- /* Do we need to allocate an interrupt? */
- p_dev->config_flags |= CONF_ENABLE_IRQ;
-
/* IO window settings */
p_dev->resource[0]->end = p_dev->resource[1]->end = 0;
if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
@@ -329,6 +321,8 @@ static void dio24_config(struct pcmcia_device *link)
dev_dbg(&link->dev, "dio24_config\n");
+ link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_AUDIO;
+
ret = pcmcia_loop_config(link, dio24_pcmcia_config_loop, NULL);
if (ret) {
dev_warn(&link->dev, "no configuration found\n");
diff --git a/drivers/staging/comedi/drivers/ni_labpc_cs.c b/drivers/staging/comedi/drivers/ni_labpc_cs.c
index 255cf40..6eacbd7 100644
--- a/drivers/staging/comedi/drivers/ni_labpc_cs.c
+++ b/drivers/staging/comedi/drivers/ni_labpc_cs.c
@@ -263,19 +263,11 @@ static void labpc_cs_detach(struct pcmcia_device *link)
static int labpc_pcmcia_config_loop(struct pcmcia_device *p_dev,
cistpl_cftable_entry_t *cfg,
cistpl_cftable_entry_t *dflt,
- unsigned int vcc,
void *priv_data)
{
if (cfg->index == 0)
return -ENODEV;
- /* Does this card need audio output? */
- if (cfg->flags & CISTPL_CFTABLE_AUDIO)
- p_dev->config_flags |= CONF_ENABLE_SPKR;
-
- /* Do we need to allocate an interrupt? */
- p_dev->config_flags |= CONF_ENABLE_IRQ | CONF_ENABLE_PULSE_IRQ;
-
/* IO window settings */
p_dev->resource[0]->end = p_dev->resource[1]->end = 0;
if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
@@ -307,6 +299,9 @@ static void labpc_config(struct pcmcia_device *link)
dev_dbg(&link->dev, "labpc_config\n");
+ link->config_flags |= CONF_ENABLE_IRQ | CONF_ENABLE_PULSE_IRQ |
+ CONF_AUTO_AUDIO;
+
ret = pcmcia_loop_config(link, labpc_pcmcia_config_loop, NULL);
if (ret) {
dev_warn(&link->dev, "no configuration found\n");
diff --git a/drivers/staging/comedi/drivers/ni_mio_cs.c b/drivers/staging/comedi/drivers/ni_mio_cs.c
index b88f52d..da4e2a2 100644
--- a/drivers/staging/comedi/drivers/ni_mio_cs.c
+++ b/drivers/staging/comedi/drivers/ni_mio_cs.c
@@ -302,7 +302,6 @@ static int mio_cs_resume(struct pcmcia_device *link)
static int mio_pcmcia_config_loop(struct pcmcia_device *p_dev,
cistpl_cftable_entry_t *cfg,
cistpl_cftable_entry_t *dflt,
- unsigned int vcc,
void *priv_data)
{
int base, ret;
diff --git a/drivers/staging/comedi/drivers/quatech_daqp_cs.c b/drivers/staging/comedi/drivers/quatech_daqp_cs.c
index b8940d7..03a72d7 100644
--- a/drivers/staging/comedi/drivers/quatech_daqp_cs.c
+++ b/drivers/staging/comedi/drivers/quatech_daqp_cs.c
@@ -1071,7 +1071,6 @@ static void daqp_cs_detach(struct pcmcia_device *link)
static int daqp_pcmcia_config_loop(struct pcmcia_device *p_dev,
cistpl_cftable_entry_t *cfg,
cistpl_cftable_entry_t *dflt,
- unsigned int vcc,
void *priv_data)
{
if (cfg->index == 0)
diff --git a/drivers/telephony/ixj_pcmcia.c b/drivers/telephony/ixj_pcmcia.c
index e23270d..670a76b 100644
--- a/drivers/telephony/ixj_pcmcia.c
+++ b/drivers/telephony/ixj_pcmcia.c
@@ -112,7 +112,6 @@ failed:
static int ixj_config_check(struct pcmcia_device *p_dev,
cistpl_cftable_entry_t *cfg,
cistpl_cftable_entry_t *dflt,
- unsigned int vcc,
void *priv_data)
{
if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
diff --git a/drivers/usb/host/sl811_cs.c b/drivers/usb/host/sl811_cs.c
index 744c2cd..d960629 100644
--- a/drivers/usb/host/sl811_cs.c
+++ b/drivers/usb/host/sl811_cs.c
@@ -134,32 +134,11 @@ static void sl811_cs_release(struct pcmcia_device * link)
static int sl811_cs_config_check(struct pcmcia_device *p_dev,
cistpl_cftable_entry_t *cfg,
cistpl_cftable_entry_t *dflt,
- unsigned int vcc,
void *priv_data)
{
if (cfg->index == 0)
return -ENODEV;
- /* Use power settings for Vcc and Vpp if present */
- /* Note that the CIS values need to be rescaled */
- if (cfg->vcc.present & (1<<CISTPL_POWER_VNOM)) {
- if (cfg->vcc.param[CISTPL_POWER_VNOM]/10000 != vcc)
- return -ENODEV;
- } else if (dflt->vcc.present & (1<<CISTPL_POWER_VNOM)) {
- if (dflt->vcc.param[CISTPL_POWER_VNOM]/10000 != vcc)
- return -ENODEV;
- }
-
- if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM))
- p_dev->vpp =
- cfg->vpp1.param[CISTPL_POWER_VNOM]/10000;
- else if (dflt->vpp1.present & (1<<CISTPL_POWER_VNOM))
- p_dev->vpp =
- dflt->vpp1.param[CISTPL_POWER_VNOM]/10000;
-
- /* we need an interrupt */
- p_dev->config_flags |= CONF_ENABLE_IRQ;
-
/* IO window settings */
p_dev->resource[0]->end = p_dev->resource[1]->end = 0;
if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
@@ -184,6 +163,9 @@ static int sl811_cs_config(struct pcmcia_device *link)
dev_dbg(&link->dev, "sl811_cs_config\n");
+ link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_VPP |
+ CONF_AUTO_CHECK_VCC;
+
if (pcmcia_loop_config(link, sl811_cs_config_check, NULL))
goto failed;
diff --git a/include/pcmcia/ds.h b/include/pcmcia/ds.h
index 50b03fd..0577e5f 100644
--- a/include/pcmcia/ds.h
+++ b/include/pcmcia/ds.h
@@ -177,7 +177,6 @@ int pcmcia_loop_config(struct pcmcia_device *p_dev,
int (*conf_check) (struct pcmcia_device *p_dev,
cistpl_cftable_entry_t *cf,
cistpl_cftable_entry_t *dflt,
- unsigned int vcc,
void *priv_data),
void *priv_data);
@@ -270,6 +269,12 @@ static inline int pcmcia_io_cfg_data_width(unsigned int flags)
#define CONF_ENABLE_PULSE_IRQ 0x04
#define CONF_ENABLE_ESR 0x08
+/* flags used by pcmcia_loop_config() autoconfiguration */
+#define CONF_AUTO_CHECK_VCC 0x10 /* check for matching Vcc? */
+#define CONF_AUTO_SET_VPP 0x20 /* set Vpp? */
+#define CONF_AUTO_AUDIO 0x40 /* enable audio line? */
+
+
#endif /* __KERNEL__ */
#endif /* _LINUX_DS_H */
--
1.7.0.4
1
0

[alsa-devel] [PATCH 07/22] pcmcia: move config_{base, index, regs} to struct pcmcia_device
by Dominik Brodowski 21 Oct '10
by Dominik Brodowski 21 Oct '10
21 Oct '10
Several drivers prefer to explicitly set config_{base,index,regs},
formerly known as ConfigBase, ConfigIndex and Present. Instead of
passing these values inside config_req_t, store it in struct
pcmcia_device.
CC: netdev(a)vger.kernel.org
CC: linux-wireless(a)vger.kernel.org
CC: linux-ide(a)vger.kernel.org
CC: linux-usb(a)vger.kernel.org
CC: laforge(a)gnumonks.org
CC: linux-mtd(a)lists.infradead.org
CC: alsa-devel(a)alsa-project.org
CC: linux-serial(a)vger.kernel.org
CC: Jiri Kosina <jkosina(a)suse.cz>
CC: linux-scsi(a)vger.kernel.org
Acked-by: Gustavo F. Padovan <padovan(a)profusion.mobi> (for drivers/bluetooth)
Tested-by: Wolfram Sang <w.sang(a)pengutronix.de>
Signed-off-by: Dominik Brodowski <linux(a)dominikbrodowski.net>
---
drivers/bluetooth/bluecard_cs.c | 2 +-
drivers/char/pcmcia/ipwireless/main.c | 2 +-
drivers/char/pcmcia/synclink_cs.c | 6 ++--
drivers/ide/ide-cs.c | 3 +-
drivers/isdn/hardware/avm/avm_cs.c | 4 +-
drivers/isdn/hisax/avma1_cs.c | 4 +-
drivers/isdn/hisax/elsa_cs.c | 2 +-
drivers/isdn/hisax/sedlbauer_cs.c | 2 +-
drivers/isdn/hisax/teles_cs.c | 2 +-
drivers/mtd/maps/pcmciamtd.c | 2 +-
drivers/net/pcmcia/3c574_cs.c | 2 +-
drivers/net/pcmcia/3c589_cs.c | 2 +-
drivers/net/pcmcia/axnet_cs.c | 6 ++--
drivers/net/pcmcia/fmvj18x_cs.c | 22 ++++++------
drivers/net/pcmcia/ibmtr_cs.c | 4 +-
drivers/net/pcmcia/nmclan_cs.c | 4 +-
drivers/net/pcmcia/pcnet_cs.c | 6 ++--
drivers/net/pcmcia/smc91c92_cs.c | 10 +++---
drivers/net/pcmcia/xirc2ps_cs.c | 2 +-
drivers/net/wireless/airo_cs.c | 2 +-
drivers/net/wireless/hostap/hostap_cs.c | 2 +-
drivers/net/wireless/ray_cs.c | 2 +-
drivers/net/wireless/wl3501_cs.c | 2 +-
drivers/parport/parport_cs.c | 2 +-
drivers/pcmcia/cs_internal.h | 3 --
drivers/pcmcia/ds.c | 8 ++--
drivers/pcmcia/pcmcia_cis.c | 2 +-
drivers/pcmcia/pcmcia_resource.c | 38 +++++++++++-----------
drivers/scsi/pcmcia/aha152x_stub.c | 2 +-
drivers/scsi/pcmcia/fdomain_stub.c | 2 +-
drivers/scsi/pcmcia/nsp_cs.c | 2 +-
drivers/scsi/pcmcia/qlogic_stub.c | 2 +-
drivers/serial/serial_cs.c | 6 ++--
drivers/staging/comedi/drivers/cb_das16_cs.c | 2 +-
drivers/staging/comedi/drivers/das08_cs.c | 2 +-
drivers/staging/comedi/drivers/ni_daq_700.c | 2 +-
drivers/staging/comedi/drivers/ni_daq_dio24.c | 2 +-
drivers/staging/comedi/drivers/ni_labpc_cs.c | 2 +-
drivers/staging/comedi/drivers/quatech_daqp_cs.c | 2 +-
drivers/staging/wlags49_h2/wl_cs.c | 4 +-
drivers/usb/host/sl811_cs.c | 2 +-
include/pcmcia/cs.h | 15 --------
include/pcmcia/ds.h | 14 ++++++++
sound/pcmcia/pdaudiocf/pdaudiocf.c | 6 ++--
sound/pcmcia/vx/vxpocket.c | 4 +-
45 files changed, 107 insertions(+), 112 deletions(-)
diff --git a/drivers/bluetooth/bluecard_cs.c b/drivers/bluetooth/bluecard_cs.c
index 4cb2dfe..08f4818 100644
--- a/drivers/bluetooth/bluecard_cs.c
+++ b/drivers/bluetooth/bluecard_cs.c
@@ -885,7 +885,7 @@ static int bluecard_config(struct pcmcia_device *link)
bluecard_info_t *info = link->priv;
int i, n;
- link->conf.ConfigIndex = 0x20;
+ link->config_index = 0x20;
link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
link->resource[0]->end = 64;
diff --git a/drivers/char/pcmcia/ipwireless/main.c b/drivers/char/pcmcia/ipwireless/main.c
index 0f0be4d..05c4e68 100644
--- a/drivers/char/pcmcia/ipwireless/main.c
+++ b/drivers/char/pcmcia/ipwireless/main.c
@@ -92,7 +92,7 @@ static int ipwireless_probe(struct pcmcia_device *p_dev,
/* 0x40 causes it to generate level mode interrupts. */
/* 0x04 enables IREQ pin. */
- p_dev->conf.ConfigIndex = cfg->index | 0x44;
+ p_dev->config_index = cfg->index | 0x44;
p_dev->io_lines = 16;
ret = pcmcia_request_io(p_dev);
if (ret)
diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
index ba7ccf5..535aa08 100644
--- a/drivers/char/pcmcia/synclink_cs.c
+++ b/drivers/char/pcmcia/synclink_cs.c
@@ -594,8 +594,8 @@ static int mgslpc_config(struct pcmcia_device *link)
goto failed;
link->conf.Attributes = CONF_ENABLE_IRQ;
- link->conf.ConfigIndex = 8;
- link->conf.Present = PRESENT_OPTION;
+ link->config_index = 8;
+ link->config_regs = PRESENT_OPTION;
ret = pcmcia_request_irq(link, mgslpc_isr);
if (ret)
@@ -608,7 +608,7 @@ static int mgslpc_config(struct pcmcia_device *link)
info->irq_level = link->irq;
dev_info(&link->dev, "index 0x%02x:",
- link->conf.ConfigIndex);
+ link->config_index);
if (link->conf.Attributes & CONF_ENABLE_IRQ)
printk(", irq %d", link->irq);
if (link->resource[0])
diff --git a/drivers/ide/ide-cs.c b/drivers/ide/ide-cs.c
index cf7cb49..07e3787 100644
--- a/drivers/ide/ide-cs.c
+++ b/drivers/ide/ide-cs.c
@@ -227,8 +227,7 @@ static int pcmcia_check_one_config(struct pcmcia_device *pdev,
if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
pdev->io_lines = io->flags & CISTPL_IO_LINES_MASK;
-
- pdev->conf.ConfigIndex = cfg->index;
+ pdev->config_index = cfg->index;
pdev->resource[0]->start = io->win[0].base;
if (!(io->flags & CISTPL_IO_16BIT)) {
pdev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
diff --git a/drivers/isdn/hardware/avm/avm_cs.c b/drivers/isdn/hardware/avm/avm_cs.c
index 938ca41..2d8bbbf 100644
--- a/drivers/isdn/hardware/avm/avm_cs.c
+++ b/drivers/isdn/hardware/avm/avm_cs.c
@@ -80,8 +80,8 @@ static int avmcs_probe(struct pcmcia_device *p_dev)
/* General socket configuration */
p_dev->conf.Attributes = CONF_ENABLE_IRQ;
- p_dev->conf.ConfigIndex = 1;
- p_dev->conf.Present = PRESENT_OPTION;
+ p_dev->config_index = 1;
+ p_dev->config_regs = PRESENT_OPTION;
return avmcs_config(p_dev);
} /* avmcs_attach */
diff --git a/drivers/isdn/hisax/avma1_cs.c b/drivers/isdn/hisax/avma1_cs.c
index 7d5ff20..e25f6c7 100644
--- a/drivers/isdn/hisax/avma1_cs.c
+++ b/drivers/isdn/hisax/avma1_cs.c
@@ -85,8 +85,8 @@ static int __devinit avma1cs_probe(struct pcmcia_device *p_dev)
/* General socket configuration */
p_dev->conf.Attributes = CONF_ENABLE_IRQ;
- p_dev->conf.ConfigIndex = 1;
- p_dev->conf.Present = PRESENT_OPTION;
+ p_dev->config_index = 1;
+ p_dev->config_regs = PRESENT_OPTION;
return avma1cs_config(p_dev);
} /* avma1cs_attach */
diff --git a/drivers/isdn/hisax/elsa_cs.c b/drivers/isdn/hisax/elsa_cs.c
index df360c8..f276e84 100644
--- a/drivers/isdn/hisax/elsa_cs.c
+++ b/drivers/isdn/hisax/elsa_cs.c
@@ -211,7 +211,7 @@ static int __devinit elsa_cs_config(struct pcmcia_device *link)
/* Finally, report what we've done */
dev_info(&link->dev, "index 0x%02x: ",
- link->conf.ConfigIndex);
+ link->config_index);
if (link->conf.Attributes & CONF_ENABLE_IRQ)
printk(", irq %d", link->irq);
if (link->resource[0])
diff --git a/drivers/isdn/hisax/sedlbauer_cs.c b/drivers/isdn/hisax/sedlbauer_cs.c
index 169061f..43d0a4e 100644
--- a/drivers/isdn/hisax/sedlbauer_cs.c
+++ b/drivers/isdn/hisax/sedlbauer_cs.c
@@ -253,7 +253,7 @@ static int __devinit sedlbauer_config(struct pcmcia_device *link)
/* Finally, report what we've done */
dev_info(&link->dev, "index 0x%02x:",
- link->conf.ConfigIndex);
+ link->config_index);
if (link->vpp)
printk(", Vpp %d.%d", link->vpp/10, link->vpp%10);
if (link->conf.Attributes & CONF_ENABLE_IRQ)
diff --git a/drivers/isdn/hisax/teles_cs.c b/drivers/isdn/hisax/teles_cs.c
index 46e72a1..614afc6 100644
--- a/drivers/isdn/hisax/teles_cs.c
+++ b/drivers/isdn/hisax/teles_cs.c
@@ -191,7 +191,7 @@ static int __devinit teles_cs_config(struct pcmcia_device *link)
/* Finally, report what we've done */
dev_info(&link->dev, "index 0x%02x:",
- link->conf.ConfigIndex);
+ link->config_index);
if (link->conf.Attributes & CONF_ENABLE_IRQ)
printk(", irq %d", link->irq);
if (link->resource[0])
diff --git a/drivers/mtd/maps/pcmciamtd.c b/drivers/mtd/maps/pcmciamtd.c
index 663b48b..99c7257 100644
--- a/drivers/mtd/maps/pcmciamtd.c
+++ b/drivers/mtd/maps/pcmciamtd.c
@@ -575,7 +575,7 @@ static int pcmciamtd_config(struct pcmcia_device *link)
link->vpp = 0;
}
- link->conf.ConfigIndex = 0;
+ link->config_index = 0;
DEBUG(2, "Setting Configuration");
ret = pcmcia_request_configuration(link, &link->conf);
if (ret != 0) {
diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c
index 41ecb27..4b670b3 100644
--- a/drivers/net/pcmcia/3c574_cs.c
+++ b/drivers/net/pcmcia/3c574_cs.c
@@ -281,7 +281,7 @@ static int tc574_probe(struct pcmcia_device *link)
link->resource[0]->end = 32;
link->resource[0]->flags |= IO_DATA_PATH_WIDTH_16;
link->conf.Attributes = CONF_ENABLE_IRQ;
- link->conf.ConfigIndex = 1;
+ link->config_index = 1;
dev->netdev_ops = &el3_netdev_ops;
SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c
index 6888672..6549e2c 100644
--- a/drivers/net/pcmcia/3c589_cs.c
+++ b/drivers/net/pcmcia/3c589_cs.c
@@ -217,7 +217,7 @@ static int tc589_probe(struct pcmcia_device *link)
link->resource[0]->flags |= IO_DATA_PATH_WIDTH_16;
link->conf.Attributes = CONF_ENABLE_IRQ;
- link->conf.ConfigIndex = 1;
+ link->config_index = 1;
dev->netdev_ops = &el3_netdev_ops;
dev->watchdog_timeo = TX_TIMEOUT;
diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c
index 4d4928a..2c273ce 100644
--- a/drivers/net/pcmcia/axnet_cs.c
+++ b/drivers/net/pcmcia/axnet_cs.c
@@ -230,7 +230,7 @@ static int get_prom(struct pcmcia_device *link)
};
/* Not much of a test, but the alternatives are messy */
- if (link->conf.ConfigBase != 0x03c0)
+ if (link->config_base != 0x03c0)
return 0;
axnet_reset_8390(dev);
@@ -297,7 +297,7 @@ static int axnet_configcheck(struct pcmcia_device *p_dev,
if (cfg->index == 0 || cfg->io.nwin == 0)
return -ENODEV;
- p_dev->conf.ConfigIndex = 0x05;
+ p_dev->config_index = 0x05;
/* For multifunction cards, by convention, we configure the
network function with window 0, and serial with window 1 */
if (io->nwin > 1) {
@@ -325,7 +325,7 @@ static int axnet_config(struct pcmcia_device *link)
dev_dbg(&link->dev, "axnet_config(0x%p)\n", link);
/* don't trust the CIS on this; Linksys got it wrong */
- link->conf.Present = 0x63;
+ link->config_regs = 0x63;
ret = pcmcia_loop_config(link, axnet_configcheck, NULL);
if (ret != 0)
goto failed;
diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c
index caf2b2e..23f5333 100644
--- a/drivers/net/pcmcia/fmvj18x_cs.c
+++ b/drivers/net/pcmcia/fmvj18x_cs.c
@@ -312,7 +312,7 @@ static int ungermann_try_io_port(struct pcmcia_device *link)
ret = pcmcia_request_io(link);
if (ret == 0) {
/* calculate ConfigIndex value */
- link->conf.ConfigIndex =
+ link->config_index =
((link->resource[0]->start & 0x0f0) >> 3) | 0x22;
return ret;
}
@@ -361,28 +361,28 @@ static int fmvj18x_config(struct pcmcia_device *link)
link->card_id == PRODID_TDK_NP9610 ||
link->card_id == PRODID_TDK_MN3200) {
/* MultiFunction Card */
- link->conf.ConfigBase = 0x800;
- link->conf.ConfigIndex = 0x47;
+ link->config_base = 0x800;
+ link->config_index = 0x47;
link->resource[1]->end = 8;
}
break;
case MANFID_NEC:
cardtype = NEC; /* MultiFunction Card */
- link->conf.ConfigBase = 0x800;
- link->conf.ConfigIndex = 0x47;
+ link->config_base = 0x800;
+ link->config_index = 0x47;
link->resource[1]->end = 8;
break;
case MANFID_KME:
cardtype = KME; /* MultiFunction Card */
- link->conf.ConfigBase = 0x800;
- link->conf.ConfigIndex = 0x47;
+ link->config_base = 0x800;
+ link->config_index = 0x47;
link->resource[1]->end = 8;
break;
case MANFID_CONTEC:
cardtype = CONTEC;
break;
case MANFID_FUJITSU:
- if (link->conf.ConfigBase == 0x0fe0)
+ if (link->config_base == 0x0fe0)
cardtype = MBH10302;
else if (link->card_id == PRODID_FUJITSU_MBH10302)
/* RATOC REX-5588/9822/4886's PRODID are 0004(=MBH10302),
@@ -402,10 +402,10 @@ static int fmvj18x_config(struct pcmcia_device *link)
case MANFID_FUJITSU:
if (link->card_id == PRODID_FUJITSU_MBH10304) {
cardtype = XXX10304; /* MBH10304 with buggy CIS */
- link->conf.ConfigIndex = 0x20;
+ link->config_index = 0x20;
} else {
cardtype = MBH10302; /* NextCom NC5310, etc. */
- link->conf.ConfigIndex = 1;
+ link->config_index = 1;
}
break;
case MANFID_UNGERMANN:
@@ -413,7 +413,7 @@ static int fmvj18x_config(struct pcmcia_device *link)
break;
default:
cardtype = MBH10302;
- link->conf.ConfigIndex = 1;
+ link->config_index = 1;
}
}
diff --git a/drivers/net/pcmcia/ibmtr_cs.c b/drivers/net/pcmcia/ibmtr_cs.c
index 1327f08..feedeeb 100644
--- a/drivers/net/pcmcia/ibmtr_cs.c
+++ b/drivers/net/pcmcia/ibmtr_cs.c
@@ -153,7 +153,7 @@ static int __devinit ibmtr_attach(struct pcmcia_device *link)
link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
link->resource[0]->end = 4;
link->conf.Attributes = CONF_ENABLE_IRQ;
- link->conf.Present = PRESENT_OPTION;
+ link->config_regs = PRESENT_OPTION;
info->dev = dev;
@@ -212,8 +212,8 @@ static int __devinit ibmtr_config(struct pcmcia_device *link)
dev_dbg(&link->dev, "ibmtr_config\n");
- link->conf.ConfigIndex = 0x61;
link->io_lines = 16;
+ link->config_index = 0x61;
/* Determine if this is PRIMARY or ALTERNATE. */
diff --git a/drivers/net/pcmcia/nmclan_cs.c b/drivers/net/pcmcia/nmclan_cs.c
index 90d1728..98c4a69 100644
--- a/drivers/net/pcmcia/nmclan_cs.c
+++ b/drivers/net/pcmcia/nmclan_cs.c
@@ -461,8 +461,8 @@ static int nmclan_probe(struct pcmcia_device *link)
link->resource[0]->end = 32;
link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
link->conf.Attributes = CONF_ENABLE_IRQ;
- link->conf.ConfigIndex = 1;
- link->conf.Present = PRESENT_OPTION;
+ link->config_index = 1;
+ link->config_regs = PRESENT_OPTION;
lp->tx_free_frames=AM2150_MAX_TX_FRAMES;
diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c
index 6913576..68c4675 100644
--- a/drivers/net/pcmcia/pcnet_cs.c
+++ b/drivers/net/pcmcia/pcnet_cs.c
@@ -420,7 +420,7 @@ static hw_info_t *get_ax88190(struct pcmcia_device *link)
int i, j;
/* Not much of a test, but the alternatives are messy */
- if (link->conf.ConfigBase != 0x03c0)
+ if (link->config_base != 0x03c0)
return NULL;
outb_p(0x01, ioaddr + EN0_DCFG); /* Set word-wide access. */
@@ -564,7 +564,7 @@ static hw_info_t *pcnet_try_config(struct pcmcia_device *link,
if ((link->manf_id == MANFID_IBM) &&
(link->card_id == PRODID_IBM_HOME_AND_AWAY))
- link->conf.ConfigIndex |= 0x10;
+ link->config_index |= 0x10;
ret = pcmcia_request_configuration(link, &link->conf);
if (ret)
@@ -581,7 +581,7 @@ static hw_info_t *pcnet_try_config(struct pcmcia_device *link,
} else
dev->if_port = 0;
- if ((link->conf.ConfigBase == 0x03c0) &&
+ if ((link->config_base == 0x03c0) &&
(link->manf_id == 0x149) && (link->card_id == 0xc1ab)) {
dev_info(&link->dev,
"this is an AX88190 card - use axnet_cs instead.\n");
diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c
index 2c2a878..59f5034 100644
--- a/drivers/net/pcmcia/smc91c92_cs.c
+++ b/drivers/net/pcmcia/smc91c92_cs.c
@@ -411,9 +411,9 @@ static int mhz_3288_power(struct pcmcia_device *link)
mdelay(200);
/* Now read and write the COR... */
- tmp = readb(smc->base + link->conf.ConfigBase + CISREG_COR);
+ tmp = readb(smc->base + link->config_base + CISREG_COR);
udelay(5);
- writeb(tmp, smc->base + link->conf.ConfigBase + CISREG_COR);
+ writeb(tmp, smc->base + link->config_base + CISREG_COR);
return 0;
}
@@ -464,7 +464,7 @@ static int mhz_mfc_config(struct pcmcia_device *link)
smc->base = ioremap(link->resource[2]->start,
resource_size(link->resource[2]));
- offset = (smc->manfid == MANFID_MOTOROLA) ? link->conf.ConfigBase : 0;
+ offset = (smc->manfid == MANFID_MOTOROLA) ? link->config_base : 0;
i = pcmcia_map_mem_page(link, link->resource[2], offset);
if ((i == 0) &&
(smc->manfid == MANFID_MEGAHERTZ) &&
@@ -643,8 +643,8 @@ static int osi_config(struct pcmcia_device *link)
link->resource[1]->end = 8;
/* Enable Hard Decode, LAN, Modem */
- link->conf.ConfigIndex = 0x23;
link->io_lines = 16;
+ link->config_index = 0x23;
for (i = j = 0; j < 4; j++) {
link->resource[1]->start = com[j];
@@ -654,7 +654,7 @@ static int osi_config(struct pcmcia_device *link)
}
if (i != 0) {
/* Fallback: turn off hard decode */
- link->conf.ConfigIndex = 0x03;
+ link->config_index = 0x03;
link->resource[1]->end = 0;
i = pcmcia_request_io(link);
}
diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c
index 1776f49..1c8ebf2 100644
--- a/drivers/net/pcmcia/xirc2ps_cs.c
+++ b/drivers/net/pcmcia/xirc2ps_cs.c
@@ -530,7 +530,7 @@ xirc2ps_probe(struct pcmcia_device *link)
/* General socket configuration */
link->conf.Attributes = CONF_ENABLE_IRQ;
- link->conf.ConfigIndex = 1;
+ link->config_index = 1;
/* Fill in card specific entries */
dev->netdev_ops = &netdev_ops;
diff --git a/drivers/net/wireless/airo_cs.c b/drivers/net/wireless/airo_cs.c
index ccb2fdd..40f9ed7 100644
--- a/drivers/net/wireless/airo_cs.c
+++ b/drivers/net/wireless/airo_cs.c
@@ -240,7 +240,7 @@ static int airo_config(struct pcmcia_device *link)
/* Finally, report what we've done */
dev_info(&link->dev, "index 0x%02x: ",
- link->conf.ConfigIndex);
+ link->config_index);
if (link->vpp)
printk(", Vpp %d.%d", link->vpp/10, link->vpp%10);
printk(", irq %d", link->irq);
diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c
index 0fe6f82..5704d3f 100644
--- a/drivers/net/wireless/hostap/hostap_cs.c
+++ b/drivers/net/wireless/hostap/hostap_cs.c
@@ -601,7 +601,7 @@ static int prism2_config(struct pcmcia_device *link)
/* Finally, report what we've done */
printk(KERN_INFO "%s: index 0x%02x: ",
- dev_info, link->conf.ConfigIndex);
+ dev_info, link->config_index);
if (link->vpp)
printk(", Vpp %d.%d", link->vpp / 10,
link->vpp % 10);
diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c
index 30cfd88..7fb66cc 100644
--- a/drivers/net/wireless/ray_cs.c
+++ b/drivers/net/wireless/ray_cs.c
@@ -319,7 +319,7 @@ static int ray_probe(struct pcmcia_device *p_dev)
/* General socket configuration */
p_dev->conf.Attributes = CONF_ENABLE_IRQ;
- p_dev->conf.ConfigIndex = 1;
+ p_dev->config_index = 1;
p_dev->priv = dev;
diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c
index 92a9ad5..3947cf8 100644
--- a/drivers/net/wireless/wl3501_cs.c
+++ b/drivers/net/wireless/wl3501_cs.c
@@ -1889,7 +1889,7 @@ static int wl3501_probe(struct pcmcia_device *p_dev)
/* General socket configuration */
p_dev->conf.Attributes = CONF_ENABLE_IRQ;
- p_dev->conf.ConfigIndex = 1;
+ p_dev->config_index = 1;
dev = alloc_etherdev(sizeof(struct wl3501_card));
if (!dev)
diff --git a/drivers/parport/parport_cs.c b/drivers/parport/parport_cs.c
index afd946e..8faf634 100644
--- a/drivers/parport/parport_cs.c
+++ b/drivers/parport/parport_cs.c
@@ -144,7 +144,7 @@ static int parport_config_check(struct pcmcia_device *p_dev,
cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
p_dev->io_lines = io->flags & CISTPL_IO_LINES_MASK;
if (epp_mode)
- p_dev->conf.ConfigIndex |= FORCE_EPP_MODE;
+ p_dev->config_index |= FORCE_EPP_MODE;
p_dev->resource[0]->start = io->win[0].base;
p_dev->resource[0]->end = io->win[0].len;
if (io->nwin == 2) {
diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h
index a0c5adb..42eef43 100644
--- a/drivers/pcmcia/cs_internal.h
+++ b/drivers/pcmcia/cs_internal.h
@@ -34,9 +34,6 @@ typedef struct config_t {
struct kref ref;
unsigned int state;
unsigned int Attributes;
- unsigned int ConfigBase;
- unsigned char Option;
- unsigned int CardValues;
struct resource io[MAX_IO_WIN]; /* io ports */
struct resource mem[MAX_WIN]; /* mem areas */
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c
index 55570d9..00db600 100644
--- a/drivers/pcmcia/ds.c
+++ b/drivers/pcmcia/ds.c
@@ -276,13 +276,13 @@ static int pcmcia_device_probe(struct device *dev)
ret = pccard_read_tuple(p_dev->socket, p_dev->func, CISTPL_CONFIG,
&cis_config);
if (!ret) {
- p_dev->conf.ConfigBase = cis_config.base;
- p_dev->conf.Present = cis_config.rmask[0];
+ p_dev->config_base = cis_config.base;
+ p_dev->config_regs = cis_config.rmask[0];
} else {
dev_printk(KERN_INFO, dev,
"pcmcia: could not parse base and rmask0 of CIS\n");
- p_dev->conf.ConfigBase = 0;
- p_dev->conf.Present = 0;
+ p_dev->config_base = 0;
+ p_dev->config_regs = 0;
}
ret = p_drv->probe(p_dev);
diff --git a/drivers/pcmcia/pcmcia_cis.c b/drivers/pcmcia/pcmcia_cis.c
index 0ac54da..ac47cc4 100644
--- a/drivers/pcmcia/pcmcia_cis.c
+++ b/drivers/pcmcia/pcmcia_cis.c
@@ -151,7 +151,7 @@ static int pcmcia_do_loop_config(tuple_t *tuple, cisparse_t *parse, void *priv)
struct pcmcia_cfg_mem *cfg_mem = priv;
/* default values */
- cfg_mem->p_dev->conf.ConfigIndex = cfg->index;
+ cfg_mem->p_dev->config_index = cfg->index;
if (cfg->flags & CISTPL_CFTABLE_DEFAULT)
cfg_mem->dflt = *cfg;
diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c
index 6210e1c..a1fb0dc 100644
--- a/drivers/pcmcia/pcmcia_resource.c
+++ b/drivers/pcmcia/pcmcia_resource.c
@@ -168,7 +168,7 @@ static int pcmcia_access_config(struct pcmcia_device *p_dev,
return -EACCES;
}
- addr = (c->ConfigBase + where) >> 1;
+ addr = (p_dev->config_base + where) >> 1;
ret = accessf(s, 1, addr, 1, val);
@@ -443,6 +443,7 @@ int pcmcia_request_configuration(struct pcmcia_device *p_dev,
pccard_io_map iomap;
unsigned char status = 0;
unsigned char ext_status = 0;
+ unsigned char option = 0;
if (!(s->state & SOCKET_PRESENT))
return -ENODEV;
@@ -473,7 +474,7 @@ int pcmcia_request_configuration(struct pcmcia_device *p_dev,
if (req->Attributes & CONF_ENABLE_SPKR) {
s->socket.flags |= SS_SPKR_ENA;
status = CCSR_AUDIO_ENA;
- if (!(req->Present & PRESENT_STATUS))
+ if (!(p_dev->config_regs & PRESENT_STATUS))
dev_warn(&p_dev->dev, "speaker requested, but "
"PRESENT_STATUS not set!\n");
}
@@ -482,54 +483,53 @@ int pcmcia_request_configuration(struct pcmcia_device *p_dev,
else
s->socket.io_irq = 0;
if (req->Attributes & CONF_ENABLE_ESR) {
- req->Present |= PRESENT_EXT_STATUS;
+ p_dev->config_regs |= PRESENT_EXT_STATUS;
ext_status = ESR_REQ_ATTN_ENA;
}
s->ops->set_socket(s, &s->socket);
s->lock_count++;
/* Set up CIS configuration registers */
- base = c->ConfigBase = req->ConfigBase;
- c->CardValues = req->Present;
- if (req->Present & PRESENT_COPY) {
+ base = p_dev->config_base;
+ if (p_dev->config_regs & PRESENT_COPY) {
u16 tmp = 0;
dev_dbg(&p_dev->dev, "clearing CISREG_SCR\n");
pcmcia_write_cis_mem(s, 1, (base + CISREG_SCR)>>1, 1, &tmp);
}
- if (req->Present & PRESENT_PIN_REPLACE) {
+ if (p_dev->config_regs & PRESENT_PIN_REPLACE) {
u16 tmp = 0;
dev_dbg(&p_dev->dev, "clearing CISREG_PRR\n");
pcmcia_write_cis_mem(s, 1, (base + CISREG_PRR)>>1, 1, &tmp);
}
- if (req->Present & PRESENT_OPTION) {
+ if (p_dev->config_regs & PRESENT_OPTION) {
if (s->functions == 1) {
- c->Option = req->ConfigIndex & COR_CONFIG_MASK;
+ option = p_dev->config_index & COR_CONFIG_MASK;
} else {
- c->Option = req->ConfigIndex & COR_MFC_CONFIG_MASK;
- c->Option |= COR_FUNC_ENA|COR_IREQ_ENA;
- if (req->Present & PRESENT_IOBASE_0)
- c->Option |= COR_ADDR_DECODE;
+ option = p_dev->config_index & COR_MFC_CONFIG_MASK;
+ option |= COR_FUNC_ENA|COR_IREQ_ENA;
+ if (p_dev->config_regs & PRESENT_IOBASE_0)
+ option |= COR_ADDR_DECODE;
}
if ((req->Attributes & CONF_ENABLE_IRQ) &&
!(req->Attributes & CONF_ENABLE_PULSE_IRQ))
- c->Option |= COR_LEVEL_REQ;
- pcmcia_write_cis_mem(s, 1, (base + CISREG_COR)>>1, 1, &c->Option);
+ option |= COR_LEVEL_REQ;
+ pcmcia_write_cis_mem(s, 1, (base + CISREG_COR)>>1, 1, &option);
mdelay(40);
}
- if (req->Present & PRESENT_STATUS)
+ if (p_dev->config_regs & PRESENT_STATUS)
pcmcia_write_cis_mem(s, 1, (base + CISREG_CCSR)>>1, 1, &status);
- if (req->Present & PRESENT_EXT_STATUS)
+ if (p_dev->config_regs & PRESENT_EXT_STATUS)
pcmcia_write_cis_mem(s, 1, (base + CISREG_ESR)>>1, 1,
&ext_status);
- if (req->Present & PRESENT_IOBASE_0) {
+ if (p_dev->config_regs & PRESENT_IOBASE_0) {
u8 b = c->io[0].start & 0xff;
pcmcia_write_cis_mem(s, 1, (base + CISREG_IOBASE_0)>>1, 1, &b);
b = (c->io[0].start >> 8) & 0xff;
pcmcia_write_cis_mem(s, 1, (base + CISREG_IOBASE_1)>>1, 1, &b);
}
- if (req->Present & PRESENT_IOSIZE) {
+ if (p_dev->config_regs & PRESENT_IOSIZE) {
u8 b = resource_size(&c->io[0]) + resource_size(&c->io[1]) - 1;
pcmcia_write_cis_mem(s, 1, (base + CISREG_IOSIZE)>>1, 1, &b);
}
diff --git a/drivers/scsi/pcmcia/aha152x_stub.c b/drivers/scsi/pcmcia/aha152x_stub.c
index 3c0046e..c368249 100644
--- a/drivers/scsi/pcmcia/aha152x_stub.c
+++ b/drivers/scsi/pcmcia/aha152x_stub.c
@@ -103,7 +103,7 @@ static int aha152x_probe(struct pcmcia_device *link)
link->resource[0]->end = 0x20;
link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
link->conf.Attributes = CONF_ENABLE_IRQ;
- link->conf.Present = PRESENT_OPTION;
+ link->config_regs = PRESENT_OPTION;
return aha152x_config_cs(link);
} /* aha152x_attach */
diff --git a/drivers/scsi/pcmcia/fdomain_stub.c b/drivers/scsi/pcmcia/fdomain_stub.c
index 8ff7603..bb909e1 100644
--- a/drivers/scsi/pcmcia/fdomain_stub.c
+++ b/drivers/scsi/pcmcia/fdomain_stub.c
@@ -86,7 +86,7 @@ static int fdomain_probe(struct pcmcia_device *link)
link->resource[0]->end = 0x10;
link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
link->conf.Attributes = CONF_ENABLE_IRQ;
- link->conf.Present = PRESENT_OPTION;
+ link->config_regs = PRESENT_OPTION;
return fdomain_config(link);
} /* fdomain_attach */
diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c
index c0cf2df..a5648e9 100644
--- a/drivers/scsi/pcmcia/nsp_cs.c
+++ b/drivers/scsi/pcmcia/nsp_cs.c
@@ -1745,7 +1745,7 @@ static int nsp_cs_config(struct pcmcia_device *link)
/* Finally, report what we've done */
printk(KERN_INFO "nsp_cs: index 0x%02x: ",
- link->conf.ConfigIndex);
+ link->config_index);
if (link->vpp) {
printk(", Vpp %d.%d", link->vpp/10, link->vpp%10);
}
diff --git a/drivers/scsi/pcmcia/qlogic_stub.c b/drivers/scsi/pcmcia/qlogic_stub.c
index 77f46a2..5e2cbe0 100644
--- a/drivers/scsi/pcmcia/qlogic_stub.c
+++ b/drivers/scsi/pcmcia/qlogic_stub.c
@@ -159,7 +159,7 @@ static int qlogic_probe(struct pcmcia_device *link)
link->resource[0]->end = 16;
link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
link->conf.Attributes = CONF_ENABLE_IRQ;
- link->conf.Present = PRESENT_OPTION;
+ link->config_regs = PRESENT_OPTION;
return qlogic_config(link);
} /* qlogic_attach */
diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c
index 38baede..ee19f2d 100644
--- a/drivers/serial/serial_cs.c
+++ b/drivers/serial/serial_cs.c
@@ -495,7 +495,7 @@ static int simple_config(struct pcmcia_device *link)
found_port:
if (info->multi && (info->manfid == MANFID_3COM))
- link->conf.ConfigIndex &= ~(0x08);
+ link->config_index &= ~(0x08);
/*
* Apply any configuration quirks.
@@ -591,8 +591,8 @@ static int multi_config(struct pcmcia_device *link)
info->prodid == PRODID_POSSIO_GCC)) {
int err;
- if (link->conf.ConfigIndex == 1 ||
- link->conf.ConfigIndex == 3) {
+ if (link->config_index == 1 ||
+ link->config_index == 3) {
err = setup_serial(link, info, base2,
link->irq);
base2 = link->resource[0]->start;;
diff --git a/drivers/staging/comedi/drivers/cb_das16_cs.c b/drivers/staging/comedi/drivers/cb_das16_cs.c
index 11271b6..034cbfc 100644
--- a/drivers/staging/comedi/drivers/cb_das16_cs.c
+++ b/drivers/staging/comedi/drivers/cb_das16_cs.c
@@ -772,7 +772,7 @@ static void das16cs_pcmcia_config(struct pcmcia_device *link)
goto failed;
/* Finally, report what we've done */
- dev_info(&link->dev, "index 0x%02x", link->conf.ConfigIndex);
+ dev_info(&link->dev, "index 0x%02x", link->config_index);
if (link->conf.Attributes & CONF_ENABLE_IRQ)
printk(", irq %u", link->irq);
if (link->resource[0])
diff --git a/drivers/staging/comedi/drivers/das08_cs.c b/drivers/staging/comedi/drivers/das08_cs.c
index 319aad4..e37ea79 100644
--- a/drivers/staging/comedi/drivers/das08_cs.c
+++ b/drivers/staging/comedi/drivers/das08_cs.c
@@ -268,7 +268,7 @@ static void das08_pcmcia_config(struct pcmcia_device *link)
goto failed;
/* Finally, report what we've done */
- dev_info(&link->dev, "index 0x%02x", link->conf.ConfigIndex);
+ dev_info(&link->dev, "index 0x%02x", link->config_index);
if (link->conf.Attributes & CONF_ENABLE_IRQ)
printk(", irq %u", link->irq);
if (link->resource[0])
diff --git a/drivers/staging/comedi/drivers/ni_daq_700.c b/drivers/staging/comedi/drivers/ni_daq_700.c
index d269bbd..8107e40 100644
--- a/drivers/staging/comedi/drivers/ni_daq_700.c
+++ b/drivers/staging/comedi/drivers/ni_daq_700.c
@@ -607,7 +607,7 @@ static void dio700_config(struct pcmcia_device *link)
goto failed;
/* Finally, report what we've done */
- dev_info(&link->dev, "index 0x%02x", link->conf.ConfigIndex);
+ dev_info(&link->dev, "index 0x%02x", link->config_index);
if (link->conf.Attributes & CONF_ENABLE_IRQ)
printk(", irq %d", link->irq);
if (link->resource[0])
diff --git a/drivers/staging/comedi/drivers/ni_daq_dio24.c b/drivers/staging/comedi/drivers/ni_daq_dio24.c
index fcaa829..4f9daa3 100644
--- a/drivers/staging/comedi/drivers/ni_daq_dio24.c
+++ b/drivers/staging/comedi/drivers/ni_daq_dio24.c
@@ -358,7 +358,7 @@ static void dio24_config(struct pcmcia_device *link)
goto failed;
/* Finally, report what we've done */
- dev_info(&link->dev, "index 0x%02x", link->conf.ConfigIndex);
+ dev_info(&link->dev, "index 0x%02x", link->config_index);
if (link->conf.Attributes & CONF_ENABLE_IRQ)
printk(", irq %d", link->irq);
if (link->resource[0])
diff --git a/drivers/staging/comedi/drivers/ni_labpc_cs.c b/drivers/staging/comedi/drivers/ni_labpc_cs.c
index a936c11..2e27a30 100644
--- a/drivers/staging/comedi/drivers/ni_labpc_cs.c
+++ b/drivers/staging/comedi/drivers/ni_labpc_cs.c
@@ -336,7 +336,7 @@ static void labpc_config(struct pcmcia_device *link)
goto failed;
/* Finally, report what we've done */
- dev_info(&link->dev, "index 0x%02x", link->conf.ConfigIndex);
+ dev_info(&link->dev, "index 0x%02x", link->config_index);
if (link->conf.Attributes & CONF_ENABLE_IRQ)
printk(", irq %d", link->irq);
if (link->resource[0])
diff --git a/drivers/staging/comedi/drivers/quatech_daqp_cs.c b/drivers/staging/comedi/drivers/quatech_daqp_cs.c
index cd818fb..a2a32de 100644
--- a/drivers/staging/comedi/drivers/quatech_daqp_cs.c
+++ b/drivers/staging/comedi/drivers/quatech_daqp_cs.c
@@ -1137,7 +1137,7 @@ static void daqp_cs_config(struct pcmcia_device *link)
goto failed;
/* Finally, report what we've done */
- dev_info(&link->dev, "index 0x%02x", link->conf.ConfigIndex);
+ dev_info(&link->dev, "index 0x%02x", link->config_index);
if (link->conf.Attributes & CONF_ENABLE_IRQ)
printk(", irq %u", link->irq);
if (link->resource[0])
diff --git a/drivers/staging/wlags49_h2/wl_cs.c b/drivers/staging/wlags49_h2/wl_cs.c
index b2efff6..778800f 100644
--- a/drivers/staging/wlags49_h2/wl_cs.c
+++ b/drivers/staging/wlags49_h2/wl_cs.c
@@ -148,8 +148,8 @@ static int wl_adapter_attach(struct pcmcia_device *link)
link->resource[0]->end = HCF_NUM_IO_PORTS;
link->resource[0]->flags= IO_DATA_PATH_WIDTH_16;
link->conf.Attributes = CONF_ENABLE_IRQ;
- link->conf.ConfigIndex = 5;
- link->conf.Present = PRESENT_OPTION;
+ link->config_index = 5;
+ link->config_regs = PRESENT_OPTION;
link->priv = dev;
lp = wl_priv(dev);
diff --git a/drivers/usb/host/sl811_cs.c b/drivers/usb/host/sl811_cs.c
index 78bad51..5904053 100644
--- a/drivers/usb/host/sl811_cs.c
+++ b/drivers/usb/host/sl811_cs.c
@@ -200,7 +200,7 @@ static int sl811_cs_config(struct pcmcia_device *link)
goto failed;
dev_info(&link->dev, "index 0x%02x: ",
- link->conf.ConfigIndex);
+ link->config_index);
if (link->vpp)
printk(", Vpp %d.%d", link->vpp/10, link->vpp%10);
printk(", irq %d", link->irq);
diff --git a/include/pcmcia/cs.h b/include/pcmcia/cs.h
index 674edbc..47b6092 100644
--- a/include/pcmcia/cs.h
+++ b/include/pcmcia/cs.h
@@ -22,9 +22,6 @@
/* For RequestConfiguration */
typedef struct config_req_t {
u_int Attributes;
- u_int ConfigBase;
- u_char ConfigIndex;
- u_int Present;
} config_req_t;
/* Attributes for RequestConfiguration */
@@ -35,16 +32,4 @@ typedef struct config_req_t {
#define CONF_ENABLE_ESR 0x10
#define CONF_VALID_CLIENT 0x100
-/* Configuration registers present */
-#define PRESENT_OPTION 0x001
-#define PRESENT_STATUS 0x002
-#define PRESENT_PIN_REPLACE 0x004
-#define PRESENT_COPY 0x008
-#define PRESENT_EXT_STATUS 0x010
-#define PRESENT_IOBASE_0 0x020
-#define PRESENT_IOBASE_1 0x040
-#define PRESENT_IOBASE_2 0x080
-#define PRESENT_IOBASE_3 0x100
-#define PRESENT_IOSIZE 0x200
-
#endif /* _LINUX_CS_H */
diff --git a/include/pcmcia/ds.h b/include/pcmcia/ds.h
index 6137fbc..bc28f96 100644
--- a/include/pcmcia/ds.h
+++ b/include/pcmcia/ds.h
@@ -97,6 +97,9 @@ struct pcmcia_device {
unsigned int vpp;
unsigned int io_lines; /* number of I/O lines */
+ unsigned int config_base;
+ unsigned int config_index;
+ unsigned int config_regs; /* PRESENT_ flags below */
/* Is the device suspended? */
u16 suspended:1;
@@ -250,6 +253,17 @@ static inline int pcmcia_io_cfg_data_width(unsigned int flags)
0x0c -> 2
0x10 -> 3 */
+/* config_reg{ister}s present for this PCMCIA device */
+#define PRESENT_OPTION 0x001
+#define PRESENT_STATUS 0x002
+#define PRESENT_PIN_REPLACE 0x004
+#define PRESENT_COPY 0x008
+#define PRESENT_EXT_STATUS 0x010
+#define PRESENT_IOBASE_0 0x020
+#define PRESENT_IOBASE_1 0x040
+#define PRESENT_IOBASE_2 0x080
+#define PRESENT_IOBASE_3 0x100
+#define PRESENT_IOSIZE 0x200
#endif /* __KERNEL__ */
diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf.c b/sound/pcmcia/pdaudiocf/pdaudiocf.c
index 2e1282d..4df07fc 100644
--- a/sound/pcmcia/pdaudiocf/pdaudiocf.c
+++ b/sound/pcmcia/pdaudiocf/pdaudiocf.c
@@ -143,8 +143,8 @@ static int snd_pdacf_probe(struct pcmcia_device *link)
link->resource[0]->end = 16;
link->conf.Attributes = CONF_ENABLE_IRQ | CONF_ENABLE_PULSE_IRQ;
- link->conf.ConfigIndex = 1;
- link->conf.Present = PRESENT_OPTION;
+ link->config_index = 1;
+ link->config_regs = PRESENT_OPTION;
return pdacf_config(link);
}
@@ -216,7 +216,7 @@ static int pdacf_config(struct pcmcia_device *link)
int ret;
snd_printdd(KERN_DEBUG "pdacf_config called\n");
- link->conf.ConfigIndex = 0x5;
+ link->config_index = 0x5;
ret = pcmcia_request_io(link);
if (ret)
diff --git a/sound/pcmcia/vx/vxpocket.c b/sound/pcmcia/vx/vxpocket.c
index a48b3ee..16186ad 100644
--- a/sound/pcmcia/vx/vxpocket.c
+++ b/sound/pcmcia/vx/vxpocket.c
@@ -163,8 +163,8 @@ static int snd_vxpocket_new(struct snd_card *card, int ibl,
link->resource[0]->end = 16;
link->conf.Attributes = CONF_ENABLE_IRQ;
- link->conf.ConfigIndex = 1;
- link->conf.Present = PRESENT_OPTION;
+ link->config_index = 1;
+ link->config_regs = PRESENT_OPTION;
*chip_ret = vxp;
return 0;
--
1.7.0.4
1
0
IntType was only set to INT_MEMORY (driver pcmciamtd) or INT_MEMORY_AND_IO
(all other drivers). As this flags seems to relate to ioport access, make
it conditional to the driver having requested IO port access. There are two
drivers which do not request IO ports, but did set INT_MEMORY_AND_IO:
ray_cs and b43. For those, we consistently only set INT_MEMORY in future.
CC: netdev(a)vger.kernel.org
CC: linux-wireless(a)vger.kernel.org
CC: linux-ide(a)vger.kernel.org
CC: linux-usb(a)vger.kernel.org
CC: laforge(a)gnumonks.org
CC: linux-mtd(a)lists.infradead.org
CC: alsa-devel(a)alsa-project.org
CC: linux-serial(a)vger.kernel.org
CC: Jiri Kosina <jkosina(a)suse.cz>
CC: linux-scsi(a)vger.kernel.org
Acked-by: Gustavo F. Padovan <padovan(a)profusion.mobi> (for drivers/bluetooth)
Tested-by: Wolfram Sang <w.sang(a)pengutronix.de>
Signed-off-by: Dominik Brodowski <linux(a)dominikbrodowski.net>
---
drivers/ata/pata_pcmcia.c | 1 -
drivers/bluetooth/bluecard_cs.c | 1 -
drivers/bluetooth/bt3c_cs.c | 1 -
drivers/bluetooth/btuart_cs.c | 1 -
drivers/bluetooth/dtl1_cs.c | 1 -
drivers/char/pcmcia/cm4000_cs.c | 3 ---
drivers/char/pcmcia/cm4040_cs.c | 3 ---
drivers/char/pcmcia/ipwireless/main.c | 1 -
drivers/char/pcmcia/synclink_cs.c | 2 --
drivers/ide/ide-cs.c | 1 -
drivers/isdn/hardware/avm/avm_cs.c | 1 -
drivers/isdn/hisax/avma1_cs.c | 1 -
drivers/isdn/hisax/elsa_cs.c | 1 -
drivers/isdn/hisax/sedlbauer_cs.c | 1 -
drivers/isdn/hisax/teles_cs.c | 1 -
drivers/mtd/maps/pcmciamtd.c | 2 --
drivers/net/pcmcia/3c574_cs.c | 1 -
drivers/net/pcmcia/3c589_cs.c | 1 -
drivers/net/pcmcia/axnet_cs.c | 1 -
drivers/net/pcmcia/com20020_cs.c | 1 -
drivers/net/pcmcia/fmvj18x_cs.c | 1 -
drivers/net/pcmcia/ibmtr_cs.c | 1 -
drivers/net/pcmcia/nmclan_cs.c | 1 -
drivers/net/pcmcia/pcnet_cs.c | 1 -
drivers/net/pcmcia/smc91c92_cs.c | 1 -
drivers/net/pcmcia/xirc2ps_cs.c | 1 -
drivers/net/wireless/airo_cs.c | 1 -
drivers/net/wireless/atmel_cs.c | 1 -
drivers/net/wireless/b43/pcmcia.c | 1 -
drivers/net/wireless/hostap/hostap_cs.c | 1 -
drivers/net/wireless/libertas/if_cs.c | 1 -
drivers/net/wireless/orinoco/orinoco_cs.c | 1 -
drivers/net/wireless/orinoco/spectrum_cs.c | 1 -
drivers/net/wireless/ray_cs.c | 1 -
drivers/net/wireless/wl3501_cs.c | 1 -
drivers/parport/parport_cs.c | 1 -
drivers/pcmcia/cs_internal.h | 1 -
drivers/pcmcia/pcmcia_resource.c | 10 +---------
drivers/scsi/pcmcia/aha152x_stub.c | 1 -
drivers/scsi/pcmcia/fdomain_stub.c | 1 -
drivers/scsi/pcmcia/nsp_cs.c | 1 -
drivers/scsi/pcmcia/qlogic_stub.c | 1 -
drivers/scsi/pcmcia/sym53c500_cs.c | 1 -
drivers/serial/serial_cs.c | 2 --
drivers/staging/comedi/drivers/cb_das16_cs.c | 1 -
drivers/staging/comedi/drivers/das08_cs.c | 1 -
drivers/staging/comedi/drivers/ni_daq_700.c | 1 -
drivers/staging/comedi/drivers/ni_daq_dio24.c | 1 -
drivers/staging/comedi/drivers/ni_labpc_cs.c | 1 -
drivers/staging/comedi/drivers/ni_mio_cs.c | 1 -
drivers/staging/comedi/drivers/quatech_daqp_cs.c | 1 -
drivers/staging/wlags49_h2/wl_cs.c | 1 -
drivers/telephony/ixj_pcmcia.c | 1 -
drivers/usb/host/sl811_cs.c | 1 -
include/pcmcia/cs.h | 7 -------
sound/pcmcia/pdaudiocf/pdaudiocf.c | 1 -
sound/pcmcia/vx/vxpocket.c | 1 -
57 files changed, 1 insertions(+), 78 deletions(-)
diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c
index 12cdc9f..c2679c0 100644
--- a/drivers/ata/pata_pcmcia.c
+++ b/drivers/ata/pata_pcmcia.c
@@ -250,7 +250,6 @@ static int pcmcia_init_one(struct pcmcia_device *pdev)
pdev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
pdev->resource[1]->flags |= IO_DATA_PATH_WIDTH_8;
pdev->conf.Attributes = CONF_ENABLE_IRQ;
- pdev->conf.IntType = INT_MEMORY_AND_IO;
/* See if we have a manufacturer identifier. Use it to set is_kme for
vendor quirks */
diff --git a/drivers/bluetooth/bluecard_cs.c b/drivers/bluetooth/bluecard_cs.c
index d52e90a..4cb2dfe 100644
--- a/drivers/bluetooth/bluecard_cs.c
+++ b/drivers/bluetooth/bluecard_cs.c
@@ -866,7 +866,6 @@ static int bluecard_probe(struct pcmcia_device *link)
link->priv = info;
link->conf.Attributes = CONF_ENABLE_IRQ;
- link->conf.IntType = INT_MEMORY_AND_IO;
return bluecard_config(link);
}
diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c
index 2c8d981..fb01807 100644
--- a/drivers/bluetooth/bt3c_cs.c
+++ b/drivers/bluetooth/bt3c_cs.c
@@ -661,7 +661,6 @@ static int bt3c_probe(struct pcmcia_device *link)
link->resource[0]->end = 8;
link->conf.Attributes = CONF_ENABLE_IRQ;
- link->conf.IntType = INT_MEMORY_AND_IO;
return bt3c_config(link);
}
diff --git a/drivers/bluetooth/btuart_cs.c b/drivers/bluetooth/btuart_cs.c
index 7ea6fa4..897c7c7 100644
--- a/drivers/bluetooth/btuart_cs.c
+++ b/drivers/bluetooth/btuart_cs.c
@@ -590,7 +590,6 @@ static int btuart_probe(struct pcmcia_device *link)
link->resource[0]->end = 8;
link->conf.Attributes = CONF_ENABLE_IRQ;
- link->conf.IntType = INT_MEMORY_AND_IO;
return btuart_config(link);
}
diff --git a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c
index db7c8db..b4c9a2e 100644
--- a/drivers/bluetooth/dtl1_cs.c
+++ b/drivers/bluetooth/dtl1_cs.c
@@ -576,7 +576,6 @@ static int dtl1_probe(struct pcmcia_device *link)
link->resource[0]->end = 8;
link->conf.Attributes = CONF_ENABLE_IRQ;
- link->conf.IntType = INT_MEMORY_AND_IO;
return dtl1_config(link);
}
diff --git a/drivers/char/pcmcia/cm4000_cs.c b/drivers/char/pcmcia/cm4000_cs.c
index ec73d9f..d2accd6 100644
--- a/drivers/char/pcmcia/cm4000_cs.c
+++ b/drivers/char/pcmcia/cm4000_cs.c
@@ -1767,8 +1767,6 @@ static int cm4000_config(struct pcmcia_device * link, int devno)
if (pcmcia_loop_config(link, cm4000_config_check, NULL))
goto cs_release;
- link->conf.IntType = 00000002;
-
if (pcmcia_request_configuration(link, &link->conf))
goto cs_release;
@@ -1829,7 +1827,6 @@ static int cm4000_probe(struct pcmcia_device *link)
dev->p_dev = link;
link->priv = dev;
- link->conf.IntType = INT_MEMORY_AND_IO;
dev_table[i] = link;
init_waitqueue_head(&dev->devq);
diff --git a/drivers/char/pcmcia/cm4040_cs.c b/drivers/char/pcmcia/cm4040_cs.c
index 815cde1..a32eba0 100644
--- a/drivers/char/pcmcia/cm4040_cs.c
+++ b/drivers/char/pcmcia/cm4040_cs.c
@@ -547,8 +547,6 @@ static int reader_config(struct pcmcia_device *link, int devno)
if (pcmcia_loop_config(link, cm4040_config_check, NULL))
goto cs_release;
- link->conf.IntType = 00000002;
-
fail_rc = pcmcia_request_configuration(link, &link->conf);
if (fail_rc != 0) {
dev_printk(KERN_INFO, &link->dev,
@@ -599,7 +597,6 @@ static int reader_probe(struct pcmcia_device *link)
link->priv = dev;
dev->p_dev = link;
- link->conf.IntType = INT_MEMORY_AND_IO;
dev_table[i] = link;
init_waitqueue_head(&dev->devq);
diff --git a/drivers/char/pcmcia/ipwireless/main.c b/drivers/char/pcmcia/ipwireless/main.c
index 8d2b86a..0f0be4d 100644
--- a/drivers/char/pcmcia/ipwireless/main.c
+++ b/drivers/char/pcmcia/ipwireless/main.c
@@ -173,7 +173,6 @@ static int config_ipwireless(struct ipw_dev *ipw)
return ret;
link->conf.Attributes = CONF_ENABLE_IRQ;
- link->conf.IntType = INT_MEMORY_AND_IO;
INIT_WORK(&ipw->work_reboot, signalled_reboot_work);
diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
index 9ecd6be..ba7ccf5 100644
--- a/drivers/char/pcmcia/synclink_cs.c
+++ b/drivers/char/pcmcia/synclink_cs.c
@@ -551,7 +551,6 @@ static int mgslpc_probe(struct pcmcia_device *link)
/* Initialize the struct pcmcia_device structure */
link->conf.Attributes = 0;
- link->conf.IntType = INT_MEMORY_AND_IO;
ret = mgslpc_config(link);
if (ret)
@@ -595,7 +594,6 @@ static int mgslpc_config(struct pcmcia_device *link)
goto failed;
link->conf.Attributes = CONF_ENABLE_IRQ;
- link->conf.IntType = INT_MEMORY_AND_IO;
link->conf.ConfigIndex = 8;
link->conf.Present = PRESENT_OPTION;
diff --git a/drivers/ide/ide-cs.c b/drivers/ide/ide-cs.c
index 82690e4..cf7cb49 100644
--- a/drivers/ide/ide-cs.c
+++ b/drivers/ide/ide-cs.c
@@ -100,7 +100,6 @@ static int ide_probe(struct pcmcia_device *link)
link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
link->resource[1]->flags |= IO_DATA_PATH_WIDTH_8;
link->conf.Attributes = CONF_ENABLE_IRQ;
- link->conf.IntType = INT_MEMORY_AND_IO;
return ide_config(link);
} /* ide_attach */
diff --git a/drivers/isdn/hardware/avm/avm_cs.c b/drivers/isdn/hardware/avm/avm_cs.c
index 09b1795..938ca41 100644
--- a/drivers/isdn/hardware/avm/avm_cs.c
+++ b/drivers/isdn/hardware/avm/avm_cs.c
@@ -80,7 +80,6 @@ static int avmcs_probe(struct pcmcia_device *p_dev)
/* General socket configuration */
p_dev->conf.Attributes = CONF_ENABLE_IRQ;
- p_dev->conf.IntType = INT_MEMORY_AND_IO;
p_dev->conf.ConfigIndex = 1;
p_dev->conf.Present = PRESENT_OPTION;
diff --git a/drivers/isdn/hisax/avma1_cs.c b/drivers/isdn/hisax/avma1_cs.c
index 94263c2..7d5ff20 100644
--- a/drivers/isdn/hisax/avma1_cs.c
+++ b/drivers/isdn/hisax/avma1_cs.c
@@ -85,7 +85,6 @@ static int __devinit avma1cs_probe(struct pcmcia_device *p_dev)
/* General socket configuration */
p_dev->conf.Attributes = CONF_ENABLE_IRQ;
- p_dev->conf.IntType = INT_MEMORY_AND_IO;
p_dev->conf.ConfigIndex = 1;
p_dev->conf.Present = PRESENT_OPTION;
diff --git a/drivers/isdn/hisax/elsa_cs.c b/drivers/isdn/hisax/elsa_cs.c
index b3c08aa..df360c8 100644
--- a/drivers/isdn/hisax/elsa_cs.c
+++ b/drivers/isdn/hisax/elsa_cs.c
@@ -130,7 +130,6 @@ static int __devinit elsa_cs_probe(struct pcmcia_device *link)
link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
link->conf.Attributes = CONF_ENABLE_IRQ;
- link->conf.IntType = INT_MEMORY_AND_IO;
return elsa_cs_config(link);
} /* elsa_cs_attach */
diff --git a/drivers/isdn/hisax/sedlbauer_cs.c b/drivers/isdn/hisax/sedlbauer_cs.c
index 40001ad..169061f 100644
--- a/drivers/isdn/hisax/sedlbauer_cs.c
+++ b/drivers/isdn/hisax/sedlbauer_cs.c
@@ -133,7 +133,6 @@ static int __devinit sedlbauer_probe(struct pcmcia_device *link)
link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
link->conf.Attributes = 0;
- link->conf.IntType = INT_MEMORY_AND_IO;
return sedlbauer_config(link);
} /* sedlbauer_attach */
diff --git a/drivers/isdn/hisax/teles_cs.c b/drivers/isdn/hisax/teles_cs.c
index 7296102..46e72a1 100644
--- a/drivers/isdn/hisax/teles_cs.c
+++ b/drivers/isdn/hisax/teles_cs.c
@@ -110,7 +110,6 @@ static int __devinit teles_probe(struct pcmcia_device *link)
link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
link->conf.Attributes = CONF_ENABLE_IRQ;
- link->conf.IntType = INT_MEMORY_AND_IO;
return teles_cs_config(link);
} /* teles_attach */
diff --git a/drivers/mtd/maps/pcmciamtd.c b/drivers/mtd/maps/pcmciamtd.c
index ab94c8a..663b48b 100644
--- a/drivers/mtd/maps/pcmciamtd.c
+++ b/drivers/mtd/maps/pcmciamtd.c
@@ -575,7 +575,6 @@ static int pcmciamtd_config(struct pcmcia_device *link)
link->vpp = 0;
}
- link->conf.IntType = INT_MEMORY;
link->conf.ConfigIndex = 0;
DEBUG(2, "Setting Configuration");
ret = pcmcia_request_configuration(link, &link->conf);
@@ -720,7 +719,6 @@ static int pcmciamtd_probe(struct pcmcia_device *link)
link->priv = dev;
link->conf.Attributes = 0;
- link->conf.IntType = INT_MEMORY;
return pcmciamtd_config(link);
}
diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c
index c683f77..41ecb27 100644
--- a/drivers/net/pcmcia/3c574_cs.c
+++ b/drivers/net/pcmcia/3c574_cs.c
@@ -281,7 +281,6 @@ static int tc574_probe(struct pcmcia_device *link)
link->resource[0]->end = 32;
link->resource[0]->flags |= IO_DATA_PATH_WIDTH_16;
link->conf.Attributes = CONF_ENABLE_IRQ;
- link->conf.IntType = INT_MEMORY_AND_IO;
link->conf.ConfigIndex = 1;
dev->netdev_ops = &el3_netdev_ops;
diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c
index 61f9cf2..6888672 100644
--- a/drivers/net/pcmcia/3c589_cs.c
+++ b/drivers/net/pcmcia/3c589_cs.c
@@ -217,7 +217,6 @@ static int tc589_probe(struct pcmcia_device *link)
link->resource[0]->flags |= IO_DATA_PATH_WIDTH_16;
link->conf.Attributes = CONF_ENABLE_IRQ;
- link->conf.IntType = INT_MEMORY_AND_IO;
link->conf.ConfigIndex = 1;
dev->netdev_ops = &el3_netdev_ops;
diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c
index 8734ed8..4d4928a 100644
--- a/drivers/net/pcmcia/axnet_cs.c
+++ b/drivers/net/pcmcia/axnet_cs.c
@@ -167,7 +167,6 @@ static int axnet_probe(struct pcmcia_device *link)
info->p_dev = link;
link->priv = dev;
link->conf.Attributes = CONF_ENABLE_IRQ;
- link->conf.IntType = INT_MEMORY_AND_IO;
dev->netdev_ops = &axnet_netdev_ops;
diff --git a/drivers/net/pcmcia/com20020_cs.c b/drivers/net/pcmcia/com20020_cs.c
index 3c400cf..a58eafe 100644
--- a/drivers/net/pcmcia/com20020_cs.c
+++ b/drivers/net/pcmcia/com20020_cs.c
@@ -161,7 +161,6 @@ static int com20020_probe(struct pcmcia_device *p_dev)
p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
p_dev->resource[0]->end = 16;
p_dev->conf.Attributes = CONF_ENABLE_IRQ;
- p_dev->conf.IntType = INT_MEMORY_AND_IO;
info->dev = dev;
p_dev->priv = info;
diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c
index dfd3284..caf2b2e 100644
--- a/drivers/net/pcmcia/fmvj18x_cs.c
+++ b/drivers/net/pcmcia/fmvj18x_cs.c
@@ -253,7 +253,6 @@ static int fmvj18x_probe(struct pcmcia_device *link)
/* General socket configuration */
link->conf.Attributes = CONF_ENABLE_IRQ;
- link->conf.IntType = INT_MEMORY_AND_IO;
dev->netdev_ops = &fjn_netdev_ops;
dev->watchdog_timeo = TX_TIMEOUT;
diff --git a/drivers/net/pcmcia/ibmtr_cs.c b/drivers/net/pcmcia/ibmtr_cs.c
index dbdea7f..1327f08 100644
--- a/drivers/net/pcmcia/ibmtr_cs.c
+++ b/drivers/net/pcmcia/ibmtr_cs.c
@@ -153,7 +153,6 @@ static int __devinit ibmtr_attach(struct pcmcia_device *link)
link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
link->resource[0]->end = 4;
link->conf.Attributes = CONF_ENABLE_IRQ;
- link->conf.IntType = INT_MEMORY_AND_IO;
link->conf.Present = PRESENT_OPTION;
info->dev = dev;
diff --git a/drivers/net/pcmcia/nmclan_cs.c b/drivers/net/pcmcia/nmclan_cs.c
index 68f2dee..90d1728 100644
--- a/drivers/net/pcmcia/nmclan_cs.c
+++ b/drivers/net/pcmcia/nmclan_cs.c
@@ -461,7 +461,6 @@ static int nmclan_probe(struct pcmcia_device *link)
link->resource[0]->end = 32;
link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
link->conf.Attributes = CONF_ENABLE_IRQ;
- link->conf.IntType = INT_MEMORY_AND_IO;
link->conf.ConfigIndex = 1;
link->conf.Present = PRESENT_OPTION;
diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c
index f3d7a14..6913576 100644
--- a/drivers/net/pcmcia/pcnet_cs.c
+++ b/drivers/net/pcmcia/pcnet_cs.c
@@ -261,7 +261,6 @@ static int pcnet_probe(struct pcmcia_device *link)
link->priv = dev;
link->conf.Attributes = CONF_ENABLE_IRQ;
- link->conf.IntType = INT_MEMORY_AND_IO;
dev->netdev_ops = &pcnet_netdev_ops;
diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c
index 2031a27..2c2a878 100644
--- a/drivers/net/pcmcia/smc91c92_cs.c
+++ b/drivers/net/pcmcia/smc91c92_cs.c
@@ -327,7 +327,6 @@ static int smc91c92_probe(struct pcmcia_device *link)
link->resource[0]->end = 16;
link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
link->conf.Attributes = CONF_ENABLE_IRQ;
- link->conf.IntType = INT_MEMORY_AND_IO;
/* The SMC91c92-specific entries in the device structure. */
dev->netdev_ops = &smc_netdev_ops;
diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c
index 59398a6..1776f49 100644
--- a/drivers/net/pcmcia/xirc2ps_cs.c
+++ b/drivers/net/pcmcia/xirc2ps_cs.c
@@ -530,7 +530,6 @@ xirc2ps_probe(struct pcmcia_device *link)
/* General socket configuration */
link->conf.Attributes = CONF_ENABLE_IRQ;
- link->conf.IntType = INT_MEMORY_AND_IO;
link->conf.ConfigIndex = 1;
/* Fill in card specific entries */
diff --git a/drivers/net/wireless/airo_cs.c b/drivers/net/wireless/airo_cs.c
index ab60f10..ccb2fdd 100644
--- a/drivers/net/wireless/airo_cs.c
+++ b/drivers/net/wireless/airo_cs.c
@@ -104,7 +104,6 @@ static int airo_probe(struct pcmcia_device *p_dev)
device, and can be hard-wired here.
*/
p_dev->conf.Attributes = 0;
- p_dev->conf.IntType = INT_MEMORY_AND_IO;
/* Allocate space for private device-specific data */
local = kzalloc(sizeof(local_info_t), GFP_KERNEL);
diff --git a/drivers/net/wireless/atmel_cs.c b/drivers/net/wireless/atmel_cs.c
index d6d585c..8b75158 100644
--- a/drivers/net/wireless/atmel_cs.c
+++ b/drivers/net/wireless/atmel_cs.c
@@ -114,7 +114,6 @@ static int atmel_probe(struct pcmcia_device *p_dev)
device, and can be hard-wired here.
*/
p_dev->conf.Attributes = 0;
- p_dev->conf.IntType = INT_MEMORY_AND_IO;
/* Allocate space for private device-specific data */
local = kzalloc(sizeof(local_info_t), GFP_KERNEL);
diff --git a/drivers/net/wireless/b43/pcmcia.c b/drivers/net/wireless/b43/pcmcia.c
index 618d9b5..138b26f 100644
--- a/drivers/net/wireless/b43/pcmcia.c
+++ b/drivers/net/wireless/b43/pcmcia.c
@@ -73,7 +73,6 @@ static int __devinit b43_pcmcia_probe(struct pcmcia_device *dev)
err = -ENODEV;
dev->conf.Attributes = CONF_ENABLE_IRQ;
- dev->conf.IntType = INT_MEMORY_AND_IO;
dev->resource[2]->flags |= WIN_ENABLE | WIN_DATA_WIDTH_16 |
WIN_USE_WAIT;
diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c
index 3fa285b..0fe6f82 100644
--- a/drivers/net/wireless/hostap/hostap_cs.c
+++ b/drivers/net/wireless/hostap/hostap_cs.c
@@ -437,7 +437,6 @@ static int hostap_cs_probe(struct pcmcia_device *p_dev)
int ret;
PDEBUG(DEBUG_HW, "%s: setting Vcc=33 (constant)\n", dev_info);
- p_dev->conf.IntType = INT_MEMORY_AND_IO;
ret = prism2_config(p_dev);
if (ret) {
diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c
index 9c29839..814b7fa 100644
--- a/drivers/net/wireless/libertas/if_cs.c
+++ b/drivers/net/wireless/libertas/if_cs.c
@@ -836,7 +836,6 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
p_dev->priv = card;
p_dev->conf.Attributes = 0;
- p_dev->conf.IntType = INT_MEMORY_AND_IO;
if (pcmcia_loop_config(p_dev, if_cs_ioprobe, NULL)) {
lbs_pr_err("error in pcmcia_loop_config\n");
diff --git a/drivers/net/wireless/orinoco/orinoco_cs.c b/drivers/net/wireless/orinoco/orinoco_cs.c
index f7e3fa6..1147d6b 100644
--- a/drivers/net/wireless/orinoco/orinoco_cs.c
+++ b/drivers/net/wireless/orinoco/orinoco_cs.c
@@ -123,7 +123,6 @@ orinoco_cs_probe(struct pcmcia_device *link)
* number, sizes, and attributes of IO windows) are fixed by
* the nature of the device, and can be hard-wired here. */
link->conf.Attributes = 0;
- link->conf.IntType = INT_MEMORY_AND_IO;
return orinoco_cs_config(link);
} /* orinoco_cs_attach */
diff --git a/drivers/net/wireless/orinoco/spectrum_cs.c b/drivers/net/wireless/orinoco/spectrum_cs.c
index 1bbad10..20b08ab 100644
--- a/drivers/net/wireless/orinoco/spectrum_cs.c
+++ b/drivers/net/wireless/orinoco/spectrum_cs.c
@@ -185,7 +185,6 @@ spectrum_cs_probe(struct pcmcia_device *link)
* number, sizes, and attributes of IO windows) are fixed by
* the nature of the device, and can be hard-wired here. */
link->conf.Attributes = 0;
- link->conf.IntType = INT_MEMORY_AND_IO;
return spectrum_cs_config(link);
} /* spectrum_cs_attach */
diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c
index ab34cb8..30cfd88 100644
--- a/drivers/net/wireless/ray_cs.c
+++ b/drivers/net/wireless/ray_cs.c
@@ -319,7 +319,6 @@ static int ray_probe(struct pcmcia_device *p_dev)
/* General socket configuration */
p_dev->conf.Attributes = CONF_ENABLE_IRQ;
- p_dev->conf.IntType = INT_MEMORY_AND_IO;
p_dev->conf.ConfigIndex = 1;
p_dev->priv = dev;
diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c
index a1cc2d4..92a9ad5 100644
--- a/drivers/net/wireless/wl3501_cs.c
+++ b/drivers/net/wireless/wl3501_cs.c
@@ -1889,7 +1889,6 @@ static int wl3501_probe(struct pcmcia_device *p_dev)
/* General socket configuration */
p_dev->conf.Attributes = CONF_ENABLE_IRQ;
- p_dev->conf.IntType = INT_MEMORY_AND_IO;
p_dev->conf.ConfigIndex = 1;
dev = alloc_etherdev(sizeof(struct wl3501_card));
diff --git a/drivers/parport/parport_cs.c b/drivers/parport/parport_cs.c
index 23e50f4..afd946e 100644
--- a/drivers/parport/parport_cs.c
+++ b/drivers/parport/parport_cs.c
@@ -104,7 +104,6 @@ static int parport_probe(struct pcmcia_device *link)
link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
link->resource[1]->flags |= IO_DATA_PATH_WIDTH_8;
link->conf.Attributes = CONF_ENABLE_IRQ;
- link->conf.IntType = INT_MEMORY_AND_IO;
return parport_config(link);
} /* parport_attach */
diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h
index 7ef464d..a0c5adb 100644
--- a/drivers/pcmcia/cs_internal.h
+++ b/drivers/pcmcia/cs_internal.h
@@ -34,7 +34,6 @@ typedef struct config_t {
struct kref ref;
unsigned int state;
unsigned int Attributes;
- unsigned int IntType;
unsigned int ConfigBase;
unsigned char Option;
unsigned int CardValues;
diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c
index 8834bb4..6210e1c 100644
--- a/drivers/pcmcia/pcmcia_resource.c
+++ b/drivers/pcmcia/pcmcia_resource.c
@@ -447,11 +447,6 @@ int pcmcia_request_configuration(struct pcmcia_device *p_dev,
if (!(s->state & SOCKET_PRESENT))
return -ENODEV;
- if (req->IntType & INT_CARDBUS) {
- dev_dbg(&p_dev->dev, "IntType may not be INT_CARDBUS\n");
- return -EINVAL;
- }
-
mutex_lock(&s->ops_mutex);
c = p_dev->function_config;
if (c->state & CONFIG_LOCKED) {
@@ -470,12 +465,9 @@ int pcmcia_request_configuration(struct pcmcia_device *p_dev,
}
/* Pick memory or I/O card, DMA mode, interrupt */
- c->IntType = req->IntType;
c->Attributes = req->Attributes;
- if (req->IntType & INT_MEMORY_AND_IO)
+ if (p_dev->_io)
s->socket.flags |= SS_IOCARD;
- if (req->IntType & INT_ZOOMED_VIDEO)
- s->socket.flags |= SS_ZVCARD | SS_IOCARD;
if (req->Attributes & CONF_ENABLE_DMA)
s->socket.flags |= SS_DMA_MODE;
if (req->Attributes & CONF_ENABLE_SPKR) {
diff --git a/drivers/scsi/pcmcia/aha152x_stub.c b/drivers/scsi/pcmcia/aha152x_stub.c
index 61f49bd..3c0046e 100644
--- a/drivers/scsi/pcmcia/aha152x_stub.c
+++ b/drivers/scsi/pcmcia/aha152x_stub.c
@@ -103,7 +103,6 @@ static int aha152x_probe(struct pcmcia_device *link)
link->resource[0]->end = 0x20;
link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
link->conf.Attributes = CONF_ENABLE_IRQ;
- link->conf.IntType = INT_MEMORY_AND_IO;
link->conf.Present = PRESENT_OPTION;
return aha152x_config_cs(link);
diff --git a/drivers/scsi/pcmcia/fdomain_stub.c b/drivers/scsi/pcmcia/fdomain_stub.c
index 13dbe5c..8ff7603 100644
--- a/drivers/scsi/pcmcia/fdomain_stub.c
+++ b/drivers/scsi/pcmcia/fdomain_stub.c
@@ -86,7 +86,6 @@ static int fdomain_probe(struct pcmcia_device *link)
link->resource[0]->end = 0x10;
link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
link->conf.Attributes = CONF_ENABLE_IRQ;
- link->conf.IntType = INT_MEMORY_AND_IO;
link->conf.Present = PRESENT_OPTION;
return fdomain_config(link);
diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c
index b90cade..c0cf2df 100644
--- a/drivers/scsi/pcmcia/nsp_cs.c
+++ b/drivers/scsi/pcmcia/nsp_cs.c
@@ -1563,7 +1563,6 @@ static int nsp_cs_probe(struct pcmcia_device *link)
/* General socket configuration */
link->conf.Attributes = CONF_ENABLE_IRQ;
- link->conf.IntType = INT_MEMORY_AND_IO;
ret = nsp_cs_config(link);
diff --git a/drivers/scsi/pcmcia/qlogic_stub.c b/drivers/scsi/pcmcia/qlogic_stub.c
index eb775f1..77f46a2 100644
--- a/drivers/scsi/pcmcia/qlogic_stub.c
+++ b/drivers/scsi/pcmcia/qlogic_stub.c
@@ -159,7 +159,6 @@ static int qlogic_probe(struct pcmcia_device *link)
link->resource[0]->end = 16;
link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
link->conf.Attributes = CONF_ENABLE_IRQ;
- link->conf.IntType = INT_MEMORY_AND_IO;
link->conf.Present = PRESENT_OPTION;
return qlogic_config(link);
diff --git a/drivers/scsi/pcmcia/sym53c500_cs.c b/drivers/scsi/pcmcia/sym53c500_cs.c
index 321e390..9aaf974 100644
--- a/drivers/scsi/pcmcia/sym53c500_cs.c
+++ b/drivers/scsi/pcmcia/sym53c500_cs.c
@@ -862,7 +862,6 @@ SYM53C500_probe(struct pcmcia_device *link)
link->resource[0]->end = 16;
link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
link->conf.Attributes = CONF_ENABLE_IRQ;
- link->conf.IntType = INT_MEMORY_AND_IO;
return SYM53C500_config(link);
} /* SYM53C500_attach */
diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c
index 0460c08..38baede 100644
--- a/drivers/serial/serial_cs.c
+++ b/drivers/serial/serial_cs.c
@@ -337,8 +337,6 @@ static int serial_probe(struct pcmcia_device *link)
if (do_sound)
link->conf.Attributes |= CONF_ENABLE_SPKR;
- link->conf.IntType = INT_MEMORY_AND_IO;
-
return serial_config(link);
}
diff --git a/drivers/staging/comedi/drivers/cb_das16_cs.c b/drivers/staging/comedi/drivers/cb_das16_cs.c
index f8ede11..11271b6 100644
--- a/drivers/staging/comedi/drivers/cb_das16_cs.c
+++ b/drivers/staging/comedi/drivers/cb_das16_cs.c
@@ -694,7 +694,6 @@ static int das16cs_pcmcia_attach(struct pcmcia_device *link)
/* Initialize the pcmcia_device structure */
link->conf.Attributes = 0;
- link->conf.IntType = INT_MEMORY_AND_IO;
cur_dev = link;
diff --git a/drivers/staging/comedi/drivers/das08_cs.c b/drivers/staging/comedi/drivers/das08_cs.c
index 48d9fb1..319aad4 100644
--- a/drivers/staging/comedi/drivers/das08_cs.c
+++ b/drivers/staging/comedi/drivers/das08_cs.c
@@ -170,7 +170,6 @@ static int das08_pcmcia_attach(struct pcmcia_device *link)
device, and can be hard-wired here.
*/
link->conf.Attributes = 0;
- link->conf.IntType = INT_MEMORY_AND_IO;
cur_dev = link;
diff --git a/drivers/staging/comedi/drivers/ni_daq_700.c b/drivers/staging/comedi/drivers/ni_daq_700.c
index 8cf56cb..d269bbd 100644
--- a/drivers/staging/comedi/drivers/ni_daq_700.c
+++ b/drivers/staging/comedi/drivers/ni_daq_700.c
@@ -499,7 +499,6 @@ static int dio700_cs_attach(struct pcmcia_device *link)
device, and can be hard-wired here.
*/
link->conf.Attributes = 0;
- link->conf.IntType = INT_MEMORY_AND_IO;
pcmcia_cur_dev = link;
diff --git a/drivers/staging/comedi/drivers/ni_daq_dio24.c b/drivers/staging/comedi/drivers/ni_daq_dio24.c
index ba69343..fcaa829 100644
--- a/drivers/staging/comedi/drivers/ni_daq_dio24.c
+++ b/drivers/staging/comedi/drivers/ni_daq_dio24.c
@@ -251,7 +251,6 @@ static int dio24_cs_attach(struct pcmcia_device *link)
device, and can be hard-wired here.
*/
link->conf.Attributes = 0;
- link->conf.IntType = INT_MEMORY_AND_IO;
pcmcia_cur_dev = link;
diff --git a/drivers/staging/comedi/drivers/ni_labpc_cs.c b/drivers/staging/comedi/drivers/ni_labpc_cs.c
index 5d5f11f..a936c11 100644
--- a/drivers/staging/comedi/drivers/ni_labpc_cs.c
+++ b/drivers/staging/comedi/drivers/ni_labpc_cs.c
@@ -227,7 +227,6 @@ static int labpc_cs_attach(struct pcmcia_device *link)
device, and can be hard-wired here.
*/
link->conf.Attributes = 0;
- link->conf.IntType = INT_MEMORY_AND_IO;
pcmcia_cur_dev = link;
diff --git a/drivers/staging/comedi/drivers/ni_mio_cs.c b/drivers/staging/comedi/drivers/ni_mio_cs.c
index 1f24263..be7e021 100644
--- a/drivers/staging/comedi/drivers/ni_mio_cs.c
+++ b/drivers/staging/comedi/drivers/ni_mio_cs.c
@@ -266,7 +266,6 @@ static int cs_attach(struct pcmcia_device *link)
link->resource[0]->flags |= IO_DATA_PATH_WIDTH_16;
link->resource[0]->end = 16;
link->conf.Attributes = CONF_ENABLE_IRQ;
- link->conf.IntType = INT_MEMORY_AND_IO;
cur_dev = link;
diff --git a/drivers/staging/comedi/drivers/quatech_daqp_cs.c b/drivers/staging/comedi/drivers/quatech_daqp_cs.c
index bf489d7..cd818fb 100644
--- a/drivers/staging/comedi/drivers/quatech_daqp_cs.c
+++ b/drivers/staging/comedi/drivers/quatech_daqp_cs.c
@@ -1039,7 +1039,6 @@ static int daqp_cs_attach(struct pcmcia_device *link)
device, and can be hard-wired here.
*/
link->conf.Attributes = 0;
- link->conf.IntType = INT_MEMORY_AND_IO;
daqp_cs_config(link);
diff --git a/drivers/staging/wlags49_h2/wl_cs.c b/drivers/staging/wlags49_h2/wl_cs.c
index 19c3354..b2efff6 100644
--- a/drivers/staging/wlags49_h2/wl_cs.c
+++ b/drivers/staging/wlags49_h2/wl_cs.c
@@ -148,7 +148,6 @@ static int wl_adapter_attach(struct pcmcia_device *link)
link->resource[0]->end = HCF_NUM_IO_PORTS;
link->resource[0]->flags= IO_DATA_PATH_WIDTH_16;
link->conf.Attributes = CONF_ENABLE_IRQ;
- link->conf.IntType = INT_MEMORY_AND_IO;
link->conf.ConfigIndex = 5;
link->conf.Present = PRESENT_OPTION;
diff --git a/drivers/telephony/ixj_pcmcia.c b/drivers/telephony/ixj_pcmcia.c
index a1900e5..5ccc6d0 100644
--- a/drivers/telephony/ixj_pcmcia.c
+++ b/drivers/telephony/ixj_pcmcia.c
@@ -34,7 +34,6 @@ static int ixj_probe(struct pcmcia_device *p_dev)
/* Create new ixj device */
p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
p_dev->resource[1]->flags |= IO_DATA_PATH_WIDTH_8;
- p_dev->conf.IntType = INT_MEMORY_AND_IO;
p_dev->priv = kzalloc(sizeof(struct ixj_info_t), GFP_KERNEL);
if (!p_dev->priv) {
return -ENOMEM;
diff --git a/drivers/usb/host/sl811_cs.c b/drivers/usb/host/sl811_cs.c
index 8e84752..78bad51 100644
--- a/drivers/usb/host/sl811_cs.c
+++ b/drivers/usb/host/sl811_cs.c
@@ -228,7 +228,6 @@ static int sl811_cs_probe(struct pcmcia_device *link)
link->priv = local;
link->conf.Attributes = 0;
- link->conf.IntType = INT_MEMORY_AND_IO;
return sl811_cs_config(link);
}
diff --git a/include/pcmcia/cs.h b/include/pcmcia/cs.h
index 29d693f..674edbc 100644
--- a/include/pcmcia/cs.h
+++ b/include/pcmcia/cs.h
@@ -22,7 +22,6 @@
/* For RequestConfiguration */
typedef struct config_req_t {
u_int Attributes;
- u_int IntType;
u_int ConfigBase;
u_char ConfigIndex;
u_int Present;
@@ -36,12 +35,6 @@ typedef struct config_req_t {
#define CONF_ENABLE_ESR 0x10
#define CONF_VALID_CLIENT 0x100
-/* IntType field */
-#define INT_MEMORY 0x01
-#define INT_MEMORY_AND_IO 0x02
-#define INT_CARDBUS 0x04
-#define INT_ZOOMED_VIDEO 0x08
-
/* Configuration registers present */
#define PRESENT_OPTION 0x001
#define PRESENT_STATUS 0x002
diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf.c b/sound/pcmcia/pdaudiocf/pdaudiocf.c
index 7ab9174..2e1282d 100644
--- a/sound/pcmcia/pdaudiocf/pdaudiocf.c
+++ b/sound/pcmcia/pdaudiocf/pdaudiocf.c
@@ -143,7 +143,6 @@ static int snd_pdacf_probe(struct pcmcia_device *link)
link->resource[0]->end = 16;
link->conf.Attributes = CONF_ENABLE_IRQ | CONF_ENABLE_PULSE_IRQ;
- link->conf.IntType = INT_MEMORY_AND_IO;
link->conf.ConfigIndex = 1;
link->conf.Present = PRESENT_OPTION;
diff --git a/sound/pcmcia/vx/vxpocket.c b/sound/pcmcia/vx/vxpocket.c
index a6edfc3..a48b3ee 100644
--- a/sound/pcmcia/vx/vxpocket.c
+++ b/sound/pcmcia/vx/vxpocket.c
@@ -163,7 +163,6 @@ static int snd_vxpocket_new(struct snd_card *card, int ibl,
link->resource[0]->end = 16;
link->conf.Attributes = CONF_ENABLE_IRQ;
- link->conf.IntType = INT_MEMORY_AND_IO;
link->conf.ConfigIndex = 1;
link->conf.Present = PRESENT_OPTION;
--
1.7.0.4
1
0

[alsa-devel] [patch 3/3] Staging: sst: fixups in SNDRV_SST_STREAM_DECODE
by Dan Carpenter 21 Oct '10
by Dan Carpenter 21 Oct '10
21 Oct '10
This is another patch about copying data to the kernel before using it.
SNDRV_SST_STREAM_DECODE is sort of tricky because we need to do a
copy_from_user() that gives us another two pointers and we have copy
those. Those again give us some more pointers that we have to copy.
Besides those problems, the code had a stack overflow:
- struct snd_sst_buff_entry ibuf_temp[param->ibufs->entries],
- obuf_temp[param->obufs->entries];
param->ibufs->entries comes from the user.
Signed-off-by: Dan Carpenter <error27(a)gmail.com>
---
Is there no standard API for this kind of thing?
diff --git a/drivers/staging/intel_sst/intel_sst_app_interface.c b/drivers/staging/intel_sst/intel_sst_app_interface.c
index 8390aa7..d20724d 100644
--- a/drivers/staging/intel_sst/intel_sst_app_interface.c
+++ b/drivers/staging/intel_sst/intel_sst_app_interface.c
@@ -1105,62 +1105,83 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg)
}
case _IOC_NR(SNDRV_SST_STREAM_DECODE): {
- struct snd_sst_dbufs *param =
- (struct snd_sst_dbufs *)arg, dbufs_local;
- int i;
+ struct snd_sst_dbufs param;
+ struct snd_sst_dbufs dbufs_local;
struct snd_sst_buffs ibufs, obufs;
- struct snd_sst_buff_entry ibuf_temp[param->ibufs->entries],
- obuf_temp[param->obufs->entries];
+ struct snd_sst_buff_entry *ibuf_tmp, *obuf_tmp;
+ char __user *dest;
pr_debug("sst: SNDRV_SST_STREAM_DECODE recived\n");
if (minor != STREAM_MODULE) {
retval = -EBADRQC;
break;
}
- if (!param) {
- retval = -EINVAL;
+ if (copy_from_user(¶m, (void __user *)arg,
+ sizeof(param))) {
+ retval = -EFAULT;
break;
}
- dbufs_local.input_bytes_consumed = param->input_bytes_consumed;
+ dbufs_local.input_bytes_consumed = param.input_bytes_consumed;
dbufs_local.output_bytes_produced =
- param->output_bytes_produced;
- dbufs_local.ibufs = &ibufs;
- dbufs_local.obufs = &obufs;
- dbufs_local.ibufs->entries = param->ibufs->entries;
- dbufs_local.ibufs->type = param->ibufs->type;
- dbufs_local.obufs->entries = param->obufs->entries;
- dbufs_local.obufs->type = param->obufs->type;
-
- dbufs_local.ibufs->buff_entry = ibuf_temp;
- for (i = 0; i < dbufs_local.ibufs->entries; i++) {
- ibuf_temp[i].buffer =
- param->ibufs->buff_entry[i].buffer;
- ibuf_temp[i].size =
- param->ibufs->buff_entry[i].size;
+ param.output_bytes_produced;
+
+ if (copy_from_user(&ibufs, param.ibufs, sizeof(ibufs))) {
+ retval = -EFAULT;
+ break;
+ }
+ if (copy_from_user(&obufs, param.obufs, sizeof(obufs))) {
+ retval = -EFAULT;
+ break;
+ }
+
+ ibuf_tmp = kcalloc(ibufs.entries, sizeof(*ibuf_tmp), GFP_KERNEL);
+ obuf_tmp = kcalloc(obufs.entries, sizeof(*obuf_tmp), GFP_KERNEL);
+ if (!ibuf_tmp || !obuf_tmp) {
+ retval = -ENOMEM;
+ goto free_iobufs;
+ }
+
+ if (copy_from_user(ibuf_tmp, ibufs.buff_entry,
+ ibufs.entries * sizeof(*ibuf_tmp))) {
+ retval = -EFAULT;
+ goto free_iobufs;
}
- dbufs_local.obufs->buff_entry = obuf_temp;
- for (i = 0; i < dbufs_local.obufs->entries; i++) {
- obuf_temp[i].buffer =
- param->obufs->buff_entry[i].buffer;
- obuf_temp[i].size =
- param->obufs->buff_entry[i].size;
+ ibufs.buff_entry = ibuf_tmp;
+ dbufs_local.ibufs = &ibufs;
+
+ if (copy_from_user(obuf_tmp, obufs.buff_entry,
+ obufs.entries * sizeof(*obuf_tmp))) {
+ retval = -EFAULT;
+ goto free_iobufs;
}
+ obufs.buff_entry = obuf_tmp;
+ dbufs_local.obufs = &obufs;
+
retval = sst_decode(str_id, &dbufs_local);
- if (retval)
- retval = -EAGAIN;
- if (copy_to_user(¶m->input_bytes_consumed,
+ if (retval) {
+ retval = -EAGAIN;
+ goto free_iobufs;
+ }
+
+ dest = (char *)arg + offsetof(struct snd_sst_dbufs, input_bytes_consumed);
+ if (copy_to_user(dest,
&dbufs_local.input_bytes_consumed,
sizeof(unsigned long long))) {
- retval = -EFAULT;
- break;
+ retval = -EFAULT;
+ goto free_iobufs;
}
- if (copy_to_user(¶m->output_bytes_produced,
+
+ dest = (char *)arg + offsetof(struct snd_sst_dbufs, input_bytes_consumed);
+ if (copy_to_user(dest,
&dbufs_local.output_bytes_produced,
sizeof(unsigned long long))) {
- retval = -EFAULT;
- break;
+ retval = -EFAULT;
+ goto free_iobufs;
}
+free_iobufs:
+ kfree(ibuf_tmp);
+ kfree(obuf_tmp);
break;
}
2
1

20 Oct '10
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Hi,
I'm working on getting the usb part of this very nice control surface to
work with alsa. I sniffed the usb traffic of the windows driver then
browsed the snd-usb-audio source code for clues.
I managed to get it partially working using a modified QUIRK_MIDI_EMAGIC
since the protocols are fairly similar (at least the 0xF5 port switching
part).
Please find attached the patch I came up to.
I have a few problems and dark areas I hope you'll be able to light up a
little :
First, I more or less get the picture of what the code is doing but
there's one part I fiddled with that I don't understand fully. What are
the .out_cables and .in_cables bitmasks doing besides defining the
number of ports ?
Next, the input part seem to work flawlessly on all ports, but I have
what seems to be a buffer overflow on the device when outputting midi
data. Comparing the windows and linux usb traffic, something obvious
shows up : the windows driver seem to be waiting for the device's
acknowledgment after each sent byte before sending the next one while
the snd-usb-audio module sends a bunch of bytes at once that ends up
confusing the device _and_ module. How can I make it behave like the
windows driver ?
I have traffic and error logs available if needed.
Thanks.
- --
Raphaël Doursenaud
http://raphael.doursenaud.fr
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.16 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/
iEYEARECAAYFAky+oqQACgkQaZKmNAdXaVUopgCgifnK+eSsCNpR5rx21iUqmXBQ
wJIAoJlt4h7Tp8tYYSbg9ZfLekE1QQfL
=d7vi
-----END PGP SIGNATURE-----
2
2

20 Oct '10
Hi,
This patch set is for new I2S SSP common driver that supports I2S audio on Intel MID platforms.
It is used for sending/receving I2S audio samples on Intel MID platform.
This interface is mostly used on Intel MID platforms and provide the low level interface for some upper layer drivers such as Alsa sound card driver for Bluetooth/FM peripherals, char device interfaces for modem (cmt_speech),...
As this is used to transfer speech frames from/to cellular modem that have specific timing constraints (and modem also uses the I2S path to send some side-info), the Alsa SoC interface cannot be used.
It is based on low level part of cmt_speech driver that can be found in N900 (see http://lists.meego.com/pipermail/meego-kernel/2010-September/000078.html ). The intel_mid_i2s have been separated from cmt_speech in order to be more generic and to be used on other ports (for instance, to provide Alsa sound card driver for Bluetooth and FM).
Upper level drivers cmt_speech and Alsa sound card driver that uses intel_mid_i2s will be up-streamed in coming days and is planned to use the same folder path (sound/pci/intel_mid_i2s/). So once these files will be upstream, this will provides Alsa sound driver interface for Bluetooth and FM for Intel Mid platform, and specific speech audio interface (char device) that is used by lib cmt speech data.
I will provide soon some draft version of example driver that uses intel_mid_i2s so reviewers can have better understanding of how it is used and how it fits together.
Best Regards,
Louis Le Gall
Here is a simple diagram that explain where is the intel_mid_i2s in software architecture.
+-----------+
| |
|Pulse Audio|
| |
| |
+-----------+
|
|
+------------+------------+
| |
| |
| |
+-----------+ +-----------+
| | |Lib cmt |
|Alsa Lib |------+ |speech |------+
| | | |data | |
| | | | | |
+-----------+ | +-----------+ |
| | |
| | | User
......|............|.........................|.................................
| | | Kernel
| | |
| | |
| | |
| | |
| | |
| | |
\|/ \|/ \|/
V V V
+---------+ ++---------++ ++---------++
| | ||Alsa snd || ||cmt ||
|Intel SST| ||driver || ||speech ||
| "MAD" | ||SSP || ||driver ||
| | ||BT/FM || || ||
+---------+ ++---------++ ++---------++
| | |
| | |
| | |
| | |
\|/ | \|/
V | V
+-----------+ | ++---------++
| | | \ ||intel mid||
|LPE | +------------------>||i2s ||
| | / ||unified ||
| | ||driver ||
+-----------+ ++---------++
| |
| | Kernel
......|......................................|.................................
| | Hardware
\|/ \|/
V V
+-- --+ +-- --+
| | | |
|MISC | |SSP in I2S |
| | |config |
| | | |
+-- --+ +-- --+
4
5

19 Oct '10
From: Victor Rodriguez <victor.rodriguez(a)sasken.com>
This patch adds
EMAC, EDMA, ASoC, SOUND, MMC/SD and USB OHCI
support for the Hawkboard-L138 system
It is under the machine name "omapl138_hawkboard".
This system is based on the da850 davinci CPU architecture.
Victor Rodriguez (9):
davinci: EMAC support for Omapl138-Hawkboard
davinci: EDMA support for Omapl138-Hawkboard
davinci: ASoC support for Omapl138-Hawkboard
davinci: McASP configuration for Omapl138-Hawkboard
davinci: Audio support for Omapl138-Hawkboard
davinci: MMC/SD and USB-OHCI configuration for Omapl138-Hawkboard
davinci: MMC/SD support for Omapl138-Hawkboar
davinci: USB clocks for Omapl138-Hawkboard
davinci: USB1.1 support for Omapl138-Hawkboard
arch/arm/mach-davinci/board-omapl138-hawk.c | 308 +++++++++++++++++++++++++++
arch/arm/mach-davinci/da850.c | 22 ++-
arch/arm/mach-davinci/include/mach/mux.h | 4 +
sound/soc/davinci/Kconfig | 5 +-
sound/soc/davinci/davinci-evm.c | 6 +-
5 files changed, 340 insertions(+), 5 deletions(-)
5
21
Cem ERGEN wrote:
> how could i learn sample format?
/proc/asound/cardX/stream0
Regards,
Clemens
1
0
> ... so the whole messages can be reduced to a sentense:
> "Rewrite the driver based on ASoC!"
>
> Then it's a question to Intel guys. If they would like to support for
> it, we can happily wait for it before merging. If they don't want but
> keep as is, then questions are:
> - whether to keep it in upstream or not
> - where to keep it, in staging or in sound tree
>
> and, the latter question is nothing but a bikeshedding; in anyway it's
> a second choice, after all. We should spend time for more useful
> things :)
Yes Intel is planning to rewrite the sound card driver for ASoC.
I will take us little time for that :-)
Meanwhile IMO it would be great to have this driver in staging or in sound
whichever you guys agree to
~Vinod
2
1

[alsa-devel] Newbie needs help to understand SNDRV_PCM_TRIGGER_START?
by Radivoje Jovanovic 19 Oct '10
by Radivoje Jovanovic 19 Oct '10
19 Oct '10
I am writing my first ALSA driver. We have hardware where the amp is
controlled with another CPU (non Linux) so I have to forward the buffers
from ALSA to it. We do not have working solution on another CPU so I cannot
test sound playback yet. ALSA hits trigger method in my driver and soon
after it leaves my trigger method throws an null pointer exception (probably
since I did not do anything in my trigger method). I am wondering if the
ALSA will call SNDRV_PCM_TRIGGER_START every single time new buffer is
available. Do I need to manage circular queue of buffers or ALSA is doing
this for me already?
Thanx
2
1

19 Oct '10
From: Jassi Brar <jassi.brar(a)samsung.com>
The variable is not used anyway.
Signed-off-by: Jassi Brar <jassi.brar(a)samsung.com>
---
sound/soc/codecs/wm8580.c | 4 ----
1 files changed, 0 insertions(+), 4 deletions(-)
diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c
index ad5987e..a2e0ed5 100644
--- a/sound/soc/codecs/wm8580.c
+++ b/sound/soc/codecs/wm8580.c
@@ -548,11 +548,9 @@ static int wm8580_set_paif_dai_fmt(struct snd_soc_dai *codec_dai,
unsigned int fmt)
{
struct snd_soc_codec *codec = codec_dai->codec;
- struct wm8580_priv *wm8580 = snd_soc_codec_get_drvdata(codec);
unsigned int aifa;
unsigned int aifb;
int can_invert_lrclk;
- int sysclk;
aifa = snd_soc_read(codec, WM8580_PAIF1 + codec_dai->driver->id);
aifb = snd_soc_read(codec, WM8580_PAIF3 + codec_dai->driver->id);
@@ -621,8 +619,6 @@ static int wm8580_set_paif_dai_fmt(struct snd_soc_dai *codec_dai,
return -EINVAL;
}
- sysclk = wm8580->sysclk[codec_dai->driver->id];
-
snd_soc_write(codec, WM8580_PAIF1 + codec_dai->driver->id, aifa);
snd_soc_write(codec, WM8580_PAIF3 + codec_dai->driver->id, aifb);
--
1.6.2.5
3
2

19 Oct '10
Use bitwise AND instead of logical AND when masking.
Signed-off-by: Jarkko Nikula <jhnikula(a)gmail.com>
---
Random note, not known to cause any problems at the moment as id field of
codec seems to be unused.
---
sound/soc/soc-core.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 8751efd..fe9f20b 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -2892,7 +2892,7 @@ static inline char *fmt_single_name(struct device *dev, int *id)
char tmp[NAME_SIZE];
/* create unique ID number from I2C addr and bus */
- *id = ((id1 && 0xffff) << 16) + id2;
+ *id = ((id1 & 0xffff) << 16) + id2;
/* sanitize component name for DAI link creation */
snprintf(tmp, NAME_SIZE, "%s.%s", dev->driver->name, name);
--
1.7.1
3
2

19 Oct '10
From: Jassi Brar <jassi.brar(a)samsung.com>
Finally, move the 's3c24xx' directory to 'samsung'
Signed-off-by: Jassi Brar <jassi.brar(a)samsung.com>
---
sound/soc/Kconfig | 2 +-
sound/soc/Makefile | 2 +-
sound/soc/s3c24xx/Kconfig | 154 ---
sound/soc/s3c24xx/Makefile | 51 -
sound/soc/s3c24xx/ac97.c | 520 ----------
sound/soc/s3c24xx/ac97.h | 21 -
sound/soc/s3c24xx/dma.c | 503 ----------
sound/soc/s3c24xx/dma.h | 30 -
sound/soc/s3c24xx/goni_wm8994.c | 309 ------
sound/soc/s3c24xx/i2s.c | 1251 ------------------------
sound/soc/s3c24xx/i2s.h | 29 -
sound/soc/s3c24xx/jive_wm8750.c | 191 ----
sound/soc/s3c24xx/lm4857.h | 32 -
sound/soc/s3c24xx/ln2440sbc_alc650.c | 78 --
sound/soc/s3c24xx/neo1973_gta02_wm8753.c | 504 ----------
sound/soc/s3c24xx/neo1973_wm8753.c | 704 -------------
sound/soc/s3c24xx/pcm.c | 552 -----------
sound/soc/s3c24xx/pcm.h | 124 ---
sound/soc/s3c24xx/regs-i2s-v2.h | 115 ---
sound/soc/s3c24xx/rx1950_uda1380.c | 333 -------
sound/soc/s3c24xx/s3c-i2s-v2.c | 757 --------------
sound/soc/s3c24xx/s3c-i2s-v2.h | 106 --
sound/soc/s3c24xx/s3c2412-i2s.c | 212 ----
sound/soc/s3c24xx/s3c2412-i2s.h | 27 -
sound/soc/s3c24xx/s3c24xx-i2s.c | 519 ----------
sound/soc/s3c24xx/s3c24xx-i2s.h | 35 -
sound/soc/s3c24xx/s3c24xx_simtec.c | 395 --------
sound/soc/s3c24xx/s3c24xx_simtec.h | 22 -
sound/soc/s3c24xx/s3c24xx_simtec_hermes.c | 146 ---
sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c | 134 ---
sound/soc/s3c24xx/s3c24xx_uda134x.c | 368 -------
sound/soc/s3c24xx/smartq_wm8987.c | 287 ------
sound/soc/s3c24xx/smdk2443_wm9710.c | 74 --
sound/soc/s3c24xx/smdk_spdif.c | 223 -----
sound/soc/s3c24xx/smdk_wm8580.c | 284 ------
sound/soc/s3c24xx/smdk_wm9713.c | 107 --
sound/soc/s3c24xx/spdif.c | 501 ----------
sound/soc/s3c24xx/spdif.h | 19 -
sound/soc/samsung/Kconfig | 154 +++
sound/soc/samsung/Makefile | 51 +
sound/soc/samsung/ac97.c | 520 ++++++++++
sound/soc/samsung/ac97.h | 21 +
sound/soc/samsung/dma.c | 503 ++++++++++
sound/soc/samsung/dma.h | 30 +
sound/soc/samsung/goni_wm8994.c | 309 ++++++
sound/soc/samsung/i2s.c | 1251 ++++++++++++++++++++++++
sound/soc/samsung/i2s.h | 29 +
sound/soc/samsung/jive_wm8750.c | 191 ++++
sound/soc/samsung/lm4857.h | 32 +
sound/soc/samsung/ln2440sbc_alc650.c | 78 ++
sound/soc/samsung/neo1973_gta02_wm8753.c | 504 ++++++++++
sound/soc/samsung/neo1973_wm8753.c | 704 +++++++++++++
sound/soc/samsung/pcm.c | 552 +++++++++++
sound/soc/samsung/pcm.h | 124 +++
sound/soc/samsung/regs-i2s-v2.h | 115 +++
sound/soc/samsung/rx1950_uda1380.c | 333 +++++++
sound/soc/samsung/s3c-i2s-v2.c | 757 ++++++++++++++
sound/soc/samsung/s3c-i2s-v2.h | 106 ++
sound/soc/samsung/s3c2412-i2s.c | 212 ++++
sound/soc/samsung/s3c2412-i2s.h | 27 +
sound/soc/samsung/s3c24xx-i2s.c | 519 ++++++++++
sound/soc/samsung/s3c24xx-i2s.h | 35 +
sound/soc/samsung/s3c24xx_simtec.c | 395 ++++++++
sound/soc/samsung/s3c24xx_simtec.h | 22 +
sound/soc/samsung/s3c24xx_simtec_hermes.c | 146 +++
sound/soc/samsung/s3c24xx_simtec_tlv320aic23.c | 134 +++
sound/soc/samsung/s3c24xx_uda134x.c | 368 +++++++
sound/soc/samsung/smartq_wm8987.c | 287 ++++++
sound/soc/samsung/smdk2443_wm9710.c | 74 ++
sound/soc/samsung/smdk_spdif.c | 223 +++++
sound/soc/samsung/smdk_wm8580.c | 284 ++++++
sound/soc/samsung/smdk_wm9713.c | 107 ++
sound/soc/samsung/spdif.c | 501 ++++++++++
sound/soc/samsung/spdif.h | 19 +
74 files changed, 9719 insertions(+), 9719 deletions(-)
delete mode 100644 sound/soc/s3c24xx/Kconfig
delete mode 100644 sound/soc/s3c24xx/Makefile
delete mode 100644 sound/soc/s3c24xx/ac97.c
delete mode 100644 sound/soc/s3c24xx/ac97.h
delete mode 100644 sound/soc/s3c24xx/dma.c
delete mode 100644 sound/soc/s3c24xx/dma.h
delete mode 100644 sound/soc/s3c24xx/goni_wm8994.c
delete mode 100644 sound/soc/s3c24xx/i2s.c
delete mode 100644 sound/soc/s3c24xx/i2s.h
delete mode 100644 sound/soc/s3c24xx/jive_wm8750.c
delete mode 100644 sound/soc/s3c24xx/lm4857.h
delete mode 100644 sound/soc/s3c24xx/ln2440sbc_alc650.c
delete mode 100644 sound/soc/s3c24xx/neo1973_gta02_wm8753.c
delete mode 100644 sound/soc/s3c24xx/neo1973_wm8753.c
delete mode 100644 sound/soc/s3c24xx/pcm.c
delete mode 100644 sound/soc/s3c24xx/pcm.h
delete mode 100644 sound/soc/s3c24xx/regs-i2s-v2.h
delete mode 100644 sound/soc/s3c24xx/rx1950_uda1380.c
delete mode 100644 sound/soc/s3c24xx/s3c-i2s-v2.c
delete mode 100644 sound/soc/s3c24xx/s3c-i2s-v2.h
delete mode 100644 sound/soc/s3c24xx/s3c2412-i2s.c
delete mode 100644 sound/soc/s3c24xx/s3c2412-i2s.h
delete mode 100644 sound/soc/s3c24xx/s3c24xx-i2s.c
delete mode 100644 sound/soc/s3c24xx/s3c24xx-i2s.h
delete mode 100644 sound/soc/s3c24xx/s3c24xx_simtec.c
delete mode 100644 sound/soc/s3c24xx/s3c24xx_simtec.h
delete mode 100644 sound/soc/s3c24xx/s3c24xx_simtec_hermes.c
delete mode 100644 sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c
delete mode 100644 sound/soc/s3c24xx/s3c24xx_uda134x.c
delete mode 100644 sound/soc/s3c24xx/smartq_wm8987.c
delete mode 100644 sound/soc/s3c24xx/smdk2443_wm9710.c
delete mode 100644 sound/soc/s3c24xx/smdk_spdif.c
delete mode 100644 sound/soc/s3c24xx/smdk_wm8580.c
delete mode 100644 sound/soc/s3c24xx/smdk_wm9713.c
delete mode 100644 sound/soc/s3c24xx/spdif.c
delete mode 100644 sound/soc/s3c24xx/spdif.h
create mode 100644 sound/soc/samsung/Kconfig
create mode 100644 sound/soc/samsung/Makefile
create mode 100644 sound/soc/samsung/ac97.c
create mode 100644 sound/soc/samsung/ac97.h
create mode 100644 sound/soc/samsung/dma.c
create mode 100644 sound/soc/samsung/dma.h
create mode 100644 sound/soc/samsung/goni_wm8994.c
create mode 100644 sound/soc/samsung/i2s.c
create mode 100644 sound/soc/samsung/i2s.h
create mode 100644 sound/soc/samsung/jive_wm8750.c
create mode 100644 sound/soc/samsung/lm4857.h
create mode 100644 sound/soc/samsung/ln2440sbc_alc650.c
create mode 100644 sound/soc/samsung/neo1973_gta02_wm8753.c
create mode 100644 sound/soc/samsung/neo1973_wm8753.c
create mode 100644 sound/soc/samsung/pcm.c
create mode 100644 sound/soc/samsung/pcm.h
create mode 100644 sound/soc/samsung/regs-i2s-v2.h
create mode 100644 sound/soc/samsung/rx1950_uda1380.c
create mode 100644 sound/soc/samsung/s3c-i2s-v2.c
create mode 100644 sound/soc/samsung/s3c-i2s-v2.h
create mode 100644 sound/soc/samsung/s3c2412-i2s.c
create mode 100644 sound/soc/samsung/s3c2412-i2s.h
create mode 100644 sound/soc/samsung/s3c24xx-i2s.c
create mode 100644 sound/soc/samsung/s3c24xx-i2s.h
create mode 100644 sound/soc/samsung/s3c24xx_simtec.c
create mode 100644 sound/soc/samsung/s3c24xx_simtec.h
create mode 100644 sound/soc/samsung/s3c24xx_simtec_hermes.c
create mode 100644 sound/soc/samsung/s3c24xx_simtec_tlv320aic23.c
create mode 100644 sound/soc/samsung/s3c24xx_uda134x.c
create mode 100644 sound/soc/samsung/smartq_wm8987.c
create mode 100644 sound/soc/samsung/smdk2443_wm9710.c
create mode 100644 sound/soc/samsung/smdk_spdif.c
create mode 100644 sound/soc/samsung/smdk_wm8580.c
create mode 100644 sound/soc/samsung/smdk_wm9713.c
create mode 100644 sound/soc/samsung/spdif.c
create mode 100644 sound/soc/samsung/spdif.h
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
index 3e598e7..2722b19 100644
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -36,7 +36,7 @@ source "sound/soc/nuc900/Kconfig"
source "sound/soc/omap/Kconfig"
source "sound/soc/kirkwood/Kconfig"
source "sound/soc/pxa/Kconfig"
-source "sound/soc/s3c24xx/Kconfig"
+source "sound/soc/samsung/Kconfig"
source "sound/soc/s6000/Kconfig"
source "sound/soc/sh/Kconfig"
source "sound/soc/txx9/Kconfig"
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index eb18344..ce913bf 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -14,7 +14,7 @@ obj-$(CONFIG_SND_SOC) += nuc900/
obj-$(CONFIG_SND_SOC) += omap/
obj-$(CONFIG_SND_SOC) += kirkwood/
obj-$(CONFIG_SND_SOC) += pxa/
-obj-$(CONFIG_SND_SOC) += s3c24xx/
+obj-$(CONFIG_SND_SOC) += samsung/
obj-$(CONFIG_SND_SOC) += s6000/
obj-$(CONFIG_SND_SOC) += sh/
obj-$(CONFIG_SND_SOC) += txx9/
diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig
deleted file mode 100644
index 140095e..0000000
--- a/sound/soc/s3c24xx/Kconfig
+++ /dev/null
@@ -1,154 +0,0 @@
-config ASOC_SAMSUNG
- tristate "ASoC support for Samsung"
- depends on ARCH_S3C2410 || ARCH_S3C64XX || ARCH_S5PC100 || ARCH_S5PV210
- select S3C64XX_DMA if ARCH_S3C64XX
- help
- Say Y or M if you want to add support for codecs attached to
- the Samsung SoCs' Audio interfaces. You will also need to
- select the audio interfaces to support below.
-
-config SND_S3C24XX_I2S
- tristate
- select S3C2410_DMA
-
-config SND_S3C_I2SV2_SOC
- tristate
-
-config SND_S3C2412_SOC_I2S
- tristate
- select SND_S3C_I2SV2_SOC
- select S3C2410_DMA
-
-config SND_SAMSUNG_PCM
- tristate
-
-config SND_SAMSUNG_AC97
- tristate
- select SND_SOC_AC97_BUS
-
-config SND_SAMSUNG_SPDIF
- tristate
- select SND_SOC_SPDIF
-
-config SND_SAMSUNG_I2S
- tristate
-
-config ASOC_SAMSUNG_NEO1973_WM8753
- tristate "SoC I2S Audio support for NEO1973 - WM8753"
- depends on ASOC_SAMSUNG && MACH_NEO1973_GTA01
- select SND_S3C24XX_I2S
- select SND_SOC_WM8753
- help
- Say Y if you want to add support for SoC audio on smdk2440
- with the WM8753.
-
-config ASOC_SAMSUNG_NEO1973_GTA02_WM8753
- tristate "Audio support for the Openmoko Neo FreeRunner (GTA02)"
- depends on ASOC_SAMSUNG && MACH_NEO1973_GTA02
- select SND_S3C24XX_I2S
- select SND_SOC_WM8753
- help
- This driver provides audio support for the Openmoko Neo FreeRunner
- smartphone.
-
-config ASOC_SAMSUNG_JIVE_WM8750
- tristate "SoC I2S Audio support for Jive"
- depends on ASOC_SAMSUNG && MACH_JIVE
- select SND_SOC_WM8750
- select SND_S3C2412_SOC_I2S
- help
- Sat Y if you want to add support for SoC audio on the Jive.
-
-config ASOC_SAMSUNG_SMDK_WM8580
- tristate "SoC I2S Audio support for WM8580 on SMDK"
- depends on ASOC_SAMSUNG && (MACH_SMDK6410 || MACH_SMDKC100)
- select SND_SOC_WM8580
- select SND_SAMSUNG_I2S
- help
- Say Y if you want to add support for SoC audio on the SMDKs.
-
-config ASOC_SAMSUNG_SMDK2443_WM9710
- tristate "SoC AC97 Audio support for SMDK2443 - WM9710"
- depends on ASOC_SAMSUNG && MACH_SMDK2443
- select S3C2410_DMA
- select AC97_BUS
- select SND_SOC_AC97_CODEC
- select SND_SAMSUNG_AC97
- help
- Say Y if you want to add support for SoC audio on smdk2443
- with the WM9710.
-
-config ASOC_SAMSUNG_LN2440SBC_ALC650
- tristate "SoC AC97 Audio support for LN2440SBC - ALC650"
- depends on ASOC_SAMSUNG && ARCH_S3C2410
- select S3C2410_DMA
- select AC97_BUS
- select SND_SOC_AC97_CODEC
- select SND_SAMSUNG_AC97
- help
- Say Y if you want to add support for SoC audio on ln2440sbc
- with the ALC650.
-
-config ASOC_SAMSUNG_S3C24XX_UDA134X
- tristate "SoC I2S Audio support UDA134X wired to a S3C24XX"
- depends on ASOC_SAMSUNG && ARCH_S3C2410
- select SND_S3C24XX_I2S
- select SND_SOC_L3
- select SND_SOC_UDA134X
-
-config ASOC_SAMSUNG_SIMTEC
- tristate
- help
- Internal node for common S3C24XX/Simtec suppor
-
-config ASOC_SAMSUNG_SIMTEC_TLV320AIC23
- tristate "SoC I2S Audio support for TLV320AIC23 on Simtec boards"
- depends on ASOC_SAMSUNG && ARCH_S3C2410
- select SND_S3C24XX_I2S
- select SND_SOC_TLV320AIC23
- select ASOC_SAMSUNG_SIMTEC
-
-config ASOC_SAMSUNG_SIMTEC_HERMES
- tristate "SoC I2S Audio support for Simtec Hermes board"
- depends on ASOC_SAMSUNG && ARCH_S3C2410
- select SND_S3C24XX_I2S
- select SND_SOC_TLV320AIC3X
- select ASOC_SAMSUNG_SIMTEC
-
-config ASOC_SAMSUNG_RX1950_UDA1380
- tristate "Audio support for the HP iPAQ RX1950"
- depends on ASOC_SAMSUNG && MACH_RX1950
- select SND_S3C24XX_I2S
- select SND_SOC_UDA1380
- help
- This driver provides audio support for HP iPAQ RX1950 PDA.
-
-config ASOC_SAMSUNG_SMDK_WM9713
- tristate "SoC AC97 Audio support for SMDK with WM9713"
- depends on ASOC_SAMSUNG && (MACH_SMDK6410 || MACH_SMDKC100 || MACH_SMDKV210 || MACH_SMDKC110)
- select SND_SOC_WM9713
- select SND_SAMSUNG_AC97
- help
- Sat Y if you want to add support for SoC audio on the SMDK.
-
-config ASOC_SMARTQ
- tristate "SoC I2S Audio support for SmartQ board"
- depends on ASOC_SAMSUNG && MACH_SMARTQ
- select SND_SAMSUNG_I2S
- select SND_SOC_WM8750
-
-config ASOC_GONI_AQUILA_WM8994
- tristate "SoC I2S Audio support for AQUILA/GONI - WM8994"
- depends on ASOC_SAMSUNG && (MACH_GONI || MACH_AQUILA)
- select SND_SAMSUNG_I2S
- select SND_SOC_WM8994
- help
- Say Y if you want to add support for SoC audio on goni or aquila
- with the WM8994.
-
-config ASOC_SAMSUNG_SMDK_SPDIF
- tristate "SoC S/PDIF Audio support for SMDK"
- depends on SND_S3C24XX_SOC && (MACH_SMDKC100 || MACH_SMDKC110 || MACH_SMDKV210)
- select SND_SAMSUNG_SPDIF
- help
- Say Y if you want to add support for SoC S/PDIF audio on the SMDK.
diff --git a/sound/soc/s3c24xx/Makefile b/sound/soc/s3c24xx/Makefile
deleted file mode 100644
index 0d24f95..0000000
--- a/sound/soc/s3c24xx/Makefile
+++ /dev/null
@@ -1,51 +0,0 @@
-# S3c24XX Platform Support
-snd-soc-s3c24xx-objs := dma.o
-snd-soc-s3c24xx-i2s-objs := s3c24xx-i2s.o
-snd-soc-s3c2412-i2s-objs := s3c2412-i2s.o
-snd-soc-ac97-objs := ac97.o
-snd-soc-s3c-i2s-v2-objs := s3c-i2s-v2.o
-snd-soc-samsung-spdif-objs := spdif.o
-snd-soc-pcm-objs := pcm.o
-snd-soc-i2s-objs := i2s.o
-
-obj-$(CONFIG_ASOC_SAMSUNG) += snd-soc-s3c24xx.o
-obj-$(CONFIG_SND_S3C24XX_I2S) += snd-soc-s3c24xx-i2s.o
-obj-$(CONFIG_SND_SAMSUNG_AC97) += snd-soc-ac97.o
-obj-$(CONFIG_SND_S3C2412_SOC_I2S) += snd-soc-s3c2412-i2s.o
-obj-$(CONFIG_SND_S3C_I2SV2_SOC) += snd-soc-s3c-i2s-v2.o
-obj-$(CONFIG_SND_SAMSUNG_SPDIF) += snd-soc-samsung-spdif.o
-obj-$(CONFIG_SND_SAMSUNG_PCM) += snd-soc-pcm.o
-obj-$(CONFIG_SND_SAMSUNG_I2S) += snd-soc-i2s.o
-
-# S3C24XX Machine Support
-snd-soc-jive-wm8750-objs := jive_wm8750.o
-snd-soc-neo1973-wm8753-objs := neo1973_wm8753.o
-snd-soc-neo1973-gta02-wm8753-objs := neo1973_gta02_wm8753.o
-snd-soc-smdk2443-wm9710-objs := smdk2443_wm9710.o
-snd-soc-ln2440sbc-alc650-objs := ln2440sbc_alc650.o
-snd-soc-s3c24xx-uda134x-objs := s3c24xx_uda134x.o
-snd-soc-s3c24xx-simtec-objs := s3c24xx_simtec.o
-snd-soc-s3c24xx-simtec-hermes-objs := s3c24xx_simtec_hermes.o
-snd-soc-s3c24xx-simtec-tlv320aic23-objs := s3c24xx_simtec_tlv320aic23.o
-snd-soc-rx1950-uda1380-objs := rx1950_uda1380.o
-snd-soc-smdk-wm8580-objs := smdk_wm8580.o
-snd-soc-smdk-wm9713-objs := smdk_wm9713.o
-snd-soc-s3c64xx-smartq-wm8987-objs := smartq_wm8987.o
-snd-soc-goni-wm8994-objs := goni_wm8994.o
-snd-soc-smdk-spdif-objs := smdk_spdif.o
-
-obj-$(CONFIG_ASOC_SAMSUNG_JIVE_WM8750) += snd-soc-jive-wm8750.o
-obj-$(CONFIG_ASOC_SAMSUNG_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o
-obj-$(CONFIG_ASOC_SAMSUNG_NEO1973_GTA02_WM8753) += snd-soc-neo1973-gta02-wm8753.o
-obj-$(CONFIG_ASOC_SAMSUNG_SMDK2443_WM9710) += snd-soc-smdk2443-wm9710.o
-obj-$(CONFIG_ASOC_SAMSUNG_LN2440SBC_ALC650) += snd-soc-ln2440sbc-alc650.o
-obj-$(CONFIG_ASOC_SAMSUNG_S3C24XX_UDA134X) += snd-soc-s3c24xx-uda134x.o
-obj-$(CONFIG_ASOC_SAMSUNG_SIMTEC) += snd-soc-s3c24xx-simtec.o
-obj-$(CONFIG_ASOC_SAMSUNG_SIMTEC_HERMES) += snd-soc-s3c24xx-simtec-hermes.o
-obj-$(CONFIG_ASOC_SAMSUNG_SIMTEC_TLV320AIC23) += snd-soc-s3c24xx-simtec-tlv320aic23.o
-obj-$(CONFIG_ASOC_SAMSUNG_RX1950_UDA1380) += snd-soc-rx1950-uda1380.o
-obj-$(CONFIG_ASOC_SAMSUNG_SMDK_WM8580) += snd-soc-smdk-wm8580.o
-obj-$(CONFIG_ASOC_SAMSUNG_SMDK_WM9713) += snd-soc-smdk-wm9713.o
-obj-$(CONFIG_ASOC_SMARTQ) += snd-soc-s3c64xx-smartq-wm8987.o
-obj-$(CONFIG_ASOC_SAMSUNG_SMDK_SPDIF) += snd-soc-smdk-spdif.o
-obj-$(CONFIG_ASOC_GONI_AQUILA_WM8994) += snd-soc-goni-wm8994.o
diff --git a/sound/soc/s3c24xx/ac97.c b/sound/soc/s3c24xx/ac97.c
deleted file mode 100644
index 4f999d1..0000000
--- a/sound/soc/s3c24xx/ac97.c
+++ /dev/null
@@ -1,520 +0,0 @@
-/* sound/soc/s3c24xx/ac97.c
- *
- * ALSA SoC Audio Layer - S3C AC97 Controller driver
- * Evolved from s3c2443-ac97.c
- *
- * Copyright (c) 2010 Samsung Electronics Co. Ltd
- * Author: Jaswinder Singh <jassi.brar(a)samsung.com>
- * Credits: Graeme Gregory, Sean Choi
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/io.h>
-#include <linux/delay.h>
-#include <linux/clk.h>
-
-#include <sound/soc.h>
-
-#include <plat/regs-ac97.h>
-#include <mach/dma.h>
-#include <plat/audio.h>
-
-#include "dma.h"
-#include "ac97.h"
-
-#define AC_CMD_ADDR(x) (x << 16)
-#define AC_CMD_DATA(x) (x & 0xffff)
-
-struct s3c_ac97_info {
- struct clk *ac97_clk;
- void __iomem *regs;
- struct mutex lock;
- struct completion done;
-};
-static struct s3c_ac97_info s3c_ac97;
-
-static struct s3c2410_dma_client s3c_dma_client_out = {
- .name = "AC97 PCMOut"
-};
-
-static struct s3c2410_dma_client s3c_dma_client_in = {
- .name = "AC97 PCMIn"
-};
-
-static struct s3c2410_dma_client s3c_dma_client_micin = {
- .name = "AC97 MicIn"
-};
-
-static struct s3c_dma_params s3c_ac97_pcm_out = {
- .client = &s3c_dma_client_out,
- .dma_size = 4,
-};
-
-static struct s3c_dma_params s3c_ac97_pcm_in = {
- .client = &s3c_dma_client_in,
- .dma_size = 4,
-};
-
-static struct s3c_dma_params s3c_ac97_mic_in = {
- .client = &s3c_dma_client_micin,
- .dma_size = 4,
-};
-
-static void s3c_ac97_activate(struct snd_ac97 *ac97)
-{
- u32 ac_glbctrl, stat;
-
- stat = readl(s3c_ac97.regs + S3C_AC97_GLBSTAT) & 0x7;
- if (stat == S3C_AC97_GLBSTAT_MAINSTATE_ACTIVE)
- return; /* Return if already active */
-
- INIT_COMPLETION(s3c_ac97.done);
-
- ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
- ac_glbctrl = S3C_AC97_GLBCTRL_ACLINKON;
- writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
- msleep(1);
-
- ac_glbctrl |= S3C_AC97_GLBCTRL_TRANSFERDATAENABLE;
- writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
- msleep(1);
-
- ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
- ac_glbctrl |= S3C_AC97_GLBCTRL_CODECREADYIE;
- writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
-
- if (!wait_for_completion_timeout(&s3c_ac97.done, HZ))
- pr_err("AC97: Unable to activate!");
-}
-
-static unsigned short s3c_ac97_read(struct snd_ac97 *ac97,
- unsigned short reg)
-{
- u32 ac_glbctrl, ac_codec_cmd;
- u32 stat, addr, data;
-
- mutex_lock(&s3c_ac97.lock);
-
- s3c_ac97_activate(ac97);
-
- INIT_COMPLETION(s3c_ac97.done);
-
- ac_codec_cmd = readl(s3c_ac97.regs + S3C_AC97_CODEC_CMD);
- ac_codec_cmd = S3C_AC97_CODEC_CMD_READ | AC_CMD_ADDR(reg);
- writel(ac_codec_cmd, s3c_ac97.regs + S3C_AC97_CODEC_CMD);
-
- udelay(50);
-
- ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
- ac_glbctrl |= S3C_AC97_GLBCTRL_CODECREADYIE;
- writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
-
- if (!wait_for_completion_timeout(&s3c_ac97.done, HZ))
- pr_err("AC97: Unable to read!");
-
- stat = readl(s3c_ac97.regs + S3C_AC97_STAT);
- addr = (stat >> 16) & 0x7f;
- data = (stat & 0xffff);
-
- if (addr != reg)
- pr_err("ac97: req addr = %02x, rep addr = %02x\n",
- reg, addr);
-
- mutex_unlock(&s3c_ac97.lock);
-
- return (unsigned short)data;
-}
-
-static void s3c_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
- unsigned short val)
-{
- u32 ac_glbctrl, ac_codec_cmd;
-
- mutex_lock(&s3c_ac97.lock);
-
- s3c_ac97_activate(ac97);
-
- INIT_COMPLETION(s3c_ac97.done);
-
- ac_codec_cmd = readl(s3c_ac97.regs + S3C_AC97_CODEC_CMD);
- ac_codec_cmd = AC_CMD_ADDR(reg) | AC_CMD_DATA(val);
- writel(ac_codec_cmd, s3c_ac97.regs + S3C_AC97_CODEC_CMD);
-
- udelay(50);
-
- ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
- ac_glbctrl |= S3C_AC97_GLBCTRL_CODECREADYIE;
- writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
-
- if (!wait_for_completion_timeout(&s3c_ac97.done, HZ))
- pr_err("AC97: Unable to write!");
-
- ac_codec_cmd = readl(s3c_ac97.regs + S3C_AC97_CODEC_CMD);
- ac_codec_cmd |= S3C_AC97_CODEC_CMD_READ;
- writel(ac_codec_cmd, s3c_ac97.regs + S3C_AC97_CODEC_CMD);
-
- mutex_unlock(&s3c_ac97.lock);
-}
-
-static void s3c_ac97_cold_reset(struct snd_ac97 *ac97)
-{
- pr_debug("AC97: Cold reset\n");
- writel(S3C_AC97_GLBCTRL_COLDRESET,
- s3c_ac97.regs + S3C_AC97_GLBCTRL);
- msleep(1);
-
- writel(0, s3c_ac97.regs + S3C_AC97_GLBCTRL);
- msleep(1);
-}
-
-static void s3c_ac97_warm_reset(struct snd_ac97 *ac97)
-{
- u32 stat;
-
- stat = readl(s3c_ac97.regs + S3C_AC97_GLBSTAT) & 0x7;
- if (stat == S3C_AC97_GLBSTAT_MAINSTATE_ACTIVE)
- return; /* Return if already active */
-
- pr_debug("AC97: Warm reset\n");
-
- writel(S3C_AC97_GLBCTRL_WARMRESET, s3c_ac97.regs + S3C_AC97_GLBCTRL);
- msleep(1);
-
- writel(0, s3c_ac97.regs + S3C_AC97_GLBCTRL);
- msleep(1);
-
- s3c_ac97_activate(ac97);
-}
-
-static irqreturn_t s3c_ac97_irq(int irq, void *dev_id)
-{
- u32 ac_glbctrl, ac_glbstat;
-
- ac_glbstat = readl(s3c_ac97.regs + S3C_AC97_GLBSTAT);
-
- if (ac_glbstat & S3C_AC97_GLBSTAT_CODECREADY) {
-
- ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
- ac_glbctrl &= ~S3C_AC97_GLBCTRL_CODECREADYIE;
- writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
-
- complete(&s3c_ac97.done);
- }
-
- ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
- ac_glbctrl |= (1<<30); /* Clear interrupt */
- writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
-
- return IRQ_HANDLED;
-}
-
-struct snd_ac97_bus_ops soc_ac97_ops = {
- .read = s3c_ac97_read,
- .write = s3c_ac97_write,
- .warm_reset = s3c_ac97_warm_reset,
- .reset = s3c_ac97_cold_reset,
-};
-EXPORT_SYMBOL_GPL(soc_ac97_ops);
-
-static int s3c_ac97_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_dai *cpu_dai = rtd->cpu_dai;
- struct s3c_dma_params *dma_data;
-
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- dma_data = &s3c_ac97_pcm_out;
- else
- dma_data = &s3c_ac97_pcm_in;
-
- snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data);
-
- return 0;
-}
-
-static int s3c_ac97_trigger(struct snd_pcm_substream *substream, int cmd,
- struct snd_soc_dai *dai)
-{
- u32 ac_glbctrl;
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct s3c_dma_params *dma_data =
- snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
-
- ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
- if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
- ac_glbctrl &= ~S3C_AC97_GLBCTRL_PCMINTM_MASK;
- else
- ac_glbctrl &= ~S3C_AC97_GLBCTRL_PCMOUTTM_MASK;
-
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
- case SNDRV_PCM_TRIGGER_RESUME:
- case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
- ac_glbctrl |= S3C_AC97_GLBCTRL_PCMINTM_DMA;
- else
- ac_glbctrl |= S3C_AC97_GLBCTRL_PCMOUTTM_DMA;
- break;
-
- case SNDRV_PCM_TRIGGER_STOP:
- case SNDRV_PCM_TRIGGER_SUSPEND:
- case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- break;
- }
-
- writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
-
- s3c2410_dma_ctrl(dma_data->channel, S3C2410_DMAOP_STARTED);
-
- return 0;
-}
-
-static int s3c_ac97_hw_mic_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_dai *cpu_dai = rtd->cpu_dai;
-
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- return -ENODEV;
- else
- snd_soc_dai_set_dma_data(cpu_dai, substream, &s3c_ac97_mic_in);
-
- return 0;
-}
-
-static int s3c_ac97_mic_trigger(struct snd_pcm_substream *substream,
- int cmd, struct snd_soc_dai *dai)
-{
- u32 ac_glbctrl;
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct s3c_dma_params *dma_data =
- snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
-
- ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
- ac_glbctrl &= ~S3C_AC97_GLBCTRL_MICINTM_MASK;
-
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
- case SNDRV_PCM_TRIGGER_RESUME:
- case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- ac_glbctrl |= S3C_AC97_GLBCTRL_MICINTM_DMA;
- break;
-
- case SNDRV_PCM_TRIGGER_STOP:
- case SNDRV_PCM_TRIGGER_SUSPEND:
- case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- break;
- }
-
- writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
-
- s3c2410_dma_ctrl(dma_data->channel, S3C2410_DMAOP_STARTED);
-
- return 0;
-}
-
-static struct snd_soc_dai_ops s3c_ac97_dai_ops = {
- .hw_params = s3c_ac97_hw_params,
- .trigger = s3c_ac97_trigger,
-};
-
-static struct snd_soc_dai_ops s3c_ac97_mic_dai_ops = {
- .hw_params = s3c_ac97_hw_mic_params,
- .trigger = s3c_ac97_mic_trigger,
-};
-
-static struct snd_soc_dai_driver s3c_ac97_dai[] = {
- [S3C_AC97_DAI_PCM] = {
- .name = "samsung-ac97",
- .ac97_control = 1,
- .playback = {
- .stream_name = "AC97 Playback",
- .channels_min = 2,
- .channels_max = 2,
- .rates = SNDRV_PCM_RATE_8000_48000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,},
- .capture = {
- .stream_name = "AC97 Capture",
- .channels_min = 2,
- .channels_max = 2,
- .rates = SNDRV_PCM_RATE_8000_48000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,},
- .ops = &s3c_ac97_dai_ops,
- },
- [S3C_AC97_DAI_MIC] = {
- .name = "samsung-ac97-mic",
- .ac97_control = 1,
- .capture = {
- .stream_name = "AC97 Mic Capture",
- .channels_min = 1,
- .channels_max = 1,
- .rates = SNDRV_PCM_RATE_8000_48000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,},
- .ops = &s3c_ac97_mic_dai_ops,
- },
-};
-
-static __devinit int s3c_ac97_probe(struct platform_device *pdev)
-{
- struct resource *mem_res, *dmatx_res, *dmarx_res, *dmamic_res, *irq_res;
- struct s3c_audio_pdata *ac97_pdata;
- int ret;
-
- ac97_pdata = pdev->dev.platform_data;
- if (!ac97_pdata || !ac97_pdata->cfg_gpio) {
- dev_err(&pdev->dev, "cfg_gpio callback not provided!\n");
- return -EINVAL;
- }
-
- /* Check for availability of necessary resource */
- dmatx_res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
- if (!dmatx_res) {
- dev_err(&pdev->dev, "Unable to get AC97-TX dma resource\n");
- return -ENXIO;
- }
-
- dmarx_res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
- if (!dmarx_res) {
- dev_err(&pdev->dev, "Unable to get AC97-RX dma resource\n");
- return -ENXIO;
- }
-
- dmamic_res = platform_get_resource(pdev, IORESOURCE_DMA, 2);
- if (!dmamic_res) {
- dev_err(&pdev->dev, "Unable to get AC97-MIC dma resource\n");
- return -ENXIO;
- }
-
- mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!mem_res) {
- dev_err(&pdev->dev, "Unable to get register resource\n");
- return -ENXIO;
- }
-
- irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (!irq_res) {
- dev_err(&pdev->dev, "AC97 IRQ not provided!\n");
- return -ENXIO;
- }
-
- if (!request_mem_region(mem_res->start,
- resource_size(mem_res), "ac97")) {
- dev_err(&pdev->dev, "Unable to request register region\n");
- return -EBUSY;
- }
-
- s3c_ac97_pcm_out.channel = dmatx_res->start;
- s3c_ac97_pcm_out.dma_addr = mem_res->start + S3C_AC97_PCM_DATA;
- s3c_ac97_pcm_in.channel = dmarx_res->start;
- s3c_ac97_pcm_in.dma_addr = mem_res->start + S3C_AC97_PCM_DATA;
- s3c_ac97_mic_in.channel = dmamic_res->start;
- s3c_ac97_mic_in.dma_addr = mem_res->start + S3C_AC97_MIC_DATA;
-
- init_completion(&s3c_ac97.done);
- mutex_init(&s3c_ac97.lock);
-
- s3c_ac97.regs = ioremap(mem_res->start, resource_size(mem_res));
- if (s3c_ac97.regs == NULL) {
- dev_err(&pdev->dev, "Unable to ioremap register region\n");
- ret = -ENXIO;
- goto err1;
- }
-
- s3c_ac97.ac97_clk = clk_get(&pdev->dev, "ac97");
- if (IS_ERR(s3c_ac97.ac97_clk)) {
- dev_err(&pdev->dev, "ac97 failed to get ac97_clock\n");
- ret = -ENODEV;
- goto err2;
- }
- clk_enable(s3c_ac97.ac97_clk);
-
- if (ac97_pdata->cfg_gpio(pdev)) {
- dev_err(&pdev->dev, "Unable to configure gpio\n");
- ret = -EINVAL;
- goto err3;
- }
-
- ret = request_irq(irq_res->start, s3c_ac97_irq,
- IRQF_DISABLED, "AC97", NULL);
- if (ret < 0) {
- dev_err(&pdev->dev, "ac97: interrupt request failed.\n");
- goto err4;
- }
-
- ret = snd_soc_register_dais(&pdev->dev, s3c_ac97_dai,
- ARRAY_SIZE(s3c_ac97_dai));
- if (ret)
- goto err5;
-
- return 0;
-
-err5:
- free_irq(irq_res->start, NULL);
-err4:
-err3:
- clk_disable(s3c_ac97.ac97_clk);
- clk_put(s3c_ac97.ac97_clk);
-err2:
- iounmap(s3c_ac97.regs);
-err1:
- release_mem_region(mem_res->start, resource_size(mem_res));
-
- return ret;
-}
-
-static __devexit int s3c_ac97_remove(struct platform_device *pdev)
-{
- struct resource *mem_res, *irq_res;
-
- snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(s3c_ac97_dai));
-
- irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (irq_res)
- free_irq(irq_res->start, NULL);
-
- clk_disable(s3c_ac97.ac97_clk);
- clk_put(s3c_ac97.ac97_clk);
-
- iounmap(s3c_ac97.regs);
-
- mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (mem_res)
- release_mem_region(mem_res->start, resource_size(mem_res));
-
- return 0;
-}
-
-static struct platform_driver s3c_ac97_driver = {
- .probe = s3c_ac97_probe,
- .remove = s3c_ac97_remove,
- .driver = {
- .name = "samsung-ac97",
- .owner = THIS_MODULE,
- },
-};
-
-static int __init s3c_ac97_init(void)
-{
- return platform_driver_register(&s3c_ac97_driver);
-}
-module_init(s3c_ac97_init);
-
-static void __exit s3c_ac97_exit(void)
-{
- platform_driver_unregister(&s3c_ac97_driver);
-}
-module_exit(s3c_ac97_exit);
-
-MODULE_AUTHOR("Jaswinder Singh, <jassi.brar(a)samsung.com>");
-MODULE_DESCRIPTION("AC97 driver for the Samsung SoC");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:samsung-ac97");
diff --git a/sound/soc/s3c24xx/ac97.h b/sound/soc/s3c24xx/ac97.h
deleted file mode 100644
index a8f01b7..0000000
--- a/sound/soc/s3c24xx/ac97.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/* sound/soc/s3c24xx/ac97.h
- *
- * ALSA SoC Audio Layer - S3C AC97 Controller driver
- * Evolved from s3c2443-ac97.h
- *
- * Copyright (c) 2010 Samsung Electronics Co. Ltd
- * Author: Jaswinder Singh <jassi.brar(a)samsung.com>
- * Credits: Graeme Gregory, Sean Choi
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef __S3C_AC97_H_
-#define __S3C_AC97_H_
-
-#define S3C_AC97_DAI_PCM 0
-#define S3C_AC97_DAI_MIC 1
-
-#endif /* __S3C_AC97_H_ */
diff --git a/sound/soc/s3c24xx/dma.c b/sound/soc/s3c24xx/dma.c
deleted file mode 100644
index 12622f3..0000000
--- a/sound/soc/s3c24xx/dma.c
+++ /dev/null
@@ -1,503 +0,0 @@
-/*
- * dma.c -- ALSA Soc Audio Layer
- *
- * (c) 2006 Wolfson Microelectronics PLC.
- * Graeme Gregory graeme.gregory(a)wolfsonmicro.com or linux(a)wolfsonmicro.com
- *
- * Copyright 2004-2005 Simtec Electronics
- * http://armlinux.simtec.co.uk/
- * Ben Dooks <ben(a)simtec.co.uk>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/dma-mapping.h>
-
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-
-#include <asm/dma.h>
-#include <mach/hardware.h>
-#include <mach/dma.h>
-
-#include "dma.h"
-
-static const struct snd_pcm_hardware dma_hardware = {
- .info = SNDRV_PCM_INFO_INTERLEAVED |
- SNDRV_PCM_INFO_BLOCK_TRANSFER |
- SNDRV_PCM_INFO_MMAP |
- SNDRV_PCM_INFO_MMAP_VALID |
- SNDRV_PCM_INFO_PAUSE |
- SNDRV_PCM_INFO_RESUME,
- .formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_U16_LE |
- SNDRV_PCM_FMTBIT_U8 |
- SNDRV_PCM_FMTBIT_S8,
- .channels_min = 2,
- .channels_max = 2,
- .buffer_bytes_max = 128*1024,
- .period_bytes_min = PAGE_SIZE,
- .period_bytes_max = PAGE_SIZE*2,
- .periods_min = 2,
- .periods_max = 128,
- .fifo_size = 32,
-};
-
-struct runtime_data {
- spinlock_t lock;
- int state;
- unsigned int dma_loaded;
- unsigned int dma_limit;
- unsigned int dma_period;
- dma_addr_t dma_start;
- dma_addr_t dma_pos;
- dma_addr_t dma_end;
- struct s3c_dma_params *params;
-};
-
-/* dma_enqueue
- *
- * place a dma buffer onto the queue for the dma system
- * to handle.
-*/
-static void dma_enqueue(struct snd_pcm_substream *substream)
-{
- struct runtime_data *prtd = substream->runtime->private_data;
- dma_addr_t pos = prtd->dma_pos;
- unsigned int limit;
- int ret;
-
- pr_debug("Entered %s\n", __func__);
-
- if (s3c_dma_has_circular())
- limit = (prtd->dma_end - prtd->dma_start) / prtd->dma_period;
- else
- limit = prtd->dma_limit;
-
- pr_debug("%s: loaded %d, limit %d\n",
- __func__, prtd->dma_loaded, limit);
-
- while (prtd->dma_loaded < limit) {
- unsigned long len = prtd->dma_period;
-
- pr_debug("dma_loaded: %d\n", prtd->dma_loaded);
-
- if ((pos + len) > prtd->dma_end) {
- len = prtd->dma_end - pos;
- pr_debug(KERN_DEBUG "%s: corrected dma len %ld\n",
- __func__, len);
- }
-
- ret = s3c2410_dma_enqueue(prtd->params->channel,
- substream, pos, len);
-
- if (ret == 0) {
- prtd->dma_loaded++;
- pos += prtd->dma_period;
- if (pos >= prtd->dma_end)
- pos = prtd->dma_start;
- } else
- break;
- }
-
- prtd->dma_pos = pos;
-}
-
-static void audio_buffdone(struct s3c2410_dma_chan *channel,
- void *dev_id, int size,
- enum s3c2410_dma_buffresult result)
-{
- struct snd_pcm_substream *substream = dev_id;
- struct runtime_data *prtd;
-
- pr_debug("Entered %s\n", __func__);
-
- if (result == S3C2410_RES_ABORT || result == S3C2410_RES_ERR)
- return;
-
- prtd = substream->runtime->private_data;
-
- if (substream)
- snd_pcm_period_elapsed(substream);
-
- spin_lock(&prtd->lock);
- if (prtd->state & ST_RUNNING && !s3c_dma_has_circular()) {
- prtd->dma_loaded--;
- dma_enqueue(substream);
- }
-
- spin_unlock(&prtd->lock);
-}
-
-static int dma_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
-{
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct runtime_data *prtd = runtime->private_data;
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- unsigned long totbytes = params_buffer_bytes(params);
- struct s3c_dma_params *dma =
- snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
- int ret = 0;
-
-
- pr_debug("Entered %s\n", __func__);
-
- /* return if this is a bufferless transfer e.g.
- * codec <--> BT codec or GSM modem -- lg FIXME */
- if (!dma)
- return 0;
-
- /* this may get called several times by oss emulation
- * with different params -HW */
- if (prtd->params == NULL) {
- /* prepare DMA */
- prtd->params = dma;
-
- pr_debug("params %p, client %p, channel %d\n", prtd->params,
- prtd->params->client, prtd->params->channel);
-
- ret = s3c2410_dma_request(prtd->params->channel,
- prtd->params->client, NULL);
-
- if (ret < 0) {
- printk(KERN_ERR "failed to get dma channel\n");
- return ret;
- }
-
- /* use the circular buffering if we have it available. */
- if (s3c_dma_has_circular())
- s3c2410_dma_setflags(prtd->params->channel,
- S3C2410_DMAF_CIRCULAR);
- }
-
- s3c2410_dma_set_buffdone_fn(prtd->params->channel,
- audio_buffdone);
-
- snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
-
- runtime->dma_bytes = totbytes;
-
- spin_lock_irq(&prtd->lock);
- prtd->dma_loaded = 0;
- prtd->dma_limit = runtime->hw.periods_min;
- prtd->dma_period = params_period_bytes(params);
- prtd->dma_start = runtime->dma_addr;
- prtd->dma_pos = prtd->dma_start;
- prtd->dma_end = prtd->dma_start + totbytes;
- spin_unlock_irq(&prtd->lock);
-
- return 0;
-}
-
-static int dma_hw_free(struct snd_pcm_substream *substream)
-{
- struct runtime_data *prtd = substream->runtime->private_data;
-
- pr_debug("Entered %s\n", __func__);
-
- /* TODO - do we need to ensure DMA flushed */
- snd_pcm_set_runtime_buffer(substream, NULL);
-
- if (prtd->params) {
- s3c2410_dma_free(prtd->params->channel, prtd->params->client);
- prtd->params = NULL;
- }
-
- return 0;
-}
-
-static int dma_prepare(struct snd_pcm_substream *substream)
-{
- struct runtime_data *prtd = substream->runtime->private_data;
- int ret = 0;
-
- pr_debug("Entered %s\n", __func__);
-
- /* return if this is a bufferless transfer e.g.
- * codec <--> BT codec or GSM modem -- lg FIXME */
- if (!prtd->params)
- return 0;
-
- /* channel needs configuring for mem=>device, increment memory addr,
- * sync to pclk, half-word transfers to the IIS-FIFO. */
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- s3c2410_dma_devconfig(prtd->params->channel,
- S3C2410_DMASRC_MEM,
- prtd->params->dma_addr);
- } else {
- s3c2410_dma_devconfig(prtd->params->channel,
- S3C2410_DMASRC_HW,
- prtd->params->dma_addr);
- }
-
- s3c2410_dma_config(prtd->params->channel,
- prtd->params->dma_size);
-
- /* flush the DMA channel */
- s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_FLUSH);
- prtd->dma_loaded = 0;
- prtd->dma_pos = prtd->dma_start;
-
- /* enqueue dma buffers */
- dma_enqueue(substream);
-
- return ret;
-}
-
-static int dma_trigger(struct snd_pcm_substream *substream, int cmd)
-{
- struct runtime_data *prtd = substream->runtime->private_data;
- int ret = 0;
-
- pr_debug("Entered %s\n", __func__);
-
- spin_lock(&prtd->lock);
-
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
- case SNDRV_PCM_TRIGGER_RESUME:
- case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- prtd->state |= ST_RUNNING;
- s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_START);
- break;
-
- case SNDRV_PCM_TRIGGER_STOP:
- case SNDRV_PCM_TRIGGER_SUSPEND:
- case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- prtd->state &= ~ST_RUNNING;
- s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_STOP);
- break;
-
- default:
- ret = -EINVAL;
- break;
- }
-
- spin_unlock(&prtd->lock);
-
- return ret;
-}
-
-static snd_pcm_uframes_t
-dma_pointer(struct snd_pcm_substream *substream)
-{
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct runtime_data *prtd = runtime->private_data;
- unsigned long res;
- dma_addr_t src, dst;
-
- pr_debug("Entered %s\n", __func__);
-
- spin_lock(&prtd->lock);
- s3c2410_dma_getposition(prtd->params->channel, &src, &dst);
-
- if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
- res = dst - prtd->dma_start;
- else
- res = src - prtd->dma_start;
-
- spin_unlock(&prtd->lock);
-
- pr_debug("Pointer %x %x\n", src, dst);
-
- /* we seem to be getting the odd error from the pcm library due
- * to out-of-bounds pointers. this is maybe due to the dma engine
- * not having loaded the new values for the channel before being
- * callled... (todo - fix )
- */
-
- if (res >= snd_pcm_lib_buffer_bytes(substream)) {
- if (res == snd_pcm_lib_buffer_bytes(substream))
- res = 0;
- }
-
- return bytes_to_frames(substream->runtime, res);
-}
-
-static int dma_open(struct snd_pcm_substream *substream)
-{
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct runtime_data *prtd;
-
- pr_debug("Entered %s\n", __func__);
-
- snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
- snd_soc_set_runtime_hwparams(substream, &dma_hardware);
-
- prtd = kzalloc(sizeof(struct runtime_data), GFP_KERNEL);
- if (prtd == NULL)
- return -ENOMEM;
-
- spin_lock_init(&prtd->lock);
-
- runtime->private_data = prtd;
- return 0;
-}
-
-static int dma_close(struct snd_pcm_substream *substream)
-{
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct runtime_data *prtd = runtime->private_data;
-
- pr_debug("Entered %s\n", __func__);
-
- if (!prtd)
- pr_debug("dma_close called with prtd == NULL\n");
-
- kfree(prtd);
-
- return 0;
-}
-
-static int dma_mmap(struct snd_pcm_substream *substream,
- struct vm_area_struct *vma)
-{
- struct snd_pcm_runtime *runtime = substream->runtime;
-
- pr_debug("Entered %s\n", __func__);
-
- return dma_mmap_writecombine(substream->pcm->card->dev, vma,
- runtime->dma_area,
- runtime->dma_addr,
- runtime->dma_bytes);
-}
-
-static struct snd_pcm_ops dma_ops = {
- .open = dma_open,
- .close = dma_close,
- .ioctl = snd_pcm_lib_ioctl,
- .hw_params = dma_hw_params,
- .hw_free = dma_hw_free,
- .prepare = dma_prepare,
- .trigger = dma_trigger,
- .pointer = dma_pointer,
- .mmap = dma_mmap,
-};
-
-static int preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
-{
- struct snd_pcm_substream *substream = pcm->streams[stream].substream;
- struct snd_dma_buffer *buf = &substream->dma_buffer;
- size_t size = dma_hardware.buffer_bytes_max;
-
- pr_debug("Entered %s\n", __func__);
-
- buf->dev.type = SNDRV_DMA_TYPE_DEV;
- buf->dev.dev = pcm->card->dev;
- buf->private_data = NULL;
- buf->area = dma_alloc_writecombine(pcm->card->dev, size,
- &buf->addr, GFP_KERNEL);
- if (!buf->area)
- return -ENOMEM;
- buf->bytes = size;
- return 0;
-}
-
-static void dma_free_dma_buffers(struct snd_pcm *pcm)
-{
- struct snd_pcm_substream *substream;
- struct snd_dma_buffer *buf;
- int stream;
-
- pr_debug("Entered %s\n", __func__);
-
- for (stream = 0; stream < 2; stream++) {
- substream = pcm->streams[stream].substream;
- if (!substream)
- continue;
-
- buf = &substream->dma_buffer;
- if (!buf->area)
- continue;
-
- dma_free_writecombine(pcm->card->dev, buf->bytes,
- buf->area, buf->addr);
- buf->area = NULL;
- }
-}
-
-static u64 dma_mask = DMA_BIT_MASK(32);
-
-static int dma_new(struct snd_card *card,
- struct snd_soc_dai *dai, struct snd_pcm *pcm)
-{
- int ret = 0;
-
- pr_debug("Entered %s\n", __func__);
-
- if (!card->dev->dma_mask)
- card->dev->dma_mask = &dma_mask;
- if (!card->dev->coherent_dma_mask)
- card->dev->coherent_dma_mask = 0xffffffff;
-
- if (dai->driver->playback.channels_min) {
- ret = preallocate_dma_buffer(pcm,
- SNDRV_PCM_STREAM_PLAYBACK);
- if (ret)
- goto out;
- }
-
- if (dai->driver->capture.channels_min) {
- ret = preallocate_dma_buffer(pcm,
- SNDRV_PCM_STREAM_CAPTURE);
- if (ret)
- goto out;
- }
-out:
- return ret;
-}
-
-static struct snd_soc_platform_driver samsung_asoc_platform = {
- .ops = &dma_ops,
- .pcm_new = dma_new,
- .pcm_free = dma_free_dma_buffers,
-};
-
-static int __devinit samsung_asoc_platform_probe(struct platform_device *pdev)
-{
- return snd_soc_register_platform(&pdev->dev, &samsung_asoc_platform);
-}
-
-static int __devexit samsung_asoc_platform_remove(struct platform_device *pdev)
-{
- snd_soc_unregister_platform(&pdev->dev);
- return 0;
-}
-
-static struct platform_driver asoc_dma_driver = {
- .driver = {
- .name = "samsung-audio",
- .owner = THIS_MODULE,
- },
-
- .probe = samsung_asoc_platform_probe,
- .remove = __devexit_p(samsung_asoc_platform_remove),
-};
-
-static int __init samsung_asoc_init(void)
-{
- return platform_driver_register(&asoc_dma_driver);
-}
-module_init(samsung_asoc_init);
-
-static void __exit samsung_asoc_exit(void)
-{
- platform_driver_unregister(&asoc_dma_driver);
-}
-module_exit(samsung_asoc_exit);
-
-MODULE_AUTHOR("Ben Dooks, <ben(a)simtec.co.uk>");
-MODULE_DESCRIPTION("Samsung ASoC DMA Driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:samsung-audio");
diff --git a/sound/soc/s3c24xx/dma.h b/sound/soc/s3c24xx/dma.h
deleted file mode 100644
index f8cd2b4..0000000
--- a/sound/soc/s3c24xx/dma.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * dma.h --
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * ALSA PCM interface for the Samsung S3C24xx CPU
- */
-
-#ifndef _S3C_AUDIO_H
-#define _S3C_AUDIO_H
-
-#define ST_RUNNING (1<<0)
-#define ST_OPENED (1<<1)
-
-struct s3c_dma_params {
- struct s3c2410_dma_client *client; /* stream identifier */
- int channel; /* Channel ID */
- dma_addr_t dma_addr;
- int dma_size; /* Size of the DMA transfer */
-};
-
-#define S3C24XX_DAI_I2S 0
-
-/* platform data */
-extern struct snd_ac97_bus_ops s3c24xx_ac97_ops;
-
-#endif
diff --git a/sound/soc/s3c24xx/goni_wm8994.c b/sound/soc/s3c24xx/goni_wm8994.c
deleted file mode 100644
index dcaf7c3..0000000
--- a/sound/soc/s3c24xx/goni_wm8994.c
+++ /dev/null
@@ -1,309 +0,0 @@
-/*
- * goni_wm8994.c
- *
- * Copyright (C) 2010 Samsung Electronics Co.Ltd
- * Author: Chanwoo Choi <cw00.choi(a)samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/io.h>
-#include <linux/platform_device.h>
-#include <sound/soc.h>
-#include <sound/soc-dapm.h>
-#include <sound/jack.h>
-#include <asm/mach-types.h>
-#include <mach/gpio.h>
-#include <mach/regs-clock.h>
-
-#include <linux/mfd/wm8994/core.h>
-#include <linux/mfd/wm8994/registers.h>
-#include "../codecs/wm8994.h"
-#include "dma.h"
-#include "i2s.h"
-
-#define MACHINE_NAME 0
-#define CPU_VOICE_DAI 1
-
-static const char *aquila_str[] = {
- [MACHINE_NAME] = "aquila",
- [CPU_VOICE_DAI] = "aquila-voice-dai",
-};
-
-static struct snd_soc_card goni;
-static struct platform_device *goni_snd_device;
-
-/* 3.5 pie jack */
-static struct snd_soc_jack jack;
-
-/* 3.5 pie jack detection DAPM pins */
-static struct snd_soc_jack_pin jack_pins[] = {
- {
- .pin = "Headset Mic",
- .mask = SND_JACK_MICROPHONE,
- }, {
- .pin = "Headset Stereophone",
- .mask = SND_JACK_HEADPHONE | SND_JACK_MECHANICAL |
- SND_JACK_AVOUT,
- },
-};
-
-/* 3.5 pie jack detection gpios */
-static struct snd_soc_jack_gpio jack_gpios[] = {
- {
- .gpio = S5PV210_GPH0(6),
- .name = "DET_3.5",
- .report = SND_JACK_HEADSET | SND_JACK_MECHANICAL |
- SND_JACK_AVOUT,
- .debounce_time = 200,
- },
-};
-
-static const struct snd_soc_dapm_widget goni_dapm_widgets[] = {
- SND_SOC_DAPM_SPK("Ext Left Spk", NULL),
- SND_SOC_DAPM_SPK("Ext Right Spk", NULL),
- SND_SOC_DAPM_SPK("Ext Rcv", NULL),
- SND_SOC_DAPM_HP("Headset Stereophone", NULL),
- SND_SOC_DAPM_MIC("Headset Mic", NULL),
- SND_SOC_DAPM_MIC("Main Mic", NULL),
- SND_SOC_DAPM_MIC("2nd Mic", NULL),
- SND_SOC_DAPM_LINE("Radio In", NULL),
-};
-
-static const struct snd_soc_dapm_route goni_dapm_routes[] = {
- {"Ext Left Spk", NULL, "SPKOUTLP"},
- {"Ext Left Spk", NULL, "SPKOUTLN"},
-
- {"Ext Right Spk", NULL, "SPKOUTRP"},
- {"Ext Right Spk", NULL, "SPKOUTRN"},
-
- {"Ext Rcv", NULL, "HPOUT2N"},
- {"Ext Rcv", NULL, "HPOUT2P"},
-
- {"Headset Stereophone", NULL, "HPOUT1L"},
- {"Headset Stereophone", NULL, "HPOUT1R"},
-
- {"IN1RN", NULL, "Headset Mic"},
- {"IN1RP", NULL, "Headset Mic"},
-
- {"IN1RN", NULL, "2nd Mic"},
- {"IN1RP", NULL, "2nd Mic"},
-
- {"IN1LN", NULL, "Main Mic"},
- {"IN1LP", NULL, "Main Mic"},
-
- {"IN2LN", NULL, "Radio In"},
- {"IN2RN", NULL, "Radio In"},
-};
-
-static int goni_wm8994_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_soc_codec *codec = rtd->codec;
- int ret;
-
- /* add goni specific widgets */
- snd_soc_dapm_new_controls(codec, goni_dapm_widgets,
- ARRAY_SIZE(goni_dapm_widgets));
-
- /* set up goni specific audio routes */
- snd_soc_dapm_add_routes(codec, goni_dapm_routes,
- ARRAY_SIZE(goni_dapm_routes));
-
- /* set endpoints to not connected */
- snd_soc_dapm_nc_pin(codec, "IN2LP:VXRN");
- snd_soc_dapm_nc_pin(codec, "IN2RP:VXRP");
- snd_soc_dapm_nc_pin(codec, "LINEOUT1N");
- snd_soc_dapm_nc_pin(codec, "LINEOUT1P");
- snd_soc_dapm_nc_pin(codec, "LINEOUT2N");
- snd_soc_dapm_nc_pin(codec, "LINEOUT2P");
-
- if (machine_is_aquila()) {
- snd_soc_dapm_nc_pin(codec, "SPKOUTRN");
- snd_soc_dapm_nc_pin(codec, "SPKOUTRP");
- }
-
- snd_soc_dapm_sync(codec);
-
- /* Headset jack detection */
- ret = snd_soc_jack_new(&goni, "Headset Jack",
- SND_JACK_HEADSET | SND_JACK_MECHANICAL | SND_JACK_AVOUT,
- &jack);
- if (ret)
- return ret;
-
- ret = snd_soc_jack_add_pins(&jack, ARRAY_SIZE(jack_pins), jack_pins);
- if (ret)
- return ret;
-
- ret = snd_soc_jack_add_gpios(&jack, ARRAY_SIZE(jack_gpios), jack_gpios);
- if (ret)
- return ret;
-
- return 0;
-}
-
-static int goni_hifi_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
-{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- unsigned int pll_out = 24000000;
- int ret = 0;
-
- /* set the cpu DAI configuration */
- ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
- if (ret < 0)
- return ret;
-
- /* set codec DAI configuration */
- ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
- if (ret < 0)
- return ret;
-
- /* set the codec FLL */
- ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL1, 0, pll_out,
- params_rate(params) * 256);
- if (ret < 0)
- return ret;
-
- /* set the codec system clock */
- ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_FLL1,
- params_rate(params) * 256, SND_SOC_CLOCK_IN);
- if (ret < 0)
- return ret;
-
- return 0;
-}
-
-static struct snd_soc_ops goni_hifi_ops = {
- .hw_params = goni_hifi_hw_params,
-};
-
-static int goni_voice_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
-{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->codec_dai;
- unsigned int pll_out = 24000000;
- int ret = 0;
-
- if (params_rate(params) != 8000)
- return -EINVAL;
-
- /* set codec DAI configuration */
- ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_LEFT_J |
- SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_CBM_CFM);
- if (ret < 0)
- return ret;
-
- /* set the codec FLL */
- ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL2, 0, pll_out,
- params_rate(params) * 256);
- if (ret < 0)
- return ret;
-
- /* set the codec system clock */
- ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_FLL2,
- params_rate(params) * 256, SND_SOC_CLOCK_IN);
- if (ret < 0)
- return ret;
-
- return 0;
-}
-
-static struct snd_soc_dai_driver voice_dai = {
- .name = "goni-voice-dai",
- .id = 0,
- .playback = {
- .channels_min = 1,
- .channels_max = 2,
- .rates = SNDRV_PCM_RATE_8000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,},
- .capture = {
- .channels_min = 1,
- .channels_max = 2,
- .rates = SNDRV_PCM_RATE_8000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,},
-};
-
-static struct snd_soc_ops goni_voice_ops = {
- .hw_params = goni_voice_hw_params,
-};
-
-static struct snd_soc_dai_link goni_dai[] = {
-{
- .name = "WM8994",
- .stream_name = "WM8994 HiFi",
- .cpu_dai_name = "samsung-i2s.0",
- .codec_dai_name = "wm8994-hifi",
- .platform_name = "samsung-audio",
- .codec_name = "wm8994-codec.0-0x1a",
- .init = goni_wm8994_init,
- .ops = &goni_hifi_ops,
-}, {
- .name = "WM8994 Voice",
- .stream_name = "Voice",
- .cpu_dai_name = "goni-voice-dai",
- .codec_dai_name = "wm8994-voice",
- .platform_name = "samsung-audio",
- .codec_name = "wm8994-codec.0-0x1a",
- .ops = &goni_voice_ops,
-},
-};
-
-static struct snd_soc_card goni = {
- .name = "goni",
- .dai_link = goni_dai,
- .num_links = ARRAY_SIZE(goni_dai),
-};
-
-static int __init goni_init(void)
-{
- int ret;
-
- if (machine_is_aquila()) {
- voice_dai.name = aquila_str[CPU_VOICE_DAI];
- goni_dai[1].cpu_dai_name = aquila_str[CPU_VOICE_DAI];
- goni.name = aquila_str[MACHINE_NAME];
- } else if (!machine_is_goni())
- return -ENODEV;
-
- goni_snd_device = platform_device_alloc("soc-audio", -1);
- if (!goni_snd_device)
- return -ENOMEM;
-
- /* register voice DAI here */
- ret = snd_soc_register_dai(&goni_snd_device->dev, &voice_dai);
- if (ret)
- return ret;
-
- platform_set_drvdata(goni_snd_device, &goni);
- ret = platform_device_add(goni_snd_device);
-
- if (ret)
- platform_device_put(goni_snd_device);
-
- return ret;
-}
-
-static void __exit goni_exit(void)
-{
- platform_device_unregister(goni_snd_device);
-}
-
-module_init(goni_init);
-module_exit(goni_exit);
-
-/* Module information */
-MODULE_DESCRIPTION("ALSA SoC WM8994 GONI(S5PV210)");
-MODULE_AUTHOR("Chanwoo Choi <cw00.choi(a)samsung.com>");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/i2s.c b/sound/soc/s3c24xx/i2s.c
deleted file mode 100644
index 6869f51..0000000
--- a/sound/soc/s3c24xx/i2s.c
+++ /dev/null
@@ -1,1251 +0,0 @@
-/* sound/soc/s3c24xx/i2s.c
- *
- * ALSA SoC Audio Layer - Samsung I2S Controller driver
- *
- * Copyright (c) 2010 Samsung Electronics Co. Ltd.
- * Jaswinder Singh <jassi.brar(a)samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-
-#include <plat/audio.h>
-
-#include "dma.h"
-#include "i2s.h"
-
-#define I2SCON 0x0
-#define I2SMOD 0x4
-#define I2SFIC 0x8
-#define I2SPSR 0xc
-#define I2STXD 0x10
-#define I2SRXD 0x14
-#define I2SFICS 0x18
-#define I2STXDS 0x1c
-
-#define CON_RSTCLR (1 << 31)
-#define CON_FRXOFSTATUS (1 << 26)
-#define CON_FRXORINTEN (1 << 25)
-#define CON_FTXSURSTAT (1 << 24)
-#define CON_FTXSURINTEN (1 << 23)
-#define CON_TXSDMA_PAUSE (1 << 20)
-#define CON_TXSDMA_ACTIVE (1 << 18)
-
-#define CON_FTXURSTATUS (1 << 17)
-#define CON_FTXURINTEN (1 << 16)
-#define CON_TXFIFO2_EMPTY (1 << 15)
-#define CON_TXFIFO1_EMPTY (1 << 14)
-#define CON_TXFIFO2_FULL (1 << 13)
-#define CON_TXFIFO1_FULL (1 << 12)
-
-#define CON_LRINDEX (1 << 11)
-#define CON_TXFIFO_EMPTY (1 << 10)
-#define CON_RXFIFO_EMPTY (1 << 9)
-#define CON_TXFIFO_FULL (1 << 8)
-#define CON_RXFIFO_FULL (1 << 7)
-#define CON_TXDMA_PAUSE (1 << 6)
-#define CON_RXDMA_PAUSE (1 << 5)
-#define CON_TXCH_PAUSE (1 << 4)
-#define CON_RXCH_PAUSE (1 << 3)
-#define CON_TXDMA_ACTIVE (1 << 2)
-#define CON_RXDMA_ACTIVE (1 << 1)
-#define CON_ACTIVE (1 << 0)
-
-#define MOD_OPCLK_CDCLK_OUT (0 << 30)
-#define MOD_OPCLK_CDCLK_IN (1 << 30)
-#define MOD_OPCLK_BCLK_OUT (2 << 30)
-#define MOD_OPCLK_PCLK (3 << 30)
-#define MOD_OPCLK_MASK (3 << 30)
-#define MOD_TXS_IDMA (1 << 28) /* Sec_TXFIFO use I-DMA */
-
-#define MOD_BLCS_SHIFT 26
-#define MOD_BLCS_16BIT (0 << MOD_BLCS_SHIFT)
-#define MOD_BLCS_8BIT (1 << MOD_BLCS_SHIFT)
-#define MOD_BLCS_24BIT (2 << MOD_BLCS_SHIFT)
-#define MOD_BLCS_MASK (3 << MOD_BLCS_SHIFT)
-#define MOD_BLCP_SHIFT 24
-#define MOD_BLCP_16BIT (0 << MOD_BLCP_SHIFT)
-#define MOD_BLCP_8BIT (1 << MOD_BLCP_SHIFT)
-#define MOD_BLCP_24BIT (2 << MOD_BLCP_SHIFT)
-#define MOD_BLCP_MASK (3 << MOD_BLCP_SHIFT)
-
-#define MOD_C2DD_HHALF (1 << 21) /* Discard Higher-half */
-#define MOD_C2DD_LHALF (1 << 20) /* Discard Lower-half */
-#define MOD_C1DD_HHALF (1 << 19)
-#define MOD_C1DD_LHALF (1 << 18)
-#define MOD_DC2_EN (1 << 17)
-#define MOD_DC1_EN (1 << 16)
-#define MOD_BLC_16BIT (0 << 13)
-#define MOD_BLC_8BIT (1 << 13)
-#define MOD_BLC_24BIT (2 << 13)
-#define MOD_BLC_MASK (3 << 13)
-
-#define MOD_IMS_SYSMUX (1 << 10)
-#define MOD_SLAVE (1 << 11)
-#define MOD_TXONLY (0 << 8)
-#define MOD_RXONLY (1 << 8)
-#define MOD_TXRX (2 << 8)
-#define MOD_MASK (3 << 8)
-#define MOD_LR_LLOW (0 << 7)
-#define MOD_LR_RLOW (1 << 7)
-#define MOD_SDF_IIS (0 << 5)
-#define MOD_SDF_MSB (1 << 5)
-#define MOD_SDF_LSB (2 << 5)
-#define MOD_SDF_MASK (3 << 5)
-#define MOD_RCLK_256FS (0 << 3)
-#define MOD_RCLK_512FS (1 << 3)
-#define MOD_RCLK_384FS (2 << 3)
-#define MOD_RCLK_768FS (3 << 3)
-#define MOD_RCLK_MASK (3 << 3)
-#define MOD_BCLK_32FS (0 << 1)
-#define MOD_BCLK_48FS (1 << 1)
-#define MOD_BCLK_16FS (2 << 1)
-#define MOD_BCLK_24FS (3 << 1)
-#define MOD_BCLK_MASK (3 << 1)
-#define MOD_8BIT (1 << 0)
-
-#define MOD_CDCLKCON (1 << 12)
-
-#define PSR_PSREN (1 << 15)
-
-#define FIC_TX2COUNT(x) (((x) >> 24) & 0xf)
-#define FIC_TX1COUNT(x) (((x) >> 16) & 0xf)
-
-#define FIC_TXFLUSH (1 << 15)
-#define FIC_RXFLUSH (1 << 7)
-#define FIC_TXCOUNT(x) (((x) >> 8) & 0xf)
-#define FIC_RXCOUNT(x) (((x) >> 0) & 0xf)
-#define FICS_TXCOUNT(x) (((x) >> 8) & 0x7f)
-
-#define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t)
-
-struct i2s_dai {
- /* Platform device for this DAI */
- struct platform_device *pdev;
- /* IOREMAP'd SFRs */
- void __iomem *addr;
- /* Physical base address of SFRs */
- u32 base;
- /* Rate of RCLK source clock */
- unsigned long rclk_srcrate;
- /* Frame Clock */
- unsigned frmclk;
- /*
- * Specifically requested RCLK,BCLK by MACHINE Driver.
- * 0 indicates CPU driver is free to choose any value.
- */
- unsigned rfs, bfs;
- /* I2S Controller's core clock */
- struct clk *clk;
- /* Clock for generating I2S signals */
- struct clk *op_clk;
- /* Array of clock names for op_clk */
- const char **src_clk;
- /* Pointer to the Primary_Fifo if this is Sec_Fifo, NULL otherwise */
- struct i2s_dai *pri_dai;
- /* Pointer to the Secondary_Fifo if it has one, NULL otherwise */
- struct i2s_dai *sec_dai;
-#define DAI_OPENED (1 << 0) /* Dai is opened */
-#define DAI_MANAGER (1 << 1) /* Dai is the manager */
- unsigned mode;
- /* Driver for this DAI */
- struct snd_soc_dai_driver s3c_i2s_drv;
- /* DMA parameters */
- struct s3c_dma_params dma_playback;
- struct s3c_dma_params dma_capture;
- u32 quirks;
- u32 suspend_i2smod;
- u32 suspend_i2scon;
- u32 suspend_i2spsr;
-};
-
-/* Lock for cross i/f checks */
-static DEFINE_SPINLOCK(lock);
-
-/* If this is the 'overlay' stereo DAI */
-static inline bool is_secondary(struct i2s_dai *i2s)
-{
- return i2s->pri_dai ? true : false;
-}
-
-/* If operating in SoC-Slave mode */
-static inline bool is_slave(struct i2s_dai *i2s)
-{
- return (readl(i2s->addr + I2SMOD) & MOD_SLAVE) ? true : false;
-}
-
-/* If this interface of the controller is transmitting data */
-static inline bool tx_active(struct i2s_dai *i2s)
-{
- u32 active;
-
- if (!i2s)
- return false;
-
- active = readl(i2s->addr + I2SMOD);
-
- if (is_secondary(i2s))
- active &= CON_TXSDMA_ACTIVE;
- else
- active &= CON_TXDMA_ACTIVE;
-
- return active ? true : false;
-}
-
-/* If the other interface of the controller is transmitting data */
-static inline bool other_tx_active(struct i2s_dai *i2s)
-{
- struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
-
- return tx_active(other);
-}
-
-/* If any interface of the controller is transmitting data */
-static inline bool any_tx_active(struct i2s_dai *i2s)
-{
- return tx_active(i2s) || other_tx_active(i2s);
-}
-
-/* If this interface of the controller is receiving data */
-static inline bool rx_active(struct i2s_dai *i2s)
-{
- u32 active;
-
- if (!i2s)
- return false;
-
- active = readl(i2s->addr + I2SMOD) & CON_RXDMA_ACTIVE;
-
- return active ? true : false;
-}
-
-/* If the other interface of the controller is receiving data */
-static inline bool other_rx_active(struct i2s_dai *i2s)
-{
- struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
-
- return rx_active(other);
-}
-
-/* If any interface of the controller is receiving data */
-static inline bool any_rx_active(struct i2s_dai *i2s)
-{
- return rx_active(i2s) || other_rx_active(i2s);
-}
-
-/* If the other DAI is transmitting or receiving data */
-static inline bool other_active(struct i2s_dai *i2s)
-{
- return other_rx_active(i2s) || other_tx_active(i2s);
-}
-
-/* If this DAI is transmitting or receiving data */
-static inline bool this_active(struct i2s_dai *i2s)
-{
- return tx_active(i2s) || rx_active(i2s);
-}
-
-/* If the controller is active anyway */
-static inline bool any_active(struct i2s_dai *i2s)
-{
- return this_active(i2s) || other_active(i2s);
-}
-
-static inline struct i2s_dai *to_info(struct snd_soc_dai *dai)
-{
- return snd_soc_dai_get_drvdata(dai);
-}
-
-static inline bool is_opened(struct i2s_dai *i2s)
-{
- if (i2s && (i2s->mode & DAI_OPENED))
- return true;
- else
- return false;
-}
-
-static inline bool is_manager(struct i2s_dai *i2s)
-{
- if (is_opened(i2s) && (i2s->mode & DAI_MANAGER))
- return true;
- else
- return false;
-}
-
-/* Read RCLK of I2S (in multiples of LRCLK) */
-static inline unsigned get_rfs(struct i2s_dai *i2s)
-{
- u32 rfs = (readl(i2s->addr + I2SMOD) >> 3) & 0x3;
-
- switch (rfs) {
- case 3: return 768;
- case 2: return 384;
- case 1: return 512;
- default: return 256;
- }
-}
-
-/* Write RCLK of I2S (in multiples of LRCLK) */
-static inline void set_rfs(struct i2s_dai *i2s, unsigned rfs)
-{
- u32 mod = readl(i2s->addr + I2SMOD);
-
- mod &= ~MOD_RCLK_MASK;
-
- switch (rfs) {
- case 768:
- mod |= MOD_RCLK_768FS;
- break;
- case 512:
- mod |= MOD_RCLK_512FS;
- break;
- case 384:
- mod |= MOD_RCLK_384FS;
- break;
- default:
- mod |= MOD_RCLK_256FS;
- break;
- }
-
- writel(mod, i2s->addr + I2SMOD);
-}
-
-/* Read Bit-Clock of I2S (in multiples of LRCLK) */
-static inline unsigned get_bfs(struct i2s_dai *i2s)
-{
- u32 bfs = (readl(i2s->addr + I2SMOD) >> 1) & 0x3;
-
- switch (bfs) {
- case 3: return 24;
- case 2: return 16;
- case 1: return 48;
- default: return 32;
- }
-}
-
-/* Write Bit-Clock of I2S (in multiples of LRCLK) */
-static inline void set_bfs(struct i2s_dai *i2s, unsigned bfs)
-{
- u32 mod = readl(i2s->addr + I2SMOD);
-
- mod &= ~MOD_BCLK_MASK;
-
- switch (bfs) {
- case 48:
- mod |= MOD_BCLK_48FS;
- break;
- case 32:
- mod |= MOD_BCLK_32FS;
- break;
- case 24:
- mod |= MOD_BCLK_24FS;
- break;
- default:
- mod |= MOD_BCLK_16FS;
- break;
- }
-
- writel(mod, i2s->addr + I2SMOD);
-}
-
-/* Sample-Size */
-static inline int get_blc(struct i2s_dai *i2s)
-{
- int blc = readl(i2s->addr + I2SMOD);
-
- blc = (blc >> 13) & 0x3;
-
- switch (blc) {
- case 2: return 24;
- case 1: return 8;
- default: return 16;
- }
-}
-
-/* TX Channel Control */
-static void s3c_i2sv2_txctrl(struct i2s_dai *i2s, int on)
-{
- void __iomem *addr = i2s->addr;
- u32 con = readl(addr + I2SCON);
- u32 mod = readl(addr + I2SMOD) & ~MOD_MASK;
-
- if (on) {
- con |= CON_ACTIVE;
- con &= ~CON_TXCH_PAUSE;
-
- if (is_secondary(i2s)) {
- con |= CON_TXSDMA_ACTIVE;
- con &= ~CON_TXSDMA_PAUSE;
- } else {
- con |= CON_TXDMA_ACTIVE;
- con &= ~CON_TXDMA_PAUSE;
- }
-
- if (any_rx_active(i2s))
- mod |= MOD_TXRX;
- else
- mod |= MOD_TXONLY;
- } else {
- if (is_secondary(i2s)) {
- con |= CON_TXSDMA_PAUSE;
- con &= ~CON_TXSDMA_ACTIVE;
- } else {
- con |= CON_TXDMA_PAUSE;
- con &= ~CON_TXDMA_ACTIVE;
- }
-
- if (other_tx_active(i2s)) {
- writel(con, addr + I2SCON);
- return;
- }
-
- con |= CON_TXCH_PAUSE;
-
- if (any_rx_active(i2s))
- mod |= MOD_RXONLY;
- else
- con &= ~CON_ACTIVE;
- }
-
- writel(mod, addr + I2SMOD);
- writel(con, addr + I2SCON);
-}
-
-/* RX Channel Control */
-static void s3c_i2sv2_rxctrl(struct i2s_dai *i2s, int on)
-{
- void __iomem *addr = i2s->addr;
- u32 con = readl(addr + I2SCON);
- u32 mod = readl(addr + I2SMOD) & ~MOD_MASK;
-
- if (on) {
- con |= CON_RXDMA_ACTIVE | CON_ACTIVE;
- con &= ~(CON_RXDMA_PAUSE | CON_RXCH_PAUSE);
-
- if (any_tx_active(i2s))
- mod |= MOD_TXRX;
- else
- mod |= MOD_RXONLY;
- } else {
- con |= CON_RXDMA_PAUSE | CON_RXCH_PAUSE;
- con &= ~CON_RXDMA_ACTIVE;
-
- if (any_tx_active(i2s))
- mod |= MOD_TXONLY;
- else
- con &= ~CON_ACTIVE;
- }
-
- writel(mod, addr + I2SMOD);
- writel(con, addr + I2SCON);
-}
-
-/* Flush FIFO of an interface */
-static inline void s3c_i2sv2_fifo(struct i2s_dai *i2s, u32 flush)
-{
- void __iomem *fic;
- u32 val;
-
- if (!i2s)
- return;
-
- if (is_secondary(i2s))
- fic = i2s->addr + I2SFICS;
- else
- fic = i2s->addr + I2SFIC;
-
- /* Flush the FIFO */
- writel(readl(fic) | flush, fic);
-
- /* Be patient */
- val = msecs_to_loops(1) / 1000; /* 1 usec */
- while (--val)
- cpu_relax();
-
- writel(readl(fic) & ~flush, fic);
-}
-
-static int s3c_i2sv2_set_sysclk(struct snd_soc_dai *dai,
- int clk_id, unsigned int rfs, int dir)
-{
- struct i2s_dai *i2s = to_info(dai);
- struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
- u32 mod = readl(i2s->addr + I2SMOD);
-
- switch (clk_id) {
- case SAMSUNG_I2S_CDCLK:
- /* Shouldn't matter in GATING(CLOCK_IN) mode */
- if (dir == SND_SOC_CLOCK_IN)
- rfs = 0;
-
- if ((rfs && other->rfs && (other->rfs != rfs)) ||
- (any_active(i2s) &&
- (((dir == SND_SOC_CLOCK_IN)
- && !(mod & MOD_CDCLKCON)) ||
- ((dir == SND_SOC_CLOCK_OUT)
- && (mod & MOD_CDCLKCON))))) {
- dev_err(&i2s->pdev->dev,
- "%s:%d Other DAI busy\n", __func__, __LINE__);
- return -EAGAIN;
- }
-
- if (dir == SND_SOC_CLOCK_IN)
- mod |= MOD_CDCLKCON;
- else
- mod &= ~MOD_CDCLKCON;
-
- i2s->rfs = rfs;
- break;
-
- case SAMSUNG_I2S_RCLKSRC_0: /* clock corrsponding to IISMOD[10] := 0 */
- case SAMSUNG_I2S_RCLKSRC_1: /* clock corrsponding to IISMOD[10] := 1 */
- if ((i2s->quirks & QUIRK_NO_MUXPSR)
- || (clk_id == SAMSUNG_I2S_RCLKSRC_0))
- clk_id = 0;
- else
- clk_id = 1;
-
- if (!any_active(i2s)) {
- if (i2s->op_clk) {
- if ((clk_id && !(mod & MOD_IMS_SYSMUX)) ||
- (!clk_id && (mod & MOD_IMS_SYSMUX))) {
- clk_disable(i2s->op_clk);
- clk_put(i2s->op_clk);
- } else {
- return 0;
- }
- }
-
- i2s->op_clk = clk_get(&i2s->pdev->dev,
- i2s->src_clk[clk_id]);
- clk_enable(i2s->op_clk);
- i2s->rclk_srcrate = clk_get_rate(i2s->op_clk);
-
- /* Over-ride the other's */
- if (other) {
- other->op_clk = i2s->op_clk;
- other->rclk_srcrate = i2s->rclk_srcrate;
- }
- } else if ((!clk_id && (mod & MOD_IMS_SYSMUX))
- || (clk_id && !(mod & MOD_IMS_SYSMUX))) {
- dev_err(&i2s->pdev->dev,
- "%s:%d Other DAI busy\n", __func__, __LINE__);
- return -EAGAIN;
- } else {
- /* Call can't be on the active DAI */
- i2s->op_clk = other->op_clk;
- i2s->rclk_srcrate = other->rclk_srcrate;
- return 0;
- }
-
- if (clk_id == 0)
- mod &= ~MOD_IMS_SYSMUX;
- else
- mod |= MOD_IMS_SYSMUX;
- break;
-
- default:
- dev_err(&i2s->pdev->dev, "We don't serve that!\n");
- return -EINVAL;
- }
-
- writel(mod, i2s->addr + I2SMOD);
-
- return 0;
-}
-
-static int i2sv2_i2s_set_fmt(struct snd_soc_dai *dai,
- unsigned int fmt)
-{
- struct i2s_dai *i2s = to_info(dai);
- u32 mod = readl(i2s->addr + I2SMOD);
- u32 tmp = 0;
-
- /* Format is priority */
- switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
- case SND_SOC_DAIFMT_RIGHT_J:
- tmp |= MOD_LR_RLOW;
- tmp |= MOD_SDF_MSB;
- break;
- case SND_SOC_DAIFMT_LEFT_J:
- tmp |= MOD_LR_RLOW;
- tmp |= MOD_SDF_LSB;
- break;
- case SND_SOC_DAIFMT_I2S:
- tmp |= MOD_SDF_IIS;
- break;
- default:
- dev_err(&i2s->pdev->dev, "Format not supported\n");
- return -EINVAL;
- }
-
- /* Allow LRCLK-inverted version of the supported formats */
- switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
- case SND_SOC_DAIFMT_NB_NF:
- break;
- case SND_SOC_DAIFMT_NB_IF:
- if (tmp & MOD_LR_RLOW)
- tmp &= ~MOD_LR_RLOW;
- else
- tmp |= MOD_LR_RLOW;
- break;
- default:
- dev_err(&i2s->pdev->dev, "Polarity not supported\n");
- return -EINVAL;
- }
-
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
- tmp |= MOD_SLAVE;
- break;
- case SND_SOC_DAIFMT_CBS_CFS:
- /* Set default source clock in Master mode */
- if (i2s->rclk_srcrate == 0)
- s3c_i2sv2_set_sysclk(dai, SAMSUNG_I2S_RCLKSRC_0,
- 0, SND_SOC_CLOCK_IN);
- break;
- default:
- dev_err(&i2s->pdev->dev, "master/slave format not supported\n");
- return -EINVAL;
- }
-
- if (any_active(i2s) &&
- ((mod & (MOD_SDF_MASK | MOD_LR_RLOW
- | MOD_SLAVE)) != tmp)) {
- dev_err(&i2s->pdev->dev,
- "%s:%d Other DAI busy\n", __func__, __LINE__);
- return -EAGAIN;
- }
-
- mod &= ~(MOD_SDF_MASK | MOD_LR_RLOW | MOD_SLAVE);
- mod |= tmp;
- writel(mod, i2s->addr + I2SMOD);
-
- return 0;
-}
-
-static int s3c_i2sv2_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
-{
- struct i2s_dai *i2s = to_info(dai);
- u32 mod = readl(i2s->addr + I2SMOD);
-
- if (!is_secondary(i2s))
- mod &= ~(MOD_DC2_EN | MOD_DC1_EN);
-
- switch (params_channels(params)) {
- case 6:
- mod |= MOD_DC2_EN;
- case 4:
- mod |= MOD_DC1_EN;
- break;
- case 2:
- break;
- default:
- dev_err(&i2s->pdev->dev, "%d channels not supported\n",
- params_channels(params));
- return -EINVAL;
- }
-
- if (is_secondary(i2s))
- mod &= ~MOD_BLCS_MASK;
- else
- mod &= ~MOD_BLCP_MASK;
-
- if (is_manager(i2s))
- mod &= ~MOD_BLC_MASK;
-
- switch (params_format(params)) {
- case SNDRV_PCM_FORMAT_S8:
- if (is_secondary(i2s))
- mod |= MOD_BLCS_8BIT;
- else
- mod |= MOD_BLCP_8BIT;
- if (is_manager(i2s))
- mod |= MOD_BLC_8BIT;
- break;
- case SNDRV_PCM_FORMAT_S16_LE:
- if (is_secondary(i2s))
- mod |= MOD_BLCS_16BIT;
- else
- mod |= MOD_BLCP_16BIT;
- if (is_manager(i2s))
- mod |= MOD_BLC_16BIT;
- break;
- case SNDRV_PCM_FORMAT_S24_LE:
- if (is_secondary(i2s))
- mod |= MOD_BLCS_24BIT;
- else
- mod |= MOD_BLCP_24BIT;
- if (is_manager(i2s))
- mod |= MOD_BLC_24BIT;
- break;
- default:
- dev_err(&i2s->pdev->dev, "Format(%d) not supported\n",
- params_format(params));
- return -EINVAL;
- }
- writel(mod, i2s->addr + I2SMOD);
-
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- snd_soc_dai_set_dma_data(dai, substream,
- (void *)&i2s->dma_playback);
- else
- snd_soc_dai_set_dma_data(dai, substream,
- (void *)&i2s->dma_capture);
-
- i2s->frmclk = params_rate(params);
-
- return 0;
-}
-
-/* We set constraints on the substream acc to the version of I2S */
-static int s3c_i2sv2_startup(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
-{
- struct i2s_dai *i2s = to_info(dai);
- struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
- unsigned long flags;
-
- spin_lock_irqsave(&lock, flags);
-
- i2s->mode |= DAI_OPENED;
-
- if (is_manager(other))
- i2s->mode &= ~DAI_MANAGER;
- else
- i2s->mode |= DAI_MANAGER;
-
- /* Enforce set_sysclk in Master mode */
- i2s->rclk_srcrate = 0;
-
- spin_unlock_irqrestore(&lock, flags);
-
- return 0;
-}
-
-static void s3c_i2sv2_shutdown(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
-{
- struct i2s_dai *i2s = to_info(dai);
- struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
- unsigned long flags;
-
- spin_lock_irqsave(&lock, flags);
-
- i2s->mode &= ~DAI_OPENED;
- i2s->mode &= ~DAI_MANAGER;
-
- if (is_opened(other))
- other->mode |= DAI_MANAGER;
-
- /* Reset any constraint on RFS and BFS */
- i2s->rfs = 0;
- i2s->bfs = 0;
-
- spin_unlock_irqrestore(&lock, flags);
-
- /* Gate CDCLK by default */
- if (!is_opened(other))
- s3c_i2sv2_set_sysclk(dai, SAMSUNG_I2S_CDCLK,
- 0, SND_SOC_CLOCK_IN);
-}
-
-static int config_setup(struct i2s_dai *i2s)
-{
- struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
- unsigned rfs, bfs, blc;
- u32 psr;
-
- blc = get_blc(i2s);
-
- bfs = i2s->bfs;
-
- if (!bfs && other)
- bfs = other->bfs;
-
- /* Select least possible multiple(2) if no constraint set */
- if (!bfs)
- bfs = blc * 2;
-
- rfs = i2s->rfs;
-
- if (!rfs && other)
- rfs = other->rfs;
-
- if ((rfs == 256 || rfs == 512) && (blc == 24)) {
- dev_err(&i2s->pdev->dev,
- "%d-RFS not supported for 24-blc\n", rfs);
- return -EINVAL;
- }
-
- if (!rfs) {
- if (bfs == 16 || bfs == 32)
- rfs = 256;
- else
- rfs = 384;
- }
-
- /* If already setup and running */
- if (any_active(i2s) && (get_rfs(i2s) != rfs || get_bfs(i2s) != bfs)) {
- dev_err(&i2s->pdev->dev,
- "%s:%d Other DAI busy\n", __func__, __LINE__);
- return -EAGAIN;
- }
-
- /* We don't care about BFS in Slave mode */
- if (is_slave(i2s))
- return 0;
-
- set_bfs(i2s, bfs);
- set_rfs(i2s, rfs);
-
- if (!(i2s->quirks & QUIRK_NO_MUXPSR)) {
- psr = i2s->rclk_srcrate / i2s->frmclk / rfs;
- writel(((psr - 1) << 8) | PSR_PSREN, i2s->addr + I2SPSR);
- dev_dbg(&i2s->pdev->dev,
- "RCLK_SRC=%luHz PSR=%u, RCLK=%dfs, BCLK=%dfs\n",
- i2s->rclk_srcrate, psr, rfs, bfs);
- }
-
- return 0;
-}
-
-static int i2sv2_i2s_trigger(struct snd_pcm_substream *substream,
- int cmd, struct snd_soc_dai *dai)
-{
- int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct i2s_dai *i2s = to_info(rtd->cpu_dai);
- unsigned long flags;
-
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
- case SNDRV_PCM_TRIGGER_RESUME:
- case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- local_irq_save(flags);
-
- if (capture)
- s3c_i2sv2_fifo(i2s, FIC_RXFLUSH);
- else
- s3c_i2sv2_fifo(i2s, FIC_TXFLUSH);
-
- if (config_setup(i2s)) {
- local_irq_restore(flags);
- return -EINVAL;
- }
-
- if (capture)
- s3c_i2sv2_rxctrl(i2s, 1);
- else
- s3c_i2sv2_txctrl(i2s, 1);
-
- local_irq_restore(flags);
- break;
- case SNDRV_PCM_TRIGGER_STOP:
- case SNDRV_PCM_TRIGGER_SUSPEND:
- case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- local_irq_save(flags);
-
- if (capture)
- s3c_i2sv2_rxctrl(i2s, 0);
- else
- s3c_i2sv2_txctrl(i2s, 0);
-
- local_irq_restore(flags);
- break;
- }
-
- return 0;
-}
-
-static int i2sv2_i2s_set_clkdiv(struct snd_soc_dai *dai,
- int div_id, int div)
-{
- struct i2s_dai *i2s = to_info(dai);
- struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
-
- if (div_id == SAMSUNG_I2S_DIV_BCLK) {
- if ((any_active(i2s) && div && (get_bfs(i2s) != div))
- || (other && other->bfs && (other->bfs != div))) {
- dev_err(&i2s->pdev->dev,
- "%s:%d Other DAI busy\n", __func__, __LINE__);
- return -EAGAIN;
- }
- i2s->bfs = div;
- } else {
- dev_err(&i2s->pdev->dev,
- "Invalid clock divider(%d)\n", div_id);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static snd_pcm_sframes_t
-i2sv2_i2s_delay(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
-{
- struct i2s_dai *i2s = to_info(dai);
- u32 reg = readl(i2s->addr + I2SFIC);
- snd_pcm_sframes_t delay;
-
- if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
- delay = FIC_RXCOUNT(reg);
- else if (is_secondary(i2s))
- delay = FICS_TXCOUNT(readl(i2s->addr + I2SFICS));
- else
- delay = FIC_TXCOUNT(reg);
-
- return delay;
-}
-
-#ifdef CONFIG_PM
-static int i2sv2_i2s_suspend(struct snd_soc_dai *dai)
-{
- struct i2s_dai *i2s = to_info(dai);
-
- if (dai->active) {
- i2s->suspend_i2smod = readl(i2s->addr + I2SMOD);
- i2s->suspend_i2scon = readl(i2s->addr + I2SCON);
- i2s->suspend_i2spsr = readl(i2s->addr + I2SPSR);
- }
-
- return 0;
-}
-
-static int i2sv2_i2s_resume(struct snd_soc_dai *dai)
-{
- struct i2s_dai *i2s = to_info(dai);
-
- if (dai->active) {
- writel(i2s->suspend_i2scon, i2s->addr + I2SCON);
- writel(i2s->suspend_i2smod, i2s->addr + I2SMOD);
- writel(i2s->suspend_i2spsr, i2s->addr + I2SPSR);
- }
-
- return 0;
-}
-#else
-#define i2sv2_i2s_suspend NULL
-#define i2sv2_i2s_resume NULL
-#endif
-
-static int samsung_i2s_dai_probe(struct snd_soc_dai *dai)
-{
- struct i2s_dai *i2s = to_info(dai);
- struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
-
- if (other && other->clk) /* If this is probe on secondary */
- goto probe_exit;
-
- i2s->addr = ioremap(i2s->base, 0x100);
- if (i2s->addr == NULL) {
- dev_err(&i2s->pdev->dev, "cannot ioremap registers\n");
- return -ENXIO;
- }
-
- i2s->clk = clk_get(&i2s->pdev->dev, "iis");
- if (IS_ERR(i2s->clk)) {
- dev_err(&i2s->pdev->dev, "failed to get i2s_clock\n");
- iounmap(i2s->addr);
- return -ENOENT;
- }
- clk_enable(i2s->clk);
-
- if (other) {
- other->addr = i2s->addr;
- other->clk = i2s->clk;
- }
-
- if (i2s->quirks & QUIRK_NEED_RSTCLR)
- writel(CON_RSTCLR, i2s->addr + I2SCON);
-
-probe_exit:
- /* Reset any constraint on RFS and BFS */
- i2s->rfs = 0;
- i2s->bfs = 0;
- s3c_i2sv2_txctrl(i2s, 0);
- s3c_i2sv2_rxctrl(i2s, 0);
- s3c_i2sv2_fifo(i2s, FIC_TXFLUSH);
- s3c_i2sv2_fifo(other, FIC_TXFLUSH);
- s3c_i2sv2_fifo(i2s, FIC_RXFLUSH);
-
- /* Gate CDCLK by default */
- if (!is_opened(other))
- s3c_i2sv2_set_sysclk(dai, SAMSUNG_I2S_CDCLK,
- 0, SND_SOC_CLOCK_IN);
-
- return 0;
-}
-
-static int samsung_i2s_dai_remove(struct snd_soc_dai *dai)
-{
- struct i2s_dai *i2s = snd_soc_dai_get_drvdata(dai);
- struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
-
- if (!other || !other->clk) {
-
- if (i2s->quirks & QUIRK_NEED_RSTCLR)
- writel(0, i2s->addr + I2SCON);
-
- clk_disable(i2s->clk);
- clk_put(i2s->clk);
-
- iounmap(i2s->addr);
- }
-
- i2s->clk = NULL;
-
- return 0;
-}
-
-static struct snd_soc_dai_ops samsung_i2s_dai_ops = {
- .trigger = i2sv2_i2s_trigger,
- .hw_params = s3c_i2sv2_hw_params,
- .set_fmt = i2sv2_i2s_set_fmt,
- .set_clkdiv = i2sv2_i2s_set_clkdiv,
- .set_sysclk = s3c_i2sv2_set_sysclk,
- .startup = s3c_i2sv2_startup,
- .shutdown = s3c_i2sv2_shutdown,
- .delay = i2sv2_i2s_delay,
-};
-
-#define SAMSUNG_I2S_RATES \
- (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \
- SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
- SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
-
-#define SAMSUNG_I2S_FMTS \
- (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |\
- SNDRV_PCM_FMTBIT_S24_LE)
-
-static __devinit
-struct i2s_dai *s3c_alloc_dai(struct platform_device *pdev, bool sec)
-{
- struct i2s_dai *i2s;
-
- i2s = kzalloc(sizeof(struct i2s_dai), GFP_KERNEL);
- if (i2s == NULL)
- return NULL;
-
- i2s->pdev = pdev;
- i2s->pri_dai = NULL;
- i2s->sec_dai = NULL;
- i2s->s3c_i2s_drv.symmetric_rates = 1;
- i2s->s3c_i2s_drv.probe = samsung_i2s_dai_probe;
- i2s->s3c_i2s_drv.remove = samsung_i2s_dai_remove;
- i2s->s3c_i2s_drv.ops = &samsung_i2s_dai_ops;
- i2s->s3c_i2s_drv.suspend = i2sv2_i2s_suspend;
- i2s->s3c_i2s_drv.resume = i2sv2_i2s_resume;
- i2s->s3c_i2s_drv.playback.channels_min = 2;
- i2s->s3c_i2s_drv.playback.channels_max = 2;
- i2s->s3c_i2s_drv.playback.rates = SAMSUNG_I2S_RATES;
- i2s->s3c_i2s_drv.playback.formats = SAMSUNG_I2S_FMTS;
-
- if (!sec) {
- i2s->s3c_i2s_drv.capture.channels_min = 2;
- i2s->s3c_i2s_drv.capture.channels_max = 2;
- i2s->s3c_i2s_drv.capture.rates = SAMSUNG_I2S_RATES;
- i2s->s3c_i2s_drv.capture.formats = SAMSUNG_I2S_FMTS;
- } else { /* Create a new platform_device for Secondary */
- i2s->pdev = platform_device_register_resndata(NULL,
- pdev->name, pdev->id + MAX_I2S,
- NULL, 0, NULL, 0);
- if (IS_ERR(i2s->pdev)) {
- kfree(i2s);
- return NULL;
- }
- }
-
- /* Pre-assign snd_soc_dai_set_drvdata */
- dev_set_drvdata(&i2s->pdev->dev, i2s);
-
- return i2s;
-}
-
-static __devinit int samsung_i2s_probe(struct platform_device *pdev)
-{
- u32 dma_pl_chan, dma_cp_chan, dma_pl_sec_chan;
- struct i2s_dai *pri_dai, *sec_dai = NULL;
- struct s3c_audio_pdata *i2s_pdata;
- struct samsung_i2s *i2s_cfg;
- struct resource *res;
- u32 regs_base, quirks;
- int ret = 0;
-
- /* Call during Seconday interface registration */
- if (pdev->id >= MAX_I2S) {
- sec_dai = dev_get_drvdata(&pdev->dev);
- snd_soc_register_dai(&sec_dai->pdev->dev,
- &sec_dai->s3c_i2s_drv);
- return 0;
- }
-
- i2s_pdata = pdev->dev.platform_data;
- if (i2s_pdata == NULL) {
- dev_err(&pdev->dev, "Can't work without s3c_audio_pdata\n");
- return -EINVAL;
- }
-
- res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
- if (!res) {
- dev_err(&pdev->dev, "Unable to get I2S-TX dma resource\n");
- return -ENXIO;
- }
- dma_pl_chan = res->start;
-
- res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
- if (!res) {
- dev_err(&pdev->dev, "Unable to get I2S-RX dma resource\n");
- return -ENXIO;
- }
- dma_cp_chan = res->start;
-
- res = platform_get_resource(pdev, IORESOURCE_DMA, 2);
- if (res)
- dma_pl_sec_chan = res->start;
- else
- dma_pl_sec_chan = 0;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(&pdev->dev, "Unable to get I2S SFR address\n");
- return -ENXIO;
- }
-
- if (!request_mem_region(res->start, resource_size(res),
- "samsung-i2s")) {
- dev_err(&pdev->dev, "Unable to request SFR region\n");
- return -EBUSY;
- }
- regs_base = res->start;
-
- i2s_cfg = &i2s_pdata->type.i2s;
- quirks = i2s_cfg->quirks;
-
- pri_dai = s3c_alloc_dai(pdev, false);
- if (!pri_dai) {
- dev_err(&pdev->dev, "Unable to alloc I2S_pri\n");
- ret = -ENOMEM;
- goto err1;
- }
-
- pri_dai->dma_playback.dma_addr = regs_base + I2STXD;
- pri_dai->dma_capture.dma_addr = regs_base + I2SRXD;
- pri_dai->dma_playback.client =
- (struct s3c2410_dma_client *)&pri_dai->dma_playback;
- pri_dai->dma_capture.client =
- (struct s3c2410_dma_client *)&pri_dai->dma_capture;
- pri_dai->dma_playback.channel = dma_pl_chan;
- pri_dai->dma_capture.channel = dma_cp_chan;
- pri_dai->src_clk = i2s_cfg->src_clk;
- pri_dai->dma_playback.dma_size = 4;
- pri_dai->dma_capture.dma_size = 4;
- pri_dai->base = regs_base;
- pri_dai->quirks = quirks;
-
- if (quirks & QUIRK_PRI_6CHAN)
- pri_dai->s3c_i2s_drv.playback.channels_max = 6;
-
- if (quirks & QUIRK_SEC_DAI) {
- sec_dai = s3c_alloc_dai(pdev, true);
- if (!sec_dai) {
- dev_err(&pdev->dev, "Unable to alloc I2S_sec\n");
- ret = -ENOMEM;
- goto err2;
- }
- sec_dai->dma_playback.dma_addr = regs_base + I2STXDS;
- sec_dai->dma_playback.client =
- (struct s3c2410_dma_client *)&sec_dai->dma_playback;
- /* Use iDMA always if SysDMA not provided */
- sec_dai->dma_playback.channel = dma_pl_sec_chan ? : -1;
- sec_dai->src_clk = i2s_cfg->src_clk;
- sec_dai->dma_playback.dma_size = 4;
- sec_dai->base = regs_base;
- sec_dai->quirks = quirks;
- sec_dai->pri_dai = pri_dai;
- pri_dai->sec_dai = sec_dai;
- }
-
- if (i2s_pdata->cfg_gpio && i2s_pdata->cfg_gpio(pdev)) {
- dev_err(&pdev->dev, "Unable to configure gpio\n");
- ret = -EINVAL;
- goto err3;
- }
-
- snd_soc_register_dai(&pri_dai->pdev->dev, &pri_dai->s3c_i2s_drv);
-
- return 0;
-err3:
- kfree(sec_dai);
-err2:
- kfree(pri_dai);
-err1:
- release_mem_region(regs_base, resource_size(res));
-
- return ret;
-}
-
-static __devexit int samsung_i2s_remove(struct platform_device *pdev)
-{
- struct i2s_dai *i2s, *other;
-
- i2s = dev_get_drvdata(&pdev->dev);
- other = i2s->pri_dai ? : i2s->sec_dai;
-
- if (other) {
- other->pri_dai = NULL;
- other->sec_dai = NULL;
- } else {
- struct resource *res;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (res)
- release_mem_region(res->start, resource_size(res));
- }
-
- i2s->pri_dai = NULL;
- i2s->sec_dai = NULL;
-
- kfree(i2s);
-
- snd_soc_unregister_dai(&pdev->dev);
-
- return 0;
-}
-
-static struct platform_driver samsung_i2s_driver = {
- .probe = samsung_i2s_probe,
- .remove = samsung_i2s_remove,
- .driver = {
- .name = "samsung-i2s",
- .owner = THIS_MODULE,
- },
-};
-
-static int __init samsung_i2s_init(void)
-{
- return platform_driver_register(&samsung_i2s_driver);
-}
-module_init(samsung_i2s_init);
-
-static void __exit samsung_i2s_exit(void)
-{
- platform_driver_unregister(&samsung_i2s_driver);
-}
-module_exit(samsung_i2s_exit);
-
-/* Module information */
-MODULE_AUTHOR("Jaswinder Singh, <jassi.brar(a)samsung.com>");
-MODULE_DESCRIPTION("Samsung I2S Interface");
-MODULE_ALIAS("platform:samsung-i2s");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/i2s.h b/sound/soc/s3c24xx/i2s.h
deleted file mode 100644
index 77b7965..0000000
--- a/sound/soc/s3c24xx/i2s.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/* sound/soc/s3c24xx/i2s.h
- *
- * ALSA SoC Audio Layer - Samsung I2S Controller driver
- *
- * Copyright (c) 2010 Samsung Electronics Co. Ltd.
- * Jaswinder Singh <jassi.brar(a)samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef __SND_SOC_SAMSUNG_I2S_H
-#define __SND_SOC_SAMSUNG_I2S_H
-
-/*
- * Maximum number of I2S blocks that any SoC can have.
- * The secondary interface of a CPU dai(if there exists any),
- * is indexed at [cpu-dai's ID + MAX_I2S]
- */
-#define MAX_I2S 4
-
-#define SAMSUNG_I2S_DIV_BCLK 1
-
-#define SAMSUNG_I2S_RCLKSRC_0 0
-#define SAMSUNG_I2S_RCLKSRC_1 1
-#define SAMSUNG_I2S_CDCLK 2
-
-#endif /* __SND_SOC_SAMSUNG_I2S_H */
diff --git a/sound/soc/s3c24xx/jive_wm8750.c b/sound/soc/s3c24xx/jive_wm8750.c
deleted file mode 100644
index 4e1b8ac..0000000
--- a/sound/soc/s3c24xx/jive_wm8750.c
+++ /dev/null
@@ -1,191 +0,0 @@
-/* sound/soc/s3c24xx/jive_wm8750.c
- *
- * Copyright 2007,2008 Simtec Electronics
- *
- * Based on sound/soc/pxa/spitz.c
- * Copyright 2005 Wolfson Microelectronics PLC.
- * Copyright 2005 Openedhand Ltd.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/platform_device.h>
-#include <linux/clk.h>
-
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-#include <sound/soc-dapm.h>
-
-#include <asm/mach-types.h>
-
-#include "dma.h"
-#include "s3c2412-i2s.h"
-
-#include "../codecs/wm8750.h"
-
-static const struct snd_soc_dapm_route audio_map[] = {
- { "Headphone Jack", NULL, "LOUT1" },
- { "Headphone Jack", NULL, "ROUT1" },
- { "Internal Speaker", NULL, "LOUT2" },
- { "Internal Speaker", NULL, "ROUT2" },
- { "LINPUT1", NULL, "Line Input" },
- { "RINPUT1", NULL, "Line Input" },
-};
-
-static const struct snd_soc_dapm_widget wm8750_dapm_widgets[] = {
- SND_SOC_DAPM_HP("Headphone Jack", NULL),
- SND_SOC_DAPM_SPK("Internal Speaker", NULL),
- SND_SOC_DAPM_LINE("Line In", NULL),
-};
-
-static int jive_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
-{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- struct s3c_i2sv2_rate_calc div;
- unsigned int clk = 0;
- int ret = 0;
-
- switch (params_rate(params)) {
- case 8000:
- case 16000:
- case 48000:
- case 96000:
- clk = 12288000;
- break;
- case 11025:
- case 22050:
- case 44100:
- clk = 11289600;
- break;
- }
-
- s3c_i2sv2_iis_calc_rate(&div, NULL, params_rate(params),
- s3c_i2sv2_get_clock(cpu_dai));
-
- /* set codec DAI configuration */
- ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBS_CFS);
- if (ret < 0)
- return ret;
-
- /* set cpu DAI configuration */
- ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBS_CFS);
- if (ret < 0)
- return ret;
-
- /* set the codec system clock for DAC and ADC */
- ret = snd_soc_dai_set_sysclk(codec_dai, WM8750_SYSCLK, clk,
- SND_SOC_CLOCK_IN);
- if (ret < 0)
- return ret;
-
- ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C2412_DIV_RCLK, div.fs_div);
- if (ret < 0)
- return ret;
-
- ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C2412_DIV_PRESCALER,
- div.clk_div - 1);
- if (ret < 0)
- return ret;
-
- return 0;
-}
-
-static struct snd_soc_ops jive_ops = {
- .hw_params = jive_hw_params,
-};
-
-static int jive_wm8750_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_soc_codec *codec = rtd->codec;
- int err;
-
- /* These endpoints are not being used. */
- snd_soc_dapm_nc_pin(codec, "LINPUT2");
- snd_soc_dapm_nc_pin(codec, "RINPUT2");
- snd_soc_dapm_nc_pin(codec, "LINPUT3");
- snd_soc_dapm_nc_pin(codec, "RINPUT3");
- snd_soc_dapm_nc_pin(codec, "OUT3");
- snd_soc_dapm_nc_pin(codec, "MONO");
-
- /* Add jive specific widgets */
- err = snd_soc_dapm_new_controls(codec, wm8750_dapm_widgets,
- ARRAY_SIZE(wm8750_dapm_widgets));
- if (err) {
- printk(KERN_ERR "%s: failed to add widgets (%d)\n",
- __func__, err);
- return err;
- }
-
- snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
- snd_soc_dapm_sync(codec);
-
- return 0;
-}
-
-static struct snd_soc_dai_link jive_dai = {
- .name = "wm8750",
- .stream_name = "WM8750",
- .cpu_dai_name = "s3c2412-i2s",
- .codec_dai_name = "wm8750-hifi",
- .platform_name = "samsung-audio",
- .codec_name = "wm8750-codec.0-0x1a",
- .init = jive_wm8750_init,
- .ops = &jive_ops,
-};
-
-/* jive audio machine driver */
-static struct snd_soc_card snd_soc_machine_jive = {
- .name = "Jive",
- .dai_link = &jive_dai,
- .num_links = 1,
-};
-
-static struct platform_device *jive_snd_device;
-
-static int __init jive_init(void)
-{
- int ret;
-
- if (!machine_is_jive())
- return 0;
-
- printk("JIVE WM8750 Audio support\n");
-
- jive_snd_device = platform_device_alloc("soc-audio", -1);
- if (!jive_snd_device)
- return -ENOMEM;
-
- platform_set_drvdata(jive_snd_device, &snd_soc_machine_jive);
- ret = platform_device_add(jive_snd_device);
-
- if (ret)
- platform_device_put(jive_snd_device);
-
- return ret;
-}
-
-static void __exit jive_exit(void)
-{
- platform_device_unregister(jive_snd_device);
-}
-
-module_init(jive_init);
-module_exit(jive_exit);
-
-MODULE_AUTHOR("Ben Dooks <ben(a)simtec.co.uk>");
-MODULE_DESCRIPTION("ALSA SoC Jive Audio support");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/lm4857.h b/sound/soc/s3c24xx/lm4857.h
deleted file mode 100644
index 0cf5b70..0000000
--- a/sound/soc/s3c24xx/lm4857.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * lm4857.h -- ALSA Soc Audio Layer
- *
- * Copyright 2007 Wolfson Microelectronics PLC.
- * Author: Graeme Gregory
- * graeme.gregory(a)wolfsonmicro.com or linux(a)wolfsonmicro.com
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * Revision history
- * 18th Jun 2007 Initial version.
- */
-
-#ifndef LM4857_H_
-#define LM4857_H_
-
-/* The register offsets in the cache array */
-#define LM4857_MVOL 0
-#define LM4857_LVOL 1
-#define LM4857_RVOL 2
-#define LM4857_CTRL 3
-
-/* the shifts required to set these bits */
-#define LM4857_3D 5
-#define LM4857_WAKEUP 5
-#define LM4857_EPGAIN 4
-
-#endif /*LM4857_H_*/
-
diff --git a/sound/soc/s3c24xx/ln2440sbc_alc650.c b/sound/soc/s3c24xx/ln2440sbc_alc650.c
deleted file mode 100644
index e507174..0000000
--- a/sound/soc/s3c24xx/ln2440sbc_alc650.c
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * SoC audio for ln2440sbc
- *
- * Copyright 2007 KonekTel, a.s.
- * Author: Ivan Kuten
- * ivan.kuten(a)promwad.com
- *
- * Heavily based on smdk2443_wm9710.c
- * Copyright 2007 Wolfson Microelectronics PLC.
- * Author: Graeme Gregory
- * graeme.gregory(a)wolfsonmicro.com or linux(a)wolfsonmicro.com
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- */
-
-#include <linux/module.h>
-#include <linux/device.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-#include <sound/soc-dapm.h>
-
-#include "dma.h"
-#include "ac97.h"
-
-static struct snd_soc_card ln2440sbc;
-
-static struct snd_soc_dai_link ln2440sbc_dai[] = {
-{
- .name = "AC97",
- .stream_name = "AC97 HiFi",
- .cpu_dai_name = "samsung-ac97",
- .codec_dai_name = "ac97-hifi",
- .codec_name = "ac97-codec",
- .platform_name = "samsung-audio",
-},
-};
-
-static struct snd_soc_card ln2440sbc = {
- .name = "LN2440SBC",
- .dai_link = ln2440sbc_dai,
- .num_links = ARRAY_SIZE(ln2440sbc_dai),
-};
-
-static struct platform_device *ln2440sbc_snd_ac97_device;
-
-static int __init ln2440sbc_init(void)
-{
- int ret;
-
- ln2440sbc_snd_ac97_device = platform_device_alloc("soc-audio", -1);
- if (!ln2440sbc_snd_ac97_device)
- return -ENOMEM;
-
- platform_set_drvdata(ln2440sbc_snd_ac97_device, &ln2440sbc);
- ret = platform_device_add(ln2440sbc_snd_ac97_device);
-
- if (ret)
- platform_device_put(ln2440sbc_snd_ac97_device);
-
- return ret;
-}
-
-static void __exit ln2440sbc_exit(void)
-{
- platform_device_unregister(ln2440sbc_snd_ac97_device);
-}
-
-module_init(ln2440sbc_init);
-module_exit(ln2440sbc_exit);
-
-/* Module information */
-MODULE_AUTHOR("Ivan Kuten");
-MODULE_DESCRIPTION("ALSA SoC ALC650 LN2440SBC");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/neo1973_gta02_wm8753.c b/sound/soc/s3c24xx/neo1973_gta02_wm8753.c
deleted file mode 100644
index c4b2013..0000000
--- a/sound/soc/s3c24xx/neo1973_gta02_wm8753.c
+++ /dev/null
@@ -1,504 +0,0 @@
-/*
- * neo1973_gta02_wm8753.c -- SoC audio for Openmoko Freerunner(GTA02)
- *
- * Copyright 2007 Openmoko Inc
- * Author: Graeme Gregory <graeme(a)openmoko.org>
- * Copyright 2007 Wolfson Microelectronics PLC.
- * Author: Graeme Gregory <linux(a)wolfsonmicro.com>
- * Copyright 2009 Wolfson Microelectronics
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/platform_device.h>
-#include <linux/gpio.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-#include <sound/soc-dapm.h>
-
-#include <asm/mach-types.h>
-
-#include <plat/regs-iis.h>
-
-#include <mach/regs-clock.h>
-#include <asm/io.h>
-#include <mach/gta02.h>
-#include "../codecs/wm8753.h"
-#include "dma.h"
-#include "s3c24xx-i2s.h"
-
-static struct snd_soc_card neo1973_gta02;
-
-static int neo1973_gta02_hifi_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
-{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- unsigned int pll_out = 0, bclk = 0;
- int ret = 0;
- unsigned long iis_clkrate;
-
- iis_clkrate = s3c24xx_i2s_get_clockrate();
-
- switch (params_rate(params)) {
- case 8000:
- case 16000:
- pll_out = 12288000;
- break;
- case 48000:
- bclk = WM8753_BCLK_DIV_4;
- pll_out = 12288000;
- break;
- case 96000:
- bclk = WM8753_BCLK_DIV_2;
- pll_out = 12288000;
- break;
- case 11025:
- bclk = WM8753_BCLK_DIV_16;
- pll_out = 11289600;
- break;
- case 22050:
- bclk = WM8753_BCLK_DIV_8;
- pll_out = 11289600;
- break;
- case 44100:
- bclk = WM8753_BCLK_DIV_4;
- pll_out = 11289600;
- break;
- case 88200:
- bclk = WM8753_BCLK_DIV_2;
- pll_out = 11289600;
- break;
- }
-
- /* set codec DAI configuration */
- ret = snd_soc_dai_set_fmt(codec_dai,
- SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBM_CFM);
- if (ret < 0)
- return ret;
-
- /* set cpu DAI configuration */
- ret = snd_soc_dai_set_fmt(cpu_dai,
- SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBM_CFM);
- if (ret < 0)
- return ret;
-
- /* set the codec system clock for DAC and ADC */
- ret = snd_soc_dai_set_sysclk(codec_dai, WM8753_MCLK, pll_out,
- SND_SOC_CLOCK_IN);
- if (ret < 0)
- return ret;
-
- /* set MCLK division for sample rate */
- ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK,
- S3C2410_IISMOD_32FS);
- if (ret < 0)
- return ret;
-
- /* set codec BCLK division for sample rate */
- ret = snd_soc_dai_set_clkdiv(codec_dai,
- WM8753_BCLKDIV, bclk);
- if (ret < 0)
- return ret;
-
- /* set prescaler division for sample rate */
- ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER,
- S3C24XX_PRESCALE(4, 4));
- if (ret < 0)
- return ret;
-
- /* codec PLL input is PCLK/4 */
- ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0,
- iis_clkrate / 4, pll_out);
- if (ret < 0)
- return ret;
-
- return 0;
-}
-
-static int neo1973_gta02_hifi_hw_free(struct snd_pcm_substream *substream)
-{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->codec_dai;
-
- /* disable the PLL */
- return snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, 0, 0);
-}
-
-/*
- * Neo1973 WM8753 HiFi DAI opserations.
- */
-static struct snd_soc_ops neo1973_gta02_hifi_ops = {
- .hw_params = neo1973_gta02_hifi_hw_params,
- .hw_free = neo1973_gta02_hifi_hw_free,
-};
-
-static int neo1973_gta02_voice_hw_params(
- struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
-{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->codec_dai;
- unsigned int pcmdiv = 0;
- int ret = 0;
- unsigned long iis_clkrate;
-
- iis_clkrate = s3c24xx_i2s_get_clockrate();
-
- if (params_rate(params) != 8000)
- return -EINVAL;
- if (params_channels(params) != 1)
- return -EINVAL;
-
- pcmdiv = WM8753_PCM_DIV_6; /* 2.048 MHz */
-
- /* todo: gg check mode (DSP_B) against CSR datasheet */
- /* set codec DAI configuration */
- ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_B |
- SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
- if (ret < 0)
- return ret;
-
- /* set the codec system clock for DAC and ADC */
- ret = snd_soc_dai_set_sysclk(codec_dai, WM8753_PCMCLK,
- 12288000, SND_SOC_CLOCK_IN);
- if (ret < 0)
- return ret;
-
- /* set codec PCM division for sample rate */
- ret = snd_soc_dai_set_clkdiv(codec_dai, WM8753_PCMDIV,
- pcmdiv);
- if (ret < 0)
- return ret;
-
- /* configue and enable PLL for 12.288MHz output */
- ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0,
- iis_clkrate / 4, 12288000);
- if (ret < 0)
- return ret;
-
- return 0;
-}
-
-static int neo1973_gta02_voice_hw_free(struct snd_pcm_substream *substream)
-{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->codec_dai;
-
- /* disable the PLL */
- return snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, 0, 0);
-}
-
-static struct snd_soc_ops neo1973_gta02_voice_ops = {
- .hw_params = neo1973_gta02_voice_hw_params,
- .hw_free = neo1973_gta02_voice_hw_free,
-};
-
-#define LM4853_AMP 1
-#define LM4853_SPK 2
-
-static u8 lm4853_state;
-
-/* This has no effect, it exists only to maintain compatibility with
- * existing ALSA state files.
- */
-static int lm4853_set_state(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- int val = ucontrol->value.integer.value[0];
-
- if (val)
- lm4853_state |= LM4853_AMP;
- else
- lm4853_state &= ~LM4853_AMP;
-
- return 0;
-}
-
-static int lm4853_get_state(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- ucontrol->value.integer.value[0] = lm4853_state & LM4853_AMP;
-
- return 0;
-}
-
-static int lm4853_set_spk(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- int val = ucontrol->value.integer.value[0];
-
- if (val) {
- lm4853_state |= LM4853_SPK;
- gpio_set_value(GTA02_GPIO_HP_IN, 0);
- } else {
- lm4853_state &= ~LM4853_SPK;
- gpio_set_value(GTA02_GPIO_HP_IN, 1);
- }
-
- return 0;
-}
-
-static int lm4853_get_spk(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- ucontrol->value.integer.value[0] = (lm4853_state & LM4853_SPK) >> 1;
-
- return 0;
-}
-
-static int lm4853_event(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *k,
- int event)
-{
- gpio_set_value(GTA02_GPIO_AMP_SHUT, SND_SOC_DAPM_EVENT_OFF(event));
-
- return 0;
-}
-
-static const struct snd_soc_dapm_widget wm8753_dapm_widgets[] = {
- SND_SOC_DAPM_SPK("Stereo Out", lm4853_event),
- SND_SOC_DAPM_LINE("GSM Line Out", NULL),
- SND_SOC_DAPM_LINE("GSM Line In", NULL),
- SND_SOC_DAPM_MIC("Headset Mic", NULL),
- SND_SOC_DAPM_MIC("Handset Mic", NULL),
- SND_SOC_DAPM_SPK("Handset Spk", NULL),
-};
-
-
-/* example machine audio_mapnections */
-static const struct snd_soc_dapm_route audio_map[] = {
-
- /* Connections to the lm4853 amp */
- {"Stereo Out", NULL, "LOUT1"},
- {"Stereo Out", NULL, "ROUT1"},
-
- /* Connections to the GSM Module */
- {"GSM Line Out", NULL, "MONO1"},
- {"GSM Line Out", NULL, "MONO2"},
- {"RXP", NULL, "GSM Line In"},
- {"RXN", NULL, "GSM Line In"},
-
- /* Connections to Headset */
- {"MIC1", NULL, "Mic Bias"},
- {"Mic Bias", NULL, "Headset Mic"},
-
- /* Call Mic */
- {"MIC2", NULL, "Mic Bias"},
- {"MIC2N", NULL, "Mic Bias"},
- {"Mic Bias", NULL, "Handset Mic"},
-
- /* Call Speaker */
- {"Handset Spk", NULL, "LOUT2"},
- {"Handset Spk", NULL, "ROUT2"},
-
- /* Connect the ALC pins */
- {"ACIN", NULL, "ACOP"},
-};
-
-static const struct snd_kcontrol_new wm8753_neo1973_gta02_controls[] = {
- SOC_DAPM_PIN_SWITCH("Stereo Out"),
- SOC_DAPM_PIN_SWITCH("GSM Line Out"),
- SOC_DAPM_PIN_SWITCH("GSM Line In"),
- SOC_DAPM_PIN_SWITCH("Headset Mic"),
- SOC_DAPM_PIN_SWITCH("Handset Mic"),
- SOC_DAPM_PIN_SWITCH("Handset Spk"),
-
- /* This has no effect, it exists only to maintain compatibility with
- * existing ALSA state files.
- */
- SOC_SINGLE_EXT("Amp State Switch", 6, 0, 1, 0,
- lm4853_get_state,
- lm4853_set_state),
- SOC_SINGLE_EXT("Amp Spk Switch", 7, 0, 1, 0,
- lm4853_get_spk,
- lm4853_set_spk),
-};
-
-/*
- * This is an example machine initialisation for a wm8753 connected to a
- * neo1973 GTA02.
- */
-static int neo1973_gta02_wm8753_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_soc_codec *codec = rtd->codec;
- int err;
-
- /* set up NC codec pins */
- snd_soc_dapm_nc_pin(codec, "OUT3");
- snd_soc_dapm_nc_pin(codec, "OUT4");
- snd_soc_dapm_nc_pin(codec, "LINE1");
- snd_soc_dapm_nc_pin(codec, "LINE2");
-
- /* Add neo1973 gta02 specific widgets */
- snd_soc_dapm_new_controls(codec, wm8753_dapm_widgets,
- ARRAY_SIZE(wm8753_dapm_widgets));
-
- /* add neo1973 gta02 specific controls */
- err = snd_soc_add_controls(codec, wm8753_neo1973_gta02_controls,
- ARRAY_SIZE(wm8753_neo1973_gta02_controls));
-
- if (err < 0)
- return err;
-
- /* set up neo1973 gta02 specific audio path audio_map */
- snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
-
- /* set endpoints to default off mode */
- snd_soc_dapm_disable_pin(codec, "Stereo Out");
- snd_soc_dapm_disable_pin(codec, "GSM Line Out");
- snd_soc_dapm_disable_pin(codec, "GSM Line In");
- snd_soc_dapm_disable_pin(codec, "Headset Mic");
- snd_soc_dapm_disable_pin(codec, "Handset Mic");
- snd_soc_dapm_disable_pin(codec, "Handset Spk");
-
- /* allow audio paths from the GSM modem to run during suspend */
- snd_soc_dapm_ignore_suspend(codec, "Stereo Out");
- snd_soc_dapm_ignore_suspend(codec, "GSM Line Out");
- snd_soc_dapm_ignore_suspend(codec, "GSM Line In");
- snd_soc_dapm_ignore_suspend(codec, "Headset Mic");
- snd_soc_dapm_ignore_suspend(codec, "Handset Mic");
- snd_soc_dapm_ignore_suspend(codec, "Handset Spk");
-
- snd_soc_dapm_sync(codec);
-
- return 0;
-}
-
-/*
- * BT Codec DAI
- */
-static struct snd_soc_dai_driver bt_dai = {
- .name = "bluetooth-dai",
- .playback = {
- .channels_min = 1,
- .channels_max = 1,
- .rates = SNDRV_PCM_RATE_8000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,},
- .capture = {
- .channels_min = 1,
- .channels_max = 1,
- .rates = SNDRV_PCM_RATE_8000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,},
-};
-
-static struct snd_soc_dai_link neo1973_gta02_dai[] = {
-{ /* Hifi Playback - for similatious use with voice below */
- .name = "WM8753",
- .stream_name = "WM8753 HiFi",
- .cpu_dai_name = "s3c24xx-i2s",
- .codec_dai_name = "wm8753-hifi",
- .init = neo1973_gta02_wm8753_init,
- .platform_name = "samsung-audio",
- .codec_name = "wm8753-codec.0-0x1a",
- .ops = &neo1973_gta02_hifi_ops,
-},
-{ /* Voice via BT */
- .name = "Bluetooth",
- .stream_name = "Voice",
- .cpu_dai_name = "bluetooth-dai",
- .codec_dai_name = "wm8753-voice",
- .ops = &neo1973_gta02_voice_ops,
- .codec_name = "wm8753-codec.0-0x1a",
- .platform_name = "samsung-audio",
-},
-};
-
-static struct snd_soc_card neo1973_gta02 = {
- .name = "neo1973-gta02",
- .dai_link = neo1973_gta02_dai,
- .num_links = ARRAY_SIZE(neo1973_gta02_dai),
-};
-
-static struct platform_device *neo1973_gta02_snd_device;
-
-static int __init neo1973_gta02_init(void)
-{
- int ret;
-
- if (!machine_is_neo1973_gta02()) {
- printk(KERN_INFO
- "Only GTA02 is supported by this ASoC driver\n");
- return -ENODEV;
- }
-
- neo1973_gta02_snd_device = platform_device_alloc("soc-audio", -1);
- if (!neo1973_gta02_snd_device)
- return -ENOMEM;
-
- /* register bluetooth DAI here */
- ret = snd_soc_register_dai(&neo1973_gta02_snd_device->dev, -1, &bt_dai);
- if (ret) {
- platform_device_put(neo1973_gta02_snd_device);
- return ret;
- }
-
- platform_set_drvdata(neo1973_gta02_snd_device, &neo1973_gta02);
- ret = platform_device_add(neo1973_gta02_snd_device);
-
- if (ret) {
- platform_device_put(neo1973_gta02_snd_device);
- return ret;
- }
-
- /* Initialise GPIOs used by amp */
- ret = gpio_request(GTA02_GPIO_HP_IN, "GTA02_HP_IN");
- if (ret) {
- pr_err("gta02_wm8753: Failed to register GPIO %d\n", GTA02_GPIO_HP_IN);
- goto err_unregister_device;
- }
-
- ret = gpio_direction_output(GTA02_GPIO_HP_IN, 1);
- if (ret) {
- pr_err("gta02_wm8753: Failed to configure GPIO %d\n", GTA02_GPIO_HP_IN);
- goto err_free_gpio_hp_in;
- }
-
- ret = gpio_request(GTA02_GPIO_AMP_SHUT, "GTA02_AMP_SHUT");
- if (ret) {
- pr_err("gta02_wm8753: Failed to register GPIO %d\n", GTA02_GPIO_AMP_SHUT);
- goto err_free_gpio_hp_in;
- }
-
- ret = gpio_direction_output(GTA02_GPIO_AMP_SHUT, 1);
- if (ret) {
- pr_err("gta02_wm8753: Failed to configure GPIO %d\n", GTA02_GPIO_AMP_SHUT);
- goto err_free_gpio_amp_shut;
- }
-
- return 0;
-
-err_free_gpio_amp_shut:
- gpio_free(GTA02_GPIO_AMP_SHUT);
-err_free_gpio_hp_in:
- gpio_free(GTA02_GPIO_HP_IN);
-err_unregister_device:
- platform_device_unregister(neo1973_gta02_snd_device);
- return ret;
-}
-module_init(neo1973_gta02_init);
-
-static void __exit neo1973_gta02_exit(void)
-{
- snd_soc_unregister_dai(&neo1973_gta02_snd_device->dev, -1);
- platform_device_unregister(neo1973_gta02_snd_device);
- gpio_free(GTA02_GPIO_HP_IN);
- gpio_free(GTA02_GPIO_AMP_SHUT);
-}
-module_exit(neo1973_gta02_exit);
-
-/* Module information */
-MODULE_AUTHOR("Graeme Gregory, graeme(a)openmoko.org");
-MODULE_DESCRIPTION("ALSA SoC WM8753 Neo1973 GTA02");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/neo1973_wm8753.c b/sound/soc/s3c24xx/neo1973_wm8753.c
deleted file mode 100644
index 96dda57..0000000
--- a/sound/soc/s3c24xx/neo1973_wm8753.c
+++ /dev/null
@@ -1,704 +0,0 @@
-/*
- * neo1973_wm8753.c -- SoC audio for Neo1973
- *
- * Copyright 2007 Wolfson Microelectronics PLC.
- * Author: Graeme Gregory
- * graeme.gregory(a)wolfsonmicro.com or linux(a)wolfsonmicro.com
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/platform_device.h>
-#include <linux/i2c.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-#include <sound/soc-dapm.h>
-#include <sound/tlv.h>
-
-#include <asm/mach-types.h>
-#include <asm/hardware/scoop.h>
-#include <mach/regs-clock.h>
-#include <mach/regs-gpio.h>
-#include <mach/hardware.h>
-#include <linux/io.h>
-#include <mach/spi-gpio.h>
-
-#include <plat/regs-iis.h>
-
-#include "../codecs/wm8753.h"
-#include "lm4857.h"
-#include "dma.h"
-#include "s3c24xx-i2s.h"
-
-/* define the scenarios */
-#define NEO_AUDIO_OFF 0
-#define NEO_GSM_CALL_AUDIO_HANDSET 1
-#define NEO_GSM_CALL_AUDIO_HEADSET 2
-#define NEO_GSM_CALL_AUDIO_BLUETOOTH 3
-#define NEO_STEREO_TO_SPEAKERS 4
-#define NEO_STEREO_TO_HEADPHONES 5
-#define NEO_CAPTURE_HANDSET 6
-#define NEO_CAPTURE_HEADSET 7
-#define NEO_CAPTURE_BLUETOOTH 8
-
-static struct snd_soc_card neo1973;
-static struct i2c_client *i2c;
-
-static int neo1973_hifi_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
-{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- unsigned int pll_out = 0, bclk = 0;
- int ret = 0;
- unsigned long iis_clkrate;
-
- pr_debug("Entered %s\n", __func__);
-
- iis_clkrate = s3c24xx_i2s_get_clockrate();
-
- switch (params_rate(params)) {
- case 8000:
- case 16000:
- pll_out = 12288000;
- break;
- case 48000:
- bclk = WM8753_BCLK_DIV_4;
- pll_out = 12288000;
- break;
- case 96000:
- bclk = WM8753_BCLK_DIV_2;
- pll_out = 12288000;
- break;
- case 11025:
- bclk = WM8753_BCLK_DIV_16;
- pll_out = 11289600;
- break;
- case 22050:
- bclk = WM8753_BCLK_DIV_8;
- pll_out = 11289600;
- break;
- case 44100:
- bclk = WM8753_BCLK_DIV_4;
- pll_out = 11289600;
- break;
- case 88200:
- bclk = WM8753_BCLK_DIV_2;
- pll_out = 11289600;
- break;
- }
-
- /* set codec DAI configuration */
- ret = snd_soc_dai_set_fmt(codec_dai,
- SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBM_CFM);
- if (ret < 0)
- return ret;
-
- /* set cpu DAI configuration */
- ret = snd_soc_dai_set_fmt(cpu_dai,
- SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBM_CFM);
- if (ret < 0)
- return ret;
-
- /* set the codec system clock for DAC and ADC */
- ret = snd_soc_dai_set_sysclk(codec_dai, WM8753_MCLK, pll_out,
- SND_SOC_CLOCK_IN);
- if (ret < 0)
- return ret;
-
- /* set MCLK division for sample rate */
- ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK,
- S3C2410_IISMOD_32FS);
- if (ret < 0)
- return ret;
-
- /* set codec BCLK division for sample rate */
- ret = snd_soc_dai_set_clkdiv(codec_dai, WM8753_BCLKDIV, bclk);
- if (ret < 0)
- return ret;
-
- /* set prescaler division for sample rate */
- ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER,
- S3C24XX_PRESCALE(4, 4));
- if (ret < 0)
- return ret;
-
- /* codec PLL input is PCLK/4 */
- ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0,
- iis_clkrate / 4, pll_out);
- if (ret < 0)
- return ret;
-
- return 0;
-}
-
-static int neo1973_hifi_hw_free(struct snd_pcm_substream *substream)
-{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->codec_dai;
-
- pr_debug("Entered %s\n", __func__);
-
- /* disable the PLL */
- return snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, 0, 0);
-}
-
-/*
- * Neo1973 WM8753 HiFi DAI opserations.
- */
-static struct snd_soc_ops neo1973_hifi_ops = {
- .hw_params = neo1973_hifi_hw_params,
- .hw_free = neo1973_hifi_hw_free,
-};
-
-static int neo1973_voice_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
-{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->codec_dai;
- unsigned int pcmdiv = 0;
- int ret = 0;
- unsigned long iis_clkrate;
-
- pr_debug("Entered %s\n", __func__);
-
- iis_clkrate = s3c24xx_i2s_get_clockrate();
-
- if (params_rate(params) != 8000)
- return -EINVAL;
- if (params_channels(params) != 1)
- return -EINVAL;
-
- pcmdiv = WM8753_PCM_DIV_6; /* 2.048 MHz */
-
- /* todo: gg check mode (DSP_B) against CSR datasheet */
- /* set codec DAI configuration */
- ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_B |
- SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
- if (ret < 0)
- return ret;
-
- /* set the codec system clock for DAC and ADC */
- ret = snd_soc_dai_set_sysclk(codec_dai, WM8753_PCMCLK, 12288000,
- SND_SOC_CLOCK_IN);
- if (ret < 0)
- return ret;
-
- /* set codec PCM division for sample rate */
- ret = snd_soc_dai_set_clkdiv(codec_dai, WM8753_PCMDIV, pcmdiv);
- if (ret < 0)
- return ret;
-
- /* configue and enable PLL for 12.288MHz output */
- ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0,
- iis_clkrate / 4, 12288000);
- if (ret < 0)
- return ret;
-
- return 0;
-}
-
-static int neo1973_voice_hw_free(struct snd_pcm_substream *substream)
-{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->codec_dai;
-
- pr_debug("Entered %s\n", __func__);
-
- /* disable the PLL */
- return snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, 0, 0);
-}
-
-static struct snd_soc_ops neo1973_voice_ops = {
- .hw_params = neo1973_voice_hw_params,
- .hw_free = neo1973_voice_hw_free,
-};
-
-static int neo1973_scenario;
-
-static int neo1973_get_scenario(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- ucontrol->value.integer.value[0] = neo1973_scenario;
- return 0;
-}
-
-static int set_scenario_endpoints(struct snd_soc_codec *codec, int scenario)
-{
- pr_debug("Entered %s\n", __func__);
-
- switch (neo1973_scenario) {
- case NEO_AUDIO_OFF:
- snd_soc_dapm_disable_pin(codec, "Audio Out");
- snd_soc_dapm_disable_pin(codec, "GSM Line Out");
- snd_soc_dapm_disable_pin(codec, "GSM Line In");
- snd_soc_dapm_disable_pin(codec, "Headset Mic");
- snd_soc_dapm_disable_pin(codec, "Call Mic");
- break;
- case NEO_GSM_CALL_AUDIO_HANDSET:
- snd_soc_dapm_enable_pin(codec, "Audio Out");
- snd_soc_dapm_enable_pin(codec, "GSM Line Out");
- snd_soc_dapm_enable_pin(codec, "GSM Line In");
- snd_soc_dapm_disable_pin(codec, "Headset Mic");
- snd_soc_dapm_enable_pin(codec, "Call Mic");
- break;
- case NEO_GSM_CALL_AUDIO_HEADSET:
- snd_soc_dapm_enable_pin(codec, "Audio Out");
- snd_soc_dapm_enable_pin(codec, "GSM Line Out");
- snd_soc_dapm_enable_pin(codec, "GSM Line In");
- snd_soc_dapm_enable_pin(codec, "Headset Mic");
- snd_soc_dapm_disable_pin(codec, "Call Mic");
- break;
- case NEO_GSM_CALL_AUDIO_BLUETOOTH:
- snd_soc_dapm_disable_pin(codec, "Audio Out");
- snd_soc_dapm_enable_pin(codec, "GSM Line Out");
- snd_soc_dapm_enable_pin(codec, "GSM Line In");
- snd_soc_dapm_disable_pin(codec, "Headset Mic");
- snd_soc_dapm_disable_pin(codec, "Call Mic");
- break;
- case NEO_STEREO_TO_SPEAKERS:
- snd_soc_dapm_enable_pin(codec, "Audio Out");
- snd_soc_dapm_disable_pin(codec, "GSM Line Out");
- snd_soc_dapm_disable_pin(codec, "GSM Line In");
- snd_soc_dapm_disable_pin(codec, "Headset Mic");
- snd_soc_dapm_disable_pin(codec, "Call Mic");
- break;
- case NEO_STEREO_TO_HEADPHONES:
- snd_soc_dapm_enable_pin(codec, "Audio Out");
- snd_soc_dapm_disable_pin(codec, "GSM Line Out");
- snd_soc_dapm_disable_pin(codec, "GSM Line In");
- snd_soc_dapm_disable_pin(codec, "Headset Mic");
- snd_soc_dapm_disable_pin(codec, "Call Mic");
- break;
- case NEO_CAPTURE_HANDSET:
- snd_soc_dapm_disable_pin(codec, "Audio Out");
- snd_soc_dapm_disable_pin(codec, "GSM Line Out");
- snd_soc_dapm_disable_pin(codec, "GSM Line In");
- snd_soc_dapm_disable_pin(codec, "Headset Mic");
- snd_soc_dapm_enable_pin(codec, "Call Mic");
- break;
- case NEO_CAPTURE_HEADSET:
- snd_soc_dapm_disable_pin(codec, "Audio Out");
- snd_soc_dapm_disable_pin(codec, "GSM Line Out");
- snd_soc_dapm_disable_pin(codec, "GSM Line In");
- snd_soc_dapm_enable_pin(codec, "Headset Mic");
- snd_soc_dapm_disable_pin(codec, "Call Mic");
- break;
- case NEO_CAPTURE_BLUETOOTH:
- snd_soc_dapm_disable_pin(codec, "Audio Out");
- snd_soc_dapm_disable_pin(codec, "GSM Line Out");
- snd_soc_dapm_disable_pin(codec, "GSM Line In");
- snd_soc_dapm_disable_pin(codec, "Headset Mic");
- snd_soc_dapm_disable_pin(codec, "Call Mic");
- break;
- default:
- snd_soc_dapm_disable_pin(codec, "Audio Out");
- snd_soc_dapm_disable_pin(codec, "GSM Line Out");
- snd_soc_dapm_disable_pin(codec, "GSM Line In");
- snd_soc_dapm_disable_pin(codec, "Headset Mic");
- snd_soc_dapm_disable_pin(codec, "Call Mic");
- }
-
- snd_soc_dapm_sync(codec);
-
- return 0;
-}
-
-static int neo1973_set_scenario(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-
- pr_debug("Entered %s\n", __func__);
-
- if (neo1973_scenario == ucontrol->value.integer.value[0])
- return 0;
-
- neo1973_scenario = ucontrol->value.integer.value[0];
- set_scenario_endpoints(codec, neo1973_scenario);
- return 1;
-}
-
-static u8 lm4857_regs[4] = {0x00, 0x40, 0x80, 0xC0};
-
-static void lm4857_write_regs(void)
-{
- pr_debug("Entered %s\n", __func__);
-
- if (i2c_master_send(i2c, lm4857_regs, 4) != 4)
- printk(KERN_ERR "lm4857: i2c write failed\n");
-}
-
-static int lm4857_get_reg(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct soc_mixer_control *mc =
- (struct soc_mixer_control *)kcontrol->private_value;
- int reg = mc->reg;
- int shift = mc->shift;
- int mask = mc->max;
-
- pr_debug("Entered %s\n", __func__);
-
- ucontrol->value.integer.value[0] = (lm4857_regs[reg] >> shift) & mask;
- return 0;
-}
-
-static int lm4857_set_reg(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct soc_mixer_control *mc =
- (struct soc_mixer_control *)kcontrol->private_value;
- int reg = mc->reg;
- int shift = mc->shift;
- int mask = mc->max;
-
- if (((lm4857_regs[reg] >> shift) & mask) ==
- ucontrol->value.integer.value[0])
- return 0;
-
- lm4857_regs[reg] &= ~(mask << shift);
- lm4857_regs[reg] |= ucontrol->value.integer.value[0] << shift;
- lm4857_write_regs();
- return 1;
-}
-
-static int lm4857_get_mode(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- u8 value = lm4857_regs[LM4857_CTRL] & 0x0F;
-
- pr_debug("Entered %s\n", __func__);
-
- if (value)
- value -= 5;
-
- ucontrol->value.integer.value[0] = value;
- return 0;
-}
-
-static int lm4857_set_mode(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- u8 value = ucontrol->value.integer.value[0];
-
- pr_debug("Entered %s\n", __func__);
-
- if (value)
- value += 5;
-
- if ((lm4857_regs[LM4857_CTRL] & 0x0F) == value)
- return 0;
-
- lm4857_regs[LM4857_CTRL] &= 0xF0;
- lm4857_regs[LM4857_CTRL] |= value;
- lm4857_write_regs();
- return 1;
-}
-
-static const struct snd_soc_dapm_widget wm8753_dapm_widgets[] = {
- SND_SOC_DAPM_LINE("Audio Out", NULL),
- SND_SOC_DAPM_LINE("GSM Line Out", NULL),
- SND_SOC_DAPM_LINE("GSM Line In", NULL),
- SND_SOC_DAPM_MIC("Headset Mic", NULL),
- SND_SOC_DAPM_MIC("Call Mic", NULL),
-};
-
-
-static const struct snd_soc_dapm_route dapm_routes[] = {
-
- /* Connections to the lm4857 amp */
- {"Audio Out", NULL, "LOUT1"},
- {"Audio Out", NULL, "ROUT1"},
-
- /* Connections to the GSM Module */
- {"GSM Line Out", NULL, "MONO1"},
- {"GSM Line Out", NULL, "MONO2"},
- {"RXP", NULL, "GSM Line In"},
- {"RXN", NULL, "GSM Line In"},
-
- /* Connections to Headset */
- {"MIC1", NULL, "Mic Bias"},
- {"Mic Bias", NULL, "Headset Mic"},
-
- /* Call Mic */
- {"MIC2", NULL, "Mic Bias"},
- {"MIC2N", NULL, "Mic Bias"},
- {"Mic Bias", NULL, "Call Mic"},
-
- /* Connect the ALC pins */
- {"ACIN", NULL, "ACOP"},
-};
-
-static const char *lm4857_mode[] = {
- "Off",
- "Call Speaker",
- "Stereo Speakers",
- "Stereo Speakers + Headphones",
- "Headphones"
-};
-
-static const struct soc_enum lm4857_mode_enum[] = {
- SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(lm4857_mode), lm4857_mode),
-};
-
-static const char *neo_scenarios[] = {
- "Off",
- "GSM Handset",
- "GSM Headset",
- "GSM Bluetooth",
- "Speakers",
- "Headphones",
- "Capture Handset",
- "Capture Headset",
- "Capture Bluetooth"
-};
-
-static const struct soc_enum neo_scenario_enum[] = {
- SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(neo_scenarios), neo_scenarios),
-};
-
-static const DECLARE_TLV_DB_SCALE(stereo_tlv, -4050, 150, 0);
-static const DECLARE_TLV_DB_SCALE(mono_tlv, -3450, 150, 0);
-
-static const struct snd_kcontrol_new wm8753_neo1973_controls[] = {
- SOC_SINGLE_EXT_TLV("Amp Left Playback Volume", LM4857_LVOL, 0, 31, 0,
- lm4857_get_reg, lm4857_set_reg, stereo_tlv),
- SOC_SINGLE_EXT_TLV("Amp Right Playback Volume", LM4857_RVOL, 0, 31, 0,
- lm4857_get_reg, lm4857_set_reg, stereo_tlv),
- SOC_SINGLE_EXT_TLV("Amp Mono Playback Volume", LM4857_MVOL, 0, 31, 0,
- lm4857_get_reg, lm4857_set_reg, mono_tlv),
- SOC_ENUM_EXT("Amp Mode", lm4857_mode_enum[0],
- lm4857_get_mode, lm4857_set_mode),
- SOC_ENUM_EXT("Neo Mode", neo_scenario_enum[0],
- neo1973_get_scenario, neo1973_set_scenario),
- SOC_SINGLE_EXT("Amp Spk 3D Playback Switch", LM4857_LVOL, 5, 1, 0,
- lm4857_get_reg, lm4857_set_reg),
- SOC_SINGLE_EXT("Amp HP 3d Playback Switch", LM4857_RVOL, 5, 1, 0,
- lm4857_get_reg, lm4857_set_reg),
- SOC_SINGLE_EXT("Amp Fast Wakeup Playback Switch", LM4857_CTRL, 5, 1, 0,
- lm4857_get_reg, lm4857_set_reg),
- SOC_SINGLE_EXT("Amp Earpiece 6dB Playback Switch", LM4857_CTRL, 4, 1, 0,
- lm4857_get_reg, lm4857_set_reg),
-};
-
-/*
- * This is an example machine initialisation for a wm8753 connected to a
- * neo1973 II. It is missing logic to detect hp/mic insertions and logic
- * to re-route the audio in such an event.
- */
-static int neo1973_wm8753_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_soc_codec *codec = rtd->codec;
- int err;
-
- pr_debug("Entered %s\n", __func__);
-
- /* set up NC codec pins */
- snd_soc_dapm_nc_pin(codec, "LOUT2");
- snd_soc_dapm_nc_pin(codec, "ROUT2");
- snd_soc_dapm_nc_pin(codec, "OUT3");
- snd_soc_dapm_nc_pin(codec, "OUT4");
- snd_soc_dapm_nc_pin(codec, "LINE1");
- snd_soc_dapm_nc_pin(codec, "LINE2");
-
- /* Add neo1973 specific widgets */
- snd_soc_dapm_new_controls(codec, wm8753_dapm_widgets,
- ARRAY_SIZE(wm8753_dapm_widgets));
-
- /* set endpoints to default mode */
- set_scenario_endpoints(codec, NEO_AUDIO_OFF);
-
- /* add neo1973 specific controls */
- err = snd_soc_add_controls(codec, wm8753_neo1973_controls,
- ARRAY_SIZE(8753_neo1973_controls));
- if (err < 0)
- return err;
-
- /* set up neo1973 specific audio routes */
- err = snd_soc_dapm_add_routes(codec, dapm_routes,
- ARRAY_SIZE(dapm_routes));
-
- snd_soc_dapm_sync(codec);
- return 0;
-}
-
-/*
- * BT Codec DAI
- */
-static struct snd_soc_dai bt_dai = {
- .name = "bluetooth-dai",
- .playback = {
- .channels_min = 1,
- .channels_max = 1,
- .rates = SNDRV_PCM_RATE_8000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,},
- .capture = {
- .channels_min = 1,
- .channels_max = 1,
- .rates = SNDRV_PCM_RATE_8000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,},
-};
-
-static struct snd_soc_dai_link neo1973_dai[] = {
-{ /* Hifi Playback - for similatious use with voice below */
- .name = "WM8753",
- .stream_name = "WM8753 HiFi",
- .platform_name = "samsung-audio",
- .cpu_dai_name = "s3c24xx-i2s",
- .codec_dai_name = "wm8753-hifi",
- .codec_name = "wm8753-codec.0-0x1a",
- .init = neo1973_wm8753_init,
- .ops = &neo1973_hifi_ops,
-},
-{ /* Voice via BT */
- .name = "Bluetooth",
- .stream_name = "Voice",
- .platform_name = "samsung-audio",
- .cpu_dai_name = "bluetooth-dai",
- .codec_dai_name = "wm8753-voice",
- .codec_name = "wm8753-codec.0-0x1a",
- .ops = &neo1973_voice_ops,
-},
-};
-
-static struct snd_soc_card neo1973 = {
- .name = "neo1973",
- .dai_link = neo1973_dai,
- .num_links = ARRAY_SIZE(neo1973_dai),
-};
-
-static int lm4857_i2c_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
-{
- pr_debug("Entered %s\n", __func__);
-
- i2c = client;
-
- lm4857_write_regs();
- return 0;
-}
-
-static int lm4857_i2c_remove(struct i2c_client *client)
-{
- pr_debug("Entered %s\n", __func__);
-
- i2c = NULL;
-
- return 0;
-}
-
-static u8 lm4857_state;
-
-static int lm4857_suspend(struct i2c_client *dev, pm_message_t state)
-{
- pr_debug("Entered %s\n", __func__);
-
- dev_dbg(&dev->dev, "lm4857_suspend\n");
- lm4857_state = lm4857_regs[LM4857_CTRL] & 0xf;
- if (lm4857_state) {
- lm4857_regs[LM4857_CTRL] &= 0xf0;
- lm4857_write_regs();
- }
- return 0;
-}
-
-static int lm4857_resume(struct i2c_client *dev)
-{
- pr_debug("Entered %s\n", __func__);
-
- if (lm4857_state) {
- lm4857_regs[LM4857_CTRL] |= (lm4857_state & 0x0f);
- lm4857_write_regs();
- }
- return 0;
-}
-
-static void lm4857_shutdown(struct i2c_client *dev)
-{
- pr_debug("Entered %s\n", __func__);
-
- dev_dbg(&dev->dev, "lm4857_shutdown\n");
- lm4857_regs[LM4857_CTRL] &= 0xf0;
- lm4857_write_regs();
-}
-
-static const struct i2c_device_id lm4857_i2c_id[] = {
- { "neo1973_lm4857", 0 },
- { }
-};
-
-static struct i2c_driver lm4857_i2c_driver = {
- .driver = {
- .name = "LM4857 I2C Amp",
- .owner = THIS_MODULE,
- },
- .suspend = lm4857_suspend,
- .resume = lm4857_resume,
- .shutdown = lm4857_shutdown,
- .probe = lm4857_i2c_probe,
- .remove = lm4857_i2c_remove,
- .id_table = lm4857_i2c_id,
-};
-
-static struct platform_device *neo1973_snd_device;
-
-static int __init neo1973_init(void)
-{
- int ret;
-
- pr_debug("Entered %s\n", __func__);
-
- if (!machine_is_neo1973_gta01()) {
- printk(KERN_INFO
- "Only GTA01 hardware supported by ASoC driver\n");
- return -ENODEV;
- }
-
- neo1973_snd_device = platform_device_alloc("soc-audio", -1);
- if (!neo1973_snd_device)
- return -ENOMEM;
-
- platform_set_drvdata(neo1973_snd_device, &neo1973);
- ret = platform_device_add(neo1973_snd_device);
-
- if (ret) {
- platform_device_put(neo1973_snd_device);
- return ret;
- }
-
- ret = i2c_add_driver(&lm4857_i2c_driver);
-
- if (ret != 0)
- platform_device_unregister(neo1973_snd_device);
-
- return ret;
-}
-
-static void __exit neo1973_exit(void)
-{
- pr_debug("Entered %s\n", __func__);
-
- i2c_del_driver(&lm4857_i2c_driver);
- platform_device_unregister(neo1973_snd_device);
-}
-
-module_init(neo1973_init);
-module_exit(neo1973_exit);
-
-/* Module information */
-MODULE_AUTHOR("Graeme Gregory, graeme(a)openmoko.org, www.openmoko.org");
-MODULE_DESCRIPTION("ALSA SoC WM8753 Neo1973");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/pcm.c b/sound/soc/s3c24xx/pcm.c
deleted file mode 100644
index 4d0f6e4..0000000
--- a/sound/soc/s3c24xx/pcm.c
+++ /dev/null
@@ -1,552 +0,0 @@
-/* sound/soc/s3c24xx/pcm.c
- *
- * ALSA SoC Audio Layer - S3C PCM-Controller driver
- *
- * Copyright (c) 2009 Samsung Electronics Co. Ltd
- * Author: Jaswinder Singh <jassi.brar(a)samsung.com>
- * based upon I2S drivers by Ben Dooks.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/delay.h>
-#include <linux/clk.h>
-#include <linux/kernel.h>
-#include <linux/gpio.h>
-#include <linux/io.h>
-
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/initval.h>
-#include <sound/soc.h>
-
-#include <plat/audio.h>
-#include <plat/dma.h>
-
-#include "dma.h"
-#include "pcm.h"
-
-static struct s3c2410_dma_client s3c_pcm_dma_client_out = {
- .name = "PCM Stereo out"
-};
-
-static struct s3c2410_dma_client s3c_pcm_dma_client_in = {
- .name = "PCM Stereo in"
-};
-
-static struct s3c_dma_params s3c_pcm_stereo_out[] = {
- [0] = {
- .client = &s3c_pcm_dma_client_out,
- .dma_size = 4,
- },
- [1] = {
- .client = &s3c_pcm_dma_client_out,
- .dma_size = 4,
- },
-};
-
-static struct s3c_dma_params s3c_pcm_stereo_in[] = {
- [0] = {
- .client = &s3c_pcm_dma_client_in,
- .dma_size = 4,
- },
- [1] = {
- .client = &s3c_pcm_dma_client_in,
- .dma_size = 4,
- },
-};
-
-static struct s3c_pcm_info s3c_pcm[2];
-
-static void s3c_pcm_snd_txctrl(struct s3c_pcm_info *pcm, int on)
-{
- void __iomem *regs = pcm->regs;
- u32 ctl, clkctl;
-
- clkctl = readl(regs + S3C_PCM_CLKCTL);
- ctl = readl(regs + S3C_PCM_CTL);
- ctl &= ~(S3C_PCM_CTL_TXDIPSTICK_MASK
- << S3C_PCM_CTL_TXDIPSTICK_SHIFT);
-
- if (on) {
- ctl |= S3C_PCM_CTL_TXDMA_EN;
- ctl |= S3C_PCM_CTL_TXFIFO_EN;
- ctl |= S3C_PCM_CTL_ENABLE;
- ctl |= (0x4<<S3C_PCM_CTL_TXDIPSTICK_SHIFT);
- clkctl |= S3C_PCM_CLKCTL_SERCLK_EN;
- } else {
- ctl &= ~S3C_PCM_CTL_TXDMA_EN;
- ctl &= ~S3C_PCM_CTL_TXFIFO_EN;
-
- if (!(ctl & S3C_PCM_CTL_RXFIFO_EN)) {
- ctl &= ~S3C_PCM_CTL_ENABLE;
- if (!pcm->idleclk)
- clkctl |= S3C_PCM_CLKCTL_SERCLK_EN;
- }
- }
-
- writel(clkctl, regs + S3C_PCM_CLKCTL);
- writel(ctl, regs + S3C_PCM_CTL);
-}
-
-static void s3c_pcm_snd_rxctrl(struct s3c_pcm_info *pcm, int on)
-{
- void __iomem *regs = pcm->regs;
- u32 ctl, clkctl;
-
- ctl = readl(regs + S3C_PCM_CTL);
- clkctl = readl(regs + S3C_PCM_CLKCTL);
- ctl &= ~(S3C_PCM_CTL_RXDIPSTICK_MASK
- << S3C_PCM_CTL_RXDIPSTICK_SHIFT);
-
- if (on) {
- ctl |= S3C_PCM_CTL_RXDMA_EN;
- ctl |= S3C_PCM_CTL_RXFIFO_EN;
- ctl |= S3C_PCM_CTL_ENABLE;
- ctl |= (0x20<<S3C_PCM_CTL_RXDIPSTICK_SHIFT);
- clkctl |= S3C_PCM_CLKCTL_SERCLK_EN;
- } else {
- ctl &= ~S3C_PCM_CTL_RXDMA_EN;
- ctl &= ~S3C_PCM_CTL_RXFIFO_EN;
-
- if (!(ctl & S3C_PCM_CTL_TXFIFO_EN)) {
- ctl &= ~S3C_PCM_CTL_ENABLE;
- if (!pcm->idleclk)
- clkctl |= S3C_PCM_CLKCTL_SERCLK_EN;
- }
- }
-
- writel(clkctl, regs + S3C_PCM_CLKCTL);
- writel(ctl, regs + S3C_PCM_CTL);
-}
-
-static int s3c_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
- struct snd_soc_dai *dai)
-{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(rtd->cpu_dai);
- unsigned long flags;
-
- dev_dbg(pcm->dev, "Entered %s\n", __func__);
-
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
- case SNDRV_PCM_TRIGGER_RESUME:
- case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- spin_lock_irqsave(&pcm->lock, flags);
-
- if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
- s3c_pcm_snd_rxctrl(pcm, 1);
- else
- s3c_pcm_snd_txctrl(pcm, 1);
-
- spin_unlock_irqrestore(&pcm->lock, flags);
- break;
-
- case SNDRV_PCM_TRIGGER_STOP:
- case SNDRV_PCM_TRIGGER_SUSPEND:
- case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- spin_lock_irqsave(&pcm->lock, flags);
-
- if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
- s3c_pcm_snd_rxctrl(pcm, 0);
- else
- s3c_pcm_snd_txctrl(pcm, 0);
-
- spin_unlock_irqrestore(&pcm->lock, flags);
- break;
-
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int s3c_pcm_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params,
- struct snd_soc_dai *socdai)
-{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(rtd->cpu_dai);
- struct s3c_dma_params *dma_data;
- void __iomem *regs = pcm->regs;
- struct clk *clk;
- int sclk_div, sync_div;
- unsigned long flags;
- u32 clkctl;
-
- dev_dbg(pcm->dev, "Entered %s\n", __func__);
-
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- dma_data = pcm->dma_playback;
- else
- dma_data = pcm->dma_capture;
-
- snd_soc_dai_set_dma_data(rtd->cpu_dai, substream, dma_data);
-
- /* Strictly check for sample size */
- switch (params_format(params)) {
- case SNDRV_PCM_FORMAT_S16_LE:
- break;
- default:
- return -EINVAL;
- }
-
- spin_lock_irqsave(&pcm->lock, flags);
-
- /* Get hold of the PCMSOURCE_CLK */
- clkctl = readl(regs + S3C_PCM_CLKCTL);
- if (clkctl & S3C_PCM_CLKCTL_SERCLKSEL_PCLK)
- clk = pcm->pclk;
- else
- clk = pcm->cclk;
-
- /* Set the SCLK divider */
- sclk_div = clk_get_rate(clk) / pcm->sclk_per_fs /
- params_rate(params) / 2 - 1;
-
- clkctl &= ~(S3C_PCM_CLKCTL_SCLKDIV_MASK
- << S3C_PCM_CLKCTL_SCLKDIV_SHIFT);
- clkctl |= ((sclk_div & S3C_PCM_CLKCTL_SCLKDIV_MASK)
- << S3C_PCM_CLKCTL_SCLKDIV_SHIFT);
-
- /* Set the SYNC divider */
- sync_div = pcm->sclk_per_fs - 1;
-
- clkctl &= ~(S3C_PCM_CLKCTL_SYNCDIV_MASK
- << S3C_PCM_CLKCTL_SYNCDIV_SHIFT);
- clkctl |= ((sync_div & S3C_PCM_CLKCTL_SYNCDIV_MASK)
- << S3C_PCM_CLKCTL_SYNCDIV_SHIFT);
-
- writel(clkctl, regs + S3C_PCM_CLKCTL);
-
- spin_unlock_irqrestore(&pcm->lock, flags);
-
- dev_dbg(pcm->dev, "PCMSOURCE_CLK-%lu SCLK=%ufs SCLK_DIV=%d SYNC_DIV=%d\n",
- clk_get_rate(clk), pcm->sclk_per_fs,
- sclk_div, sync_div);
-
- return 0;
-}
-
-static int s3c_pcm_set_fmt(struct snd_soc_dai *cpu_dai,
- unsigned int fmt)
-{
- struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(cpu_dai);
- void __iomem *regs = pcm->regs;
- unsigned long flags;
- int ret = 0;
- u32 ctl;
-
- dev_dbg(pcm->dev, "Entered %s\n", __func__);
-
- spin_lock_irqsave(&pcm->lock, flags);
-
- ctl = readl(regs + S3C_PCM_CTL);
-
- switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
- case SND_SOC_DAIFMT_NB_NF:
- /* Nothing to do, NB_NF by default */
- break;
- default:
- dev_err(pcm->dev, "Unsupported clock inversion!\n");
- ret = -EINVAL;
- goto exit;
- }
-
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFS:
- /* Nothing to do, Master by default */
- break;
- default:
- dev_err(pcm->dev, "Unsupported master/slave format!\n");
- ret = -EINVAL;
- goto exit;
- }
-
- switch (fmt & SND_SOC_DAIFMT_CLOCK_MASK) {
- case SND_SOC_DAIFMT_CONT:
- pcm->idleclk = 1;
- break;
- case SND_SOC_DAIFMT_GATED:
- pcm->idleclk = 0;
- break;
- default:
- dev_err(pcm->dev, "Invalid Clock gating request!\n");
- ret = -EINVAL;
- goto exit;
- }
-
- switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
- case SND_SOC_DAIFMT_DSP_A:
- ctl |= S3C_PCM_CTL_TXMSB_AFTER_FSYNC;
- ctl |= S3C_PCM_CTL_RXMSB_AFTER_FSYNC;
- break;
- case SND_SOC_DAIFMT_DSP_B:
- ctl &= ~S3C_PCM_CTL_TXMSB_AFTER_FSYNC;
- ctl &= ~S3C_PCM_CTL_RXMSB_AFTER_FSYNC;
- break;
- default:
- dev_err(pcm->dev, "Unsupported data format!\n");
- ret = -EINVAL;
- goto exit;
- }
-
- writel(ctl, regs + S3C_PCM_CTL);
-
-exit:
- spin_unlock_irqrestore(&pcm->lock, flags);
-
- return ret;
-}
-
-static int s3c_pcm_set_clkdiv(struct snd_soc_dai *cpu_dai,
- int div_id, int div)
-{
- struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(cpu_dai);
-
- switch (div_id) {
- case S3C_PCM_SCLK_PER_FS:
- pcm->sclk_per_fs = div;
- break;
-
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int s3c_pcm_set_sysclk(struct snd_soc_dai *cpu_dai,
- int clk_id, unsigned int freq, int dir)
-{
- struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(cpu_dai);
- void __iomem *regs = pcm->regs;
- u32 clkctl = readl(regs + S3C_PCM_CLKCTL);
-
- switch (clk_id) {
- case S3C_PCM_CLKSRC_PCLK:
- clkctl |= S3C_PCM_CLKCTL_SERCLKSEL_PCLK;
- break;
-
- case S3C_PCM_CLKSRC_MUX:
- clkctl &= ~S3C_PCM_CLKCTL_SERCLKSEL_PCLK;
-
- if (clk_get_rate(pcm->cclk) != freq)
- clk_set_rate(pcm->cclk, freq);
-
- break;
-
- default:
- return -EINVAL;
- }
-
- writel(clkctl, regs + S3C_PCM_CLKCTL);
-
- return 0;
-}
-
-static struct snd_soc_dai_ops s3c_pcm_dai_ops = {
- .set_sysclk = s3c_pcm_set_sysclk,
- .set_clkdiv = s3c_pcm_set_clkdiv,
- .trigger = s3c_pcm_trigger,
- .hw_params = s3c_pcm_hw_params,
- .set_fmt = s3c_pcm_set_fmt,
-};
-
-#define S3C_PCM_RATES SNDRV_PCM_RATE_8000_96000
-
-#define S3C_PCM_DAI_DECLARE \
- .symmetric_rates = 1, \
- .ops = &s3c_pcm_dai_ops, \
- .playback = { \
- .channels_min = 2, \
- .channels_max = 2, \
- .rates = S3C_PCM_RATES, \
- .formats = SNDRV_PCM_FMTBIT_S16_LE, \
- }, \
- .capture = { \
- .channels_min = 2, \
- .channels_max = 2, \
- .rates = S3C_PCM_RATES, \
- .formats = SNDRV_PCM_FMTBIT_S16_LE, \
- }
-
-struct snd_soc_dai_driver s3c_pcm_dai[] = {
- [0] = {
- .name = "samsung-pcm.0",
- S3C_PCM_DAI_DECLARE,
- },
- [1] = {
- .name = "samsung-pcm.1",
- S3C_PCM_DAI_DECLARE,
- },
-};
-EXPORT_SYMBOL_GPL(s3c_pcm_dai);
-
-static __devinit int s3c_pcm_dev_probe(struct platform_device *pdev)
-{
- struct s3c_pcm_info *pcm;
- struct resource *mem_res, *dmatx_res, *dmarx_res;
- struct s3c_audio_pdata *pcm_pdata;
- int ret;
-
- /* Check for valid device index */
- if ((pdev->id < 0) || pdev->id >= ARRAY_SIZE(s3c_pcm)) {
- dev_err(&pdev->dev, "id %d out of range\n", pdev->id);
- return -EINVAL;
- }
-
- pcm_pdata = pdev->dev.platform_data;
-
- /* Check for availability of necessary resource */
- dmatx_res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
- if (!dmatx_res) {
- dev_err(&pdev->dev, "Unable to get PCM-TX dma resource\n");
- return -ENXIO;
- }
-
- dmarx_res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
- if (!dmarx_res) {
- dev_err(&pdev->dev, "Unable to get PCM-RX dma resource\n");
- return -ENXIO;
- }
-
- mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!mem_res) {
- dev_err(&pdev->dev, "Unable to get register resource\n");
- return -ENXIO;
- }
-
- if (pcm_pdata && pcm_pdata->cfg_gpio && pcm_pdata->cfg_gpio(pdev)) {
- dev_err(&pdev->dev, "Unable to configure gpio\n");
- return -EINVAL;
- }
-
- pcm = &s3c_pcm[pdev->id];
- pcm->dev = &pdev->dev;
-
- spin_lock_init(&pcm->lock);
-
- /* Default is 128fs */
- pcm->sclk_per_fs = 128;
-
- pcm->cclk = clk_get(&pdev->dev, "audio-bus");
- if (IS_ERR(pcm->cclk)) {
- dev_err(&pdev->dev, "failed to get audio-bus\n");
- ret = PTR_ERR(pcm->cclk);
- goto err1;
- }
- clk_enable(pcm->cclk);
-
- /* record our pcm structure for later use in the callbacks */
- dev_set_drvdata(&pdev->dev, pcm);
-
- if (!request_mem_region(mem_res->start,
- resource_size(mem_res), "samsung-pcm")) {
- dev_err(&pdev->dev, "Unable to request register region\n");
- ret = -EBUSY;
- goto err2;
- }
-
- pcm->regs = ioremap(mem_res->start, 0x100);
- if (pcm->regs == NULL) {
- dev_err(&pdev->dev, "cannot ioremap registers\n");
- ret = -ENXIO;
- goto err3;
- }
-
- pcm->pclk = clk_get(&pdev->dev, "pcm");
- if (IS_ERR(pcm->pclk)) {
- dev_err(&pdev->dev, "failed to get pcm_clock\n");
- ret = -ENOENT;
- goto err4;
- }
- clk_enable(pcm->pclk);
-
- ret = snd_soc_register_dai(&pdev->dev, &s3c_pcm_dai[pdev->id]);
- if (ret != 0) {
- dev_err(&pdev->dev, "failed to get pcm_clock\n");
- goto err5;
- }
-
- s3c_pcm_stereo_in[pdev->id].dma_addr = mem_res->start
- + S3C_PCM_RXFIFO;
- s3c_pcm_stereo_out[pdev->id].dma_addr = mem_res->start
- + S3C_PCM_TXFIFO;
-
- s3c_pcm_stereo_in[pdev->id].channel = dmarx_res->start;
- s3c_pcm_stereo_out[pdev->id].channel = dmatx_res->start;
-
- pcm->dma_capture = &s3c_pcm_stereo_in[pdev->id];
- pcm->dma_playback = &s3c_pcm_stereo_out[pdev->id];
-
- return 0;
-
-err5:
- clk_disable(pcm->pclk);
- clk_put(pcm->pclk);
-err4:
- iounmap(pcm->regs);
-err3:
- release_mem_region(mem_res->start, resource_size(mem_res));
-err2:
- clk_disable(pcm->cclk);
- clk_put(pcm->cclk);
-err1:
- return ret;
-}
-
-static __devexit int s3c_pcm_dev_remove(struct platform_device *pdev)
-{
- struct s3c_pcm_info *pcm = &s3c_pcm[pdev->id];
- struct resource *mem_res;
-
- snd_soc_unregister_dai(&pdev->dev);
-
- iounmap(pcm->regs);
-
- mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- release_mem_region(mem_res->start, resource_size(mem_res));
-
- clk_disable(pcm->cclk);
- clk_disable(pcm->pclk);
- clk_put(pcm->pclk);
- clk_put(pcm->cclk);
-
- return 0;
-}
-
-static struct platform_driver s3c_pcm_driver = {
- .probe = s3c_pcm_dev_probe,
- .remove = s3c_pcm_dev_remove,
- .driver = {
- .name = "samsung-pcm",
- .owner = THIS_MODULE,
- },
-};
-
-static int __init s3c_pcm_init(void)
-{
- return platform_driver_register(&s3c_pcm_driver);
-}
-module_init(s3c_pcm_init);
-
-static void __exit s3c_pcm_exit(void)
-{
- platform_driver_unregister(&s3c_pcm_driver);
-}
-module_exit(s3c_pcm_exit);
-
-/* Module information */
-MODULE_AUTHOR("Jaswinder Singh, <jassi.brar(a)samsung.com>");
-MODULE_DESCRIPTION("S3C PCM Controller Driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:samsung-pcm");
diff --git a/sound/soc/s3c24xx/pcm.h b/sound/soc/s3c24xx/pcm.h
deleted file mode 100644
index 3775216..0000000
--- a/sound/soc/s3c24xx/pcm.h
+++ /dev/null
@@ -1,124 +0,0 @@
-/* sound/soc/s3c24xx/pcm.h
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- */
-
-#ifndef __S3C_PCM_H
-#define __S3C_PCM_H __FILE__
-
-/*Register Offsets */
-#define S3C_PCM_CTL (0x00)
-#define S3C_PCM_CLKCTL (0x04)
-#define S3C_PCM_TXFIFO (0x08)
-#define S3C_PCM_RXFIFO (0x0C)
-#define S3C_PCM_IRQCTL (0x10)
-#define S3C_PCM_IRQSTAT (0x14)
-#define S3C_PCM_FIFOSTAT (0x18)
-#define S3C_PCM_CLRINT (0x20)
-
-/* PCM_CTL Bit-Fields */
-#define S3C_PCM_CTL_TXDIPSTICK_MASK (0x3f)
-#define S3C_PCM_CTL_TXDIPSTICK_SHIFT (13)
-#define S3C_PCM_CTL_RXDIPSTICK_MASK (0x3f)
-#define S3C_PCM_CTL_RXDIPSTICK_SHIFT (7)
-#define S3C_PCM_CTL_TXDMA_EN (0x1<<6)
-#define S3C_PCM_CTL_RXDMA_EN (0x1<<5)
-#define S3C_PCM_CTL_TXMSB_AFTER_FSYNC (0x1<<4)
-#define S3C_PCM_CTL_RXMSB_AFTER_FSYNC (0x1<<3)
-#define S3C_PCM_CTL_TXFIFO_EN (0x1<<2)
-#define S3C_PCM_CTL_RXFIFO_EN (0x1<<1)
-#define S3C_PCM_CTL_ENABLE (0x1<<0)
-
-/* PCM_CLKCTL Bit-Fields */
-#define S3C_PCM_CLKCTL_SERCLK_EN (0x1<<19)
-#define S3C_PCM_CLKCTL_SERCLKSEL_PCLK (0x1<<18)
-#define S3C_PCM_CLKCTL_SCLKDIV_MASK (0x1ff)
-#define S3C_PCM_CLKCTL_SYNCDIV_MASK (0x1ff)
-#define S3C_PCM_CLKCTL_SCLKDIV_SHIFT (9)
-#define S3C_PCM_CLKCTL_SYNCDIV_SHIFT (0)
-
-/* PCM_TXFIFO Bit-Fields */
-#define S3C_PCM_TXFIFO_DVALID (0x1<<16)
-#define S3C_PCM_TXFIFO_DATA_MSK (0xffff<<0)
-
-/* PCM_RXFIFO Bit-Fields */
-#define S3C_PCM_RXFIFO_DVALID (0x1<<16)
-#define S3C_PCM_RXFIFO_DATA_MSK (0xffff<<0)
-
-/* PCM_IRQCTL Bit-Fields */
-#define S3C_PCM_IRQCTL_IRQEN (0x1<<14)
-#define S3C_PCM_IRQCTL_WRDEN (0x1<<12)
-#define S3C_PCM_IRQCTL_TXEMPTYEN (0x1<<11)
-#define S3C_PCM_IRQCTL_TXALMSTEMPTYEN (0x1<<10)
-#define S3C_PCM_IRQCTL_TXFULLEN (0x1<<9)
-#define S3C_PCM_IRQCTL_TXALMSTFULLEN (0x1<<8)
-#define S3C_PCM_IRQCTL_TXSTARVEN (0x1<<7)
-#define S3C_PCM_IRQCTL_TXERROVRFLEN (0x1<<6)
-#define S3C_PCM_IRQCTL_RXEMPTEN (0x1<<5)
-#define S3C_PCM_IRQCTL_RXALMSTEMPTEN (0x1<<4)
-#define S3C_PCM_IRQCTL_RXFULLEN (0x1<<3)
-#define S3C_PCM_IRQCTL_RXALMSTFULLEN (0x1<<2)
-#define S3C_PCM_IRQCTL_RXSTARVEN (0x1<<1)
-#define S3C_PCM_IRQCTL_RXERROVRFLEN (0x1<<0)
-
-/* PCM_IRQSTAT Bit-Fields */
-#define S3C_PCM_IRQSTAT_IRQPND (0x1<<13)
-#define S3C_PCM_IRQSTAT_WRD_XFER (0x1<<12)
-#define S3C_PCM_IRQSTAT_TXEMPTY (0x1<<11)
-#define S3C_PCM_IRQSTAT_TXALMSTEMPTY (0x1<<10)
-#define S3C_PCM_IRQSTAT_TXFULL (0x1<<9)
-#define S3C_PCM_IRQSTAT_TXALMSTFULL (0x1<<8)
-#define S3C_PCM_IRQSTAT_TXSTARV (0x1<<7)
-#define S3C_PCM_IRQSTAT_TXERROVRFL (0x1<<6)
-#define S3C_PCM_IRQSTAT_RXEMPT (0x1<<5)
-#define S3C_PCM_IRQSTAT_RXALMSTEMPT (0x1<<4)
-#define S3C_PCM_IRQSTAT_RXFULL (0x1<<3)
-#define S3C_PCM_IRQSTAT_RXALMSTFULL (0x1<<2)
-#define S3C_PCM_IRQSTAT_RXSTARV (0x1<<1)
-#define S3C_PCM_IRQSTAT_RXERROVRFL (0x1<<0)
-
-/* PCM_FIFOSTAT Bit-Fields */
-#define S3C_PCM_FIFOSTAT_TXCNT_MSK (0x3f<<14)
-#define S3C_PCM_FIFOSTAT_TXFIFOEMPTY (0x1<<13)
-#define S3C_PCM_FIFOSTAT_TXFIFOALMSTEMPTY (0x1<<12)
-#define S3C_PCM_FIFOSTAT_TXFIFOFULL (0x1<<11)
-#define S3C_PCM_FIFOSTAT_TXFIFOALMSTFULL (0x1<<10)
-#define S3C_PCM_FIFOSTAT_RXCNT_MSK (0x3f<<4)
-#define S3C_PCM_FIFOSTAT_RXFIFOEMPTY (0x1<<3)
-#define S3C_PCM_FIFOSTAT_RXFIFOALMSTEMPTY (0x1<<2)
-#define S3C_PCM_FIFOSTAT_RXFIFOFULL (0x1<<1)
-#define S3C_PCM_FIFOSTAT_RXFIFOALMSTFULL (0x1<<0)
-
-#define S3C_PCM_CLKSRC_PCLK 0
-#define S3C_PCM_CLKSRC_MUX 1
-
-#define S3C_PCM_SCLK_PER_FS 0
-
-/**
- * struct s3c_pcm_info - S3C PCM Controller information
- * @dev: The parent device passed to use from the probe.
- * @regs: The pointer to the device register block.
- * @dma_playback: DMA information for playback channel.
- * @dma_capture: DMA information for capture channel.
- */
-struct s3c_pcm_info {
- spinlock_t lock;
- struct device *dev;
- void __iomem *regs;
-
- unsigned int sclk_per_fs;
-
- /* Whether to keep PCMSCLK enabled even when idle(no active xfer) */
- unsigned int idleclk;
-
- struct clk *pclk;
- struct clk *cclk;
-
- struct s3c_dma_params *dma_playback;
- struct s3c_dma_params *dma_capture;
-};
-
-#endif /* __S3C_PCM_H */
diff --git a/sound/soc/s3c24xx/regs-i2s-v2.h b/sound/soc/s3c24xx/regs-i2s-v2.h
deleted file mode 100644
index 5e5e568..0000000
--- a/sound/soc/s3c24xx/regs-i2s-v2.h
+++ /dev/null
@@ -1,115 +0,0 @@
-/* linux/include/asm-arm/plat-s3c24xx/regs-s3c2412-iis.h
- *
- * Copyright 2007 Simtec Electronics <linux(a)simtec.co.uk>
- * http://armlinux.simtec.co.uk/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * S3C2412 IIS register definition
-*/
-
-#ifndef __ASM_ARCH_REGS_S3C2412_IIS_H
-#define __ASM_ARCH_REGS_S3C2412_IIS_H
-
-#define S3C2412_IISCON (0x00)
-#define S3C2412_IISMOD (0x04)
-#define S3C2412_IISFIC (0x08)
-#define S3C2412_IISPSR (0x0C)
-#define S3C2412_IISTXD (0x10)
-#define S3C2412_IISRXD (0x14)
-
-#define S5PC1XX_IISFICS 0x18
-#define S5PC1XX_IISTXDS 0x1C
-
-#define S5PC1XX_IISCON_SW_RST (1 << 31)
-#define S5PC1XX_IISCON_FRXOFSTATUS (1 << 26)
-#define S5PC1XX_IISCON_FRXORINTEN (1 << 25)
-#define S5PC1XX_IISCON_FTXSURSTAT (1 << 24)
-#define S5PC1XX_IISCON_FTXSURINTEN (1 << 23)
-#define S5PC1XX_IISCON_TXSDMAPAUSE (1 << 20)
-#define S5PC1XX_IISCON_TXSDMACTIVE (1 << 18)
-
-#define S3C64XX_IISCON_FTXURSTATUS (1 << 17)
-#define S3C64XX_IISCON_FTXURINTEN (1 << 16)
-#define S3C64XX_IISCON_TXFIFO2_EMPTY (1 << 15)
-#define S3C64XX_IISCON_TXFIFO1_EMPTY (1 << 14)
-#define S3C64XX_IISCON_TXFIFO2_FULL (1 << 13)
-#define S3C64XX_IISCON_TXFIFO1_FULL (1 << 12)
-
-#define S3C2412_IISCON_LRINDEX (1 << 11)
-#define S3C2412_IISCON_TXFIFO_EMPTY (1 << 10)
-#define S3C2412_IISCON_RXFIFO_EMPTY (1 << 9)
-#define S3C2412_IISCON_TXFIFO_FULL (1 << 8)
-#define S3C2412_IISCON_RXFIFO_FULL (1 << 7)
-#define S3C2412_IISCON_TXDMA_PAUSE (1 << 6)
-#define S3C2412_IISCON_RXDMA_PAUSE (1 << 5)
-#define S3C2412_IISCON_TXCH_PAUSE (1 << 4)
-#define S3C2412_IISCON_RXCH_PAUSE (1 << 3)
-#define S3C2412_IISCON_TXDMA_ACTIVE (1 << 2)
-#define S3C2412_IISCON_RXDMA_ACTIVE (1 << 1)
-#define S3C2412_IISCON_IIS_ACTIVE (1 << 0)
-
-#define S5PC1XX_IISMOD_OPCLK_CDCLK_OUT (0 << 30)
-#define S5PC1XX_IISMOD_OPCLK_CDCLK_IN (1 << 30)
-#define S5PC1XX_IISMOD_OPCLK_BCLK_OUT (2 << 30)
-#define S5PC1XX_IISMOD_OPCLK_PCLK (3 << 30)
-#define S5PC1XX_IISMOD_OPCLK_MASK (3 << 30)
-#define S5PC1XX_IISMOD_TXS_IDMA (1 << 28) /* Sec_TXFIFO use I-DMA */
-#define S5PC1XX_IISMOD_BLCS_MASK 0x3
-#define S5PC1XX_IISMOD_BLCS_SHIFT 26
-#define S5PC1XX_IISMOD_BLCP_MASK 0x3
-#define S5PC1XX_IISMOD_BLCP_SHIFT 24
-
-#define S3C64XX_IISMOD_C2DD_HHALF (1 << 21) /* Discard Higher-half */
-#define S3C64XX_IISMOD_C2DD_LHALF (1 << 20) /* Discard Lower-half */
-#define S3C64XX_IISMOD_C1DD_HHALF (1 << 19)
-#define S3C64XX_IISMOD_C1DD_LHALF (1 << 18)
-#define S3C64XX_IISMOD_DC2_EN (1 << 17)
-#define S3C64XX_IISMOD_DC1_EN (1 << 16)
-#define S3C64XX_IISMOD_BLC_16BIT (0 << 13)
-#define S3C64XX_IISMOD_BLC_8BIT (1 << 13)
-#define S3C64XX_IISMOD_BLC_24BIT (2 << 13)
-#define S3C64XX_IISMOD_BLC_MASK (3 << 13)
-
-#define S3C2412_IISMOD_IMS_SYSMUX (1 << 10)
-#define S3C2412_IISMOD_SLAVE (1 << 11)
-#define S3C2412_IISMOD_MODE_TXONLY (0 << 8)
-#define S3C2412_IISMOD_MODE_RXONLY (1 << 8)
-#define S3C2412_IISMOD_MODE_TXRX (2 << 8)
-#define S3C2412_IISMOD_MODE_MASK (3 << 8)
-#define S3C2412_IISMOD_LR_LLOW (0 << 7)
-#define S3C2412_IISMOD_LR_RLOW (1 << 7)
-#define S3C2412_IISMOD_SDF_IIS (0 << 5)
-#define S3C2412_IISMOD_SDF_MSB (1 << 5)
-#define S3C2412_IISMOD_SDF_LSB (2 << 5)
-#define S3C2412_IISMOD_SDF_MASK (3 << 5)
-#define S3C2412_IISMOD_RCLK_256FS (0 << 3)
-#define S3C2412_IISMOD_RCLK_512FS (1 << 3)
-#define S3C2412_IISMOD_RCLK_384FS (2 << 3)
-#define S3C2412_IISMOD_RCLK_768FS (3 << 3)
-#define S3C2412_IISMOD_RCLK_MASK (3 << 3)
-#define S3C2412_IISMOD_BCLK_32FS (0 << 1)
-#define S3C2412_IISMOD_BCLK_48FS (1 << 1)
-#define S3C2412_IISMOD_BCLK_16FS (2 << 1)
-#define S3C2412_IISMOD_BCLK_24FS (3 << 1)
-#define S3C2412_IISMOD_BCLK_MASK (3 << 1)
-#define S3C2412_IISMOD_8BIT (1 << 0)
-
-#define S3C64XX_IISMOD_CDCLKCON (1 << 12)
-
-#define S3C2412_IISPSR_PSREN (1 << 15)
-
-#define S3C64XX_IISFIC_TX2COUNT(x) (((x) >> 24) & 0xf)
-#define S3C64XX_IISFIC_TX1COUNT(x) (((x) >> 16) & 0xf)
-
-#define S3C2412_IISFIC_TXFLUSH (1 << 15)
-#define S3C2412_IISFIC_RXFLUSH (1 << 7)
-#define S3C2412_IISFIC_TXCOUNT(x) (((x) >> 8) & 0xf)
-#define S3C2412_IISFIC_RXCOUNT(x) (((x) >> 0) & 0xf)
-
-#define S5PC1XX_IISFICS_TXFLUSH (1 << 15)
-#define S5PC1XX_IISFICS_TXCOUNT(x) (((x) >> 8) & 0x7f)
-
-#endif /* __ASM_ARCH_REGS_S3C2412_IIS_H */
diff --git a/sound/soc/s3c24xx/rx1950_uda1380.c b/sound/soc/s3c24xx/rx1950_uda1380.c
deleted file mode 100644
index 07197ee..0000000
--- a/sound/soc/s3c24xx/rx1950_uda1380.c
+++ /dev/null
@@ -1,333 +0,0 @@
-/*
- * rx1950.c -- ALSA Soc Audio Layer
- *
- * Copyright (c) 2010 Vasily Khoruzhick <anarsoul(a)gmail.com>
- *
- * Based on smdk2440.c and magician.c
- *
- * Authors: Graeme Gregory graeme.gregory(a)wolfsonmicro.com
- * Philipp Zabel <philipp.zabel(a)gmail.com>
- * Denis Grigoriev <dgreenday(a)gmail.com>
- * Vasily Khoruzhick <anarsoul(a)gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/platform_device.h>
-#include <linux/i2c.h>
-#include <linux/gpio.h>
-#include <linux/clk.h>
-
-#include <sound/soc.h>
-#include <sound/soc-dapm.h>
-#include <sound/uda1380.h>
-#include <sound/jack.h>
-
-#include <plat/regs-iis.h>
-
-#include <mach/regs-clock.h>
-
-#include <asm/mach-types.h>
-
-#include "dma.h"
-#include "s3c24xx-i2s.h"
-#include "../codecs/uda1380.h"
-
-static int rx1950_uda1380_init(struct snd_soc_pcm_runtime *rtd);
-static int rx1950_startup(struct snd_pcm_substream *substream);
-static int rx1950_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params);
-static int rx1950_spk_power(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event);
-
-static unsigned int rates[] = {
- 16000,
- 44100,
- 48000,
- 88200,
-};
-
-static struct snd_pcm_hw_constraint_list hw_rates = {
- .count = ARRAY_SIZE(rates),
- .list = rates,
- .mask = 0,
-};
-
-static struct snd_soc_jack hp_jack;
-
-static struct snd_soc_jack_pin hp_jack_pins[] = {
- {
- .pin = "Headphone Jack",
- .mask = SND_JACK_HEADPHONE,
- },
- {
- .pin = "Speaker",
- .mask = SND_JACK_HEADPHONE,
- .invert = 1,
- },
-};
-
-static struct snd_soc_jack_gpio hp_jack_gpios[] = {
- [0] = {
- .gpio = S3C2410_GPG(12),
- .name = "hp-gpio",
- .report = SND_JACK_HEADPHONE,
- .invert = 1,
- .debounce_time = 200,
- },
-};
-
-static struct snd_soc_ops rx1950_ops = {
- .startup = rx1950_startup,
- .hw_params = rx1950_hw_params,
-};
-
-/* s3c24xx digital audio interface glue - connects codec <--> CPU */
-static struct snd_soc_dai_link rx1950_uda1380_dai[] = {
- {
- .name = "uda1380",
- .stream_name = "UDA1380 Duplex",
- .cpu_dai_name = "s3c24xx-iis",
- .codec_dai_name = "uda1380-hifi",
- .init = rx1950_uda1380_init,
- .platform_name = "samsung-audio",
- .codec_name = "uda1380-codec.0-001a",
- .ops = &rx1950_ops,
- },
-};
-
-static struct snd_soc_card rx1950_asoc = {
- .name = "rx1950",
- .dai_link = rx1950_uda1380_dai,
- .num_links = ARRAY_SIZE(rx1950_uda1380_dai),
-};
-
-/* rx1950 machine dapm widgets */
-static const struct snd_soc_dapm_widget uda1380_dapm_widgets[] = {
- SND_SOC_DAPM_HP("Headphone Jack", NULL),
- SND_SOC_DAPM_MIC("Mic Jack", NULL),
- SND_SOC_DAPM_SPK("Speaker", rx1950_spk_power),
-};
-
-/* rx1950 machine audio_map */
-static const struct snd_soc_dapm_route audio_map[] = {
- /* headphone connected to VOUTLHP, VOUTRHP */
- {"Headphone Jack", NULL, "VOUTLHP"},
- {"Headphone Jack", NULL, "VOUTRHP"},
-
- /* ext speaker connected to VOUTL, VOUTR */
- {"Speaker", NULL, "VOUTL"},
- {"Speaker", NULL, "VOUTR"},
-
- /* mic is connected to VINM */
- {"VINM", NULL, "Mic Jack"},
-};
-
-static struct platform_device *s3c24xx_snd_device;
-static struct clk *xtal;
-
-static int rx1950_startup(struct snd_pcm_substream *substream)
-{
- struct snd_pcm_runtime *runtime = substream->runtime;
-
- runtime->hw.rate_min = hw_rates.list[0];
- runtime->hw.rate_max = hw_rates.list[hw_rates.count - 1];
- runtime->hw.rates = SNDRV_PCM_RATE_KNOT;
-
- return snd_pcm_hw_constraint_list(runtime, 0,
- SNDRV_PCM_HW_PARAM_RATE,
- &hw_rates);
-}
-
-static int rx1950_spk_power(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
-{
- if (SND_SOC_DAPM_EVENT_ON(event))
- gpio_set_value(S3C2410_GPA(1), 1);
- else
- gpio_set_value(S3C2410_GPA(1), 0);
-
- return 0;
-}
-
-static int rx1950_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
-{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- struct snd_soc_dai *codec_dai = rtd->codec_dai;
- int div;
- int ret;
- unsigned int rate = params_rate(params);
- int clk_source, fs_mode;
-
- switch (rate) {
- case 16000:
- case 48000:
- clk_source = S3C24XX_CLKSRC_PCLK;
- fs_mode = S3C2410_IISMOD_256FS;
- div = s3c24xx_i2s_get_clockrate() / (256 * rate);
- if (s3c24xx_i2s_get_clockrate() % (256 * rate) > (128 * rate))
- div++;
- break;
- case 44100:
- case 88200:
- clk_source = S3C24XX_CLKSRC_MPLL;
- fs_mode = S3C2410_IISMOD_256FS;
- div = clk_get_rate(xtal) / (256 * rate);
- if (clk_get_rate(xtal) % (256 * rate) > (128 * rate))
- div++;
- break;
- default:
- printk(KERN_ERR "%s: rate %d is not supported\n",
- __func__, rate);
- return -EINVAL;
- }
-
- /* set codec DAI configuration */
- ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
- if (ret < 0)
- return ret;
-
- /* set cpu DAI configuration */
- ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
- if (ret < 0)
- return ret;
-
- /* select clock source */
- ret = snd_soc_dai_set_sysclk(cpu_dai, clk_source, rate,
- SND_SOC_CLOCK_OUT);
- if (ret < 0)
- return ret;
-
- /* set MCLK division for sample rate */
- ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK,
- S3C2410_IISMOD_384FS);
- if (ret < 0)
- return ret;
-
- /* set BCLK division for sample rate */
- ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_BCLK,
- S3C2410_IISMOD_32FS);
- if (ret < 0)
- return ret;
-
- /* set prescaler division for sample rate */
- ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER,
- S3C24XX_PRESCALE(div, div));
- if (ret < 0)
- return ret;
-
- return 0;
-}
-
-static int rx1950_uda1380_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_soc_codec *codec = rtd->codec;
- int err;
-
- /* Add rx1950 specific widgets */
- err = snd_soc_dapm_new_controls(codec, uda1380_dapm_widgets,
- ARRAY_SIZE(uda1380_dapm_widgets));
-
- if (err)
- return err;
-
- /* Set up rx1950 specific audio path audio_mapnects */
- err = snd_soc_dapm_add_routes(codec, audio_map,
- ARRAY_SIZE(audio_map));
-
- if (err)
- return err;
-
- snd_soc_dapm_enable_pin(codec, "Headphone Jack");
- snd_soc_dapm_enable_pin(codec, "Speaker");
-
- snd_soc_dapm_sync(codec);
-
- snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE,
- &hp_jack);
-
- snd_soc_jack_add_pins(&hp_jack, ARRAY_SIZE(hp_jack_pins),
- hp_jack_pins);
-
- snd_soc_jack_add_gpios(&hp_jack, ARRAY_SIZE(hp_jack_gpios),
- hp_jack_gpios);
-
- return 0;
-}
-
-static int __init rx1950_init(void)
-{
- int ret;
-
- if (!machine_is_rx1950())
- return -ENODEV;
-
- /* configure some gpios */
- ret = gpio_request(S3C2410_GPA(1), "speaker-power");
- if (ret)
- goto err_gpio;
-
- ret = gpio_direction_output(S3C2410_GPA(1), 0);
- if (ret)
- goto err_gpio_conf;
-
- s3c24xx_snd_device = platform_device_alloc("soc-audio", -1);
- if (!s3c24xx_snd_device) {
- ret = -ENOMEM;
- goto err_plat_alloc;
- }
-
- platform_set_drvdata(s3c24xx_snd_device, &rx1950_asoc);
- ret = platform_device_add(s3c24xx_snd_device);
-
- if (ret) {
- platform_device_put(s3c24xx_snd_device);
- goto err_plat_add;
- }
-
- xtal = clk_get(&s3c24xx_snd_device->dev, "xtal");
-
- if (IS_ERR(xtal)) {
- ret = PTR_ERR(xtal);
- platform_device_unregister(s3c24xx_snd_device);
- goto err_clk;
- }
-
- return 0;
-
-err_clk:
-err_plat_add:
-err_plat_alloc:
-err_gpio_conf:
- gpio_free(S3C2410_GPA(1));
-
-err_gpio:
- return ret;
-}
-
-static void __exit rx1950_exit(void)
-{
- platform_device_unregister(s3c24xx_snd_device);
- snd_soc_jack_free_gpios(&hp_jack, ARRAY_SIZE(hp_jack_gpios),
- hp_jack_gpios);
- clk_put(xtal);
- gpio_free(S3C2410_GPA(1));
-}
-
-module_init(rx1950_init);
-module_exit(rx1950_exit);
-
-/* Module information */
-MODULE_AUTHOR("Vasily Khoruzhick");
-MODULE_DESCRIPTION("ALSA SoC RX1950");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/s3c-i2s-v2.c b/sound/soc/s3c24xx/s3c-i2s-v2.c
deleted file mode 100644
index c471431..0000000
--- a/sound/soc/s3c24xx/s3c-i2s-v2.c
+++ /dev/null
@@ -1,757 +0,0 @@
-/* sound/soc/s3c24xx/s3c-i2c-v2.c
- *
- * ALSA Soc Audio Layer - I2S core for newer Samsung SoCs.
- *
- * Copyright (c) 2006 Wolfson Microelectronics PLC.
- * Graeme Gregory graeme.gregory(a)wolfsonmicro.com
- * linux(a)wolfsonmicro.com
- *
- * Copyright (c) 2008, 2007, 2004-2005 Simtec Electronics
- * http://armlinux.simtec.co.uk/
- * Ben Dooks <ben(a)simtec.co.uk>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- */
-
-#include <linux/delay.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-
-#include <mach/dma.h>
-
-#include "regs-i2s-v2.h"
-#include "s3c-i2s-v2.h"
-#include "dma.h"
-
-#undef S3C_IIS_V2_SUPPORTED
-
-#if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413) \
- || defined(CONFIG_CPU_S5PV210)
-#define S3C_IIS_V2_SUPPORTED
-#endif
-
-#ifdef CONFIG_PLAT_S3C64XX
-#define S3C_IIS_V2_SUPPORTED
-#endif
-
-#ifndef S3C_IIS_V2_SUPPORTED
-#error Unsupported CPU model
-#endif
-
-#define S3C2412_I2S_DEBUG_CON 0
-
-static inline struct s3c_i2sv2_info *to_info(struct snd_soc_dai *cpu_dai)
-{
- return snd_soc_dai_get_drvdata(cpu_dai);
-}
-
-#define bit_set(v, b) (((v) & (b)) ? 1 : 0)
-
-#if S3C2412_I2S_DEBUG_CON
-static void dbg_showcon(const char *fn, u32 con)
-{
- printk(KERN_DEBUG "%s: LRI=%d, TXFEMPT=%d, RXFEMPT=%d, TXFFULL=%d, RXFFULL=%d\n", fn,
- bit_set(con, S3C2412_IISCON_LRINDEX),
- bit_set(con, S3C2412_IISCON_TXFIFO_EMPTY),
- bit_set(con, S3C2412_IISCON_RXFIFO_EMPTY),
- bit_set(con, S3C2412_IISCON_TXFIFO_FULL),
- bit_set(con, S3C2412_IISCON_RXFIFO_FULL));
-
- printk(KERN_DEBUG "%s: PAUSE: TXDMA=%d, RXDMA=%d, TXCH=%d, RXCH=%d\n",
- fn,
- bit_set(con, S3C2412_IISCON_TXDMA_PAUSE),
- bit_set(con, S3C2412_IISCON_RXDMA_PAUSE),
- bit_set(con, S3C2412_IISCON_TXCH_PAUSE),
- bit_set(con, S3C2412_IISCON_RXCH_PAUSE));
- printk(KERN_DEBUG "%s: ACTIVE: TXDMA=%d, RXDMA=%d, IIS=%d\n", fn,
- bit_set(con, S3C2412_IISCON_TXDMA_ACTIVE),
- bit_set(con, S3C2412_IISCON_RXDMA_ACTIVE),
- bit_set(con, S3C2412_IISCON_IIS_ACTIVE));
-}
-#else
-static inline void dbg_showcon(const char *fn, u32 con)
-{
-}
-#endif
-
-
-/* Turn on or off the transmission path. */
-static void s3c2412_snd_txctrl(struct s3c_i2sv2_info *i2s, int on)
-{
- void __iomem *regs = i2s->regs;
- u32 fic, con, mod;
-
- pr_debug("%s(%d)\n", __func__, on);
-
- fic = readl(regs + S3C2412_IISFIC);
- con = readl(regs + S3C2412_IISCON);
- mod = readl(regs + S3C2412_IISMOD);
-
- pr_debug("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
-
- if (on) {
- con |= S3C2412_IISCON_TXDMA_ACTIVE | S3C2412_IISCON_IIS_ACTIVE;
- con &= ~S3C2412_IISCON_TXDMA_PAUSE;
- con &= ~S3C2412_IISCON_TXCH_PAUSE;
-
- switch (mod & S3C2412_IISMOD_MODE_MASK) {
- case S3C2412_IISMOD_MODE_TXONLY:
- case S3C2412_IISMOD_MODE_TXRX:
- /* do nothing, we are in the right mode */
- break;
-
- case S3C2412_IISMOD_MODE_RXONLY:
- mod &= ~S3C2412_IISMOD_MODE_MASK;
- mod |= S3C2412_IISMOD_MODE_TXRX;
- break;
-
- default:
- dev_err(i2s->dev, "TXEN: Invalid MODE %x in IISMOD\n",
- mod & S3C2412_IISMOD_MODE_MASK);
- break;
- }
-
- writel(con, regs + S3C2412_IISCON);
- writel(mod, regs + S3C2412_IISMOD);
- } else {
- /* Note, we do not have any indication that the FIFO problems
- * tha the S3C2410/2440 had apply here, so we should be able
- * to disable the DMA and TX without resetting the FIFOS.
- */
-
- con |= S3C2412_IISCON_TXDMA_PAUSE;
- con |= S3C2412_IISCON_TXCH_PAUSE;
- con &= ~S3C2412_IISCON_TXDMA_ACTIVE;
-
- switch (mod & S3C2412_IISMOD_MODE_MASK) {
- case S3C2412_IISMOD_MODE_TXRX:
- mod &= ~S3C2412_IISMOD_MODE_MASK;
- mod |= S3C2412_IISMOD_MODE_RXONLY;
- break;
-
- case S3C2412_IISMOD_MODE_TXONLY:
- mod &= ~S3C2412_IISMOD_MODE_MASK;
- con &= ~S3C2412_IISCON_IIS_ACTIVE;
- break;
-
- default:
- dev_err(i2s->dev, "TXDIS: Invalid MODE %x in IISMOD\n",
- mod & S3C2412_IISMOD_MODE_MASK);
- break;
- }
-
- writel(mod, regs + S3C2412_IISMOD);
- writel(con, regs + S3C2412_IISCON);
- }
-
- fic = readl(regs + S3C2412_IISFIC);
- dbg_showcon(__func__, con);
- pr_debug("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
-}
-
-static void s3c2412_snd_rxctrl(struct s3c_i2sv2_info *i2s, int on)
-{
- void __iomem *regs = i2s->regs;
- u32 fic, con, mod;
-
- pr_debug("%s(%d)\n", __func__, on);
-
- fic = readl(regs + S3C2412_IISFIC);
- con = readl(regs + S3C2412_IISCON);
- mod = readl(regs + S3C2412_IISMOD);
-
- pr_debug("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
-
- if (on) {
- con |= S3C2412_IISCON_RXDMA_ACTIVE | S3C2412_IISCON_IIS_ACTIVE;
- con &= ~S3C2412_IISCON_RXDMA_PAUSE;
- con &= ~S3C2412_IISCON_RXCH_PAUSE;
-
- switch (mod & S3C2412_IISMOD_MODE_MASK) {
- case S3C2412_IISMOD_MODE_TXRX:
- case S3C2412_IISMOD_MODE_RXONLY:
- /* do nothing, we are in the right mode */
- break;
-
- case S3C2412_IISMOD_MODE_TXONLY:
- mod &= ~S3C2412_IISMOD_MODE_MASK;
- mod |= S3C2412_IISMOD_MODE_TXRX;
- break;
-
- default:
- dev_err(i2s->dev, "RXEN: Invalid MODE %x in IISMOD\n",
- mod & S3C2412_IISMOD_MODE_MASK);
- }
-
- writel(mod, regs + S3C2412_IISMOD);
- writel(con, regs + S3C2412_IISCON);
- } else {
- /* See txctrl notes on FIFOs. */
-
- con &= ~S3C2412_IISCON_RXDMA_ACTIVE;
- con |= S3C2412_IISCON_RXDMA_PAUSE;
- con |= S3C2412_IISCON_RXCH_PAUSE;
-
- switch (mod & S3C2412_IISMOD_MODE_MASK) {
- case S3C2412_IISMOD_MODE_RXONLY:
- con &= ~S3C2412_IISCON_IIS_ACTIVE;
- mod &= ~S3C2412_IISMOD_MODE_MASK;
- break;
-
- case S3C2412_IISMOD_MODE_TXRX:
- mod &= ~S3C2412_IISMOD_MODE_MASK;
- mod |= S3C2412_IISMOD_MODE_TXONLY;
- break;
-
- default:
- dev_err(i2s->dev, "RXDIS: Invalid MODE %x in IISMOD\n",
- mod & S3C2412_IISMOD_MODE_MASK);
- }
-
- writel(con, regs + S3C2412_IISCON);
- writel(mod, regs + S3C2412_IISMOD);
- }
-
- fic = readl(regs + S3C2412_IISFIC);
- pr_debug("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
-}
-
-#define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t)
-
-/*
- * Wait for the LR signal to allow synchronisation to the L/R clock
- * from the codec. May only be needed for slave mode.
- */
-static int s3c2412_snd_lrsync(struct s3c_i2sv2_info *i2s)
-{
- u32 iiscon;
- unsigned long loops = msecs_to_loops(5);
-
- pr_debug("Entered %s\n", __func__);
-
- while (--loops) {
- iiscon = readl(i2s->regs + S3C2412_IISCON);
- if (iiscon & S3C2412_IISCON_LRINDEX)
- break;
-
- cpu_relax();
- }
-
- if (!loops) {
- printk(KERN_ERR "%s: timeout\n", __func__);
- return -ETIMEDOUT;
- }
-
- return 0;
-}
-
-/*
- * Set S3C2412 I2S DAI format
- */
-static int s3c2412_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
- unsigned int fmt)
-{
- struct s3c_i2sv2_info *i2s = to_info(cpu_dai);
- u32 iismod;
-
- pr_debug("Entered %s\n", __func__);
-
- iismod = readl(i2s->regs + S3C2412_IISMOD);
- pr_debug("hw_params r: IISMOD: %x \n", iismod);
-
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
- i2s->master = 0;
- iismod |= S3C2412_IISMOD_SLAVE;
- break;
- case SND_SOC_DAIFMT_CBS_CFS:
- i2s->master = 1;
- iismod &= ~S3C2412_IISMOD_SLAVE;
- break;
- default:
- pr_err("unknwon master/slave format\n");
- return -EINVAL;
- }
-
- iismod &= ~S3C2412_IISMOD_SDF_MASK;
-
- switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
- case SND_SOC_DAIFMT_RIGHT_J:
- iismod |= S3C2412_IISMOD_LR_RLOW;
- iismod |= S3C2412_IISMOD_SDF_MSB;
- break;
- case SND_SOC_DAIFMT_LEFT_J:
- iismod |= S3C2412_IISMOD_LR_RLOW;
- iismod |= S3C2412_IISMOD_SDF_LSB;
- break;
- case SND_SOC_DAIFMT_I2S:
- iismod &= ~S3C2412_IISMOD_LR_RLOW;
- iismod |= S3C2412_IISMOD_SDF_IIS;
- break;
- default:
- pr_err("Unknown data format\n");
- return -EINVAL;
- }
-
- writel(iismod, i2s->regs + S3C2412_IISMOD);
- pr_debug("hw_params w: IISMOD: %x \n", iismod);
- return 0;
-}
-
-static int s3c_i2sv2_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params,
- struct snd_soc_dai *dai)
-{
- struct s3c_i2sv2_info *i2s = to_info(dai);
- struct s3c_dma_params *dma_data;
- u32 iismod;
-
- pr_debug("Entered %s\n", __func__);
-
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- dma_data = i2s->dma_playback;
- else
- dma_data = i2s->dma_capture;
-
- snd_soc_dai_set_dma_data(dai, substream, dma_data);
-
- /* Working copies of register */
- iismod = readl(i2s->regs + S3C2412_IISMOD);
- pr_debug("%s: r: IISMOD: %x\n", __func__, iismod);
-
- iismod &= ~S3C64XX_IISMOD_BLC_MASK;
- /* Sample size */
- switch (params_format(params)) {
- case SNDRV_PCM_FORMAT_S8:
- iismod |= S3C64XX_IISMOD_BLC_8BIT;
- break;
- case SNDRV_PCM_FORMAT_S16_LE:
- break;
- case SNDRV_PCM_FORMAT_S24_LE:
- iismod |= S3C64XX_IISMOD_BLC_24BIT;
- break;
- }
-
- writel(iismod, i2s->regs + S3C2412_IISMOD);
- pr_debug("%s: w: IISMOD: %x\n", __func__, iismod);
-
- return 0;
-}
-
-static int s3c_i2sv2_set_sysclk(struct snd_soc_dai *cpu_dai,
- int clk_id, unsigned int freq, int dir)
-{
- struct s3c_i2sv2_info *i2s = to_info(cpu_dai);
- u32 iismod = readl(i2s->regs + S3C2412_IISMOD);
-
- pr_debug("Entered %s\n", __func__);
- pr_debug("%s r: IISMOD: %x\n", __func__, iismod);
-
- switch (clk_id) {
- case S3C_I2SV2_CLKSRC_PCLK:
- iismod &= ~S3C2412_IISMOD_IMS_SYSMUX;
- break;
-
- case S3C_I2SV2_CLKSRC_AUDIOBUS:
- iismod |= S3C2412_IISMOD_IMS_SYSMUX;
- break;
-
- case S3C_I2SV2_CLKSRC_CDCLK:
- /* Error if controller doesn't have the CDCLKCON bit */
- if (!(i2s->feature & S3C_FEATURE_CDCLKCON))
- return -EINVAL;
-
- switch (dir) {
- case SND_SOC_CLOCK_IN:
- iismod |= S3C64XX_IISMOD_CDCLKCON;
- break;
- case SND_SOC_CLOCK_OUT:
- iismod &= ~S3C64XX_IISMOD_CDCLKCON;
- break;
- default:
- return -EINVAL;
- }
- break;
-
- default:
- return -EINVAL;
- }
-
- writel(iismod, i2s->regs + S3C2412_IISMOD);
- pr_debug("%s w: IISMOD: %x\n", __func__, iismod);
-
- return 0;
-}
-
-static int s3c2412_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
- struct snd_soc_dai *dai)
-{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct s3c_i2sv2_info *i2s = to_info(rtd->cpu_dai);
- int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
- unsigned long irqs;
- int ret = 0;
- struct s3c_dma_params *dma_data =
- snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
-
- pr_debug("Entered %s\n", __func__);
-
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
- /* On start, ensure that the FIFOs are cleared and reset. */
-
- writel(capture ? S3C2412_IISFIC_RXFLUSH : S3C2412_IISFIC_TXFLUSH,
- i2s->regs + S3C2412_IISFIC);
-
- /* clear again, just in case */
- writel(0x0, i2s->regs + S3C2412_IISFIC);
-
- case SNDRV_PCM_TRIGGER_RESUME:
- case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- if (!i2s->master) {
- ret = s3c2412_snd_lrsync(i2s);
- if (ret)
- goto exit_err;
- }
-
- local_irq_save(irqs);
-
- if (capture)
- s3c2412_snd_rxctrl(i2s, 1);
- else
- s3c2412_snd_txctrl(i2s, 1);
-
- local_irq_restore(irqs);
-
- /*
- * Load the next buffer to DMA to meet the reqirement
- * of the auto reload mechanism of S3C24XX.
- * This call won't bother S3C64XX.
- */
- s3c2410_dma_ctrl(dma_data->channel, S3C2410_DMAOP_STARTED);
-
- break;
-
- case SNDRV_PCM_TRIGGER_STOP:
- case SNDRV_PCM_TRIGGER_SUSPEND:
- case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- local_irq_save(irqs);
-
- if (capture)
- s3c2412_snd_rxctrl(i2s, 0);
- else
- s3c2412_snd_txctrl(i2s, 0);
-
- local_irq_restore(irqs);
- break;
- default:
- ret = -EINVAL;
- break;
- }
-
-exit_err:
- return ret;
-}
-
-/*
- * Set S3C2412 Clock dividers
- */
-static int s3c2412_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai,
- int div_id, int div)
-{
- struct s3c_i2sv2_info *i2s = to_info(cpu_dai);
- u32 reg;
-
- pr_debug("%s(%p, %d, %d)\n", __func__, cpu_dai, div_id, div);
-
- switch (div_id) {
- case S3C_I2SV2_DIV_BCLK:
- switch (div) {
- case 16:
- div = S3C2412_IISMOD_BCLK_16FS;
- break;
-
- case 32:
- div = S3C2412_IISMOD_BCLK_32FS;
- break;
-
- case 24:
- div = S3C2412_IISMOD_BCLK_24FS;
- break;
-
- case 48:
- div = S3C2412_IISMOD_BCLK_48FS;
- break;
-
- default:
- return -EINVAL;
- }
-
- reg = readl(i2s->regs + S3C2412_IISMOD);
- reg &= ~S3C2412_IISMOD_BCLK_MASK;
- writel(reg | div, i2s->regs + S3C2412_IISMOD);
-
- pr_debug("%s: MOD=%08x\n", __func__, readl(i2s->regs + S3C2412_IISMOD));
- break;
-
- case S3C_I2SV2_DIV_RCLK:
- switch (div) {
- case 256:
- div = S3C2412_IISMOD_RCLK_256FS;
- break;
-
- case 384:
- div = S3C2412_IISMOD_RCLK_384FS;
- break;
-
- case 512:
- div = S3C2412_IISMOD_RCLK_512FS;
- break;
-
- case 768:
- div = S3C2412_IISMOD_RCLK_768FS;
- break;
-
- default:
- return -EINVAL;
- }
-
- reg = readl(i2s->regs + S3C2412_IISMOD);
- reg &= ~S3C2412_IISMOD_RCLK_MASK;
- writel(reg | div, i2s->regs + S3C2412_IISMOD);
- pr_debug("%s: MOD=%08x\n", __func__, readl(i2s->regs + S3C2412_IISMOD));
- break;
-
- case S3C_I2SV2_DIV_PRESCALER:
- if (div >= 0) {
- writel((div << 8) | S3C2412_IISPSR_PSREN,
- i2s->regs + S3C2412_IISPSR);
- } else {
- writel(0x0, i2s->regs + S3C2412_IISPSR);
- }
- pr_debug("%s: PSR=%08x\n", __func__, readl(i2s->regs + S3C2412_IISPSR));
- break;
-
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-static snd_pcm_sframes_t s3c2412_i2s_delay(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
-{
- struct s3c_i2sv2_info *i2s = to_info(dai);
- u32 reg = readl(i2s->regs + S3C2412_IISFIC);
- snd_pcm_sframes_t delay;
-
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- delay = S3C2412_IISFIC_TXCOUNT(reg);
- else
- delay = S3C2412_IISFIC_RXCOUNT(reg);
-
- return delay;
-}
-
-struct clk *s3c_i2sv2_get_clock(struct snd_soc_dai *cpu_dai)
-{
- struct s3c_i2sv2_info *i2s = to_info(cpu_dai);
- u32 iismod = readl(i2s->regs + S3C2412_IISMOD);
-
- if (iismod & S3C2412_IISMOD_IMS_SYSMUX)
- return i2s->iis_cclk;
- else
- return i2s->iis_pclk;
-}
-EXPORT_SYMBOL_GPL(s3c_i2sv2_get_clock);
-
-/* default table of all avaialable root fs divisors */
-static unsigned int iis_fs_tab[] = { 256, 512, 384, 768 };
-
-int s3c_i2sv2_iis_calc_rate(struct s3c_i2sv2_rate_calc *info,
- unsigned int *fstab,
- unsigned int rate, struct clk *clk)
-{
- unsigned long clkrate = clk_get_rate(clk);
- unsigned int div;
- unsigned int fsclk;
- unsigned int actual;
- unsigned int fs;
- unsigned int fsdiv;
- signed int deviation = 0;
- unsigned int best_fs = 0;
- unsigned int best_div = 0;
- unsigned int best_rate = 0;
- unsigned int best_deviation = INT_MAX;
-
- pr_debug("Input clock rate %ldHz\n", clkrate);
-
- if (fstab == NULL)
- fstab = iis_fs_tab;
-
- for (fs = 0; fs < ARRAY_SIZE(iis_fs_tab); fs++) {
- fsdiv = iis_fs_tab[fs];
-
- fsclk = clkrate / fsdiv;
- div = fsclk / rate;
-
- if ((fsclk % rate) > (rate / 2))
- div++;
-
- if (div <= 1)
- continue;
-
- actual = clkrate / (fsdiv * div);
- deviation = actual - rate;
-
- printk(KERN_DEBUG "%ufs: div %u => result %u, deviation %d\n",
- fsdiv, div, actual, deviation);
-
- deviation = abs(deviation);
-
- if (deviation < best_deviation) {
- best_fs = fsdiv;
- best_div = div;
- best_rate = actual;
- best_deviation = deviation;
- }
-
- if (deviation == 0)
- break;
- }
-
- printk(KERN_DEBUG "best: fs=%u, div=%u, rate=%u\n",
- best_fs, best_div, best_rate);
-
- info->fs_div = best_fs;
- info->clk_div = best_div;
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(s3c_i2sv2_iis_calc_rate);
-
-int s3c_i2sv2_probe(struct snd_soc_dai *dai,
- struct s3c_i2sv2_info *i2s,
- unsigned long base)
-{
- struct device *dev = dai->dev;
- unsigned int iismod;
-
- i2s->dev = dev;
-
- /* record our i2s structure for later use in the callbacks */
- snd_soc_dai_set_drvdata(dai, i2s);
-
- i2s->regs = ioremap(base, 0x100);
- if (i2s->regs == NULL) {
- dev_err(dev, "cannot ioremap registers\n");
- return -ENXIO;
- }
-
- i2s->iis_pclk = clk_get(dev, "iis");
- if (IS_ERR(i2s->iis_pclk)) {
- dev_err(dev, "failed to get iis_clock\n");
- iounmap(i2s->regs);
- return -ENOENT;
- }
-
- clk_enable(i2s->iis_pclk);
-
- /* Mark ourselves as in TXRX mode so we can run through our cleanup
- * process without warnings. */
- iismod = readl(i2s->regs + S3C2412_IISMOD);
- iismod |= S3C2412_IISMOD_MODE_TXRX;
- writel(iismod, i2s->regs + S3C2412_IISMOD);
- s3c2412_snd_txctrl(i2s, 0);
- s3c2412_snd_rxctrl(i2s, 0);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(s3c_i2sv2_probe);
-
-#ifdef CONFIG_PM
-static int s3c2412_i2s_suspend(struct snd_soc_dai *dai)
-{
- struct s3c_i2sv2_info *i2s = to_info(dai);
- u32 iismod;
-
- if (dai->active) {
- i2s->suspend_iismod = readl(i2s->regs + S3C2412_IISMOD);
- i2s->suspend_iiscon = readl(i2s->regs + S3C2412_IISCON);
- i2s->suspend_iispsr = readl(i2s->regs + S3C2412_IISPSR);
-
- /* some basic suspend checks */
-
- iismod = readl(i2s->regs + S3C2412_IISMOD);
-
- if (iismod & S3C2412_IISCON_RXDMA_ACTIVE)
- pr_warning("%s: RXDMA active?\n", __func__);
-
- if (iismod & S3C2412_IISCON_TXDMA_ACTIVE)
- pr_warning("%s: TXDMA active?\n", __func__);
-
- if (iismod & S3C2412_IISCON_IIS_ACTIVE)
- pr_warning("%s: IIS active\n", __func__);
- }
-
- return 0;
-}
-
-static int s3c2412_i2s_resume(struct snd_soc_dai *dai)
-{
- struct s3c_i2sv2_info *i2s = to_info(dai);
-
- pr_info("dai_active %d, IISMOD %08x, IISCON %08x\n",
- dai->active, i2s->suspend_iismod, i2s->suspend_iiscon);
-
- if (dai->active) {
- writel(i2s->suspend_iiscon, i2s->regs + S3C2412_IISCON);
- writel(i2s->suspend_iismod, i2s->regs + S3C2412_IISMOD);
- writel(i2s->suspend_iispsr, i2s->regs + S3C2412_IISPSR);
-
- writel(S3C2412_IISFIC_RXFLUSH | S3C2412_IISFIC_TXFLUSH,
- i2s->regs + S3C2412_IISFIC);
-
- ndelay(250);
- writel(0x0, i2s->regs + S3C2412_IISFIC);
- }
-
- return 0;
-}
-#else
-#define s3c2412_i2s_suspend NULL
-#define s3c2412_i2s_resume NULL
-#endif
-
-int s3c_i2sv2_register_dai(struct device *dev, int id,
- struct snd_soc_dai_driver *drv)
-{
- struct snd_soc_dai_ops *ops = drv->ops;
-
- ops->trigger = s3c2412_i2s_trigger;
- if (!ops->hw_params)
- ops->hw_params = s3c_i2sv2_hw_params;
- ops->set_fmt = s3c2412_i2s_set_fmt;
- ops->set_clkdiv = s3c2412_i2s_set_clkdiv;
- ops->set_sysclk = s3c_i2sv2_set_sysclk;
-
- /* Allow overriding by (for example) IISv4 */
- if (!ops->delay)
- ops->delay = s3c2412_i2s_delay;
-
- drv->suspend = s3c2412_i2s_suspend;
- drv->resume = s3c2412_i2s_resume;
-
- return snd_soc_register_dai(dev, drv);
-}
-EXPORT_SYMBOL_GPL(s3c_i2sv2_register_dai);
-
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/s3c-i2s-v2.h b/sound/soc/s3c24xx/s3c-i2s-v2.h
deleted file mode 100644
index d458301..0000000
--- a/sound/soc/s3c24xx/s3c-i2s-v2.h
+++ /dev/null
@@ -1,106 +0,0 @@
-/* sound/soc/s3c24xx/s3c-i2s-v2.h
- *
- * ALSA Soc Audio Layer - S3C_I2SV2 I2S driver
- *
- * Copyright (c) 2007 Simtec Electronics
- * http://armlinux.simtec.co.uk/
- * Ben Dooks <ben(a)simtec.co.uk>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
-*/
-
-/* This code is the core support for the I2S block found in a number of
- * Samsung SoC devices which is unofficially named I2S-V2. Currently the
- * S3C2412 and the S3C64XX series use this block to provide 1 or 2 I2S
- * channels via configurable GPIO.
- */
-
-#ifndef __SND_SOC_S3C24XX_S3C_I2SV2_I2S_H
-#define __SND_SOC_S3C24XX_S3C_I2SV2_I2S_H __FILE__
-
-#define S3C_I2SV2_DIV_BCLK (1)
-#define S3C_I2SV2_DIV_RCLK (2)
-#define S3C_I2SV2_DIV_PRESCALER (3)
-
-#define S3C_I2SV2_CLKSRC_PCLK 0
-#define S3C_I2SV2_CLKSRC_AUDIOBUS 1
-#define S3C_I2SV2_CLKSRC_CDCLK 2
-
-/* Set this flag for I2S controllers that have the bit IISMOD[12]
- * bridge/break RCLK signal and external Xi2sCDCLK pin.
- */
-#define S3C_FEATURE_CDCLKCON (1 << 0)
-
-/**
- * struct s3c_i2sv2_info - S3C I2S-V2 information
- * @dev: The parent device passed to use from the probe.
- * @regs: The pointer to the device registe block.
- * @feature: Set of bit-flags indicating features of the controller.
- * @master: True if the I2S core is the I2S bit clock master.
- * @dma_playback: DMA information for playback channel.
- * @dma_capture: DMA information for capture channel.
- * @suspend_iismod: PM save for the IISMOD register.
- * @suspend_iiscon: PM save for the IISCON register.
- * @suspend_iispsr: PM save for the IISPSR register.
- *
- * This is the private codec state for the hardware associated with an
- * I2S channel such as the register mappings and clock sources.
- */
-struct s3c_i2sv2_info {
- struct device *dev;
- void __iomem *regs;
-
- u32 feature;
-
- struct clk *iis_pclk;
- struct clk *iis_cclk;
-
- unsigned char master;
-
- struct s3c_dma_params *dma_playback;
- struct s3c_dma_params *dma_capture;
-
- u32 suspend_iismod;
- u32 suspend_iiscon;
- u32 suspend_iispsr;
-
- unsigned long base;
-};
-
-extern struct clk *s3c_i2sv2_get_clock(struct snd_soc_dai *cpu_dai);
-
-struct s3c_i2sv2_rate_calc {
- unsigned int clk_div; /* for prescaler */
- unsigned int fs_div; /* for root frame clock */
-};
-
-extern int s3c_i2sv2_iis_calc_rate(struct s3c_i2sv2_rate_calc *info,
- unsigned int *fstab,
- unsigned int rate, struct clk *clk);
-
-/**
- * s3c_i2sv2_probe - probe for i2s device helper
- * @dai: The ASoC DAI structure supplied to the original probe.
- * @i2s: Our local i2s structure to fill in.
- * @base: The base address for the registers.
- */
-extern int s3c_i2sv2_probe(struct snd_soc_dai *dai,
- struct s3c_i2sv2_info *i2s,
- unsigned long base);
-
-/**
- * s3c_i2sv2_register_dai - register dai with soc core
- * @dev: DAI device
- * @id: DAI ID
- * @drv: The driver structure to register
- *
- * Fill in any missing fields and then register the given dai with the
- * soc core.
- */
-extern int s3c_i2sv2_register_dai(struct device *dev, int id,
- struct snd_soc_dai_driver *drv);
-
-#endif /* __SND_SOC_S3C24XX_S3C_I2SV2_I2S_H */
diff --git a/sound/soc/s3c24xx/s3c2412-i2s.c b/sound/soc/s3c24xx/s3c2412-i2s.c
deleted file mode 100644
index d953ff4..0000000
--- a/sound/soc/s3c24xx/s3c2412-i2s.c
+++ /dev/null
@@ -1,212 +0,0 @@
-/* sound/soc/s3c24xx/s3c2412-i2s.c
- *
- * ALSA Soc Audio Layer - S3C2412 I2S driver
- *
- * Copyright (c) 2006 Wolfson Microelectronics PLC.
- * Graeme Gregory graeme.gregory(a)wolfsonmicro.com
- * linux(a)wolfsonmicro.com
- *
- * Copyright (c) 2007, 2004-2005 Simtec Electronics
- * http://armlinux.simtec.co.uk/
- * Ben Dooks <ben(a)simtec.co.uk>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/delay.h>
-#include <linux/gpio.h>
-#include <linux/clk.h>
-#include <linux/kernel.h>
-#include <linux/io.h>
-
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/initval.h>
-#include <sound/soc.h>
-#include <mach/hardware.h>
-
-#include <mach/regs-gpio.h>
-#include <mach/dma.h>
-
-#include "dma.h"
-#include "regs-i2s-v2.h"
-#include "s3c2412-i2s.h"
-
-#define S3C2412_I2S_DEBUG 0
-
-static struct s3c2410_dma_client s3c2412_dma_client_out = {
- .name = "I2S PCM Stereo out"
-};
-
-static struct s3c2410_dma_client s3c2412_dma_client_in = {
- .name = "I2S PCM Stereo in"
-};
-
-static struct s3c_dma_params s3c2412_i2s_pcm_stereo_out = {
- .client = &s3c2412_dma_client_out,
- .channel = DMACH_I2S_OUT,
- .dma_addr = S3C2410_PA_IIS + S3C2412_IISTXD,
- .dma_size = 4,
-};
-
-static struct s3c_dma_params s3c2412_i2s_pcm_stereo_in = {
- .client = &s3c2412_dma_client_in,
- .channel = DMACH_I2S_IN,
- .dma_addr = S3C2410_PA_IIS + S3C2412_IISRXD,
- .dma_size = 4,
-};
-
-static struct s3c_i2sv2_info s3c2412_i2s;
-
-static int s3c2412_i2s_probe(struct snd_soc_dai *dai)
-{
- int ret;
-
- pr_debug("Entered %s\n", __func__);
-
- ret = s3c_i2sv2_probe(dai, &s3c2412_i2s, S3C2410_PA_IIS);
- if (ret)
- return ret;
-
- s3c2412_i2s.dma_capture = &s3c2412_i2s_pcm_stereo_in;
- s3c2412_i2s.dma_playback = &s3c2412_i2s_pcm_stereo_out;
-
- s3c2412_i2s.iis_cclk = clk_get(dai->dev, "i2sclk");
- if (s3c2412_i2s.iis_cclk == NULL) {
- pr_err("failed to get i2sclk clock\n");
- iounmap(s3c2412_i2s.regs);
- return -ENODEV;
- }
-
- /* Set MPLL as the source for IIS CLK */
-
- clk_set_parent(s3c2412_i2s.iis_cclk, clk_get(NULL, "mpll"));
- clk_enable(s3c2412_i2s.iis_cclk);
-
- s3c2412_i2s.iis_cclk = s3c2412_i2s.iis_pclk;
-
- /* Configure the I2S pins in correct mode */
- s3c2410_gpio_cfgpin(S3C2410_GPE0, S3C2410_GPE0_I2SLRCK);
- s3c2410_gpio_cfgpin(S3C2410_GPE1, S3C2410_GPE1_I2SSCLK);
- s3c2410_gpio_cfgpin(S3C2410_GPE2, S3C2410_GPE2_CDCLK);
- s3c2410_gpio_cfgpin(S3C2410_GPE3, S3C2410_GPE3_I2SSDI);
- s3c2410_gpio_cfgpin(S3C2410_GPE4, S3C2410_GPE4_I2SSDO);
-
- return 0;
-}
-
-static int s3c2412_i2s_remove(struct snd_soc_dai *dai)
-{
- clk_disable(s3c2412_i2s.iis_cclk);
- clk_put(s3c2412_i2s.iis_cclk);
- iounmap(s3c2412_i2s.regs);
-
- return 0;
-}
-
-static int s3c2412_i2s_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params,
- struct snd_soc_dai *cpu_dai)
-{
- struct s3c_i2sv2_info *i2s = snd_soc_dai_get_drvdata(cpu_dai);
- struct s3c_dma_params *dma_data;
- u32 iismod;
-
- pr_debug("Entered %s\n", __func__);
-
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- dma_data = i2s->dma_playback;
- else
- dma_data = i2s->dma_capture;
-
- snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data);
-
- iismod = readl(i2s->regs + S3C2412_IISMOD);
- pr_debug("%s: r: IISMOD: %x\n", __func__, iismod);
-
- switch (params_format(params)) {
- case SNDRV_PCM_FORMAT_S8:
- iismod |= S3C2412_IISMOD_8BIT;
- break;
- case SNDRV_PCM_FORMAT_S16_LE:
- iismod &= ~S3C2412_IISMOD_8BIT;
- break;
- }
-
- writel(iismod, i2s->regs + S3C2412_IISMOD);
- pr_debug("%s: w: IISMOD: %x\n", __func__, iismod);
-
- return 0;
-}
-
-#define S3C2412_I2S_RATES \
- (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \
- SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
- SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
-
-static struct snd_soc_dai_ops s3c2412_i2s_dai_ops = {
- .hw_params = s3c2412_i2s_hw_params,
-};
-
-static struct snd_soc_dai_driver s3c2412_i2s_dai = {
- .probe = s3c2412_i2s_probe,
- .remove = s3c2412_i2s_remove,
- .playback = {
- .channels_min = 2,
- .channels_max = 2,
- .rates = S3C2412_I2S_RATES,
- .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,
- },
- .capture = {
- .channels_min = 2,
- .channels_max = 2,
- .rates = S3C2412_I2S_RATES,
- .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,
- },
- .ops = &s3c2412_i2s_dai_ops,
-};
-
-static __devinit int s3c2412_iis_dev_probe(struct platform_device *pdev)
-{
- return snd_soc_register_dai(&pdev->dev, &s3c2412_i2s_dai);
-}
-
-static __devexit int s3c2412_iis_dev_remove(struct platform_device *pdev)
-{
- snd_soc_unregister_dai(&pdev->dev);
- return 0;
-}
-
-static struct platform_driver s3c2412_iis_driver = {
- .probe = s3c2412_iis_dev_probe,
- .remove = s3c2412_iis_dev_remove,
- .driver = {
- .name = "s3c2412-iis",
- .owner = THIS_MODULE,
- },
-};
-
-static int __init s3c2412_i2s_init(void)
-{
- return platform_driver_register(&s3c2412_iis_driver);
-}
-module_init(s3c2412_i2s_init);
-
-static void __exit s3c2412_i2s_exit(void)
-{
- platform_driver_unregister(&s3c2412_iis_driver);
-}
-module_exit(s3c2412_i2s_exit);
-
-/* Module information */
-MODULE_AUTHOR("Ben Dooks, <ben(a)simtec.co.uk>");
-MODULE_DESCRIPTION("S3C2412 I2S SoC Interface");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:s3c2412-iis");
diff --git a/sound/soc/s3c24xx/s3c2412-i2s.h b/sound/soc/s3c24xx/s3c2412-i2s.h
deleted file mode 100644
index 01a0471..0000000
--- a/sound/soc/s3c24xx/s3c2412-i2s.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/* sound/soc/s3c24xx/s3c2412-i2s.c
- *
- * ALSA Soc Audio Layer - S3C2412 I2S driver
- *
- * Copyright (c) 2007 Simtec Electronics
- * http://armlinux.simtec.co.uk/
- * Ben Dooks <ben(a)simtec.co.uk>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
-*/
-
-#ifndef __SND_SOC_S3C24XX_S3C2412_I2S_H
-#define __SND_SOC_S3C24XX_S3C2412_I2S_H __FILE__
-
-#include "s3c-i2s-v2.h"
-
-#define S3C2412_DIV_BCLK S3C_I2SV2_DIV_BCLK
-#define S3C2412_DIV_RCLK S3C_I2SV2_DIV_RCLK
-#define S3C2412_DIV_PRESCALER S3C_I2SV2_DIV_PRESCALER
-
-#define S3C2412_CLKSRC_PCLK S3C_I2SV2_CLKSRC_PCLK
-#define S3C2412_CLKSRC_I2SCLK S3C_I2SV2_CLKSRC_AUDIOBUS
-
-#endif /* __SND_SOC_S3C24XX_S3C2412_I2S_H */
diff --git a/sound/soc/s3c24xx/s3c24xx-i2s.c b/sound/soc/s3c24xx/s3c24xx-i2s.c
deleted file mode 100644
index 13e41ed..0000000
--- a/sound/soc/s3c24xx/s3c24xx-i2s.c
+++ /dev/null
@@ -1,519 +0,0 @@
-/*
- * s3c24xx-i2s.c -- ALSA Soc Audio Layer
- *
- * (c) 2006 Wolfson Microelectronics PLC.
- * Graeme Gregory graeme.gregory(a)wolfsonmicro.com or linux(a)wolfsonmicro.com
- *
- * Copyright 2004-2005 Simtec Electronics
- * http://armlinux.simtec.co.uk/
- * Ben Dooks <ben(a)simtec.co.uk>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/delay.h>
-#include <linux/clk.h>
-#include <linux/jiffies.h>
-#include <linux/io.h>
-#include <linux/gpio.h>
-
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/initval.h>
-#include <sound/soc.h>
-
-#include <mach/hardware.h>
-#include <mach/regs-gpio.h>
-#include <mach/regs-clock.h>
-
-#include <asm/dma.h>
-#include <mach/dma.h>
-
-#include <plat/regs-iis.h>
-
-#include "dma.h"
-#include "s3c24xx-i2s.h"
-
-static struct s3c2410_dma_client s3c24xx_dma_client_out = {
- .name = "I2S PCM Stereo out"
-};
-
-static struct s3c2410_dma_client s3c24xx_dma_client_in = {
- .name = "I2S PCM Stereo in"
-};
-
-static struct s3c_dma_params s3c24xx_i2s_pcm_stereo_out = {
- .client = &s3c24xx_dma_client_out,
- .channel = DMACH_I2S_OUT,
- .dma_addr = S3C2410_PA_IIS + S3C2410_IISFIFO,
- .dma_size = 2,
-};
-
-static struct s3c_dma_params s3c24xx_i2s_pcm_stereo_in = {
- .client = &s3c24xx_dma_client_in,
- .channel = DMACH_I2S_IN,
- .dma_addr = S3C2410_PA_IIS + S3C2410_IISFIFO,
- .dma_size = 2,
-};
-
-struct s3c24xx_i2s_info {
- void __iomem *regs;
- struct clk *iis_clk;
- u32 iiscon;
- u32 iismod;
- u32 iisfcon;
- u32 iispsr;
-};
-static struct s3c24xx_i2s_info s3c24xx_i2s;
-
-static void s3c24xx_snd_txctrl(int on)
-{
- u32 iisfcon;
- u32 iiscon;
- u32 iismod;
-
- pr_debug("Entered %s\n", __func__);
-
- iisfcon = readl(s3c24xx_i2s.regs + S3C2410_IISFCON);
- iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON);
- iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
-
- pr_debug("r: IISCON: %x IISMOD: %x IISFCON: %x\n", iiscon, iismod, iisfcon);
-
- if (on) {
- iisfcon |= S3C2410_IISFCON_TXDMA | S3C2410_IISFCON_TXENABLE;
- iiscon |= S3C2410_IISCON_TXDMAEN | S3C2410_IISCON_IISEN;
- iiscon &= ~S3C2410_IISCON_TXIDLE;
- iismod |= S3C2410_IISMOD_TXMODE;
-
- writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD);
- writel(iisfcon, s3c24xx_i2s.regs + S3C2410_IISFCON);
- writel(iiscon, s3c24xx_i2s.regs + S3C2410_IISCON);
- } else {
- /* note, we have to disable the FIFOs otherwise bad things
- * seem to happen when the DMA stops. According to the
- * Samsung supplied kernel, this should allow the DMA
- * engine and FIFOs to reset. If this isn't allowed, the
- * DMA engine will simply freeze randomly.
- */
-
- iisfcon &= ~S3C2410_IISFCON_TXENABLE;
- iisfcon &= ~S3C2410_IISFCON_TXDMA;
- iiscon |= S3C2410_IISCON_TXIDLE;
- iiscon &= ~S3C2410_IISCON_TXDMAEN;
- iismod &= ~S3C2410_IISMOD_TXMODE;
-
- writel(iiscon, s3c24xx_i2s.regs + S3C2410_IISCON);
- writel(iisfcon, s3c24xx_i2s.regs + S3C2410_IISFCON);
- writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD);
- }
-
- pr_debug("w: IISCON: %x IISMOD: %x IISFCON: %x\n", iiscon, iismod, iisfcon);
-}
-
-static void s3c24xx_snd_rxctrl(int on)
-{
- u32 iisfcon;
- u32 iiscon;
- u32 iismod;
-
- pr_debug("Entered %s\n", __func__);
-
- iisfcon = readl(s3c24xx_i2s.regs + S3C2410_IISFCON);
- iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON);
- iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
-
- pr_debug("r: IISCON: %x IISMOD: %x IISFCON: %x\n", iiscon, iismod, iisfcon);
-
- if (on) {
- iisfcon |= S3C2410_IISFCON_RXDMA | S3C2410_IISFCON_RXENABLE;
- iiscon |= S3C2410_IISCON_RXDMAEN | S3C2410_IISCON_IISEN;
- iiscon &= ~S3C2410_IISCON_RXIDLE;
- iismod |= S3C2410_IISMOD_RXMODE;
-
- writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD);
- writel(iisfcon, s3c24xx_i2s.regs + S3C2410_IISFCON);
- writel(iiscon, s3c24xx_i2s.regs + S3C2410_IISCON);
- } else {
- /* note, we have to disable the FIFOs otherwise bad things
- * seem to happen when the DMA stops. According to the
- * Samsung supplied kernel, this should allow the DMA
- * engine and FIFOs to reset. If this isn't allowed, the
- * DMA engine will simply freeze randomly.
- */
-
- iisfcon &= ~S3C2410_IISFCON_RXENABLE;
- iisfcon &= ~S3C2410_IISFCON_RXDMA;
- iiscon |= S3C2410_IISCON_RXIDLE;
- iiscon &= ~S3C2410_IISCON_RXDMAEN;
- iismod &= ~S3C2410_IISMOD_RXMODE;
-
- writel(iisfcon, s3c24xx_i2s.regs + S3C2410_IISFCON);
- writel(iiscon, s3c24xx_i2s.regs + S3C2410_IISCON);
- writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD);
- }
-
- pr_debug("w: IISCON: %x IISMOD: %x IISFCON: %x\n", iiscon, iismod, iisfcon);
-}
-
-/*
- * Wait for the LR signal to allow synchronisation to the L/R clock
- * from the codec. May only be needed for slave mode.
- */
-static int s3c24xx_snd_lrsync(void)
-{
- u32 iiscon;
- int timeout = 50; /* 5ms */
-
- pr_debug("Entered %s\n", __func__);
-
- while (1) {
- iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON);
- if (iiscon & S3C2410_IISCON_LRINDEX)
- break;
-
- if (!timeout--)
- return -ETIMEDOUT;
- udelay(100);
- }
-
- return 0;
-}
-
-/*
- * Check whether CPU is the master or slave
- */
-static inline int s3c24xx_snd_is_clkmaster(void)
-{
- pr_debug("Entered %s\n", __func__);
-
- return (readl(s3c24xx_i2s.regs + S3C2410_IISMOD) & S3C2410_IISMOD_SLAVE) ? 0:1;
-}
-
-/*
- * Set S3C24xx I2S DAI format
- */
-static int s3c24xx_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
- unsigned int fmt)
-{
- u32 iismod;
-
- pr_debug("Entered %s\n", __func__);
-
- iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
- pr_debug("hw_params r: IISMOD: %x \n", iismod);
-
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
- iismod |= S3C2410_IISMOD_SLAVE;
- break;
- case SND_SOC_DAIFMT_CBS_CFS:
- iismod &= ~S3C2410_IISMOD_SLAVE;
- break;
- default:
- return -EINVAL;
- }
-
- switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
- case SND_SOC_DAIFMT_LEFT_J:
- iismod |= S3C2410_IISMOD_MSB;
- break;
- case SND_SOC_DAIFMT_I2S:
- iismod &= ~S3C2410_IISMOD_MSB;
- break;
- default:
- return -EINVAL;
- }
-
- writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD);
- pr_debug("hw_params w: IISMOD: %x \n", iismod);
- return 0;
-}
-
-static int s3c24xx_i2s_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 s3c_dma_params *dma_data;
- u32 iismod;
-
- pr_debug("Entered %s\n", __func__);
-
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- dma_data = &s3c24xx_i2s_pcm_stereo_out;
- else
- dma_data = &s3c24xx_i2s_pcm_stereo_in;
-
- snd_soc_dai_set_dma_data(rtd->cpu_dai, substream, dma_data);
-
- /* Working copies of register */
- iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
- pr_debug("hw_params r: IISMOD: %x\n", iismod);
-
- switch (params_format(params)) {
- case SNDRV_PCM_FORMAT_S8:
- iismod &= ~S3C2410_IISMOD_16BIT;
- dma_data->dma_size = 1;
- break;
- case SNDRV_PCM_FORMAT_S16_LE:
- iismod |= S3C2410_IISMOD_16BIT;
- dma_data->dma_size = 2;
- break;
- default:
- return -EINVAL;
- }
-
- writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD);
- pr_debug("hw_params w: IISMOD: %x\n", iismod);
- return 0;
-}
-
-static int s3c24xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
- struct snd_soc_dai *dai)
-{
- int ret = 0;
- struct s3c_dma_params *dma_data =
- snd_soc_dai_get_dma_data(dai, substream);
-
- pr_debug("Entered %s\n", __func__);
-
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
- case SNDRV_PCM_TRIGGER_RESUME:
- case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- if (!s3c24xx_snd_is_clkmaster()) {
- ret = s3c24xx_snd_lrsync();
- if (ret)
- goto exit_err;
- }
-
- if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
- s3c24xx_snd_rxctrl(1);
- else
- s3c24xx_snd_txctrl(1);
-
- s3c2410_dma_ctrl(dma_data->channel, S3C2410_DMAOP_STARTED);
- break;
- case SNDRV_PCM_TRIGGER_STOP:
- case SNDRV_PCM_TRIGGER_SUSPEND:
- case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
- s3c24xx_snd_rxctrl(0);
- else
- s3c24xx_snd_txctrl(0);
- break;
- default:
- ret = -EINVAL;
- break;
- }
-
-exit_err:
- return ret;
-}
-
-/*
- * Set S3C24xx Clock source
- */
-static int s3c24xx_i2s_set_sysclk(struct snd_soc_dai *cpu_dai,
- int clk_id, unsigned int freq, int dir)
-{
- u32 iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
-
- pr_debug("Entered %s\n", __func__);
-
- iismod &= ~S3C2440_IISMOD_MPLL;
-
- switch (clk_id) {
- case S3C24XX_CLKSRC_PCLK:
- break;
- case S3C24XX_CLKSRC_MPLL:
- iismod |= S3C2440_IISMOD_MPLL;
- break;
- default:
- return -EINVAL;
- }
-
- writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD);
- return 0;
-}
-
-/*
- * Set S3C24xx Clock dividers
- */
-static int s3c24xx_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai,
- int div_id, int div)
-{
- u32 reg;
-
- pr_debug("Entered %s\n", __func__);
-
- switch (div_id) {
- case S3C24XX_DIV_BCLK:
- reg = readl(s3c24xx_i2s.regs + S3C2410_IISMOD) & ~S3C2410_IISMOD_FS_MASK;
- writel(reg | div, s3c24xx_i2s.regs + S3C2410_IISMOD);
- break;
- case S3C24XX_DIV_MCLK:
- reg = readl(s3c24xx_i2s.regs + S3C2410_IISMOD) & ~(S3C2410_IISMOD_384FS);
- writel(reg | div, s3c24xx_i2s.regs + S3C2410_IISMOD);
- break;
- case S3C24XX_DIV_PRESCALER:
- writel(div, s3c24xx_i2s.regs + S3C2410_IISPSR);
- reg = readl(s3c24xx_i2s.regs + S3C2410_IISCON);
- writel(reg | S3C2410_IISCON_PSCEN, s3c24xx_i2s.regs + S3C2410_IISCON);
- break;
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-/*
- * To avoid duplicating clock code, allow machine driver to
- * get the clockrate from here.
- */
-u32 s3c24xx_i2s_get_clockrate(void)
-{
- return clk_get_rate(s3c24xx_i2s.iis_clk);
-}
-EXPORT_SYMBOL_GPL(s3c24xx_i2s_get_clockrate);
-
-static int s3c24xx_i2s_probe(struct snd_soc_dai *dai)
-{
- pr_debug("Entered %s\n", __func__);
-
- s3c24xx_i2s.regs = ioremap(S3C2410_PA_IIS, 0x100);
- if (s3c24xx_i2s.regs == NULL)
- return -ENXIO;
-
- s3c24xx_i2s.iis_clk = clk_get(dai->dev, "iis");
- if (s3c24xx_i2s.iis_clk == NULL) {
- pr_err("failed to get iis_clock\n");
- iounmap(s3c24xx_i2s.regs);
- return -ENODEV;
- }
- clk_enable(s3c24xx_i2s.iis_clk);
-
- /* Configure the I2S pins in correct mode */
- s3c2410_gpio_cfgpin(S3C2410_GPE0, S3C2410_GPE0_I2SLRCK);
- s3c2410_gpio_cfgpin(S3C2410_GPE1, S3C2410_GPE1_I2SSCLK);
- s3c2410_gpio_cfgpin(S3C2410_GPE2, S3C2410_GPE2_CDCLK);
- s3c2410_gpio_cfgpin(S3C2410_GPE3, S3C2410_GPE3_I2SSDI);
- s3c2410_gpio_cfgpin(S3C2410_GPE4, S3C2410_GPE4_I2SSDO);
-
- writel(S3C2410_IISCON_IISEN, s3c24xx_i2s.regs + S3C2410_IISCON);
-
- s3c24xx_snd_txctrl(0);
- s3c24xx_snd_rxctrl(0);
-
- return 0;
-}
-
-#ifdef CONFIG_PM
-static int s3c24xx_i2s_suspend(struct snd_soc_dai *cpu_dai)
-{
- pr_debug("Entered %s\n", __func__);
-
- s3c24xx_i2s.iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON);
- s3c24xx_i2s.iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
- s3c24xx_i2s.iisfcon = readl(s3c24xx_i2s.regs + S3C2410_IISFCON);
- s3c24xx_i2s.iispsr = readl(s3c24xx_i2s.regs + S3C2410_IISPSR);
-
- clk_disable(s3c24xx_i2s.iis_clk);
-
- return 0;
-}
-
-static int s3c24xx_i2s_resume(struct snd_soc_dai *cpu_dai)
-{
- pr_debug("Entered %s\n", __func__);
- clk_enable(s3c24xx_i2s.iis_clk);
-
- writel(s3c24xx_i2s.iiscon, s3c24xx_i2s.regs + S3C2410_IISCON);
- writel(s3c24xx_i2s.iismod, s3c24xx_i2s.regs + S3C2410_IISMOD);
- writel(s3c24xx_i2s.iisfcon, s3c24xx_i2s.regs + S3C2410_IISFCON);
- writel(s3c24xx_i2s.iispsr, s3c24xx_i2s.regs + S3C2410_IISPSR);
-
- return 0;
-}
-#else
-#define s3c24xx_i2s_suspend NULL
-#define s3c24xx_i2s_resume NULL
-#endif
-
-
-#define S3C24XX_I2S_RATES \
- (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \
- SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
- SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
-
-static struct snd_soc_dai_ops s3c24xx_i2s_dai_ops = {
- .trigger = s3c24xx_i2s_trigger,
- .hw_params = s3c24xx_i2s_hw_params,
- .set_fmt = s3c24xx_i2s_set_fmt,
- .set_clkdiv = s3c24xx_i2s_set_clkdiv,
- .set_sysclk = s3c24xx_i2s_set_sysclk,
-};
-
-static struct snd_soc_dai_driver s3c24xx_i2s_dai = {
- .probe = s3c24xx_i2s_probe,
- .suspend = s3c24xx_i2s_suspend,
- .resume = s3c24xx_i2s_resume,
- .playback = {
- .channels_min = 2,
- .channels_max = 2,
- .rates = S3C24XX_I2S_RATES,
- .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,},
- .capture = {
- .channels_min = 2,
- .channels_max = 2,
- .rates = S3C24XX_I2S_RATES,
- .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,},
- .ops = &s3c24xx_i2s_dai_ops,
-};
-
-static __devinit int s3c24xx_iis_dev_probe(struct platform_device *pdev)
-{
- return snd_soc_register_dai(&pdev->dev, &s3c24xx_i2s_dai);
-}
-
-static __devexit int s3c24xx_iis_dev_remove(struct platform_device *pdev)
-{
- snd_soc_unregister_dai(&pdev->dev);
- return 0;
-}
-
-static struct platform_driver s3c24xx_iis_driver = {
- .probe = s3c24xx_iis_dev_probe,
- .remove = s3c24xx_iis_dev_remove,
- .driver = {
- .name = "s3c24xx-iis",
- .owner = THIS_MODULE,
- },
-};
-
-static int __init s3c24xx_i2s_init(void)
-{
- return platform_driver_register(&s3c24xx_iis_driver);
-}
-module_init(s3c24xx_i2s_init);
-
-static void __exit s3c24xx_i2s_exit(void)
-{
- platform_driver_unregister(&s3c24xx_iis_driver);
-}
-module_exit(s3c24xx_i2s_exit);
-
-/* Module information */
-MODULE_AUTHOR("Ben Dooks, <ben(a)simtec.co.uk>");
-MODULE_DESCRIPTION("s3c24xx I2S SoC Interface");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:s3c24xx-iis");
diff --git a/sound/soc/s3c24xx/s3c24xx-i2s.h b/sound/soc/s3c24xx/s3c24xx-i2s.h
deleted file mode 100644
index f9ca04e..0000000
--- a/sound/soc/s3c24xx/s3c24xx-i2s.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * s3c24xx-i2s.c -- ALSA Soc Audio Layer
- *
- * Copyright 2005 Wolfson Microelectronics PLC.
- * Author: Graeme Gregory
- * graeme.gregory(a)wolfsonmicro.com or linux(a)wolfsonmicro.com
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * Revision history
- * 10th Nov 2006 Initial version.
- */
-
-#ifndef S3C24XXI2S_H_
-#define S3C24XXI2S_H_
-
-/* clock sources */
-#define S3C24XX_CLKSRC_PCLK 0
-#define S3C24XX_CLKSRC_MPLL 1
-
-/* Clock dividers */
-#define S3C24XX_DIV_MCLK 0
-#define S3C24XX_DIV_BCLK 1
-#define S3C24XX_DIV_PRESCALER 2
-
-/* prescaler */
-#define S3C24XX_PRESCALE(a,b) \
- (((a - 1) << S3C2410_IISPSR_INTSHIFT) | ((b - 1) << S3C2410_IISPSR_EXTSHFIT))
-
-u32 s3c24xx_i2s_get_clockrate(void);
-
-#endif /*S3C24XXI2S_H_*/
diff --git a/sound/soc/s3c24xx/s3c24xx_simtec.c b/sound/soc/s3c24xx/s3c24xx_simtec.c
deleted file mode 100644
index 3f052a5..0000000
--- a/sound/soc/s3c24xx/s3c24xx_simtec.c
+++ /dev/null
@@ -1,395 +0,0 @@
-/* sound/soc/s3c24xx/s3c24xx_simtec.c
- *
- * Copyright 2009 Simtec Electronics
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/platform_device.h>
-#include <linux/gpio.h>
-#include <linux/clk.h>
-#include <linux/i2c.h>
-
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-#include <sound/soc-dapm.h>
-
-#include <plat/audio-simtec.h>
-
-#include "dma.h"
-#include "s3c24xx-i2s.h"
-#include "s3c24xx_simtec.h"
-
-static struct s3c24xx_audio_simtec_pdata *pdata;
-static struct clk *xtal_clk;
-
-static int spk_gain;
-static int spk_unmute;
-
-/**
- * speaker_gain_get - read the speaker gain setting.
- * @kcontrol: The control for the speaker gain.
- * @ucontrol: The value that needs to be updated.
- *
- * Read the value for the AMP gain control.
- */
-static int speaker_gain_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- ucontrol->value.integer.value[0] = spk_gain;
- return 0;
-}
-
-/**
- * speaker_gain_set - set the value of the speaker amp gain
- * @value: The value to write.
- */
-static void speaker_gain_set(int value)
-{
- gpio_set_value_cansleep(pdata->amp_gain[0], value & 1);
- gpio_set_value_cansleep(pdata->amp_gain[1], value >> 1);
-}
-
-/**
- * speaker_gain_put - set the speaker gain setting.
- * @kcontrol: The control for the speaker gain.
- * @ucontrol: The value that needs to be set.
- *
- * Set the value of the speaker gain from the specified
- * @ucontrol setting.
- *
- * Note, if the speaker amp is muted, then we do not set a gain value
- * as at-least one of the ICs that is fitted will try and power up even
- * if the main control is set to off.
- */
-static int speaker_gain_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- int value = ucontrol->value.integer.value[0];
-
- spk_gain = value;
-
- if (!spk_unmute)
- speaker_gain_set(value);
-
- return 0;
-}
-
-static const struct snd_kcontrol_new amp_gain_controls[] = {
- SOC_SINGLE_EXT("Speaker Gain", 0, 0, 3, 0,
- speaker_gain_get, speaker_gain_put),
-};
-
-/**
- * spk_unmute_state - set the unmute state of the speaker
- * @to: zero to unmute, non-zero to ununmute.
- */
-static void spk_unmute_state(int to)
-{
- pr_debug("%s: to=%d\n", __func__, to);
-
- spk_unmute = to;
- gpio_set_value(pdata->amp_gpio, to);
-
- /* if we're umuting, also re-set the gain */
- if (to && pdata->amp_gain[0] > 0)
- speaker_gain_set(spk_gain);
-}
-
-/**
- * speaker_unmute_get - read the speaker unmute setting.
- * @kcontrol: The control for the speaker gain.
- * @ucontrol: The value that needs to be updated.
- *
- * Read the value for the AMP gain control.
- */
-static int speaker_unmute_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- ucontrol->value.integer.value[0] = spk_unmute;
- return 0;
-}
-
-/**
- * speaker_unmute_put - set the speaker unmute setting.
- * @kcontrol: The control for the speaker gain.
- * @ucontrol: The value that needs to be set.
- *
- * Set the value of the speaker gain from the specified
- * @ucontrol setting.
- */
-static int speaker_unmute_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- spk_unmute_state(ucontrol->value.integer.value[0]);
- return 0;
-}
-
-/* This is added as a manual control as the speaker amps create clicks
- * when their power state is changed, which are far more noticeable than
- * anything produced by the CODEC itself.
- */
-static const struct snd_kcontrol_new amp_unmute_controls[] = {
- SOC_SINGLE_EXT("Speaker Switch", 0, 0, 1, 0,
- speaker_unmute_get, speaker_unmute_put),
-};
-
-void simtec_audio_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_soc_codec *codec = rtd->codec;
-
- if (pdata->amp_gpio > 0) {
- pr_debug("%s: adding amp routes\n", __func__);
-
- snd_soc_add_controls(codec, amp_unmute_controls,
- ARRAY_SIZE(amp_unmute_controls));
- }
-
- if (pdata->amp_gain[0] > 0) {
- pr_debug("%s: adding amp controls\n", __func__);
- snd_soc_add_controls(codec, amp_gain_controls,
- ARRAY_SIZE(amp_gain_controls));
- }
-}
-EXPORT_SYMBOL_GPL(simtec_audio_init);
-
-#define CODEC_CLOCK 12000000
-
-/**
- * simtec_hw_params - update hardware parameters
- * @substream: The audio substream instance.
- * @params: The parameters requested.
- *
- * Update the codec data routing and configuration settings
- * from the supplied data.
- */
-static int simtec_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
-{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- int ret;
-
- /* Set the CODEC as the bus clock master, I2S */
- ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBM_CFM);
- if (ret) {
- pr_err("%s: failed set cpu dai format\n", __func__);
- return ret;
- }
-
- /* Set the CODEC as the bus clock master */
- ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBM_CFM);
- if (ret) {
- pr_err("%s: failed set codec dai format\n", __func__);
- return ret;
- }
-
- ret = snd_soc_dai_set_sysclk(codec_dai, 0,
- CODEC_CLOCK, SND_SOC_CLOCK_IN);
- if (ret) {
- pr_err( "%s: failed setting codec sysclk\n", __func__);
- return ret;
- }
-
- if (pdata->use_mpllin) {
- ret = snd_soc_dai_set_sysclk(cpu_dai, S3C24XX_CLKSRC_MPLL,
- 0, SND_SOC_CLOCK_OUT);
-
- if (ret) {
- pr_err("%s: failed to set MPLLin as clksrc\n",
- __func__);
- return ret;
- }
- }
-
- if (pdata->output_cdclk) {
- int cdclk_scale;
-
- cdclk_scale = clk_get_rate(xtal_clk) / CODEC_CLOCK;
- cdclk_scale--;
-
- ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER,
- cdclk_scale);
- }
-
- return 0;
-}
-
-static int simtec_call_startup(struct s3c24xx_audio_simtec_pdata *pd)
-{
- /* call any board supplied startup code, this currently only
- * covers the bast/vr1000 which have a CPLD in the way of the
- * LRCLK */
- if (pd->startup)
- pd->startup();
-
- return 0;
-}
-
-static struct snd_soc_ops simtec_snd_ops = {
- .hw_params = simtec_hw_params,
-};
-
-/**
- * attach_gpio_amp - get and configure the necessary gpios
- * @dev: The device we're probing.
- * @pd: The platform data supplied by the board.
- *
- * If there is a GPIO based amplifier attached to the board, claim
- * the necessary GPIO lines for it, and set default values.
- */
-static int attach_gpio_amp(struct device *dev,
- struct s3c24xx_audio_simtec_pdata *pd)
-{
- int ret;
-
- /* attach gpio amp gain (if any) */
- if (pdata->amp_gain[0] > 0) {
- ret = gpio_request(pd->amp_gain[0], "gpio-amp-gain0");
- if (ret) {
- dev_err(dev, "cannot get amp gpio gain0\n");
- return ret;
- }
-
- ret = gpio_request(pd->amp_gain[1], "gpio-amp-gain1");
- if (ret) {
- dev_err(dev, "cannot get amp gpio gain1\n");
- gpio_free(pdata->amp_gain[0]);
- return ret;
- }
-
- gpio_direction_output(pd->amp_gain[0], 0);
- gpio_direction_output(pd->amp_gain[1], 0);
- }
-
- /* note, currently we assume GPA0 isn't valid amp */
- if (pdata->amp_gpio > 0) {
- ret = gpio_request(pd->amp_gpio, "gpio-amp");
- if (ret) {
- dev_err(dev, "cannot get amp gpio %d (%d)\n",
- pd->amp_gpio, ret);
- goto err_amp;
- }
-
- /* set the amp off at startup */
- spk_unmute_state(0);
- }
-
- return 0;
-
-err_amp:
- if (pd->amp_gain[0] > 0) {
- gpio_free(pd->amp_gain[0]);
- gpio_free(pd->amp_gain[1]);
- }
-
- return ret;
-}
-
-static void detach_gpio_amp(struct s3c24xx_audio_simtec_pdata *pd)
-{
- if (pd->amp_gain[0] > 0) {
- gpio_free(pd->amp_gain[0]);
- gpio_free(pd->amp_gain[1]);
- }
-
- if (pd->amp_gpio > 0)
- gpio_free(pd->amp_gpio);
-}
-
-#ifdef CONFIG_PM
-int simtec_audio_resume(struct device *dev)
-{
- simtec_call_startup(pdata);
- return 0;
-}
-
-const struct dev_pm_ops simtec_audio_pmops = {
- .resume = simtec_audio_resume,
-};
-EXPORT_SYMBOL_GPL(simtec_audio_pmops);
-#endif
-
-int __devinit simtec_audio_core_probe(struct platform_device *pdev,
- struct snd_soc_card *card)
-{
- struct platform_device *snd_dev;
- int ret;
-
- card->dai_link->ops = &simtec_snd_ops;
-
- pdata = pdev->dev.platform_data;
- if (!pdata) {
- dev_err(&pdev->dev, "no platform data supplied\n");
- return -EINVAL;
- }
-
- simtec_call_startup(pdata);
-
- xtal_clk = clk_get(&pdev->dev, "xtal");
- if (IS_ERR(xtal_clk)) {
- dev_err(&pdev->dev, "could not get clkout0\n");
- return -EINVAL;
- }
-
- dev_info(&pdev->dev, "xtal rate is %ld\n", clk_get_rate(xtal_clk));
-
- ret = attach_gpio_amp(&pdev->dev, pdata);
- if (ret)
- goto err_clk;
-
- snd_dev = platform_device_alloc("soc-audio", -1);
- if (!snd_dev) {
- dev_err(&pdev->dev, "failed to alloc soc-audio devicec\n");
- ret = -ENOMEM;
- goto err_gpio;
- }
-
- platform_set_drvdata(snd_dev, card);
-
- ret = platform_device_add(snd_dev);
- if (ret) {
- dev_err(&pdev->dev, "failed to add soc-audio dev\n");
- goto err_pdev;
- }
-
- platform_set_drvdata(pdev, snd_dev);
- return 0;
-
-err_pdev:
- platform_device_put(snd_dev);
-
-err_gpio:
- detach_gpio_amp(pdata);
-
-err_clk:
- clk_put(xtal_clk);
- return ret;
-}
-EXPORT_SYMBOL_GPL(simtec_audio_core_probe);
-
-int __devexit simtec_audio_remove(struct platform_device *pdev)
-{
- struct platform_device *snd_dev = platform_get_drvdata(pdev);
-
- platform_device_unregister(snd_dev);
-
- detach_gpio_amp(pdata);
- clk_put(xtal_clk);
- return 0;
-}
-EXPORT_SYMBOL_GPL(simtec_audio_remove);
-
-MODULE_AUTHOR("Ben Dooks <ben(a)simtec.co.uk>");
-MODULE_DESCRIPTION("ALSA SoC Simtec Audio common support");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/s3c24xx_simtec.h b/sound/soc/s3c24xx/s3c24xx_simtec.h
deleted file mode 100644
index e63d5ff..0000000
--- a/sound/soc/s3c24xx/s3c24xx_simtec.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/* sound/soc/s3c24xx/s3c24xx_simtec.h
- *
- * Copyright 2009 Simtec Electronics
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-extern void simtec_audio_init(struct snd_soc_pcm_runtime *rtd);
-
-extern int simtec_audio_core_probe(struct platform_device *pdev,
- struct snd_soc_card *card);
-
-extern int simtec_audio_remove(struct platform_device *pdev);
-
-#ifdef CONFIG_PM
-extern const struct dev_pm_ops simtec_audio_pmops;
-#define simtec_audio_pm &simtec_audio_pmops
-#else
-#define simtec_audio_pm NULL
-#endif
diff --git a/sound/soc/s3c24xx/s3c24xx_simtec_hermes.c b/sound/soc/s3c24xx/s3c24xx_simtec_hermes.c
deleted file mode 100644
index 8b246ab..0000000
--- a/sound/soc/s3c24xx/s3c24xx_simtec_hermes.c
+++ /dev/null
@@ -1,146 +0,0 @@
-/* sound/soc/s3c24xx/s3c24xx_simtec_hermes.c
- *
- * Copyright 2009 Simtec Electronics
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#include <linux/module.h>
-#include <linux/clk.h>
-#include <linux/platform_device.h>
-
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-#include <sound/soc-dapm.h>
-
-#include <plat/audio-simtec.h>
-
-#include "dma.h"
-#include "s3c24xx-i2s.h"
-#include "s3c24xx_simtec.h"
-
-#include "../codecs/tlv320aic3x.h"
-
-static const struct snd_soc_dapm_widget dapm_widgets[] = {
- SND_SOC_DAPM_LINE("GSM Out", NULL),
- SND_SOC_DAPM_LINE("GSM In", NULL),
- SND_SOC_DAPM_LINE("Line In", NULL),
- SND_SOC_DAPM_LINE("Line Out", NULL),
- SND_SOC_DAPM_LINE("ZV", NULL),
- SND_SOC_DAPM_MIC("Mic Jack", NULL),
- SND_SOC_DAPM_HP("Headphone Jack", NULL),
-};
-
-static const struct snd_soc_dapm_route base_map[] = {
- /* Headphone connected to HP{L,R}OUT and HP{L,R}COM */
-
- { "Headphone Jack", NULL, "HPLOUT" },
- { "Headphone Jack", NULL, "HPLCOM" },
- { "Headphone Jack", NULL, "HPROUT" },
- { "Headphone Jack", NULL, "HPRCOM" },
-
- /* ZV connected to Line1 */
-
- { "LINE1L", NULL, "ZV" },
- { "LINE1R", NULL, "ZV" },
-
- /* Line In connected to Line2 */
-
- { "LINE2L", NULL, "Line In" },
- { "LINE2R", NULL, "Line In" },
-
- /* Microphone connected to MIC3R and MIC_BIAS */
-
- { "MIC3L", NULL, "Mic Jack" },
-
- /* GSM connected to MONO_LOUT and MIC3L (in) */
-
- { "GSM Out", NULL, "MONO_LOUT" },
- { "MIC3L", NULL, "GSM In" },
-
- /* Speaker is connected to LINEOUT{LN,LP,RN,RP}, however we are
- * not using the DAPM to power it up and down as there it makes
- * a click when powering up. */
-};
-
-/**
- * simtec_hermes_init - initialise and add controls
- * @codec; The codec instance to attach to.
- *
- * Attach our controls and configure the necessary codec
- * mappings for our sound card instance.
-*/
-static int simtec_hermes_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_soc_codec *codec = rtd->codec;
-
- snd_soc_dapm_new_controls(codec, dapm_widgets,
- ARRAY_SIZE(dapm_widgets));
-
- snd_soc_dapm_add_routes(codec, base_map, ARRAY_SIZE(base_map));
-
- snd_soc_dapm_enable_pin(codec, "Headphone Jack");
- snd_soc_dapm_enable_pin(codec, "Line In");
- snd_soc_dapm_enable_pin(codec, "Line Out");
- snd_soc_dapm_enable_pin(codec, "Mic Jack");
-
- simtec_audio_init(rtd);
- snd_soc_dapm_sync(codec);
-
- return 0;
-}
-
-static struct snd_soc_dai_link simtec_dai_aic33 = {
- .name = "tlv320aic33",
- .stream_name = "TLV320AIC33",
- .codec_name = "tlv320aic3x-codec.0-0x1a",
- .cpu_dai_name = "s3c24xx-i2s",
- .codec_dai_name = "tlv320aic3x-hifi",
- .platform_name = "samsung-audio",
- .init = simtec_hermes_init,
-};
-
-/* simtec audio machine driver */
-static struct snd_soc_card snd_soc_machine_simtec_aic33 = {
- .name = "Simtec-Hermes",
- .dai_link = &simtec_dai_aic33,
- .num_links = 1,
-};
-
-static int __devinit simtec_audio_hermes_probe(struct platform_device *pd)
-{
- dev_info(&pd->dev, "probing....\n");
- return simtec_audio_core_probe(pd, &snd_soc_machine_simtec_aic33);
-}
-
-static struct platform_driver simtec_audio_hermes_platdrv = {
- .driver = {
- .owner = THIS_MODULE,
- .name = "s3c24xx-simtec-hermes-snd",
- .pm = simtec_audio_pm,
- },
- .probe = simtec_audio_hermes_probe,
- .remove = __devexit_p(simtec_audio_remove),
-};
-
-MODULE_ALIAS("platform:s3c24xx-simtec-hermes-snd");
-
-static int __init simtec_hermes_modinit(void)
-{
- return platform_driver_register(&simtec_audio_hermes_platdrv);
-}
-
-static void __exit simtec_hermes_modexit(void)
-{
- platform_driver_unregister(&simtec_audio_hermes_platdrv);
-}
-
-module_init(simtec_hermes_modinit);
-module_exit(simtec_hermes_modexit);
-
-MODULE_AUTHOR("Ben Dooks <ben(a)simtec.co.uk>");
-MODULE_DESCRIPTION("ALSA SoC Simtec Audio support");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c b/sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c
deleted file mode 100644
index a922e1e..0000000
--- a/sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c
+++ /dev/null
@@ -1,134 +0,0 @@
-/* sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c
- *
- * Copyright 2009 Simtec Electronics
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#include <linux/module.h>
-#include <linux/clk.h>
-#include <linux/platform_device.h>
-
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-#include <sound/soc-dapm.h>
-
-#include <plat/audio-simtec.h>
-
-#include "dma.h"
-#include "s3c24xx-i2s.h"
-#include "s3c24xx_simtec.h"
-
-#include "../codecs/tlv320aic23.h"
-
-/* supported machines:
- *
- * Machine Connections AMP
- * ------- ----------- ---
- * BAST MIC, HPOUT, LOUT, LIN TPA2001D1 (HPOUTL,R) (gain hardwired)
- * VR1000 HPOUT, LIN None
- * VR2000 LIN, LOUT, MIC, HP LM4871 (HPOUTL,R)
- * DePicture LIN, LOUT, MIC, HP LM4871 (HPOUTL,R)
- * Anubis LIN, LOUT, MIC, HP TPA2001D1 (HPOUTL,R)
- */
-
-static const struct snd_soc_dapm_widget dapm_widgets[] = {
- SND_SOC_DAPM_HP("Headphone Jack", NULL),
- SND_SOC_DAPM_LINE("Line In", NULL),
- SND_SOC_DAPM_LINE("Line Out", NULL),
- SND_SOC_DAPM_MIC("Mic Jack", NULL),
-};
-
-static const struct snd_soc_dapm_route base_map[] = {
- { "Headphone Jack", NULL, "LHPOUT"},
- { "Headphone Jack", NULL, "RHPOUT"},
-
- { "Line Out", NULL, "LOUT" },
- { "Line Out", NULL, "ROUT" },
-
- { "LLINEIN", NULL, "Line In"},
- { "RLINEIN", NULL, "Line In"},
-
- { "MICIN", NULL, "Mic Jack"},
-};
-
-/**
- * simtec_tlv320aic23_init - initialise and add controls
- * @codec; The codec instance to attach to.
- *
- * Attach our controls and configure the necessary codec
- * mappings for our sound card instance.
-*/
-static int simtec_tlv320aic23_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_soc_codec *codec = rtd->codec;
-
- snd_soc_dapm_new_controls(codec, dapm_widgets,
- ARRAY_SIZE(dapm_widgets));
-
- snd_soc_dapm_add_routes(codec, base_map, ARRAY_SIZE(base_map));
-
- snd_soc_dapm_enable_pin(codec, "Headphone Jack");
- snd_soc_dapm_enable_pin(codec, "Line In");
- snd_soc_dapm_enable_pin(codec, "Line Out");
- snd_soc_dapm_enable_pin(codec, "Mic Jack");
-
- simtec_audio_init(rtd);
- snd_soc_dapm_sync(codec);
-
- return 0;
-}
-
-static struct snd_soc_dai_link simtec_dai_aic23 = {
- .name = "tlv320aic23",
- .stream_name = "TLV320AIC23",
- .codec_name = "tlv320aic3x-codec.0-0x1a",
- .cpu_dai_name = "s3c24xx-i2s",
- .codec_dai_name = "tlv320aic3x-hifi",
- .platform_name = "samsung-audio",
- .init = simtec_tlv320aic23_init,
-};
-
-/* simtec audio machine driver */
-static struct snd_soc_card snd_soc_machine_simtec_aic23 = {
- .name = "Simtec",
- .dai_link = &simtec_dai_aic23,
- .num_links = 1,
-};
-
-static int __devinit simtec_audio_tlv320aic23_probe(struct platform_device *pd)
-{
- return simtec_audio_core_probe(pd, &snd_soc_machine_simtec_aic23);
-}
-
-static struct platform_driver simtec_audio_tlv320aic23_platdrv = {
- .driver = {
- .owner = THIS_MODULE,
- .name = "s3c24xx-simtec-tlv320aic23",
- .pm = simtec_audio_pm,
- },
- .probe = simtec_audio_tlv320aic23_probe,
- .remove = __devexit_p(simtec_audio_remove),
-};
-
-MODULE_ALIAS("platform:s3c24xx-simtec-tlv320aic23");
-
-static int __init simtec_tlv320aic23_modinit(void)
-{
- return platform_driver_register(&simtec_audio_tlv320aic23_platdrv);
-}
-
-static void __exit simtec_tlv320aic23_modexit(void)
-{
- platform_driver_unregister(&simtec_audio_tlv320aic23_platdrv);
-}
-
-module_init(simtec_tlv320aic23_modinit);
-module_exit(simtec_tlv320aic23_modexit);
-
-MODULE_AUTHOR("Ben Dooks <ben(a)simtec.co.uk>");
-MODULE_DESCRIPTION("ALSA SoC Simtec Audio support");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/s3c24xx_uda134x.c b/sound/soc/s3c24xx/s3c24xx_uda134x.c
deleted file mode 100644
index 87eeb46..0000000
--- a/sound/soc/s3c24xx/s3c24xx_uda134x.c
+++ /dev/null
@@ -1,368 +0,0 @@
-/*
- * Modifications by Christian Pellegrin <chripell(a)evolware.org>
- *
- * s3c24xx_uda134x.c -- S3C24XX_UDA134X ALSA SoC Audio board driver
- *
- * Copyright 2007 Dension Audio Systems Ltd.
- * Author: Zoltan Devai
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/module.h>
-#include <linux/clk.h>
-#include <linux/mutex.h>
-#include <linux/gpio.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-#include <sound/soc-dapm.h>
-#include <sound/s3c24xx_uda134x.h>
-#include <sound/uda134x.h>
-
-#include <plat/regs-iis.h>
-
-#include "dma.h"
-#include "s3c24xx-i2s.h"
-#include "../codecs/uda134x.h"
-
-
-/* #define ENFORCE_RATES 1 */
-/*
- Unfortunately the S3C24XX in master mode has a limited capacity of
- generating the clock for the codec. If you define this only rates
- that are really available will be enforced. But be careful, most
- user level application just want the usual sampling frequencies (8,
- 11.025, 22.050, 44.1 kHz) and anyway resampling is a costly
- operation for embedded systems. So if you aren't very lucky or your
- hardware engineer wasn't very forward-looking it's better to leave
- this undefined. If you do so an approximate value for the requested
- sampling rate in the range -/+ 5% will be chosen. If this in not
- possible an error will be returned.
-*/
-
-static struct clk *xtal;
-static struct clk *pclk;
-/* this is need because we don't have a place where to keep the
- * pointers to the clocks in each substream. We get the clocks only
- * when we are actually using them so we don't block stuff like
- * frequency change or oscillator power-off */
-static int clk_users;
-static DEFINE_MUTEX(clk_lock);
-
-static unsigned int rates[33 * 2];
-#ifdef ENFORCE_RATES
-static struct snd_pcm_hw_constraint_list hw_constraints_rates = {
- .count = ARRAY_SIZE(rates),
- .list = rates,
- .mask = 0,
-};
-#endif
-
-static struct platform_device *s3c24xx_uda134x_snd_device;
-
-static int s3c24xx_uda134x_startup(struct snd_pcm_substream *substream)
-{
- int ret = 0;
-#ifdef ENFORCE_RATES
- struct snd_pcm_runtime *runtime = substream->runtime;
-#endif
-
- mutex_lock(&clk_lock);
- pr_debug("%s %d\n", __func__, clk_users);
- if (clk_users == 0) {
- xtal = clk_get(&s3c24xx_uda134x_snd_device->dev, "xtal");
- if (!xtal) {
- printk(KERN_ERR "%s cannot get xtal\n", __func__);
- ret = -EBUSY;
- } else {
- pclk = clk_get(&s3c24xx_uda134x_snd_device->dev,
- "pclk");
- if (!pclk) {
- printk(KERN_ERR "%s cannot get pclk\n",
- __func__);
- clk_put(xtal);
- ret = -EBUSY;
- }
- }
- if (!ret) {
- int i, j;
-
- for (i = 0; i < 2; i++) {
- int fs = i ? 256 : 384;
-
- rates[i*33] = clk_get_rate(xtal) / fs;
- for (j = 1; j < 33; j++)
- rates[i*33 + j] = clk_get_rate(pclk) /
- (j * fs);
- }
- }
- }
- clk_users += 1;
- mutex_unlock(&clk_lock);
- if (!ret) {
-#ifdef ENFORCE_RATES
- ret = snd_pcm_hw_constraint_list(runtime, 0,
- SNDRV_PCM_HW_PARAM_RATE,
- &hw_constraints_rates);
- if (ret < 0)
- printk(KERN_ERR "%s cannot set constraints\n",
- __func__);
-#endif
- }
- return ret;
-}
-
-static void s3c24xx_uda134x_shutdown(struct snd_pcm_substream *substream)
-{
- mutex_lock(&clk_lock);
- pr_debug("%s %d\n", __func__, clk_users);
- clk_users -= 1;
- if (clk_users == 0) {
- clk_put(xtal);
- xtal = NULL;
- clk_put(pclk);
- pclk = NULL;
- }
- mutex_unlock(&clk_lock);
-}
-
-static int s3c24xx_uda134x_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
-{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- unsigned int clk = 0;
- int ret = 0;
- int clk_source, fs_mode;
- unsigned long rate = params_rate(params);
- long err, cerr;
- unsigned int div;
- int i, bi;
-
- err = 999999;
- bi = 0;
- for (i = 0; i < 2*33; i++) {
- cerr = rates[i] - rate;
- if (cerr < 0)
- cerr = -cerr;
- if (cerr < err) {
- err = cerr;
- bi = i;
- }
- }
- if (bi / 33 == 1)
- fs_mode = S3C2410_IISMOD_256FS;
- else
- fs_mode = S3C2410_IISMOD_384FS;
- if (bi % 33 == 0) {
- clk_source = S3C24XX_CLKSRC_MPLL;
- div = 1;
- } else {
- clk_source = S3C24XX_CLKSRC_PCLK;
- div = bi % 33;
- }
- pr_debug("%s desired rate %lu, %d\n", __func__, rate, bi);
-
- clk = (fs_mode == S3C2410_IISMOD_384FS ? 384 : 256) * rate;
- pr_debug("%s will use: %s %s %d sysclk %d err %ld\n", __func__,
- fs_mode == S3C2410_IISMOD_384FS ? "384FS" : "256FS",
- clk_source == S3C24XX_CLKSRC_MPLL ? "MPLLin" : "PCLK",
- div, clk, err);
-
- if ((err * 100 / rate) > 5) {
- printk(KERN_ERR "S3C24XX_UDA134X: effective frequency "
- "too different from desired (%ld%%)\n",
- err * 100 / rate);
- return -EINVAL;
- }
-
- ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
- if (ret < 0)
- return ret;
-
- ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
- if (ret < 0)
- return ret;
-
- ret = snd_soc_dai_set_sysclk(cpu_dai, clk_source , clk,
- SND_SOC_CLOCK_IN);
- if (ret < 0)
- return ret;
-
- ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK, fs_mode);
- if (ret < 0)
- return ret;
-
- ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_BCLK,
- S3C2410_IISMOD_32FS);
- if (ret < 0)
- return ret;
-
- ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER,
- S3C24XX_PRESCALE(div, div));
- if (ret < 0)
- return ret;
-
- /* set the codec system clock for DAC and ADC */
- ret = snd_soc_dai_set_sysclk(codec_dai, 0, clk,
- SND_SOC_CLOCK_OUT);
- if (ret < 0)
- return ret;
-
- return 0;
-}
-
-static struct snd_soc_ops s3c24xx_uda134x_ops = {
- .startup = s3c24xx_uda134x_startup,
- .shutdown = s3c24xx_uda134x_shutdown,
- .hw_params = s3c24xx_uda134x_hw_params,
-};
-
-static struct snd_soc_dai_link s3c24xx_uda134x_dai_link = {
- .name = "UDA134X",
- .stream_name = "UDA134X",
- .codec_name = "uda134x-hifi",
- .codec_dai_name = "uda134x-hifi",
- .cpu_dai_name = "s3c24xx-i2s",
- .ops = &s3c24xx_uda134x_ops,
- .platform_name = "samsung-audio",
-};
-
-static struct snd_soc_card snd_soc_s3c24xx_uda134x = {
- .name = "S3C24XX_UDA134X",
- .dai_link = &s3c24xx_uda134x_dai_link,
- .num_links = 1,
-};
-
-static struct s3c24xx_uda134x_platform_data *s3c24xx_uda134x_l3_pins;
-
-static void setdat(int v)
-{
- gpio_set_value(s3c24xx_uda134x_l3_pins->l3_data, v > 0);
-}
-
-static void setclk(int v)
-{
- gpio_set_value(s3c24xx_uda134x_l3_pins->l3_clk, v > 0);
-}
-
-static void setmode(int v)
-{
- gpio_set_value(s3c24xx_uda134x_l3_pins->l3_mode, v > 0);
-}
-
-/* FIXME - This must be codec platform data but in which board file ?? */
-static struct uda134x_platform_data s3c24xx_uda134x = {
- .l3 = {
- .setdat = setdat,
- .setclk = setclk,
- .setmode = setmode,
- .data_hold = 1,
- .data_setup = 1,
- .clock_high = 1,
- .mode_hold = 1,
- .mode = 1,
- .mode_setup = 1,
- },
-};
-
-static int s3c24xx_uda134x_setup_pin(int pin, char *fun)
-{
- if (gpio_request(pin, "s3c24xx_uda134x") < 0) {
- printk(KERN_ERR "S3C24XX_UDA134X SoC Audio: "
- "l3 %s pin already in use", fun);
- return -EBUSY;
- }
- gpio_direction_output(pin, 0);
- return 0;
-}
-
-static int s3c24xx_uda134x_probe(struct platform_device *pdev)
-{
- int ret;
-
- printk(KERN_INFO "S3C24XX_UDA134X SoC Audio driver\n");
-
- s3c24xx_uda134x_l3_pins = pdev->dev.platform_data;
- if (s3c24xx_uda134x_l3_pins == NULL) {
- printk(KERN_ERR "S3C24XX_UDA134X SoC Audio: "
- "unable to find platform data\n");
- return -ENODEV;
- }
- s3c24xx_uda134x.power = s3c24xx_uda134x_l3_pins->power;
- s3c24xx_uda134x.model = s3c24xx_uda134x_l3_pins->model;
-
- if (s3c24xx_uda134x_setup_pin(s3c24xx_uda134x_l3_pins->l3_data,
- "data") < 0)
- return -EBUSY;
- if (s3c24xx_uda134x_setup_pin(s3c24xx_uda134x_l3_pins->l3_clk,
- "clk") < 0) {
- gpio_free(s3c24xx_uda134x_l3_pins->l3_data);
- return -EBUSY;
- }
- if (s3c24xx_uda134x_setup_pin(s3c24xx_uda134x_l3_pins->l3_mode,
- "mode") < 0) {
- gpio_free(s3c24xx_uda134x_l3_pins->l3_data);
- gpio_free(s3c24xx_uda134x_l3_pins->l3_clk);
- return -EBUSY;
- }
-
- s3c24xx_uda134x_snd_device = platform_device_alloc("soc-audio", -1);
- if (!s3c24xx_uda134x_snd_device) {
- printk(KERN_ERR "S3C24XX_UDA134X SoC Audio: "
- "Unable to register\n");
- return -ENOMEM;
- }
-
- platform_set_drvdata(s3c24xx_uda134x_snd_device,
- &snd_soc_s3c24xx_uda134x);
- ret = platform_device_add(s3c24xx_uda134x_snd_device);
- if (ret) {
- printk(KERN_ERR "S3C24XX_UDA134X SoC Audio: Unable to add\n");
- platform_device_put(s3c24xx_uda134x_snd_device);
- }
-
- return ret;
-}
-
-static int s3c24xx_uda134x_remove(struct platform_device *pdev)
-{
- platform_device_unregister(s3c24xx_uda134x_snd_device);
- gpio_free(s3c24xx_uda134x_l3_pins->l3_data);
- gpio_free(s3c24xx_uda134x_l3_pins->l3_clk);
- gpio_free(s3c24xx_uda134x_l3_pins->l3_mode);
- return 0;
-}
-
-static struct platform_driver s3c24xx_uda134x_driver = {
- .probe = s3c24xx_uda134x_probe,
- .remove = s3c24xx_uda134x_remove,
- .driver = {
- .name = "s3c24xx_uda134x",
- .owner = THIS_MODULE,
- },
-};
-
-static int __init s3c24xx_uda134x_init(void)
-{
- return platform_driver_register(&s3c24xx_uda134x_driver);
-}
-
-static void __exit s3c24xx_uda134x_exit(void)
-{
- platform_driver_unregister(&s3c24xx_uda134x_driver);
-}
-
-
-module_init(s3c24xx_uda134x_init);
-module_exit(s3c24xx_uda134x_exit);
-
-MODULE_AUTHOR("Zoltan Devai, Christian Pellegrin <chripell(a)evolware.org>");
-MODULE_DESCRIPTION("S3C24XX_UDA134X ALSA SoC audio driver");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/smartq_wm8987.c b/sound/soc/s3c24xx/smartq_wm8987.c
deleted file mode 100644
index 5fcc420..0000000
--- a/sound/soc/s3c24xx/smartq_wm8987.c
+++ /dev/null
@@ -1,287 +0,0 @@
-/* sound/soc/s3c24xx/smartq_wm8987.c
- *
- * Copyright 2010 Maurus Cuelenaere <mcuelenaere(a)gmail.com>
- *
- * Based on smdk6410_wm8987.c
- * Copyright 2007 Wolfson Microelectronics PLC. - linux(a)wolfsonmicro.com
- * Graeme Gregory - graeme.gregory(a)wolfsonmicro.com
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- */
-
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/gpio.h>
-
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc-dapm.h>
-#include <sound/jack.h>
-
-#include <asm/mach-types.h>
-
-#include "dma.h"
-#include "i2s.h"
-
-#include "../codecs/wm8750.h"
-
-/*
- * WM8987 is register compatible with WM8750, so using that as base driver.
- */
-
-static struct snd_soc_card snd_soc_smartq;
-
-static int smartq_hifi_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
-{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
- unsigned int clk = 0;
- int ret;
-
- switch (params_rate(params)) {
- case 8000:
- case 16000:
- case 32000:
- case 48000:
- case 96000:
- clk = 12288000;
- break;
- case 11025:
- case 22050:
- case 44100:
- case 88200:
- clk = 11289600;
- break;
- }
-
- /* set codec DAI configuration */
- ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBS_CFS);
- if (ret < 0)
- return ret;
-
- /* set cpu DAI configuration */
- ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBS_CFS);
- if (ret < 0)
- return ret;
-
- /* Use PCLK for I2S signal generation */
- ret = snd_soc_dai_set_sysclk(cpu_dai, SAMSUNG_I2S_RCLKSRC_0,
- 0, SND_SOC_CLOCK_IN);
- if (ret < 0)
- return ret;
-
- /* Gate the RCLK output on PAD */
- ret = snd_soc_dai_set_sysclk(cpu_dai, SAMSUNG_I2S_CDCLK,
- 0, SND_SOC_CLOCK_IN);
- if (ret < 0)
- return ret;
-
- /* set the codec system clock for DAC and ADC */
- ret = snd_soc_dai_set_sysclk(codec_dai, WM8750_SYSCLK, clk,
- SND_SOC_CLOCK_IN);
- if (ret < 0)
- return ret;
-
- return 0;
-}
-
-/*
- * SmartQ WM8987 HiFi DAI operations.
- */
-static struct snd_soc_ops smartq_hifi_ops = {
- .hw_params = smartq_hifi_hw_params,
-};
-
-static struct snd_soc_jack smartq_jack;
-
-static struct snd_soc_jack_pin smartq_jack_pins[] = {
- /* Disable speaker when headphone is plugged in */
- {
- .pin = "Internal Speaker",
- .mask = SND_JACK_HEADPHONE,
- },
-};
-
-static struct snd_soc_jack_gpio smartq_jack_gpios[] = {
- {
- .gpio = S3C64XX_GPL(12),
- .name = "headphone detect",
- .report = SND_JACK_HEADPHONE,
- .debounce_time = 200,
- },
-};
-
-static const struct snd_kcontrol_new wm8987_smartq_controls[] = {
- SOC_DAPM_PIN_SWITCH("Internal Speaker"),
- SOC_DAPM_PIN_SWITCH("Headphone Jack"),
- SOC_DAPM_PIN_SWITCH("Internal Mic"),
-};
-
-static int smartq_speaker_event(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *k,
- int event)
-{
- gpio_set_value(S3C64XX_GPK(12), SND_SOC_DAPM_EVENT_OFF(event));
-
- return 0;
-}
-
-static const struct snd_soc_dapm_widget wm8987_dapm_widgets[] = {
- SND_SOC_DAPM_SPK("Internal Speaker", smartq_speaker_event),
- SND_SOC_DAPM_HP("Headphone Jack", NULL),
- SND_SOC_DAPM_MIC("Internal Mic", NULL),
-};
-
-static const struct snd_soc_dapm_route audio_map[] = {
- {"Headphone Jack", NULL, "LOUT2"},
- {"Headphone Jack", NULL, "ROUT2"},
-
- {"Internal Speaker", NULL, "LOUT2"},
- {"Internal Speaker", NULL, "ROUT2"},
-
- {"Mic Bias", NULL, "Internal Mic"},
- {"LINPUT2", NULL, "Mic Bias"},
-};
-
-static int smartq_wm8987_init(struct snd_soc_codec *codec)
-{
- int err = 0;
-
- /* Add SmartQ specific widgets */
- snd_soc_dapm_new_controls(codec, wm8987_dapm_widgets,
- ARRAY_SIZE(wm8987_dapm_widgets));
-
- /* add SmartQ specific controls */
- err = snd_soc_add_controls(codec, wm8987_smartq_controls,
- ARRAY_SIZE(wm8987_smartq_controls));
-
- if (err < 0)
- return err;
-
- /* setup SmartQ specific audio path */
- snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
-
- /* set endpoints to not connected */
- snd_soc_dapm_nc_pin(codec, "LINPUT1");
- snd_soc_dapm_nc_pin(codec, "RINPUT1");
- snd_soc_dapm_nc_pin(codec, "OUT3");
- snd_soc_dapm_nc_pin(codec, "ROUT1");
-
- /* set endpoints to default off mode */
- snd_soc_dapm_enable_pin(codec, "Internal Speaker");
- snd_soc_dapm_enable_pin(codec, "Internal Mic");
- snd_soc_dapm_disable_pin(codec, "Headphone Jack");
-
- err = snd_soc_dapm_sync(codec);
- if (err)
- return err;
-
- /* Headphone jack detection */
- err = snd_soc_jack_new(&snd_soc_smartq, "Headphone Jack",
- SND_JACK_HEADPHONE, &smartq_jack);
- if (err)
- return err;
-
- err = snd_soc_jack_add_pins(&smartq_jack, ARRAY_SIZE(smartq_jack_pins),
- smartq_jack_pins);
- if (err)
- return err;
-
- err = snd_soc_jack_add_gpios(&smartq_jack,
- ARRAY_SIZE(smartq_jack_gpios),
- smartq_jack_gpios);
-
- return err;
-}
-
-static struct snd_soc_dai_link smartq_dai[] = {
- {
- .name = "wm8987",
- .stream_name = "SmartQ Hi-Fi",
- .cpu_dai_name = "samsung-i2s.0",
- .codec_dai_name = "wm8750-hifi",
- .platform_name = "samsung-audio",
- .codec_name = "wm8750-codec.0-0x1a",
- .init = smartq_wm8987_init,
- .ops = &smartq_hifi_ops,
- },
-};
-
-static struct snd_soc_card snd_soc_smartq = {
- .name = "SmartQ",
- .dai_link = smartq_dai,
- .num_links = ARRAY_SIZE(smartq_dai),
-};
-
-static struct platform_device *smartq_snd_device;
-
-static int __init smartq_init(void)
-{
- int ret;
-
- if (!machine_is_smartq7() && !machine_is_smartq5()) {
- pr_info("Only SmartQ is supported by this ASoC driver\n");
- return -ENODEV;
- }
-
- smartq_snd_device = platform_device_alloc("soc-audio", -1);
- if (!smartq_snd_device)
- return -ENOMEM;
-
- platform_set_drvdata(smartq_snd_device, &snd_soc_smartq);
-
- ret = platform_device_add(smartq_snd_device);
- if (ret) {
- platform_device_put(smartq_snd_device);
- return ret;
- }
-
- /* Initialise GPIOs used by amplifiers */
- ret = gpio_request(S3C64XX_GPK(12), "amplifiers shutdown");
- if (ret) {
- dev_err(&smartq_snd_device->dev, "Failed to register GPK12\n");
- goto err_unregister_device;
- }
-
- /* Disable amplifiers */
- ret = gpio_direction_output(S3C64XX_GPK(12), 1);
- if (ret) {
- dev_err(&smartq_snd_device->dev, "Failed to configure GPK12\n");
- goto err_free_gpio_amp_shut;
- }
-
- return 0;
-
-err_free_gpio_amp_shut:
- gpio_free(S3C64XX_GPK(12));
-err_unregister_device:
- platform_device_unregister(smartq_snd_device);
-
- return ret;
-}
-
-static void __exit smartq_exit(void)
-{
- snd_soc_jack_free_gpios(&smartq_jack, ARRAY_SIZE(smartq_jack_gpios),
- smartq_jack_gpios);
-
- platform_device_unregister(smartq_snd_device);
-}
-
-module_init(smartq_init);
-module_exit(smartq_exit);
-
-/* Module information */
-MODULE_AUTHOR("Maurus Cuelenaere <mcuelenaere(a)gmail.com>");
-MODULE_DESCRIPTION("ALSA SoC SmartQ WM8987");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/smdk2443_wm9710.c b/sound/soc/s3c24xx/smdk2443_wm9710.c
deleted file mode 100644
index 5051699..0000000
--- a/sound/soc/s3c24xx/smdk2443_wm9710.c
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * smdk2443_wm9710.c -- SoC audio for smdk2443
- *
- * Copyright 2007 Wolfson Microelectronics PLC.
- * Author: Graeme Gregory
- * graeme.gregory(a)wolfsonmicro.com or linux(a)wolfsonmicro.com
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- */
-
-#include <linux/module.h>
-#include <linux/device.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-#include <sound/soc-dapm.h>
-
-#include "dma.h"
-#include "ac97.h"
-
-static struct snd_soc_card smdk2443;
-
-static struct snd_soc_dai_link smdk2443_dai[] = {
-{
- .name = "AC97",
- .stream_name = "AC97 HiFi",
- .cpu_dai_name = "samsung-ac97",
- .codec_dai_name = "ac97-hifi",
- .codec_name = "ac97-codec",
- .platform_name = "samsung-audio",
-},
-};
-
-static struct snd_soc_card smdk2443 = {
- .name = "SMDK2443",
- .dai_link = smdk2443_dai,
- .num_links = ARRAY_SIZE(smdk2443_dai),
-};
-
-static struct platform_device *smdk2443_snd_ac97_device;
-
-static int __init smdk2443_init(void)
-{
- int ret;
-
- smdk2443_snd_ac97_device = platform_device_alloc("soc-audio", -1);
- if (!smdk2443_snd_ac97_device)
- return -ENOMEM;
-
- platform_set_drvdata(smdk2443_snd_ac97_device, &smdk2443);
- ret = platform_device_add(smdk2443_snd_ac97_device);
-
- if (ret)
- platform_device_put(smdk2443_snd_ac97_device);
-
- return ret;
-}
-
-static void __exit smdk2443_exit(void)
-{
- platform_device_unregister(smdk2443_snd_ac97_device);
-}
-
-module_init(smdk2443_init);
-module_exit(smdk2443_exit);
-
-/* Module information */
-MODULE_AUTHOR("Graeme Gregory, graeme.gregory(a)wolfsonmicro.com, www.wolfsonmicro.com");
-MODULE_DESCRIPTION("ALSA SoC WM9710 SMDK2443");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/smdk_spdif.c b/sound/soc/s3c24xx/smdk_spdif.c
deleted file mode 100644
index 4fc6a9f..0000000
--- a/sound/soc/s3c24xx/smdk_spdif.c
+++ /dev/null
@@ -1,223 +0,0 @@
-/*
- * smdk_spdif.c -- S/PDIF audio for SMDK
- *
- * Copyright 2010 Samsung Electronics Co. Ltd.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- */
-
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/clk.h>
-
-#include <plat/devs.h>
-
-#include <sound/soc.h>
-
-#include "dma.h"
-#include "spdif.h"
-
-/* Audio clock settings are belonged to board specific part. Every
- * board can set audio source clock setting which is matched with H/W
- * like this function-'set_audio_clock_heirachy'.
- */
-static int set_audio_clock_heirachy(struct platform_device *pdev)
-{
- struct clk *fout_epll, *mout_epll, *sclk_audio0, *sclk_spdif;
- int ret;
-
- fout_epll = clk_get(NULL, "fout_epll");
- if (IS_ERR(fout_epll)) {
- printk(KERN_WARNING "%s: Cannot find fout_epll.\n",
- __func__);
- return -EINVAL;
- }
-
- mout_epll = clk_get(NULL, "mout_epll");
- if (IS_ERR(fout_epll)) {
- printk(KERN_WARNING "%s: Cannot find mout_epll.\n",
- __func__);
- ret = -EINVAL;
- goto out1;
- }
-
- sclk_audio0 = clk_get(&pdev->dev, "sclk_audio");
- if (IS_ERR(sclk_audio0)) {
- printk(KERN_WARNING "%s: Cannot find sclk_audio.\n",
- __func__);
- ret = -EINVAL;
- goto out2;
- }
-
- sclk_spdif = clk_get(NULL, "sclk_spdif");
- if (IS_ERR(fout_epll)) {
- printk(KERN_WARNING "%s: Cannot find sclk_spdif.\n",
- __func__);
- ret = -EINVAL;
- goto out3;
- }
-
- /* Set audio clock heirachy for S/PDIF */
- clk_set_parent(mout_epll, fout_epll);
- clk_set_parent(sclk_audio0, mout_epll);
- clk_set_parent(sclk_spdif, sclk_audio0);
-
- clk_put(sclk_spdif);
-out3:
- clk_put(sclk_audio0);
-out2:
- clk_put(mout_epll);
-out1:
- clk_put(fout_epll);
-
- return ret;
-}
-
-/* We should haved to set clock directly on this part because of clock
- * scheme of Samsudng SoCs did not support to set rates from abstrct
- * clock of it's heirachy.
- */
-static int set_audio_clock_rate(unsigned long epll_rate,
- unsigned long audio_rate)
-{
- struct clk *fout_epll, *sclk_spdif;
-
- fout_epll = clk_get(NULL, "fout_epll");
- if (IS_ERR(fout_epll)) {
- printk(KERN_ERR "%s: failed to get fout_epll\n", __func__);
- return -ENOENT;
- }
-
- clk_set_rate(fout_epll, epll_rate);
- clk_put(fout_epll);
-
- sclk_spdif = clk_get(NULL, "sclk_spdif");
- if (IS_ERR(sclk_spdif)) {
- printk(KERN_ERR "%s: failed to get sclk_spdif\n", __func__);
- return -ENOENT;
- }
-
- clk_set_rate(sclk_spdif, audio_rate);
- clk_put(sclk_spdif);
-
- return 0;
-}
-
-static int smdk_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
-{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- unsigned long pll_out, rclk_rate;
- int ret, ratio;
-
- switch (params_rate(params)) {
- case 44100:
- pll_out = 45158400;
- break;
- case 32000:
- case 48000:
- case 96000:
- pll_out = 49152000;
- break;
- default:
- return -EINVAL;
- }
-
- /* Setting ratio to 512fs helps to use S/PDIF with HDMI without
- * modify S/PDIF ASoC machine driver.
- */
- ratio = 512;
- rclk_rate = params_rate(params) * ratio;
-
- /* Set audio source clock rates */
- ret = set_audio_clock_rate(pll_out, rclk_rate);
- if (ret < 0)
- return ret;
-
- /* Set S/PDIF uses internal source clock */
- ret = snd_soc_dai_set_sysclk(cpu_dai, SND_SOC_SPDIF_INT_MCLK,
- rclk_rate, SND_SOC_CLOCK_IN);
- if (ret < 0)
- return ret;
-
- return ret;
-}
-
-static struct snd_soc_ops smdk_spdif_ops = {
- .hw_params = smdk_hw_params,
-};
-
-static struct snd_soc_card smdk;
-
-static struct snd_soc_dai_link smdk_dai = {
- .name = "S/PDIF",
- .stream_name = "S/PDIF PCM Playback",
- .platform_name = "samsung-audio",
- .cpu_dai_name = "samsung-spdif",
- .codec_dai_name = "dit-hifi",
- .codec_name = "spdif-dit",
- .ops = &smdk_spdif_ops,
-};
-
-static struct snd_soc_card smdk = {
- .name = "SMDK-S/PDIF",
- .dai_link = &smdk_dai,
- .num_links = 1,
-};
-
-static struct platform_device *smdk_snd_spdif_dit_device;
-static struct platform_device *smdk_snd_spdif_device;
-
-static int __init smdk_init(void)
-{
- int ret;
-
- smdk_snd_spdif_dit_device = platform_device_alloc("spdif-dit", -1);
- if (!smdk_snd_spdif_dit_device)
- return -ENOMEM;
-
- ret = platform_device_add(smdk_snd_spdif_dit_device);
- if (ret)
- goto err2;
-
- smdk_snd_spdif_device = platform_device_alloc("soc-audio", -1);
- if (!smdk_snd_spdif_device) {
- ret = -ENOMEM;
- goto err2;
- }
-
- platform_set_drvdata(smdk_snd_spdif_device, &smdk);
-
- ret = platform_device_add(smdk_snd_spdif_device);
- if (ret)
- goto err1;
-
- /* Set audio clock heirachy manually */
- ret = set_audio_clock_heirachy(smdk_snd_spdif_device);
- if (ret)
- goto err1;
-
- return 0;
-err1:
- platform_device_put(smdk_snd_spdif_device);
-err2:
- platform_device_put(smdk_snd_spdif_dit_device);
- return ret;
-}
-
-static void __exit smdk_exit(void)
-{
- platform_device_unregister(smdk_snd_spdif_device);
-}
-
-module_init(smdk_init);
-module_exit(smdk_exit);
-
-MODULE_AUTHOR("Seungwhan Youn, <sw.youn(a)samsung.com>");
-MODULE_DESCRIPTION("ALSA SoC SMDK+S/PDIF");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/smdk_wm8580.c b/sound/soc/s3c24xx/smdk_wm8580.c
deleted file mode 100644
index 46ab884..0000000
--- a/sound/soc/s3c24xx/smdk_wm8580.c
+++ /dev/null
@@ -1,284 +0,0 @@
-/*
- * smdk_wm8580.c
- *
- * Copyright (c) 2009 Samsung Electronics Co. Ltd
- * Author: Jaswinder Singh <jassi.brar(a)samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- */
-
-#include <linux/platform_device.h>
-#include <linux/clk.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-#include <sound/soc-dapm.h>
-
-#include <asm/mach-types.h>
-
-#include "../codecs/wm8580.h"
-#include "dma.h"
-#include "i2s.h"
-
-/*
- * Default CFG switch settings to use this driver:
- *
- * SMDK6410: Set CFG1 1-3 Off, CFG2 1-4 On
- */
-
-/* SMDK has a 12MHZ crystal attached to WM8580 */
-#define SMDK_WM8580_FREQ 12000000
-
-static int smdk_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
-{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- struct snd_soc_dai *codec_dai = rtd->codec_dai;
- unsigned int pll_out;
- int bfs, rfs, ret;
-
- switch (params_format(params)) {
- case SNDRV_PCM_FORMAT_U8:
- case SNDRV_PCM_FORMAT_S8:
- bfs = 16;
- break;
- case SNDRV_PCM_FORMAT_U16_LE:
- case SNDRV_PCM_FORMAT_S16_LE:
- bfs = 32;
- break;
- default:
- return -EINVAL;
- }
-
- /* The Fvco for WM8580 PLLs must fall within [90,100]MHz.
- * This criterion can't be met if we request PLL output
- * as {8000x256, 64000x256, 11025x256}Hz.
- * As a wayout, we rather change rfs to a minimum value that
- * results in (params_rate(params) * rfs), and itself, acceptable
- * to both - the CODEC and the CPU.
- */
- switch (params_rate(params)) {
- case 16000:
- case 22050:
- case 32000:
- case 44100:
- case 48000:
- case 88200:
- case 96000:
- rfs = 256;
- break;
- case 64000:
- rfs = 384;
- break;
- case 8000:
- case 11025:
- rfs = 512;
- break;
- default:
- return -EINVAL;
- }
- pll_out = params_rate(params) * rfs;
-
- /* Set the Codec DAI configuration */
- ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S
- | SND_SOC_DAIFMT_NB_NF
- | SND_SOC_DAIFMT_CBM_CFM);
- if (ret < 0)
- return ret;
-
- /* Set the AP DAI configuration */
- ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S
- | SND_SOC_DAIFMT_NB_NF
- | SND_SOC_DAIFMT_CBM_CFM);
- if (ret < 0)
- return ret;
-
- /* Set WM8580 to drive MCLK from its PLLA */
- ret = snd_soc_dai_set_clkdiv(codec_dai, WM8580_MCLK,
- WM8580_CLKSRC_PLLA);
- if (ret < 0)
- return ret;
-
- ret = snd_soc_dai_set_pll(codec_dai, WM8580_PLLA, 0,
- SMDK_WM8580_FREQ, pll_out);
- if (ret < 0)
- return ret;
-
- ret = snd_soc_dai_set_sysclk(codec_dai, WM8580_CLKSRC_PLLA,
- pll_out, SND_SOC_CLOCK_IN);
- if (ret < 0)
- return ret;
-
- return 0;
-}
-
-/*
- * SMDK WM8580 DAI operations.
- */
-static struct snd_soc_ops smdk_ops = {
- .hw_params = smdk_hw_params,
-};
-
-/* SMDK Playback widgets */
-static const struct snd_soc_dapm_widget wm8580_dapm_widgets_pbk[] = {
- SND_SOC_DAPM_HP("Front", NULL),
- SND_SOC_DAPM_HP("Center+Sub", NULL),
- SND_SOC_DAPM_HP("Rear", NULL),
-};
-
-/* SMDK Capture widgets */
-static const struct snd_soc_dapm_widget wm8580_dapm_widgets_cpt[] = {
- SND_SOC_DAPM_MIC("MicIn", NULL),
- SND_SOC_DAPM_LINE("LineIn", NULL),
-};
-
-/* SMDK-PAIFTX connections */
-static const struct snd_soc_dapm_route audio_map_tx[] = {
- /* MicIn feeds AINL */
- {"AINL", NULL, "MicIn"},
-
- /* LineIn feeds AINL/R */
- {"AINL", NULL, "LineIn"},
- {"AINR", NULL, "LineIn"},
-};
-
-/* SMDK-PAIFRX connections */
-static const struct snd_soc_dapm_route audio_map_rx[] = {
- /* Front Left/Right are fed VOUT1L/R */
- {"Front", NULL, "VOUT1L"},
- {"Front", NULL, "VOUT1R"},
-
- /* Center/Sub are fed VOUT2L/R */
- {"Center+Sub", NULL, "VOUT2L"},
- {"Center+Sub", NULL, "VOUT2R"},
-
- /* Rear Left/Right are fed VOUT3L/R */
- {"Rear", NULL, "VOUT3L"},
- {"Rear", NULL, "VOUT3R"},
-};
-
-static int smdk_wm8580_init_paiftx(struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_soc_codec *codec = rtd->codec;
-
- /* Add smdk specific Capture widgets */
- snd_soc_dapm_new_controls(codec, wm8580_dapm_widgets_cpt,
- ARRAY_SIZE(wm8580_dapm_widgets_cpt));
-
- /* Set up PAIFTX audio path */
- snd_soc_dapm_add_routes(codec, audio_map_tx, ARRAY_SIZE(audio_map_tx));
-
- /* Enabling the microphone requires the fitting of a 0R
- * resistor to connect the line from the microphone jack.
- */
- snd_soc_dapm_disable_pin(codec, "MicIn");
-
- /* signal a DAPM event */
- snd_soc_dapm_sync(codec);
-
- return 0;
-}
-
-static int smdk_wm8580_init_paifrx(struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_soc_codec *codec = rtd->codec;
-
- /* Add smdk specific Playback widgets */
- snd_soc_dapm_new_controls(codec, wm8580_dapm_widgets_pbk,
- ARRAY_SIZE(wm8580_dapm_widgets_pbk));
-
- /* Set up PAIFRX audio path */
- snd_soc_dapm_add_routes(codec, audio_map_rx, ARRAY_SIZE(audio_map_rx));
-
- /* signal a DAPM event */
- snd_soc_dapm_sync(codec);
-
- return 0;
-}
-
-enum {
- PRI_PLAYBACK = 0,
- PRI_CAPTURE,
- SEC_PLAYBACK,
-};
-
-static struct snd_soc_dai_link smdk_dai[] = {
- [PRI_PLAYBACK] = { /* Primary Playback i/f */
- .name = "WM8580 PAIF RX",
- .stream_name = "Playback",
- .cpu_dai_name = "samsung-i2s.2",
- .codec_dai_name = "wm8580-hifi-playback",
- .platform_name = "samsung-audio",
- .codec_name = "wm8580-codec.0-001b",
- .init = smdk_wm8580_init_paifrx,
- .ops = &smdk_ops,
- },
- [PRI_CAPTURE] = { /* Primary Capture i/f */
- .name = "WM8580 PAIF TX",
- .stream_name = "Capture",
- .cpu_dai_name = "samsung-i2s.2",
- .codec_dai_name = "wm8580-hifi-capture",
- .platform_name = "samsung-audio",
- .codec_name = "wm8580-codec.0-001b",
- .init = smdk_wm8580_init_paiftx,
- .ops = &smdk_ops,
- },
- [SEC_PLAYBACK] = { /* Sec_Fifo Playback i/f */
- .name = "Sec_FIFO TX",
- .stream_name = "Playback",
- .cpu_dai_name = "samsung-i2s.x",
- .codec_dai_name = "wm8580-hifi-playback",
- .platform_name = "samsung-audio",
- .codec_name = "wm8580-codec.0-001b",
- .init = smdk_wm8580_init_paifrx,
- .ops = &smdk_ops,
- },
-};
-
-static struct snd_soc_card smdk = {
- .name = "SMDK-I2S",
- .dai_link = smdk_dai,
- .num_links = 2,
-};
-
-static struct platform_device *smdk_snd_device;
-
-static int __init smdk_audio_init(void)
-{
- int ret;
- char *str;
-
- if (machine_is_smdkc100()) {
- smdk.num_links = 3;
- /* S5PC100 has I2S0 as v5 */
- str = (char *)smdk_dai[PRI_PLAYBACK].cpu_dai_name;
- str[strlen(str) - 1] = '0';
- str = (char *)smdk_dai[PRI_CAPTURE].cpu_dai_name;
- str[strlen(str) - 1] = '0';
- /* Secondary is at offset MAX_I2S from Primary */
- str = (char *)smdk_dai[SEC_PLAYBACK].cpu_dai_name;
- str[strlen(str) - 1] = '0' + MAX_I2S;
- }
-
- smdk_snd_device = platform_device_alloc("soc-audio", -1);
- if (!smdk_snd_device)
- return -ENOMEM;
-
- platform_set_drvdata(smdk_snd_device, &smdk);
- ret = platform_device_add(smdk_snd_device);
-
- if (ret)
- platform_device_put(smdk_snd_device);
-
- return ret;
-}
-module_init(smdk_audio_init);
-
-MODULE_AUTHOR("Jaswinder Singh, jassi.brar(a)samsung.com");
-MODULE_DESCRIPTION("ALSA SoC SMDK WM8580");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/smdk_wm9713.c b/sound/soc/s3c24xx/smdk_wm9713.c
deleted file mode 100644
index 7ce2430..0000000
--- a/sound/soc/s3c24xx/smdk_wm9713.c
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * smdk_wm9713.c -- SoC audio for SMDK
- *
- * Copyright 2010 Samsung Electronics Co. Ltd.
- * Author: Jaswinder Singh Brar <jassi.brar(a)samsung.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- */
-
-#include <linux/module.h>
-#include <linux/device.h>
-#include <sound/soc.h>
-
-#include "dma.h"
-#include "ac97.h"
-
-static struct snd_soc_card smdk;
-
-/*
- * Default CFG switch settings to use this driver:
- *
- * SMDK6410: Set CFG1 1-3 On, CFG2 1-4 Off
- * SMDKC100: Set CFG6 1-3 On, CFG7 1 On
- * SMDKC110: Set CFGB10 1-2 Off, CFGB12 1-3 On
- * SMDKV210: Set CFGB10 1-2 Off, CFGB12 1-3 On
- */
-
-/*
- Playback (HeadPhone):-
- $ amixer sset 'Headphone' unmute
- $ amixer sset 'Right Headphone Out Mux' 'Headphone'
- $ amixer sset 'Left Headphone Out Mux' 'Headphone'
- $ amixer sset 'Right HP Mixer PCM' unmute
- $ amixer sset 'Left HP Mixer PCM' unmute
-
- Capture (LineIn):-
- $ amixer sset 'Right Capture Source' 'Line'
- $ amixer sset 'Left Capture Source' 'Line'
-*/
-
-static struct snd_soc_dai_link smdk_dai = {
- .name = "AC97",
- .stream_name = "AC97 PCM",
- .platform_name = "samsung-audio",
- .cpu_dai_name = "samsung-ac97",
- .codec_dai_name = "wm9713-hifi",
- .codec_name = "wm9713-codec",
-};
-
-static struct snd_soc_card smdk = {
- .name = "SMDK WM9713",
- .dai_link = &smdk_dai,
- .num_links = 1,
-};
-
-static struct platform_device *smdk_snd_wm9713_device;
-static struct platform_device *smdk_snd_ac97_device;
-
-static int __init smdk_init(void)
-{
- int ret;
-
- smdk_snd_wm9713_device = platform_device_alloc("wm9713-codec", -1);
- if (!smdk_snd_wm9713_device)
- return -ENOMEM;
-
- ret = platform_device_add(smdk_snd_wm9713_device);
- if (ret)
- goto err;
-
- smdk_snd_ac97_device = platform_device_alloc("soc-audio", -1);
- if (!smdk_snd_ac97_device) {
- ret = -ENOMEM;
- goto err;
- }
-
- platform_set_drvdata(smdk_snd_ac97_device, &smdk);
-
- ret = platform_device_add(smdk_snd_ac97_device);
- if (ret) {
- platform_device_put(smdk_snd_ac97_device);
- goto err;
- }
-
- return 0;
-err:
- platform_device_put(smdk_snd_wm9713_device);
- return ret;
-}
-
-static void __exit smdk_exit(void)
-{
- platform_device_unregister(smdk_snd_ac97_device);
- platform_device_unregister(smdk_snd_wm9713_device);
-}
-
-module_init(smdk_init);
-module_exit(smdk_exit);
-
-/* Module information */
-MODULE_AUTHOR("Jaswinder Singh Brar, jassi.brar(a)samsung.com");
-MODULE_DESCRIPTION("ALSA SoC SMDK+WM9713");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/spdif.c b/sound/soc/s3c24xx/spdif.c
deleted file mode 100644
index dc85df3..0000000
--- a/sound/soc/s3c24xx/spdif.c
+++ /dev/null
@@ -1,501 +0,0 @@
-/* sound/soc/s3c24xx/spdif.c
- *
- * ALSA SoC Audio Layer - Samsung S/PDIF Controller driver
- *
- * Copyright (c) 2010 Samsung Electronics Co. Ltd
- * http://www.samsung.com/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/clk.h>
-#include <linux/io.h>
-
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-
-#include <plat/audio.h>
-#include <mach/dma.h>
-
-#include "dma.h"
-#include "spdif.h"
-
-/* Registers */
-#define CLKCON 0x00
-#define CON 0x04
-#define BSTAS 0x08
-#define CSTAS 0x0C
-#define DATA_OUTBUF 0x10
-#define DCNT 0x14
-#define BSTAS_S 0x18
-#define DCNT_S 0x1C
-
-#define CLKCTL_MASK 0x7
-#define CLKCTL_MCLK_EXT (0x1 << 2)
-#define CLKCTL_PWR_ON (0x1 << 0)
-
-#define CON_MASK 0x3ffffff
-#define CON_FIFO_TH_SHIFT 19
-#define CON_FIFO_TH_MASK (0x7 << 19)
-#define CON_USERDATA_23RDBIT (0x1 << 12)
-
-#define CON_SW_RESET (0x1 << 5)
-
-#define CON_MCLKDIV_MASK (0x3 << 3)
-#define CON_MCLKDIV_256FS (0x0 << 3)
-#define CON_MCLKDIV_384FS (0x1 << 3)
-#define CON_MCLKDIV_512FS (0x2 << 3)
-
-#define CON_PCM_MASK (0x3 << 1)
-#define CON_PCM_16BIT (0x0 << 1)
-#define CON_PCM_20BIT (0x1 << 1)
-#define CON_PCM_24BIT (0x2 << 1)
-
-#define CON_PCM_DATA (0x1 << 0)
-
-#define CSTAS_MASK 0x3fffffff
-#define CSTAS_SAMP_FREQ_MASK (0xF << 24)
-#define CSTAS_SAMP_FREQ_44 (0x0 << 24)
-#define CSTAS_SAMP_FREQ_48 (0x2 << 24)
-#define CSTAS_SAMP_FREQ_32 (0x3 << 24)
-#define CSTAS_SAMP_FREQ_96 (0xA << 24)
-
-#define CSTAS_CATEGORY_MASK (0xFF << 8)
-#define CSTAS_CATEGORY_CODE_CDP (0x01 << 8)
-
-#define CSTAS_NO_COPYRIGHT (0x1 << 2)
-
-/**
- * struct samsung_spdif_info - Samsung S/PDIF Controller information
- * @lock: Spin lock for S/PDIF.
- * @dev: The parent device passed to use from the probe.
- * @regs: The pointer to the device register block.
- * @clk_rate: Current clock rate for calcurate ratio.
- * @pclk: The peri-clock pointer for spdif master operation.
- * @sclk: The source clock pointer for making sync signals.
- * @save_clkcon: Backup clkcon reg. in suspend.
- * @save_con: Backup con reg. in suspend.
- * @save_cstas: Backup cstas reg. in suspend.
- * @dma_playback: DMA information for playback channel.
- */
-struct samsung_spdif_info {
- spinlock_t lock;
- struct device *dev;
- void __iomem *regs;
- unsigned long clk_rate;
- struct clk *pclk;
- struct clk *sclk;
- u32 saved_clkcon;
- u32 saved_con;
- u32 saved_cstas;
- struct s3c_dma_params *dma_playback;
-};
-
-static struct s3c2410_dma_client spdif_dma_client_out = {
- .name = "S/PDIF Stereo out",
-};
-
-static struct s3c_dma_params spdif_stereo_out;
-static struct samsung_spdif_info spdif_info;
-
-static inline struct samsung_spdif_info *to_info(struct snd_soc_dai *cpu_dai)
-{
- return snd_soc_dai_get_drvdata(cpu_dai);
-}
-
-static void spdif_snd_txctrl(struct samsung_spdif_info *spdif, int on)
-{
- void __iomem *regs = spdif->regs;
- u32 clkcon;
-
- dev_dbg(spdif->dev, "Entered %s\n", __func__);
-
- clkcon = readl(regs + CLKCON) & CLKCTL_MASK;
- if (on)
- writel(clkcon | CLKCTL_PWR_ON, regs + CLKCON);
- else
- writel(clkcon & ~CLKCTL_PWR_ON, regs + CLKCON);
-}
-
-static int spdif_set_sysclk(struct snd_soc_dai *cpu_dai,
- int clk_id, unsigned int freq, int dir)
-{
- struct samsung_spdif_info *spdif = to_info(cpu_dai);
- u32 clkcon;
-
- dev_dbg(spdif->dev, "Entered %s\n", __func__);
-
- clkcon = readl(spdif->regs + CLKCON);
-
- if (clk_id == SND_SOC_SPDIF_INT_MCLK)
- clkcon &= ~CLKCTL_MCLK_EXT;
- else
- clkcon |= CLKCTL_MCLK_EXT;
-
- writel(clkcon, spdif->regs + CLKCON);
-
- spdif->clk_rate = freq;
-
- return 0;
-}
-
-static int spdif_trigger(struct snd_pcm_substream *substream, int cmd,
- struct snd_soc_dai *dai)
-{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct samsung_spdif_info *spdif = to_info(rtd->cpu_dai);
- unsigned long flags;
-
- dev_dbg(spdif->dev, "Entered %s\n", __func__);
-
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
- case SNDRV_PCM_TRIGGER_RESUME:
- case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- spin_lock_irqsave(&spdif->lock, flags);
- spdif_snd_txctrl(spdif, 1);
- spin_unlock_irqrestore(&spdif->lock, flags);
- break;
- case SNDRV_PCM_TRIGGER_STOP:
- case SNDRV_PCM_TRIGGER_SUSPEND:
- case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- spin_lock_irqsave(&spdif->lock, flags);
- spdif_snd_txctrl(spdif, 0);
- spin_unlock_irqrestore(&spdif->lock, flags);
- break;
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int spdif_sysclk_ratios[] = {
- 512, 384, 256,
-};
-
-static int spdif_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params,
- struct snd_soc_dai *socdai)
-{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct samsung_spdif_info *spdif = to_info(rtd->cpu_dai);
- void __iomem *regs = spdif->regs;
- struct s3c_dma_params *dma_data;
- u32 con, clkcon, cstas;
- unsigned long flags;
- int i, ratio;
-
- dev_dbg(spdif->dev, "Entered %s\n", __func__);
-
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- dma_data = spdif->dma_playback;
- else {
- dev_err(spdif->dev, "Capture is not supported\n");
- return -EINVAL;
- }
-
- snd_soc_dai_set_dma_data(rtd->cpu_dai, substream, dma_data);
-
- spin_lock_irqsave(&spdif->lock, flags);
-
- con = readl(regs + CON) & CON_MASK;
- cstas = readl(regs + CSTAS) & CSTAS_MASK;
- clkcon = readl(regs + CLKCON) & CLKCTL_MASK;
-
- con &= ~CON_FIFO_TH_MASK;
- con |= (0x7 << CON_FIFO_TH_SHIFT);
- con |= CON_USERDATA_23RDBIT;
- con |= CON_PCM_DATA;
-
- con &= ~CON_PCM_MASK;
- switch (params_format(params)) {
- case SNDRV_PCM_FORMAT_S16_LE:
- con |= CON_PCM_16BIT;
- break;
- default:
- dev_err(spdif->dev, "Unsupported data size.\n");
- goto err;
- }
-
- ratio = spdif->clk_rate / params_rate(params);
- for (i = 0; i < ARRAY_SIZE(spdif_sysclk_ratios); i++)
- if (ratio == spdif_sysclk_ratios[i])
- break;
- if (i == ARRAY_SIZE(spdif_sysclk_ratios)) {
- dev_err(spdif->dev, "Invalid clock ratio %ld/%d\n",
- spdif->clk_rate, params_rate(params));
- goto err;
- }
-
- con &= ~CON_MCLKDIV_MASK;
- switch (ratio) {
- case 256:
- con |= CON_MCLKDIV_256FS;
- break;
- case 384:
- con |= CON_MCLKDIV_384FS;
- break;
- case 512:
- con |= CON_MCLKDIV_512FS;
- break;
- }
-
- cstas &= ~CSTAS_SAMP_FREQ_MASK;
- switch (params_rate(params)) {
- case 44100:
- cstas |= CSTAS_SAMP_FREQ_44;
- break;
- case 48000:
- cstas |= CSTAS_SAMP_FREQ_48;
- break;
- case 32000:
- cstas |= CSTAS_SAMP_FREQ_32;
- break;
- case 96000:
- cstas |= CSTAS_SAMP_FREQ_96;
- break;
- default:
- dev_err(spdif->dev, "Invalid sampling rate %d\n",
- params_rate(params));
- goto err;
- }
-
- cstas &= ~CSTAS_CATEGORY_MASK;
- cstas |= CSTAS_CATEGORY_CODE_CDP;
- cstas |= CSTAS_NO_COPYRIGHT;
-
- writel(con, regs + CON);
- writel(cstas, regs + CSTAS);
- writel(clkcon, regs + CLKCON);
-
- spin_unlock_irqrestore(&spdif->lock, flags);
-
- return 0;
-err:
- spin_unlock_irqrestore(&spdif->lock, flags);
- return -EINVAL;
-}
-
-static void spdif_shutdown(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
-{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct samsung_spdif_info *spdif = to_info(rtd->cpu_dai);
- void __iomem *regs = spdif->regs;
- u32 con, clkcon;
-
- dev_dbg(spdif->dev, "Entered %s\n", __func__);
-
- con = readl(regs + CON) & CON_MASK;
- clkcon = readl(regs + CLKCON) & CLKCTL_MASK;
-
- writel(con | CON_SW_RESET, regs + CON);
- cpu_relax();
-
- writel(clkcon & ~CLKCTL_PWR_ON, regs + CLKCON);
-}
-
-#ifdef CONFIG_PM
-static int spdif_suspend(struct snd_soc_dai *cpu_dai)
-{
- struct samsung_spdif_info *spdif = to_info(cpu_dai);
- u32 con = spdif->saved_con;
-
- dev_dbg(spdif->dev, "Entered %s\n", __func__);
-
- spdif->saved_clkcon = readl(spdif->regs + CLKCON) & CLKCTL_MASK;
- spdif->saved_con = readl(spdif->regs + CON) & CON_MASK;
- spdif->saved_cstas = readl(spdif->regs + CSTAS) & CSTAS_MASK;
-
- writel(con | CON_SW_RESET, spdif->regs + CON);
- cpu_relax();
-
- return 0;
-}
-
-static int spdif_resume(struct snd_soc_dai *cpu_dai)
-{
- struct samsung_spdif_info *spdif = to_info(cpu_dai);
-
- dev_dbg(spdif->dev, "Entered %s\n", __func__);
-
- writel(spdif->saved_clkcon, spdif->regs + CLKCON);
- writel(spdif->saved_con, spdif->regs + CON);
- writel(spdif->saved_cstas, spdif->regs + CSTAS);
-
- return 0;
-}
-#else
-#define spdif_suspend NULL
-#define spdif_resume NULL
-#endif
-
-static struct snd_soc_dai_ops spdif_dai_ops = {
- .set_sysclk = spdif_set_sysclk,
- .trigger = spdif_trigger,
- .hw_params = spdif_hw_params,
- .shutdown = spdif_shutdown,
-};
-
-struct snd_soc_dai_driver samsung_spdif_dai = {
- .name = "samsung-spdif",
- .playback = {
- .stream_name = "S/PDIF Playback",
- .channels_min = 2,
- .channels_max = 2,
- .rates = (SNDRV_PCM_RATE_32000 |
- SNDRV_PCM_RATE_44100 |
- SNDRV_PCM_RATE_48000 |
- SNDRV_PCM_RATE_96000),
- .formats = SNDRV_PCM_FMTBIT_S16_LE, },
- .ops = &spdif_dai_ops,
- .suspend = spdif_suspend,
- .resume = spdif_resume,
-};
-
-static __devinit int spdif_probe(struct platform_device *pdev)
-{
- struct s3c_audio_pdata *spdif_pdata;
- struct resource *mem_res, *dma_res;
- struct samsung_spdif_info *spdif;
- int ret;
-
- spdif_pdata = pdev->dev.platform_data;
-
- dev_dbg(&pdev->dev, "Entered %s\n", __func__);
-
- dma_res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
- if (!dma_res) {
- dev_err(&pdev->dev, "Unable to get dma resource.\n");
- return -ENXIO;
- }
-
- mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!mem_res) {
- dev_err(&pdev->dev, "Unable to get register resource.\n");
- return -ENXIO;
- }
-
- if (spdif_pdata && spdif_pdata->cfg_gpio
- && spdif_pdata->cfg_gpio(pdev)) {
- dev_err(&pdev->dev, "Unable to configure GPIO pins\n");
- return -EINVAL;
- }
-
- spdif = &spdif_info;
- spdif->dev = &pdev->dev;
-
- spin_lock_init(&spdif->lock);
-
- spdif->pclk = clk_get(&pdev->dev, "spdif");
- if (IS_ERR(spdif->pclk)) {
- dev_err(&pdev->dev, "failed to get peri-clock\n");
- ret = -ENOENT;
- goto err0;
- }
- clk_enable(spdif->pclk);
-
- spdif->sclk = clk_get(&pdev->dev, "sclk_spdif");
- if (IS_ERR(spdif->sclk)) {
- dev_err(&pdev->dev, "failed to get internal source clock\n");
- ret = -ENOENT;
- goto err1;
- }
- clk_enable(spdif->sclk);
-
- /* Request S/PDIF Register's memory region */
- if (!request_mem_region(mem_res->start,
- resource_size(mem_res), "samsung-spdif")) {
- dev_err(&pdev->dev, "Unable to request register region\n");
- ret = -EBUSY;
- goto err2;
- }
-
- spdif->regs = ioremap(mem_res->start, 0x100);
- if (spdif->regs == NULL) {
- dev_err(&pdev->dev, "Cannot ioremap registers\n");
- ret = -ENXIO;
- goto err3;
- }
-
- dev_set_drvdata(&pdev->dev, spdif);
-
- ret = snd_soc_register_dai(&pdev->dev, &samsung_spdif_dai);
- if (ret != 0) {
- dev_err(&pdev->dev, "fail to register dai\n");
- goto err4;
- }
-
- spdif_stereo_out.dma_size = 2;
- spdif_stereo_out.client = &spdif_dma_client_out;
- spdif_stereo_out.dma_addr = mem_res->start + DATA_OUTBUF;
- spdif_stereo_out.channel = dma_res->start;
-
- spdif->dma_playback = &spdif_stereo_out;
-
- return 0;
-
-err4:
- iounmap(spdif->regs);
-err3:
- release_mem_region(mem_res->start, resource_size(mem_res));
-err2:
- clk_disable(spdif->sclk);
- clk_put(spdif->sclk);
-err1:
- clk_disable(spdif->pclk);
- clk_put(spdif->pclk);
-err0:
- return ret;
-}
-
-static __devexit int spdif_remove(struct platform_device *pdev)
-{
- struct samsung_spdif_info *spdif = &spdif_info;
- struct resource *mem_res;
-
- snd_soc_unregister_dai(&pdev->dev);
-
- iounmap(spdif->regs);
-
- mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (mem_res)
- release_mem_region(mem_res->start, resource_size(mem_res));
-
- clk_disable(spdif->sclk);
- clk_put(spdif->sclk);
- clk_disable(spdif->pclk);
- clk_put(spdif->pclk);
-
- return 0;
-}
-
-static struct platform_driver samsung_spdif_driver = {
- .probe = spdif_probe,
- .remove = spdif_remove,
- .driver = {
- .name = "samsung-spdif",
- .owner = THIS_MODULE,
- },
-};
-
-static int __init spdif_init(void)
-{
- return platform_driver_register(&samsung_spdif_driver);
-}
-module_init(spdif_init);
-
-static void __exit spdif_exit(void)
-{
- platform_driver_unregister(&samsung_spdif_driver);
-}
-module_exit(spdif_exit);
-
-MODULE_AUTHOR("Seungwhan Youn, <sw.youn(a)samsung.com>");
-MODULE_DESCRIPTION("Samsung S/PDIF Controller Driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:samsung-spdif");
diff --git a/sound/soc/s3c24xx/spdif.h b/sound/soc/s3c24xx/spdif.h
deleted file mode 100644
index 3ed5559..0000000
--- a/sound/soc/s3c24xx/spdif.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/* sound/soc/s3c24xx/spdif.h
- *
- * ALSA SoC Audio Layer - Samsung S/PDIF Controller driver
- *
- * Copyright (c) 2010 Samsung Electronics Co. Ltd
- * http://www.samsung.com/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef __SND_SOC_SAMSUNG_SPDIF_H
-#define __SND_SOC_SAMSUNG_SPDIF_H __FILE__
-
-#define SND_SOC_SPDIF_INT_MCLK 0
-#define SND_SOC_SPDIF_EXT_MCLK 1
-
-#endif /* __SND_SOC_SAMSUNG_SPDIF_H */
diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig
new file mode 100644
index 0000000..140095e
--- /dev/null
+++ b/sound/soc/samsung/Kconfig
@@ -0,0 +1,154 @@
+config ASOC_SAMSUNG
+ tristate "ASoC support for Samsung"
+ depends on ARCH_S3C2410 || ARCH_S3C64XX || ARCH_S5PC100 || ARCH_S5PV210
+ select S3C64XX_DMA if ARCH_S3C64XX
+ help
+ Say Y or M if you want to add support for codecs attached to
+ the Samsung SoCs' Audio interfaces. You will also need to
+ select the audio interfaces to support below.
+
+config SND_S3C24XX_I2S
+ tristate
+ select S3C2410_DMA
+
+config SND_S3C_I2SV2_SOC
+ tristate
+
+config SND_S3C2412_SOC_I2S
+ tristate
+ select SND_S3C_I2SV2_SOC
+ select S3C2410_DMA
+
+config SND_SAMSUNG_PCM
+ tristate
+
+config SND_SAMSUNG_AC97
+ tristate
+ select SND_SOC_AC97_BUS
+
+config SND_SAMSUNG_SPDIF
+ tristate
+ select SND_SOC_SPDIF
+
+config SND_SAMSUNG_I2S
+ tristate
+
+config ASOC_SAMSUNG_NEO1973_WM8753
+ tristate "SoC I2S Audio support for NEO1973 - WM8753"
+ depends on ASOC_SAMSUNG && MACH_NEO1973_GTA01
+ select SND_S3C24XX_I2S
+ select SND_SOC_WM8753
+ help
+ Say Y if you want to add support for SoC audio on smdk2440
+ with the WM8753.
+
+config ASOC_SAMSUNG_NEO1973_GTA02_WM8753
+ tristate "Audio support for the Openmoko Neo FreeRunner (GTA02)"
+ depends on ASOC_SAMSUNG && MACH_NEO1973_GTA02
+ select SND_S3C24XX_I2S
+ select SND_SOC_WM8753
+ help
+ This driver provides audio support for the Openmoko Neo FreeRunner
+ smartphone.
+
+config ASOC_SAMSUNG_JIVE_WM8750
+ tristate "SoC I2S Audio support for Jive"
+ depends on ASOC_SAMSUNG && MACH_JIVE
+ select SND_SOC_WM8750
+ select SND_S3C2412_SOC_I2S
+ help
+ Sat Y if you want to add support for SoC audio on the Jive.
+
+config ASOC_SAMSUNG_SMDK_WM8580
+ tristate "SoC I2S Audio support for WM8580 on SMDK"
+ depends on ASOC_SAMSUNG && (MACH_SMDK6410 || MACH_SMDKC100)
+ select SND_SOC_WM8580
+ select SND_SAMSUNG_I2S
+ help
+ Say Y if you want to add support for SoC audio on the SMDKs.
+
+config ASOC_SAMSUNG_SMDK2443_WM9710
+ tristate "SoC AC97 Audio support for SMDK2443 - WM9710"
+ depends on ASOC_SAMSUNG && MACH_SMDK2443
+ select S3C2410_DMA
+ select AC97_BUS
+ select SND_SOC_AC97_CODEC
+ select SND_SAMSUNG_AC97
+ help
+ Say Y if you want to add support for SoC audio on smdk2443
+ with the WM9710.
+
+config ASOC_SAMSUNG_LN2440SBC_ALC650
+ tristate "SoC AC97 Audio support for LN2440SBC - ALC650"
+ depends on ASOC_SAMSUNG && ARCH_S3C2410
+ select S3C2410_DMA
+ select AC97_BUS
+ select SND_SOC_AC97_CODEC
+ select SND_SAMSUNG_AC97
+ help
+ Say Y if you want to add support for SoC audio on ln2440sbc
+ with the ALC650.
+
+config ASOC_SAMSUNG_S3C24XX_UDA134X
+ tristate "SoC I2S Audio support UDA134X wired to a S3C24XX"
+ depends on ASOC_SAMSUNG && ARCH_S3C2410
+ select SND_S3C24XX_I2S
+ select SND_SOC_L3
+ select SND_SOC_UDA134X
+
+config ASOC_SAMSUNG_SIMTEC
+ tristate
+ help
+ Internal node for common S3C24XX/Simtec suppor
+
+config ASOC_SAMSUNG_SIMTEC_TLV320AIC23
+ tristate "SoC I2S Audio support for TLV320AIC23 on Simtec boards"
+ depends on ASOC_SAMSUNG && ARCH_S3C2410
+ select SND_S3C24XX_I2S
+ select SND_SOC_TLV320AIC23
+ select ASOC_SAMSUNG_SIMTEC
+
+config ASOC_SAMSUNG_SIMTEC_HERMES
+ tristate "SoC I2S Audio support for Simtec Hermes board"
+ depends on ASOC_SAMSUNG && ARCH_S3C2410
+ select SND_S3C24XX_I2S
+ select SND_SOC_TLV320AIC3X
+ select ASOC_SAMSUNG_SIMTEC
+
+config ASOC_SAMSUNG_RX1950_UDA1380
+ tristate "Audio support for the HP iPAQ RX1950"
+ depends on ASOC_SAMSUNG && MACH_RX1950
+ select SND_S3C24XX_I2S
+ select SND_SOC_UDA1380
+ help
+ This driver provides audio support for HP iPAQ RX1950 PDA.
+
+config ASOC_SAMSUNG_SMDK_WM9713
+ tristate "SoC AC97 Audio support for SMDK with WM9713"
+ depends on ASOC_SAMSUNG && (MACH_SMDK6410 || MACH_SMDKC100 || MACH_SMDKV210 || MACH_SMDKC110)
+ select SND_SOC_WM9713
+ select SND_SAMSUNG_AC97
+ help
+ Sat Y if you want to add support for SoC audio on the SMDK.
+
+config ASOC_SMARTQ
+ tristate "SoC I2S Audio support for SmartQ board"
+ depends on ASOC_SAMSUNG && MACH_SMARTQ
+ select SND_SAMSUNG_I2S
+ select SND_SOC_WM8750
+
+config ASOC_GONI_AQUILA_WM8994
+ tristate "SoC I2S Audio support for AQUILA/GONI - WM8994"
+ depends on ASOC_SAMSUNG && (MACH_GONI || MACH_AQUILA)
+ select SND_SAMSUNG_I2S
+ select SND_SOC_WM8994
+ help
+ Say Y if you want to add support for SoC audio on goni or aquila
+ with the WM8994.
+
+config ASOC_SAMSUNG_SMDK_SPDIF
+ tristate "SoC S/PDIF Audio support for SMDK"
+ depends on SND_S3C24XX_SOC && (MACH_SMDKC100 || MACH_SMDKC110 || MACH_SMDKV210)
+ select SND_SAMSUNG_SPDIF
+ help
+ Say Y if you want to add support for SoC S/PDIF audio on the SMDK.
diff --git a/sound/soc/samsung/Makefile b/sound/soc/samsung/Makefile
new file mode 100644
index 0000000..0d24f95
--- /dev/null
+++ b/sound/soc/samsung/Makefile
@@ -0,0 +1,51 @@
+# S3c24XX Platform Support
+snd-soc-s3c24xx-objs := dma.o
+snd-soc-s3c24xx-i2s-objs := s3c24xx-i2s.o
+snd-soc-s3c2412-i2s-objs := s3c2412-i2s.o
+snd-soc-ac97-objs := ac97.o
+snd-soc-s3c-i2s-v2-objs := s3c-i2s-v2.o
+snd-soc-samsung-spdif-objs := spdif.o
+snd-soc-pcm-objs := pcm.o
+snd-soc-i2s-objs := i2s.o
+
+obj-$(CONFIG_ASOC_SAMSUNG) += snd-soc-s3c24xx.o
+obj-$(CONFIG_SND_S3C24XX_I2S) += snd-soc-s3c24xx-i2s.o
+obj-$(CONFIG_SND_SAMSUNG_AC97) += snd-soc-ac97.o
+obj-$(CONFIG_SND_S3C2412_SOC_I2S) += snd-soc-s3c2412-i2s.o
+obj-$(CONFIG_SND_S3C_I2SV2_SOC) += snd-soc-s3c-i2s-v2.o
+obj-$(CONFIG_SND_SAMSUNG_SPDIF) += snd-soc-samsung-spdif.o
+obj-$(CONFIG_SND_SAMSUNG_PCM) += snd-soc-pcm.o
+obj-$(CONFIG_SND_SAMSUNG_I2S) += snd-soc-i2s.o
+
+# S3C24XX Machine Support
+snd-soc-jive-wm8750-objs := jive_wm8750.o
+snd-soc-neo1973-wm8753-objs := neo1973_wm8753.o
+snd-soc-neo1973-gta02-wm8753-objs := neo1973_gta02_wm8753.o
+snd-soc-smdk2443-wm9710-objs := smdk2443_wm9710.o
+snd-soc-ln2440sbc-alc650-objs := ln2440sbc_alc650.o
+snd-soc-s3c24xx-uda134x-objs := s3c24xx_uda134x.o
+snd-soc-s3c24xx-simtec-objs := s3c24xx_simtec.o
+snd-soc-s3c24xx-simtec-hermes-objs := s3c24xx_simtec_hermes.o
+snd-soc-s3c24xx-simtec-tlv320aic23-objs := s3c24xx_simtec_tlv320aic23.o
+snd-soc-rx1950-uda1380-objs := rx1950_uda1380.o
+snd-soc-smdk-wm8580-objs := smdk_wm8580.o
+snd-soc-smdk-wm9713-objs := smdk_wm9713.o
+snd-soc-s3c64xx-smartq-wm8987-objs := smartq_wm8987.o
+snd-soc-goni-wm8994-objs := goni_wm8994.o
+snd-soc-smdk-spdif-objs := smdk_spdif.o
+
+obj-$(CONFIG_ASOC_SAMSUNG_JIVE_WM8750) += snd-soc-jive-wm8750.o
+obj-$(CONFIG_ASOC_SAMSUNG_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o
+obj-$(CONFIG_ASOC_SAMSUNG_NEO1973_GTA02_WM8753) += snd-soc-neo1973-gta02-wm8753.o
+obj-$(CONFIG_ASOC_SAMSUNG_SMDK2443_WM9710) += snd-soc-smdk2443-wm9710.o
+obj-$(CONFIG_ASOC_SAMSUNG_LN2440SBC_ALC650) += snd-soc-ln2440sbc-alc650.o
+obj-$(CONFIG_ASOC_SAMSUNG_S3C24XX_UDA134X) += snd-soc-s3c24xx-uda134x.o
+obj-$(CONFIG_ASOC_SAMSUNG_SIMTEC) += snd-soc-s3c24xx-simtec.o
+obj-$(CONFIG_ASOC_SAMSUNG_SIMTEC_HERMES) += snd-soc-s3c24xx-simtec-hermes.o
+obj-$(CONFIG_ASOC_SAMSUNG_SIMTEC_TLV320AIC23) += snd-soc-s3c24xx-simtec-tlv320aic23.o
+obj-$(CONFIG_ASOC_SAMSUNG_RX1950_UDA1380) += snd-soc-rx1950-uda1380.o
+obj-$(CONFIG_ASOC_SAMSUNG_SMDK_WM8580) += snd-soc-smdk-wm8580.o
+obj-$(CONFIG_ASOC_SAMSUNG_SMDK_WM9713) += snd-soc-smdk-wm9713.o
+obj-$(CONFIG_ASOC_SMARTQ) += snd-soc-s3c64xx-smartq-wm8987.o
+obj-$(CONFIG_ASOC_SAMSUNG_SMDK_SPDIF) += snd-soc-smdk-spdif.o
+obj-$(CONFIG_ASOC_GONI_AQUILA_WM8994) += snd-soc-goni-wm8994.o
diff --git a/sound/soc/samsung/ac97.c b/sound/soc/samsung/ac97.c
new file mode 100644
index 0000000..4770a95
--- /dev/null
+++ b/sound/soc/samsung/ac97.c
@@ -0,0 +1,520 @@
+/* sound/soc/samsung/ac97.c
+ *
+ * ALSA SoC Audio Layer - S3C AC97 Controller driver
+ * Evolved from s3c2443-ac97.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co. Ltd
+ * Author: Jaswinder Singh <jassi.brar(a)samsung.com>
+ * Credits: Graeme Gregory, Sean Choi
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+
+#include <sound/soc.h>
+
+#include <plat/regs-ac97.h>
+#include <mach/dma.h>
+#include <plat/audio.h>
+
+#include "dma.h"
+#include "ac97.h"
+
+#define AC_CMD_ADDR(x) (x << 16)
+#define AC_CMD_DATA(x) (x & 0xffff)
+
+struct s3c_ac97_info {
+ struct clk *ac97_clk;
+ void __iomem *regs;
+ struct mutex lock;
+ struct completion done;
+};
+static struct s3c_ac97_info s3c_ac97;
+
+static struct s3c2410_dma_client s3c_dma_client_out = {
+ .name = "AC97 PCMOut"
+};
+
+static struct s3c2410_dma_client s3c_dma_client_in = {
+ .name = "AC97 PCMIn"
+};
+
+static struct s3c2410_dma_client s3c_dma_client_micin = {
+ .name = "AC97 MicIn"
+};
+
+static struct s3c_dma_params s3c_ac97_pcm_out = {
+ .client = &s3c_dma_client_out,
+ .dma_size = 4,
+};
+
+static struct s3c_dma_params s3c_ac97_pcm_in = {
+ .client = &s3c_dma_client_in,
+ .dma_size = 4,
+};
+
+static struct s3c_dma_params s3c_ac97_mic_in = {
+ .client = &s3c_dma_client_micin,
+ .dma_size = 4,
+};
+
+static void s3c_ac97_activate(struct snd_ac97 *ac97)
+{
+ u32 ac_glbctrl, stat;
+
+ stat = readl(s3c_ac97.regs + S3C_AC97_GLBSTAT) & 0x7;
+ if (stat == S3C_AC97_GLBSTAT_MAINSTATE_ACTIVE)
+ return; /* Return if already active */
+
+ INIT_COMPLETION(s3c_ac97.done);
+
+ ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
+ ac_glbctrl = S3C_AC97_GLBCTRL_ACLINKON;
+ writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
+ msleep(1);
+
+ ac_glbctrl |= S3C_AC97_GLBCTRL_TRANSFERDATAENABLE;
+ writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
+ msleep(1);
+
+ ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
+ ac_glbctrl |= S3C_AC97_GLBCTRL_CODECREADYIE;
+ writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
+
+ if (!wait_for_completion_timeout(&s3c_ac97.done, HZ))
+ pr_err("AC97: Unable to activate!");
+}
+
+static unsigned short s3c_ac97_read(struct snd_ac97 *ac97,
+ unsigned short reg)
+{
+ u32 ac_glbctrl, ac_codec_cmd;
+ u32 stat, addr, data;
+
+ mutex_lock(&s3c_ac97.lock);
+
+ s3c_ac97_activate(ac97);
+
+ INIT_COMPLETION(s3c_ac97.done);
+
+ ac_codec_cmd = readl(s3c_ac97.regs + S3C_AC97_CODEC_CMD);
+ ac_codec_cmd = S3C_AC97_CODEC_CMD_READ | AC_CMD_ADDR(reg);
+ writel(ac_codec_cmd, s3c_ac97.regs + S3C_AC97_CODEC_CMD);
+
+ udelay(50);
+
+ ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
+ ac_glbctrl |= S3C_AC97_GLBCTRL_CODECREADYIE;
+ writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
+
+ if (!wait_for_completion_timeout(&s3c_ac97.done, HZ))
+ pr_err("AC97: Unable to read!");
+
+ stat = readl(s3c_ac97.regs + S3C_AC97_STAT);
+ addr = (stat >> 16) & 0x7f;
+ data = (stat & 0xffff);
+
+ if (addr != reg)
+ pr_err("ac97: req addr = %02x, rep addr = %02x\n",
+ reg, addr);
+
+ mutex_unlock(&s3c_ac97.lock);
+
+ return (unsigned short)data;
+}
+
+static void s3c_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
+ unsigned short val)
+{
+ u32 ac_glbctrl, ac_codec_cmd;
+
+ mutex_lock(&s3c_ac97.lock);
+
+ s3c_ac97_activate(ac97);
+
+ INIT_COMPLETION(s3c_ac97.done);
+
+ ac_codec_cmd = readl(s3c_ac97.regs + S3C_AC97_CODEC_CMD);
+ ac_codec_cmd = AC_CMD_ADDR(reg) | AC_CMD_DATA(val);
+ writel(ac_codec_cmd, s3c_ac97.regs + S3C_AC97_CODEC_CMD);
+
+ udelay(50);
+
+ ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
+ ac_glbctrl |= S3C_AC97_GLBCTRL_CODECREADYIE;
+ writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
+
+ if (!wait_for_completion_timeout(&s3c_ac97.done, HZ))
+ pr_err("AC97: Unable to write!");
+
+ ac_codec_cmd = readl(s3c_ac97.regs + S3C_AC97_CODEC_CMD);
+ ac_codec_cmd |= S3C_AC97_CODEC_CMD_READ;
+ writel(ac_codec_cmd, s3c_ac97.regs + S3C_AC97_CODEC_CMD);
+
+ mutex_unlock(&s3c_ac97.lock);
+}
+
+static void s3c_ac97_cold_reset(struct snd_ac97 *ac97)
+{
+ pr_debug("AC97: Cold reset\n");
+ writel(S3C_AC97_GLBCTRL_COLDRESET,
+ s3c_ac97.regs + S3C_AC97_GLBCTRL);
+ msleep(1);
+
+ writel(0, s3c_ac97.regs + S3C_AC97_GLBCTRL);
+ msleep(1);
+}
+
+static void s3c_ac97_warm_reset(struct snd_ac97 *ac97)
+{
+ u32 stat;
+
+ stat = readl(s3c_ac97.regs + S3C_AC97_GLBSTAT) & 0x7;
+ if (stat == S3C_AC97_GLBSTAT_MAINSTATE_ACTIVE)
+ return; /* Return if already active */
+
+ pr_debug("AC97: Warm reset\n");
+
+ writel(S3C_AC97_GLBCTRL_WARMRESET, s3c_ac97.regs + S3C_AC97_GLBCTRL);
+ msleep(1);
+
+ writel(0, s3c_ac97.regs + S3C_AC97_GLBCTRL);
+ msleep(1);
+
+ s3c_ac97_activate(ac97);
+}
+
+static irqreturn_t s3c_ac97_irq(int irq, void *dev_id)
+{
+ u32 ac_glbctrl, ac_glbstat;
+
+ ac_glbstat = readl(s3c_ac97.regs + S3C_AC97_GLBSTAT);
+
+ if (ac_glbstat & S3C_AC97_GLBSTAT_CODECREADY) {
+
+ ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
+ ac_glbctrl &= ~S3C_AC97_GLBCTRL_CODECREADYIE;
+ writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
+
+ complete(&s3c_ac97.done);
+ }
+
+ ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
+ ac_glbctrl |= (1<<30); /* Clear interrupt */
+ writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
+
+ return IRQ_HANDLED;
+}
+
+struct snd_ac97_bus_ops soc_ac97_ops = {
+ .read = s3c_ac97_read,
+ .write = s3c_ac97_write,
+ .warm_reset = s3c_ac97_warm_reset,
+ .reset = s3c_ac97_cold_reset,
+};
+EXPORT_SYMBOL_GPL(soc_ac97_ops);
+
+static int s3c_ac97_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_dai *cpu_dai = rtd->cpu_dai;
+ struct s3c_dma_params *dma_data;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ dma_data = &s3c_ac97_pcm_out;
+ else
+ dma_data = &s3c_ac97_pcm_in;
+
+ snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data);
+
+ return 0;
+}
+
+static int s3c_ac97_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *dai)
+{
+ u32 ac_glbctrl;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct s3c_dma_params *dma_data =
+ snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
+
+ ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ ac_glbctrl &= ~S3C_AC97_GLBCTRL_PCMINTM_MASK;
+ else
+ ac_glbctrl &= ~S3C_AC97_GLBCTRL_PCMOUTTM_MASK;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ ac_glbctrl |= S3C_AC97_GLBCTRL_PCMINTM_DMA;
+ else
+ ac_glbctrl |= S3C_AC97_GLBCTRL_PCMOUTTM_DMA;
+ break;
+
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ break;
+ }
+
+ writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
+
+ s3c2410_dma_ctrl(dma_data->channel, S3C2410_DMAOP_STARTED);
+
+ return 0;
+}
+
+static int s3c_ac97_hw_mic_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_dai *cpu_dai = rtd->cpu_dai;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ return -ENODEV;
+ else
+ snd_soc_dai_set_dma_data(cpu_dai, substream, &s3c_ac97_mic_in);
+
+ return 0;
+}
+
+static int s3c_ac97_mic_trigger(struct snd_pcm_substream *substream,
+ int cmd, struct snd_soc_dai *dai)
+{
+ u32 ac_glbctrl;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct s3c_dma_params *dma_data =
+ snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
+
+ ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
+ ac_glbctrl &= ~S3C_AC97_GLBCTRL_MICINTM_MASK;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ ac_glbctrl |= S3C_AC97_GLBCTRL_MICINTM_DMA;
+ break;
+
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ break;
+ }
+
+ writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
+
+ s3c2410_dma_ctrl(dma_data->channel, S3C2410_DMAOP_STARTED);
+
+ return 0;
+}
+
+static struct snd_soc_dai_ops s3c_ac97_dai_ops = {
+ .hw_params = s3c_ac97_hw_params,
+ .trigger = s3c_ac97_trigger,
+};
+
+static struct snd_soc_dai_ops s3c_ac97_mic_dai_ops = {
+ .hw_params = s3c_ac97_hw_mic_params,
+ .trigger = s3c_ac97_mic_trigger,
+};
+
+static struct snd_soc_dai_driver s3c_ac97_dai[] = {
+ [S3C_AC97_DAI_PCM] = {
+ .name = "samsung-ac97",
+ .ac97_control = 1,
+ .playback = {
+ .stream_name = "AC97 Playback",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+ .capture = {
+ .stream_name = "AC97 Capture",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+ .ops = &s3c_ac97_dai_ops,
+ },
+ [S3C_AC97_DAI_MIC] = {
+ .name = "samsung-ac97-mic",
+ .ac97_control = 1,
+ .capture = {
+ .stream_name = "AC97 Mic Capture",
+ .channels_min = 1,
+ .channels_max = 1,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+ .ops = &s3c_ac97_mic_dai_ops,
+ },
+};
+
+static __devinit int s3c_ac97_probe(struct platform_device *pdev)
+{
+ struct resource *mem_res, *dmatx_res, *dmarx_res, *dmamic_res, *irq_res;
+ struct s3c_audio_pdata *ac97_pdata;
+ int ret;
+
+ ac97_pdata = pdev->dev.platform_data;
+ if (!ac97_pdata || !ac97_pdata->cfg_gpio) {
+ dev_err(&pdev->dev, "cfg_gpio callback not provided!\n");
+ return -EINVAL;
+ }
+
+ /* Check for availability of necessary resource */
+ dmatx_res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+ if (!dmatx_res) {
+ dev_err(&pdev->dev, "Unable to get AC97-TX dma resource\n");
+ return -ENXIO;
+ }
+
+ dmarx_res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+ if (!dmarx_res) {
+ dev_err(&pdev->dev, "Unable to get AC97-RX dma resource\n");
+ return -ENXIO;
+ }
+
+ dmamic_res = platform_get_resource(pdev, IORESOURCE_DMA, 2);
+ if (!dmamic_res) {
+ dev_err(&pdev->dev, "Unable to get AC97-MIC dma resource\n");
+ return -ENXIO;
+ }
+
+ mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem_res) {
+ dev_err(&pdev->dev, "Unable to get register resource\n");
+ return -ENXIO;
+ }
+
+ irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!irq_res) {
+ dev_err(&pdev->dev, "AC97 IRQ not provided!\n");
+ return -ENXIO;
+ }
+
+ if (!request_mem_region(mem_res->start,
+ resource_size(mem_res), "ac97")) {
+ dev_err(&pdev->dev, "Unable to request register region\n");
+ return -EBUSY;
+ }
+
+ s3c_ac97_pcm_out.channel = dmatx_res->start;
+ s3c_ac97_pcm_out.dma_addr = mem_res->start + S3C_AC97_PCM_DATA;
+ s3c_ac97_pcm_in.channel = dmarx_res->start;
+ s3c_ac97_pcm_in.dma_addr = mem_res->start + S3C_AC97_PCM_DATA;
+ s3c_ac97_mic_in.channel = dmamic_res->start;
+ s3c_ac97_mic_in.dma_addr = mem_res->start + S3C_AC97_MIC_DATA;
+
+ init_completion(&s3c_ac97.done);
+ mutex_init(&s3c_ac97.lock);
+
+ s3c_ac97.regs = ioremap(mem_res->start, resource_size(mem_res));
+ if (s3c_ac97.regs == NULL) {
+ dev_err(&pdev->dev, "Unable to ioremap register region\n");
+ ret = -ENXIO;
+ goto err1;
+ }
+
+ s3c_ac97.ac97_clk = clk_get(&pdev->dev, "ac97");
+ if (IS_ERR(s3c_ac97.ac97_clk)) {
+ dev_err(&pdev->dev, "ac97 failed to get ac97_clock\n");
+ ret = -ENODEV;
+ goto err2;
+ }
+ clk_enable(s3c_ac97.ac97_clk);
+
+ if (ac97_pdata->cfg_gpio(pdev)) {
+ dev_err(&pdev->dev, "Unable to configure gpio\n");
+ ret = -EINVAL;
+ goto err3;
+ }
+
+ ret = request_irq(irq_res->start, s3c_ac97_irq,
+ IRQF_DISABLED, "AC97", NULL);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "ac97: interrupt request failed.\n");
+ goto err4;
+ }
+
+ ret = snd_soc_register_dais(&pdev->dev, s3c_ac97_dai,
+ ARRAY_SIZE(s3c_ac97_dai));
+ if (ret)
+ goto err5;
+
+ return 0;
+
+err5:
+ free_irq(irq_res->start, NULL);
+err4:
+err3:
+ clk_disable(s3c_ac97.ac97_clk);
+ clk_put(s3c_ac97.ac97_clk);
+err2:
+ iounmap(s3c_ac97.regs);
+err1:
+ release_mem_region(mem_res->start, resource_size(mem_res));
+
+ return ret;
+}
+
+static __devexit int s3c_ac97_remove(struct platform_device *pdev)
+{
+ struct resource *mem_res, *irq_res;
+
+ snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(s3c_ac97_dai));
+
+ irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (irq_res)
+ free_irq(irq_res->start, NULL);
+
+ clk_disable(s3c_ac97.ac97_clk);
+ clk_put(s3c_ac97.ac97_clk);
+
+ iounmap(s3c_ac97.regs);
+
+ mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (mem_res)
+ release_mem_region(mem_res->start, resource_size(mem_res));
+
+ return 0;
+}
+
+static struct platform_driver s3c_ac97_driver = {
+ .probe = s3c_ac97_probe,
+ .remove = s3c_ac97_remove,
+ .driver = {
+ .name = "samsung-ac97",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init s3c_ac97_init(void)
+{
+ return platform_driver_register(&s3c_ac97_driver);
+}
+module_init(s3c_ac97_init);
+
+static void __exit s3c_ac97_exit(void)
+{
+ platform_driver_unregister(&s3c_ac97_driver);
+}
+module_exit(s3c_ac97_exit);
+
+MODULE_AUTHOR("Jaswinder Singh, <jassi.brar(a)samsung.com>");
+MODULE_DESCRIPTION("AC97 driver for the Samsung SoC");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:samsung-ac97");
diff --git a/sound/soc/samsung/ac97.h b/sound/soc/samsung/ac97.h
new file mode 100644
index 0000000..0d0e1b5
--- /dev/null
+++ b/sound/soc/samsung/ac97.h
@@ -0,0 +1,21 @@
+/* sound/soc/samsung/ac97.h
+ *
+ * ALSA SoC Audio Layer - S3C AC97 Controller driver
+ * Evolved from s3c2443-ac97.h
+ *
+ * Copyright (c) 2010 Samsung Electronics Co. Ltd
+ * Author: Jaswinder Singh <jassi.brar(a)samsung.com>
+ * Credits: Graeme Gregory, Sean Choi
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __S3C_AC97_H_
+#define __S3C_AC97_H_
+
+#define S3C_AC97_DAI_PCM 0
+#define S3C_AC97_DAI_MIC 1
+
+#endif /* __S3C_AC97_H_ */
diff --git a/sound/soc/samsung/dma.c b/sound/soc/samsung/dma.c
new file mode 100644
index 0000000..12622f3
--- /dev/null
+++ b/sound/soc/samsung/dma.c
@@ -0,0 +1,503 @@
+/*
+ * dma.c -- ALSA Soc Audio Layer
+ *
+ * (c) 2006 Wolfson Microelectronics PLC.
+ * Graeme Gregory graeme.gregory(a)wolfsonmicro.com or linux(a)wolfsonmicro.com
+ *
+ * Copyright 2004-2005 Simtec Electronics
+ * http://armlinux.simtec.co.uk/
+ * Ben Dooks <ben(a)simtec.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include <asm/dma.h>
+#include <mach/hardware.h>
+#include <mach/dma.h>
+
+#include "dma.h"
+
+static const struct snd_pcm_hardware dma_hardware = {
+ .info = SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_PAUSE |
+ SNDRV_PCM_INFO_RESUME,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_U16_LE |
+ SNDRV_PCM_FMTBIT_U8 |
+ SNDRV_PCM_FMTBIT_S8,
+ .channels_min = 2,
+ .channels_max = 2,
+ .buffer_bytes_max = 128*1024,
+ .period_bytes_min = PAGE_SIZE,
+ .period_bytes_max = PAGE_SIZE*2,
+ .periods_min = 2,
+ .periods_max = 128,
+ .fifo_size = 32,
+};
+
+struct runtime_data {
+ spinlock_t lock;
+ int state;
+ unsigned int dma_loaded;
+ unsigned int dma_limit;
+ unsigned int dma_period;
+ dma_addr_t dma_start;
+ dma_addr_t dma_pos;
+ dma_addr_t dma_end;
+ struct s3c_dma_params *params;
+};
+
+/* dma_enqueue
+ *
+ * place a dma buffer onto the queue for the dma system
+ * to handle.
+*/
+static void dma_enqueue(struct snd_pcm_substream *substream)
+{
+ struct runtime_data *prtd = substream->runtime->private_data;
+ dma_addr_t pos = prtd->dma_pos;
+ unsigned int limit;
+ int ret;
+
+ pr_debug("Entered %s\n", __func__);
+
+ if (s3c_dma_has_circular())
+ limit = (prtd->dma_end - prtd->dma_start) / prtd->dma_period;
+ else
+ limit = prtd->dma_limit;
+
+ pr_debug("%s: loaded %d, limit %d\n",
+ __func__, prtd->dma_loaded, limit);
+
+ while (prtd->dma_loaded < limit) {
+ unsigned long len = prtd->dma_period;
+
+ pr_debug("dma_loaded: %d\n", prtd->dma_loaded);
+
+ if ((pos + len) > prtd->dma_end) {
+ len = prtd->dma_end - pos;
+ pr_debug(KERN_DEBUG "%s: corrected dma len %ld\n",
+ __func__, len);
+ }
+
+ ret = s3c2410_dma_enqueue(prtd->params->channel,
+ substream, pos, len);
+
+ if (ret == 0) {
+ prtd->dma_loaded++;
+ pos += prtd->dma_period;
+ if (pos >= prtd->dma_end)
+ pos = prtd->dma_start;
+ } else
+ break;
+ }
+
+ prtd->dma_pos = pos;
+}
+
+static void audio_buffdone(struct s3c2410_dma_chan *channel,
+ void *dev_id, int size,
+ enum s3c2410_dma_buffresult result)
+{
+ struct snd_pcm_substream *substream = dev_id;
+ struct runtime_data *prtd;
+
+ pr_debug("Entered %s\n", __func__);
+
+ if (result == S3C2410_RES_ABORT || result == S3C2410_RES_ERR)
+ return;
+
+ prtd = substream->runtime->private_data;
+
+ if (substream)
+ snd_pcm_period_elapsed(substream);
+
+ spin_lock(&prtd->lock);
+ if (prtd->state & ST_RUNNING && !s3c_dma_has_circular()) {
+ prtd->dma_loaded--;
+ dma_enqueue(substream);
+ }
+
+ spin_unlock(&prtd->lock);
+}
+
+static int dma_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct runtime_data *prtd = runtime->private_data;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ unsigned long totbytes = params_buffer_bytes(params);
+ struct s3c_dma_params *dma =
+ snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
+ int ret = 0;
+
+
+ pr_debug("Entered %s\n", __func__);
+
+ /* return if this is a bufferless transfer e.g.
+ * codec <--> BT codec or GSM modem -- lg FIXME */
+ if (!dma)
+ return 0;
+
+ /* this may get called several times by oss emulation
+ * with different params -HW */
+ if (prtd->params == NULL) {
+ /* prepare DMA */
+ prtd->params = dma;
+
+ pr_debug("params %p, client %p, channel %d\n", prtd->params,
+ prtd->params->client, prtd->params->channel);
+
+ ret = s3c2410_dma_request(prtd->params->channel,
+ prtd->params->client, NULL);
+
+ if (ret < 0) {
+ printk(KERN_ERR "failed to get dma channel\n");
+ return ret;
+ }
+
+ /* use the circular buffering if we have it available. */
+ if (s3c_dma_has_circular())
+ s3c2410_dma_setflags(prtd->params->channel,
+ S3C2410_DMAF_CIRCULAR);
+ }
+
+ s3c2410_dma_set_buffdone_fn(prtd->params->channel,
+ audio_buffdone);
+
+ snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+
+ runtime->dma_bytes = totbytes;
+
+ spin_lock_irq(&prtd->lock);
+ prtd->dma_loaded = 0;
+ prtd->dma_limit = runtime->hw.periods_min;
+ prtd->dma_period = params_period_bytes(params);
+ prtd->dma_start = runtime->dma_addr;
+ prtd->dma_pos = prtd->dma_start;
+ prtd->dma_end = prtd->dma_start + totbytes;
+ spin_unlock_irq(&prtd->lock);
+
+ return 0;
+}
+
+static int dma_hw_free(struct snd_pcm_substream *substream)
+{
+ struct runtime_data *prtd = substream->runtime->private_data;
+
+ pr_debug("Entered %s\n", __func__);
+
+ /* TODO - do we need to ensure DMA flushed */
+ snd_pcm_set_runtime_buffer(substream, NULL);
+
+ if (prtd->params) {
+ s3c2410_dma_free(prtd->params->channel, prtd->params->client);
+ prtd->params = NULL;
+ }
+
+ return 0;
+}
+
+static int dma_prepare(struct snd_pcm_substream *substream)
+{
+ struct runtime_data *prtd = substream->runtime->private_data;
+ int ret = 0;
+
+ pr_debug("Entered %s\n", __func__);
+
+ /* return if this is a bufferless transfer e.g.
+ * codec <--> BT codec or GSM modem -- lg FIXME */
+ if (!prtd->params)
+ return 0;
+
+ /* channel needs configuring for mem=>device, increment memory addr,
+ * sync to pclk, half-word transfers to the IIS-FIFO. */
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ s3c2410_dma_devconfig(prtd->params->channel,
+ S3C2410_DMASRC_MEM,
+ prtd->params->dma_addr);
+ } else {
+ s3c2410_dma_devconfig(prtd->params->channel,
+ S3C2410_DMASRC_HW,
+ prtd->params->dma_addr);
+ }
+
+ s3c2410_dma_config(prtd->params->channel,
+ prtd->params->dma_size);
+
+ /* flush the DMA channel */
+ s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_FLUSH);
+ prtd->dma_loaded = 0;
+ prtd->dma_pos = prtd->dma_start;
+
+ /* enqueue dma buffers */
+ dma_enqueue(substream);
+
+ return ret;
+}
+
+static int dma_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct runtime_data *prtd = substream->runtime->private_data;
+ int ret = 0;
+
+ pr_debug("Entered %s\n", __func__);
+
+ spin_lock(&prtd->lock);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ prtd->state |= ST_RUNNING;
+ s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_START);
+ break;
+
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ prtd->state &= ~ST_RUNNING;
+ s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_STOP);
+ break;
+
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ spin_unlock(&prtd->lock);
+
+ return ret;
+}
+
+static snd_pcm_uframes_t
+dma_pointer(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct runtime_data *prtd = runtime->private_data;
+ unsigned long res;
+ dma_addr_t src, dst;
+
+ pr_debug("Entered %s\n", __func__);
+
+ spin_lock(&prtd->lock);
+ s3c2410_dma_getposition(prtd->params->channel, &src, &dst);
+
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ res = dst - prtd->dma_start;
+ else
+ res = src - prtd->dma_start;
+
+ spin_unlock(&prtd->lock);
+
+ pr_debug("Pointer %x %x\n", src, dst);
+
+ /* we seem to be getting the odd error from the pcm library due
+ * to out-of-bounds pointers. this is maybe due to the dma engine
+ * not having loaded the new values for the channel before being
+ * callled... (todo - fix )
+ */
+
+ if (res >= snd_pcm_lib_buffer_bytes(substream)) {
+ if (res == snd_pcm_lib_buffer_bytes(substream))
+ res = 0;
+ }
+
+ return bytes_to_frames(substream->runtime, res);
+}
+
+static int dma_open(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct runtime_data *prtd;
+
+ pr_debug("Entered %s\n", __func__);
+
+ snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
+ snd_soc_set_runtime_hwparams(substream, &dma_hardware);
+
+ prtd = kzalloc(sizeof(struct runtime_data), GFP_KERNEL);
+ if (prtd == NULL)
+ return -ENOMEM;
+
+ spin_lock_init(&prtd->lock);
+
+ runtime->private_data = prtd;
+ return 0;
+}
+
+static int dma_close(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct runtime_data *prtd = runtime->private_data;
+
+ pr_debug("Entered %s\n", __func__);
+
+ if (!prtd)
+ pr_debug("dma_close called with prtd == NULL\n");
+
+ kfree(prtd);
+
+ return 0;
+}
+
+static int dma_mmap(struct snd_pcm_substream *substream,
+ struct vm_area_struct *vma)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+
+ pr_debug("Entered %s\n", __func__);
+
+ return dma_mmap_writecombine(substream->pcm->card->dev, vma,
+ runtime->dma_area,
+ runtime->dma_addr,
+ runtime->dma_bytes);
+}
+
+static struct snd_pcm_ops dma_ops = {
+ .open = dma_open,
+ .close = dma_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = dma_hw_params,
+ .hw_free = dma_hw_free,
+ .prepare = dma_prepare,
+ .trigger = dma_trigger,
+ .pointer = dma_pointer,
+ .mmap = dma_mmap,
+};
+
+static int preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
+{
+ struct snd_pcm_substream *substream = pcm->streams[stream].substream;
+ struct snd_dma_buffer *buf = &substream->dma_buffer;
+ size_t size = dma_hardware.buffer_bytes_max;
+
+ pr_debug("Entered %s\n", __func__);
+
+ buf->dev.type = SNDRV_DMA_TYPE_DEV;
+ buf->dev.dev = pcm->card->dev;
+ buf->private_data = NULL;
+ buf->area = dma_alloc_writecombine(pcm->card->dev, size,
+ &buf->addr, GFP_KERNEL);
+ if (!buf->area)
+ return -ENOMEM;
+ buf->bytes = size;
+ return 0;
+}
+
+static void dma_free_dma_buffers(struct snd_pcm *pcm)
+{
+ struct snd_pcm_substream *substream;
+ struct snd_dma_buffer *buf;
+ int stream;
+
+ pr_debug("Entered %s\n", __func__);
+
+ for (stream = 0; stream < 2; stream++) {
+ substream = pcm->streams[stream].substream;
+ if (!substream)
+ continue;
+
+ buf = &substream->dma_buffer;
+ if (!buf->area)
+ continue;
+
+ dma_free_writecombine(pcm->card->dev, buf->bytes,
+ buf->area, buf->addr);
+ buf->area = NULL;
+ }
+}
+
+static u64 dma_mask = DMA_BIT_MASK(32);
+
+static int dma_new(struct snd_card *card,
+ struct snd_soc_dai *dai, struct snd_pcm *pcm)
+{
+ int ret = 0;
+
+ pr_debug("Entered %s\n", __func__);
+
+ if (!card->dev->dma_mask)
+ card->dev->dma_mask = &dma_mask;
+ if (!card->dev->coherent_dma_mask)
+ card->dev->coherent_dma_mask = 0xffffffff;
+
+ if (dai->driver->playback.channels_min) {
+ ret = preallocate_dma_buffer(pcm,
+ SNDRV_PCM_STREAM_PLAYBACK);
+ if (ret)
+ goto out;
+ }
+
+ if (dai->driver->capture.channels_min) {
+ ret = preallocate_dma_buffer(pcm,
+ SNDRV_PCM_STREAM_CAPTURE);
+ if (ret)
+ goto out;
+ }
+out:
+ return ret;
+}
+
+static struct snd_soc_platform_driver samsung_asoc_platform = {
+ .ops = &dma_ops,
+ .pcm_new = dma_new,
+ .pcm_free = dma_free_dma_buffers,
+};
+
+static int __devinit samsung_asoc_platform_probe(struct platform_device *pdev)
+{
+ return snd_soc_register_platform(&pdev->dev, &samsung_asoc_platform);
+}
+
+static int __devexit samsung_asoc_platform_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_platform(&pdev->dev);
+ return 0;
+}
+
+static struct platform_driver asoc_dma_driver = {
+ .driver = {
+ .name = "samsung-audio",
+ .owner = THIS_MODULE,
+ },
+
+ .probe = samsung_asoc_platform_probe,
+ .remove = __devexit_p(samsung_asoc_platform_remove),
+};
+
+static int __init samsung_asoc_init(void)
+{
+ return platform_driver_register(&asoc_dma_driver);
+}
+module_init(samsung_asoc_init);
+
+static void __exit samsung_asoc_exit(void)
+{
+ platform_driver_unregister(&asoc_dma_driver);
+}
+module_exit(samsung_asoc_exit);
+
+MODULE_AUTHOR("Ben Dooks, <ben(a)simtec.co.uk>");
+MODULE_DESCRIPTION("Samsung ASoC DMA Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:samsung-audio");
diff --git a/sound/soc/samsung/dma.h b/sound/soc/samsung/dma.h
new file mode 100644
index 0000000..f8cd2b4
--- /dev/null
+++ b/sound/soc/samsung/dma.h
@@ -0,0 +1,30 @@
+/*
+ * dma.h --
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * ALSA PCM interface for the Samsung S3C24xx CPU
+ */
+
+#ifndef _S3C_AUDIO_H
+#define _S3C_AUDIO_H
+
+#define ST_RUNNING (1<<0)
+#define ST_OPENED (1<<1)
+
+struct s3c_dma_params {
+ struct s3c2410_dma_client *client; /* stream identifier */
+ int channel; /* Channel ID */
+ dma_addr_t dma_addr;
+ int dma_size; /* Size of the DMA transfer */
+};
+
+#define S3C24XX_DAI_I2S 0
+
+/* platform data */
+extern struct snd_ac97_bus_ops s3c24xx_ac97_ops;
+
+#endif
diff --git a/sound/soc/samsung/goni_wm8994.c b/sound/soc/samsung/goni_wm8994.c
new file mode 100644
index 0000000..dcaf7c3
--- /dev/null
+++ b/sound/soc/samsung/goni_wm8994.c
@@ -0,0 +1,309 @@
+/*
+ * goni_wm8994.c
+ *
+ * Copyright (C) 2010 Samsung Electronics Co.Ltd
+ * Author: Chanwoo Choi <cw00.choi(a)samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/jack.h>
+#include <asm/mach-types.h>
+#include <mach/gpio.h>
+#include <mach/regs-clock.h>
+
+#include <linux/mfd/wm8994/core.h>
+#include <linux/mfd/wm8994/registers.h>
+#include "../codecs/wm8994.h"
+#include "dma.h"
+#include "i2s.h"
+
+#define MACHINE_NAME 0
+#define CPU_VOICE_DAI 1
+
+static const char *aquila_str[] = {
+ [MACHINE_NAME] = "aquila",
+ [CPU_VOICE_DAI] = "aquila-voice-dai",
+};
+
+static struct snd_soc_card goni;
+static struct platform_device *goni_snd_device;
+
+/* 3.5 pie jack */
+static struct snd_soc_jack jack;
+
+/* 3.5 pie jack detection DAPM pins */
+static struct snd_soc_jack_pin jack_pins[] = {
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ }, {
+ .pin = "Headset Stereophone",
+ .mask = SND_JACK_HEADPHONE | SND_JACK_MECHANICAL |
+ SND_JACK_AVOUT,
+ },
+};
+
+/* 3.5 pie jack detection gpios */
+static struct snd_soc_jack_gpio jack_gpios[] = {
+ {
+ .gpio = S5PV210_GPH0(6),
+ .name = "DET_3.5",
+ .report = SND_JACK_HEADSET | SND_JACK_MECHANICAL |
+ SND_JACK_AVOUT,
+ .debounce_time = 200,
+ },
+};
+
+static const struct snd_soc_dapm_widget goni_dapm_widgets[] = {
+ SND_SOC_DAPM_SPK("Ext Left Spk", NULL),
+ SND_SOC_DAPM_SPK("Ext Right Spk", NULL),
+ SND_SOC_DAPM_SPK("Ext Rcv", NULL),
+ SND_SOC_DAPM_HP("Headset Stereophone", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_MIC("Main Mic", NULL),
+ SND_SOC_DAPM_MIC("2nd Mic", NULL),
+ SND_SOC_DAPM_LINE("Radio In", NULL),
+};
+
+static const struct snd_soc_dapm_route goni_dapm_routes[] = {
+ {"Ext Left Spk", NULL, "SPKOUTLP"},
+ {"Ext Left Spk", NULL, "SPKOUTLN"},
+
+ {"Ext Right Spk", NULL, "SPKOUTRP"},
+ {"Ext Right Spk", NULL, "SPKOUTRN"},
+
+ {"Ext Rcv", NULL, "HPOUT2N"},
+ {"Ext Rcv", NULL, "HPOUT2P"},
+
+ {"Headset Stereophone", NULL, "HPOUT1L"},
+ {"Headset Stereophone", NULL, "HPOUT1R"},
+
+ {"IN1RN", NULL, "Headset Mic"},
+ {"IN1RP", NULL, "Headset Mic"},
+
+ {"IN1RN", NULL, "2nd Mic"},
+ {"IN1RP", NULL, "2nd Mic"},
+
+ {"IN1LN", NULL, "Main Mic"},
+ {"IN1LP", NULL, "Main Mic"},
+
+ {"IN2LN", NULL, "Radio In"},
+ {"IN2RN", NULL, "Radio In"},
+};
+
+static int goni_wm8994_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_codec *codec = rtd->codec;
+ int ret;
+
+ /* add goni specific widgets */
+ snd_soc_dapm_new_controls(codec, goni_dapm_widgets,
+ ARRAY_SIZE(goni_dapm_widgets));
+
+ /* set up goni specific audio routes */
+ snd_soc_dapm_add_routes(codec, goni_dapm_routes,
+ ARRAY_SIZE(goni_dapm_routes));
+
+ /* set endpoints to not connected */
+ snd_soc_dapm_nc_pin(codec, "IN2LP:VXRN");
+ snd_soc_dapm_nc_pin(codec, "IN2RP:VXRP");
+ snd_soc_dapm_nc_pin(codec, "LINEOUT1N");
+ snd_soc_dapm_nc_pin(codec, "LINEOUT1P");
+ snd_soc_dapm_nc_pin(codec, "LINEOUT2N");
+ snd_soc_dapm_nc_pin(codec, "LINEOUT2P");
+
+ if (machine_is_aquila()) {
+ snd_soc_dapm_nc_pin(codec, "SPKOUTRN");
+ snd_soc_dapm_nc_pin(codec, "SPKOUTRP");
+ }
+
+ snd_soc_dapm_sync(codec);
+
+ /* Headset jack detection */
+ ret = snd_soc_jack_new(&goni, "Headset Jack",
+ SND_JACK_HEADSET | SND_JACK_MECHANICAL | SND_JACK_AVOUT,
+ &jack);
+ if (ret)
+ return ret;
+
+ ret = snd_soc_jack_add_pins(&jack, ARRAY_SIZE(jack_pins), jack_pins);
+ if (ret)
+ return ret;
+
+ ret = snd_soc_jack_add_gpios(&jack, ARRAY_SIZE(jack_gpios), jack_gpios);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int goni_hifi_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ unsigned int pll_out = 24000000;
+ int ret = 0;
+
+ /* set the cpu DAI configuration */
+ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+ if (ret < 0)
+ return ret;
+
+ /* set codec DAI configuration */
+ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+ if (ret < 0)
+ return ret;
+
+ /* set the codec FLL */
+ ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL1, 0, pll_out,
+ params_rate(params) * 256);
+ if (ret < 0)
+ return ret;
+
+ /* set the codec system clock */
+ ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_FLL1,
+ params_rate(params) * 256, SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static struct snd_soc_ops goni_hifi_ops = {
+ .hw_params = goni_hifi_hw_params,
+};
+
+static int goni_voice_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ unsigned int pll_out = 24000000;
+ int ret = 0;
+
+ if (params_rate(params) != 8000)
+ return -EINVAL;
+
+ /* set codec DAI configuration */
+ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_LEFT_J |
+ SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_CBM_CFM);
+ if (ret < 0)
+ return ret;
+
+ /* set the codec FLL */
+ ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL2, 0, pll_out,
+ params_rate(params) * 256);
+ if (ret < 0)
+ return ret;
+
+ /* set the codec system clock */
+ ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_FLL2,
+ params_rate(params) * 256, SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static struct snd_soc_dai_driver voice_dai = {
+ .name = "goni-voice-dai",
+ .id = 0,
+ .playback = {
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+ .capture = {
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+};
+
+static struct snd_soc_ops goni_voice_ops = {
+ .hw_params = goni_voice_hw_params,
+};
+
+static struct snd_soc_dai_link goni_dai[] = {
+{
+ .name = "WM8994",
+ .stream_name = "WM8994 HiFi",
+ .cpu_dai_name = "samsung-i2s.0",
+ .codec_dai_name = "wm8994-hifi",
+ .platform_name = "samsung-audio",
+ .codec_name = "wm8994-codec.0-0x1a",
+ .init = goni_wm8994_init,
+ .ops = &goni_hifi_ops,
+}, {
+ .name = "WM8994 Voice",
+ .stream_name = "Voice",
+ .cpu_dai_name = "goni-voice-dai",
+ .codec_dai_name = "wm8994-voice",
+ .platform_name = "samsung-audio",
+ .codec_name = "wm8994-codec.0-0x1a",
+ .ops = &goni_voice_ops,
+},
+};
+
+static struct snd_soc_card goni = {
+ .name = "goni",
+ .dai_link = goni_dai,
+ .num_links = ARRAY_SIZE(goni_dai),
+};
+
+static int __init goni_init(void)
+{
+ int ret;
+
+ if (machine_is_aquila()) {
+ voice_dai.name = aquila_str[CPU_VOICE_DAI];
+ goni_dai[1].cpu_dai_name = aquila_str[CPU_VOICE_DAI];
+ goni.name = aquila_str[MACHINE_NAME];
+ } else if (!machine_is_goni())
+ return -ENODEV;
+
+ goni_snd_device = platform_device_alloc("soc-audio", -1);
+ if (!goni_snd_device)
+ return -ENOMEM;
+
+ /* register voice DAI here */
+ ret = snd_soc_register_dai(&goni_snd_device->dev, &voice_dai);
+ if (ret)
+ return ret;
+
+ platform_set_drvdata(goni_snd_device, &goni);
+ ret = platform_device_add(goni_snd_device);
+
+ if (ret)
+ platform_device_put(goni_snd_device);
+
+ return ret;
+}
+
+static void __exit goni_exit(void)
+{
+ platform_device_unregister(goni_snd_device);
+}
+
+module_init(goni_init);
+module_exit(goni_exit);
+
+/* Module information */
+MODULE_DESCRIPTION("ALSA SoC WM8994 GONI(S5PV210)");
+MODULE_AUTHOR("Chanwoo Choi <cw00.choi(a)samsung.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c
new file mode 100644
index 0000000..d5d8975
--- /dev/null
+++ b/sound/soc/samsung/i2s.c
@@ -0,0 +1,1251 @@
+/* sound/soc/samsung/i2s.c
+ *
+ * ALSA SoC Audio Layer - Samsung I2S Controller driver
+ *
+ * Copyright (c) 2010 Samsung Electronics Co. Ltd.
+ * Jaswinder Singh <jassi.brar(a)samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include <plat/audio.h>
+
+#include "dma.h"
+#include "i2s.h"
+
+#define I2SCON 0x0
+#define I2SMOD 0x4
+#define I2SFIC 0x8
+#define I2SPSR 0xc
+#define I2STXD 0x10
+#define I2SRXD 0x14
+#define I2SFICS 0x18
+#define I2STXDS 0x1c
+
+#define CON_RSTCLR (1 << 31)
+#define CON_FRXOFSTATUS (1 << 26)
+#define CON_FRXORINTEN (1 << 25)
+#define CON_FTXSURSTAT (1 << 24)
+#define CON_FTXSURINTEN (1 << 23)
+#define CON_TXSDMA_PAUSE (1 << 20)
+#define CON_TXSDMA_ACTIVE (1 << 18)
+
+#define CON_FTXURSTATUS (1 << 17)
+#define CON_FTXURINTEN (1 << 16)
+#define CON_TXFIFO2_EMPTY (1 << 15)
+#define CON_TXFIFO1_EMPTY (1 << 14)
+#define CON_TXFIFO2_FULL (1 << 13)
+#define CON_TXFIFO1_FULL (1 << 12)
+
+#define CON_LRINDEX (1 << 11)
+#define CON_TXFIFO_EMPTY (1 << 10)
+#define CON_RXFIFO_EMPTY (1 << 9)
+#define CON_TXFIFO_FULL (1 << 8)
+#define CON_RXFIFO_FULL (1 << 7)
+#define CON_TXDMA_PAUSE (1 << 6)
+#define CON_RXDMA_PAUSE (1 << 5)
+#define CON_TXCH_PAUSE (1 << 4)
+#define CON_RXCH_PAUSE (1 << 3)
+#define CON_TXDMA_ACTIVE (1 << 2)
+#define CON_RXDMA_ACTIVE (1 << 1)
+#define CON_ACTIVE (1 << 0)
+
+#define MOD_OPCLK_CDCLK_OUT (0 << 30)
+#define MOD_OPCLK_CDCLK_IN (1 << 30)
+#define MOD_OPCLK_BCLK_OUT (2 << 30)
+#define MOD_OPCLK_PCLK (3 << 30)
+#define MOD_OPCLK_MASK (3 << 30)
+#define MOD_TXS_IDMA (1 << 28) /* Sec_TXFIFO use I-DMA */
+
+#define MOD_BLCS_SHIFT 26
+#define MOD_BLCS_16BIT (0 << MOD_BLCS_SHIFT)
+#define MOD_BLCS_8BIT (1 << MOD_BLCS_SHIFT)
+#define MOD_BLCS_24BIT (2 << MOD_BLCS_SHIFT)
+#define MOD_BLCS_MASK (3 << MOD_BLCS_SHIFT)
+#define MOD_BLCP_SHIFT 24
+#define MOD_BLCP_16BIT (0 << MOD_BLCP_SHIFT)
+#define MOD_BLCP_8BIT (1 << MOD_BLCP_SHIFT)
+#define MOD_BLCP_24BIT (2 << MOD_BLCP_SHIFT)
+#define MOD_BLCP_MASK (3 << MOD_BLCP_SHIFT)
+
+#define MOD_C2DD_HHALF (1 << 21) /* Discard Higher-half */
+#define MOD_C2DD_LHALF (1 << 20) /* Discard Lower-half */
+#define MOD_C1DD_HHALF (1 << 19)
+#define MOD_C1DD_LHALF (1 << 18)
+#define MOD_DC2_EN (1 << 17)
+#define MOD_DC1_EN (1 << 16)
+#define MOD_BLC_16BIT (0 << 13)
+#define MOD_BLC_8BIT (1 << 13)
+#define MOD_BLC_24BIT (2 << 13)
+#define MOD_BLC_MASK (3 << 13)
+
+#define MOD_IMS_SYSMUX (1 << 10)
+#define MOD_SLAVE (1 << 11)
+#define MOD_TXONLY (0 << 8)
+#define MOD_RXONLY (1 << 8)
+#define MOD_TXRX (2 << 8)
+#define MOD_MASK (3 << 8)
+#define MOD_LR_LLOW (0 << 7)
+#define MOD_LR_RLOW (1 << 7)
+#define MOD_SDF_IIS (0 << 5)
+#define MOD_SDF_MSB (1 << 5)
+#define MOD_SDF_LSB (2 << 5)
+#define MOD_SDF_MASK (3 << 5)
+#define MOD_RCLK_256FS (0 << 3)
+#define MOD_RCLK_512FS (1 << 3)
+#define MOD_RCLK_384FS (2 << 3)
+#define MOD_RCLK_768FS (3 << 3)
+#define MOD_RCLK_MASK (3 << 3)
+#define MOD_BCLK_32FS (0 << 1)
+#define MOD_BCLK_48FS (1 << 1)
+#define MOD_BCLK_16FS (2 << 1)
+#define MOD_BCLK_24FS (3 << 1)
+#define MOD_BCLK_MASK (3 << 1)
+#define MOD_8BIT (1 << 0)
+
+#define MOD_CDCLKCON (1 << 12)
+
+#define PSR_PSREN (1 << 15)
+
+#define FIC_TX2COUNT(x) (((x) >> 24) & 0xf)
+#define FIC_TX1COUNT(x) (((x) >> 16) & 0xf)
+
+#define FIC_TXFLUSH (1 << 15)
+#define FIC_RXFLUSH (1 << 7)
+#define FIC_TXCOUNT(x) (((x) >> 8) & 0xf)
+#define FIC_RXCOUNT(x) (((x) >> 0) & 0xf)
+#define FICS_TXCOUNT(x) (((x) >> 8) & 0x7f)
+
+#define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t)
+
+struct i2s_dai {
+ /* Platform device for this DAI */
+ struct platform_device *pdev;
+ /* IOREMAP'd SFRs */
+ void __iomem *addr;
+ /* Physical base address of SFRs */
+ u32 base;
+ /* Rate of RCLK source clock */
+ unsigned long rclk_srcrate;
+ /* Frame Clock */
+ unsigned frmclk;
+ /*
+ * Specifically requested RCLK,BCLK by MACHINE Driver.
+ * 0 indicates CPU driver is free to choose any value.
+ */
+ unsigned rfs, bfs;
+ /* I2S Controller's core clock */
+ struct clk *clk;
+ /* Clock for generating I2S signals */
+ struct clk *op_clk;
+ /* Array of clock names for op_clk */
+ const char **src_clk;
+ /* Pointer to the Primary_Fifo if this is Sec_Fifo, NULL otherwise */
+ struct i2s_dai *pri_dai;
+ /* Pointer to the Secondary_Fifo if it has one, NULL otherwise */
+ struct i2s_dai *sec_dai;
+#define DAI_OPENED (1 << 0) /* Dai is opened */
+#define DAI_MANAGER (1 << 1) /* Dai is the manager */
+ unsigned mode;
+ /* Driver for this DAI */
+ struct snd_soc_dai_driver s3c_i2s_drv;
+ /* DMA parameters */
+ struct s3c_dma_params dma_playback;
+ struct s3c_dma_params dma_capture;
+ u32 quirks;
+ u32 suspend_i2smod;
+ u32 suspend_i2scon;
+ u32 suspend_i2spsr;
+};
+
+/* Lock for cross i/f checks */
+static DEFINE_SPINLOCK(lock);
+
+/* If this is the 'overlay' stereo DAI */
+static inline bool is_secondary(struct i2s_dai *i2s)
+{
+ return i2s->pri_dai ? true : false;
+}
+
+/* If operating in SoC-Slave mode */
+static inline bool is_slave(struct i2s_dai *i2s)
+{
+ return (readl(i2s->addr + I2SMOD) & MOD_SLAVE) ? true : false;
+}
+
+/* If this interface of the controller is transmitting data */
+static inline bool tx_active(struct i2s_dai *i2s)
+{
+ u32 active;
+
+ if (!i2s)
+ return false;
+
+ active = readl(i2s->addr + I2SMOD);
+
+ if (is_secondary(i2s))
+ active &= CON_TXSDMA_ACTIVE;
+ else
+ active &= CON_TXDMA_ACTIVE;
+
+ return active ? true : false;
+}
+
+/* If the other interface of the controller is transmitting data */
+static inline bool other_tx_active(struct i2s_dai *i2s)
+{
+ struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
+
+ return tx_active(other);
+}
+
+/* If any interface of the controller is transmitting data */
+static inline bool any_tx_active(struct i2s_dai *i2s)
+{
+ return tx_active(i2s) || other_tx_active(i2s);
+}
+
+/* If this interface of the controller is receiving data */
+static inline bool rx_active(struct i2s_dai *i2s)
+{
+ u32 active;
+
+ if (!i2s)
+ return false;
+
+ active = readl(i2s->addr + I2SMOD) & CON_RXDMA_ACTIVE;
+
+ return active ? true : false;
+}
+
+/* If the other interface of the controller is receiving data */
+static inline bool other_rx_active(struct i2s_dai *i2s)
+{
+ struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
+
+ return rx_active(other);
+}
+
+/* If any interface of the controller is receiving data */
+static inline bool any_rx_active(struct i2s_dai *i2s)
+{
+ return rx_active(i2s) || other_rx_active(i2s);
+}
+
+/* If the other DAI is transmitting or receiving data */
+static inline bool other_active(struct i2s_dai *i2s)
+{
+ return other_rx_active(i2s) || other_tx_active(i2s);
+}
+
+/* If this DAI is transmitting or receiving data */
+static inline bool this_active(struct i2s_dai *i2s)
+{
+ return tx_active(i2s) || rx_active(i2s);
+}
+
+/* If the controller is active anyway */
+static inline bool any_active(struct i2s_dai *i2s)
+{
+ return this_active(i2s) || other_active(i2s);
+}
+
+static inline struct i2s_dai *to_info(struct snd_soc_dai *dai)
+{
+ return snd_soc_dai_get_drvdata(dai);
+}
+
+static inline bool is_opened(struct i2s_dai *i2s)
+{
+ if (i2s && (i2s->mode & DAI_OPENED))
+ return true;
+ else
+ return false;
+}
+
+static inline bool is_manager(struct i2s_dai *i2s)
+{
+ if (is_opened(i2s) && (i2s->mode & DAI_MANAGER))
+ return true;
+ else
+ return false;
+}
+
+/* Read RCLK of I2S (in multiples of LRCLK) */
+static inline unsigned get_rfs(struct i2s_dai *i2s)
+{
+ u32 rfs = (readl(i2s->addr + I2SMOD) >> 3) & 0x3;
+
+ switch (rfs) {
+ case 3: return 768;
+ case 2: return 384;
+ case 1: return 512;
+ default: return 256;
+ }
+}
+
+/* Write RCLK of I2S (in multiples of LRCLK) */
+static inline void set_rfs(struct i2s_dai *i2s, unsigned rfs)
+{
+ u32 mod = readl(i2s->addr + I2SMOD);
+
+ mod &= ~MOD_RCLK_MASK;
+
+ switch (rfs) {
+ case 768:
+ mod |= MOD_RCLK_768FS;
+ break;
+ case 512:
+ mod |= MOD_RCLK_512FS;
+ break;
+ case 384:
+ mod |= MOD_RCLK_384FS;
+ break;
+ default:
+ mod |= MOD_RCLK_256FS;
+ break;
+ }
+
+ writel(mod, i2s->addr + I2SMOD);
+}
+
+/* Read Bit-Clock of I2S (in multiples of LRCLK) */
+static inline unsigned get_bfs(struct i2s_dai *i2s)
+{
+ u32 bfs = (readl(i2s->addr + I2SMOD) >> 1) & 0x3;
+
+ switch (bfs) {
+ case 3: return 24;
+ case 2: return 16;
+ case 1: return 48;
+ default: return 32;
+ }
+}
+
+/* Write Bit-Clock of I2S (in multiples of LRCLK) */
+static inline void set_bfs(struct i2s_dai *i2s, unsigned bfs)
+{
+ u32 mod = readl(i2s->addr + I2SMOD);
+
+ mod &= ~MOD_BCLK_MASK;
+
+ switch (bfs) {
+ case 48:
+ mod |= MOD_BCLK_48FS;
+ break;
+ case 32:
+ mod |= MOD_BCLK_32FS;
+ break;
+ case 24:
+ mod |= MOD_BCLK_24FS;
+ break;
+ default:
+ mod |= MOD_BCLK_16FS;
+ break;
+ }
+
+ writel(mod, i2s->addr + I2SMOD);
+}
+
+/* Sample-Size */
+static inline int get_blc(struct i2s_dai *i2s)
+{
+ int blc = readl(i2s->addr + I2SMOD);
+
+ blc = (blc >> 13) & 0x3;
+
+ switch (blc) {
+ case 2: return 24;
+ case 1: return 8;
+ default: return 16;
+ }
+}
+
+/* TX Channel Control */
+static void s3c_i2sv2_txctrl(struct i2s_dai *i2s, int on)
+{
+ void __iomem *addr = i2s->addr;
+ u32 con = readl(addr + I2SCON);
+ u32 mod = readl(addr + I2SMOD) & ~MOD_MASK;
+
+ if (on) {
+ con |= CON_ACTIVE;
+ con &= ~CON_TXCH_PAUSE;
+
+ if (is_secondary(i2s)) {
+ con |= CON_TXSDMA_ACTIVE;
+ con &= ~CON_TXSDMA_PAUSE;
+ } else {
+ con |= CON_TXDMA_ACTIVE;
+ con &= ~CON_TXDMA_PAUSE;
+ }
+
+ if (any_rx_active(i2s))
+ mod |= MOD_TXRX;
+ else
+ mod |= MOD_TXONLY;
+ } else {
+ if (is_secondary(i2s)) {
+ con |= CON_TXSDMA_PAUSE;
+ con &= ~CON_TXSDMA_ACTIVE;
+ } else {
+ con |= CON_TXDMA_PAUSE;
+ con &= ~CON_TXDMA_ACTIVE;
+ }
+
+ if (other_tx_active(i2s)) {
+ writel(con, addr + I2SCON);
+ return;
+ }
+
+ con |= CON_TXCH_PAUSE;
+
+ if (any_rx_active(i2s))
+ mod |= MOD_RXONLY;
+ else
+ con &= ~CON_ACTIVE;
+ }
+
+ writel(mod, addr + I2SMOD);
+ writel(con, addr + I2SCON);
+}
+
+/* RX Channel Control */
+static void s3c_i2sv2_rxctrl(struct i2s_dai *i2s, int on)
+{
+ void __iomem *addr = i2s->addr;
+ u32 con = readl(addr + I2SCON);
+ u32 mod = readl(addr + I2SMOD) & ~MOD_MASK;
+
+ if (on) {
+ con |= CON_RXDMA_ACTIVE | CON_ACTIVE;
+ con &= ~(CON_RXDMA_PAUSE | CON_RXCH_PAUSE);
+
+ if (any_tx_active(i2s))
+ mod |= MOD_TXRX;
+ else
+ mod |= MOD_RXONLY;
+ } else {
+ con |= CON_RXDMA_PAUSE | CON_RXCH_PAUSE;
+ con &= ~CON_RXDMA_ACTIVE;
+
+ if (any_tx_active(i2s))
+ mod |= MOD_TXONLY;
+ else
+ con &= ~CON_ACTIVE;
+ }
+
+ writel(mod, addr + I2SMOD);
+ writel(con, addr + I2SCON);
+}
+
+/* Flush FIFO of an interface */
+static inline void s3c_i2sv2_fifo(struct i2s_dai *i2s, u32 flush)
+{
+ void __iomem *fic;
+ u32 val;
+
+ if (!i2s)
+ return;
+
+ if (is_secondary(i2s))
+ fic = i2s->addr + I2SFICS;
+ else
+ fic = i2s->addr + I2SFIC;
+
+ /* Flush the FIFO */
+ writel(readl(fic) | flush, fic);
+
+ /* Be patient */
+ val = msecs_to_loops(1) / 1000; /* 1 usec */
+ while (--val)
+ cpu_relax();
+
+ writel(readl(fic) & ~flush, fic);
+}
+
+static int s3c_i2sv2_set_sysclk(struct snd_soc_dai *dai,
+ int clk_id, unsigned int rfs, int dir)
+{
+ struct i2s_dai *i2s = to_info(dai);
+ struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
+ u32 mod = readl(i2s->addr + I2SMOD);
+
+ switch (clk_id) {
+ case SAMSUNG_I2S_CDCLK:
+ /* Shouldn't matter in GATING(CLOCK_IN) mode */
+ if (dir == SND_SOC_CLOCK_IN)
+ rfs = 0;
+
+ if ((rfs && other->rfs && (other->rfs != rfs)) ||
+ (any_active(i2s) &&
+ (((dir == SND_SOC_CLOCK_IN)
+ && !(mod & MOD_CDCLKCON)) ||
+ ((dir == SND_SOC_CLOCK_OUT)
+ && (mod & MOD_CDCLKCON))))) {
+ dev_err(&i2s->pdev->dev,
+ "%s:%d Other DAI busy\n", __func__, __LINE__);
+ return -EAGAIN;
+ }
+
+ if (dir == SND_SOC_CLOCK_IN)
+ mod |= MOD_CDCLKCON;
+ else
+ mod &= ~MOD_CDCLKCON;
+
+ i2s->rfs = rfs;
+ break;
+
+ case SAMSUNG_I2S_RCLKSRC_0: /* clock corrsponding to IISMOD[10] := 0 */
+ case SAMSUNG_I2S_RCLKSRC_1: /* clock corrsponding to IISMOD[10] := 1 */
+ if ((i2s->quirks & QUIRK_NO_MUXPSR)
+ || (clk_id == SAMSUNG_I2S_RCLKSRC_0))
+ clk_id = 0;
+ else
+ clk_id = 1;
+
+ if (!any_active(i2s)) {
+ if (i2s->op_clk) {
+ if ((clk_id && !(mod & MOD_IMS_SYSMUX)) ||
+ (!clk_id && (mod & MOD_IMS_SYSMUX))) {
+ clk_disable(i2s->op_clk);
+ clk_put(i2s->op_clk);
+ } else {
+ return 0;
+ }
+ }
+
+ i2s->op_clk = clk_get(&i2s->pdev->dev,
+ i2s->src_clk[clk_id]);
+ clk_enable(i2s->op_clk);
+ i2s->rclk_srcrate = clk_get_rate(i2s->op_clk);
+
+ /* Over-ride the other's */
+ if (other) {
+ other->op_clk = i2s->op_clk;
+ other->rclk_srcrate = i2s->rclk_srcrate;
+ }
+ } else if ((!clk_id && (mod & MOD_IMS_SYSMUX))
+ || (clk_id && !(mod & MOD_IMS_SYSMUX))) {
+ dev_err(&i2s->pdev->dev,
+ "%s:%d Other DAI busy\n", __func__, __LINE__);
+ return -EAGAIN;
+ } else {
+ /* Call can't be on the active DAI */
+ i2s->op_clk = other->op_clk;
+ i2s->rclk_srcrate = other->rclk_srcrate;
+ return 0;
+ }
+
+ if (clk_id == 0)
+ mod &= ~MOD_IMS_SYSMUX;
+ else
+ mod |= MOD_IMS_SYSMUX;
+ break;
+
+ default:
+ dev_err(&i2s->pdev->dev, "We don't serve that!\n");
+ return -EINVAL;
+ }
+
+ writel(mod, i2s->addr + I2SMOD);
+
+ return 0;
+}
+
+static int i2sv2_i2s_set_fmt(struct snd_soc_dai *dai,
+ unsigned int fmt)
+{
+ struct i2s_dai *i2s = to_info(dai);
+ u32 mod = readl(i2s->addr + I2SMOD);
+ u32 tmp = 0;
+
+ /* Format is priority */
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_RIGHT_J:
+ tmp |= MOD_LR_RLOW;
+ tmp |= MOD_SDF_MSB;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ tmp |= MOD_LR_RLOW;
+ tmp |= MOD_SDF_LSB;
+ break;
+ case SND_SOC_DAIFMT_I2S:
+ tmp |= MOD_SDF_IIS;
+ break;
+ default:
+ dev_err(&i2s->pdev->dev, "Format not supported\n");
+ return -EINVAL;
+ }
+
+ /* Allow LRCLK-inverted version of the supported formats */
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ if (tmp & MOD_LR_RLOW)
+ tmp &= ~MOD_LR_RLOW;
+ else
+ tmp |= MOD_LR_RLOW;
+ break;
+ default:
+ dev_err(&i2s->pdev->dev, "Polarity not supported\n");
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ tmp |= MOD_SLAVE;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ /* Set default source clock in Master mode */
+ if (i2s->rclk_srcrate == 0)
+ s3c_i2sv2_set_sysclk(dai, SAMSUNG_I2S_RCLKSRC_0,
+ 0, SND_SOC_CLOCK_IN);
+ break;
+ default:
+ dev_err(&i2s->pdev->dev, "master/slave format not supported\n");
+ return -EINVAL;
+ }
+
+ if (any_active(i2s) &&
+ ((mod & (MOD_SDF_MASK | MOD_LR_RLOW
+ | MOD_SLAVE)) != tmp)) {
+ dev_err(&i2s->pdev->dev,
+ "%s:%d Other DAI busy\n", __func__, __LINE__);
+ return -EAGAIN;
+ }
+
+ mod &= ~(MOD_SDF_MASK | MOD_LR_RLOW | MOD_SLAVE);
+ mod |= tmp;
+ writel(mod, i2s->addr + I2SMOD);
+
+ return 0;
+}
+
+static int s3c_i2sv2_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+ struct i2s_dai *i2s = to_info(dai);
+ u32 mod = readl(i2s->addr + I2SMOD);
+
+ if (!is_secondary(i2s))
+ mod &= ~(MOD_DC2_EN | MOD_DC1_EN);
+
+ switch (params_channels(params)) {
+ case 6:
+ mod |= MOD_DC2_EN;
+ case 4:
+ mod |= MOD_DC1_EN;
+ break;
+ case 2:
+ break;
+ default:
+ dev_err(&i2s->pdev->dev, "%d channels not supported\n",
+ params_channels(params));
+ return -EINVAL;
+ }
+
+ if (is_secondary(i2s))
+ mod &= ~MOD_BLCS_MASK;
+ else
+ mod &= ~MOD_BLCP_MASK;
+
+ if (is_manager(i2s))
+ mod &= ~MOD_BLC_MASK;
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S8:
+ if (is_secondary(i2s))
+ mod |= MOD_BLCS_8BIT;
+ else
+ mod |= MOD_BLCP_8BIT;
+ if (is_manager(i2s))
+ mod |= MOD_BLC_8BIT;
+ break;
+ case SNDRV_PCM_FORMAT_S16_LE:
+ if (is_secondary(i2s))
+ mod |= MOD_BLCS_16BIT;
+ else
+ mod |= MOD_BLCP_16BIT;
+ if (is_manager(i2s))
+ mod |= MOD_BLC_16BIT;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ if (is_secondary(i2s))
+ mod |= MOD_BLCS_24BIT;
+ else
+ mod |= MOD_BLCP_24BIT;
+ if (is_manager(i2s))
+ mod |= MOD_BLC_24BIT;
+ break;
+ default:
+ dev_err(&i2s->pdev->dev, "Format(%d) not supported\n",
+ params_format(params));
+ return -EINVAL;
+ }
+ writel(mod, i2s->addr + I2SMOD);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ snd_soc_dai_set_dma_data(dai, substream,
+ (void *)&i2s->dma_playback);
+ else
+ snd_soc_dai_set_dma_data(dai, substream,
+ (void *)&i2s->dma_capture);
+
+ i2s->frmclk = params_rate(params);
+
+ return 0;
+}
+
+/* We set constraints on the substream acc to the version of I2S */
+static int s3c_i2sv2_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct i2s_dai *i2s = to_info(dai);
+ struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
+ unsigned long flags;
+
+ spin_lock_irqsave(&lock, flags);
+
+ i2s->mode |= DAI_OPENED;
+
+ if (is_manager(other))
+ i2s->mode &= ~DAI_MANAGER;
+ else
+ i2s->mode |= DAI_MANAGER;
+
+ /* Enforce set_sysclk in Master mode */
+ i2s->rclk_srcrate = 0;
+
+ spin_unlock_irqrestore(&lock, flags);
+
+ return 0;
+}
+
+static void s3c_i2sv2_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct i2s_dai *i2s = to_info(dai);
+ struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
+ unsigned long flags;
+
+ spin_lock_irqsave(&lock, flags);
+
+ i2s->mode &= ~DAI_OPENED;
+ i2s->mode &= ~DAI_MANAGER;
+
+ if (is_opened(other))
+ other->mode |= DAI_MANAGER;
+
+ /* Reset any constraint on RFS and BFS */
+ i2s->rfs = 0;
+ i2s->bfs = 0;
+
+ spin_unlock_irqrestore(&lock, flags);
+
+ /* Gate CDCLK by default */
+ if (!is_opened(other))
+ s3c_i2sv2_set_sysclk(dai, SAMSUNG_I2S_CDCLK,
+ 0, SND_SOC_CLOCK_IN);
+}
+
+static int config_setup(struct i2s_dai *i2s)
+{
+ struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
+ unsigned rfs, bfs, blc;
+ u32 psr;
+
+ blc = get_blc(i2s);
+
+ bfs = i2s->bfs;
+
+ if (!bfs && other)
+ bfs = other->bfs;
+
+ /* Select least possible multiple(2) if no constraint set */
+ if (!bfs)
+ bfs = blc * 2;
+
+ rfs = i2s->rfs;
+
+ if (!rfs && other)
+ rfs = other->rfs;
+
+ if ((rfs == 256 || rfs == 512) && (blc == 24)) {
+ dev_err(&i2s->pdev->dev,
+ "%d-RFS not supported for 24-blc\n", rfs);
+ return -EINVAL;
+ }
+
+ if (!rfs) {
+ if (bfs == 16 || bfs == 32)
+ rfs = 256;
+ else
+ rfs = 384;
+ }
+
+ /* If already setup and running */
+ if (any_active(i2s) && (get_rfs(i2s) != rfs || get_bfs(i2s) != bfs)) {
+ dev_err(&i2s->pdev->dev,
+ "%s:%d Other DAI busy\n", __func__, __LINE__);
+ return -EAGAIN;
+ }
+
+ /* We don't care about BFS in Slave mode */
+ if (is_slave(i2s))
+ return 0;
+
+ set_bfs(i2s, bfs);
+ set_rfs(i2s, rfs);
+
+ if (!(i2s->quirks & QUIRK_NO_MUXPSR)) {
+ psr = i2s->rclk_srcrate / i2s->frmclk / rfs;
+ writel(((psr - 1) << 8) | PSR_PSREN, i2s->addr + I2SPSR);
+ dev_dbg(&i2s->pdev->dev,
+ "RCLK_SRC=%luHz PSR=%u, RCLK=%dfs, BCLK=%dfs\n",
+ i2s->rclk_srcrate, psr, rfs, bfs);
+ }
+
+ return 0;
+}
+
+static int i2sv2_i2s_trigger(struct snd_pcm_substream *substream,
+ int cmd, struct snd_soc_dai *dai)
+{
+ int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct i2s_dai *i2s = to_info(rtd->cpu_dai);
+ unsigned long flags;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ local_irq_save(flags);
+
+ if (capture)
+ s3c_i2sv2_fifo(i2s, FIC_RXFLUSH);
+ else
+ s3c_i2sv2_fifo(i2s, FIC_TXFLUSH);
+
+ if (config_setup(i2s)) {
+ local_irq_restore(flags);
+ return -EINVAL;
+ }
+
+ if (capture)
+ s3c_i2sv2_rxctrl(i2s, 1);
+ else
+ s3c_i2sv2_txctrl(i2s, 1);
+
+ local_irq_restore(flags);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ local_irq_save(flags);
+
+ if (capture)
+ s3c_i2sv2_rxctrl(i2s, 0);
+ else
+ s3c_i2sv2_txctrl(i2s, 0);
+
+ local_irq_restore(flags);
+ break;
+ }
+
+ return 0;
+}
+
+static int i2sv2_i2s_set_clkdiv(struct snd_soc_dai *dai,
+ int div_id, int div)
+{
+ struct i2s_dai *i2s = to_info(dai);
+ struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
+
+ if (div_id == SAMSUNG_I2S_DIV_BCLK) {
+ if ((any_active(i2s) && div && (get_bfs(i2s) != div))
+ || (other && other->bfs && (other->bfs != div))) {
+ dev_err(&i2s->pdev->dev,
+ "%s:%d Other DAI busy\n", __func__, __LINE__);
+ return -EAGAIN;
+ }
+ i2s->bfs = div;
+ } else {
+ dev_err(&i2s->pdev->dev,
+ "Invalid clock divider(%d)\n", div_id);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static snd_pcm_sframes_t
+i2sv2_i2s_delay(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
+{
+ struct i2s_dai *i2s = to_info(dai);
+ u32 reg = readl(i2s->addr + I2SFIC);
+ snd_pcm_sframes_t delay;
+
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ delay = FIC_RXCOUNT(reg);
+ else if (is_secondary(i2s))
+ delay = FICS_TXCOUNT(readl(i2s->addr + I2SFICS));
+ else
+ delay = FIC_TXCOUNT(reg);
+
+ return delay;
+}
+
+#ifdef CONFIG_PM
+static int i2sv2_i2s_suspend(struct snd_soc_dai *dai)
+{
+ struct i2s_dai *i2s = to_info(dai);
+
+ if (dai->active) {
+ i2s->suspend_i2smod = readl(i2s->addr + I2SMOD);
+ i2s->suspend_i2scon = readl(i2s->addr + I2SCON);
+ i2s->suspend_i2spsr = readl(i2s->addr + I2SPSR);
+ }
+
+ return 0;
+}
+
+static int i2sv2_i2s_resume(struct snd_soc_dai *dai)
+{
+ struct i2s_dai *i2s = to_info(dai);
+
+ if (dai->active) {
+ writel(i2s->suspend_i2scon, i2s->addr + I2SCON);
+ writel(i2s->suspend_i2smod, i2s->addr + I2SMOD);
+ writel(i2s->suspend_i2spsr, i2s->addr + I2SPSR);
+ }
+
+ return 0;
+}
+#else
+#define i2sv2_i2s_suspend NULL
+#define i2sv2_i2s_resume NULL
+#endif
+
+static int samsung_i2s_dai_probe(struct snd_soc_dai *dai)
+{
+ struct i2s_dai *i2s = to_info(dai);
+ struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
+
+ if (other && other->clk) /* If this is probe on secondary */
+ goto probe_exit;
+
+ i2s->addr = ioremap(i2s->base, 0x100);
+ if (i2s->addr == NULL) {
+ dev_err(&i2s->pdev->dev, "cannot ioremap registers\n");
+ return -ENXIO;
+ }
+
+ i2s->clk = clk_get(&i2s->pdev->dev, "iis");
+ if (IS_ERR(i2s->clk)) {
+ dev_err(&i2s->pdev->dev, "failed to get i2s_clock\n");
+ iounmap(i2s->addr);
+ return -ENOENT;
+ }
+ clk_enable(i2s->clk);
+
+ if (other) {
+ other->addr = i2s->addr;
+ other->clk = i2s->clk;
+ }
+
+ if (i2s->quirks & QUIRK_NEED_RSTCLR)
+ writel(CON_RSTCLR, i2s->addr + I2SCON);
+
+probe_exit:
+ /* Reset any constraint on RFS and BFS */
+ i2s->rfs = 0;
+ i2s->bfs = 0;
+ s3c_i2sv2_txctrl(i2s, 0);
+ s3c_i2sv2_rxctrl(i2s, 0);
+ s3c_i2sv2_fifo(i2s, FIC_TXFLUSH);
+ s3c_i2sv2_fifo(other, FIC_TXFLUSH);
+ s3c_i2sv2_fifo(i2s, FIC_RXFLUSH);
+
+ /* Gate CDCLK by default */
+ if (!is_opened(other))
+ s3c_i2sv2_set_sysclk(dai, SAMSUNG_I2S_CDCLK,
+ 0, SND_SOC_CLOCK_IN);
+
+ return 0;
+}
+
+static int samsung_i2s_dai_remove(struct snd_soc_dai *dai)
+{
+ struct i2s_dai *i2s = snd_soc_dai_get_drvdata(dai);
+ struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
+
+ if (!other || !other->clk) {
+
+ if (i2s->quirks & QUIRK_NEED_RSTCLR)
+ writel(0, i2s->addr + I2SCON);
+
+ clk_disable(i2s->clk);
+ clk_put(i2s->clk);
+
+ iounmap(i2s->addr);
+ }
+
+ i2s->clk = NULL;
+
+ return 0;
+}
+
+static struct snd_soc_dai_ops samsung_i2s_dai_ops = {
+ .trigger = i2sv2_i2s_trigger,
+ .hw_params = s3c_i2sv2_hw_params,
+ .set_fmt = i2sv2_i2s_set_fmt,
+ .set_clkdiv = i2sv2_i2s_set_clkdiv,
+ .set_sysclk = s3c_i2sv2_set_sysclk,
+ .startup = s3c_i2sv2_startup,
+ .shutdown = s3c_i2sv2_shutdown,
+ .delay = i2sv2_i2s_delay,
+};
+
+#define SAMSUNG_I2S_RATES \
+ (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \
+ SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
+ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
+
+#define SAMSUNG_I2S_FMTS \
+ (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |\
+ SNDRV_PCM_FMTBIT_S24_LE)
+
+static __devinit
+struct i2s_dai *s3c_alloc_dai(struct platform_device *pdev, bool sec)
+{
+ struct i2s_dai *i2s;
+
+ i2s = kzalloc(sizeof(struct i2s_dai), GFP_KERNEL);
+ if (i2s == NULL)
+ return NULL;
+
+ i2s->pdev = pdev;
+ i2s->pri_dai = NULL;
+ i2s->sec_dai = NULL;
+ i2s->s3c_i2s_drv.symmetric_rates = 1;
+ i2s->s3c_i2s_drv.probe = samsung_i2s_dai_probe;
+ i2s->s3c_i2s_drv.remove = samsung_i2s_dai_remove;
+ i2s->s3c_i2s_drv.ops = &samsung_i2s_dai_ops;
+ i2s->s3c_i2s_drv.suspend = i2sv2_i2s_suspend;
+ i2s->s3c_i2s_drv.resume = i2sv2_i2s_resume;
+ i2s->s3c_i2s_drv.playback.channels_min = 2;
+ i2s->s3c_i2s_drv.playback.channels_max = 2;
+ i2s->s3c_i2s_drv.playback.rates = SAMSUNG_I2S_RATES;
+ i2s->s3c_i2s_drv.playback.formats = SAMSUNG_I2S_FMTS;
+
+ if (!sec) {
+ i2s->s3c_i2s_drv.capture.channels_min = 2;
+ i2s->s3c_i2s_drv.capture.channels_max = 2;
+ i2s->s3c_i2s_drv.capture.rates = SAMSUNG_I2S_RATES;
+ i2s->s3c_i2s_drv.capture.formats = SAMSUNG_I2S_FMTS;
+ } else { /* Create a new platform_device for Secondary */
+ i2s->pdev = platform_device_register_resndata(NULL,
+ pdev->name, pdev->id + MAX_I2S,
+ NULL, 0, NULL, 0);
+ if (IS_ERR(i2s->pdev)) {
+ kfree(i2s);
+ return NULL;
+ }
+ }
+
+ /* Pre-assign snd_soc_dai_set_drvdata */
+ dev_set_drvdata(&i2s->pdev->dev, i2s);
+
+ return i2s;
+}
+
+static __devinit int samsung_i2s_probe(struct platform_device *pdev)
+{
+ u32 dma_pl_chan, dma_cp_chan, dma_pl_sec_chan;
+ struct i2s_dai *pri_dai, *sec_dai = NULL;
+ struct s3c_audio_pdata *i2s_pdata;
+ struct samsung_i2s *i2s_cfg;
+ struct resource *res;
+ u32 regs_base, quirks;
+ int ret = 0;
+
+ /* Call during Seconday interface registration */
+ if (pdev->id >= MAX_I2S) {
+ sec_dai = dev_get_drvdata(&pdev->dev);
+ snd_soc_register_dai(&sec_dai->pdev->dev,
+ &sec_dai->s3c_i2s_drv);
+ return 0;
+ }
+
+ i2s_pdata = pdev->dev.platform_data;
+ if (i2s_pdata == NULL) {
+ dev_err(&pdev->dev, "Can't work without s3c_audio_pdata\n");
+ return -EINVAL;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "Unable to get I2S-TX dma resource\n");
+ return -ENXIO;
+ }
+ dma_pl_chan = res->start;
+
+ res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+ if (!res) {
+ dev_err(&pdev->dev, "Unable to get I2S-RX dma resource\n");
+ return -ENXIO;
+ }
+ dma_cp_chan = res->start;
+
+ res = platform_get_resource(pdev, IORESOURCE_DMA, 2);
+ if (res)
+ dma_pl_sec_chan = res->start;
+ else
+ dma_pl_sec_chan = 0;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "Unable to get I2S SFR address\n");
+ return -ENXIO;
+ }
+
+ if (!request_mem_region(res->start, resource_size(res),
+ "samsung-i2s")) {
+ dev_err(&pdev->dev, "Unable to request SFR region\n");
+ return -EBUSY;
+ }
+ regs_base = res->start;
+
+ i2s_cfg = &i2s_pdata->type.i2s;
+ quirks = i2s_cfg->quirks;
+
+ pri_dai = s3c_alloc_dai(pdev, false);
+ if (!pri_dai) {
+ dev_err(&pdev->dev, "Unable to alloc I2S_pri\n");
+ ret = -ENOMEM;
+ goto err1;
+ }
+
+ pri_dai->dma_playback.dma_addr = regs_base + I2STXD;
+ pri_dai->dma_capture.dma_addr = regs_base + I2SRXD;
+ pri_dai->dma_playback.client =
+ (struct s3c2410_dma_client *)&pri_dai->dma_playback;
+ pri_dai->dma_capture.client =
+ (struct s3c2410_dma_client *)&pri_dai->dma_capture;
+ pri_dai->dma_playback.channel = dma_pl_chan;
+ pri_dai->dma_capture.channel = dma_cp_chan;
+ pri_dai->src_clk = i2s_cfg->src_clk;
+ pri_dai->dma_playback.dma_size = 4;
+ pri_dai->dma_capture.dma_size = 4;
+ pri_dai->base = regs_base;
+ pri_dai->quirks = quirks;
+
+ if (quirks & QUIRK_PRI_6CHAN)
+ pri_dai->s3c_i2s_drv.playback.channels_max = 6;
+
+ if (quirks & QUIRK_SEC_DAI) {
+ sec_dai = s3c_alloc_dai(pdev, true);
+ if (!sec_dai) {
+ dev_err(&pdev->dev, "Unable to alloc I2S_sec\n");
+ ret = -ENOMEM;
+ goto err2;
+ }
+ sec_dai->dma_playback.dma_addr = regs_base + I2STXDS;
+ sec_dai->dma_playback.client =
+ (struct s3c2410_dma_client *)&sec_dai->dma_playback;
+ /* Use iDMA always if SysDMA not provided */
+ sec_dai->dma_playback.channel = dma_pl_sec_chan ? : -1;
+ sec_dai->src_clk = i2s_cfg->src_clk;
+ sec_dai->dma_playback.dma_size = 4;
+ sec_dai->base = regs_base;
+ sec_dai->quirks = quirks;
+ sec_dai->pri_dai = pri_dai;
+ pri_dai->sec_dai = sec_dai;
+ }
+
+ if (i2s_pdata->cfg_gpio && i2s_pdata->cfg_gpio(pdev)) {
+ dev_err(&pdev->dev, "Unable to configure gpio\n");
+ ret = -EINVAL;
+ goto err3;
+ }
+
+ snd_soc_register_dai(&pri_dai->pdev->dev, &pri_dai->s3c_i2s_drv);
+
+ return 0;
+err3:
+ kfree(sec_dai);
+err2:
+ kfree(pri_dai);
+err1:
+ release_mem_region(regs_base, resource_size(res));
+
+ return ret;
+}
+
+static __devexit int samsung_i2s_remove(struct platform_device *pdev)
+{
+ struct i2s_dai *i2s, *other;
+
+ i2s = dev_get_drvdata(&pdev->dev);
+ other = i2s->pri_dai ? : i2s->sec_dai;
+
+ if (other) {
+ other->pri_dai = NULL;
+ other->sec_dai = NULL;
+ } else {
+ struct resource *res;
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res)
+ release_mem_region(res->start, resource_size(res));
+ }
+
+ i2s->pri_dai = NULL;
+ i2s->sec_dai = NULL;
+
+ kfree(i2s);
+
+ snd_soc_unregister_dai(&pdev->dev);
+
+ return 0;
+}
+
+static struct platform_driver samsung_i2s_driver = {
+ .probe = samsung_i2s_probe,
+ .remove = samsung_i2s_remove,
+ .driver = {
+ .name = "samsung-i2s",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init samsung_i2s_init(void)
+{
+ return platform_driver_register(&samsung_i2s_driver);
+}
+module_init(samsung_i2s_init);
+
+static void __exit samsung_i2s_exit(void)
+{
+ platform_driver_unregister(&samsung_i2s_driver);
+}
+module_exit(samsung_i2s_exit);
+
+/* Module information */
+MODULE_AUTHOR("Jaswinder Singh, <jassi.brar(a)samsung.com>");
+MODULE_DESCRIPTION("Samsung I2S Interface");
+MODULE_ALIAS("platform:samsung-i2s");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/samsung/i2s.h b/sound/soc/samsung/i2s.h
new file mode 100644
index 0000000..73a71cd
--- /dev/null
+++ b/sound/soc/samsung/i2s.h
@@ -0,0 +1,29 @@
+/* sound/soc/samsung/i2s.h
+ *
+ * ALSA SoC Audio Layer - Samsung I2S Controller driver
+ *
+ * Copyright (c) 2010 Samsung Electronics Co. Ltd.
+ * Jaswinder Singh <jassi.brar(a)samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __SND_SOC_SAMSUNG_I2S_H
+#define __SND_SOC_SAMSUNG_I2S_H
+
+/*
+ * Maximum number of I2S blocks that any SoC can have.
+ * The secondary interface of a CPU dai(if there exists any),
+ * is indexed at [cpu-dai's ID + MAX_I2S]
+ */
+#define MAX_I2S 4
+
+#define SAMSUNG_I2S_DIV_BCLK 1
+
+#define SAMSUNG_I2S_RCLKSRC_0 0
+#define SAMSUNG_I2S_RCLKSRC_1 1
+#define SAMSUNG_I2S_CDCLK 2
+
+#endif /* __SND_SOC_SAMSUNG_I2S_H */
diff --git a/sound/soc/samsung/jive_wm8750.c b/sound/soc/samsung/jive_wm8750.c
new file mode 100644
index 0000000..fe1649e
--- /dev/null
+++ b/sound/soc/samsung/jive_wm8750.c
@@ -0,0 +1,191 @@
+/* sound/soc/samsung/jive_wm8750.c
+ *
+ * Copyright 2007,2008 Simtec Electronics
+ *
+ * Based on sound/soc/pxa/spitz.c
+ * Copyright 2005 Wolfson Microelectronics PLC.
+ * Copyright 2005 Openedhand Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include <asm/mach-types.h>
+
+#include "dma.h"
+#include "s3c2412-i2s.h"
+
+#include "../codecs/wm8750.h"
+
+static const struct snd_soc_dapm_route audio_map[] = {
+ { "Headphone Jack", NULL, "LOUT1" },
+ { "Headphone Jack", NULL, "ROUT1" },
+ { "Internal Speaker", NULL, "LOUT2" },
+ { "Internal Speaker", NULL, "ROUT2" },
+ { "LINPUT1", NULL, "Line Input" },
+ { "RINPUT1", NULL, "Line Input" },
+};
+
+static const struct snd_soc_dapm_widget wm8750_dapm_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
+ SND_SOC_DAPM_SPK("Internal Speaker", NULL),
+ SND_SOC_DAPM_LINE("Line In", NULL),
+};
+
+static int jive_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct s3c_i2sv2_rate_calc div;
+ unsigned int clk = 0;
+ int ret = 0;
+
+ switch (params_rate(params)) {
+ case 8000:
+ case 16000:
+ case 48000:
+ case 96000:
+ clk = 12288000;
+ break;
+ case 11025:
+ case 22050:
+ case 44100:
+ clk = 11289600;
+ break;
+ }
+
+ s3c_i2sv2_iis_calc_rate(&div, NULL, params_rate(params),
+ s3c_i2sv2_get_clock(cpu_dai));
+
+ /* set codec DAI configuration */
+ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBS_CFS);
+ if (ret < 0)
+ return ret;
+
+ /* set cpu DAI configuration */
+ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBS_CFS);
+ if (ret < 0)
+ return ret;
+
+ /* set the codec system clock for DAC and ADC */
+ ret = snd_soc_dai_set_sysclk(codec_dai, WM8750_SYSCLK, clk,
+ SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C2412_DIV_RCLK, div.fs_div);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C2412_DIV_PRESCALER,
+ div.clk_div - 1);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static struct snd_soc_ops jive_ops = {
+ .hw_params = jive_hw_params,
+};
+
+static int jive_wm8750_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_codec *codec = rtd->codec;
+ int err;
+
+ /* These endpoints are not being used. */
+ snd_soc_dapm_nc_pin(codec, "LINPUT2");
+ snd_soc_dapm_nc_pin(codec, "RINPUT2");
+ snd_soc_dapm_nc_pin(codec, "LINPUT3");
+ snd_soc_dapm_nc_pin(codec, "RINPUT3");
+ snd_soc_dapm_nc_pin(codec, "OUT3");
+ snd_soc_dapm_nc_pin(codec, "MONO");
+
+ /* Add jive specific widgets */
+ err = snd_soc_dapm_new_controls(codec, wm8750_dapm_widgets,
+ ARRAY_SIZE(wm8750_dapm_widgets));
+ if (err) {
+ printk(KERN_ERR "%s: failed to add widgets (%d)\n",
+ __func__, err);
+ return err;
+ }
+
+ snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+ snd_soc_dapm_sync(codec);
+
+ return 0;
+}
+
+static struct snd_soc_dai_link jive_dai = {
+ .name = "wm8750",
+ .stream_name = "WM8750",
+ .cpu_dai_name = "s3c2412-i2s",
+ .codec_dai_name = "wm8750-hifi",
+ .platform_name = "samsung-audio",
+ .codec_name = "wm8750-codec.0-0x1a",
+ .init = jive_wm8750_init,
+ .ops = &jive_ops,
+};
+
+/* jive audio machine driver */
+static struct snd_soc_card snd_soc_machine_jive = {
+ .name = "Jive",
+ .dai_link = &jive_dai,
+ .num_links = 1,
+};
+
+static struct platform_device *jive_snd_device;
+
+static int __init jive_init(void)
+{
+ int ret;
+
+ if (!machine_is_jive())
+ return 0;
+
+ printk("JIVE WM8750 Audio support\n");
+
+ jive_snd_device = platform_device_alloc("soc-audio", -1);
+ if (!jive_snd_device)
+ return -ENOMEM;
+
+ platform_set_drvdata(jive_snd_device, &snd_soc_machine_jive);
+ ret = platform_device_add(jive_snd_device);
+
+ if (ret)
+ platform_device_put(jive_snd_device);
+
+ return ret;
+}
+
+static void __exit jive_exit(void)
+{
+ platform_device_unregister(jive_snd_device);
+}
+
+module_init(jive_init);
+module_exit(jive_exit);
+
+MODULE_AUTHOR("Ben Dooks <ben(a)simtec.co.uk>");
+MODULE_DESCRIPTION("ALSA SoC Jive Audio support");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/samsung/lm4857.h b/sound/soc/samsung/lm4857.h
new file mode 100644
index 0000000..0cf5b70
--- /dev/null
+++ b/sound/soc/samsung/lm4857.h
@@ -0,0 +1,32 @@
+/*
+ * lm4857.h -- ALSA Soc Audio Layer
+ *
+ * Copyright 2007 Wolfson Microelectronics PLC.
+ * Author: Graeme Gregory
+ * graeme.gregory(a)wolfsonmicro.com or linux(a)wolfsonmicro.com
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * Revision history
+ * 18th Jun 2007 Initial version.
+ */
+
+#ifndef LM4857_H_
+#define LM4857_H_
+
+/* The register offsets in the cache array */
+#define LM4857_MVOL 0
+#define LM4857_LVOL 1
+#define LM4857_RVOL 2
+#define LM4857_CTRL 3
+
+/* the shifts required to set these bits */
+#define LM4857_3D 5
+#define LM4857_WAKEUP 5
+#define LM4857_EPGAIN 4
+
+#endif /*LM4857_H_*/
+
diff --git a/sound/soc/samsung/ln2440sbc_alc650.c b/sound/soc/samsung/ln2440sbc_alc650.c
new file mode 100644
index 0000000..e507174
--- /dev/null
+++ b/sound/soc/samsung/ln2440sbc_alc650.c
@@ -0,0 +1,78 @@
+/*
+ * SoC audio for ln2440sbc
+ *
+ * Copyright 2007 KonekTel, a.s.
+ * Author: Ivan Kuten
+ * ivan.kuten(a)promwad.com
+ *
+ * Heavily based on smdk2443_wm9710.c
+ * Copyright 2007 Wolfson Microelectronics PLC.
+ * Author: Graeme Gregory
+ * graeme.gregory(a)wolfsonmicro.com or linux(a)wolfsonmicro.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include "dma.h"
+#include "ac97.h"
+
+static struct snd_soc_card ln2440sbc;
+
+static struct snd_soc_dai_link ln2440sbc_dai[] = {
+{
+ .name = "AC97",
+ .stream_name = "AC97 HiFi",
+ .cpu_dai_name = "samsung-ac97",
+ .codec_dai_name = "ac97-hifi",
+ .codec_name = "ac97-codec",
+ .platform_name = "samsung-audio",
+},
+};
+
+static struct snd_soc_card ln2440sbc = {
+ .name = "LN2440SBC",
+ .dai_link = ln2440sbc_dai,
+ .num_links = ARRAY_SIZE(ln2440sbc_dai),
+};
+
+static struct platform_device *ln2440sbc_snd_ac97_device;
+
+static int __init ln2440sbc_init(void)
+{
+ int ret;
+
+ ln2440sbc_snd_ac97_device = platform_device_alloc("soc-audio", -1);
+ if (!ln2440sbc_snd_ac97_device)
+ return -ENOMEM;
+
+ platform_set_drvdata(ln2440sbc_snd_ac97_device, &ln2440sbc);
+ ret = platform_device_add(ln2440sbc_snd_ac97_device);
+
+ if (ret)
+ platform_device_put(ln2440sbc_snd_ac97_device);
+
+ return ret;
+}
+
+static void __exit ln2440sbc_exit(void)
+{
+ platform_device_unregister(ln2440sbc_snd_ac97_device);
+}
+
+module_init(ln2440sbc_init);
+module_exit(ln2440sbc_exit);
+
+/* Module information */
+MODULE_AUTHOR("Ivan Kuten");
+MODULE_DESCRIPTION("ALSA SoC ALC650 LN2440SBC");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/samsung/neo1973_gta02_wm8753.c b/sound/soc/samsung/neo1973_gta02_wm8753.c
new file mode 100644
index 0000000..c4b2013
--- /dev/null
+++ b/sound/soc/samsung/neo1973_gta02_wm8753.c
@@ -0,0 +1,504 @@
+/*
+ * neo1973_gta02_wm8753.c -- SoC audio for Openmoko Freerunner(GTA02)
+ *
+ * Copyright 2007 Openmoko Inc
+ * Author: Graeme Gregory <graeme(a)openmoko.org>
+ * Copyright 2007 Wolfson Microelectronics PLC.
+ * Author: Graeme Gregory <linux(a)wolfsonmicro.com>
+ * Copyright 2009 Wolfson Microelectronics
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include <asm/mach-types.h>
+
+#include <plat/regs-iis.h>
+
+#include <mach/regs-clock.h>
+#include <asm/io.h>
+#include <mach/gta02.h>
+#include "../codecs/wm8753.h"
+#include "dma.h"
+#include "s3c24xx-i2s.h"
+
+static struct snd_soc_card neo1973_gta02;
+
+static int neo1973_gta02_hifi_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ unsigned int pll_out = 0, bclk = 0;
+ int ret = 0;
+ unsigned long iis_clkrate;
+
+ iis_clkrate = s3c24xx_i2s_get_clockrate();
+
+ switch (params_rate(params)) {
+ case 8000:
+ case 16000:
+ pll_out = 12288000;
+ break;
+ case 48000:
+ bclk = WM8753_BCLK_DIV_4;
+ pll_out = 12288000;
+ break;
+ case 96000:
+ bclk = WM8753_BCLK_DIV_2;
+ pll_out = 12288000;
+ break;
+ case 11025:
+ bclk = WM8753_BCLK_DIV_16;
+ pll_out = 11289600;
+ break;
+ case 22050:
+ bclk = WM8753_BCLK_DIV_8;
+ pll_out = 11289600;
+ break;
+ case 44100:
+ bclk = WM8753_BCLK_DIV_4;
+ pll_out = 11289600;
+ break;
+ case 88200:
+ bclk = WM8753_BCLK_DIV_2;
+ pll_out = 11289600;
+ break;
+ }
+
+ /* set codec DAI configuration */
+ ret = snd_soc_dai_set_fmt(codec_dai,
+ SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBM_CFM);
+ if (ret < 0)
+ return ret;
+
+ /* set cpu DAI configuration */
+ ret = snd_soc_dai_set_fmt(cpu_dai,
+ SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBM_CFM);
+ if (ret < 0)
+ return ret;
+
+ /* set the codec system clock for DAC and ADC */
+ ret = snd_soc_dai_set_sysclk(codec_dai, WM8753_MCLK, pll_out,
+ SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ return ret;
+
+ /* set MCLK division for sample rate */
+ ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK,
+ S3C2410_IISMOD_32FS);
+ if (ret < 0)
+ return ret;
+
+ /* set codec BCLK division for sample rate */
+ ret = snd_soc_dai_set_clkdiv(codec_dai,
+ WM8753_BCLKDIV, bclk);
+ if (ret < 0)
+ return ret;
+
+ /* set prescaler division for sample rate */
+ ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER,
+ S3C24XX_PRESCALE(4, 4));
+ if (ret < 0)
+ return ret;
+
+ /* codec PLL input is PCLK/4 */
+ ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0,
+ iis_clkrate / 4, pll_out);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int neo1973_gta02_hifi_hw_free(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+
+ /* disable the PLL */
+ return snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, 0, 0);
+}
+
+/*
+ * Neo1973 WM8753 HiFi DAI opserations.
+ */
+static struct snd_soc_ops neo1973_gta02_hifi_ops = {
+ .hw_params = neo1973_gta02_hifi_hw_params,
+ .hw_free = neo1973_gta02_hifi_hw_free,
+};
+
+static int neo1973_gta02_voice_hw_params(
+ struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ unsigned int pcmdiv = 0;
+ int ret = 0;
+ unsigned long iis_clkrate;
+
+ iis_clkrate = s3c24xx_i2s_get_clockrate();
+
+ if (params_rate(params) != 8000)
+ return -EINVAL;
+ if (params_channels(params) != 1)
+ return -EINVAL;
+
+ pcmdiv = WM8753_PCM_DIV_6; /* 2.048 MHz */
+
+ /* todo: gg check mode (DSP_B) against CSR datasheet */
+ /* set codec DAI configuration */
+ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_B |
+ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+ if (ret < 0)
+ return ret;
+
+ /* set the codec system clock for DAC and ADC */
+ ret = snd_soc_dai_set_sysclk(codec_dai, WM8753_PCMCLK,
+ 12288000, SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ return ret;
+
+ /* set codec PCM division for sample rate */
+ ret = snd_soc_dai_set_clkdiv(codec_dai, WM8753_PCMDIV,
+ pcmdiv);
+ if (ret < 0)
+ return ret;
+
+ /* configue and enable PLL for 12.288MHz output */
+ ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0,
+ iis_clkrate / 4, 12288000);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int neo1973_gta02_voice_hw_free(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+
+ /* disable the PLL */
+ return snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, 0, 0);
+}
+
+static struct snd_soc_ops neo1973_gta02_voice_ops = {
+ .hw_params = neo1973_gta02_voice_hw_params,
+ .hw_free = neo1973_gta02_voice_hw_free,
+};
+
+#define LM4853_AMP 1
+#define LM4853_SPK 2
+
+static u8 lm4853_state;
+
+/* This has no effect, it exists only to maintain compatibility with
+ * existing ALSA state files.
+ */
+static int lm4853_set_state(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int val = ucontrol->value.integer.value[0];
+
+ if (val)
+ lm4853_state |= LM4853_AMP;
+ else
+ lm4853_state &= ~LM4853_AMP;
+
+ return 0;
+}
+
+static int lm4853_get_state(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = lm4853_state & LM4853_AMP;
+
+ return 0;
+}
+
+static int lm4853_set_spk(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int val = ucontrol->value.integer.value[0];
+
+ if (val) {
+ lm4853_state |= LM4853_SPK;
+ gpio_set_value(GTA02_GPIO_HP_IN, 0);
+ } else {
+ lm4853_state &= ~LM4853_SPK;
+ gpio_set_value(GTA02_GPIO_HP_IN, 1);
+ }
+
+ return 0;
+}
+
+static int lm4853_get_spk(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = (lm4853_state & LM4853_SPK) >> 1;
+
+ return 0;
+}
+
+static int lm4853_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k,
+ int event)
+{
+ gpio_set_value(GTA02_GPIO_AMP_SHUT, SND_SOC_DAPM_EVENT_OFF(event));
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget wm8753_dapm_widgets[] = {
+ SND_SOC_DAPM_SPK("Stereo Out", lm4853_event),
+ SND_SOC_DAPM_LINE("GSM Line Out", NULL),
+ SND_SOC_DAPM_LINE("GSM Line In", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_MIC("Handset Mic", NULL),
+ SND_SOC_DAPM_SPK("Handset Spk", NULL),
+};
+
+
+/* example machine audio_mapnections */
+static const struct snd_soc_dapm_route audio_map[] = {
+
+ /* Connections to the lm4853 amp */
+ {"Stereo Out", NULL, "LOUT1"},
+ {"Stereo Out", NULL, "ROUT1"},
+
+ /* Connections to the GSM Module */
+ {"GSM Line Out", NULL, "MONO1"},
+ {"GSM Line Out", NULL, "MONO2"},
+ {"RXP", NULL, "GSM Line In"},
+ {"RXN", NULL, "GSM Line In"},
+
+ /* Connections to Headset */
+ {"MIC1", NULL, "Mic Bias"},
+ {"Mic Bias", NULL, "Headset Mic"},
+
+ /* Call Mic */
+ {"MIC2", NULL, "Mic Bias"},
+ {"MIC2N", NULL, "Mic Bias"},
+ {"Mic Bias", NULL, "Handset Mic"},
+
+ /* Call Speaker */
+ {"Handset Spk", NULL, "LOUT2"},
+ {"Handset Spk", NULL, "ROUT2"},
+
+ /* Connect the ALC pins */
+ {"ACIN", NULL, "ACOP"},
+};
+
+static const struct snd_kcontrol_new wm8753_neo1973_gta02_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Stereo Out"),
+ SOC_DAPM_PIN_SWITCH("GSM Line Out"),
+ SOC_DAPM_PIN_SWITCH("GSM Line In"),
+ SOC_DAPM_PIN_SWITCH("Headset Mic"),
+ SOC_DAPM_PIN_SWITCH("Handset Mic"),
+ SOC_DAPM_PIN_SWITCH("Handset Spk"),
+
+ /* This has no effect, it exists only to maintain compatibility with
+ * existing ALSA state files.
+ */
+ SOC_SINGLE_EXT("Amp State Switch", 6, 0, 1, 0,
+ lm4853_get_state,
+ lm4853_set_state),
+ SOC_SINGLE_EXT("Amp Spk Switch", 7, 0, 1, 0,
+ lm4853_get_spk,
+ lm4853_set_spk),
+};
+
+/*
+ * This is an example machine initialisation for a wm8753 connected to a
+ * neo1973 GTA02.
+ */
+static int neo1973_gta02_wm8753_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_codec *codec = rtd->codec;
+ int err;
+
+ /* set up NC codec pins */
+ snd_soc_dapm_nc_pin(codec, "OUT3");
+ snd_soc_dapm_nc_pin(codec, "OUT4");
+ snd_soc_dapm_nc_pin(codec, "LINE1");
+ snd_soc_dapm_nc_pin(codec, "LINE2");
+
+ /* Add neo1973 gta02 specific widgets */
+ snd_soc_dapm_new_controls(codec, wm8753_dapm_widgets,
+ ARRAY_SIZE(wm8753_dapm_widgets));
+
+ /* add neo1973 gta02 specific controls */
+ err = snd_soc_add_controls(codec, wm8753_neo1973_gta02_controls,
+ ARRAY_SIZE(wm8753_neo1973_gta02_controls));
+
+ if (err < 0)
+ return err;
+
+ /* set up neo1973 gta02 specific audio path audio_map */
+ snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+
+ /* set endpoints to default off mode */
+ snd_soc_dapm_disable_pin(codec, "Stereo Out");
+ snd_soc_dapm_disable_pin(codec, "GSM Line Out");
+ snd_soc_dapm_disable_pin(codec, "GSM Line In");
+ snd_soc_dapm_disable_pin(codec, "Headset Mic");
+ snd_soc_dapm_disable_pin(codec, "Handset Mic");
+ snd_soc_dapm_disable_pin(codec, "Handset Spk");
+
+ /* allow audio paths from the GSM modem to run during suspend */
+ snd_soc_dapm_ignore_suspend(codec, "Stereo Out");
+ snd_soc_dapm_ignore_suspend(codec, "GSM Line Out");
+ snd_soc_dapm_ignore_suspend(codec, "GSM Line In");
+ snd_soc_dapm_ignore_suspend(codec, "Headset Mic");
+ snd_soc_dapm_ignore_suspend(codec, "Handset Mic");
+ snd_soc_dapm_ignore_suspend(codec, "Handset Spk");
+
+ snd_soc_dapm_sync(codec);
+
+ return 0;
+}
+
+/*
+ * BT Codec DAI
+ */
+static struct snd_soc_dai_driver bt_dai = {
+ .name = "bluetooth-dai",
+ .playback = {
+ .channels_min = 1,
+ .channels_max = 1,
+ .rates = SNDRV_PCM_RATE_8000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+ .capture = {
+ .channels_min = 1,
+ .channels_max = 1,
+ .rates = SNDRV_PCM_RATE_8000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+};
+
+static struct snd_soc_dai_link neo1973_gta02_dai[] = {
+{ /* Hifi Playback - for similatious use with voice below */
+ .name = "WM8753",
+ .stream_name = "WM8753 HiFi",
+ .cpu_dai_name = "s3c24xx-i2s",
+ .codec_dai_name = "wm8753-hifi",
+ .init = neo1973_gta02_wm8753_init,
+ .platform_name = "samsung-audio",
+ .codec_name = "wm8753-codec.0-0x1a",
+ .ops = &neo1973_gta02_hifi_ops,
+},
+{ /* Voice via BT */
+ .name = "Bluetooth",
+ .stream_name = "Voice",
+ .cpu_dai_name = "bluetooth-dai",
+ .codec_dai_name = "wm8753-voice",
+ .ops = &neo1973_gta02_voice_ops,
+ .codec_name = "wm8753-codec.0-0x1a",
+ .platform_name = "samsung-audio",
+},
+};
+
+static struct snd_soc_card neo1973_gta02 = {
+ .name = "neo1973-gta02",
+ .dai_link = neo1973_gta02_dai,
+ .num_links = ARRAY_SIZE(neo1973_gta02_dai),
+};
+
+static struct platform_device *neo1973_gta02_snd_device;
+
+static int __init neo1973_gta02_init(void)
+{
+ int ret;
+
+ if (!machine_is_neo1973_gta02()) {
+ printk(KERN_INFO
+ "Only GTA02 is supported by this ASoC driver\n");
+ return -ENODEV;
+ }
+
+ neo1973_gta02_snd_device = platform_device_alloc("soc-audio", -1);
+ if (!neo1973_gta02_snd_device)
+ return -ENOMEM;
+
+ /* register bluetooth DAI here */
+ ret = snd_soc_register_dai(&neo1973_gta02_snd_device->dev, -1, &bt_dai);
+ if (ret) {
+ platform_device_put(neo1973_gta02_snd_device);
+ return ret;
+ }
+
+ platform_set_drvdata(neo1973_gta02_snd_device, &neo1973_gta02);
+ ret = platform_device_add(neo1973_gta02_snd_device);
+
+ if (ret) {
+ platform_device_put(neo1973_gta02_snd_device);
+ return ret;
+ }
+
+ /* Initialise GPIOs used by amp */
+ ret = gpio_request(GTA02_GPIO_HP_IN, "GTA02_HP_IN");
+ if (ret) {
+ pr_err("gta02_wm8753: Failed to register GPIO %d\n", GTA02_GPIO_HP_IN);
+ goto err_unregister_device;
+ }
+
+ ret = gpio_direction_output(GTA02_GPIO_HP_IN, 1);
+ if (ret) {
+ pr_err("gta02_wm8753: Failed to configure GPIO %d\n", GTA02_GPIO_HP_IN);
+ goto err_free_gpio_hp_in;
+ }
+
+ ret = gpio_request(GTA02_GPIO_AMP_SHUT, "GTA02_AMP_SHUT");
+ if (ret) {
+ pr_err("gta02_wm8753: Failed to register GPIO %d\n", GTA02_GPIO_AMP_SHUT);
+ goto err_free_gpio_hp_in;
+ }
+
+ ret = gpio_direction_output(GTA02_GPIO_AMP_SHUT, 1);
+ if (ret) {
+ pr_err("gta02_wm8753: Failed to configure GPIO %d\n", GTA02_GPIO_AMP_SHUT);
+ goto err_free_gpio_amp_shut;
+ }
+
+ return 0;
+
+err_free_gpio_amp_shut:
+ gpio_free(GTA02_GPIO_AMP_SHUT);
+err_free_gpio_hp_in:
+ gpio_free(GTA02_GPIO_HP_IN);
+err_unregister_device:
+ platform_device_unregister(neo1973_gta02_snd_device);
+ return ret;
+}
+module_init(neo1973_gta02_init);
+
+static void __exit neo1973_gta02_exit(void)
+{
+ snd_soc_unregister_dai(&neo1973_gta02_snd_device->dev, -1);
+ platform_device_unregister(neo1973_gta02_snd_device);
+ gpio_free(GTA02_GPIO_HP_IN);
+ gpio_free(GTA02_GPIO_AMP_SHUT);
+}
+module_exit(neo1973_gta02_exit);
+
+/* Module information */
+MODULE_AUTHOR("Graeme Gregory, graeme(a)openmoko.org");
+MODULE_DESCRIPTION("ALSA SoC WM8753 Neo1973 GTA02");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/samsung/neo1973_wm8753.c b/sound/soc/samsung/neo1973_wm8753.c
new file mode 100644
index 0000000..96dda57
--- /dev/null
+++ b/sound/soc/samsung/neo1973_wm8753.c
@@ -0,0 +1,704 @@
+/*
+ * neo1973_wm8753.c -- SoC audio for Neo1973
+ *
+ * Copyright 2007 Wolfson Microelectronics PLC.
+ * Author: Graeme Gregory
+ * graeme.gregory(a)wolfsonmicro.com or linux(a)wolfsonmicro.com
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+
+#include <asm/mach-types.h>
+#include <asm/hardware/scoop.h>
+#include <mach/regs-clock.h>
+#include <mach/regs-gpio.h>
+#include <mach/hardware.h>
+#include <linux/io.h>
+#include <mach/spi-gpio.h>
+
+#include <plat/regs-iis.h>
+
+#include "../codecs/wm8753.h"
+#include "lm4857.h"
+#include "dma.h"
+#include "s3c24xx-i2s.h"
+
+/* define the scenarios */
+#define NEO_AUDIO_OFF 0
+#define NEO_GSM_CALL_AUDIO_HANDSET 1
+#define NEO_GSM_CALL_AUDIO_HEADSET 2
+#define NEO_GSM_CALL_AUDIO_BLUETOOTH 3
+#define NEO_STEREO_TO_SPEAKERS 4
+#define NEO_STEREO_TO_HEADPHONES 5
+#define NEO_CAPTURE_HANDSET 6
+#define NEO_CAPTURE_HEADSET 7
+#define NEO_CAPTURE_BLUETOOTH 8
+
+static struct snd_soc_card neo1973;
+static struct i2c_client *i2c;
+
+static int neo1973_hifi_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ unsigned int pll_out = 0, bclk = 0;
+ int ret = 0;
+ unsigned long iis_clkrate;
+
+ pr_debug("Entered %s\n", __func__);
+
+ iis_clkrate = s3c24xx_i2s_get_clockrate();
+
+ switch (params_rate(params)) {
+ case 8000:
+ case 16000:
+ pll_out = 12288000;
+ break;
+ case 48000:
+ bclk = WM8753_BCLK_DIV_4;
+ pll_out = 12288000;
+ break;
+ case 96000:
+ bclk = WM8753_BCLK_DIV_2;
+ pll_out = 12288000;
+ break;
+ case 11025:
+ bclk = WM8753_BCLK_DIV_16;
+ pll_out = 11289600;
+ break;
+ case 22050:
+ bclk = WM8753_BCLK_DIV_8;
+ pll_out = 11289600;
+ break;
+ case 44100:
+ bclk = WM8753_BCLK_DIV_4;
+ pll_out = 11289600;
+ break;
+ case 88200:
+ bclk = WM8753_BCLK_DIV_2;
+ pll_out = 11289600;
+ break;
+ }
+
+ /* set codec DAI configuration */
+ ret = snd_soc_dai_set_fmt(codec_dai,
+ SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBM_CFM);
+ if (ret < 0)
+ return ret;
+
+ /* set cpu DAI configuration */
+ ret = snd_soc_dai_set_fmt(cpu_dai,
+ SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBM_CFM);
+ if (ret < 0)
+ return ret;
+
+ /* set the codec system clock for DAC and ADC */
+ ret = snd_soc_dai_set_sysclk(codec_dai, WM8753_MCLK, pll_out,
+ SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ return ret;
+
+ /* set MCLK division for sample rate */
+ ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK,
+ S3C2410_IISMOD_32FS);
+ if (ret < 0)
+ return ret;
+
+ /* set codec BCLK division for sample rate */
+ ret = snd_soc_dai_set_clkdiv(codec_dai, WM8753_BCLKDIV, bclk);
+ if (ret < 0)
+ return ret;
+
+ /* set prescaler division for sample rate */
+ ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER,
+ S3C24XX_PRESCALE(4, 4));
+ if (ret < 0)
+ return ret;
+
+ /* codec PLL input is PCLK/4 */
+ ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0,
+ iis_clkrate / 4, pll_out);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int neo1973_hifi_hw_free(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+
+ pr_debug("Entered %s\n", __func__);
+
+ /* disable the PLL */
+ return snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, 0, 0);
+}
+
+/*
+ * Neo1973 WM8753 HiFi DAI opserations.
+ */
+static struct snd_soc_ops neo1973_hifi_ops = {
+ .hw_params = neo1973_hifi_hw_params,
+ .hw_free = neo1973_hifi_hw_free,
+};
+
+static int neo1973_voice_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ unsigned int pcmdiv = 0;
+ int ret = 0;
+ unsigned long iis_clkrate;
+
+ pr_debug("Entered %s\n", __func__);
+
+ iis_clkrate = s3c24xx_i2s_get_clockrate();
+
+ if (params_rate(params) != 8000)
+ return -EINVAL;
+ if (params_channels(params) != 1)
+ return -EINVAL;
+
+ pcmdiv = WM8753_PCM_DIV_6; /* 2.048 MHz */
+
+ /* todo: gg check mode (DSP_B) against CSR datasheet */
+ /* set codec DAI configuration */
+ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_B |
+ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+ if (ret < 0)
+ return ret;
+
+ /* set the codec system clock for DAC and ADC */
+ ret = snd_soc_dai_set_sysclk(codec_dai, WM8753_PCMCLK, 12288000,
+ SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ return ret;
+
+ /* set codec PCM division for sample rate */
+ ret = snd_soc_dai_set_clkdiv(codec_dai, WM8753_PCMDIV, pcmdiv);
+ if (ret < 0)
+ return ret;
+
+ /* configue and enable PLL for 12.288MHz output */
+ ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0,
+ iis_clkrate / 4, 12288000);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int neo1973_voice_hw_free(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+
+ pr_debug("Entered %s\n", __func__);
+
+ /* disable the PLL */
+ return snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, 0, 0);
+}
+
+static struct snd_soc_ops neo1973_voice_ops = {
+ .hw_params = neo1973_voice_hw_params,
+ .hw_free = neo1973_voice_hw_free,
+};
+
+static int neo1973_scenario;
+
+static int neo1973_get_scenario(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = neo1973_scenario;
+ return 0;
+}
+
+static int set_scenario_endpoints(struct snd_soc_codec *codec, int scenario)
+{
+ pr_debug("Entered %s\n", __func__);
+
+ switch (neo1973_scenario) {
+ case NEO_AUDIO_OFF:
+ snd_soc_dapm_disable_pin(codec, "Audio Out");
+ snd_soc_dapm_disable_pin(codec, "GSM Line Out");
+ snd_soc_dapm_disable_pin(codec, "GSM Line In");
+ snd_soc_dapm_disable_pin(codec, "Headset Mic");
+ snd_soc_dapm_disable_pin(codec, "Call Mic");
+ break;
+ case NEO_GSM_CALL_AUDIO_HANDSET:
+ snd_soc_dapm_enable_pin(codec, "Audio Out");
+ snd_soc_dapm_enable_pin(codec, "GSM Line Out");
+ snd_soc_dapm_enable_pin(codec, "GSM Line In");
+ snd_soc_dapm_disable_pin(codec, "Headset Mic");
+ snd_soc_dapm_enable_pin(codec, "Call Mic");
+ break;
+ case NEO_GSM_CALL_AUDIO_HEADSET:
+ snd_soc_dapm_enable_pin(codec, "Audio Out");
+ snd_soc_dapm_enable_pin(codec, "GSM Line Out");
+ snd_soc_dapm_enable_pin(codec, "GSM Line In");
+ snd_soc_dapm_enable_pin(codec, "Headset Mic");
+ snd_soc_dapm_disable_pin(codec, "Call Mic");
+ break;
+ case NEO_GSM_CALL_AUDIO_BLUETOOTH:
+ snd_soc_dapm_disable_pin(codec, "Audio Out");
+ snd_soc_dapm_enable_pin(codec, "GSM Line Out");
+ snd_soc_dapm_enable_pin(codec, "GSM Line In");
+ snd_soc_dapm_disable_pin(codec, "Headset Mic");
+ snd_soc_dapm_disable_pin(codec, "Call Mic");
+ break;
+ case NEO_STEREO_TO_SPEAKERS:
+ snd_soc_dapm_enable_pin(codec, "Audio Out");
+ snd_soc_dapm_disable_pin(codec, "GSM Line Out");
+ snd_soc_dapm_disable_pin(codec, "GSM Line In");
+ snd_soc_dapm_disable_pin(codec, "Headset Mic");
+ snd_soc_dapm_disable_pin(codec, "Call Mic");
+ break;
+ case NEO_STEREO_TO_HEADPHONES:
+ snd_soc_dapm_enable_pin(codec, "Audio Out");
+ snd_soc_dapm_disable_pin(codec, "GSM Line Out");
+ snd_soc_dapm_disable_pin(codec, "GSM Line In");
+ snd_soc_dapm_disable_pin(codec, "Headset Mic");
+ snd_soc_dapm_disable_pin(codec, "Call Mic");
+ break;
+ case NEO_CAPTURE_HANDSET:
+ snd_soc_dapm_disable_pin(codec, "Audio Out");
+ snd_soc_dapm_disable_pin(codec, "GSM Line Out");
+ snd_soc_dapm_disable_pin(codec, "GSM Line In");
+ snd_soc_dapm_disable_pin(codec, "Headset Mic");
+ snd_soc_dapm_enable_pin(codec, "Call Mic");
+ break;
+ case NEO_CAPTURE_HEADSET:
+ snd_soc_dapm_disable_pin(codec, "Audio Out");
+ snd_soc_dapm_disable_pin(codec, "GSM Line Out");
+ snd_soc_dapm_disable_pin(codec, "GSM Line In");
+ snd_soc_dapm_enable_pin(codec, "Headset Mic");
+ snd_soc_dapm_disable_pin(codec, "Call Mic");
+ break;
+ case NEO_CAPTURE_BLUETOOTH:
+ snd_soc_dapm_disable_pin(codec, "Audio Out");
+ snd_soc_dapm_disable_pin(codec, "GSM Line Out");
+ snd_soc_dapm_disable_pin(codec, "GSM Line In");
+ snd_soc_dapm_disable_pin(codec, "Headset Mic");
+ snd_soc_dapm_disable_pin(codec, "Call Mic");
+ break;
+ default:
+ snd_soc_dapm_disable_pin(codec, "Audio Out");
+ snd_soc_dapm_disable_pin(codec, "GSM Line Out");
+ snd_soc_dapm_disable_pin(codec, "GSM Line In");
+ snd_soc_dapm_disable_pin(codec, "Headset Mic");
+ snd_soc_dapm_disable_pin(codec, "Call Mic");
+ }
+
+ snd_soc_dapm_sync(codec);
+
+ return 0;
+}
+
+static int neo1973_set_scenario(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+
+ pr_debug("Entered %s\n", __func__);
+
+ if (neo1973_scenario == ucontrol->value.integer.value[0])
+ return 0;
+
+ neo1973_scenario = ucontrol->value.integer.value[0];
+ set_scenario_endpoints(codec, neo1973_scenario);
+ return 1;
+}
+
+static u8 lm4857_regs[4] = {0x00, 0x40, 0x80, 0xC0};
+
+static void lm4857_write_regs(void)
+{
+ pr_debug("Entered %s\n", __func__);
+
+ if (i2c_master_send(i2c, lm4857_regs, 4) != 4)
+ printk(KERN_ERR "lm4857: i2c write failed\n");
+}
+
+static int lm4857_get_reg(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ int reg = mc->reg;
+ int shift = mc->shift;
+ int mask = mc->max;
+
+ pr_debug("Entered %s\n", __func__);
+
+ ucontrol->value.integer.value[0] = (lm4857_regs[reg] >> shift) & mask;
+ return 0;
+}
+
+static int lm4857_set_reg(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ int reg = mc->reg;
+ int shift = mc->shift;
+ int mask = mc->max;
+
+ if (((lm4857_regs[reg] >> shift) & mask) ==
+ ucontrol->value.integer.value[0])
+ return 0;
+
+ lm4857_regs[reg] &= ~(mask << shift);
+ lm4857_regs[reg] |= ucontrol->value.integer.value[0] << shift;
+ lm4857_write_regs();
+ return 1;
+}
+
+static int lm4857_get_mode(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ u8 value = lm4857_regs[LM4857_CTRL] & 0x0F;
+
+ pr_debug("Entered %s\n", __func__);
+
+ if (value)
+ value -= 5;
+
+ ucontrol->value.integer.value[0] = value;
+ return 0;
+}
+
+static int lm4857_set_mode(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ u8 value = ucontrol->value.integer.value[0];
+
+ pr_debug("Entered %s\n", __func__);
+
+ if (value)
+ value += 5;
+
+ if ((lm4857_regs[LM4857_CTRL] & 0x0F) == value)
+ return 0;
+
+ lm4857_regs[LM4857_CTRL] &= 0xF0;
+ lm4857_regs[LM4857_CTRL] |= value;
+ lm4857_write_regs();
+ return 1;
+}
+
+static const struct snd_soc_dapm_widget wm8753_dapm_widgets[] = {
+ SND_SOC_DAPM_LINE("Audio Out", NULL),
+ SND_SOC_DAPM_LINE("GSM Line Out", NULL),
+ SND_SOC_DAPM_LINE("GSM Line In", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_MIC("Call Mic", NULL),
+};
+
+
+static const struct snd_soc_dapm_route dapm_routes[] = {
+
+ /* Connections to the lm4857 amp */
+ {"Audio Out", NULL, "LOUT1"},
+ {"Audio Out", NULL, "ROUT1"},
+
+ /* Connections to the GSM Module */
+ {"GSM Line Out", NULL, "MONO1"},
+ {"GSM Line Out", NULL, "MONO2"},
+ {"RXP", NULL, "GSM Line In"},
+ {"RXN", NULL, "GSM Line In"},
+
+ /* Connections to Headset */
+ {"MIC1", NULL, "Mic Bias"},
+ {"Mic Bias", NULL, "Headset Mic"},
+
+ /* Call Mic */
+ {"MIC2", NULL, "Mic Bias"},
+ {"MIC2N", NULL, "Mic Bias"},
+ {"Mic Bias", NULL, "Call Mic"},
+
+ /* Connect the ALC pins */
+ {"ACIN", NULL, "ACOP"},
+};
+
+static const char *lm4857_mode[] = {
+ "Off",
+ "Call Speaker",
+ "Stereo Speakers",
+ "Stereo Speakers + Headphones",
+ "Headphones"
+};
+
+static const struct soc_enum lm4857_mode_enum[] = {
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(lm4857_mode), lm4857_mode),
+};
+
+static const char *neo_scenarios[] = {
+ "Off",
+ "GSM Handset",
+ "GSM Headset",
+ "GSM Bluetooth",
+ "Speakers",
+ "Headphones",
+ "Capture Handset",
+ "Capture Headset",
+ "Capture Bluetooth"
+};
+
+static const struct soc_enum neo_scenario_enum[] = {
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(neo_scenarios), neo_scenarios),
+};
+
+static const DECLARE_TLV_DB_SCALE(stereo_tlv, -4050, 150, 0);
+static const DECLARE_TLV_DB_SCALE(mono_tlv, -3450, 150, 0);
+
+static const struct snd_kcontrol_new wm8753_neo1973_controls[] = {
+ SOC_SINGLE_EXT_TLV("Amp Left Playback Volume", LM4857_LVOL, 0, 31, 0,
+ lm4857_get_reg, lm4857_set_reg, stereo_tlv),
+ SOC_SINGLE_EXT_TLV("Amp Right Playback Volume", LM4857_RVOL, 0, 31, 0,
+ lm4857_get_reg, lm4857_set_reg, stereo_tlv),
+ SOC_SINGLE_EXT_TLV("Amp Mono Playback Volume", LM4857_MVOL, 0, 31, 0,
+ lm4857_get_reg, lm4857_set_reg, mono_tlv),
+ SOC_ENUM_EXT("Amp Mode", lm4857_mode_enum[0],
+ lm4857_get_mode, lm4857_set_mode),
+ SOC_ENUM_EXT("Neo Mode", neo_scenario_enum[0],
+ neo1973_get_scenario, neo1973_set_scenario),
+ SOC_SINGLE_EXT("Amp Spk 3D Playback Switch", LM4857_LVOL, 5, 1, 0,
+ lm4857_get_reg, lm4857_set_reg),
+ SOC_SINGLE_EXT("Amp HP 3d Playback Switch", LM4857_RVOL, 5, 1, 0,
+ lm4857_get_reg, lm4857_set_reg),
+ SOC_SINGLE_EXT("Amp Fast Wakeup Playback Switch", LM4857_CTRL, 5, 1, 0,
+ lm4857_get_reg, lm4857_set_reg),
+ SOC_SINGLE_EXT("Amp Earpiece 6dB Playback Switch", LM4857_CTRL, 4, 1, 0,
+ lm4857_get_reg, lm4857_set_reg),
+};
+
+/*
+ * This is an example machine initialisation for a wm8753 connected to a
+ * neo1973 II. It is missing logic to detect hp/mic insertions and logic
+ * to re-route the audio in such an event.
+ */
+static int neo1973_wm8753_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_codec *codec = rtd->codec;
+ int err;
+
+ pr_debug("Entered %s\n", __func__);
+
+ /* set up NC codec pins */
+ snd_soc_dapm_nc_pin(codec, "LOUT2");
+ snd_soc_dapm_nc_pin(codec, "ROUT2");
+ snd_soc_dapm_nc_pin(codec, "OUT3");
+ snd_soc_dapm_nc_pin(codec, "OUT4");
+ snd_soc_dapm_nc_pin(codec, "LINE1");
+ snd_soc_dapm_nc_pin(codec, "LINE2");
+
+ /* Add neo1973 specific widgets */
+ snd_soc_dapm_new_controls(codec, wm8753_dapm_widgets,
+ ARRAY_SIZE(wm8753_dapm_widgets));
+
+ /* set endpoints to default mode */
+ set_scenario_endpoints(codec, NEO_AUDIO_OFF);
+
+ /* add neo1973 specific controls */
+ err = snd_soc_add_controls(codec, wm8753_neo1973_controls,
+ ARRAY_SIZE(8753_neo1973_controls));
+ if (err < 0)
+ return err;
+
+ /* set up neo1973 specific audio routes */
+ err = snd_soc_dapm_add_routes(codec, dapm_routes,
+ ARRAY_SIZE(dapm_routes));
+
+ snd_soc_dapm_sync(codec);
+ return 0;
+}
+
+/*
+ * BT Codec DAI
+ */
+static struct snd_soc_dai bt_dai = {
+ .name = "bluetooth-dai",
+ .playback = {
+ .channels_min = 1,
+ .channels_max = 1,
+ .rates = SNDRV_PCM_RATE_8000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+ .capture = {
+ .channels_min = 1,
+ .channels_max = 1,
+ .rates = SNDRV_PCM_RATE_8000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+};
+
+static struct snd_soc_dai_link neo1973_dai[] = {
+{ /* Hifi Playback - for similatious use with voice below */
+ .name = "WM8753",
+ .stream_name = "WM8753 HiFi",
+ .platform_name = "samsung-audio",
+ .cpu_dai_name = "s3c24xx-i2s",
+ .codec_dai_name = "wm8753-hifi",
+ .codec_name = "wm8753-codec.0-0x1a",
+ .init = neo1973_wm8753_init,
+ .ops = &neo1973_hifi_ops,
+},
+{ /* Voice via BT */
+ .name = "Bluetooth",
+ .stream_name = "Voice",
+ .platform_name = "samsung-audio",
+ .cpu_dai_name = "bluetooth-dai",
+ .codec_dai_name = "wm8753-voice",
+ .codec_name = "wm8753-codec.0-0x1a",
+ .ops = &neo1973_voice_ops,
+},
+};
+
+static struct snd_soc_card neo1973 = {
+ .name = "neo1973",
+ .dai_link = neo1973_dai,
+ .num_links = ARRAY_SIZE(neo1973_dai),
+};
+
+static int lm4857_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ pr_debug("Entered %s\n", __func__);
+
+ i2c = client;
+
+ lm4857_write_regs();
+ return 0;
+}
+
+static int lm4857_i2c_remove(struct i2c_client *client)
+{
+ pr_debug("Entered %s\n", __func__);
+
+ i2c = NULL;
+
+ return 0;
+}
+
+static u8 lm4857_state;
+
+static int lm4857_suspend(struct i2c_client *dev, pm_message_t state)
+{
+ pr_debug("Entered %s\n", __func__);
+
+ dev_dbg(&dev->dev, "lm4857_suspend\n");
+ lm4857_state = lm4857_regs[LM4857_CTRL] & 0xf;
+ if (lm4857_state) {
+ lm4857_regs[LM4857_CTRL] &= 0xf0;
+ lm4857_write_regs();
+ }
+ return 0;
+}
+
+static int lm4857_resume(struct i2c_client *dev)
+{
+ pr_debug("Entered %s\n", __func__);
+
+ if (lm4857_state) {
+ lm4857_regs[LM4857_CTRL] |= (lm4857_state & 0x0f);
+ lm4857_write_regs();
+ }
+ return 0;
+}
+
+static void lm4857_shutdown(struct i2c_client *dev)
+{
+ pr_debug("Entered %s\n", __func__);
+
+ dev_dbg(&dev->dev, "lm4857_shutdown\n");
+ lm4857_regs[LM4857_CTRL] &= 0xf0;
+ lm4857_write_regs();
+}
+
+static const struct i2c_device_id lm4857_i2c_id[] = {
+ { "neo1973_lm4857", 0 },
+ { }
+};
+
+static struct i2c_driver lm4857_i2c_driver = {
+ .driver = {
+ .name = "LM4857 I2C Amp",
+ .owner = THIS_MODULE,
+ },
+ .suspend = lm4857_suspend,
+ .resume = lm4857_resume,
+ .shutdown = lm4857_shutdown,
+ .probe = lm4857_i2c_probe,
+ .remove = lm4857_i2c_remove,
+ .id_table = lm4857_i2c_id,
+};
+
+static struct platform_device *neo1973_snd_device;
+
+static int __init neo1973_init(void)
+{
+ int ret;
+
+ pr_debug("Entered %s\n", __func__);
+
+ if (!machine_is_neo1973_gta01()) {
+ printk(KERN_INFO
+ "Only GTA01 hardware supported by ASoC driver\n");
+ return -ENODEV;
+ }
+
+ neo1973_snd_device = platform_device_alloc("soc-audio", -1);
+ if (!neo1973_snd_device)
+ return -ENOMEM;
+
+ platform_set_drvdata(neo1973_snd_device, &neo1973);
+ ret = platform_device_add(neo1973_snd_device);
+
+ if (ret) {
+ platform_device_put(neo1973_snd_device);
+ return ret;
+ }
+
+ ret = i2c_add_driver(&lm4857_i2c_driver);
+
+ if (ret != 0)
+ platform_device_unregister(neo1973_snd_device);
+
+ return ret;
+}
+
+static void __exit neo1973_exit(void)
+{
+ pr_debug("Entered %s\n", __func__);
+
+ i2c_del_driver(&lm4857_i2c_driver);
+ platform_device_unregister(neo1973_snd_device);
+}
+
+module_init(neo1973_init);
+module_exit(neo1973_exit);
+
+/* Module information */
+MODULE_AUTHOR("Graeme Gregory, graeme(a)openmoko.org, www.openmoko.org");
+MODULE_DESCRIPTION("ALSA SoC WM8753 Neo1973");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/samsung/pcm.c b/sound/soc/samsung/pcm.c
new file mode 100644
index 0000000..48d0b75
--- /dev/null
+++ b/sound/soc/samsung/pcm.c
@@ -0,0 +1,552 @@
+/* sound/soc/samsung/pcm.c
+ *
+ * ALSA SoC Audio Layer - S3C PCM-Controller driver
+ *
+ * Copyright (c) 2009 Samsung Electronics Co. Ltd
+ * Author: Jaswinder Singh <jassi.brar(a)samsung.com>
+ * based upon I2S drivers by Ben Dooks.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/kernel.h>
+#include <linux/gpio.h>
+#include <linux/io.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+#include <plat/audio.h>
+#include <plat/dma.h>
+
+#include "dma.h"
+#include "pcm.h"
+
+static struct s3c2410_dma_client s3c_pcm_dma_client_out = {
+ .name = "PCM Stereo out"
+};
+
+static struct s3c2410_dma_client s3c_pcm_dma_client_in = {
+ .name = "PCM Stereo in"
+};
+
+static struct s3c_dma_params s3c_pcm_stereo_out[] = {
+ [0] = {
+ .client = &s3c_pcm_dma_client_out,
+ .dma_size = 4,
+ },
+ [1] = {
+ .client = &s3c_pcm_dma_client_out,
+ .dma_size = 4,
+ },
+};
+
+static struct s3c_dma_params s3c_pcm_stereo_in[] = {
+ [0] = {
+ .client = &s3c_pcm_dma_client_in,
+ .dma_size = 4,
+ },
+ [1] = {
+ .client = &s3c_pcm_dma_client_in,
+ .dma_size = 4,
+ },
+};
+
+static struct s3c_pcm_info s3c_pcm[2];
+
+static void s3c_pcm_snd_txctrl(struct s3c_pcm_info *pcm, int on)
+{
+ void __iomem *regs = pcm->regs;
+ u32 ctl, clkctl;
+
+ clkctl = readl(regs + S3C_PCM_CLKCTL);
+ ctl = readl(regs + S3C_PCM_CTL);
+ ctl &= ~(S3C_PCM_CTL_TXDIPSTICK_MASK
+ << S3C_PCM_CTL_TXDIPSTICK_SHIFT);
+
+ if (on) {
+ ctl |= S3C_PCM_CTL_TXDMA_EN;
+ ctl |= S3C_PCM_CTL_TXFIFO_EN;
+ ctl |= S3C_PCM_CTL_ENABLE;
+ ctl |= (0x4<<S3C_PCM_CTL_TXDIPSTICK_SHIFT);
+ clkctl |= S3C_PCM_CLKCTL_SERCLK_EN;
+ } else {
+ ctl &= ~S3C_PCM_CTL_TXDMA_EN;
+ ctl &= ~S3C_PCM_CTL_TXFIFO_EN;
+
+ if (!(ctl & S3C_PCM_CTL_RXFIFO_EN)) {
+ ctl &= ~S3C_PCM_CTL_ENABLE;
+ if (!pcm->idleclk)
+ clkctl |= S3C_PCM_CLKCTL_SERCLK_EN;
+ }
+ }
+
+ writel(clkctl, regs + S3C_PCM_CLKCTL);
+ writel(ctl, regs + S3C_PCM_CTL);
+}
+
+static void s3c_pcm_snd_rxctrl(struct s3c_pcm_info *pcm, int on)
+{
+ void __iomem *regs = pcm->regs;
+ u32 ctl, clkctl;
+
+ ctl = readl(regs + S3C_PCM_CTL);
+ clkctl = readl(regs + S3C_PCM_CLKCTL);
+ ctl &= ~(S3C_PCM_CTL_RXDIPSTICK_MASK
+ << S3C_PCM_CTL_RXDIPSTICK_SHIFT);
+
+ if (on) {
+ ctl |= S3C_PCM_CTL_RXDMA_EN;
+ ctl |= S3C_PCM_CTL_RXFIFO_EN;
+ ctl |= S3C_PCM_CTL_ENABLE;
+ ctl |= (0x20<<S3C_PCM_CTL_RXDIPSTICK_SHIFT);
+ clkctl |= S3C_PCM_CLKCTL_SERCLK_EN;
+ } else {
+ ctl &= ~S3C_PCM_CTL_RXDMA_EN;
+ ctl &= ~S3C_PCM_CTL_RXFIFO_EN;
+
+ if (!(ctl & S3C_PCM_CTL_TXFIFO_EN)) {
+ ctl &= ~S3C_PCM_CTL_ENABLE;
+ if (!pcm->idleclk)
+ clkctl |= S3C_PCM_CLKCTL_SERCLK_EN;
+ }
+ }
+
+ writel(clkctl, regs + S3C_PCM_CLKCTL);
+ writel(ctl, regs + S3C_PCM_CTL);
+}
+
+static int s3c_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(rtd->cpu_dai);
+ unsigned long flags;
+
+ dev_dbg(pcm->dev, "Entered %s\n", __func__);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ spin_lock_irqsave(&pcm->lock, flags);
+
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ s3c_pcm_snd_rxctrl(pcm, 1);
+ else
+ s3c_pcm_snd_txctrl(pcm, 1);
+
+ spin_unlock_irqrestore(&pcm->lock, flags);
+ break;
+
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ spin_lock_irqsave(&pcm->lock, flags);
+
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ s3c_pcm_snd_rxctrl(pcm, 0);
+ else
+ s3c_pcm_snd_txctrl(pcm, 0);
+
+ spin_unlock_irqrestore(&pcm->lock, flags);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int s3c_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *socdai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(rtd->cpu_dai);
+ struct s3c_dma_params *dma_data;
+ void __iomem *regs = pcm->regs;
+ struct clk *clk;
+ int sclk_div, sync_div;
+ unsigned long flags;
+ u32 clkctl;
+
+ dev_dbg(pcm->dev, "Entered %s\n", __func__);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ dma_data = pcm->dma_playback;
+ else
+ dma_data = pcm->dma_capture;
+
+ snd_soc_dai_set_dma_data(rtd->cpu_dai, substream, dma_data);
+
+ /* Strictly check for sample size */
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&pcm->lock, flags);
+
+ /* Get hold of the PCMSOURCE_CLK */
+ clkctl = readl(regs + S3C_PCM_CLKCTL);
+ if (clkctl & S3C_PCM_CLKCTL_SERCLKSEL_PCLK)
+ clk = pcm->pclk;
+ else
+ clk = pcm->cclk;
+
+ /* Set the SCLK divider */
+ sclk_div = clk_get_rate(clk) / pcm->sclk_per_fs /
+ params_rate(params) / 2 - 1;
+
+ clkctl &= ~(S3C_PCM_CLKCTL_SCLKDIV_MASK
+ << S3C_PCM_CLKCTL_SCLKDIV_SHIFT);
+ clkctl |= ((sclk_div & S3C_PCM_CLKCTL_SCLKDIV_MASK)
+ << S3C_PCM_CLKCTL_SCLKDIV_SHIFT);
+
+ /* Set the SYNC divider */
+ sync_div = pcm->sclk_per_fs - 1;
+
+ clkctl &= ~(S3C_PCM_CLKCTL_SYNCDIV_MASK
+ << S3C_PCM_CLKCTL_SYNCDIV_SHIFT);
+ clkctl |= ((sync_div & S3C_PCM_CLKCTL_SYNCDIV_MASK)
+ << S3C_PCM_CLKCTL_SYNCDIV_SHIFT);
+
+ writel(clkctl, regs + S3C_PCM_CLKCTL);
+
+ spin_unlock_irqrestore(&pcm->lock, flags);
+
+ dev_dbg(pcm->dev, "PCMSOURCE_CLK-%lu SCLK=%ufs SCLK_DIV=%d SYNC_DIV=%d\n",
+ clk_get_rate(clk), pcm->sclk_per_fs,
+ sclk_div, sync_div);
+
+ return 0;
+}
+
+static int s3c_pcm_set_fmt(struct snd_soc_dai *cpu_dai,
+ unsigned int fmt)
+{
+ struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(cpu_dai);
+ void __iomem *regs = pcm->regs;
+ unsigned long flags;
+ int ret = 0;
+ u32 ctl;
+
+ dev_dbg(pcm->dev, "Entered %s\n", __func__);
+
+ spin_lock_irqsave(&pcm->lock, flags);
+
+ ctl = readl(regs + S3C_PCM_CTL);
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ /* Nothing to do, NB_NF by default */
+ break;
+ default:
+ dev_err(pcm->dev, "Unsupported clock inversion!\n");
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ /* Nothing to do, Master by default */
+ break;
+ default:
+ dev_err(pcm->dev, "Unsupported master/slave format!\n");
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_MASK) {
+ case SND_SOC_DAIFMT_CONT:
+ pcm->idleclk = 1;
+ break;
+ case SND_SOC_DAIFMT_GATED:
+ pcm->idleclk = 0;
+ break;
+ default:
+ dev_err(pcm->dev, "Invalid Clock gating request!\n");
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_DSP_A:
+ ctl |= S3C_PCM_CTL_TXMSB_AFTER_FSYNC;
+ ctl |= S3C_PCM_CTL_RXMSB_AFTER_FSYNC;
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ ctl &= ~S3C_PCM_CTL_TXMSB_AFTER_FSYNC;
+ ctl &= ~S3C_PCM_CTL_RXMSB_AFTER_FSYNC;
+ break;
+ default:
+ dev_err(pcm->dev, "Unsupported data format!\n");
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ writel(ctl, regs + S3C_PCM_CTL);
+
+exit:
+ spin_unlock_irqrestore(&pcm->lock, flags);
+
+ return ret;
+}
+
+static int s3c_pcm_set_clkdiv(struct snd_soc_dai *cpu_dai,
+ int div_id, int div)
+{
+ struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(cpu_dai);
+
+ switch (div_id) {
+ case S3C_PCM_SCLK_PER_FS:
+ pcm->sclk_per_fs = div;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int s3c_pcm_set_sysclk(struct snd_soc_dai *cpu_dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(cpu_dai);
+ void __iomem *regs = pcm->regs;
+ u32 clkctl = readl(regs + S3C_PCM_CLKCTL);
+
+ switch (clk_id) {
+ case S3C_PCM_CLKSRC_PCLK:
+ clkctl |= S3C_PCM_CLKCTL_SERCLKSEL_PCLK;
+ break;
+
+ case S3C_PCM_CLKSRC_MUX:
+ clkctl &= ~S3C_PCM_CLKCTL_SERCLKSEL_PCLK;
+
+ if (clk_get_rate(pcm->cclk) != freq)
+ clk_set_rate(pcm->cclk, freq);
+
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ writel(clkctl, regs + S3C_PCM_CLKCTL);
+
+ return 0;
+}
+
+static struct snd_soc_dai_ops s3c_pcm_dai_ops = {
+ .set_sysclk = s3c_pcm_set_sysclk,
+ .set_clkdiv = s3c_pcm_set_clkdiv,
+ .trigger = s3c_pcm_trigger,
+ .hw_params = s3c_pcm_hw_params,
+ .set_fmt = s3c_pcm_set_fmt,
+};
+
+#define S3C_PCM_RATES SNDRV_PCM_RATE_8000_96000
+
+#define S3C_PCM_DAI_DECLARE \
+ .symmetric_rates = 1, \
+ .ops = &s3c_pcm_dai_ops, \
+ .playback = { \
+ .channels_min = 2, \
+ .channels_max = 2, \
+ .rates = S3C_PCM_RATES, \
+ .formats = SNDRV_PCM_FMTBIT_S16_LE, \
+ }, \
+ .capture = { \
+ .channels_min = 2, \
+ .channels_max = 2, \
+ .rates = S3C_PCM_RATES, \
+ .formats = SNDRV_PCM_FMTBIT_S16_LE, \
+ }
+
+struct snd_soc_dai_driver s3c_pcm_dai[] = {
+ [0] = {
+ .name = "samsung-pcm.0",
+ S3C_PCM_DAI_DECLARE,
+ },
+ [1] = {
+ .name = "samsung-pcm.1",
+ S3C_PCM_DAI_DECLARE,
+ },
+};
+EXPORT_SYMBOL_GPL(s3c_pcm_dai);
+
+static __devinit int s3c_pcm_dev_probe(struct platform_device *pdev)
+{
+ struct s3c_pcm_info *pcm;
+ struct resource *mem_res, *dmatx_res, *dmarx_res;
+ struct s3c_audio_pdata *pcm_pdata;
+ int ret;
+
+ /* Check for valid device index */
+ if ((pdev->id < 0) || pdev->id >= ARRAY_SIZE(s3c_pcm)) {
+ dev_err(&pdev->dev, "id %d out of range\n", pdev->id);
+ return -EINVAL;
+ }
+
+ pcm_pdata = pdev->dev.platform_data;
+
+ /* Check for availability of necessary resource */
+ dmatx_res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+ if (!dmatx_res) {
+ dev_err(&pdev->dev, "Unable to get PCM-TX dma resource\n");
+ return -ENXIO;
+ }
+
+ dmarx_res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+ if (!dmarx_res) {
+ dev_err(&pdev->dev, "Unable to get PCM-RX dma resource\n");
+ return -ENXIO;
+ }
+
+ mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem_res) {
+ dev_err(&pdev->dev, "Unable to get register resource\n");
+ return -ENXIO;
+ }
+
+ if (pcm_pdata && pcm_pdata->cfg_gpio && pcm_pdata->cfg_gpio(pdev)) {
+ dev_err(&pdev->dev, "Unable to configure gpio\n");
+ return -EINVAL;
+ }
+
+ pcm = &s3c_pcm[pdev->id];
+ pcm->dev = &pdev->dev;
+
+ spin_lock_init(&pcm->lock);
+
+ /* Default is 128fs */
+ pcm->sclk_per_fs = 128;
+
+ pcm->cclk = clk_get(&pdev->dev, "audio-bus");
+ if (IS_ERR(pcm->cclk)) {
+ dev_err(&pdev->dev, "failed to get audio-bus\n");
+ ret = PTR_ERR(pcm->cclk);
+ goto err1;
+ }
+ clk_enable(pcm->cclk);
+
+ /* record our pcm structure for later use in the callbacks */
+ dev_set_drvdata(&pdev->dev, pcm);
+
+ if (!request_mem_region(mem_res->start,
+ resource_size(mem_res), "samsung-pcm")) {
+ dev_err(&pdev->dev, "Unable to request register region\n");
+ ret = -EBUSY;
+ goto err2;
+ }
+
+ pcm->regs = ioremap(mem_res->start, 0x100);
+ if (pcm->regs == NULL) {
+ dev_err(&pdev->dev, "cannot ioremap registers\n");
+ ret = -ENXIO;
+ goto err3;
+ }
+
+ pcm->pclk = clk_get(&pdev->dev, "pcm");
+ if (IS_ERR(pcm->pclk)) {
+ dev_err(&pdev->dev, "failed to get pcm_clock\n");
+ ret = -ENOENT;
+ goto err4;
+ }
+ clk_enable(pcm->pclk);
+
+ ret = snd_soc_register_dai(&pdev->dev, &s3c_pcm_dai[pdev->id]);
+ if (ret != 0) {
+ dev_err(&pdev->dev, "failed to get pcm_clock\n");
+ goto err5;
+ }
+
+ s3c_pcm_stereo_in[pdev->id].dma_addr = mem_res->start
+ + S3C_PCM_RXFIFO;
+ s3c_pcm_stereo_out[pdev->id].dma_addr = mem_res->start
+ + S3C_PCM_TXFIFO;
+
+ s3c_pcm_stereo_in[pdev->id].channel = dmarx_res->start;
+ s3c_pcm_stereo_out[pdev->id].channel = dmatx_res->start;
+
+ pcm->dma_capture = &s3c_pcm_stereo_in[pdev->id];
+ pcm->dma_playback = &s3c_pcm_stereo_out[pdev->id];
+
+ return 0;
+
+err5:
+ clk_disable(pcm->pclk);
+ clk_put(pcm->pclk);
+err4:
+ iounmap(pcm->regs);
+err3:
+ release_mem_region(mem_res->start, resource_size(mem_res));
+err2:
+ clk_disable(pcm->cclk);
+ clk_put(pcm->cclk);
+err1:
+ return ret;
+}
+
+static __devexit int s3c_pcm_dev_remove(struct platform_device *pdev)
+{
+ struct s3c_pcm_info *pcm = &s3c_pcm[pdev->id];
+ struct resource *mem_res;
+
+ snd_soc_unregister_dai(&pdev->dev);
+
+ iounmap(pcm->regs);
+
+ mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ release_mem_region(mem_res->start, resource_size(mem_res));
+
+ clk_disable(pcm->cclk);
+ clk_disable(pcm->pclk);
+ clk_put(pcm->pclk);
+ clk_put(pcm->cclk);
+
+ return 0;
+}
+
+static struct platform_driver s3c_pcm_driver = {
+ .probe = s3c_pcm_dev_probe,
+ .remove = s3c_pcm_dev_remove,
+ .driver = {
+ .name = "samsung-pcm",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init s3c_pcm_init(void)
+{
+ return platform_driver_register(&s3c_pcm_driver);
+}
+module_init(s3c_pcm_init);
+
+static void __exit s3c_pcm_exit(void)
+{
+ platform_driver_unregister(&s3c_pcm_driver);
+}
+module_exit(s3c_pcm_exit);
+
+/* Module information */
+MODULE_AUTHOR("Jaswinder Singh, <jassi.brar(a)samsung.com>");
+MODULE_DESCRIPTION("S3C PCM Controller Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:samsung-pcm");
diff --git a/sound/soc/samsung/pcm.h b/sound/soc/samsung/pcm.h
new file mode 100644
index 0000000..03393dc
--- /dev/null
+++ b/sound/soc/samsung/pcm.h
@@ -0,0 +1,124 @@
+/* sound/soc/samsung/pcm.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef __S3C_PCM_H
+#define __S3C_PCM_H __FILE__
+
+/*Register Offsets */
+#define S3C_PCM_CTL (0x00)
+#define S3C_PCM_CLKCTL (0x04)
+#define S3C_PCM_TXFIFO (0x08)
+#define S3C_PCM_RXFIFO (0x0C)
+#define S3C_PCM_IRQCTL (0x10)
+#define S3C_PCM_IRQSTAT (0x14)
+#define S3C_PCM_FIFOSTAT (0x18)
+#define S3C_PCM_CLRINT (0x20)
+
+/* PCM_CTL Bit-Fields */
+#define S3C_PCM_CTL_TXDIPSTICK_MASK (0x3f)
+#define S3C_PCM_CTL_TXDIPSTICK_SHIFT (13)
+#define S3C_PCM_CTL_RXDIPSTICK_MASK (0x3f)
+#define S3C_PCM_CTL_RXDIPSTICK_SHIFT (7)
+#define S3C_PCM_CTL_TXDMA_EN (0x1<<6)
+#define S3C_PCM_CTL_RXDMA_EN (0x1<<5)
+#define S3C_PCM_CTL_TXMSB_AFTER_FSYNC (0x1<<4)
+#define S3C_PCM_CTL_RXMSB_AFTER_FSYNC (0x1<<3)
+#define S3C_PCM_CTL_TXFIFO_EN (0x1<<2)
+#define S3C_PCM_CTL_RXFIFO_EN (0x1<<1)
+#define S3C_PCM_CTL_ENABLE (0x1<<0)
+
+/* PCM_CLKCTL Bit-Fields */
+#define S3C_PCM_CLKCTL_SERCLK_EN (0x1<<19)
+#define S3C_PCM_CLKCTL_SERCLKSEL_PCLK (0x1<<18)
+#define S3C_PCM_CLKCTL_SCLKDIV_MASK (0x1ff)
+#define S3C_PCM_CLKCTL_SYNCDIV_MASK (0x1ff)
+#define S3C_PCM_CLKCTL_SCLKDIV_SHIFT (9)
+#define S3C_PCM_CLKCTL_SYNCDIV_SHIFT (0)
+
+/* PCM_TXFIFO Bit-Fields */
+#define S3C_PCM_TXFIFO_DVALID (0x1<<16)
+#define S3C_PCM_TXFIFO_DATA_MSK (0xffff<<0)
+
+/* PCM_RXFIFO Bit-Fields */
+#define S3C_PCM_RXFIFO_DVALID (0x1<<16)
+#define S3C_PCM_RXFIFO_DATA_MSK (0xffff<<0)
+
+/* PCM_IRQCTL Bit-Fields */
+#define S3C_PCM_IRQCTL_IRQEN (0x1<<14)
+#define S3C_PCM_IRQCTL_WRDEN (0x1<<12)
+#define S3C_PCM_IRQCTL_TXEMPTYEN (0x1<<11)
+#define S3C_PCM_IRQCTL_TXALMSTEMPTYEN (0x1<<10)
+#define S3C_PCM_IRQCTL_TXFULLEN (0x1<<9)
+#define S3C_PCM_IRQCTL_TXALMSTFULLEN (0x1<<8)
+#define S3C_PCM_IRQCTL_TXSTARVEN (0x1<<7)
+#define S3C_PCM_IRQCTL_TXERROVRFLEN (0x1<<6)
+#define S3C_PCM_IRQCTL_RXEMPTEN (0x1<<5)
+#define S3C_PCM_IRQCTL_RXALMSTEMPTEN (0x1<<4)
+#define S3C_PCM_IRQCTL_RXFULLEN (0x1<<3)
+#define S3C_PCM_IRQCTL_RXALMSTFULLEN (0x1<<2)
+#define S3C_PCM_IRQCTL_RXSTARVEN (0x1<<1)
+#define S3C_PCM_IRQCTL_RXERROVRFLEN (0x1<<0)
+
+/* PCM_IRQSTAT Bit-Fields */
+#define S3C_PCM_IRQSTAT_IRQPND (0x1<<13)
+#define S3C_PCM_IRQSTAT_WRD_XFER (0x1<<12)
+#define S3C_PCM_IRQSTAT_TXEMPTY (0x1<<11)
+#define S3C_PCM_IRQSTAT_TXALMSTEMPTY (0x1<<10)
+#define S3C_PCM_IRQSTAT_TXFULL (0x1<<9)
+#define S3C_PCM_IRQSTAT_TXALMSTFULL (0x1<<8)
+#define S3C_PCM_IRQSTAT_TXSTARV (0x1<<7)
+#define S3C_PCM_IRQSTAT_TXERROVRFL (0x1<<6)
+#define S3C_PCM_IRQSTAT_RXEMPT (0x1<<5)
+#define S3C_PCM_IRQSTAT_RXALMSTEMPT (0x1<<4)
+#define S3C_PCM_IRQSTAT_RXFULL (0x1<<3)
+#define S3C_PCM_IRQSTAT_RXALMSTFULL (0x1<<2)
+#define S3C_PCM_IRQSTAT_RXSTARV (0x1<<1)
+#define S3C_PCM_IRQSTAT_RXERROVRFL (0x1<<0)
+
+/* PCM_FIFOSTAT Bit-Fields */
+#define S3C_PCM_FIFOSTAT_TXCNT_MSK (0x3f<<14)
+#define S3C_PCM_FIFOSTAT_TXFIFOEMPTY (0x1<<13)
+#define S3C_PCM_FIFOSTAT_TXFIFOALMSTEMPTY (0x1<<12)
+#define S3C_PCM_FIFOSTAT_TXFIFOFULL (0x1<<11)
+#define S3C_PCM_FIFOSTAT_TXFIFOALMSTFULL (0x1<<10)
+#define S3C_PCM_FIFOSTAT_RXCNT_MSK (0x3f<<4)
+#define S3C_PCM_FIFOSTAT_RXFIFOEMPTY (0x1<<3)
+#define S3C_PCM_FIFOSTAT_RXFIFOALMSTEMPTY (0x1<<2)
+#define S3C_PCM_FIFOSTAT_RXFIFOFULL (0x1<<1)
+#define S3C_PCM_FIFOSTAT_RXFIFOALMSTFULL (0x1<<0)
+
+#define S3C_PCM_CLKSRC_PCLK 0
+#define S3C_PCM_CLKSRC_MUX 1
+
+#define S3C_PCM_SCLK_PER_FS 0
+
+/**
+ * struct s3c_pcm_info - S3C PCM Controller information
+ * @dev: The parent device passed to use from the probe.
+ * @regs: The pointer to the device register block.
+ * @dma_playback: DMA information for playback channel.
+ * @dma_capture: DMA information for capture channel.
+ */
+struct s3c_pcm_info {
+ spinlock_t lock;
+ struct device *dev;
+ void __iomem *regs;
+
+ unsigned int sclk_per_fs;
+
+ /* Whether to keep PCMSCLK enabled even when idle(no active xfer) */
+ unsigned int idleclk;
+
+ struct clk *pclk;
+ struct clk *cclk;
+
+ struct s3c_dma_params *dma_playback;
+ struct s3c_dma_params *dma_capture;
+};
+
+#endif /* __S3C_PCM_H */
diff --git a/sound/soc/samsung/regs-i2s-v2.h b/sound/soc/samsung/regs-i2s-v2.h
new file mode 100644
index 0000000..5e5e568
--- /dev/null
+++ b/sound/soc/samsung/regs-i2s-v2.h
@@ -0,0 +1,115 @@
+/* linux/include/asm-arm/plat-s3c24xx/regs-s3c2412-iis.h
+ *
+ * Copyright 2007 Simtec Electronics <linux(a)simtec.co.uk>
+ * http://armlinux.simtec.co.uk/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * S3C2412 IIS register definition
+*/
+
+#ifndef __ASM_ARCH_REGS_S3C2412_IIS_H
+#define __ASM_ARCH_REGS_S3C2412_IIS_H
+
+#define S3C2412_IISCON (0x00)
+#define S3C2412_IISMOD (0x04)
+#define S3C2412_IISFIC (0x08)
+#define S3C2412_IISPSR (0x0C)
+#define S3C2412_IISTXD (0x10)
+#define S3C2412_IISRXD (0x14)
+
+#define S5PC1XX_IISFICS 0x18
+#define S5PC1XX_IISTXDS 0x1C
+
+#define S5PC1XX_IISCON_SW_RST (1 << 31)
+#define S5PC1XX_IISCON_FRXOFSTATUS (1 << 26)
+#define S5PC1XX_IISCON_FRXORINTEN (1 << 25)
+#define S5PC1XX_IISCON_FTXSURSTAT (1 << 24)
+#define S5PC1XX_IISCON_FTXSURINTEN (1 << 23)
+#define S5PC1XX_IISCON_TXSDMAPAUSE (1 << 20)
+#define S5PC1XX_IISCON_TXSDMACTIVE (1 << 18)
+
+#define S3C64XX_IISCON_FTXURSTATUS (1 << 17)
+#define S3C64XX_IISCON_FTXURINTEN (1 << 16)
+#define S3C64XX_IISCON_TXFIFO2_EMPTY (1 << 15)
+#define S3C64XX_IISCON_TXFIFO1_EMPTY (1 << 14)
+#define S3C64XX_IISCON_TXFIFO2_FULL (1 << 13)
+#define S3C64XX_IISCON_TXFIFO1_FULL (1 << 12)
+
+#define S3C2412_IISCON_LRINDEX (1 << 11)
+#define S3C2412_IISCON_TXFIFO_EMPTY (1 << 10)
+#define S3C2412_IISCON_RXFIFO_EMPTY (1 << 9)
+#define S3C2412_IISCON_TXFIFO_FULL (1 << 8)
+#define S3C2412_IISCON_RXFIFO_FULL (1 << 7)
+#define S3C2412_IISCON_TXDMA_PAUSE (1 << 6)
+#define S3C2412_IISCON_RXDMA_PAUSE (1 << 5)
+#define S3C2412_IISCON_TXCH_PAUSE (1 << 4)
+#define S3C2412_IISCON_RXCH_PAUSE (1 << 3)
+#define S3C2412_IISCON_TXDMA_ACTIVE (1 << 2)
+#define S3C2412_IISCON_RXDMA_ACTIVE (1 << 1)
+#define S3C2412_IISCON_IIS_ACTIVE (1 << 0)
+
+#define S5PC1XX_IISMOD_OPCLK_CDCLK_OUT (0 << 30)
+#define S5PC1XX_IISMOD_OPCLK_CDCLK_IN (1 << 30)
+#define S5PC1XX_IISMOD_OPCLK_BCLK_OUT (2 << 30)
+#define S5PC1XX_IISMOD_OPCLK_PCLK (3 << 30)
+#define S5PC1XX_IISMOD_OPCLK_MASK (3 << 30)
+#define S5PC1XX_IISMOD_TXS_IDMA (1 << 28) /* Sec_TXFIFO use I-DMA */
+#define S5PC1XX_IISMOD_BLCS_MASK 0x3
+#define S5PC1XX_IISMOD_BLCS_SHIFT 26
+#define S5PC1XX_IISMOD_BLCP_MASK 0x3
+#define S5PC1XX_IISMOD_BLCP_SHIFT 24
+
+#define S3C64XX_IISMOD_C2DD_HHALF (1 << 21) /* Discard Higher-half */
+#define S3C64XX_IISMOD_C2DD_LHALF (1 << 20) /* Discard Lower-half */
+#define S3C64XX_IISMOD_C1DD_HHALF (1 << 19)
+#define S3C64XX_IISMOD_C1DD_LHALF (1 << 18)
+#define S3C64XX_IISMOD_DC2_EN (1 << 17)
+#define S3C64XX_IISMOD_DC1_EN (1 << 16)
+#define S3C64XX_IISMOD_BLC_16BIT (0 << 13)
+#define S3C64XX_IISMOD_BLC_8BIT (1 << 13)
+#define S3C64XX_IISMOD_BLC_24BIT (2 << 13)
+#define S3C64XX_IISMOD_BLC_MASK (3 << 13)
+
+#define S3C2412_IISMOD_IMS_SYSMUX (1 << 10)
+#define S3C2412_IISMOD_SLAVE (1 << 11)
+#define S3C2412_IISMOD_MODE_TXONLY (0 << 8)
+#define S3C2412_IISMOD_MODE_RXONLY (1 << 8)
+#define S3C2412_IISMOD_MODE_TXRX (2 << 8)
+#define S3C2412_IISMOD_MODE_MASK (3 << 8)
+#define S3C2412_IISMOD_LR_LLOW (0 << 7)
+#define S3C2412_IISMOD_LR_RLOW (1 << 7)
+#define S3C2412_IISMOD_SDF_IIS (0 << 5)
+#define S3C2412_IISMOD_SDF_MSB (1 << 5)
+#define S3C2412_IISMOD_SDF_LSB (2 << 5)
+#define S3C2412_IISMOD_SDF_MASK (3 << 5)
+#define S3C2412_IISMOD_RCLK_256FS (0 << 3)
+#define S3C2412_IISMOD_RCLK_512FS (1 << 3)
+#define S3C2412_IISMOD_RCLK_384FS (2 << 3)
+#define S3C2412_IISMOD_RCLK_768FS (3 << 3)
+#define S3C2412_IISMOD_RCLK_MASK (3 << 3)
+#define S3C2412_IISMOD_BCLK_32FS (0 << 1)
+#define S3C2412_IISMOD_BCLK_48FS (1 << 1)
+#define S3C2412_IISMOD_BCLK_16FS (2 << 1)
+#define S3C2412_IISMOD_BCLK_24FS (3 << 1)
+#define S3C2412_IISMOD_BCLK_MASK (3 << 1)
+#define S3C2412_IISMOD_8BIT (1 << 0)
+
+#define S3C64XX_IISMOD_CDCLKCON (1 << 12)
+
+#define S3C2412_IISPSR_PSREN (1 << 15)
+
+#define S3C64XX_IISFIC_TX2COUNT(x) (((x) >> 24) & 0xf)
+#define S3C64XX_IISFIC_TX1COUNT(x) (((x) >> 16) & 0xf)
+
+#define S3C2412_IISFIC_TXFLUSH (1 << 15)
+#define S3C2412_IISFIC_RXFLUSH (1 << 7)
+#define S3C2412_IISFIC_TXCOUNT(x) (((x) >> 8) & 0xf)
+#define S3C2412_IISFIC_RXCOUNT(x) (((x) >> 0) & 0xf)
+
+#define S5PC1XX_IISFICS_TXFLUSH (1 << 15)
+#define S5PC1XX_IISFICS_TXCOUNT(x) (((x) >> 8) & 0x7f)
+
+#endif /* __ASM_ARCH_REGS_S3C2412_IIS_H */
diff --git a/sound/soc/samsung/rx1950_uda1380.c b/sound/soc/samsung/rx1950_uda1380.c
new file mode 100644
index 0000000..07197ee
--- /dev/null
+++ b/sound/soc/samsung/rx1950_uda1380.c
@@ -0,0 +1,333 @@
+/*
+ * rx1950.c -- ALSA Soc Audio Layer
+ *
+ * Copyright (c) 2010 Vasily Khoruzhick <anarsoul(a)gmail.com>
+ *
+ * Based on smdk2440.c and magician.c
+ *
+ * Authors: Graeme Gregory graeme.gregory(a)wolfsonmicro.com
+ * Philipp Zabel <philipp.zabel(a)gmail.com>
+ * Denis Grigoriev <dgreenday(a)gmail.com>
+ * Vasily Khoruzhick <anarsoul(a)gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/clk.h>
+
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/uda1380.h>
+#include <sound/jack.h>
+
+#include <plat/regs-iis.h>
+
+#include <mach/regs-clock.h>
+
+#include <asm/mach-types.h>
+
+#include "dma.h"
+#include "s3c24xx-i2s.h"
+#include "../codecs/uda1380.h"
+
+static int rx1950_uda1380_init(struct snd_soc_pcm_runtime *rtd);
+static int rx1950_startup(struct snd_pcm_substream *substream);
+static int rx1950_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params);
+static int rx1950_spk_power(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event);
+
+static unsigned int rates[] = {
+ 16000,
+ 44100,
+ 48000,
+ 88200,
+};
+
+static struct snd_pcm_hw_constraint_list hw_rates = {
+ .count = ARRAY_SIZE(rates),
+ .list = rates,
+ .mask = 0,
+};
+
+static struct snd_soc_jack hp_jack;
+
+static struct snd_soc_jack_pin hp_jack_pins[] = {
+ {
+ .pin = "Headphone Jack",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Speaker",
+ .mask = SND_JACK_HEADPHONE,
+ .invert = 1,
+ },
+};
+
+static struct snd_soc_jack_gpio hp_jack_gpios[] = {
+ [0] = {
+ .gpio = S3C2410_GPG(12),
+ .name = "hp-gpio",
+ .report = SND_JACK_HEADPHONE,
+ .invert = 1,
+ .debounce_time = 200,
+ },
+};
+
+static struct snd_soc_ops rx1950_ops = {
+ .startup = rx1950_startup,
+ .hw_params = rx1950_hw_params,
+};
+
+/* s3c24xx digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link rx1950_uda1380_dai[] = {
+ {
+ .name = "uda1380",
+ .stream_name = "UDA1380 Duplex",
+ .cpu_dai_name = "s3c24xx-iis",
+ .codec_dai_name = "uda1380-hifi",
+ .init = rx1950_uda1380_init,
+ .platform_name = "samsung-audio",
+ .codec_name = "uda1380-codec.0-001a",
+ .ops = &rx1950_ops,
+ },
+};
+
+static struct snd_soc_card rx1950_asoc = {
+ .name = "rx1950",
+ .dai_link = rx1950_uda1380_dai,
+ .num_links = ARRAY_SIZE(rx1950_uda1380_dai),
+};
+
+/* rx1950 machine dapm widgets */
+static const struct snd_soc_dapm_widget uda1380_dapm_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
+ SND_SOC_DAPM_MIC("Mic Jack", NULL),
+ SND_SOC_DAPM_SPK("Speaker", rx1950_spk_power),
+};
+
+/* rx1950 machine audio_map */
+static const struct snd_soc_dapm_route audio_map[] = {
+ /* headphone connected to VOUTLHP, VOUTRHP */
+ {"Headphone Jack", NULL, "VOUTLHP"},
+ {"Headphone Jack", NULL, "VOUTRHP"},
+
+ /* ext speaker connected to VOUTL, VOUTR */
+ {"Speaker", NULL, "VOUTL"},
+ {"Speaker", NULL, "VOUTR"},
+
+ /* mic is connected to VINM */
+ {"VINM", NULL, "Mic Jack"},
+};
+
+static struct platform_device *s3c24xx_snd_device;
+static struct clk *xtal;
+
+static int rx1950_startup(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+
+ runtime->hw.rate_min = hw_rates.list[0];
+ runtime->hw.rate_max = hw_rates.list[hw_rates.count - 1];
+ runtime->hw.rates = SNDRV_PCM_RATE_KNOT;
+
+ return snd_pcm_hw_constraint_list(runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE,
+ &hw_rates);
+}
+
+static int rx1950_spk_power(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ if (SND_SOC_DAPM_EVENT_ON(event))
+ gpio_set_value(S3C2410_GPA(1), 1);
+ else
+ gpio_set_value(S3C2410_GPA(1), 0);
+
+ return 0;
+}
+
+static int rx1950_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ int div;
+ int ret;
+ unsigned int rate = params_rate(params);
+ int clk_source, fs_mode;
+
+ switch (rate) {
+ case 16000:
+ case 48000:
+ clk_source = S3C24XX_CLKSRC_PCLK;
+ fs_mode = S3C2410_IISMOD_256FS;
+ div = s3c24xx_i2s_get_clockrate() / (256 * rate);
+ if (s3c24xx_i2s_get_clockrate() % (256 * rate) > (128 * rate))
+ div++;
+ break;
+ case 44100:
+ case 88200:
+ clk_source = S3C24XX_CLKSRC_MPLL;
+ fs_mode = S3C2410_IISMOD_256FS;
+ div = clk_get_rate(xtal) / (256 * rate);
+ if (clk_get_rate(xtal) % (256 * rate) > (128 * rate))
+ div++;
+ break;
+ default:
+ printk(KERN_ERR "%s: rate %d is not supported\n",
+ __func__, rate);
+ return -EINVAL;
+ }
+
+ /* set codec DAI configuration */
+ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+ if (ret < 0)
+ return ret;
+
+ /* set cpu DAI configuration */
+ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+ if (ret < 0)
+ return ret;
+
+ /* select clock source */
+ ret = snd_soc_dai_set_sysclk(cpu_dai, clk_source, rate,
+ SND_SOC_CLOCK_OUT);
+ if (ret < 0)
+ return ret;
+
+ /* set MCLK division for sample rate */
+ ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK,
+ S3C2410_IISMOD_384FS);
+ if (ret < 0)
+ return ret;
+
+ /* set BCLK division for sample rate */
+ ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_BCLK,
+ S3C2410_IISMOD_32FS);
+ if (ret < 0)
+ return ret;
+
+ /* set prescaler division for sample rate */
+ ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER,
+ S3C24XX_PRESCALE(div, div));
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int rx1950_uda1380_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_codec *codec = rtd->codec;
+ int err;
+
+ /* Add rx1950 specific widgets */
+ err = snd_soc_dapm_new_controls(codec, uda1380_dapm_widgets,
+ ARRAY_SIZE(uda1380_dapm_widgets));
+
+ if (err)
+ return err;
+
+ /* Set up rx1950 specific audio path audio_mapnects */
+ err = snd_soc_dapm_add_routes(codec, audio_map,
+ ARRAY_SIZE(audio_map));
+
+ if (err)
+ return err;
+
+ snd_soc_dapm_enable_pin(codec, "Headphone Jack");
+ snd_soc_dapm_enable_pin(codec, "Speaker");
+
+ snd_soc_dapm_sync(codec);
+
+ snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE,
+ &hp_jack);
+
+ snd_soc_jack_add_pins(&hp_jack, ARRAY_SIZE(hp_jack_pins),
+ hp_jack_pins);
+
+ snd_soc_jack_add_gpios(&hp_jack, ARRAY_SIZE(hp_jack_gpios),
+ hp_jack_gpios);
+
+ return 0;
+}
+
+static int __init rx1950_init(void)
+{
+ int ret;
+
+ if (!machine_is_rx1950())
+ return -ENODEV;
+
+ /* configure some gpios */
+ ret = gpio_request(S3C2410_GPA(1), "speaker-power");
+ if (ret)
+ goto err_gpio;
+
+ ret = gpio_direction_output(S3C2410_GPA(1), 0);
+ if (ret)
+ goto err_gpio_conf;
+
+ s3c24xx_snd_device = platform_device_alloc("soc-audio", -1);
+ if (!s3c24xx_snd_device) {
+ ret = -ENOMEM;
+ goto err_plat_alloc;
+ }
+
+ platform_set_drvdata(s3c24xx_snd_device, &rx1950_asoc);
+ ret = platform_device_add(s3c24xx_snd_device);
+
+ if (ret) {
+ platform_device_put(s3c24xx_snd_device);
+ goto err_plat_add;
+ }
+
+ xtal = clk_get(&s3c24xx_snd_device->dev, "xtal");
+
+ if (IS_ERR(xtal)) {
+ ret = PTR_ERR(xtal);
+ platform_device_unregister(s3c24xx_snd_device);
+ goto err_clk;
+ }
+
+ return 0;
+
+err_clk:
+err_plat_add:
+err_plat_alloc:
+err_gpio_conf:
+ gpio_free(S3C2410_GPA(1));
+
+err_gpio:
+ return ret;
+}
+
+static void __exit rx1950_exit(void)
+{
+ platform_device_unregister(s3c24xx_snd_device);
+ snd_soc_jack_free_gpios(&hp_jack, ARRAY_SIZE(hp_jack_gpios),
+ hp_jack_gpios);
+ clk_put(xtal);
+ gpio_free(S3C2410_GPA(1));
+}
+
+module_init(rx1950_init);
+module_exit(rx1950_exit);
+
+/* Module information */
+MODULE_AUTHOR("Vasily Khoruzhick");
+MODULE_DESCRIPTION("ALSA SoC RX1950");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/samsung/s3c-i2s-v2.c b/sound/soc/samsung/s3c-i2s-v2.c
new file mode 100644
index 0000000..094f36e
--- /dev/null
+++ b/sound/soc/samsung/s3c-i2s-v2.c
@@ -0,0 +1,757 @@
+/* sound/soc/samsung/s3c-i2c-v2.c
+ *
+ * ALSA Soc Audio Layer - I2S core for newer Samsung SoCs.
+ *
+ * Copyright (c) 2006 Wolfson Microelectronics PLC.
+ * Graeme Gregory graeme.gregory(a)wolfsonmicro.com
+ * linux(a)wolfsonmicro.com
+ *
+ * Copyright (c) 2008, 2007, 2004-2005 Simtec Electronics
+ * http://armlinux.simtec.co.uk/
+ * Ben Dooks <ben(a)simtec.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include <mach/dma.h>
+
+#include "regs-i2s-v2.h"
+#include "s3c-i2s-v2.h"
+#include "dma.h"
+
+#undef S3C_IIS_V2_SUPPORTED
+
+#if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413) \
+ || defined(CONFIG_CPU_S5PV210)
+#define S3C_IIS_V2_SUPPORTED
+#endif
+
+#ifdef CONFIG_PLAT_S3C64XX
+#define S3C_IIS_V2_SUPPORTED
+#endif
+
+#ifndef S3C_IIS_V2_SUPPORTED
+#error Unsupported CPU model
+#endif
+
+#define S3C2412_I2S_DEBUG_CON 0
+
+static inline struct s3c_i2sv2_info *to_info(struct snd_soc_dai *cpu_dai)
+{
+ return snd_soc_dai_get_drvdata(cpu_dai);
+}
+
+#define bit_set(v, b) (((v) & (b)) ? 1 : 0)
+
+#if S3C2412_I2S_DEBUG_CON
+static void dbg_showcon(const char *fn, u32 con)
+{
+ printk(KERN_DEBUG "%s: LRI=%d, TXFEMPT=%d, RXFEMPT=%d, TXFFULL=%d, RXFFULL=%d\n", fn,
+ bit_set(con, S3C2412_IISCON_LRINDEX),
+ bit_set(con, S3C2412_IISCON_TXFIFO_EMPTY),
+ bit_set(con, S3C2412_IISCON_RXFIFO_EMPTY),
+ bit_set(con, S3C2412_IISCON_TXFIFO_FULL),
+ bit_set(con, S3C2412_IISCON_RXFIFO_FULL));
+
+ printk(KERN_DEBUG "%s: PAUSE: TXDMA=%d, RXDMA=%d, TXCH=%d, RXCH=%d\n",
+ fn,
+ bit_set(con, S3C2412_IISCON_TXDMA_PAUSE),
+ bit_set(con, S3C2412_IISCON_RXDMA_PAUSE),
+ bit_set(con, S3C2412_IISCON_TXCH_PAUSE),
+ bit_set(con, S3C2412_IISCON_RXCH_PAUSE));
+ printk(KERN_DEBUG "%s: ACTIVE: TXDMA=%d, RXDMA=%d, IIS=%d\n", fn,
+ bit_set(con, S3C2412_IISCON_TXDMA_ACTIVE),
+ bit_set(con, S3C2412_IISCON_RXDMA_ACTIVE),
+ bit_set(con, S3C2412_IISCON_IIS_ACTIVE));
+}
+#else
+static inline void dbg_showcon(const char *fn, u32 con)
+{
+}
+#endif
+
+
+/* Turn on or off the transmission path. */
+static void s3c2412_snd_txctrl(struct s3c_i2sv2_info *i2s, int on)
+{
+ void __iomem *regs = i2s->regs;
+ u32 fic, con, mod;
+
+ pr_debug("%s(%d)\n", __func__, on);
+
+ fic = readl(regs + S3C2412_IISFIC);
+ con = readl(regs + S3C2412_IISCON);
+ mod = readl(regs + S3C2412_IISMOD);
+
+ pr_debug("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
+
+ if (on) {
+ con |= S3C2412_IISCON_TXDMA_ACTIVE | S3C2412_IISCON_IIS_ACTIVE;
+ con &= ~S3C2412_IISCON_TXDMA_PAUSE;
+ con &= ~S3C2412_IISCON_TXCH_PAUSE;
+
+ switch (mod & S3C2412_IISMOD_MODE_MASK) {
+ case S3C2412_IISMOD_MODE_TXONLY:
+ case S3C2412_IISMOD_MODE_TXRX:
+ /* do nothing, we are in the right mode */
+ break;
+
+ case S3C2412_IISMOD_MODE_RXONLY:
+ mod &= ~S3C2412_IISMOD_MODE_MASK;
+ mod |= S3C2412_IISMOD_MODE_TXRX;
+ break;
+
+ default:
+ dev_err(i2s->dev, "TXEN: Invalid MODE %x in IISMOD\n",
+ mod & S3C2412_IISMOD_MODE_MASK);
+ break;
+ }
+
+ writel(con, regs + S3C2412_IISCON);
+ writel(mod, regs + S3C2412_IISMOD);
+ } else {
+ /* Note, we do not have any indication that the FIFO problems
+ * tha the S3C2410/2440 had apply here, so we should be able
+ * to disable the DMA and TX without resetting the FIFOS.
+ */
+
+ con |= S3C2412_IISCON_TXDMA_PAUSE;
+ con |= S3C2412_IISCON_TXCH_PAUSE;
+ con &= ~S3C2412_IISCON_TXDMA_ACTIVE;
+
+ switch (mod & S3C2412_IISMOD_MODE_MASK) {
+ case S3C2412_IISMOD_MODE_TXRX:
+ mod &= ~S3C2412_IISMOD_MODE_MASK;
+ mod |= S3C2412_IISMOD_MODE_RXONLY;
+ break;
+
+ case S3C2412_IISMOD_MODE_TXONLY:
+ mod &= ~S3C2412_IISMOD_MODE_MASK;
+ con &= ~S3C2412_IISCON_IIS_ACTIVE;
+ break;
+
+ default:
+ dev_err(i2s->dev, "TXDIS: Invalid MODE %x in IISMOD\n",
+ mod & S3C2412_IISMOD_MODE_MASK);
+ break;
+ }
+
+ writel(mod, regs + S3C2412_IISMOD);
+ writel(con, regs + S3C2412_IISCON);
+ }
+
+ fic = readl(regs + S3C2412_IISFIC);
+ dbg_showcon(__func__, con);
+ pr_debug("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
+}
+
+static void s3c2412_snd_rxctrl(struct s3c_i2sv2_info *i2s, int on)
+{
+ void __iomem *regs = i2s->regs;
+ u32 fic, con, mod;
+
+ pr_debug("%s(%d)\n", __func__, on);
+
+ fic = readl(regs + S3C2412_IISFIC);
+ con = readl(regs + S3C2412_IISCON);
+ mod = readl(regs + S3C2412_IISMOD);
+
+ pr_debug("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
+
+ if (on) {
+ con |= S3C2412_IISCON_RXDMA_ACTIVE | S3C2412_IISCON_IIS_ACTIVE;
+ con &= ~S3C2412_IISCON_RXDMA_PAUSE;
+ con &= ~S3C2412_IISCON_RXCH_PAUSE;
+
+ switch (mod & S3C2412_IISMOD_MODE_MASK) {
+ case S3C2412_IISMOD_MODE_TXRX:
+ case S3C2412_IISMOD_MODE_RXONLY:
+ /* do nothing, we are in the right mode */
+ break;
+
+ case S3C2412_IISMOD_MODE_TXONLY:
+ mod &= ~S3C2412_IISMOD_MODE_MASK;
+ mod |= S3C2412_IISMOD_MODE_TXRX;
+ break;
+
+ default:
+ dev_err(i2s->dev, "RXEN: Invalid MODE %x in IISMOD\n",
+ mod & S3C2412_IISMOD_MODE_MASK);
+ }
+
+ writel(mod, regs + S3C2412_IISMOD);
+ writel(con, regs + S3C2412_IISCON);
+ } else {
+ /* See txctrl notes on FIFOs. */
+
+ con &= ~S3C2412_IISCON_RXDMA_ACTIVE;
+ con |= S3C2412_IISCON_RXDMA_PAUSE;
+ con |= S3C2412_IISCON_RXCH_PAUSE;
+
+ switch (mod & S3C2412_IISMOD_MODE_MASK) {
+ case S3C2412_IISMOD_MODE_RXONLY:
+ con &= ~S3C2412_IISCON_IIS_ACTIVE;
+ mod &= ~S3C2412_IISMOD_MODE_MASK;
+ break;
+
+ case S3C2412_IISMOD_MODE_TXRX:
+ mod &= ~S3C2412_IISMOD_MODE_MASK;
+ mod |= S3C2412_IISMOD_MODE_TXONLY;
+ break;
+
+ default:
+ dev_err(i2s->dev, "RXDIS: Invalid MODE %x in IISMOD\n",
+ mod & S3C2412_IISMOD_MODE_MASK);
+ }
+
+ writel(con, regs + S3C2412_IISCON);
+ writel(mod, regs + S3C2412_IISMOD);
+ }
+
+ fic = readl(regs + S3C2412_IISFIC);
+ pr_debug("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
+}
+
+#define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t)
+
+/*
+ * Wait for the LR signal to allow synchronisation to the L/R clock
+ * from the codec. May only be needed for slave mode.
+ */
+static int s3c2412_snd_lrsync(struct s3c_i2sv2_info *i2s)
+{
+ u32 iiscon;
+ unsigned long loops = msecs_to_loops(5);
+
+ pr_debug("Entered %s\n", __func__);
+
+ while (--loops) {
+ iiscon = readl(i2s->regs + S3C2412_IISCON);
+ if (iiscon & S3C2412_IISCON_LRINDEX)
+ break;
+
+ cpu_relax();
+ }
+
+ if (!loops) {
+ printk(KERN_ERR "%s: timeout\n", __func__);
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+/*
+ * Set S3C2412 I2S DAI format
+ */
+static int s3c2412_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
+ unsigned int fmt)
+{
+ struct s3c_i2sv2_info *i2s = to_info(cpu_dai);
+ u32 iismod;
+
+ pr_debug("Entered %s\n", __func__);
+
+ iismod = readl(i2s->regs + S3C2412_IISMOD);
+ pr_debug("hw_params r: IISMOD: %x \n", iismod);
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ i2s->master = 0;
+ iismod |= S3C2412_IISMOD_SLAVE;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ i2s->master = 1;
+ iismod &= ~S3C2412_IISMOD_SLAVE;
+ break;
+ default:
+ pr_err("unknwon master/slave format\n");
+ return -EINVAL;
+ }
+
+ iismod &= ~S3C2412_IISMOD_SDF_MASK;
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_RIGHT_J:
+ iismod |= S3C2412_IISMOD_LR_RLOW;
+ iismod |= S3C2412_IISMOD_SDF_MSB;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ iismod |= S3C2412_IISMOD_LR_RLOW;
+ iismod |= S3C2412_IISMOD_SDF_LSB;
+ break;
+ case SND_SOC_DAIFMT_I2S:
+ iismod &= ~S3C2412_IISMOD_LR_RLOW;
+ iismod |= S3C2412_IISMOD_SDF_IIS;
+ break;
+ default:
+ pr_err("Unknown data format\n");
+ return -EINVAL;
+ }
+
+ writel(iismod, i2s->regs + S3C2412_IISMOD);
+ pr_debug("hw_params w: IISMOD: %x \n", iismod);
+ return 0;
+}
+
+static int s3c_i2sv2_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct s3c_i2sv2_info *i2s = to_info(dai);
+ struct s3c_dma_params *dma_data;
+ u32 iismod;
+
+ pr_debug("Entered %s\n", __func__);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ dma_data = i2s->dma_playback;
+ else
+ dma_data = i2s->dma_capture;
+
+ snd_soc_dai_set_dma_data(dai, substream, dma_data);
+
+ /* Working copies of register */
+ iismod = readl(i2s->regs + S3C2412_IISMOD);
+ pr_debug("%s: r: IISMOD: %x\n", __func__, iismod);
+
+ iismod &= ~S3C64XX_IISMOD_BLC_MASK;
+ /* Sample size */
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S8:
+ iismod |= S3C64XX_IISMOD_BLC_8BIT;
+ break;
+ case SNDRV_PCM_FORMAT_S16_LE:
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ iismod |= S3C64XX_IISMOD_BLC_24BIT;
+ break;
+ }
+
+ writel(iismod, i2s->regs + S3C2412_IISMOD);
+ pr_debug("%s: w: IISMOD: %x\n", __func__, iismod);
+
+ return 0;
+}
+
+static int s3c_i2sv2_set_sysclk(struct snd_soc_dai *cpu_dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct s3c_i2sv2_info *i2s = to_info(cpu_dai);
+ u32 iismod = readl(i2s->regs + S3C2412_IISMOD);
+
+ pr_debug("Entered %s\n", __func__);
+ pr_debug("%s r: IISMOD: %x\n", __func__, iismod);
+
+ switch (clk_id) {
+ case S3C_I2SV2_CLKSRC_PCLK:
+ iismod &= ~S3C2412_IISMOD_IMS_SYSMUX;
+ break;
+
+ case S3C_I2SV2_CLKSRC_AUDIOBUS:
+ iismod |= S3C2412_IISMOD_IMS_SYSMUX;
+ break;
+
+ case S3C_I2SV2_CLKSRC_CDCLK:
+ /* Error if controller doesn't have the CDCLKCON bit */
+ if (!(i2s->feature & S3C_FEATURE_CDCLKCON))
+ return -EINVAL;
+
+ switch (dir) {
+ case SND_SOC_CLOCK_IN:
+ iismod |= S3C64XX_IISMOD_CDCLKCON;
+ break;
+ case SND_SOC_CLOCK_OUT:
+ iismod &= ~S3C64XX_IISMOD_CDCLKCON;
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ writel(iismod, i2s->regs + S3C2412_IISMOD);
+ pr_debug("%s w: IISMOD: %x\n", __func__, iismod);
+
+ return 0;
+}
+
+static int s3c2412_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct s3c_i2sv2_info *i2s = to_info(rtd->cpu_dai);
+ int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
+ unsigned long irqs;
+ int ret = 0;
+ struct s3c_dma_params *dma_data =
+ snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
+
+ pr_debug("Entered %s\n", __func__);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ /* On start, ensure that the FIFOs are cleared and reset. */
+
+ writel(capture ? S3C2412_IISFIC_RXFLUSH : S3C2412_IISFIC_TXFLUSH,
+ i2s->regs + S3C2412_IISFIC);
+
+ /* clear again, just in case */
+ writel(0x0, i2s->regs + S3C2412_IISFIC);
+
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ if (!i2s->master) {
+ ret = s3c2412_snd_lrsync(i2s);
+ if (ret)
+ goto exit_err;
+ }
+
+ local_irq_save(irqs);
+
+ if (capture)
+ s3c2412_snd_rxctrl(i2s, 1);
+ else
+ s3c2412_snd_txctrl(i2s, 1);
+
+ local_irq_restore(irqs);
+
+ /*
+ * Load the next buffer to DMA to meet the reqirement
+ * of the auto reload mechanism of S3C24XX.
+ * This call won't bother S3C64XX.
+ */
+ s3c2410_dma_ctrl(dma_data->channel, S3C2410_DMAOP_STARTED);
+
+ break;
+
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ local_irq_save(irqs);
+
+ if (capture)
+ s3c2412_snd_rxctrl(i2s, 0);
+ else
+ s3c2412_snd_txctrl(i2s, 0);
+
+ local_irq_restore(irqs);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+exit_err:
+ return ret;
+}
+
+/*
+ * Set S3C2412 Clock dividers
+ */
+static int s3c2412_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai,
+ int div_id, int div)
+{
+ struct s3c_i2sv2_info *i2s = to_info(cpu_dai);
+ u32 reg;
+
+ pr_debug("%s(%p, %d, %d)\n", __func__, cpu_dai, div_id, div);
+
+ switch (div_id) {
+ case S3C_I2SV2_DIV_BCLK:
+ switch (div) {
+ case 16:
+ div = S3C2412_IISMOD_BCLK_16FS;
+ break;
+
+ case 32:
+ div = S3C2412_IISMOD_BCLK_32FS;
+ break;
+
+ case 24:
+ div = S3C2412_IISMOD_BCLK_24FS;
+ break;
+
+ case 48:
+ div = S3C2412_IISMOD_BCLK_48FS;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ reg = readl(i2s->regs + S3C2412_IISMOD);
+ reg &= ~S3C2412_IISMOD_BCLK_MASK;
+ writel(reg | div, i2s->regs + S3C2412_IISMOD);
+
+ pr_debug("%s: MOD=%08x\n", __func__, readl(i2s->regs + S3C2412_IISMOD));
+ break;
+
+ case S3C_I2SV2_DIV_RCLK:
+ switch (div) {
+ case 256:
+ div = S3C2412_IISMOD_RCLK_256FS;
+ break;
+
+ case 384:
+ div = S3C2412_IISMOD_RCLK_384FS;
+ break;
+
+ case 512:
+ div = S3C2412_IISMOD_RCLK_512FS;
+ break;
+
+ case 768:
+ div = S3C2412_IISMOD_RCLK_768FS;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ reg = readl(i2s->regs + S3C2412_IISMOD);
+ reg &= ~S3C2412_IISMOD_RCLK_MASK;
+ writel(reg | div, i2s->regs + S3C2412_IISMOD);
+ pr_debug("%s: MOD=%08x\n", __func__, readl(i2s->regs + S3C2412_IISMOD));
+ break;
+
+ case S3C_I2SV2_DIV_PRESCALER:
+ if (div >= 0) {
+ writel((div << 8) | S3C2412_IISPSR_PSREN,
+ i2s->regs + S3C2412_IISPSR);
+ } else {
+ writel(0x0, i2s->regs + S3C2412_IISPSR);
+ }
+ pr_debug("%s: PSR=%08x\n", __func__, readl(i2s->regs + S3C2412_IISPSR));
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static snd_pcm_sframes_t s3c2412_i2s_delay(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct s3c_i2sv2_info *i2s = to_info(dai);
+ u32 reg = readl(i2s->regs + S3C2412_IISFIC);
+ snd_pcm_sframes_t delay;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ delay = S3C2412_IISFIC_TXCOUNT(reg);
+ else
+ delay = S3C2412_IISFIC_RXCOUNT(reg);
+
+ return delay;
+}
+
+struct clk *s3c_i2sv2_get_clock(struct snd_soc_dai *cpu_dai)
+{
+ struct s3c_i2sv2_info *i2s = to_info(cpu_dai);
+ u32 iismod = readl(i2s->regs + S3C2412_IISMOD);
+
+ if (iismod & S3C2412_IISMOD_IMS_SYSMUX)
+ return i2s->iis_cclk;
+ else
+ return i2s->iis_pclk;
+}
+EXPORT_SYMBOL_GPL(s3c_i2sv2_get_clock);
+
+/* default table of all avaialable root fs divisors */
+static unsigned int iis_fs_tab[] = { 256, 512, 384, 768 };
+
+int s3c_i2sv2_iis_calc_rate(struct s3c_i2sv2_rate_calc *info,
+ unsigned int *fstab,
+ unsigned int rate, struct clk *clk)
+{
+ unsigned long clkrate = clk_get_rate(clk);
+ unsigned int div;
+ unsigned int fsclk;
+ unsigned int actual;
+ unsigned int fs;
+ unsigned int fsdiv;
+ signed int deviation = 0;
+ unsigned int best_fs = 0;
+ unsigned int best_div = 0;
+ unsigned int best_rate = 0;
+ unsigned int best_deviation = INT_MAX;
+
+ pr_debug("Input clock rate %ldHz\n", clkrate);
+
+ if (fstab == NULL)
+ fstab = iis_fs_tab;
+
+ for (fs = 0; fs < ARRAY_SIZE(iis_fs_tab); fs++) {
+ fsdiv = iis_fs_tab[fs];
+
+ fsclk = clkrate / fsdiv;
+ div = fsclk / rate;
+
+ if ((fsclk % rate) > (rate / 2))
+ div++;
+
+ if (div <= 1)
+ continue;
+
+ actual = clkrate / (fsdiv * div);
+ deviation = actual - rate;
+
+ printk(KERN_DEBUG "%ufs: div %u => result %u, deviation %d\n",
+ fsdiv, div, actual, deviation);
+
+ deviation = abs(deviation);
+
+ if (deviation < best_deviation) {
+ best_fs = fsdiv;
+ best_div = div;
+ best_rate = actual;
+ best_deviation = deviation;
+ }
+
+ if (deviation == 0)
+ break;
+ }
+
+ printk(KERN_DEBUG "best: fs=%u, div=%u, rate=%u\n",
+ best_fs, best_div, best_rate);
+
+ info->fs_div = best_fs;
+ info->clk_div = best_div;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(s3c_i2sv2_iis_calc_rate);
+
+int s3c_i2sv2_probe(struct snd_soc_dai *dai,
+ struct s3c_i2sv2_info *i2s,
+ unsigned long base)
+{
+ struct device *dev = dai->dev;
+ unsigned int iismod;
+
+ i2s->dev = dev;
+
+ /* record our i2s structure for later use in the callbacks */
+ snd_soc_dai_set_drvdata(dai, i2s);
+
+ i2s->regs = ioremap(base, 0x100);
+ if (i2s->regs == NULL) {
+ dev_err(dev, "cannot ioremap registers\n");
+ return -ENXIO;
+ }
+
+ i2s->iis_pclk = clk_get(dev, "iis");
+ if (IS_ERR(i2s->iis_pclk)) {
+ dev_err(dev, "failed to get iis_clock\n");
+ iounmap(i2s->regs);
+ return -ENOENT;
+ }
+
+ clk_enable(i2s->iis_pclk);
+
+ /* Mark ourselves as in TXRX mode so we can run through our cleanup
+ * process without warnings. */
+ iismod = readl(i2s->regs + S3C2412_IISMOD);
+ iismod |= S3C2412_IISMOD_MODE_TXRX;
+ writel(iismod, i2s->regs + S3C2412_IISMOD);
+ s3c2412_snd_txctrl(i2s, 0);
+ s3c2412_snd_rxctrl(i2s, 0);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(s3c_i2sv2_probe);
+
+#ifdef CONFIG_PM
+static int s3c2412_i2s_suspend(struct snd_soc_dai *dai)
+{
+ struct s3c_i2sv2_info *i2s = to_info(dai);
+ u32 iismod;
+
+ if (dai->active) {
+ i2s->suspend_iismod = readl(i2s->regs + S3C2412_IISMOD);
+ i2s->suspend_iiscon = readl(i2s->regs + S3C2412_IISCON);
+ i2s->suspend_iispsr = readl(i2s->regs + S3C2412_IISPSR);
+
+ /* some basic suspend checks */
+
+ iismod = readl(i2s->regs + S3C2412_IISMOD);
+
+ if (iismod & S3C2412_IISCON_RXDMA_ACTIVE)
+ pr_warning("%s: RXDMA active?\n", __func__);
+
+ if (iismod & S3C2412_IISCON_TXDMA_ACTIVE)
+ pr_warning("%s: TXDMA active?\n", __func__);
+
+ if (iismod & S3C2412_IISCON_IIS_ACTIVE)
+ pr_warning("%s: IIS active\n", __func__);
+ }
+
+ return 0;
+}
+
+static int s3c2412_i2s_resume(struct snd_soc_dai *dai)
+{
+ struct s3c_i2sv2_info *i2s = to_info(dai);
+
+ pr_info("dai_active %d, IISMOD %08x, IISCON %08x\n",
+ dai->active, i2s->suspend_iismod, i2s->suspend_iiscon);
+
+ if (dai->active) {
+ writel(i2s->suspend_iiscon, i2s->regs + S3C2412_IISCON);
+ writel(i2s->suspend_iismod, i2s->regs + S3C2412_IISMOD);
+ writel(i2s->suspend_iispsr, i2s->regs + S3C2412_IISPSR);
+
+ writel(S3C2412_IISFIC_RXFLUSH | S3C2412_IISFIC_TXFLUSH,
+ i2s->regs + S3C2412_IISFIC);
+
+ ndelay(250);
+ writel(0x0, i2s->regs + S3C2412_IISFIC);
+ }
+
+ return 0;
+}
+#else
+#define s3c2412_i2s_suspend NULL
+#define s3c2412_i2s_resume NULL
+#endif
+
+int s3c_i2sv2_register_dai(struct device *dev, int id,
+ struct snd_soc_dai_driver *drv)
+{
+ struct snd_soc_dai_ops *ops = drv->ops;
+
+ ops->trigger = s3c2412_i2s_trigger;
+ if (!ops->hw_params)
+ ops->hw_params = s3c_i2sv2_hw_params;
+ ops->set_fmt = s3c2412_i2s_set_fmt;
+ ops->set_clkdiv = s3c2412_i2s_set_clkdiv;
+ ops->set_sysclk = s3c_i2sv2_set_sysclk;
+
+ /* Allow overriding by (for example) IISv4 */
+ if (!ops->delay)
+ ops->delay = s3c2412_i2s_delay;
+
+ drv->suspend = s3c2412_i2s_suspend;
+ drv->resume = s3c2412_i2s_resume;
+
+ return snd_soc_register_dai(dev, drv);
+}
+EXPORT_SYMBOL_GPL(s3c_i2sv2_register_dai);
+
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/samsung/s3c-i2s-v2.h b/sound/soc/samsung/s3c-i2s-v2.h
new file mode 100644
index 0000000..f8297d9
--- /dev/null
+++ b/sound/soc/samsung/s3c-i2s-v2.h
@@ -0,0 +1,106 @@
+/* sound/soc/samsung/s3c-i2s-v2.h
+ *
+ * ALSA Soc Audio Layer - S3C_I2SV2 I2S driver
+ *
+ * Copyright (c) 2007 Simtec Electronics
+ * http://armlinux.simtec.co.uk/
+ * Ben Dooks <ben(a)simtec.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+*/
+
+/* This code is the core support for the I2S block found in a number of
+ * Samsung SoC devices which is unofficially named I2S-V2. Currently the
+ * S3C2412 and the S3C64XX series use this block to provide 1 or 2 I2S
+ * channels via configurable GPIO.
+ */
+
+#ifndef __SND_SOC_S3C24XX_S3C_I2SV2_I2S_H
+#define __SND_SOC_S3C24XX_S3C_I2SV2_I2S_H __FILE__
+
+#define S3C_I2SV2_DIV_BCLK (1)
+#define S3C_I2SV2_DIV_RCLK (2)
+#define S3C_I2SV2_DIV_PRESCALER (3)
+
+#define S3C_I2SV2_CLKSRC_PCLK 0
+#define S3C_I2SV2_CLKSRC_AUDIOBUS 1
+#define S3C_I2SV2_CLKSRC_CDCLK 2
+
+/* Set this flag for I2S controllers that have the bit IISMOD[12]
+ * bridge/break RCLK signal and external Xi2sCDCLK pin.
+ */
+#define S3C_FEATURE_CDCLKCON (1 << 0)
+
+/**
+ * struct s3c_i2sv2_info - S3C I2S-V2 information
+ * @dev: The parent device passed to use from the probe.
+ * @regs: The pointer to the device registe block.
+ * @feature: Set of bit-flags indicating features of the controller.
+ * @master: True if the I2S core is the I2S bit clock master.
+ * @dma_playback: DMA information for playback channel.
+ * @dma_capture: DMA information for capture channel.
+ * @suspend_iismod: PM save for the IISMOD register.
+ * @suspend_iiscon: PM save for the IISCON register.
+ * @suspend_iispsr: PM save for the IISPSR register.
+ *
+ * This is the private codec state for the hardware associated with an
+ * I2S channel such as the register mappings and clock sources.
+ */
+struct s3c_i2sv2_info {
+ struct device *dev;
+ void __iomem *regs;
+
+ u32 feature;
+
+ struct clk *iis_pclk;
+ struct clk *iis_cclk;
+
+ unsigned char master;
+
+ struct s3c_dma_params *dma_playback;
+ struct s3c_dma_params *dma_capture;
+
+ u32 suspend_iismod;
+ u32 suspend_iiscon;
+ u32 suspend_iispsr;
+
+ unsigned long base;
+};
+
+extern struct clk *s3c_i2sv2_get_clock(struct snd_soc_dai *cpu_dai);
+
+struct s3c_i2sv2_rate_calc {
+ unsigned int clk_div; /* for prescaler */
+ unsigned int fs_div; /* for root frame clock */
+};
+
+extern int s3c_i2sv2_iis_calc_rate(struct s3c_i2sv2_rate_calc *info,
+ unsigned int *fstab,
+ unsigned int rate, struct clk *clk);
+
+/**
+ * s3c_i2sv2_probe - probe for i2s device helper
+ * @dai: The ASoC DAI structure supplied to the original probe.
+ * @i2s: Our local i2s structure to fill in.
+ * @base: The base address for the registers.
+ */
+extern int s3c_i2sv2_probe(struct snd_soc_dai *dai,
+ struct s3c_i2sv2_info *i2s,
+ unsigned long base);
+
+/**
+ * s3c_i2sv2_register_dai - register dai with soc core
+ * @dev: DAI device
+ * @id: DAI ID
+ * @drv: The driver structure to register
+ *
+ * Fill in any missing fields and then register the given dai with the
+ * soc core.
+ */
+extern int s3c_i2sv2_register_dai(struct device *dev, int id,
+ struct snd_soc_dai_driver *drv);
+
+#endif /* __SND_SOC_S3C24XX_S3C_I2SV2_I2S_H */
diff --git a/sound/soc/samsung/s3c2412-i2s.c b/sound/soc/samsung/s3c2412-i2s.c
new file mode 100644
index 0000000..7ea8378
--- /dev/null
+++ b/sound/soc/samsung/s3c2412-i2s.c
@@ -0,0 +1,212 @@
+/* sound/soc/samsung/s3c2412-i2s.c
+ *
+ * ALSA Soc Audio Layer - S3C2412 I2S driver
+ *
+ * Copyright (c) 2006 Wolfson Microelectronics PLC.
+ * Graeme Gregory graeme.gregory(a)wolfsonmicro.com
+ * linux(a)wolfsonmicro.com
+ *
+ * Copyright (c) 2007, 2004-2005 Simtec Electronics
+ * http://armlinux.simtec.co.uk/
+ * Ben Dooks <ben(a)simtec.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/clk.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include <mach/hardware.h>
+
+#include <mach/regs-gpio.h>
+#include <mach/dma.h>
+
+#include "dma.h"
+#include "regs-i2s-v2.h"
+#include "s3c2412-i2s.h"
+
+#define S3C2412_I2S_DEBUG 0
+
+static struct s3c2410_dma_client s3c2412_dma_client_out = {
+ .name = "I2S PCM Stereo out"
+};
+
+static struct s3c2410_dma_client s3c2412_dma_client_in = {
+ .name = "I2S PCM Stereo in"
+};
+
+static struct s3c_dma_params s3c2412_i2s_pcm_stereo_out = {
+ .client = &s3c2412_dma_client_out,
+ .channel = DMACH_I2S_OUT,
+ .dma_addr = S3C2410_PA_IIS + S3C2412_IISTXD,
+ .dma_size = 4,
+};
+
+static struct s3c_dma_params s3c2412_i2s_pcm_stereo_in = {
+ .client = &s3c2412_dma_client_in,
+ .channel = DMACH_I2S_IN,
+ .dma_addr = S3C2410_PA_IIS + S3C2412_IISRXD,
+ .dma_size = 4,
+};
+
+static struct s3c_i2sv2_info s3c2412_i2s;
+
+static int s3c2412_i2s_probe(struct snd_soc_dai *dai)
+{
+ int ret;
+
+ pr_debug("Entered %s\n", __func__);
+
+ ret = s3c_i2sv2_probe(dai, &s3c2412_i2s, S3C2410_PA_IIS);
+ if (ret)
+ return ret;
+
+ s3c2412_i2s.dma_capture = &s3c2412_i2s_pcm_stereo_in;
+ s3c2412_i2s.dma_playback = &s3c2412_i2s_pcm_stereo_out;
+
+ s3c2412_i2s.iis_cclk = clk_get(dai->dev, "i2sclk");
+ if (s3c2412_i2s.iis_cclk == NULL) {
+ pr_err("failed to get i2sclk clock\n");
+ iounmap(s3c2412_i2s.regs);
+ return -ENODEV;
+ }
+
+ /* Set MPLL as the source for IIS CLK */
+
+ clk_set_parent(s3c2412_i2s.iis_cclk, clk_get(NULL, "mpll"));
+ clk_enable(s3c2412_i2s.iis_cclk);
+
+ s3c2412_i2s.iis_cclk = s3c2412_i2s.iis_pclk;
+
+ /* Configure the I2S pins in correct mode */
+ s3c2410_gpio_cfgpin(S3C2410_GPE0, S3C2410_GPE0_I2SLRCK);
+ s3c2410_gpio_cfgpin(S3C2410_GPE1, S3C2410_GPE1_I2SSCLK);
+ s3c2410_gpio_cfgpin(S3C2410_GPE2, S3C2410_GPE2_CDCLK);
+ s3c2410_gpio_cfgpin(S3C2410_GPE3, S3C2410_GPE3_I2SSDI);
+ s3c2410_gpio_cfgpin(S3C2410_GPE4, S3C2410_GPE4_I2SSDO);
+
+ return 0;
+}
+
+static int s3c2412_i2s_remove(struct snd_soc_dai *dai)
+{
+ clk_disable(s3c2412_i2s.iis_cclk);
+ clk_put(s3c2412_i2s.iis_cclk);
+ iounmap(s3c2412_i2s.regs);
+
+ return 0;
+}
+
+static int s3c2412_i2s_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *cpu_dai)
+{
+ struct s3c_i2sv2_info *i2s = snd_soc_dai_get_drvdata(cpu_dai);
+ struct s3c_dma_params *dma_data;
+ u32 iismod;
+
+ pr_debug("Entered %s\n", __func__);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ dma_data = i2s->dma_playback;
+ else
+ dma_data = i2s->dma_capture;
+
+ snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data);
+
+ iismod = readl(i2s->regs + S3C2412_IISMOD);
+ pr_debug("%s: r: IISMOD: %x\n", __func__, iismod);
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S8:
+ iismod |= S3C2412_IISMOD_8BIT;
+ break;
+ case SNDRV_PCM_FORMAT_S16_LE:
+ iismod &= ~S3C2412_IISMOD_8BIT;
+ break;
+ }
+
+ writel(iismod, i2s->regs + S3C2412_IISMOD);
+ pr_debug("%s: w: IISMOD: %x\n", __func__, iismod);
+
+ return 0;
+}
+
+#define S3C2412_I2S_RATES \
+ (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \
+ SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
+ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
+
+static struct snd_soc_dai_ops s3c2412_i2s_dai_ops = {
+ .hw_params = s3c2412_i2s_hw_params,
+};
+
+static struct snd_soc_dai_driver s3c2412_i2s_dai = {
+ .probe = s3c2412_i2s_probe,
+ .remove = s3c2412_i2s_remove,
+ .playback = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = S3C2412_I2S_RATES,
+ .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .capture = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = S3C2412_I2S_RATES,
+ .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .ops = &s3c2412_i2s_dai_ops,
+};
+
+static __devinit int s3c2412_iis_dev_probe(struct platform_device *pdev)
+{
+ return snd_soc_register_dai(&pdev->dev, &s3c2412_i2s_dai);
+}
+
+static __devexit int s3c2412_iis_dev_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_dai(&pdev->dev);
+ return 0;
+}
+
+static struct platform_driver s3c2412_iis_driver = {
+ .probe = s3c2412_iis_dev_probe,
+ .remove = s3c2412_iis_dev_remove,
+ .driver = {
+ .name = "s3c2412-iis",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init s3c2412_i2s_init(void)
+{
+ return platform_driver_register(&s3c2412_iis_driver);
+}
+module_init(s3c2412_i2s_init);
+
+static void __exit s3c2412_i2s_exit(void)
+{
+ platform_driver_unregister(&s3c2412_iis_driver);
+}
+module_exit(s3c2412_i2s_exit);
+
+/* Module information */
+MODULE_AUTHOR("Ben Dooks, <ben(a)simtec.co.uk>");
+MODULE_DESCRIPTION("S3C2412 I2S SoC Interface");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:s3c2412-iis");
diff --git a/sound/soc/samsung/s3c2412-i2s.h b/sound/soc/samsung/s3c2412-i2s.h
new file mode 100644
index 0000000..02ad579
--- /dev/null
+++ b/sound/soc/samsung/s3c2412-i2s.h
@@ -0,0 +1,27 @@
+/* sound/soc/samsung/s3c2412-i2s.c
+ *
+ * ALSA Soc Audio Layer - S3C2412 I2S driver
+ *
+ * Copyright (c) 2007 Simtec Electronics
+ * http://armlinux.simtec.co.uk/
+ * Ben Dooks <ben(a)simtec.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+*/
+
+#ifndef __SND_SOC_S3C24XX_S3C2412_I2S_H
+#define __SND_SOC_S3C24XX_S3C2412_I2S_H __FILE__
+
+#include "s3c-i2s-v2.h"
+
+#define S3C2412_DIV_BCLK S3C_I2SV2_DIV_BCLK
+#define S3C2412_DIV_RCLK S3C_I2SV2_DIV_RCLK
+#define S3C2412_DIV_PRESCALER S3C_I2SV2_DIV_PRESCALER
+
+#define S3C2412_CLKSRC_PCLK S3C_I2SV2_CLKSRC_PCLK
+#define S3C2412_CLKSRC_I2SCLK S3C_I2SV2_CLKSRC_AUDIOBUS
+
+#endif /* __SND_SOC_S3C24XX_S3C2412_I2S_H */
diff --git a/sound/soc/samsung/s3c24xx-i2s.c b/sound/soc/samsung/s3c24xx-i2s.c
new file mode 100644
index 0000000..13e41ed
--- /dev/null
+++ b/sound/soc/samsung/s3c24xx-i2s.c
@@ -0,0 +1,519 @@
+/*
+ * s3c24xx-i2s.c -- ALSA Soc Audio Layer
+ *
+ * (c) 2006 Wolfson Microelectronics PLC.
+ * Graeme Gregory graeme.gregory(a)wolfsonmicro.com or linux(a)wolfsonmicro.com
+ *
+ * Copyright 2004-2005 Simtec Electronics
+ * http://armlinux.simtec.co.uk/
+ * Ben Dooks <ben(a)simtec.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/jiffies.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+#include <mach/hardware.h>
+#include <mach/regs-gpio.h>
+#include <mach/regs-clock.h>
+
+#include <asm/dma.h>
+#include <mach/dma.h>
+
+#include <plat/regs-iis.h>
+
+#include "dma.h"
+#include "s3c24xx-i2s.h"
+
+static struct s3c2410_dma_client s3c24xx_dma_client_out = {
+ .name = "I2S PCM Stereo out"
+};
+
+static struct s3c2410_dma_client s3c24xx_dma_client_in = {
+ .name = "I2S PCM Stereo in"
+};
+
+static struct s3c_dma_params s3c24xx_i2s_pcm_stereo_out = {
+ .client = &s3c24xx_dma_client_out,
+ .channel = DMACH_I2S_OUT,
+ .dma_addr = S3C2410_PA_IIS + S3C2410_IISFIFO,
+ .dma_size = 2,
+};
+
+static struct s3c_dma_params s3c24xx_i2s_pcm_stereo_in = {
+ .client = &s3c24xx_dma_client_in,
+ .channel = DMACH_I2S_IN,
+ .dma_addr = S3C2410_PA_IIS + S3C2410_IISFIFO,
+ .dma_size = 2,
+};
+
+struct s3c24xx_i2s_info {
+ void __iomem *regs;
+ struct clk *iis_clk;
+ u32 iiscon;
+ u32 iismod;
+ u32 iisfcon;
+ u32 iispsr;
+};
+static struct s3c24xx_i2s_info s3c24xx_i2s;
+
+static void s3c24xx_snd_txctrl(int on)
+{
+ u32 iisfcon;
+ u32 iiscon;
+ u32 iismod;
+
+ pr_debug("Entered %s\n", __func__);
+
+ iisfcon = readl(s3c24xx_i2s.regs + S3C2410_IISFCON);
+ iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON);
+ iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
+
+ pr_debug("r: IISCON: %x IISMOD: %x IISFCON: %x\n", iiscon, iismod, iisfcon);
+
+ if (on) {
+ iisfcon |= S3C2410_IISFCON_TXDMA | S3C2410_IISFCON_TXENABLE;
+ iiscon |= S3C2410_IISCON_TXDMAEN | S3C2410_IISCON_IISEN;
+ iiscon &= ~S3C2410_IISCON_TXIDLE;
+ iismod |= S3C2410_IISMOD_TXMODE;
+
+ writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD);
+ writel(iisfcon, s3c24xx_i2s.regs + S3C2410_IISFCON);
+ writel(iiscon, s3c24xx_i2s.regs + S3C2410_IISCON);
+ } else {
+ /* note, we have to disable the FIFOs otherwise bad things
+ * seem to happen when the DMA stops. According to the
+ * Samsung supplied kernel, this should allow the DMA
+ * engine and FIFOs to reset. If this isn't allowed, the
+ * DMA engine will simply freeze randomly.
+ */
+
+ iisfcon &= ~S3C2410_IISFCON_TXENABLE;
+ iisfcon &= ~S3C2410_IISFCON_TXDMA;
+ iiscon |= S3C2410_IISCON_TXIDLE;
+ iiscon &= ~S3C2410_IISCON_TXDMAEN;
+ iismod &= ~S3C2410_IISMOD_TXMODE;
+
+ writel(iiscon, s3c24xx_i2s.regs + S3C2410_IISCON);
+ writel(iisfcon, s3c24xx_i2s.regs + S3C2410_IISFCON);
+ writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD);
+ }
+
+ pr_debug("w: IISCON: %x IISMOD: %x IISFCON: %x\n", iiscon, iismod, iisfcon);
+}
+
+static void s3c24xx_snd_rxctrl(int on)
+{
+ u32 iisfcon;
+ u32 iiscon;
+ u32 iismod;
+
+ pr_debug("Entered %s\n", __func__);
+
+ iisfcon = readl(s3c24xx_i2s.regs + S3C2410_IISFCON);
+ iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON);
+ iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
+
+ pr_debug("r: IISCON: %x IISMOD: %x IISFCON: %x\n", iiscon, iismod, iisfcon);
+
+ if (on) {
+ iisfcon |= S3C2410_IISFCON_RXDMA | S3C2410_IISFCON_RXENABLE;
+ iiscon |= S3C2410_IISCON_RXDMAEN | S3C2410_IISCON_IISEN;
+ iiscon &= ~S3C2410_IISCON_RXIDLE;
+ iismod |= S3C2410_IISMOD_RXMODE;
+
+ writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD);
+ writel(iisfcon, s3c24xx_i2s.regs + S3C2410_IISFCON);
+ writel(iiscon, s3c24xx_i2s.regs + S3C2410_IISCON);
+ } else {
+ /* note, we have to disable the FIFOs otherwise bad things
+ * seem to happen when the DMA stops. According to the
+ * Samsung supplied kernel, this should allow the DMA
+ * engine and FIFOs to reset. If this isn't allowed, the
+ * DMA engine will simply freeze randomly.
+ */
+
+ iisfcon &= ~S3C2410_IISFCON_RXENABLE;
+ iisfcon &= ~S3C2410_IISFCON_RXDMA;
+ iiscon |= S3C2410_IISCON_RXIDLE;
+ iiscon &= ~S3C2410_IISCON_RXDMAEN;
+ iismod &= ~S3C2410_IISMOD_RXMODE;
+
+ writel(iisfcon, s3c24xx_i2s.regs + S3C2410_IISFCON);
+ writel(iiscon, s3c24xx_i2s.regs + S3C2410_IISCON);
+ writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD);
+ }
+
+ pr_debug("w: IISCON: %x IISMOD: %x IISFCON: %x\n", iiscon, iismod, iisfcon);
+}
+
+/*
+ * Wait for the LR signal to allow synchronisation to the L/R clock
+ * from the codec. May only be needed for slave mode.
+ */
+static int s3c24xx_snd_lrsync(void)
+{
+ u32 iiscon;
+ int timeout = 50; /* 5ms */
+
+ pr_debug("Entered %s\n", __func__);
+
+ while (1) {
+ iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON);
+ if (iiscon & S3C2410_IISCON_LRINDEX)
+ break;
+
+ if (!timeout--)
+ return -ETIMEDOUT;
+ udelay(100);
+ }
+
+ return 0;
+}
+
+/*
+ * Check whether CPU is the master or slave
+ */
+static inline int s3c24xx_snd_is_clkmaster(void)
+{
+ pr_debug("Entered %s\n", __func__);
+
+ return (readl(s3c24xx_i2s.regs + S3C2410_IISMOD) & S3C2410_IISMOD_SLAVE) ? 0:1;
+}
+
+/*
+ * Set S3C24xx I2S DAI format
+ */
+static int s3c24xx_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
+ unsigned int fmt)
+{
+ u32 iismod;
+
+ pr_debug("Entered %s\n", __func__);
+
+ iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
+ pr_debug("hw_params r: IISMOD: %x \n", iismod);
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ iismod |= S3C2410_IISMOD_SLAVE;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ iismod &= ~S3C2410_IISMOD_SLAVE;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_LEFT_J:
+ iismod |= S3C2410_IISMOD_MSB;
+ break;
+ case SND_SOC_DAIFMT_I2S:
+ iismod &= ~S3C2410_IISMOD_MSB;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD);
+ pr_debug("hw_params w: IISMOD: %x \n", iismod);
+ return 0;
+}
+
+static int s3c24xx_i2s_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 s3c_dma_params *dma_data;
+ u32 iismod;
+
+ pr_debug("Entered %s\n", __func__);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ dma_data = &s3c24xx_i2s_pcm_stereo_out;
+ else
+ dma_data = &s3c24xx_i2s_pcm_stereo_in;
+
+ snd_soc_dai_set_dma_data(rtd->cpu_dai, substream, dma_data);
+
+ /* Working copies of register */
+ iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
+ pr_debug("hw_params r: IISMOD: %x\n", iismod);
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S8:
+ iismod &= ~S3C2410_IISMOD_16BIT;
+ dma_data->dma_size = 1;
+ break;
+ case SNDRV_PCM_FORMAT_S16_LE:
+ iismod |= S3C2410_IISMOD_16BIT;
+ dma_data->dma_size = 2;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD);
+ pr_debug("hw_params w: IISMOD: %x\n", iismod);
+ return 0;
+}
+
+static int s3c24xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *dai)
+{
+ int ret = 0;
+ struct s3c_dma_params *dma_data =
+ snd_soc_dai_get_dma_data(dai, substream);
+
+ pr_debug("Entered %s\n", __func__);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ if (!s3c24xx_snd_is_clkmaster()) {
+ ret = s3c24xx_snd_lrsync();
+ if (ret)
+ goto exit_err;
+ }
+
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ s3c24xx_snd_rxctrl(1);
+ else
+ s3c24xx_snd_txctrl(1);
+
+ s3c2410_dma_ctrl(dma_data->channel, S3C2410_DMAOP_STARTED);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ s3c24xx_snd_rxctrl(0);
+ else
+ s3c24xx_snd_txctrl(0);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+exit_err:
+ return ret;
+}
+
+/*
+ * Set S3C24xx Clock source
+ */
+static int s3c24xx_i2s_set_sysclk(struct snd_soc_dai *cpu_dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ u32 iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
+
+ pr_debug("Entered %s\n", __func__);
+
+ iismod &= ~S3C2440_IISMOD_MPLL;
+
+ switch (clk_id) {
+ case S3C24XX_CLKSRC_PCLK:
+ break;
+ case S3C24XX_CLKSRC_MPLL:
+ iismod |= S3C2440_IISMOD_MPLL;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD);
+ return 0;
+}
+
+/*
+ * Set S3C24xx Clock dividers
+ */
+static int s3c24xx_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai,
+ int div_id, int div)
+{
+ u32 reg;
+
+ pr_debug("Entered %s\n", __func__);
+
+ switch (div_id) {
+ case S3C24XX_DIV_BCLK:
+ reg = readl(s3c24xx_i2s.regs + S3C2410_IISMOD) & ~S3C2410_IISMOD_FS_MASK;
+ writel(reg | div, s3c24xx_i2s.regs + S3C2410_IISMOD);
+ break;
+ case S3C24XX_DIV_MCLK:
+ reg = readl(s3c24xx_i2s.regs + S3C2410_IISMOD) & ~(S3C2410_IISMOD_384FS);
+ writel(reg | div, s3c24xx_i2s.regs + S3C2410_IISMOD);
+ break;
+ case S3C24XX_DIV_PRESCALER:
+ writel(div, s3c24xx_i2s.regs + S3C2410_IISPSR);
+ reg = readl(s3c24xx_i2s.regs + S3C2410_IISCON);
+ writel(reg | S3C2410_IISCON_PSCEN, s3c24xx_i2s.regs + S3C2410_IISCON);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/*
+ * To avoid duplicating clock code, allow machine driver to
+ * get the clockrate from here.
+ */
+u32 s3c24xx_i2s_get_clockrate(void)
+{
+ return clk_get_rate(s3c24xx_i2s.iis_clk);
+}
+EXPORT_SYMBOL_GPL(s3c24xx_i2s_get_clockrate);
+
+static int s3c24xx_i2s_probe(struct snd_soc_dai *dai)
+{
+ pr_debug("Entered %s\n", __func__);
+
+ s3c24xx_i2s.regs = ioremap(S3C2410_PA_IIS, 0x100);
+ if (s3c24xx_i2s.regs == NULL)
+ return -ENXIO;
+
+ s3c24xx_i2s.iis_clk = clk_get(dai->dev, "iis");
+ if (s3c24xx_i2s.iis_clk == NULL) {
+ pr_err("failed to get iis_clock\n");
+ iounmap(s3c24xx_i2s.regs);
+ return -ENODEV;
+ }
+ clk_enable(s3c24xx_i2s.iis_clk);
+
+ /* Configure the I2S pins in correct mode */
+ s3c2410_gpio_cfgpin(S3C2410_GPE0, S3C2410_GPE0_I2SLRCK);
+ s3c2410_gpio_cfgpin(S3C2410_GPE1, S3C2410_GPE1_I2SSCLK);
+ s3c2410_gpio_cfgpin(S3C2410_GPE2, S3C2410_GPE2_CDCLK);
+ s3c2410_gpio_cfgpin(S3C2410_GPE3, S3C2410_GPE3_I2SSDI);
+ s3c2410_gpio_cfgpin(S3C2410_GPE4, S3C2410_GPE4_I2SSDO);
+
+ writel(S3C2410_IISCON_IISEN, s3c24xx_i2s.regs + S3C2410_IISCON);
+
+ s3c24xx_snd_txctrl(0);
+ s3c24xx_snd_rxctrl(0);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int s3c24xx_i2s_suspend(struct snd_soc_dai *cpu_dai)
+{
+ pr_debug("Entered %s\n", __func__);
+
+ s3c24xx_i2s.iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON);
+ s3c24xx_i2s.iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
+ s3c24xx_i2s.iisfcon = readl(s3c24xx_i2s.regs + S3C2410_IISFCON);
+ s3c24xx_i2s.iispsr = readl(s3c24xx_i2s.regs + S3C2410_IISPSR);
+
+ clk_disable(s3c24xx_i2s.iis_clk);
+
+ return 0;
+}
+
+static int s3c24xx_i2s_resume(struct snd_soc_dai *cpu_dai)
+{
+ pr_debug("Entered %s\n", __func__);
+ clk_enable(s3c24xx_i2s.iis_clk);
+
+ writel(s3c24xx_i2s.iiscon, s3c24xx_i2s.regs + S3C2410_IISCON);
+ writel(s3c24xx_i2s.iismod, s3c24xx_i2s.regs + S3C2410_IISMOD);
+ writel(s3c24xx_i2s.iisfcon, s3c24xx_i2s.regs + S3C2410_IISFCON);
+ writel(s3c24xx_i2s.iispsr, s3c24xx_i2s.regs + S3C2410_IISPSR);
+
+ return 0;
+}
+#else
+#define s3c24xx_i2s_suspend NULL
+#define s3c24xx_i2s_resume NULL
+#endif
+
+
+#define S3C24XX_I2S_RATES \
+ (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \
+ SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
+ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
+
+static struct snd_soc_dai_ops s3c24xx_i2s_dai_ops = {
+ .trigger = s3c24xx_i2s_trigger,
+ .hw_params = s3c24xx_i2s_hw_params,
+ .set_fmt = s3c24xx_i2s_set_fmt,
+ .set_clkdiv = s3c24xx_i2s_set_clkdiv,
+ .set_sysclk = s3c24xx_i2s_set_sysclk,
+};
+
+static struct snd_soc_dai_driver s3c24xx_i2s_dai = {
+ .probe = s3c24xx_i2s_probe,
+ .suspend = s3c24xx_i2s_suspend,
+ .resume = s3c24xx_i2s_resume,
+ .playback = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = S3C24XX_I2S_RATES,
+ .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,},
+ .capture = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = S3C24XX_I2S_RATES,
+ .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,},
+ .ops = &s3c24xx_i2s_dai_ops,
+};
+
+static __devinit int s3c24xx_iis_dev_probe(struct platform_device *pdev)
+{
+ return snd_soc_register_dai(&pdev->dev, &s3c24xx_i2s_dai);
+}
+
+static __devexit int s3c24xx_iis_dev_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_dai(&pdev->dev);
+ return 0;
+}
+
+static struct platform_driver s3c24xx_iis_driver = {
+ .probe = s3c24xx_iis_dev_probe,
+ .remove = s3c24xx_iis_dev_remove,
+ .driver = {
+ .name = "s3c24xx-iis",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init s3c24xx_i2s_init(void)
+{
+ return platform_driver_register(&s3c24xx_iis_driver);
+}
+module_init(s3c24xx_i2s_init);
+
+static void __exit s3c24xx_i2s_exit(void)
+{
+ platform_driver_unregister(&s3c24xx_iis_driver);
+}
+module_exit(s3c24xx_i2s_exit);
+
+/* Module information */
+MODULE_AUTHOR("Ben Dooks, <ben(a)simtec.co.uk>");
+MODULE_DESCRIPTION("s3c24xx I2S SoC Interface");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:s3c24xx-iis");
diff --git a/sound/soc/samsung/s3c24xx-i2s.h b/sound/soc/samsung/s3c24xx-i2s.h
new file mode 100644
index 0000000..f9ca04e
--- /dev/null
+++ b/sound/soc/samsung/s3c24xx-i2s.h
@@ -0,0 +1,35 @@
+/*
+ * s3c24xx-i2s.c -- ALSA Soc Audio Layer
+ *
+ * Copyright 2005 Wolfson Microelectronics PLC.
+ * Author: Graeme Gregory
+ * graeme.gregory(a)wolfsonmicro.com or linux(a)wolfsonmicro.com
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * Revision history
+ * 10th Nov 2006 Initial version.
+ */
+
+#ifndef S3C24XXI2S_H_
+#define S3C24XXI2S_H_
+
+/* clock sources */
+#define S3C24XX_CLKSRC_PCLK 0
+#define S3C24XX_CLKSRC_MPLL 1
+
+/* Clock dividers */
+#define S3C24XX_DIV_MCLK 0
+#define S3C24XX_DIV_BCLK 1
+#define S3C24XX_DIV_PRESCALER 2
+
+/* prescaler */
+#define S3C24XX_PRESCALE(a,b) \
+ (((a - 1) << S3C2410_IISPSR_INTSHIFT) | ((b - 1) << S3C2410_IISPSR_EXTSHFIT))
+
+u32 s3c24xx_i2s_get_clockrate(void);
+
+#endif /*S3C24XXI2S_H_*/
diff --git a/sound/soc/samsung/s3c24xx_simtec.c b/sound/soc/samsung/s3c24xx_simtec.c
new file mode 100644
index 0000000..4a1b002
--- /dev/null
+++ b/sound/soc/samsung/s3c24xx_simtec.c
@@ -0,0 +1,395 @@
+/* sound/soc/samsung/s3c24xx_simtec.c
+ *
+ * Copyright 2009 Simtec Electronics
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/clk.h>
+#include <linux/i2c.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include <plat/audio-simtec.h>
+
+#include "dma.h"
+#include "s3c24xx-i2s.h"
+#include "s3c24xx_simtec.h"
+
+static struct s3c24xx_audio_simtec_pdata *pdata;
+static struct clk *xtal_clk;
+
+static int spk_gain;
+static int spk_unmute;
+
+/**
+ * speaker_gain_get - read the speaker gain setting.
+ * @kcontrol: The control for the speaker gain.
+ * @ucontrol: The value that needs to be updated.
+ *
+ * Read the value for the AMP gain control.
+ */
+static int speaker_gain_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = spk_gain;
+ return 0;
+}
+
+/**
+ * speaker_gain_set - set the value of the speaker amp gain
+ * @value: The value to write.
+ */
+static void speaker_gain_set(int value)
+{
+ gpio_set_value_cansleep(pdata->amp_gain[0], value & 1);
+ gpio_set_value_cansleep(pdata->amp_gain[1], value >> 1);
+}
+
+/**
+ * speaker_gain_put - set the speaker gain setting.
+ * @kcontrol: The control for the speaker gain.
+ * @ucontrol: The value that needs to be set.
+ *
+ * Set the value of the speaker gain from the specified
+ * @ucontrol setting.
+ *
+ * Note, if the speaker amp is muted, then we do not set a gain value
+ * as at-least one of the ICs that is fitted will try and power up even
+ * if the main control is set to off.
+ */
+static int speaker_gain_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int value = ucontrol->value.integer.value[0];
+
+ spk_gain = value;
+
+ if (!spk_unmute)
+ speaker_gain_set(value);
+
+ return 0;
+}
+
+static const struct snd_kcontrol_new amp_gain_controls[] = {
+ SOC_SINGLE_EXT("Speaker Gain", 0, 0, 3, 0,
+ speaker_gain_get, speaker_gain_put),
+};
+
+/**
+ * spk_unmute_state - set the unmute state of the speaker
+ * @to: zero to unmute, non-zero to ununmute.
+ */
+static void spk_unmute_state(int to)
+{
+ pr_debug("%s: to=%d\n", __func__, to);
+
+ spk_unmute = to;
+ gpio_set_value(pdata->amp_gpio, to);
+
+ /* if we're umuting, also re-set the gain */
+ if (to && pdata->amp_gain[0] > 0)
+ speaker_gain_set(spk_gain);
+}
+
+/**
+ * speaker_unmute_get - read the speaker unmute setting.
+ * @kcontrol: The control for the speaker gain.
+ * @ucontrol: The value that needs to be updated.
+ *
+ * Read the value for the AMP gain control.
+ */
+static int speaker_unmute_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = spk_unmute;
+ return 0;
+}
+
+/**
+ * speaker_unmute_put - set the speaker unmute setting.
+ * @kcontrol: The control for the speaker gain.
+ * @ucontrol: The value that needs to be set.
+ *
+ * Set the value of the speaker gain from the specified
+ * @ucontrol setting.
+ */
+static int speaker_unmute_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ spk_unmute_state(ucontrol->value.integer.value[0]);
+ return 0;
+}
+
+/* This is added as a manual control as the speaker amps create clicks
+ * when their power state is changed, which are far more noticeable than
+ * anything produced by the CODEC itself.
+ */
+static const struct snd_kcontrol_new amp_unmute_controls[] = {
+ SOC_SINGLE_EXT("Speaker Switch", 0, 0, 1, 0,
+ speaker_unmute_get, speaker_unmute_put),
+};
+
+void simtec_audio_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_codec *codec = rtd->codec;
+
+ if (pdata->amp_gpio > 0) {
+ pr_debug("%s: adding amp routes\n", __func__);
+
+ snd_soc_add_controls(codec, amp_unmute_controls,
+ ARRAY_SIZE(amp_unmute_controls));
+ }
+
+ if (pdata->amp_gain[0] > 0) {
+ pr_debug("%s: adding amp controls\n", __func__);
+ snd_soc_add_controls(codec, amp_gain_controls,
+ ARRAY_SIZE(amp_gain_controls));
+ }
+}
+EXPORT_SYMBOL_GPL(simtec_audio_init);
+
+#define CODEC_CLOCK 12000000
+
+/**
+ * simtec_hw_params - update hardware parameters
+ * @substream: The audio substream instance.
+ * @params: The parameters requested.
+ *
+ * Update the codec data routing and configuration settings
+ * from the supplied data.
+ */
+static int simtec_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ int ret;
+
+ /* Set the CODEC as the bus clock master, I2S */
+ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBM_CFM);
+ if (ret) {
+ pr_err("%s: failed set cpu dai format\n", __func__);
+ return ret;
+ }
+
+ /* Set the CODEC as the bus clock master */
+ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBM_CFM);
+ if (ret) {
+ pr_err("%s: failed set codec dai format\n", __func__);
+ return ret;
+ }
+
+ ret = snd_soc_dai_set_sysclk(codec_dai, 0,
+ CODEC_CLOCK, SND_SOC_CLOCK_IN);
+ if (ret) {
+ pr_err( "%s: failed setting codec sysclk\n", __func__);
+ return ret;
+ }
+
+ if (pdata->use_mpllin) {
+ ret = snd_soc_dai_set_sysclk(cpu_dai, S3C24XX_CLKSRC_MPLL,
+ 0, SND_SOC_CLOCK_OUT);
+
+ if (ret) {
+ pr_err("%s: failed to set MPLLin as clksrc\n",
+ __func__);
+ return ret;
+ }
+ }
+
+ if (pdata->output_cdclk) {
+ int cdclk_scale;
+
+ cdclk_scale = clk_get_rate(xtal_clk) / CODEC_CLOCK;
+ cdclk_scale--;
+
+ ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER,
+ cdclk_scale);
+ }
+
+ return 0;
+}
+
+static int simtec_call_startup(struct s3c24xx_audio_simtec_pdata *pd)
+{
+ /* call any board supplied startup code, this currently only
+ * covers the bast/vr1000 which have a CPLD in the way of the
+ * LRCLK */
+ if (pd->startup)
+ pd->startup();
+
+ return 0;
+}
+
+static struct snd_soc_ops simtec_snd_ops = {
+ .hw_params = simtec_hw_params,
+};
+
+/**
+ * attach_gpio_amp - get and configure the necessary gpios
+ * @dev: The device we're probing.
+ * @pd: The platform data supplied by the board.
+ *
+ * If there is a GPIO based amplifier attached to the board, claim
+ * the necessary GPIO lines for it, and set default values.
+ */
+static int attach_gpio_amp(struct device *dev,
+ struct s3c24xx_audio_simtec_pdata *pd)
+{
+ int ret;
+
+ /* attach gpio amp gain (if any) */
+ if (pdata->amp_gain[0] > 0) {
+ ret = gpio_request(pd->amp_gain[0], "gpio-amp-gain0");
+ if (ret) {
+ dev_err(dev, "cannot get amp gpio gain0\n");
+ return ret;
+ }
+
+ ret = gpio_request(pd->amp_gain[1], "gpio-amp-gain1");
+ if (ret) {
+ dev_err(dev, "cannot get amp gpio gain1\n");
+ gpio_free(pdata->amp_gain[0]);
+ return ret;
+ }
+
+ gpio_direction_output(pd->amp_gain[0], 0);
+ gpio_direction_output(pd->amp_gain[1], 0);
+ }
+
+ /* note, currently we assume GPA0 isn't valid amp */
+ if (pdata->amp_gpio > 0) {
+ ret = gpio_request(pd->amp_gpio, "gpio-amp");
+ if (ret) {
+ dev_err(dev, "cannot get amp gpio %d (%d)\n",
+ pd->amp_gpio, ret);
+ goto err_amp;
+ }
+
+ /* set the amp off at startup */
+ spk_unmute_state(0);
+ }
+
+ return 0;
+
+err_amp:
+ if (pd->amp_gain[0] > 0) {
+ gpio_free(pd->amp_gain[0]);
+ gpio_free(pd->amp_gain[1]);
+ }
+
+ return ret;
+}
+
+static void detach_gpio_amp(struct s3c24xx_audio_simtec_pdata *pd)
+{
+ if (pd->amp_gain[0] > 0) {
+ gpio_free(pd->amp_gain[0]);
+ gpio_free(pd->amp_gain[1]);
+ }
+
+ if (pd->amp_gpio > 0)
+ gpio_free(pd->amp_gpio);
+}
+
+#ifdef CONFIG_PM
+int simtec_audio_resume(struct device *dev)
+{
+ simtec_call_startup(pdata);
+ return 0;
+}
+
+const struct dev_pm_ops simtec_audio_pmops = {
+ .resume = simtec_audio_resume,
+};
+EXPORT_SYMBOL_GPL(simtec_audio_pmops);
+#endif
+
+int __devinit simtec_audio_core_probe(struct platform_device *pdev,
+ struct snd_soc_card *card)
+{
+ struct platform_device *snd_dev;
+ int ret;
+
+ card->dai_link->ops = &simtec_snd_ops;
+
+ pdata = pdev->dev.platform_data;
+ if (!pdata) {
+ dev_err(&pdev->dev, "no platform data supplied\n");
+ return -EINVAL;
+ }
+
+ simtec_call_startup(pdata);
+
+ xtal_clk = clk_get(&pdev->dev, "xtal");
+ if (IS_ERR(xtal_clk)) {
+ dev_err(&pdev->dev, "could not get clkout0\n");
+ return -EINVAL;
+ }
+
+ dev_info(&pdev->dev, "xtal rate is %ld\n", clk_get_rate(xtal_clk));
+
+ ret = attach_gpio_amp(&pdev->dev, pdata);
+ if (ret)
+ goto err_clk;
+
+ snd_dev = platform_device_alloc("soc-audio", -1);
+ if (!snd_dev) {
+ dev_err(&pdev->dev, "failed to alloc soc-audio devicec\n");
+ ret = -ENOMEM;
+ goto err_gpio;
+ }
+
+ platform_set_drvdata(snd_dev, card);
+
+ ret = platform_device_add(snd_dev);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to add soc-audio dev\n");
+ goto err_pdev;
+ }
+
+ platform_set_drvdata(pdev, snd_dev);
+ return 0;
+
+err_pdev:
+ platform_device_put(snd_dev);
+
+err_gpio:
+ detach_gpio_amp(pdata);
+
+err_clk:
+ clk_put(xtal_clk);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(simtec_audio_core_probe);
+
+int __devexit simtec_audio_remove(struct platform_device *pdev)
+{
+ struct platform_device *snd_dev = platform_get_drvdata(pdev);
+
+ platform_device_unregister(snd_dev);
+
+ detach_gpio_amp(pdata);
+ clk_put(xtal_clk);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(simtec_audio_remove);
+
+MODULE_AUTHOR("Ben Dooks <ben(a)simtec.co.uk>");
+MODULE_DESCRIPTION("ALSA SoC Simtec Audio common support");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/samsung/s3c24xx_simtec.h b/sound/soc/samsung/s3c24xx_simtec.h
new file mode 100644
index 0000000..8270748
--- /dev/null
+++ b/sound/soc/samsung/s3c24xx_simtec.h
@@ -0,0 +1,22 @@
+/* sound/soc/samsung/s3c24xx_simtec.h
+ *
+ * Copyright 2009 Simtec Electronics
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+extern void simtec_audio_init(struct snd_soc_pcm_runtime *rtd);
+
+extern int simtec_audio_core_probe(struct platform_device *pdev,
+ struct snd_soc_card *card);
+
+extern int simtec_audio_remove(struct platform_device *pdev);
+
+#ifdef CONFIG_PM
+extern const struct dev_pm_ops simtec_audio_pmops;
+#define simtec_audio_pm &simtec_audio_pmops
+#else
+#define simtec_audio_pm NULL
+#endif
diff --git a/sound/soc/samsung/s3c24xx_simtec_hermes.c b/sound/soc/samsung/s3c24xx_simtec_hermes.c
new file mode 100644
index 0000000..fec4cac
--- /dev/null
+++ b/sound/soc/samsung/s3c24xx_simtec_hermes.c
@@ -0,0 +1,146 @@
+/* sound/soc/samsung/s3c24xx_simtec_hermes.c
+ *
+ * Copyright 2009 Simtec Electronics
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include <plat/audio-simtec.h>
+
+#include "dma.h"
+#include "s3c24xx-i2s.h"
+#include "s3c24xx_simtec.h"
+
+#include "../codecs/tlv320aic3x.h"
+
+static const struct snd_soc_dapm_widget dapm_widgets[] = {
+ SND_SOC_DAPM_LINE("GSM Out", NULL),
+ SND_SOC_DAPM_LINE("GSM In", NULL),
+ SND_SOC_DAPM_LINE("Line In", NULL),
+ SND_SOC_DAPM_LINE("Line Out", NULL),
+ SND_SOC_DAPM_LINE("ZV", NULL),
+ SND_SOC_DAPM_MIC("Mic Jack", NULL),
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
+};
+
+static const struct snd_soc_dapm_route base_map[] = {
+ /* Headphone connected to HP{L,R}OUT and HP{L,R}COM */
+
+ { "Headphone Jack", NULL, "HPLOUT" },
+ { "Headphone Jack", NULL, "HPLCOM" },
+ { "Headphone Jack", NULL, "HPROUT" },
+ { "Headphone Jack", NULL, "HPRCOM" },
+
+ /* ZV connected to Line1 */
+
+ { "LINE1L", NULL, "ZV" },
+ { "LINE1R", NULL, "ZV" },
+
+ /* Line In connected to Line2 */
+
+ { "LINE2L", NULL, "Line In" },
+ { "LINE2R", NULL, "Line In" },
+
+ /* Microphone connected to MIC3R and MIC_BIAS */
+
+ { "MIC3L", NULL, "Mic Jack" },
+
+ /* GSM connected to MONO_LOUT and MIC3L (in) */
+
+ { "GSM Out", NULL, "MONO_LOUT" },
+ { "MIC3L", NULL, "GSM In" },
+
+ /* Speaker is connected to LINEOUT{LN,LP,RN,RP}, however we are
+ * not using the DAPM to power it up and down as there it makes
+ * a click when powering up. */
+};
+
+/**
+ * simtec_hermes_init - initialise and add controls
+ * @codec; The codec instance to attach to.
+ *
+ * Attach our controls and configure the necessary codec
+ * mappings for our sound card instance.
+*/
+static int simtec_hermes_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_codec *codec = rtd->codec;
+
+ snd_soc_dapm_new_controls(codec, dapm_widgets,
+ ARRAY_SIZE(dapm_widgets));
+
+ snd_soc_dapm_add_routes(codec, base_map, ARRAY_SIZE(base_map));
+
+ snd_soc_dapm_enable_pin(codec, "Headphone Jack");
+ snd_soc_dapm_enable_pin(codec, "Line In");
+ snd_soc_dapm_enable_pin(codec, "Line Out");
+ snd_soc_dapm_enable_pin(codec, "Mic Jack");
+
+ simtec_audio_init(rtd);
+ snd_soc_dapm_sync(codec);
+
+ return 0;
+}
+
+static struct snd_soc_dai_link simtec_dai_aic33 = {
+ .name = "tlv320aic33",
+ .stream_name = "TLV320AIC33",
+ .codec_name = "tlv320aic3x-codec.0-0x1a",
+ .cpu_dai_name = "s3c24xx-i2s",
+ .codec_dai_name = "tlv320aic3x-hifi",
+ .platform_name = "samsung-audio",
+ .init = simtec_hermes_init,
+};
+
+/* simtec audio machine driver */
+static struct snd_soc_card snd_soc_machine_simtec_aic33 = {
+ .name = "Simtec-Hermes",
+ .dai_link = &simtec_dai_aic33,
+ .num_links = 1,
+};
+
+static int __devinit simtec_audio_hermes_probe(struct platform_device *pd)
+{
+ dev_info(&pd->dev, "probing....\n");
+ return simtec_audio_core_probe(pd, &snd_soc_machine_simtec_aic33);
+}
+
+static struct platform_driver simtec_audio_hermes_platdrv = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "s3c24xx-simtec-hermes-snd",
+ .pm = simtec_audio_pm,
+ },
+ .probe = simtec_audio_hermes_probe,
+ .remove = __devexit_p(simtec_audio_remove),
+};
+
+MODULE_ALIAS("platform:s3c24xx-simtec-hermes-snd");
+
+static int __init simtec_hermes_modinit(void)
+{
+ return platform_driver_register(&simtec_audio_hermes_platdrv);
+}
+
+static void __exit simtec_hermes_modexit(void)
+{
+ platform_driver_unregister(&simtec_audio_hermes_platdrv);
+}
+
+module_init(simtec_hermes_modinit);
+module_exit(simtec_hermes_modexit);
+
+MODULE_AUTHOR("Ben Dooks <ben(a)simtec.co.uk>");
+MODULE_DESCRIPTION("ALSA SoC Simtec Audio support");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/samsung/s3c24xx_simtec_tlv320aic23.c b/sound/soc/samsung/s3c24xx_simtec_tlv320aic23.c
new file mode 100644
index 0000000..7915e02
--- /dev/null
+++ b/sound/soc/samsung/s3c24xx_simtec_tlv320aic23.c
@@ -0,0 +1,134 @@
+/* sound/soc/samsung/s3c24xx_simtec_tlv320aic23.c
+ *
+ * Copyright 2009 Simtec Electronics
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include <plat/audio-simtec.h>
+
+#include "dma.h"
+#include "s3c24xx-i2s.h"
+#include "s3c24xx_simtec.h"
+
+#include "../codecs/tlv320aic23.h"
+
+/* supported machines:
+ *
+ * Machine Connections AMP
+ * ------- ----------- ---
+ * BAST MIC, HPOUT, LOUT, LIN TPA2001D1 (HPOUTL,R) (gain hardwired)
+ * VR1000 HPOUT, LIN None
+ * VR2000 LIN, LOUT, MIC, HP LM4871 (HPOUTL,R)
+ * DePicture LIN, LOUT, MIC, HP LM4871 (HPOUTL,R)
+ * Anubis LIN, LOUT, MIC, HP TPA2001D1 (HPOUTL,R)
+ */
+
+static const struct snd_soc_dapm_widget dapm_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
+ SND_SOC_DAPM_LINE("Line In", NULL),
+ SND_SOC_DAPM_LINE("Line Out", NULL),
+ SND_SOC_DAPM_MIC("Mic Jack", NULL),
+};
+
+static const struct snd_soc_dapm_route base_map[] = {
+ { "Headphone Jack", NULL, "LHPOUT"},
+ { "Headphone Jack", NULL, "RHPOUT"},
+
+ { "Line Out", NULL, "LOUT" },
+ { "Line Out", NULL, "ROUT" },
+
+ { "LLINEIN", NULL, "Line In"},
+ { "RLINEIN", NULL, "Line In"},
+
+ { "MICIN", NULL, "Mic Jack"},
+};
+
+/**
+ * simtec_tlv320aic23_init - initialise and add controls
+ * @codec; The codec instance to attach to.
+ *
+ * Attach our controls and configure the necessary codec
+ * mappings for our sound card instance.
+*/
+static int simtec_tlv320aic23_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_codec *codec = rtd->codec;
+
+ snd_soc_dapm_new_controls(codec, dapm_widgets,
+ ARRAY_SIZE(dapm_widgets));
+
+ snd_soc_dapm_add_routes(codec, base_map, ARRAY_SIZE(base_map));
+
+ snd_soc_dapm_enable_pin(codec, "Headphone Jack");
+ snd_soc_dapm_enable_pin(codec, "Line In");
+ snd_soc_dapm_enable_pin(codec, "Line Out");
+ snd_soc_dapm_enable_pin(codec, "Mic Jack");
+
+ simtec_audio_init(rtd);
+ snd_soc_dapm_sync(codec);
+
+ return 0;
+}
+
+static struct snd_soc_dai_link simtec_dai_aic23 = {
+ .name = "tlv320aic23",
+ .stream_name = "TLV320AIC23",
+ .codec_name = "tlv320aic3x-codec.0-0x1a",
+ .cpu_dai_name = "s3c24xx-i2s",
+ .codec_dai_name = "tlv320aic3x-hifi",
+ .platform_name = "samsung-audio",
+ .init = simtec_tlv320aic23_init,
+};
+
+/* simtec audio machine driver */
+static struct snd_soc_card snd_soc_machine_simtec_aic23 = {
+ .name = "Simtec",
+ .dai_link = &simtec_dai_aic23,
+ .num_links = 1,
+};
+
+static int __devinit simtec_audio_tlv320aic23_probe(struct platform_device *pd)
+{
+ return simtec_audio_core_probe(pd, &snd_soc_machine_simtec_aic23);
+}
+
+static struct platform_driver simtec_audio_tlv320aic23_platdrv = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "s3c24xx-simtec-tlv320aic23",
+ .pm = simtec_audio_pm,
+ },
+ .probe = simtec_audio_tlv320aic23_probe,
+ .remove = __devexit_p(simtec_audio_remove),
+};
+
+MODULE_ALIAS("platform:s3c24xx-simtec-tlv320aic23");
+
+static int __init simtec_tlv320aic23_modinit(void)
+{
+ return platform_driver_register(&simtec_audio_tlv320aic23_platdrv);
+}
+
+static void __exit simtec_tlv320aic23_modexit(void)
+{
+ platform_driver_unregister(&simtec_audio_tlv320aic23_platdrv);
+}
+
+module_init(simtec_tlv320aic23_modinit);
+module_exit(simtec_tlv320aic23_modexit);
+
+MODULE_AUTHOR("Ben Dooks <ben(a)simtec.co.uk>");
+MODULE_DESCRIPTION("ALSA SoC Simtec Audio support");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/samsung/s3c24xx_uda134x.c b/sound/soc/samsung/s3c24xx_uda134x.c
new file mode 100644
index 0000000..87eeb46
--- /dev/null
+++ b/sound/soc/samsung/s3c24xx_uda134x.c
@@ -0,0 +1,368 @@
+/*
+ * Modifications by Christian Pellegrin <chripell(a)evolware.org>
+ *
+ * s3c24xx_uda134x.c -- S3C24XX_UDA134X ALSA SoC Audio board driver
+ *
+ * Copyright 2007 Dension Audio Systems Ltd.
+ * Author: Zoltan Devai
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/mutex.h>
+#include <linux/gpio.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/s3c24xx_uda134x.h>
+#include <sound/uda134x.h>
+
+#include <plat/regs-iis.h>
+
+#include "dma.h"
+#include "s3c24xx-i2s.h"
+#include "../codecs/uda134x.h"
+
+
+/* #define ENFORCE_RATES 1 */
+/*
+ Unfortunately the S3C24XX in master mode has a limited capacity of
+ generating the clock for the codec. If you define this only rates
+ that are really available will be enforced. But be careful, most
+ user level application just want the usual sampling frequencies (8,
+ 11.025, 22.050, 44.1 kHz) and anyway resampling is a costly
+ operation for embedded systems. So if you aren't very lucky or your
+ hardware engineer wasn't very forward-looking it's better to leave
+ this undefined. If you do so an approximate value for the requested
+ sampling rate in the range -/+ 5% will be chosen. If this in not
+ possible an error will be returned.
+*/
+
+static struct clk *xtal;
+static struct clk *pclk;
+/* this is need because we don't have a place where to keep the
+ * pointers to the clocks in each substream. We get the clocks only
+ * when we are actually using them so we don't block stuff like
+ * frequency change or oscillator power-off */
+static int clk_users;
+static DEFINE_MUTEX(clk_lock);
+
+static unsigned int rates[33 * 2];
+#ifdef ENFORCE_RATES
+static struct snd_pcm_hw_constraint_list hw_constraints_rates = {
+ .count = ARRAY_SIZE(rates),
+ .list = rates,
+ .mask = 0,
+};
+#endif
+
+static struct platform_device *s3c24xx_uda134x_snd_device;
+
+static int s3c24xx_uda134x_startup(struct snd_pcm_substream *substream)
+{
+ int ret = 0;
+#ifdef ENFORCE_RATES
+ struct snd_pcm_runtime *runtime = substream->runtime;
+#endif
+
+ mutex_lock(&clk_lock);
+ pr_debug("%s %d\n", __func__, clk_users);
+ if (clk_users == 0) {
+ xtal = clk_get(&s3c24xx_uda134x_snd_device->dev, "xtal");
+ if (!xtal) {
+ printk(KERN_ERR "%s cannot get xtal\n", __func__);
+ ret = -EBUSY;
+ } else {
+ pclk = clk_get(&s3c24xx_uda134x_snd_device->dev,
+ "pclk");
+ if (!pclk) {
+ printk(KERN_ERR "%s cannot get pclk\n",
+ __func__);
+ clk_put(xtal);
+ ret = -EBUSY;
+ }
+ }
+ if (!ret) {
+ int i, j;
+
+ for (i = 0; i < 2; i++) {
+ int fs = i ? 256 : 384;
+
+ rates[i*33] = clk_get_rate(xtal) / fs;
+ for (j = 1; j < 33; j++)
+ rates[i*33 + j] = clk_get_rate(pclk) /
+ (j * fs);
+ }
+ }
+ }
+ clk_users += 1;
+ mutex_unlock(&clk_lock);
+ if (!ret) {
+#ifdef ENFORCE_RATES
+ ret = snd_pcm_hw_constraint_list(runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE,
+ &hw_constraints_rates);
+ if (ret < 0)
+ printk(KERN_ERR "%s cannot set constraints\n",
+ __func__);
+#endif
+ }
+ return ret;
+}
+
+static void s3c24xx_uda134x_shutdown(struct snd_pcm_substream *substream)
+{
+ mutex_lock(&clk_lock);
+ pr_debug("%s %d\n", __func__, clk_users);
+ clk_users -= 1;
+ if (clk_users == 0) {
+ clk_put(xtal);
+ xtal = NULL;
+ clk_put(pclk);
+ pclk = NULL;
+ }
+ mutex_unlock(&clk_lock);
+}
+
+static int s3c24xx_uda134x_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ unsigned int clk = 0;
+ int ret = 0;
+ int clk_source, fs_mode;
+ unsigned long rate = params_rate(params);
+ long err, cerr;
+ unsigned int div;
+ int i, bi;
+
+ err = 999999;
+ bi = 0;
+ for (i = 0; i < 2*33; i++) {
+ cerr = rates[i] - rate;
+ if (cerr < 0)
+ cerr = -cerr;
+ if (cerr < err) {
+ err = cerr;
+ bi = i;
+ }
+ }
+ if (bi / 33 == 1)
+ fs_mode = S3C2410_IISMOD_256FS;
+ else
+ fs_mode = S3C2410_IISMOD_384FS;
+ if (bi % 33 == 0) {
+ clk_source = S3C24XX_CLKSRC_MPLL;
+ div = 1;
+ } else {
+ clk_source = S3C24XX_CLKSRC_PCLK;
+ div = bi % 33;
+ }
+ pr_debug("%s desired rate %lu, %d\n", __func__, rate, bi);
+
+ clk = (fs_mode == S3C2410_IISMOD_384FS ? 384 : 256) * rate;
+ pr_debug("%s will use: %s %s %d sysclk %d err %ld\n", __func__,
+ fs_mode == S3C2410_IISMOD_384FS ? "384FS" : "256FS",
+ clk_source == S3C24XX_CLKSRC_MPLL ? "MPLLin" : "PCLK",
+ div, clk, err);
+
+ if ((err * 100 / rate) > 5) {
+ printk(KERN_ERR "S3C24XX_UDA134X: effective frequency "
+ "too different from desired (%ld%%)\n",
+ err * 100 / rate);
+ return -EINVAL;
+ }
+
+ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_soc_dai_set_sysclk(cpu_dai, clk_source , clk,
+ SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK, fs_mode);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_BCLK,
+ S3C2410_IISMOD_32FS);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER,
+ S3C24XX_PRESCALE(div, div));
+ if (ret < 0)
+ return ret;
+
+ /* set the codec system clock for DAC and ADC */
+ ret = snd_soc_dai_set_sysclk(codec_dai, 0, clk,
+ SND_SOC_CLOCK_OUT);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static struct snd_soc_ops s3c24xx_uda134x_ops = {
+ .startup = s3c24xx_uda134x_startup,
+ .shutdown = s3c24xx_uda134x_shutdown,
+ .hw_params = s3c24xx_uda134x_hw_params,
+};
+
+static struct snd_soc_dai_link s3c24xx_uda134x_dai_link = {
+ .name = "UDA134X",
+ .stream_name = "UDA134X",
+ .codec_name = "uda134x-hifi",
+ .codec_dai_name = "uda134x-hifi",
+ .cpu_dai_name = "s3c24xx-i2s",
+ .ops = &s3c24xx_uda134x_ops,
+ .platform_name = "samsung-audio",
+};
+
+static struct snd_soc_card snd_soc_s3c24xx_uda134x = {
+ .name = "S3C24XX_UDA134X",
+ .dai_link = &s3c24xx_uda134x_dai_link,
+ .num_links = 1,
+};
+
+static struct s3c24xx_uda134x_platform_data *s3c24xx_uda134x_l3_pins;
+
+static void setdat(int v)
+{
+ gpio_set_value(s3c24xx_uda134x_l3_pins->l3_data, v > 0);
+}
+
+static void setclk(int v)
+{
+ gpio_set_value(s3c24xx_uda134x_l3_pins->l3_clk, v > 0);
+}
+
+static void setmode(int v)
+{
+ gpio_set_value(s3c24xx_uda134x_l3_pins->l3_mode, v > 0);
+}
+
+/* FIXME - This must be codec platform data but in which board file ?? */
+static struct uda134x_platform_data s3c24xx_uda134x = {
+ .l3 = {
+ .setdat = setdat,
+ .setclk = setclk,
+ .setmode = setmode,
+ .data_hold = 1,
+ .data_setup = 1,
+ .clock_high = 1,
+ .mode_hold = 1,
+ .mode = 1,
+ .mode_setup = 1,
+ },
+};
+
+static int s3c24xx_uda134x_setup_pin(int pin, char *fun)
+{
+ if (gpio_request(pin, "s3c24xx_uda134x") < 0) {
+ printk(KERN_ERR "S3C24XX_UDA134X SoC Audio: "
+ "l3 %s pin already in use", fun);
+ return -EBUSY;
+ }
+ gpio_direction_output(pin, 0);
+ return 0;
+}
+
+static int s3c24xx_uda134x_probe(struct platform_device *pdev)
+{
+ int ret;
+
+ printk(KERN_INFO "S3C24XX_UDA134X SoC Audio driver\n");
+
+ s3c24xx_uda134x_l3_pins = pdev->dev.platform_data;
+ if (s3c24xx_uda134x_l3_pins == NULL) {
+ printk(KERN_ERR "S3C24XX_UDA134X SoC Audio: "
+ "unable to find platform data\n");
+ return -ENODEV;
+ }
+ s3c24xx_uda134x.power = s3c24xx_uda134x_l3_pins->power;
+ s3c24xx_uda134x.model = s3c24xx_uda134x_l3_pins->model;
+
+ if (s3c24xx_uda134x_setup_pin(s3c24xx_uda134x_l3_pins->l3_data,
+ "data") < 0)
+ return -EBUSY;
+ if (s3c24xx_uda134x_setup_pin(s3c24xx_uda134x_l3_pins->l3_clk,
+ "clk") < 0) {
+ gpio_free(s3c24xx_uda134x_l3_pins->l3_data);
+ return -EBUSY;
+ }
+ if (s3c24xx_uda134x_setup_pin(s3c24xx_uda134x_l3_pins->l3_mode,
+ "mode") < 0) {
+ gpio_free(s3c24xx_uda134x_l3_pins->l3_data);
+ gpio_free(s3c24xx_uda134x_l3_pins->l3_clk);
+ return -EBUSY;
+ }
+
+ s3c24xx_uda134x_snd_device = platform_device_alloc("soc-audio", -1);
+ if (!s3c24xx_uda134x_snd_device) {
+ printk(KERN_ERR "S3C24XX_UDA134X SoC Audio: "
+ "Unable to register\n");
+ return -ENOMEM;
+ }
+
+ platform_set_drvdata(s3c24xx_uda134x_snd_device,
+ &snd_soc_s3c24xx_uda134x);
+ ret = platform_device_add(s3c24xx_uda134x_snd_device);
+ if (ret) {
+ printk(KERN_ERR "S3C24XX_UDA134X SoC Audio: Unable to add\n");
+ platform_device_put(s3c24xx_uda134x_snd_device);
+ }
+
+ return ret;
+}
+
+static int s3c24xx_uda134x_remove(struct platform_device *pdev)
+{
+ platform_device_unregister(s3c24xx_uda134x_snd_device);
+ gpio_free(s3c24xx_uda134x_l3_pins->l3_data);
+ gpio_free(s3c24xx_uda134x_l3_pins->l3_clk);
+ gpio_free(s3c24xx_uda134x_l3_pins->l3_mode);
+ return 0;
+}
+
+static struct platform_driver s3c24xx_uda134x_driver = {
+ .probe = s3c24xx_uda134x_probe,
+ .remove = s3c24xx_uda134x_remove,
+ .driver = {
+ .name = "s3c24xx_uda134x",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init s3c24xx_uda134x_init(void)
+{
+ return platform_driver_register(&s3c24xx_uda134x_driver);
+}
+
+static void __exit s3c24xx_uda134x_exit(void)
+{
+ platform_driver_unregister(&s3c24xx_uda134x_driver);
+}
+
+
+module_init(s3c24xx_uda134x_init);
+module_exit(s3c24xx_uda134x_exit);
+
+MODULE_AUTHOR("Zoltan Devai, Christian Pellegrin <chripell(a)evolware.org>");
+MODULE_DESCRIPTION("S3C24XX_UDA134X ALSA SoC audio driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/samsung/smartq_wm8987.c b/sound/soc/samsung/smartq_wm8987.c
new file mode 100644
index 0000000..3564e00
--- /dev/null
+++ b/sound/soc/samsung/smartq_wm8987.c
@@ -0,0 +1,287 @@
+/* sound/soc/samsung/smartq_wm8987.c
+ *
+ * Copyright 2010 Maurus Cuelenaere <mcuelenaere(a)gmail.com>
+ *
+ * Based on smdk6410_wm8987.c
+ * Copyright 2007 Wolfson Microelectronics PLC. - linux(a)wolfsonmicro.com
+ * Graeme Gregory - graeme.gregory(a)wolfsonmicro.com
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc-dapm.h>
+#include <sound/jack.h>
+
+#include <asm/mach-types.h>
+
+#include "dma.h"
+#include "i2s.h"
+
+#include "../codecs/wm8750.h"
+
+/*
+ * WM8987 is register compatible with WM8750, so using that as base driver.
+ */
+
+static struct snd_soc_card snd_soc_smartq;
+
+static int smartq_hifi_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ unsigned int clk = 0;
+ int ret;
+
+ switch (params_rate(params)) {
+ case 8000:
+ case 16000:
+ case 32000:
+ case 48000:
+ case 96000:
+ clk = 12288000;
+ break;
+ case 11025:
+ case 22050:
+ case 44100:
+ case 88200:
+ clk = 11289600;
+ break;
+ }
+
+ /* set codec DAI configuration */
+ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBS_CFS);
+ if (ret < 0)
+ return ret;
+
+ /* set cpu DAI configuration */
+ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBS_CFS);
+ if (ret < 0)
+ return ret;
+
+ /* Use PCLK for I2S signal generation */
+ ret = snd_soc_dai_set_sysclk(cpu_dai, SAMSUNG_I2S_RCLKSRC_0,
+ 0, SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ return ret;
+
+ /* Gate the RCLK output on PAD */
+ ret = snd_soc_dai_set_sysclk(cpu_dai, SAMSUNG_I2S_CDCLK,
+ 0, SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ return ret;
+
+ /* set the codec system clock for DAC and ADC */
+ ret = snd_soc_dai_set_sysclk(codec_dai, WM8750_SYSCLK, clk,
+ SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+/*
+ * SmartQ WM8987 HiFi DAI operations.
+ */
+static struct snd_soc_ops smartq_hifi_ops = {
+ .hw_params = smartq_hifi_hw_params,
+};
+
+static struct snd_soc_jack smartq_jack;
+
+static struct snd_soc_jack_pin smartq_jack_pins[] = {
+ /* Disable speaker when headphone is plugged in */
+ {
+ .pin = "Internal Speaker",
+ .mask = SND_JACK_HEADPHONE,
+ },
+};
+
+static struct snd_soc_jack_gpio smartq_jack_gpios[] = {
+ {
+ .gpio = S3C64XX_GPL(12),
+ .name = "headphone detect",
+ .report = SND_JACK_HEADPHONE,
+ .debounce_time = 200,
+ },
+};
+
+static const struct snd_kcontrol_new wm8987_smartq_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Internal Speaker"),
+ SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+ SOC_DAPM_PIN_SWITCH("Internal Mic"),
+};
+
+static int smartq_speaker_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k,
+ int event)
+{
+ gpio_set_value(S3C64XX_GPK(12), SND_SOC_DAPM_EVENT_OFF(event));
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget wm8987_dapm_widgets[] = {
+ SND_SOC_DAPM_SPK("Internal Speaker", smartq_speaker_event),
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
+ SND_SOC_DAPM_MIC("Internal Mic", NULL),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+ {"Headphone Jack", NULL, "LOUT2"},
+ {"Headphone Jack", NULL, "ROUT2"},
+
+ {"Internal Speaker", NULL, "LOUT2"},
+ {"Internal Speaker", NULL, "ROUT2"},
+
+ {"Mic Bias", NULL, "Internal Mic"},
+ {"LINPUT2", NULL, "Mic Bias"},
+};
+
+static int smartq_wm8987_init(struct snd_soc_codec *codec)
+{
+ int err = 0;
+
+ /* Add SmartQ specific widgets */
+ snd_soc_dapm_new_controls(codec, wm8987_dapm_widgets,
+ ARRAY_SIZE(wm8987_dapm_widgets));
+
+ /* add SmartQ specific controls */
+ err = snd_soc_add_controls(codec, wm8987_smartq_controls,
+ ARRAY_SIZE(wm8987_smartq_controls));
+
+ if (err < 0)
+ return err;
+
+ /* setup SmartQ specific audio path */
+ snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+
+ /* set endpoints to not connected */
+ snd_soc_dapm_nc_pin(codec, "LINPUT1");
+ snd_soc_dapm_nc_pin(codec, "RINPUT1");
+ snd_soc_dapm_nc_pin(codec, "OUT3");
+ snd_soc_dapm_nc_pin(codec, "ROUT1");
+
+ /* set endpoints to default off mode */
+ snd_soc_dapm_enable_pin(codec, "Internal Speaker");
+ snd_soc_dapm_enable_pin(codec, "Internal Mic");
+ snd_soc_dapm_disable_pin(codec, "Headphone Jack");
+
+ err = snd_soc_dapm_sync(codec);
+ if (err)
+ return err;
+
+ /* Headphone jack detection */
+ err = snd_soc_jack_new(&snd_soc_smartq, "Headphone Jack",
+ SND_JACK_HEADPHONE, &smartq_jack);
+ if (err)
+ return err;
+
+ err = snd_soc_jack_add_pins(&smartq_jack, ARRAY_SIZE(smartq_jack_pins),
+ smartq_jack_pins);
+ if (err)
+ return err;
+
+ err = snd_soc_jack_add_gpios(&smartq_jack,
+ ARRAY_SIZE(smartq_jack_gpios),
+ smartq_jack_gpios);
+
+ return err;
+}
+
+static struct snd_soc_dai_link smartq_dai[] = {
+ {
+ .name = "wm8987",
+ .stream_name = "SmartQ Hi-Fi",
+ .cpu_dai_name = "samsung-i2s.0",
+ .codec_dai_name = "wm8750-hifi",
+ .platform_name = "samsung-audio",
+ .codec_name = "wm8750-codec.0-0x1a",
+ .init = smartq_wm8987_init,
+ .ops = &smartq_hifi_ops,
+ },
+};
+
+static struct snd_soc_card snd_soc_smartq = {
+ .name = "SmartQ",
+ .dai_link = smartq_dai,
+ .num_links = ARRAY_SIZE(smartq_dai),
+};
+
+static struct platform_device *smartq_snd_device;
+
+static int __init smartq_init(void)
+{
+ int ret;
+
+ if (!machine_is_smartq7() && !machine_is_smartq5()) {
+ pr_info("Only SmartQ is supported by this ASoC driver\n");
+ return -ENODEV;
+ }
+
+ smartq_snd_device = platform_device_alloc("soc-audio", -1);
+ if (!smartq_snd_device)
+ return -ENOMEM;
+
+ platform_set_drvdata(smartq_snd_device, &snd_soc_smartq);
+
+ ret = platform_device_add(smartq_snd_device);
+ if (ret) {
+ platform_device_put(smartq_snd_device);
+ return ret;
+ }
+
+ /* Initialise GPIOs used by amplifiers */
+ ret = gpio_request(S3C64XX_GPK(12), "amplifiers shutdown");
+ if (ret) {
+ dev_err(&smartq_snd_device->dev, "Failed to register GPK12\n");
+ goto err_unregister_device;
+ }
+
+ /* Disable amplifiers */
+ ret = gpio_direction_output(S3C64XX_GPK(12), 1);
+ if (ret) {
+ dev_err(&smartq_snd_device->dev, "Failed to configure GPK12\n");
+ goto err_free_gpio_amp_shut;
+ }
+
+ return 0;
+
+err_free_gpio_amp_shut:
+ gpio_free(S3C64XX_GPK(12));
+err_unregister_device:
+ platform_device_unregister(smartq_snd_device);
+
+ return ret;
+}
+
+static void __exit smartq_exit(void)
+{
+ snd_soc_jack_free_gpios(&smartq_jack, ARRAY_SIZE(smartq_jack_gpios),
+ smartq_jack_gpios);
+
+ platform_device_unregister(smartq_snd_device);
+}
+
+module_init(smartq_init);
+module_exit(smartq_exit);
+
+/* Module information */
+MODULE_AUTHOR("Maurus Cuelenaere <mcuelenaere(a)gmail.com>");
+MODULE_DESCRIPTION("ALSA SoC SmartQ WM8987");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/samsung/smdk2443_wm9710.c b/sound/soc/samsung/smdk2443_wm9710.c
new file mode 100644
index 0000000..5051699
--- /dev/null
+++ b/sound/soc/samsung/smdk2443_wm9710.c
@@ -0,0 +1,74 @@
+/*
+ * smdk2443_wm9710.c -- SoC audio for smdk2443
+ *
+ * Copyright 2007 Wolfson Microelectronics PLC.
+ * Author: Graeme Gregory
+ * graeme.gregory(a)wolfsonmicro.com or linux(a)wolfsonmicro.com
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include "dma.h"
+#include "ac97.h"
+
+static struct snd_soc_card smdk2443;
+
+static struct snd_soc_dai_link smdk2443_dai[] = {
+{
+ .name = "AC97",
+ .stream_name = "AC97 HiFi",
+ .cpu_dai_name = "samsung-ac97",
+ .codec_dai_name = "ac97-hifi",
+ .codec_name = "ac97-codec",
+ .platform_name = "samsung-audio",
+},
+};
+
+static struct snd_soc_card smdk2443 = {
+ .name = "SMDK2443",
+ .dai_link = smdk2443_dai,
+ .num_links = ARRAY_SIZE(smdk2443_dai),
+};
+
+static struct platform_device *smdk2443_snd_ac97_device;
+
+static int __init smdk2443_init(void)
+{
+ int ret;
+
+ smdk2443_snd_ac97_device = platform_device_alloc("soc-audio", -1);
+ if (!smdk2443_snd_ac97_device)
+ return -ENOMEM;
+
+ platform_set_drvdata(smdk2443_snd_ac97_device, &smdk2443);
+ ret = platform_device_add(smdk2443_snd_ac97_device);
+
+ if (ret)
+ platform_device_put(smdk2443_snd_ac97_device);
+
+ return ret;
+}
+
+static void __exit smdk2443_exit(void)
+{
+ platform_device_unregister(smdk2443_snd_ac97_device);
+}
+
+module_init(smdk2443_init);
+module_exit(smdk2443_exit);
+
+/* Module information */
+MODULE_AUTHOR("Graeme Gregory, graeme.gregory(a)wolfsonmicro.com, www.wolfsonmicro.com");
+MODULE_DESCRIPTION("ALSA SoC WM9710 SMDK2443");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/samsung/smdk_spdif.c b/sound/soc/samsung/smdk_spdif.c
new file mode 100644
index 0000000..4fc6a9f
--- /dev/null
+++ b/sound/soc/samsung/smdk_spdif.c
@@ -0,0 +1,223 @@
+/*
+ * smdk_spdif.c -- S/PDIF audio for SMDK
+ *
+ * Copyright 2010 Samsung Electronics Co. Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/clk.h>
+
+#include <plat/devs.h>
+
+#include <sound/soc.h>
+
+#include "dma.h"
+#include "spdif.h"
+
+/* Audio clock settings are belonged to board specific part. Every
+ * board can set audio source clock setting which is matched with H/W
+ * like this function-'set_audio_clock_heirachy'.
+ */
+static int set_audio_clock_heirachy(struct platform_device *pdev)
+{
+ struct clk *fout_epll, *mout_epll, *sclk_audio0, *sclk_spdif;
+ int ret;
+
+ fout_epll = clk_get(NULL, "fout_epll");
+ if (IS_ERR(fout_epll)) {
+ printk(KERN_WARNING "%s: Cannot find fout_epll.\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ mout_epll = clk_get(NULL, "mout_epll");
+ if (IS_ERR(fout_epll)) {
+ printk(KERN_WARNING "%s: Cannot find mout_epll.\n",
+ __func__);
+ ret = -EINVAL;
+ goto out1;
+ }
+
+ sclk_audio0 = clk_get(&pdev->dev, "sclk_audio");
+ if (IS_ERR(sclk_audio0)) {
+ printk(KERN_WARNING "%s: Cannot find sclk_audio.\n",
+ __func__);
+ ret = -EINVAL;
+ goto out2;
+ }
+
+ sclk_spdif = clk_get(NULL, "sclk_spdif");
+ if (IS_ERR(fout_epll)) {
+ printk(KERN_WARNING "%s: Cannot find sclk_spdif.\n",
+ __func__);
+ ret = -EINVAL;
+ goto out3;
+ }
+
+ /* Set audio clock heirachy for S/PDIF */
+ clk_set_parent(mout_epll, fout_epll);
+ clk_set_parent(sclk_audio0, mout_epll);
+ clk_set_parent(sclk_spdif, sclk_audio0);
+
+ clk_put(sclk_spdif);
+out3:
+ clk_put(sclk_audio0);
+out2:
+ clk_put(mout_epll);
+out1:
+ clk_put(fout_epll);
+
+ return ret;
+}
+
+/* We should haved to set clock directly on this part because of clock
+ * scheme of Samsudng SoCs did not support to set rates from abstrct
+ * clock of it's heirachy.
+ */
+static int set_audio_clock_rate(unsigned long epll_rate,
+ unsigned long audio_rate)
+{
+ struct clk *fout_epll, *sclk_spdif;
+
+ fout_epll = clk_get(NULL, "fout_epll");
+ if (IS_ERR(fout_epll)) {
+ printk(KERN_ERR "%s: failed to get fout_epll\n", __func__);
+ return -ENOENT;
+ }
+
+ clk_set_rate(fout_epll, epll_rate);
+ clk_put(fout_epll);
+
+ sclk_spdif = clk_get(NULL, "sclk_spdif");
+ if (IS_ERR(sclk_spdif)) {
+ printk(KERN_ERR "%s: failed to get sclk_spdif\n", __func__);
+ return -ENOENT;
+ }
+
+ clk_set_rate(sclk_spdif, audio_rate);
+ clk_put(sclk_spdif);
+
+ return 0;
+}
+
+static int smdk_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ unsigned long pll_out, rclk_rate;
+ int ret, ratio;
+
+ switch (params_rate(params)) {
+ case 44100:
+ pll_out = 45158400;
+ break;
+ case 32000:
+ case 48000:
+ case 96000:
+ pll_out = 49152000;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* Setting ratio to 512fs helps to use S/PDIF with HDMI without
+ * modify S/PDIF ASoC machine driver.
+ */
+ ratio = 512;
+ rclk_rate = params_rate(params) * ratio;
+
+ /* Set audio source clock rates */
+ ret = set_audio_clock_rate(pll_out, rclk_rate);
+ if (ret < 0)
+ return ret;
+
+ /* Set S/PDIF uses internal source clock */
+ ret = snd_soc_dai_set_sysclk(cpu_dai, SND_SOC_SPDIF_INT_MCLK,
+ rclk_rate, SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ return ret;
+
+ return ret;
+}
+
+static struct snd_soc_ops smdk_spdif_ops = {
+ .hw_params = smdk_hw_params,
+};
+
+static struct snd_soc_card smdk;
+
+static struct snd_soc_dai_link smdk_dai = {
+ .name = "S/PDIF",
+ .stream_name = "S/PDIF PCM Playback",
+ .platform_name = "samsung-audio",
+ .cpu_dai_name = "samsung-spdif",
+ .codec_dai_name = "dit-hifi",
+ .codec_name = "spdif-dit",
+ .ops = &smdk_spdif_ops,
+};
+
+static struct snd_soc_card smdk = {
+ .name = "SMDK-S/PDIF",
+ .dai_link = &smdk_dai,
+ .num_links = 1,
+};
+
+static struct platform_device *smdk_snd_spdif_dit_device;
+static struct platform_device *smdk_snd_spdif_device;
+
+static int __init smdk_init(void)
+{
+ int ret;
+
+ smdk_snd_spdif_dit_device = platform_device_alloc("spdif-dit", -1);
+ if (!smdk_snd_spdif_dit_device)
+ return -ENOMEM;
+
+ ret = platform_device_add(smdk_snd_spdif_dit_device);
+ if (ret)
+ goto err2;
+
+ smdk_snd_spdif_device = platform_device_alloc("soc-audio", -1);
+ if (!smdk_snd_spdif_device) {
+ ret = -ENOMEM;
+ goto err2;
+ }
+
+ platform_set_drvdata(smdk_snd_spdif_device, &smdk);
+
+ ret = platform_device_add(smdk_snd_spdif_device);
+ if (ret)
+ goto err1;
+
+ /* Set audio clock heirachy manually */
+ ret = set_audio_clock_heirachy(smdk_snd_spdif_device);
+ if (ret)
+ goto err1;
+
+ return 0;
+err1:
+ platform_device_put(smdk_snd_spdif_device);
+err2:
+ platform_device_put(smdk_snd_spdif_dit_device);
+ return ret;
+}
+
+static void __exit smdk_exit(void)
+{
+ platform_device_unregister(smdk_snd_spdif_device);
+}
+
+module_init(smdk_init);
+module_exit(smdk_exit);
+
+MODULE_AUTHOR("Seungwhan Youn, <sw.youn(a)samsung.com>");
+MODULE_DESCRIPTION("ALSA SoC SMDK+S/PDIF");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/samsung/smdk_wm8580.c b/sound/soc/samsung/smdk_wm8580.c
new file mode 100644
index 0000000..46ab884
--- /dev/null
+++ b/sound/soc/samsung/smdk_wm8580.c
@@ -0,0 +1,284 @@
+/*
+ * smdk_wm8580.c
+ *
+ * Copyright (c) 2009 Samsung Electronics Co. Ltd
+ * Author: Jaswinder Singh <jassi.brar(a)samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include <asm/mach-types.h>
+
+#include "../codecs/wm8580.h"
+#include "dma.h"
+#include "i2s.h"
+
+/*
+ * Default CFG switch settings to use this driver:
+ *
+ * SMDK6410: Set CFG1 1-3 Off, CFG2 1-4 On
+ */
+
+/* SMDK has a 12MHZ crystal attached to WM8580 */
+#define SMDK_WM8580_FREQ 12000000
+
+static int smdk_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ unsigned int pll_out;
+ int bfs, rfs, ret;
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_U8:
+ case SNDRV_PCM_FORMAT_S8:
+ bfs = 16;
+ break;
+ case SNDRV_PCM_FORMAT_U16_LE:
+ case SNDRV_PCM_FORMAT_S16_LE:
+ bfs = 32;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* The Fvco for WM8580 PLLs must fall within [90,100]MHz.
+ * This criterion can't be met if we request PLL output
+ * as {8000x256, 64000x256, 11025x256}Hz.
+ * As a wayout, we rather change rfs to a minimum value that
+ * results in (params_rate(params) * rfs), and itself, acceptable
+ * to both - the CODEC and the CPU.
+ */
+ switch (params_rate(params)) {
+ case 16000:
+ case 22050:
+ case 32000:
+ case 44100:
+ case 48000:
+ case 88200:
+ case 96000:
+ rfs = 256;
+ break;
+ case 64000:
+ rfs = 384;
+ break;
+ case 8000:
+ case 11025:
+ rfs = 512;
+ break;
+ default:
+ return -EINVAL;
+ }
+ pll_out = params_rate(params) * rfs;
+
+ /* Set the Codec DAI configuration */
+ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S
+ | SND_SOC_DAIFMT_NB_NF
+ | SND_SOC_DAIFMT_CBM_CFM);
+ if (ret < 0)
+ return ret;
+
+ /* Set the AP DAI configuration */
+ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S
+ | SND_SOC_DAIFMT_NB_NF
+ | SND_SOC_DAIFMT_CBM_CFM);
+ if (ret < 0)
+ return ret;
+
+ /* Set WM8580 to drive MCLK from its PLLA */
+ ret = snd_soc_dai_set_clkdiv(codec_dai, WM8580_MCLK,
+ WM8580_CLKSRC_PLLA);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_soc_dai_set_pll(codec_dai, WM8580_PLLA, 0,
+ SMDK_WM8580_FREQ, pll_out);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_soc_dai_set_sysclk(codec_dai, WM8580_CLKSRC_PLLA,
+ pll_out, SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+/*
+ * SMDK WM8580 DAI operations.
+ */
+static struct snd_soc_ops smdk_ops = {
+ .hw_params = smdk_hw_params,
+};
+
+/* SMDK Playback widgets */
+static const struct snd_soc_dapm_widget wm8580_dapm_widgets_pbk[] = {
+ SND_SOC_DAPM_HP("Front", NULL),
+ SND_SOC_DAPM_HP("Center+Sub", NULL),
+ SND_SOC_DAPM_HP("Rear", NULL),
+};
+
+/* SMDK Capture widgets */
+static const struct snd_soc_dapm_widget wm8580_dapm_widgets_cpt[] = {
+ SND_SOC_DAPM_MIC("MicIn", NULL),
+ SND_SOC_DAPM_LINE("LineIn", NULL),
+};
+
+/* SMDK-PAIFTX connections */
+static const struct snd_soc_dapm_route audio_map_tx[] = {
+ /* MicIn feeds AINL */
+ {"AINL", NULL, "MicIn"},
+
+ /* LineIn feeds AINL/R */
+ {"AINL", NULL, "LineIn"},
+ {"AINR", NULL, "LineIn"},
+};
+
+/* SMDK-PAIFRX connections */
+static const struct snd_soc_dapm_route audio_map_rx[] = {
+ /* Front Left/Right are fed VOUT1L/R */
+ {"Front", NULL, "VOUT1L"},
+ {"Front", NULL, "VOUT1R"},
+
+ /* Center/Sub are fed VOUT2L/R */
+ {"Center+Sub", NULL, "VOUT2L"},
+ {"Center+Sub", NULL, "VOUT2R"},
+
+ /* Rear Left/Right are fed VOUT3L/R */
+ {"Rear", NULL, "VOUT3L"},
+ {"Rear", NULL, "VOUT3R"},
+};
+
+static int smdk_wm8580_init_paiftx(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_codec *codec = rtd->codec;
+
+ /* Add smdk specific Capture widgets */
+ snd_soc_dapm_new_controls(codec, wm8580_dapm_widgets_cpt,
+ ARRAY_SIZE(wm8580_dapm_widgets_cpt));
+
+ /* Set up PAIFTX audio path */
+ snd_soc_dapm_add_routes(codec, audio_map_tx, ARRAY_SIZE(audio_map_tx));
+
+ /* Enabling the microphone requires the fitting of a 0R
+ * resistor to connect the line from the microphone jack.
+ */
+ snd_soc_dapm_disable_pin(codec, "MicIn");
+
+ /* signal a DAPM event */
+ snd_soc_dapm_sync(codec);
+
+ return 0;
+}
+
+static int smdk_wm8580_init_paifrx(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_codec *codec = rtd->codec;
+
+ /* Add smdk specific Playback widgets */
+ snd_soc_dapm_new_controls(codec, wm8580_dapm_widgets_pbk,
+ ARRAY_SIZE(wm8580_dapm_widgets_pbk));
+
+ /* Set up PAIFRX audio path */
+ snd_soc_dapm_add_routes(codec, audio_map_rx, ARRAY_SIZE(audio_map_rx));
+
+ /* signal a DAPM event */
+ snd_soc_dapm_sync(codec);
+
+ return 0;
+}
+
+enum {
+ PRI_PLAYBACK = 0,
+ PRI_CAPTURE,
+ SEC_PLAYBACK,
+};
+
+static struct snd_soc_dai_link smdk_dai[] = {
+ [PRI_PLAYBACK] = { /* Primary Playback i/f */
+ .name = "WM8580 PAIF RX",
+ .stream_name = "Playback",
+ .cpu_dai_name = "samsung-i2s.2",
+ .codec_dai_name = "wm8580-hifi-playback",
+ .platform_name = "samsung-audio",
+ .codec_name = "wm8580-codec.0-001b",
+ .init = smdk_wm8580_init_paifrx,
+ .ops = &smdk_ops,
+ },
+ [PRI_CAPTURE] = { /* Primary Capture i/f */
+ .name = "WM8580 PAIF TX",
+ .stream_name = "Capture",
+ .cpu_dai_name = "samsung-i2s.2",
+ .codec_dai_name = "wm8580-hifi-capture",
+ .platform_name = "samsung-audio",
+ .codec_name = "wm8580-codec.0-001b",
+ .init = smdk_wm8580_init_paiftx,
+ .ops = &smdk_ops,
+ },
+ [SEC_PLAYBACK] = { /* Sec_Fifo Playback i/f */
+ .name = "Sec_FIFO TX",
+ .stream_name = "Playback",
+ .cpu_dai_name = "samsung-i2s.x",
+ .codec_dai_name = "wm8580-hifi-playback",
+ .platform_name = "samsung-audio",
+ .codec_name = "wm8580-codec.0-001b",
+ .init = smdk_wm8580_init_paifrx,
+ .ops = &smdk_ops,
+ },
+};
+
+static struct snd_soc_card smdk = {
+ .name = "SMDK-I2S",
+ .dai_link = smdk_dai,
+ .num_links = 2,
+};
+
+static struct platform_device *smdk_snd_device;
+
+static int __init smdk_audio_init(void)
+{
+ int ret;
+ char *str;
+
+ if (machine_is_smdkc100()) {
+ smdk.num_links = 3;
+ /* S5PC100 has I2S0 as v5 */
+ str = (char *)smdk_dai[PRI_PLAYBACK].cpu_dai_name;
+ str[strlen(str) - 1] = '0';
+ str = (char *)smdk_dai[PRI_CAPTURE].cpu_dai_name;
+ str[strlen(str) - 1] = '0';
+ /* Secondary is at offset MAX_I2S from Primary */
+ str = (char *)smdk_dai[SEC_PLAYBACK].cpu_dai_name;
+ str[strlen(str) - 1] = '0' + MAX_I2S;
+ }
+
+ smdk_snd_device = platform_device_alloc("soc-audio", -1);
+ if (!smdk_snd_device)
+ return -ENOMEM;
+
+ platform_set_drvdata(smdk_snd_device, &smdk);
+ ret = platform_device_add(smdk_snd_device);
+
+ if (ret)
+ platform_device_put(smdk_snd_device);
+
+ return ret;
+}
+module_init(smdk_audio_init);
+
+MODULE_AUTHOR("Jaswinder Singh, jassi.brar(a)samsung.com");
+MODULE_DESCRIPTION("ALSA SoC SMDK WM8580");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/samsung/smdk_wm9713.c b/sound/soc/samsung/smdk_wm9713.c
new file mode 100644
index 0000000..7ce2430
--- /dev/null
+++ b/sound/soc/samsung/smdk_wm9713.c
@@ -0,0 +1,107 @@
+/*
+ * smdk_wm9713.c -- SoC audio for SMDK
+ *
+ * Copyright 2010 Samsung Electronics Co. Ltd.
+ * Author: Jaswinder Singh Brar <jassi.brar(a)samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <sound/soc.h>
+
+#include "dma.h"
+#include "ac97.h"
+
+static struct snd_soc_card smdk;
+
+/*
+ * Default CFG switch settings to use this driver:
+ *
+ * SMDK6410: Set CFG1 1-3 On, CFG2 1-4 Off
+ * SMDKC100: Set CFG6 1-3 On, CFG7 1 On
+ * SMDKC110: Set CFGB10 1-2 Off, CFGB12 1-3 On
+ * SMDKV210: Set CFGB10 1-2 Off, CFGB12 1-3 On
+ */
+
+/*
+ Playback (HeadPhone):-
+ $ amixer sset 'Headphone' unmute
+ $ amixer sset 'Right Headphone Out Mux' 'Headphone'
+ $ amixer sset 'Left Headphone Out Mux' 'Headphone'
+ $ amixer sset 'Right HP Mixer PCM' unmute
+ $ amixer sset 'Left HP Mixer PCM' unmute
+
+ Capture (LineIn):-
+ $ amixer sset 'Right Capture Source' 'Line'
+ $ amixer sset 'Left Capture Source' 'Line'
+*/
+
+static struct snd_soc_dai_link smdk_dai = {
+ .name = "AC97",
+ .stream_name = "AC97 PCM",
+ .platform_name = "samsung-audio",
+ .cpu_dai_name = "samsung-ac97",
+ .codec_dai_name = "wm9713-hifi",
+ .codec_name = "wm9713-codec",
+};
+
+static struct snd_soc_card smdk = {
+ .name = "SMDK WM9713",
+ .dai_link = &smdk_dai,
+ .num_links = 1,
+};
+
+static struct platform_device *smdk_snd_wm9713_device;
+static struct platform_device *smdk_snd_ac97_device;
+
+static int __init smdk_init(void)
+{
+ int ret;
+
+ smdk_snd_wm9713_device = platform_device_alloc("wm9713-codec", -1);
+ if (!smdk_snd_wm9713_device)
+ return -ENOMEM;
+
+ ret = platform_device_add(smdk_snd_wm9713_device);
+ if (ret)
+ goto err;
+
+ smdk_snd_ac97_device = platform_device_alloc("soc-audio", -1);
+ if (!smdk_snd_ac97_device) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ platform_set_drvdata(smdk_snd_ac97_device, &smdk);
+
+ ret = platform_device_add(smdk_snd_ac97_device);
+ if (ret) {
+ platform_device_put(smdk_snd_ac97_device);
+ goto err;
+ }
+
+ return 0;
+err:
+ platform_device_put(smdk_snd_wm9713_device);
+ return ret;
+}
+
+static void __exit smdk_exit(void)
+{
+ platform_device_unregister(smdk_snd_ac97_device);
+ platform_device_unregister(smdk_snd_wm9713_device);
+}
+
+module_init(smdk_init);
+module_exit(smdk_exit);
+
+/* Module information */
+MODULE_AUTHOR("Jaswinder Singh Brar, jassi.brar(a)samsung.com");
+MODULE_DESCRIPTION("ALSA SoC SMDK+WM9713");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/samsung/spdif.c b/sound/soc/samsung/spdif.c
new file mode 100644
index 0000000..f081640
--- /dev/null
+++ b/sound/soc/samsung/spdif.c
@@ -0,0 +1,501 @@
+/* sound/soc/samsung/spdif.c
+ *
+ * ALSA SoC Audio Layer - Samsung S/PDIF Controller driver
+ *
+ * Copyright (c) 2010 Samsung Electronics Co. Ltd
+ * http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include <plat/audio.h>
+#include <mach/dma.h>
+
+#include "dma.h"
+#include "spdif.h"
+
+/* Registers */
+#define CLKCON 0x00
+#define CON 0x04
+#define BSTAS 0x08
+#define CSTAS 0x0C
+#define DATA_OUTBUF 0x10
+#define DCNT 0x14
+#define BSTAS_S 0x18
+#define DCNT_S 0x1C
+
+#define CLKCTL_MASK 0x7
+#define CLKCTL_MCLK_EXT (0x1 << 2)
+#define CLKCTL_PWR_ON (0x1 << 0)
+
+#define CON_MASK 0x3ffffff
+#define CON_FIFO_TH_SHIFT 19
+#define CON_FIFO_TH_MASK (0x7 << 19)
+#define CON_USERDATA_23RDBIT (0x1 << 12)
+
+#define CON_SW_RESET (0x1 << 5)
+
+#define CON_MCLKDIV_MASK (0x3 << 3)
+#define CON_MCLKDIV_256FS (0x0 << 3)
+#define CON_MCLKDIV_384FS (0x1 << 3)
+#define CON_MCLKDIV_512FS (0x2 << 3)
+
+#define CON_PCM_MASK (0x3 << 1)
+#define CON_PCM_16BIT (0x0 << 1)
+#define CON_PCM_20BIT (0x1 << 1)
+#define CON_PCM_24BIT (0x2 << 1)
+
+#define CON_PCM_DATA (0x1 << 0)
+
+#define CSTAS_MASK 0x3fffffff
+#define CSTAS_SAMP_FREQ_MASK (0xF << 24)
+#define CSTAS_SAMP_FREQ_44 (0x0 << 24)
+#define CSTAS_SAMP_FREQ_48 (0x2 << 24)
+#define CSTAS_SAMP_FREQ_32 (0x3 << 24)
+#define CSTAS_SAMP_FREQ_96 (0xA << 24)
+
+#define CSTAS_CATEGORY_MASK (0xFF << 8)
+#define CSTAS_CATEGORY_CODE_CDP (0x01 << 8)
+
+#define CSTAS_NO_COPYRIGHT (0x1 << 2)
+
+/**
+ * struct samsung_spdif_info - Samsung S/PDIF Controller information
+ * @lock: Spin lock for S/PDIF.
+ * @dev: The parent device passed to use from the probe.
+ * @regs: The pointer to the device register block.
+ * @clk_rate: Current clock rate for calcurate ratio.
+ * @pclk: The peri-clock pointer for spdif master operation.
+ * @sclk: The source clock pointer for making sync signals.
+ * @save_clkcon: Backup clkcon reg. in suspend.
+ * @save_con: Backup con reg. in suspend.
+ * @save_cstas: Backup cstas reg. in suspend.
+ * @dma_playback: DMA information for playback channel.
+ */
+struct samsung_spdif_info {
+ spinlock_t lock;
+ struct device *dev;
+ void __iomem *regs;
+ unsigned long clk_rate;
+ struct clk *pclk;
+ struct clk *sclk;
+ u32 saved_clkcon;
+ u32 saved_con;
+ u32 saved_cstas;
+ struct s3c_dma_params *dma_playback;
+};
+
+static struct s3c2410_dma_client spdif_dma_client_out = {
+ .name = "S/PDIF Stereo out",
+};
+
+static struct s3c_dma_params spdif_stereo_out;
+static struct samsung_spdif_info spdif_info;
+
+static inline struct samsung_spdif_info *to_info(struct snd_soc_dai *cpu_dai)
+{
+ return snd_soc_dai_get_drvdata(cpu_dai);
+}
+
+static void spdif_snd_txctrl(struct samsung_spdif_info *spdif, int on)
+{
+ void __iomem *regs = spdif->regs;
+ u32 clkcon;
+
+ dev_dbg(spdif->dev, "Entered %s\n", __func__);
+
+ clkcon = readl(regs + CLKCON) & CLKCTL_MASK;
+ if (on)
+ writel(clkcon | CLKCTL_PWR_ON, regs + CLKCON);
+ else
+ writel(clkcon & ~CLKCTL_PWR_ON, regs + CLKCON);
+}
+
+static int spdif_set_sysclk(struct snd_soc_dai *cpu_dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct samsung_spdif_info *spdif = to_info(cpu_dai);
+ u32 clkcon;
+
+ dev_dbg(spdif->dev, "Entered %s\n", __func__);
+
+ clkcon = readl(spdif->regs + CLKCON);
+
+ if (clk_id == SND_SOC_SPDIF_INT_MCLK)
+ clkcon &= ~CLKCTL_MCLK_EXT;
+ else
+ clkcon |= CLKCTL_MCLK_EXT;
+
+ writel(clkcon, spdif->regs + CLKCON);
+
+ spdif->clk_rate = freq;
+
+ return 0;
+}
+
+static int spdif_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct samsung_spdif_info *spdif = to_info(rtd->cpu_dai);
+ unsigned long flags;
+
+ dev_dbg(spdif->dev, "Entered %s\n", __func__);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ spin_lock_irqsave(&spdif->lock, flags);
+ spdif_snd_txctrl(spdif, 1);
+ spin_unlock_irqrestore(&spdif->lock, flags);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ spin_lock_irqsave(&spdif->lock, flags);
+ spdif_snd_txctrl(spdif, 0);
+ spin_unlock_irqrestore(&spdif->lock, flags);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int spdif_sysclk_ratios[] = {
+ 512, 384, 256,
+};
+
+static int spdif_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *socdai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct samsung_spdif_info *spdif = to_info(rtd->cpu_dai);
+ void __iomem *regs = spdif->regs;
+ struct s3c_dma_params *dma_data;
+ u32 con, clkcon, cstas;
+ unsigned long flags;
+ int i, ratio;
+
+ dev_dbg(spdif->dev, "Entered %s\n", __func__);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ dma_data = spdif->dma_playback;
+ else {
+ dev_err(spdif->dev, "Capture is not supported\n");
+ return -EINVAL;
+ }
+
+ snd_soc_dai_set_dma_data(rtd->cpu_dai, substream, dma_data);
+
+ spin_lock_irqsave(&spdif->lock, flags);
+
+ con = readl(regs + CON) & CON_MASK;
+ cstas = readl(regs + CSTAS) & CSTAS_MASK;
+ clkcon = readl(regs + CLKCON) & CLKCTL_MASK;
+
+ con &= ~CON_FIFO_TH_MASK;
+ con |= (0x7 << CON_FIFO_TH_SHIFT);
+ con |= CON_USERDATA_23RDBIT;
+ con |= CON_PCM_DATA;
+
+ con &= ~CON_PCM_MASK;
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ con |= CON_PCM_16BIT;
+ break;
+ default:
+ dev_err(spdif->dev, "Unsupported data size.\n");
+ goto err;
+ }
+
+ ratio = spdif->clk_rate / params_rate(params);
+ for (i = 0; i < ARRAY_SIZE(spdif_sysclk_ratios); i++)
+ if (ratio == spdif_sysclk_ratios[i])
+ break;
+ if (i == ARRAY_SIZE(spdif_sysclk_ratios)) {
+ dev_err(spdif->dev, "Invalid clock ratio %ld/%d\n",
+ spdif->clk_rate, params_rate(params));
+ goto err;
+ }
+
+ con &= ~CON_MCLKDIV_MASK;
+ switch (ratio) {
+ case 256:
+ con |= CON_MCLKDIV_256FS;
+ break;
+ case 384:
+ con |= CON_MCLKDIV_384FS;
+ break;
+ case 512:
+ con |= CON_MCLKDIV_512FS;
+ break;
+ }
+
+ cstas &= ~CSTAS_SAMP_FREQ_MASK;
+ switch (params_rate(params)) {
+ case 44100:
+ cstas |= CSTAS_SAMP_FREQ_44;
+ break;
+ case 48000:
+ cstas |= CSTAS_SAMP_FREQ_48;
+ break;
+ case 32000:
+ cstas |= CSTAS_SAMP_FREQ_32;
+ break;
+ case 96000:
+ cstas |= CSTAS_SAMP_FREQ_96;
+ break;
+ default:
+ dev_err(spdif->dev, "Invalid sampling rate %d\n",
+ params_rate(params));
+ goto err;
+ }
+
+ cstas &= ~CSTAS_CATEGORY_MASK;
+ cstas |= CSTAS_CATEGORY_CODE_CDP;
+ cstas |= CSTAS_NO_COPYRIGHT;
+
+ writel(con, regs + CON);
+ writel(cstas, regs + CSTAS);
+ writel(clkcon, regs + CLKCON);
+
+ spin_unlock_irqrestore(&spdif->lock, flags);
+
+ return 0;
+err:
+ spin_unlock_irqrestore(&spdif->lock, flags);
+ return -EINVAL;
+}
+
+static void spdif_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct samsung_spdif_info *spdif = to_info(rtd->cpu_dai);
+ void __iomem *regs = spdif->regs;
+ u32 con, clkcon;
+
+ dev_dbg(spdif->dev, "Entered %s\n", __func__);
+
+ con = readl(regs + CON) & CON_MASK;
+ clkcon = readl(regs + CLKCON) & CLKCTL_MASK;
+
+ writel(con | CON_SW_RESET, regs + CON);
+ cpu_relax();
+
+ writel(clkcon & ~CLKCTL_PWR_ON, regs + CLKCON);
+}
+
+#ifdef CONFIG_PM
+static int spdif_suspend(struct snd_soc_dai *cpu_dai)
+{
+ struct samsung_spdif_info *spdif = to_info(cpu_dai);
+ u32 con = spdif->saved_con;
+
+ dev_dbg(spdif->dev, "Entered %s\n", __func__);
+
+ spdif->saved_clkcon = readl(spdif->regs + CLKCON) & CLKCTL_MASK;
+ spdif->saved_con = readl(spdif->regs + CON) & CON_MASK;
+ spdif->saved_cstas = readl(spdif->regs + CSTAS) & CSTAS_MASK;
+
+ writel(con | CON_SW_RESET, spdif->regs + CON);
+ cpu_relax();
+
+ return 0;
+}
+
+static int spdif_resume(struct snd_soc_dai *cpu_dai)
+{
+ struct samsung_spdif_info *spdif = to_info(cpu_dai);
+
+ dev_dbg(spdif->dev, "Entered %s\n", __func__);
+
+ writel(spdif->saved_clkcon, spdif->regs + CLKCON);
+ writel(spdif->saved_con, spdif->regs + CON);
+ writel(spdif->saved_cstas, spdif->regs + CSTAS);
+
+ return 0;
+}
+#else
+#define spdif_suspend NULL
+#define spdif_resume NULL
+#endif
+
+static struct snd_soc_dai_ops spdif_dai_ops = {
+ .set_sysclk = spdif_set_sysclk,
+ .trigger = spdif_trigger,
+ .hw_params = spdif_hw_params,
+ .shutdown = spdif_shutdown,
+};
+
+struct snd_soc_dai_driver samsung_spdif_dai = {
+ .name = "samsung-spdif",
+ .playback = {
+ .stream_name = "S/PDIF Playback",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = (SNDRV_PCM_RATE_32000 |
+ SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_96000),
+ .formats = SNDRV_PCM_FMTBIT_S16_LE, },
+ .ops = &spdif_dai_ops,
+ .suspend = spdif_suspend,
+ .resume = spdif_resume,
+};
+
+static __devinit int spdif_probe(struct platform_device *pdev)
+{
+ struct s3c_audio_pdata *spdif_pdata;
+ struct resource *mem_res, *dma_res;
+ struct samsung_spdif_info *spdif;
+ int ret;
+
+ spdif_pdata = pdev->dev.platform_data;
+
+ dev_dbg(&pdev->dev, "Entered %s\n", __func__);
+
+ dma_res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+ if (!dma_res) {
+ dev_err(&pdev->dev, "Unable to get dma resource.\n");
+ return -ENXIO;
+ }
+
+ mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem_res) {
+ dev_err(&pdev->dev, "Unable to get register resource.\n");
+ return -ENXIO;
+ }
+
+ if (spdif_pdata && spdif_pdata->cfg_gpio
+ && spdif_pdata->cfg_gpio(pdev)) {
+ dev_err(&pdev->dev, "Unable to configure GPIO pins\n");
+ return -EINVAL;
+ }
+
+ spdif = &spdif_info;
+ spdif->dev = &pdev->dev;
+
+ spin_lock_init(&spdif->lock);
+
+ spdif->pclk = clk_get(&pdev->dev, "spdif");
+ if (IS_ERR(spdif->pclk)) {
+ dev_err(&pdev->dev, "failed to get peri-clock\n");
+ ret = -ENOENT;
+ goto err0;
+ }
+ clk_enable(spdif->pclk);
+
+ spdif->sclk = clk_get(&pdev->dev, "sclk_spdif");
+ if (IS_ERR(spdif->sclk)) {
+ dev_err(&pdev->dev, "failed to get internal source clock\n");
+ ret = -ENOENT;
+ goto err1;
+ }
+ clk_enable(spdif->sclk);
+
+ /* Request S/PDIF Register's memory region */
+ if (!request_mem_region(mem_res->start,
+ resource_size(mem_res), "samsung-spdif")) {
+ dev_err(&pdev->dev, "Unable to request register region\n");
+ ret = -EBUSY;
+ goto err2;
+ }
+
+ spdif->regs = ioremap(mem_res->start, 0x100);
+ if (spdif->regs == NULL) {
+ dev_err(&pdev->dev, "Cannot ioremap registers\n");
+ ret = -ENXIO;
+ goto err3;
+ }
+
+ dev_set_drvdata(&pdev->dev, spdif);
+
+ ret = snd_soc_register_dai(&pdev->dev, &samsung_spdif_dai);
+ if (ret != 0) {
+ dev_err(&pdev->dev, "fail to register dai\n");
+ goto err4;
+ }
+
+ spdif_stereo_out.dma_size = 2;
+ spdif_stereo_out.client = &spdif_dma_client_out;
+ spdif_stereo_out.dma_addr = mem_res->start + DATA_OUTBUF;
+ spdif_stereo_out.channel = dma_res->start;
+
+ spdif->dma_playback = &spdif_stereo_out;
+
+ return 0;
+
+err4:
+ iounmap(spdif->regs);
+err3:
+ release_mem_region(mem_res->start, resource_size(mem_res));
+err2:
+ clk_disable(spdif->sclk);
+ clk_put(spdif->sclk);
+err1:
+ clk_disable(spdif->pclk);
+ clk_put(spdif->pclk);
+err0:
+ return ret;
+}
+
+static __devexit int spdif_remove(struct platform_device *pdev)
+{
+ struct samsung_spdif_info *spdif = &spdif_info;
+ struct resource *mem_res;
+
+ snd_soc_unregister_dai(&pdev->dev);
+
+ iounmap(spdif->regs);
+
+ mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (mem_res)
+ release_mem_region(mem_res->start, resource_size(mem_res));
+
+ clk_disable(spdif->sclk);
+ clk_put(spdif->sclk);
+ clk_disable(spdif->pclk);
+ clk_put(spdif->pclk);
+
+ return 0;
+}
+
+static struct platform_driver samsung_spdif_driver = {
+ .probe = spdif_probe,
+ .remove = spdif_remove,
+ .driver = {
+ .name = "samsung-spdif",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init spdif_init(void)
+{
+ return platform_driver_register(&samsung_spdif_driver);
+}
+module_init(spdif_init);
+
+static void __exit spdif_exit(void)
+{
+ platform_driver_unregister(&samsung_spdif_driver);
+}
+module_exit(spdif_exit);
+
+MODULE_AUTHOR("Seungwhan Youn, <sw.youn(a)samsung.com>");
+MODULE_DESCRIPTION("Samsung S/PDIF Controller Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:samsung-spdif");
diff --git a/sound/soc/samsung/spdif.h b/sound/soc/samsung/spdif.h
new file mode 100644
index 0000000..4f72cb4
--- /dev/null
+++ b/sound/soc/samsung/spdif.h
@@ -0,0 +1,19 @@
+/* sound/soc/samsung/spdif.h
+ *
+ * ALSA SoC Audio Layer - Samsung S/PDIF Controller driver
+ *
+ * Copyright (c) 2010 Samsung Electronics Co. Ltd
+ * http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __SND_SOC_SAMSUNG_SPDIF_H
+#define __SND_SOC_SAMSUNG_SPDIF_H __FILE__
+
+#define SND_SOC_SPDIF_INT_MCLK 0
+#define SND_SOC_SPDIF_EXT_MCLK 1
+
+#endif /* __SND_SOC_SAMSUNG_SPDIF_H */
--
1.6.2.5
2
2

19 Oct '10
From: Jassi Brar <jassi.brar(a)samsung.com>
Finally, move the 's3c24xx' directory to 'samsung'
Signed-off-by: Jassi Brar <jassi.brar(a)samsung.com>
---
sound/soc/Kconfig | 2 +-
sound/soc/Makefile | 2 +-
sound/soc/{s3c24xx => samsung}/Kconfig | 0
sound/soc/{s3c24xx => samsung}/Makefile | 0
sound/soc/{s3c24xx => samsung}/ac97.c | 2 +-
sound/soc/{s3c24xx => samsung}/ac97.h | 2 +-
sound/soc/{s3c24xx => samsung}/dma.c | 0
sound/soc/{s3c24xx => samsung}/dma.h | 0
sound/soc/{s3c24xx => samsung}/goni_wm8994.c | 0
sound/soc/{s3c24xx => samsung}/i2s.c | 2 +-
sound/soc/{s3c24xx => samsung}/i2s.h | 2 +-
sound/soc/{s3c24xx => samsung}/jive_wm8750.c | 2 +-
sound/soc/{s3c24xx => samsung}/lm4857.h | 0
sound/soc/{s3c24xx => samsung}/ln2440sbc_alc650.c | 0
.../{s3c24xx => samsung}/neo1973_gta02_wm8753.c | 0
sound/soc/{s3c24xx => samsung}/neo1973_wm8753.c | 0
sound/soc/{s3c24xx => samsung}/pcm.c | 2 +-
sound/soc/{s3c24xx => samsung}/pcm.h | 2 +-
sound/soc/{s3c24xx => samsung}/regs-i2s-v2.h | 0
sound/soc/{s3c24xx => samsung}/rx1950_uda1380.c | 0
sound/soc/{s3c24xx => samsung}/s3c-i2s-v2.c | 2 +-
sound/soc/{s3c24xx => samsung}/s3c-i2s-v2.h | 2 +-
sound/soc/{s3c24xx => samsung}/s3c2412-i2s.c | 2 +-
sound/soc/{s3c24xx => samsung}/s3c2412-i2s.h | 2 +-
sound/soc/{s3c24xx => samsung}/s3c24xx-i2s.c | 0
sound/soc/{s3c24xx => samsung}/s3c24xx-i2s.h | 0
sound/soc/{s3c24xx => samsung}/s3c24xx_simtec.c | 2 +-
sound/soc/{s3c24xx => samsung}/s3c24xx_simtec.h | 2 +-
.../{s3c24xx => samsung}/s3c24xx_simtec_hermes.c | 2 +-
.../s3c24xx_simtec_tlv320aic23.c | 2 +-
sound/soc/{s3c24xx => samsung}/s3c24xx_uda134x.c | 0
sound/soc/{s3c24xx => samsung}/smartq_wm8987.c | 2 +-
sound/soc/{s3c24xx => samsung}/smdk2443_wm9710.c | 0
sound/soc/{s3c24xx => samsung}/smdk_spdif.c | 0
sound/soc/{s3c24xx => samsung}/smdk_wm8580.c | 0
sound/soc/{s3c24xx => samsung}/smdk_wm9713.c | 0
sound/soc/{s3c24xx => samsung}/spdif.c | 2 +-
sound/soc/{s3c24xx => samsung}/spdif.h | 2 +-
38 files changed, 20 insertions(+), 20 deletions(-)
rename sound/soc/{s3c24xx => samsung}/Kconfig (100%)
rename sound/soc/{s3c24xx => samsung}/Makefile (100%)
rename sound/soc/{s3c24xx => samsung}/ac97.c (99%)
rename sound/soc/{s3c24xx => samsung}/ac97.h (95%)
rename sound/soc/{s3c24xx => samsung}/dma.c (100%)
rename sound/soc/{s3c24xx => samsung}/dma.h (100%)
rename sound/soc/{s3c24xx => samsung}/goni_wm8994.c (100%)
rename sound/soc/{s3c24xx => samsung}/i2s.c (99%)
rename sound/soc/{s3c24xx => samsung}/i2s.h (96%)
rename sound/soc/{s3c24xx => samsung}/jive_wm8750.c (99%)
rename sound/soc/{s3c24xx => samsung}/lm4857.h (100%)
rename sound/soc/{s3c24xx => samsung}/ln2440sbc_alc650.c (100%)
rename sound/soc/{s3c24xx => samsung}/neo1973_gta02_wm8753.c (100%)
rename sound/soc/{s3c24xx => samsung}/neo1973_wm8753.c (100%)
rename sound/soc/{s3c24xx => samsung}/pcm.c (99%)
rename sound/soc/{s3c24xx => samsung}/pcm.h (99%)
rename sound/soc/{s3c24xx => samsung}/regs-i2s-v2.h (100%)
rename sound/soc/{s3c24xx => samsung}/rx1950_uda1380.c (100%)
rename sound/soc/{s3c24xx => samsung}/s3c-i2s-v2.c (99%)
rename sound/soc/{s3c24xx => samsung}/s3c-i2s-v2.h (98%)
rename sound/soc/{s3c24xx => samsung}/s3c2412-i2s.c (99%)
rename sound/soc/{s3c24xx => samsung}/s3c2412-i2s.h (95%)
rename sound/soc/{s3c24xx => samsung}/s3c24xx-i2s.c (100%)
rename sound/soc/{s3c24xx => samsung}/s3c24xx-i2s.h (100%)
rename sound/soc/{s3c24xx => samsung}/s3c24xx_simtec.c (99%)
rename sound/soc/{s3c24xx => samsung}/s3c24xx_simtec.h (94%)
rename sound/soc/{s3c24xx => samsung}/s3c24xx_simtec_hermes.c (98%)
rename sound/soc/{s3c24xx => samsung}/s3c24xx_simtec_tlv320aic23.c (98%)
rename sound/soc/{s3c24xx => samsung}/s3c24xx_uda134x.c (100%)
rename sound/soc/{s3c24xx => samsung}/smartq_wm8987.c (99%)
rename sound/soc/{s3c24xx => samsung}/smdk2443_wm9710.c (100%)
rename sound/soc/{s3c24xx => samsung}/smdk_spdif.c (100%)
rename sound/soc/{s3c24xx => samsung}/smdk_wm8580.c (100%)
rename sound/soc/{s3c24xx => samsung}/smdk_wm9713.c (100%)
rename sound/soc/{s3c24xx => samsung}/spdif.c (99%)
rename sound/soc/{s3c24xx => samsung}/spdif.h (94%)
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
index 3e598e7..2722b19 100644
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -36,7 +36,7 @@ source "sound/soc/nuc900/Kconfig"
source "sound/soc/omap/Kconfig"
source "sound/soc/kirkwood/Kconfig"
source "sound/soc/pxa/Kconfig"
-source "sound/soc/s3c24xx/Kconfig"
+source "sound/soc/samsung/Kconfig"
source "sound/soc/s6000/Kconfig"
source "sound/soc/sh/Kconfig"
source "sound/soc/txx9/Kconfig"
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index eb18344..ce913bf 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -14,7 +14,7 @@ obj-$(CONFIG_SND_SOC) += nuc900/
obj-$(CONFIG_SND_SOC) += omap/
obj-$(CONFIG_SND_SOC) += kirkwood/
obj-$(CONFIG_SND_SOC) += pxa/
-obj-$(CONFIG_SND_SOC) += s3c24xx/
+obj-$(CONFIG_SND_SOC) += samsung/
obj-$(CONFIG_SND_SOC) += s6000/
obj-$(CONFIG_SND_SOC) += sh/
obj-$(CONFIG_SND_SOC) += txx9/
diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/samsung/Kconfig
similarity index 100%
rename from sound/soc/s3c24xx/Kconfig
rename to sound/soc/samsung/Kconfig
diff --git a/sound/soc/s3c24xx/Makefile b/sound/soc/samsung/Makefile
similarity index 100%
rename from sound/soc/s3c24xx/Makefile
rename to sound/soc/samsung/Makefile
diff --git a/sound/soc/s3c24xx/ac97.c b/sound/soc/samsung/ac97.c
similarity index 99%
rename from sound/soc/s3c24xx/ac97.c
rename to sound/soc/samsung/ac97.c
index 4f999d1..4770a95 100644
--- a/sound/soc/s3c24xx/ac97.c
+++ b/sound/soc/samsung/ac97.c
@@ -1,4 +1,4 @@
-/* sound/soc/s3c24xx/ac97.c
+/* sound/soc/samsung/ac97.c
*
* ALSA SoC Audio Layer - S3C AC97 Controller driver
* Evolved from s3c2443-ac97.c
diff --git a/sound/soc/s3c24xx/ac97.h b/sound/soc/samsung/ac97.h
similarity index 95%
rename from sound/soc/s3c24xx/ac97.h
rename to sound/soc/samsung/ac97.h
index a8f01b7..0d0e1b5 100644
--- a/sound/soc/s3c24xx/ac97.h
+++ b/sound/soc/samsung/ac97.h
@@ -1,4 +1,4 @@
-/* sound/soc/s3c24xx/ac97.h
+/* sound/soc/samsung/ac97.h
*
* ALSA SoC Audio Layer - S3C AC97 Controller driver
* Evolved from s3c2443-ac97.h
diff --git a/sound/soc/s3c24xx/dma.c b/sound/soc/samsung/dma.c
similarity index 100%
rename from sound/soc/s3c24xx/dma.c
rename to sound/soc/samsung/dma.c
diff --git a/sound/soc/s3c24xx/dma.h b/sound/soc/samsung/dma.h
similarity index 100%
rename from sound/soc/s3c24xx/dma.h
rename to sound/soc/samsung/dma.h
diff --git a/sound/soc/s3c24xx/goni_wm8994.c b/sound/soc/samsung/goni_wm8994.c
similarity index 100%
rename from sound/soc/s3c24xx/goni_wm8994.c
rename to sound/soc/samsung/goni_wm8994.c
diff --git a/sound/soc/s3c24xx/i2s.c b/sound/soc/samsung/i2s.c
similarity index 99%
rename from sound/soc/s3c24xx/i2s.c
rename to sound/soc/samsung/i2s.c
index 6869f51..d5d8975 100644
--- a/sound/soc/s3c24xx/i2s.c
+++ b/sound/soc/samsung/i2s.c
@@ -1,4 +1,4 @@
-/* sound/soc/s3c24xx/i2s.c
+/* sound/soc/samsung/i2s.c
*
* ALSA SoC Audio Layer - Samsung I2S Controller driver
*
diff --git a/sound/soc/s3c24xx/i2s.h b/sound/soc/samsung/i2s.h
similarity index 96%
rename from sound/soc/s3c24xx/i2s.h
rename to sound/soc/samsung/i2s.h
index 77b7965..73a71cd 100644
--- a/sound/soc/s3c24xx/i2s.h
+++ b/sound/soc/samsung/i2s.h
@@ -1,4 +1,4 @@
-/* sound/soc/s3c24xx/i2s.h
+/* sound/soc/samsung/i2s.h
*
* ALSA SoC Audio Layer - Samsung I2S Controller driver
*
diff --git a/sound/soc/s3c24xx/jive_wm8750.c b/sound/soc/samsung/jive_wm8750.c
similarity index 99%
rename from sound/soc/s3c24xx/jive_wm8750.c
rename to sound/soc/samsung/jive_wm8750.c
index 4e1b8ac..fe1649e 100644
--- a/sound/soc/s3c24xx/jive_wm8750.c
+++ b/sound/soc/samsung/jive_wm8750.c
@@ -1,4 +1,4 @@
-/* sound/soc/s3c24xx/jive_wm8750.c
+/* sound/soc/samsung/jive_wm8750.c
*
* Copyright 2007,2008 Simtec Electronics
*
diff --git a/sound/soc/s3c24xx/lm4857.h b/sound/soc/samsung/lm4857.h
similarity index 100%
rename from sound/soc/s3c24xx/lm4857.h
rename to sound/soc/samsung/lm4857.h
diff --git a/sound/soc/s3c24xx/ln2440sbc_alc650.c b/sound/soc/samsung/ln2440sbc_alc650.c
similarity index 100%
rename from sound/soc/s3c24xx/ln2440sbc_alc650.c
rename to sound/soc/samsung/ln2440sbc_alc650.c
diff --git a/sound/soc/s3c24xx/neo1973_gta02_wm8753.c b/sound/soc/samsung/neo1973_gta02_wm8753.c
similarity index 100%
rename from sound/soc/s3c24xx/neo1973_gta02_wm8753.c
rename to sound/soc/samsung/neo1973_gta02_wm8753.c
diff --git a/sound/soc/s3c24xx/neo1973_wm8753.c b/sound/soc/samsung/neo1973_wm8753.c
similarity index 100%
rename from sound/soc/s3c24xx/neo1973_wm8753.c
rename to sound/soc/samsung/neo1973_wm8753.c
diff --git a/sound/soc/s3c24xx/pcm.c b/sound/soc/samsung/pcm.c
similarity index 99%
rename from sound/soc/s3c24xx/pcm.c
rename to sound/soc/samsung/pcm.c
index 4d0f6e4..48d0b75 100644
--- a/sound/soc/s3c24xx/pcm.c
+++ b/sound/soc/samsung/pcm.c
@@ -1,4 +1,4 @@
-/* sound/soc/s3c24xx/pcm.c
+/* sound/soc/samsung/pcm.c
*
* ALSA SoC Audio Layer - S3C PCM-Controller driver
*
diff --git a/sound/soc/s3c24xx/pcm.h b/sound/soc/samsung/pcm.h
similarity index 99%
rename from sound/soc/s3c24xx/pcm.h
rename to sound/soc/samsung/pcm.h
index 3775216..03393dc 100644
--- a/sound/soc/s3c24xx/pcm.h
+++ b/sound/soc/samsung/pcm.h
@@ -1,4 +1,4 @@
-/* sound/soc/s3c24xx/pcm.h
+/* sound/soc/samsung/pcm.h
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
diff --git a/sound/soc/s3c24xx/regs-i2s-v2.h b/sound/soc/samsung/regs-i2s-v2.h
similarity index 100%
rename from sound/soc/s3c24xx/regs-i2s-v2.h
rename to sound/soc/samsung/regs-i2s-v2.h
diff --git a/sound/soc/s3c24xx/rx1950_uda1380.c b/sound/soc/samsung/rx1950_uda1380.c
similarity index 100%
rename from sound/soc/s3c24xx/rx1950_uda1380.c
rename to sound/soc/samsung/rx1950_uda1380.c
diff --git a/sound/soc/s3c24xx/s3c-i2s-v2.c b/sound/soc/samsung/s3c-i2s-v2.c
similarity index 99%
rename from sound/soc/s3c24xx/s3c-i2s-v2.c
rename to sound/soc/samsung/s3c-i2s-v2.c
index c471431..094f36e 100644
--- a/sound/soc/s3c24xx/s3c-i2s-v2.c
+++ b/sound/soc/samsung/s3c-i2s-v2.c
@@ -1,4 +1,4 @@
-/* sound/soc/s3c24xx/s3c-i2c-v2.c
+/* sound/soc/samsung/s3c-i2c-v2.c
*
* ALSA Soc Audio Layer - I2S core for newer Samsung SoCs.
*
diff --git a/sound/soc/s3c24xx/s3c-i2s-v2.h b/sound/soc/samsung/s3c-i2s-v2.h
similarity index 98%
rename from sound/soc/s3c24xx/s3c-i2s-v2.h
rename to sound/soc/samsung/s3c-i2s-v2.h
index d458301..f8297d9 100644
--- a/sound/soc/s3c24xx/s3c-i2s-v2.h
+++ b/sound/soc/samsung/s3c-i2s-v2.h
@@ -1,4 +1,4 @@
-/* sound/soc/s3c24xx/s3c-i2s-v2.h
+/* sound/soc/samsung/s3c-i2s-v2.h
*
* ALSA Soc Audio Layer - S3C_I2SV2 I2S driver
*
diff --git a/sound/soc/s3c24xx/s3c2412-i2s.c b/sound/soc/samsung/s3c2412-i2s.c
similarity index 99%
rename from sound/soc/s3c24xx/s3c2412-i2s.c
rename to sound/soc/samsung/s3c2412-i2s.c
index d953ff4..7ea8378 100644
--- a/sound/soc/s3c24xx/s3c2412-i2s.c
+++ b/sound/soc/samsung/s3c2412-i2s.c
@@ -1,4 +1,4 @@
-/* sound/soc/s3c24xx/s3c2412-i2s.c
+/* sound/soc/samsung/s3c2412-i2s.c
*
* ALSA Soc Audio Layer - S3C2412 I2S driver
*
diff --git a/sound/soc/s3c24xx/s3c2412-i2s.h b/sound/soc/samsung/s3c2412-i2s.h
similarity index 95%
rename from sound/soc/s3c24xx/s3c2412-i2s.h
rename to sound/soc/samsung/s3c2412-i2s.h
index 01a0471..02ad579 100644
--- a/sound/soc/s3c24xx/s3c2412-i2s.h
+++ b/sound/soc/samsung/s3c2412-i2s.h
@@ -1,4 +1,4 @@
-/* sound/soc/s3c24xx/s3c2412-i2s.c
+/* sound/soc/samsung/s3c2412-i2s.c
*
* ALSA Soc Audio Layer - S3C2412 I2S driver
*
diff --git a/sound/soc/s3c24xx/s3c24xx-i2s.c b/sound/soc/samsung/s3c24xx-i2s.c
similarity index 100%
rename from sound/soc/s3c24xx/s3c24xx-i2s.c
rename to sound/soc/samsung/s3c24xx-i2s.c
diff --git a/sound/soc/s3c24xx/s3c24xx-i2s.h b/sound/soc/samsung/s3c24xx-i2s.h
similarity index 100%
rename from sound/soc/s3c24xx/s3c24xx-i2s.h
rename to sound/soc/samsung/s3c24xx-i2s.h
diff --git a/sound/soc/s3c24xx/s3c24xx_simtec.c b/sound/soc/samsung/s3c24xx_simtec.c
similarity index 99%
rename from sound/soc/s3c24xx/s3c24xx_simtec.c
rename to sound/soc/samsung/s3c24xx_simtec.c
index 3f052a5..4a1b002 100644
--- a/sound/soc/s3c24xx/s3c24xx_simtec.c
+++ b/sound/soc/samsung/s3c24xx_simtec.c
@@ -1,4 +1,4 @@
-/* sound/soc/s3c24xx/s3c24xx_simtec.c
+/* sound/soc/samsung/s3c24xx_simtec.c
*
* Copyright 2009 Simtec Electronics
*
diff --git a/sound/soc/s3c24xx/s3c24xx_simtec.h b/sound/soc/samsung/s3c24xx_simtec.h
similarity index 94%
rename from sound/soc/s3c24xx/s3c24xx_simtec.h
rename to sound/soc/samsung/s3c24xx_simtec.h
index e63d5ff..8270748 100644
--- a/sound/soc/s3c24xx/s3c24xx_simtec.h
+++ b/sound/soc/samsung/s3c24xx_simtec.h
@@ -1,4 +1,4 @@
-/* sound/soc/s3c24xx/s3c24xx_simtec.h
+/* sound/soc/samsung/s3c24xx_simtec.h
*
* Copyright 2009 Simtec Electronics
*
diff --git a/sound/soc/s3c24xx/s3c24xx_simtec_hermes.c b/sound/soc/samsung/s3c24xx_simtec_hermes.c
similarity index 98%
rename from sound/soc/s3c24xx/s3c24xx_simtec_hermes.c
rename to sound/soc/samsung/s3c24xx_simtec_hermes.c
index 8b246ab..fec4cac 100644
--- a/sound/soc/s3c24xx/s3c24xx_simtec_hermes.c
+++ b/sound/soc/samsung/s3c24xx_simtec_hermes.c
@@ -1,4 +1,4 @@
-/* sound/soc/s3c24xx/s3c24xx_simtec_hermes.c
+/* sound/soc/samsung/s3c24xx_simtec_hermes.c
*
* Copyright 2009 Simtec Electronics
*
diff --git a/sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c b/sound/soc/samsung/s3c24xx_simtec_tlv320aic23.c
similarity index 98%
rename from sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c
rename to sound/soc/samsung/s3c24xx_simtec_tlv320aic23.c
index a922e1e..7915e02 100644
--- a/sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c
+++ b/sound/soc/samsung/s3c24xx_simtec_tlv320aic23.c
@@ -1,4 +1,4 @@
-/* sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c
+/* sound/soc/samsung/s3c24xx_simtec_tlv320aic23.c
*
* Copyright 2009 Simtec Electronics
*
diff --git a/sound/soc/s3c24xx/s3c24xx_uda134x.c b/sound/soc/samsung/s3c24xx_uda134x.c
similarity index 100%
rename from sound/soc/s3c24xx/s3c24xx_uda134x.c
rename to sound/soc/samsung/s3c24xx_uda134x.c
diff --git a/sound/soc/s3c24xx/smartq_wm8987.c b/sound/soc/samsung/smartq_wm8987.c
similarity index 99%
rename from sound/soc/s3c24xx/smartq_wm8987.c
rename to sound/soc/samsung/smartq_wm8987.c
index 5fcc420..3564e00 100644
--- a/sound/soc/s3c24xx/smartq_wm8987.c
+++ b/sound/soc/samsung/smartq_wm8987.c
@@ -1,4 +1,4 @@
-/* sound/soc/s3c24xx/smartq_wm8987.c
+/* sound/soc/samsung/smartq_wm8987.c
*
* Copyright 2010 Maurus Cuelenaere <mcuelenaere(a)gmail.com>
*
diff --git a/sound/soc/s3c24xx/smdk2443_wm9710.c b/sound/soc/samsung/smdk2443_wm9710.c
similarity index 100%
rename from sound/soc/s3c24xx/smdk2443_wm9710.c
rename to sound/soc/samsung/smdk2443_wm9710.c
diff --git a/sound/soc/s3c24xx/smdk_spdif.c b/sound/soc/samsung/smdk_spdif.c
similarity index 100%
rename from sound/soc/s3c24xx/smdk_spdif.c
rename to sound/soc/samsung/smdk_spdif.c
diff --git a/sound/soc/s3c24xx/smdk_wm8580.c b/sound/soc/samsung/smdk_wm8580.c
similarity index 100%
rename from sound/soc/s3c24xx/smdk_wm8580.c
rename to sound/soc/samsung/smdk_wm8580.c
diff --git a/sound/soc/s3c24xx/smdk_wm9713.c b/sound/soc/samsung/smdk_wm9713.c
similarity index 100%
rename from sound/soc/s3c24xx/smdk_wm9713.c
rename to sound/soc/samsung/smdk_wm9713.c
diff --git a/sound/soc/s3c24xx/spdif.c b/sound/soc/samsung/spdif.c
similarity index 99%
rename from sound/soc/s3c24xx/spdif.c
rename to sound/soc/samsung/spdif.c
index dc85df3..f081640 100644
--- a/sound/soc/s3c24xx/spdif.c
+++ b/sound/soc/samsung/spdif.c
@@ -1,4 +1,4 @@
-/* sound/soc/s3c24xx/spdif.c
+/* sound/soc/samsung/spdif.c
*
* ALSA SoC Audio Layer - Samsung S/PDIF Controller driver
*
diff --git a/sound/soc/s3c24xx/spdif.h b/sound/soc/samsung/spdif.h
similarity index 94%
rename from sound/soc/s3c24xx/spdif.h
rename to sound/soc/samsung/spdif.h
index 3ed5559..4f72cb4 100644
--- a/sound/soc/s3c24xx/spdif.h
+++ b/sound/soc/samsung/spdif.h
@@ -1,4 +1,4 @@
-/* sound/soc/s3c24xx/spdif.h
+/* sound/soc/samsung/spdif.h
*
* ALSA SoC Audio Layer - Samsung S/PDIF Controller driver
*
--
1.6.2.5
1
0

19 Oct '10
From: Jassi Brar <jassi.brar(a)samsung.com>
The ASoC uses common DMA driver for Audio devices. So it makes
sense to a common audio-dma device shared across all platforms.
Signed-off-by: Jassi Brar <jassi.brar(a)samsung.com>
---
arch/arm/mach-s3c64xx/dev-audio.c | 13 -------------
arch/arm/mach-s3c64xx/mach-smdk6410.c | 2 +-
arch/arm/plat-s3c24xx/devs.c | 15 ---------------
arch/arm/plat-samsung/Makefile | 1 +
arch/arm/plat-samsung/dev-asocdma.c | 24 ++++++++++++++++++++++++
arch/arm/plat-samsung/include/plat/devs.h | 2 +-
6 files changed, 27 insertions(+), 30 deletions(-)
create mode 100644 arch/arm/plat-samsung/dev-asocdma.c
diff --git a/arch/arm/mach-s3c64xx/dev-audio.c b/arch/arm/mach-s3c64xx/dev-audio.c
index c45cc37..c730dd2 100644
--- a/arch/arm/mach-s3c64xx/dev-audio.c
+++ b/arch/arm/mach-s3c64xx/dev-audio.c
@@ -336,16 +336,3 @@ void __init s3c64xx_ac97_setup_gpio(int num)
else
s3c_ac97_pdata.cfg_gpio = s3c64xx_ac97_cfg_gpe;
}
-
-static u64 s3c_device_audio_dmamask = 0xffffffffUL;
-
-struct platform_device s3c_device_pcm = {
- .name = "samsung-audio",
- .id = -1,
- .dev = {
- .dma_mask = &s3c_device_audio_dmamask,
- .coherent_dma_mask = 0xffffffffUL
- }
-};
-EXPORT_SYMBOL(s3c_device_pcm);
-
diff --git a/arch/arm/mach-s3c64xx/mach-smdk6410.c b/arch/arm/mach-s3c64xx/mach-smdk6410.c
index ecbddd3..e2b18b8 100644
--- a/arch/arm/mach-s3c64xx/mach-smdk6410.c
+++ b/arch/arm/mach-s3c64xx/mach-smdk6410.c
@@ -283,7 +283,7 @@ static struct platform_device *smdk6410_devices[] __initdata = {
&s3c_device_fb,
&s3c_device_ohci,
&s3c_device_usb_hsotg,
- &s3c_device_pcm,
+ &samsung_asoc_dma,
&s3c64xx_device_iisv4,
&samsung_device_keypad,
diff --git a/arch/arm/plat-s3c24xx/devs.c b/arch/arm/plat-s3c24xx/devs.c
index 4bf0b39..d8fb4e6 100644
--- a/arch/arm/plat-s3c24xx/devs.c
+++ b/arch/arm/plat-s3c24xx/devs.c
@@ -259,21 +259,6 @@ struct platform_device s3c_device_iis = {
EXPORT_SYMBOL(s3c_device_iis);
-/* ASoC PCM DMA */
-
-static u64 s3c_device_audio_dmamask = 0xffffffffUL;
-
-struct platform_device s3c_device_pcm = {
- .name = "samsung-audio",
- .id = -1,
- .dev = {
- .dma_mask = &s3c_device_audio_dmamask,
- .coherent_dma_mask = 0xffffffffUL
- }
-};
-
-EXPORT_SYMBOL(s3c_device_pcm);
-
/* RTC */
static struct resource s3c_rtc_resource[] = {
diff --git a/arch/arm/plat-samsung/Makefile b/arch/arm/plat-samsung/Makefile
index 4d8ff92..b97623a 100644
--- a/arch/arm/plat-samsung/Makefile
+++ b/arch/arm/plat-samsung/Makefile
@@ -17,6 +17,7 @@ obj-y += clock.o
obj-y += pwm-clock.o
obj-y += gpio.o
obj-y += gpio-config.o
+obj-y += dev-asocdma.o
obj-$(CONFIG_SAMSUNG_GPIOLIB_4BIT) += gpiolib.o
obj-$(CONFIG_SAMSUNG_CLKSRC) += clock-clksrc.o
diff --git a/arch/arm/plat-samsung/dev-asocdma.c b/arch/arm/plat-samsung/dev-asocdma.c
new file mode 100644
index 0000000..b7b1fca
--- /dev/null
+++ b/arch/arm/plat-samsung/dev-asocdma.c
@@ -0,0 +1,24 @@
+/* linux/arch/arm/plat-samsung/dev-asocdma.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co. Ltd
+ * Jaswinder Singh <jassi.brar(a)samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+
+static u64 audio_dmamask = DMA_BIT_MASK(32);
+
+struct platform_device samsung_asoc_dma = {
+ .name = "samsung-audio",
+ .id = -1,
+ .dev = {
+ .dma_mask = &audio_dmamask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ }
+};
+EXPORT_SYMBOL(samsung_asoc_dma);
diff --git a/arch/arm/plat-samsung/include/plat/devs.h b/arch/arm/plat-samsung/include/plat/devs.h
index a9fecd6..21dfa68 100644
--- a/arch/arm/plat-samsung/include/plat/devs.h
+++ b/arch/arm/plat-samsung/include/plat/devs.h
@@ -32,7 +32,7 @@ extern struct platform_device s3c64xx_device_iisv4;
extern struct platform_device s3c64xx_device_spi0;
extern struct platform_device s3c64xx_device_spi1;
-extern struct platform_device s3c_device_pcm;
+extern struct platform_device samsung_asoc_dma;
extern struct platform_device s3c64xx_device_pcm0;
extern struct platform_device s3c64xx_device_pcm1;
--
1.6.2.5
2
1

19 Oct '10
From: Jassi Brar <jassi.brar(a)samsung.com>
Move prefixes to repesent the nature of Samsung ASoC suitably.
SND_S3C24XX_SOC -> ASOC_SAMSUNG
SND_S3C_SOC_PCM -> SND_SAMSUNG_PCM
SND_S3C_SOC_AC97 -> SND_SAMSUNG_AC97
SND_S5P_SOC_SPDIF -> SND_SAMSUNG_SPDIF
SND_S3C24XX_SOC_I2S -> SND_S3C24XX_I2S
SND_S3C64XX_SOC_SMARTQ -> ASOC_SMARTQ
SND_SOC_SMDK_SPDIF -> ASOC_SAMSUNG_SMDK_SPDIF
SND_SOC_SMDK_WM8580 -> ASOC_SAMSUNG_SMDK_WM8580
SND_SOC_SMDK_WM9713 -> ASOC_SAMSUNG_SMDK_WM9713
SND_SOC_GONI_AQUILA_WM8994 -> ASOC_GONI_AQUILA_WM8994
Signed-off-by: Jassi Brar <jassi.brar(a)samsung.com>
---
sound/soc/s3c24xx/Kconfig | 96 ++++++++++++++++++++++----------------------
sound/soc/s3c24xx/Makefile | 40 +++++++++---------
2 files changed, 68 insertions(+), 68 deletions(-)
diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig
index 4fabd62..140095e 100644
--- a/sound/soc/s3c24xx/Kconfig
+++ b/sound/soc/s3c24xx/Kconfig
@@ -1,13 +1,13 @@
-config SND_S3C24XX_SOC
- tristate "SoC Audio for the Samsung S3CXXXX chips"
+config ASOC_SAMSUNG
+ tristate "ASoC support for Samsung"
depends on ARCH_S3C2410 || ARCH_S3C64XX || ARCH_S5PC100 || ARCH_S5PV210
select S3C64XX_DMA if ARCH_S3C64XX
help
Say Y or M if you want to add support for codecs attached to
- the S3C24XX AC97 or I2S interfaces. You will also need to
+ the Samsung SoCs' Audio interfaces. You will also need to
select the audio interfaces to support below.
-config SND_S3C24XX_SOC_I2S
+config SND_S3C24XX_I2S
tristate
select S3C2410_DMA
@@ -19,136 +19,136 @@ config SND_S3C2412_SOC_I2S
select SND_S3C_I2SV2_SOC
select S3C2410_DMA
-config SND_S3C_SOC_PCM
+config SND_SAMSUNG_PCM
tristate
-config SND_S3C_SOC_AC97
+config SND_SAMSUNG_AC97
tristate
select SND_SOC_AC97_BUS
-config SND_S5P_SOC_SPDIF
+config SND_SAMSUNG_SPDIF
tristate
select SND_SOC_SPDIF
config SND_SAMSUNG_I2S
tristate
-config SND_S3C24XX_SOC_NEO1973_WM8753
+config ASOC_SAMSUNG_NEO1973_WM8753
tristate "SoC I2S Audio support for NEO1973 - WM8753"
- depends on SND_S3C24XX_SOC && MACH_NEO1973_GTA01
- select SND_S3C24XX_SOC_I2S
+ depends on ASOC_SAMSUNG && MACH_NEO1973_GTA01
+ select SND_S3C24XX_I2S
select SND_SOC_WM8753
help
Say Y if you want to add support for SoC audio on smdk2440
with the WM8753.
-config SND_S3C24XX_SOC_NEO1973_GTA02_WM8753
+config ASOC_SAMSUNG_NEO1973_GTA02_WM8753
tristate "Audio support for the Openmoko Neo FreeRunner (GTA02)"
- depends on SND_S3C24XX_SOC && MACH_NEO1973_GTA02
- select SND_S3C24XX_SOC_I2S
+ depends on ASOC_SAMSUNG && MACH_NEO1973_GTA02
+ select SND_S3C24XX_I2S
select SND_SOC_WM8753
help
This driver provides audio support for the Openmoko Neo FreeRunner
smartphone.
-config SND_S3C24XX_SOC_JIVE_WM8750
+config ASOC_SAMSUNG_JIVE_WM8750
tristate "SoC I2S Audio support for Jive"
- depends on SND_S3C24XX_SOC && MACH_JIVE
+ depends on ASOC_SAMSUNG && MACH_JIVE
select SND_SOC_WM8750
select SND_S3C2412_SOC_I2S
help
Sat Y if you want to add support for SoC audio on the Jive.
-config SND_SOC_SMDK_WM8580
+config ASOC_SAMSUNG_SMDK_WM8580
tristate "SoC I2S Audio support for WM8580 on SMDK"
- depends on SND_S3C24XX_SOC && (MACH_SMDK6410 || MACH_SMDKC100)
+ depends on ASOC_SAMSUNG && (MACH_SMDK6410 || MACH_SMDKC100)
select SND_SOC_WM8580
select SND_SAMSUNG_I2S
help
Say Y if you want to add support for SoC audio on the SMDKs.
-config SND_S3C24XX_SOC_SMDK2443_WM9710
+config ASOC_SAMSUNG_SMDK2443_WM9710
tristate "SoC AC97 Audio support for SMDK2443 - WM9710"
- depends on SND_S3C24XX_SOC && MACH_SMDK2443
+ depends on ASOC_SAMSUNG && MACH_SMDK2443
select S3C2410_DMA
select AC97_BUS
select SND_SOC_AC97_CODEC
- select SND_S3C_SOC_AC97
+ select SND_SAMSUNG_AC97
help
Say Y if you want to add support for SoC audio on smdk2443
with the WM9710.
-config SND_S3C24XX_SOC_LN2440SBC_ALC650
+config ASOC_SAMSUNG_LN2440SBC_ALC650
tristate "SoC AC97 Audio support for LN2440SBC - ALC650"
- depends on SND_S3C24XX_SOC && ARCH_S3C2410
+ depends on ASOC_SAMSUNG && ARCH_S3C2410
select S3C2410_DMA
select AC97_BUS
select SND_SOC_AC97_CODEC
- select SND_S3C_SOC_AC97
+ select SND_SAMSUNG_AC97
help
Say Y if you want to add support for SoC audio on ln2440sbc
with the ALC650.
-config SND_S3C24XX_SOC_S3C24XX_UDA134X
+config ASOC_SAMSUNG_S3C24XX_UDA134X
tristate "SoC I2S Audio support UDA134X wired to a S3C24XX"
- depends on SND_S3C24XX_SOC && ARCH_S3C2410
- select SND_S3C24XX_SOC_I2S
+ depends on ASOC_SAMSUNG && ARCH_S3C2410
+ select SND_S3C24XX_I2S
select SND_SOC_L3
- select SND_SOC_UDA134X
+ select SND_SOC_UDA134X
-config SND_S3C24XX_SOC_SIMTEC
+config ASOC_SAMSUNG_SIMTEC
tristate
help
Internal node for common S3C24XX/Simtec suppor
-config SND_S3C24XX_SOC_SIMTEC_TLV320AIC23
+config ASOC_SAMSUNG_SIMTEC_TLV320AIC23
tristate "SoC I2S Audio support for TLV320AIC23 on Simtec boards"
- depends on SND_S3C24XX_SOC && ARCH_S3C2410
- select SND_S3C24XX_SOC_I2S
+ depends on ASOC_SAMSUNG && ARCH_S3C2410
+ select SND_S3C24XX_I2S
select SND_SOC_TLV320AIC23
- select SND_S3C24XX_SOC_SIMTEC
+ select ASOC_SAMSUNG_SIMTEC
-config SND_S3C24XX_SOC_SIMTEC_HERMES
+config ASOC_SAMSUNG_SIMTEC_HERMES
tristate "SoC I2S Audio support for Simtec Hermes board"
- depends on SND_S3C24XX_SOC && ARCH_S3C2410
- select SND_S3C24XX_SOC_I2S
+ depends on ASOC_SAMSUNG && ARCH_S3C2410
+ select SND_S3C24XX_I2S
select SND_SOC_TLV320AIC3X
- select SND_S3C24XX_SOC_SIMTEC
+ select ASOC_SAMSUNG_SIMTEC
-config SND_S3C24XX_SOC_RX1950_UDA1380
+config ASOC_SAMSUNG_RX1950_UDA1380
tristate "Audio support for the HP iPAQ RX1950"
- depends on SND_S3C24XX_SOC && MACH_RX1950
- select SND_S3C24XX_SOC_I2S
+ depends on ASOC_SAMSUNG && MACH_RX1950
+ select SND_S3C24XX_I2S
select SND_SOC_UDA1380
help
This driver provides audio support for HP iPAQ RX1950 PDA.
-config SND_SOC_SMDK_WM9713
+config ASOC_SAMSUNG_SMDK_WM9713
tristate "SoC AC97 Audio support for SMDK with WM9713"
- depends on SND_S3C24XX_SOC && (MACH_SMDK6410 || MACH_SMDKC100 || MACH_SMDKV210 || MACH_SMDKC110)
+ depends on ASOC_SAMSUNG && (MACH_SMDK6410 || MACH_SMDKC100 || MACH_SMDKV210 || MACH_SMDKC110)
select SND_SOC_WM9713
- select SND_S3C_SOC_AC97
+ select SND_SAMSUNG_AC97
help
Sat Y if you want to add support for SoC audio on the SMDK.
-config SND_S3C64XX_SOC_SMARTQ
+config ASOC_SMARTQ
tristate "SoC I2S Audio support for SmartQ board"
- depends on SND_S3C24XX_SOC && MACH_SMARTQ
+ depends on ASOC_SAMSUNG && MACH_SMARTQ
select SND_SAMSUNG_I2S
select SND_SOC_WM8750
-config SND_SOC_GONI_AQUILA_WM8994
+config ASOC_GONI_AQUILA_WM8994
tristate "SoC I2S Audio support for AQUILA/GONI - WM8994"
- depends on SND_S3C24XX_SOC && (MACH_GONI || MACH_AQUILA)
+ depends on ASOC_SAMSUNG && (MACH_GONI || MACH_AQUILA)
select SND_SAMSUNG_I2S
select SND_SOC_WM8994
help
Say Y if you want to add support for SoC audio on goni or aquila
with the WM8994.
-config SND_SOC_SMDK_SPDIF
+config ASOC_SAMSUNG_SMDK_SPDIF
tristate "SoC S/PDIF Audio support for SMDK"
depends on SND_S3C24XX_SOC && (MACH_SMDKC100 || MACH_SMDKC110 || MACH_SMDKV210)
- select SND_S5P_SOC_SPDIF
+ select SND_SAMSUNG_SPDIF
help
Say Y if you want to add support for SoC S/PDIF audio on the SMDK.
diff --git a/sound/soc/s3c24xx/Makefile b/sound/soc/s3c24xx/Makefile
index 7eee57f..0d24f95 100644
--- a/sound/soc/s3c24xx/Makefile
+++ b/sound/soc/s3c24xx/Makefile
@@ -8,13 +8,13 @@ snd-soc-samsung-spdif-objs := spdif.o
snd-soc-pcm-objs := pcm.o
snd-soc-i2s-objs := i2s.o
-obj-$(CONFIG_SND_S3C24XX_SOC) += snd-soc-s3c24xx.o
-obj-$(CONFIG_SND_S3C24XX_SOC_I2S) += snd-soc-s3c24xx-i2s.o
-obj-$(CONFIG_SND_S3C_SOC_AC97) += snd-soc-ac97.o
+obj-$(CONFIG_ASOC_SAMSUNG) += snd-soc-s3c24xx.o
+obj-$(CONFIG_SND_S3C24XX_I2S) += snd-soc-s3c24xx-i2s.o
+obj-$(CONFIG_SND_SAMSUNG_AC97) += snd-soc-ac97.o
obj-$(CONFIG_SND_S3C2412_SOC_I2S) += snd-soc-s3c2412-i2s.o
obj-$(CONFIG_SND_S3C_I2SV2_SOC) += snd-soc-s3c-i2s-v2.o
-obj-$(CONFIG_SND_S5P_SOC_SPDIF) += snd-soc-samsung-spdif.o
-obj-$(CONFIG_SND_S3C_SOC_PCM) += snd-soc-pcm.o
+obj-$(CONFIG_SND_SAMSUNG_SPDIF) += snd-soc-samsung-spdif.o
+obj-$(CONFIG_SND_SAMSUNG_PCM) += snd-soc-pcm.o
obj-$(CONFIG_SND_SAMSUNG_I2S) += snd-soc-i2s.o
# S3C24XX Machine Support
@@ -34,18 +34,18 @@ snd-soc-s3c64xx-smartq-wm8987-objs := smartq_wm8987.o
snd-soc-goni-wm8994-objs := goni_wm8994.o
snd-soc-smdk-spdif-objs := smdk_spdif.o
-obj-$(CONFIG_SND_S3C24XX_SOC_JIVE_WM8750) += snd-soc-jive-wm8750.o
-obj-$(CONFIG_SND_S3C24XX_SOC_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o
-obj-$(CONFIG_SND_S3C24XX_SOC_NEO1973_GTA02_WM8753) += snd-soc-neo1973-gta02-wm8753.o
-obj-$(CONFIG_SND_S3C24XX_SOC_SMDK2443_WM9710) += snd-soc-smdk2443-wm9710.o
-obj-$(CONFIG_SND_S3C24XX_SOC_LN2440SBC_ALC650) += snd-soc-ln2440sbc-alc650.o
-obj-$(CONFIG_SND_S3C24XX_SOC_S3C24XX_UDA134X) += snd-soc-s3c24xx-uda134x.o
-obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC) += snd-soc-s3c24xx-simtec.o
-obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC_HERMES) += snd-soc-s3c24xx-simtec-hermes.o
-obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC_TLV320AIC23) += snd-soc-s3c24xx-simtec-tlv320aic23.o
-obj-$(CONFIG_SND_S3C24XX_SOC_RX1950_UDA1380) += snd-soc-rx1950-uda1380.o
-obj-$(CONFIG_SND_SOC_SMDK_WM8580) += snd-soc-smdk-wm8580.o
-obj-$(CONFIG_SND_SOC_SMDK_WM9713) += snd-soc-smdk-wm9713.o
-obj-$(CONFIG_SND_S3C64XX_SOC_SMARTQ) += snd-soc-s3c64xx-smartq-wm8987.o
-obj-$(CONFIG_SND_SOC_SMDK_SPDIF) += snd-soc-smdk-spdif.o
-obj-$(CONFIG_SND_SOC_GONI_AQUILA_WM8994) += snd-soc-goni-wm8994.o
+obj-$(CONFIG_ASOC_SAMSUNG_JIVE_WM8750) += snd-soc-jive-wm8750.o
+obj-$(CONFIG_ASOC_SAMSUNG_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o
+obj-$(CONFIG_ASOC_SAMSUNG_NEO1973_GTA02_WM8753) += snd-soc-neo1973-gta02-wm8753.o
+obj-$(CONFIG_ASOC_SAMSUNG_SMDK2443_WM9710) += snd-soc-smdk2443-wm9710.o
+obj-$(CONFIG_ASOC_SAMSUNG_LN2440SBC_ALC650) += snd-soc-ln2440sbc-alc650.o
+obj-$(CONFIG_ASOC_SAMSUNG_S3C24XX_UDA134X) += snd-soc-s3c24xx-uda134x.o
+obj-$(CONFIG_ASOC_SAMSUNG_SIMTEC) += snd-soc-s3c24xx-simtec.o
+obj-$(CONFIG_ASOC_SAMSUNG_SIMTEC_HERMES) += snd-soc-s3c24xx-simtec-hermes.o
+obj-$(CONFIG_ASOC_SAMSUNG_SIMTEC_TLV320AIC23) += snd-soc-s3c24xx-simtec-tlv320aic23.o
+obj-$(CONFIG_ASOC_SAMSUNG_RX1950_UDA1380) += snd-soc-rx1950-uda1380.o
+obj-$(CONFIG_ASOC_SAMSUNG_SMDK_WM8580) += snd-soc-smdk-wm8580.o
+obj-$(CONFIG_ASOC_SAMSUNG_SMDK_WM9713) += snd-soc-smdk-wm9713.o
+obj-$(CONFIG_ASOC_SMARTQ) += snd-soc-s3c64xx-smartq-wm8987.o
+obj-$(CONFIG_ASOC_SAMSUNG_SMDK_SPDIF) += snd-soc-smdk-spdif.o
+obj-$(CONFIG_ASOC_GONI_AQUILA_WM8994) += snd-soc-goni-wm8994.o
--
1.6.2.5
1
0

19 Oct '10
From: Jassi Brar <jassi.brar(a)samsung.com>
Enable the ASoC Machine driver to run on SMDKC100 as well.
Signed-off-by: Jassi Brar <jassi.brar(a)samsung.com>
---
arch/arm/mach-s5pc100/mach-smdkc100.c | 2 +
sound/soc/s3c24xx/Kconfig | 2 +-
sound/soc/s3c24xx/smdk_wm8580.c | 73 +++++++++++++++++++++++---------
3 files changed, 55 insertions(+), 22 deletions(-)
diff --git a/arch/arm/mach-s5pc100/mach-smdkc100.c b/arch/arm/mach-s5pc100/mach-smdkc100.c
index 020c3f9..8e35bfa 100644
--- a/arch/arm/mach-s5pc100/mach-smdkc100.c
+++ b/arch/arm/mach-s5pc100/mach-smdkc100.c
@@ -95,6 +95,7 @@ static struct s3c2410_uartcfg smdkc100_uartcfgs[] __initdata = {
/* I2C0 */
static struct i2c_board_info i2c_devs0[] __initdata = {
+ {I2C_BOARD_INFO("wm8580", 0x1b),},
};
/* I2C1 */
@@ -189,6 +190,7 @@ static struct platform_device *smdkc100_devices[] __initdata = {
&s3c_device_ts,
&s3c_device_wdt,
&smdkc100_lcd_powerdev,
+ &samsung_asoc_dma,
&s5pc100_device_iis0,
&samsung_device_keypad,
&s5pc100_device_ac97,
diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig
index 95bdd0d..4fabd62 100644
--- a/sound/soc/s3c24xx/Kconfig
+++ b/sound/soc/s3c24xx/Kconfig
@@ -61,7 +61,7 @@ config SND_S3C24XX_SOC_JIVE_WM8750
config SND_SOC_SMDK_WM8580
tristate "SoC I2S Audio support for WM8580 on SMDK"
- depends on SND_S3C24XX_SOC && MACH_SMDK6410
+ depends on SND_S3C24XX_SOC && (MACH_SMDK6410 || MACH_SMDKC100)
select SND_SOC_WM8580
select SND_SAMSUNG_I2S
help
diff --git a/sound/soc/s3c24xx/smdk_wm8580.c b/sound/soc/s3c24xx/smdk_wm8580.c
index bbd6c97..46ab884 100644
--- a/sound/soc/s3c24xx/smdk_wm8580.c
+++ b/sound/soc/s3c24xx/smdk_wm8580.c
@@ -18,6 +18,8 @@
#include <sound/soc.h>
#include <sound/soc-dapm.h>
+#include <asm/mach-types.h>
+
#include "../codecs/wm8580.h"
#include "dma.h"
#include "i2s.h"
@@ -199,33 +201,49 @@ static int smdk_wm8580_init_paifrx(struct snd_soc_pcm_runtime *rtd)
return 0;
}
+enum {
+ PRI_PLAYBACK = 0,
+ PRI_CAPTURE,
+ SEC_PLAYBACK,
+};
+
static struct snd_soc_dai_link smdk_dai[] = {
-{ /* Primary Playback i/f */
- .name = "WM8580 PAIF RX",
- .stream_name = "Playback",
- .cpu_dai_name = "samsung-i2s.2",
- .codec_dai_name = "wm8580-hifi-playback",
- .platform_name = "samsung-audio",
- .codec_name = "wm8580-codec.0-001b",
- .init = smdk_wm8580_init_paifrx,
- .ops = &smdk_ops,
-},
-{ /* Primary Capture i/f */
- .name = "WM8580 PAIF TX",
- .stream_name = "Capture",
- .cpu_dai_name = "samsung-i2s.2",
- .codec_dai_name = "wm8580-hifi-capture",
- .platform_name = "samsung-audio",
- .codec_name = "wm8580-codec.0-001b",
- .init = smdk_wm8580_init_paiftx,
- .ops = &smdk_ops,
-},
+ [PRI_PLAYBACK] = { /* Primary Playback i/f */
+ .name = "WM8580 PAIF RX",
+ .stream_name = "Playback",
+ .cpu_dai_name = "samsung-i2s.2",
+ .codec_dai_name = "wm8580-hifi-playback",
+ .platform_name = "samsung-audio",
+ .codec_name = "wm8580-codec.0-001b",
+ .init = smdk_wm8580_init_paifrx,
+ .ops = &smdk_ops,
+ },
+ [PRI_CAPTURE] = { /* Primary Capture i/f */
+ .name = "WM8580 PAIF TX",
+ .stream_name = "Capture",
+ .cpu_dai_name = "samsung-i2s.2",
+ .codec_dai_name = "wm8580-hifi-capture",
+ .platform_name = "samsung-audio",
+ .codec_name = "wm8580-codec.0-001b",
+ .init = smdk_wm8580_init_paiftx,
+ .ops = &smdk_ops,
+ },
+ [SEC_PLAYBACK] = { /* Sec_Fifo Playback i/f */
+ .name = "Sec_FIFO TX",
+ .stream_name = "Playback",
+ .cpu_dai_name = "samsung-i2s.x",
+ .codec_dai_name = "wm8580-hifi-playback",
+ .platform_name = "samsung-audio",
+ .codec_name = "wm8580-codec.0-001b",
+ .init = smdk_wm8580_init_paifrx,
+ .ops = &smdk_ops,
+ },
};
static struct snd_soc_card smdk = {
.name = "SMDK-I2S",
.dai_link = smdk_dai,
- .num_links = ARRAY_SIZE(smdk_dai),
+ .num_links = 2,
};
static struct platform_device *smdk_snd_device;
@@ -233,6 +251,19 @@ static struct platform_device *smdk_snd_device;
static int __init smdk_audio_init(void)
{
int ret;
+ char *str;
+
+ if (machine_is_smdkc100()) {
+ smdk.num_links = 3;
+ /* S5PC100 has I2S0 as v5 */
+ str = (char *)smdk_dai[PRI_PLAYBACK].cpu_dai_name;
+ str[strlen(str) - 1] = '0';
+ str = (char *)smdk_dai[PRI_CAPTURE].cpu_dai_name;
+ str[strlen(str) - 1] = '0';
+ /* Secondary is at offset MAX_I2S from Primary */
+ str = (char *)smdk_dai[SEC_PLAYBACK].cpu_dai_name;
+ str[strlen(str) - 1] = '0' + MAX_I2S;
+ }
smdk_snd_device = platform_device_alloc("soc-audio", -1);
if (!smdk_snd_device)
--
1.6.2.5
1
0

19 Oct '10
From: Jassi Brar <jassi.brar(a)samsung.com>
We plan to use the same ASoC Machine driver for most of
latest SMDK platforms. So rename the 64XX specific driver
to generic named.
Signed-off-by: Jassi Brar <jassi.brar(a)samsung.com>
---
sound/soc/s3c24xx/Kconfig | 6 +-
sound/soc/s3c24xx/Makefile | 4 +-
sound/soc/s3c24xx/smdk64xx_wm8580.c | 253 -----------------------------------
sound/soc/s3c24xx/smdk_wm8580.c | 253 +++++++++++++++++++++++++++++++++++
4 files changed, 258 insertions(+), 258 deletions(-)
delete mode 100644 sound/soc/s3c24xx/smdk64xx_wm8580.c
create mode 100644 sound/soc/s3c24xx/smdk_wm8580.c
diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig
index 32f1877..95bdd0d 100644
--- a/sound/soc/s3c24xx/Kconfig
+++ b/sound/soc/s3c24xx/Kconfig
@@ -59,13 +59,13 @@ config SND_S3C24XX_SOC_JIVE_WM8750
help
Sat Y if you want to add support for SoC audio on the Jive.
-config SND_S3C64XX_SOC_WM8580
- tristate "SoC I2S Audio support for WM8580 on SMDK64XX"
+config SND_SOC_SMDK_WM8580
+ tristate "SoC I2S Audio support for WM8580 on SMDK"
depends on SND_S3C24XX_SOC && MACH_SMDK6410
select SND_SOC_WM8580
select SND_SAMSUNG_I2S
help
- Say Y if you want to add support for SoC audio on the SMDK6410.
+ Say Y if you want to add support for SoC audio on the SMDKs.
config SND_S3C24XX_SOC_SMDK2443_WM9710
tristate "SoC AC97 Audio support for SMDK2443 - WM9710"
diff --git a/sound/soc/s3c24xx/Makefile b/sound/soc/s3c24xx/Makefile
index dac41ee..7eee57f 100644
--- a/sound/soc/s3c24xx/Makefile
+++ b/sound/soc/s3c24xx/Makefile
@@ -28,7 +28,7 @@ snd-soc-s3c24xx-simtec-objs := s3c24xx_simtec.o
snd-soc-s3c24xx-simtec-hermes-objs := s3c24xx_simtec_hermes.o
snd-soc-s3c24xx-simtec-tlv320aic23-objs := s3c24xx_simtec_tlv320aic23.o
snd-soc-rx1950-uda1380-objs := rx1950_uda1380.o
-snd-soc-smdk64xx-wm8580-objs := smdk64xx_wm8580.o
+snd-soc-smdk-wm8580-objs := smdk_wm8580.o
snd-soc-smdk-wm9713-objs := smdk_wm9713.o
snd-soc-s3c64xx-smartq-wm8987-objs := smartq_wm8987.o
snd-soc-goni-wm8994-objs := goni_wm8994.o
@@ -44,7 +44,7 @@ obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC) += snd-soc-s3c24xx-simtec.o
obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC_HERMES) += snd-soc-s3c24xx-simtec-hermes.o
obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC_TLV320AIC23) += snd-soc-s3c24xx-simtec-tlv320aic23.o
obj-$(CONFIG_SND_S3C24XX_SOC_RX1950_UDA1380) += snd-soc-rx1950-uda1380.o
-obj-$(CONFIG_SND_S3C64XX_SOC_WM8580) += snd-soc-smdk64xx-wm8580.o
+obj-$(CONFIG_SND_SOC_SMDK_WM8580) += snd-soc-smdk-wm8580.o
obj-$(CONFIG_SND_SOC_SMDK_WM9713) += snd-soc-smdk-wm9713.o
obj-$(CONFIG_SND_S3C64XX_SOC_SMARTQ) += snd-soc-s3c64xx-smartq-wm8987.o
obj-$(CONFIG_SND_SOC_SMDK_SPDIF) += snd-soc-smdk-spdif.o
diff --git a/sound/soc/s3c24xx/smdk64xx_wm8580.c b/sound/soc/s3c24xx/smdk64xx_wm8580.c
deleted file mode 100644
index 5f51db0..0000000
--- a/sound/soc/s3c24xx/smdk64xx_wm8580.c
+++ /dev/null
@@ -1,253 +0,0 @@
-/*
- * smdk64xx_wm8580.c
- *
- * Copyright (c) 2009 Samsung Electronics Co. Ltd
- * Author: Jaswinder Singh <jassi.brar(a)samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- */
-
-#include <linux/platform_device.h>
-#include <linux/clk.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-#include <sound/soc-dapm.h>
-
-#include "../codecs/wm8580.h"
-#include "dma.h"
-#include "i2s.h"
-
-/*
- * Default CFG switch settings to use this driver:
- *
- * SMDK6410: Set CFG1 1-3 Off, CFG2 1-4 On
- */
-
-/* SMDK64XX has a 12MHZ crystal attached to WM8580 */
-#define SMDK64XX_WM8580_FREQ 12000000
-
-static int smdk64xx_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
-{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- struct snd_soc_dai *codec_dai = rtd->codec_dai;
- unsigned int pll_out;
- int bfs, rfs, ret;
-
- switch (params_format(params)) {
- case SNDRV_PCM_FORMAT_U8:
- case SNDRV_PCM_FORMAT_S8:
- bfs = 16;
- break;
- case SNDRV_PCM_FORMAT_U16_LE:
- case SNDRV_PCM_FORMAT_S16_LE:
- bfs = 32;
- break;
- default:
- return -EINVAL;
- }
-
- /* The Fvco for WM8580 PLLs must fall within [90,100]MHz.
- * This criterion can't be met if we request PLL output
- * as {8000x256, 64000x256, 11025x256}Hz.
- * As a wayout, we rather change rfs to a minimum value that
- * results in (params_rate(params) * rfs), and itself, acceptable
- * to both - the CODEC and the CPU.
- */
- switch (params_rate(params)) {
- case 16000:
- case 22050:
- case 32000:
- case 44100:
- case 48000:
- case 88200:
- case 96000:
- rfs = 256;
- break;
- case 64000:
- rfs = 384;
- break;
- case 8000:
- case 11025:
- rfs = 512;
- break;
- default:
- return -EINVAL;
- }
- pll_out = params_rate(params) * rfs;
-
- /* Set the Codec DAI configuration */
- ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S
- | SND_SOC_DAIFMT_NB_NF
- | SND_SOC_DAIFMT_CBM_CFM);
- if (ret < 0)
- return ret;
-
- /* Set the AP DAI configuration */
- ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S
- | SND_SOC_DAIFMT_NB_NF
- | SND_SOC_DAIFMT_CBM_CFM);
- if (ret < 0)
- return ret;
-
- /* Set WM8580 to drive MCLK from its PLLA */
- ret = snd_soc_dai_set_clkdiv(codec_dai, WM8580_MCLK,
- WM8580_CLKSRC_PLLA);
- if (ret < 0)
- return ret;
-
- ret = snd_soc_dai_set_pll(codec_dai, WM8580_PLLA, 0,
- SMDK64XX_WM8580_FREQ, pll_out);
- if (ret < 0)
- return ret;
-
- ret = snd_soc_dai_set_sysclk(codec_dai, WM8580_CLKSRC_PLLA,
- pll_out, SND_SOC_CLOCK_IN);
- if (ret < 0)
- return ret;
-
- return 0;
-}
-
-/*
- * SMDK64XX WM8580 DAI operations.
- */
-static struct snd_soc_ops smdk64xx_ops = {
- .hw_params = smdk64xx_hw_params,
-};
-
-/* SMDK64xx Playback widgets */
-static const struct snd_soc_dapm_widget wm8580_dapm_widgets_pbk[] = {
- SND_SOC_DAPM_HP("Front", NULL),
- SND_SOC_DAPM_HP("Center+Sub", NULL),
- SND_SOC_DAPM_HP("Rear", NULL),
-};
-
-/* SMDK64xx Capture widgets */
-static const struct snd_soc_dapm_widget wm8580_dapm_widgets_cpt[] = {
- SND_SOC_DAPM_MIC("MicIn", NULL),
- SND_SOC_DAPM_LINE("LineIn", NULL),
-};
-
-/* SMDK-PAIFTX connections */
-static const struct snd_soc_dapm_route audio_map_tx[] = {
- /* MicIn feeds AINL */
- {"AINL", NULL, "MicIn"},
-
- /* LineIn feeds AINL/R */
- {"AINL", NULL, "LineIn"},
- {"AINR", NULL, "LineIn"},
-};
-
-/* SMDK-PAIFRX connections */
-static const struct snd_soc_dapm_route audio_map_rx[] = {
- /* Front Left/Right are fed VOUT1L/R */
- {"Front", NULL, "VOUT1L"},
- {"Front", NULL, "VOUT1R"},
-
- /* Center/Sub are fed VOUT2L/R */
- {"Center+Sub", NULL, "VOUT2L"},
- {"Center+Sub", NULL, "VOUT2R"},
-
- /* Rear Left/Right are fed VOUT3L/R */
- {"Rear", NULL, "VOUT3L"},
- {"Rear", NULL, "VOUT3R"},
-};
-
-static int smdk64xx_wm8580_init_paiftx(struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_soc_codec *codec = rtd->codec;
-
- /* Add smdk64xx specific Capture widgets */
- snd_soc_dapm_new_controls(codec, wm8580_dapm_widgets_cpt,
- ARRAY_SIZE(wm8580_dapm_widgets_cpt));
-
- /* Set up PAIFTX audio path */
- snd_soc_dapm_add_routes(codec, audio_map_tx, ARRAY_SIZE(audio_map_tx));
-
- /* Enabling the microphone requires the fitting of a 0R
- * resistor to connect the line from the microphone jack.
- */
- snd_soc_dapm_disable_pin(codec, "MicIn");
-
- /* signal a DAPM event */
- snd_soc_dapm_sync(codec);
-
- return 0;
-}
-
-static int smdk64xx_wm8580_init_paifrx(struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_soc_codec *codec = rtd->codec;
-
- /* Add smdk64xx specific Playback widgets */
- snd_soc_dapm_new_controls(codec, wm8580_dapm_widgets_pbk,
- ARRAY_SIZE(wm8580_dapm_widgets_pbk));
-
- /* Set up PAIFRX audio path */
- snd_soc_dapm_add_routes(codec, audio_map_rx, ARRAY_SIZE(audio_map_rx));
-
- /* signal a DAPM event */
- snd_soc_dapm_sync(codec);
-
- return 0;
-}
-
-static struct snd_soc_dai_link smdk64xx_dai[] = {
-{ /* Primary Playback i/f */
- .name = "WM8580 PAIF RX",
- .stream_name = "Playback",
- .cpu_dai_name = "samsung-i2s.2",
- .codec_dai_name = "wm8580-hifi-playback",
- .platform_name = "samsung-audio",
- .codec_name = "wm8580-codec.0-001b",
- .init = smdk64xx_wm8580_init_paifrx,
- .ops = &smdk64xx_ops,
-},
-{ /* Primary Capture i/f */
- .name = "WM8580 PAIF TX",
- .stream_name = "Capture",
- .cpu_dai_name = "samsung-i2s.2",
- .codec_dai_name = "wm8580-hifi-capture",
- .platform_name = "samsung-audio",
- .codec_name = "wm8580-codec.0-001b",
- .init = smdk64xx_wm8580_init_paiftx,
- .ops = &smdk64xx_ops,
-},
-};
-
-static struct snd_soc_card smdk64xx = {
- .name = "SMDK64xx 5.1",
- .dai_link = smdk64xx_dai,
- .num_links = ARRAY_SIZE(smdk64xx_dai),
-};
-
-static struct platform_device *smdk64xx_snd_device;
-
-static int __init smdk64xx_audio_init(void)
-{
- int ret;
-
- smdk64xx_snd_device = platform_device_alloc("soc-audio", -1);
- if (!smdk64xx_snd_device)
- return -ENOMEM;
-
- platform_set_drvdata(smdk64xx_snd_device, &smdk64xx);
- ret = platform_device_add(smdk64xx_snd_device);
-
- if (ret)
- platform_device_put(smdk64xx_snd_device);
-
- return ret;
-}
-module_init(smdk64xx_audio_init);
-
-MODULE_AUTHOR("Jaswinder Singh, jassi.brar(a)samsung.com");
-MODULE_DESCRIPTION("ALSA SoC SMDK64XX WM8580");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/smdk_wm8580.c b/sound/soc/s3c24xx/smdk_wm8580.c
new file mode 100644
index 0000000..bbd6c97
--- /dev/null
+++ b/sound/soc/s3c24xx/smdk_wm8580.c
@@ -0,0 +1,253 @@
+/*
+ * smdk_wm8580.c
+ *
+ * Copyright (c) 2009 Samsung Electronics Co. Ltd
+ * Author: Jaswinder Singh <jassi.brar(a)samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include "../codecs/wm8580.h"
+#include "dma.h"
+#include "i2s.h"
+
+/*
+ * Default CFG switch settings to use this driver:
+ *
+ * SMDK6410: Set CFG1 1-3 Off, CFG2 1-4 On
+ */
+
+/* SMDK has a 12MHZ crystal attached to WM8580 */
+#define SMDK_WM8580_FREQ 12000000
+
+static int smdk_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ unsigned int pll_out;
+ int bfs, rfs, ret;
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_U8:
+ case SNDRV_PCM_FORMAT_S8:
+ bfs = 16;
+ break;
+ case SNDRV_PCM_FORMAT_U16_LE:
+ case SNDRV_PCM_FORMAT_S16_LE:
+ bfs = 32;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* The Fvco for WM8580 PLLs must fall within [90,100]MHz.
+ * This criterion can't be met if we request PLL output
+ * as {8000x256, 64000x256, 11025x256}Hz.
+ * As a wayout, we rather change rfs to a minimum value that
+ * results in (params_rate(params) * rfs), and itself, acceptable
+ * to both - the CODEC and the CPU.
+ */
+ switch (params_rate(params)) {
+ case 16000:
+ case 22050:
+ case 32000:
+ case 44100:
+ case 48000:
+ case 88200:
+ case 96000:
+ rfs = 256;
+ break;
+ case 64000:
+ rfs = 384;
+ break;
+ case 8000:
+ case 11025:
+ rfs = 512;
+ break;
+ default:
+ return -EINVAL;
+ }
+ pll_out = params_rate(params) * rfs;
+
+ /* Set the Codec DAI configuration */
+ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S
+ | SND_SOC_DAIFMT_NB_NF
+ | SND_SOC_DAIFMT_CBM_CFM);
+ if (ret < 0)
+ return ret;
+
+ /* Set the AP DAI configuration */
+ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S
+ | SND_SOC_DAIFMT_NB_NF
+ | SND_SOC_DAIFMT_CBM_CFM);
+ if (ret < 0)
+ return ret;
+
+ /* Set WM8580 to drive MCLK from its PLLA */
+ ret = snd_soc_dai_set_clkdiv(codec_dai, WM8580_MCLK,
+ WM8580_CLKSRC_PLLA);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_soc_dai_set_pll(codec_dai, WM8580_PLLA, 0,
+ SMDK_WM8580_FREQ, pll_out);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_soc_dai_set_sysclk(codec_dai, WM8580_CLKSRC_PLLA,
+ pll_out, SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+/*
+ * SMDK WM8580 DAI operations.
+ */
+static struct snd_soc_ops smdk_ops = {
+ .hw_params = smdk_hw_params,
+};
+
+/* SMDK Playback widgets */
+static const struct snd_soc_dapm_widget wm8580_dapm_widgets_pbk[] = {
+ SND_SOC_DAPM_HP("Front", NULL),
+ SND_SOC_DAPM_HP("Center+Sub", NULL),
+ SND_SOC_DAPM_HP("Rear", NULL),
+};
+
+/* SMDK Capture widgets */
+static const struct snd_soc_dapm_widget wm8580_dapm_widgets_cpt[] = {
+ SND_SOC_DAPM_MIC("MicIn", NULL),
+ SND_SOC_DAPM_LINE("LineIn", NULL),
+};
+
+/* SMDK-PAIFTX connections */
+static const struct snd_soc_dapm_route audio_map_tx[] = {
+ /* MicIn feeds AINL */
+ {"AINL", NULL, "MicIn"},
+
+ /* LineIn feeds AINL/R */
+ {"AINL", NULL, "LineIn"},
+ {"AINR", NULL, "LineIn"},
+};
+
+/* SMDK-PAIFRX connections */
+static const struct snd_soc_dapm_route audio_map_rx[] = {
+ /* Front Left/Right are fed VOUT1L/R */
+ {"Front", NULL, "VOUT1L"},
+ {"Front", NULL, "VOUT1R"},
+
+ /* Center/Sub are fed VOUT2L/R */
+ {"Center+Sub", NULL, "VOUT2L"},
+ {"Center+Sub", NULL, "VOUT2R"},
+
+ /* Rear Left/Right are fed VOUT3L/R */
+ {"Rear", NULL, "VOUT3L"},
+ {"Rear", NULL, "VOUT3R"},
+};
+
+static int smdk_wm8580_init_paiftx(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_codec *codec = rtd->codec;
+
+ /* Add smdk specific Capture widgets */
+ snd_soc_dapm_new_controls(codec, wm8580_dapm_widgets_cpt,
+ ARRAY_SIZE(wm8580_dapm_widgets_cpt));
+
+ /* Set up PAIFTX audio path */
+ snd_soc_dapm_add_routes(codec, audio_map_tx, ARRAY_SIZE(audio_map_tx));
+
+ /* Enabling the microphone requires the fitting of a 0R
+ * resistor to connect the line from the microphone jack.
+ */
+ snd_soc_dapm_disable_pin(codec, "MicIn");
+
+ /* signal a DAPM event */
+ snd_soc_dapm_sync(codec);
+
+ return 0;
+}
+
+static int smdk_wm8580_init_paifrx(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_codec *codec = rtd->codec;
+
+ /* Add smdk specific Playback widgets */
+ snd_soc_dapm_new_controls(codec, wm8580_dapm_widgets_pbk,
+ ARRAY_SIZE(wm8580_dapm_widgets_pbk));
+
+ /* Set up PAIFRX audio path */
+ snd_soc_dapm_add_routes(codec, audio_map_rx, ARRAY_SIZE(audio_map_rx));
+
+ /* signal a DAPM event */
+ snd_soc_dapm_sync(codec);
+
+ return 0;
+}
+
+static struct snd_soc_dai_link smdk_dai[] = {
+{ /* Primary Playback i/f */
+ .name = "WM8580 PAIF RX",
+ .stream_name = "Playback",
+ .cpu_dai_name = "samsung-i2s.2",
+ .codec_dai_name = "wm8580-hifi-playback",
+ .platform_name = "samsung-audio",
+ .codec_name = "wm8580-codec.0-001b",
+ .init = smdk_wm8580_init_paifrx,
+ .ops = &smdk_ops,
+},
+{ /* Primary Capture i/f */
+ .name = "WM8580 PAIF TX",
+ .stream_name = "Capture",
+ .cpu_dai_name = "samsung-i2s.2",
+ .codec_dai_name = "wm8580-hifi-capture",
+ .platform_name = "samsung-audio",
+ .codec_name = "wm8580-codec.0-001b",
+ .init = smdk_wm8580_init_paiftx,
+ .ops = &smdk_ops,
+},
+};
+
+static struct snd_soc_card smdk = {
+ .name = "SMDK-I2S",
+ .dai_link = smdk_dai,
+ .num_links = ARRAY_SIZE(smdk_dai),
+};
+
+static struct platform_device *smdk_snd_device;
+
+static int __init smdk_audio_init(void)
+{
+ int ret;
+
+ smdk_snd_device = platform_device_alloc("soc-audio", -1);
+ if (!smdk_snd_device)
+ return -ENOMEM;
+
+ platform_set_drvdata(smdk_snd_device, &smdk);
+ ret = platform_device_add(smdk_snd_device);
+
+ if (ret)
+ platform_device_put(smdk_snd_device);
+
+ return ret;
+}
+module_init(smdk_audio_init);
+
+MODULE_AUTHOR("Jaswinder Singh, jassi.brar(a)samsung.com");
+MODULE_DESCRIPTION("ALSA SoC SMDK WM8580");
+MODULE_LICENSE("GPL");
--
1.6.2.5
1
0

19 Oct '10
From: Jassi Brar <jassi.brar(a)samsung.com>
Now that we have better I2S CPU drivers and no need for the old
ones, discard them.
Signed-off-by: Jassi Brar <jassi.brar(a)samsung.com>
---
sound/soc/s3c24xx/Kconfig | 10 --
sound/soc/s3c24xx/Makefile | 4 -
sound/soc/s3c24xx/s3c64xx-i2s-v4.c | 230 ----------------------------------
sound/soc/s3c24xx/s3c64xx-i2s.c | 242 ------------------------------------
sound/soc/s3c24xx/s3c64xx-i2s.h | 41 ------
5 files changed, 0 insertions(+), 527 deletions(-)
delete mode 100644 sound/soc/s3c24xx/s3c64xx-i2s-v4.c
delete mode 100644 sound/soc/s3c24xx/s3c64xx-i2s.c
delete mode 100644 sound/soc/s3c24xx/s3c64xx-i2s.h
diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig
index 085a7b0..32f1877 100644
--- a/sound/soc/s3c24xx/Kconfig
+++ b/sound/soc/s3c24xx/Kconfig
@@ -19,16 +19,6 @@ config SND_S3C2412_SOC_I2S
select SND_S3C_I2SV2_SOC
select S3C2410_DMA
-config SND_S3C64XX_SOC_I2S
- tristate
- select SND_S3C_I2SV2_SOC
- select S3C64XX_DMA
-
-config SND_S3C64XX_SOC_I2S_V4
- tristate
- select SND_S3C_I2SV2_SOC
- select S3C64XX_DMA
-
config SND_S3C_SOC_PCM
tristate
diff --git a/sound/soc/s3c24xx/Makefile b/sound/soc/s3c24xx/Makefile
index 1d6fc07..dac41ee 100644
--- a/sound/soc/s3c24xx/Makefile
+++ b/sound/soc/s3c24xx/Makefile
@@ -2,9 +2,7 @@
snd-soc-s3c24xx-objs := dma.o
snd-soc-s3c24xx-i2s-objs := s3c24xx-i2s.o
snd-soc-s3c2412-i2s-objs := s3c2412-i2s.o
-snd-soc-s3c64xx-i2s-objs := s3c64xx-i2s.o
snd-soc-ac97-objs := ac97.o
-snd-soc-s3c64xx-i2s-v4-objs := s3c64xx-i2s-v4.o
snd-soc-s3c-i2s-v2-objs := s3c-i2s-v2.o
snd-soc-samsung-spdif-objs := spdif.o
snd-soc-pcm-objs := pcm.o
@@ -14,8 +12,6 @@ obj-$(CONFIG_SND_S3C24XX_SOC) += snd-soc-s3c24xx.o
obj-$(CONFIG_SND_S3C24XX_SOC_I2S) += snd-soc-s3c24xx-i2s.o
obj-$(CONFIG_SND_S3C_SOC_AC97) += snd-soc-ac97.o
obj-$(CONFIG_SND_S3C2412_SOC_I2S) += snd-soc-s3c2412-i2s.o
-obj-$(CONFIG_SND_S3C64XX_SOC_I2S) += snd-soc-s3c64xx-i2s.o
-obj-$(CONFIG_SND_S3C64XX_SOC_I2S_V4) += snd-soc-s3c64xx-i2s-v4.o
obj-$(CONFIG_SND_S3C_I2SV2_SOC) += snd-soc-s3c-i2s-v2.o
obj-$(CONFIG_SND_S5P_SOC_SPDIF) += snd-soc-samsung-spdif.o
obj-$(CONFIG_SND_S3C_SOC_PCM) += snd-soc-pcm.o
diff --git a/sound/soc/s3c24xx/s3c64xx-i2s-v4.c b/sound/soc/s3c24xx/s3c64xx-i2s-v4.c
deleted file mode 100644
index 8a08041..0000000
--- a/sound/soc/s3c24xx/s3c64xx-i2s-v4.c
+++ /dev/null
@@ -1,230 +0,0 @@
-/* sound/soc/s3c24xx/s3c64xx-i2s-v4.c
- *
- * ALSA SoC Audio Layer - S3C64XX I2Sv4 driver
- * Copyright (c) 2010 Samsung Electronics Co. Ltd
- * Author: Jaswinder Singh <jassi.brar(a)samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/clk.h>
-#include <linux/gpio.h>
-#include <linux/io.h>
-
-#include <sound/soc.h>
-#include <sound/pcm_params.h>
-
-#include <plat/audio.h>
-
-#include <mach/map.h>
-#include <mach/dma.h>
-
-#include "dma.h"
-#include "regs-i2s-v2.h"
-#include "s3c64xx-i2s.h"
-
-static struct s3c2410_dma_client s3c64xx_dma_client_out = {
- .name = "I2Sv4 PCM Stereo out"
-};
-
-static struct s3c2410_dma_client s3c64xx_dma_client_in = {
- .name = "I2Sv4 PCM Stereo in"
-};
-
-static struct s3c_dma_params s3c64xx_i2sv4_pcm_stereo_out;
-static struct s3c_dma_params s3c64xx_i2sv4_pcm_stereo_in;
-static struct s3c_i2sv2_info s3c64xx_i2sv4;
-
-static int s3c64xx_i2sv4_probe(struct snd_soc_dai *dai)
-{
- struct s3c_i2sv2_info *i2s = &s3c64xx_i2sv4;
- int ret = 0;
-
- snd_soc_dai_set_drvdata(dai, i2s);
-
- ret = s3c_i2sv2_probe(dai, i2s, i2s->base);
-
- return ret;
-}
-
-static int s3c_i2sv4_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params,
- struct snd_soc_dai *cpu_dai)
-{
- struct s3c_i2sv2_info *i2s = snd_soc_dai_get_drvdata(cpu_dai);
- struct s3c_dma_params *dma_data;
- u32 iismod;
-
- dev_dbg(cpu_dai->dev, "Entered %s\n", __func__);
-
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- dma_data = i2s->dma_playback;
- else
- dma_data = i2s->dma_capture;
-
- snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data);
-
- iismod = readl(i2s->regs + S3C2412_IISMOD);
- dev_dbg(cpu_dai->dev, "%s: r: IISMOD: %x\n", __func__, iismod);
-
- iismod &= ~S3C64XX_IISMOD_BLC_MASK;
- switch (params_format(params)) {
- case SNDRV_PCM_FORMAT_S8:
- iismod |= S3C64XX_IISMOD_BLC_8BIT;
- break;
- case SNDRV_PCM_FORMAT_S16_LE:
- break;
- case SNDRV_PCM_FORMAT_S24_LE:
- iismod |= S3C64XX_IISMOD_BLC_24BIT;
- break;
- }
-
- writel(iismod, i2s->regs + S3C2412_IISMOD);
- dev_dbg(cpu_dai->dev, "%s: w: IISMOD: %x\n", __func__, iismod);
-
- return 0;
-}
-
-static struct snd_soc_dai_ops s3c64xx_i2sv4_dai_ops = {
- .hw_params = s3c_i2sv4_hw_params,
-};
-
-static struct snd_soc_dai_driver s3c64xx_i2s_v4_dai = {
- .symmetric_rates = 1,
- .playback = {
- .channels_min = 2,
- .channels_max = 2,
- .rates = S3C64XX_I2S_RATES,
- .formats = S3C64XX_I2S_FMTS,
- },
- .capture = {
- .channels_min = 2,
- .channels_max = 2,
- .rates = S3C64XX_I2S_RATES,
- .formats = S3C64XX_I2S_FMTS,
- },
- .probe = s3c64xx_i2sv4_probe,
- .ops = &s3c64xx_i2sv4_dai_ops,
-};
-
-static __devinit int s3c64xx_i2sv4_dev_probe(struct platform_device *pdev)
-{
- struct s3c_audio_pdata *i2s_pdata;
- struct s3c_i2sv2_info *i2s;
- struct resource *res;
- int ret;
-
- i2s = &s3c64xx_i2sv4;
-
- i2s->feature |= S3C_FEATURE_CDCLKCON;
-
- i2s->dma_capture = &s3c64xx_i2sv4_pcm_stereo_in;
- i2s->dma_playback = &s3c64xx_i2sv4_pcm_stereo_out;
-
- res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
- if (!res) {
- dev_err(&pdev->dev, "Unable to get I2S-TX dma resource\n");
- return -ENXIO;
- }
- i2s->dma_playback->channel = res->start;
-
- res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
- if (!res) {
- dev_err(&pdev->dev, "Unable to get I2S-RX dma resource\n");
- return -ENXIO;
- }
- i2s->dma_capture->channel = res->start;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(&pdev->dev, "Unable to get I2S SFR address\n");
- return -ENXIO;
- }
-
- if (!request_mem_region(res->start, resource_size(res),
- "s3c64xx-i2s-v4")) {
- dev_err(&pdev->dev, "Unable to request SFR region\n");
- return -EBUSY;
- }
- i2s->dma_capture->dma_addr = res->start + S3C2412_IISRXD;
- i2s->dma_playback->dma_addr = res->start + S3C2412_IISTXD;
-
- i2s->dma_capture->client = &s3c64xx_dma_client_in;
- i2s->dma_capture->dma_size = 4;
- i2s->dma_playback->client = &s3c64xx_dma_client_out;
- i2s->dma_playback->dma_size = 4;
-
- i2s->base = res->start;
-
- i2s_pdata = pdev->dev.platform_data;
- if (i2s_pdata && i2s_pdata->cfg_gpio && i2s_pdata->cfg_gpio(pdev)) {
- dev_err(&pdev->dev, "Unable to configure gpio\n");
- return -EINVAL;
- }
-
- i2s->iis_cclk = clk_get(&pdev->dev, "audio-bus");
- if (IS_ERR(i2s->iis_cclk)) {
- dev_err(&pdev->dev, "failed to get audio-bus\n");
- ret = PTR_ERR(i2s->iis_cclk);
- goto err;
- }
-
- clk_enable(i2s->iis_cclk);
-
- ret = s3c_i2sv2_register_dai(&pdev->dev, pdev->id, &s3c64xx_i2s_v4_dai);
- if (ret != 0)
- goto err_i2sv2;
-
- return 0;
-
-err_i2sv2:
- clk_put(i2s->iis_cclk);
-err:
- return ret;
-}
-
-static __devexit int s3c64xx_i2sv4_dev_remove(struct platform_device *pdev)
-{
- struct s3c_i2sv2_info *i2s = &s3c64xx_i2sv4;
- struct resource *res;
-
- snd_soc_unregister_dai(&pdev->dev);
- clk_put(i2s->iis_cclk);
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (res)
- release_mem_region(res->start, resource_size(res));
- else
- dev_warn(&pdev->dev, "Unable to get I2S SFR address\n");
-
- return 0;
-}
-
-static struct platform_driver s3c64xx_i2sv4_driver = {
- .probe = s3c64xx_i2sv4_dev_probe,
- .remove = s3c64xx_i2sv4_dev_remove,
- .driver = {
- .name = "samsung-i2s-v4",
- .owner = THIS_MODULE,
- },
-};
-
-static int __init s3c64xx_i2sv4_init(void)
-{
- return platform_driver_register(&s3c64xx_i2sv4_driver);
-}
-module_init(s3c64xx_i2sv4_init);
-
-static void __exit s3c64xx_i2sv4_exit(void)
-{
- platform_driver_unregister(&s3c64xx_i2sv4_driver);
-}
-module_exit(s3c64xx_i2sv4_exit);
-
-/* Module information */
-MODULE_AUTHOR("Jaswinder Singh, <jassi.brar(a)samsung.com>");
-MODULE_DESCRIPTION("S3C64XX I2Sv4 SoC Interface");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:samsung-i2s-v4");
diff --git a/sound/soc/s3c24xx/s3c64xx-i2s.c b/sound/soc/s3c24xx/s3c64xx-i2s.c
deleted file mode 100644
index 0fefbb5..0000000
--- a/sound/soc/s3c24xx/s3c64xx-i2s.c
+++ /dev/null
@@ -1,242 +0,0 @@
-/* sound/soc/s3c24xx/s3c64xx-i2s.c
- *
- * ALSA SoC Audio Layer - S3C64XX I2S driver
- *
- * Copyright 2008 Openmoko, Inc.
- * Copyright 2008 Simtec Electronics
- * Ben Dooks <ben(a)simtec.co.uk>
- * http://armlinux.simtec.co.uk/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/module.h>
-#include <linux/clk.h>
-#include <linux/gpio.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-
-#include <sound/soc.h>
-
-#include <plat/audio.h>
-
-#include <mach/map.h>
-#include <mach/dma.h>
-
-#include "dma.h"
-#include "regs-i2s-v2.h"
-#include "s3c64xx-i2s.h"
-
-/* The value should be set to maximum of the total number
- * of I2Sv3 controllers that any supported SoC has.
- */
-#define MAX_I2SV3 2
-
-static struct s3c2410_dma_client s3c64xx_dma_client_out = {
- .name = "I2S PCM Stereo out"
-};
-
-static struct s3c2410_dma_client s3c64xx_dma_client_in = {
- .name = "I2S PCM Stereo in"
-};
-
-static struct s3c_dma_params s3c64xx_i2s_pcm_stereo_out[MAX_I2SV3];
-static struct s3c_dma_params s3c64xx_i2s_pcm_stereo_in[MAX_I2SV3];
-static struct s3c_i2sv2_info s3c64xx_i2s[MAX_I2SV3];
-
-struct clk *s3c64xx_i2s_get_clock(struct snd_soc_dai *dai)
-{
- struct s3c_i2sv2_info *i2s = snd_soc_dai_get_drvdata(dai);
- u32 iismod = readl(i2s->regs + S3C2412_IISMOD);
-
- if (iismod & S3C2412_IISMOD_IMS_SYSMUX)
- return i2s->iis_cclk;
- else
- return i2s->iis_pclk;
-}
-EXPORT_SYMBOL_GPL(s3c64xx_i2s_get_clock);
-
-static int s3c64xx_i2s_probe(struct snd_soc_dai *dai)
-{
- struct s3c_i2sv2_info *i2s;
- int ret;
-
- if (dai->id >= MAX_I2SV3) {
- dev_err(dai->dev, "id %d out of range\n", dai->id);
- return -EINVAL;
- }
-
- i2s = &s3c64xx_i2s[dai->id];
- snd_soc_dai_set_drvdata(dai, i2s);
-
- i2s->iis_cclk = clk_get(dai->dev, "audio-bus");
- if (IS_ERR(i2s->iis_cclk)) {
- dev_err(dai->dev, "failed to get audio-bus\n");
- ret = PTR_ERR(i2s->iis_cclk);
- goto err;
- }
-
- clk_enable(i2s->iis_cclk);
-
- ret = s3c_i2sv2_probe(dai, i2s, i2s->base);
- if (ret)
- goto err_clk;
-
- return 0;
-
-err_clk:
- clk_disable(i2s->iis_cclk);
- clk_put(i2s->iis_cclk);
-err:
- kfree(i2s);
- return ret;
-}
-
-static int s3c64xx_i2s_remove(struct snd_soc_dai *dai)
-{
- struct s3c_i2sv2_info *i2s = snd_soc_dai_get_drvdata(dai);
-
- clk_disable(i2s->iis_cclk);
- clk_put(i2s->iis_cclk);
- kfree(i2s);
- return 0;
-}
-
-static struct snd_soc_dai_ops s3c64xx_i2s_dai_ops;
-
-static struct snd_soc_dai_driver s3c64xx_i2s_dai[MAX_I2SV3] = {
-{
- .name = "s3c64xx-i2s-0",
- .probe = s3c64xx_i2s_probe,
- .remove = s3c64xx_i2s_remove,
- .playback = {
- .channels_min = 2,
- .channels_max = 2,
- .rates = S3C64XX_I2S_RATES,
- .formats = S3C64XX_I2S_FMTS,},
- .capture = {
- .channels_min = 2,
- .channels_max = 2,
- .rates = S3C64XX_I2S_RATES,
- .formats = S3C64XX_I2S_FMTS,},
- .ops = &s3c64xx_i2s_dai_ops,
- .symmetric_rates = 1,
-}, {
- .name = "s3c64xx-i2s-1",
- .probe = s3c64xx_i2s_probe,
- .remove = s3c64xx_i2s_remove,
- .playback = {
- .channels_min = 2,
- .channels_max = 2,
- .rates = S3C64XX_I2S_RATES,
- .formats = S3C64XX_I2S_FMTS,},
- .capture = {
- .channels_min = 2,
- .channels_max = 2,
- .rates = S3C64XX_I2S_RATES,
- .formats = S3C64XX_I2S_FMTS,},
- .ops = &s3c64xx_i2s_dai_ops,
- .symmetric_rates = 1,
-},};
-
-static __devinit int s3c64xx_iis_dev_probe(struct platform_device *pdev)
-{
- struct s3c_audio_pdata *i2s_pdata;
- struct s3c_i2sv2_info *i2s;
- struct resource *res;
- int i, ret;
-
- if (pdev->id >= MAX_I2SV3) {
- dev_err(&pdev->dev, "id %d out of range\n", pdev->id);
- return -EINVAL;
- }
-
- i2s = &s3c64xx_i2s[pdev->id];
-
- i2s->dma_capture = &s3c64xx_i2s_pcm_stereo_in[pdev->id];
- i2s->dma_playback = &s3c64xx_i2s_pcm_stereo_out[pdev->id];
-
- res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
- if (!res) {
- dev_err(&pdev->dev, "Unable to get I2S-TX dma resource\n");
- return -ENXIO;
- }
- i2s->dma_playback->channel = res->start;
-
- res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
- if (!res) {
- dev_err(&pdev->dev, "Unable to get I2S-RX dma resource\n");
- return -ENXIO;
- }
- i2s->dma_capture->channel = res->start;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(&pdev->dev, "Unable to get I2S SFR address\n");
- return -ENXIO;
- }
-
- if (!request_mem_region(res->start, resource_size(res),
- "s3c64xx-i2s")) {
- dev_err(&pdev->dev, "Unable to request SFR region\n");
- return -EBUSY;
- }
- i2s->base = res->start;
-
- i2s_pdata = pdev->dev.platform_data;
- if (i2s_pdata && i2s_pdata->cfg_gpio && i2s_pdata->cfg_gpio(pdev)) {
- dev_err(&pdev->dev, "Unable to configure gpio\n");
- return -EINVAL;
- }
- i2s->dma_capture->dma_addr = res->start + S3C2412_IISRXD;
- i2s->dma_playback->dma_addr = res->start + S3C2412_IISTXD;
-
- i2s->dma_capture->client = &s3c64xx_dma_client_in;
- i2s->dma_capture->dma_size = 4;
- i2s->dma_playback->client = &s3c64xx_dma_client_out;
- i2s->dma_playback->dma_size = 4;
-
- for (i = 0; i < ARRAY_SIZE(s3c64xx_i2s_dai); i++) {
- ret = s3c_i2sv2_register_dai(&pdev->dev, i,
- &s3c64xx_i2s_dai[i]);
- if (ret != 0)
- return ret;
- }
-
- return 0;
-}
-
-static __devexit int s3c64xx_iis_dev_remove(struct platform_device *pdev)
-{
- snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(s3c64xx_i2s_dai));
- return 0;
-}
-
-static struct platform_driver s3c64xx_iis_driver = {
- .probe = s3c64xx_iis_dev_probe,
- .remove = s3c64xx_iis_dev_remove,
- .driver = {
- .name = "samsung-i2s",
- .owner = THIS_MODULE,
- },
-};
-
-static int __init s3c64xx_i2s_init(void)
-{
- return platform_driver_register(&s3c64xx_iis_driver);
-}
-module_init(s3c64xx_i2s_init);
-
-static void __exit s3c64xx_i2s_exit(void)
-{
- platform_driver_unregister(&s3c64xx_iis_driver);
-}
-module_exit(s3c64xx_i2s_exit);
-
-/* Module information */
-MODULE_AUTHOR("Ben Dooks, <ben(a)simtec.co.uk>");
-MODULE_DESCRIPTION("S3C64XX I2S SoC Interface");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:samsung-i2s");
diff --git a/sound/soc/s3c24xx/s3c64xx-i2s.h b/sound/soc/s3c24xx/s3c64xx-i2s.h
deleted file mode 100644
index de4075d..0000000
--- a/sound/soc/s3c24xx/s3c64xx-i2s.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/* sound/soc/s3c24xx/s3c64xx-i2s.h
- *
- * ALSA SoC Audio Layer - S3C64XX I2S driver
- *
- * Copyright 2008 Openmoko, Inc.
- * Copyright 2008 Simtec Electronics
- * Ben Dooks <ben(a)simtec.co.uk>
- * http://armlinux.simtec.co.uk/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef __SND_SOC_S3C24XX_S3C64XX_I2S_H
-#define __SND_SOC_S3C24XX_S3C64XX_I2S_H __FILE__
-
-struct clk;
-
-#include "s3c-i2s-v2.h"
-
-#define S3C64XX_DIV_BCLK S3C_I2SV2_DIV_BCLK
-#define S3C64XX_DIV_RCLK S3C_I2SV2_DIV_RCLK
-#define S3C64XX_DIV_PRESCALER S3C_I2SV2_DIV_PRESCALER
-
-#define S3C64XX_CLKSRC_PCLK S3C_I2SV2_CLKSRC_PCLK
-#define S3C64XX_CLKSRC_MUX S3C_I2SV2_CLKSRC_AUDIOBUS
-#define S3C64XX_CLKSRC_CDCLK S3C_I2SV2_CLKSRC_CDCLK
-
-#define S3C64XX_I2S_RATES \
- (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \
- SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
- SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
-
-#define S3C64XX_I2S_FMTS \
- (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |\
- SNDRV_PCM_FMTBIT_S24_LE)
-
-struct clk *s3c64xx_i2s_get_clock(struct snd_soc_dai *dai);
-
-#endif /* __SND_SOC_S3C24XX_S3C64XX_I2S_H */
--
1.6.2.5
1
0

19 Oct '10
From: Jassi Brar <jassi.brar(a)samsung.com>
Modify the smdk64xx_wm8580.c to use new i2s controller driver.
Signed-off-by: Jassi Brar <jassi.brar(a)samsung.com>
---
sound/soc/s3c24xx/Kconfig | 2 +-
sound/soc/s3c24xx/smdk64xx_wm8580.c | 25 +++----------------------
2 files changed, 4 insertions(+), 23 deletions(-)
diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig
index f12e7c8..085a7b0 100644
--- a/sound/soc/s3c24xx/Kconfig
+++ b/sound/soc/s3c24xx/Kconfig
@@ -73,7 +73,7 @@ config SND_S3C64XX_SOC_WM8580
tristate "SoC I2S Audio support for WM8580 on SMDK64XX"
depends on SND_S3C24XX_SOC && MACH_SMDK6410
select SND_SOC_WM8580
- select SND_S3C64XX_SOC_I2S_V4
+ select SND_SAMSUNG_I2S
help
Say Y if you want to add support for SoC audio on the SMDK6410.
diff --git a/sound/soc/s3c24xx/smdk64xx_wm8580.c b/sound/soc/s3c24xx/smdk64xx_wm8580.c
index 1d59317..5f51db0 100644
--- a/sound/soc/s3c24xx/smdk64xx_wm8580.c
+++ b/sound/soc/s3c24xx/smdk64xx_wm8580.c
@@ -20,7 +20,7 @@
#include "../codecs/wm8580.h"
#include "dma.h"
-#include "s3c64xx-i2s.h"
+#include "i2s.h"
/*
* Default CFG switch settings to use this driver:
@@ -96,17 +96,6 @@ static int smdk64xx_hw_params(struct snd_pcm_substream *substream,
if (ret < 0)
return ret;
- ret = snd_soc_dai_set_sysclk(cpu_dai, S3C64XX_CLKSRC_CDCLK,
- 0, SND_SOC_CLOCK_IN);
- if (ret < 0)
- return ret;
-
- /* We use PCLK for basic ops in SoC-Slave mode */
- ret = snd_soc_dai_set_sysclk(cpu_dai, S3C64XX_CLKSRC_PCLK,
- 0, SND_SOC_CLOCK_IN);
- if (ret < 0)
- return ret;
-
/* Set WM8580 to drive MCLK from its PLLA */
ret = snd_soc_dai_set_clkdiv(codec_dai, WM8580_MCLK,
WM8580_CLKSRC_PLLA);
@@ -123,14 +112,6 @@ static int smdk64xx_hw_params(struct snd_pcm_substream *substream,
if (ret < 0)
return ret;
- ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C_I2SV2_DIV_BCLK, bfs);
- if (ret < 0)
- return ret;
-
- ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C_I2SV2_DIV_RCLK, rfs);
- if (ret < 0)
- return ret;
-
return 0;
}
@@ -222,7 +203,7 @@ static struct snd_soc_dai_link smdk64xx_dai[] = {
{ /* Primary Playback i/f */
.name = "WM8580 PAIF RX",
.stream_name = "Playback",
- .cpu_dai_name = "samsung-i2s-v4",
+ .cpu_dai_name = "samsung-i2s.2",
.codec_dai_name = "wm8580-hifi-playback",
.platform_name = "samsung-audio",
.codec_name = "wm8580-codec.0-001b",
@@ -232,7 +213,7 @@ static struct snd_soc_dai_link smdk64xx_dai[] = {
{ /* Primary Capture i/f */
.name = "WM8580 PAIF TX",
.stream_name = "Capture",
- .cpu_dai_name = "samsung-i2s-v4",
+ .cpu_dai_name = "samsung-i2s.2",
.codec_dai_name = "wm8580-hifi-capture",
.platform_name = "samsung-audio",
.codec_name = "wm8580-codec.0-001b",
--
1.6.2.5
1
0

19 Oct '10
From: Jassi Brar <jassi.brar(a)samsung.com>
Modify the goni_wm8994.c to use new i2s controller driver.
Signed-off-by: Jassi Brar <jassi.brar(a)samsung.com>
---
sound/soc/s3c24xx/Kconfig | 2 +-
sound/soc/s3c24xx/goni_wm8994.c | 10 ++--------
2 files changed, 3 insertions(+), 9 deletions(-)
diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig
index e7fad53..f12e7c8 100644
--- a/sound/soc/s3c24xx/Kconfig
+++ b/sound/soc/s3c24xx/Kconfig
@@ -150,7 +150,7 @@ config SND_S3C64XX_SOC_SMARTQ
config SND_SOC_GONI_AQUILA_WM8994
tristate "SoC I2S Audio support for AQUILA/GONI - WM8994"
depends on SND_S3C24XX_SOC && (MACH_GONI || MACH_AQUILA)
- select SND_S3C64XX_SOC_I2S_V4
+ select SND_SAMSUNG_I2S
select SND_SOC_WM8994
help
Say Y if you want to add support for SoC audio on goni or aquila
diff --git a/sound/soc/s3c24xx/goni_wm8994.c b/sound/soc/s3c24xx/goni_wm8994.c
index 201056c..dcaf7c3 100644
--- a/sound/soc/s3c24xx/goni_wm8994.c
+++ b/sound/soc/s3c24xx/goni_wm8994.c
@@ -26,7 +26,7 @@
#include <linux/mfd/wm8994/registers.h>
#include "../codecs/wm8994.h"
#include "dma.h"
-#include "s3c64xx-i2s.h"
+#include "i2s.h"
#define MACHINE_NAME 0
#define CPU_VOICE_DAI 1
@@ -163,12 +163,6 @@ static int goni_hifi_hw_params(struct snd_pcm_substream *substream,
if (ret < 0)
return ret;
- /* set the cpu system clock */
- ret = snd_soc_dai_set_sysclk(cpu_dai, S3C64XX_CLKSRC_PCLK,
- 0, SND_SOC_CLOCK_IN);
- if (ret < 0)
- return ret;
-
/* set codec DAI configuration */
ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
@@ -249,7 +243,7 @@ static struct snd_soc_dai_link goni_dai[] = {
{
.name = "WM8994",
.stream_name = "WM8994 HiFi",
- .cpu_dai_name = "s3c64xx-i2s-v4",
+ .cpu_dai_name = "samsung-i2s.0",
.codec_dai_name = "wm8994-hifi",
.platform_name = "samsung-audio",
.codec_name = "wm8994-codec.0-0x1a",
--
1.6.2.5
1
0

19 Oct '10
From: Jassi Brar <jassi.brar(a)samsung.com>
Modify the smartq_wm8987.c to use new i2s controller driver.
Signed-off-by: Jassi Brar <jassi.brar(a)samsung.com>
---
sound/soc/s3c24xx/Kconfig | 2 +-
sound/soc/s3c24xx/smartq_wm8987.c | 25 +++++++++++--------------
2 files changed, 12 insertions(+), 15 deletions(-)
diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig
index 20fe288..e7fad53 100644
--- a/sound/soc/s3c24xx/Kconfig
+++ b/sound/soc/s3c24xx/Kconfig
@@ -144,7 +144,7 @@ config SND_SOC_SMDK_WM9713
config SND_S3C64XX_SOC_SMARTQ
tristate "SoC I2S Audio support for SmartQ board"
depends on SND_S3C24XX_SOC && MACH_SMARTQ
- select SND_S3C64XX_SOC_I2S
+ select SND_SAMSUNG_I2S
select SND_SOC_WM8750
config SND_SOC_GONI_AQUILA_WM8994
diff --git a/sound/soc/s3c24xx/smartq_wm8987.c b/sound/soc/s3c24xx/smartq_wm8987.c
index 1d55312..5fcc420 100644
--- a/sound/soc/s3c24xx/smartq_wm8987.c
+++ b/sound/soc/s3c24xx/smartq_wm8987.c
@@ -25,7 +25,7 @@
#include <asm/mach-types.h>
#include "dma.h"
-#include "s3c64xx-i2s.h"
+#include "i2s.h"
#include "../codecs/wm8750.h"
@@ -41,13 +41,9 @@ static int smartq_hifi_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
- struct s3c_i2sv2_rate_calc div;
unsigned int clk = 0;
int ret;
- s3c_i2sv2_iis_calc_rate(&div, NULL, params_rate(params),
- s3c_i2sv2_get_clock(cpu_dai));
-
switch (params_rate(params)) {
case 8000:
case 16000:
@@ -78,20 +74,21 @@ static int smartq_hifi_hw_params(struct snd_pcm_substream *substream,
if (ret < 0)
return ret;
- /* set the codec system clock for DAC and ADC */
- ret = snd_soc_dai_set_sysclk(codec_dai, WM8750_SYSCLK, clk,
- SND_SOC_CLOCK_IN);
+ /* Use PCLK for I2S signal generation */
+ ret = snd_soc_dai_set_sysclk(cpu_dai, SAMSUNG_I2S_RCLKSRC_0,
+ 0, SND_SOC_CLOCK_IN);
if (ret < 0)
return ret;
- /* set MCLK division for sample rate */
- ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C_I2SV2_DIV_RCLK, div.fs_div);
+ /* Gate the RCLK output on PAD */
+ ret = snd_soc_dai_set_sysclk(cpu_dai, SAMSUNG_I2S_CDCLK,
+ 0, SND_SOC_CLOCK_IN);
if (ret < 0)
return ret;
- /* set prescaler division for sample rate */
- ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C_I2SV2_DIV_PRESCALER,
- div.clk_div - 1);
+ /* set the codec system clock for DAC and ADC */
+ ret = snd_soc_dai_set_sysclk(codec_dai, WM8750_SYSCLK, clk,
+ SND_SOC_CLOCK_IN);
if (ret < 0)
return ret;
@@ -211,7 +208,7 @@ static struct snd_soc_dai_link smartq_dai[] = {
{
.name = "wm8987",
.stream_name = "SmartQ Hi-Fi",
- .cpu_dai_name = "s3c64xx-i2s.0",
+ .cpu_dai_name = "samsung-i2s.0",
.codec_dai_name = "wm8750-hifi",
.platform_name = "samsung-audio",
.codec_name = "wm8750-codec.0-0x1a",
--
1.6.2.5
1
0

19 Oct '10
From: Jassi Brar <jassi.brar(a)samsung.com>
Define platform devices for all audio devices found on S5PV310
Signed-off-by: Jassi Brar <jassi.brar(a)samsung.com>
---
arch/arm/mach-s5pv310/Makefile | 1 +
arch/arm/mach-s5pv310/dev-audio.c | 356 +++++++++++++++++++++++++++++++++++++
2 files changed, 357 insertions(+), 0 deletions(-)
create mode 100644 arch/arm/mach-s5pv310/dev-audio.c
diff --git a/arch/arm/mach-s5pv310/Makefile b/arch/arm/mach-s5pv310/Makefile
index d5b51c7..b511650 100644
--- a/arch/arm/mach-s5pv310/Makefile
+++ b/arch/arm/mach-s5pv310/Makefile
@@ -26,5 +26,6 @@ obj-$(CONFIG_MACH_UNIVERSAL_C210) += mach-universal_c210.o
# device support
+obj-y += dev-audio.o
obj-$(CONFIG_S5PV310_SETUP_I2C1) += setup-i2c1.o
obj-$(CONFIG_S5PV310_SETUP_I2C2) += setup-i2c2.o
diff --git a/arch/arm/mach-s5pv310/dev-audio.c b/arch/arm/mach-s5pv310/dev-audio.c
new file mode 100644
index 0000000..ebb9f73
--- /dev/null
+++ b/arch/arm/mach-s5pv310/dev-audio.c
@@ -0,0 +1,356 @@
+/* linux/arch/arm/mach-s5pv310/dev-audio.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co. Ltd
+ * Jaswinder Singh <jassi.brar(a)samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/gpio.h>
+
+#include <plat/gpio-cfg.h>
+#include <plat/audio.h>
+
+#include <mach/map.h>
+#include <mach/dma.h>
+#include <mach/irqs.h>
+
+static const char *rclksrc_v5[] = {
+ [0] = "busclk",
+ [1] = "i2sclk",
+};
+
+static int s5pv310_cfg_i2s(struct platform_device *pdev)
+{
+ /* configure GPIO for i2s port */
+ switch (pdev->id) {
+ case 0:
+ s3c_gpio_cfgpin(S5PV310_GPZ(0), S3C_GPIO_SFN(2));
+ s3c_gpio_cfgpin(S5PV310_GPZ(1), S3C_GPIO_SFN(2));
+ s3c_gpio_cfgpin(S5PV310_GPZ(2), S3C_GPIO_SFN(2));
+ s3c_gpio_cfgpin(S5PV310_GPZ(3), S3C_GPIO_SFN(2));
+ s3c_gpio_cfgpin(S5PV310_GPZ(4), S3C_GPIO_SFN(2));
+ s3c_gpio_cfgpin(S5PV310_GPZ(5), S3C_GPIO_SFN(2));
+ s3c_gpio_cfgpin(S5PV310_GPZ(6), S3C_GPIO_SFN(2));
+ break;
+ case 1:
+ s3c_gpio_cfgpin(S5PV310_GPC0(0), S3C_GPIO_SFN(2));
+ s3c_gpio_cfgpin(S5PV310_GPC0(1), S3C_GPIO_SFN(2));
+ s3c_gpio_cfgpin(S5PV310_GPC0(2), S3C_GPIO_SFN(2));
+ s3c_gpio_cfgpin(S5PV310_GPC0(3), S3C_GPIO_SFN(2));
+ s3c_gpio_cfgpin(S5PV310_GPC0(4), S3C_GPIO_SFN(2));
+ break;
+ case 2:
+ s3c_gpio_cfgpin(S5PV310_GPC1(0), S3C_GPIO_SFN(4));
+ s3c_gpio_cfgpin(S5PV310_GPC1(1), S3C_GPIO_SFN(4));
+ s3c_gpio_cfgpin(S5PV310_GPC1(2), S3C_GPIO_SFN(4));
+ s3c_gpio_cfgpin(S5PV310_GPC1(3), S3C_GPIO_SFN(4));
+ s3c_gpio_cfgpin(S5PV310_GPC1(4), S3C_GPIO_SFN(4));
+ break;
+ default:
+ printk(KERN_ERR "Invalid Device %d\n", pdev->id);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static struct s3c_audio_pdata i2sv5_pdata = {
+ .cfg_gpio = s5pv310_cfg_i2s,
+ .type = {
+ .i2s = {
+ .quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI
+ | QUIRK_NEED_RSTCLR,
+ .src_clk = rclksrc_v5,
+ },
+ },
+};
+
+static struct resource s5pv310_iis0_resource[] = {
+ [0] = {
+ .start = S5PV310_PA_IIS0,
+ .end = S5PV310_PA_IIS0 + 0x100 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = DMACH_I2S0_TX,
+ .end = DMACH_I2S0_TX,
+ .flags = IORESOURCE_DMA,
+ },
+ [2] = {
+ .start = DMACH_I2S0_RX,
+ .end = DMACH_I2S0_RX,
+ .flags = IORESOURCE_DMA,
+ },
+ [3] = {
+ .start = DMACH_I2S0S_TX,
+ .end = DMACH_I2S0S_TX,
+ .flags = IORESOURCE_DMA,
+ },
+};
+
+struct platform_device s5pv310_device_iis0 = {
+ .name = "samsung-i2s",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(s5pv310_iis0_resource),
+ .resource = s5pv310_iis0_resource,
+ .dev = {
+ .platform_data = &i2sv5_pdata,
+ },
+};
+
+static const char *rclksrc_v3[] = {
+ [0] = "sclk_i2s",
+ [1] = "no_such_clock",
+};
+
+static struct s3c_audio_pdata i2sv3_pdata = {
+ .cfg_gpio = s5pv310_cfg_i2s,
+ .type = {
+ .i2s = {
+ .quirks = QUIRK_NO_MUXPSR,
+ .src_clk = rclksrc_v3,
+ },
+ },
+};
+
+static struct resource s5pv310_iis1_resource[] = {
+ [0] = {
+ .start = S5PV310_PA_IIS1,
+ .end = S5PV310_PA_IIS1 + 0x100 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = DMACH_I2S1_TX,
+ .end = DMACH_I2S1_TX,
+ .flags = IORESOURCE_DMA,
+ },
+ [2] = {
+ .start = DMACH_I2S1_RX,
+ .end = DMACH_I2S1_RX,
+ .flags = IORESOURCE_DMA,
+ },
+};
+
+struct platform_device s5pv310_device_iis1 = {
+ .name = "samsung-i2s",
+ .id = 1,
+ .num_resources = ARRAY_SIZE(s5pv310_iis1_resource),
+ .resource = s5pv310_iis1_resource,
+ .dev = {
+ .platform_data = &i2sv3_pdata,
+ },
+};
+
+static struct resource s5pv310_iis2_resource[] = {
+ [0] = {
+ .start = S5PV310_PA_IIS2,
+ .end = S5PV310_PA_IIS2 + 0x100 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = DMACH_I2S2_TX,
+ .end = DMACH_I2S2_TX,
+ .flags = IORESOURCE_DMA,
+ },
+ [2] = {
+ .start = DMACH_I2S2_RX,
+ .end = DMACH_I2S2_RX,
+ .flags = IORESOURCE_DMA,
+ },
+};
+
+struct platform_device s5pv310_device_iis2 = {
+ .name = "samsung-i2s",
+ .id = 2,
+ .num_resources = ARRAY_SIZE(s5pv310_iis2_resource),
+ .resource = s5pv310_iis2_resource,
+ .dev = {
+ .platform_data = &i2sv3_pdata,
+ },
+};
+
+/* PCM Controller platform_devices */
+
+static int s5pv310_pcm_cfg_gpio(struct platform_device *pdev)
+{
+ switch (pdev->id) {
+ case 0:
+ s3c_gpio_cfgpin(S5PV310_GPZ(0), S3C_GPIO_SFN(3));
+ s3c_gpio_cfgpin(S5PV310_GPZ(1), S3C_GPIO_SFN(3));
+ s3c_gpio_cfgpin(S5PV310_GPZ(2), S3C_GPIO_SFN(3));
+ s3c_gpio_cfgpin(S5PV310_GPZ(3), S3C_GPIO_SFN(3));
+ s3c_gpio_cfgpin(S5PV310_GPZ(4), S3C_GPIO_SFN(3));
+ break;
+ case 1:
+ s3c_gpio_cfgpin(S5PV310_GPC0(0), S3C_GPIO_SFN(3));
+ s3c_gpio_cfgpin(S5PV310_GPC0(1), S3C_GPIO_SFN(3));
+ s3c_gpio_cfgpin(S5PV310_GPC0(2), S3C_GPIO_SFN(3));
+ s3c_gpio_cfgpin(S5PV310_GPC0(3), S3C_GPIO_SFN(3));
+ s3c_gpio_cfgpin(S5PV310_GPC0(4), S3C_GPIO_SFN(3));
+ break;
+ case 2:
+ s3c_gpio_cfgpin(S5PV310_GPC1(0), S3C_GPIO_SFN(3));
+ s3c_gpio_cfgpin(S5PV310_GPC1(1), S3C_GPIO_SFN(3));
+ s3c_gpio_cfgpin(S5PV310_GPC1(2), S3C_GPIO_SFN(3));
+ s3c_gpio_cfgpin(S5PV310_GPC1(3), S3C_GPIO_SFN(3));
+ s3c_gpio_cfgpin(S5PV310_GPC1(4), S3C_GPIO_SFN(3));
+ break;
+ default:
+ printk(KERN_DEBUG "Invalid PCM Controller number!");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static struct s3c_audio_pdata s3c_pcm_pdata = {
+ .cfg_gpio = s5pv310_pcm_cfg_gpio,
+};
+
+static struct resource s5pv310_pcm0_resource[] = {
+ [0] = {
+ .start = S5PV310_PA_PCM0,
+ .end = S5PV310_PA_PCM0 + 0x100 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = DMACH_PCM0_TX,
+ .end = DMACH_PCM0_TX,
+ .flags = IORESOURCE_DMA,
+ },
+ [2] = {
+ .start = DMACH_PCM0_RX,
+ .end = DMACH_PCM0_RX,
+ .flags = IORESOURCE_DMA,
+ },
+};
+
+struct platform_device s5pv310_device_pcm0 = {
+ .name = "samsung-pcm",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(s5pv310_pcm0_resource),
+ .resource = s5pv310_pcm0_resource,
+ .dev = {
+ .platform_data = &s3c_pcm_pdata,
+ },
+};
+
+static struct resource s5pv310_pcm1_resource[] = {
+ [0] = {
+ .start = S5PV310_PA_PCM1,
+ .end = S5PV310_PA_PCM1 + 0x100 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = DMACH_PCM1_TX,
+ .end = DMACH_PCM1_TX,
+ .flags = IORESOURCE_DMA,
+ },
+ [2] = {
+ .start = DMACH_PCM1_RX,
+ .end = DMACH_PCM1_RX,
+ .flags = IORESOURCE_DMA,
+ },
+};
+
+struct platform_device s5pv310_device_pcm1 = {
+ .name = "samsung-pcm",
+ .id = 1,
+ .num_resources = ARRAY_SIZE(s5pv310_pcm1_resource),
+ .resource = s5pv310_pcm1_resource,
+ .dev = {
+ .platform_data = &s3c_pcm_pdata,
+ },
+};
+
+static struct resource s5pv310_pcm2_resource[] = {
+ [0] = {
+ .start = S5PV310_PA_PCM2,
+ .end = S5PV310_PA_PCM2 + 0x100 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = DMACH_PCM2_TX,
+ .end = DMACH_PCM2_TX,
+ .flags = IORESOURCE_DMA,
+ },
+ [2] = {
+ .start = DMACH_PCM2_RX,
+ .end = DMACH_PCM2_RX,
+ .flags = IORESOURCE_DMA,
+ },
+};
+
+struct platform_device s5pv310_device_pcm2 = {
+ .name = "samsung-pcm",
+ .id = 2,
+ .num_resources = ARRAY_SIZE(s5pv310_pcm2_resource),
+ .resource = s5pv310_pcm2_resource,
+ .dev = {
+ .platform_data = &s3c_pcm_pdata,
+ },
+};
+
+/* AC97 Controller platform devices */
+
+static int s5pv310_ac97_cfg_gpio(struct platform_device *pdev)
+{
+ s3c_gpio_cfgpin(S5PV310_GPC0(0), S3C_GPIO_SFN(4));
+ s3c_gpio_cfgpin(S5PV310_GPC0(1), S3C_GPIO_SFN(4));
+ s3c_gpio_cfgpin(S5PV310_GPC0(2), S3C_GPIO_SFN(4));
+ s3c_gpio_cfgpin(S5PV310_GPC0(3), S3C_GPIO_SFN(4));
+ s3c_gpio_cfgpin(S5PV310_GPC0(4), S3C_GPIO_SFN(4));
+
+ return 0;
+}
+
+static struct resource s5pv310_ac97_resource[] = {
+ [0] = {
+ .start = S5PV310_PA_AC97,
+ .end = S5PV310_PA_AC97 + 0x100 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = DMACH_AC97_PCMOUT,
+ .end = DMACH_AC97_PCMOUT,
+ .flags = IORESOURCE_DMA,
+ },
+ [2] = {
+ .start = DMACH_AC97_PCMIN,
+ .end = DMACH_AC97_PCMIN,
+ .flags = IORESOURCE_DMA,
+ },
+ [3] = {
+ .start = DMACH_AC97_MICIN,
+ .end = DMACH_AC97_MICIN,
+ .flags = IORESOURCE_DMA,
+ },
+ [4] = {
+ .start = IRQ_AC97,
+ .end = IRQ_AC97,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct s3c_audio_pdata s3c_ac97_pdata = {
+ .cfg_gpio = s5pv310_ac97_cfg_gpio,
+};
+
+static u64 s5pv310_ac97_dmamask = DMA_BIT_MASK(32);
+
+struct platform_device s5pv310_device_ac97 = {
+ .name = "samsung-ac97",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(s5pv310_ac97_resource),
+ .resource = s5pv310_ac97_resource,
+ .dev = {
+ .platform_data = &s3c_ac97_pdata,
+ .dma_mask = &s5pv310_ac97_dmamask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+};
--
1.6.2.5
1
0

19 Oct '10
From: Jassi Brar <jassi.brar(a)samsung.com>
Add more information to I2S platform_devices in order
to prepare them for new controller driver.
Signed-off-by: Jassi Brar <jassi.brar(a)samsung.com>
---
arch/arm/mach-s5pv210/clock.c | 10 +++---
arch/arm/mach-s5pv210/dev-audio.c | 64 ++++++++++++++++++++++++++----------
2 files changed, 51 insertions(+), 23 deletions(-)
diff --git a/arch/arm/mach-s5pv210/clock.c b/arch/arm/mach-s5pv210/clock.c
index af91fef..e5b8061 100644
--- a/arch/arm/mach-s5pv210/clock.c
+++ b/arch/arm/mach-s5pv210/clock.c
@@ -401,20 +401,20 @@ static struct clk init_clocks_disable[] = {
.enable = s5pv210_clk_ip3_ctrl,
.ctrlbit = (1<<21),
}, {
- .name = "i2s_v50",
+ .name = "iis",
.id = 0,
.parent = &clk_p,
.enable = s5pv210_clk_ip3_ctrl,
.ctrlbit = (1<<4),
}, {
- .name = "i2s_v32",
- .id = 0,
+ .name = "iis",
+ .id = 1,
.parent = &clk_p,
.enable = s5pv210_clk_ip3_ctrl,
.ctrlbit = (1 << 5),
}, {
- .name = "i2s_v32",
- .id = 1,
+ .name = "iis",
+ .id = 2,
.parent = &clk_p,
.enable = s5pv210_clk_ip3_ctrl,
.ctrlbit = (1 << 6),
diff --git a/arch/arm/mach-s5pv210/dev-audio.c b/arch/arm/mach-s5pv210/dev-audio.c
index 6e60041..d5f5361 100644
--- a/arch/arm/mach-s5pv210/dev-audio.c
+++ b/arch/arm/mach-s5pv210/dev-audio.c
@@ -19,10 +19,24 @@
#include <mach/dma.h>
#include <mach/irqs.h>
+static const char *rclksrc[] = {
+ [0] = "busclk",
+ [1] = "i2sclk",
+};
+
static int s5pv210_cfg_i2s(struct platform_device *pdev)
{
/* configure GPIO for i2s port */
switch (pdev->id) {
+ case 0:
+ s3c_gpio_cfgpin(S5PV210_GPI(0), S3C_GPIO_SFN(2));
+ s3c_gpio_cfgpin(S5PV210_GPI(1), S3C_GPIO_SFN(2));
+ s3c_gpio_cfgpin(S5PV210_GPI(2), S3C_GPIO_SFN(2));
+ s3c_gpio_cfgpin(S5PV210_GPI(3), S3C_GPIO_SFN(2));
+ s3c_gpio_cfgpin(S5PV210_GPI(4), S3C_GPIO_SFN(2));
+ s3c_gpio_cfgpin(S5PV210_GPI(5), S3C_GPIO_SFN(2));
+ s3c_gpio_cfgpin(S5PV210_GPI(6), S3C_GPIO_SFN(2));
+ break;
case 1:
s3c_gpio_cfgpin(S5PV210_GPC0(0), S3C_GPIO_SFN(2));
s3c_gpio_cfgpin(S5PV210_GPC0(1), S3C_GPIO_SFN(2));
@@ -30,7 +44,6 @@ static int s5pv210_cfg_i2s(struct platform_device *pdev)
s3c_gpio_cfgpin(S5PV210_GPC0(3), S3C_GPIO_SFN(2));
s3c_gpio_cfgpin(S5PV210_GPC0(4), S3C_GPIO_SFN(2));
break;
-
case 2:
s3c_gpio_cfgpin(S5PV210_GPC1(0), S3C_GPIO_SFN(4));
s3c_gpio_cfgpin(S5PV210_GPC1(1), S3C_GPIO_SFN(4));
@@ -38,17 +51,6 @@ static int s5pv210_cfg_i2s(struct platform_device *pdev)
s3c_gpio_cfgpin(S5PV210_GPC1(3), S3C_GPIO_SFN(4));
s3c_gpio_cfgpin(S5PV210_GPC1(4), S3C_GPIO_SFN(4));
break;
-
- case -1:
- s3c_gpio_cfgpin(S5PV210_GPI(0), S3C_GPIO_SFN(2));
- s3c_gpio_cfgpin(S5PV210_GPI(1), S3C_GPIO_SFN(2));
- s3c_gpio_cfgpin(S5PV210_GPI(2), S3C_GPIO_SFN(2));
- s3c_gpio_cfgpin(S5PV210_GPI(3), S3C_GPIO_SFN(2));
- s3c_gpio_cfgpin(S5PV210_GPI(4), S3C_GPIO_SFN(2));
- s3c_gpio_cfgpin(S5PV210_GPI(5), S3C_GPIO_SFN(2));
- s3c_gpio_cfgpin(S5PV210_GPI(6), S3C_GPIO_SFN(2));
- break;
-
default:
printk(KERN_ERR "Invalid Device %d\n", pdev->id);
return -EINVAL;
@@ -57,8 +59,15 @@ static int s5pv210_cfg_i2s(struct platform_device *pdev)
return 0;
}
-static struct s3c_audio_pdata s3c_i2s_pdata = {
+static struct s3c_audio_pdata i2sv5_pdata = {
.cfg_gpio = s5pv210_cfg_i2s,
+ .type = {
+ .i2s = {
+ .quriks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI
+ | QUIRK_NEED_RSTCLR,
+ .src_clk = rclksrc,
+ },
+ },
};
static struct resource s5pv210_iis0_resource[] = {
@@ -77,15 +86,34 @@ static struct resource s5pv210_iis0_resource[] = {
.end = DMACH_I2S0_RX,
.flags = IORESOURCE_DMA,
},
+ [3] = {
+ .start = DMACH_I2S0S_TX,
+ .end = DMACH_I2S0S_TX,
+ .flags = IORESOURCE_DMA,
+ },
};
struct platform_device s5pv210_device_iis0 = {
- .name = "samsung-i2s-v4",
- .id = -1,
+ .name = "samsung-i2s",
+ .id = 0,
.num_resources = ARRAY_SIZE(s5pv210_iis0_resource),
.resource = s5pv210_iis0_resource,
.dev = {
- .platform_data = &s3c_i2s_pdata,
+ .platform_data = &i2sv5_pdata,
+ },
+};
+
+static const char *rclksrc_v3[] = {
+ [0] = "iis",
+ [1] = "audio-bus",
+};
+
+static struct s3c_audio_pdata i2sv3_pdata = {
+ .cfg_gpio = s5pv210_cfg_i2s,
+ .type = {
+ .i2s = {
+ .src_clk = rclksrc_v3,
+ },
},
};
@@ -113,7 +141,7 @@ struct platform_device s5pv210_device_iis1 = {
.num_resources = ARRAY_SIZE(s5pv210_iis1_resource),
.resource = s5pv210_iis1_resource,
.dev = {
- .platform_data = &s3c_i2s_pdata,
+ .platform_data = &i2sv3_pdata,
},
};
@@ -141,7 +169,7 @@ struct platform_device s5pv210_device_iis2 = {
.num_resources = ARRAY_SIZE(s5pv210_iis2_resource),
.resource = s5pv210_iis2_resource,
.dev = {
- .platform_data = &s3c_i2s_pdata,
+ .platform_data = &i2sv3_pdata,
},
};
--
1.6.2.5
1
0

19 Oct '10
From: Jassi Brar <jassi.brar(a)samsung.com>
Add more information to I2S platform_devices in order to
prepare them for new controller driver.
Signed-off-by: Jassi Brar <jassi.brar(a)samsung.com>
---
arch/arm/mach-s5pc100/dev-audio.c | 50 ++++++++++++++++++++++++++++--------
1 files changed, 39 insertions(+), 11 deletions(-)
diff --git a/arch/arm/mach-s5pc100/dev-audio.c b/arch/arm/mach-s5pc100/dev-audio.c
index 3cf22ff..e14137b 100644
--- a/arch/arm/mach-s5pc100/dev-audio.c
+++ b/arch/arm/mach-s5pc100/dev-audio.c
@@ -23,6 +23,8 @@ static int s5pc100_cfg_i2s(struct platform_device *pdev)
{
/* configure GPIO for i2s port */
switch (pdev->id) {
+ case 0: /* Dedicated pins */
+ break;
case 1:
s3c_gpio_cfgpin(S5PC100_GPC(0), S3C_GPIO_SFN(2));
s3c_gpio_cfgpin(S5PC100_GPC(1), S3C_GPIO_SFN(2));
@@ -30,7 +32,6 @@ static int s5pc100_cfg_i2s(struct platform_device *pdev)
s3c_gpio_cfgpin(S5PC100_GPC(3), S3C_GPIO_SFN(2));
s3c_gpio_cfgpin(S5PC100_GPC(4), S3C_GPIO_SFN(2));
break;
-
case 2:
s3c_gpio_cfgpin(S5PC100_GPG3(0), S3C_GPIO_SFN(4));
s3c_gpio_cfgpin(S5PC100_GPG3(1), S3C_GPIO_SFN(4));
@@ -38,10 +39,6 @@ static int s5pc100_cfg_i2s(struct platform_device *pdev)
s3c_gpio_cfgpin(S5PC100_GPG3(3), S3C_GPIO_SFN(4));
s3c_gpio_cfgpin(S5PC100_GPG3(4), S3C_GPIO_SFN(4));
break;
-
- case -1: /* Dedicated pins */
- break;
-
default:
printk(KERN_ERR "Invalid Device %d\n", pdev->id);
return -EINVAL;
@@ -50,8 +47,20 @@ static int s5pc100_cfg_i2s(struct platform_device *pdev)
return 0;
}
-static struct s3c_audio_pdata s3c_i2s_pdata = {
+static const char *rclksrc_v5[] = {
+ [0] = "iis",
+ [1] = "i2sclkd2",
+};
+
+static struct s3c_audio_pdata i2sv5_pdata = {
.cfg_gpio = s5pc100_cfg_i2s,
+ .type = {
+ .i2s = {
+ .quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI
+ | QUIRK_NEED_RSTCLR,
+ .src_clk = rclksrc_v5,
+ },
+ },
};
static struct resource s5pc100_iis0_resource[] = {
@@ -70,15 +79,34 @@ static struct resource s5pc100_iis0_resource[] = {
.end = DMACH_I2S0_RX,
.flags = IORESOURCE_DMA,
},
+ [3] = {
+ .start = DMACH_I2S0S_TX,
+ .end = DMACH_I2S0S_TX,
+ .flags = IORESOURCE_DMA,
+ },
};
struct platform_device s5pc100_device_iis0 = {
- .name = "samsung-i2s-v4",
- .id = -1,
+ .name = "samsung-i2s",
+ .id = 0,
.num_resources = ARRAY_SIZE(s5pc100_iis0_resource),
.resource = s5pc100_iis0_resource,
.dev = {
- .platform_data = &s3c_i2s_pdata,
+ .platform_data = &i2sv5_pdata,
+ },
+};
+
+static const char *rclksrc_v3[] = {
+ [0] = "iis",
+ [1] = "sclk_audio",
+};
+
+static struct s3c_audio_pdata i2sv3_pdata = {
+ .cfg_gpio = s5pc100_cfg_i2s,
+ .type = {
+ .i2s = {
+ .src_clk = rclksrc_v3,
+ },
},
};
@@ -106,7 +134,7 @@ struct platform_device s5pc100_device_iis1 = {
.num_resources = ARRAY_SIZE(s5pc100_iis1_resource),
.resource = s5pc100_iis1_resource,
.dev = {
- .platform_data = &s3c_i2s_pdata,
+ .platform_data = &i2sv3_pdata,
},
};
@@ -134,7 +162,7 @@ struct platform_device s5pc100_device_iis2 = {
.num_resources = ARRAY_SIZE(s5pc100_iis2_resource),
.resource = s5pc100_iis2_resource,
.dev = {
- .platform_data = &s3c_i2s_pdata,
+ .platform_data = &i2sv3_pdata,
},
};
--
1.6.2.5
1
0

19 Oct '10
From: Jassi Brar <jassi.brar(a)samsung.com>
Add more information to I2S platform_devices in order
to prepare them for new controller driver.
Signed-off-by: Jassi Brar <jassi.brar(a)samsung.com>
---
arch/arm/mach-s5p6442/dev-audio.c | 44 ++++++++++++++++++++++++++++++------
1 files changed, 36 insertions(+), 8 deletions(-)
diff --git a/arch/arm/mach-s5p6442/dev-audio.c b/arch/arm/mach-s5p6442/dev-audio.c
index 1419442..b91463e 100644
--- a/arch/arm/mach-s5p6442/dev-audio.c
+++ b/arch/arm/mach-s5p6442/dev-audio.c
@@ -30,15 +30,13 @@ static int s5p6442_cfg_i2s(struct platform_device *pdev)
s3c_gpio_cfgpin(S5P6442_GPC1(3), S3C_GPIO_SFN(2));
s3c_gpio_cfgpin(S5P6442_GPC1(4), S3C_GPIO_SFN(2));
break;
-
- case -1:
+ case 0:
s3c_gpio_cfgpin(S5P6442_GPC0(0), S3C_GPIO_SFN(2));
s3c_gpio_cfgpin(S5P6442_GPC0(1), S3C_GPIO_SFN(2));
s3c_gpio_cfgpin(S5P6442_GPC0(2), S3C_GPIO_SFN(2));
s3c_gpio_cfgpin(S5P6442_GPC0(3), S3C_GPIO_SFN(2));
s3c_gpio_cfgpin(S5P6442_GPC0(4), S3C_GPIO_SFN(2));
break;
-
default:
printk(KERN_ERR "Invalid Device %d\n", pdev->id);
return -EINVAL;
@@ -47,8 +45,19 @@ static int s5p6442_cfg_i2s(struct platform_device *pdev)
return 0;
}
-static struct s3c_audio_pdata s3c_i2s_pdata = {
+static const char *rclksrc_v35[] = {
+ [0] = "busclk",
+ [1] = "i2sclk",
+};
+
+static struct s3c_audio_pdata i2sv35_pdata = {
.cfg_gpio = s5p6442_cfg_i2s,
+ .type = {
+ .i2s = {
+ .quirks = QUIRK_SEC_DAI | QUIRK_NEED_RSTCLR,
+ .src_clk = rclksrc_v35,
+ },
+ },
};
static struct resource s5p6442_iis0_resource[] = {
@@ -67,15 +76,34 @@ static struct resource s5p6442_iis0_resource[] = {
.end = DMACH_I2S0_RX,
.flags = IORESOURCE_DMA,
},
+ [3] = {
+ .start = DMACH_I2S0S_TX,
+ .end = DMACH_I2S0S_TX,
+ .flags = IORESOURCE_DMA,
+ },
};
struct platform_device s5p6442_device_iis0 = {
- .name = "samsung-i2s-v4",
- .id = -1,
+ .name = "samsung-i2s",
+ .id = 0,
.num_resources = ARRAY_SIZE(s5p6442_iis0_resource),
.resource = s5p6442_iis0_resource,
.dev = {
- .platform_data = &s3c_i2s_pdata,
+ .platform_data = &i2sv35_pdata,
+ },
+};
+
+static const char *rclksrc_v3[] = {
+ [0] = "iis",
+ [1] = "sclk_audio",
+};
+
+static struct s3c_audio_pdata i2sv3_pdata = {
+ .cfg_gpio = s5p6442_cfg_i2s,
+ .type = {
+ .i2s = {
+ .src_clk = rclksrc_v3,
+ },
},
};
@@ -103,7 +131,7 @@ struct platform_device s5p6442_device_iis1 = {
.num_resources = ARRAY_SIZE(s5p6442_iis1_resource),
.resource = s5p6442_iis1_resource,
.dev = {
- .platform_data = &s3c_i2s_pdata,
+ .platform_data = &i2sv3_pdata,
},
};
--
1.6.2.5
1
0

19 Oct '10
From: Jassi Brar <jassi.brar(a)samsung.com>
Add more information to I2S platform_devices in order
to prepare them for new controller driver.
Signed-off-by: Jassi Brar <jassi.brar(a)samsung.com>
---
arch/arm/mach-s5p6440/clock.c | 2 +-
arch/arm/mach-s5p6440/dev-audio.c | 21 ++++++++++++++++-----
2 files changed, 17 insertions(+), 6 deletions(-)
diff --git a/arch/arm/mach-s5p6440/clock.c b/arch/arm/mach-s5p6440/clock.c
index ca6e48d..a80a019 100644
--- a/arch/arm/mach-s5p6440/clock.c
+++ b/arch/arm/mach-s5p6440/clock.c
@@ -371,7 +371,7 @@ static struct clk init_clocks_disable[] = {
.enable = s5p6440_pclk_ctrl,
.ctrlbit = S5P_CLKCON_PCLK_IIC0,
}, {
- .name = "i2s_v40",
+ .name = "iis",
.id = 0,
.parent = &clk_pclk_low.clk,
.enable = s5p6440_pclk_ctrl,
diff --git a/arch/arm/mach-s5p6440/dev-audio.c b/arch/arm/mach-s5p6440/dev-audio.c
index 5d98629..9d61f5d 100644
--- a/arch/arm/mach-s5p6440/dev-audio.c
+++ b/arch/arm/mach-s5p6440/dev-audio.c
@@ -19,11 +19,16 @@
#include <mach/dma.h>
#include <mach/irqs.h>
+static const char *rclksrc[] = {
+ [0] = "iis",
+ [1] = "sclk_audio2",
+};
+
static int s5p6440_cfg_i2s(struct platform_device *pdev)
{
/* configure GPIO for i2s port */
switch (pdev->id) {
- case -1:
+ case 0:
s3c_gpio_cfgpin(S5P6440_GPR(4), S3C_GPIO_SFN(5));
s3c_gpio_cfgpin(S5P6440_GPR(5), S3C_GPIO_SFN(5));
s3c_gpio_cfgpin(S5P6440_GPR(6), S3C_GPIO_SFN(5));
@@ -41,8 +46,14 @@ static int s5p6440_cfg_i2s(struct platform_device *pdev)
return 0;
}
-static struct s3c_audio_pdata s3c_i2s_pdata = {
+static struct s3c_audio_pdata i2sv4_pdata = {
.cfg_gpio = s5p6440_cfg_i2s,
+ .type = {
+ .i2s = {
+ .quirks = QUIRK_PRI_6CHAN,
+ .src_clk = rclksrc,
+ },
+ },
};
static struct resource s5p6440_iis0_resource[] = {
@@ -64,12 +75,12 @@ static struct resource s5p6440_iis0_resource[] = {
};
struct platform_device s5p6440_device_iis = {
- .name = "samsung-i2s-v4",
- .id = -1,
+ .name = "samsung-i2s",
+ .id = 0,
.num_resources = ARRAY_SIZE(s5p6440_iis0_resource),
.resource = s5p6440_iis0_resource,
.dev = {
- .platform_data = &s3c_i2s_pdata,
+ .platform_data = &i2sv4_pdata,
},
};
--
1.6.2.5
1
0

19 Oct '10
From: Jassi Brar <jassi.brar(a)samsung.com>
Add more information to I2S platform_devices in order to
prepare them for new controller driver.
Signed-off-by: Jassi Brar <jassi.brar(a)samsung.com>
---
arch/arm/mach-s3c64xx/clock.c | 2 +-
arch/arm/mach-s3c64xx/dev-audio.c | 62 +++++++++++++++++++++----------------
2 files changed, 36 insertions(+), 28 deletions(-)
diff --git a/arch/arm/mach-s3c64xx/clock.c b/arch/arm/mach-s3c64xx/clock.c
index 7e03f0a..1c98d2f 100644
--- a/arch/arm/mach-s3c64xx/clock.c
+++ b/arch/arm/mach-s3c64xx/clock.c
@@ -695,7 +695,7 @@ static struct clksrc_clk clksrcs[] = {
}, {
.clk = {
.name = "audio-bus",
- .id = -1, /* There's only one IISv4 port */
+ .id = 2,
.ctrlbit = S3C6410_CLKCON_SCLK_AUDIO2,
.enable = s3c64xx_sclk_ctrl,
},
diff --git a/arch/arm/mach-s3c64xx/dev-audio.c b/arch/arm/mach-s3c64xx/dev-audio.c
index 01dda91..c2ad04c 100644
--- a/arch/arm/mach-s3c64xx/dev-audio.c
+++ b/arch/arm/mach-s3c64xx/dev-audio.c
@@ -27,7 +27,12 @@
#include <mach/gpio-bank-e.h>
#include <mach/gpio-bank-h.h>
-static int s3c64xx_i2sv3_cfg_gpio(struct platform_device *pdev)
+static const char *rclksrc[] = {
+ [0] = "iis",
+ [1] = "audio-bus",
+};
+
+static int s3c64xx_i2s_cfg_gpio(struct platform_device *pdev)
{
switch (pdev->id) {
case 0:
@@ -44,6 +49,15 @@ static int s3c64xx_i2sv3_cfg_gpio(struct platform_device *pdev)
s3c_gpio_cfgpin(S3C64XX_GPE(3), S3C64XX_GPE3_I2S1_DI);
s3c_gpio_cfgpin(S3C64XX_GPE(4), S3C64XX_GPE4_I2S1_D0);
break;
+ case 2:
+ s3c_gpio_cfgpin(S3C64XX_GPC(4), S3C64XX_GPC4_I2S_V40_DO0);
+ s3c_gpio_cfgpin(S3C64XX_GPC(5), S3C64XX_GPC5_I2S_V40_DO1);
+ s3c_gpio_cfgpin(S3C64XX_GPC(7), S3C64XX_GPC7_I2S_V40_DO2);
+ s3c_gpio_cfgpin(S3C64XX_GPH(6), S3C64XX_GPH6_I2S_V40_BCLK);
+ s3c_gpio_cfgpin(S3C64XX_GPH(7), S3C64XX_GPH7_I2S_V40_CDCLK);
+ s3c_gpio_cfgpin(S3C64XX_GPH(8), S3C64XX_GPH8_I2S_V40_LRCLK);
+ s3c_gpio_cfgpin(S3C64XX_GPH(9), S3C64XX_GPH9_I2S_V40_DI);
+ break;
default:
printk(KERN_DEBUG "Invalid I2S Controller number: %d\n",
pdev->id);
@@ -53,19 +67,6 @@ static int s3c64xx_i2sv3_cfg_gpio(struct platform_device *pdev)
return 0;
}
-static int s3c64xx_i2sv4_cfg_gpio(struct platform_device *pdev)
-{
- s3c_gpio_cfgpin(S3C64XX_GPC(4), S3C64XX_GPC4_I2S_V40_DO0);
- s3c_gpio_cfgpin(S3C64XX_GPC(5), S3C64XX_GPC5_I2S_V40_DO1);
- s3c_gpio_cfgpin(S3C64XX_GPC(7), S3C64XX_GPC7_I2S_V40_DO2);
- s3c_gpio_cfgpin(S3C64XX_GPH(6), S3C64XX_GPH6_I2S_V40_BCLK);
- s3c_gpio_cfgpin(S3C64XX_GPH(7), S3C64XX_GPH7_I2S_V40_CDCLK);
- s3c_gpio_cfgpin(S3C64XX_GPH(8), S3C64XX_GPH8_I2S_V40_LRCLK);
- s3c_gpio_cfgpin(S3C64XX_GPH(9), S3C64XX_GPH9_I2S_V40_DI);
-
- return 0;
-}
-
static struct resource s3c64xx_iis0_resource[] = {
[0] = {
.start = S3C64XX_PA_IIS0,
@@ -84,8 +85,13 @@ static struct resource s3c64xx_iis0_resource[] = {
},
};
-static struct s3c_audio_pdata s3c_i2s0_pdata = {
- .cfg_gpio = s3c64xx_i2sv3_cfg_gpio,
+static struct s3c_audio_pdata i2sv3_pdata = {
+ .cfg_gpio = s3c64xx_i2s_cfg_gpio,
+ .type = {
+ .i2s = {
+ .src_clk = rclksrc,
+ },
+ },
};
struct platform_device s3c64xx_device_iis0 = {
@@ -94,7 +100,7 @@ struct platform_device s3c64xx_device_iis0 = {
.num_resources = ARRAY_SIZE(s3c64xx_iis0_resource),
.resource = s3c64xx_iis0_resource,
.dev = {
- .platform_data = &s3c_i2s0_pdata,
+ .platform_data = &i2sv3_pdata,
},
};
EXPORT_SYMBOL(s3c64xx_device_iis0);
@@ -117,17 +123,13 @@ static struct resource s3c64xx_iis1_resource[] = {
},
};
-static struct s3c_audio_pdata s3c_i2s1_pdata = {
- .cfg_gpio = s3c64xx_i2sv3_cfg_gpio,
-};
-
struct platform_device s3c64xx_device_iis1 = {
.name = "samsung-i2s",
.id = 1,
.num_resources = ARRAY_SIZE(s3c64xx_iis1_resource),
.resource = s3c64xx_iis1_resource,
.dev = {
- .platform_data = &s3c_i2s1_pdata,
+ .platform_data = &i2sv3_pdata,
},
};
EXPORT_SYMBOL(s3c64xx_device_iis1);
@@ -150,17 +152,23 @@ static struct resource s3c64xx_iisv4_resource[] = {
},
};
-static struct s3c_audio_pdata s3c_i2sv4_pdata = {
- .cfg_gpio = s3c64xx_i2sv4_cfg_gpio,
+static struct s3c_audio_pdata i2sv4_pdata = {
+ .cfg_gpio = s3c64xx_i2s_cfg_gpio,
+ .type = {
+ .i2s = {
+ .quirks = QUIRK_PRI_6CHAN,
+ .src_clk = rclksrc,
+ },
+ },
};
struct platform_device s3c64xx_device_iisv4 = {
- .name = "samsung-i2s-v4",
- .id = -1,
+ .name = "samsung-i2s",
+ .id = 2,
.num_resources = ARRAY_SIZE(s3c64xx_iisv4_resource),
.resource = s3c64xx_iisv4_resource,
.dev = {
- .platform_data = &s3c_i2sv4_pdata,
+ .platform_data = &i2sv4_pdata,
},
};
EXPORT_SYMBOL(s3c64xx_device_iisv4);
--
1.6.2.5
1
0

19 Oct '10
From: Jassi Brar <jassi.brar(a)samsung.com>
Since the I2S of S3C64XX and newer SoCs are incremental
versions of each other with changes managable in a single
driver, rename the 's3c64xx-iis' -> 'samsung-i2s'
Signed-off-by: Jassi Brar <jassi.brar(a)samsung.com>
---
arch/arm/mach-s3c64xx/dev-audio.c | 6 +++---
arch/arm/mach-s5p6440/dev-audio.c | 2 +-
arch/arm/mach-s5p6442/dev-audio.c | 4 ++--
arch/arm/mach-s5pc100/dev-audio.c | 6 +++---
arch/arm/mach-s5pv210/dev-audio.c | 6 +++---
sound/soc/s3c24xx/s3c64xx-i2s-v4.c | 4 ++--
sound/soc/s3c24xx/s3c64xx-i2s.c | 4 ++--
sound/soc/s3c24xx/smdk64xx_wm8580.c | 4 ++--
8 files changed, 18 insertions(+), 18 deletions(-)
diff --git a/arch/arm/mach-s3c64xx/dev-audio.c b/arch/arm/mach-s3c64xx/dev-audio.c
index 1615c94..01dda91 100644
--- a/arch/arm/mach-s3c64xx/dev-audio.c
+++ b/arch/arm/mach-s3c64xx/dev-audio.c
@@ -89,7 +89,7 @@ static struct s3c_audio_pdata s3c_i2s0_pdata = {
};
struct platform_device s3c64xx_device_iis0 = {
- .name = "s3c64xx-iis",
+ .name = "samsung-i2s",
.id = 0,
.num_resources = ARRAY_SIZE(s3c64xx_iis0_resource),
.resource = s3c64xx_iis0_resource,
@@ -122,7 +122,7 @@ static struct s3c_audio_pdata s3c_i2s1_pdata = {
};
struct platform_device s3c64xx_device_iis1 = {
- .name = "s3c64xx-iis",
+ .name = "samsung-i2s",
.id = 1,
.num_resources = ARRAY_SIZE(s3c64xx_iis1_resource),
.resource = s3c64xx_iis1_resource,
@@ -155,7 +155,7 @@ static struct s3c_audio_pdata s3c_i2sv4_pdata = {
};
struct platform_device s3c64xx_device_iisv4 = {
- .name = "s3c64xx-iis-v4",
+ .name = "samsung-i2s-v4",
.id = -1,
.num_resources = ARRAY_SIZE(s3c64xx_iisv4_resource),
.resource = s3c64xx_iisv4_resource,
diff --git a/arch/arm/mach-s5p6440/dev-audio.c b/arch/arm/mach-s5p6440/dev-audio.c
index 3ca0d2b..5d98629 100644
--- a/arch/arm/mach-s5p6440/dev-audio.c
+++ b/arch/arm/mach-s5p6440/dev-audio.c
@@ -64,7 +64,7 @@ static struct resource s5p6440_iis0_resource[] = {
};
struct platform_device s5p6440_device_iis = {
- .name = "s3c64xx-iis-v4",
+ .name = "samsung-i2s-v4",
.id = -1,
.num_resources = ARRAY_SIZE(s5p6440_iis0_resource),
.resource = s5p6440_iis0_resource,
diff --git a/arch/arm/mach-s5p6442/dev-audio.c b/arch/arm/mach-s5p6442/dev-audio.c
index 7a4e347..1419442 100644
--- a/arch/arm/mach-s5p6442/dev-audio.c
+++ b/arch/arm/mach-s5p6442/dev-audio.c
@@ -70,7 +70,7 @@ static struct resource s5p6442_iis0_resource[] = {
};
struct platform_device s5p6442_device_iis0 = {
- .name = "s3c64xx-iis-v4",
+ .name = "samsung-i2s-v4",
.id = -1,
.num_resources = ARRAY_SIZE(s5p6442_iis0_resource),
.resource = s5p6442_iis0_resource,
@@ -98,7 +98,7 @@ static struct resource s5p6442_iis1_resource[] = {
};
struct platform_device s5p6442_device_iis1 = {
- .name = "s3c64xx-iis",
+ .name = "samsung-i2s",
.id = 1,
.num_resources = ARRAY_SIZE(s5p6442_iis1_resource),
.resource = s5p6442_iis1_resource,
diff --git a/arch/arm/mach-s5pc100/dev-audio.c b/arch/arm/mach-s5pc100/dev-audio.c
index 4207511..3cf22ff 100644
--- a/arch/arm/mach-s5pc100/dev-audio.c
+++ b/arch/arm/mach-s5pc100/dev-audio.c
@@ -73,7 +73,7 @@ static struct resource s5pc100_iis0_resource[] = {
};
struct platform_device s5pc100_device_iis0 = {
- .name = "s3c64xx-iis-v4",
+ .name = "samsung-i2s-v4",
.id = -1,
.num_resources = ARRAY_SIZE(s5pc100_iis0_resource),
.resource = s5pc100_iis0_resource,
@@ -101,7 +101,7 @@ static struct resource s5pc100_iis1_resource[] = {
};
struct platform_device s5pc100_device_iis1 = {
- .name = "s3c64xx-iis",
+ .name = "samsung-i2s",
.id = 1,
.num_resources = ARRAY_SIZE(s5pc100_iis1_resource),
.resource = s5pc100_iis1_resource,
@@ -129,7 +129,7 @@ static struct resource s5pc100_iis2_resource[] = {
};
struct platform_device s5pc100_device_iis2 = {
- .name = "s3c64xx-iis",
+ .name = "samsung-i2s",
.id = 2,
.num_resources = ARRAY_SIZE(s5pc100_iis2_resource),
.resource = s5pc100_iis2_resource,
diff --git a/arch/arm/mach-s5pv210/dev-audio.c b/arch/arm/mach-s5pv210/dev-audio.c
index e6db957..6e60041 100644
--- a/arch/arm/mach-s5pv210/dev-audio.c
+++ b/arch/arm/mach-s5pv210/dev-audio.c
@@ -80,7 +80,7 @@ static struct resource s5pv210_iis0_resource[] = {
};
struct platform_device s5pv210_device_iis0 = {
- .name = "s3c64xx-iis-v4",
+ .name = "samsung-i2s-v4",
.id = -1,
.num_resources = ARRAY_SIZE(s5pv210_iis0_resource),
.resource = s5pv210_iis0_resource,
@@ -108,7 +108,7 @@ static struct resource s5pv210_iis1_resource[] = {
};
struct platform_device s5pv210_device_iis1 = {
- .name = "s3c64xx-iis",
+ .name = "samsung-i2s",
.id = 1,
.num_resources = ARRAY_SIZE(s5pv210_iis1_resource),
.resource = s5pv210_iis1_resource,
@@ -136,7 +136,7 @@ static struct resource s5pv210_iis2_resource[] = {
};
struct platform_device s5pv210_device_iis2 = {
- .name = "s3c64xx-iis",
+ .name = "samsung-i2s",
.id = 2,
.num_resources = ARRAY_SIZE(s5pv210_iis2_resource),
.resource = s5pv210_iis2_resource,
diff --git a/sound/soc/s3c24xx/s3c64xx-i2s-v4.c b/sound/soc/s3c24xx/s3c64xx-i2s-v4.c
index 46b65d7..8a08041 100644
--- a/sound/soc/s3c24xx/s3c64xx-i2s-v4.c
+++ b/sound/soc/s3c24xx/s3c64xx-i2s-v4.c
@@ -206,7 +206,7 @@ static struct platform_driver s3c64xx_i2sv4_driver = {
.probe = s3c64xx_i2sv4_dev_probe,
.remove = s3c64xx_i2sv4_dev_remove,
.driver = {
- .name = "s3c64xx-iis-v4",
+ .name = "samsung-i2s-v4",
.owner = THIS_MODULE,
},
};
@@ -227,4 +227,4 @@ module_exit(s3c64xx_i2sv4_exit);
MODULE_AUTHOR("Jaswinder Singh, <jassi.brar(a)samsung.com>");
MODULE_DESCRIPTION("S3C64XX I2Sv4 SoC Interface");
MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:s3c64xx-iis-v4");
+MODULE_ALIAS("platform:samsung-i2s-v4");
diff --git a/sound/soc/s3c24xx/s3c64xx-i2s.c b/sound/soc/s3c24xx/s3c64xx-i2s.c
index 0288d4e..0fefbb5 100644
--- a/sound/soc/s3c24xx/s3c64xx-i2s.c
+++ b/sound/soc/s3c24xx/s3c64xx-i2s.c
@@ -218,7 +218,7 @@ static struct platform_driver s3c64xx_iis_driver = {
.probe = s3c64xx_iis_dev_probe,
.remove = s3c64xx_iis_dev_remove,
.driver = {
- .name = "s3c64xx-iis",
+ .name = "samsung-i2s",
.owner = THIS_MODULE,
},
};
@@ -239,4 +239,4 @@ module_exit(s3c64xx_i2s_exit);
MODULE_AUTHOR("Ben Dooks, <ben(a)simtec.co.uk>");
MODULE_DESCRIPTION("S3C64XX I2S SoC Interface");
MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:s3c64xx-iis");
+MODULE_ALIAS("platform:samsung-i2s");
diff --git a/sound/soc/s3c24xx/smdk64xx_wm8580.c b/sound/soc/s3c24xx/smdk64xx_wm8580.c
index 9ddc964..1d59317 100644
--- a/sound/soc/s3c24xx/smdk64xx_wm8580.c
+++ b/sound/soc/s3c24xx/smdk64xx_wm8580.c
@@ -222,7 +222,7 @@ static struct snd_soc_dai_link smdk64xx_dai[] = {
{ /* Primary Playback i/f */
.name = "WM8580 PAIF RX",
.stream_name = "Playback",
- .cpu_dai_name = "s3c64xx-iis-v4",
+ .cpu_dai_name = "samsung-i2s-v4",
.codec_dai_name = "wm8580-hifi-playback",
.platform_name = "samsung-audio",
.codec_name = "wm8580-codec.0-001b",
@@ -232,7 +232,7 @@ static struct snd_soc_dai_link smdk64xx_dai[] = {
{ /* Primary Capture i/f */
.name = "WM8580 PAIF TX",
.stream_name = "Capture",
- .cpu_dai_name = "s3c64xx-iis-v4",
+ .cpu_dai_name = "samsung-i2s-v4",
.codec_dai_name = "wm8580-hifi-capture",
.platform_name = "samsung-audio",
.codec_name = "wm8580-codec.0-001b",
--
1.6.2.5
1
0

19 Oct '10
From: Jassi Brar <jassi.brar(a)samsung.com>
Remove S3C,s3c from static defines.
s3c_dma_ -> dma_
s3c24xx_runtime_ -> runtime_
s3c24xx_audio_ -> audio_
s3c_preallocate_ -> preallocate_
s3c24xx_soc_platform -> samsung_asoc_platform
s3c24xx_pcm_driver -> asoc_dma_driver
snd_s3c24xx_pcm_ -> samsung_asoc_
Signed-off-by: Jassi Brar <jassi.brar(a)samsung.com>
---
sound/soc/s3c24xx/dma.c | 124 +++++++++++++++++++++++-----------------------
1 files changed, 62 insertions(+), 62 deletions(-)
diff --git a/sound/soc/s3c24xx/dma.c b/sound/soc/s3c24xx/dma.c
index b4c7c85..12622f3 100644
--- a/sound/soc/s3c24xx/dma.c
+++ b/sound/soc/s3c24xx/dma.c
@@ -32,7 +32,7 @@
#include "dma.h"
-static const struct snd_pcm_hardware s3c_dma_hardware = {
+static const struct snd_pcm_hardware dma_hardware = {
.info = SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP |
@@ -53,7 +53,7 @@ static const struct snd_pcm_hardware s3c_dma_hardware = {
.fifo_size = 32,
};
-struct s3c24xx_runtime_data {
+struct runtime_data {
spinlock_t lock;
int state;
unsigned int dma_loaded;
@@ -65,14 +65,14 @@ struct s3c24xx_runtime_data {
struct s3c_dma_params *params;
};
-/* s3c_dma_enqueue
+/* dma_enqueue
*
* place a dma buffer onto the queue for the dma system
* to handle.
*/
-static void s3c_dma_enqueue(struct snd_pcm_substream *substream)
+static void dma_enqueue(struct snd_pcm_substream *substream)
{
- struct s3c24xx_runtime_data *prtd = substream->runtime->private_data;
+ struct runtime_data *prtd = substream->runtime->private_data;
dma_addr_t pos = prtd->dma_pos;
unsigned int limit;
int ret;
@@ -113,12 +113,12 @@ static void s3c_dma_enqueue(struct snd_pcm_substream *substream)
prtd->dma_pos = pos;
}
-static void s3c24xx_audio_buffdone(struct s3c2410_dma_chan *channel,
+static void audio_buffdone(struct s3c2410_dma_chan *channel,
void *dev_id, int size,
enum s3c2410_dma_buffresult result)
{
struct snd_pcm_substream *substream = dev_id;
- struct s3c24xx_runtime_data *prtd;
+ struct runtime_data *prtd;
pr_debug("Entered %s\n", __func__);
@@ -133,17 +133,17 @@ static void s3c24xx_audio_buffdone(struct s3c2410_dma_chan *channel,
spin_lock(&prtd->lock);
if (prtd->state & ST_RUNNING && !s3c_dma_has_circular()) {
prtd->dma_loaded--;
- s3c_dma_enqueue(substream);
+ dma_enqueue(substream);
}
spin_unlock(&prtd->lock);
}
-static int s3c_dma_hw_params(struct snd_pcm_substream *substream,
+static int dma_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_pcm_runtime *runtime = substream->runtime;
- struct s3c24xx_runtime_data *prtd = runtime->private_data;
+ struct runtime_data *prtd = runtime->private_data;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
unsigned long totbytes = params_buffer_bytes(params);
struct s3c_dma_params *dma =
@@ -182,7 +182,7 @@ static int s3c_dma_hw_params(struct snd_pcm_substream *substream,
}
s3c2410_dma_set_buffdone_fn(prtd->params->channel,
- s3c24xx_audio_buffdone);
+ audio_buffdone);
snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
@@ -200,9 +200,9 @@ static int s3c_dma_hw_params(struct snd_pcm_substream *substream,
return 0;
}
-static int s3c_dma_hw_free(struct snd_pcm_substream *substream)
+static int dma_hw_free(struct snd_pcm_substream *substream)
{
- struct s3c24xx_runtime_data *prtd = substream->runtime->private_data;
+ struct runtime_data *prtd = substream->runtime->private_data;
pr_debug("Entered %s\n", __func__);
@@ -217,9 +217,9 @@ static int s3c_dma_hw_free(struct snd_pcm_substream *substream)
return 0;
}
-static int s3c_dma_prepare(struct snd_pcm_substream *substream)
+static int dma_prepare(struct snd_pcm_substream *substream)
{
- struct s3c24xx_runtime_data *prtd = substream->runtime->private_data;
+ struct runtime_data *prtd = substream->runtime->private_data;
int ret = 0;
pr_debug("Entered %s\n", __func__);
@@ -250,14 +250,14 @@ static int s3c_dma_prepare(struct snd_pcm_substream *substream)
prtd->dma_pos = prtd->dma_start;
/* enqueue dma buffers */
- s3c_dma_enqueue(substream);
+ dma_enqueue(substream);
return ret;
}
-static int s3c_dma_trigger(struct snd_pcm_substream *substream, int cmd)
+static int dma_trigger(struct snd_pcm_substream *substream, int cmd)
{
- struct s3c24xx_runtime_data *prtd = substream->runtime->private_data;
+ struct runtime_data *prtd = substream->runtime->private_data;
int ret = 0;
pr_debug("Entered %s\n", __func__);
@@ -290,10 +290,10 @@ static int s3c_dma_trigger(struct snd_pcm_substream *substream, int cmd)
}
static snd_pcm_uframes_t
-s3c_dma_pointer(struct snd_pcm_substream *substream)
+dma_pointer(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
- struct s3c24xx_runtime_data *prtd = runtime->private_data;
+ struct runtime_data *prtd = runtime->private_data;
unsigned long res;
dma_addr_t src, dst;
@@ -325,17 +325,17 @@ s3c_dma_pointer(struct snd_pcm_substream *substream)
return bytes_to_frames(substream->runtime, res);
}
-static int s3c_dma_open(struct snd_pcm_substream *substream)
+static int dma_open(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
- struct s3c24xx_runtime_data *prtd;
+ struct runtime_data *prtd;
pr_debug("Entered %s\n", __func__);
snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
- snd_soc_set_runtime_hwparams(substream, &s3c_dma_hardware);
+ snd_soc_set_runtime_hwparams(substream, &dma_hardware);
- prtd = kzalloc(sizeof(struct s3c24xx_runtime_data), GFP_KERNEL);
+ prtd = kzalloc(sizeof(struct runtime_data), GFP_KERNEL);
if (prtd == NULL)
return -ENOMEM;
@@ -345,22 +345,22 @@ static int s3c_dma_open(struct snd_pcm_substream *substream)
return 0;
}
-static int s3c_dma_close(struct snd_pcm_substream *substream)
+static int dma_close(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
- struct s3c24xx_runtime_data *prtd = runtime->private_data;
+ struct runtime_data *prtd = runtime->private_data;
pr_debug("Entered %s\n", __func__);
if (!prtd)
- pr_debug("s3c_dma_close called with prtd == NULL\n");
+ pr_debug("dma_close called with prtd == NULL\n");
kfree(prtd);
return 0;
}
-static int s3c_dma_mmap(struct snd_pcm_substream *substream,
+static int dma_mmap(struct snd_pcm_substream *substream,
struct vm_area_struct *vma)
{
struct snd_pcm_runtime *runtime = substream->runtime;
@@ -373,23 +373,23 @@ static int s3c_dma_mmap(struct snd_pcm_substream *substream,
runtime->dma_bytes);
}
-static struct snd_pcm_ops s3c_dma_ops = {
- .open = s3c_dma_open,
- .close = s3c_dma_close,
+static struct snd_pcm_ops dma_ops = {
+ .open = dma_open,
+ .close = dma_close,
.ioctl = snd_pcm_lib_ioctl,
- .hw_params = s3c_dma_hw_params,
- .hw_free = s3c_dma_hw_free,
- .prepare = s3c_dma_prepare,
- .trigger = s3c_dma_trigger,
- .pointer = s3c_dma_pointer,
- .mmap = s3c_dma_mmap,
+ .hw_params = dma_hw_params,
+ .hw_free = dma_hw_free,
+ .prepare = dma_prepare,
+ .trigger = dma_trigger,
+ .pointer = dma_pointer,
+ .mmap = dma_mmap,
};
-static int s3c_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
+static int preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
{
struct snd_pcm_substream *substream = pcm->streams[stream].substream;
struct snd_dma_buffer *buf = &substream->dma_buffer;
- size_t size = s3c_dma_hardware.buffer_bytes_max;
+ size_t size = dma_hardware.buffer_bytes_max;
pr_debug("Entered %s\n", __func__);
@@ -404,7 +404,7 @@ static int s3c_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
return 0;
}
-static void s3c_dma_free_dma_buffers(struct snd_pcm *pcm)
+static void dma_free_dma_buffers(struct snd_pcm *pcm)
{
struct snd_pcm_substream *substream;
struct snd_dma_buffer *buf;
@@ -427,9 +427,9 @@ static void s3c_dma_free_dma_buffers(struct snd_pcm *pcm)
}
}
-static u64 s3c_dma_mask = DMA_BIT_MASK(32);
+static u64 dma_mask = DMA_BIT_MASK(32);
-static int s3c_dma_new(struct snd_card *card,
+static int dma_new(struct snd_card *card,
struct snd_soc_dai *dai, struct snd_pcm *pcm)
{
int ret = 0;
@@ -437,19 +437,19 @@ static int s3c_dma_new(struct snd_card *card,
pr_debug("Entered %s\n", __func__);
if (!card->dev->dma_mask)
- card->dev->dma_mask = &s3c_dma_mask;
+ card->dev->dma_mask = &dma_mask;
if (!card->dev->coherent_dma_mask)
card->dev->coherent_dma_mask = 0xffffffff;
if (dai->driver->playback.channels_min) {
- ret = s3c_preallocate_dma_buffer(pcm,
+ ret = preallocate_dma_buffer(pcm,
SNDRV_PCM_STREAM_PLAYBACK);
if (ret)
goto out;
}
if (dai->driver->capture.channels_min) {
- ret = s3c_preallocate_dma_buffer(pcm,
+ ret = preallocate_dma_buffer(pcm,
SNDRV_PCM_STREAM_CAPTURE);
if (ret)
goto out;
@@ -458,46 +458,46 @@ out:
return ret;
}
-static struct snd_soc_platform_driver s3c24xx_soc_platform = {
- .ops = &s3c_dma_ops,
- .pcm_new = s3c_dma_new,
- .pcm_free = s3c_dma_free_dma_buffers,
+static struct snd_soc_platform_driver samsung_asoc_platform = {
+ .ops = &dma_ops,
+ .pcm_new = dma_new,
+ .pcm_free = dma_free_dma_buffers,
};
-static int __devinit s3c24xx_soc_platform_probe(struct platform_device *pdev)
+static int __devinit samsung_asoc_platform_probe(struct platform_device *pdev)
{
- return snd_soc_register_platform(&pdev->dev, &s3c24xx_soc_platform);
+ return snd_soc_register_platform(&pdev->dev, &samsung_asoc_platform);
}
-static int __devexit s3c24xx_soc_platform_remove(struct platform_device *pdev)
+static int __devexit samsung_asoc_platform_remove(struct platform_device *pdev)
{
snd_soc_unregister_platform(&pdev->dev);
return 0;
}
-static struct platform_driver s3c24xx_pcm_driver = {
+static struct platform_driver asoc_dma_driver = {
.driver = {
.name = "samsung-audio",
.owner = THIS_MODULE,
},
- .probe = s3c24xx_soc_platform_probe,
- .remove = __devexit_p(s3c24xx_soc_platform_remove),
+ .probe = samsung_asoc_platform_probe,
+ .remove = __devexit_p(samsung_asoc_platform_remove),
};
-static int __init snd_s3c24xx_pcm_init(void)
+static int __init samsung_asoc_init(void)
{
- return platform_driver_register(&s3c24xx_pcm_driver);
+ return platform_driver_register(&asoc_dma_driver);
}
-module_init(snd_s3c24xx_pcm_init);
+module_init(samsung_asoc_init);
-static void __exit snd_s3c24xx_pcm_exit(void)
+static void __exit samsung_asoc_exit(void)
{
- platform_driver_unregister(&s3c24xx_pcm_driver);
+ platform_driver_unregister(&asoc_dma_driver);
}
-module_exit(snd_s3c24xx_pcm_exit);
+module_exit(samsung_asoc_exit);
MODULE_AUTHOR("Ben Dooks, <ben(a)simtec.co.uk>");
-MODULE_DESCRIPTION("Samsung S3C Audio DMA module");
+MODULE_DESCRIPTION("Samsung ASoC DMA Driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:samsung-audio");
--
1.6.2.5
1
0
From: Jassi Brar <jassi.brar(a)samsung.com>
Rename Samsung PCM Controller driver
s3c-pcm.[c/h] -> pcm.[c/h]
Signed-off-by: Jassi Brar <jassi.brar(a)samsung.com>
---
sound/soc/s3c24xx/Makefile | 4 +-
sound/soc/s3c24xx/pcm.c | 552 +++++++++++++++++++++++++++++++++++++++++++
sound/soc/s3c24xx/pcm.h | 124 ++++++++++
sound/soc/s3c24xx/s3c-pcm.c | 552 -------------------------------------------
sound/soc/s3c24xx/s3c-pcm.h | 124 ----------
5 files changed, 678 insertions(+), 678 deletions(-)
create mode 100644 sound/soc/s3c24xx/pcm.c
create mode 100644 sound/soc/s3c24xx/pcm.h
delete mode 100644 sound/soc/s3c24xx/s3c-pcm.c
delete mode 100644 sound/soc/s3c24xx/s3c-pcm.h
diff --git a/sound/soc/s3c24xx/Makefile b/sound/soc/s3c24xx/Makefile
index 551a63d..93de2a0 100644
--- a/sound/soc/s3c24xx/Makefile
+++ b/sound/soc/s3c24xx/Makefile
@@ -6,8 +6,8 @@ snd-soc-s3c64xx-i2s-objs := s3c64xx-i2s.o
snd-soc-ac97-objs := ac97.o
snd-soc-s3c64xx-i2s-v4-objs := s3c64xx-i2s-v4.o
snd-soc-s3c-i2s-v2-objs := s3c-i2s-v2.o
-snd-soc-s3c-pcm-objs := s3c-pcm.o
snd-soc-samsung-spdif-objs := spdif.o
+snd-soc-pcm-objs := pcm.o
obj-$(CONFIG_SND_S3C24XX_SOC) += snd-soc-s3c24xx.o
obj-$(CONFIG_SND_S3C24XX_SOC_I2S) += snd-soc-s3c24xx-i2s.o
@@ -16,8 +16,8 @@ obj-$(CONFIG_SND_S3C2412_SOC_I2S) += snd-soc-s3c2412-i2s.o
obj-$(CONFIG_SND_S3C64XX_SOC_I2S) += snd-soc-s3c64xx-i2s.o
obj-$(CONFIG_SND_S3C64XX_SOC_I2S_V4) += snd-soc-s3c64xx-i2s-v4.o
obj-$(CONFIG_SND_S3C_I2SV2_SOC) += snd-soc-s3c-i2s-v2.o
-obj-$(CONFIG_SND_S3C_SOC_PCM) += snd-soc-s3c-pcm.o
obj-$(CONFIG_SND_S5P_SOC_SPDIF) += snd-soc-samsung-spdif.o
+obj-$(CONFIG_SND_S3C_SOC_PCM) += snd-soc-pcm.o
# S3C24XX Machine Support
snd-soc-jive-wm8750-objs := jive_wm8750.o
diff --git a/sound/soc/s3c24xx/pcm.c b/sound/soc/s3c24xx/pcm.c
new file mode 100644
index 0000000..4d0f6e4
--- /dev/null
+++ b/sound/soc/s3c24xx/pcm.c
@@ -0,0 +1,552 @@
+/* sound/soc/s3c24xx/pcm.c
+ *
+ * ALSA SoC Audio Layer - S3C PCM-Controller driver
+ *
+ * Copyright (c) 2009 Samsung Electronics Co. Ltd
+ * Author: Jaswinder Singh <jassi.brar(a)samsung.com>
+ * based upon I2S drivers by Ben Dooks.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/kernel.h>
+#include <linux/gpio.h>
+#include <linux/io.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+#include <plat/audio.h>
+#include <plat/dma.h>
+
+#include "dma.h"
+#include "pcm.h"
+
+static struct s3c2410_dma_client s3c_pcm_dma_client_out = {
+ .name = "PCM Stereo out"
+};
+
+static struct s3c2410_dma_client s3c_pcm_dma_client_in = {
+ .name = "PCM Stereo in"
+};
+
+static struct s3c_dma_params s3c_pcm_stereo_out[] = {
+ [0] = {
+ .client = &s3c_pcm_dma_client_out,
+ .dma_size = 4,
+ },
+ [1] = {
+ .client = &s3c_pcm_dma_client_out,
+ .dma_size = 4,
+ },
+};
+
+static struct s3c_dma_params s3c_pcm_stereo_in[] = {
+ [0] = {
+ .client = &s3c_pcm_dma_client_in,
+ .dma_size = 4,
+ },
+ [1] = {
+ .client = &s3c_pcm_dma_client_in,
+ .dma_size = 4,
+ },
+};
+
+static struct s3c_pcm_info s3c_pcm[2];
+
+static void s3c_pcm_snd_txctrl(struct s3c_pcm_info *pcm, int on)
+{
+ void __iomem *regs = pcm->regs;
+ u32 ctl, clkctl;
+
+ clkctl = readl(regs + S3C_PCM_CLKCTL);
+ ctl = readl(regs + S3C_PCM_CTL);
+ ctl &= ~(S3C_PCM_CTL_TXDIPSTICK_MASK
+ << S3C_PCM_CTL_TXDIPSTICK_SHIFT);
+
+ if (on) {
+ ctl |= S3C_PCM_CTL_TXDMA_EN;
+ ctl |= S3C_PCM_CTL_TXFIFO_EN;
+ ctl |= S3C_PCM_CTL_ENABLE;
+ ctl |= (0x4<<S3C_PCM_CTL_TXDIPSTICK_SHIFT);
+ clkctl |= S3C_PCM_CLKCTL_SERCLK_EN;
+ } else {
+ ctl &= ~S3C_PCM_CTL_TXDMA_EN;
+ ctl &= ~S3C_PCM_CTL_TXFIFO_EN;
+
+ if (!(ctl & S3C_PCM_CTL_RXFIFO_EN)) {
+ ctl &= ~S3C_PCM_CTL_ENABLE;
+ if (!pcm->idleclk)
+ clkctl |= S3C_PCM_CLKCTL_SERCLK_EN;
+ }
+ }
+
+ writel(clkctl, regs + S3C_PCM_CLKCTL);
+ writel(ctl, regs + S3C_PCM_CTL);
+}
+
+static void s3c_pcm_snd_rxctrl(struct s3c_pcm_info *pcm, int on)
+{
+ void __iomem *regs = pcm->regs;
+ u32 ctl, clkctl;
+
+ ctl = readl(regs + S3C_PCM_CTL);
+ clkctl = readl(regs + S3C_PCM_CLKCTL);
+ ctl &= ~(S3C_PCM_CTL_RXDIPSTICK_MASK
+ << S3C_PCM_CTL_RXDIPSTICK_SHIFT);
+
+ if (on) {
+ ctl |= S3C_PCM_CTL_RXDMA_EN;
+ ctl |= S3C_PCM_CTL_RXFIFO_EN;
+ ctl |= S3C_PCM_CTL_ENABLE;
+ ctl |= (0x20<<S3C_PCM_CTL_RXDIPSTICK_SHIFT);
+ clkctl |= S3C_PCM_CLKCTL_SERCLK_EN;
+ } else {
+ ctl &= ~S3C_PCM_CTL_RXDMA_EN;
+ ctl &= ~S3C_PCM_CTL_RXFIFO_EN;
+
+ if (!(ctl & S3C_PCM_CTL_TXFIFO_EN)) {
+ ctl &= ~S3C_PCM_CTL_ENABLE;
+ if (!pcm->idleclk)
+ clkctl |= S3C_PCM_CLKCTL_SERCLK_EN;
+ }
+ }
+
+ writel(clkctl, regs + S3C_PCM_CLKCTL);
+ writel(ctl, regs + S3C_PCM_CTL);
+}
+
+static int s3c_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(rtd->cpu_dai);
+ unsigned long flags;
+
+ dev_dbg(pcm->dev, "Entered %s\n", __func__);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ spin_lock_irqsave(&pcm->lock, flags);
+
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ s3c_pcm_snd_rxctrl(pcm, 1);
+ else
+ s3c_pcm_snd_txctrl(pcm, 1);
+
+ spin_unlock_irqrestore(&pcm->lock, flags);
+ break;
+
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ spin_lock_irqsave(&pcm->lock, flags);
+
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ s3c_pcm_snd_rxctrl(pcm, 0);
+ else
+ s3c_pcm_snd_txctrl(pcm, 0);
+
+ spin_unlock_irqrestore(&pcm->lock, flags);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int s3c_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *socdai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(rtd->cpu_dai);
+ struct s3c_dma_params *dma_data;
+ void __iomem *regs = pcm->regs;
+ struct clk *clk;
+ int sclk_div, sync_div;
+ unsigned long flags;
+ u32 clkctl;
+
+ dev_dbg(pcm->dev, "Entered %s\n", __func__);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ dma_data = pcm->dma_playback;
+ else
+ dma_data = pcm->dma_capture;
+
+ snd_soc_dai_set_dma_data(rtd->cpu_dai, substream, dma_data);
+
+ /* Strictly check for sample size */
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&pcm->lock, flags);
+
+ /* Get hold of the PCMSOURCE_CLK */
+ clkctl = readl(regs + S3C_PCM_CLKCTL);
+ if (clkctl & S3C_PCM_CLKCTL_SERCLKSEL_PCLK)
+ clk = pcm->pclk;
+ else
+ clk = pcm->cclk;
+
+ /* Set the SCLK divider */
+ sclk_div = clk_get_rate(clk) / pcm->sclk_per_fs /
+ params_rate(params) / 2 - 1;
+
+ clkctl &= ~(S3C_PCM_CLKCTL_SCLKDIV_MASK
+ << S3C_PCM_CLKCTL_SCLKDIV_SHIFT);
+ clkctl |= ((sclk_div & S3C_PCM_CLKCTL_SCLKDIV_MASK)
+ << S3C_PCM_CLKCTL_SCLKDIV_SHIFT);
+
+ /* Set the SYNC divider */
+ sync_div = pcm->sclk_per_fs - 1;
+
+ clkctl &= ~(S3C_PCM_CLKCTL_SYNCDIV_MASK
+ << S3C_PCM_CLKCTL_SYNCDIV_SHIFT);
+ clkctl |= ((sync_div & S3C_PCM_CLKCTL_SYNCDIV_MASK)
+ << S3C_PCM_CLKCTL_SYNCDIV_SHIFT);
+
+ writel(clkctl, regs + S3C_PCM_CLKCTL);
+
+ spin_unlock_irqrestore(&pcm->lock, flags);
+
+ dev_dbg(pcm->dev, "PCMSOURCE_CLK-%lu SCLK=%ufs SCLK_DIV=%d SYNC_DIV=%d\n",
+ clk_get_rate(clk), pcm->sclk_per_fs,
+ sclk_div, sync_div);
+
+ return 0;
+}
+
+static int s3c_pcm_set_fmt(struct snd_soc_dai *cpu_dai,
+ unsigned int fmt)
+{
+ struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(cpu_dai);
+ void __iomem *regs = pcm->regs;
+ unsigned long flags;
+ int ret = 0;
+ u32 ctl;
+
+ dev_dbg(pcm->dev, "Entered %s\n", __func__);
+
+ spin_lock_irqsave(&pcm->lock, flags);
+
+ ctl = readl(regs + S3C_PCM_CTL);
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ /* Nothing to do, NB_NF by default */
+ break;
+ default:
+ dev_err(pcm->dev, "Unsupported clock inversion!\n");
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ /* Nothing to do, Master by default */
+ break;
+ default:
+ dev_err(pcm->dev, "Unsupported master/slave format!\n");
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_MASK) {
+ case SND_SOC_DAIFMT_CONT:
+ pcm->idleclk = 1;
+ break;
+ case SND_SOC_DAIFMT_GATED:
+ pcm->idleclk = 0;
+ break;
+ default:
+ dev_err(pcm->dev, "Invalid Clock gating request!\n");
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_DSP_A:
+ ctl |= S3C_PCM_CTL_TXMSB_AFTER_FSYNC;
+ ctl |= S3C_PCM_CTL_RXMSB_AFTER_FSYNC;
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ ctl &= ~S3C_PCM_CTL_TXMSB_AFTER_FSYNC;
+ ctl &= ~S3C_PCM_CTL_RXMSB_AFTER_FSYNC;
+ break;
+ default:
+ dev_err(pcm->dev, "Unsupported data format!\n");
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ writel(ctl, regs + S3C_PCM_CTL);
+
+exit:
+ spin_unlock_irqrestore(&pcm->lock, flags);
+
+ return ret;
+}
+
+static int s3c_pcm_set_clkdiv(struct snd_soc_dai *cpu_dai,
+ int div_id, int div)
+{
+ struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(cpu_dai);
+
+ switch (div_id) {
+ case S3C_PCM_SCLK_PER_FS:
+ pcm->sclk_per_fs = div;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int s3c_pcm_set_sysclk(struct snd_soc_dai *cpu_dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(cpu_dai);
+ void __iomem *regs = pcm->regs;
+ u32 clkctl = readl(regs + S3C_PCM_CLKCTL);
+
+ switch (clk_id) {
+ case S3C_PCM_CLKSRC_PCLK:
+ clkctl |= S3C_PCM_CLKCTL_SERCLKSEL_PCLK;
+ break;
+
+ case S3C_PCM_CLKSRC_MUX:
+ clkctl &= ~S3C_PCM_CLKCTL_SERCLKSEL_PCLK;
+
+ if (clk_get_rate(pcm->cclk) != freq)
+ clk_set_rate(pcm->cclk, freq);
+
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ writel(clkctl, regs + S3C_PCM_CLKCTL);
+
+ return 0;
+}
+
+static struct snd_soc_dai_ops s3c_pcm_dai_ops = {
+ .set_sysclk = s3c_pcm_set_sysclk,
+ .set_clkdiv = s3c_pcm_set_clkdiv,
+ .trigger = s3c_pcm_trigger,
+ .hw_params = s3c_pcm_hw_params,
+ .set_fmt = s3c_pcm_set_fmt,
+};
+
+#define S3C_PCM_RATES SNDRV_PCM_RATE_8000_96000
+
+#define S3C_PCM_DAI_DECLARE \
+ .symmetric_rates = 1, \
+ .ops = &s3c_pcm_dai_ops, \
+ .playback = { \
+ .channels_min = 2, \
+ .channels_max = 2, \
+ .rates = S3C_PCM_RATES, \
+ .formats = SNDRV_PCM_FMTBIT_S16_LE, \
+ }, \
+ .capture = { \
+ .channels_min = 2, \
+ .channels_max = 2, \
+ .rates = S3C_PCM_RATES, \
+ .formats = SNDRV_PCM_FMTBIT_S16_LE, \
+ }
+
+struct snd_soc_dai_driver s3c_pcm_dai[] = {
+ [0] = {
+ .name = "samsung-pcm.0",
+ S3C_PCM_DAI_DECLARE,
+ },
+ [1] = {
+ .name = "samsung-pcm.1",
+ S3C_PCM_DAI_DECLARE,
+ },
+};
+EXPORT_SYMBOL_GPL(s3c_pcm_dai);
+
+static __devinit int s3c_pcm_dev_probe(struct platform_device *pdev)
+{
+ struct s3c_pcm_info *pcm;
+ struct resource *mem_res, *dmatx_res, *dmarx_res;
+ struct s3c_audio_pdata *pcm_pdata;
+ int ret;
+
+ /* Check for valid device index */
+ if ((pdev->id < 0) || pdev->id >= ARRAY_SIZE(s3c_pcm)) {
+ dev_err(&pdev->dev, "id %d out of range\n", pdev->id);
+ return -EINVAL;
+ }
+
+ pcm_pdata = pdev->dev.platform_data;
+
+ /* Check for availability of necessary resource */
+ dmatx_res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+ if (!dmatx_res) {
+ dev_err(&pdev->dev, "Unable to get PCM-TX dma resource\n");
+ return -ENXIO;
+ }
+
+ dmarx_res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+ if (!dmarx_res) {
+ dev_err(&pdev->dev, "Unable to get PCM-RX dma resource\n");
+ return -ENXIO;
+ }
+
+ mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem_res) {
+ dev_err(&pdev->dev, "Unable to get register resource\n");
+ return -ENXIO;
+ }
+
+ if (pcm_pdata && pcm_pdata->cfg_gpio && pcm_pdata->cfg_gpio(pdev)) {
+ dev_err(&pdev->dev, "Unable to configure gpio\n");
+ return -EINVAL;
+ }
+
+ pcm = &s3c_pcm[pdev->id];
+ pcm->dev = &pdev->dev;
+
+ spin_lock_init(&pcm->lock);
+
+ /* Default is 128fs */
+ pcm->sclk_per_fs = 128;
+
+ pcm->cclk = clk_get(&pdev->dev, "audio-bus");
+ if (IS_ERR(pcm->cclk)) {
+ dev_err(&pdev->dev, "failed to get audio-bus\n");
+ ret = PTR_ERR(pcm->cclk);
+ goto err1;
+ }
+ clk_enable(pcm->cclk);
+
+ /* record our pcm structure for later use in the callbacks */
+ dev_set_drvdata(&pdev->dev, pcm);
+
+ if (!request_mem_region(mem_res->start,
+ resource_size(mem_res), "samsung-pcm")) {
+ dev_err(&pdev->dev, "Unable to request register region\n");
+ ret = -EBUSY;
+ goto err2;
+ }
+
+ pcm->regs = ioremap(mem_res->start, 0x100);
+ if (pcm->regs == NULL) {
+ dev_err(&pdev->dev, "cannot ioremap registers\n");
+ ret = -ENXIO;
+ goto err3;
+ }
+
+ pcm->pclk = clk_get(&pdev->dev, "pcm");
+ if (IS_ERR(pcm->pclk)) {
+ dev_err(&pdev->dev, "failed to get pcm_clock\n");
+ ret = -ENOENT;
+ goto err4;
+ }
+ clk_enable(pcm->pclk);
+
+ ret = snd_soc_register_dai(&pdev->dev, &s3c_pcm_dai[pdev->id]);
+ if (ret != 0) {
+ dev_err(&pdev->dev, "failed to get pcm_clock\n");
+ goto err5;
+ }
+
+ s3c_pcm_stereo_in[pdev->id].dma_addr = mem_res->start
+ + S3C_PCM_RXFIFO;
+ s3c_pcm_stereo_out[pdev->id].dma_addr = mem_res->start
+ + S3C_PCM_TXFIFO;
+
+ s3c_pcm_stereo_in[pdev->id].channel = dmarx_res->start;
+ s3c_pcm_stereo_out[pdev->id].channel = dmatx_res->start;
+
+ pcm->dma_capture = &s3c_pcm_stereo_in[pdev->id];
+ pcm->dma_playback = &s3c_pcm_stereo_out[pdev->id];
+
+ return 0;
+
+err5:
+ clk_disable(pcm->pclk);
+ clk_put(pcm->pclk);
+err4:
+ iounmap(pcm->regs);
+err3:
+ release_mem_region(mem_res->start, resource_size(mem_res));
+err2:
+ clk_disable(pcm->cclk);
+ clk_put(pcm->cclk);
+err1:
+ return ret;
+}
+
+static __devexit int s3c_pcm_dev_remove(struct platform_device *pdev)
+{
+ struct s3c_pcm_info *pcm = &s3c_pcm[pdev->id];
+ struct resource *mem_res;
+
+ snd_soc_unregister_dai(&pdev->dev);
+
+ iounmap(pcm->regs);
+
+ mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ release_mem_region(mem_res->start, resource_size(mem_res));
+
+ clk_disable(pcm->cclk);
+ clk_disable(pcm->pclk);
+ clk_put(pcm->pclk);
+ clk_put(pcm->cclk);
+
+ return 0;
+}
+
+static struct platform_driver s3c_pcm_driver = {
+ .probe = s3c_pcm_dev_probe,
+ .remove = s3c_pcm_dev_remove,
+ .driver = {
+ .name = "samsung-pcm",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init s3c_pcm_init(void)
+{
+ return platform_driver_register(&s3c_pcm_driver);
+}
+module_init(s3c_pcm_init);
+
+static void __exit s3c_pcm_exit(void)
+{
+ platform_driver_unregister(&s3c_pcm_driver);
+}
+module_exit(s3c_pcm_exit);
+
+/* Module information */
+MODULE_AUTHOR("Jaswinder Singh, <jassi.brar(a)samsung.com>");
+MODULE_DESCRIPTION("S3C PCM Controller Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:samsung-pcm");
diff --git a/sound/soc/s3c24xx/pcm.h b/sound/soc/s3c24xx/pcm.h
new file mode 100644
index 0000000..3775216
--- /dev/null
+++ b/sound/soc/s3c24xx/pcm.h
@@ -0,0 +1,124 @@
+/* sound/soc/s3c24xx/pcm.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef __S3C_PCM_H
+#define __S3C_PCM_H __FILE__
+
+/*Register Offsets */
+#define S3C_PCM_CTL (0x00)
+#define S3C_PCM_CLKCTL (0x04)
+#define S3C_PCM_TXFIFO (0x08)
+#define S3C_PCM_RXFIFO (0x0C)
+#define S3C_PCM_IRQCTL (0x10)
+#define S3C_PCM_IRQSTAT (0x14)
+#define S3C_PCM_FIFOSTAT (0x18)
+#define S3C_PCM_CLRINT (0x20)
+
+/* PCM_CTL Bit-Fields */
+#define S3C_PCM_CTL_TXDIPSTICK_MASK (0x3f)
+#define S3C_PCM_CTL_TXDIPSTICK_SHIFT (13)
+#define S3C_PCM_CTL_RXDIPSTICK_MASK (0x3f)
+#define S3C_PCM_CTL_RXDIPSTICK_SHIFT (7)
+#define S3C_PCM_CTL_TXDMA_EN (0x1<<6)
+#define S3C_PCM_CTL_RXDMA_EN (0x1<<5)
+#define S3C_PCM_CTL_TXMSB_AFTER_FSYNC (0x1<<4)
+#define S3C_PCM_CTL_RXMSB_AFTER_FSYNC (0x1<<3)
+#define S3C_PCM_CTL_TXFIFO_EN (0x1<<2)
+#define S3C_PCM_CTL_RXFIFO_EN (0x1<<1)
+#define S3C_PCM_CTL_ENABLE (0x1<<0)
+
+/* PCM_CLKCTL Bit-Fields */
+#define S3C_PCM_CLKCTL_SERCLK_EN (0x1<<19)
+#define S3C_PCM_CLKCTL_SERCLKSEL_PCLK (0x1<<18)
+#define S3C_PCM_CLKCTL_SCLKDIV_MASK (0x1ff)
+#define S3C_PCM_CLKCTL_SYNCDIV_MASK (0x1ff)
+#define S3C_PCM_CLKCTL_SCLKDIV_SHIFT (9)
+#define S3C_PCM_CLKCTL_SYNCDIV_SHIFT (0)
+
+/* PCM_TXFIFO Bit-Fields */
+#define S3C_PCM_TXFIFO_DVALID (0x1<<16)
+#define S3C_PCM_TXFIFO_DATA_MSK (0xffff<<0)
+
+/* PCM_RXFIFO Bit-Fields */
+#define S3C_PCM_RXFIFO_DVALID (0x1<<16)
+#define S3C_PCM_RXFIFO_DATA_MSK (0xffff<<0)
+
+/* PCM_IRQCTL Bit-Fields */
+#define S3C_PCM_IRQCTL_IRQEN (0x1<<14)
+#define S3C_PCM_IRQCTL_WRDEN (0x1<<12)
+#define S3C_PCM_IRQCTL_TXEMPTYEN (0x1<<11)
+#define S3C_PCM_IRQCTL_TXALMSTEMPTYEN (0x1<<10)
+#define S3C_PCM_IRQCTL_TXFULLEN (0x1<<9)
+#define S3C_PCM_IRQCTL_TXALMSTFULLEN (0x1<<8)
+#define S3C_PCM_IRQCTL_TXSTARVEN (0x1<<7)
+#define S3C_PCM_IRQCTL_TXERROVRFLEN (0x1<<6)
+#define S3C_PCM_IRQCTL_RXEMPTEN (0x1<<5)
+#define S3C_PCM_IRQCTL_RXALMSTEMPTEN (0x1<<4)
+#define S3C_PCM_IRQCTL_RXFULLEN (0x1<<3)
+#define S3C_PCM_IRQCTL_RXALMSTFULLEN (0x1<<2)
+#define S3C_PCM_IRQCTL_RXSTARVEN (0x1<<1)
+#define S3C_PCM_IRQCTL_RXERROVRFLEN (0x1<<0)
+
+/* PCM_IRQSTAT Bit-Fields */
+#define S3C_PCM_IRQSTAT_IRQPND (0x1<<13)
+#define S3C_PCM_IRQSTAT_WRD_XFER (0x1<<12)
+#define S3C_PCM_IRQSTAT_TXEMPTY (0x1<<11)
+#define S3C_PCM_IRQSTAT_TXALMSTEMPTY (0x1<<10)
+#define S3C_PCM_IRQSTAT_TXFULL (0x1<<9)
+#define S3C_PCM_IRQSTAT_TXALMSTFULL (0x1<<8)
+#define S3C_PCM_IRQSTAT_TXSTARV (0x1<<7)
+#define S3C_PCM_IRQSTAT_TXERROVRFL (0x1<<6)
+#define S3C_PCM_IRQSTAT_RXEMPT (0x1<<5)
+#define S3C_PCM_IRQSTAT_RXALMSTEMPT (0x1<<4)
+#define S3C_PCM_IRQSTAT_RXFULL (0x1<<3)
+#define S3C_PCM_IRQSTAT_RXALMSTFULL (0x1<<2)
+#define S3C_PCM_IRQSTAT_RXSTARV (0x1<<1)
+#define S3C_PCM_IRQSTAT_RXERROVRFL (0x1<<0)
+
+/* PCM_FIFOSTAT Bit-Fields */
+#define S3C_PCM_FIFOSTAT_TXCNT_MSK (0x3f<<14)
+#define S3C_PCM_FIFOSTAT_TXFIFOEMPTY (0x1<<13)
+#define S3C_PCM_FIFOSTAT_TXFIFOALMSTEMPTY (0x1<<12)
+#define S3C_PCM_FIFOSTAT_TXFIFOFULL (0x1<<11)
+#define S3C_PCM_FIFOSTAT_TXFIFOALMSTFULL (0x1<<10)
+#define S3C_PCM_FIFOSTAT_RXCNT_MSK (0x3f<<4)
+#define S3C_PCM_FIFOSTAT_RXFIFOEMPTY (0x1<<3)
+#define S3C_PCM_FIFOSTAT_RXFIFOALMSTEMPTY (0x1<<2)
+#define S3C_PCM_FIFOSTAT_RXFIFOFULL (0x1<<1)
+#define S3C_PCM_FIFOSTAT_RXFIFOALMSTFULL (0x1<<0)
+
+#define S3C_PCM_CLKSRC_PCLK 0
+#define S3C_PCM_CLKSRC_MUX 1
+
+#define S3C_PCM_SCLK_PER_FS 0
+
+/**
+ * struct s3c_pcm_info - S3C PCM Controller information
+ * @dev: The parent device passed to use from the probe.
+ * @regs: The pointer to the device register block.
+ * @dma_playback: DMA information for playback channel.
+ * @dma_capture: DMA information for capture channel.
+ */
+struct s3c_pcm_info {
+ spinlock_t lock;
+ struct device *dev;
+ void __iomem *regs;
+
+ unsigned int sclk_per_fs;
+
+ /* Whether to keep PCMSCLK enabled even when idle(no active xfer) */
+ unsigned int idleclk;
+
+ struct clk *pclk;
+ struct clk *cclk;
+
+ struct s3c_dma_params *dma_playback;
+ struct s3c_dma_params *dma_capture;
+};
+
+#endif /* __S3C_PCM_H */
diff --git a/sound/soc/s3c24xx/s3c-pcm.c b/sound/soc/s3c24xx/s3c-pcm.c
deleted file mode 100644
index e111d23..0000000
--- a/sound/soc/s3c24xx/s3c-pcm.c
+++ /dev/null
@@ -1,552 +0,0 @@
-/* sound/soc/s3c24xx/s3c-pcm.c
- *
- * ALSA SoC Audio Layer - S3C PCM-Controller driver
- *
- * Copyright (c) 2009 Samsung Electronics Co. Ltd
- * Author: Jaswinder Singh <jassi.brar(a)samsung.com>
- * based upon I2S drivers by Ben Dooks.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/delay.h>
-#include <linux/clk.h>
-#include <linux/kernel.h>
-#include <linux/gpio.h>
-#include <linux/io.h>
-
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/initval.h>
-#include <sound/soc.h>
-
-#include <plat/audio.h>
-#include <plat/dma.h>
-
-#include "dma.h"
-#include "s3c-pcm.h"
-
-static struct s3c2410_dma_client s3c_pcm_dma_client_out = {
- .name = "PCM Stereo out"
-};
-
-static struct s3c2410_dma_client s3c_pcm_dma_client_in = {
- .name = "PCM Stereo in"
-};
-
-static struct s3c_dma_params s3c_pcm_stereo_out[] = {
- [0] = {
- .client = &s3c_pcm_dma_client_out,
- .dma_size = 4,
- },
- [1] = {
- .client = &s3c_pcm_dma_client_out,
- .dma_size = 4,
- },
-};
-
-static struct s3c_dma_params s3c_pcm_stereo_in[] = {
- [0] = {
- .client = &s3c_pcm_dma_client_in,
- .dma_size = 4,
- },
- [1] = {
- .client = &s3c_pcm_dma_client_in,
- .dma_size = 4,
- },
-};
-
-static struct s3c_pcm_info s3c_pcm[2];
-
-static void s3c_pcm_snd_txctrl(struct s3c_pcm_info *pcm, int on)
-{
- void __iomem *regs = pcm->regs;
- u32 ctl, clkctl;
-
- clkctl = readl(regs + S3C_PCM_CLKCTL);
- ctl = readl(regs + S3C_PCM_CTL);
- ctl &= ~(S3C_PCM_CTL_TXDIPSTICK_MASK
- << S3C_PCM_CTL_TXDIPSTICK_SHIFT);
-
- if (on) {
- ctl |= S3C_PCM_CTL_TXDMA_EN;
- ctl |= S3C_PCM_CTL_TXFIFO_EN;
- ctl |= S3C_PCM_CTL_ENABLE;
- ctl |= (0x4<<S3C_PCM_CTL_TXDIPSTICK_SHIFT);
- clkctl |= S3C_PCM_CLKCTL_SERCLK_EN;
- } else {
- ctl &= ~S3C_PCM_CTL_TXDMA_EN;
- ctl &= ~S3C_PCM_CTL_TXFIFO_EN;
-
- if (!(ctl & S3C_PCM_CTL_RXFIFO_EN)) {
- ctl &= ~S3C_PCM_CTL_ENABLE;
- if (!pcm->idleclk)
- clkctl |= S3C_PCM_CLKCTL_SERCLK_EN;
- }
- }
-
- writel(clkctl, regs + S3C_PCM_CLKCTL);
- writel(ctl, regs + S3C_PCM_CTL);
-}
-
-static void s3c_pcm_snd_rxctrl(struct s3c_pcm_info *pcm, int on)
-{
- void __iomem *regs = pcm->regs;
- u32 ctl, clkctl;
-
- ctl = readl(regs + S3C_PCM_CTL);
- clkctl = readl(regs + S3C_PCM_CLKCTL);
- ctl &= ~(S3C_PCM_CTL_RXDIPSTICK_MASK
- << S3C_PCM_CTL_RXDIPSTICK_SHIFT);
-
- if (on) {
- ctl |= S3C_PCM_CTL_RXDMA_EN;
- ctl |= S3C_PCM_CTL_RXFIFO_EN;
- ctl |= S3C_PCM_CTL_ENABLE;
- ctl |= (0x20<<S3C_PCM_CTL_RXDIPSTICK_SHIFT);
- clkctl |= S3C_PCM_CLKCTL_SERCLK_EN;
- } else {
- ctl &= ~S3C_PCM_CTL_RXDMA_EN;
- ctl &= ~S3C_PCM_CTL_RXFIFO_EN;
-
- if (!(ctl & S3C_PCM_CTL_TXFIFO_EN)) {
- ctl &= ~S3C_PCM_CTL_ENABLE;
- if (!pcm->idleclk)
- clkctl |= S3C_PCM_CLKCTL_SERCLK_EN;
- }
- }
-
- writel(clkctl, regs + S3C_PCM_CLKCTL);
- writel(ctl, regs + S3C_PCM_CTL);
-}
-
-static int s3c_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
- struct snd_soc_dai *dai)
-{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(rtd->cpu_dai);
- unsigned long flags;
-
- dev_dbg(pcm->dev, "Entered %s\n", __func__);
-
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
- case SNDRV_PCM_TRIGGER_RESUME:
- case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- spin_lock_irqsave(&pcm->lock, flags);
-
- if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
- s3c_pcm_snd_rxctrl(pcm, 1);
- else
- s3c_pcm_snd_txctrl(pcm, 1);
-
- spin_unlock_irqrestore(&pcm->lock, flags);
- break;
-
- case SNDRV_PCM_TRIGGER_STOP:
- case SNDRV_PCM_TRIGGER_SUSPEND:
- case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- spin_lock_irqsave(&pcm->lock, flags);
-
- if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
- s3c_pcm_snd_rxctrl(pcm, 0);
- else
- s3c_pcm_snd_txctrl(pcm, 0);
-
- spin_unlock_irqrestore(&pcm->lock, flags);
- break;
-
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int s3c_pcm_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params,
- struct snd_soc_dai *socdai)
-{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(rtd->cpu_dai);
- struct s3c_dma_params *dma_data;
- void __iomem *regs = pcm->regs;
- struct clk *clk;
- int sclk_div, sync_div;
- unsigned long flags;
- u32 clkctl;
-
- dev_dbg(pcm->dev, "Entered %s\n", __func__);
-
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- dma_data = pcm->dma_playback;
- else
- dma_data = pcm->dma_capture;
-
- snd_soc_dai_set_dma_data(rtd->cpu_dai, substream, dma_data);
-
- /* Strictly check for sample size */
- switch (params_format(params)) {
- case SNDRV_PCM_FORMAT_S16_LE:
- break;
- default:
- return -EINVAL;
- }
-
- spin_lock_irqsave(&pcm->lock, flags);
-
- /* Get hold of the PCMSOURCE_CLK */
- clkctl = readl(regs + S3C_PCM_CLKCTL);
- if (clkctl & S3C_PCM_CLKCTL_SERCLKSEL_PCLK)
- clk = pcm->pclk;
- else
- clk = pcm->cclk;
-
- /* Set the SCLK divider */
- sclk_div = clk_get_rate(clk) / pcm->sclk_per_fs /
- params_rate(params) / 2 - 1;
-
- clkctl &= ~(S3C_PCM_CLKCTL_SCLKDIV_MASK
- << S3C_PCM_CLKCTL_SCLKDIV_SHIFT);
- clkctl |= ((sclk_div & S3C_PCM_CLKCTL_SCLKDIV_MASK)
- << S3C_PCM_CLKCTL_SCLKDIV_SHIFT);
-
- /* Set the SYNC divider */
- sync_div = pcm->sclk_per_fs - 1;
-
- clkctl &= ~(S3C_PCM_CLKCTL_SYNCDIV_MASK
- << S3C_PCM_CLKCTL_SYNCDIV_SHIFT);
- clkctl |= ((sync_div & S3C_PCM_CLKCTL_SYNCDIV_MASK)
- << S3C_PCM_CLKCTL_SYNCDIV_SHIFT);
-
- writel(clkctl, regs + S3C_PCM_CLKCTL);
-
- spin_unlock_irqrestore(&pcm->lock, flags);
-
- dev_dbg(pcm->dev, "PCMSOURCE_CLK-%lu SCLK=%ufs SCLK_DIV=%d SYNC_DIV=%d\n",
- clk_get_rate(clk), pcm->sclk_per_fs,
- sclk_div, sync_div);
-
- return 0;
-}
-
-static int s3c_pcm_set_fmt(struct snd_soc_dai *cpu_dai,
- unsigned int fmt)
-{
- struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(cpu_dai);
- void __iomem *regs = pcm->regs;
- unsigned long flags;
- int ret = 0;
- u32 ctl;
-
- dev_dbg(pcm->dev, "Entered %s\n", __func__);
-
- spin_lock_irqsave(&pcm->lock, flags);
-
- ctl = readl(regs + S3C_PCM_CTL);
-
- switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
- case SND_SOC_DAIFMT_NB_NF:
- /* Nothing to do, NB_NF by default */
- break;
- default:
- dev_err(pcm->dev, "Unsupported clock inversion!\n");
- ret = -EINVAL;
- goto exit;
- }
-
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFS:
- /* Nothing to do, Master by default */
- break;
- default:
- dev_err(pcm->dev, "Unsupported master/slave format!\n");
- ret = -EINVAL;
- goto exit;
- }
-
- switch (fmt & SND_SOC_DAIFMT_CLOCK_MASK) {
- case SND_SOC_DAIFMT_CONT:
- pcm->idleclk = 1;
- break;
- case SND_SOC_DAIFMT_GATED:
- pcm->idleclk = 0;
- break;
- default:
- dev_err(pcm->dev, "Invalid Clock gating request!\n");
- ret = -EINVAL;
- goto exit;
- }
-
- switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
- case SND_SOC_DAIFMT_DSP_A:
- ctl |= S3C_PCM_CTL_TXMSB_AFTER_FSYNC;
- ctl |= S3C_PCM_CTL_RXMSB_AFTER_FSYNC;
- break;
- case SND_SOC_DAIFMT_DSP_B:
- ctl &= ~S3C_PCM_CTL_TXMSB_AFTER_FSYNC;
- ctl &= ~S3C_PCM_CTL_RXMSB_AFTER_FSYNC;
- break;
- default:
- dev_err(pcm->dev, "Unsupported data format!\n");
- ret = -EINVAL;
- goto exit;
- }
-
- writel(ctl, regs + S3C_PCM_CTL);
-
-exit:
- spin_unlock_irqrestore(&pcm->lock, flags);
-
- return ret;
-}
-
-static int s3c_pcm_set_clkdiv(struct snd_soc_dai *cpu_dai,
- int div_id, int div)
-{
- struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(cpu_dai);
-
- switch (div_id) {
- case S3C_PCM_SCLK_PER_FS:
- pcm->sclk_per_fs = div;
- break;
-
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int s3c_pcm_set_sysclk(struct snd_soc_dai *cpu_dai,
- int clk_id, unsigned int freq, int dir)
-{
- struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(cpu_dai);
- void __iomem *regs = pcm->regs;
- u32 clkctl = readl(regs + S3C_PCM_CLKCTL);
-
- switch (clk_id) {
- case S3C_PCM_CLKSRC_PCLK:
- clkctl |= S3C_PCM_CLKCTL_SERCLKSEL_PCLK;
- break;
-
- case S3C_PCM_CLKSRC_MUX:
- clkctl &= ~S3C_PCM_CLKCTL_SERCLKSEL_PCLK;
-
- if (clk_get_rate(pcm->cclk) != freq)
- clk_set_rate(pcm->cclk, freq);
-
- break;
-
- default:
- return -EINVAL;
- }
-
- writel(clkctl, regs + S3C_PCM_CLKCTL);
-
- return 0;
-}
-
-static struct snd_soc_dai_ops s3c_pcm_dai_ops = {
- .set_sysclk = s3c_pcm_set_sysclk,
- .set_clkdiv = s3c_pcm_set_clkdiv,
- .trigger = s3c_pcm_trigger,
- .hw_params = s3c_pcm_hw_params,
- .set_fmt = s3c_pcm_set_fmt,
-};
-
-#define S3C_PCM_RATES SNDRV_PCM_RATE_8000_96000
-
-#define S3C_PCM_DAI_DECLARE \
- .symmetric_rates = 1, \
- .ops = &s3c_pcm_dai_ops, \
- .playback = { \
- .channels_min = 2, \
- .channels_max = 2, \
- .rates = S3C_PCM_RATES, \
- .formats = SNDRV_PCM_FMTBIT_S16_LE, \
- }, \
- .capture = { \
- .channels_min = 2, \
- .channels_max = 2, \
- .rates = S3C_PCM_RATES, \
- .formats = SNDRV_PCM_FMTBIT_S16_LE, \
- }
-
-struct snd_soc_dai_driver s3c_pcm_dai[] = {
- [0] = {
- .name = "samsung-pcm.0",
- S3C_PCM_DAI_DECLARE,
- },
- [1] = {
- .name = "samsung-pcm.1",
- S3C_PCM_DAI_DECLARE,
- },
-};
-EXPORT_SYMBOL_GPL(s3c_pcm_dai);
-
-static __devinit int s3c_pcm_dev_probe(struct platform_device *pdev)
-{
- struct s3c_pcm_info *pcm;
- struct resource *mem_res, *dmatx_res, *dmarx_res;
- struct s3c_audio_pdata *pcm_pdata;
- int ret;
-
- /* Check for valid device index */
- if ((pdev->id < 0) || pdev->id >= ARRAY_SIZE(s3c_pcm)) {
- dev_err(&pdev->dev, "id %d out of range\n", pdev->id);
- return -EINVAL;
- }
-
- pcm_pdata = pdev->dev.platform_data;
-
- /* Check for availability of necessary resource */
- dmatx_res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
- if (!dmatx_res) {
- dev_err(&pdev->dev, "Unable to get PCM-TX dma resource\n");
- return -ENXIO;
- }
-
- dmarx_res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
- if (!dmarx_res) {
- dev_err(&pdev->dev, "Unable to get PCM-RX dma resource\n");
- return -ENXIO;
- }
-
- mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!mem_res) {
- dev_err(&pdev->dev, "Unable to get register resource\n");
- return -ENXIO;
- }
-
- if (pcm_pdata && pcm_pdata->cfg_gpio && pcm_pdata->cfg_gpio(pdev)) {
- dev_err(&pdev->dev, "Unable to configure gpio\n");
- return -EINVAL;
- }
-
- pcm = &s3c_pcm[pdev->id];
- pcm->dev = &pdev->dev;
-
- spin_lock_init(&pcm->lock);
-
- /* Default is 128fs */
- pcm->sclk_per_fs = 128;
-
- pcm->cclk = clk_get(&pdev->dev, "audio-bus");
- if (IS_ERR(pcm->cclk)) {
- dev_err(&pdev->dev, "failed to get audio-bus\n");
- ret = PTR_ERR(pcm->cclk);
- goto err1;
- }
- clk_enable(pcm->cclk);
-
- /* record our pcm structure for later use in the callbacks */
- dev_set_drvdata(&pdev->dev, pcm);
-
- if (!request_mem_region(mem_res->start,
- resource_size(mem_res), "samsung-pcm")) {
- dev_err(&pdev->dev, "Unable to request register region\n");
- ret = -EBUSY;
- goto err2;
- }
-
- pcm->regs = ioremap(mem_res->start, 0x100);
- if (pcm->regs == NULL) {
- dev_err(&pdev->dev, "cannot ioremap registers\n");
- ret = -ENXIO;
- goto err3;
- }
-
- pcm->pclk = clk_get(&pdev->dev, "pcm");
- if (IS_ERR(pcm->pclk)) {
- dev_err(&pdev->dev, "failed to get pcm_clock\n");
- ret = -ENOENT;
- goto err4;
- }
- clk_enable(pcm->pclk);
-
- ret = snd_soc_register_dai(&pdev->dev, &s3c_pcm_dai[pdev->id]);
- if (ret != 0) {
- dev_err(&pdev->dev, "failed to get pcm_clock\n");
- goto err5;
- }
-
- s3c_pcm_stereo_in[pdev->id].dma_addr = mem_res->start
- + S3C_PCM_RXFIFO;
- s3c_pcm_stereo_out[pdev->id].dma_addr = mem_res->start
- + S3C_PCM_TXFIFO;
-
- s3c_pcm_stereo_in[pdev->id].channel = dmarx_res->start;
- s3c_pcm_stereo_out[pdev->id].channel = dmatx_res->start;
-
- pcm->dma_capture = &s3c_pcm_stereo_in[pdev->id];
- pcm->dma_playback = &s3c_pcm_stereo_out[pdev->id];
-
- return 0;
-
-err5:
- clk_disable(pcm->pclk);
- clk_put(pcm->pclk);
-err4:
- iounmap(pcm->regs);
-err3:
- release_mem_region(mem_res->start, resource_size(mem_res));
-err2:
- clk_disable(pcm->cclk);
- clk_put(pcm->cclk);
-err1:
- return ret;
-}
-
-static __devexit int s3c_pcm_dev_remove(struct platform_device *pdev)
-{
- struct s3c_pcm_info *pcm = &s3c_pcm[pdev->id];
- struct resource *mem_res;
-
- snd_soc_unregister_dai(&pdev->dev);
-
- iounmap(pcm->regs);
-
- mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- release_mem_region(mem_res->start, resource_size(mem_res));
-
- clk_disable(pcm->cclk);
- clk_disable(pcm->pclk);
- clk_put(pcm->pclk);
- clk_put(pcm->cclk);
-
- return 0;
-}
-
-static struct platform_driver s3c_pcm_driver = {
- .probe = s3c_pcm_dev_probe,
- .remove = s3c_pcm_dev_remove,
- .driver = {
- .name = "samsung-pcm",
- .owner = THIS_MODULE,
- },
-};
-
-static int __init s3c_pcm_init(void)
-{
- return platform_driver_register(&s3c_pcm_driver);
-}
-module_init(s3c_pcm_init);
-
-static void __exit s3c_pcm_exit(void)
-{
- platform_driver_unregister(&s3c_pcm_driver);
-}
-module_exit(s3c_pcm_exit);
-
-/* Module information */
-MODULE_AUTHOR("Jaswinder Singh, <jassi.brar(a)samsung.com>");
-MODULE_DESCRIPTION("S3C PCM Controller Driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:samsung-pcm");
diff --git a/sound/soc/s3c24xx/s3c-pcm.h b/sound/soc/s3c24xx/s3c-pcm.h
deleted file mode 100644
index f60baa1..0000000
--- a/sound/soc/s3c24xx/s3c-pcm.h
+++ /dev/null
@@ -1,124 +0,0 @@
-/* sound/soc/s3c24xx/s3c-pcm.h
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- */
-
-#ifndef __S3C_PCM_H
-#define __S3C_PCM_H __FILE__
-
-/*Register Offsets */
-#define S3C_PCM_CTL (0x00)
-#define S3C_PCM_CLKCTL (0x04)
-#define S3C_PCM_TXFIFO (0x08)
-#define S3C_PCM_RXFIFO (0x0C)
-#define S3C_PCM_IRQCTL (0x10)
-#define S3C_PCM_IRQSTAT (0x14)
-#define S3C_PCM_FIFOSTAT (0x18)
-#define S3C_PCM_CLRINT (0x20)
-
-/* PCM_CTL Bit-Fields */
-#define S3C_PCM_CTL_TXDIPSTICK_MASK (0x3f)
-#define S3C_PCM_CTL_TXDIPSTICK_SHIFT (13)
-#define S3C_PCM_CTL_RXDIPSTICK_MASK (0x3f)
-#define S3C_PCM_CTL_RXDIPSTICK_SHIFT (7)
-#define S3C_PCM_CTL_TXDMA_EN (0x1<<6)
-#define S3C_PCM_CTL_RXDMA_EN (0x1<<5)
-#define S3C_PCM_CTL_TXMSB_AFTER_FSYNC (0x1<<4)
-#define S3C_PCM_CTL_RXMSB_AFTER_FSYNC (0x1<<3)
-#define S3C_PCM_CTL_TXFIFO_EN (0x1<<2)
-#define S3C_PCM_CTL_RXFIFO_EN (0x1<<1)
-#define S3C_PCM_CTL_ENABLE (0x1<<0)
-
-/* PCM_CLKCTL Bit-Fields */
-#define S3C_PCM_CLKCTL_SERCLK_EN (0x1<<19)
-#define S3C_PCM_CLKCTL_SERCLKSEL_PCLK (0x1<<18)
-#define S3C_PCM_CLKCTL_SCLKDIV_MASK (0x1ff)
-#define S3C_PCM_CLKCTL_SYNCDIV_MASK (0x1ff)
-#define S3C_PCM_CLKCTL_SCLKDIV_SHIFT (9)
-#define S3C_PCM_CLKCTL_SYNCDIV_SHIFT (0)
-
-/* PCM_TXFIFO Bit-Fields */
-#define S3C_PCM_TXFIFO_DVALID (0x1<<16)
-#define S3C_PCM_TXFIFO_DATA_MSK (0xffff<<0)
-
-/* PCM_RXFIFO Bit-Fields */
-#define S3C_PCM_RXFIFO_DVALID (0x1<<16)
-#define S3C_PCM_RXFIFO_DATA_MSK (0xffff<<0)
-
-/* PCM_IRQCTL Bit-Fields */
-#define S3C_PCM_IRQCTL_IRQEN (0x1<<14)
-#define S3C_PCM_IRQCTL_WRDEN (0x1<<12)
-#define S3C_PCM_IRQCTL_TXEMPTYEN (0x1<<11)
-#define S3C_PCM_IRQCTL_TXALMSTEMPTYEN (0x1<<10)
-#define S3C_PCM_IRQCTL_TXFULLEN (0x1<<9)
-#define S3C_PCM_IRQCTL_TXALMSTFULLEN (0x1<<8)
-#define S3C_PCM_IRQCTL_TXSTARVEN (0x1<<7)
-#define S3C_PCM_IRQCTL_TXERROVRFLEN (0x1<<6)
-#define S3C_PCM_IRQCTL_RXEMPTEN (0x1<<5)
-#define S3C_PCM_IRQCTL_RXALMSTEMPTEN (0x1<<4)
-#define S3C_PCM_IRQCTL_RXFULLEN (0x1<<3)
-#define S3C_PCM_IRQCTL_RXALMSTFULLEN (0x1<<2)
-#define S3C_PCM_IRQCTL_RXSTARVEN (0x1<<1)
-#define S3C_PCM_IRQCTL_RXERROVRFLEN (0x1<<0)
-
-/* PCM_IRQSTAT Bit-Fields */
-#define S3C_PCM_IRQSTAT_IRQPND (0x1<<13)
-#define S3C_PCM_IRQSTAT_WRD_XFER (0x1<<12)
-#define S3C_PCM_IRQSTAT_TXEMPTY (0x1<<11)
-#define S3C_PCM_IRQSTAT_TXALMSTEMPTY (0x1<<10)
-#define S3C_PCM_IRQSTAT_TXFULL (0x1<<9)
-#define S3C_PCM_IRQSTAT_TXALMSTFULL (0x1<<8)
-#define S3C_PCM_IRQSTAT_TXSTARV (0x1<<7)
-#define S3C_PCM_IRQSTAT_TXERROVRFL (0x1<<6)
-#define S3C_PCM_IRQSTAT_RXEMPT (0x1<<5)
-#define S3C_PCM_IRQSTAT_RXALMSTEMPT (0x1<<4)
-#define S3C_PCM_IRQSTAT_RXFULL (0x1<<3)
-#define S3C_PCM_IRQSTAT_RXALMSTFULL (0x1<<2)
-#define S3C_PCM_IRQSTAT_RXSTARV (0x1<<1)
-#define S3C_PCM_IRQSTAT_RXERROVRFL (0x1<<0)
-
-/* PCM_FIFOSTAT Bit-Fields */
-#define S3C_PCM_FIFOSTAT_TXCNT_MSK (0x3f<<14)
-#define S3C_PCM_FIFOSTAT_TXFIFOEMPTY (0x1<<13)
-#define S3C_PCM_FIFOSTAT_TXFIFOALMSTEMPTY (0x1<<12)
-#define S3C_PCM_FIFOSTAT_TXFIFOFULL (0x1<<11)
-#define S3C_PCM_FIFOSTAT_TXFIFOALMSTFULL (0x1<<10)
-#define S3C_PCM_FIFOSTAT_RXCNT_MSK (0x3f<<4)
-#define S3C_PCM_FIFOSTAT_RXFIFOEMPTY (0x1<<3)
-#define S3C_PCM_FIFOSTAT_RXFIFOALMSTEMPTY (0x1<<2)
-#define S3C_PCM_FIFOSTAT_RXFIFOFULL (0x1<<1)
-#define S3C_PCM_FIFOSTAT_RXFIFOALMSTFULL (0x1<<0)
-
-#define S3C_PCM_CLKSRC_PCLK 0
-#define S3C_PCM_CLKSRC_MUX 1
-
-#define S3C_PCM_SCLK_PER_FS 0
-
-/**
- * struct s3c_pcm_info - S3C PCM Controller information
- * @dev: The parent device passed to use from the probe.
- * @regs: The pointer to the device register block.
- * @dma_playback: DMA information for playback channel.
- * @dma_capture: DMA information for capture channel.
- */
-struct s3c_pcm_info {
- spinlock_t lock;
- struct device *dev;
- void __iomem *regs;
-
- unsigned int sclk_per_fs;
-
- /* Whether to keep PCMSCLK enabled even when idle(no active xfer) */
- unsigned int idleclk;
-
- struct clk *pclk;
- struct clk *cclk;
-
- struct s3c_dma_params *dma_playback;
- struct s3c_dma_params *dma_capture;
-};
-
-#endif /* __S3C_PCM_H */
--
1.6.2.5
1
0
From: Jassi Brar <jassi.brar(a)samsung.com>
Rename Samsung AC97 driver
s3c-ac97.[c/h] -> ac97.[c/h]
Signed-off-by: Jassi Brar <jassi.brar(a)samsung.com>
---
sound/soc/s3c24xx/Makefile | 4 +-
sound/soc/s3c24xx/ac97.c | 520 ++++++++++++++++++++++++++++++++++
sound/soc/s3c24xx/ac97.h | 21 ++
sound/soc/s3c24xx/ln2440sbc_alc650.c | 2 +-
sound/soc/s3c24xx/s3c-ac97.c | 520 ----------------------------------
sound/soc/s3c24xx/s3c-ac97.h | 21 --
sound/soc/s3c24xx/smdk2443_wm9710.c | 2 +-
sound/soc/s3c24xx/smdk_wm9713.c | 2 +-
8 files changed, 546 insertions(+), 546 deletions(-)
create mode 100644 sound/soc/s3c24xx/ac97.c
create mode 100644 sound/soc/s3c24xx/ac97.h
delete mode 100644 sound/soc/s3c24xx/s3c-ac97.c
delete mode 100644 sound/soc/s3c24xx/s3c-ac97.h
diff --git a/sound/soc/s3c24xx/Makefile b/sound/soc/s3c24xx/Makefile
index 20aac45..551a63d 100644
--- a/sound/soc/s3c24xx/Makefile
+++ b/sound/soc/s3c24xx/Makefile
@@ -3,7 +3,7 @@ snd-soc-s3c24xx-objs := dma.o
snd-soc-s3c24xx-i2s-objs := s3c24xx-i2s.o
snd-soc-s3c2412-i2s-objs := s3c2412-i2s.o
snd-soc-s3c64xx-i2s-objs := s3c64xx-i2s.o
-snd-soc-s3c-ac97-objs := s3c-ac97.o
+snd-soc-ac97-objs := ac97.o
snd-soc-s3c64xx-i2s-v4-objs := s3c64xx-i2s-v4.o
snd-soc-s3c-i2s-v2-objs := s3c-i2s-v2.o
snd-soc-s3c-pcm-objs := s3c-pcm.o
@@ -11,7 +11,7 @@ snd-soc-samsung-spdif-objs := spdif.o
obj-$(CONFIG_SND_S3C24XX_SOC) += snd-soc-s3c24xx.o
obj-$(CONFIG_SND_S3C24XX_SOC_I2S) += snd-soc-s3c24xx-i2s.o
-obj-$(CONFIG_SND_S3C_SOC_AC97) += snd-soc-s3c-ac97.o
+obj-$(CONFIG_SND_S3C_SOC_AC97) += snd-soc-ac97.o
obj-$(CONFIG_SND_S3C2412_SOC_I2S) += snd-soc-s3c2412-i2s.o
obj-$(CONFIG_SND_S3C64XX_SOC_I2S) += snd-soc-s3c64xx-i2s.o
obj-$(CONFIG_SND_S3C64XX_SOC_I2S_V4) += snd-soc-s3c64xx-i2s-v4.o
diff --git a/sound/soc/s3c24xx/ac97.c b/sound/soc/s3c24xx/ac97.c
new file mode 100644
index 0000000..4f999d1
--- /dev/null
+++ b/sound/soc/s3c24xx/ac97.c
@@ -0,0 +1,520 @@
+/* sound/soc/s3c24xx/ac97.c
+ *
+ * ALSA SoC Audio Layer - S3C AC97 Controller driver
+ * Evolved from s3c2443-ac97.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co. Ltd
+ * Author: Jaswinder Singh <jassi.brar(a)samsung.com>
+ * Credits: Graeme Gregory, Sean Choi
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+
+#include <sound/soc.h>
+
+#include <plat/regs-ac97.h>
+#include <mach/dma.h>
+#include <plat/audio.h>
+
+#include "dma.h"
+#include "ac97.h"
+
+#define AC_CMD_ADDR(x) (x << 16)
+#define AC_CMD_DATA(x) (x & 0xffff)
+
+struct s3c_ac97_info {
+ struct clk *ac97_clk;
+ void __iomem *regs;
+ struct mutex lock;
+ struct completion done;
+};
+static struct s3c_ac97_info s3c_ac97;
+
+static struct s3c2410_dma_client s3c_dma_client_out = {
+ .name = "AC97 PCMOut"
+};
+
+static struct s3c2410_dma_client s3c_dma_client_in = {
+ .name = "AC97 PCMIn"
+};
+
+static struct s3c2410_dma_client s3c_dma_client_micin = {
+ .name = "AC97 MicIn"
+};
+
+static struct s3c_dma_params s3c_ac97_pcm_out = {
+ .client = &s3c_dma_client_out,
+ .dma_size = 4,
+};
+
+static struct s3c_dma_params s3c_ac97_pcm_in = {
+ .client = &s3c_dma_client_in,
+ .dma_size = 4,
+};
+
+static struct s3c_dma_params s3c_ac97_mic_in = {
+ .client = &s3c_dma_client_micin,
+ .dma_size = 4,
+};
+
+static void s3c_ac97_activate(struct snd_ac97 *ac97)
+{
+ u32 ac_glbctrl, stat;
+
+ stat = readl(s3c_ac97.regs + S3C_AC97_GLBSTAT) & 0x7;
+ if (stat == S3C_AC97_GLBSTAT_MAINSTATE_ACTIVE)
+ return; /* Return if already active */
+
+ INIT_COMPLETION(s3c_ac97.done);
+
+ ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
+ ac_glbctrl = S3C_AC97_GLBCTRL_ACLINKON;
+ writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
+ msleep(1);
+
+ ac_glbctrl |= S3C_AC97_GLBCTRL_TRANSFERDATAENABLE;
+ writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
+ msleep(1);
+
+ ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
+ ac_glbctrl |= S3C_AC97_GLBCTRL_CODECREADYIE;
+ writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
+
+ if (!wait_for_completion_timeout(&s3c_ac97.done, HZ))
+ pr_err("AC97: Unable to activate!");
+}
+
+static unsigned short s3c_ac97_read(struct snd_ac97 *ac97,
+ unsigned short reg)
+{
+ u32 ac_glbctrl, ac_codec_cmd;
+ u32 stat, addr, data;
+
+ mutex_lock(&s3c_ac97.lock);
+
+ s3c_ac97_activate(ac97);
+
+ INIT_COMPLETION(s3c_ac97.done);
+
+ ac_codec_cmd = readl(s3c_ac97.regs + S3C_AC97_CODEC_CMD);
+ ac_codec_cmd = S3C_AC97_CODEC_CMD_READ | AC_CMD_ADDR(reg);
+ writel(ac_codec_cmd, s3c_ac97.regs + S3C_AC97_CODEC_CMD);
+
+ udelay(50);
+
+ ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
+ ac_glbctrl |= S3C_AC97_GLBCTRL_CODECREADYIE;
+ writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
+
+ if (!wait_for_completion_timeout(&s3c_ac97.done, HZ))
+ pr_err("AC97: Unable to read!");
+
+ stat = readl(s3c_ac97.regs + S3C_AC97_STAT);
+ addr = (stat >> 16) & 0x7f;
+ data = (stat & 0xffff);
+
+ if (addr != reg)
+ pr_err("ac97: req addr = %02x, rep addr = %02x\n",
+ reg, addr);
+
+ mutex_unlock(&s3c_ac97.lock);
+
+ return (unsigned short)data;
+}
+
+static void s3c_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
+ unsigned short val)
+{
+ u32 ac_glbctrl, ac_codec_cmd;
+
+ mutex_lock(&s3c_ac97.lock);
+
+ s3c_ac97_activate(ac97);
+
+ INIT_COMPLETION(s3c_ac97.done);
+
+ ac_codec_cmd = readl(s3c_ac97.regs + S3C_AC97_CODEC_CMD);
+ ac_codec_cmd = AC_CMD_ADDR(reg) | AC_CMD_DATA(val);
+ writel(ac_codec_cmd, s3c_ac97.regs + S3C_AC97_CODEC_CMD);
+
+ udelay(50);
+
+ ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
+ ac_glbctrl |= S3C_AC97_GLBCTRL_CODECREADYIE;
+ writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
+
+ if (!wait_for_completion_timeout(&s3c_ac97.done, HZ))
+ pr_err("AC97: Unable to write!");
+
+ ac_codec_cmd = readl(s3c_ac97.regs + S3C_AC97_CODEC_CMD);
+ ac_codec_cmd |= S3C_AC97_CODEC_CMD_READ;
+ writel(ac_codec_cmd, s3c_ac97.regs + S3C_AC97_CODEC_CMD);
+
+ mutex_unlock(&s3c_ac97.lock);
+}
+
+static void s3c_ac97_cold_reset(struct snd_ac97 *ac97)
+{
+ pr_debug("AC97: Cold reset\n");
+ writel(S3C_AC97_GLBCTRL_COLDRESET,
+ s3c_ac97.regs + S3C_AC97_GLBCTRL);
+ msleep(1);
+
+ writel(0, s3c_ac97.regs + S3C_AC97_GLBCTRL);
+ msleep(1);
+}
+
+static void s3c_ac97_warm_reset(struct snd_ac97 *ac97)
+{
+ u32 stat;
+
+ stat = readl(s3c_ac97.regs + S3C_AC97_GLBSTAT) & 0x7;
+ if (stat == S3C_AC97_GLBSTAT_MAINSTATE_ACTIVE)
+ return; /* Return if already active */
+
+ pr_debug("AC97: Warm reset\n");
+
+ writel(S3C_AC97_GLBCTRL_WARMRESET, s3c_ac97.regs + S3C_AC97_GLBCTRL);
+ msleep(1);
+
+ writel(0, s3c_ac97.regs + S3C_AC97_GLBCTRL);
+ msleep(1);
+
+ s3c_ac97_activate(ac97);
+}
+
+static irqreturn_t s3c_ac97_irq(int irq, void *dev_id)
+{
+ u32 ac_glbctrl, ac_glbstat;
+
+ ac_glbstat = readl(s3c_ac97.regs + S3C_AC97_GLBSTAT);
+
+ if (ac_glbstat & S3C_AC97_GLBSTAT_CODECREADY) {
+
+ ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
+ ac_glbctrl &= ~S3C_AC97_GLBCTRL_CODECREADYIE;
+ writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
+
+ complete(&s3c_ac97.done);
+ }
+
+ ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
+ ac_glbctrl |= (1<<30); /* Clear interrupt */
+ writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
+
+ return IRQ_HANDLED;
+}
+
+struct snd_ac97_bus_ops soc_ac97_ops = {
+ .read = s3c_ac97_read,
+ .write = s3c_ac97_write,
+ .warm_reset = s3c_ac97_warm_reset,
+ .reset = s3c_ac97_cold_reset,
+};
+EXPORT_SYMBOL_GPL(soc_ac97_ops);
+
+static int s3c_ac97_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_dai *cpu_dai = rtd->cpu_dai;
+ struct s3c_dma_params *dma_data;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ dma_data = &s3c_ac97_pcm_out;
+ else
+ dma_data = &s3c_ac97_pcm_in;
+
+ snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data);
+
+ return 0;
+}
+
+static int s3c_ac97_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *dai)
+{
+ u32 ac_glbctrl;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct s3c_dma_params *dma_data =
+ snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
+
+ ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ ac_glbctrl &= ~S3C_AC97_GLBCTRL_PCMINTM_MASK;
+ else
+ ac_glbctrl &= ~S3C_AC97_GLBCTRL_PCMOUTTM_MASK;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ ac_glbctrl |= S3C_AC97_GLBCTRL_PCMINTM_DMA;
+ else
+ ac_glbctrl |= S3C_AC97_GLBCTRL_PCMOUTTM_DMA;
+ break;
+
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ break;
+ }
+
+ writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
+
+ s3c2410_dma_ctrl(dma_data->channel, S3C2410_DMAOP_STARTED);
+
+ return 0;
+}
+
+static int s3c_ac97_hw_mic_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_dai *cpu_dai = rtd->cpu_dai;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ return -ENODEV;
+ else
+ snd_soc_dai_set_dma_data(cpu_dai, substream, &s3c_ac97_mic_in);
+
+ return 0;
+}
+
+static int s3c_ac97_mic_trigger(struct snd_pcm_substream *substream,
+ int cmd, struct snd_soc_dai *dai)
+{
+ u32 ac_glbctrl;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct s3c_dma_params *dma_data =
+ snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
+
+ ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
+ ac_glbctrl &= ~S3C_AC97_GLBCTRL_MICINTM_MASK;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ ac_glbctrl |= S3C_AC97_GLBCTRL_MICINTM_DMA;
+ break;
+
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ break;
+ }
+
+ writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
+
+ s3c2410_dma_ctrl(dma_data->channel, S3C2410_DMAOP_STARTED);
+
+ return 0;
+}
+
+static struct snd_soc_dai_ops s3c_ac97_dai_ops = {
+ .hw_params = s3c_ac97_hw_params,
+ .trigger = s3c_ac97_trigger,
+};
+
+static struct snd_soc_dai_ops s3c_ac97_mic_dai_ops = {
+ .hw_params = s3c_ac97_hw_mic_params,
+ .trigger = s3c_ac97_mic_trigger,
+};
+
+static struct snd_soc_dai_driver s3c_ac97_dai[] = {
+ [S3C_AC97_DAI_PCM] = {
+ .name = "samsung-ac97",
+ .ac97_control = 1,
+ .playback = {
+ .stream_name = "AC97 Playback",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+ .capture = {
+ .stream_name = "AC97 Capture",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+ .ops = &s3c_ac97_dai_ops,
+ },
+ [S3C_AC97_DAI_MIC] = {
+ .name = "samsung-ac97-mic",
+ .ac97_control = 1,
+ .capture = {
+ .stream_name = "AC97 Mic Capture",
+ .channels_min = 1,
+ .channels_max = 1,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+ .ops = &s3c_ac97_mic_dai_ops,
+ },
+};
+
+static __devinit int s3c_ac97_probe(struct platform_device *pdev)
+{
+ struct resource *mem_res, *dmatx_res, *dmarx_res, *dmamic_res, *irq_res;
+ struct s3c_audio_pdata *ac97_pdata;
+ int ret;
+
+ ac97_pdata = pdev->dev.platform_data;
+ if (!ac97_pdata || !ac97_pdata->cfg_gpio) {
+ dev_err(&pdev->dev, "cfg_gpio callback not provided!\n");
+ return -EINVAL;
+ }
+
+ /* Check for availability of necessary resource */
+ dmatx_res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+ if (!dmatx_res) {
+ dev_err(&pdev->dev, "Unable to get AC97-TX dma resource\n");
+ return -ENXIO;
+ }
+
+ dmarx_res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+ if (!dmarx_res) {
+ dev_err(&pdev->dev, "Unable to get AC97-RX dma resource\n");
+ return -ENXIO;
+ }
+
+ dmamic_res = platform_get_resource(pdev, IORESOURCE_DMA, 2);
+ if (!dmamic_res) {
+ dev_err(&pdev->dev, "Unable to get AC97-MIC dma resource\n");
+ return -ENXIO;
+ }
+
+ mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem_res) {
+ dev_err(&pdev->dev, "Unable to get register resource\n");
+ return -ENXIO;
+ }
+
+ irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!irq_res) {
+ dev_err(&pdev->dev, "AC97 IRQ not provided!\n");
+ return -ENXIO;
+ }
+
+ if (!request_mem_region(mem_res->start,
+ resource_size(mem_res), "ac97")) {
+ dev_err(&pdev->dev, "Unable to request register region\n");
+ return -EBUSY;
+ }
+
+ s3c_ac97_pcm_out.channel = dmatx_res->start;
+ s3c_ac97_pcm_out.dma_addr = mem_res->start + S3C_AC97_PCM_DATA;
+ s3c_ac97_pcm_in.channel = dmarx_res->start;
+ s3c_ac97_pcm_in.dma_addr = mem_res->start + S3C_AC97_PCM_DATA;
+ s3c_ac97_mic_in.channel = dmamic_res->start;
+ s3c_ac97_mic_in.dma_addr = mem_res->start + S3C_AC97_MIC_DATA;
+
+ init_completion(&s3c_ac97.done);
+ mutex_init(&s3c_ac97.lock);
+
+ s3c_ac97.regs = ioremap(mem_res->start, resource_size(mem_res));
+ if (s3c_ac97.regs == NULL) {
+ dev_err(&pdev->dev, "Unable to ioremap register region\n");
+ ret = -ENXIO;
+ goto err1;
+ }
+
+ s3c_ac97.ac97_clk = clk_get(&pdev->dev, "ac97");
+ if (IS_ERR(s3c_ac97.ac97_clk)) {
+ dev_err(&pdev->dev, "ac97 failed to get ac97_clock\n");
+ ret = -ENODEV;
+ goto err2;
+ }
+ clk_enable(s3c_ac97.ac97_clk);
+
+ if (ac97_pdata->cfg_gpio(pdev)) {
+ dev_err(&pdev->dev, "Unable to configure gpio\n");
+ ret = -EINVAL;
+ goto err3;
+ }
+
+ ret = request_irq(irq_res->start, s3c_ac97_irq,
+ IRQF_DISABLED, "AC97", NULL);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "ac97: interrupt request failed.\n");
+ goto err4;
+ }
+
+ ret = snd_soc_register_dais(&pdev->dev, s3c_ac97_dai,
+ ARRAY_SIZE(s3c_ac97_dai));
+ if (ret)
+ goto err5;
+
+ return 0;
+
+err5:
+ free_irq(irq_res->start, NULL);
+err4:
+err3:
+ clk_disable(s3c_ac97.ac97_clk);
+ clk_put(s3c_ac97.ac97_clk);
+err2:
+ iounmap(s3c_ac97.regs);
+err1:
+ release_mem_region(mem_res->start, resource_size(mem_res));
+
+ return ret;
+}
+
+static __devexit int s3c_ac97_remove(struct platform_device *pdev)
+{
+ struct resource *mem_res, *irq_res;
+
+ snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(s3c_ac97_dai));
+
+ irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (irq_res)
+ free_irq(irq_res->start, NULL);
+
+ clk_disable(s3c_ac97.ac97_clk);
+ clk_put(s3c_ac97.ac97_clk);
+
+ iounmap(s3c_ac97.regs);
+
+ mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (mem_res)
+ release_mem_region(mem_res->start, resource_size(mem_res));
+
+ return 0;
+}
+
+static struct platform_driver s3c_ac97_driver = {
+ .probe = s3c_ac97_probe,
+ .remove = s3c_ac97_remove,
+ .driver = {
+ .name = "samsung-ac97",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init s3c_ac97_init(void)
+{
+ return platform_driver_register(&s3c_ac97_driver);
+}
+module_init(s3c_ac97_init);
+
+static void __exit s3c_ac97_exit(void)
+{
+ platform_driver_unregister(&s3c_ac97_driver);
+}
+module_exit(s3c_ac97_exit);
+
+MODULE_AUTHOR("Jaswinder Singh, <jassi.brar(a)samsung.com>");
+MODULE_DESCRIPTION("AC97 driver for the Samsung SoC");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:samsung-ac97");
diff --git a/sound/soc/s3c24xx/ac97.h b/sound/soc/s3c24xx/ac97.h
new file mode 100644
index 0000000..a8f01b7
--- /dev/null
+++ b/sound/soc/s3c24xx/ac97.h
@@ -0,0 +1,21 @@
+/* sound/soc/s3c24xx/ac97.h
+ *
+ * ALSA SoC Audio Layer - S3C AC97 Controller driver
+ * Evolved from s3c2443-ac97.h
+ *
+ * Copyright (c) 2010 Samsung Electronics Co. Ltd
+ * Author: Jaswinder Singh <jassi.brar(a)samsung.com>
+ * Credits: Graeme Gregory, Sean Choi
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __S3C_AC97_H_
+#define __S3C_AC97_H_
+
+#define S3C_AC97_DAI_PCM 0
+#define S3C_AC97_DAI_MIC 1
+
+#endif /* __S3C_AC97_H_ */
diff --git a/sound/soc/s3c24xx/ln2440sbc_alc650.c b/sound/soc/s3c24xx/ln2440sbc_alc650.c
index dda11ac..e507174 100644
--- a/sound/soc/s3c24xx/ln2440sbc_alc650.c
+++ b/sound/soc/s3c24xx/ln2440sbc_alc650.c
@@ -24,7 +24,7 @@
#include <sound/soc-dapm.h>
#include "dma.h"
-#include "s3c-ac97.h"
+#include "ac97.h"
static struct snd_soc_card ln2440sbc;
diff --git a/sound/soc/s3c24xx/s3c-ac97.c b/sound/soc/s3c24xx/s3c-ac97.c
deleted file mode 100644
index 5352cac..0000000
--- a/sound/soc/s3c24xx/s3c-ac97.c
+++ /dev/null
@@ -1,520 +0,0 @@
-/* sound/soc/s3c24xx/s3c-ac97.c
- *
- * ALSA SoC Audio Layer - S3C AC97 Controller driver
- * Evolved from s3c2443-ac97.c
- *
- * Copyright (c) 2010 Samsung Electronics Co. Ltd
- * Author: Jaswinder Singh <jassi.brar(a)samsung.com>
- * Credits: Graeme Gregory, Sean Choi
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/io.h>
-#include <linux/delay.h>
-#include <linux/clk.h>
-
-#include <sound/soc.h>
-
-#include <plat/regs-ac97.h>
-#include <mach/dma.h>
-#include <plat/audio.h>
-
-#include "dma.h"
-#include "s3c-ac97.h"
-
-#define AC_CMD_ADDR(x) (x << 16)
-#define AC_CMD_DATA(x) (x & 0xffff)
-
-struct s3c_ac97_info {
- struct clk *ac97_clk;
- void __iomem *regs;
- struct mutex lock;
- struct completion done;
-};
-static struct s3c_ac97_info s3c_ac97;
-
-static struct s3c2410_dma_client s3c_dma_client_out = {
- .name = "AC97 PCMOut"
-};
-
-static struct s3c2410_dma_client s3c_dma_client_in = {
- .name = "AC97 PCMIn"
-};
-
-static struct s3c2410_dma_client s3c_dma_client_micin = {
- .name = "AC97 MicIn"
-};
-
-static struct s3c_dma_params s3c_ac97_pcm_out = {
- .client = &s3c_dma_client_out,
- .dma_size = 4,
-};
-
-static struct s3c_dma_params s3c_ac97_pcm_in = {
- .client = &s3c_dma_client_in,
- .dma_size = 4,
-};
-
-static struct s3c_dma_params s3c_ac97_mic_in = {
- .client = &s3c_dma_client_micin,
- .dma_size = 4,
-};
-
-static void s3c_ac97_activate(struct snd_ac97 *ac97)
-{
- u32 ac_glbctrl, stat;
-
- stat = readl(s3c_ac97.regs + S3C_AC97_GLBSTAT) & 0x7;
- if (stat == S3C_AC97_GLBSTAT_MAINSTATE_ACTIVE)
- return; /* Return if already active */
-
- INIT_COMPLETION(s3c_ac97.done);
-
- ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
- ac_glbctrl = S3C_AC97_GLBCTRL_ACLINKON;
- writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
- msleep(1);
-
- ac_glbctrl |= S3C_AC97_GLBCTRL_TRANSFERDATAENABLE;
- writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
- msleep(1);
-
- ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
- ac_glbctrl |= S3C_AC97_GLBCTRL_CODECREADYIE;
- writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
-
- if (!wait_for_completion_timeout(&s3c_ac97.done, HZ))
- pr_err("AC97: Unable to activate!");
-}
-
-static unsigned short s3c_ac97_read(struct snd_ac97 *ac97,
- unsigned short reg)
-{
- u32 ac_glbctrl, ac_codec_cmd;
- u32 stat, addr, data;
-
- mutex_lock(&s3c_ac97.lock);
-
- s3c_ac97_activate(ac97);
-
- INIT_COMPLETION(s3c_ac97.done);
-
- ac_codec_cmd = readl(s3c_ac97.regs + S3C_AC97_CODEC_CMD);
- ac_codec_cmd = S3C_AC97_CODEC_CMD_READ | AC_CMD_ADDR(reg);
- writel(ac_codec_cmd, s3c_ac97.regs + S3C_AC97_CODEC_CMD);
-
- udelay(50);
-
- ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
- ac_glbctrl |= S3C_AC97_GLBCTRL_CODECREADYIE;
- writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
-
- if (!wait_for_completion_timeout(&s3c_ac97.done, HZ))
- pr_err("AC97: Unable to read!");
-
- stat = readl(s3c_ac97.regs + S3C_AC97_STAT);
- addr = (stat >> 16) & 0x7f;
- data = (stat & 0xffff);
-
- if (addr != reg)
- pr_err("s3c-ac97: req addr = %02x, rep addr = %02x\n",
- reg, addr);
-
- mutex_unlock(&s3c_ac97.lock);
-
- return (unsigned short)data;
-}
-
-static void s3c_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
- unsigned short val)
-{
- u32 ac_glbctrl, ac_codec_cmd;
-
- mutex_lock(&s3c_ac97.lock);
-
- s3c_ac97_activate(ac97);
-
- INIT_COMPLETION(s3c_ac97.done);
-
- ac_codec_cmd = readl(s3c_ac97.regs + S3C_AC97_CODEC_CMD);
- ac_codec_cmd = AC_CMD_ADDR(reg) | AC_CMD_DATA(val);
- writel(ac_codec_cmd, s3c_ac97.regs + S3C_AC97_CODEC_CMD);
-
- udelay(50);
-
- ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
- ac_glbctrl |= S3C_AC97_GLBCTRL_CODECREADYIE;
- writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
-
- if (!wait_for_completion_timeout(&s3c_ac97.done, HZ))
- pr_err("AC97: Unable to write!");
-
- ac_codec_cmd = readl(s3c_ac97.regs + S3C_AC97_CODEC_CMD);
- ac_codec_cmd |= S3C_AC97_CODEC_CMD_READ;
- writel(ac_codec_cmd, s3c_ac97.regs + S3C_AC97_CODEC_CMD);
-
- mutex_unlock(&s3c_ac97.lock);
-}
-
-static void s3c_ac97_cold_reset(struct snd_ac97 *ac97)
-{
- pr_debug("AC97: Cold reset\n");
- writel(S3C_AC97_GLBCTRL_COLDRESET,
- s3c_ac97.regs + S3C_AC97_GLBCTRL);
- msleep(1);
-
- writel(0, s3c_ac97.regs + S3C_AC97_GLBCTRL);
- msleep(1);
-}
-
-static void s3c_ac97_warm_reset(struct snd_ac97 *ac97)
-{
- u32 stat;
-
- stat = readl(s3c_ac97.regs + S3C_AC97_GLBSTAT) & 0x7;
- if (stat == S3C_AC97_GLBSTAT_MAINSTATE_ACTIVE)
- return; /* Return if already active */
-
- pr_debug("AC97: Warm reset\n");
-
- writel(S3C_AC97_GLBCTRL_WARMRESET, s3c_ac97.regs + S3C_AC97_GLBCTRL);
- msleep(1);
-
- writel(0, s3c_ac97.regs + S3C_AC97_GLBCTRL);
- msleep(1);
-
- s3c_ac97_activate(ac97);
-}
-
-static irqreturn_t s3c_ac97_irq(int irq, void *dev_id)
-{
- u32 ac_glbctrl, ac_glbstat;
-
- ac_glbstat = readl(s3c_ac97.regs + S3C_AC97_GLBSTAT);
-
- if (ac_glbstat & S3C_AC97_GLBSTAT_CODECREADY) {
-
- ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
- ac_glbctrl &= ~S3C_AC97_GLBCTRL_CODECREADYIE;
- writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
-
- complete(&s3c_ac97.done);
- }
-
- ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
- ac_glbctrl |= (1<<30); /* Clear interrupt */
- writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
-
- return IRQ_HANDLED;
-}
-
-struct snd_ac97_bus_ops soc_ac97_ops = {
- .read = s3c_ac97_read,
- .write = s3c_ac97_write,
- .warm_reset = s3c_ac97_warm_reset,
- .reset = s3c_ac97_cold_reset,
-};
-EXPORT_SYMBOL_GPL(soc_ac97_ops);
-
-static int s3c_ac97_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_dai *cpu_dai = rtd->cpu_dai;
- struct s3c_dma_params *dma_data;
-
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- dma_data = &s3c_ac97_pcm_out;
- else
- dma_data = &s3c_ac97_pcm_in;
-
- snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data);
-
- return 0;
-}
-
-static int s3c_ac97_trigger(struct snd_pcm_substream *substream, int cmd,
- struct snd_soc_dai *dai)
-{
- u32 ac_glbctrl;
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct s3c_dma_params *dma_data =
- snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
-
- ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
- if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
- ac_glbctrl &= ~S3C_AC97_GLBCTRL_PCMINTM_MASK;
- else
- ac_glbctrl &= ~S3C_AC97_GLBCTRL_PCMOUTTM_MASK;
-
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
- case SNDRV_PCM_TRIGGER_RESUME:
- case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
- ac_glbctrl |= S3C_AC97_GLBCTRL_PCMINTM_DMA;
- else
- ac_glbctrl |= S3C_AC97_GLBCTRL_PCMOUTTM_DMA;
- break;
-
- case SNDRV_PCM_TRIGGER_STOP:
- case SNDRV_PCM_TRIGGER_SUSPEND:
- case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- break;
- }
-
- writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
-
- s3c2410_dma_ctrl(dma_data->channel, S3C2410_DMAOP_STARTED);
-
- return 0;
-}
-
-static int s3c_ac97_hw_mic_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_dai *cpu_dai = rtd->cpu_dai;
-
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- return -ENODEV;
- else
- snd_soc_dai_set_dma_data(cpu_dai, substream, &s3c_ac97_mic_in);
-
- return 0;
-}
-
-static int s3c_ac97_mic_trigger(struct snd_pcm_substream *substream,
- int cmd, struct snd_soc_dai *dai)
-{
- u32 ac_glbctrl;
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct s3c_dma_params *dma_data =
- snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
-
- ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
- ac_glbctrl &= ~S3C_AC97_GLBCTRL_MICINTM_MASK;
-
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
- case SNDRV_PCM_TRIGGER_RESUME:
- case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- ac_glbctrl |= S3C_AC97_GLBCTRL_MICINTM_DMA;
- break;
-
- case SNDRV_PCM_TRIGGER_STOP:
- case SNDRV_PCM_TRIGGER_SUSPEND:
- case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- break;
- }
-
- writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
-
- s3c2410_dma_ctrl(dma_data->channel, S3C2410_DMAOP_STARTED);
-
- return 0;
-}
-
-static struct snd_soc_dai_ops s3c_ac97_dai_ops = {
- .hw_params = s3c_ac97_hw_params,
- .trigger = s3c_ac97_trigger,
-};
-
-static struct snd_soc_dai_ops s3c_ac97_mic_dai_ops = {
- .hw_params = s3c_ac97_hw_mic_params,
- .trigger = s3c_ac97_mic_trigger,
-};
-
-static struct snd_soc_dai_driver s3c_ac97_dai[] = {
- [S3C_AC97_DAI_PCM] = {
- .name = "s3c-ac97",
- .ac97_control = 1,
- .playback = {
- .stream_name = "AC97 Playback",
- .channels_min = 2,
- .channels_max = 2,
- .rates = SNDRV_PCM_RATE_8000_48000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,},
- .capture = {
- .stream_name = "AC97 Capture",
- .channels_min = 2,
- .channels_max = 2,
- .rates = SNDRV_PCM_RATE_8000_48000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,},
- .ops = &s3c_ac97_dai_ops,
- },
- [S3C_AC97_DAI_MIC] = {
- .name = "s3c-ac97-mic",
- .ac97_control = 1,
- .capture = {
- .stream_name = "AC97 Mic Capture",
- .channels_min = 1,
- .channels_max = 1,
- .rates = SNDRV_PCM_RATE_8000_48000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,},
- .ops = &s3c_ac97_mic_dai_ops,
- },
-};
-
-static __devinit int s3c_ac97_probe(struct platform_device *pdev)
-{
- struct resource *mem_res, *dmatx_res, *dmarx_res, *dmamic_res, *irq_res;
- struct s3c_audio_pdata *ac97_pdata;
- int ret;
-
- ac97_pdata = pdev->dev.platform_data;
- if (!ac97_pdata || !ac97_pdata->cfg_gpio) {
- dev_err(&pdev->dev, "cfg_gpio callback not provided!\n");
- return -EINVAL;
- }
-
- /* Check for availability of necessary resource */
- dmatx_res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
- if (!dmatx_res) {
- dev_err(&pdev->dev, "Unable to get AC97-TX dma resource\n");
- return -ENXIO;
- }
-
- dmarx_res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
- if (!dmarx_res) {
- dev_err(&pdev->dev, "Unable to get AC97-RX dma resource\n");
- return -ENXIO;
- }
-
- dmamic_res = platform_get_resource(pdev, IORESOURCE_DMA, 2);
- if (!dmamic_res) {
- dev_err(&pdev->dev, "Unable to get AC97-MIC dma resource\n");
- return -ENXIO;
- }
-
- mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!mem_res) {
- dev_err(&pdev->dev, "Unable to get register resource\n");
- return -ENXIO;
- }
-
- irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (!irq_res) {
- dev_err(&pdev->dev, "AC97 IRQ not provided!\n");
- return -ENXIO;
- }
-
- if (!request_mem_region(mem_res->start,
- resource_size(mem_res), "s3c-ac97")) {
- dev_err(&pdev->dev, "Unable to request register region\n");
- return -EBUSY;
- }
-
- s3c_ac97_pcm_out.channel = dmatx_res->start;
- s3c_ac97_pcm_out.dma_addr = mem_res->start + S3C_AC97_PCM_DATA;
- s3c_ac97_pcm_in.channel = dmarx_res->start;
- s3c_ac97_pcm_in.dma_addr = mem_res->start + S3C_AC97_PCM_DATA;
- s3c_ac97_mic_in.channel = dmamic_res->start;
- s3c_ac97_mic_in.dma_addr = mem_res->start + S3C_AC97_MIC_DATA;
-
- init_completion(&s3c_ac97.done);
- mutex_init(&s3c_ac97.lock);
-
- s3c_ac97.regs = ioremap(mem_res->start, resource_size(mem_res));
- if (s3c_ac97.regs == NULL) {
- dev_err(&pdev->dev, "Unable to ioremap register region\n");
- ret = -ENXIO;
- goto err1;
- }
-
- s3c_ac97.ac97_clk = clk_get(&pdev->dev, "ac97");
- if (IS_ERR(s3c_ac97.ac97_clk)) {
- dev_err(&pdev->dev, "s3c-ac97 failed to get ac97_clock\n");
- ret = -ENODEV;
- goto err2;
- }
- clk_enable(s3c_ac97.ac97_clk);
-
- if (ac97_pdata->cfg_gpio(pdev)) {
- dev_err(&pdev->dev, "Unable to configure gpio\n");
- ret = -EINVAL;
- goto err3;
- }
-
- ret = request_irq(irq_res->start, s3c_ac97_irq,
- IRQF_DISABLED, "AC97", NULL);
- if (ret < 0) {
- dev_err(&pdev->dev, "s3c-ac97: interrupt request failed.\n");
- goto err4;
- }
-
- ret = snd_soc_register_dais(&pdev->dev, s3c_ac97_dai,
- ARRAY_SIZE(s3c_ac97_dai));
- if (ret)
- goto err5;
-
- return 0;
-
-err5:
- free_irq(irq_res->start, NULL);
-err4:
-err3:
- clk_disable(s3c_ac97.ac97_clk);
- clk_put(s3c_ac97.ac97_clk);
-err2:
- iounmap(s3c_ac97.regs);
-err1:
- release_mem_region(mem_res->start, resource_size(mem_res));
-
- return ret;
-}
-
-static __devexit int s3c_ac97_remove(struct platform_device *pdev)
-{
- struct resource *mem_res, *irq_res;
-
- snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(s3c_ac97_dai));
-
- irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (irq_res)
- free_irq(irq_res->start, NULL);
-
- clk_disable(s3c_ac97.ac97_clk);
- clk_put(s3c_ac97.ac97_clk);
-
- iounmap(s3c_ac97.regs);
-
- mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (mem_res)
- release_mem_region(mem_res->start, resource_size(mem_res));
-
- return 0;
-}
-
-static struct platform_driver s3c_ac97_driver = {
- .probe = s3c_ac97_probe,
- .remove = s3c_ac97_remove,
- .driver = {
- .name = "samsung-ac97",
- .owner = THIS_MODULE,
- },
-};
-
-static int __init s3c_ac97_init(void)
-{
- return platform_driver_register(&s3c_ac97_driver);
-}
-module_init(s3c_ac97_init);
-
-static void __exit s3c_ac97_exit(void)
-{
- platform_driver_unregister(&s3c_ac97_driver);
-}
-module_exit(s3c_ac97_exit);
-
-MODULE_AUTHOR("Jaswinder Singh, <jassi.brar(a)samsung.com>");
-MODULE_DESCRIPTION("AC97 driver for the Samsung SoC");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:samsung-ac97");
diff --git a/sound/soc/s3c24xx/s3c-ac97.h b/sound/soc/s3c24xx/s3c-ac97.h
deleted file mode 100644
index 5dcedd0..0000000
--- a/sound/soc/s3c24xx/s3c-ac97.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/* sound/soc/s3c24xx/s3c-ac97.h
- *
- * ALSA SoC Audio Layer - S3C AC97 Controller driver
- * Evolved from s3c2443-ac97.h
- *
- * Copyright (c) 2010 Samsung Electronics Co. Ltd
- * Author: Jaswinder Singh <jassi.brar(a)samsung.com>
- * Credits: Graeme Gregory, Sean Choi
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef __S3C_AC97_H_
-#define __S3C_AC97_H_
-
-#define S3C_AC97_DAI_PCM 0
-#define S3C_AC97_DAI_MIC 1
-
-#endif /* __S3C_AC97_H_ */
diff --git a/sound/soc/s3c24xx/smdk2443_wm9710.c b/sound/soc/s3c24xx/smdk2443_wm9710.c
index 0205138..5051699 100644
--- a/sound/soc/s3c24xx/smdk2443_wm9710.c
+++ b/sound/soc/s3c24xx/smdk2443_wm9710.c
@@ -20,7 +20,7 @@
#include <sound/soc-dapm.h>
#include "dma.h"
-#include "s3c-ac97.h"
+#include "ac97.h"
static struct snd_soc_card smdk2443;
diff --git a/sound/soc/s3c24xx/smdk_wm9713.c b/sound/soc/s3c24xx/smdk_wm9713.c
index 56b448d..7ce2430 100644
--- a/sound/soc/s3c24xx/smdk_wm9713.c
+++ b/sound/soc/s3c24xx/smdk_wm9713.c
@@ -16,7 +16,7 @@
#include <sound/soc.h>
#include "dma.h"
-#include "s3c-ac97.h"
+#include "ac97.h"
static struct snd_soc_card smdk;
--
1.6.2.5
1
0

19 Oct '10
From: Jassi Brar <jassi.brar(a)samsung.com>
Call the AC97 controller devices found in S3C, S5P and newer
SoCs as 'samsung-ac97' rather than 's3c-ac97'.
Signed-off-by: Jassi Brar <jassi.brar(a)samsung.com>
---
arch/arm/mach-s3c64xx/dev-audio.c | 2 +-
arch/arm/mach-s5pc100/dev-audio.c | 2 +-
arch/arm/mach-s5pv210/dev-audio.c | 2 +-
arch/arm/plat-s3c24xx/devs.c | 2 +-
sound/soc/s3c24xx/ln2440sbc_alc650.c | 2 +-
sound/soc/s3c24xx/s3c-ac97.c | 4 ++--
sound/soc/s3c24xx/smdk2443_wm9710.c | 2 +-
sound/soc/s3c24xx/smdk_wm9713.c | 2 +-
8 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/arch/arm/mach-s3c64xx/dev-audio.c b/arch/arm/mach-s3c64xx/dev-audio.c
index c730dd2..1615c94 100644
--- a/arch/arm/mach-s3c64xx/dev-audio.c
+++ b/arch/arm/mach-s3c64xx/dev-audio.c
@@ -317,7 +317,7 @@ static struct s3c_audio_pdata s3c_ac97_pdata;
static u64 s3c64xx_ac97_dmamask = DMA_BIT_MASK(32);
struct platform_device s3c64xx_device_ac97 = {
- .name = "s3c-ac97",
+ .name = "samsung-ac97",
.id = -1,
.num_resources = ARRAY_SIZE(s3c64xx_ac97_resource),
.resource = s3c64xx_ac97_resource,
diff --git a/arch/arm/mach-s5pc100/dev-audio.c b/arch/arm/mach-s5pc100/dev-audio.c
index a699ed6..4207511 100644
--- a/arch/arm/mach-s5pc100/dev-audio.c
+++ b/arch/arm/mach-s5pc100/dev-audio.c
@@ -275,7 +275,7 @@ static struct s3c_audio_pdata s3c_ac97_pdata = {
static u64 s5pc100_ac97_dmamask = DMA_BIT_MASK(32);
struct platform_device s5pc100_device_ac97 = {
- .name = "s3c-ac97",
+ .name = "samsung-ac97",
.id = -1,
.num_resources = ARRAY_SIZE(s5pc100_ac97_resource),
.resource = s5pc100_ac97_resource,
diff --git a/arch/arm/mach-s5pv210/dev-audio.c b/arch/arm/mach-s5pv210/dev-audio.c
index 21dc6cf..e6db957 100644
--- a/arch/arm/mach-s5pv210/dev-audio.c
+++ b/arch/arm/mach-s5pv210/dev-audio.c
@@ -315,7 +315,7 @@ static struct s3c_audio_pdata s3c_ac97_pdata = {
static u64 s5pv210_ac97_dmamask = DMA_BIT_MASK(32);
struct platform_device s5pv210_device_ac97 = {
- .name = "s3c-ac97",
+ .name = "samsung-ac97",
.id = -1,
.num_resources = ARRAY_SIZE(s5pv210_ac97_resource),
.resource = s5pv210_ac97_resource,
diff --git a/arch/arm/plat-s3c24xx/devs.c b/arch/arm/plat-s3c24xx/devs.c
index d8fb4e6..2f99fff 100644
--- a/arch/arm/plat-s3c24xx/devs.c
+++ b/arch/arm/plat-s3c24xx/devs.c
@@ -482,7 +482,7 @@ static struct resource s3c_ac97_resource[] = {
};
struct platform_device s3c_device_ac97 = {
- .name = "s3c-ac97",
+ .name = "samsung-ac97",
.id = -1,
.num_resources = ARRAY_SIZE(s3c_ac97_resource),
.resource = s3c_ac97_resource,
diff --git a/sound/soc/s3c24xx/ln2440sbc_alc650.c b/sound/soc/s3c24xx/ln2440sbc_alc650.c
index 36e7e85..dda11ac 100644
--- a/sound/soc/s3c24xx/ln2440sbc_alc650.c
+++ b/sound/soc/s3c24xx/ln2440sbc_alc650.c
@@ -32,7 +32,7 @@ static struct snd_soc_dai_link ln2440sbc_dai[] = {
{
.name = "AC97",
.stream_name = "AC97 HiFi",
- .cpu_dai_name = "s3c-ac97",
+ .cpu_dai_name = "samsung-ac97",
.codec_dai_name = "ac97-hifi",
.codec_name = "ac97-codec",
.platform_name = "samsung-audio",
diff --git a/sound/soc/s3c24xx/s3c-ac97.c b/sound/soc/s3c24xx/s3c-ac97.c
index 408f9c9..5352cac 100644
--- a/sound/soc/s3c24xx/s3c-ac97.c
+++ b/sound/soc/s3c24xx/s3c-ac97.c
@@ -497,7 +497,7 @@ static struct platform_driver s3c_ac97_driver = {
.probe = s3c_ac97_probe,
.remove = s3c_ac97_remove,
.driver = {
- .name = "s3c-ac97",
+ .name = "samsung-ac97",
.owner = THIS_MODULE,
},
};
@@ -517,4 +517,4 @@ module_exit(s3c_ac97_exit);
MODULE_AUTHOR("Jaswinder Singh, <jassi.brar(a)samsung.com>");
MODULE_DESCRIPTION("AC97 driver for the Samsung SoC");
MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:s3c-ac97");
+MODULE_ALIAS("platform:samsung-ac97");
diff --git a/sound/soc/s3c24xx/smdk2443_wm9710.c b/sound/soc/s3c24xx/smdk2443_wm9710.c
index c50d19c..0205138 100644
--- a/sound/soc/s3c24xx/smdk2443_wm9710.c
+++ b/sound/soc/s3c24xx/smdk2443_wm9710.c
@@ -28,7 +28,7 @@ static struct snd_soc_dai_link smdk2443_dai[] = {
{
.name = "AC97",
.stream_name = "AC97 HiFi",
- .cpu_dai_name = "s3c-ac97",
+ .cpu_dai_name = "samsung-ac97",
.codec_dai_name = "ac97-hifi",
.codec_name = "ac97-codec",
.platform_name = "samsung-audio",
diff --git a/sound/soc/s3c24xx/smdk_wm9713.c b/sound/soc/s3c24xx/smdk_wm9713.c
index 80f2aef..56b448d 100644
--- a/sound/soc/s3c24xx/smdk_wm9713.c
+++ b/sound/soc/s3c24xx/smdk_wm9713.c
@@ -46,7 +46,7 @@ static struct snd_soc_dai_link smdk_dai = {
.name = "AC97",
.stream_name = "AC97 PCM",
.platform_name = "samsung-audio",
- .cpu_dai_name = "s3c-ac97",
+ .cpu_dai_name = "samsung-ac97",
.codec_dai_name = "wm9713-hifi",
.codec_name = "wm9713-codec",
};
--
1.6.2.5
1
0

19 Oct '10
From: Jassi Brar <jassi.brar(a)samsung.com>
Rename Samsung ASoC DMA driver
s3c-dma.[c/h] -> dma.[c/h]
Signed-off-by: Jassi Brar <jassi.brar(a)samsung.com>
---
sound/soc/s3c24xx/Makefile | 2 +-
sound/soc/s3c24xx/dma.c | 503 ++++++++++++++++++++++++
sound/soc/s3c24xx/dma.h | 30 ++
sound/soc/s3c24xx/goni_wm8994.c | 2 +-
sound/soc/s3c24xx/jive_wm8750.c | 2 +-
sound/soc/s3c24xx/ln2440sbc_alc650.c | 2 +-
sound/soc/s3c24xx/neo1973_gta02_wm8753.c | 2 +-
sound/soc/s3c24xx/neo1973_wm8753.c | 2 +-
sound/soc/s3c24xx/rx1950_uda1380.c | 2 +-
sound/soc/s3c24xx/s3c-ac97.c | 2 +-
sound/soc/s3c24xx/s3c-dma.c | 503 ------------------------
sound/soc/s3c24xx/s3c-dma.h | 30 --
sound/soc/s3c24xx/s3c-i2s-v2.c | 2 +-
sound/soc/s3c24xx/s3c-pcm.c | 2 +-
sound/soc/s3c24xx/s3c2412-i2s.c | 2 +-
sound/soc/s3c24xx/s3c24xx-i2s.c | 2 +-
sound/soc/s3c24xx/s3c24xx_simtec.c | 2 +-
sound/soc/s3c24xx/s3c24xx_simtec_hermes.c | 2 +-
sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c | 2 +-
sound/soc/s3c24xx/s3c24xx_uda134x.c | 2 +-
sound/soc/s3c24xx/s3c64xx-i2s-v4.c | 2 +-
sound/soc/s3c24xx/s3c64xx-i2s.c | 2 +-
sound/soc/s3c24xx/smartq_wm8987.c | 2 +-
sound/soc/s3c24xx/smdk2443_wm9710.c | 2 +-
sound/soc/s3c24xx/smdk64xx_wm8580.c | 2 +-
sound/soc/s3c24xx/smdk_spdif.c | 2 +-
sound/soc/s3c24xx/smdk_wm9713.c | 2 +-
sound/soc/s3c24xx/spdif.c | 2 +-
28 files changed, 557 insertions(+), 557 deletions(-)
create mode 100644 sound/soc/s3c24xx/dma.c
create mode 100644 sound/soc/s3c24xx/dma.h
delete mode 100644 sound/soc/s3c24xx/s3c-dma.c
delete mode 100644 sound/soc/s3c24xx/s3c-dma.h
diff --git a/sound/soc/s3c24xx/Makefile b/sound/soc/s3c24xx/Makefile
index 4e232f1..20aac45 100644
--- a/sound/soc/s3c24xx/Makefile
+++ b/sound/soc/s3c24xx/Makefile
@@ -1,5 +1,5 @@
# S3c24XX Platform Support
-snd-soc-s3c24xx-objs := s3c-dma.o
+snd-soc-s3c24xx-objs := dma.o
snd-soc-s3c24xx-i2s-objs := s3c24xx-i2s.o
snd-soc-s3c2412-i2s-objs := s3c2412-i2s.o
snd-soc-s3c64xx-i2s-objs := s3c64xx-i2s.o
diff --git a/sound/soc/s3c24xx/dma.c b/sound/soc/s3c24xx/dma.c
new file mode 100644
index 0000000..b4c7c85
--- /dev/null
+++ b/sound/soc/s3c24xx/dma.c
@@ -0,0 +1,503 @@
+/*
+ * dma.c -- ALSA Soc Audio Layer
+ *
+ * (c) 2006 Wolfson Microelectronics PLC.
+ * Graeme Gregory graeme.gregory(a)wolfsonmicro.com or linux(a)wolfsonmicro.com
+ *
+ * Copyright 2004-2005 Simtec Electronics
+ * http://armlinux.simtec.co.uk/
+ * Ben Dooks <ben(a)simtec.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include <asm/dma.h>
+#include <mach/hardware.h>
+#include <mach/dma.h>
+
+#include "dma.h"
+
+static const struct snd_pcm_hardware s3c_dma_hardware = {
+ .info = SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_PAUSE |
+ SNDRV_PCM_INFO_RESUME,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_U16_LE |
+ SNDRV_PCM_FMTBIT_U8 |
+ SNDRV_PCM_FMTBIT_S8,
+ .channels_min = 2,
+ .channels_max = 2,
+ .buffer_bytes_max = 128*1024,
+ .period_bytes_min = PAGE_SIZE,
+ .period_bytes_max = PAGE_SIZE*2,
+ .periods_min = 2,
+ .periods_max = 128,
+ .fifo_size = 32,
+};
+
+struct s3c24xx_runtime_data {
+ spinlock_t lock;
+ int state;
+ unsigned int dma_loaded;
+ unsigned int dma_limit;
+ unsigned int dma_period;
+ dma_addr_t dma_start;
+ dma_addr_t dma_pos;
+ dma_addr_t dma_end;
+ struct s3c_dma_params *params;
+};
+
+/* s3c_dma_enqueue
+ *
+ * place a dma buffer onto the queue for the dma system
+ * to handle.
+*/
+static void s3c_dma_enqueue(struct snd_pcm_substream *substream)
+{
+ struct s3c24xx_runtime_data *prtd = substream->runtime->private_data;
+ dma_addr_t pos = prtd->dma_pos;
+ unsigned int limit;
+ int ret;
+
+ pr_debug("Entered %s\n", __func__);
+
+ if (s3c_dma_has_circular())
+ limit = (prtd->dma_end - prtd->dma_start) / prtd->dma_period;
+ else
+ limit = prtd->dma_limit;
+
+ pr_debug("%s: loaded %d, limit %d\n",
+ __func__, prtd->dma_loaded, limit);
+
+ while (prtd->dma_loaded < limit) {
+ unsigned long len = prtd->dma_period;
+
+ pr_debug("dma_loaded: %d\n", prtd->dma_loaded);
+
+ if ((pos + len) > prtd->dma_end) {
+ len = prtd->dma_end - pos;
+ pr_debug(KERN_DEBUG "%s: corrected dma len %ld\n",
+ __func__, len);
+ }
+
+ ret = s3c2410_dma_enqueue(prtd->params->channel,
+ substream, pos, len);
+
+ if (ret == 0) {
+ prtd->dma_loaded++;
+ pos += prtd->dma_period;
+ if (pos >= prtd->dma_end)
+ pos = prtd->dma_start;
+ } else
+ break;
+ }
+
+ prtd->dma_pos = pos;
+}
+
+static void s3c24xx_audio_buffdone(struct s3c2410_dma_chan *channel,
+ void *dev_id, int size,
+ enum s3c2410_dma_buffresult result)
+{
+ struct snd_pcm_substream *substream = dev_id;
+ struct s3c24xx_runtime_data *prtd;
+
+ pr_debug("Entered %s\n", __func__);
+
+ if (result == S3C2410_RES_ABORT || result == S3C2410_RES_ERR)
+ return;
+
+ prtd = substream->runtime->private_data;
+
+ if (substream)
+ snd_pcm_period_elapsed(substream);
+
+ spin_lock(&prtd->lock);
+ if (prtd->state & ST_RUNNING && !s3c_dma_has_circular()) {
+ prtd->dma_loaded--;
+ s3c_dma_enqueue(substream);
+ }
+
+ spin_unlock(&prtd->lock);
+}
+
+static int s3c_dma_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct s3c24xx_runtime_data *prtd = runtime->private_data;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ unsigned long totbytes = params_buffer_bytes(params);
+ struct s3c_dma_params *dma =
+ snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
+ int ret = 0;
+
+
+ pr_debug("Entered %s\n", __func__);
+
+ /* return if this is a bufferless transfer e.g.
+ * codec <--> BT codec or GSM modem -- lg FIXME */
+ if (!dma)
+ return 0;
+
+ /* this may get called several times by oss emulation
+ * with different params -HW */
+ if (prtd->params == NULL) {
+ /* prepare DMA */
+ prtd->params = dma;
+
+ pr_debug("params %p, client %p, channel %d\n", prtd->params,
+ prtd->params->client, prtd->params->channel);
+
+ ret = s3c2410_dma_request(prtd->params->channel,
+ prtd->params->client, NULL);
+
+ if (ret < 0) {
+ printk(KERN_ERR "failed to get dma channel\n");
+ return ret;
+ }
+
+ /* use the circular buffering if we have it available. */
+ if (s3c_dma_has_circular())
+ s3c2410_dma_setflags(prtd->params->channel,
+ S3C2410_DMAF_CIRCULAR);
+ }
+
+ s3c2410_dma_set_buffdone_fn(prtd->params->channel,
+ s3c24xx_audio_buffdone);
+
+ snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+
+ runtime->dma_bytes = totbytes;
+
+ spin_lock_irq(&prtd->lock);
+ prtd->dma_loaded = 0;
+ prtd->dma_limit = runtime->hw.periods_min;
+ prtd->dma_period = params_period_bytes(params);
+ prtd->dma_start = runtime->dma_addr;
+ prtd->dma_pos = prtd->dma_start;
+ prtd->dma_end = prtd->dma_start + totbytes;
+ spin_unlock_irq(&prtd->lock);
+
+ return 0;
+}
+
+static int s3c_dma_hw_free(struct snd_pcm_substream *substream)
+{
+ struct s3c24xx_runtime_data *prtd = substream->runtime->private_data;
+
+ pr_debug("Entered %s\n", __func__);
+
+ /* TODO - do we need to ensure DMA flushed */
+ snd_pcm_set_runtime_buffer(substream, NULL);
+
+ if (prtd->params) {
+ s3c2410_dma_free(prtd->params->channel, prtd->params->client);
+ prtd->params = NULL;
+ }
+
+ return 0;
+}
+
+static int s3c_dma_prepare(struct snd_pcm_substream *substream)
+{
+ struct s3c24xx_runtime_data *prtd = substream->runtime->private_data;
+ int ret = 0;
+
+ pr_debug("Entered %s\n", __func__);
+
+ /* return if this is a bufferless transfer e.g.
+ * codec <--> BT codec or GSM modem -- lg FIXME */
+ if (!prtd->params)
+ return 0;
+
+ /* channel needs configuring for mem=>device, increment memory addr,
+ * sync to pclk, half-word transfers to the IIS-FIFO. */
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ s3c2410_dma_devconfig(prtd->params->channel,
+ S3C2410_DMASRC_MEM,
+ prtd->params->dma_addr);
+ } else {
+ s3c2410_dma_devconfig(prtd->params->channel,
+ S3C2410_DMASRC_HW,
+ prtd->params->dma_addr);
+ }
+
+ s3c2410_dma_config(prtd->params->channel,
+ prtd->params->dma_size);
+
+ /* flush the DMA channel */
+ s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_FLUSH);
+ prtd->dma_loaded = 0;
+ prtd->dma_pos = prtd->dma_start;
+
+ /* enqueue dma buffers */
+ s3c_dma_enqueue(substream);
+
+ return ret;
+}
+
+static int s3c_dma_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct s3c24xx_runtime_data *prtd = substream->runtime->private_data;
+ int ret = 0;
+
+ pr_debug("Entered %s\n", __func__);
+
+ spin_lock(&prtd->lock);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ prtd->state |= ST_RUNNING;
+ s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_START);
+ break;
+
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ prtd->state &= ~ST_RUNNING;
+ s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_STOP);
+ break;
+
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ spin_unlock(&prtd->lock);
+
+ return ret;
+}
+
+static snd_pcm_uframes_t
+s3c_dma_pointer(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct s3c24xx_runtime_data *prtd = runtime->private_data;
+ unsigned long res;
+ dma_addr_t src, dst;
+
+ pr_debug("Entered %s\n", __func__);
+
+ spin_lock(&prtd->lock);
+ s3c2410_dma_getposition(prtd->params->channel, &src, &dst);
+
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ res = dst - prtd->dma_start;
+ else
+ res = src - prtd->dma_start;
+
+ spin_unlock(&prtd->lock);
+
+ pr_debug("Pointer %x %x\n", src, dst);
+
+ /* we seem to be getting the odd error from the pcm library due
+ * to out-of-bounds pointers. this is maybe due to the dma engine
+ * not having loaded the new values for the channel before being
+ * callled... (todo - fix )
+ */
+
+ if (res >= snd_pcm_lib_buffer_bytes(substream)) {
+ if (res == snd_pcm_lib_buffer_bytes(substream))
+ res = 0;
+ }
+
+ return bytes_to_frames(substream->runtime, res);
+}
+
+static int s3c_dma_open(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct s3c24xx_runtime_data *prtd;
+
+ pr_debug("Entered %s\n", __func__);
+
+ snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
+ snd_soc_set_runtime_hwparams(substream, &s3c_dma_hardware);
+
+ prtd = kzalloc(sizeof(struct s3c24xx_runtime_data), GFP_KERNEL);
+ if (prtd == NULL)
+ return -ENOMEM;
+
+ spin_lock_init(&prtd->lock);
+
+ runtime->private_data = prtd;
+ return 0;
+}
+
+static int s3c_dma_close(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct s3c24xx_runtime_data *prtd = runtime->private_data;
+
+ pr_debug("Entered %s\n", __func__);
+
+ if (!prtd)
+ pr_debug("s3c_dma_close called with prtd == NULL\n");
+
+ kfree(prtd);
+
+ return 0;
+}
+
+static int s3c_dma_mmap(struct snd_pcm_substream *substream,
+ struct vm_area_struct *vma)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+
+ pr_debug("Entered %s\n", __func__);
+
+ return dma_mmap_writecombine(substream->pcm->card->dev, vma,
+ runtime->dma_area,
+ runtime->dma_addr,
+ runtime->dma_bytes);
+}
+
+static struct snd_pcm_ops s3c_dma_ops = {
+ .open = s3c_dma_open,
+ .close = s3c_dma_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = s3c_dma_hw_params,
+ .hw_free = s3c_dma_hw_free,
+ .prepare = s3c_dma_prepare,
+ .trigger = s3c_dma_trigger,
+ .pointer = s3c_dma_pointer,
+ .mmap = s3c_dma_mmap,
+};
+
+static int s3c_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
+{
+ struct snd_pcm_substream *substream = pcm->streams[stream].substream;
+ struct snd_dma_buffer *buf = &substream->dma_buffer;
+ size_t size = s3c_dma_hardware.buffer_bytes_max;
+
+ pr_debug("Entered %s\n", __func__);
+
+ buf->dev.type = SNDRV_DMA_TYPE_DEV;
+ buf->dev.dev = pcm->card->dev;
+ buf->private_data = NULL;
+ buf->area = dma_alloc_writecombine(pcm->card->dev, size,
+ &buf->addr, GFP_KERNEL);
+ if (!buf->area)
+ return -ENOMEM;
+ buf->bytes = size;
+ return 0;
+}
+
+static void s3c_dma_free_dma_buffers(struct snd_pcm *pcm)
+{
+ struct snd_pcm_substream *substream;
+ struct snd_dma_buffer *buf;
+ int stream;
+
+ pr_debug("Entered %s\n", __func__);
+
+ for (stream = 0; stream < 2; stream++) {
+ substream = pcm->streams[stream].substream;
+ if (!substream)
+ continue;
+
+ buf = &substream->dma_buffer;
+ if (!buf->area)
+ continue;
+
+ dma_free_writecombine(pcm->card->dev, buf->bytes,
+ buf->area, buf->addr);
+ buf->area = NULL;
+ }
+}
+
+static u64 s3c_dma_mask = DMA_BIT_MASK(32);
+
+static int s3c_dma_new(struct snd_card *card,
+ struct snd_soc_dai *dai, struct snd_pcm *pcm)
+{
+ int ret = 0;
+
+ pr_debug("Entered %s\n", __func__);
+
+ if (!card->dev->dma_mask)
+ card->dev->dma_mask = &s3c_dma_mask;
+ if (!card->dev->coherent_dma_mask)
+ card->dev->coherent_dma_mask = 0xffffffff;
+
+ if (dai->driver->playback.channels_min) {
+ ret = s3c_preallocate_dma_buffer(pcm,
+ SNDRV_PCM_STREAM_PLAYBACK);
+ if (ret)
+ goto out;
+ }
+
+ if (dai->driver->capture.channels_min) {
+ ret = s3c_preallocate_dma_buffer(pcm,
+ SNDRV_PCM_STREAM_CAPTURE);
+ if (ret)
+ goto out;
+ }
+out:
+ return ret;
+}
+
+static struct snd_soc_platform_driver s3c24xx_soc_platform = {
+ .ops = &s3c_dma_ops,
+ .pcm_new = s3c_dma_new,
+ .pcm_free = s3c_dma_free_dma_buffers,
+};
+
+static int __devinit s3c24xx_soc_platform_probe(struct platform_device *pdev)
+{
+ return snd_soc_register_platform(&pdev->dev, &s3c24xx_soc_platform);
+}
+
+static int __devexit s3c24xx_soc_platform_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_platform(&pdev->dev);
+ return 0;
+}
+
+static struct platform_driver s3c24xx_pcm_driver = {
+ .driver = {
+ .name = "samsung-audio",
+ .owner = THIS_MODULE,
+ },
+
+ .probe = s3c24xx_soc_platform_probe,
+ .remove = __devexit_p(s3c24xx_soc_platform_remove),
+};
+
+static int __init snd_s3c24xx_pcm_init(void)
+{
+ return platform_driver_register(&s3c24xx_pcm_driver);
+}
+module_init(snd_s3c24xx_pcm_init);
+
+static void __exit snd_s3c24xx_pcm_exit(void)
+{
+ platform_driver_unregister(&s3c24xx_pcm_driver);
+}
+module_exit(snd_s3c24xx_pcm_exit);
+
+MODULE_AUTHOR("Ben Dooks, <ben(a)simtec.co.uk>");
+MODULE_DESCRIPTION("Samsung S3C Audio DMA module");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:samsung-audio");
diff --git a/sound/soc/s3c24xx/dma.h b/sound/soc/s3c24xx/dma.h
new file mode 100644
index 0000000..f8cd2b4
--- /dev/null
+++ b/sound/soc/s3c24xx/dma.h
@@ -0,0 +1,30 @@
+/*
+ * dma.h --
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * ALSA PCM interface for the Samsung S3C24xx CPU
+ */
+
+#ifndef _S3C_AUDIO_H
+#define _S3C_AUDIO_H
+
+#define ST_RUNNING (1<<0)
+#define ST_OPENED (1<<1)
+
+struct s3c_dma_params {
+ struct s3c2410_dma_client *client; /* stream identifier */
+ int channel; /* Channel ID */
+ dma_addr_t dma_addr;
+ int dma_size; /* Size of the DMA transfer */
+};
+
+#define S3C24XX_DAI_I2S 0
+
+/* platform data */
+extern struct snd_ac97_bus_ops s3c24xx_ac97_ops;
+
+#endif
diff --git a/sound/soc/s3c24xx/goni_wm8994.c b/sound/soc/s3c24xx/goni_wm8994.c
index c568f69..201056c 100644
--- a/sound/soc/s3c24xx/goni_wm8994.c
+++ b/sound/soc/s3c24xx/goni_wm8994.c
@@ -25,7 +25,7 @@
#include <linux/mfd/wm8994/core.h>
#include <linux/mfd/wm8994/registers.h>
#include "../codecs/wm8994.h"
-#include "s3c-dma.h"
+#include "dma.h"
#include "s3c64xx-i2s.h"
#define MACHINE_NAME 0
diff --git a/sound/soc/s3c24xx/jive_wm8750.c b/sound/soc/s3c24xx/jive_wm8750.c
index 7a6b0fa..4e1b8ac 100644
--- a/sound/soc/s3c24xx/jive_wm8750.c
+++ b/sound/soc/s3c24xx/jive_wm8750.c
@@ -25,7 +25,7 @@
#include <asm/mach-types.h>
-#include "s3c-dma.h"
+#include "dma.h"
#include "s3c2412-i2s.h"
#include "../codecs/wm8750.h"
diff --git a/sound/soc/s3c24xx/ln2440sbc_alc650.c b/sound/soc/s3c24xx/ln2440sbc_alc650.c
index 6b7bb38..36e7e85 100644
--- a/sound/soc/s3c24xx/ln2440sbc_alc650.c
+++ b/sound/soc/s3c24xx/ln2440sbc_alc650.c
@@ -23,7 +23,7 @@
#include <sound/soc.h>
#include <sound/soc-dapm.h>
-#include "s3c-dma.h"
+#include "dma.h"
#include "s3c-ac97.h"
static struct snd_soc_card ln2440sbc;
diff --git a/sound/soc/s3c24xx/neo1973_gta02_wm8753.c b/sound/soc/s3c24xx/neo1973_gta02_wm8753.c
index a9a4bbb..c4b2013 100644
--- a/sound/soc/s3c24xx/neo1973_gta02_wm8753.c
+++ b/sound/soc/s3c24xx/neo1973_gta02_wm8753.c
@@ -32,7 +32,7 @@
#include <asm/io.h>
#include <mach/gta02.h>
#include "../codecs/wm8753.h"
-#include "s3c-dma.h"
+#include "dma.h"
#include "s3c24xx-i2s.h"
static struct snd_soc_card neo1973_gta02;
diff --git a/sound/soc/s3c24xx/neo1973_wm8753.c b/sound/soc/s3c24xx/neo1973_wm8753.c
index d5e4148..96dda57 100644
--- a/sound/soc/s3c24xx/neo1973_wm8753.c
+++ b/sound/soc/s3c24xx/neo1973_wm8753.c
@@ -36,7 +36,7 @@
#include "../codecs/wm8753.h"
#include "lm4857.h"
-#include "s3c-dma.h"
+#include "dma.h"
#include "s3c24xx-i2s.h"
/* define the scenarios */
diff --git a/sound/soc/s3c24xx/rx1950_uda1380.c b/sound/soc/s3c24xx/rx1950_uda1380.c
index 99bb86e..07197ee 100644
--- a/sound/soc/s3c24xx/rx1950_uda1380.c
+++ b/sound/soc/s3c24xx/rx1950_uda1380.c
@@ -35,7 +35,7 @@
#include <asm/mach-types.h>
-#include "s3c-dma.h"
+#include "dma.h"
#include "s3c24xx-i2s.h"
#include "../codecs/uda1380.h"
diff --git a/sound/soc/s3c24xx/s3c-ac97.c b/sound/soc/s3c24xx/s3c-ac97.c
index f891eb7..408f9c9 100644
--- a/sound/soc/s3c24xx/s3c-ac97.c
+++ b/sound/soc/s3c24xx/s3c-ac97.c
@@ -24,7 +24,7 @@
#include <mach/dma.h>
#include <plat/audio.h>
-#include "s3c-dma.h"
+#include "dma.h"
#include "s3c-ac97.h"
#define AC_CMD_ADDR(x) (x << 16)
diff --git a/sound/soc/s3c24xx/s3c-dma.c b/sound/soc/s3c24xx/s3c-dma.c
deleted file mode 100644
index 0c1cd6c..0000000
--- a/sound/soc/s3c24xx/s3c-dma.c
+++ /dev/null
@@ -1,503 +0,0 @@
-/*
- * s3c-dma.c -- ALSA Soc Audio Layer
- *
- * (c) 2006 Wolfson Microelectronics PLC.
- * Graeme Gregory graeme.gregory(a)wolfsonmicro.com or linux(a)wolfsonmicro.com
- *
- * Copyright 2004-2005 Simtec Electronics
- * http://armlinux.simtec.co.uk/
- * Ben Dooks <ben(a)simtec.co.uk>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/dma-mapping.h>
-
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-
-#include <asm/dma.h>
-#include <mach/hardware.h>
-#include <mach/dma.h>
-
-#include "s3c-dma.h"
-
-static const struct snd_pcm_hardware s3c_dma_hardware = {
- .info = SNDRV_PCM_INFO_INTERLEAVED |
- SNDRV_PCM_INFO_BLOCK_TRANSFER |
- SNDRV_PCM_INFO_MMAP |
- SNDRV_PCM_INFO_MMAP_VALID |
- SNDRV_PCM_INFO_PAUSE |
- SNDRV_PCM_INFO_RESUME,
- .formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_U16_LE |
- SNDRV_PCM_FMTBIT_U8 |
- SNDRV_PCM_FMTBIT_S8,
- .channels_min = 2,
- .channels_max = 2,
- .buffer_bytes_max = 128*1024,
- .period_bytes_min = PAGE_SIZE,
- .period_bytes_max = PAGE_SIZE*2,
- .periods_min = 2,
- .periods_max = 128,
- .fifo_size = 32,
-};
-
-struct s3c24xx_runtime_data {
- spinlock_t lock;
- int state;
- unsigned int dma_loaded;
- unsigned int dma_limit;
- unsigned int dma_period;
- dma_addr_t dma_start;
- dma_addr_t dma_pos;
- dma_addr_t dma_end;
- struct s3c_dma_params *params;
-};
-
-/* s3c_dma_enqueue
- *
- * place a dma buffer onto the queue for the dma system
- * to handle.
-*/
-static void s3c_dma_enqueue(struct snd_pcm_substream *substream)
-{
- struct s3c24xx_runtime_data *prtd = substream->runtime->private_data;
- dma_addr_t pos = prtd->dma_pos;
- unsigned int limit;
- int ret;
-
- pr_debug("Entered %s\n", __func__);
-
- if (s3c_dma_has_circular())
- limit = (prtd->dma_end - prtd->dma_start) / prtd->dma_period;
- else
- limit = prtd->dma_limit;
-
- pr_debug("%s: loaded %d, limit %d\n",
- __func__, prtd->dma_loaded, limit);
-
- while (prtd->dma_loaded < limit) {
- unsigned long len = prtd->dma_period;
-
- pr_debug("dma_loaded: %d\n", prtd->dma_loaded);
-
- if ((pos + len) > prtd->dma_end) {
- len = prtd->dma_end - pos;
- pr_debug(KERN_DEBUG "%s: corrected dma len %ld\n",
- __func__, len);
- }
-
- ret = s3c2410_dma_enqueue(prtd->params->channel,
- substream, pos, len);
-
- if (ret == 0) {
- prtd->dma_loaded++;
- pos += prtd->dma_period;
- if (pos >= prtd->dma_end)
- pos = prtd->dma_start;
- } else
- break;
- }
-
- prtd->dma_pos = pos;
-}
-
-static void s3c24xx_audio_buffdone(struct s3c2410_dma_chan *channel,
- void *dev_id, int size,
- enum s3c2410_dma_buffresult result)
-{
- struct snd_pcm_substream *substream = dev_id;
- struct s3c24xx_runtime_data *prtd;
-
- pr_debug("Entered %s\n", __func__);
-
- if (result == S3C2410_RES_ABORT || result == S3C2410_RES_ERR)
- return;
-
- prtd = substream->runtime->private_data;
-
- if (substream)
- snd_pcm_period_elapsed(substream);
-
- spin_lock(&prtd->lock);
- if (prtd->state & ST_RUNNING && !s3c_dma_has_circular()) {
- prtd->dma_loaded--;
- s3c_dma_enqueue(substream);
- }
-
- spin_unlock(&prtd->lock);
-}
-
-static int s3c_dma_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
-{
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct s3c24xx_runtime_data *prtd = runtime->private_data;
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- unsigned long totbytes = params_buffer_bytes(params);
- struct s3c_dma_params *dma =
- snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
- int ret = 0;
-
-
- pr_debug("Entered %s\n", __func__);
-
- /* return if this is a bufferless transfer e.g.
- * codec <--> BT codec or GSM modem -- lg FIXME */
- if (!dma)
- return 0;
-
- /* this may get called several times by oss emulation
- * with different params -HW */
- if (prtd->params == NULL) {
- /* prepare DMA */
- prtd->params = dma;
-
- pr_debug("params %p, client %p, channel %d\n", prtd->params,
- prtd->params->client, prtd->params->channel);
-
- ret = s3c2410_dma_request(prtd->params->channel,
- prtd->params->client, NULL);
-
- if (ret < 0) {
- printk(KERN_ERR "failed to get dma channel\n");
- return ret;
- }
-
- /* use the circular buffering if we have it available. */
- if (s3c_dma_has_circular())
- s3c2410_dma_setflags(prtd->params->channel,
- S3C2410_DMAF_CIRCULAR);
- }
-
- s3c2410_dma_set_buffdone_fn(prtd->params->channel,
- s3c24xx_audio_buffdone);
-
- snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
-
- runtime->dma_bytes = totbytes;
-
- spin_lock_irq(&prtd->lock);
- prtd->dma_loaded = 0;
- prtd->dma_limit = runtime->hw.periods_min;
- prtd->dma_period = params_period_bytes(params);
- prtd->dma_start = runtime->dma_addr;
- prtd->dma_pos = prtd->dma_start;
- prtd->dma_end = prtd->dma_start + totbytes;
- spin_unlock_irq(&prtd->lock);
-
- return 0;
-}
-
-static int s3c_dma_hw_free(struct snd_pcm_substream *substream)
-{
- struct s3c24xx_runtime_data *prtd = substream->runtime->private_data;
-
- pr_debug("Entered %s\n", __func__);
-
- /* TODO - do we need to ensure DMA flushed */
- snd_pcm_set_runtime_buffer(substream, NULL);
-
- if (prtd->params) {
- s3c2410_dma_free(prtd->params->channel, prtd->params->client);
- prtd->params = NULL;
- }
-
- return 0;
-}
-
-static int s3c_dma_prepare(struct snd_pcm_substream *substream)
-{
- struct s3c24xx_runtime_data *prtd = substream->runtime->private_data;
- int ret = 0;
-
- pr_debug("Entered %s\n", __func__);
-
- /* return if this is a bufferless transfer e.g.
- * codec <--> BT codec or GSM modem -- lg FIXME */
- if (!prtd->params)
- return 0;
-
- /* channel needs configuring for mem=>device, increment memory addr,
- * sync to pclk, half-word transfers to the IIS-FIFO. */
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- s3c2410_dma_devconfig(prtd->params->channel,
- S3C2410_DMASRC_MEM,
- prtd->params->dma_addr);
- } else {
- s3c2410_dma_devconfig(prtd->params->channel,
- S3C2410_DMASRC_HW,
- prtd->params->dma_addr);
- }
-
- s3c2410_dma_config(prtd->params->channel,
- prtd->params->dma_size);
-
- /* flush the DMA channel */
- s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_FLUSH);
- prtd->dma_loaded = 0;
- prtd->dma_pos = prtd->dma_start;
-
- /* enqueue dma buffers */
- s3c_dma_enqueue(substream);
-
- return ret;
-}
-
-static int s3c_dma_trigger(struct snd_pcm_substream *substream, int cmd)
-{
- struct s3c24xx_runtime_data *prtd = substream->runtime->private_data;
- int ret = 0;
-
- pr_debug("Entered %s\n", __func__);
-
- spin_lock(&prtd->lock);
-
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
- case SNDRV_PCM_TRIGGER_RESUME:
- case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- prtd->state |= ST_RUNNING;
- s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_START);
- break;
-
- case SNDRV_PCM_TRIGGER_STOP:
- case SNDRV_PCM_TRIGGER_SUSPEND:
- case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- prtd->state &= ~ST_RUNNING;
- s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_STOP);
- break;
-
- default:
- ret = -EINVAL;
- break;
- }
-
- spin_unlock(&prtd->lock);
-
- return ret;
-}
-
-static snd_pcm_uframes_t
-s3c_dma_pointer(struct snd_pcm_substream *substream)
-{
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct s3c24xx_runtime_data *prtd = runtime->private_data;
- unsigned long res;
- dma_addr_t src, dst;
-
- pr_debug("Entered %s\n", __func__);
-
- spin_lock(&prtd->lock);
- s3c2410_dma_getposition(prtd->params->channel, &src, &dst);
-
- if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
- res = dst - prtd->dma_start;
- else
- res = src - prtd->dma_start;
-
- spin_unlock(&prtd->lock);
-
- pr_debug("Pointer %x %x\n", src, dst);
-
- /* we seem to be getting the odd error from the pcm library due
- * to out-of-bounds pointers. this is maybe due to the dma engine
- * not having loaded the new values for the channel before being
- * callled... (todo - fix )
- */
-
- if (res >= snd_pcm_lib_buffer_bytes(substream)) {
- if (res == snd_pcm_lib_buffer_bytes(substream))
- res = 0;
- }
-
- return bytes_to_frames(substream->runtime, res);
-}
-
-static int s3c_dma_open(struct snd_pcm_substream *substream)
-{
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct s3c24xx_runtime_data *prtd;
-
- pr_debug("Entered %s\n", __func__);
-
- snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
- snd_soc_set_runtime_hwparams(substream, &s3c_dma_hardware);
-
- prtd = kzalloc(sizeof(struct s3c24xx_runtime_data), GFP_KERNEL);
- if (prtd == NULL)
- return -ENOMEM;
-
- spin_lock_init(&prtd->lock);
-
- runtime->private_data = prtd;
- return 0;
-}
-
-static int s3c_dma_close(struct snd_pcm_substream *substream)
-{
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct s3c24xx_runtime_data *prtd = runtime->private_data;
-
- pr_debug("Entered %s\n", __func__);
-
- if (!prtd)
- pr_debug("s3c_dma_close called with prtd == NULL\n");
-
- kfree(prtd);
-
- return 0;
-}
-
-static int s3c_dma_mmap(struct snd_pcm_substream *substream,
- struct vm_area_struct *vma)
-{
- struct snd_pcm_runtime *runtime = substream->runtime;
-
- pr_debug("Entered %s\n", __func__);
-
- return dma_mmap_writecombine(substream->pcm->card->dev, vma,
- runtime->dma_area,
- runtime->dma_addr,
- runtime->dma_bytes);
-}
-
-static struct snd_pcm_ops s3c_dma_ops = {
- .open = s3c_dma_open,
- .close = s3c_dma_close,
- .ioctl = snd_pcm_lib_ioctl,
- .hw_params = s3c_dma_hw_params,
- .hw_free = s3c_dma_hw_free,
- .prepare = s3c_dma_prepare,
- .trigger = s3c_dma_trigger,
- .pointer = s3c_dma_pointer,
- .mmap = s3c_dma_mmap,
-};
-
-static int s3c_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
-{
- struct snd_pcm_substream *substream = pcm->streams[stream].substream;
- struct snd_dma_buffer *buf = &substream->dma_buffer;
- size_t size = s3c_dma_hardware.buffer_bytes_max;
-
- pr_debug("Entered %s\n", __func__);
-
- buf->dev.type = SNDRV_DMA_TYPE_DEV;
- buf->dev.dev = pcm->card->dev;
- buf->private_data = NULL;
- buf->area = dma_alloc_writecombine(pcm->card->dev, size,
- &buf->addr, GFP_KERNEL);
- if (!buf->area)
- return -ENOMEM;
- buf->bytes = size;
- return 0;
-}
-
-static void s3c_dma_free_dma_buffers(struct snd_pcm *pcm)
-{
- struct snd_pcm_substream *substream;
- struct snd_dma_buffer *buf;
- int stream;
-
- pr_debug("Entered %s\n", __func__);
-
- for (stream = 0; stream < 2; stream++) {
- substream = pcm->streams[stream].substream;
- if (!substream)
- continue;
-
- buf = &substream->dma_buffer;
- if (!buf->area)
- continue;
-
- dma_free_writecombine(pcm->card->dev, buf->bytes,
- buf->area, buf->addr);
- buf->area = NULL;
- }
-}
-
-static u64 s3c_dma_mask = DMA_BIT_MASK(32);
-
-static int s3c_dma_new(struct snd_card *card,
- struct snd_soc_dai *dai, struct snd_pcm *pcm)
-{
- int ret = 0;
-
- pr_debug("Entered %s\n", __func__);
-
- if (!card->dev->dma_mask)
- card->dev->dma_mask = &s3c_dma_mask;
- if (!card->dev->coherent_dma_mask)
- card->dev->coherent_dma_mask = 0xffffffff;
-
- if (dai->driver->playback.channels_min) {
- ret = s3c_preallocate_dma_buffer(pcm,
- SNDRV_PCM_STREAM_PLAYBACK);
- if (ret)
- goto out;
- }
-
- if (dai->driver->capture.channels_min) {
- ret = s3c_preallocate_dma_buffer(pcm,
- SNDRV_PCM_STREAM_CAPTURE);
- if (ret)
- goto out;
- }
- out:
- return ret;
-}
-
-static struct snd_soc_platform_driver s3c24xx_soc_platform = {
- .ops = &s3c_dma_ops,
- .pcm_new = s3c_dma_new,
- .pcm_free = s3c_dma_free_dma_buffers,
-};
-
-static int __devinit s3c24xx_soc_platform_probe(struct platform_device *pdev)
-{
- return snd_soc_register_platform(&pdev->dev, &s3c24xx_soc_platform);
-}
-
-static int __devexit s3c24xx_soc_platform_remove(struct platform_device *pdev)
-{
- snd_soc_unregister_platform(&pdev->dev);
- return 0;
-}
-
-static struct platform_driver s3c24xx_pcm_driver = {
- .driver = {
- .name = "samsung-audio",
- .owner = THIS_MODULE,
- },
-
- .probe = s3c24xx_soc_platform_probe,
- .remove = __devexit_p(s3c24xx_soc_platform_remove),
-};
-
-static int __init snd_s3c24xx_pcm_init(void)
-{
- return platform_driver_register(&s3c24xx_pcm_driver);
-}
-module_init(snd_s3c24xx_pcm_init);
-
-static void __exit snd_s3c24xx_pcm_exit(void)
-{
- platform_driver_unregister(&s3c24xx_pcm_driver);
-}
-module_exit(snd_s3c24xx_pcm_exit);
-
-MODULE_AUTHOR("Ben Dooks, <ben(a)simtec.co.uk>");
-MODULE_DESCRIPTION("Samsung S3C Audio DMA module");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:samsung-audio");
diff --git a/sound/soc/s3c24xx/s3c-dma.h b/sound/soc/s3c24xx/s3c-dma.h
deleted file mode 100644
index 748c07d..0000000
--- a/sound/soc/s3c24xx/s3c-dma.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * s3c-dma.h --
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * ALSA PCM interface for the Samsung S3C24xx CPU
- */
-
-#ifndef _S3C_AUDIO_H
-#define _S3C_AUDIO_H
-
-#define ST_RUNNING (1<<0)
-#define ST_OPENED (1<<1)
-
-struct s3c_dma_params {
- struct s3c2410_dma_client *client; /* stream identifier */
- int channel; /* Channel ID */
- dma_addr_t dma_addr;
- int dma_size; /* Size of the DMA transfer */
-};
-
-#define S3C24XX_DAI_I2S 0
-
-/* platform data */
-extern struct snd_ac97_bus_ops s3c24xx_ac97_ops;
-
-#endif
diff --git a/sound/soc/s3c24xx/s3c-i2s-v2.c b/sound/soc/s3c24xx/s3c-i2s-v2.c
index b3866d5..c471431 100644
--- a/sound/soc/s3c24xx/s3c-i2s-v2.c
+++ b/sound/soc/s3c24xx/s3c-i2s-v2.c
@@ -28,7 +28,7 @@
#include "regs-i2s-v2.h"
#include "s3c-i2s-v2.h"
-#include "s3c-dma.h"
+#include "dma.h"
#undef S3C_IIS_V2_SUPPORTED
diff --git a/sound/soc/s3c24xx/s3c-pcm.c b/sound/soc/s3c24xx/s3c-pcm.c
index 2e020e1..e111d23 100644
--- a/sound/soc/s3c24xx/s3c-pcm.c
+++ b/sound/soc/s3c24xx/s3c-pcm.c
@@ -29,7 +29,7 @@
#include <plat/audio.h>
#include <plat/dma.h>
-#include "s3c-dma.h"
+#include "dma.h"
#include "s3c-pcm.h"
static struct s3c2410_dma_client s3c_pcm_dma_client_out = {
diff --git a/sound/soc/s3c24xx/s3c2412-i2s.c b/sound/soc/s3c24xx/s3c2412-i2s.c
index 4a861cf..d953ff4 100644
--- a/sound/soc/s3c24xx/s3c2412-i2s.c
+++ b/sound/soc/s3c24xx/s3c2412-i2s.c
@@ -35,7 +35,7 @@
#include <mach/regs-gpio.h>
#include <mach/dma.h>
-#include "s3c-dma.h"
+#include "dma.h"
#include "regs-i2s-v2.h"
#include "s3c2412-i2s.h"
diff --git a/sound/soc/s3c24xx/s3c24xx-i2s.c b/sound/soc/s3c24xx/s3c24xx-i2s.c
index e060daa..13e41ed 100644
--- a/sound/soc/s3c24xx/s3c24xx-i2s.c
+++ b/sound/soc/s3c24xx/s3c24xx-i2s.c
@@ -38,7 +38,7 @@
#include <plat/regs-iis.h>
-#include "s3c-dma.h"
+#include "dma.h"
#include "s3c24xx-i2s.h"
static struct s3c2410_dma_client s3c24xx_dma_client_out = {
diff --git a/sound/soc/s3c24xx/s3c24xx_simtec.c b/sound/soc/s3c24xx/s3c24xx_simtec.c
index c4c1114..3f052a5 100644
--- a/sound/soc/s3c24xx/s3c24xx_simtec.c
+++ b/sound/soc/s3c24xx/s3c24xx_simtec.c
@@ -21,7 +21,7 @@
#include <plat/audio-simtec.h>
-#include "s3c-dma.h"
+#include "dma.h"
#include "s3c24xx-i2s.h"
#include "s3c24xx_simtec.h"
diff --git a/sound/soc/s3c24xx/s3c24xx_simtec_hermes.c b/sound/soc/s3c24xx/s3c24xx_simtec_hermes.c
index 5180c2a..8b246ab 100644
--- a/sound/soc/s3c24xx/s3c24xx_simtec_hermes.c
+++ b/sound/soc/s3c24xx/s3c24xx_simtec_hermes.c
@@ -18,7 +18,7 @@
#include <plat/audio-simtec.h>
-#include "s3c-dma.h"
+#include "dma.h"
#include "s3c24xx-i2s.h"
#include "s3c24xx_simtec.h"
diff --git a/sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c b/sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c
index 7a7bb53..a922e1e 100644
--- a/sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c
+++ b/sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c
@@ -18,7 +18,7 @@
#include <plat/audio-simtec.h>
-#include "s3c-dma.h"
+#include "dma.h"
#include "s3c24xx-i2s.h"
#include "s3c24xx_simtec.h"
diff --git a/sound/soc/s3c24xx/s3c24xx_uda134x.c b/sound/soc/s3c24xx/s3c24xx_uda134x.c
index 50d44fa..87eeb46 100644
--- a/sound/soc/s3c24xx/s3c24xx_uda134x.c
+++ b/sound/soc/s3c24xx/s3c24xx_uda134x.c
@@ -24,7 +24,7 @@
#include <plat/regs-iis.h>
-#include "s3c-dma.h"
+#include "dma.h"
#include "s3c24xx-i2s.h"
#include "../codecs/uda134x.h"
diff --git a/sound/soc/s3c24xx/s3c64xx-i2s-v4.c b/sound/soc/s3c24xx/s3c64xx-i2s-v4.c
index a962847..46b65d7 100644
--- a/sound/soc/s3c24xx/s3c64xx-i2s-v4.c
+++ b/sound/soc/s3c24xx/s3c64xx-i2s-v4.c
@@ -21,7 +21,7 @@
#include <mach/map.h>
#include <mach/dma.h>
-#include "s3c-dma.h"
+#include "dma.h"
#include "regs-i2s-v2.h"
#include "s3c64xx-i2s.h"
diff --git a/sound/soc/s3c24xx/s3c64xx-i2s.c b/sound/soc/s3c24xx/s3c64xx-i2s.c
index ae7acb6..0288d4e 100644
--- a/sound/soc/s3c24xx/s3c64xx-i2s.c
+++ b/sound/soc/s3c24xx/s3c64xx-i2s.c
@@ -25,7 +25,7 @@
#include <mach/map.h>
#include <mach/dma.h>
-#include "s3c-dma.h"
+#include "dma.h"
#include "regs-i2s-v2.h"
#include "s3c64xx-i2s.h"
diff --git a/sound/soc/s3c24xx/smartq_wm8987.c b/sound/soc/s3c24xx/smartq_wm8987.c
index 863631a..1d55312 100644
--- a/sound/soc/s3c24xx/smartq_wm8987.c
+++ b/sound/soc/s3c24xx/smartq_wm8987.c
@@ -24,7 +24,7 @@
#include <asm/mach-types.h>
-#include "s3c-dma.h"
+#include "dma.h"
#include "s3c64xx-i2s.h"
#include "../codecs/wm8750.h"
diff --git a/sound/soc/s3c24xx/smdk2443_wm9710.c b/sound/soc/s3c24xx/smdk2443_wm9710.c
index 911bb60..c50d19c 100644
--- a/sound/soc/s3c24xx/smdk2443_wm9710.c
+++ b/sound/soc/s3c24xx/smdk2443_wm9710.c
@@ -19,7 +19,7 @@
#include <sound/soc.h>
#include <sound/soc-dapm.h>
-#include "s3c-dma.h"
+#include "dma.h"
#include "s3c-ac97.h"
static struct snd_soc_card smdk2443;
diff --git a/sound/soc/s3c24xx/smdk64xx_wm8580.c b/sound/soc/s3c24xx/smdk64xx_wm8580.c
index 7e75c8d..9ddc964 100644
--- a/sound/soc/s3c24xx/smdk64xx_wm8580.c
+++ b/sound/soc/s3c24xx/smdk64xx_wm8580.c
@@ -19,7 +19,7 @@
#include <sound/soc-dapm.h>
#include "../codecs/wm8580.h"
-#include "s3c-dma.h"
+#include "dma.h"
#include "s3c64xx-i2s.h"
/*
diff --git a/sound/soc/s3c24xx/smdk_spdif.c b/sound/soc/s3c24xx/smdk_spdif.c
index 082b88d..4fc6a9f 100644
--- a/sound/soc/s3c24xx/smdk_spdif.c
+++ b/sound/soc/s3c24xx/smdk_spdif.c
@@ -18,7 +18,7 @@
#include <sound/soc.h>
-#include "s3c-dma.h"
+#include "dma.h"
#include "spdif.h"
/* Audio clock settings are belonged to board specific part. Every
diff --git a/sound/soc/s3c24xx/smdk_wm9713.c b/sound/soc/s3c24xx/smdk_wm9713.c
index ea96a51..80f2aef 100644
--- a/sound/soc/s3c24xx/smdk_wm9713.c
+++ b/sound/soc/s3c24xx/smdk_wm9713.c
@@ -15,7 +15,7 @@
#include <linux/device.h>
#include <sound/soc.h>
-#include "s3c-dma.h"
+#include "dma.h"
#include "s3c-ac97.h"
static struct snd_soc_card smdk;
diff --git a/sound/soc/s3c24xx/spdif.c b/sound/soc/s3c24xx/spdif.c
index ce554e9..dc85df3 100644
--- a/sound/soc/s3c24xx/spdif.c
+++ b/sound/soc/s3c24xx/spdif.c
@@ -20,7 +20,7 @@
#include <plat/audio.h>
#include <mach/dma.h>
-#include "s3c-dma.h"
+#include "dma.h"
#include "spdif.h"
/* Registers */
--
1.6.2.5
1
0
From: Jassi Brar <jassi.brar(a)samsung.com>
Some Samsung SoCs have a PCM(DSP) controller. So the name
s3c24xx-pcm-audio for DMA driver is not very appropraite.
This patch moves :-
s3c24xx-pcm-audio -> samsung-audio
Signed-off-by: Jassi Brar <jassi.brar(a)samsung.com>
---
arch/arm/mach-s3c64xx/dev-audio.c | 2 +-
arch/arm/plat-s3c24xx/devs.c | 2 +-
sound/soc/s3c24xx/goni_wm8994.c | 4 ++--
sound/soc/s3c24xx/jive_wm8750.c | 2 +-
sound/soc/s3c24xx/ln2440sbc_alc650.c | 2 +-
sound/soc/s3c24xx/neo1973_gta02_wm8753.c | 4 ++--
sound/soc/s3c24xx/neo1973_wm8753.c | 4 ++--
sound/soc/s3c24xx/rx1950_uda1380.c | 2 +-
sound/soc/s3c24xx/s3c-dma.c | 4 ++--
sound/soc/s3c24xx/s3c24xx_simtec_hermes.c | 2 +-
sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c | 2 +-
sound/soc/s3c24xx/s3c24xx_uda134x.c | 2 +-
sound/soc/s3c24xx/smartq_wm8987.c | 2 +-
sound/soc/s3c24xx/smdk2443_wm9710.c | 2 +-
sound/soc/s3c24xx/smdk64xx_wm8580.c | 4 ++--
sound/soc/s3c24xx/smdk_spdif.c | 2 +-
sound/soc/s3c24xx/smdk_wm9713.c | 2 +-
17 files changed, 22 insertions(+), 22 deletions(-)
diff --git a/arch/arm/mach-s3c64xx/dev-audio.c b/arch/arm/mach-s3c64xx/dev-audio.c
index 3838335..c45cc37 100644
--- a/arch/arm/mach-s3c64xx/dev-audio.c
+++ b/arch/arm/mach-s3c64xx/dev-audio.c
@@ -340,7 +340,7 @@ void __init s3c64xx_ac97_setup_gpio(int num)
static u64 s3c_device_audio_dmamask = 0xffffffffUL;
struct platform_device s3c_device_pcm = {
- .name = "s3c24xx-pcm-audio",
+ .name = "samsung-audio",
.id = -1,
.dev = {
.dma_mask = &s3c_device_audio_dmamask,
diff --git a/arch/arm/plat-s3c24xx/devs.c b/arch/arm/plat-s3c24xx/devs.c
index 2f91057..4bf0b39 100644
--- a/arch/arm/plat-s3c24xx/devs.c
+++ b/arch/arm/plat-s3c24xx/devs.c
@@ -264,7 +264,7 @@ EXPORT_SYMBOL(s3c_device_iis);
static u64 s3c_device_audio_dmamask = 0xffffffffUL;
struct platform_device s3c_device_pcm = {
- .name = "s3c24xx-pcm-audio",
+ .name = "samsung-audio",
.id = -1,
.dev = {
.dma_mask = &s3c_device_audio_dmamask,
diff --git a/sound/soc/s3c24xx/goni_wm8994.c b/sound/soc/s3c24xx/goni_wm8994.c
index ef22f14..c568f69 100644
--- a/sound/soc/s3c24xx/goni_wm8994.c
+++ b/sound/soc/s3c24xx/goni_wm8994.c
@@ -251,7 +251,7 @@ static struct snd_soc_dai_link goni_dai[] = {
.stream_name = "WM8994 HiFi",
.cpu_dai_name = "s3c64xx-i2s-v4",
.codec_dai_name = "wm8994-hifi",
- .platform_name = "s3c24xx-pcm-audio",
+ .platform_name = "samsung-audio",
.codec_name = "wm8994-codec.0-0x1a",
.init = goni_wm8994_init,
.ops = &goni_hifi_ops,
@@ -260,7 +260,7 @@ static struct snd_soc_dai_link goni_dai[] = {
.stream_name = "Voice",
.cpu_dai_name = "goni-voice-dai",
.codec_dai_name = "wm8994-voice",
- .platform_name = "s3c24xx-pcm-audio",
+ .platform_name = "samsung-audio",
.codec_name = "wm8994-codec.0-0x1a",
.ops = &goni_voice_ops,
},
diff --git a/sound/soc/s3c24xx/jive_wm8750.c b/sound/soc/s3c24xx/jive_wm8750.c
index 49605cd..7a6b0fa 100644
--- a/sound/soc/s3c24xx/jive_wm8750.c
+++ b/sound/soc/s3c24xx/jive_wm8750.c
@@ -141,7 +141,7 @@ static struct snd_soc_dai_link jive_dai = {
.stream_name = "WM8750",
.cpu_dai_name = "s3c2412-i2s",
.codec_dai_name = "wm8750-hifi",
- .platform_name = "s3c24xx-pcm-audio",
+ .platform_name = "samsung-audio",
.codec_name = "wm8750-codec.0-0x1a",
.init = jive_wm8750_init,
.ops = &jive_ops,
diff --git a/sound/soc/s3c24xx/ln2440sbc_alc650.c b/sound/soc/s3c24xx/ln2440sbc_alc650.c
index abe64ab..6b7bb38 100644
--- a/sound/soc/s3c24xx/ln2440sbc_alc650.c
+++ b/sound/soc/s3c24xx/ln2440sbc_alc650.c
@@ -35,7 +35,7 @@ static struct snd_soc_dai_link ln2440sbc_dai[] = {
.cpu_dai_name = "s3c-ac97",
.codec_dai_name = "ac97-hifi",
.codec_name = "ac97-codec",
- .platform_name = "s3c24xx-pcm-audio",
+ .platform_name = "samsung-audio",
},
};
diff --git a/sound/soc/s3c24xx/neo1973_gta02_wm8753.c b/sound/soc/s3c24xx/neo1973_gta02_wm8753.c
index c457bfd..a9a4bbb 100644
--- a/sound/soc/s3c24xx/neo1973_gta02_wm8753.c
+++ b/sound/soc/s3c24xx/neo1973_gta02_wm8753.c
@@ -400,7 +400,7 @@ static struct snd_soc_dai_link neo1973_gta02_dai[] = {
.cpu_dai_name = "s3c24xx-i2s",
.codec_dai_name = "wm8753-hifi",
.init = neo1973_gta02_wm8753_init,
- .platform_name = "s3c24xx-pcm-audio",
+ .platform_name = "samsung-audio",
.codec_name = "wm8753-codec.0-0x1a",
.ops = &neo1973_gta02_hifi_ops,
},
@@ -411,7 +411,7 @@ static struct snd_soc_dai_link neo1973_gta02_dai[] = {
.codec_dai_name = "wm8753-voice",
.ops = &neo1973_gta02_voice_ops,
.codec_name = "wm8753-codec.0-0x1a",
- .platform_name = "s3c24xx-pcm-audio",
+ .platform_name = "samsung-audio",
},
};
diff --git a/sound/soc/s3c24xx/neo1973_wm8753.c b/sound/soc/s3c24xx/neo1973_wm8753.c
index d7a39a0..d5e4148 100644
--- a/sound/soc/s3c24xx/neo1973_wm8753.c
+++ b/sound/soc/s3c24xx/neo1973_wm8753.c
@@ -556,7 +556,7 @@ static struct snd_soc_dai_link neo1973_dai[] = {
{ /* Hifi Playback - for similatious use with voice below */
.name = "WM8753",
.stream_name = "WM8753 HiFi",
- .platform_name = "s3c24xx-pcm-audio",
+ .platform_name = "samsung-audio",
.cpu_dai_name = "s3c24xx-i2s",
.codec_dai_name = "wm8753-hifi",
.codec_name = "wm8753-codec.0-0x1a",
@@ -566,7 +566,7 @@ static struct snd_soc_dai_link neo1973_dai[] = {
{ /* Voice via BT */
.name = "Bluetooth",
.stream_name = "Voice",
- .platform_name = "s3c24xx-pcm-audio",
+ .platform_name = "samsung-audio",
.cpu_dai_name = "bluetooth-dai",
.codec_dai_name = "wm8753-voice",
.codec_name = "wm8753-codec.0-0x1a",
diff --git a/sound/soc/s3c24xx/rx1950_uda1380.c b/sound/soc/s3c24xx/rx1950_uda1380.c
index ffd5cf2..99bb86e 100644
--- a/sound/soc/s3c24xx/rx1950_uda1380.c
+++ b/sound/soc/s3c24xx/rx1950_uda1380.c
@@ -96,7 +96,7 @@ static struct snd_soc_dai_link rx1950_uda1380_dai[] = {
.cpu_dai_name = "s3c24xx-iis",
.codec_dai_name = "uda1380-hifi",
.init = rx1950_uda1380_init,
- .platform_name = "s3c24xx-pcm-audio",
+ .platform_name = "samsung-audio",
.codec_name = "uda1380-codec.0-001a",
.ops = &rx1950_ops,
},
diff --git a/sound/soc/s3c24xx/s3c-dma.c b/sound/soc/s3c24xx/s3c-dma.c
index 54bff83..0c1cd6c 100644
--- a/sound/soc/s3c24xx/s3c-dma.c
+++ b/sound/soc/s3c24xx/s3c-dma.c
@@ -477,7 +477,7 @@ static int __devexit s3c24xx_soc_platform_remove(struct platform_device *pdev)
static struct platform_driver s3c24xx_pcm_driver = {
.driver = {
- .name = "s3c24xx-pcm-audio",
+ .name = "samsung-audio",
.owner = THIS_MODULE,
},
@@ -500,4 +500,4 @@ module_exit(snd_s3c24xx_pcm_exit);
MODULE_AUTHOR("Ben Dooks, <ben(a)simtec.co.uk>");
MODULE_DESCRIPTION("Samsung S3C Audio DMA module");
MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:s3c24xx-pcm-audio");
+MODULE_ALIAS("platform:samsung-audio");
diff --git a/sound/soc/s3c24xx/s3c24xx_simtec_hermes.c b/sound/soc/s3c24xx/s3c24xx_simtec_hermes.c
index f884537..5180c2a 100644
--- a/sound/soc/s3c24xx/s3c24xx_simtec_hermes.c
+++ b/sound/soc/s3c24xx/s3c24xx_simtec_hermes.c
@@ -99,7 +99,7 @@ static struct snd_soc_dai_link simtec_dai_aic33 = {
.codec_name = "tlv320aic3x-codec.0-0x1a",
.cpu_dai_name = "s3c24xx-i2s",
.codec_dai_name = "tlv320aic3x-hifi",
- .platform_name = "s3c24xx-pcm-audio",
+ .platform_name = "samsung-audio",
.init = simtec_hermes_init,
};
diff --git a/sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c b/sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c
index c096759..7a7bb53 100644
--- a/sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c
+++ b/sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c
@@ -88,7 +88,7 @@ static struct snd_soc_dai_link simtec_dai_aic23 = {
.codec_name = "tlv320aic3x-codec.0-0x1a",
.cpu_dai_name = "s3c24xx-i2s",
.codec_dai_name = "tlv320aic3x-hifi",
- .platform_name = "s3c24xx-pcm-audio",
+ .platform_name = "samsung-audio",
.init = simtec_tlv320aic23_init,
};
diff --git a/sound/soc/s3c24xx/s3c24xx_uda134x.c b/sound/soc/s3c24xx/s3c24xx_uda134x.c
index bd48ffb..50d44fa 100644
--- a/sound/soc/s3c24xx/s3c24xx_uda134x.c
+++ b/sound/soc/s3c24xx/s3c24xx_uda134x.c
@@ -231,7 +231,7 @@ static struct snd_soc_dai_link s3c24xx_uda134x_dai_link = {
.codec_dai_name = "uda134x-hifi",
.cpu_dai_name = "s3c24xx-i2s",
.ops = &s3c24xx_uda134x_ops,
- .platform_name = "s3c24xx-pcm-audio",
+ .platform_name = "samsung-audio",
};
static struct snd_soc_card snd_soc_s3c24xx_uda134x = {
diff --git a/sound/soc/s3c24xx/smartq_wm8987.c b/sound/soc/s3c24xx/smartq_wm8987.c
index dd20ca7..863631a 100644
--- a/sound/soc/s3c24xx/smartq_wm8987.c
+++ b/sound/soc/s3c24xx/smartq_wm8987.c
@@ -213,7 +213,7 @@ static struct snd_soc_dai_link smartq_dai[] = {
.stream_name = "SmartQ Hi-Fi",
.cpu_dai_name = "s3c64xx-i2s.0",
.codec_dai_name = "wm8750-hifi",
- .platform_name = "s3c24xx-pcm-audio",
+ .platform_name = "samsung-audio",
.codec_name = "wm8750-codec.0-0x1a",
.init = smartq_wm8987_init,
.ops = &smartq_hifi_ops,
diff --git a/sound/soc/s3c24xx/smdk2443_wm9710.c b/sound/soc/s3c24xx/smdk2443_wm9710.c
index 4613288..911bb60 100644
--- a/sound/soc/s3c24xx/smdk2443_wm9710.c
+++ b/sound/soc/s3c24xx/smdk2443_wm9710.c
@@ -31,7 +31,7 @@ static struct snd_soc_dai_link smdk2443_dai[] = {
.cpu_dai_name = "s3c-ac97",
.codec_dai_name = "ac97-hifi",
.codec_name = "ac97-codec",
- .platform_name = "s3c24xx-pcm-audio",
+ .platform_name = "samsung-audio",
},
};
diff --git a/sound/soc/s3c24xx/smdk64xx_wm8580.c b/sound/soc/s3c24xx/smdk64xx_wm8580.c
index 052e499..7e75c8d 100644
--- a/sound/soc/s3c24xx/smdk64xx_wm8580.c
+++ b/sound/soc/s3c24xx/smdk64xx_wm8580.c
@@ -224,7 +224,7 @@ static struct snd_soc_dai_link smdk64xx_dai[] = {
.stream_name = "Playback",
.cpu_dai_name = "s3c64xx-iis-v4",
.codec_dai_name = "wm8580-hifi-playback",
- .platform_name = "s3c24xx-pcm-audio",
+ .platform_name = "samsung-audio",
.codec_name = "wm8580-codec.0-001b",
.init = smdk64xx_wm8580_init_paifrx,
.ops = &smdk64xx_ops,
@@ -234,7 +234,7 @@ static struct snd_soc_dai_link smdk64xx_dai[] = {
.stream_name = "Capture",
.cpu_dai_name = "s3c64xx-iis-v4",
.codec_dai_name = "wm8580-hifi-capture",
- .platform_name = "s3c24xx-pcm-audio",
+ .platform_name = "samsung-audio",
.codec_name = "wm8580-codec.0-001b",
.init = smdk64xx_wm8580_init_paiftx,
.ops = &smdk64xx_ops,
diff --git a/sound/soc/s3c24xx/smdk_spdif.c b/sound/soc/s3c24xx/smdk_spdif.c
index f31d22a..082b88d 100644
--- a/sound/soc/s3c24xx/smdk_spdif.c
+++ b/sound/soc/s3c24xx/smdk_spdif.c
@@ -157,7 +157,7 @@ static struct snd_soc_card smdk;
static struct snd_soc_dai_link smdk_dai = {
.name = "S/PDIF",
.stream_name = "S/PDIF PCM Playback",
- .platform_name = "s3c24xx-pcm-audio",
+ .platform_name = "samsung-audio",
.cpu_dai_name = "samsung-spdif",
.codec_dai_name = "dit-hifi",
.codec_name = "spdif-dit",
diff --git a/sound/soc/s3c24xx/smdk_wm9713.c b/sound/soc/s3c24xx/smdk_wm9713.c
index 33ba8fd..ea96a51 100644
--- a/sound/soc/s3c24xx/smdk_wm9713.c
+++ b/sound/soc/s3c24xx/smdk_wm9713.c
@@ -45,7 +45,7 @@ static struct snd_soc_card smdk;
static struct snd_soc_dai_link smdk_dai = {
.name = "AC97",
.stream_name = "AC97 PCM",
- .platform_name = "s3c24xx-pcm-audio",
+ .platform_name = "samsung-audio",
.cpu_dai_name = "s3c-ac97",
.codec_dai_name = "wm9713-hifi",
.codec_name = "wm9713-codec",
--
1.6.2.5
1
0

19 Oct '10
From: Jassi Brar <jassi.brar(a)samsung.com>
AQUILA and GONI are essentially the same h/w w.r.t ASoC.
They only differ by the fact that GONI has stereo speaker-out
whereas AQUILA has mono.
The difference can easily be handled in the same MACHINE driver
by making machine-specific runtime changes.
Signed-off-by: Jassi Brar <jassi.brar(a)samsung.com>
---
sound/soc/s3c24xx/Kconfig | 17 +--
sound/soc/s3c24xx/Makefile | 4 +-
sound/soc/s3c24xx/aquila_wm8994.c | 295 -------------------------------------
sound/soc/s3c24xx/goni_wm8994.c | 19 +++-
4 files changed, 23 insertions(+), 312 deletions(-)
delete mode 100644 sound/soc/s3c24xx/aquila_wm8994.c
diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig
index 8a6b53c..6efdf65 100644
--- a/sound/soc/s3c24xx/Kconfig
+++ b/sound/soc/s3c24xx/Kconfig
@@ -144,22 +144,13 @@ config SND_S3C64XX_SOC_SMARTQ
select SND_S3C64XX_SOC_I2S
select SND_SOC_WM8750
-config SND_S5PC110_SOC_AQUILA_WM8994
- tristate "SoC I2S Audio support for AQUILA - WM8994"
- depends on SND_S3C24XX_SOC && MACH_AQUILA
+config SND_SOC_GONI_AQUILA_WM8994
+ tristate "SoC I2S Audio support for AQUILA/GONI - WM8994"
+ depends on SND_S3C24XX_SOC && (MACH_GONI || MACH_AQUILA)
select SND_S3C64XX_SOC_I2S_V4
select SND_SOC_WM8994
help
- Say Y if you want to add support for SoC audio on aquila
- with the WM8994.
-
-config SND_S5PV210_SOC_GONI_WM8994
- tristate "SoC I2S Audio support for GONI - WM8994"
- depends on SND_S3C24XX_SOC && MACH_GONI
- select SND_S3C64XX_SOC_I2S_V4
- select SND_SOC_WM8994
- help
- Say Y if you want to add support for SoC audio on goni
+ Say Y if you want to add support for SoC audio on goni or aquila
with the WM8994.
config SND_SOC_SMDK_SPDIF
diff --git a/sound/soc/s3c24xx/Makefile b/sound/soc/s3c24xx/Makefile
index ee8f41d..4e232f1 100644
--- a/sound/soc/s3c24xx/Makefile
+++ b/sound/soc/s3c24xx/Makefile
@@ -33,7 +33,6 @@ snd-soc-rx1950-uda1380-objs := rx1950_uda1380.o
snd-soc-smdk64xx-wm8580-objs := smdk64xx_wm8580.o
snd-soc-smdk-wm9713-objs := smdk_wm9713.o
snd-soc-s3c64xx-smartq-wm8987-objs := smartq_wm8987.o
-snd-soc-aquila-wm8994-objs := aquila_wm8994.o
snd-soc-goni-wm8994-objs := goni_wm8994.o
snd-soc-smdk-spdif-objs := smdk_spdif.o
@@ -50,6 +49,5 @@ obj-$(CONFIG_SND_S3C24XX_SOC_RX1950_UDA1380) += snd-soc-rx1950-uda1380.o
obj-$(CONFIG_SND_S3C64XX_SOC_WM8580) += snd-soc-smdk64xx-wm8580.o
obj-$(CONFIG_SND_SOC_SMDK_WM9713) += snd-soc-smdk-wm9713.o
obj-$(CONFIG_SND_S3C64XX_SOC_SMARTQ) += snd-soc-s3c64xx-smartq-wm8987.o
-obj-$(CONFIG_SND_S5PC110_SOC_AQUILA_WM8994) += snd-soc-aquila-wm8994.o
-obj-$(CONFIG_SND_S5PV210_SOC_GONI_WM8994) += snd-soc-goni-wm8994.o
obj-$(CONFIG_SND_SOC_SMDK_SPDIF) += snd-soc-smdk-spdif.o
+obj-$(CONFIG_SND_SOC_GONI_AQUILA_WM8994) += snd-soc-goni-wm8994.o
diff --git a/sound/soc/s3c24xx/aquila_wm8994.c b/sound/soc/s3c24xx/aquila_wm8994.c
deleted file mode 100644
index 235d197..0000000
--- a/sound/soc/s3c24xx/aquila_wm8994.c
+++ /dev/null
@@ -1,295 +0,0 @@
-/*
- * aquila_wm8994.c
- *
- * Copyright (C) 2010 Samsung Electronics Co.Ltd
- * Author: Chanwoo Choi <cw00.choi(a)samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/io.h>
-#include <linux/platform_device.h>
-#include <sound/soc.h>
-#include <sound/soc-dapm.h>
-#include <sound/jack.h>
-#include <asm/mach-types.h>
-#include <mach/gpio.h>
-#include <mach/regs-clock.h>
-
-#include <linux/mfd/wm8994/core.h>
-#include <linux/mfd/wm8994/registers.h>
-#include "../codecs/wm8994.h"
-#include "s3c-dma.h"
-#include "s3c64xx-i2s.h"
-
-static struct snd_soc_card aquila;
-static struct platform_device *aquila_snd_device;
-
-/* 3.5 pie jack */
-static struct snd_soc_jack jack;
-
-/* 3.5 pie jack detection DAPM pins */
-static struct snd_soc_jack_pin jack_pins[] = {
- {
- .pin = "Headset Mic",
- .mask = SND_JACK_MICROPHONE,
- }, {
- .pin = "Headset Stereophone",
- .mask = SND_JACK_HEADPHONE | SND_JACK_MECHANICAL |
- SND_JACK_AVOUT,
- },
-};
-
-/* 3.5 pie jack detection gpios */
-static struct snd_soc_jack_gpio jack_gpios[] = {
- {
- .gpio = S5PV210_GPH0(6),
- .name = "DET_3.5",
- .report = SND_JACK_HEADSET | SND_JACK_MECHANICAL |
- SND_JACK_AVOUT,
- .debounce_time = 200,
- },
-};
-
-static const struct snd_soc_dapm_widget aquila_dapm_widgets[] = {
- SND_SOC_DAPM_SPK("Ext Spk", NULL),
- SND_SOC_DAPM_SPK("Ext Rcv", NULL),
- SND_SOC_DAPM_HP("Headset Stereophone", NULL),
- SND_SOC_DAPM_MIC("Headset Mic", NULL),
- SND_SOC_DAPM_MIC("Main Mic", NULL),
- SND_SOC_DAPM_MIC("2nd Mic", NULL),
- SND_SOC_DAPM_LINE("Radio In", NULL),
-};
-
-static const struct snd_soc_dapm_route aquila_dapm_routes[] = {
- {"Ext Spk", NULL, "SPKOUTLP"},
- {"Ext Spk", NULL, "SPKOUTLN"},
-
- {"Ext Rcv", NULL, "HPOUT2N"},
- {"Ext Rcv", NULL, "HPOUT2P"},
-
- {"Headset Stereophone", NULL, "HPOUT1L"},
- {"Headset Stereophone", NULL, "HPOUT1R"},
-
- {"IN1RN", NULL, "Headset Mic"},
- {"IN1RP", NULL, "Headset Mic"},
-
- {"IN1RN", NULL, "2nd Mic"},
- {"IN1RP", NULL, "2nd Mic"},
-
- {"IN1LN", NULL, "Main Mic"},
- {"IN1LP", NULL, "Main Mic"},
-
- {"IN2LN", NULL, "Radio In"},
- {"IN2RN", NULL, "Radio In"},
-};
-
-static int aquila_wm8994_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_soc_codec *codec = rtd->codec;
- int ret;
-
- /* add aquila specific widgets */
- snd_soc_dapm_new_controls(codec, aquila_dapm_widgets,
- ARRAY_SIZE(aquila_dapm_widgets));
-
- /* set up aquila specific audio routes */
- snd_soc_dapm_add_routes(codec, aquila_dapm_routes,
- ARRAY_SIZE(aquila_dapm_routes));
-
- /* set endpoints to not connected */
- snd_soc_dapm_nc_pin(codec, "IN2LP:VXRN");
- snd_soc_dapm_nc_pin(codec, "IN2RP:VXRP");
- snd_soc_dapm_nc_pin(codec, "LINEOUT1N");
- snd_soc_dapm_nc_pin(codec, "LINEOUT1P");
- snd_soc_dapm_nc_pin(codec, "LINEOUT2N");
- snd_soc_dapm_nc_pin(codec, "LINEOUT2P");
- snd_soc_dapm_nc_pin(codec, "SPKOUTRN");
- snd_soc_dapm_nc_pin(codec, "SPKOUTRP");
-
- snd_soc_dapm_sync(codec);
-
- /* Headset jack detection */
- ret = snd_soc_jack_new(&aquila, "Headset Jack",
- SND_JACK_HEADSET | SND_JACK_MECHANICAL | SND_JACK_AVOUT,
- &jack);
- if (ret)
- return ret;
-
- ret = snd_soc_jack_add_pins(&jack, ARRAY_SIZE(jack_pins), jack_pins);
- if (ret)
- return ret;
-
- ret = snd_soc_jack_add_gpios(&jack, ARRAY_SIZE(jack_gpios), jack_gpios);
- if (ret)
- return ret;
-
- return 0;
-}
-
-static int aquila_hifi_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
-{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- unsigned int pll_out = 24000000;
- int ret = 0;
-
- /* set the cpu DAI configuration */
- ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
- if (ret < 0)
- return ret;
-
- /* set the cpu system clock */
- ret = snd_soc_dai_set_sysclk(cpu_dai, S3C64XX_CLKSRC_PCLK,
- 0, SND_SOC_CLOCK_IN);
- if (ret < 0)
- return ret;
-
- /* set codec DAI configuration */
- ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
- if (ret < 0)
- return ret;
-
- /* set the codec FLL */
- ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL1, 0, pll_out,
- params_rate(params) * 256);
- if (ret < 0)
- return ret;
-
- /* set the codec system clock */
- ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_FLL1,
- params_rate(params) * 256, SND_SOC_CLOCK_IN);
- if (ret < 0)
- return ret;
-
- return 0;
-}
-
-static struct snd_soc_ops aquila_hifi_ops = {
- .hw_params = aquila_hifi_hw_params,
-};
-
-static int aquila_voice_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
-{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->codec_dai;
- unsigned int pll_out = 24000000;
- int ret = 0;
-
- if (params_rate(params) != 8000)
- return -EINVAL;
-
- /* set codec DAI configuration */
- ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_LEFT_J |
- SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_CBM_CFM);
- if (ret < 0)
- return ret;
-
- /* set the codec FLL */
- ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL2, 0, pll_out,
- params_rate(params) * 256);
- if (ret < 0)
- return ret;
-
- /* set the codec system clock */
- ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_FLL2,
- params_rate(params) * 256, SND_SOC_CLOCK_IN);
- if (ret < 0)
- return ret;
-
- return 0;
-}
-
-static struct snd_soc_dai_driver voice_dai = {
- .name = "aquila-voice-dai",
- .playback = {
- .channels_min = 1,
- .channels_max = 2,
- .rates = SNDRV_PCM_RATE_8000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,},
- .capture = {
- .channels_min = 1,
- .channels_max = 2,
- .rates = SNDRV_PCM_RATE_8000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,},
-};
-
-static struct snd_soc_ops aquila_voice_ops = {
- .hw_params = aquila_voice_hw_params,
-};
-
-static struct snd_soc_dai_link aquila_dai[] = {
-{
- .name = "WM8994",
- .stream_name = "WM8994 HiFi",
- .cpu_dai_name = "s3c64xx-i2s-v4",
- .codec_dai_name = "wm8994-hifi",
- .platform_name = "s3c24xx-pcm-audio",
- .codec_name = "wm8994-codec.0-0x1a",
- .init = aquila_wm8994_init,
- .ops = &aquila_hifi_ops,
-}, {
- .name = "WM8994 Voice",
- .stream_name = "Voice",
- .cpu_dai_name = "aquila-voice-dai",
- .codec_dai_name = "wm8994-voice",
- .platform_name = "s3c24xx-pcm-audio",
- .codec_name = "wm8994-codec.0-0x1a",
- .ops = &aquila_voice_ops,
-},
-};
-
-static struct snd_soc_card aquila = {
- .name = "aquila",
- .dai_link = aquila_dai,
- .num_links = ARRAY_SIZE(aquila_dai),
-};
-
-static int __init aquila_init(void)
-{
- int ret;
-
- if (!machine_is_aquila())
- return -ENODEV;
-
- aquila_snd_device = platform_device_alloc("soc-audio", -1);
- if (!aquila_snd_device)
- return -ENOMEM;
-
- /* register voice DAI here */
- ret = snd_soc_register_dai(&aquila_snd_device->dev, &voice_dai);
- if (ret)
- return ret;
-
- platform_set_drvdata(aquila_snd_device, &aquila);
- ret = platform_device_add(aquila_snd_device);
-
- if (ret)
- platform_device_put(aquila_snd_device);
-
- return ret;
-}
-
-static void __exit aquila_exit(void)
-{
- platform_device_unregister(aquila_snd_device);
-}
-
-module_init(aquila_init);
-module_exit(aquila_exit);
-
-/* Module information */
-MODULE_DESCRIPTION("ALSA SoC WM8994 Aquila(S5PC110)");
-MODULE_AUTHOR("Chanwoo Choi <cw00.choi(a)samsung.com>");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/goni_wm8994.c b/sound/soc/s3c24xx/goni_wm8994.c
index 694f702..ef22f14 100644
--- a/sound/soc/s3c24xx/goni_wm8994.c
+++ b/sound/soc/s3c24xx/goni_wm8994.c
@@ -28,6 +28,14 @@
#include "s3c-dma.h"
#include "s3c64xx-i2s.h"
+#define MACHINE_NAME 0
+#define CPU_VOICE_DAI 1
+
+static const char *aquila_str[] = {
+ [MACHINE_NAME] = "aquila",
+ [CPU_VOICE_DAI] = "aquila-voice-dai",
+};
+
static struct snd_soc_card goni;
static struct platform_device *goni_snd_device;
@@ -115,6 +123,11 @@ static int goni_wm8994_init(struct snd_soc_pcm_runtime *rtd)
snd_soc_dapm_nc_pin(codec, "LINEOUT2N");
snd_soc_dapm_nc_pin(codec, "LINEOUT2P");
+ if (machine_is_aquila()) {
+ snd_soc_dapm_nc_pin(codec, "SPKOUTRN");
+ snd_soc_dapm_nc_pin(codec, "SPKOUTRP");
+ }
+
snd_soc_dapm_sync(codec);
/* Headset jack detection */
@@ -263,7 +276,11 @@ static int __init goni_init(void)
{
int ret;
- if (!machine_is_goni())
+ if (machine_is_aquila()) {
+ voice_dai.name = aquila_str[CPU_VOICE_DAI];
+ goni_dai[1].cpu_dai_name = aquila_str[CPU_VOICE_DAI];
+ goni.name = aquila_str[MACHINE_NAME];
+ } else if (!machine_is_goni())
return -ENODEV;
goni_snd_device = platform_device_alloc("soc-audio", -1);
--
1.6.2.5
1
0
Greetings,
I have this emachines em350 notebook, which is equipped with ALC272X
codec (a personal project this time...)
By default the internal mic does not work.
(See also https://bugs.launchpad.net/ubuntu/+source/alsa-driver/+bug/639846)
Using hda_analyzer, The internal mic appears to be a digital mic on NID 12
This change enables it:
Diff for codec 0/0 (0x10ec0272):
---
+++
@@ -312,12 +312,12 @@
0x0c 0x0d* 0x0e
Node 0x22 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In
Amp-In caps: ofs=0x00, nsteps=0x00, stepsize=0x00, mute=1
Amp-In vals: [0x80 0x80] [0x80 0x80] [0x80 0x80] [0x80 0x80] [0x80
0x80] [0x80 0x80] [0x80 0x80] [0x80 0x80] [0x80 0x80] [0x00 0x00]
Connection: 10
0x18 0x19 0x1a 0x1b 0x1d 0x14 0x15 0x16 0x0b 0x12
Node 0x23 [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] [0x80 0x80] [0x80 0x80] [0x80
0x80] [0x80 0x80] [0x80 0x80] [0x80 0x80] [0x80 0x80] [0x80 0x80]
+ 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 0x1d 0x14 0x15 0x16 0x0b 0x13
According to the ALC272 datasheet, there is no feedthrough path from
DMIC to analog out.
Also no
Some of the other controls for this netbook are also superfluous.
It only has (as far as I can make out)
Internal speaker on NID 0x14 (LOUT1 PORT-D)
Internal mic: DMIC on NID 0x12 (DMIC-1/2)
External headphone on NID 0x21 (HP-OUT PORT-I)
External mic on NID 0x18 (MIC1 PORT-B)
So, I'm looking for either an existing model=X to use with this
machine, or how to create a new one?
regards
Eliot
1
0
On Sun, Oct 03, 2010 at 11:22:44AM +0100, Alan Cox wrote:
> > Having things as a series does make things easier for review, reducing
> > reviewer fatigue if nothing else. I've given this a bit of a once
> > over below but not a deep dive - splitting the series would really
> > help with reviewability.
> It really wouldn't help in this case for most people I think. You end up
> with what there is in the original which is a series of patches for old
> code all quite large and just a big one chopped into chunks, followed
> by a series of updates that fix half the bugs you found reviewing the
> first big splat.
IIRC at least one version had a split where the ALSA integration stuff
was separated out from the underlying DSP interface code - that was
pretty helpful since it helps focus on the ALSA specifics.
> I did think about it, but what history we have is fairly basic because
> it was basically written then fired in my direction to help sort out
Yeah, I wasn't thinking about history so much as about helping break
down the areas covered for comprehensibility.
> > To be honest all this stuff looks sufficiently generic that it might
> > be worth considering factoring out an abstraction which can be used by
> > other offload engines - having a standard kernel API for them would
> > be a real win. That's just a nice to have, though.
> Agreed, although gstreamer is pretty good at that it would save work if
> it can be partly generic. It's not trivial however because the offload
Plus the fact that not everyone is using gstreamer at the application
level :/
> interface with suitable firmware loaded does things other than PCM and
> you have very firmware specific interfaces for configuring those.
We ought to be able to come up with something for the core streaming
stuff, though. Like I say, it's just a nice to have though.
> So are you happy for it to go into staging. I'm hoping that way at
> least all the changes will be visible and trackable. I'll start by
> sending GregKH a follow up patch which is a TODO list summary based on
> your feedback
Happy is a strong term but this looks like exactly the sort of stuff
staging is there for so yes, it should go in. Probably best to look for
feedback from at least Takashi and/or Jaroslav as well, but obviously we
can update the TODO later.
I do have some nervousness about the concept of staging for embedded
stuff since I worry that inclusion in staging can send the wrong message
to vendors but that's a completely separate issue to this driver.
5
17

[alsa-devel] [PATCH v3 1/9] davinci: EMAC support for Omapl138-Hawkboard
by vm.rod25@gmail.com 19 Oct '10
by vm.rod25@gmail.com 19 Oct '10
19 Oct '10
From: Victor Rodriguez <vm.rod25(a)gmail.com>
This patch adds EMAC support for the Hawkboard-L138 system
Signed-off-by: Victor Rodriguez <victor.rodriguez(a)sasken.com>
---
arch/arm/mach-davinci/board-omapl138-hawk.c | 49 +++++++++++++++++++++++++++
1 files changed, 49 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-davinci/board-omapl138-hawk.c b/arch/arm/mach-davinci/board-omapl138-hawk.c
index c472dd8..3ae5178 100644
--- a/arch/arm/mach-davinci/board-omapl138-hawk.c
+++ b/arch/arm/mach-davinci/board-omapl138-hawk.c
@@ -19,6 +19,53 @@
#include <mach/cp_intc.h>
#include <mach/da8xx.h>
+#include <mach/mux.h>
+
+#define HAWKBOARD_PHY_ID "0:07"
+
+static short omapl138_hawk_mii_pins[] __initdata = {
+ DA850_MII_TXEN, DA850_MII_TXCLK, DA850_MII_COL, DA850_MII_TXD_3,
+ DA850_MII_TXD_2, DA850_MII_TXD_1, DA850_MII_TXD_0, DA850_MII_RXER,
+ DA850_MII_CRS, DA850_MII_RXCLK, DA850_MII_RXDV, DA850_MII_RXD_3,
+ DA850_MII_RXD_2, DA850_MII_RXD_1, DA850_MII_RXD_0, DA850_MDIO_CLK,
+ DA850_MDIO_D,
+ -1
+};
+
+static int __init omapl138_hawk_config_emac(void)
+{
+ void __iomem *cfgchip3;
+ int ret;
+ u32 val;
+ struct davinci_soc_info *soc_info = &davinci_soc_info;
+
+ if (!machine_is_omapl138_hawkboard())
+ return 0;
+
+ cfgchip3 = DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP3_REG);
+
+ val = __raw_readl(cfgchip3);
+
+ val &= ~BIT(8);
+ ret = davinci_cfg_reg_list(omapl138_hawk_mii_pins);
+ pr_info("EMAC: MII PHY configured\n");
+
+ if (ret)
+ pr_warning("%s: "
+ "cpgmac/mii mux setup failed: %d\n", __func__, ret);
+
+ /* configure the CFGCHIP3 register for MII */
+ __raw_writel(val, cfgchip3);
+
+ soc_info->emac_pdata->phy_id = HAWKBOARD_PHY_ID;
+
+ ret = da8xx_register_emac();
+ if (ret)
+ pr_warning("%s: "
+ "emac registration failed: %d\n", __func__, ret);
+ return 0;
+}
+
static struct davinci_uart_config omapl138_hawk_uart_config __initdata = {
.enabled_uarts = 0x7,
@@ -30,6 +77,8 @@ static __init void omapl138_hawk_init(void)
davinci_serial_init(&omapl138_hawk_uart_config);
+ ret = omapl138_hawk_config_emac();
+
ret = da8xx_register_watchdog();
if (ret)
pr_warning("omapl138_hawk_init: "
--
1.6.0.5
3
4

[alsa-devel] [PATCH 1/2] sound/soc/davinci/davinci-mcasp.c: Return error code in failure
by Julia Lawall 19 Oct '10
by Julia Lawall 19 Oct '10
19 Oct '10
In this code, 0 is returned on failure, even though other
failures return -ENOMEM or other similar values.
A simplified version of the semantic match that finds this problem is as
follows: (http://coccinelle.lip6.fr/)
// <smpl>
@a@
identifier alloc;
identifier ret;
constant C;
expression x;
@@
x = alloc(...);
if (x == NULL) { <+... \(ret = -C; \| return -C; \) ...+> }
@@
identifier f, a.alloc;
expression ret;
expression x,e1,e2,e3;
@@
ret = 0
... when != ret = e1
*x = alloc(...)
... when != ret = e2
if (x == NULL) { ... when != ret = e3
return ret;
}
// </smpl>
Signed-off-by: Julia Lawall <julia(a)diku.dk>
---
Another call to platform_get_resource in the same function returns -ENODEV
on error, so I have used that value.
sound/soc/davinci/davinci-mcasp.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c
index c8e97dc..86918ee 100644
--- a/sound/soc/davinci/davinci-mcasp.c
+++ b/sound/soc/davinci/davinci-mcasp.c
@@ -898,6 +898,7 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
if (!res) {
dev_err(&pdev->dev, "no DMA resource\n");
+ ret = -ENODEV;
goto err_release_region;
}
@@ -912,6 +913,7 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
if (!res) {
dev_err(&pdev->dev, "no DMA resource\n");
+ ret = -ENODEV;
goto err_release_region;
}
3
2
hi
I had tried to cross compile the Alsa-utils 1.0.23 & m getting following
errors:
checking for libasound headers version >= 1.0.16... not present.
configure: error: Sufficiently new version of libasound not found
In my host PC alsa-lib 1.0.22 is installed
--
Reena Chauhan
Scientist-C
Application & Baseband Platform,
SBSG ,DEAL,Raipur Road
Dehradun-248001
2
1

19 Oct '10
Hello everybody.
This is my first "post" here, so please be "gentle".
I have created PAVC plugin for ALSA, it is based on COPY plugin, and
use SOFTVOL plugin for sound output. As far as I can tell from current
tests - It works perfectly, and it doesn't break compatibility with
any apps I use (and PulseAudio does). So I was wondering - is there
any chance this plugin would be added to the next official ALSA
release?
Here is the patch that enables it on current alsa-lib-1.0.23
(hopefully this mailing list is a good place to "post" this):
--- a/configure.in 2010-09-23 17:03:00.000000000 +0200
+++ b/configure.in 2010-09-23 17:09:11.029900400 +0200
@@ -445,7 +445,7 @@
pcm_plugins=""
fi
-PCM_PLUGIN_LIST="copy linear route mulaw alaw adpcm rate plug multi
shm file null empty share meter hooks lfloat ladspa dmix dshare dsnoop
asym iec958 softvol extplug ioplug mmap_emul"
+PCM_PLUGIN_LIST="copy linear route mulaw alaw adpcm rate plug multi
shm file null empty share meter hooks lfloat ladspa dmix dshare dsnoop
asym iec958 softvol extplug ioplug mmap_emul pavc"
build_pcm_plugin="no"
for t in $PCM_PLUGIN_LIST; do
@@ -516,6 +516,7 @@
AM_CONDITIONAL(BUILD_PCM_PLUGIN_EXTPLUG, test x$build_pcm_extplug = xyes)
AM_CONDITIONAL(BUILD_PCM_PLUGIN_IOPLUG, test x$build_pcm_ioplug = xyes)
AM_CONDITIONAL(BUILD_PCM_PLUGIN_MMAP_EMUL, test x$build_pcm_mmap_emul = xyes)
+AM_CONDITIONAL(BUILD_PCM_PLUGIN_PAVC, test x$build_pcm_pavc = xyes)
dnl Defines for plug plugin
if test "$build_pcm_rate" = "yes"; then
--- a/src/pcm/Makefile.am 2010-04-16 13:11:05.000000000 +0200
+++ b/src/pcm/Makefile.am 2010-09-23 17:20:10.601899695 +0200
@@ -102,6 +102,9 @@
if BUILD_PCM_PLUGIN_MMAP_EMUL
libpcm_la_SOURCES += pcm_mmap_emul.c
endif
+if BUILD_PCM_PLUGIN_PAVC
+libpcm_la_SOURCES += pcm_pavc.c
+endif
EXTRA_DIST = pcm_dmix_i386.c pcm_dmix_x86_64.c pcm_dmix_generic.c
--- a/src/pcm/pcm.c 2010-04-16 13:11:05.000000000 +0200
+++ b/src/pcm/pcm.c 2010-09-23 17:10:43.813900406 +0200
@@ -2047,7 +2047,7 @@
static const char *const build_in_pcms[] = {
"adpcm", "alaw", "copy", "dmix", "file", "hooks", "hw", "ladspa", "lfloat",
"linear", "meter", "mulaw", "multi", "null", "empty", "plug",
"rate", "route", "share",
- "shm", "dsnoop", "dshare", "asym", "iec958", "softvol", "mmap_emul",
+ "shm", "dsnoop", "dshare", "asym", "iec958", "softvol", "mmap_emul","pavc",
NULL
};
--- a/include/pcm.h 2010-04-16 13:11:05.000000000 +0200
+++ b/include/pcm.h 2010-09-23 17:11:58.389899158 +0200
@@ -376,7 +376,9 @@
SND_PCM_TYPE_EXTPLUG,
/** Mmap-emulation plugin */
SND_PCM_TYPE_MMAP_EMUL,
- SND_PCM_TYPE_LAST = SND_PCM_TYPE_MMAP_EMUL
+ /** PAVC plugin */
+ SND_PCM_TYPE_PAVC,
+ SND_PCM_TYPE_LAST = SND_PCM_TYPE_PAVC
};
/** PCM type */
--- a/src/pcm/pcm_pavc.c
+++ b/src/pcm/pcm_pavc.c
@@ -0,0 +1,846 @@
+/*
+ * PCM - PAVC plugin
+ * Based on PCM - Copy conversion plugin by Abramo Bagnara
<abramo(a)alsa-project.org>
+ *
+ * Copyright (c) 2010 by Adrian Kobyliński <huk256(a)gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <byteswap.h>
+#include "pcm_local.h"
+#include "pcm_plugin.h"
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/wait.h>
+
+
+#ifndef PIC
+/* entry for static linking */
+const char *_snd_module_pcm_pavc = "";
+#endif
+
+#ifndef DOC_HIDDEN
+typedef struct {
+ /* This field need to be the first */
+ snd_pcm_plugin_t plug;
+} snd_pcm_pavc_t;
+#endif
+
+static int snd_pcm_pavc_hw_refine_cprepare(snd_pcm_t *pcm
ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params)
+{
+ int err;
+ snd_pcm_access_mask_t access_mask = { SND_PCM_ACCBIT_SHM };
+ err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_ACCESS,
+ &access_mask);
+ if (err < 0)
+ return err;
+ params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
+ return 0;
+}
+
+static int snd_pcm_pavc_hw_refine_sprepare(snd_pcm_t *pcm
ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *sparams)
+{
+ snd_pcm_access_mask_t saccess_mask = { SND_PCM_ACCBIT_MMAP };
+ _snd_pcm_hw_params_any(sparams);
+ _snd_pcm_hw_param_set_mask(sparams, SND_PCM_HW_PARAM_ACCESS,
+ &saccess_mask);
+ return 0;
+}
+
+static int snd_pcm_pavc_hw_refine_schange(snd_pcm_t *pcm
ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params,
+ snd_pcm_hw_params_t *sparams)
+{
+ int err;
+ unsigned int links = ~SND_PCM_HW_PARBIT_ACCESS;
+ err = _snd_pcm_hw_params_refine(sparams, links, params);
+ if (err < 0)
+ return err;
+ return 0;
+}
+
+static int snd_pcm_pavc_hw_refine_cchange(snd_pcm_t *pcm
ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params,
+ snd_pcm_hw_params_t *sparams)
+{
+ int err;
+ unsigned int links = ~SND_PCM_HW_PARBIT_ACCESS;
+ err = _snd_pcm_hw_params_refine(params, links, sparams);
+ if (err < 0)
+ return err;
+ return 0;
+}
+
+static int snd_pcm_pavc_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
+{
+ return snd_pcm_hw_refine_slave(pcm, params,
+ snd_pcm_pavc_hw_refine_cprepare,
+ snd_pcm_pavc_hw_refine_cchange,
+ snd_pcm_pavc_hw_refine_sprepare,
+ snd_pcm_pavc_hw_refine_schange,
+ snd_pcm_generic_hw_refine);
+}
+
+static int snd_pcm_pavc_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
+{
+ return snd_pcm_hw_params_slave(pcm, params,
+ snd_pcm_pavc_hw_refine_cchange,
+ snd_pcm_pavc_hw_refine_sprepare,
+ snd_pcm_pavc_hw_refine_schange,
+ snd_pcm_generic_hw_params);
+}
+
+static snd_pcm_uframes_t
+ snd_pcm_pavc_write_areas(snd_pcm_t *pcm,
+ const snd_pcm_channel_area_t *areas,
+ snd_pcm_uframes_t offset,
+ snd_pcm_uframes_t size,
+ const snd_pcm_channel_area_t *slave_areas,
+ snd_pcm_uframes_t slave_offset,
+ snd_pcm_uframes_t *slave_sizep)
+{
+ if (size > *slave_sizep)
+ size = *slave_sizep;
+ snd_pcm_areas_copy(slave_areas, slave_offset,
+ areas, offset,
+ pcm->channels, size, pcm->format);
+ *slave_sizep = size;
+ return size;
+}
+
+static snd_pcm_uframes_t
+ snd_pcm_pavc_read_areas(snd_pcm_t *pcm,
+ const snd_pcm_channel_area_t *areas,
+ snd_pcm_uframes_t offset,
+ snd_pcm_uframes_t size,
+ const snd_pcm_channel_area_t *slave_areas,
+ snd_pcm_uframes_t slave_offset,
+ snd_pcm_uframes_t *slave_sizep)
+{
+ if (size > *slave_sizep)
+ size = *slave_sizep;
+ snd_pcm_areas_copy(areas, offset,
+ slave_areas, slave_offset,
+ pcm->channels, size, pcm->format);
+ *slave_sizep = size;
+ return size;
+}
+
+static void snd_pcm_pavc_dump(snd_pcm_t *pcm, snd_output_t *out)
+{
+ snd_pcm_pavc_t *pavc = pcm->private_data;
+ snd_output_printf(out, "Copy conversion PCM\n");
+ if (pcm->setup) {
+ snd_output_printf(out, "Its setup is:\n");
+ snd_pcm_dump_setup(pcm, out);
+ }
+ snd_output_printf(out, "Slave: ");
+ snd_pcm_dump(pavc->plug.gen.slave, out);
+}
+
+static const snd_pcm_ops_t snd_pcm_pavc_ops = {
+ .close = snd_pcm_generic_close,
+ .info = snd_pcm_generic_info,
+ .hw_refine = snd_pcm_pavc_hw_refine,
+ .hw_params = snd_pcm_pavc_hw_params,
+ .hw_free = snd_pcm_generic_hw_free,
+ .sw_params = snd_pcm_generic_sw_params,
+ .channel_info = snd_pcm_generic_channel_info,
+ .dump = snd_pcm_pavc_dump,
+ .nonblock = snd_pcm_generic_nonblock,
+ .async = snd_pcm_generic_async,
+ .mmap = snd_pcm_generic_mmap,
+ .munmap = snd_pcm_generic_munmap,
+};
+
+/**
+ * \brief Creates a new copy PCM
+ * \param pcmp Returns created PCM handle
+ * \param name Name of PCM
+ * \param slave Slave PCM handle
+ * \param close_slave When set, the slave PCM handle is closed with copy PCM
+ * \retval zero on success otherwise a negative error code
+ * \warning Using of this function might be dangerous in the sense
+ * of compatibility reasons. The prototype might be freely
+ * changed in future.
+ */
+int snd_pcm_pavc_open(snd_pcm_t **pcmp, const char *name, snd_pcm_t
*slave, int close_slave)
+{
+ snd_pcm_t *pcm;
+ snd_pcm_pavc_t *pavc;
+ int err;
+ assert(pcmp && slave);
+ pavc = calloc(1, sizeof(snd_pcm_pavc_t));
+ if (!pavc) {
+ return -ENOMEM;
+ }
+ snd_pcm_plugin_init(&pavc->plug);
+ pavc->plug.read = snd_pcm_pavc_read_areas;
+ pavc->plug.write = snd_pcm_pavc_write_areas;
+ pavc->plug.undo_read = snd_pcm_plugin_undo_read_generic;
+ pavc->plug.undo_write = snd_pcm_plugin_undo_write_generic;
+ pavc->plug.gen.slave = slave;
+ pavc->plug.gen.close_slave = close_slave;
+
+ err = snd_pcm_new(&pcm, SND_PCM_TYPE_PAVC, name, slave->stream,
slave->mode);
+ if (err < 0) {
+ free(pavc);
+ return err;
+ }
+ pcm->ops = &snd_pcm_pavc_ops;
+ pcm->fast_ops = &snd_pcm_plugin_fast_ops;
+ pcm->private_data = pavc;
+ pcm->poll_fd = slave->poll_fd;
+ pcm->poll_events = slave->poll_events;
+ pcm->monotonic = slave->monotonic;
+ snd_pcm_set_hw_ptr(pcm, &pavc->plug.hw_ptr, -1, 0);
+ snd_pcm_set_appl_ptr(pcm, &pavc->plug.appl_ptr, -1, 0);
+ *pcmp = pcm;
+
+ return 0;
+}
+
+int countString(char * x,char x2,int count)
+{
+ int i;
+ int z=0;
+ for(i=0;i<count;++i)
+ {
+ if(x[i]==x2)
+ {
+ ++z;
+ }
+ }
+ return z;
+}
+
+char *deleteChar(char *x, char x2, int count)
+{
+ char *ret;
+ ret=(char*) malloc(count+1);
+ int i;
+ for(i=0;i<count;++i)
+ {
+ ret[i]=0;
+ }
+ for(i=0;i<count;++i)
+ {
+ if(x[i]!=x2)
+ {
+ ret[i]=x[i];
+ }
+ else
+ {
+ ret[i]=' ';
+ }
+ }
+ return ret;
+}
+
+char *getProceses()
+{
+ FILE *pipe;
+ if ( !(pipe = (FILE*)popen("lsof -F p /dev/snd/pcmC0D0p","r")) )
+ { // If fpipe is NULL
+ perror("Problems with pipe");
+ return NULL;
+ }
+
+ int i=0,j=0;
+ int c;
+
+ do {
+ c = fgetc (pipe);
+ ++i;
+ } while (c != EOF);
+ fclose (pipe);
+
+ char *buf=(char*)malloc(sizeof(char)*i);
+
+ for(j=0;j<i;++j)
+ {
+ buf[j]=0;
+ }
+
+ i=0;
+
+ if ( !(pipe = (FILE*)popen("lsof -F p /dev/snd/pcmC0D0p","r")) )
+ { // If fpipe is NULL
+ perror("Problems with pipe");
+ return NULL;
+ }
+
+ do {
+ c = fgetc (pipe);
+ if(c!=EOF && c!='p' && c!='\n')
+ {
+ buf[i]=c;
+ }
+ else if(c=='p')
+ {
+ buf[i]=' ';
+ }
+ else if(c=='\n')
+ {
+ buf[i]=',';
+ }
+ ++i;
+ } while (c != EOF);
+ fclose (pipe);
+
+ return buf;
+}
+
+char *loadPid(char *name)
+{
+ FILE *file;
+ int c,i=0,j=0;
+
+ file=fopen(name,"r");
+ if(file!=NULL)
+ {
+ do{
+ c=fgetc(file);
+ ++i;
+ }while(c!=EOF);
+ fclose(file);
+
+ char *buf=malloc((sizeof(char))*i);
+ for(j=0;j<i;++j)
+ {
+ buf[j]=0;
+ }
+
+ i=0;
+
+ file=fopen(name,"r");
+ if(file!=NULL)
+ {
+ do{
+ c=fgetc(file);
+ if(c!=EOF && c!='\n')
+ buf[i]=c;
+ ++i;
+ }while(c!=EOF);
+ fclose(file);
+
+ return buf;
+ }
+ else
+ {
+ return NULL;
+ }
+
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+void savePid(char *pid,char *file)
+{
+ int i;
+ char command3[256];
+
+ for(i=0;i<256;++i)
+ {
+ command3[i]=0;
+ }
+
+ strcat(command3,"echo ");
+ strcat(command3,pid);
+ strcat(command3," > ");
+ strcat(command3,file);
+
+ for(i=5;i<256;++i)
+ {
+ if(command3[i]!=EOF && command3[i]!='\n' && command3[i]!='*')
+ {
+ command3[i]=command3[i];
+ }
+ else
+ {
+ command3[i]=' ';
+ }
+ }
+
+ system(command3);
+}
+
+int checkDir(char *name)
+{
+ char command[128];
+ memset(command,0,128);
+
+ strcat(command,"ls -aF ");
+ strcat(command,getenv("HOME"));
+ strcat(command," | grep \\./$ | grep -w ");
+ strcat(command,name);
+
+ FILE *pipe;
+ if ( !(pipe = (FILE*)popen(command,"r")) )
+ {
+ perror("Problems with pipe");
+ return -1;
+ }
+
+ int i=0;
+ int c;
+
+ do {
+ c = fgetc (pipe);
+ if(c!=EOF && c!='\n')
+ ++i;
+ } while (c != EOF);
+ fclose (pipe);
+
+ if(i>0)
+ {
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+int createDir(char *name)
+{
+ pid_t PID;
+ int status;
+
+ PID=fork();
+
+ if(PID>0)
+ {
+ char command[128];
+ memset(command,0,128);
+
+ strcat(command,getenv("HOME"));
+ strcat(command,"/");
+ strcat(command,".softvol");
+
+ execlp("mkdir","mkdir",command,NULL);
+ }
+ else
+ {
+ pid_t wpid = waitpid(PID, &status, WUNTRACED);
+ }
+
+ return WEXITSTATUS(status);
+}
+
+char *getDir(char *name)
+{
+ static char command[128];
+ memset(command,0,128);
+
+ strcat(command,getenv("HOME"));
+ strcat(command,"/");
+ strcat(command,name);
+
+ return command;
+}
+
+char *getSoftvolNumber(int channelCount,int current)
+{
+ size_t i;
+ static char ret[4];
+ memset(ret,0,5);
+ char buf1[4],buf2[4];
+ sprintf(buf1,"%i",channelCount);
+ sprintf(buf2,"%i",current);
+
+ if(strlen(buf2)<strlen(buf1))
+ {
+ for(i=0;i<(strlen(buf1)-1);++i)
+ {
+ ret[i]='0';
+ }
+
+ strcat(ret,buf2);
+
+ return ret;
+ }
+ else if(strlen(buf2)==strlen(buf1))
+ {
+ strcat(ret,buf2);
+ return ret;
+ }
+ else
+ {
+ //this should never happen
+ return NULL;
+ }
+}
+
+int checkSoftvolProcess(int channelcount)
+{
+ int i=0,c=0,ret=channelcount-1,j=0;
+ char nameBuf[1024];
+ char pidBuf[32];
+ char numBuf[4];
+ char command[128];
+ char fileName[64];
+
+ FILE *fpipe;
+
+ for(i=0;i<channelcount;++i)
+ {
+ memset(nameBuf,0,1024);
+ memset(numBuf,0,4);
+ memset(command,0,128);
+ memset(fileName,0,64);
+
+ strcat(command,"ps -A -o pid= | grep -w -f ");
+ strcat(command,getDir(".softvol"));
+ strcat(command,"/SOFTVOL");
+ strcat(command,getSoftvolNumber(channelcount,i));
+ strcat(command,".pid");
+
+ strcat(fileName,getDir(".softvol"));
+ strcat(fileName,"/SOFTVOL");
+ strcat(fileName,getSoftvolNumber(channelcount,i));
+ strcat(fileName,".pid");
+
+ //Here we check if current process is already conected to something
+ FILE *temp=fopen(fileName,"r");
+ if(temp!=NULL)
+ {
+ j=0;
+ do{
+ c=fgetc(temp);
+ if(c!=EOF && c!='\n')
+ {
+ nameBuf[j]=c;
+ }
+ else
+ {
+ nameBuf[j]='\0';
+ }
+
+ ++j;
+ }while(c!=EOF);
+ }
+ else
+ {
+ memset(nameBuf,0,1024);
+ }
+
+ sprintf(pidBuf,"%d",getpid());
+
+ if(strcmp(nameBuf,pidBuf)==0)
+ {
+ //Current process wants to re-initialize the sound - so
we connect it
+ //to the output it is currently using
+ ret=i;
+ break;
+ }
+ else
+ {
+ //Current process is not connected to anything - so we connect it
+ //to the firs unused softvol output
+ memset(fileName,0,64);
+ }
+ }
+
+ if(fileName[0]!=0)
+ {
+ //Current process is already using some softvol output - so we
+ //reconnect it to this output
+ for(i=0;i<channelcount;++i)
+ {
+ memset(numBuf,0,4);
+ memset(command,0,128);
+ memset(fileName,0,64);
+
+ strcat(command,"ps -A -o pid= | grep -w -f ");
+ strcat(command,getDir(".softvol"));
+ strcat(command,"/SOFTVOL");
+ strcat(command,getSoftvolNumber(channelcount,i));
+ strcat(command,".pid 2> /dev/null");
+
+ strcat(fileName,getDir(".softvol"));
+ strcat(fileName,"/SOFTVOL");
+ strcat(fileName,getSoftvolNumber(channelcount,i));
+ strcat(fileName,".pid");
+
+ //Here we check if process is alive...
+ if ( !(fpipe = (FILE*)popen(command,"r")) )
+ { // If fpipe is NULL
+ perror("Problems with pipe");
+ }
+
+ j=0;
+
+ do {
+ c = fgetc (fpipe);
+ if(c!=EOF)
+ ++j;
+ } while (c != EOF);
+ fclose (fpipe);
+
+ //...and if it is the current process
+ if(j>0)
+ {
+ FILE *temp=fopen(fileName,"r");
+ j=0;
+ do{
+ c=fgetc(temp);
+ if(c!=EOF && c!='\n')
+ {
+ nameBuf[j]=c;
+ }
+ else
+ {
+ nameBuf[j]='\0';
+ }
+
+ ++j;
+ }while(c!=EOF);
+
+ char pidBuf[32];
+ sprintf(pidBuf,"%d",getpid());
+
+ if(strcmp(nameBuf,pidBuf)==0)
+ {
+ //Current process wants to re-initialize the
sound - so we connect it
+ //to the output it is currently using
+ ret=i;
+ break;
+ }
+ else
+ {
+ //It is some other process - so we connect it
+ //to the first unused softvol output
+ ret=i+1;
+ }
+ }
+ else
+ {
+ ret=i;
+ }
+ }
+ }
+ else
+ {
+ //Process isn't using any softvol output - so we connect it
+ //to the first unused on the list
+
+ for(i=0;i<channelcount;++i)
+ {
+ memset(numBuf,0,4);
+ memset(command,0,128);
+ memset(fileName,0,64);
+
+ strcat(command,"ps -A -o pid= | grep -w -f ");
+ strcat(command,getDir(".softvol"));
+ strcat(command,"/SOFTVOL");
+ strcat(command,getSoftvolNumber(channelcount,i));
+ strcat(command,".pid 2> /dev/null");
+
+ strcat(fileName,getDir(".softvol"));
+ strcat(fileName,"/SOFTVOL");
+ strcat(fileName,getSoftvolNumber(channelcount,i));
+ strcat(fileName,".pid");
+
+ //Here we check if process is alive...
+ if ( !(fpipe = (FILE*)popen(command,"r")) )
+ { // If fpipe is NULL
+ perror("Problems with pipe");
+ }
+
+ j=0;
+
+ do {
+ c = fgetc (fpipe);
+ if(c!=EOF)
+ ++j;
+ } while (c != EOF);
+ fclose (fpipe);
+
+ //...and if it is the current process
+ if(j>0)
+ {
+
+ }
+ else
+ {
+ ret=i;
+ break;
+ }
+ }
+ }
+ return ret;
+}
+
+/*! \page pcm_plugins
+
+\section pcm_plugins_copy Plugin: copy
+
+This plugin copies samples from master copy PCM to given slave PCM.
+The channel count, format and rate must match for both of them.
+
+\code
+pcm.name {
+ type copy # Copy PCM
+ slave STR # Slave name
+ # or
+ slave { # Slave definition
+ pcm STR # Slave PCM name
+ # or
+ pcm { } # Slave PCM definition
+ }
+}
+\endcode
+
+\subsection pcm_plugins_copy_funcref Function reference
+
+<UL>
+ <LI>snd_pcm_copy_open()
+ <LI>_snd_pcm_copy_open()
+</UL>
+
+*/
+
+/**
+ * \brief Creates a new copy PCM
+ * \param pcmp Returns created PCM handle
+ * \param name Name of PCM
+ * \param root Root configuration node
+ * \param conf Configuration node with copy PCM description
+ * \param stream Stream type
+ * \param mode Stream mode
+ * \retval zero on success otherwise a negative error code
+ * \warning Using of this function might be dangerous in the sense
+ * of compatibility reasons. The prototype might be freely
+ * changed in future.
+ */
+int _snd_pcm_pavc_open(snd_pcm_t **pcmp, const char *name,
+ snd_config_t *root, snd_config_t *conf,
+ snd_pcm_stream_t stream, int mode)
+{
+ long channelcount=-1;
+ int ret=0;
+ char softvolName[64];
+ char pidBuf[32];
+ char fileName[64];
+ char helpBuf[32];
+
+ memset(softvolName,0,64);
+
+ snd_config_iterator_t i, next;
+ int err;
+ snd_pcm_t *spcm;
+ snd_config_t *slave = NULL, *sconf;
+
+ snd_config_t *tempConfig;
+ err=snd_config_search(conf,"channelcount",&tempConfig);
+ if(err<0)
+ {
+ SNDERR("channelcount field not found");
+ return -ENOENT;
+ }
+ err=snd_config_get_integer(tempConfig,&channelcount);
+ if(err<0)
+ {
+ SNDERR("channelcount vaule must be integer");
+ return -EINVAL;
+ }
+
+ snd_config_t *softvol[channelcount];
+
+ int counter=0;
+
+ sprintf(softvolName,"softvol%i",counter);
+
+ snd_config_for_each(i, next, conf)
+ {
+ snd_config_t *n = snd_config_iterator_entry(i);
+ const char *id;
+ if (snd_config_get_id(n, &id) < 0)
+ continue;
+ if (snd_pcm_conf_generic_id(id))
+ continue;
+ if (strcmp(id, "slave") == 0)
+ {
+ slave = n;
+ continue;
+ }
+ if (strcmp(id, "channelcount") == 0)
+ {
+ continue;
+ }
+ if((counter<channelcount) && strcmp(id,softvolName)==0)
+ {
+ softvol[counter]=n;
+ ++counter;
+ sprintf(softvolName,"softvol%i",counter);
+ continue;
+ }
+ SNDERR("Unknown field %s", id);
+ return -EINVAL;
+ }
+
+ if (!slave) {
+ SNDERR("slave is not defined");
+ return -EINVAL;
+ }
+
+ if(checkDir(".softvol"))
+ {
+ //Directory exists - we do nothing
+ }
+ else
+ {
+ //Directory doesn't exists we need to create it
+ if((err=createDir(".softvol"))!=0)
+ {
+ SNDERR("Unable to create ~/.softvol directory - unknown
error %i",err);
+ return err;
+ }
+ }
+
+ ret=checkSoftvolProcess(channelcount);
+
+ err = snd_pcm_slave_conf(root, softvol[ret], &sconf, 0);
+
+ if (err < 0)
+ return err;
+ err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf);
+ snd_config_delete(sconf);
+ if (err < 0)
+ return err;
+ err = snd_pcm_pavc_open(pcmp, name, spcm, 1);
+ if (err < 0)
+ snd_pcm_close(spcm);
+
+ sprintf(pidBuf,"%d",getpid());
+ memset(fileName,0,64);
+ strcat(fileName,getDir(".softvol"));
+ strcat(fileName,"/SOFTVOL");
+
+ strcat(fileName,getSoftvolNumber(channelcount,ret));
+ strcat(fileName,".pid");
+
+ savePid(pidBuf,fileName);
+
+ return err;
+}
+#ifndef DOC_HIDDEN
+SND_DLSYM_BUILD_VERSION(_snd_pcm_pavc_open, SND_PCM_DLSYM_VERSION);
+#endif
To test PAVC, we have to rebuild alsa-lib, and create .asoundrc or
/etc/asound.conf that looks like this:
pcm.!default {
type plug
slave.pcm "asymed"
}
pcm.asymed
{
type asym
playback.pcm "pavcp"
capture.pcm "dsnooped"
}
pcm.dmixer {
type dmix
ipc_key 1025
slave {
pcm "hw:0"
period_time 0
period_size 256
#buffer_size 4096
periods 128
rate 44100
}
}
pcm.dsnooped {
type dsnoop
ipc_key 1026
slave
{
pcm "hw:0"
channels 2
period_size 256
#buffer_size 4096
rate 44100
periods 0
period_time 0
}
}
pcm.softvol00 {
type softvol
slave {
pcm "dmixer"
}
control {
name "Softvol00"
card 0
}
}
pcm.softvol01 {
type softvol
slave {
pcm "dmixer"
}
control {
name "Softvol01"
card 0
}
}
pcm.softvol02 {
type softvol
slave {
pcm "dmixer"
}
control {
name "Softvol02"
card 0
}
}
pcm.softvol03 {
type softvol
slave {
pcm "dmixer"
}
control {
name "Softvol03"
card 0
}
}
pcm.softvol04 {
type softvol
slave {
pcm "dmixer"
}
control {
name "Softvol04"
card 0
}
}
pcm.softvol05 {
type softvol
slave {
pcm "dmixer"
}
control {
name "Softvol05"
card 0
}
}
pcm.softvol06 {
type softvol
slave {
pcm "dmixer"
}
control {
name "Softvol06"
card 0
}
}
pcm.softvol07 {
type softvol
slave {
pcm "dmixer"
}
control {
name "Softvol07"
card 0
}
}
pcm.softvol08 {
type softvol
slave {
pcm "dmixer"
}
control {
name "Softvol08"
card 0
}
}
pcm.softvol09 {
type softvol
slave {
pcm "dmixer"
}
control {
name "Softvol09"
card 0
}
}
pcm.softvol10 {
type softvol
slave {
pcm "dmixer"
}
control {
name "Softvol10"
card 0
}
}
pcm.softvol11 {
type softvol
slave {
pcm "dmixer"
}
control {
name "Softvol11"
card 0
}
}
ctl.dmixer {
type hw
card 0
}
ctl.dsnooped {
type hw
card 0
}
pcm.pavcp
{
type pavc
slave.pcm "dmixer"
channelcount 12
softvol0.pcm "softvol00"
softvol1.pcm "softvol01"
softvol2.pcm "softvol02"
softvol3.pcm "softvol03"
softvol4.pcm "softvol04"
softvol5.pcm "softvol05"
softvol6.pcm "softvol06"
softvol7.pcm "softvol07"
softvol8.pcm "softvol08"
softvol9.pcm "softvol09"
softvol10.pcm "softvol10"
softvol11.pcm "softvol11"
}
With this, anything connected to "default" will be automatically
redirected to the first unused softvol channel. PIDs of apps that
currently use softvol channels are saved to ~/.softvol/SOFTVOLXX.pid,
so this can be checked at any time. If some application will try to
restart only its sound subsystem, PAVC plugin will check those files
to determine if it should be connected to the new softvol channel, or
the one it currently uses. I tried to mimic the way this works with
OSS4.
Current limitations:
-Since there is no "mute and slider at the same time" support in
SOFTVOL plugin - there is no mute switch for software channels (or
maybe there is a way I don't know about?)
-Software channels must be named SOFTVOL00,01,02 and so on
-SOFTVOL channels have both PLAYBACK and CAPTURE capabilities by
default - this makes some mixers go haywire, and display double
sliders - maybe there is a way around this I don't know about (like
setting PLAYBACK only capability)?
-Code of PAVC, could probably look nicer
Hopefully someone will take a look at this, of course I am open to
suggestions and critics.
Best regards.
P.S
Sorry for my English ;]
4
7

18 Oct '10
--- Julian Scheel <julian(a)jusst.de> wrote:
There may also be
> >a limitation in that the Same EP number cannot be used
> >for both IN and OUT.
>
> Hm, I'm not sure about this. You think I should move the feedback
> pipe into it's own EP?
> I will recheck the At91SAM7 specs later, to see if I can find a note
> on such a limitation.
Hi Julian,
You might like to refer to this thread:
http://www.avrfreaks.net/index.php?name=PNphpBB2&file=printview&t=88432&sta…
As I have found out, it is not necessary to have the same EP number for IN and OUT for rate feedback to work with a Linux or OSX host. This may be a requirement for Vista/Win7 hosts though. We are still doing testing.
Alex
5
18

18 Oct '10
CCR is defined in emu10k1, but SuperH is defined too.
If user use this driver with SuperH, it becomes a double definition.
Signed-off-by: Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj(a)renesas.com>
CC: Takashi iwai <tiwai(a)suse.de>
CC: Paul Mundt <lethal(a)linux-sh.org>
---
include/sound/emu10k1.h | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h
index 7dc97d1..d1fcc31 100644
--- a/include/sound/emu10k1.h
+++ b/include/sound/emu10k1.h
@@ -438,6 +438,7 @@
#define CCCA_CURRADDR_MASK 0x00ffffff /* Current address of the selected channel */
#define CCCA_CURRADDR 0x18000008
+#undef CCR
#define CCR 0x09 /* Cache control register */
#define CCR_CACHEINVALIDSIZE 0x07190009
#define CCR_CACHEINVALIDSIZE_MASK 0xfe000000 /* Number of invalid samples cache for this channel */
--
1.7.1
--
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
2
1
The following changes since commit 630f2d445f922c9dcf1bb54ffde78685e2c63072:
fbdev: sh_mobile_hdmi: fix compilation without SOUND enabled (2010-10-15 11:56:46 +0100)
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound-2.6.git for-2.6.37
Mark Brown (1):
Revert "ASoC: Add max98088 CODEC driver"
sound/soc/codecs/Kconfig | 4 -
sound/soc/codecs/Makefile | 2 -
sound/soc/codecs/max98088.c | 2097 -------------------------------------------
sound/soc/codecs/max98088.h | 193 ----
4 files changed, 0 insertions(+), 2296 deletions(-)
delete mode 100644 sound/soc/codecs/max98088.c
delete mode 100644 sound/soc/codecs/max98088.h
1
0
Dear all
i want report a bug in davinci sound device driver (sound/soc/davinci-pcm.c)
This bug cause by DMA copy Overflow. It will cause kernel oops with a lot of unusual info.
And this problem seem still in latest stable kernel (version 2.6.35.7)
Bug Symptom at the end of mail
Here is my analyse of this bug:
Device will call function : davinci_pcm_new
This function will malloc a lagre Continuous Pages buffer (Typicly:128K) both Playback and Capture.
Those two buffer will use as DMA copy !
When someone recoder sound date ! This driver will use DMA.Copy register date to Capture buffer that malloc at function davinci_pcm_new !
every DMA copy finish.callback function davinci_pcm_dma_irq will run. function davinci_pcm_enqueue_dma will work.This function will
set DMA copy params again. And problem is in here !
It set DMA params :
src = sound recoder 32-bit reg address
dst = prtd->period * period_size
src_bidx = 0 //(Every dma copy finish the src will not change)
dst_bidx = data_type; //date_type = 2, because only high 16-bit is the sound date.
acnt = 4
bcnt = 2048
cnt = 1
Use this param.DMA Internal work like:
for(c=0;c<cnt;c++) {
for(b=0;b<bcnt;b++) {
memcopy(&dst,&src,4)
src += src_bidx; //src_bidx = 0;
dst += dst_bidx //dst_bidx = data_type =2 16bit sound date
}
}
This copy will make all dst buffer has source high 16 bit date. but will cause 2 byptes Overflow
every time the dma copy finish. it will change 4K bytes + 2 bytes. The 2 bytes is DMA copy Overflow.
it will not error until you copy to the last period! because. your date total copy 128K +2bytes . and we only malloc 128K bytes
other 2 bytes is kernel space memory. this two bytes will be use random by kernel. And those 2 bytes copy by dma. kernel don't know
anything about this segment default.
This easy way to fix the problem is change:
if(unlikely(prtd->period >= runtime->periods))
prtd->period = 0;
In function davinci_pcm_enqueue_dma to:
if(unlikely(prtd->period >= (runtime->periods-1)))
prtd->period = 0;
Below is the Symptom:
Symptom 1:
Bad pte = 04040202, process = sleep, vm_flags = 1875, vaddr = 1b000
VM: killing process sleep
Bad pte = 04040601, process = ???, vm_flags = 1875, vaddr = 17000
Bad pte = ffffffff, process = ???, vm_flags = 1875, vaddr = 43000
Bad pte = 00000001, process = ???, vm_flags = 1875, vaddr = 44000
…………..
Bad pte = 00000001, process = ???, vm_flags = 1875, vaddr = 88000
Symptom 2:
Unhandled fault: page domain fault (0x8fb) at 0x00011008
Internal error: : 8fb [#1]
Modules linked in: tlv320aic24 dm365_gpio dm365_pwm davinci_vpbe davinci_capture dm365_imp dm365mmap edmak irqk cmemk
CPU: 0
PC is at __copy_to_user+0x54/0x3a8
LR is at 0x5eff968
pc : [<c0117568>] lr : [<05eff968>] Not tainted
sp : c436befc ip : e4640f80 fp : c436bf4c
r10: 00000000 r9 : c436a000 r8 : dcfd0362
r7 : 0ee2fab7 r6 : f7a60e69 r5 : fe9cf7d3 r4 : 026603c7
r3 : 0b7de3b1 r2 : 00000760 r1 : c5056020 r0 : 00011008
Flags: nzCv IRQs on FIQs on Mode SVC_32 Segment user
Control: 5317F
Table: 843C0000 DAC: 00000015
,,,,,,,,,,,,,,,,,,,,,,,,
page:c0363be0 flags:0x00000068 mapping:c4273d18 mapcount:0 count:0
Trying to fix it up, but a reboot is needed
Symptom 3:
159.99.249.249 login: VM: killing process video_test
Bad pte = 00000003, process = ???, vm_flags = 1875, vaddr = 9000
Bad pte = 00000005, process = ???, vm_flags = 1875, vaddr = b000
,,,,,,,,,,,,,,,,,,,,,
Bad pte = 00000001, process = ???, vm_flags = 100077, vaddr = 31000
Bad page state in process 'desched/0'
page:c035e3e0 flags:0x0000006c mapping:c06ecec8 mapcount:0 count:0
Trying to fix it up, but a reboot is needed
Symptom 4:
159.99.249.249 login: Bad pte = ffb7ffb6, process = inetd, vm_flags = 100177, vaddr = bea82000
Stopping interneBad pte = ffb7ffb6, process = inetd, vm_flags = 100177, vaddr = bea82000
t superserver: iBad pte = ffb7ffb6, process = inetd, vm_flags = 100177, vaddr = bea82000
netdBad pte = ffb7ffb6, process = inetd, vm_flags = 100177, vaddr = bea82000
Bad pte = ffb7ffb6, process = inetd, vm_flags = 100177, vaddr = bea82000
Bad pte = ffb7ffb6, process = inetd, vm_flags = 100177, vaddr = bea82000
,,,,,,,,,,,,,,,,,,,,,,,,,,,,
Bad pte = ffb7ffb6, process = inetd, vm_flags = 100177, vaddr = bea82000
Symptom 5:
Unable to handle kernel NULL pointer dereference at virtual address 00000000
done.
pgd = c0004000
[00000000] *pgd=00000000
Internal error: Oops: 817 [#1]
Modules linked in: tlv320aic24 dm365_gpio dm365_pwm davinci_vpbe davinci_capture dm365_imp dm365mmap edmak irqk cmemk
CPU: 0
PC is at __free_pages+0x18/0x58
LR is at __init_begin+0x3fff8000/0x30
pc : [<c007626c>] lr : [<00000000>] Not tainted
sp : c03cdf50 ip : c03cdf60 fp : c03cdf5c
r10: c02de000 r9 : 00000002 r8 : c02ca460
r7 : 00000000 r6 : 843cffd0 r5 : c43c0000 r4 : c03cc000
r3 : 00000000 r2 : c02ca444 r1 : 00000000 r0 : c03659e0
Flags: nZCv IRQs on FIQs on Mode SVC_32 Segment kernel
Control: 5317F
Table: 805BC000 DAC: 00000017
Process desched/0 (pid: 11, stack limit = 0xc03cc258)
Stack: (0xc03cdf50 to 0xc03ce000)
df40: c03cdf84 c03cdf60 c003ad7c c0076264
df60: c002b6c0 c002b6c0 00000000 c02c2990 00000001 c02c2998 c03cdf9c c03cdf88
df80: c0045d54 c003ac64 c03b3f18 c03cc000 c03cdfcc c03cdfa0 c0047b2c c0045d38
dfa0: 00000000 00000000 c03cc000 c0047a7c c03b3f18 00000000 00000000 00000000
dfc0: c03cdff4 c03cdfd0 c005eca8 c0047a8c ffffffff ffffffff 00000000 00000000
dfe0: 00000000 00000000 00000000 c03cdff8 c004ba28 c005ebd0 00000000 00000000
Backtrace:
[<c0076254>] (__free_pages+0x0/0x58) from [<c003ad7c>] (free_pgd_slow+0x128/0x148)
[<c003ac54>] (free_pgd_slow+0x0/0x148) from [<c0045d54>] (__mmdrop+0x2c/0x48)
[<c0045d28>] (__mmdrop+0x0/0x48) from [<c0047b2c>] (desched_thread+0xb0/0x130)
r4 = C03CC000
[<c0047a7c>] (desched_thread+0x0/0x130) from [<c005eca8>] (kthread+0xe8/0x128)
[<c005ebc0>] (kthread+0x0/0x128) from [<c004ba28>] (do_exit+0x0/0x9cc)
r7 = 00000000 r6 = 00000000 r5 = 00000000 r4 = 00000000
Code: e24cb004 e5903004 e1a0e001 e3530000 (05833000)
prev->state: 2 != TASK_RUNNING??
desched/0/11[CPU#0]: BUG in __schedule at kernel/sched.c:3826
Symptom 6:
VM: killing process sys_monitor
Bad pte = e1a0c00d, process = ???, vm_flags = 100077, vaddr = 12000
Bad pte = e1a0c00d, process = ???, vm_flags = 100077, vaddr = 17000
Bad pte = e1a00001, process = ???, vm_flags = 100077, vaddr = 1a000
Bad pte = e3a00001, process = ???, vm_flags = 100077, vaddr = 22000
Bad pte = e1a0c00d, process = ???, vm_flags = 100077, vaddr = 24000
Bad pte = e1a04003, process = ???, vm_flags = 100077, vaddr = 29000
Bad pte = e0821001, process = ???, vm_flags = 100077, vaddr = 2a000
Bad pte = 979ff101, process = ???, vm_flags = 100077, vaddr = 2c000
Unable to handle kernel NULL pointer dereference at virtual address 00000000
pgd = c0004000
[00000000] *pgd=00000000
Internal error: Oops: 817 [#1]
Modules linked in: tlv320aic24 dm365_gpio dm365_pwm davinci_vpbe davinci_capture dm365_imp dm365mmap edmak irqk cmemk
CPU: 0
PC is at __free_pages+0x18/0x58
LR is at __init_begin+0x3fff8000/0x30
pc : [<c007626c>] lr : [<00000000>] Not tainted
sp : c434de98 ip : c434dea8 fp : c434dea4
r10: c02de000 r9 : c40b26e0 r8 : c02ca460
r7 : 00000000 r6 : 8434ffd1 r5 : c43c0000 r4 : c434c000
r3 : 00000000 r2 : c02ca444 r1 : 00000000 r0 : c03649e0
Flags: nZCv IRQs on FIQs on Mode SVC_32 Segment user
Control: 5317F
Table: 8437C000 DAC: 00000015
Process sys_monitor (pid: 581, stack limit = 0xc434c258)
Stack: (0xc434de98 to 0xc434e000)
de80: c434decc c434dea8
dea0: c003ad7c c0076264 c40b26e0 c40b26e0 c40b2714 c0495ac0 00000009 00008fa0
dec0: c434dee4 c434ded0 c0045d54 c003ac64 c0495ac0 c40b26e0 c434defc c434dee8
dee0: c0045e40 c0045d38 c0063250 c434c000 c434df1c c434df00 c004a28c c0045d80
df00: c434c000 c0495ac0 c0495ac0 00000001 c434df3c c434df20 c004bbd8 c004a180
df20: c434df84 c434df40 c00398ec c0049190 c434df84 c434df40 c00398f4 c004ba38
df40: 00000001 00000000 be90fb28 00000000 c434dfb0 00000000 c434de58 ffffffff
df60: 00000000 be90fb28 00000000 be90fba8 00000003 be90fc84 c434df9c c434df88
df80: c00399fc c0039744 0000008e ffffffff c434dfac c434dfa0 c0039aac c00399f0
dfa0: 00000000 c434dfb0 c0032d88 c0039aa4 00000000 be90fb28 00000000 00000000
dfc0: be90fc90 00000000 be90fb28 00000000 be90fba8 00000003 be90fc84 00000004
dfe0: 00000000 be90fb08 00008fa0 00008fa0 00000010 ffffffff 00000000 00000000
Backtrace:
[<c0076254>] (__free_pages+0x0/0x58) from [<c003ad7c>] (free_pgd_slow+0x128/0x148)
[<c003ac54>] (free_pgd_slow+0x0/0x148) from [<c0045d54>] (__mmdrop+0x2c/0x48)
[<c0045d28>] (__mmdrop+0x0/0x48) from [<c0045e40>] (mmput+0xd0/0xdc)
r4 = C40B26E0
[<c0045d70>] (mmput+0x0/0xdc) from [<c004a28c>] (exit_mm+0x11c/0x120)
r4 = C434C000
[<c004a170>] (exit_mm+0x0/0x120) from [<c004bbd8>] (do_exit+0x1b0/0x9cc)
r7 = 00000001 r6 = C0495AC0 r5 = C0495AC0 r4 = C434C000
[<c004ba28>] (do_exit+0x0/0x9cc) from [<c00398f4>] (do_page_fault+0x1c0/0x228)
[<c0039734>] (do_page_fault+0x0/0x228) from [<c00399fc>] (do_translation_fault+0x1c/0xb4)
[<c00399e0>] (do_translation_fault+0x0/0xb4) from [<c0039aac>] (do_PrefetchAbort+0x18/0x1c)
r4 = FFFFFFFF
[<c0039a94>] (do_PrefetchAbort+0x0/0x1c) from [<c0032d88>] (ret_from_exception+0x0/0x10)
Code: e24cb004 e5903004 e1a0e001 e3530000 (05833000)
<1>Fixing recursive fault but reboot is needed!
Thanks and Best Regards
Honeywell
Ivan Zhang(wenjie.zhang(a)honeywell.com)
Firmware Engineer - Honeywell Security R&D - Asia Pacific
No.430 Li Bing Road, Zhang Jiang Hi-Tech.Park,
Pudong New Area,Shanghai, China(201203)
Tel:(8621)-28942292
1
0
Am Donnerstag, 14. Oktober 2010, 13:15:45 schrieb Alex:
> > Great to hear that ASYNC OUT with rate feedback is working for u now :-)
>
> Btw, are u using 12.13 format for Linux ? U can try with OSX snow leopard,
> which can understand 10.14 and 16.16. Apply Clemens' patch and linux can
> understand all formats - but users will have to wait for kernel 2.6.37 !
>
> I have implemented a sophisticated rate feedback with ping pong audio
> buffer, calculation of gap between USB data and i2s data, determining
> whether gap is increasing or decreasing etc.
One more question on the feedback: In your project you fo 10.14 for Full Speed
devices (which mine is - the AT91SAM7A3 can't do High Speed) and 12.13 for
highspeed. Why do you distinguish that way? Is your device initialised in High
Speed mode whenever it's connected to a Linux host?
Regards,
Julian
3
19
> > > IIRC at least one version had a split where the ALSA integration stuff
> > > was separated out from the underlying DSP interface code - that was
> > > pretty helpful since it helps focus on the ALSA specifics.
> >
> > Yes but that split is no longer there once the clean up patches sit on
> > top because they weren't put together as separate bits. This is exactly
> > the sort of reason I want to get it in staging.
> >
> >
> > > > Agreed, although gstreamer is pretty good at that it would save
> > > > work if it can be partly generic. It's not trivial however because
> > > > the offload
> > >
> > > Plus the fact that not everyone is using gstreamer at the application
> > > level :/
> > >
> > > > interface with suitable firmware loaded does things other than PCM
> > > > and you have very firmware specific interfaces for configuring
> > > > those.
> > >
> > > We ought to be able to come up with something for the core streaming
> > > stuff, though. Like I say, it's just a nice to have though.
> >
> > I would have thought PCM at least was also going to have some kind of
> > common structure.
> >
> > > I do have some nervousness about the concept of staging for embedded
> > > stuff since I worry that inclusion in staging can send the wrong
> > > message to vendors but that's a completely separate issue to this
> > > driver.
> >
> > Noted. But I'll point you at the SEP driver which did get bogged down
> > for ages for reasons I can't really go into publically, and we
> > therefore pulled out of staging.
>
> Sorry to be too late to join the review (as I've been too busy and in
> other troubles...)
No problem :)
>
> SST driver has been once (sort of) posted and reviewed, but stalled
> since then. But in general I'm not against merging to the sound main
> tree at all. The only reason that it didn't occur was that the
> activity just stopped somehow.
Takshi, we had fixed the comments given by you and Mark at that time.
Somehow never managed to get bits upstream again.
>
> Anyway, I'm going to review in the next week or so. Then maybe we can
> move it to sound/ directory (e.g. creating sound/platform/x86
> directory) before rc1, unless you'd like to keep the stuff rather in
> staging tree.
That would be wonderful :)
Greg was kind enough to stage it in his staging and there is some activity going on there as well.
If you feel this is good enough to go ahead to sound tree, please merge.
We will resolve the comments by you and community as we go forward and also fix the TODOs.
Thanks
Vinod Koul
1
0

[alsa-devel] [PATCH 2/2] configure.in: don't rely on test -a, not all shells support it
by Simon McVittie 17 Oct '10
by Simon McVittie 17 Oct '10
17 Oct '10
Notably, /bin/sh in Debian and Ubuntu is dash, which doesn't.
---
configure.in | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/configure.in b/configure.in
index e904956..c353759 100644
--- a/configure.in
+++ b/configure.in
@@ -119,7 +119,7 @@ if test "$versioned" = "yes"; then
major=`echo $xres | cut -d . -f 1`
minor=`echo $xres | cut -d . -f 2`
pass=0
- if test $major -eq 1 -a $minor -gt 3; then
+ if test $major -eq 1 && test $minor -gt 3; then
pass=1
else
if test $major -gt 1; then
--
1.7.1
2
2

[alsa-devel] [PATCH 1/2] Version-check libtool correctly when doing an out-of-tree build
by Simon McVittie 17 Oct '10
by Simon McVittie 17 Oct '10
17 Oct '10
libtool is only created at the end of ./configure, so it doesn't make
sense to grep it in ./configure (the check would always fail the first
time). However, ltmain.sh is copied into the ${srcdir} by libtoolize and
should be safe to check at any time that configure can be run.
Signed-off-by: Simon McVittie <smcv(a)debian.org>
---
configure.in | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/configure.in b/configure.in
index abc4687..e904956 100644
--- a/configure.in
+++ b/configure.in
@@ -115,7 +115,7 @@ AC_ARG_WITH(versioned,
versioned="$withval", versioned="yes")
if test "$versioned" = "yes"; then
# it seems that GNU ld versions since 2.10 are not broken
- xres=`grep '^VERSION=' libtool | cut -d = -f 2 | cut -d \" -f 2`
+ xres=`grep '^VERSION=' ${srcdir}/ltmain.sh | cut -d = -f 2 | cut -d \" -f 2`
major=`echo $xres | cut -d . -f 1`
minor=`echo $xres | cut -d . -f 2`
pass=0
--
1.7.1
2
1

17 Oct '10
I'm using speaker-test in an Ubuntu-specific bug triaging
script/application ("ubuntu-bug audio"), and without showing the
terminal that speaker-test outputs. So when the stream cannot be opened
for one reason or another, my application hangs indefinitely and the
user cannot report the bug.
Looking at the code, seems like Takashi removed all error loops except
this one four years ago, so there shouldn't be any controversy in
removing this one as well.
--
David Henningsson, Canonical Ltd.
http://launchpad.net/~diwic
2
1

[alsa-devel] [PATCH] ALSA: fix unused warnings with snd_power_get_state
by Mike Frysinger 17 Oct '10
by Mike Frysinger 17 Oct '10
17 Oct '10
If we compile the ASoC code with PM disabled, we hit stuff like:
sound/soc/soc-dapm.c: In function 'snd_soc_dapm_suspend_check':
sound/soc/soc-dapm.c:440: warning: unused variable 'codec'
So tweak the stub macro to avoid these issues.
Signed-off-by: Mike Frysinger <vapier(a)gentoo.org>
---
include/sound/core.h | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/include/sound/core.h b/include/sound/core.h
index 89e0ac1..c129f08 100644
--- a/include/sound/core.h
+++ b/include/sound/core.h
@@ -179,7 +179,7 @@ int snd_power_wait(struct snd_card *card, unsigned int power_state);
#define snd_power_lock(card) do { (void)(card); } while (0)
#define snd_power_unlock(card) do { (void)(card); } while (0)
static inline int snd_power_wait(struct snd_card *card, unsigned int state) { return 0; }
-#define snd_power_get_state(card) SNDRV_CTL_POWER_D0
+#define snd_power_get_state(card) ({ (void)(card); SNDRV_CTL_POWER_D0; })
#define snd_power_change_state(card, state) do { (void)(card); } while (0)
#endif /* CONFIG_PM */
--
1.7.3.1
2
1
The following changes since commit 0f9141c974b2dc29b7d1cf245bbf4685350521be:
ASoC: Pay attention to driver supplied DAI IDs (2010-10-13 11:02:43 +0100)
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound-2.6.git for-2.6.37
Guennadi Liakhovetski (1):
fbdev: sh_mobile_hdmi: fix compilation without SOUND enabled
Joe Perches (1):
ASoC: Remove unused vol field from WM8994 access mask table
Kuninori Morimoto (2):
ASoC: fsi: simultaneous playback/recorde support
ASoC: ak4642: make sure name of register/value
Mika Westerberg (3):
ASoC: add ep93xx AC97 audio driver
ARM: ep93xx: add AC97 platform support
ASoC: ep93xx: add Simplemachines Sim.One AC97 audio support
Peter Hsiang (1):
ASoC: Add max98088 CODEC driver
Seungwhan Youn (2):
ASoC: SAMSUNG: Add S/PDIF CPU driver
ASoC: SAMSUNG: Add Machine driver for S/PDIF PCM audio
Timur Tabi (1):
powerpc/85xx: add DIU support to the Freecale P1022DS reference board
arch/arm/mach-ep93xx/core.c | 34 +
arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h | 1 +
arch/arm/mach-ep93xx/include/mach/platform.h | 1 +
arch/arm/mach-ep93xx/simone.c | 1 +
arch/powerpc/configs/mpc85xx_defconfig | 3 +
arch/powerpc/configs/mpc85xx_smp_defconfig | 3 +
arch/powerpc/platforms/85xx/p1022_ds.c | 212 ++-
drivers/video/Kconfig | 2 +
sound/soc/codecs/Kconfig | 4 +
sound/soc/codecs/Makefile | 2 +
sound/soc/codecs/ak4642.c | 64 +-
sound/soc/codecs/max98088.c | 2097 +++++++++++++++
sound/soc/codecs/max98088.h | 193 ++
sound/soc/codecs/wm8994.c | 3147 +++++++++++------------
sound/soc/ep93xx/Kconfig | 16 +-
sound/soc/ep93xx/Makefile | 4 +
sound/soc/ep93xx/ep93xx-ac97.c | 468 ++++
sound/soc/ep93xx/simone.c | 89 +
sound/soc/s3c24xx/Kconfig | 11 +
sound/soc/s3c24xx/Makefile | 4 +
sound/soc/s3c24xx/smdk_spdif.c | 223 ++
sound/soc/s3c24xx/spdif.c | 501 ++++
sound/soc/s3c24xx/spdif.h | 19 +
sound/soc/sh/fsi.c | 152 +-
24 files changed, 5598 insertions(+), 1653 deletions(-)
create mode 100644 sound/soc/codecs/max98088.c
create mode 100644 sound/soc/codecs/max98088.h
create mode 100644 sound/soc/ep93xx/ep93xx-ac97.c
create mode 100644 sound/soc/ep93xx/simone.c
create mode 100644 sound/soc/s3c24xx/smdk_spdif.c
create mode 100644 sound/soc/s3c24xx/spdif.c
create mode 100644 sound/soc/s3c24xx/spdif.h
2
1

[alsa-devel] [PATCH] ALSA: hda: Add speaker pin to automute Acer Aspire 8943G
by David Henningsson 16 Oct '10
by David Henningsson 16 Oct '10
16 Oct '10
BugLink: https://bugs.launchpad.net/bugs/656625
Add clause for handling Acer Aspire 8943G's subwoofer as additional
speaker pin for automuting.
Reported-by: RussianNeuroMancer
Cc: stable(a)kernel.org
Signed-off-by: Daniel T Chen <crimsun(a)ubuntu.com>
Signed-off-by: David Henningsson <david.henningsson(a)canonical.com>
--
David Henningsson, Canonical Ltd.
http://launchpad.net/~diwic
4
10

16 Oct '10
Hi,
This patch-set is a 2nd version for new S/PDIF common driver that supports
S/PDIF PCM audio on S5PC100, S5PC110 and S5PV210.
This patch-set is based on two different branches that :-
o ARM patches are based on Kukjin Kim's git branch 'for-next'
(commit id - 64dcc6aef86593e478cf297a8508e55b54cceaf8)
o ASoC patches are based on Mark Brown's git branch 'for-next'
(commit id - fe3e2e7ff2da41bd7a985c4c206e05a95ebe7a6b)
This patch-set updates followings from the 1st submit :-
o Add EPLL enable and get_rate function as common EPLL function
o Add EPLL rate change warning
o Fix S/PDIF's audio clock divider set dynamically at CPU driver
o Move S/PDIF specific register macros and structure into CPU driver
This patch-set contains followings :-
o To Kukjin Kim and Ben Dooks,
- [PATCH v2 1/6] ARM: S5P: Reduce duplicated EPLL control codes
- [PATCH v2 2/6] ARM: S5PV210: Fix wrong EPLL rate getting on setup clocks
- [PATCH v2 3/6] ARM: S5PV210: Add EPLL clock operations
- [PATCH v2 4/6] ARM: S5P: Add EPLL rate change warning
o To Jassi Brar, Mark Brown and Liam Girdwood,
- [PATCH v2 5/6] ASoC: SAMSUNG: Add S/PDIF CPU driver
- [PATCH v2 6/6] ASoC: SAMSUNG: Add Machine driver for S/PDIF PCM audio
Best Regards,
Claude(Seungwhan Youn)
5
16
This patch adds the MAX98088 CODEC driver.
Signed-off-by: Peter Hsiang <peter.hsiang(a)maxim-ic.com>
---
include/sound/max98088.h | 54 +
sound/soc/codecs/Kconfig | 4 +
sound/soc/codecs/Makefile | 2 +
sound/soc/codecs/max98088.c | 2355 +++++++++++++++++++++++++++++++++++++++++++
sound/soc/codecs/max98088.h | 190 ++++
5 files changed, 2605 insertions(+), 0 deletions(-)
create mode 100644 include/sound/max98088.h
create mode 100644 sound/soc/codecs/max98088.c
create mode 100644 sound/soc/codecs/max98088.h
diff --git a/include/sound/max98088.h b/include/sound/max98088.h
new file mode 100644
index 0000000..30652be
--- /dev/null
+++ b/include/sound/max98088.h
@@ -0,0 +1,54 @@
+/*
+ * Platform data for MAX98088
+ *
+ * Copyright 2010 Maxim Integrated Products
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#ifndef __SOUND_MAX98088_PDATA_H__
+#define __SOUND_MAX98088_PDATA_H__
+
+#define EQ_CFG_MAX 32
+
+/* Equalizer filter response configuration */
+struct max98088_eq_cfg {
+ const char *name;
+ unsigned int rate;
+ u16 band1[5];
+ u16 band2[5];
+ u16 band3[5];
+ u16 band4[5];
+ u16 band5[5];
+};
+
+/* codec platform data */
+struct max98088_pdata {
+
+ /* Equalizers for DAI1 and DAI2 */
+ struct max98088_eq_cfg *eq1_cfg;
+ struct max98088_eq_cfg *eq2_cfg;
+ unsigned int eq1_cfgcnt;
+ unsigned int eq2_cfgcnt;
+
+ /* Receiver output can be configured as power amplifier or LINE out */
+ /* Set receiver_mode to:
+ * 0 = amplifier output, or
+ * 1 = LINE level output
+ */
+ unsigned int receiver_mode:1;
+
+ /* Analog/digital microphone configuration:
+ * 0 = analog microphone input (normal setting)
+ * 1 = digital microphone input
+ */
+ unsigned int digmic_left_mode:1;
+ unsigned int digmic_right_mode:1;
+
+};
+
+#endif
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 4ccc2b7..4e6713c 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -27,6 +27,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_CS4270 if I2C
select SND_SOC_DA7210 if I2C
select SND_SOC_JZ4740 if SOC_JZ4740
+ select SND_SOC_MAX98088 if I2C
select SND_SOC_MAX9877 if I2C
select SND_SOC_PCM3008
select SND_SOC_SPDIF
@@ -157,6 +158,9 @@ config SND_SOC_L3
config SND_SOC_DA7210
tristate
+config SND_SOC_MAX98088
+ tristate
+
config SND_SOC_PCM3008
tristate
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 23e7e2c..7184611 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -15,6 +15,7 @@ snd-soc-cs4270-objs := cs4270.o
snd-soc-cx20442-objs := cx20442.o
snd-soc-da7210-objs := da7210.o
snd-soc-l3-objs := l3.o
+snd-soc-max98088-objs := max98088.o
snd-soc-pcm3008-objs := pcm3008.o
snd-soc-spdif-objs := spdif_transciever.o
snd-soc-ssm2602-objs := ssm2602.o
@@ -88,6 +89,7 @@ obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o
obj-$(CONFIG_SND_SOC_DA7210) += snd-soc-da7210.o
obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o
obj-$(CONFIG_SND_SOC_JZ4740_CODEC) += snd-soc-jz4740-codec.o
+obj-$(CONFIG_SND_SOC_MAX98088) += snd-soc-max98088.o
obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o
obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif.o
obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o
diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c
new file mode 100644
index 0000000..52f57d5
--- /dev/null
+++ b/sound/soc/codecs/max98088.c
@@ -0,0 +1,2355 @@
+/*
+ * max98088.c -- MAX98088 ALSA SoC Audio driver
+ *
+ * Copyright 2010 Maxim Integrated Products
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.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 <sound/tlv.h>
+#include <linux/slab.h>
+#include <sound/max98088.h>
+#include "max98088.h"
+
+/* Configurations associated with each channel of DAI stream */
+struct max98088_cdata {
+ unsigned int rate;
+ unsigned int fmt;
+ int eq_textcnt;
+ const char *eq_texts[EQ_CFG_MAX];
+ int eq_sel;
+ struct soc_enum eq_enum;
+};
+
+/* Codec private data */
+struct max98088_priv {
+ u8 reg_cache[M98088_REG_CNT];
+ void *control_data;
+ struct max98088_pdata *pdata;
+
+ unsigned int sysclk;
+ struct max98088_cdata dai[2];
+ u8 power_state;
+ unsigned int ex_mode;
+ unsigned int digmic;
+ unsigned int mic1pre;
+ unsigned int mic2pre;
+ unsigned int extmic_mode;
+};
+
+static const u8 max98088_reg[M98088_REG_CNT] = {
+ 0x00, /* 00 IRQ status */
+ 0x00, /* 01 MIC status */
+ 0x00, /* 02 jack status */
+ 0x00, /* 03 battery voltage */
+ 0x00, /* 04 */
+ 0x00, /* 05 */
+ 0x00, /* 06 */
+ 0x00, /* 07 */
+ 0x00, /* 08 */
+ 0x00, /* 09 */
+ 0x00, /* 0A */
+ 0x00, /* 0B */
+ 0x00, /* 0C */
+ 0x00, /* 0D */
+ 0x00, /* 0E */
+ 0x00, /* 0F interrupt enable */
+
+ 0x00, /* 10 master clock */
+ 0x00, /* 11 DAI1 clock mode */
+ 0x00, /* 12 DAI1 clock control */
+ 0x00, /* 13 DAI1 clock control */
+ 0x00, /* 14 DAI1 format */
+ 0x00, /* 15 DAI1 clock */
+ 0x00, /* 16 DAI1 config */
+ 0x00, /* 17 DAI1 TDM */
+ 0x00, /* 18 DAI1 filters */
+ 0x00, /* 19 DAI2 clock mode */
+ 0x00, /* 1A DAI2 clock control */
+ 0x00, /* 1B DAI2 clock control */
+ 0x00, /* 1C DAI2 format */
+ 0x00, /* 1D DAI2 clock */
+ 0x00, /* 1E DAI2 config */
+ 0x00, /* 1F DAI2 TDM */
+
+ 0x00, /* 20 DAI2 filters */
+ 0x00, /* 21 data config */
+ 0x00, /* 22 DAC mixer */
+ 0x00, /* 23 left ADC mixer */
+ 0x00, /* 24 right ADC mixer */
+ 0x00, /* 25 left HP mixer */
+ 0x00, /* 26 right HP mixer */
+ 0x00, /* 27 HP control */
+ 0x00, /* 28 left REC mixer */
+ 0x00, /* 29 right REC mixer */
+ 0x00, /* 2A REC control */
+ 0x00, /* 2B left SPK mixer */
+ 0x00, /* 2C right SPK mixer */
+ 0x00, /* 2D SPK control */
+ 0x00, /* 2E sidetone */
+ 0x00, /* 2F DAI1 playback level */
+
+ 0x00, /* 30 DAI1 playback level */
+ 0x00, /* 31 DAI2 playback level */
+ 0x00, /* 32 DAI2 playbakc level */
+ 0x00, /* 33 left ADC level */
+ 0x00, /* 34 right ADC level */
+ 0x00, /* 35 MIC1 level */
+ 0x00, /* 36 MIC2 level */
+ 0x00, /* 37 INA level */
+ 0x00, /* 38 INB level */
+ 0x00, /* 39 left HP volume */
+ 0x00, /* 3A right HP volume */
+ 0x00, /* 3B left REC volume */
+ 0x00, /* 3C right REC volume */
+ 0x00, /* 3D left SPK volume */
+ 0x00, /* 3E right SPK volume */
+ 0x00, /* 3F MIC config */
+
+ 0x00, /* 40 MIC threshold */
+ 0x00, /* 41 excursion limiter filter */
+ 0x00, /* 42 excursion limiter threshold */
+ 0x00, /* 43 ALC */
+ 0x00, /* 44 power limiter threshold */
+ 0x00, /* 45 power limiter config */
+ 0x00, /* 46 distortion limiter config */
+ 0x00, /* 47 audio input */
+ 0x00, /* 48 microphone */
+ 0x00, /* 49 level control */
+ 0x00, /* 4A bypass switches */
+ 0x00, /* 4B jack detect */
+ 0x00, /* 4C input enable */
+ 0x00, /* 4D output enable */
+ 0xF0, /* 4E bias control */
+ 0x00, /* 4F DAC power */
+
+ 0x0F, /* 50 DAC power */
+ 0x00, /* 51 system */
+ 0x00, /* 52 DAI1 EQ1 */
+ 0x00, /* 53 DAI1 EQ1 */
+ 0x00, /* 54 DAI1 EQ1 */
+ 0x00, /* 55 DAI1 EQ1 */
+ 0x00, /* 56 DAI1 EQ1 */
+ 0x00, /* 57 DAI1 EQ1 */
+ 0x00, /* 58 DAI1 EQ1 */
+ 0x00, /* 59 DAI1 EQ1 */
+ 0x00, /* 5A DAI1 EQ1 */
+ 0x00, /* 5B DAI1 EQ1 */
+ 0x00, /* 5C DAI1 EQ2 */
+ 0x00, /* 5D DAI1 EQ2 */
+ 0x00, /* 5E DAI1 EQ2 */
+ 0x00, /* 5F DAI1 EQ2 */
+
+ 0x00, /* 60 DAI1 EQ2 */
+ 0x00, /* 61 DAI1 EQ2 */
+ 0x00, /* 62 DAI1 EQ2 */
+ 0x00, /* 63 DAI1 EQ2 */
+ 0x00, /* 64 DAI1 EQ2 */
+ 0x00, /* 65 DAI1 EQ2 */
+ 0x00, /* 66 DAI1 EQ3 */
+ 0x00, /* 67 DAI1 EQ3 */
+ 0x00, /* 68 DAI1 EQ3 */
+ 0x00, /* 69 DAI1 EQ3 */
+ 0x00, /* 6A DAI1 EQ3 */
+ 0x00, /* 6B DAI1 EQ3 */
+ 0x00, /* 6C DAI1 EQ3 */
+ 0x00, /* 6D DAI1 EQ3 */
+ 0x00, /* 6E DAI1 EQ3 */
+ 0x00, /* 6F DAI1 EQ3 */
+
+ 0x00, /* 70 DAI1 EQ4 */
+ 0x00, /* 71 DAI1 EQ4 */
+ 0x00, /* 72 DAI1 EQ4 */
+ 0x00, /* 73 DAI1 EQ4 */
+ 0x00, /* 74 DAI1 EQ4 */
+ 0x00, /* 75 DAI1 EQ4 */
+ 0x00, /* 76 DAI1 EQ4 */
+ 0x00, /* 77 DAI1 EQ4 */
+ 0x00, /* 78 DAI1 EQ4 */
+ 0x00, /* 79 DAI1 EQ4 */
+ 0x00, /* 7A DAI1 EQ5 */
+ 0x00, /* 7B DAI1 EQ5 */
+ 0x00, /* 7C DAI1 EQ5 */
+ 0x00, /* 7D DAI1 EQ5 */
+ 0x00, /* 7E DAI1 EQ5 */
+ 0x00, /* 7F DAI1 EQ5 */
+
+ 0x00, /* 80 DAI1 EQ5 */
+ 0x00, /* 81 DAI1 EQ5 */
+ 0x00, /* 82 DAI1 EQ5 */
+ 0x00, /* 83 DAI1 EQ5 */
+ 0x00, /* 84 DAI2 EQ1 */
+ 0x00, /* 85 DAI2 EQ1 */
+ 0x00, /* 86 DAI2 EQ1 */
+ 0x00, /* 87 DAI2 EQ1 */
+ 0x00, /* 88 DAI2 EQ1 */
+ 0x00, /* 89 DAI2 EQ1 */
+ 0x00, /* 8A DAI2 EQ1 */
+ 0x00, /* 8B DAI2 EQ1 */
+ 0x00, /* 8C DAI2 EQ1 */
+ 0x00, /* 8D DAI2 EQ1 */
+ 0x00, /* 8E DAI2 EQ2 */
+ 0x00, /* 8F DAI2 EQ2 */
+
+ 0x00, /* 90 DAI2 EQ2 */
+ 0x00, /* 91 DAI2 EQ2 */
+ 0x00, /* 92 DAI2 EQ2 */
+ 0x00, /* 93 DAI2 EQ2 */
+ 0x00, /* 94 DAI2 EQ2 */
+ 0x00, /* 95 DAI2 EQ2 */
+ 0x00, /* 96 DAI2 EQ2 */
+ 0x00, /* 97 DAI2 EQ2 */
+ 0x00, /* 98 DAI2 EQ3 */
+ 0x00, /* 99 DAI2 EQ3 */
+ 0x00, /* 9A DAI2 EQ3 */
+ 0x00, /* 9B DAI2 EQ3 */
+ 0x00, /* 9C DAI2 EQ3 */
+ 0x00, /* 9D DAI2 EQ3 */
+ 0x00, /* 9E DAI2 EQ3 */
+ 0x00, /* 9F DAI2 EQ3 */
+
+ 0x00, /* A0 DAI2 EQ3 */
+ 0x00, /* A1 DAI2 EQ3 */
+ 0x00, /* A2 DAI2 EQ4 */
+ 0x00, /* A3 DAI2 EQ4 */
+ 0x00, /* A4 DAI2 EQ4 */
+ 0x00, /* A5 DAI2 EQ4 */
+ 0x00, /* A6 DAI2 EQ4 */
+ 0x00, /* A7 DAI2 EQ4 */
+ 0x00, /* A8 DAI2 EQ4 */
+ 0x00, /* A9 DAI2 EQ4 */
+ 0x00, /* AA DAI2 EQ4 */
+ 0x00, /* AB DAI2 EQ4 */
+ 0x00, /* AC DAI2 EQ5 */
+ 0x00, /* AD DAI2 EQ5 */
+ 0x00, /* AE DAI2 EQ5 */
+ 0x00, /* AF DAI2 EQ5 */
+
+ 0x00, /* B0 DAI2 EQ5 */
+ 0x00, /* B1 DAI2 EQ5 */
+ 0x00, /* B2 DAI2 EQ5 */
+ 0x00, /* B3 DAI2 EQ5 */
+ 0x00, /* B4 DAI2 EQ5 */
+ 0x00, /* B5 DAI2 EQ5 */
+ 0x00, /* B6 DAI1 biquad */
+ 0x00, /* B7 DAI1 biquad */
+ 0x00, /* B8 DAI1 biquad */
+ 0x00, /* B9 DAI1 biquad */
+ 0x00, /* BA DAI1 biquad */
+ 0x00, /* BB DAI1 biquad */
+ 0x00, /* BC DAI1 biquad */
+ 0x00, /* BD DAI1 biquad */
+ 0x00, /* BE DAI1 biquad */
+ 0x00, /* BF DAI1 biquad */
+
+ 0x00, /* C0 DAI2 biquad */
+ 0x00, /* C1 DAI2 biquad */
+ 0x00, /* C2 DAI2 biquad */
+ 0x00, /* C3 DAI2 biquad */
+ 0x00, /* C4 DAI2 biquad */
+ 0x00, /* C5 DAI2 biquad */
+ 0x00, /* C6 DAI2 biquad */
+ 0x00, /* C7 DAI2 biquad */
+ 0x00, /* C8 DAI2 biquad */
+ 0x00, /* C9 DAI2 biquad */
+ 0x00, /* CA */
+ 0x00, /* CB */
+ 0x00, /* CC */
+ 0x00, /* CD */
+ 0x00, /* CE */
+ 0x00, /* CF */
+
+ 0x00, /* D0 */
+ 0x00, /* D1 */
+ 0x00, /* D2 */
+ 0x00, /* D3 */
+ 0x00, /* D4 */
+ 0x00, /* D5 */
+ 0x00, /* D6 */
+ 0x00, /* D7 */
+ 0x00, /* D8 */
+ 0x00, /* D9 */
+ 0x00, /* DA */
+ 0x70, /* DB */
+ 0x00, /* DC */
+ 0x00, /* DD */
+ 0x00, /* DE */
+ 0x00, /* DF */
+
+ 0x00, /* E0 */
+ 0x00, /* E1 */
+ 0x00, /* E2 */
+ 0x00, /* E3 */
+ 0x00, /* E4 */
+ 0x00, /* E5 */
+ 0x00, /* E6 */
+ 0x00, /* E7 */
+ 0x00, /* E8 */
+ 0x00, /* E9 */
+ 0x00, /* EA */
+ 0x00, /* EB */
+ 0x00, /* EC */
+ 0x00, /* ED */
+ 0x00, /* EE */
+ 0x00, /* EF */
+
+ 0x00, /* F0 */
+ 0x00, /* F1 */
+ 0x00, /* F2 */
+ 0x00, /* F3 */
+ 0x00, /* F4 */
+ 0x00, /* F5 */
+ 0x00, /* F6 */
+ 0x00, /* F7 */
+ 0x00, /* F8 */
+ 0x00, /* F9 */
+ 0x00, /* FA */
+ 0x00, /* FB */
+ 0x00, /* FC */
+ 0x00, /* FD */
+ 0x00, /* FE */
+ 0x00, /* FF */
+};
+
+static struct {
+ int readable;
+ int writable;
+ int vol;
+} max98088_access[M98088_REG_CNT] = {
+ { 0xFF, 0xFF, 1 }, /* 00 IRQ status */
+ { 0xFF, 0x00, 1 }, /* 01 MIC status */
+ { 0xFF, 0x00, 1 }, /* 02 jack status */
+ { 0x1F, 0x1F, 1 }, /* 03 battery voltage */
+ { 0xFF, 0xFF, 0 }, /* 04 */
+ { 0xFF, 0xFF, 0 }, /* 05 */
+ { 0xFF, 0xFF, 0 }, /* 06 */
+ { 0xFF, 0xFF, 0 }, /* 07 */
+ { 0xFF, 0xFF, 0 }, /* 08 */
+ { 0xFF, 0xFF, 0 }, /* 09 */
+ { 0xFF, 0xFF, 0 }, /* 0A */
+ { 0xFF, 0xFF, 0 }, /* 0B */
+ { 0xFF, 0xFF, 0 }, /* 0C */
+ { 0xFF, 0xFF, 0 }, /* 0D */
+ { 0xFF, 0xFF, 0 }, /* 0E */
+ { 0xFF, 0xFF, 0 }, /* 0F interrupt enable */
+
+ { 0xFF, 0xFF, 0 }, /* 10 master clock */
+ { 0xFF, 0xFF, 0 }, /* 11 DAI1 clock mode */
+ { 0xFF, 0xFF, 0 }, /* 12 DAI1 clock control */
+ { 0xFF, 0xFF, 0 }, /* 13 DAI1 clock control */
+ { 0xFF, 0xFF, 0 }, /* 14 DAI1 format */
+ { 0xFF, 0xFF, 0 }, /* 15 DAI1 clock */
+ { 0xFF, 0xFF, 0 }, /* 16 DAI1 config */
+ { 0xFF, 0xFF, 0 }, /* 17 DAI1 TDM */
+ { 0xFF, 0xFF, 0 }, /* 18 DAI1 filters */
+ { 0xFF, 0xFF, 0 }, /* 19 DAI2 clock mode */
+ { 0xFF, 0xFF, 0 }, /* 1A DAI2 clock control */
+ { 0xFF, 0xFF, 0 }, /* 1B DAI2 clock control */
+ { 0xFF, 0xFF, 0 }, /* 1C DAI2 format */
+ { 0xFF, 0xFF, 0 }, /* 1D DAI2 clock */
+ { 0xFF, 0xFF, 0 }, /* 1E DAI2 config */
+ { 0xFF, 0xFF, 0 }, /* 1F DAI2 TDM */
+
+ { 0xFF, 0xFF, 0 }, /* 20 DAI2 filters */
+ { 0xFF, 0xFF, 0 }, /* 21 data config */
+ { 0xFF, 0xFF, 0 }, /* 22 DAC mixer */
+ { 0xFF, 0xFF, 0 }, /* 23 left ADC mixer */
+ { 0xFF, 0xFF, 0 }, /* 24 right ADC mixer */
+ { 0xFF, 0xFF, 0 }, /* 25 left HP mixer */
+ { 0xFF, 0xFF, 0 }, /* 26 right HP mixer */
+ { 0xFF, 0xFF, 0 }, /* 27 HP control */
+ { 0xFF, 0xFF, 0 }, /* 28 left REC mixer */
+ { 0xFF, 0xFF, 0 }, /* 29 right REC mixer */
+ { 0xFF, 0xFF, 0 }, /* 2A REC control */
+ { 0xFF, 0xFF, 0 }, /* 2B left SPK mixer */
+ { 0xFF, 0xFF, 0 }, /* 2C right SPK mixer */
+ { 0xFF, 0xFF, 0 }, /* 2D SPK control */
+ { 0xFF, 0xFF, 0 }, /* 2E sidetone */
+ { 0xFF, 0xFF, 0 }, /* 2F DAI1 playback level */
+
+ { 0xFF, 0xFF, 0 }, /* 30 DAI1 playback level */
+ { 0xFF, 0xFF, 0 }, /* 31 DAI2 playback level */
+ { 0xFF, 0xFF, 0 }, /* 32 DAI2 playbakc level */
+ { 0xFF, 0xFF, 0 }, /* 33 left ADC level */
+ { 0xFF, 0xFF, 0 }, /* 34 right ADC level */
+ { 0xFF, 0xFF, 0 }, /* 35 MIC1 level */
+ { 0xFF, 0xFF, 0 }, /* 36 MIC2 level */
+ { 0xFF, 0xFF, 0 }, /* 37 INA level */
+ { 0xFF, 0xFF, 0 }, /* 38 INB level */
+ { 0xFF, 0xFF, 0 }, /* 39 left HP volume */
+ { 0xFF, 0xFF, 0 }, /* 3A right HP volume */
+ { 0xFF, 0xFF, 0 }, /* 3B left REC volume */
+ { 0xFF, 0xFF, 0 }, /* 3C right REC volume */
+ { 0xFF, 0xFF, 0 }, /* 3D left SPK volume */
+ { 0xFF, 0xFF, 0 }, /* 3E right SPK volume */
+ { 0xFF, 0xFF, 0 }, /* 3F MIC config */
+
+ { 0xFF, 0xFF, 0 }, /* 40 MIC threshold */
+ { 0xFF, 0xFF, 0 }, /* 41 excursion limiter filter */
+ { 0xFF, 0xFF, 0 }, /* 42 excursion limiter threshold */
+ { 0xFF, 0xFF, 0 }, /* 43 ALC */
+ { 0xFF, 0xFF, 0 }, /* 44 power limiter threshold */
+ { 0xFF, 0xFF, 0 }, /* 45 power limiter config */
+ { 0xFF, 0xFF, 0 }, /* 46 distortion limiter config */
+ { 0xFF, 0xFF, 0 }, /* 47 audio input */
+ { 0xFF, 0xFF, 0 }, /* 48 microphone */
+ { 0xFF, 0xFF, 0 }, /* 49 level control */
+ { 0xFF, 0xFF, 0 }, /* 4A bypass switches */
+ { 0xFF, 0xFF, 0 }, /* 4B jack detect */
+ { 0xFF, 0xFF, 0 }, /* 4C input enable */
+ { 0xFF, 0xFF, 0 }, /* 4D output enable */
+ { 0xFF, 0xFF, 0 }, /* 4E bias control */
+ { 0xFF, 0xFF, 0 }, /* 4F DAC power */
+
+ { 0xFF, 0xFF, 0 }, /* 50 DAC power */
+ { 0xFF, 0xFF, 0 }, /* 51 system */
+ { 0xFF, 0xFF, 0 }, /* 52 DAI1 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 53 DAI1 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 54 DAI1 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 55 DAI1 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 56 DAI1 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 57 DAI1 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 58 DAI1 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 59 DAI1 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 5A DAI1 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 5B DAI1 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 5C DAI1 EQ2 */
+ { 0xFF, 0xFF, 0 }, /* 5D DAI1 EQ2 */
+ { 0xFF, 0xFF, 0 }, /* 5E DAI1 EQ2 */
+ { 0xFF, 0xFF, 0 }, /* 5F DAI1 EQ2 */
+
+ { 0xFF, 0xFF, 0 }, /* 60 DAI1 EQ2 */
+ { 0xFF, 0xFF, 0 }, /* 61 DAI1 EQ2 */
+ { 0xFF, 0xFF, 0 }, /* 62 DAI1 EQ2 */
+ { 0xFF, 0xFF, 0 }, /* 63 DAI1 EQ2 */
+ { 0xFF, 0xFF, 0 }, /* 64 DAI1 EQ2 */
+ { 0xFF, 0xFF, 0 }, /* 65 DAI1 EQ2 */
+ { 0xFF, 0xFF, 0 }, /* 66 DAI1 EQ3 */
+ { 0xFF, 0xFF, 0 }, /* 67 DAI1 EQ3 */
+ { 0xFF, 0xFF, 0 }, /* 68 DAI1 EQ3 */
+ { 0xFF, 0xFF, 0 }, /* 69 DAI1 EQ3 */
+ { 0xFF, 0xFF, 0 }, /* 6A DAI1 EQ3 */
+ { 0xFF, 0xFF, 0 }, /* 6B DAI1 EQ3 */
+ { 0xFF, 0xFF, 0 }, /* 6C DAI1 EQ3 */
+ { 0xFF, 0xFF, 0 }, /* 6D DAI1 EQ3 */
+ { 0xFF, 0xFF, 0 }, /* 6E DAI1 EQ3 */
+ { 0xFF, 0xFF, 0 }, /* 6F DAI1 EQ3 */
+
+ { 0xFF, 0xFF, 0 }, /* 70 DAI1 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* 71 DAI1 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* 72 DAI1 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* 73 DAI1 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* 74 DAI1 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* 75 DAI1 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* 76 DAI1 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* 77 DAI1 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* 78 DAI1 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* 79 DAI1 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* 7A DAI1 EQ5 */
+ { 0xFF, 0xFF, 0 }, /* 7B DAI1 EQ5 */
+ { 0xFF, 0xFF, 0 }, /* 7C DAI1 EQ5 */
+ { 0xFF, 0xFF, 0 }, /* 7D DAI1 EQ5 */
+ { 0xFF, 0xFF, 0 }, /* 7E DAI1 EQ5 */
+ { 0xFF, 0xFF, 0 }, /* 7F DAI1 EQ5 */
+
+ { 0xFF, 0xFF, 0 }, /* 80 DAI1 EQ5 */
+ { 0xFF, 0xFF, 0 }, /* 81 DAI1 EQ5 */
+ { 0xFF, 0xFF, 0 }, /* 82 DAI1 EQ5 */
+ { 0xFF, 0xFF, 0 }, /* 83 DAI1 EQ5 */
+ { 0xFF, 0xFF, 0 }, /* 84 DAI2 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 85 DAI2 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 86 DAI2 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 87 DAI2 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 88 DAI2 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 89 DAI2 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 8A DAI2 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 8B DAI2 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 8C DAI2 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 8D DAI2 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 8E DAI2 EQ2 */
+ { 0xFF, 0xFF, 0 }, /* 8F DAI2 EQ2 */
+
+ { 0xFF, 0xFF, 0 }, /* 90 DAI2 EQ2 */
+ { 0xFF, 0xFF, 0 }, /* 91 DAI2 EQ2 */
+ { 0xFF, 0xFF, 0 }, /* 92 DAI2 EQ2 */
+ { 0xFF, 0xFF, 0 }, /* 93 DAI2 EQ2 */
+ { 0xFF, 0xFF, 0 }, /* 94 DAI2 EQ2 */
+ { 0xFF, 0xFF, 0 }, /* 95 DAI2 EQ2 */
+ { 0xFF, 0xFF, 0 }, /* 96 DAI2 EQ2 */
+ { 0xFF, 0xFF, 0 }, /* 97 DAI2 EQ2 */
+ { 0xFF, 0xFF, 0 }, /* 98 DAI2 EQ3 */
+ { 0xFF, 0xFF, 0 }, /* 99 DAI2 EQ3 */
+ { 0xFF, 0xFF, 0 }, /* 9A DAI2 EQ3 */
+ { 0xFF, 0xFF, 0 }, /* 9B DAI2 EQ3 */
+ { 0xFF, 0xFF, 0 }, /* 9C DAI2 EQ3 */
+ { 0xFF, 0xFF, 0 }, /* 9D DAI2 EQ3 */
+ { 0xFF, 0xFF, 0 }, /* 9E DAI2 EQ3 */
+ { 0xFF, 0xFF, 0 }, /* 9F DAI2 EQ3 */
+
+ { 0xFF, 0xFF, 0 }, /* A0 DAI2 EQ3 */
+ { 0xFF, 0xFF, 0 }, /* A1 DAI2 EQ3 */
+ { 0xFF, 0xFF, 0 }, /* A2 DAI2 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* A3 DAI2 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* A4 DAI2 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* A5 DAI2 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* A6 DAI2 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* A7 DAI2 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* A8 DAI2 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* A9 DAI2 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* AA DAI2 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* AB DAI2 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* AC DAI2 EQ5 */
+ { 0xFF, 0xFF, 0 }, /* AD DAI2 EQ5 */
+ { 0xFF, 0xFF, 0 }, /* AE DAI2 EQ5 */
+ { 0xFF, 0xFF, 0 }, /* AF DAI2 EQ5 */
+
+ { 0xFF, 0xFF, 0 }, /* B0 DAI2 EQ5 */
+ { 0xFF, 0xFF, 0 }, /* B1 DAI2 EQ5 */
+ { 0xFF, 0xFF, 0 }, /* B2 DAI2 EQ5 */
+ { 0xFF, 0xFF, 0 }, /* B3 DAI2 EQ5 */
+ { 0xFF, 0xFF, 0 }, /* B4 DAI2 EQ5 */
+ { 0xFF, 0xFF, 0 }, /* B5 DAI2 EQ5 */
+ { 0xFF, 0xFF, 0 }, /* B6 DAI1 biquad */
+ { 0xFF, 0xFF, 0 }, /* B7 DAI1 biquad */
+ { 0xFF, 0xFF, 0 }, /* B8 DAI1 biquad */
+ { 0xFF, 0xFF, 0 }, /* B9 DAI1 biquad */
+ { 0xFF, 0xFF, 0 }, /* BA DAI1 biquad */
+ { 0xFF, 0xFF, 0 }, /* BB DAI1 biquad */
+ { 0xFF, 0xFF, 0 }, /* BC DAI1 biquad */
+ { 0xFF, 0xFF, 0 }, /* BD DAI1 biquad */
+ { 0xFF, 0xFF, 0 }, /* BE DAI1 biquad */
+ { 0xFF, 0xFF, 0 }, /* BF DAI1 biquad */
+
+ { 0xFF, 0xFF, 0 }, /* C0 DAI2 biquad */
+ { 0xFF, 0xFF, 0 }, /* C1 DAI2 biquad */
+ { 0xFF, 0xFF, 0 }, /* C2 DAI2 biquad */
+ { 0xFF, 0xFF, 0 }, /* C3 DAI2 biquad */
+ { 0xFF, 0xFF, 0 }, /* C4 DAI2 biquad */
+ { 0xFF, 0xFF, 0 }, /* C5 DAI2 biquad */
+ { 0xFF, 0xFF, 0 }, /* C6 DAI2 biquad */
+ { 0xFF, 0xFF, 0 }, /* C7 DAI2 biquad */
+ { 0xFF, 0xFF, 0 }, /* C8 DAI2 biquad */
+ { 0xFF, 0xFF, 0 }, /* C9 DAI2 biquad */
+ { 0x00, 0x00, 0 }, /* CA */
+ { 0x00, 0x00, 0 }, /* CB */
+ { 0x00, 0x00, 0 }, /* CC */
+ { 0x00, 0x00, 0 }, /* CD */
+ { 0x00, 0x00, 0 }, /* CE */
+ { 0x00, 0x00, 0 }, /* CF */
+
+ { 0x00, 0x00, 0 }, /* D0 */
+ { 0x00, 0x00, 0 }, /* D1 */
+ { 0x00, 0x00, 0 }, /* D2 */
+ { 0x00, 0x00, 0 }, /* D3 */
+ { 0x00, 0x00, 0 }, /* D4 */
+ { 0x00, 0x00, 0 }, /* D5 */
+ { 0x00, 0x00, 0 }, /* D6 */
+ { 0x00, 0x00, 0 }, /* D7 */
+ { 0x00, 0x00, 0 }, /* D8 */
+ { 0x00, 0x00, 0 }, /* D9 */
+ { 0x00, 0x00, 0 }, /* DA */
+ { 0x00, 0x00, 0 }, /* DB */
+ { 0x00, 0x00, 0 }, /* DC */
+ { 0x00, 0x00, 0 }, /* DD */
+ { 0x00, 0x00, 0 }, /* DE */
+ { 0x00, 0x00, 0 }, /* DF */
+
+ { 0x00, 0x00, 0 }, /* E0 */
+ { 0x00, 0x00, 0 }, /* E1 */
+ { 0x00, 0x00, 0 }, /* E2 */
+ { 0x00, 0x00, 0 }, /* E3 */
+ { 0x00, 0x00, 0 }, /* E4 */
+ { 0x00, 0x00, 0 }, /* E5 */
+ { 0x00, 0x00, 0 }, /* E6 */
+ { 0x00, 0x00, 0 }, /* E7 */
+ { 0x00, 0x00, 0 }, /* E8 */
+ { 0x00, 0x00, 0 }, /* E9 */
+ { 0x00, 0x00, 0 }, /* EA */
+ { 0x00, 0x00, 0 }, /* EB */
+ { 0x00, 0x00, 0 }, /* EC */
+ { 0x00, 0x00, 0 }, /* ED */
+ { 0x00, 0x00, 0 }, /* EE */
+ { 0x00, 0x00, 0 }, /* EF */
+
+ { 0x00, 0x00, 0 }, /* F0 */
+ { 0x00, 0x00, 0 }, /* F1 */
+ { 0x00, 0x00, 0 }, /* F2 */
+ { 0x00, 0x00, 0 }, /* F3 */
+ { 0x00, 0x00, 0 }, /* F4 */
+ { 0x00, 0x00, 0 }, /* F5 */
+ { 0x00, 0x00, 0 }, /* F6 */
+ { 0x00, 0x00, 0 }, /* F7 */
+ { 0x00, 0x00, 0 }, /* F8 */
+ { 0x00, 0x00, 0 }, /* F9 */
+ { 0x00, 0x00, 0 }, /* FA */
+ { 0x00, 0x00, 0 }, /* FB */
+ { 0x00, 0x00, 0 }, /* FC */
+ { 0x00, 0x00, 0 }, /* FD */
+ { 0x00, 0x00, 0 }, /* FE */
+ { 0xFF, 0x00, 1 }, /* FF */
+};
+
+static int max98088_volatile_register(unsigned int reg)
+{
+ return max98088_access[reg].vol;
+}
+
+static int max98088_hw_write(struct snd_soc_codec *codec, unsigned int reg,
+ unsigned int value)
+{
+ u8 data[2];
+
+ data[0] = reg;
+ data[1] = value;
+ if (codec->hw_write(codec->control_data, data, 2) == 2)
+ return 0;
+ else
+ return -EIO;
+}
+
+/*
+ * For kernels compiled without unsigned long long int division
+ */
+unsigned long long int ulldiv(unsigned long long int dividend,
+ unsigned long long int divisor)
+{
+ unsigned long long int quotient = 0;
+ int shift = 1;
+
+ BUG_ON(divisor == 0);
+
+ /* Result is 1.0 if divisor and dividend are equal */
+ if (divisor == dividend)
+ return 1;
+
+ /* Normalize divisor */
+ while (!(divisor & 0x8000000000000000ULL)) {
+ divisor <<= 1;
+ ++shift;
+ }
+
+ /* Shift and subtract */
+ while (shift--) {
+ quotient <<= 1;
+
+ if (divisor <= dividend) {
+ dividend -= divisor;
+ ++quotient;
+ }
+ divisor >>= 1;
+ }
+
+ /* Round up */
+ if (dividend > divisor)
+ ++quotient;
+
+ return quotient;
+}
+
+#define INA1_PGA_BIT 0x01
+#define INA2_PGA_BIT 0x02
+#define INB1_PGA_BIT 0x04
+#define INB2_PGA_BIT 0x08
+/*
+ * The INx1 and INx2 PGAs share a power control signal.
+ * This function OR's the two power events to keep an unpowered INx
+ * from turning off it's counterpart.
+ * The control names are used to identify the PGA.
+ */
+static int max98088_pga_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ u8 *state = &max98088->power_state;
+ unsigned int val;
+ unsigned int pga;
+ unsigned int mask;
+
+ BUG_ON(w->reg != M98088_REG_4C_PWR_EN_IN);
+
+ if (strncmp(w->name, "INA1", 4) == 0) {
+ pga = INA1_PGA_BIT;
+ mask = INA1_PGA_BIT | INA2_PGA_BIT;
+ } else if (strncmp(w->name, "INA2", 4) == 0) {
+ pga = INA2_PGA_BIT;
+ mask = INA1_PGA_BIT | INA2_PGA_BIT;
+ } else if (strncmp(w->name, "INB1", 4) == 0) {
+ pga = INB1_PGA_BIT;
+ mask = INB1_PGA_BIT | INB2_PGA_BIT;
+ } else if (strncmp(w->name, "INB2", 4) == 0) {
+ pga = INB2_PGA_BIT;
+ mask = INB1_PGA_BIT | INB2_PGA_BIT;
+ } else {
+ return -EINVAL;
+ }
+
+ if (event == SND_SOC_DAPM_POST_PMU) {
+ /* ON */
+ *state |= pga;
+
+ /* Turn on, avoiding unnecessary writes */
+ val = snd_soc_read(codec, w->reg);
+ if (!(val & (1 << w->shift))) {
+ val |= (1 << w->shift);
+ snd_soc_write(codec, w->reg, val);
+ }
+ } else if (event == SND_SOC_DAPM_POST_PMD) {
+ /* OFF */
+ *state &= ~pga;
+
+ /* Turn off if both are off, avoiding unnecessary writes */
+ if (!(*state & mask)) {
+ val = snd_soc_read(codec, w->reg);
+ if (val & (1 << w->shift)) {
+ val &= ~(1 << w->shift);
+ snd_soc_write(codec, w->reg, val);
+ }
+ }
+ } else {
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/*
+ * Load equalizer DSP coefficient configurations registers
+ */
+void m98088_eq_band(struct snd_soc_codec *codec, unsigned int dai,
+ unsigned int band, u16 *coefs)
+{
+ unsigned int eq_reg;
+ unsigned int i;
+
+ BUG_ON(band > 4);
+ BUG_ON(dai > 1);
+
+ /* Load the base register address */
+ eq_reg = dai ? M98088_REG_84_DAI2_EQ_BASE : M98088_REG_52_DAI1_EQ_BASE;
+
+ /* Add the band address offset, note adjustment for word address */
+ eq_reg += band * (M98088_COEFS_PER_BAND << 1);
+
+ /* Step through the registers and coefs */
+ for (i = 0; i < M98088_COEFS_PER_BAND; i++) {
+ snd_soc_write(codec, eq_reg++, M98088_BYTE1(coefs[i]));
+ snd_soc_write(codec, eq_reg++, M98088_BYTE0(coefs[i]));
+ }
+
+ return;
+}
+
+/*
+ * Excursion limiter modes
+ */
+static const char *max98088_ex_mode[] = {
+ "Off",
+ "100Hz",
+ "400Hz",
+ "600Hz",
+ "800Hz",
+ "1000Hz",
+ "200-400Hz",
+ "400-600Hz",
+ "400-800Hz",
+};
+
+static const unsigned int ex_mode_table[] = {
+ 0x00, /* disabled */
+ (0<<4)|3, /* 100Hz */
+ (1<<4)|0, /* 400Hz */
+ (2<<4)|0, /* 600Hz */
+ (3<<4)|0, /* 800Hz */
+ (4<<4)|0, /* 1000Hz */
+ (1<<4)|1, /* 200-400Hz */
+ (2<<4)|2, /* 400-600Hz */
+ (3<<4)|2, /* 400-800Hz */
+};
+
+static const struct soc_enum max98088_ex_mode_enum[] = {
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(max98088_ex_mode), max98088_ex_mode),
+};
+
+static int max98088_ex_mode_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ unsigned int *mode = &max98088->ex_mode;
+ int sel = ucontrol->value.integer.value[0];
+
+ if (sel >= ARRAY_SIZE(ex_mode_table))
+ return -EINVAL;
+
+ *mode = ucontrol->value.integer.value[0];
+ snd_soc_write(codec, M98088_REG_41_SPKDHP,
+ ex_mode_table[*mode]);
+
+ return 0;
+}
+
+static int max98088_ex_mode_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ unsigned int *mode = &max98088->ex_mode;
+
+ ucontrol->value.integer.value[0] = *mode;
+ return 0;
+}
+
+static const char *max98088_ex_thresh[] = { /* volts PP */
+ "0.6", "1.2", "1.8", "2.4", "3.0", "3.6", "4.2", "4.8"};
+static const struct soc_enum max98088_ex_thresh_enum[] = {
+ SOC_ENUM_SINGLE(M98088_REG_42_SPKDHP_THRESH, 0, 8,
+ max98088_ex_thresh),
+};
+
+static const char *max98088_fltr_mode[] = {"Voice", "Music" };
+static const struct soc_enum max98088_filter_mode_enum[] = {
+ SOC_ENUM_SINGLE(M98088_REG_18_DAI1_FILTERS, 7, 2, max98088_fltr_mode),
+};
+
+static const char *max98088_dai1_fltr[] = {
+ "Off", "fc=258/fs=16k", "fc=500/fs=16k",
+ "fc=258/fs=8k", "fc=500/fs=8k", "fc=200"};
+static const struct soc_enum max98088_dai1_dac_filter_enum[] = {
+ SOC_ENUM_SINGLE(M98088_REG_18_DAI1_FILTERS, 0, 6, max98088_dai1_fltr),
+};
+static const struct soc_enum max98088_dai1_adc_filter_enum[] = {
+ SOC_ENUM_SINGLE(M98088_REG_18_DAI1_FILTERS, 4, 6, max98088_dai1_fltr),
+};
+
+static const char *max98088_micpre[] = {
+ "0dB",
+ "20dB",
+ "30dB",
+};
+
+static const struct soc_enum max98088_micpre_enum[] = {
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(max98088_micpre), max98088_micpre),
+};
+
+static const char *max98088_extmic[] = {
+ "Off",
+ "MIC1",
+ "MIC2",
+};
+
+static const struct soc_enum max98088_extmic_enum[] = {
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(max98088_extmic), max98088_extmic),
+};
+
+static int max98088_mic1pre_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ unsigned int *mode = &max98088->mic1pre;
+ int sel = ucontrol->value.integer.value[0];
+
+ if (sel >= ARRAY_SIZE(max98088_micpre))
+ return -EINVAL;
+
+ *mode = ucontrol->value.integer.value[0];
+ return 0;
+}
+
+static int max98088_mic1pre_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ unsigned int *mode = &max98088->mic1pre;
+
+ ucontrol->value.integer.value[0] = *mode;
+ return 0;
+}
+
+static int max98088_mic2pre_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ unsigned int *mode = &max98088->mic2pre;
+ int sel = ucontrol->value.integer.value[0];
+
+ if (sel >= ARRAY_SIZE(max98088_micpre))
+ return -EINVAL;
+
+ *mode = ucontrol->value.integer.value[0];
+ return 0;
+}
+
+static int max98088_mic2pre_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ unsigned int *mode = &max98088->mic2pre;
+
+ ucontrol->value.integer.value[0] = *mode;
+ return 0;
+}
+
+static int max98088_extmic_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ unsigned int *mode = &max98088->extmic_mode;
+ int sel = ucontrol->value.integer.value[0];
+
+ if (sel >= ARRAY_SIZE(max98088_extmic))
+ return -EINVAL;
+
+ *mode = sel;
+ snd_soc_update_bits(codec, M98088_REG_48_CFG_MIC,
+ M98088_EXTMIC_MASK, sel);
+
+ return 0;
+}
+
+static int max98088_extmic_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ unsigned int *mode = &max98088->extmic_mode;
+
+ ucontrol->value.integer.value[0] = *mode;
+ return 0;
+}
+
+static const struct snd_kcontrol_new max98088_snd_controls[] = {
+
+ /* Analog outputs */
+
+ SOC_DOUBLE_R("Headphone Volume", M98088_REG_39_LVL_HP_L,
+ M98088_REG_3A_LVL_HP_R, 0, 31, 0),
+ SOC_DOUBLE_R("Speaker Volume", M98088_REG_3D_LVL_SPK_L,
+ M98088_REG_3E_LVL_SPK_R, 0, 31, 0),
+ SOC_DOUBLE_R("Receiver Volume", M98088_REG_3B_LVL_REC_L,
+ M98088_REG_3C_LVL_REC_R, 0, 31, 0),
+
+ SOC_DOUBLE_R("Headphone Switch", M98088_REG_39_LVL_HP_L,
+ M98088_REG_3A_LVL_HP_R, 7, 1, 1),
+ SOC_DOUBLE_R("Speaker Switch", M98088_REG_3D_LVL_SPK_L,
+ M98088_REG_3E_LVL_SPK_R, 7, 1, 1),
+ SOC_DOUBLE_R("Receiver Switch", M98088_REG_3B_LVL_REC_L,
+ M98088_REG_3C_LVL_REC_R, 7, 1, 1),
+
+ /* Analog inputs */
+
+ SOC_SINGLE("MIC1 Volume", M98088_REG_35_LVL_MIC1, 0, 31, 1),
+ SOC_SINGLE("MIC2 Volume", M98088_REG_36_LVL_MIC2, 0, 31, 1),
+
+ SOC_ENUM_EXT("MIC1 Boost Volume", max98088_micpre_enum,
+ max98088_mic1pre_get, max98088_mic1pre_set),
+
+ SOC_ENUM_EXT("MIC2 Boost Volume", max98088_micpre_enum,
+ max98088_mic2pre_get, max98088_mic2pre_set),
+
+ SOC_ENUM_EXT("Ext MIC Switch", max98088_extmic_enum,
+ max98088_extmic_get, max98088_extmic_set),
+
+ SOC_SINGLE("INA Volume", M98088_REG_37_LVL_INA, 0, 7, 1),
+ SOC_SINGLE("INB Volume", M98088_REG_38_LVL_INB, 0, 7, 1),
+
+ /* ADC input digital gains and volume controls */
+
+ SOC_SINGLE("ADCL Volume", M98088_REG_33_LVL_ADC_L, 0, 15, 0),
+ SOC_SINGLE("ADCR Volume", M98088_REG_34_LVL_ADC_R, 0, 15, 0),
+
+ SOC_SINGLE("ADCL Boost Volume", M98088_REG_33_LVL_ADC_L, 4, 3, 0),
+ SOC_SINGLE("ADCR Boost Volume", M98088_REG_34_LVL_ADC_R, 4, 3, 0),
+
+ /* Equalizer */
+
+ SOC_SINGLE("EQ1 Switch", M98088_REG_49_CFG_LEVEL, 0, 1, 0),
+ SOC_SINGLE("EQ2 Switch", M98088_REG_49_CFG_LEVEL, 1, 1, 0),
+
+ /* Excursion limiter */
+
+ SOC_ENUM_EXT("EX Limiter Mode", max98088_ex_mode_enum,
+ max98088_ex_mode_get, max98088_ex_mode_set),
+ SOC_ENUM("EX Limiter Threshold", max98088_ex_thresh_enum),
+
+ /* Voice/music filters */
+
+ SOC_ENUM("DAI1 Filter Mode", max98088_filter_mode_enum),
+ SOC_ENUM("DAI1 DAC Filter", max98088_dai1_dac_filter_enum),
+ SOC_ENUM("DAI1 ADC Filter", max98088_dai1_adc_filter_enum),
+ SOC_SINGLE("DAI2 DC Block Switch", M98088_REG_20_DAI2_FILTERS,
+ 0, 1, 0),
+
+ /* Automatic level control (for both DAI1/DAI2) */
+
+ SOC_SINGLE("ALC Switch", M98088_REG_43_SPKALC_COMP, 7, 1, 0),
+ SOC_SINGLE("ALC Threshold", M98088_REG_43_SPKALC_COMP, 0, 7, 0),
+ SOC_SINGLE("ALC Multiband", M98088_REG_43_SPKALC_COMP, 3, 1, 0),
+ SOC_SINGLE("ALC Release Time", M98088_REG_43_SPKALC_COMP, 4, 7, 0),
+
+ /* Power limiter */
+
+ SOC_SINGLE("PWR Limiter Threshold", M98088_REG_44_PWRLMT_CFG,
+ 4, 15, 0),
+ SOC_SINGLE("PWR Limiter Weight", M98088_REG_44_PWRLMT_CFG, 0, 7, 0),
+ SOC_SINGLE("PWR Limiter Time1", M98088_REG_45_PWRLMT_TIME, 0, 15, 0),
+ SOC_SINGLE("PWR Limiter Time2", M98088_REG_45_PWRLMT_TIME, 4, 15, 0),
+
+ /* THD distortion limiter */
+
+ SOC_SINGLE("THD Limiter Threshold", M98088_REG_46_THDLMT_CFG, 4, 15, 0),
+ SOC_SINGLE("THD Limiter Time", M98088_REG_46_THDLMT_CFG, 0, 7, 0),
+};
+
+/* Left speaker mixer switch */
+static const struct snd_kcontrol_new max98088_left_speaker_mixer_controls[] = {
+ SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 7, 1, 0),
+ SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 0, 1, 0),
+ SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_2B_MIX_SPK_LEFT, 7, 1, 0),
+ SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_2B_MIX_SPK_LEFT, 0, 1, 0),
+ SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 5, 1, 0),
+ SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_2B_MIX_SPK_LEFT, 6, 1, 0),
+ SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 1, 1, 0),
+ SOC_DAPM_SINGLE("INA2 Switch", M98088_REG_2B_MIX_SPK_LEFT, 2, 1, 0),
+ SOC_DAPM_SINGLE("INB1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 3, 1, 0),
+ SOC_DAPM_SINGLE("INB2 Switch", M98088_REG_2B_MIX_SPK_LEFT, 4, 1, 0),
+};
+
+/* Right speaker mixer switch */
+static const struct snd_kcontrol_new max98088_right_speaker_mixer_controls[] = {
+ SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 7, 1, 0),
+ SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 0, 1, 0),
+ SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 7, 1, 0),
+ SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 0, 1, 0),
+ SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 5, 1, 0),
+ SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 6, 1, 0),
+ SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 1, 1, 0),
+ SOC_DAPM_SINGLE("INA2 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 2, 1, 0),
+ SOC_DAPM_SINGLE("INB1 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 3, 1, 0),
+ SOC_DAPM_SINGLE("INB2 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 4, 1, 0),
+};
+
+/* Left headphone mixer switch */
+static const struct snd_kcontrol_new max98088_left_hp_mixer_controls[] = {
+ SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_25_MIX_HP_LEFT, 7, 1, 0),
+ SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_25_MIX_HP_LEFT, 0, 1, 0),
+ SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_25_MIX_HP_LEFT, 7, 1, 0),
+ SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_25_MIX_HP_LEFT, 0, 1, 0),
+ SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_25_MIX_HP_LEFT, 5, 1, 0),
+ SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_25_MIX_HP_LEFT, 6, 1, 0),
+ SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_25_MIX_HP_LEFT, 1, 1, 0),
+ SOC_DAPM_SINGLE("INA2 Switch", M98088_REG_25_MIX_HP_LEFT, 2, 1, 0),
+ SOC_DAPM_SINGLE("INB1 Switch", M98088_REG_25_MIX_HP_LEFT, 3, 1, 0),
+ SOC_DAPM_SINGLE("INB2 Switch", M98088_REG_25_MIX_HP_LEFT, 4, 1, 0),
+};
+
+/* Right headphone mixer switch */
+static const struct snd_kcontrol_new max98088_right_hp_mixer_controls[] = {
+ SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_26_MIX_HP_RIGHT, 7, 1, 0),
+ SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_26_MIX_HP_RIGHT, 0, 1, 0),
+ SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_26_MIX_HP_RIGHT, 7, 1, 0),
+ SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_26_MIX_HP_RIGHT, 0, 1, 0),
+ SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_26_MIX_HP_RIGHT, 5, 1, 0),
+ SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_26_MIX_HP_RIGHT, 6, 1, 0),
+ SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_26_MIX_HP_RIGHT, 1, 1, 0),
+ SOC_DAPM_SINGLE("INA2 Switch", M98088_REG_26_MIX_HP_RIGHT, 2, 1, 0),
+ SOC_DAPM_SINGLE("INB1 Switch", M98088_REG_26_MIX_HP_RIGHT, 3, 1, 0),
+ SOC_DAPM_SINGLE("INB2 Switch", M98088_REG_26_MIX_HP_RIGHT, 4, 1, 0),
+};
+
+/* Left earpiece/receiver mixer switch */
+static const struct snd_kcontrol_new max98088_left_rec_mixer_controls[] = {
+ SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_28_MIX_REC_LEFT, 7, 1, 0),
+ SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_28_MIX_REC_LEFT, 0, 1, 0),
+ SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_28_MIX_REC_LEFT, 7, 1, 0),
+ SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_28_MIX_REC_LEFT, 0, 1, 0),
+ SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_28_MIX_REC_LEFT, 5, 1, 0),
+ SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_28_MIX_REC_LEFT, 6, 1, 0),
+ SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_28_MIX_REC_LEFT, 1, 1, 0),
+ SOC_DAPM_SINGLE("INA2 Switch", M98088_REG_28_MIX_REC_LEFT, 2, 1, 0),
+ SOC_DAPM_SINGLE("INB1 Switch", M98088_REG_28_MIX_REC_LEFT, 3, 1, 0),
+ SOC_DAPM_SINGLE("INB2 Switch", M98088_REG_28_MIX_REC_LEFT, 4, 1, 0),
+};
+
+/* Right earpiece/receiver mixer switch */
+static const struct snd_kcontrol_new max98088_right_rec_mixer_controls[] = {
+ SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_29_MIX_REC_RIGHT, 7, 1, 0),
+ SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_29_MIX_REC_RIGHT, 0, 1, 0),
+ SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_29_MIX_REC_RIGHT, 7, 1, 0),
+ SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_29_MIX_REC_RIGHT, 0, 1, 0),
+ SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_29_MIX_REC_RIGHT, 5, 1, 0),
+ SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_29_MIX_REC_RIGHT, 6, 1, 0),
+ SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_29_MIX_REC_RIGHT, 1, 1, 0),
+ SOC_DAPM_SINGLE("INA2 Switch", M98088_REG_29_MIX_REC_RIGHT, 2, 1, 0),
+ SOC_DAPM_SINGLE("INB1 Switch", M98088_REG_29_MIX_REC_RIGHT, 3, 1, 0),
+ SOC_DAPM_SINGLE("INB2 Switch", M98088_REG_29_MIX_REC_RIGHT, 4, 1, 0),
+};
+
+/* Left ADC mixer switch */
+static const struct snd_kcontrol_new max98088_left_ADC_mixer_controls[] = {
+ SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_23_MIX_ADC_LEFT, 7, 1, 0),
+ SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_23_MIX_ADC_LEFT, 6, 1, 0),
+ SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_23_MIX_ADC_LEFT, 3, 1, 0),
+ SOC_DAPM_SINGLE("INA2 Switch", M98088_REG_23_MIX_ADC_LEFT, 2, 1, 0),
+ SOC_DAPM_SINGLE("INB1 Switch", M98088_REG_23_MIX_ADC_LEFT, 1, 1, 0),
+ SOC_DAPM_SINGLE("INB2 Switch", M98088_REG_23_MIX_ADC_LEFT, 0, 1, 0),
+};
+
+/* Right ADC mixer switch */
+static const struct snd_kcontrol_new max98088_right_ADC_mixer_controls[] = {
+ SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_24_MIX_ADC_RIGHT, 7, 1, 0),
+ SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_24_MIX_ADC_RIGHT, 6, 1, 0),
+ SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_24_MIX_ADC_RIGHT, 3, 1, 0),
+ SOC_DAPM_SINGLE("INA2 Switch", M98088_REG_24_MIX_ADC_RIGHT, 2, 1, 0),
+ SOC_DAPM_SINGLE("INB1 Switch", M98088_REG_24_MIX_ADC_RIGHT, 1, 1, 0),
+ SOC_DAPM_SINGLE("INB2 Switch", M98088_REG_24_MIX_ADC_RIGHT, 0, 1, 0),
+};
+
+static int max98088_hp_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ u16 status;
+
+ BUG_ON(event != SND_SOC_DAPM_PRE_PMD);
+
+ /* powering down headphone gracefully */
+ status = snd_soc_read(codec, M98088_REG_4D_PWR_EN_OUT);
+ if ((status & M98088_HPEN) == M98088_HPEN) {
+ max98088_hw_write(codec, M98088_REG_4D_PWR_EN_OUT,
+ (status & ~M98088_HPEN));
+ }
+ schedule_timeout(msecs_to_jiffies(20));
+
+ return 0;
+}
+
+static int max98088_mic_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ if (w->reg == M98088_REG_35_LVL_MIC1) {
+ snd_soc_update_bits(codec, w->reg, M98088_MICPRE_MASK,
+ (1+max98088->mic1pre)<<M98088_MICPRE_SHIFT);
+ } else {
+ snd_soc_update_bits(codec, w->reg, M98088_MICPRE_MASK,
+ (1+max98088->mic2pre)<<M98088_MICPRE_SHIFT);
+ }
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_update_bits(codec, w->reg, M98088_MICPRE_MASK, 0);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* DAPM widgets top level */
+static const struct snd_soc_dapm_widget max98088_dapm_widgets[] = {
+
+ SND_SOC_DAPM_ADC("ADCL", "HiFi Capture", M98088_REG_4C_PWR_EN_IN, 1, 0),
+ SND_SOC_DAPM_ADC("ADCR", "HiFi Capture", M98088_REG_4C_PWR_EN_IN, 0, 0),
+
+ SND_SOC_DAPM_DAC("DACL1", "HiFi Playback",
+ M98088_REG_4D_PWR_EN_OUT, 1, 0),
+ SND_SOC_DAPM_DAC("DACR1", "HiFi Playback",
+ M98088_REG_4D_PWR_EN_OUT, 0, 0),
+ SND_SOC_DAPM_DAC("DACL2", "Aux Playback",
+ M98088_REG_4D_PWR_EN_OUT, 1, 0),
+ SND_SOC_DAPM_DAC("DACR2", "Aux Playback",
+ M98088_REG_4D_PWR_EN_OUT, 0, 0),
+
+ SND_SOC_DAPM_PGA_E("HP Left Out", M98088_REG_4D_PWR_EN_OUT,
+ 7, 0, NULL, 0, max98088_hp_event, SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_PGA_E("HP Right Out", M98088_REG_4D_PWR_EN_OUT,
+ 6, 0, NULL, 0, max98088_hp_event, SND_SOC_DAPM_PRE_PMD),
+
+ SND_SOC_DAPM_PGA("SPK Left Out", M98088_REG_4D_PWR_EN_OUT,
+ 5, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("SPK Right Out", M98088_REG_4D_PWR_EN_OUT,
+ 4, 0, NULL, 0),
+
+ SND_SOC_DAPM_PGA("REC Left Out", M98088_REG_4D_PWR_EN_OUT,
+ 3, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("REC Right Out", M98088_REG_4D_PWR_EN_OUT,
+ 2, 0, NULL, 0),
+
+ SND_SOC_DAPM_MIXER("Left HP Mixer", SND_SOC_NOPM, 0, 0,
+ &max98088_left_hp_mixer_controls[0],
+ ARRAY_SIZE(max98088_left_hp_mixer_controls)),
+
+ SND_SOC_DAPM_MIXER("Right HP Mixer", SND_SOC_NOPM, 0, 0,
+ &max98088_right_hp_mixer_controls[0],
+ ARRAY_SIZE(max98088_right_hp_mixer_controls)),
+
+ SND_SOC_DAPM_MIXER("Left SPK Mixer", SND_SOC_NOPM, 0, 0,
+ &max98088_left_speaker_mixer_controls[0],
+ ARRAY_SIZE(max98088_left_speaker_mixer_controls)),
+
+ SND_SOC_DAPM_MIXER("Right SPK Mixer", SND_SOC_NOPM, 0, 0,
+ &max98088_right_speaker_mixer_controls[0],
+ ARRAY_SIZE(max98088_right_speaker_mixer_controls)),
+
+ SND_SOC_DAPM_MIXER("Left REC Mixer", SND_SOC_NOPM, 0, 0,
+ &max98088_left_rec_mixer_controls[0],
+ ARRAY_SIZE(max98088_left_rec_mixer_controls)),
+
+ SND_SOC_DAPM_MIXER("Right REC Mixer", SND_SOC_NOPM, 0, 0,
+ &max98088_right_rec_mixer_controls[0],
+ ARRAY_SIZE(max98088_right_rec_mixer_controls)),
+
+ SND_SOC_DAPM_MIXER("Left ADC Mixer", SND_SOC_NOPM, 0, 0,
+ &max98088_left_ADC_mixer_controls[0],
+ ARRAY_SIZE(max98088_left_ADC_mixer_controls)),
+
+ SND_SOC_DAPM_MIXER("Right ADC Mixer", SND_SOC_NOPM, 0, 0,
+ &max98088_right_ADC_mixer_controls[0],
+ ARRAY_SIZE(max98088_right_ADC_mixer_controls)),
+
+ SND_SOC_DAPM_PGA_E("MIC1 Input", M98088_REG_35_LVL_MIC1,
+ 5, 0, NULL, 0, max98088_mic_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_PGA_E("MIC2 Input", M98088_REG_36_LVL_MIC2,
+ 5, 0, NULL, 0, max98088_mic_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_PGA_E("INA1 Input", M98088_REG_4C_PWR_EN_IN,
+ 7, 0, NULL, 0, max98088_pga_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_PGA_E("INA2 Input", M98088_REG_4C_PWR_EN_IN,
+ 7, 0, NULL, 0, max98088_pga_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_PGA_E("INB1 Input", M98088_REG_4C_PWR_EN_IN,
+ 6, 0, NULL, 0, max98088_pga_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_PGA_E("INB2 Input", M98088_REG_4C_PWR_EN_IN,
+ 6, 0, NULL, 0, max98088_pga_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MICBIAS("MICBIAS", M98088_REG_4C_PWR_EN_IN, 3, 0),
+
+ SND_SOC_DAPM_OUTPUT("HPL"),
+ SND_SOC_DAPM_OUTPUT("HPR"),
+ SND_SOC_DAPM_OUTPUT("SPKL"),
+ SND_SOC_DAPM_OUTPUT("SPKR"),
+ SND_SOC_DAPM_OUTPUT("RECL"),
+ SND_SOC_DAPM_OUTPUT("RECR"),
+
+ SND_SOC_DAPM_INPUT("MIC1"),
+ SND_SOC_DAPM_INPUT("MIC2"),
+ SND_SOC_DAPM_INPUT("INA1"),
+ SND_SOC_DAPM_INPUT("INA2"),
+ SND_SOC_DAPM_INPUT("INB1"),
+ SND_SOC_DAPM_INPUT("INB2"),
+};
+
+/* DAPM AUDIO_MAP: */
+static const struct snd_soc_dapm_route audio_map[] = {
+ /* Left headphone output mixer */
+ {"Left HP Mixer", "Left DAC1 Switch", "DACL1"},
+ {"Left HP Mixer", "Left DAC2 Switch", "DACL2"},
+ {"Left HP Mixer", "Right DAC1 Switch", "DACR1"},
+ {"Left HP Mixer", "Right DAC2 Switch", "DACR2"},
+ {"Left HP Mixer", "MIC1 Switch", "MIC1 Input"},
+ {"Left HP Mixer", "MIC2 Switch", "MIC2 Input"},
+ {"Left HP Mixer", "INA1 Switch", "INA1 Input"},
+ {"Left HP Mixer", "INA2 Switch", "INA2 Input"},
+ {"Left HP Mixer", "INB1 Switch", "INB1 Input"},
+ {"Left HP Mixer", "INB2 Switch", "INB2 Input"},
+
+ /* Right headphone output mixer */
+ {"Right HP Mixer", "Left DAC1 Switch", "DACL1"},
+ {"Right HP Mixer", "Left DAC2 Switch", "DACL2" },
+ {"Right HP Mixer", "Right DAC1 Switch", "DACR1"},
+ {"Right HP Mixer", "Right DAC2 Switch", "DACR2"},
+ {"Right HP Mixer", "MIC1 Switch", "MIC1 Input"},
+ {"Right HP Mixer", "MIC2 Switch", "MIC2 Input"},
+ {"Right HP Mixer", "INA1 Switch", "INA1 Input"},
+ {"Right HP Mixer", "INA2 Switch", "INA2 Input"},
+ {"Right HP Mixer", "INB1 Switch", "INB1 Input"},
+ {"Right HP Mixer", "INB2 Switch", "INB2 Input"},
+
+ /* Left speaker output mixer */
+ {"Left SPK Mixer", "Left DAC1 Switch", "DACL1"},
+ {"Left SPK Mixer", "Left DAC2 Switch", "DACL2"},
+ {"Left SPK Mixer", "Right DAC1 Switch", "DACR1"},
+ {"Left SPK Mixer", "Right DAC2 Switch", "DACR2"},
+ {"Left SPK Mixer", "MIC1 Switch", "MIC1 Input"},
+ {"Left SPK Mixer", "MIC2 Switch", "MIC2 Input"},
+ {"Left SPK Mixer", "INA1 Switch", "INA1 Input"},
+ {"Left SPK Mixer", "INA2 Switch", "INA2 Input"},
+ {"Left SPK Mixer", "INB1 Switch", "INB1 Input"},
+ {"Left SPK Mixer", "INB2 Switch", "INB2 Input"},
+
+ /* Right speaker output mixer */
+ {"Right SPK Mixer", "Left DAC1 Switch", "DACL1"},
+ {"Right SPK Mixer", "Left DAC2 Switch", "DACL2"},
+ {"Right SPK Mixer", "Right DAC1 Switch", "DACR1"},
+ {"Right SPK Mixer", "Right DAC2 Switch", "DACR2"},
+ {"Right SPK Mixer", "MIC1 Switch", "MIC1 Input"},
+ {"Right SPK Mixer", "MIC2 Switch", "MIC2 Input"},
+ {"Right SPK Mixer", "INA1 Switch", "INA1 Input"},
+ {"Right SPK Mixer", "INA2 Switch", "INA2 Input"},
+ {"Right SPK Mixer", "INB1 Switch", "INB1 Input"},
+ {"Right SPK Mixer", "INB2 Switch", "INB2 Input"},
+
+ /* Earpiece/Receiver output mixer */
+ {"Left REC Mixer", "Left DAC1 Switch", "DACL1"},
+ {"Left REC Mixer", "Left DAC2 Switch", "DACL2"},
+ {"Left REC Mixer", "Right DAC1 Switch", "DACR1"},
+ {"Left REC Mixer", "Right DAC2 Switch", "DACR2"},
+ {"Left REC Mixer", "MIC1 Switch", "MIC1 Input"},
+ {"Left REC Mixer", "MIC2 Switch", "MIC2 Input"},
+ {"Left REC Mixer", "INA1 Switch", "INA1 Input"},
+ {"Left REC Mixer", "INA2 Switch", "INA2 Input"},
+ {"Left REC Mixer", "INB1 Switch", "INB1 Input"},
+ {"Left REC Mixer", "INB2 Switch", "INB2 Input"},
+
+ /* Earpiece/Receiver output mixer */
+ {"Right REC Mixer", "Left DAC1 Switch", "DACL1"},
+ {"Right REC Mixer", "Left DAC2 Switch", "DACL2"},
+ {"Right REC Mixer", "Right DAC1 Switch", "DACR1"},
+ {"Right REC Mixer", "Right DAC2 Switch", "DACR2"},
+ {"Right REC Mixer", "MIC1 Switch", "MIC1 Input"},
+ {"Right REC Mixer", "MIC2 Switch", "MIC2 Input"},
+ {"Right REC Mixer", "INA1 Switch", "INA1 Input"},
+ {"Right REC Mixer", "INA2 Switch", "INA2 Input"},
+ {"Right REC Mixer", "INB1 Switch", "INB1 Input"},
+ {"Right REC Mixer", "INB2 Switch", "INB2 Input"},
+
+ {"HP Left Out", NULL, "Left HP Mixer"},
+ {"HP Right Out", NULL, "Right HP Mixer"},
+ {"SPK Left Out", NULL, "Left SPK Mixer"},
+ {"SPK Right Out", NULL, "Right SPK Mixer"},
+ {"REC Left Out", NULL, "Left REC Mixer"},
+ {"REC Right Out", NULL, "Right REC Mixer"},
+
+ {"HPL", NULL, "HP Left Out"},
+ {"HPR", NULL, "HP Right Out"},
+ {"SPKL", NULL, "SPK Left Out"},
+ {"SPKR", NULL, "SPK Right Out"},
+ {"RECL", NULL, "REC Left Out"},
+ {"RECR", NULL, "REC Right Out"},
+
+ /* Left ADC input mixer */
+ {"Left ADC Mixer", "MIC1 Switch", "MIC1 Input"},
+ {"Left ADC Mixer", "MIC2 Switch", "MIC2 Input"},
+ {"Left ADC Mixer", "INA1 Switch", "INA1 Input"},
+ {"Left ADC Mixer", "INA2 Switch", "INA2 Input"},
+ {"Left ADC Mixer", "INB1 Switch", "INB1 Input"},
+ {"Left ADC Mixer", "INB2 Switch", "INB2 Input"},
+
+ /* Right ADC input mixer */
+ {"Right ADC Mixer", "MIC1 Switch", "MIC1 Input"},
+ {"Right ADC Mixer", "MIC2 Switch", "MIC2 Input"},
+ {"Right ADC Mixer", "INA1 Switch", "INA1 Input"},
+ {"Right ADC Mixer", "INA2 Switch", "INA2 Input"},
+ {"Right ADC Mixer", "INB1 Switch", "INB1 Input"},
+ {"Right ADC Mixer", "INB2 Switch", "INB2 Input"},
+
+ /* inputs */
+ {"ADCL", NULL, "Left ADC Mixer"},
+ {"ADCR", NULL, "Right ADC Mixer"},
+ {"INA1 Input", NULL, "INA1"},
+ {"INA2 Input", NULL, "INA2"},
+ {"INB1 Input", NULL, "INB1"},
+ {"INB2 Input", NULL, "INB2"},
+ {"MIC1 Input", NULL, "MIC1"},
+ {"MIC2 Input", NULL, "MIC2"},
+};
+
+static int max98088_add_widgets(struct snd_soc_codec *codec)
+{
+ snd_soc_dapm_new_controls(codec, max98088_dapm_widgets,
+ ARRAY_SIZE(max98088_dapm_widgets));
+
+ snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+
+ snd_soc_add_controls(codec, max98088_snd_controls,
+ ARRAY_SIZE(max98088_snd_controls));
+
+ snd_soc_dapm_new_widgets(codec);
+ return 0;
+}
+
+/* codec mclk clock divider coefficients */
+static const struct {
+ u32 rate;
+ u8 sr;
+} rate_table[] = {
+ {8000, 0x10},
+ {11025, 0x20},
+ {16000, 0x30},
+ {22050, 0x40},
+ {24000, 0x50},
+ {32000, 0x60},
+ {44100, 0x70},
+ {48000, 0x80},
+ {88200, 0x90},
+ {96000, 0xA0},
+};
+
+static inline int rate_value(int rate, u8 *value)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(rate_table); i++) {
+ if (rate_table[i].rate >= rate) {
+ *value = rate_table[i].sr;
+ return 0;
+ }
+ }
+ *value = rate_table[0].sr;
+ return -EINVAL;
+}
+
+static int max98088_dai1_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ struct max98088_cdata *cdata;
+ unsigned int rate;
+ u8 regval;
+ u16 ni;
+
+ cdata = &max98088->dai[0];
+
+ rate = params_rate(params);
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ snd_soc_update_bits(codec, M98088_REG_14_DAI1_FORMAT,
+ M98088_DAI_WS, 0);
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ snd_soc_update_bits(codec, M98088_REG_14_DAI1_FORMAT,
+ M98088_DAI_WS, M98088_DAI_WS);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ snd_soc_update_bits(codec, M98088_REG_51_PWR_SYS, M98088_SHDNRUN, 0);
+
+ if (rate != cdata->rate) {
+ /* set DAI1 SR1 value for the DSP; FREQ1:0=anyclock */
+ if (rate_value(rate, ®val))
+ return -EINVAL;
+
+ snd_soc_write(codec, M98088_REG_11_DAI1_CLKMODE, regval);
+ cdata->rate = rate;
+ }
+
+ /* Configure NI when operating as master */
+ if (snd_soc_read(codec, M98088_REG_14_DAI1_FORMAT)
+ & M98088_DAI_MAS) {
+ if (max98088->sysclk == 0)
+ return -EINVAL;
+ ni = (u16)ulldiv(65536ULL * (rate < 50000 ? 96ULL : 48ULL)
+ * (unsigned long long int)rate,
+ (unsigned long long int)max98088->sysclk);
+ snd_soc_write(codec, M98088_REG_12_DAI1_CLKCFG_HI,
+ (ni >> 8) & 0x7f);
+ snd_soc_write(codec, M98088_REG_13_DAI1_CLKCFG_LO,
+ ni & 0xff);
+ }
+
+ /* Update sample rate mode */
+ if (rate < 50000)
+ snd_soc_update_bits(codec, M98088_REG_18_DAI1_FILTERS,
+ M98088_DAI_DHF, 0);
+ else
+ snd_soc_update_bits(codec, M98088_REG_18_DAI1_FILTERS,
+ M98088_DAI_DHF, M98088_DAI_DHF);
+
+ snd_soc_update_bits(codec, M98088_REG_51_PWR_SYS, 0, M98088_SHDNRUN);
+
+ return 0;
+}
+
+static int max98088_dai2_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ struct max98088_cdata *cdata;
+ unsigned int rate;
+ u8 regval;
+ u16 ni;
+
+ cdata = &max98088->dai[1];
+
+ rate = params_rate(params);
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ snd_soc_update_bits(codec, M98088_REG_1C_DAI2_FORMAT,
+ M98088_DAI_WS, 0);
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ snd_soc_update_bits(codec, M98088_REG_1C_DAI2_FORMAT,
+ M98088_DAI_WS, M98088_DAI_WS);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ snd_soc_update_bits(codec, M98088_REG_51_PWR_SYS, M98088_SHDNRUN, 0);
+
+ if (rate != cdata->rate) {
+ /* set DAI2 SR2 value for the DSP */
+ if (rate_value(rate, ®val))
+ return -EINVAL;
+
+ snd_soc_write(codec, M98088_REG_19_DAI2_CLKMODE, regval);
+ cdata->rate = rate;
+ }
+
+ /* Configure NI when operating as master */
+ if (snd_soc_read(codec, M98088_REG_1C_DAI2_FORMAT)
+ & M98088_DAI_MAS) {
+ if (max98088->sysclk == 0)
+ return -EINVAL;
+ ni = (u16)ulldiv(65536ULL * (rate < 50000 ? 96ULL : 48ULL)
+ * (unsigned long long int)rate,
+ (unsigned long long int)max98088->sysclk);
+ snd_soc_write(codec, M98088_REG_1A_DAI2_CLKCFG_HI,
+ (ni >> 8) & 0x7f);
+ snd_soc_write(codec, M98088_REG_1B_DAI2_CLKCFG_LO,
+ ni & 0xff);
+ }
+
+ /* Update sample rate mode */
+ if (rate < 50000)
+ snd_soc_update_bits(codec, M98088_REG_20_DAI2_FILTERS,
+ M98088_DAI_DHF, 0);
+ else
+ snd_soc_update_bits(codec, M98088_REG_20_DAI2_FILTERS,
+ M98088_DAI_DHF, M98088_DAI_DHF);
+
+ snd_soc_update_bits(codec, M98088_REG_51_PWR_SYS, 0, M98088_SHDNRUN);
+
+ return 0;
+}
+
+static int max98088_dai_set_sysclk(struct snd_soc_dai *dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+
+ /* requested clock frequency is already setup */
+ if (freq == max98088->sysclk)
+ return 0;
+
+ max98088->sysclk = freq; /* remember current sysclk */
+
+ /* setup clocks for slave mode, and using the PLL
+ * PSCLK = 0x01 (when master clk is 10MHz to 20MHz)
+ * 0x02 (when master clk is 20MHz to 30MHz)..
+ */
+ if ((freq >= 10000000) && (freq < 20000000)) {
+ snd_soc_write(codec, M98088_REG_10_SYS_CLK, 0x10);
+ } else if ((freq >= 20000000) && (freq < 30000000)) {
+ snd_soc_write(codec, M98088_REG_10_SYS_CLK, 0x20);
+ } else {
+ dev_err(codec->dev, "Invalid master clock frequency\n");
+ return -EINVAL;
+ }
+
+ if (snd_soc_read(codec, M98088_REG_51_PWR_SYS) & M98088_SHDNRUN) {
+ snd_soc_update_bits(codec, M98088_REG_51_PWR_SYS,
+ M98088_SHDNRUN, 0);
+ snd_soc_update_bits(codec, M98088_REG_51_PWR_SYS,
+ 0, M98088_SHDNRUN);
+ }
+
+ dev_dbg(dai->dev, "Clock source is %d at %uHz\n", clk_id, freq);
+
+ max98088->sysclk = freq;
+ return 0;
+}
+
+static int max98088_dai1_set_fmt(struct snd_soc_dai *codec_dai,
+ unsigned int fmt)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ struct max98088_cdata *cdata;
+ u8 reg15val;
+ u8 reg14msk = 0;
+ u8 reg14val = 0;
+
+ cdata = &max98088->dai[0];
+
+ if (fmt != cdata->fmt) {
+ cdata->fmt = fmt;
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ /* mask MAS to select slave mode */
+ reg14msk |= M98088_DAI_MAS;
+ /* slave mode PLL */
+ snd_soc_write(codec, M98088_REG_12_DAI1_CLKCFG_HI,
+ 0x80);
+ snd_soc_write(codec, M98088_REG_13_DAI1_CLKCFG_LO,
+ 0x00);
+ break;
+ case SND_SOC_DAIFMT_CBM_CFM:
+ /* set to master mode */
+ reg14val |= M98088_DAI_MAS;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFM:
+ case SND_SOC_DAIFMT_CBM_CFS:
+ default:
+ dev_err(codec->dev, "Clock mode unsupported");
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ reg14val |= M98088_DAI_DLY;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ reg14msk |= M98088_DAI_DLY;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ reg14msk |= M98088_DAI_BCI|M98088_DAI_WCI;
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ reg14msk |= M98088_DAI_BCI;
+ reg14val |= M98088_DAI_WCI;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ reg14msk |= M98088_DAI_WCI;
+ reg14val |= M98088_DAI_BCI;
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ reg14val |= M98088_DAI_BCI|M98088_DAI_WCI;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ snd_soc_update_bits(codec, M98088_REG_14_DAI1_FORMAT,
+ reg14msk, reg14val);
+
+ reg15val = M98088_DAI_BSEL64;
+ if (max98088->digmic)
+ reg15val |= M98088_DAI_OSR64;
+ snd_soc_write(codec, M98088_REG_15_DAI1_CLOCK, reg15val);
+ }
+
+ return 0;
+}
+
+static int max98088_dai2_set_fmt(struct snd_soc_dai *codec_dai,
+ unsigned int fmt)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ struct max98088_cdata *cdata;
+ u8 reg1Cmsk = 0;
+ u8 reg1Cval = 0;
+
+ cdata = &max98088->dai[1];
+
+ if (fmt != cdata->fmt) {
+ cdata->fmt = fmt;
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ /* mask MAS to select slave mode */
+ reg1Cmsk |= M98088_DAI_MAS;
+ /* slave mode PLL */
+ snd_soc_write(codec, M98088_REG_1A_DAI2_CLKCFG_HI,
+ 0x80);
+ snd_soc_write(codec, M98088_REG_1B_DAI2_CLKCFG_LO,
+ 0x00);
+ break;
+ case SND_SOC_DAIFMT_CBM_CFM:
+ /* set to master mode */
+ reg1Cval |= M98088_DAI_MAS;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFM:
+ case SND_SOC_DAIFMT_CBM_CFS:
+ default:
+ dev_err(codec->dev, "Clock mode unsupported");
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ reg1Cval |= M98088_DAI_DLY;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ reg1Cmsk |= M98088_DAI_DLY;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ reg1Cmsk |= M98088_DAI_BCI|M98088_DAI_WCI;
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ reg1Cmsk |= M98088_DAI_BCI;
+ reg1Cval |= M98088_DAI_WCI;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ reg1Cmsk |= M98088_DAI_WCI;
+ reg1Cval |= M98088_DAI_BCI;
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ reg1Cval |= M98088_DAI_BCI|M98088_DAI_WCI;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ snd_soc_update_bits(codec, M98088_REG_1C_DAI2_FORMAT,
+ reg1Cmsk, reg1Cval);
+
+ snd_soc_write(codec, M98088_REG_1D_DAI2_CLOCK,
+ M98088_DAI_BSEL64);
+ }
+
+ return 0;
+}
+
+static void max98088_sync_cache(struct snd_soc_codec *codec)
+{
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ int i;
+
+ if (!codec->cache_sync)
+ return;
+
+ codec->cache_only = 0;
+
+ /* write back cached values if they're writeable and
+ * different from the hardware default.
+ */
+ for (i = 1; i < ARRAY_SIZE(max98088->reg_cache); i++) {
+ if (!max98088_access[i].writable)
+ continue;
+
+ if (max98088->reg_cache[i] == max98088_reg[i])
+ continue;
+
+ snd_soc_write(codec, i, max98088->reg_cache[i]);
+ }
+
+ codec->cache_sync = 0;
+}
+
+static int max98088_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:
+ max98088_sync_cache(codec);
+ snd_soc_update_bits(codec, M98088_REG_4C_PWR_EN_IN,
+ M98088_MBEN, M98088_MBEN);
+ break;
+
+ case SND_SOC_BIAS_OFF:
+ snd_soc_update_bits(codec, M98088_REG_4C_PWR_EN_IN,
+ M98088_MBEN, 0);
+#ifdef CONFIG_REGULATOR
+ codec->cache_sync = 1;
+#endif
+ break;
+ }
+ codec->bias_level = level;
+ return 0;
+}
+
+#define MAX98088_RATES SNDRV_PCM_RATE_8000_96000
+#define MAX98088_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE)
+
+static struct snd_soc_dai_ops max98088_dai1_ops = {
+ .set_sysclk = max98088_dai_set_sysclk,
+ .set_fmt = max98088_dai1_set_fmt,
+ .hw_params = max98088_dai1_hw_params,
+};
+
+static struct snd_soc_dai_ops max98088_dai2_ops = {
+ .set_sysclk = max98088_dai_set_sysclk,
+ .set_fmt = max98088_dai2_set_fmt,
+ .hw_params = max98088_dai2_hw_params,
+};
+
+static struct snd_soc_dai_driver max98088_dai[] = {
+{
+ .name = "HiFi",
+ .playback = {
+ .stream_name = "HiFi Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MAX98088_RATES,
+ .formats = MAX98088_FORMATS,
+ },
+ .capture = {
+ .stream_name = "HiFi Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MAX98088_RATES,
+ .formats = MAX98088_FORMATS,
+ },
+ .ops = &max98088_dai1_ops,
+},
+{
+ .name = "Aux",
+ .playback = {
+ .stream_name = "Aux Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MAX98088_RATES,
+ .formats = MAX98088_FORMATS,
+ },
+ .ops = &max98088_dai2_ops,
+}
+};
+
+static void max98088_setup_eq1(struct snd_soc_codec *codec)
+{
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ struct max98088_pdata *pdata = max98088->pdata;
+ struct max98088_eq_cfg *coef_set;
+ int best, best_val, save, i, sel, fs;
+ struct max98088_cdata *cdata;
+
+ cdata = &max98088->dai[0];
+
+ if (!pdata || !cdata->eq_textcnt)
+ return;
+
+ /* Find the selected configuration with nearest sample rate */
+ fs = cdata->rate;
+ sel = cdata->eq_sel;
+
+ best = 0;
+ best_val = INT_MAX;
+ for (i = 0; i < pdata->eq1_cfgcnt; i++) {
+ if (strcmp(pdata->eq1_cfg[i].name, cdata->eq_texts[sel]) == 0 &&
+ abs(pdata->eq1_cfg[i].rate - fs) < best_val) {
+ best = i;
+ best_val = abs(pdata->eq1_cfg[i].rate - fs);
+ }
+ }
+
+ dev_dbg(codec->dev, "Selected %s/%dHz for %dHz sample rate\n",
+ pdata->eq1_cfg[best].name,
+ pdata->eq1_cfg[best].rate, fs);
+
+ /* Disable EQ while configuring, and save current on/off state */
+ save = snd_soc_read(codec, M98088_REG_49_CFG_LEVEL);
+ snd_soc_update_bits(codec, M98088_REG_49_CFG_LEVEL, M98088_EQ1EN, 0);
+
+ coef_set = &pdata->eq1_cfg[sel];
+
+ m98088_eq_band(codec, 0, 0, coef_set->band1);
+ m98088_eq_band(codec, 0, 1, coef_set->band2);
+ m98088_eq_band(codec, 0, 2, coef_set->band3);
+ m98088_eq_band(codec, 0, 3, coef_set->band4);
+ m98088_eq_band(codec, 0, 4, coef_set->band5);
+
+ /* restore original on/off state */
+ snd_soc_update_bits(codec, M98088_REG_49_CFG_LEVEL, M98088_EQ1EN, save);
+}
+
+static void max98088_setup_eq2(struct snd_soc_codec *codec)
+{
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ struct max98088_pdata *pdata = max98088->pdata;
+ struct max98088_eq_cfg *coef_set;
+ int best, best_val, save, i, sel, fs;
+ struct max98088_cdata *cdata;
+
+ cdata = &max98088->dai[1];
+
+ if (!pdata || !cdata->eq_textcnt)
+ return;
+
+ /* Find the selected configuration with nearest sample rate */
+ fs = cdata->rate;
+
+ sel = cdata->eq_sel;
+ best = 0;
+ best_val = INT_MAX;
+ for (i = 0; i < pdata->eq2_cfgcnt; i++) {
+ if (strcmp(pdata->eq2_cfg[i].name, cdata->eq_texts[sel]) == 0 &&
+ abs(pdata->eq2_cfg[i].rate - fs) < best_val) {
+ best = i;
+ best_val = abs(pdata->eq2_cfg[i].rate - fs);
+ }
+ }
+
+ dev_dbg(codec->dev, "Selected %s/%dHz for %dHz sample rate\n",
+ pdata->eq2_cfg[best].name,
+ pdata->eq2_cfg[best].rate, fs);
+
+ /* Disable EQ while configuring, and save current on/off state */
+ save = snd_soc_read(codec, M98088_REG_49_CFG_LEVEL);
+ snd_soc_update_bits(codec, M98088_REG_49_CFG_LEVEL, M98088_EQ2EN, 0);
+
+ coef_set = &pdata->eq2_cfg[sel];
+
+ m98088_eq_band(codec, 1, 0, coef_set->band1);
+ m98088_eq_band(codec, 1, 1, coef_set->band2);
+ m98088_eq_band(codec, 1, 2, coef_set->band3);
+ m98088_eq_band(codec, 1, 3, coef_set->band4);
+ m98088_eq_band(codec, 1, 4, coef_set->band5);
+
+ /* restore original on/off state */
+ snd_soc_update_bits(codec, M98088_REG_49_CFG_LEVEL, M98088_EQ2EN,
+ save);
+}
+
+
+static int max98088_put_eq1_enum(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ struct max98088_pdata *pdata = max98088->pdata;
+ struct max98088_cdata *cdata;
+ int sel = ucontrol->value.integer.value[0];
+
+ cdata = &max98088->dai[0];
+
+ if (sel >= pdata->eq1_cfgcnt)
+ return -EINVAL;
+
+ cdata->eq_sel = sel;
+ max98088_setup_eq1(codec);
+ return 0;
+}
+
+static int max98088_put_eq2_enum(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ struct max98088_pdata *pdata = max98088->pdata;
+ struct max98088_cdata *cdata;
+ int sel = ucontrol->value.integer.value[0];
+
+ cdata = &max98088->dai[1];
+
+ if (sel >= pdata->eq2_cfgcnt)
+ return -EINVAL;
+
+ cdata->eq_sel = sel;
+ max98088_setup_eq2(codec);
+ return 0;
+}
+
+static int max98088_get_eq1_enum(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ struct max98088_cdata *cdata;
+
+ cdata = &max98088->dai[0];
+
+ ucontrol->value.enumerated.item[0] = cdata->eq_sel;
+ return 0;
+}
+
+static int max98088_get_eq2_enum(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ struct max98088_cdata *cdata;
+
+ cdata = &max98088->dai[1];
+
+ ucontrol->value.enumerated.item[0] = cdata->eq_sel;
+ return 0;
+}
+
+static void max98088_handle_eq1_pdata(struct snd_soc_codec *codec)
+{
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ struct max98088_pdata *pdata = max98088->pdata;
+ struct max98088_cdata *cdata;
+ int ret, i, j;
+
+ struct snd_kcontrol_new eq1control =
+ SOC_ENUM_EXT("EQ1 Mode",
+ max98088->dai[0].eq_enum,
+ max98088_get_eq1_enum,
+ max98088_put_eq1_enum);
+
+ cdata = &max98088->dai[0];
+
+ /* Build an array of texts for the enum API. The number
+ * of texts is likely fewer than the number of configurations
+ * due to multiple sample rates for the same text name. */
+ cdata->eq_textcnt = 0;
+ for (i = 0; i < pdata->eq1_cfgcnt; i++) {
+ for (j = 0; j < cdata->eq_textcnt; j++) {
+ if (strcmp(pdata->eq1_cfg[i].name,
+ cdata->eq_texts[j]) == 0) {
+ break;
+ }
+ }
+
+ if (j != cdata->eq_textcnt)
+ continue;
+
+ /* ...and remember the new version. */
+ cdata->eq_texts[i] = pdata->eq1_cfg[i].name;
+ cdata->eq_textcnt++;
+
+ if (cdata->eq_textcnt >= EQ_CFG_MAX) {
+ dev_err(codec->dev, "Too many EQ config entries\n");
+ cdata->eq_textcnt--;
+ break;
+ }
+ }
+
+ dev_dbg(codec->dev, "Installed %d EQ1 configurations\n",
+ cdata->eq_textcnt);
+
+ /* now point the soc_enum to .texts array items */
+ cdata->eq_enum.texts = cdata->eq_texts;
+ cdata->eq_enum.max = cdata->eq_textcnt;
+
+ ret = snd_soc_add_controls(codec, &eq1control, 1);
+ if (ret != 0)
+ dev_err(codec->dev, "Failed to add EQ control: %d\n", ret);
+}
+
+static void max98088_handle_eq2_pdata(struct snd_soc_codec *codec)
+{
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ struct max98088_pdata *pdata = max98088->pdata;
+ struct max98088_cdata *cdata;
+ int ret, i, j;
+
+ struct snd_kcontrol_new eq2control =
+ SOC_ENUM_EXT("EQ2 Mode",
+ max98088->dai[1].eq_enum,
+ max98088_get_eq2_enum,
+ max98088_put_eq2_enum);
+
+ cdata = &max98088->dai[1];
+
+ /* Build an array of texts for the enum API. The number
+ * of texts is likely fewer than the number of configurations
+ * due to multiple sample rates for the same text name. */
+ cdata->eq_textcnt = 0;
+ for (i = 0; i < pdata->eq2_cfgcnt; i++) {
+ for (j = 0; j < cdata->eq_textcnt; j++) {
+ if (strcmp(pdata->eq2_cfg[i].name,
+ cdata->eq_texts[j]) == 0) {
+ break;
+ }
+ }
+
+ if (j != cdata->eq_textcnt)
+ continue;
+
+ cdata->eq_texts[i] = pdata->eq2_cfg[i].name;
+ cdata->eq_textcnt++;
+
+ if (cdata->eq_textcnt >= EQ_CFG_MAX) {
+ dev_err(codec->dev, "Too many EQ config entries\n");
+ cdata->eq_textcnt--;
+ break;
+ }
+ }
+
+ dev_dbg(codec->dev, "Installed %d EQ2 configurations\n",
+ cdata->eq_textcnt);
+
+ /* now point the soc_enum to .texts array items */
+ cdata->eq_enum.texts = cdata->eq_texts;
+ cdata->eq_enum.max = cdata->eq_textcnt;
+
+ ret = snd_soc_add_controls(codec, &eq2control, 1);
+ if (ret != 0)
+ printk(KERN_ERR "Failed to add EQ control: %d\n", ret);
+}
+
+static void max98088_handle_pdata(struct snd_soc_codec *codec)
+{
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ struct max98088_pdata *pdata = max98088->pdata;
+ u8 regval = 0;
+
+ if (!pdata) {
+ dev_dbg(codec->dev, "No platform data\n");
+ return;
+ }
+
+ /* configure mic for analog/digital mic mode */
+ if (pdata->digmic_left_mode)
+ regval |= M98088_DIGMIC_L;
+
+ if (pdata->digmic_right_mode)
+ regval |= M98088_DIGMIC_R;
+
+ max98088->digmic = (regval ? 1 : 0);
+
+ snd_soc_write(codec, M98088_REG_48_CFG_MIC, regval);
+
+ /* configure receiver output */
+ regval = ((pdata->receiver_mode) ? M98088_REC_LINEMODE : 0);
+ snd_soc_update_bits(codec, M98088_REG_2A_MIC_REC_CNTL,
+ M98088_REC_LINEMODE_MASK, regval);
+
+ /* configure equalizers */
+ if (pdata->eq1_cfgcnt)
+ max98088_handle_eq1_pdata(codec);
+
+ if (pdata->eq2_cfgcnt)
+ max98088_handle_eq2_pdata(codec);
+}
+
+#ifdef CONFIG_PM
+static int max98088_suspend(struct snd_soc_codec *codec, pm_message_t state)
+{
+ max98088_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+ return 0;
+}
+
+static int max98088_resume(struct snd_soc_codec *codec)
+{
+ int i;
+ u8 *cache = codec->reg_cache;
+
+ max98088_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+ /* Sync reg_cache with the hardware */
+ for (i = 0; i < M98088_REG_CNT; i++) {
+ if (i == M98088_REG_51_PWR_SYS)
+ continue;
+
+ if (!max98088_access[i].writable)
+ continue;
+
+ max98088_hw_write(codec, i, cache[i]);
+ }
+
+ /* now enter into the resume mode bias level */
+ max98088_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+ return 0;
+}
+#else
+#define max98088_suspend NULL
+#define max98088_resume NULL
+#endif
+
+static int max98088_probe(struct snd_soc_codec *codec)
+{
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ struct max98088_cdata *cdata;
+ int ret = 0;
+
+ codec->cache_sync = 1;
+ memcpy(codec->reg_cache, max98088_reg, sizeof(max98088_reg));
+
+ ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+ return ret;
+ }
+
+ /* initalize private data */
+
+ max98088->sysclk = (unsigned)-1;
+
+ cdata = &max98088->dai[0];
+ cdata->rate = (unsigned)-1;
+ cdata->fmt = (unsigned)-1;
+ cdata->eq_textcnt = 0;
+ cdata->eq_sel = 0;
+
+ cdata = &max98088->dai[1];
+ cdata->rate = (unsigned)-1;
+ cdata->fmt = (unsigned)-1;
+ cdata->eq_textcnt = 0;
+ cdata->eq_sel = 0;
+
+ max98088->power_state = 0; /* INA INB power enable state */
+ max98088->ex_mode = 0; /* excursion limiter mode */
+ max98088->digmic = 0; /* 0=analog, 1=digital */
+ max98088->mic1pre = 0;
+ max98088->mic2pre = 0;
+
+ ret = snd_soc_read(codec, M98088_REG_FF_REV_ID);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to read device revision: %d\n",
+ ret);
+ goto err_access;
+ }
+ dev_info(codec->dev, "revision %c\n", ret + 'A');
+
+ snd_soc_write(codec, M98088_REG_51_PWR_SYS, M98088_PWRSV);
+
+ /* initialize registers cache to hardware default */
+ max98088_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+ snd_soc_write(codec, M98088_REG_0F_IRQ_ENABLE, 0x00);
+
+ snd_soc_write(codec, M98088_REG_22_MIX_DAC,
+ M98088_DAI1L_TO_DACL|M98088_DAI2L_TO_DACL|
+ M98088_DAI1R_TO_DACR|M98088_DAI2R_TO_DACR);
+
+ snd_soc_write(codec, M98088_REG_4E_BIAS_CNTL, 0xF0);
+ snd_soc_write(codec, M98088_REG_50_DAC_BIAS2, 0x0F);
+
+ snd_soc_write(codec, M98088_REG_16_DAI1_IOCFG,
+ M98088_S1NORMAL|M98088_SDATA);
+
+ snd_soc_write(codec, M98088_REG_1E_DAI2_IOCFG,
+ M98088_S2NORMAL|M98088_SDATA);
+
+ max98088_handle_pdata(codec);
+
+ max98088_add_widgets(codec);
+
+err_access:
+ return ret;
+}
+
+static int max98088_remove(struct snd_soc_codec *codec)
+{
+ if (codec->control_data)
+ max98088_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+ return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_max98088 = {
+ .probe = max98088_probe,
+ .remove = max98088_remove,
+ .suspend = max98088_suspend,
+ .resume = max98088_resume,
+ .set_bias_level = max98088_set_bias_level,
+ .reg_cache_size = ARRAY_SIZE(max98088_reg),
+ .reg_word_size = sizeof(u8),
+ .reg_cache_default = max98088_reg,
+ .volatile_register = max98088_volatile_register,
+};
+
+static int max98088_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct max98088_priv *max98088;
+ int ret;
+
+ max98088 = kzalloc(sizeof(struct max98088_priv), GFP_KERNEL);
+ if (max98088 == NULL)
+ return -ENOMEM;
+
+ i2c_set_clientdata(i2c, max98088);
+ max98088->control_data = i2c;
+ max98088->pdata = i2c->dev.platform_data;
+
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_max98088, &max98088_dai[0], 2);
+ if (ret < 0)
+ kfree(max98088);
+ return ret;
+}
+
+static int max98088_i2c_remove(struct i2c_client *client)
+{
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
+ return 0;
+}
+
+static const struct i2c_device_id max98088_i2c_id[] = {
+ { "max98088", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, max98088_i2c_id);
+
+static struct i2c_driver max98088_i2c_driver = {
+ .driver = {
+ .name = "max98088-codec",
+ .owner = THIS_MODULE,
+ },
+ .probe = max98088_i2c_probe,
+ .remove = __devexit_p(max98088_i2c_remove),
+ .id_table = max98088_i2c_id,
+};
+
+static int __init max98088_init(void)
+{
+ int ret;
+
+ ret = i2c_add_driver(&max98088_i2c_driver);
+ if (ret)
+ pr_err("Failed to register max98088 I2C driver: %d\n", ret);
+
+ return ret;
+}
+
+static void __exit max98088_exit(void)
+{
+ i2c_del_driver(&max98088_i2c_driver);
+}
+
+module_init(max98088_init);
+module_exit(max98088_exit);
+
+MODULE_DESCRIPTION("ALSA SoC MAX98088 driver");
+MODULE_AUTHOR("Peter Hsiang, Jesse Marroquin");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/max98088.h b/sound/soc/codecs/max98088.h
new file mode 100644
index 0000000..9e9d8da
--- /dev/null
+++ b/sound/soc/codecs/max98088.h
@@ -0,0 +1,190 @@
+/*
+ * max98088.h -- MAX98088 ALSA SoC Audio driver
+ *
+ * Copyright 2010 Maxim Integrated Products
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _MAX98088_H
+#define _MAX98088_H
+
+/*
+ * MAX98088 Registers Definition
+ */
+#define M98088_REG_00_IRQ_STATUS 0x00
+#define M98088_REG_01_MIC_STATUS 0x01
+#define M98088_REG_02_JACK_STAUS 0x02
+#define M98088_REG_03_BATTERY_VOLTAGE 0x03
+#define M98088_REG_0F_IRQ_ENABLE 0x0F
+#define M98088_REG_10_SYS_CLK 0x10
+#define M98088_REG_11_DAI1_CLKMODE 0x11
+#define M98088_REG_12_DAI1_CLKCFG_HI 0x12
+#define M98088_REG_13_DAI1_CLKCFG_LO 0x13
+#define M98088_REG_14_DAI1_FORMAT 0x14
+#define M98088_REG_15_DAI1_CLOCK 0x15
+#define M98088_REG_16_DAI1_IOCFG 0x16
+#define M98088_REG_17_DAI1_TDM 0x17
+#define M98088_REG_18_DAI1_FILTERS 0x18
+#define M98088_REG_19_DAI2_CLKMODE 0x19
+#define M98088_REG_1A_DAI2_CLKCFG_HI 0x1A
+#define M98088_REG_1B_DAI2_CLKCFG_LO 0x1B
+#define M98088_REG_1C_DAI2_FORMAT 0x1C
+#define M98088_REG_1D_DAI2_CLOCK 0x1D
+#define M98088_REG_1E_DAI2_IOCFG 0x1E
+#define M98088_REG_1F_DAI2_TDM 0x1F
+#define M98088_REG_20_DAI2_FILTERS 0x20
+#define M98088_REG_21_SRC 0x21
+#define M98088_REG_22_MIX_DAC 0x22
+#define M98088_REG_23_MIX_ADC_LEFT 0x23
+#define M98088_REG_24_MIX_ADC_RIGHT 0x24
+#define M98088_REG_25_MIX_HP_LEFT 0x25
+#define M98088_REG_26_MIX_HP_RIGHT 0x26
+#define M98088_REG_27_MIX_HP_CNTL 0x27
+#define M98088_REG_28_MIX_REC_LEFT 0x28
+#define M98088_REG_29_MIX_REC_RIGHT 0x29
+#define M98088_REG_2A_MIC_REC_CNTL 0x2A
+#define M98088_REG_2B_MIX_SPK_LEFT 0x2B
+#define M98088_REG_2C_MIX_SPK_RIGHT 0x2C
+#define M98088_REG_2D_MIX_SPK_CNTL 0x2D
+#define M98088_REG_2E_LVL_SIDETONE 0x2E
+#define M98088_REG_2F_LVL_DAI1_PLAY 0x2F
+#define M98088_REG_30_LVL_DAI1_PLAY_EQ 0x30
+#define M98088_REG_31_LVL_DAI2_PLAY 0x31
+#define M98088_REG_32_LVL_DAI2_PLAY_EQ 0x32
+#define M98088_REG_33_LVL_ADC_L 0x33
+#define M98088_REG_34_LVL_ADC_R 0x34
+#define M98088_REG_35_LVL_MIC1 0x35
+#define M98088_REG_36_LVL_MIC2 0x36
+#define M98088_REG_37_LVL_INA 0x37
+#define M98088_REG_38_LVL_INB 0x38
+#define M98088_REG_39_LVL_HP_L 0x39
+#define M98088_REG_3A_LVL_HP_R 0x3A
+#define M98088_REG_3B_LVL_REC_L 0x3B
+#define M98088_REG_3C_LVL_REC_R 0x3C
+#define M98088_REG_3D_LVL_SPK_L 0x3D
+#define M98088_REG_3E_LVL_SPK_R 0x3E
+#define M98088_REG_3F_MICAGC_CFG 0x3F
+#define M98088_REG_40_MICAGC_THRESH 0x40
+#define M98088_REG_41_SPKDHP 0x41
+#define M98088_REG_42_SPKDHP_THRESH 0x42
+#define M98088_REG_43_SPKALC_COMP 0x43
+#define M98088_REG_44_PWRLMT_CFG 0x44
+#define M98088_REG_45_PWRLMT_TIME 0x45
+#define M98088_REG_46_THDLMT_CFG 0x46
+#define M98088_REG_47_CFG_AUDIO_IN 0x47
+#define M98088_REG_48_CFG_MIC 0x48
+#define M98088_REG_49_CFG_LEVEL 0x49
+#define M98088_REG_4A_CFG_BYPASS 0x4A
+#define M98088_REG_4B_CFG_JACKDET 0x4B
+#define M98088_REG_4C_PWR_EN_IN 0x4C
+#define M98088_REG_4D_PWR_EN_OUT 0x4D
+#define M98088_REG_4E_BIAS_CNTL 0x4E
+#define M98088_REG_4F_DAC_BIAS1 0x4F
+#define M98088_REG_50_DAC_BIAS2 0x50
+#define M98088_REG_51_PWR_SYS 0x51
+#define M98088_REG_52_DAI1_EQ_BASE 0x52
+#define M98088_REG_84_DAI2_EQ_BASE 0x84
+#define M98088_REG_B6_DAI1_BIQUAD_BASE 0xB6
+#define M98088_REG_C0_DAI2_BIQUAD_BASE 0xC0
+#define M98088_REG_FF_REV_ID 0xFF
+
+#define M98088_REG_CNT (0xFF+1)
+
+/* MAX98088 Registers Bit Fields */
+
+/* M98088_REG_14_DAI1_FORMAT, M98088_REG_1C_DAI2_FORMAT */
+ #define M98088_DAI_MAS (1<<7)
+ #define M98088_DAI_WCI (1<<6)
+ #define M98088_DAI_BCI (1<<5)
+ #define M98088_DAI_DLY (1<<4)
+ #define M98088_DAI_TDM (1<<2)
+ #define M98088_DAI_FSW (1<<1)
+ #define M98088_DAI_WS (1<<0)
+
+/* M98088_REG_15_DAI1_CLOCK, M98088_REG_1D_DAI2_CLOCK */
+ #define M98088_DAI_BSEL64 (1<<0)
+ #define M98088_DAI_OSR64 (1<<6)
+
+/* M98088_REG_16_DAI1_IOCFG, M98088_REG_1E_DAI2_IOCFG */
+ #define M98088_S1NORMAL (1<<6)
+ #define M98088_S2NORMAL (2<<6)
+ #define M98088_SDATA (3<<0)
+
+/* M98088_REG_18_DAI1_FILTERS, M98088_REG_20_DAI2_FILTERS */
+ #define M98088_DAI_DHF (1<<3)
+
+/* M98088_REG_22_MIX_DAC */
+ #define M98088_DAI1L_TO_DACL (1<<7)
+ #define M98088_DAI1R_TO_DACL (1<<6)
+ #define M98088_DAI2L_TO_DACL (1<<5)
+ #define M98088_DAI2R_TO_DACL (1<<4)
+ #define M98088_DAI1L_TO_DACR (1<<3)
+ #define M98088_DAI1R_TO_DACR (1<<2)
+ #define M98088_DAI2L_TO_DACR (1<<1)
+ #define M98088_DAI2R_TO_DACR (1<<0)
+
+/* M98088_REG_2A_MIC_REC_CNTL */
+ #define M98088_REC_LINEMODE (1<<7)
+ #define M98088_REC_LINEMODE_MASK (1<<7)
+
+/* M98088_REG_35_LVL_MIC1, M98088_REG_36_LVL_MIC2 */
+ #define M98088_MICPRE_MASK (3<<5)
+ #define M98088_MICPRE_SHIFT 5
+
+/* M98088_REG_3A_LVL_HP_R */
+ #define M98088_HP_MUTE (1<<7)
+
+/* M98088_REG_3C_LVL_REC_R */
+ #define M98088_REC_MUTE (1<<7)
+
+/* M98088_REG_3E_LVL_SPK_R */
+ #define M98088_SP_MUTE (1<<7)
+
+/* M98088_REG_48_CFG_MIC */
+ #define M98088_EXTMIC_MASK (3<<0)
+ #define M98088_DIGMIC_L (1<<5)
+ #define M98088_DIGMIC_R (1<<4)
+
+/* M98088_REG_49_CFG_LEVEL */
+ #define M98088_VSEN (1<<6)
+ #define M98088_ZDEN (1<<5)
+ #define M98088_EQ2EN (1<<1)
+ #define M98088_EQ1EN (1<<0)
+
+/* M98088_REG_4C_PWR_EN_IN */
+ #define M98088_INAEN (1<<7)
+ #define M98088_INBEN (1<<6)
+ #define M98088_MBEN (1<<3)
+ #define M98088_ADLEN (1<<1)
+ #define M98088_ADREN (1<<0)
+
+/* M98088_REG_4D_PWR_EN_OUT */
+ #define M98088_HPLEN (1<<7)
+ #define M98088_HPREN (1<<6)
+ #define M98088_HPEN ((1<<7)|(1<<6))
+ #define M98088_SPLEN (1<<5)
+ #define M98088_SPREN (1<<4)
+ #define M98088_RECEN (1<<3)
+ #define M98088_DALEN (1<<1)
+ #define M98088_DAREN (1<<0)
+
+/* M98088_REG_51_PWR_SYS */
+ #define M98088_SHDNRUN (1<<7)
+ #define M98088_PERFMODE (1<<3)
+ #define M98088_HPPLYBACK (1<<2)
+ #define M98088_PWRSV8K (1<<1)
+ #define M98088_PWRSV (1<<0)
+
+#define M98088_COEFS_PER_BAND 5
+
+#define M98088_BYTE1(w) ((w >> 8) & 0xff)
+#define M98088_BYTE0(w) (w & 0xff)
+
+struct max98088_setup_data {
+ unsigned short i2c_address;
+};
+
+#endif
--
1.6.3.3
6
43
Cem ERGEN wrote:
> fist 3 soundcards of each hub works .. but 4 soundcards of each hub aren't
> work same time
Looks like a bandwidth issue.
You still didn't tell what sample format these devices are using.
Regards,
Clemens
1
0

Re: [alsa-devel] [PATCH 1/7] [RFC] OMAP: MCBSP: hwmod database for 2xxx devices
by Varadarajan, Charulatha 15 Oct '10
by Varadarajan, Charulatha 15 Oct '10
15 Oct '10
> -----Original Message-----
> From: ABRAHAM, KISHON VIJAY
> Sent: Tuesday, October 05, 2010 10:08 PM
> To: linux-omap(a)vger.kernel.org
> Cc: Kamat, Nishant; Varadarajan, Charulatha; ABRAHAM, KISHON
> VIJAY; Datta, Shubhrajyoti; Basak, Partha
> Subject: [PATCH 1/7] [RFC] OMAP: MCBSP: hwmod database for
> 2xxx devices
>
This patch series is targeted to implement mcbsp driver in
hwmod way and to make use of pm_runtime APIs.
This patch series is tested on OMAP3 & 4 and yet to be tested
on OMAP2.
There are few clarifications required so that the next patch series
can be implemented after aligning.
1. Audio layer is making use of mcbsp and it's dma base addresses and
is closely coupled with omap-mcbsp.
This can be handled either by
a. providing an API with which Audio layer can get these addresses.
(or)
b. move the plat-omap/mcbsp.c and mach-omap2/mcbsp.c to sound/soc/omap/
[1]
Option (a) would only be a workaround to handle the situation. As
audio is the only user for mcbsp, option (b) is better. If option(b)
is agreed upon, the same can be addressed on top of the mcbsp hwmod
series.
2. Sidetone feature is available only in OMAP3 (McBSP2&3) which has
different base address and sys configs compared to it's mcbsp port.
Hence the mcbsp is considered as a single device with two hwmods
for McBSP2&3 devices in OMAP3.
3. Autoidle needs to be disabled for sidetone before enabling the sidetone
feature. There was a design proposed by Kishon [2] to add an API in hwmod
to modify the autoidle bit but was not agreed upon. How do we handle this
situation where the device has to disable or enable the autoidle bit at
runtime?
[1] https://patchwork.kernel.org/patch/225582/
[2] https://patchwork.kernel.org/patch/134371/
We would resend the same patch series by including alsa mailing list
(alsa-devel(a)alsa-project.org)
<<snip>>
6
9

[alsa-devel] Need expert's advice - Fast Track Ultra (8R) dropping samples
by Felix Homann 15 Oct '10
by Felix Homann 15 Oct '10
15 Oct '10
Hi,
in that past months I've been trying get the Fast Track Ultra devices
working properly in Alsa. We've had lots of progress, most of the code
has moved to Alsa git and today I've even posted a patch for getting
mixer support for these devices.
Now, I need to get some expert's advice: The devices seem to drop
samples or frames. Here's a report I've got today on the M-Audio forum:
"I've got a subtle problem to report: I think audio playback is dropping
sample frames. To hear the problem, open Audacity at 48 kHz and play
a 10-kHz. sine wave. When I do that I hear a regular clicking sound, about
four clicks a second. I've tried recording the output and if I'm seeing
correctly,
exactly one sample frame in every 13312 (13x1024) is being dropped on
output.
I don't see anything similar on input. When either jack or Pd has both
the input and
the output open, the delay from input to output gradually decreases
until it forces
occasional sync errors. (I haven't tried this with audacity though.)"
(see
http://forums.m-audio.com/showthread.php?714-Not-a-problem.-FastTrack-on-li…)
I could reproduce it on my machines, even at 44.1 kHz. The clicking
sound is very subtle, it goes unnoticed when not listening to pure sines
without attention to clicks.
How can this be sorted out. Any ideas?
Kind regards,
Felix
4
23

15 Oct '10
2S SSP device on Intel MID Platforms
Signed-off-by: Louis LE GALL <louis.le.gall(a)intel.com>
Change-Id: I17052a3b464c5682d2ab17a9b6e0fad30137243f
Signed-off-by: Louis LE GALL <louis.le.gall(a)intel.com>
---
include/linux/intel_mid_i2s_if.h | 280 ++++++
sound/pci/Kconfig | 18 +
sound/pci/Makefile | 4 +-
sound/pci/intel_mid_i2s/Makefile | 18 +
sound/pci/intel_mid_i2s/intel_mid_i2s.c | 1428 +++++++++++++++++++++++++++=
++++
sound/pci/intel_mid_i2s/intel_mid_i2s.h | 500 +++++++++++
6 files changed, 2247 insertions(+), 1 deletions(-)
create mode 100644 include/linux/intel_mid_i2s_if.h
create mode 100644 sound/pci/intel_mid_i2s/Makefile
create mode 100644 sound/pci/intel_mid_i2s/intel_mid_i2s.c
create mode 100644 sound/pci/intel_mid_i2s/intel_mid_i2s.h
diff --git a/include/linux/intel_mid_i2s_if.h b/include/linux/intel_mid_i2s=
_if.h
new file mode 100644
index 0000000..1563577
--- /dev/null
+++ b/include/linux/intel_mid_i2s_if.h
@@ -0,0 +1,280 @@
+/*
+ * <Driver for I2S protocol on SSP (Moorestown and Medfield hardware)>
+ * Copyright (c) 2010, Intel Corporation.
+ * Louis LE GALL <louis.le.gall intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License =
for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License alon=
g with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MID_I2S_EXTERNAL_H_
+#define MID_I2S_EXTERNAL_H_
+
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/intel_mid_dma.h>
+
+#include <linux/interrupt.h>
+
+/*
+ * Structures Definition
+ */
+
+
+/*
+ * SSCR0 settings
+ */
+enum mrst_ssp_mode {
+ SSP_IN_NORMAL_MODE =3D 0x0,
+ SSP_IN_NETWORK_MODE
+};
+
+enum mrst_ssp_rx_fifo_over_run_int_mask {
+ SSP_RX_FIFO_OVER_INT_ENABLE =3D 0x0,
+ SSP_RX_FIFO_OVER_INT_DISABLE
+};
+
+enum mrst_ssp_tx_fifo_under_run_int_mask {
+ SSP_TX_FIFO_UNDER_INT_ENABLE =3D 0x0,
+ SSP_TX_FIFO_UNDER_INT_DISABLE
+};
+
+enum mrst_ssp_frame_format {
+ MOTOROLA_SPI_FORMAT =3D 0x0,
+ TI_SSP_FORMAT,
+ MICROWIRE_FORMAT,
+ PSP_FORMAT
+
+};
+
+enum mrst_ssp_master_mode_clock_selection {
+ SSP_ONCHIP_CLOCK =3D 0x0,
+ SSP_NETWORK_CLOCK,
+ SSP_EXTERNAL_CLOCK,
+ SSP_ONCHIP_AUDIO_CLOCK,
+ SSP_MASTER_CLOCK_UNDEFINED =3D 0xFF
+};
+
+/*
+ * SSCR1 settings
+ */
+enum mrst_ssp_txd_tristate_last_phase {
+ TXD_TRISTATE_LAST_PHASE_OFF =3D 0x0,
+ TXD_TRISTATE_LAST_PHASE_ON
+};
+
+enum mrst_ssp_txd_tristate_enable {
+ TXD_TRISTATE_OFF =3D 0x0,
+ TXD_TRISTATE_ON
+};
+
+enum mrst_ssp_slave_sspclk_free_running {
+ SLAVE_SSPCLK_ON_ALWAYS =3D 0x0,
+ SLAVE_SSPCLK_ON_DURING_TRANSFER_ONLY
+};
+
+enum mrst_ssp_sspsclk_direction {
+ SSPSCLK_MASTER_MODE =3D 0x0,
+ SSPSCLK_SLAVE_MODE
+};
+
+enum mrst_ssp_sspsfrm_direction {
+ SSPSFRM_MASTER_MODE =3D 0x0,
+ SSPSFRM_SLAVE_MODE
+};
+
+enum mrst_ssp_rx_without_tx {
+ RX_AND_TX_MODE =3D 0x0,
+ RX_WITHOUT_TX_MODE
+};
+
+enum mrst_trailing_byte_mode {
+ SSP_TRAILING_BYTE_HDL_BY_IA =3D 0x0,
+ SSP_TRAILING_BYTE_HDL_BY_DMA
+};
+
+enum mrst_ssp_tx_dma_status {
+ SSP_TX_DMA_MASK =3D 0x0,
+ SSP_TX_DMA_ENABLE
+};
+
+enum mrst_ssp_rx_dma_status {
+ SSP_RX_DMA_MASK =3D 0x0,
+ SSP_RX_DMA_ENABLE
+};
+
+enum mrst_ssp_rx_timeout_int_status {
+ SSP_RX_TIMEOUT_INT_DISABLE =3D 0x0,
+ SSP_RX_TIMEOUT_INT_ENABLE
+};
+
+enum mrst_ssp_trailing_byte_int_status {
+ SSP_TRAILING_BYTE_INT_DISABLE =3D 0x0,
+ SSP_TRAILING_BYTE_INT_ENABLE
+};
+
+enum mrst_ssp_loopback_mode_status {
+ SSP_LOOPBACK_OFF =3D 0x0,
+ SSP_LOOPBACK_ON
+};
+
+
+/*
+ * SSPSP settings: for PSP Format ONLY!!!!!!!!
+ */
+
+enum mrst_ssp_frame_sync_relative_timing_bit {
+ NEXT_FRMS_ASS_AFTER_END_OF_T4 =3D 0x0,
+ NEXT_FRMS_ASS_WITH_LSB_PREVIOUS_FRM
+};
+
+enum mrst_ssp_frame_sync_polarity_bit {
+ SSP_FRMS_ACTIVE_LOW =3D 0x0,
+ SSP_FRMS_ACTIVE_HIGH
+};
+
+enum mrst_ssp_end_of_transfer_data_state {
+ SSP_END_DATA_TRANSFER_STATE_LOW =3D 0x0,
+ SSP_END_DATA_TRANSFER_STATE_PEVIOUS_BIT
+};
+
+enum mrst_ssp_clk_mode {
+ SSP_CLK_MODE_0 =3D 0x0,
+ SSP_CLK_MODE_1,
+ SSP_CLK_MODE_2,
+ SSP_CLK_MODE_3
+};
+
+
+/*
+ * list of differents types of SSP, value depends of adid entry of
+ * capability ID of the PCI
+ */
+
+/*
+ *
+ * The PCI header associated to SSP devices now includes a configuration
+ * register. It provides information to a driver which is probed for the
+ * SSP, specifying in which way the SSP is supposed to be used. Here is
+ * the format of this byte register:
+ *
+ * bits 2..0: Mode
+ * 000=3D0x0 : Invalid, the register should be ignored
+ * 001=3D0x1 : SSP to be used as SPI controller
+ * 010=3D0x2: SSP to be used in I2S/ISS mode
+ * other: Reserved
+ *
+ * bits 5..3: Configuration
+ * In I2S/ISS mode:
+ * 000=3D0x0: Invalid
+ * 001=3D0x1: Bluetooth
+ * 010=3D0x2: Modem
+ * other: Reserved
+ * In SPI mode:
+ * Value is the SPI bus number connected to the SSP.
+ * To be used for registration to the Linux SPI
+ * framework.
+ * bit 6: SPI slave
+ * Relevant in SPI mode only. If set, indicates the SPI clock
+ * is not provided by the SSP: SPI slave mode.
+ *
+ * bit 7: Reserved (0)
+ *
+ * This configuration register is implemented in the adid field of the
+ * Vendor Specific PCI capability associated to the SSP.
+ *
+ */
+
+#define PCI_ADID_SSP_MODE_SPI (1)
+#define PCI_ADID_SSP_MODE_I2S (2)
+
+#define PCI_ADID_SSP_CONF_BT_FM (1<<3)
+#define PCI_ADID_SSP_CONF_MODEM (2<<3)
+
+
+#define PCI_CAP_ADID_I2S_BT_FM ((PCI_ADID_SSP_CONF_BT_FM) | (PCI_ADID_SSP=
_MODE_I2S))
+#define PCI_CAP_ADID_I2S_MODEM ((PCI_ADID_SSP_CONF_MODEM) | (PCI_ADID_SSP=
_MODE_I2S))
+
+enum intel_mid_i2s_ssp_usage {
+ SSP_USAGE_UNASSIGNED =3D 0x00,
+ SSP_USAGE_BLUETOOTH_FM =3D 0x01,
+ SSP_USAGE_MODEM =3D 0x02
+};
+
+/*
+ * Structure used to configure the SSP Port
+ * Please note that only the PSP format and the DMA transfer are suppo=
rted
+ */
+
+struct intel_mid_i2s_settings {
+ enum mrst_ssp_mode mode;
+ enum mrst_ssp_rx_fifo_over_run_int_mask rx_fifo_interrupt;
+ enum mrst_ssp_tx_fifo_under_run_int_mask tx_fifo_interrupt;
+ enum mrst_ssp_frame_format frame_format;
+ enum mrst_ssp_master_mode_clock_selection master_mode_clk_selectio=
n; /* for Master Mode Only */
+ u8 frame_rate_divider_contr=
ol;
+ u16 master_mode_serial_clock=
_rate; /* for Master Mode Only */
+ u16 data_size;
+
+ enum mrst_ssp_txd_tristate_last_phase tx_tristate_phase;
+ enum mrst_ssp_txd_tristate_enable tx_tristate_enable;
+ enum mrst_ssp_slave_sspclk_free_running slave_clk_free_running_s=
tatus;
+ enum mrst_ssp_sspsclk_direction sspslclk_direction;
+ enum mrst_ssp_sspsfrm_direction sspsfrm_direction;
+ enum mrst_ssp_rx_without_tx ssp_duplex_mode;
+ enum mrst_trailing_byte_mode ssp_trailing_byte_mode;
+ enum mrst_ssp_tx_dma_status ssp_tx_dma;
+ enum mrst_ssp_rx_dma_status ssp_rx_dma;
+ enum mrst_ssp_rx_timeout_int_status ssp_rx_timeout_interrupt=
_status;
+ enum mrst_ssp_trailing_byte_int_status ssp_trailing_byte_interr=
upt_status;
+ enum mrst_ssp_loopback_mode_status ssp_loopback_mode_status;
+ u8 ssp_rx_fifo_threshold;
+ u8 ssp_tx_fifo_threshold;
+
+
+ enum mrst_ssp_frame_sync_relative_timing_bit ssp_frmsync_timing_bi=
t;
+ enum mrst_ssp_frame_sync_polarity_bit ssp_frmsync_pol_bit;
+ enum mrst_ssp_end_of_transfer_data_state ssp_end_transfer_state;
+ enum mrst_ssp_clk_mode ssp_serial_clk_mode;
+ u8 ssp_psp_T1;
+ u8 ssp_psp_T2;
+ u8 ssp_psp_T4; /* DMYSTOP=
*/
+ u8 ssp_psp_T5; /* SFRMDLY=
*/
+ u8 ssp_psp_T6; /* SFRMWDT=
H */
+
+ u8 ssp_active_tx_slots_map;
+ u8 ssp_active_rx_slots_map;
+};
+
+/*
+ * Provided Interface
+ */
+
+
+struct intel_mid_i2s_hdl *intel_mid_i2s_open(enum intel_mid_i2s_ssp_usage =
usage, const struct intel_mid_i2s_settings *ps_settings);
+void intel_mid_i2s_close(struct intel_mid_i2s_hdl *handle);
+
+int intel_mid_i2s_rd_req(struct intel_mid_i2s_hdl *handle, u32 *dst, size_=
t len, void *param);
+int intel_mid_i2s_wr_req(struct intel_mid_i2s_hdl *handle, u32 *src, size_=
t len, void *param);
+int intel_mid_i2s_enable_ssp(struct intel_mid_i2s_hdl *handle);
+
+
+int intel_mid_i2s_set_wr_cb(struct intel_mid_i2s_hdl *handle, int (*write_=
callback)(void *param));
+int intel_mid_i2s_set_rd_cb(struct intel_mid_i2s_hdl *handle, int (*read_c=
allback)(void *param));
+
+
+int intel_mid_i2s_get_tx_fifo_level(struct intel_mid_i2s_hdl *handle);
+int intel_mid_i2s_get_rx_fifo_level(struct intel_mid_i2s_hdl *handle);
+int intel_mid_i2s_flush(struct intel_mid_i2s_hdl *handle);
+
+#endif /*MID_I2S_EXTERNAL_H_*/
diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig
index 12e3465..0b0a524 100644
--- a/sound/pci/Kconfig
+++ b/sound/pci/Kconfig
@@ -853,4 +853,22 @@ config SND_YMFPCI
To compile this driver as a module, choose M here: the module
will be called snd-ymfpci.
+config SND_INTEL_MID_I2S
+ tristate "Intel mid I2S hardware driver"
+ depends on EXPERIMENTAL && PCI && INTEL_MID_DMAC
+ default n
+ help
+ Say Y here if you want to build low level driver to support
+ sending/receving I2S audio samples on Intel MID SSP device.
+ This interface is mostly used on Intel MID platforms and provide
+ the low level interface for some upper layer drivers such as
+ Alsa SoC, char device interfaces... depending of peripheral conne=
cted.
+ PCI Header should have ADID field set to I2S BT_FM or
+ I2S MODEM to be used by this driver (so it know connected periphe=
ral).
+ Note this is a prototype driver and support for continuous
+ flow is still working-in-progress.
+ This driver can also be built as a module. If so, the module
+ will be called intel_mid_i2s.ko
+ If unsure, say N here.
+
endif # SND_PCI
diff --git a/sound/pci/Makefile b/sound/pci/Makefile
index 9cf4348..46613a2 100644
--- a/sound/pci/Makefile
+++ b/sound/pci/Makefile
@@ -78,4 +78,6 @@ obj-$(CONFIG_SND) +=3D \
rme9652/ \
trident/ \
ymfpci/ \
- vx222/
+ vx222/ \
+ intel_mid_i2s/
+
diff --git a/sound/pci/intel_mid_i2s/Makefile b/sound/pci/intel_mid_i2s/Mak=
efile
new file mode 100644
index 0000000..bebac1c
--- /dev/null
+++ b/sound/pci/intel_mid_i2s/Makefile
@@ -0,0 +1,18 @@
+# SSP audio driver
+# Copyright (c) 2010, Intel Corporation.
+
+# This program is free software; you can redistribute it and/or modify it
+# under the terms and conditions of the GNU General Public License,
+# version 2, as published by the Free Software Foundation.
+
+# This program is distributed in the hope it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+# more details.
+
+# You should have received a copy of the GNU General Public License along =
with
+# this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+obj-$(CONFIG_SND_INTEL_MID_I2S) +=3D intel_mid_i2s.o
+
diff --git a/sound/pci/intel_mid_i2s/intel_mid_i2s.c b/sound/pci/intel_mid_=
i2s/intel_mid_i2s.c
new file mode 100644
index 0000000..572abde
--- /dev/null
+++ b/sound/pci/intel_mid_i2s/intel_mid_i2s.c
@@ -0,0 +1,1428 @@
+/*
+ * <Driver for I2S protocol on SSP (Moorestown and Medfield hardware)>
+ * Copyright (c) 2010, Intel Corporation.
+ * Louis LE GALL <louis.le.gall intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without evenp the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License =
for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License alon=
g with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/pm_runtime.h>
+#include <linux/pci_regs.h>
+#include <linux/wait.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+
+#include <linux/device.h>
+
+#include <linux/intel_mid_i2s_if.h>
+#include "intel_mid_i2s.h"
+
+MODULE_AUTHOR("Louis LE GALL <louis.le.gall intel.com>");
+MODULE_DESCRIPTION("Intel MID I2S/PCM SSP Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("1.0.0");
+
+
+/*
+ * structures for pci probing
+ */
+static const struct dev_pm_ops intel_mid_i2s_pm_ops =3D {
+ .runtime_suspend =3D intel_mid_i2s_runtime_suspend,
+ .runtime_resume =3D intel_mid_i2s_runtime_resume,
+};
+static DEFINE_PCI_DEVICE_TABLE(pci_ids) =3D {
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, MFLD_SSP1_DEVICE_ID) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, MFLD_SSP0_DEVICE_ID) },
+ { 0, }, /* terminate list */
+};
+static struct pci_driver intel_mid_i2s_driver =3D {
+ .driver =3D {
+ .pm =3D &intel_mid_i2s_pm_ops,
+ },
+ .name =3D DRIVER_NAME,
+ .id_table =3D pci_ids,
+ .probe =3D intel_mid_i2s_probe,
+ .remove =3D __devexit_p(intel_mid_i2s_remove),
+#ifdef CONFIG_PM
+ .suspend =3D intel_mid_i2s_driver_suspend,
+ .resume =3D intel_mid_i2s_driver_resume,
+#endif
+};
+
+
+/*
+ * POWER MANAGEMENT FUNCTIONS
+ */
+
+#ifdef CONFIG_PM
+/**
+ * intel_mid_i2s_driver_suspend - driver power management suspend activity
+ * @device_ptr : pointer of the device to resume
+ *
+ * Output parameters
+ * error : 0 means no error
+ */
+static int intel_mid_i2s_driver_suspend(struct pci_dev *dev, pm_message_t=
state)
+{
+ struct intel_mid_i2s_hdl *drv_data =3D pci_get_drvdata(dev);
+ WARN(!drv_data, "Driver data=3DNULL\n");
+ if (!drv_data)
+ return 0;
+ dev_dbg(&drv_data->pdev->dev, "SUSPEND SSP ID %d\n", drv_data->pdev=
->device);
+ pci_save_state(dev);
+ pci_disable_device(dev);
+ pci_set_power_state(dev, PCI_D3hot);
+ return 0;
+}
+
+/**
+ * intel_mid_i2s_driver_resume - driver power management suspend activity
+ * @device_ptr : pointer of the device to resume
+ *
+ * Output parameters
+ * error : 0 means no error
+ */
+static int intel_mid_i2s_driver_resume(struct pci_dev *dev)
+{
+ int err;
+ int ret =3D 0;
+ struct intel_mid_i2s_hdl *drv_data =3D pci_get_drvdata(dev);
+
+ WARN(!drv_data, "Driver data=3DNULL\n");
+ if (!drv_data)
+ return -EFAULT;
+ dev_dbg(&drv_data->pdev->dev, "RESUME SSP ID %d\n", drv_data->pdev-=
>device);
+
+ err =3D pci_enable_device(dev);
+ if (err)
+ dev_err(&drv_data->pdev->dev, "Unable to re-enable device, =
trying to continue.\n");
+ dev_dbg(&drv_data->pdev->dev, "resuming\n");
+ pci_set_power_state(dev, PCI_D0);
+ pci_restore_state(dev);
+ ret =3D pci_enable_device(dev);
+ if (ret)
+ dev_err(&drv_data->pdev->dev, "I2S: device can't be enabled=
");
+ dev_dbg(&drv_data->pdev->dev, "resumed in D3\n");
+ return ret;
+}
+
+/**
+ * intel_mid_i2s_runtime_suspend - runtime power management suspend activi=
ty
+ * @device_ptr : pointer of the device to resume
+ *
+ * Output parameters
+ * error : 0 means no error
+ */
+static int intel_mid_i2s_runtime_suspend(struct device *device_ptr)
+{
+ struct pci_dev *pdev;
+ struct intel_mid_i2s_hdl *drv_data;
+ void __iomem *reg;
+
+ pdev =3D to_pci_dev(device_ptr);
+ WARN(!pdev, "Pci dev=3DNULL\n");
+ if (!pdev)
+ return -EFAULT;
+ drv_data =3D (struct intel_mid_i2s_hdl *) pci_get_drvdata(pdev);
+ WARN(!drv_data, "Driver data=3DNULL\n");
+ if (!drv_data)
+ return -EFAULT;
+ if (test_bit(I2S_PORT_OPENED, &drv_data->flags)) {
+ dev_err(device_ptr, "Trying to suspend a device that is ope=
ned\n");
+ return -ENODEV;
+ }
+ reg =3D drv_data->ioaddr;
+ dev_dbg(&drv_data->pdev->dev, "Suspend of SSP requested !!\n");
+ return intel_mid_i2s_driver_suspend(to_pci_dev(device_ptr), PMSG_SU=
SPEND);
+}
+#endif
+
+/**
+ * intel_mid_i2s_runtime_resume - runtime power management resume activity
+ * @device_ptr : pointer of the device to resume
+ *
+ * Output parameters
+ * error : 0 means no error
+ */
+static int intel_mid_i2s_runtime_resume(struct device *device_ptr)
+{
+ struct pci_dev *pdev;
+ struct intel_mid_i2s_hdl *drv_data;
+ pdev =3D to_pci_dev(device_ptr);
+ WARN(!pdev, "Pci dev=3DNULL\n");
+ if (!pdev)
+ return -EFAULT;
+ drv_data =3D (struct intel_mid_i2s_hdl *) pci_get_drvdata(pdev);
+ WARN(!drv_data, "Driver data=3DNULL\n");
+ if (!drv_data)
+ return -EFAULT;
+ dev_dbg(&drv_data->pdev->dev, "RT RESUME SSP ID\n");
+ return intel_mid_i2s_driver_resume(to_pci_dev(device_ptr));
+}
+
+/*
+ * INTERFACE FUNCTIONS
+ */
+
+/**
+ * intel_mid_i2s_flush - This is the I2S flush request
+ * @drv_data : pointer on private i2s driver data (by i2s_open function)
+ *
+ * It will flush the TX FIFO
+ * WARNING: this function is used in a Burst Mode context where it is call=
ed
+ * between Bursts i.e. when there is no FMSYNC, no transfer ongoing at
+ * that time
+ * If you need a flush while SSP configured in I2S is BUSY and FMSYNC are
+ * generated, you have to write another function
+ * (loop on BUSY bit and do not limit the flush to at most 16 samples)
+ *
+ * Output parameters
+ * int : number of samples flushed
+ */
+int intel_mid_i2s_flush(struct intel_mid_i2s_hdl *drv_data)
+{
+ u32 sssr, data;
+ u32 num =3D 0;
+ void __iomem *reg;
+
+ WARN(!drv_data, "Driver data=3DNULL\n");
+ if (!drv_data)
+ return 0;
+ reg =3D drv_data->ioaddr;
+ sssr =3D read_SSSR(reg);
+ dev_dbg(&drv_data->pdev->dev, "in flush sssr=3D0x%08X\n", sssr);
+ /*
+ * Flush "by hand" was generating spurious DMA SERV REQUEST
+ * from SSP to DMA =3D> then buggy retrieval of data for next dma_r=
eq
+ * Disable: RX Service Request from RX fifo to DMA
+ * as we will flush by hand
+ */
+ clear_SSCR1_reg(reg, RSRE);
+ /* i2s_flush is called in between 2 bursts
+ * =3D> no FMSYNC at that time (i.e. SSP not busy)
+ * =3D> at most 16 samples in the FIFO */
+ while ((read_SSSR(reg) & (SSSR_RNE_MASK<<SSSR_RNE_SHIFT))
+ && (num < FIFO_SIZE)) {
+ data =3D read_SSDR(reg);
+ num++;
+ dev_warn(&drv_data->pdev->dev, "flush(%u)=3D%u\n", num, dat=
a);
+ }
+ /* Enable: RX Service Request from RX fifo to DMA
+ * as flush by hand is done
+ */
+ set_SSCR1_reg(reg, RSRE);
+ sssr =3D read_SSSR(reg);
+ dev_dbg(&drv_data->pdev->dev, "out flush sssr=3D0x%08X\n", sssr);
+ return num;
+}
+EXPORT_SYMBOL_GPL(intel_mid_i2s_flush);
+
+/**
+ * intel_mid_i2s_get_rx_fifo_level - returns I2S rx fifo level
+ * @drv_data : pointer on private i2s driver data (by i2s_open function)
+ *
+ * Output parameters
+ * int : Number of samples currently in the RX FIFO (negative =3D err=
or)
+ */
+int intel_mid_i2s_get_rx_fifo_level(struct intel_mid_i2s_hdl *drv_data)
+{
+ u32 sssr;
+ u32 rne, rfl;
+ void __iomem *reg;
+
+ WARN(!drv_data, "Driver data=3DNULL\n");
+ if (!drv_data)
+ return -EFAULT;
+ reg =3D drv_data->ioaddr;
+ sssr =3D read_SSSR(reg);
+ rfl =3D GET_SSSR_val(sssr, RFL);
+ rne =3D GET_SSSR_val(sssr, RNE);
+ if (!rne)
+ return 0;
+ else
+ return rfl+1;
+}
+EXPORT_SYMBOL_GPL(intel_mid_i2s_get_rx_fifo_level);
+
+/**
+ * intel_mid_i2s_get_tx_fifo_level - returns I2S tx fifo level
+ * @drv_data : pointer on private i2s driver data (by i2s_open function)
+ *
+ * Output parameters
+ * int : number of samples currently in the TX FIFO (negative =3D err=
or)
+ */
+int intel_mid_i2s_get_tx_fifo_level(struct intel_mid_i2s_hdl *drv_data)
+{
+ u32 sssr;
+ u32 tnf, tfl;
+ void __iomem *reg;
+ WARN(!drv_data, "Driver data=3DNULL\n");
+ if (!drv_data)
+ return -EFAULT;
+ reg =3D drv_data->ioaddr;
+ sssr =3D read_SSSR(reg);
+ tfl =3D GET_SSSR_val(sssr, TFL);
+ tnf =3D GET_SSSR_val(sssr, TFN);
+ if (!tnf)
+ return 16;
+ else
+ return tfl;
+}
+EXPORT_SYMBOL_GPL(intel_mid_i2s_get_tx_fifo_level);
+
+/**
+ * intel_mid_i2s_set_rd_cb - set the callback function after read is done
+ * @drv_data : handle of corresponding ssp i2s (given by i2s_open function)
+ * @read_callback : pointer of callback function
+ *
+ * Output parameters
+ * error : 0 means no error
+ */
+int intel_mid_i2s_set_rd_cb(struct intel_mid_i2s_hdl *drv_data, int (*read=
_callback)(void *param))
+{
+ WARN(!drv_data, "Driver data=3DNULL\n");
+ if (!drv_data)
+ return -EFAULT;
+ mutex_lock(&drv_data->mutex);
+ if (!test_bit(I2S_PORT_OPENED, &drv_data->flags)) {
+ dev_WARN(&drv_data->pdev->dev, "set WR CB I2S_PORT NOT_OPEN=
ED");
+ mutex_unlock(&drv_data->mutex);
+ return -EPERM;
+ }
+ /* Do not change read parameters in the middle of a READ request */
+ if (test_bit(I2S_PORT_READ_BUSY, &drv_data->flags)) {
+ dev_WARN(&drv_data->pdev->dev, "CB reject I2S_PORT_READ_BUS=
Y");
+ mutex_unlock(&drv_data->mutex);
+ return -EBUSY;
+ }
+ drv_data->read_callback =3D read_callback;
+ drv_data->read_len =3D 0;
+ mutex_unlock(&drv_data->mutex);
+ return 0;
+
+}
+EXPORT_SYMBOL_GPL(intel_mid_i2s_set_rd_cb);
+
+/**
+ * intel_mid_i2s_set_wr_cb - set the callback function after write is done
+ * @drv_data : handle of corresponding ssp i2s (given by i2s_open functio=
n)
+ * @write_callback : pointer of callback function
+ *
+ * Output parameters
+ * error : 0 means no error
+ */
+int intel_mid_i2s_set_wr_cb(struct intel_mid_i2s_hdl *drv_data, int (*writ=
e_callback)(void *param))
+{
+ WARN(!drv_data, "Driver data=3DNULL\n");
+ if (!drv_data)
+ return -EFAULT;
+ mutex_lock(&drv_data->mutex);
+ if (!test_bit(I2S_PORT_OPENED, &drv_data->flags)) {
+ dev_warn(&drv_data->pdev->dev, "set WR CB I2S_PORT NOT_OPEN=
ED");
+ mutex_unlock(&drv_data->mutex);
+ return -EPERM;
+ }
+ /* Do not change write parameters in the middle of a WRITE request =
*/
+ if (test_bit(I2S_PORT_WRITE_BUSY, &drv_data->flags)) {
+ dev_warn(&drv_data->pdev->dev, "CB reject I2S_PORT_WRITE_BU=
SY");
+ mutex_unlock(&drv_data->mutex);
+ return -EBUSY;
+ }
+ drv_data->write_callback =3D write_callback;
+ drv_data->write_len =3D 0;
+ mutex_unlock(&drv_data->mutex);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(intel_mid_i2s_set_wr_cb);
+
+/**
+ * intel_mid_i2s_enable_ssp() : start the ssp right after the read/write r=
eq
+ * @drv_data : handle of corresponding ssp i2s (given by i2s_open function)
+ *
+ * This enable the read/write to be started synchronously
+ *
+ * Output parameters
+ * error : 0 means no error
+ */
+int intel_mid_i2s_enable_ssp(struct intel_mid_i2s_hdl *drv_data)
+{
+ void __iomem *reg =3D drv_data->ioaddr;
+ set_SSCR0_reg(reg, SSE);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(intel_mid_i2s_enable_ssp);
+
+/**
+ * intel_mid_i2s_rd_req - request a read from i2s peripheral
+ * @drv_data : handle of corresponding ssp i2s (given by i2s_open function)
+ * @dst : destination buffer where the read sample should be put
+ * @len : number of sample to be read (160 samples only right now)
+ * @param : private context parameter to give back to read callback
+ *
+ * Output parameters
+ * error : 0 means no error
+ */
+int intel_mid_i2s_rd_req(struct intel_mid_i2s_hdl *drv_data, u32 *destinat=
ion, size_t len, void *param)
+{
+ struct dma_async_tx_descriptor *rxdesc =3D NULL;
+ struct dma_chan *rxchan =3D drv_data->rxchan;
+ enum dma_ctrl_flags flag;
+ dma_addr_t ssdr_addr;
+ dma_addr_t dst;
+ WARN(!drv_data, "Driver data=3DNULL\n");
+ if (!drv_data)
+ return -EFAULT;
+ mutex_lock(&drv_data->mutex);
+ if (!rxchan) {
+ dev_WARN(&(drv_data->pdev->dev), "rd_req FAILED no rxchan\n=
");
+ mutex_unlock(&drv_data->mutex);
+ return -EINVAL;
+ }
+ if (!len) {
+ dev_WARN(&drv_data->pdev->dev, "rd req invalid len=3D0");
+ mutex_unlock(&drv_data->mutex);
+ return -EINVAL;
+ }
+ if (!test_bit(I2S_PORT_OPENED, &drv_data->flags)) {
+ dev_WARN(&drv_data->pdev->dev, "RD reject I2S_PORT NOT_OPEN=
ED");
+ mutex_unlock(&drv_data->mutex);
+ return -EPERM;
+ }
+ if (test_bit(I2S_PORT_CLOSING, &drv_data->flags)) {
+ dev_WARN(&drv_data->pdev->dev, "RD reject I2S_PORT CLOSING"=
);
+ mutex_unlock(&drv_data->mutex);
+ return -EPIPE;
+ }
+
+ dev_dbg(&drv_data->pdev->dev, "I2S_READ() dst=3D%p, len=3D%d, drv_d=
ata=3D%p", destination, len, drv_data);
+ dst =3D dma_map_single(NULL, destination, len, DMA_FROM_DEVICE);
+ if (!dst) {
+ dev_WARN(&drv_data->pdev->dev, "can't map DMA address %p", =
destination);
+ mutex_unlock(&drv_data->mutex);
+ return -ENOMEM;
+ }
+
+ drv_data->read_dst =3D dst;
+ drv_data->read_len =3D len;
+ /* get Data Read/Write address */
+ ssdr_addr =3D (drv_data->paddr + OFFSET_SSDR);
+ set_SSCR1_reg((drv_data->ioaddr), RSRE);
+ change_SSCR0_reg((drv_data->ioaddr), RIM,
+ ((drv_data->current_settings).rx_fifo_interrupt));
+ flag =3D DMA_PREP_INTERRUPT | DMA_CTRL_ACK;
+ /* Start the RX dma transfer */
+ rxdesc =3D rxchan->device->device_prep_dma_memcpy(
+ rxchan, /* DMA Channel */
+ dst, /* DAR */
+ ssdr_addr, /* SAR */
+ len, /* Data Length */
+ flag); /* Flag */
+ if (!rxdesc) {
+ dev_WARN(&drv_data->pdev->dev, "can not prep dma memcpy");
+ mutex_unlock(&drv_data->mutex);
+ return -EFAULT;
+ }
+ /* Only 1 READ at a time allowed. do it at end to avoid clear&wakeu=
p*/
+ if (test_and_set_bit(I2S_PORT_READ_BUSY, &drv_data->flags)) {
+ dma_unmap_single(NULL, dst, len, DMA_FROM_DEVICE);
+ dev_WARN(&drv_data->pdev->dev, "RD reject I2S_PORT READ_BUS=
Y");
+ mutex_unlock(&drv_data->mutex);
+ return -EBUSY;
+ }
+ dev_dbg(&(drv_data->pdev->dev), "RD dma tx submit\n");
+ rxdesc->callback =3D i2s_read_done;
+ drv_data->read_param =3D param;
+ rxdesc->callback_param =3D drv_data;
+ rxdesc->tx_submit(rxdesc);
+ mutex_unlock(&drv_data->mutex);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(intel_mid_i2s_rd_req);
+
+/**
+ * intel_mid_i2s_wr_req - request a write to i2s peripheral
+ * @drv_data : handle of corresponding ssp i2s (given by i2s_open function)
+ * @src : source buffer where the samples to wrote should be get
+ * @len : number of sample to be read (160 samples only right now)
+ * @param : private context parameter to give back to write callback
+ *
+ * Output parameters
+ * error : 0 means no error
+ */
+int intel_mid_i2s_wr_req(struct intel_mid_i2s_hdl *drv_data, u32 *source, =
size_t len, void *param)
+{
+ dma_addr_t ssdr_addr;
+ struct dma_async_tx_descriptor *txdesc =3D NULL;
+ struct dma_chan *txchan =3D drv_data->txchan;
+ enum dma_ctrl_flags flag;
+ dma_addr_t src;
+ WARN(!drv_data, "Driver data=3DNULL\n");
+ if (!drv_data)
+ return -EFAULT;
+ mutex_lock(&drv_data->mutex);
+ if (!txchan) {
+ dev_WARN(&(drv_data->pdev->dev), "wr_req but no txchan\n");
+ mutex_unlock(&drv_data->mutex);
+ return -EINVAL;
+ }
+ if (!len) {
+ dev_WARN(&drv_data->pdev->dev, "invalid len 0");
+ mutex_unlock(&drv_data->mutex);
+ return -EINVAL;
+ }
+ if (!test_bit(I2S_PORT_OPENED, &drv_data->flags)) {
+ dev_WARN(&drv_data->pdev->dev, "WR reject I2S_PORT NOT_OPEN=
ED");
+ mutex_unlock(&drv_data->mutex);
+ return -EPERM;
+ }
+ if (test_bit(I2S_PORT_CLOSING, &drv_data->flags)) {
+ dev_WARN(&drv_data->pdev->dev, "WR reject I2S_PORT CLOSING"=
);
+ mutex_unlock(&drv_data->mutex);
+ return -EPIPE;
+ }
+
+ dev_dbg(&drv_data->pdev->dev, "I2S_WRITE() src=3D%p, len=3D%d, drv_=
data=3D%p", source, len, drv_data);
+
+ src =3D dma_map_single(NULL, source, len, DMA_TO_DEVICE);
+ if (!src) {
+ dev_WARN(&drv_data->pdev->dev, "can't map DMA address %p", =
source);
+ mutex_unlock(&drv_data->mutex);
+ return -EFAULT;
+ }
+ drv_data->write_src =3D src;
+ drv_data->write_len =3D len;
+ /* get Data Read/Write address */
+ ssdr_addr =3D (dma_addr_t)(u32)(drv_data->paddr + OFFSET_SSDR);
+ set_SSCR1_reg((drv_data->ioaddr), TSRE);
+ change_SSCR0_reg((drv_data->ioaddr), TIM,
+ ((drv_data->current_settings).tx_fifo_interrupt));
+ flag =3D DMA_PREP_INTERRUPT | DMA_CTRL_ACK;
+ txdesc =3D txchan->device->device_prep_dma_memcpy(
+ txchan, /* DMA Channel */
+ ssdr_addr, /* DAR */
+ src, /* SAR */
+ len, /* Data Length */
+ flag); /* Flag */
+ if (!txdesc) {
+ dev_WARN(&(drv_data->pdev->dev),
+ "wr_req dma memcpy FAILED(src=3D%08x,len=3D%d,txcha=
n=3D%p)\n",
+ src, len, txchan);
+ mutex_unlock(&drv_data->mutex);
+ return -1;
+ }
+ dev_dbg(&(drv_data->pdev->dev), "WR dma tx summit\n");
+ /* Only 1 WRITE at a time allowed */
+ if (test_and_set_bit(I2S_PORT_WRITE_BUSY, &drv_data->flags)) {
+ dma_unmap_single(NULL, src, len, DMA_TO_DEVICE);
+ dev_WARN(&drv_data->pdev->dev, "WR reject I2S_PORT WRITE_BU=
SY");
+ mutex_unlock(&drv_data->mutex);
+ return -EBUSY;
+ }
+ txdesc->callback =3D i2s_write_done;
+ drv_data->write_param =3D param;
+ txdesc->callback_param =3D drv_data;
+ txdesc->tx_submit(txdesc);
+ dev_dbg(&(drv_data->pdev->dev), "wr dma req programmed\n");
+ mutex_unlock(&drv_data->mutex);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(intel_mid_i2s_wr_req);
+
+/**
+ * intel_mid_i2s_open - reserve and start a SSP depending of it's usage
+ * @usage : select which ssp i2s you need by giving usage (BT,MODEM...)
+ * @ps_settings : hardware settings to configure the SSP module
+ *
+ * May sleep (driver_find_device) : no lock permitted when called.
+ *
+ * Output parameters
+ * handle : handle of the selected SSP, or NULL if not found
+ */
+struct intel_mid_i2s_hdl *intel_mid_i2s_open(enum intel_mid_i2s_ssp_usage =
usage,
+ const struct intel_mid_i2s_settings *ps_settings)
+{
+ struct pci_dev *pdev;
+ struct intel_mid_i2s_hdl *drv_data =3D NULL;
+ struct device *found_device =3D NULL;
+ pr_debug("%s : open called,searching for device with usage=3D%x !\n=
", DRIVER_NAME, usage);
+ found_device =3D driver_find_device(&(intel_mid_i2s_driver.driver),=
NULL, &usage, check_device);
+ if (!found_device) {
+ pr_debug("%s : open can not found with usage=3D0x%02X\n", D=
RIVER_NAME, (int)usage);
+ return NULL;
+ }
+ pdev =3D to_pci_dev(found_device);
+ drv_data =3D pci_get_drvdata(pdev);
+
+ if (!drv_data) {
+ dev_err(found_device, "no drv_data in open pdev=3D%p\n", pd=
ev);
+ put_device(found_device);
+ return NULL;
+ }
+ mutex_lock(&drv_data->mutex);
+ dev_dbg(found_device, "Open found pdevice=3D0x%p\n", pdev);
+ /* pm_runtime */
+ pm_runtime_get_sync(&drv_data->pdev->dev);
+ /* dmac1 is already set during probe */
+ if (i2s_dma_start(drv_data) !=3D 0) {
+ dev_err(found_device, "Can not start DMA\n");
+ goto open_error;
+ }
+ /* if we restart after stop without suspend, we start ssp faster */
+ drv_data->current_settings =3D *ps_settings;
+ set_ssp_i2s_hw(drv_data, ps_settings);
+
+ drv_data->mask_sr =3D ((SSSR_BCE_MASK << SSSR_BCE_SHIFT) |
+ (SSSR_EOC_MASK << SSSR_EOC_SHIFT) |
+ (SSSR_ROR_MASK << SSSR_ROR_SHIFT) |
+ (SSSR_TUR_MASK << SSSR_TUR_SHIFT) |
+ (SSSR_TINT_MASK << SSSR_TINT_SHIFT) |
+ (SSSR_PINT_MASK << SSSR_PINT_SHIFT));
+ if (test_bit(I2S_PORT_CLOSING, &drv_data->flags)) {
+ dev_err(&drv_data->pdev->dev, "Opening a closing I2S!");
+ goto open_error;
+ }
+ /* there is no need to "wake up" as we can not close an opening i2s=
*/
+ clear_bit(I2S_PORT_WRITE_BUSY, &drv_data->flags);
+ clear_bit(I2S_PORT_READ_BUSY, &drv_data->flags);
+ mutex_unlock(&drv_data->mutex);
+ return drv_data;
+
+open_error:
+ put_device(found_device);
+ mutex_unlock(&drv_data->mutex);
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(intel_mid_i2s_open);
+
+/**
+ * intel_mid_i2s_close - release and stop the SSP
+ * @drv_data : handle of corresponding ssp i2s (given by i2s_open function)
+ *
+ * WARNING: This is not -yet- allowed to call close from a read/write call=
back !
+ *
+ * Output parameters
+ * none
+ */
+void intel_mid_i2s_close(struct intel_mid_i2s_hdl *drv_data)
+{
+ void __iomem *reg;
+ WARN(!drv_data, "Driver data=3DNULL\n");
+ if (!drv_data)
+ return;
+ mutex_lock(&drv_data->mutex);
+ if (!test_bit(I2S_PORT_OPENED, &drv_data->flags)) {
+ dev_err(&drv_data->pdev->dev, "not opened but closing?");
+ mutex_unlock(&drv_data->mutex);
+ return;
+ }
+ /* to be modified to wait_event_interruptible_timeout */
+ set_bit(I2S_PORT_CLOSING, &drv_data->flags);
+ dev_dbg(&drv_data->pdev->dev, "Status bit pending write=3D%d read=
=3D%d\n",
+ test_bit(I2S_PORT_WRITE_BUSY, &drv_data->flags),
+ test_bit(I2S_PORT_READ_BUSY, &drv_data->flags));
+ if (test_bit(I2S_PORT_WRITE_BUSY, &drv_data->flags) ||
+ test_bit(I2S_PORT_READ_BUSY, &drv_data->flags)) {
+ dev_dbg(&drv_data->pdev->dev, "Pending callback in close...=
\n");
+ }
+
+ /* waiting below. To be replaced when "DMA_TERMINATE_ALL" fix avail=
able */
+ wait_event(drv_data->wq_chan_closing,
+ ((!test_bit(I2S_PORT_WRITE_BUSY, &drv_data->flags)) &&
+ (!test_bit(I2S_PORT_READ_BUSY, &drv_data->flags))));
+ /* release DMA Channel.. */
+ i2s_dma_stop(drv_data);
+ reg =3D drv_data->ioaddr;
+ dev_dbg(&drv_data->pdev->dev, "Stopping the SSP\n");
+ i2s_ssp_stop(drv_data);
+ put_device(&drv_data->pdev->dev);
+ write_SSCR0(0, reg);
+ /* pm runtime */
+ pm_runtime_put(&drv_data->pdev->dev);
+ dev_dbg(&(drv_data->pdev->dev), "SSP Stopped.\n");
+ clear_bit(I2S_PORT_CLOSING, &drv_data->flags);
+ clear_bit(I2S_PORT_OPENED, &drv_data->flags);
+ mutex_unlock(&drv_data->mutex);
+}
+EXPORT_SYMBOL_GPL(intel_mid_i2s_close);
+/*
+ * INTERNAL FUNCTIONS
+ */
+
+/**
+ * check_device - return if the device is the usage we want (usage =3D*da=
ta)
+ * @device_ptr : pointer on device struct
+ * @data : pointer pointer on usage we are looking for
+ *
+ * this is called for each device by find_device() from intel_mid_i2s_open=
()
+ * Info : when found, the flag of driver is set to I2S_PORT_OPENED
+ *
+ * Output parameters
+ * integer : return 0 means not the device or already started. go next
+ * return !=3D 0 means stop the search and return this device
+ */
+static int
+check_device(struct device *device_ptr, void *data)
+{
+ struct pci_dev *pdev;
+ struct intel_mid_i2s_hdl *drv_data;
+ enum intel_mid_i2s_ssp_usage usage;
+ enum intel_mid_i2s_ssp_usage usage_to_find;
+
+ pdev =3D to_pci_dev(device_ptr);
+ WARN(!pdev, "Pci device=3DNULL\n");
+ if (!pdev)
+ return 0;
+ drv_data =3D (struct intel_mid_i2s_hdl *) pci_get_drvdata(pdev);
+ WARN(!drv_data, "Driver data=3DNULL\n");
+ if (!drv_data)
+ return 0;
+ dev_dbg(&(pdev->dev), "Check device pci_dev ptr =3D 0X%p\n", pdev);
+ usage_to_find =3D *((enum intel_mid_i2s_ssp_usage *) data);
+ usage =3D drv_data->usage;
+
+ /* Can be done in one "if" but separated in purpose : take care of
+ * test_and_set_bit that need to be done AFTER the check on usage.
+ */
+ if (usage =3D=3D usage_to_find) {
+ if (!test_and_set_bit(I2S_PORT_OPENED, &drv_data->flags))
+ return 1; /* Already opened, do not use this resul=
t */
+ };
+ return 0; /* not usage we look for, or already opened */
+}
+
+/**
+ * i2s_read_done - callback from the _dma tasklet_ after read
+ * @arg : void pointer to that should be driver data (context)
+ *
+ * Output parameters
+ * none
+ */
+static void i2s_read_done(void *arg)
+{
+ int status =3D 0;
+
+ struct intel_mid_i2s_hdl *drv_data =3D arg;
+ void *param_complete;
+ void __iomem *reg ;
+
+ WARN(!drv_data, "Driver data=3DNULL\n");
+ if (!drv_data)
+ return;
+ mutex_lock(&drv_data->mutex);
+ if (!test_bit(I2S_PORT_READ_BUSY, &drv_data->flags))
+ dev_WARN(&drv_data->pdev->dev, "spurious read dma complete"=
);
+
+ dma_unmap_single(NULL, drv_data->read_dst,
+ drv_data->read_len, DMA_FROM_DEVICE);
+ drv_data->read_len =3D 0;
+ reg =3D drv_data->ioaddr;
+ /* Rx fifo overrun Interrupt */
+ change_SSCR0_reg(reg, RIM, SSP_RX_FIFO_OVER_INT_DISABLE);
+ param_complete =3D drv_data->read_param;
+ /* Do not change order sequence:
+ * READ_BUSY clear, then test PORT_CLOSING
+ * wakeup for close() function
+ */
+ clear_bit(I2S_PORT_READ_BUSY, &drv_data->flags);
+ wake_up(&drv_data->wq_chan_closing);
+ if (test_bit(I2S_PORT_CLOSING, &drv_data->flags)) {
+ dev_dbg(&drv_data->pdev->dev, "read done waking up close");
+ mutex_unlock(&drv_data->mutex);
+ return;
+ }
+ mutex_unlock(&drv_data->mutex);
+ if (drv_data->read_callback !=3D NULL)
+ status =3D drv_data->read_callback(param_complete);
+ else
+ dev_warn(&drv_data->pdev->dev, "RD done but not callback se=
t");
+
+}
+
+/**
+ * i2s_write_done() : callback from the _dma tasklet_ after write
+ * @arg : void pointer to that should be driver data (context)
+ *
+ * Output parameters
+ * none
+ */
+static void i2s_write_done(void *arg)
+{
+ int status =3D 0;
+ void *param_complete;
+ struct intel_mid_i2s_hdl *drv_data =3D arg;
+ void __iomem *reg ;
+
+ WARN(!drv_data, "Driver data=3DNULL\n");
+ if (!drv_data)
+ return;
+ mutex_lock(&drv_data->mutex);
+ if (!test_bit(I2S_PORT_WRITE_BUSY, &drv_data->flags))
+ dev_warn(&drv_data->pdev->dev, "spurious write dma complete=
");
+ dma_unmap_single(NULL, drv_data->read_dst,
+ drv_data->read_len, DMA_TO_DEVICE);
+ drv_data->read_len =3D 0;
+ reg =3D drv_data->ioaddr;
+ change_SSCR0_reg(reg, TIM, SSP_TX_FIFO_UNDER_INT_DISABLE);
+ dev_dbg(&(drv_data->pdev->dev), "DMA channel disable..\n");
+ param_complete =3D drv_data->write_param;
+ /* Do not change order sequence:
+ * WRITE_BUSY clear, then test PORT_CLOSING
+ * wakeup for close() function
+ */
+ clear_bit(I2S_PORT_WRITE_BUSY, &drv_data->flags);
+ wake_up(&drv_data->wq_chan_closing);
+ if (test_bit(I2S_PORT_CLOSING, &drv_data->flags)) {
+ mutex_unlock(&drv_data->mutex);
+ dev_dbg(&drv_data->pdev->dev, "write done waking up close");
+ return;
+ }
+ mutex_unlock(&drv_data->mutex);
+ if (drv_data->write_callback !=3D NULL)
+ status =3D drv_data->write_callback(param_complete);
+ else
+ dev_warn(&drv_data->pdev->dev, "WR done but no callback set=
");
+}
+
+static bool chan_filter(struct dma_chan *chan, void *param)
+{
+ struct intel_mid_i2s_hdl *drv_data =3D (struct intel_mid_i2s_hdl *)=
param;
+ bool ret =3D false;
+
+ if (!drv_data->dmac1)
+ goto out;
+ if (chan->device->dev =3D=3D &drv_data->dmac1->dev)
+ ret =3D true;
+out:
+ return ret;
+}
+
+/**
+ * i2s_dma_start - prepare and reserve dma channels
+ * @arg : intel_mid_i2s_hdl pointer to that should be driver data (context)
+ *
+ * "ssp open" context and dmac1 should already be filled in drv_data
+ *
+ * Output parameters
+ * int : should be zero, else it means error code
+ */
+static int i2s_dma_start(struct intel_mid_i2s_hdl *drv_data)
+{
+ struct intel_mid_dma_slave *rxs, *txs;
+ dma_cap_mask_t mask;
+ int retval =3D 0;
+ struct pci_dev *l_pdev;
+
+ dev_dbg(&drv_data->pdev->dev, "DMAC1 start\n");
+ drv_data->txchan =3D NULL;
+ drv_data->rxchan =3D NULL;
+ l_pdev =3D drv_data->pdev;
+ /* 1. init rx channel */
+ rxs =3D &drv_data->dmas_rx;
+ rxs->dirn =3D DMA_FROM_DEVICE;
+ rxs->hs_mode =3D LNW_DMA_HW_HS;
+ rxs->cfg_mode =3D LNW_DMA_PER_TO_MEM;
+ rxs->src_width =3D LNW_DMA_WIDTH_16BIT;
+ rxs->dst_width =3D LNW_DMA_WIDTH_32BIT;
+ rxs->src_msize =3D LNW_DMA_MSIZE_8;
+ rxs->dst_msize =3D LNW_DMA_MSIZE_8;
+ rxs->device_instance =3D drv_data->device_instance;
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_MEMCPY, mask);
+ dma_cap_set(DMA_SLAVE, mask);
+ drv_data->rxchan =3D dma_request_channel(mask, chan_filter, drv_dat=
a);
+ if (!drv_data->rxchan) {
+ dev_err(&(drv_data->pdev->dev),
+ "Could not get Rx channel\n");
+ retval =3D -2;
+ goto err_exit;
+ }
+ drv_data->rxchan->private =3D rxs;
+ /* 2. init tx channel */
+ txs =3D &drv_data->dmas_tx;
+ txs->dirn =3D DMA_TO_DEVICE;
+ txs->hs_mode =3D LNW_DMA_HW_HS;
+ txs->cfg_mode =3D LNW_DMA_MEM_TO_PER;
+ txs->src_width =3D LNW_DMA_WIDTH_32BIT;
+ txs->dst_width =3D LNW_DMA_WIDTH_16BIT;
+ txs->src_msize =3D LNW_DMA_MSIZE_8;
+ txs->dst_msize =3D LNW_DMA_MSIZE_8;
+ txs->device_instance =3D drv_data->device_instance;
+ dma_cap_set(DMA_SLAVE, mask);
+ dma_cap_set(DMA_MEMCPY, mask);
+ drv_data->txchan =3D dma_request_channel(mask, chan_filter, drv_dat=
a);
+ if (!drv_data->txchan) {
+ dev_err(&(drv_data->pdev->dev),
+ "Could not get Tx channel\n");
+ retval =3D -3;
+ goto free_rxchan;
+ }
+ drv_data->txchan->private =3D txs;
+ return retval;
+free_rxchan:
+ dma_release_channel(drv_data->rxchan);
+err_exit:
+ return retval;
+}
+
+/**
+ * i2s_dma_stop - release dma channels
+ * @arg : struct intel_mid_i2s_hdl pointer to that should be driver data (=
context)
+ *
+ * called by intel_mid_i2s_close() context
+ *
+ * Output parameters
+ * none
+ */
+static void i2s_dma_stop(struct intel_mid_i2s_hdl *drv_data)
+{
+ dev_dbg(&drv_data->pdev->dev, "DMAC1 stop\n");
+ dma_release_channel(drv_data->txchan);
+ dma_release_channel(drv_data->rxchan);
+}
+
+static void i2s_ssp_stop(struct intel_mid_i2s_hdl *drv_data)
+{
+ void __iomem *reg =3D drv_data->ioaddr;
+ dev_dbg(&drv_data->pdev->dev, "Stop SSP\n");
+ clear_SSCR0_reg(reg, SSE);
+}
+
+static void ssp1_dump_registers(struct intel_mid_i2s_hdl *drv_data)
+{
+ u32 irq_status;
+ void __iomem *reg =3D drv_data->ioaddr;
+ struct device *ddbg =3D &(drv_data->pdev->dev);
+ u32 status;
+ irq_status =3D read_SSSR(reg);
+ dev_dbg(ddbg, "dump SSSR=3D0x%08X\n", irq_status);
+ status =3D read_SSCR0(reg);
+ dev_dbg(ddbg, "dump SSCR0=3D0x%08X\n", status);
+ status =3D read_SSCR1(reg);
+ dev_dbg(ddbg, "dump SSCR1=3D0x%08X\n", status);
+ status =3D read_SSPSP(reg);
+ dev_dbg(ddbg, "dump SSPSP=3D0x%08X\n", status);
+ status =3D read_SSTSA(reg);
+ dev_dbg(ddbg, "dump SSTSA=3D0x%08X\n", status);
+ status =3D read_SSRSA(reg);
+ dev_dbg(ddbg, "dump SSRSA=3D0x%08X\n", status);
+ status =3D read_SSTO(reg);
+ dev_dbg(ddbg, "dump SSTO=3D0x%08X\n", status);
+ status =3D read_SSITR(reg);
+ dev_dbg(ddbg, "dump SSITR=3D0x%08X\n", status);
+ status =3D read_SSTSS(reg);
+ dev_dbg(ddbg, "dump SSTSS=3D0x%08X\n", status);
+ status =3D read_SSACD(reg);
+ dev_dbg(ddbg, "dump SSACD=3D0x%08X\n", status);
+}
+
+/**
+ * i2s_int(): function that handles the SSP Interrupts (errors)
+ * @irq : IRQ Number
+ * @dev_id : structure that contains driver information
+ *
+ * This interrupts do nothing but warnings in case there is some problems
+ * in I2S connection (underruns, overruns...). This may be reported by add=
ing a
+ * new interface to the driver, but not yet requested by "users" of this d=
river
+ *
+ * Output parameters
+ * NA
+ */
+static irqreturn_t i2s_int(int irq, void *dev_id)
+{
+ struct intel_mid_i2s_hdl *drv_data =3D dev_id;
+ void __iomem *reg;
+ u32 irq_status =3D 0;
+ u32 mask_status =3D 0;
+ struct device *ddbg =3D &(drv_data->pdev->dev);
+ reg =3D drv_data->ioaddr;
+ irq_status =3D read_SSSR(reg);
+
+ if (!(irq_status & (drv_data->mask_sr))) {
+ return IRQ_NONE;
+ } else {
+ /* may be improved by using a tasklet to send the error
+ * (underrun,...) to client by using callback
+ */
+ if (irq_status & (SSSR_ROR_MASK << SSSR_ROR_SHIFT)) {
+ dev_warn(ddbg,
+ "ssp_int RX FIFO OVER RUN SSSR=3D0x%08X\n",
+ irq_status);
+ mask_status |=3D (SSSR_ROR_MASK << SSSR_ROR_SHIFT);
+
+ }
+ if (irq_status & (SSSR_TUR_MASK << SSSR_TUR_SHIFT)) {
+ dev_warn(ddbg,
+ "ssp_int TX FIFO UNDER RUN SSSR=3D0x%08X\n",
+ irq_status);
+ mask_status |=3D (SSSR_TUR_MASK << SSSR_TUR_SHIFT);
+
+ }
+ if (irq_status & (SSSR_TINT_MASK << SSSR_TINT_SHIFT)) {
+ dev_warn(ddbg,
+ "ssp_int RX TIME OUT SSSR=3D0x%08X\n",
+ irq_status);
+ mask_status |=3D (SSSR_TINT_MASK << SSSR_TINT_SHIFT=
);
+
+ }
+ if (irq_status & (SSSR_PINT_MASK << SSSR_PINT_SHIFT)) {
+ dev_warn(ddbg,
+ "ssp_int TRAILING BYTE SSSR=3D0x%08X\n",
+ irq_status);
+ mask_status |=3D (SSSR_PINT_MASK << SSSR_PINT_SHIFT=
);
+ }
+ if (irq_status & (SSSR_EOC_MASK << SSSR_EOC_SHIFT)) {
+ dev_warn(ddbg,
+ "ssp_int END OF CHAIN SSSR=3D0x%08X\n",
+ irq_status);
+ mask_status |=3D (SSSR_EOC_MASK << SSSR_EOC_SHIFT);
+ }
+ /* clear sticky bits */
+ write_SSSR((irq_status & mask_status), reg);
+ }
+ return IRQ_HANDLED;
+}
+
+/**
+ * calculate_sspsp_psp - separate function that calculate sspsp register
+ * @ps_settings : pointer of the settings struct
+ *
+ * this function is to simplify/clarify set_ssp_i2s_hw function
+ *
+ *
+ * Output parameters
+ * u32 : calculated SSPSP register
+ */
+u32 calculate_sspsp_psp(const struct intel_mid_i2s_settings *ps_settings)
+{
+ u32 sspsp;
+ sspsp =3D SSPSP_reg(FSRT, ps_settings->ssp_frmsync_timing_bit)
+ |SSPSP_reg(ETDS, ps_settings->ssp_end_transfer_state)
+ |SSPSP_reg(SCMODE, ps_settings->ssp_serial_clk_mode)
+ |SSPSP_reg(DMYSTOP, ps_settings->ssp_psp_T4)
+ |SSPSP_reg(SFRMDLY, ps_settings->ssp_psp_T5)
+ |SSPSP_reg(SFRMWDTH, ps_settings->ssp_psp_T6)
+ |SSPSP_reg(SFRMP, ps_settings->ssp_frmsync_pol_bit);
+ return sspsp;
+}
+
+/*
+ * calculate_sscr0_psp: separate function that calculate sscr0 register
+ * @ps_settings : pointer of the settings struct
+ *
+ * this function is to simplify/clarify set_ssp_i2s_hw function
+ *
+ * Output parameters
+ * u32 : calculated SSCR0 register
+ */
+u32 calculate_sscr0_psp(const struct intel_mid_i2s_settings *ps_settings)
+{
+ u16 l_ssp_data_size =3D ps_settings->data_size;
+ u32 sscr0;
+ if (l_ssp_data_size > 16) {
+ sscr0 =3D SSCR0_reg(DSS, SSCR0_DataSize(l_ssp_data_size -=
16))
+ | SSCR0_reg(EDSS, 1);
+ } else {
+ sscr0 =3D SSCR0_reg(DSS, SSCR0_DataSize(l_ssp_data_size))
+ | SSCR0_reg(EDSS, 0);
+ }
+/*
+Can be replaced by code below :
+sscr0 =3D SSCR0_reg(DSS, (l_ssp_data_size - 1) & 0x0F)
+| SSCR0_reg(EDSS, ((l_ssp_data_size - 1) & 0x10) >> 8);
+*/
+ sscr0 |=3D SSCR0_reg(MOD, ps_settings->mode)
+ |SSCR0_reg(FRF, ps_settings->frame_format)
+ |SSCR0_reg(RIM, SSP_RX_FIFO_OVER_INT_DISABLE)
+ |SSCR0_reg(TIM, SSP_TX_FIFO_UNDER_INT_DISABLE);
+ return sscr0;
+}
+
+/**
+ * calculate_sscr1_psp - separate function that calculate sscr1 register
+ * @ps_settings : pointer of the settings struct
+ *
+ * this function is to simplify/clarify set_ssp_i2s_hw function
+ *
+ * Output parameters
+ * u32 : calculated SSCR1 register
+ */
+u32 calculate_sscr1_psp(const struct intel_mid_i2s_settings *ps_settings)
+{
+ u32 sscr1;
+ sscr1 =3D SSCR1_reg(SFRMDIR, ps_settings->sspsfrm_direction)
+ |SSCR1_reg(SCLKDIR, ps_settings->sspslclk_direction)
+ |SSCR1_reg(TTELP, ps_settings->tx_tristate_phase)
+ |SSCR1_reg(TTE, ps_settings->tx_tristate_enable)
+ |SSCR1_reg(TRAIL, ps_settings->ssp_trailing_byte_mode)
+ |SSCR1_reg(TINTE, ps_settings->ssp_rx_timeout_interru=
pt_status)
+ |SSCR1_reg(PINTE, ps_settings->ssp_trailing_byte_inte=
rrupt_status)
+ |SSCR1_reg(LBM, ps_settings->ssp_loopback_mode_status)
+ |SSCR1_reg(RWOT, ps_settings->ssp_duplex_mode)
+ |SSCR1_reg(RFT, SSCR1_RxTresh(ps_settings->ssp_rx_fifo_thre=
shold))
+ |SSCR1_reg(TFT, SSCR1_TxTresh(ps_settings->ssp_tx_fifo_thre=
shold));
+ return sscr1;
+}
+
+/**
+ * set_ssp_i2s_hw - configure the SSP driver according to the ps_settings
+ * @drv_data : structure that contains all details about the SSP Driver
+ * @ps_settings : structure that contains SSP Hardware settings
+ *
+ * it also store ps_settings the drv_data
+ *
+ * Output parameters
+ * NA
+ */
+static void set_ssp_i2s_hw(struct intel_mid_i2s_hdl *drv_data,
+ const struct intel_mid_i2s_settings *ps_settings)
+{
+ u32 sscr0 =3D 0;
+ u32 sscr1 =3D 0;
+ u32 sstsa =3D 0;
+ u32 ssrsa =3D 0;
+ u32 sspsp =3D 0;
+ u32 sssr =3D 0;
+ /* Get the SSP Settings */
+ u16 l_ssp_clk_frm_mode =3D 0xFF;
+ void __iomem *reg =3D drv_data->ioaddr;
+ struct device *ddbg =3D &(drv_data->pdev->dev);
+ dev_dbg(ddbg,
+ "setup SSP I2S PCM1 configuration\n");
+ if ((ps_settings->sspsfrm_direction =3D=3D SSPSFRM_MASTER_MODE)
+ && (ps_settings->sspslclk_direction =3D=3D SSPSCLK_MASTER_MODE))=
{
+ l_ssp_clk_frm_mode =3D SSP_IN_MASTER_MODE;
+ } else if ((ps_settings->sspsfrm_direction =3D=3D SSPSFRM_SLAVE_MOD=
E)
+ && (ps_settings->sspslclk_direction =3D=3D SSPSCLK_SLAVE_MODE)) {
+ l_ssp_clk_frm_mode =3D SSP_IN_SLAVE_MODE;
+ } else {
+ dev_err(ddbg, "Unsupported I2S PCM1 configuration\n");
+ goto leave;
+ }
+ dev_dbg(ddbg, "SSPSFRM_DIRECTION:%d:\n",
+ ps_settings->sspsfrm_direction);
+ dev_dbg(ddbg, "SSPSCLK_DIRECTION:%d:\n",
+ ps_settings->sspslclk_direction);
+ if (ps_settings->frame_format !=3D PSP_FORMAT) {
+ dev_err(ddbg, "UNSUPPORTED FRAME FORMAT:%d:\n", ps_settings=
->frame_format);
+ goto leave;
+ }
+ if ((ps_settings->ssp_tx_dma !=3D SSP_TX_DMA_ENABLE)
+ || (ps_settings->ssp_rx_dma !=3D SSP_RX_DMA_ENABLE)) {
+ dev_err(ddbg, "ONLY DMA MODE IS SUPPORTED");
+ goto leave;
+ }
+ /*********** DMA Transfer Mode ***********/
+ dev_dbg(ddbg, "FORMAT :%d:\n", ps_settings->frame_format);
+ sscr0 =3D calculate_sscr0_psp(ps_settings);
+ dev_dbg(ddbg, " sscr0 :0x%08X\n", sscr0);
+ sscr1 =3D calculate_sscr1_psp(ps_settings);
+ dev_dbg(ddbg, " sscr1 :0x%08X\n", sscr1);
+ if (ps_settings->mode =3D=3D SSP_IN_NETWORK_MODE) {
+ dev_dbg(ddbg, "MODE :%d:\n", ps_settings->mode);
+ sscr0 |=3D SSCR0_reg(FRDC, SSCR0_SlotsPerFrm(ps_settings->f=
rame_rate_divider_control));
+ dev_dbg(ddbg, "sscr0 :0x%08X\n", sscr0);
+ sspsp =3D calculate_sspsp_psp(ps_settings);
+ dev_dbg(ddbg, "sspsp :0x%08X\n", sspsp);
+ /* set the active TX time slot (bitmap) */
+ sstsa =3D SSTSA_reg(TTSA, ps_settings->ssp_active_tx_slots_=
map);
+ /* set the active RX time slot (bitmap) */
+ ssrsa =3D SSRSA_reg(RTSA, ps_settings->ssp_active_rx_slots_=
map);
+ if (l_ssp_clk_frm_mode =3D=3D SSP_IN_MASTER_MODE) {
+ switch (ps_settings->master_mode_clk_selection) {
+ case SSP_ONCHIP_CLOCK:
+ break;
+ case SSP_NETWORK_CLOCK:
+ sscr0 |=3D SSCR0_reg(NCS, 1);
+ break;
+ case SSP_EXTERNAL_CLOCK:
+ sscr0 |=3D SSCR0_reg(ECS, 1);
+ break;
+ case SSP_ONCHIP_AUDIO_CLOCK:
+ sscr0 |=3D SSCR0_reg(ACS, 1);
+ break;
+ default:
+ dev_err(ddbg, "Master Mode clk selection UN=
KNOWN");
+ break;
+ }
+ sspsp |=3D SSPSP_reg(STRTDLY, ps_settings->ssp_psp_=
T1)
+ |SSPSP_reg(DMYSTRT, ps_settings->ssp_psp_T2=
);
+ } else { /* Set the Slave Clock Free Running Status =
*/
+ sscr1 |=3D SSCR1_reg(SCFR, ps_settings->slave_clk_f=
ree_running_status);
+ }
+ } else { /* SSP_IN_NORMAL_MODE */
+ dev_err(ddbg, "UNSUPPORTED MODE");
+ goto leave;
+ }
+
+ /* Clear status */
+ sssr =3D (SSSR_BCE_MASK << SSSR_BCE_SHIFT)
+ | (SSSR_TUR_MASK << SSSR_TUR_SHIFT)
+ | (SSSR_TINT_MASK << SSSR_TINT_SHIFT)
+ | (SSSR_PINT_MASK << SSSR_PINT_SHIFT)
+ | (SSSR_ROR_MASK << SSSR_ROR_SHIFT);
+ /* disable SSP */
+ clear_SSCR0_reg(reg, SSE);
+ dev_dbg(ddbg, "WRITE SSCR0 DISABLE\n");
+ /* Clear status */
+ write_SSSR(sssr, reg);
+ dev_dbg(ddbg, "WRITE SSSR: 0x%08X\n", sssr);
+ write_SSCR0(sscr0, reg);
+ dev_dbg(ddbg, "WRITE SSCR0\n");
+ /* first set CR1 without interrupt and service enables */
+ write_SSCR1(sscr1, reg);
+ write_SSPSP(sspsp, reg);
+ write_SSTSA(sstsa, reg);
+ write_SSRSA(ssrsa, reg);
+ /* set the time out for the reception */
+ write_SSTO(0, reg);
+ ssp1_dump_registers(drv_data);
+leave:
+ return;
+}
+
+static int
+intel_mid_i2s_find_usage(struct pci_dev *pdev,
+ struct intel_mid_i2s_hdl *drv_data,
+ enum intel_mid_i2s_ssp_usage *usage)
+{
+ int pos;
+ u8 adid;
+ int status =3D 0;
+
+ *usage =3D SSP_USAGE_UNASSIGNED;
+ pos =3D pci_find_capability(pdev, PCI_CAP_ID_VNDR);
+ dev_info((&pdev->dev),
+ "Probe/find capability (VNDR %d pos=3D0x%x)\n",
+ PCI_CAP_ID_VNDR, pos);
+ if (pos > 0) {
+ pos +=3D PCI_CAP_OFFSET_ADID;
+ pci_read_config_byte(pdev, pos, &adid);
+ dev_info(&(pdev->dev), "Vendor capability adid =3D 0x%x\n",=
adid);
+ if (adid =3D=3D PCI_CAP_ADID_I2S_BT_FM)
+ *usage =3D SSP_USAGE_BLUETOOTH_FM;
+ else if (adid =3D=3D PCI_CAP_ADID_I2S_MODEM)
+ *usage =3D SSP_USAGE_MODEM;
+ else
+ *usage =3D SSP_USAGE_UNASSIGNED;
+ }
+ /* If there is no capability, check with old PCI_ID */
+#ifdef BYPASS_ADID
+ if (*usage =3D=3D SSP_USAGE_UNASSIGNED) {
+ dev_warn(&(pdev->dev), "Vendor capability not present/inval=
id\n");
+ switch (pdev->device) {
+ case MFLD_SSP1_DEVICE_ID:
+ *usage =3D SSP_USAGE_BLUETOOTH_FM;
+ break;
+ case MFLD_SSP0_DEVICE_ID:
+ *usage =3D SSP_USAGE_MODEM;
+ break;
+ }
+ }
+#endif
+ if (*usage =3D=3D SSP_USAGE_UNASSIGNED) {
+ dev_info((&pdev->dev),
+ "No probe for I2S PCI-ID: %04x:%04x, ADID(0x%x)=3D0=
x%x\n",
+ pdev->vendor, pdev->device, pos, adid);
+ status =3D -ENODEV;
+ goto err_find_usage;
+ }
+ dev_dbg(&(pdev->dev),
+ "Detected PCI SSP (ID: %04x:%04x) usage =3D%x\n",
+ pdev->vendor, pdev->device, *usage);
+ dev_dbg(&(pdev->dev),
+ " found PCI SSP controller(ID: %04x:%04x)\n",
+ pdev->vendor, pdev->device);
+ /* Init the driver data structure fields*/
+ switch (pdev->device) {
+ case MFLD_SSP1_DEVICE_ID:
+ drv_data->device_instance =3D DMA1C_DEVICE_INSTANCE_SSP1;
+ break;
+ case MFLD_SSP0_DEVICE_ID:
+ drv_data->device_instance =3D DMA1C_DEVICE_INSTANCE_SSP0;
+ break;
+ default:
+ dev_err(&(pdev->dev),
+ "Can not determine dma device instance (PCI ID:%04x=
)\n",
+ pdev->device);
+ status =3D -ENODEV;
+ goto err_find_usage;
+ }
+ status =3D pci_enable_device(pdev);
+ if (status)
+ dev_err((&pdev->dev), "Can not enable device.Err=3D%d\n", s=
tatus);
+err_find_usage:
+ return status;
+}
+
+/**
+ * intel_mid_i2s_probe - probing function for the pci selected
+ * @pdev : pci_dev pointer that is probed
+ * @ent : pci_device_id
+ *
+ * Output parameters
+ * NA
+ */
+static int intel_mid_i2s_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ struct intel_mid_i2s_hdl *drv_data;
+ int status =3D 0;
+ enum intel_mid_i2s_ssp_usage usage;
+
+ drv_data =3D kzalloc(sizeof(struct intel_mid_i2s_hdl), GFP_KERNEL);
+ dev_dbg(&(pdev->dev), "%s Probe, drv_data =3D%p\n", DRIVER_NAME, dr=
v_data);
+ if (!drv_data) {
+ dev_err((&pdev->dev), "Can't alloc driver data in probe\n");
+ status =3D -ENOMEM;
+ goto leave;
+ }
+ dev_info((&pdev->dev), "Detected PCI SSP (ID: %04x:%04x)\n", pdev->=
vendor, pdev->device);
+ status =3D intel_mid_i2s_find_usage(pdev, drv_data, &usage);
+ if (status)
+ goto err_i2s_probe0;
+ mutex_init(&drv_data->mutex);
+ drv_data->pdev =3D pdev;
+ drv_data->usage =3D usage;
+ /*
+ * Get basic io resource and map it for SSP1 [BAR=3D0]
+ */
+ if ((pdev->device =3D=3D MFLD_SSP1_DEVICE_ID) ||
+ (pdev->device =3D=3D MFLD_SSP0_DEVICE_ID)) {
+ drv_data->paddr =3D pci_resource_start(pdev, MRST_SSP_BAR);
+ drv_data->iolen =3D pci_resource_len(pdev, MRST_SSP_BAR);
+ status =3D pci_request_region(pdev, MRST_SSP_BAR, dev_name(=
&pdev->dev));
+ /* map bus memory into CPU space */
+ drv_data->ioaddr =3D pci_ioremap_bar(pdev, MRST_SSP_BAR);
+ } else {
+ dev_err(&pdev->dev,
+ "Don't know which BAR to usefor this SSP PCDID=3D%x=
\n",
+ pdev->device);
+ status =3D -ENODEV;
+ goto err_i2s_probe1;
+ }
+ dev_dbg(&(pdev->dev), "paddr =3D : %x\n", drv_data->paddr);
+ dev_dbg(&(pdev->dev), "iolen =3D : %d\n", drv_data->iolen);
+ if (status) {
+ dev_err((&pdev->dev), "Can't request region. err=3D%d\n", s=
tatus);
+ goto err_i2s_probe1;
+ }
+ if (!drv_data->ioaddr) {
+ dev_err((&pdev->dev), "ioremap_nocache error\n");
+ status =3D -ENOMEM;
+ goto err_i2s_probe2;
+ }
+ dev_dbg(&(pdev->dev), "ioaddr =3D : %p\n", drv_data->ioaddr);
+ /* prepare for DMA channel allocation */
+ /* get the pci_dev structure pointer */
+ /* Check the SSP, if SSP3, then another DMA is used (GPDMA..) */
+ if ((pdev->device =3D=3D MFLD_SSP1_DEVICE_ID) ||
+ (pdev->device =3D=3D MFLD_SSP0_DEVICE_ID)) {
+ drv_data->dmac1 =3D pci_get_device(PCI_VENDOR_ID_INTEL,
+ MFLD_LPE_DMA_DEVICE_ID,
+ NULL);
+ } else {
+ dev_err(&pdev->dev,
+ "Don't know dma device ID for this SSP PCDID=3D%x\n=
",
+ pdev->device);
+ goto err_i2s_probe3;
+ }
+ /* in case the stop dma have to wait for end of callbacks */
+ /* This will be removed when TERMINATE_ALL available in DMA */
+ init_waitqueue_head(&drv_data->wq_chan_closing);
+ if (!drv_data->dmac1) {
+ dev_err(&(drv_data->pdev->dev), "Can't find DMAC1, dma init=
failed\n");
+ status =3D -ENODEV;
+ goto err_i2s_probe3;
+ }
+ /* increment ref count of pci device structure already done by */
+ /* pci_get_device. will do a pci_dev_put when exiting the module */
+ pci_set_drvdata(pdev, drv_data);
+ /* set SSP FrameSync and CLK direction in INPUT mode in order
+ * to avoid disturbing peripherals
+ */
+ write_SSCR1((SSCR1_SFRMDIR_MASK<<SSCR1_SFRMDIR_SHIFT)
+ | (SSCR1_SCLKDIR_MASK<<SSCR1_SCLKDIR_SHIFT),
+ drv_data->ioaddr);
+ /* Attach to IRQ */
+ drv_data->irq =3D pdev->irq;
+ dev_dbg(&(pdev->dev), "attaching to IRQ: %04x\n", pdev->irq);
+ status =3D request_irq(drv_data->irq, i2s_int, IRQF_SHARED, "i2s ss=
p", drv_data);
+ if (status < 0) {
+ dev_err(&pdev->dev, "can not get IRQ. status err=3D%d\n", s=
tatus);
+ goto err_i2s_probe3;
+ }
+ pm_runtime_enable(&(drv_data->pdev->dev));
+ goto leave;
+err_i2s_probe3:
+ iounmap(drv_data->ioaddr);
+err_i2s_probe2:
+ pci_release_region(pdev, MRST_SSP_BAR);
+err_i2s_probe1:
+ pci_disable_device(pdev);
+err_i2s_probe0:
+ kfree(drv_data);
+leave:
+ return status;
+}
+
+static void __devexit intel_mid_i2s_remove(struct pci_dev *pdev)
+{
+ struct intel_mid_i2s_hdl *drv_data;
+
+ drv_data =3D pci_get_drvdata(pdev);
+ if (!drv_data) {
+ dev_err(&pdev->dev, "no drv_data in pci device to remove!\n=
");
+ goto leave;
+ }
+ if (test_bit(I2S_PORT_OPENED, &drv_data->flags)) {
+ dev_warn(&pdev->dev, "Not closed before removing pci_dev!\n=
");
+ intel_mid_i2s_close(drv_data);
+ }
+ pci_set_drvdata(pdev, NULL);
+ /* Stop DMA is already done during close() */
+ pci_dev_put(drv_data->dmac1);
+ /* Disable the SSP at the peripheral and SOC level */
+ write_SSCR0(0, drv_data->ioaddr);
+ free_irq(drv_data->irq, drv_data);
+ iounmap(drv_data->ioaddr);
+ pci_release_region(pdev, MRST_SSP_BAR);
+ pci_release_region(pdev, MRST_LPE_BAR);
+ pci_disable_device(pdev);
+ kfree(drv_data);
+leave:
+ return;
+}
+
+/**
+ * intel_mid_i2s_init - register pci driver
+ *
+ */
+static int __init intel_mid_i2s_init(void)
+{
+ return pci_register_driver(&intel_mid_i2s_driver);
+}
+
+static void __exit intel_mid_i2s_exit(void)
+{
+ pci_unregister_driver(&intel_mid_i2s_driver);
+}
+
+
+module_init(intel_mid_i2s_init);
+module_exit(intel_mid_i2s_exit);
+
+
+
diff --git a/sound/pci/intel_mid_i2s/intel_mid_i2s.h b/sound/pci/intel_mid_=
i2s/intel_mid_i2s.h
new file mode 100644
index 0000000..ef29ce7
--- /dev/null
+++ b/sound/pci/intel_mid_i2s/intel_mid_i2s.h
@@ -0,0 +1,500 @@
+/*
+ * <Driver for I2S protocol on SSP (Moorestown and Medfield hardware)>
+ * Copyright (c) 2010, Intel Corporation.
+ * Louis LE GALL <louis.le.gall intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License =
for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License alon=
g with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#define DRIVER_NAME "I2S SSP Driver"
+/*
+ * Defines
+ */
+#define MFLD_SSP1_DEVICE_ID 0x0825 /* FOR MFLD */
+#define MRST_SSP0_DEVICE_ID 0x0815 /* FOR MRST */
+#define MFLD_SSP0_DEVICE_ID 0x0832 /* FOR MFLD */
+
+#define MRST_LPE_DMA_DEVICE_ID 0x0814
+#define MFLD_LPE_DMA_DEVICE_ID 0x0830
+
+/* SSP1 PCI device Base Address Register */
+#define MRST_SSP_BAR 0
+#define MRST_LPE_BAR 1
+#define DMA1C_DEVICE_INSTANCE_SSP0 0
+#define DMA1C_DEVICE_INSTANCE_SSP1 1
+#define OFFSET_SSCR0 0x00
+#define OFFSET_SSCR1 0x04
+#define OFFSET_SSSR 0x08
+#define OFFSET_SSITR 0x0c
+#define OFFSET_SSDR 0x10
+#define OFFSET_SSTO 0x28
+#define OFFSET_SSPSP 0x2c
+#define OFFSET_SSTSA 0x30 /* SSP Tx Timeslot Active */
+#define OFFSET_SSRSA 0x34 /* SSP Rx Timeslot Active */
+/* SST register map */
+#define OFFSET_LPE_CSR 0x00
+#define OFFSET_LPE_PISR 0x08
+#define OFFSET_LPE_PIMR 0x10
+#define OFFSET_LPE_ISRX 0x18
+#define OFFSET_LPE_IMRX 0x28
+#define OFFSET_LPE_IPCX 0x38 /* IPC IA-SST */
+#define OFFSET_LPE_IPCD 0x40 /* IPC SST-IA */
+#define OFFSET_LPE_ISRD 0x20 /* dummy register f=
or*/
+ /* shim workaround */
+#define OFFSET_LPE_SHIM_SIZE 0X44
+
+#define SSP_IN_MASTER_MODE 0x0
+#define SSP_IN_SLAVE_MODE 0x1
+
+/*
+ * Macros
+ */
+#define DEFINE_SSP_REG(reg, off) \
+static inline u32 read_##reg(void *p) { return __raw_readl(p + (off)); } \
+static inline void write_##reg(u32 v, void *p) { __raw_writel(v, p + (off)=
); }
+DEFINE_SSP_REG(SSCR0, 0x00)
+DEFINE_SSP_REG(SSCR1, 0x04)
+DEFINE_SSP_REG(SSSR, 0x08)
+DEFINE_SSP_REG(SSITR, 0x0c)
+DEFINE_SSP_REG(SSDR, 0x10)
+DEFINE_SSP_REG(SSTO, 0x28)
+DEFINE_SSP_REG(SSPSP, 0x2c)
+DEFINE_SSP_REG(SSTSA, 0x30)
+DEFINE_SSP_REG(SSRSA, 0x34)
+DEFINE_SSP_REG(SSTSS, 0x38)
+DEFINE_SSP_REG(SSACD, 0x3C)
+DEFINE_SSP_REG(I2CCTRL, 0x00);
+DEFINE_SSP_REG(I2CDATA, 0x04);
+/*
+ * Langwell SSP serial port register definitions
+ */
+#define SSCR0_DSS_MASK 0x0F /* Data Size Select [4..16] */
+#define SSCR0_DSS_SHIFT 0
+#define SSCR0_FRF_MASK 0x03 /* FRame Format */
+#define SSCR0_FRF_SHIFT 4
+#define SSCR0_ECS_MASK 0x01 /* External clock select */
+#define SSCR0_ECS_SHIFT 6
+#define SSCR0_SSE_MASK 0x01 /* Synchronous Serial Port Enable */
+#define SSCR0_SSE_SHIFT 7
+#define SSCR0_SCR_MASK 0xFFF /* Not implemented */
+#define SSCR0_SCR_SHIFT 8
+#define SSCR0_EDSS_MASK 0x1 /* Extended data size select */
+#define SSCR0_EDSS_SHIFT 20
+#define SSCR0_NCS_MASK 0x1 /* Network clock select */
+#define SSCR0_NCS_SHIFT 21
+#define SSCR0_RIM_MASK 0x1 /* Receive FIFO overrrun int mask */
+#define SSCR0_RIM_SHIFT 22
+#define SSCR0_TIM_MASK 0x1 /* Transmit FIFO underrun int mask */
+#define SSCR0_TIM_SHIFT 23
+#define SSCR0_FRDC_MASK 0x7 /* Frame Rate Divider Control */
+#define SSCR0_FRDC_SHIFT 24
+#define SSCR0_ACS_MASK 0x1 /* Audio clock select */
+#define SSCR0_ACS_SHIFT 30
+#define SSCR0_MOD_MASK 0x1 /* Mode (normal or network) */
+#define SSCR0_MOD_SHIFT 31
+
+#define SSCR0_DataSize(x) ((x) - 1) /* Data Size Select [4..16]=
*/
+#define SSCR0_SlotsPerFrm(x) ((x) - 1) /* Time slots per frame */
+#define SSCR0_SerClkDiv(x) ((x) - 1) /* Divisor [1..4096],... */
+ /*...not implemented on Langwell */
+#define SSCR1_TTELP_MASK 0x1 /* TXD Tristate Enable on Last Phas=
e */
+#define SSCR1_TTELP_SHIFT 31
+#define SSCR1_TTE_MASK 0x1 /* TXD Tristate Enable */
+#define SSCR1_TTE_SHIFT 30
+#define SSCR1_EBCEI_MASK 0x1 /* Enable Bit Count Error Interrupt=
*/
+#define SSCR1_EBCEI_SHIFT 29
+#define SSCR1_SCFR_MASK 0x1 /* Slave Clock Running */
+#define SSCR1_SCFR_SHIFT 28
+#define SSCR1_ECRA_MASK 0x1 /* Enable Clock Request A */
+#define SSCR1_ECRA_SHIFT 27
+#define SSCR1_ECRB_MASK 0x1 /* Enable Clock Request B */
+#define SSCR1_ECRB_SHIFT 26
+#define SSCR1_SCLKDIR_MASK 0x1 /* SSPCLK Direction */
+#define SSCR1_SCLKDIR_SHIFT 25
+#define SSCR1_SFRMDIR_MASK 0x1 /* SSPFRM Direction */
+#define SSCR1_SFRMDIR_SHIFT 24
+#define SSCR1_RWOT_MASK 0x1 /* Receive without Transmit */
+#define SSCR1_RWOT_SHIFT 23
+#define SSCR1_TRAIL_MASK 0x1 /* Trailing Byte */
+#define SSCR1_TRAIL_SHIFT 22
+#define SSCR1_TSRE_MASK 0x1 /* DMA Transmit Service Request Ena=
ble*/
+#define SSCR1_TSRE_SHIFT 21
+#define SSCR1_RSRE_MASK 0x1 /* DMA Receive Service Request Enab=
le */
+#define SSCR1_RSRE_SHIFT 20
+#define SSCR1_TINTE_MASK 0x1 /* Receiver Time-out Interrupt Enab=
le */
+#define SSCR1_TINTE_SHIFT 19
+#define SSCR1_PINTE_MASK 0x1 /* Periph. Trailing Byte Int. Enabl=
e */
+#define SSCR1_PINTE_SHIFT 18
+#define SSCR1_IFS_MASK 0x1 /* Invert Frame Signal */
+#define SSCR1_IFS_SHIFT 16
+#define SSCR1_STFR_MASK 0x1 /* Select FIFO for EFWR: test mode =
*/
+#define SSCR1_STFR_SHIFT 15
+#define SSCR1_EFWR_MASK 0x1 /* Enable FIFO Write/Read: test mod=
e */
+#define SSCR1_EFWR_SHIFT 14
+#define SSCR1_RFT_MASK 0xF /* Receive FIFO Trigger Threshold */
+#define SSCR1_RFT_SHIFT 10
+#define SSCR1_TFT_MASK 0xF /* Transmit FIFO Trigger Threshold =
*/
+#define SSCR1_TFT_SHIFT 6
+#define SSCR1_MWDS_MASK 0x1 /* Microwire Transmit Data Size */
+#define SSCR1_MWDS_SHIFT 5
+#define SSCR1_SPH_MASK 0x1 /* Motorola SPI SSPSCLK phase setti=
ng */
+#define SSCR1_SPH_SHIFT 4
+#define SSCR1_SPO_MASK 0x1 /* Motorola SPI SSPSCLK polarity */
+#define SSCR1_SPO_SHIFT 3
+#define SSCR1_LBM_MASK 0x1 /* Loopback mode: test mode */
+#define SSCR1_LBM_SHIFT 2
+#define SSCR1_TIE_MASK 0x1 /* Transmit FIFO Interrupt Enable */
+#define SSCR1_TIE_SHIFT 1
+#define SSCR1_RIE_MASK 0x1 /* Receive FIFO Interrupt Enable */
+#define SSCR1_RIE_SHIFT 0
+
+#define SSCR1_RxTresh(x) ((x) - 1) /* level [1..16] */
+#define SSCR1_TxTresh(x) ((x) - 1) /* level [1..16] */
+
+#define SSPSP_FSRT_MASK 0x1 /* Frame Sync Relative Timing Bit */
+#define SSPSP_FSRT_SHIFT 25
+#define SSPSP_DMYSTOP_MASK 0x3 /* Dummy Stop in Number of SSPSCLKs=
:T4*/
+#define SSPSP_DMYSTOP_SHIFT 23
+#define SSPSP_SFRMWDTH_MASK 0x3F /* Serial Frame width : T6 */
+#define SSPSP_SFRMWDTH_SHIFT 16
+#define SSPSP_SFRMDLY_MASK 0x7F /* Serial Fr. Delay in 1/2SSPSCLKs:=
T5 */
+#define SSPSP_SFRMDLY_SHIFT 9
+#define SSPSP_DMYSTRT_MASK 0x3 /* Dummy Start in Number of SSPSCLK=
s..*/
+#define SSPSP_DMYSTRT_SHIFT 7 /*...after STRTDLY, T2 (master mode onl=
y) */
+#define SSPSP_STRTDLY_MASK 0x7 /* Start Delay, T1 (master mode onl=
y) */
+#define SSPSP_STRTDLY_SHIFT 4
+#define SSPSP_ETDS_MASK 0x1 /* End of Transfer Data State */
+#define SSPSP_ETDS_SHIFT 3
+#define SSPSP_SFRMP_MASK 0x1 /* Serial Frame Polarity */
+#define SSPSP_SFRMP_SHIFT 2
+#define SSPSP_SCMODE_MASK 0x3 /* Serial bit-rate Clock Mode */
+#define SSPSP_SCMODE_SHIFT 0
+
+#define SSTSA_TTSA_MASK 0xFF
+#define SSTSA_TTSA_SHIFT 0
+
+#define SSRSA_RTSA_MASK 0xFF
+#define SSRSA_RTSA_SHIFT 0
+
+#define SSSR_BCE_MASK 0x1 /* Bit Count Error: Read/Write 1 to Clear */
+#define SSSR_BCE_SHIFT 23
+#define SSSR_CSS_MASK 0x1 /* Clock Synchronization Status */
+#define SSSR_CSS_SHIFT 22
+#define SSSR_TUR_MASK 0x1 /* Transmit FIFO UnderRun: Rd/Wr 1 to Clear=
*/
+#define SSSR_TUR_SHIFT 21
+#define SSSR_EOC_MASK 0x1 /* End Of Chain: Read/Write 1 to Clear */
+#define SSSR_EOC_SHIFT 20
+#define SSSR_TINT_MASK 0x1 /* Receiver Time-out Interrupt:... */
+#define SSSR_TINT_SHIFT 19 /* ...Read/Write 1 to Clear */
+#define SSSR_PINT_MASK 0x1 /* Peripheral Trailing Byte Interrupt:... */
+#define SSSR_PINT_SHIFT 18 /* ...Read/Write 1 to Clear */
+#define SSSR_RFL_MASK 0xF /* Receive FIFO Level */
+#define SSSR_RFL_SHIFT 12
+#define SSSR_TFL_MASK 0xF /* Transmit FIFO Level */
+#define SSSR_TFL_SHIFT 8
+#define SSSR_ROR_MASK 0x1 /* Receive FIFO Overrun: Read/Write 1 to Cl=
ear*/
+#define SSSR_ROR_SHIFT 7
+#define SSSR_RFS_MASK 0x1 /* Receive FIFO Service Request */
+#define SSSR_RFS_SHIFT 6
+#define SSSR_TFS_MASK 0x1 /* Transmit FIFO Service Request */
+#define SSSR_TFS_SHIFT 5
+#define SSSR_BSY_MASK 0x1 /* SSP Busy */
+#define SSSR_BSY_SHIFT 4
+#define SSSR_RNE_MASK 0x1 /* Receive FIFO not empty */
+#define SSSR_RNE_SHIFT 3
+#define SSSR_TFN_MASK 0x1 /* Transmit FIFO not Full */
+#define SSSR_TFN_SHIFT 2
+
+
+#define SSP_OFF 0
+#define SSP_ON 1
+
+/* bit I2S_PORT_OPENED lock for open/close
+ * bit I2S_PORT_READ_BUSY lock for read requests (serialized)
+ * bit I2S_PORT_WRITE_BUSY lock for write requests (serialized)
+ * bit I2S_PORT_CLOSING means close on going, waiting for pending callback=
s.
+ */
+
+enum i2s_flags {
+ I2S_PORT_OPENED,
+ I2S_PORT_WRITE_BUSY,
+ I2S_PORT_READ_BUSY,
+ I2S_PORT_CLOSING
+};
+
+#define FIFO_SIZE 16
+/*
+ * Structures Definition
+ */
+
+/**
+ * struct intel_mid_i2s_data - context struct to keep SSP I2S data
+ * @pdev: pci dev pointer corresponding to context
+ * @paddr:
+ * @ioaddr:
+ * @iolen:
+ * @irq:
+ * @clear_sr:
+ * @mask_sr:
+ * @dmac1:
+ * @dmas_tx: dma slave structure for transmit
+ * @dmas_rx: dma slave structure for receive
+ * @txchan: Dma channel for transmit
+ * @rxchan: Dma channel for receive
+ *
+ * @read_done:
+ * @read_dst:
+ * @read_len:
+ *
+ * @write_done:
+ * @write_src:
+ * @write_len:
+ *
+ * @mutex: a mutex to make sure we have once-at-time critical functions.
+ *
+ * Longer description
+ */
+
+/* Locking rules:
+ *
+ * All the fields, not listed below, are set during probe, and then read o=
nly
+ * So they do not require locking
+ *
+ * The fields that require locking are related to the I2S read and write
+ * requests.
+ *
+ * We allow only 1 read at a time, and 1 write at a time.
+ * We allow read in parallel of write but use separate variables.
+ * We allow only 1 user per SSP/I2S port.
+ * Typically this user will be a dedicated PulseAudio RT thread communicat=
ing
+ * with cmt-speech driver which in turns communicates with intel_mid_ssp
+ * driver.
+ * PCM mixing is done before access to kernel drivers;typically within
+ * PulseAudio or after; typically within the modem.
+ * So no concurrent users, per I2S channel, to this driver are allowed
+ * The read & write are triggered from a USER context
+ * The read & write callbacks are called from a BH context
+ * You should have not callback pending before calling close, close will w=
ait
+ * for remaining callback calls.
+ * It is not allowed to call close function from read/write callback threa=
ds.
+ *
+ * Locking is handled via drv_data->flags & atomic bitwise operations
+ *
+ * I2S0 is dedicated for PCM transfer to/from the modem module
+ * I2S1 is dedicated for PCM transfer to/from the Bluetooth or FM module
+ *
+ * read_done:
+ * read_len:
+ * read_dst:
+ *
+ * write_done:
+ * write_src:
+ * write_len:
+ *
+ * mutex: a mutex to make sure we have once-at-time critical functions.
+ * once-at-a-time actions functions are:
+ * -intel_mid_i2s_open
+ * -intel_mid_i2s_close
+ * -intel_mid_i2s_rd_req
+ * -intel_mid_i2s_wr_req
+ * -intel_mid_i2s_set_rd_cb
+ * -intel_mid_i2s_set_wr_cb
+ * These functions should not be called during a lock() neither in interru=
pt.
+ */
+
+struct intel_mid_i2s_hdl {
+ /* Driver model hookup */
+ struct pci_dev *pdev;
+ /* register addresses */
+ dma_addr_t paddr;
+ void __iomem *ioaddr;
+ u32 iolen;
+ int irq;
+
+ /* SSP masks */
+ u32 clear_sr;
+ u32 mask_sr;
+
+ /* SSP Configuration */
+ /* DMA info */
+ struct pci_dev *dmac1;
+ wait_queue_head_t wq_chan_closing;
+
+ struct intel_mid_dma_slave dmas_tx;
+ struct intel_mid_dma_slave dmas_rx;
+ struct dma_chan *txchan;
+ struct dma_chan *rxchan;
+
+ unsigned int device_instance;
+ /* Call back functions */
+ int (*read_callback)(void *param);
+ dma_addr_t read_dst;
+ size_t read_len; /* read_len > 0 <=3D> read_dma_running */
+ void *read_param; /* context param for callback */
+ int (*write_callback)(void *param);
+ dma_addr_t write_src;
+ size_t write_len; /* write_len > 0 <=3D> read_dma_running */
+ void *write_param; /* context param for callback */
+
+ unsigned long flags;
+ struct mutex mutex;
+ enum intel_mid_i2s_ssp_usage usage;
+
+ struct intel_mid_i2s_settings current_settings;
+
+};
+
+static void i2s_read_done(void *arg);
+static void i2s_write_done(void *arg);
+static bool chan_filter(struct dma_chan *chan, void *param);
+static void i2s_dma_stop(struct intel_mid_i2s_hdl *drv_data);
+static int i2s_dma_start(struct intel_mid_i2s_hdl *drv_data);
+static void ssp1_dump_registers(struct intel_mid_i2s_hdl *);
+static irqreturn_t i2s_int(int irq, void *dev_id);
+static void set_ssp_i2s_hw(struct intel_mid_i2s_hdl *drv_data,
+ const struct intel_mid_i2s_settings *ps_settings);
+static int check_device(struct device *device_ptr, void *data);
+static int intel_mid_i2s_runtime_resume(struct device *device_ptr);
+static int intel_mid_i2s_runtime_suspend(struct device *device_ptr);
+static int intel_mid_i2s_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent);
+static void intel_mid_i2s_remove(struct pci_dev *pdev);
+static void i2s_ssp_stop(struct intel_mid_i2s_hdl *drv_data);
+/*static int bt_pcm_dma_init(struct intel_mid_i2s_hdl *drv_data);*/
+
+
+#ifdef CONFIG_PM
+static int intel_mid_i2s_driver_suspend(struct pci_dev *dev,
+ pm_message_t state);
+static int intel_mid_i2s_driver_resume(struct pci_dev *dev);
+#endif
+
+/*
+ * These define will clarify source code when accessing SSCRx registers
+ */
+
+#define SSCR0_reg(regbit, value) \
+ (((value) & SSCR0_##regbit##_MASK) << SSCR0_##regbit##_SHIFT)
+
+#define SSCR1_reg(regbit, value) \
+ (((value) & SSCR1_##regbit##_MASK) << SSCR1_##regbit##_SHIFT)
+
+#define SSPSP_reg(regbit, value) \
+ (((value) & SSPSP_##regbit##_MASK) << SSPSP_##regbit##_SHIFT)
+
+#define SSRSA_reg(regbit, value) \
+ (((value) & SSRSA_##regbit##_MASK) << SSRSA_##regbit##_SHIFT)
+#define SSTSA_reg(regbit, value) \
+ (((value) & SSTSA_##regbit##_MASK) << SSTSA_##regbit##_SHIFT)
+
+
+#define change_SSCR0_reg(reg_pointer, regbit, value) \
+ write_SSCR0((read_SSCR0(reg_pointer) \
+ & (~((SSCR0_##regbit##_MASK << SSCR0_##regbit##_SHIFT)))) \
+ | (((value) & SSCR0_##regbit##_MASK) << SSCR0_##regbit##_SHIFT), \
+ reg_pointer);
+
+#define set_SSCR0_reg(reg_pointer, regbit) \
+ write_SSCR0(read_SSCR0(reg_pointer) \
+ | (SSCR0_##regbit##_MASK << SSCR0_##regbit##_SHIFT), \
+ reg_pointer);
+
+#define clear_SSCR0_reg(reg_pointer, regbit) \
+ write_SSCR0((read_SSCR0(reg_pointer) \
+ & (~((SSCR0_##regbit##_MASK << SSCR0_##regbit##_SHIFT)))), \
+ reg_pointer);
+
+#define change_SSCR1_reg(reg_pointer, regbit, value) \
+ write_SSCR1((read_SSCR1(reg_pointer) \
+ & (~((SSCR1_##regbit##_MASK << SSCR1_##regbit##_SHIFT)))) \
+ | (((value) & SSCR1_##regbit##_MASK) << SSCR1_##regbit##_SHIFT), \
+ reg_pointer);
+
+#define set_SSCR1_reg(reg_pointer, regbit) \
+ write_SSCR1(read_SSCR1(reg_pointer) \
+ | (SSCR1_##regbit##_MASK << SSCR1_##regbit##_SHIFT), \
+ reg_pointer);
+
+#define clear_SSCR1_reg(reg_pointer, regbit) \
+ write_SSCR1((read_SSCR1(reg_pointer) \
+ & (~((SSCR1_##regbit##_MASK << SSCR1_##regbit##_SHIFT)))), \
+ reg_pointer);
+
+/* RX FIFO level */
+#define GET_SSSR_val(x, regb) \
+ ((x & (SSSR_##regb##_MASK<<SSSR_##regb##_SHIFT))>>SSSR_##regb##_SHI=
FT)
+
+
+/*
+ * SSP hardware can be configured as I2S, PCM, SPI...
+ * In order to allow flexibility without modifying the software driver, the
+ * PCI header uses the configuration register 'adid':
+ *
+ * The PCI header associated to SSP devices includes a configuration regis=
ter.
+ * It provides information to a driver which is probed for the SSP, specif=
ying
+ * in which way the SSP is supposed to be used.
+ * Here is the format of this configuration register (8 bits):
+ *
+ * bits 2..0: Mode
+ * 000: Invalid, the register should be ignored
+ * 001: SSP to be used as SPI controller
+ * 010: SSP to be used in I2S/ISS mode
+ * other: Reserved
+ *
+ * bits 5..3: Configuration
+ * In I2S/ISS mode:
+ * 000: Invalid
+ * 001: Bluetooth
+ * 010: Modem
+ * other: Reserved
+ * In SPI mode:
+ * Value is the SPI bus number connected to the SSP.
+ * To be used for registration to the Linux SPI
+ * framework.
+ *
+ * bit 6: SPI slave
+ * Relevant in SPI mode only. If set, indicates the SPI clock
+ * is not provided by the SSP: SPI slave mode.
+ *
+ * bit 7: Reserved (0)
+ *
+ * This configuration register is implemented in the adid field of the
+ * Vendor Specific PCI capability associated to the SSP. The format of
+ * this capability is:
+ *
+ * uint8_t capId; < Capability ID (vendor-specific)
+ * uint8_t nextCap; < Next Item Ptr
+ * uint8_t length; < Size of this capability (7)
+ * uint8_t version; < Version of this capability (1)
+ * uint8_t lss; < Logical subsystem info
+ * Bit 7 =3D PMU (0 =3D NC, 1 =3D =
SC)
+ * Bits 6:0 =3D LSS ID
+ * uint8_t apmc; < Additional PM capabilities
+ * Bit 7 =3D Rsvd
+ * Bit 6 =3D Wake capable
+ * Bit 5 =3D D3 support
+ * Bit 4 =3D D2 support
+ * Bit 3 =3D D1 support
+ * Bit 2 =3D D0i3 support
+ * Bit 1 =3D D0i2 support
+ * Bit 0 =3D D0i1 support
+ * uint8_t adid; < Additional device ID (dev-specific)
+ * uint8_t rsvd; < Reserved for future use
+ *
+ * The capability data are in the PCI configuration space and the
+ * adid field can be modified using BMP tool.
+ */
+/* ADDID =3D Additional Device ID */
+#define PCI_CAP_OFFSET_ADID 6
+
+
--
1.6.6.1
---------------------------------------------------------------------
Intel Corporation SAS (French simplified joint stock company)
Registered headquarters: "Les Montalets"- 2, rue de Paris,=20
92196 Meudon Cedex, France
Registration Number: 302 456 199 R.C.S. NANTERRE
Capital: 4,572,000 Euros
This e-mail and any attachments may contain confidential material for
the sole use of the intended recipient(s). Any review or distribution
by others is strictly prohibited. If you are not the intended
recipient, please contact the sender and delete all copies.
--_002_2A84145621092446B6659B8A0F28E26F46FE77084Airsmsx501gerc_
Content-Type: application/octet-stream;
name="0001-New-low-level-driver-Intel_mid_i2s-provide-support-alsa.patch"
Content-Description: 0001-New-low-level-driver-Intel_mid_i2s-provide-support-alsa.patch
Content-Disposition: attachment; filename=
"0001-New-low-level-driver-Intel_mid_i2s-provide-support-alsa.patch";
size=77099; creation-date="Fri, 15 Oct 2010 16:02:59 GMT";
modification-date="Fri, 15 Oct 2010 14:45:31 GMT"
Content-Transfer-Encoding: base64
RnJvbSAxNmRhM2ViZmZhZDAyNmU0NGQ3NDUzOGI3NzczYTUxMDQ0MjU0OTIwIE1vbiBTZXAgMTcg
MDA6MDA6MDAgMjAwMQpGcm9tOiBMb3VpcyBMRSBHQUxMIDxsb3Vpcy5sZS5nYWxsQGludGVsLmNv
bT4KRGF0ZTogRnJpLCAxNSBPY3QgMjAxMCAxNTozMDo0OSArMDIwMApTdWJqZWN0OiBbUEFUQ0hd
IE5ldyBsb3cgbGV2ZWwgZHJpdmVyICJJbnRlbF9taWRfaTJzIiBwcm92aWRlIHN1cHBvcnQgZm9y
IEkyUyBTU1AgZGV2aWNlIG9uIEludGVsIE1JRCBQbGF0Zm9ybXMKIFNpZ25lZC1vZmYtYnk6IExv
dWlzIExFIEdBTEwgPGxvdWlzLmxlLmdhbGxAaW50ZWwuY29tPgoKQ2hhbmdlLUlkOiBJMTcwNTJh
M2I0NjRjNTY4MmQyYWIxN2E5YjZlMGZhZDMwMTM3MjQzZgoKU2lnbmVkLW9mZi1ieTogTG91aXMg
TEUgR0FMTCA8bG91aXMubGUuZ2FsbEBpbnRlbC5jb20+Ci0tLQogaW5jbHVkZS9saW51eC9pbnRl
bF9taWRfaTJzX2lmLmggICAgICAgIHwgIDI4MCArKysrKysKIHNvdW5kL3BjaS9LY29uZmlnICAg
ICAgICAgICAgICAgICAgICAgICB8ICAgMTggKwogc291bmQvcGNpL01ha2VmaWxlICAgICAgICAg
ICAgICAgICAgICAgIHwgICAgNCArLQogc291bmQvcGNpL2ludGVsX21pZF9pMnMvTWFrZWZpbGUg
ICAgICAgIHwgICAxOCArCiBzb3VuZC9wY2kvaW50ZWxfbWlkX2kycy9pbnRlbF9taWRfaTJzLmMg
fCAxNDI4ICsrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysKIHNvdW5kL3BjaS9pbnRlbF9t
aWRfaTJzL2ludGVsX21pZF9pMnMuaCB8ICA1MDAgKysrKysrKysrKysKIDYgZmlsZXMgY2hhbmdl
ZCwgMjI0NyBpbnNlcnRpb25zKCspLCAxIGRlbGV0aW9ucygtKQogY3JlYXRlIG1vZGUgMTAwNjQ0
IGluY2x1ZGUvbGludXgvaW50ZWxfbWlkX2kyc19pZi5oCiBjcmVhdGUgbW9kZSAxMDA2NDQgc291
bmQvcGNpL2ludGVsX21pZF9pMnMvTWFrZWZpbGUKIGNyZWF0ZSBtb2RlIDEwMDY0NCBzb3VuZC9w
Y2kvaW50ZWxfbWlkX2kycy9pbnRlbF9taWRfaTJzLmMKIGNyZWF0ZSBtb2RlIDEwMDY0NCBzb3Vu
ZC9wY2kvaW50ZWxfbWlkX2kycy9pbnRlbF9taWRfaTJzLmgKCmRpZmYgLS1naXQgYS9pbmNsdWRl
L2xpbnV4L2ludGVsX21pZF9pMnNfaWYuaCBiL2luY2x1ZGUvbGludXgvaW50ZWxfbWlkX2kyc19p
Zi5oCm5ldyBmaWxlIG1vZGUgMTAwNjQ0CmluZGV4IDAwMDAwMDAuLjE1NjM1NzcKLS0tIC9kZXYv
bnVsbAorKysgYi9pbmNsdWRlL2xpbnV4L2ludGVsX21pZF9pMnNfaWYuaApAQCAtMCwwICsxLDI4
MCBAQAorLyoKKyAgKiA8RHJpdmVyIGZvciBJMlMgcHJvdG9jb2wgb24gU1NQIChNb29yZXN0b3du
IGFuZCBNZWRmaWVsZCBoYXJkd2FyZSk+CisgICogQ29weXJpZ2h0IChjKSAyMDEwLCBJbnRlbCBD
b3Jwb3JhdGlvbi4KKyAgKiBMb3VpcyBMRSBHQUxMIDxsb3Vpcy5sZS5nYWxsIGludGVsLmNvbT4K
KyAgKgorICAqIFRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOyB5b3UgY2FuIHJlZGlzdHJp
YnV0ZSBpdCBhbmQvb3IgbW9kaWZ5IGl0CisgICogdW5kZXIgdGhlIHRlcm1zIGFuZCBjb25kaXRp
b25zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSwKKyAgKiB2ZXJzaW9uIDIsIGFz
IHB1Ymxpc2hlZCBieSB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLgorICAqCisgICogVGhp
cyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIGl0IHdpbGwgYmUgdXNlZnVsLCBi
dXQgV0lUSE9VVAorICAqIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdh
cnJhbnR5IG9mIE1FUkNIQU5UQUJJTElUWSBvcgorICAqIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxB
UiBQVVJQT1NFLiAgU2VlIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IKKyAgKiBt
b3JlIGRldGFpbHMuCisgICoKKyAgKiBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9m
IHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhbG9uZyB3aXRoCisgICogdGhpcyBwcm9n
cmFtOyBpZiBub3QsIHdyaXRlIHRvIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIEluYy4s
CisgICogNTEgRnJhbmtsaW4gU3QgLSBGaWZ0aCBGbG9vciwgQm9zdG9uLCBNQSAwMjExMC0xMzAx
IFVTQS4KKyAgKi8KKworI2lmbmRlZiBNSURfSTJTX0VYVEVSTkFMX0hfCisjZGVmaW5lIE1JRF9J
MlNfRVhURVJOQUxfSF8KKworI2luY2x1ZGUgPGxpbnV4L3BjaS5oPgorI2luY2x1ZGUgPGxpbnV4
L2RtYS1tYXBwaW5nLmg+CisjaW5jbHVkZSA8bGludXgvaW50ZWxfbWlkX2RtYS5oPgorCisjaW5j
bHVkZSA8bGludXgvaW50ZXJydXB0Lmg+CisKKy8qCisgKglTdHJ1Y3R1cmVzIERlZmluaXRpb24K
KyAqLworCisKKy8qCisgKglTU0NSMCBzZXR0aW5ncworICovCitlbnVtIG1yc3Rfc3NwX21vZGUg
eworCVNTUF9JTl9OT1JNQUxfTU9ERSA9IDB4MCwKKwlTU1BfSU5fTkVUV09SS19NT0RFCit9Owor
CitlbnVtIG1yc3Rfc3NwX3J4X2ZpZm9fb3Zlcl9ydW5faW50X21hc2sgeworCVNTUF9SWF9GSUZP
X09WRVJfSU5UX0VOQUJMRSA9IDB4MCwKKwlTU1BfUlhfRklGT19PVkVSX0lOVF9ESVNBQkxFCit9
OworCitlbnVtIG1yc3Rfc3NwX3R4X2ZpZm9fdW5kZXJfcnVuX2ludF9tYXNrIHsKKwlTU1BfVFhf
RklGT19VTkRFUl9JTlRfRU5BQkxFID0gMHgwLAorCVNTUF9UWF9GSUZPX1VOREVSX0lOVF9ESVNB
QkxFCit9OworCitlbnVtIG1yc3Rfc3NwX2ZyYW1lX2Zvcm1hdCB7CisJTU9UT1JPTEFfU1BJX0ZP
Uk1BVCA9IDB4MCwKKwlUSV9TU1BfRk9STUFULAorCU1JQ1JPV0lSRV9GT1JNQVQsCisJUFNQX0ZP
Uk1BVAorCit9OworCitlbnVtIG1yc3Rfc3NwX21hc3Rlcl9tb2RlX2Nsb2NrX3NlbGVjdGlvbiB7
CisJU1NQX09OQ0hJUF9DTE9DSyA9IDB4MCwKKwlTU1BfTkVUV09SS19DTE9DSywKKwlTU1BfRVhU
RVJOQUxfQ0xPQ0ssCisJU1NQX09OQ0hJUF9BVURJT19DTE9DSywKKwlTU1BfTUFTVEVSX0NMT0NL
X1VOREVGSU5FRCA9IDB4RkYKK307CisKKy8qCisgKglTU0NSMSBzZXR0aW5ncworICovCitlbnVt
IG1yc3Rfc3NwX3R4ZF90cmlzdGF0ZV9sYXN0X3BoYXNlIHsKKwlUWERfVFJJU1RBVEVfTEFTVF9Q
SEFTRV9PRkYgPSAgMHgwLAorCVRYRF9UUklTVEFURV9MQVNUX1BIQVNFX09OCit9OworCitlbnVt
IG1yc3Rfc3NwX3R4ZF90cmlzdGF0ZV9lbmFibGUgeworCVRYRF9UUklTVEFURV9PRkYgPSAgMHgw
LAorCVRYRF9UUklTVEFURV9PTgorfTsKKworZW51bSBtcnN0X3NzcF9zbGF2ZV9zc3BjbGtfZnJl
ZV9ydW5uaW5nIHsKKwlTTEFWRV9TU1BDTEtfT05fQUxXQVlTID0gIDB4MCwKKwlTTEFWRV9TU1BD
TEtfT05fRFVSSU5HX1RSQU5TRkVSX09OTFkKK307CisKK2VudW0gbXJzdF9zc3Bfc3Nwc2Nsa19k
aXJlY3Rpb24geworCVNTUFNDTEtfTUFTVEVSX01PREUgPSAweDAsCisJU1NQU0NMS19TTEFWRV9N
T0RFCit9OworCitlbnVtIG1yc3Rfc3NwX3NzcHNmcm1fZGlyZWN0aW9uIHsKKwlTU1BTRlJNX01B
U1RFUl9NT0RFID0gMHgwLAorCVNTUFNGUk1fU0xBVkVfTU9ERQorfTsKKworZW51bSBtcnN0X3Nz
cF9yeF93aXRob3V0X3R4IHsKKwlSWF9BTkRfVFhfTU9ERSA9IDB4MCwKKwlSWF9XSVRIT1VUX1RY
X01PREUKK307CisKK2VudW0gbXJzdF90cmFpbGluZ19ieXRlX21vZGUgeworCVNTUF9UUkFJTElO
R19CWVRFX0hETF9CWV9JQSA9IDB4MCwKKwlTU1BfVFJBSUxJTkdfQllURV9IRExfQllfRE1BCit9
OworCitlbnVtIG1yc3Rfc3NwX3R4X2RtYV9zdGF0dXMgeworCVNTUF9UWF9ETUFfTUFTSyA9IDB4
MCwKKwlTU1BfVFhfRE1BX0VOQUJMRQorfTsKKworZW51bSBtcnN0X3NzcF9yeF9kbWFfc3RhdHVz
IHsKKwlTU1BfUlhfRE1BX01BU0sgPSAweDAsCisJU1NQX1JYX0RNQV9FTkFCTEUKK307CisKK2Vu
dW0gbXJzdF9zc3BfcnhfdGltZW91dF9pbnRfc3RhdHVzIHsKKwlTU1BfUlhfVElNRU9VVF9JTlRf
RElTQUJMRSA9IDB4MCwKKwlTU1BfUlhfVElNRU9VVF9JTlRfRU5BQkxFCit9OworCitlbnVtIG1y
c3Rfc3NwX3RyYWlsaW5nX2J5dGVfaW50X3N0YXR1cyB7CisJU1NQX1RSQUlMSU5HX0JZVEVfSU5U
X0RJU0FCTEUgPSAweDAsCisJU1NQX1RSQUlMSU5HX0JZVEVfSU5UX0VOQUJMRQorfTsKKworZW51
bSBtcnN0X3NzcF9sb29wYmFja19tb2RlX3N0YXR1cyB7CisJU1NQX0xPT1BCQUNLX09GRiA9IDB4
MCwKKwlTU1BfTE9PUEJBQ0tfT04KK307CisKKworLyoKKyAqCVNTUFNQIHNldHRpbmdzOiBmb3Ig
UFNQIEZvcm1hdCBPTkxZISEhISEhISEKKyAqLworCitlbnVtIG1yc3Rfc3NwX2ZyYW1lX3N5bmNf
cmVsYXRpdmVfdGltaW5nX2JpdCB7CisJTkVYVF9GUk1TX0FTU19BRlRFUl9FTkRfT0ZfVDQgPSAg
MHgwLAorCU5FWFRfRlJNU19BU1NfV0lUSF9MU0JfUFJFVklPVVNfRlJNCit9OworCitlbnVtIG1y
c3Rfc3NwX2ZyYW1lX3N5bmNfcG9sYXJpdHlfYml0IHsKKwlTU1BfRlJNU19BQ1RJVkVfTE9XID0g
IDB4MCwKKwlTU1BfRlJNU19BQ1RJVkVfSElHSAorfTsKKworZW51bSBtcnN0X3NzcF9lbmRfb2Zf
dHJhbnNmZXJfZGF0YV9zdGF0ZSB7CisJU1NQX0VORF9EQVRBX1RSQU5TRkVSX1NUQVRFX0xPVyA9
IDB4MCwKKwlTU1BfRU5EX0RBVEFfVFJBTlNGRVJfU1RBVEVfUEVWSU9VU19CSVQKK307CisKK2Vu
dW0gbXJzdF9zc3BfY2xrX21vZGUgeworCVNTUF9DTEtfTU9ERV8wID0gMHgwLAorCVNTUF9DTEtf
TU9ERV8xLAorCVNTUF9DTEtfTU9ERV8yLAorCVNTUF9DTEtfTU9ERV8zCit9OworCisKKy8qCisg
KglsaXN0IG9mIGRpZmZlcmVudHMgdHlwZXMgb2YgU1NQLCB2YWx1ZSBkZXBlbmRzIG9mIGFkaWQg
ZW50cnkgb2YKKyAqCWNhcGFiaWxpdHkgSUQgb2YgdGhlIFBDSQorICovCisKKy8qCisgKgorICog
VGhlIFBDSSBoZWFkZXIgYXNzb2NpYXRlZCB0byBTU1AgZGV2aWNlcyBub3cgaW5jbHVkZXMgYSBj
b25maWd1cmF0aW9uCisgKiByZWdpc3Rlci4gSXQgcHJvdmlkZXMgaW5mb3JtYXRpb24gdG8gYSBk
cml2ZXIgd2hpY2ggaXMgcHJvYmVkIGZvciB0aGUKKyAqIFNTUCwgc3BlY2lmeWluZyBpbiB3aGlj
aCB3YXkgdGhlIFNTUCBpcyBzdXBwb3NlZCB0byBiZSB1c2VkLiBIZXJlIGlzCisgKiB0aGUgZm9y
bWF0IG9mIHRoaXMgYnl0ZSByZWdpc3RlcjoKKyAqCisgKgliaXRzIDIuLjA6IE1vZGUKKyAqCQkw
MDA9MHgwIDogSW52YWxpZCwgdGhlIHJlZ2lzdGVyIHNob3VsZCBiZSBpZ25vcmVkCisgKgkJMDAx
PTB4MSA6IFNTUCB0byBiZSB1c2VkIGFzIFNQSSBjb250cm9sbGVyCisgKgkJMDEwPTB4MjogU1NQ
IHRvIGJlIHVzZWQgaW4gSTJTL0lTUyBtb2RlCisgKgkJb3RoZXI6IFJlc2VydmVkCisgKgorICoJ
Yml0cyA1Li4zOiBDb25maWd1cmF0aW9uCisgKglJbiBJMlMvSVNTIG1vZGU6CisgKgkJMDAwPTB4
MDogSW52YWxpZAorICoJCTAwMT0weDE6IEJsdWV0b290aAorICoJCTAxMD0weDI6IE1vZGVtCisg
KgkJb3RoZXI6IFJlc2VydmVkCisgKglJbiBTUEkgbW9kZToKKyAqCQlWYWx1ZSBpcyB0aGUgU1BJ
IGJ1cyBudW1iZXIgY29ubmVjdGVkIHRvIHRoZSBTU1AuCisgKgkJVG8gYmUgdXNlZCBmb3IgcmVn
aXN0cmF0aW9uIHRvIHRoZSBMaW51eCBTUEkKKyAqCQlmcmFtZXdvcmsuCisgKgliaXQgNjogU1BJ
IHNsYXZlCisgKglSZWxldmFudCBpbiBTUEkgbW9kZSBvbmx5LiBJZiBzZXQsIGluZGljYXRlcyB0
aGUgU1BJIGNsb2NrCisgKglpcyBub3QgcHJvdmlkZWQgYnkgdGhlIFNTUDogU1BJIHNsYXZlIG1v
ZGUuCisgKgorICoJYml0IDc6IFJlc2VydmVkICgwKQorICoKKyAqIFRoaXMgY29uZmlndXJhdGlv
biByZWdpc3RlciBpcyBpbXBsZW1lbnRlZCBpbiB0aGUgYWRpZCBmaWVsZCBvZiB0aGUKKyAqIFZl
bmRvciBTcGVjaWZpYyBQQ0kgY2FwYWJpbGl0eSBhc3NvY2lhdGVkIHRvIHRoZSBTU1AuCisgKgor
ICovCisKKyNkZWZpbmUgUENJX0FESURfU1NQX01PREVfU1BJICAoMSkKKyNkZWZpbmUgUENJX0FE
SURfU1NQX01PREVfSTJTICAoMikKKworI2RlZmluZSBQQ0lfQURJRF9TU1BfQ09ORl9CVF9GTSAg
KDE8PDMpCisjZGVmaW5lIFBDSV9BRElEX1NTUF9DT05GX01PREVNICAoMjw8MykKKworCisjZGVm
aW5lIFBDSV9DQVBfQURJRF9JMlNfQlRfRk0gICgoUENJX0FESURfU1NQX0NPTkZfQlRfRk0pIHwg
KFBDSV9BRElEX1NTUF9NT0RFX0kyUykpCisjZGVmaW5lIFBDSV9DQVBfQURJRF9JMlNfTU9ERU0g
ICgoUENJX0FESURfU1NQX0NPTkZfTU9ERU0pIHwgKFBDSV9BRElEX1NTUF9NT0RFX0kyUykpCisK
K2VudW0gaW50ZWxfbWlkX2kyc19zc3BfdXNhZ2UgeworCVNTUF9VU0FHRV9VTkFTU0lHTkVEID0g
MHgwMCwKKwlTU1BfVVNBR0VfQkxVRVRPT1RIX0ZNID0gMHgwMSwKKwlTU1BfVVNBR0VfTU9ERU0g
PSAweDAyCit9OworCisvKgorICoJU3RydWN0dXJlIHVzZWQgdG8gY29uZmlndXJlIHRoZSBTU1Ag
UG9ydAorICoJUGxlYXNlIG5vdGUgdGhhdCBvbmx5IHRoZSBQU1AgZm9ybWF0IGFuZCB0aGUgRE1B
IHRyYW5zZmVyIGFyZSBzdXBwb3J0ZWQKKyAqLworCitzdHJ1Y3QgaW50ZWxfbWlkX2kyc19zZXR0
aW5ncyB7CisJZW51bSBtcnN0X3NzcF9tb2RlICAgICAgICAgICAgICAgICAgICAgICAgIG1vZGU7
CisJZW51bSBtcnN0X3NzcF9yeF9maWZvX292ZXJfcnVuX2ludF9tYXNrICAgIHJ4X2ZpZm9faW50
ZXJydXB0OworCWVudW0gbXJzdF9zc3BfdHhfZmlmb191bmRlcl9ydW5faW50X21hc2sgICB0eF9m
aWZvX2ludGVycnVwdDsKKwllbnVtIG1yc3Rfc3NwX2ZyYW1lX2Zvcm1hdCAgICAgICAgICAgICAg
ICAgZnJhbWVfZm9ybWF0OworCWVudW0gbXJzdF9zc3BfbWFzdGVyX21vZGVfY2xvY2tfc2VsZWN0
aW9uICBtYXN0ZXJfbW9kZV9jbGtfc2VsZWN0aW9uOyAgICAgICAgICAgICAgLyogZm9yIE1hc3Rl
ciBNb2RlIE9ubHkgKi8KKwl1OCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgZnJhbWVfcmF0ZV9kaXZpZGVyX2NvbnRyb2w7CisJdTE2ICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgIG1hc3Rlcl9tb2RlX3NlcmlhbF9jbG9ja19yYXRlOyAgICAgICAg
ICAvKiBmb3IgTWFzdGVyIE1vZGUgT25seSAqLworCXUxNiAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICBkYXRhX3NpemU7CisKKwllbnVtIG1yc3Rfc3NwX3R4ZF90cmlzdGF0
ZV9sYXN0X3BoYXNlICAgICAgdHhfdHJpc3RhdGVfcGhhc2U7CisJZW51bSBtcnN0X3NzcF90eGRf
dHJpc3RhdGVfZW5hYmxlICAgICAgICAgIHR4X3RyaXN0YXRlX2VuYWJsZTsKKwllbnVtIG1yc3Rf
c3NwX3NsYXZlX3NzcGNsa19mcmVlX3J1bm5pbmcgICAgc2xhdmVfY2xrX2ZyZWVfcnVubmluZ19z
dGF0dXM7CisJZW51bSBtcnN0X3NzcF9zc3BzY2xrX2RpcmVjdGlvbiAgICAgICAgICAgIHNzcHNs
Y2xrX2RpcmVjdGlvbjsKKwllbnVtIG1yc3Rfc3NwX3NzcHNmcm1fZGlyZWN0aW9uICAgICAgICAg
ICAgc3Nwc2ZybV9kaXJlY3Rpb247CisJZW51bSBtcnN0X3NzcF9yeF93aXRob3V0X3R4ICAgICAg
ICAgICAgICAgIHNzcF9kdXBsZXhfbW9kZTsKKwllbnVtIG1yc3RfdHJhaWxpbmdfYnl0ZV9tb2Rl
ICAgICAgICAgICAgICAgc3NwX3RyYWlsaW5nX2J5dGVfbW9kZTsKKwllbnVtIG1yc3Rfc3NwX3R4
X2RtYV9zdGF0dXMgICAgICAgICAgICAgICAgc3NwX3R4X2RtYTsKKwllbnVtIG1yc3Rfc3NwX3J4
X2RtYV9zdGF0dXMgICAgICAgICAgICAgICAgc3NwX3J4X2RtYTsKKwllbnVtIG1yc3Rfc3NwX3J4
X3RpbWVvdXRfaW50X3N0YXR1cyAgICAgICAgc3NwX3J4X3RpbWVvdXRfaW50ZXJydXB0X3N0YXR1
czsKKwllbnVtIG1yc3Rfc3NwX3RyYWlsaW5nX2J5dGVfaW50X3N0YXR1cyAgICAgc3NwX3RyYWls
aW5nX2J5dGVfaW50ZXJydXB0X3N0YXR1czsKKwllbnVtIG1yc3Rfc3NwX2xvb3BiYWNrX21vZGVf
c3RhdHVzICAgICAgICAgc3NwX2xvb3BiYWNrX21vZGVfc3RhdHVzOworCXU4ICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzc3BfcnhfZmlmb190aHJlc2hvbGQ7CisJdTgg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNzcF90eF9maWZvX3RocmVz
aG9sZDsKKworCisJZW51bSBtcnN0X3NzcF9mcmFtZV9zeW5jX3JlbGF0aXZlX3RpbWluZ19iaXQg
IHNzcF9mcm1zeW5jX3RpbWluZ19iaXQ7CisJZW51bSBtcnN0X3NzcF9mcmFtZV9zeW5jX3BvbGFy
aXR5X2JpdCAgICAgIHNzcF9mcm1zeW5jX3BvbF9iaXQ7CisJZW51bSBtcnN0X3NzcF9lbmRfb2Zf
dHJhbnNmZXJfZGF0YV9zdGF0ZSAgIHNzcF9lbmRfdHJhbnNmZXJfc3RhdGU7CisJZW51bSBtcnN0
X3NzcF9jbGtfbW9kZSAgICAgICAgICAgICAgICAgICAgIHNzcF9zZXJpYWxfY2xrX21vZGU7CisJ
dTggICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNzcF9wc3BfVDE7CisJ
dTggICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNzcF9wc3BfVDI7CisJ
dTggICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNzcF9wc3BfVDQ7ICAg
LyogRE1ZU1RPUCAqLworCXU4ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICBzc3BfcHNwX1Q1OyAgIC8qIFNGUk1ETFkgKi8KKwl1OCAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgc3NwX3BzcF9UNjsgICAvKiBTRlJNV0RUSCAqLworCisJdTggICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNzcF9hY3RpdmVfdHhfc2xvdHNf
bWFwOworCXU4ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzc3BfYWN0
aXZlX3J4X3Nsb3RzX21hcDsKK307CisKKy8qCisgKglQcm92aWRlZCBJbnRlcmZhY2UKKyAqLwor
CisKK3N0cnVjdCBpbnRlbF9taWRfaTJzX2hkbCAqaW50ZWxfbWlkX2kyc19vcGVuKGVudW0gaW50
ZWxfbWlkX2kyc19zc3BfdXNhZ2UgdXNhZ2UsIGNvbnN0IHN0cnVjdCBpbnRlbF9taWRfaTJzX3Nl
dHRpbmdzICpwc19zZXR0aW5ncyk7Cit2b2lkICBpbnRlbF9taWRfaTJzX2Nsb3NlKHN0cnVjdCBp
bnRlbF9taWRfaTJzX2hkbCAqaGFuZGxlKTsKKworaW50IGludGVsX21pZF9pMnNfcmRfcmVxKHN0
cnVjdCBpbnRlbF9taWRfaTJzX2hkbCAqaGFuZGxlLCB1MzIgKmRzdCwgc2l6ZV90IGxlbiwgdm9p
ZCAqcGFyYW0pOworaW50IGludGVsX21pZF9pMnNfd3JfcmVxKHN0cnVjdCBpbnRlbF9taWRfaTJz
X2hkbCAqaGFuZGxlLCB1MzIgKnNyYywgc2l6ZV90IGxlbiwgdm9pZCAqcGFyYW0pOworaW50IGlu
dGVsX21pZF9pMnNfZW5hYmxlX3NzcChzdHJ1Y3QgaW50ZWxfbWlkX2kyc19oZGwgKmhhbmRsZSk7
CisKKworaW50IGludGVsX21pZF9pMnNfc2V0X3dyX2NiKHN0cnVjdCBpbnRlbF9taWRfaTJzX2hk
bCAqaGFuZGxlLCBpbnQgKCp3cml0ZV9jYWxsYmFjaykodm9pZCAqcGFyYW0pKTsKK2ludCBpbnRl
bF9taWRfaTJzX3NldF9yZF9jYihzdHJ1Y3QgaW50ZWxfbWlkX2kyc19oZGwgKmhhbmRsZSwgaW50
ICgqcmVhZF9jYWxsYmFjaykodm9pZCAqcGFyYW0pKTsKKworCitpbnQgaW50ZWxfbWlkX2kyc19n
ZXRfdHhfZmlmb19sZXZlbChzdHJ1Y3QgaW50ZWxfbWlkX2kyc19oZGwgKmhhbmRsZSk7CitpbnQg
aW50ZWxfbWlkX2kyc19nZXRfcnhfZmlmb19sZXZlbChzdHJ1Y3QgaW50ZWxfbWlkX2kyc19oZGwg
KmhhbmRsZSk7CitpbnQgaW50ZWxfbWlkX2kyc19mbHVzaChzdHJ1Y3QgaW50ZWxfbWlkX2kyc19o
ZGwgKmhhbmRsZSk7CisKKyNlbmRpZiAvKk1JRF9JMlNfRVhURVJOQUxfSF8qLwpkaWZmIC0tZ2l0
IGEvc291bmQvcGNpL0tjb25maWcgYi9zb3VuZC9wY2kvS2NvbmZpZwppbmRleCAxMmUzNDY1Li4w
YjBhNTI0IDEwMDY0NAotLS0gYS9zb3VuZC9wY2kvS2NvbmZpZworKysgYi9zb3VuZC9wY2kvS2Nv
bmZpZwpAQCAtODUzLDQgKzg1MywyMiBAQCBjb25maWcgU05EX1lNRlBDSQogCSAgVG8gY29tcGls
ZSB0aGlzIGRyaXZlciBhcyBhIG1vZHVsZSwgY2hvb3NlIE0gaGVyZTogdGhlIG1vZHVsZQogCSAg
d2lsbCBiZSBjYWxsZWQgc25kLXltZnBjaS4KIAorY29uZmlnIFNORF9JTlRFTF9NSURfSTJTCisJ
dHJpc3RhdGUgIkludGVsIG1pZCBJMlMgaGFyZHdhcmUgZHJpdmVyIgorCWRlcGVuZHMgb24gRVhQ
RVJJTUVOVEFMICYmIFBDSSAmJiBJTlRFTF9NSURfRE1BQworCWRlZmF1bHQgbgorCWhlbHAKKwkg
IFNheSBZIGhlcmUgaWYgeW91IHdhbnQgdG8gYnVpbGQgbG93IGxldmVsIGRyaXZlciB0byBzdXBw
b3J0CisJICBzZW5kaW5nL3JlY2V2aW5nIEkyUyBhdWRpbyBzYW1wbGVzIG9uIEludGVsIE1JRCBT
U1AgZGV2aWNlLgorCSAgVGhpcyBpbnRlcmZhY2UgaXMgbW9zdGx5IHVzZWQgb24gSW50ZWwgTUlE
IHBsYXRmb3JtcyBhbmQgcHJvdmlkZQorCSAgdGhlIGxvdyBsZXZlbCBpbnRlcmZhY2UgZm9yIHNv
bWUgdXBwZXIgbGF5ZXIgZHJpdmVycyBzdWNoIGFzCisJICBBbHNhIFNvQywgY2hhciBkZXZpY2Ug
aW50ZXJmYWNlcy4uLiBkZXBlbmRpbmcgb2YgcGVyaXBoZXJhbCBjb25uZWN0ZWQuCisJICBQQ0kg
SGVhZGVyIHNob3VsZCBoYXZlIEFESUQgZmllbGQgc2V0IHRvIEkyUyBCVF9GTSBvciAKKwkgIEky
UyBNT0RFTSB0byBiZSB1c2VkIGJ5IHRoaXMgZHJpdmVyIChzbyBpdCBrbm93IGNvbm5lY3RlZCBw
ZXJpcGhlcmFsKS4KKwkgIE5vdGUgdGhpcyBpcyBhIHByb3RvdHlwZSBkcml2ZXIgYW5kIHN1cHBv
cnQgZm9yIGNvbnRpbnVvdXMKKwkgIGZsb3cgaXMgc3RpbGwgd29ya2luZy1pbi1wcm9ncmVzcy4K
KwkgIFRoaXMgZHJpdmVyIGNhbiBhbHNvIGJlIGJ1aWx0IGFzIGEgbW9kdWxlLiBJZiBzbywgdGhl
IG1vZHVsZQorCSAgd2lsbCBiZSBjYWxsZWQgaW50ZWxfbWlkX2kycy5rbworCSAgSWYgdW5zdXJl
LCBzYXkgTiBoZXJlLgorCiBlbmRpZgkjIFNORF9QQ0kKZGlmZiAtLWdpdCBhL3NvdW5kL3BjaS9N
YWtlZmlsZSBiL3NvdW5kL3BjaS9NYWtlZmlsZQppbmRleCA5Y2Y0MzQ4Li40NjYxM2EyIDEwMDY0
NAotLS0gYS9zb3VuZC9wY2kvTWFrZWZpbGUKKysrIGIvc291bmQvcGNpL01ha2VmaWxlCkBAIC03
OCw0ICs3OCw2IEBAIG9iai0kKENPTkZJR19TTkQpICs9IFwKIAlybWU5NjUyLyBcCiAJdHJpZGVu
dC8gXAogCXltZnBjaS8gXAotCXZ4MjIyLworCXZ4MjIyLyBcCisJaW50ZWxfbWlkX2kycy8KKwpk
aWZmIC0tZ2l0IGEvc291bmQvcGNpL2ludGVsX21pZF9pMnMvTWFrZWZpbGUgYi9zb3VuZC9wY2kv
aW50ZWxfbWlkX2kycy9NYWtlZmlsZQpuZXcgZmlsZSBtb2RlIDEwMDY0NAppbmRleCAwMDAwMDAw
Li5iZWJhYzFjCi0tLSAvZGV2L251bGwKKysrIGIvc291bmQvcGNpL2ludGVsX21pZF9pMnMvTWFr
ZWZpbGUKQEAgLTAsMCArMSwxOCBAQAorIyBTU1AgYXVkaW8gZHJpdmVyCisjIENvcHlyaWdodCAo
YykgMjAxMCwgSW50ZWwgQ29ycG9yYXRpb24uCisKKyMgVGhpcyBwcm9ncmFtIGlzIGZyZWUgc29m
dHdhcmU7IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnkgaXQKKyMgdW5kZXIg
dGhlIHRlcm1zIGFuZCBjb25kaXRpb25zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5z
ZSwKKyMgdmVyc2lvbiAyLCBhcyBwdWJsaXNoZWQgYnkgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRh
dGlvbi4KKworIyBUaGlzIHByb2dyYW0gaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgaXQgd2ls
bCBiZSB1c2VmdWwsIGJ1dCBXSVRIT1VUCisjIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRo
ZSBpbXBsaWVkIHdhcnJhbnR5IG9mIE1FUkNIQU5UQUJJTElUWSBvcgorIyBGSVRORVNTIEZPUiBB
IFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2Ug
Zm9yCisjIG1vcmUgZGV0YWlscy4KKworIyBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5
IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhbG9uZyB3aXRoCisjIHRoaXMgcHJv
Z3JhbTsgaWYgbm90LCB3cml0ZSB0byB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCBJbmMu
LAorIyA1MSBGcmFua2xpbiBTdCAtIEZpZnRoIEZsb29yLCBCb3N0b24sIE1BIDAyMTEwLTEzMDEg
VVNBLgorCitvYmotJChDT05GSUdfU05EX0lOVEVMX01JRF9JMlMpICAgICs9ICBpbnRlbF9taWRf
aTJzLm8KKwpkaWZmIC0tZ2l0IGEvc291bmQvcGNpL2ludGVsX21pZF9pMnMvaW50ZWxfbWlkX2ky
cy5jIGIvc291bmQvcGNpL2ludGVsX21pZF9pMnMvaW50ZWxfbWlkX2kycy5jCm5ldyBmaWxlIG1v
ZGUgMTAwNjQ0CmluZGV4IDAwMDAwMDAuLjU3MmFiZGUKLS0tIC9kZXYvbnVsbAorKysgYi9zb3Vu
ZC9wY2kvaW50ZWxfbWlkX2kycy9pbnRlbF9taWRfaTJzLmMKQEAgLTAsMCArMSwxNDI4IEBACisv
KgorICAqIDxEcml2ZXIgZm9yIEkyUyBwcm90b2NvbCBvbiBTU1AgKE1vb3Jlc3Rvd24gYW5kIE1l
ZGZpZWxkIGhhcmR3YXJlKT4KKyAgKiBDb3B5cmlnaHQgKGMpIDIwMTAsIEludGVsIENvcnBvcmF0
aW9uLgorICAqIExvdWlzIExFIEdBTEwgPGxvdWlzLmxlLmdhbGwgaW50ZWwuY29tPgorICAqCisg
ICogVGhpcyBwcm9ncmFtIGlzIGZyZWUgc29mdHdhcmU7IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0
IGFuZC9vciBtb2RpZnkgaXQKKyAgKiB1bmRlciB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2Yg
dGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlLAorICAqIHZlcnNpb24gMiwgYXMgcHVibGlz
aGVkIGJ5IHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24uCisgICoKKyAgKiBUaGlzIHByb2dy
YW0gaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgaXQgd2lsbCBiZSB1c2VmdWwsIGJ1dCBXSVRI
T1VUCisgICogQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW5wIHRoZSBpbXBsaWVkIHdhcnJhbnR5
IG9mIE1FUkNIQU5UQUJJTElUWSBvcgorICAqIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQ
T1NFLiAgU2VlIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IKKyAgKiBtb3JlIGRl
dGFpbHMuCisgICoKKyAgKiBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBH
TlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhbG9uZyB3aXRoCisgICogdGhpcyBwcm9ncmFtOyBp
ZiBub3QsIHdyaXRlIHRvIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIEluYy4sCisgICog
NTEgRnJhbmtsaW4gU3QgLSBGaWZ0aCBGbG9vciwgQm9zdG9uLCBNQSAwMjExMC0xMzAxIFVTQS4K
KyAgKi8KKyNpbmNsdWRlIDxsaW51eC9wY2kuaD4KKyNpbmNsdWRlIDxsaW51eC9kbWEtbWFwcGlu
Zy5oPgorI2luY2x1ZGUgPGxpbnV4L2ludGVycnVwdC5oPgorI2luY2x1ZGUgPGxpbnV4L3BtX3J1
bnRpbWUuaD4KKyNpbmNsdWRlIDxsaW51eC9wY2lfcmVncy5oPgorI2luY2x1ZGUgPGxpbnV4L3dh
aXQuaD4KKyNpbmNsdWRlIDxsaW51eC9pbnRlcnJ1cHQuaD4KKyNpbmNsdWRlIDxsaW51eC9zY2hl
ZC5oPgorCisjaW5jbHVkZSA8bGludXgvZGV2aWNlLmg+CisKKyNpbmNsdWRlIDxsaW51eC9pbnRl
bF9taWRfaTJzX2lmLmg+CisjaW5jbHVkZSAiaW50ZWxfbWlkX2kycy5oIgorCitNT0RVTEVfQVVU
SE9SKCJMb3VpcyBMRSBHQUxMIDxsb3Vpcy5sZS5nYWxsIGludGVsLmNvbT4iKTsKK01PRFVMRV9E
RVNDUklQVElPTigiSW50ZWwgTUlEIEkyUy9QQ00gU1NQIERyaXZlciIpOworTU9EVUxFX0xJQ0VO
U0UoIkdQTCIpOworTU9EVUxFX1ZFUlNJT04oIjEuMC4wIik7CisKKworLyoKKyAqIHN0cnVjdHVy
ZXMgZm9yIHBjaSBwcm9iaW5nCisgKi8KK3N0YXRpYyBjb25zdCBzdHJ1Y3QgZGV2X3BtX29wcyBp
bnRlbF9taWRfaTJzX3BtX29wcyA9IHsKKwkucnVudGltZV9zdXNwZW5kID0gaW50ZWxfbWlkX2ky
c19ydW50aW1lX3N1c3BlbmQsCisJLnJ1bnRpbWVfcmVzdW1lID0gaW50ZWxfbWlkX2kyc19ydW50
aW1lX3Jlc3VtZSwKK307CitzdGF0aWMgREVGSU5FX1BDSV9ERVZJQ0VfVEFCTEUocGNpX2lkcykg
PSB7CisJeyBQQ0lfREVWSUNFKFBDSV9WRU5ET1JfSURfSU5URUwsIE1GTERfU1NQMV9ERVZJQ0Vf
SUQpIH0sCisJeyBQQ0lfREVWSUNFKFBDSV9WRU5ET1JfSURfSU5URUwsIE1GTERfU1NQMF9ERVZJ
Q0VfSUQpIH0sCisJeyAwLCB9LCAvKiB0ZXJtaW5hdGUgbGlzdCAqLworfTsKK3N0YXRpYyBzdHJ1
Y3QgcGNpX2RyaXZlciBpbnRlbF9taWRfaTJzX2RyaXZlciA9IHsKKwkuZHJpdmVyID0geworCQku
cG0gPSAmaW50ZWxfbWlkX2kyc19wbV9vcHMsCisJfSwKKwkubmFtZSA9IERSSVZFUl9OQU1FLAor
CS5pZF90YWJsZSA9IHBjaV9pZHMsCisJLnByb2JlID0gaW50ZWxfbWlkX2kyc19wcm9iZSwKKwku
cmVtb3ZlID0gX19kZXZleGl0X3AoaW50ZWxfbWlkX2kyc19yZW1vdmUpLAorI2lmZGVmIENPTkZJ
R19QTQorCS5zdXNwZW5kID0gaW50ZWxfbWlkX2kyc19kcml2ZXJfc3VzcGVuZCwKKwkucmVzdW1l
ID0gaW50ZWxfbWlkX2kyc19kcml2ZXJfcmVzdW1lLAorI2VuZGlmCit9OworCisKKy8qCisgKiBQ
T1dFUiBNQU5BR0VNRU5UIEZVTkNUSU9OUworICovCisKKyNpZmRlZiBDT05GSUdfUE0KKy8qKgor
ICogaW50ZWxfbWlkX2kyc19kcml2ZXJfc3VzcGVuZCAtIGRyaXZlciBwb3dlciBtYW5hZ2VtZW50
IHN1c3BlbmQgYWN0aXZpdHkKKyAqIEBkZXZpY2VfcHRyIDogcG9pbnRlciBvZiB0aGUgZGV2aWNl
IHRvIHJlc3VtZQorICoKKyAqIE91dHB1dCBwYXJhbWV0ZXJzCisgKiAgICAgIGVycm9yIDogMCBt
ZWFucyBubyBlcnJvcgorICovCitzdGF0aWMgaW50ICBpbnRlbF9taWRfaTJzX2RyaXZlcl9zdXNw
ZW5kKHN0cnVjdCBwY2lfZGV2ICpkZXYsIHBtX21lc3NhZ2VfdCBzdGF0ZSkKK3sKKwlzdHJ1Y3Qg
aW50ZWxfbWlkX2kyc19oZGwgKmRydl9kYXRhID0gcGNpX2dldF9kcnZkYXRhKGRldik7CisJV0FS
TighZHJ2X2RhdGEsICJEcml2ZXIgZGF0YT1OVUxMXG4iKTsKKwlpZiAoIWRydl9kYXRhKQorCQly
ZXR1cm4gMDsKKwlkZXZfZGJnKCZkcnZfZGF0YS0+cGRldi0+ZGV2LCAiU1VTUEVORCBTU1AgSUQg
JWRcbiIsIGRydl9kYXRhLT5wZGV2LT5kZXZpY2UpOworCXBjaV9zYXZlX3N0YXRlKGRldik7CisJ
cGNpX2Rpc2FibGVfZGV2aWNlKGRldik7CisJcGNpX3NldF9wb3dlcl9zdGF0ZShkZXYsIFBDSV9E
M2hvdCk7CisJcmV0dXJuIDA7Cit9CisKKy8qKgorICogaW50ZWxfbWlkX2kyc19kcml2ZXJfcmVz
dW1lIC0gZHJpdmVyIHBvd2VyIG1hbmFnZW1lbnQgc3VzcGVuZCBhY3Rpdml0eQorICogQGRldmlj
ZV9wdHIgOiBwb2ludGVyIG9mIHRoZSBkZXZpY2UgdG8gcmVzdW1lCisgKgorICogT3V0cHV0IHBh
cmFtZXRlcnMKKyAqICAgICAgZXJyb3IgOiAwIG1lYW5zIG5vIGVycm9yCisgKi8KK3N0YXRpYyBp
bnQgaW50ZWxfbWlkX2kyc19kcml2ZXJfcmVzdW1lKHN0cnVjdCBwY2lfZGV2ICpkZXYpCit7CisJ
aW50IGVycjsKKwlpbnQgcmV0ID0gMDsKKwlzdHJ1Y3QgaW50ZWxfbWlkX2kyc19oZGwgKmRydl9k
YXRhID0gcGNpX2dldF9kcnZkYXRhKGRldik7CisKKwlXQVJOKCFkcnZfZGF0YSwgIkRyaXZlciBk
YXRhPU5VTExcbiIpOworCWlmICghZHJ2X2RhdGEpCisJCXJldHVybiAtRUZBVUxUOworCWRldl9k
YmcoJmRydl9kYXRhLT5wZGV2LT5kZXYsICJSRVNVTUUgU1NQIElEICVkXG4iLCBkcnZfZGF0YS0+
cGRldi0+ZGV2aWNlKTsKKworCWVyciA9IHBjaV9lbmFibGVfZGV2aWNlKGRldik7CisJaWYgKGVy
cikKKwkJZGV2X2VycigmZHJ2X2RhdGEtPnBkZXYtPmRldiwgIlVuYWJsZSB0byByZS1lbmFibGUg
ZGV2aWNlLCB0cnlpbmcgdG8gY29udGludWUuXG4iKTsKKwlkZXZfZGJnKCZkcnZfZGF0YS0+cGRl
di0+ZGV2LCAicmVzdW1pbmdcbiIpOworCXBjaV9zZXRfcG93ZXJfc3RhdGUoZGV2LCBQQ0lfRDAp
OworCXBjaV9yZXN0b3JlX3N0YXRlKGRldik7CisJcmV0ID0gcGNpX2VuYWJsZV9kZXZpY2UoZGV2
KTsKKwlpZiAocmV0KQorCQlkZXZfZXJyKCZkcnZfZGF0YS0+cGRldi0+ZGV2LCAiSTJTOiBkZXZp
Y2UgY2FuJ3QgYmUgZW5hYmxlZCIpOworCWRldl9kYmcoJmRydl9kYXRhLT5wZGV2LT5kZXYsICJy
ZXN1bWVkIGluIEQzXG4iKTsKKwlyZXR1cm4gcmV0OworfQorCisvKioKKyAqIGludGVsX21pZF9p
MnNfcnVudGltZV9zdXNwZW5kIC0gcnVudGltZSBwb3dlciBtYW5hZ2VtZW50IHN1c3BlbmQgYWN0
aXZpdHkKKyAqIEBkZXZpY2VfcHRyIDogcG9pbnRlciBvZiB0aGUgZGV2aWNlIHRvIHJlc3VtZQor
ICoKKyAqIE91dHB1dCBwYXJhbWV0ZXJzCisgKiAgICAgIGVycm9yIDogMCBtZWFucyBubyBlcnJv
cgorICovCitzdGF0aWMgaW50IGludGVsX21pZF9pMnNfcnVudGltZV9zdXNwZW5kKHN0cnVjdCBk
ZXZpY2UgKmRldmljZV9wdHIpCit7CisJc3RydWN0IHBjaV9kZXYgKnBkZXY7CisJc3RydWN0IGlu
dGVsX21pZF9pMnNfaGRsICpkcnZfZGF0YTsKKwl2b2lkIF9faW9tZW0gKnJlZzsKKworCXBkZXYg
PSB0b19wY2lfZGV2KGRldmljZV9wdHIpOworCVdBUk4oIXBkZXYsICJQY2kgZGV2PU5VTExcbiIp
OworCWlmICghcGRldikKKwkJcmV0dXJuIC1FRkFVTFQ7CisJZHJ2X2RhdGEgPSAoc3RydWN0IGlu
dGVsX21pZF9pMnNfaGRsICopIHBjaV9nZXRfZHJ2ZGF0YShwZGV2KTsKKwlXQVJOKCFkcnZfZGF0
YSwgIkRyaXZlciBkYXRhPU5VTExcbiIpOworCWlmICghZHJ2X2RhdGEpCisJCXJldHVybiAtRUZB
VUxUOworCWlmICh0ZXN0X2JpdChJMlNfUE9SVF9PUEVORUQsICZkcnZfZGF0YS0+ZmxhZ3MpKSB7
CisJCWRldl9lcnIoZGV2aWNlX3B0ciwgIlRyeWluZyB0byBzdXNwZW5kIGEgZGV2aWNlIHRoYXQg
aXMgb3BlbmVkXG4iKTsKKwkJcmV0dXJuIC1FTk9ERVY7CisJfQorCXJlZyA9IGRydl9kYXRhLT5p
b2FkZHI7CisJZGV2X2RiZygmZHJ2X2RhdGEtPnBkZXYtPmRldiwgIlN1c3BlbmQgb2YgU1NQIHJl
cXVlc3RlZCAhIVxuIik7CisJcmV0dXJuIGludGVsX21pZF9pMnNfZHJpdmVyX3N1c3BlbmQodG9f
cGNpX2RldihkZXZpY2VfcHRyKSwgUE1TR19TVVNQRU5EKTsKK30KKyNlbmRpZgorCisvKioKKyAq
IGludGVsX21pZF9pMnNfcnVudGltZV9yZXN1bWUgLSBydW50aW1lIHBvd2VyIG1hbmFnZW1lbnQg
cmVzdW1lIGFjdGl2aXR5CisgKiBAZGV2aWNlX3B0ciA6IHBvaW50ZXIgb2YgdGhlIGRldmljZSB0
byByZXN1bWUKKyAqCisgKiBPdXRwdXQgcGFyYW1ldGVycworICogICAgICBlcnJvciA6IDAgbWVh
bnMgbm8gZXJyb3IKKyAqLworc3RhdGljIGludCBpbnRlbF9taWRfaTJzX3J1bnRpbWVfcmVzdW1l
KHN0cnVjdCBkZXZpY2UgKmRldmljZV9wdHIpCit7CisJc3RydWN0IHBjaV9kZXYgKnBkZXY7CisJ
c3RydWN0IGludGVsX21pZF9pMnNfaGRsICpkcnZfZGF0YTsKKwlwZGV2ID0gdG9fcGNpX2Rldihk
ZXZpY2VfcHRyKTsKKwlXQVJOKCFwZGV2LCAiUGNpIGRldj1OVUxMXG4iKTsKKwlpZiAoIXBkZXYp
CisJCXJldHVybiAtRUZBVUxUOworCWRydl9kYXRhID0gKHN0cnVjdCBpbnRlbF9taWRfaTJzX2hk
bCAqKSBwY2lfZ2V0X2RydmRhdGEocGRldik7CisJV0FSTighZHJ2X2RhdGEsICJEcml2ZXIgZGF0
YT1OVUxMXG4iKTsKKwlpZiAoIWRydl9kYXRhKQorCQlyZXR1cm4gLUVGQVVMVDsKKwlkZXZfZGJn
KCZkcnZfZGF0YS0+cGRldi0+ZGV2LCAiUlQgUkVTVU1FIFNTUCBJRFxuIik7CisJcmV0dXJuIGlu
dGVsX21pZF9pMnNfZHJpdmVyX3Jlc3VtZSh0b19wY2lfZGV2KGRldmljZV9wdHIpKTsKK30KKwor
LyoKKyAqIElOVEVSRkFDRSBGVU5DVElPTlMKKyAqLworCisvKioKKyAqIGludGVsX21pZF9pMnNf
Zmx1c2ggLSBUaGlzIGlzIHRoZSBJMlMgZmx1c2ggcmVxdWVzdAorICogQGRydl9kYXRhIDogcG9p
bnRlciBvbiBwcml2YXRlIGkycyBkcml2ZXIgZGF0YSAoYnkgaTJzX29wZW4gZnVuY3Rpb24pCisg
KgorICogSXQgd2lsbCBmbHVzaCB0aGUgVFggRklGTworICogV0FSTklORzogdGhpcyBmdW5jdGlv
biBpcyB1c2VkIGluIGEgQnVyc3QgTW9kZSBjb250ZXh0IHdoZXJlIGl0IGlzIGNhbGxlZAorICog
YmV0d2VlbiBCdXJzdHMgaS5lLiB3aGVuIHRoZXJlIGlzIG5vIEZNU1lOQywgbm8gdHJhbnNmZXIg
b25nb2luZyBhdAorICogdGhhdCB0aW1lCisgKiBJZiB5b3UgbmVlZCBhIGZsdXNoIHdoaWxlIFNT
UCBjb25maWd1cmVkIGluIEkyUyBpcyBCVVNZIGFuZCBGTVNZTkMgYXJlCisgKiBnZW5lcmF0ZWQs
IHlvdSBoYXZlIHRvIHdyaXRlIGFub3RoZXIgZnVuY3Rpb24KKyAqIChsb29wIG9uIEJVU1kgYml0
IGFuZCBkbyBub3QgbGltaXQgdGhlIGZsdXNoIHRvIGF0IG1vc3QgMTYgc2FtcGxlcykKKyAqCisg
KiBPdXRwdXQgcGFyYW1ldGVycworICogICAgICBpbnQgOiBudW1iZXIgb2Ygc2FtcGxlcyBmbHVz
aGVkCisgKi8KK2ludCBpbnRlbF9taWRfaTJzX2ZsdXNoKHN0cnVjdCBpbnRlbF9taWRfaTJzX2hk
bCAqZHJ2X2RhdGEpCit7CisJdTMyIHNzc3IsIGRhdGE7CisJdTMyIG51bSA9IDA7CisJdm9pZCBf
X2lvbWVtICpyZWc7CisKKwlXQVJOKCFkcnZfZGF0YSwgIkRyaXZlciBkYXRhPU5VTExcbiIpOwor
CWlmICghZHJ2X2RhdGEpCisJCXJldHVybiAwOworCXJlZyA9IGRydl9kYXRhLT5pb2FkZHI7CisJ
c3NzciA9IHJlYWRfU1NTUihyZWcpOworCWRldl9kYmcoJmRydl9kYXRhLT5wZGV2LT5kZXYsICJp
biBmbHVzaCBzc3NyPTB4JTA4WFxuIiwgc3Nzcik7CisJLyoKKwkgKiBGbHVzaCAiYnkgaGFuZCIg
d2FzIGdlbmVyYXRpbmcgc3B1cmlvdXMgRE1BIFNFUlYgUkVRVUVTVAorCSAqIGZyb20gU1NQIHRv
IERNQSA9PiB0aGVuIGJ1Z2d5IHJldHJpZXZhbCBvZiBkYXRhIGZvciBuZXh0IGRtYV9yZXEKKwkg
KiBEaXNhYmxlOiBSWCBTZXJ2aWNlIFJlcXVlc3QgZnJvbSBSWCBmaWZvIHRvIERNQQorCSAqIGFz
IHdlIHdpbGwgZmx1c2ggYnkgaGFuZAorCSAqLworCWNsZWFyX1NTQ1IxX3JlZyhyZWcsIFJTUkUp
OworCS8qIGkyc19mbHVzaCBpcyBjYWxsZWQgaW4gYmV0d2VlbiAyIGJ1cnN0cworCSAqID0+IG5v
IEZNU1lOQyBhdCB0aGF0IHRpbWUgKGkuZS4gU1NQIG5vdCBidXN5KQorCSAqID0+IGF0IG1vc3Qg
MTYgc2FtcGxlcyBpbiB0aGUgRklGTyAqLworCXdoaWxlICgocmVhZF9TU1NSKHJlZykgJiAoU1NT
Ul9STkVfTUFTSzw8U1NTUl9STkVfU0hJRlQpKQorCQkJJiYgKG51bSA8IEZJRk9fU0laRSkpIHsK
KwkJZGF0YSA9IHJlYWRfU1NEUihyZWcpOworCQludW0rKzsKKwkJZGV2X3dhcm4oJmRydl9kYXRh
LT5wZGV2LT5kZXYsICJmbHVzaCgldSk9JXVcbiIsIG51bSwgZGF0YSk7CisJfQorCS8qIEVuYWJs
ZTogUlggU2VydmljZSBSZXF1ZXN0IGZyb20gUlggZmlmbyB0byBETUEKKwkgKiBhcyBmbHVzaCBi
eSBoYW5kIGlzIGRvbmUKKwkgKi8KKwlzZXRfU1NDUjFfcmVnKHJlZywgUlNSRSk7CisJc3NzciA9
IHJlYWRfU1NTUihyZWcpOworCWRldl9kYmcoJmRydl9kYXRhLT5wZGV2LT5kZXYsICJvdXQgZmx1
c2ggc3Nzcj0weCUwOFhcbiIsIHNzc3IpOworCXJldHVybiBudW07Cit9CitFWFBPUlRfU1lNQk9M
X0dQTChpbnRlbF9taWRfaTJzX2ZsdXNoKTsKKworLyoqCisgKiBpbnRlbF9taWRfaTJzX2dldF9y
eF9maWZvX2xldmVsIC0gcmV0dXJucyBJMlMgcnggZmlmbyBsZXZlbAorICogQGRydl9kYXRhIDog
cG9pbnRlciBvbiBwcml2YXRlIGkycyBkcml2ZXIgZGF0YSAoYnkgaTJzX29wZW4gZnVuY3Rpb24p
CisgKgorICogT3V0cHV0IHBhcmFtZXRlcnMKKyAqICAgICAgaW50IDogTnVtYmVyIG9mIHNhbXBs
ZXMgY3VycmVudGx5IGluIHRoZSBSWCBGSUZPIChuZWdhdGl2ZSA9IGVycm9yKQorICovCitpbnQg
aW50ZWxfbWlkX2kyc19nZXRfcnhfZmlmb19sZXZlbChzdHJ1Y3QgaW50ZWxfbWlkX2kyc19oZGwg
KmRydl9kYXRhKQoreworCXUzMiBzc3NyOworCXUzMiBybmUsIHJmbDsKKwl2b2lkIF9faW9tZW0g
KnJlZzsKKworCVdBUk4oIWRydl9kYXRhLCAiRHJpdmVyIGRhdGE9TlVMTFxuIik7CisJaWYgKCFk
cnZfZGF0YSkKKwkJcmV0dXJuIC1FRkFVTFQ7CisJcmVnID0gZHJ2X2RhdGEtPmlvYWRkcjsKKwlz
c3NyID0gcmVhZF9TU1NSKHJlZyk7CisJcmZsID0gR0VUX1NTU1JfdmFsKHNzc3IsIFJGTCk7CisJ
cm5lID0gR0VUX1NTU1JfdmFsKHNzc3IsIFJORSk7CisJaWYgKCFybmUpCisJCXJldHVybiAwOwor
CWVsc2UKKwkJcmV0dXJuIHJmbCsxOworfQorRVhQT1JUX1NZTUJPTF9HUEwoaW50ZWxfbWlkX2ky
c19nZXRfcnhfZmlmb19sZXZlbCk7CisKKy8qKgorICogaW50ZWxfbWlkX2kyc19nZXRfdHhfZmlm
b19sZXZlbCAtIHJldHVybnMgSTJTIHR4IGZpZm8gbGV2ZWwKKyAqIEBkcnZfZGF0YSA6IHBvaW50
ZXIgb24gcHJpdmF0ZSBpMnMgZHJpdmVyIGRhdGEgKGJ5IGkyc19vcGVuIGZ1bmN0aW9uKQorICoK
KyAqIE91dHB1dCBwYXJhbWV0ZXJzCisgKiAgICAgIGludCA6IG51bWJlciBvZiBzYW1wbGVzIGN1
cnJlbnRseSBpbiB0aGUgVFggRklGTyAobmVnYXRpdmUgPSBlcnJvcikKKyAqLworaW50IGludGVs
X21pZF9pMnNfZ2V0X3R4X2ZpZm9fbGV2ZWwoc3RydWN0IGludGVsX21pZF9pMnNfaGRsICpkcnZf
ZGF0YSkKK3sKKwl1MzIgc3NzcjsKKwl1MzIgdG5mLCB0Zmw7CisJdm9pZCBfX2lvbWVtICpyZWc7
CisJV0FSTighZHJ2X2RhdGEsICJEcml2ZXIgZGF0YT1OVUxMXG4iKTsKKwlpZiAoIWRydl9kYXRh
KQorCQlyZXR1cm4gLUVGQVVMVDsKKwlyZWcgPSBkcnZfZGF0YS0+aW9hZGRyOworCXNzc3IgPSBy
ZWFkX1NTU1IocmVnKTsKKwl0ZmwgPSBHRVRfU1NTUl92YWwoc3NzciwgVEZMKTsKKwl0bmYgPSBH
RVRfU1NTUl92YWwoc3NzciwgVEZOKTsKKwlpZiAoIXRuZikKKwkJcmV0dXJuIDE2OworCWVsc2UK
KwkJcmV0dXJuIHRmbDsKK30KK0VYUE9SVF9TWU1CT0xfR1BMKGludGVsX21pZF9pMnNfZ2V0X3R4
X2ZpZm9fbGV2ZWwpOworCisvKioKKyAqIGludGVsX21pZF9pMnNfc2V0X3JkX2NiIC0gc2V0IHRo
ZSBjYWxsYmFjayBmdW5jdGlvbiBhZnRlciByZWFkIGlzIGRvbmUKKyAqIEBkcnZfZGF0YSA6IGhh
bmRsZSBvZiBjb3JyZXNwb25kaW5nIHNzcCBpMnMgKGdpdmVuIGJ5IGkyc19vcGVuIGZ1bmN0aW9u
KQorICogQHJlYWRfY2FsbGJhY2sgOiBwb2ludGVyIG9mIGNhbGxiYWNrIGZ1bmN0aW9uCisgKgor
ICogT3V0cHV0IHBhcmFtZXRlcnMKKyAqICAgICAgZXJyb3IgOiAwIG1lYW5zIG5vIGVycm9yCisg
Ki8KK2ludCBpbnRlbF9taWRfaTJzX3NldF9yZF9jYihzdHJ1Y3QgaW50ZWxfbWlkX2kyc19oZGwg
KmRydl9kYXRhLCBpbnQgKCpyZWFkX2NhbGxiYWNrKSh2b2lkICpwYXJhbSkpCit7CisJV0FSTigh
ZHJ2X2RhdGEsICJEcml2ZXIgZGF0YT1OVUxMXG4iKTsKKwlpZiAoIWRydl9kYXRhKQorCQlyZXR1
cm4gLUVGQVVMVDsKKwltdXRleF9sb2NrKCZkcnZfZGF0YS0+bXV0ZXgpOworCWlmICghdGVzdF9i
aXQoSTJTX1BPUlRfT1BFTkVELCAmZHJ2X2RhdGEtPmZsYWdzKSkgeworCQlkZXZfV0FSTigmZHJ2
X2RhdGEtPnBkZXYtPmRldiwgInNldCBXUiBDQiBJMlNfUE9SVCBOT1RfT1BFTkVEIik7CisJCW11
dGV4X3VubG9jaygmZHJ2X2RhdGEtPm11dGV4KTsKKwkJcmV0dXJuIC1FUEVSTTsKKwl9CisJLyog
RG8gbm90IGNoYW5nZSByZWFkIHBhcmFtZXRlcnMgaW4gdGhlIG1pZGRsZSBvZiBhIFJFQUQgcmVx
dWVzdCAqLworCWlmICh0ZXN0X2JpdChJMlNfUE9SVF9SRUFEX0JVU1ksICZkcnZfZGF0YS0+Zmxh
Z3MpKSB7CisJCWRldl9XQVJOKCZkcnZfZGF0YS0+cGRldi0+ZGV2LCAiQ0IgcmVqZWN0IEkyU19Q
T1JUX1JFQURfQlVTWSIpOworCQltdXRleF91bmxvY2soJmRydl9kYXRhLT5tdXRleCk7CisJCXJl
dHVybiAtRUJVU1k7CisJfQorCWRydl9kYXRhLT5yZWFkX2NhbGxiYWNrID0gcmVhZF9jYWxsYmFj
azsKKwlkcnZfZGF0YS0+cmVhZF9sZW4gPSAwOworCW11dGV4X3VubG9jaygmZHJ2X2RhdGEtPm11
dGV4KTsKKwlyZXR1cm4gMDsKKworfQorRVhQT1JUX1NZTUJPTF9HUEwoaW50ZWxfbWlkX2kyc19z
ZXRfcmRfY2IpOworCisvKioKKyAqIGludGVsX21pZF9pMnNfc2V0X3dyX2NiIC0gc2V0IHRoZSBj
YWxsYmFjayBmdW5jdGlvbiBhZnRlciB3cml0ZSBpcyBkb25lCisgKiBAZHJ2X2RhdGEgOiBoYW5k
bGUgb2YgY29ycmVzcG9uZGluZyBzc3AgaTJzIChnaXZlbiBieSBpMnNfb3BlbiAgZnVuY3Rpb24p
CisgKiBAd3JpdGVfY2FsbGJhY2sgOiBwb2ludGVyIG9mIGNhbGxiYWNrIGZ1bmN0aW9uCisgKgor
ICogT3V0cHV0IHBhcmFtZXRlcnMKKyAqICAgICAgZXJyb3IgOiAwIG1lYW5zIG5vIGVycm9yCisg
Ki8KK2ludCBpbnRlbF9taWRfaTJzX3NldF93cl9jYihzdHJ1Y3QgaW50ZWxfbWlkX2kyc19oZGwg
KmRydl9kYXRhLCBpbnQgKCp3cml0ZV9jYWxsYmFjaykodm9pZCAqcGFyYW0pKQoreworCVdBUk4o
IWRydl9kYXRhLCAiRHJpdmVyIGRhdGE9TlVMTFxuIik7CisJaWYgKCFkcnZfZGF0YSkKKwkJcmV0
dXJuIC1FRkFVTFQ7CisJbXV0ZXhfbG9jaygmZHJ2X2RhdGEtPm11dGV4KTsKKwlpZiAoIXRlc3Rf
Yml0KEkyU19QT1JUX09QRU5FRCwgJmRydl9kYXRhLT5mbGFncykpIHsKKwkJZGV2X3dhcm4oJmRy
dl9kYXRhLT5wZGV2LT5kZXYsICJzZXQgV1IgQ0IgSTJTX1BPUlQgTk9UX09QRU5FRCIpOworCQlt
dXRleF91bmxvY2soJmRydl9kYXRhLT5tdXRleCk7CisJCXJldHVybiAtRVBFUk07CisJfQorCS8q
IERvIG5vdCBjaGFuZ2Ugd3JpdGUgcGFyYW1ldGVycyBpbiB0aGUgbWlkZGxlIG9mIGEgV1JJVEUg
cmVxdWVzdCAqLworCWlmICh0ZXN0X2JpdChJMlNfUE9SVF9XUklURV9CVVNZLCAmZHJ2X2RhdGEt
PmZsYWdzKSkgeworCQlkZXZfd2FybigmZHJ2X2RhdGEtPnBkZXYtPmRldiwgIkNCIHJlamVjdCBJ
MlNfUE9SVF9XUklURV9CVVNZIik7CisJCW11dGV4X3VubG9jaygmZHJ2X2RhdGEtPm11dGV4KTsK
KwkJcmV0dXJuIC1FQlVTWTsKKwl9CisJZHJ2X2RhdGEtPndyaXRlX2NhbGxiYWNrID0gd3JpdGVf
Y2FsbGJhY2s7CisJZHJ2X2RhdGEtPndyaXRlX2xlbiA9IDA7CisJbXV0ZXhfdW5sb2NrKCZkcnZf
ZGF0YS0+bXV0ZXgpOworCXJldHVybiAwOworfQorRVhQT1JUX1NZTUJPTF9HUEwoaW50ZWxfbWlk
X2kyc19zZXRfd3JfY2IpOworCisvKioKKyAqIGludGVsX21pZF9pMnNfZW5hYmxlX3NzcCgpIDog
c3RhcnQgdGhlIHNzcCByaWdodCBhZnRlciB0aGUgcmVhZC93cml0ZSByZXEKKyAqIEBkcnZfZGF0
YSA6IGhhbmRsZSBvZiBjb3JyZXNwb25kaW5nIHNzcCBpMnMgKGdpdmVuIGJ5IGkyc19vcGVuIGZ1
bmN0aW9uKQorICoKKyAqIFRoaXMgZW5hYmxlIHRoZSByZWFkL3dyaXRlIHRvIGJlIHN0YXJ0ZWQg
c3luY2hyb25vdXNseQorICoKKyAqIE91dHB1dCBwYXJhbWV0ZXJzCisgKiAgICAgIGVycm9yIDog
MCBtZWFucyBubyBlcnJvcgorICovCitpbnQgaW50ZWxfbWlkX2kyc19lbmFibGVfc3NwKHN0cnVj
dCBpbnRlbF9taWRfaTJzX2hkbCAqZHJ2X2RhdGEpCit7CisJdm9pZCBfX2lvbWVtICpyZWcgPSBk
cnZfZGF0YS0+aW9hZGRyOworCXNldF9TU0NSMF9yZWcocmVnLCBTU0UpOworCXJldHVybiAwOwor
fQorRVhQT1JUX1NZTUJPTF9HUEwoaW50ZWxfbWlkX2kyc19lbmFibGVfc3NwKTsKKworLyoqCisg
KiBpbnRlbF9taWRfaTJzX3JkX3JlcSAtIHJlcXVlc3QgYSByZWFkIGZyb20gaTJzIHBlcmlwaGVy
YWwKKyAqIEBkcnZfZGF0YSA6IGhhbmRsZSBvZiBjb3JyZXNwb25kaW5nIHNzcCBpMnMgKGdpdmVu
IGJ5IGkyc19vcGVuIGZ1bmN0aW9uKQorICogQGRzdCA6IGRlc3RpbmF0aW9uIGJ1ZmZlciB3aGVy
ZSB0aGUgcmVhZCBzYW1wbGUgc2hvdWxkIGJlIHB1dAorICogQGxlbiA6IG51bWJlciBvZiBzYW1w
bGUgdG8gYmUgcmVhZCAoMTYwIHNhbXBsZXMgb25seSByaWdodCBub3cpCisgKiBAcGFyYW0gOiBw
cml2YXRlIGNvbnRleHQgcGFyYW1ldGVyIHRvIGdpdmUgYmFjayB0byByZWFkIGNhbGxiYWNrCisg
KgorICogT3V0cHV0IHBhcmFtZXRlcnMKKyAqICAgICAgZXJyb3IgOiAwIG1lYW5zIG5vIGVycm9y
CisgKi8KK2ludCBpbnRlbF9taWRfaTJzX3JkX3JlcShzdHJ1Y3QgaW50ZWxfbWlkX2kyc19oZGwg
KmRydl9kYXRhLCB1MzIgKmRlc3RpbmF0aW9uLCBzaXplX3QgbGVuLCB2b2lkICpwYXJhbSkKK3sK
KwlzdHJ1Y3QgZG1hX2FzeW5jX3R4X2Rlc2NyaXB0b3IgKnJ4ZGVzYyA9IE5VTEw7CisJc3RydWN0
IGRtYV9jaGFuICpyeGNoYW4gPSBkcnZfZGF0YS0+cnhjaGFuOworCWVudW0gZG1hX2N0cmxfZmxh
Z3MgZmxhZzsKKwlkbWFfYWRkcl90IHNzZHJfYWRkcjsKKwlkbWFfYWRkcl90IGRzdDsKKwlXQVJO
KCFkcnZfZGF0YSwgIkRyaXZlciBkYXRhPU5VTExcbiIpOworCWlmICghZHJ2X2RhdGEpCisJCXJl
dHVybiAtRUZBVUxUOworCW11dGV4X2xvY2soJmRydl9kYXRhLT5tdXRleCk7CisJaWYgKCFyeGNo
YW4pIHsKKwkJZGV2X1dBUk4oJihkcnZfZGF0YS0+cGRldi0+ZGV2KSwgInJkX3JlcSBGQUlMRUQg
bm8gcnhjaGFuXG4iKTsKKwkJbXV0ZXhfdW5sb2NrKCZkcnZfZGF0YS0+bXV0ZXgpOworCQlyZXR1
cm4gLUVJTlZBTDsKKwl9CisJaWYgKCFsZW4pIHsKKwkJZGV2X1dBUk4oJmRydl9kYXRhLT5wZGV2
LT5kZXYsICJyZCByZXEgaW52YWxpZCBsZW49MCIpOworCQltdXRleF91bmxvY2soJmRydl9kYXRh
LT5tdXRleCk7CisJCXJldHVybiAtRUlOVkFMOworCX0KKwlpZiAoIXRlc3RfYml0KEkyU19QT1JU
X09QRU5FRCwgJmRydl9kYXRhLT5mbGFncykpIHsKKwkJZGV2X1dBUk4oJmRydl9kYXRhLT5wZGV2
LT5kZXYsICJSRCByZWplY3QgSTJTX1BPUlQgTk9UX09QRU5FRCIpOworCQltdXRleF91bmxvY2so
JmRydl9kYXRhLT5tdXRleCk7CisJCXJldHVybiAtRVBFUk07CisJfQorCWlmICh0ZXN0X2JpdChJ
MlNfUE9SVF9DTE9TSU5HLCAmZHJ2X2RhdGEtPmZsYWdzKSkgeworCQlkZXZfV0FSTigmZHJ2X2Rh
dGEtPnBkZXYtPmRldiwgIlJEIHJlamVjdCBJMlNfUE9SVCBDTE9TSU5HIik7CisJCW11dGV4X3Vu
bG9jaygmZHJ2X2RhdGEtPm11dGV4KTsKKwkJcmV0dXJuIC1FUElQRTsKKwl9CisKKwlkZXZfZGJn
KCZkcnZfZGF0YS0+cGRldi0+ZGV2LCAiSTJTX1JFQUQoKSBkc3Q9JXAsIGxlbj0lZCwgZHJ2X2Rh
dGE9JXAiLAlkZXN0aW5hdGlvbiwgbGVuLCBkcnZfZGF0YSk7CisJZHN0ID0gZG1hX21hcF9zaW5n
bGUoTlVMTCwgZGVzdGluYXRpb24sIGxlbiwgRE1BX0ZST01fREVWSUNFKTsKKwlpZiAoIWRzdCkg
eworCQlkZXZfV0FSTigmZHJ2X2RhdGEtPnBkZXYtPmRldiwgImNhbid0IG1hcCBETUEgYWRkcmVz
cyAlcCIsIGRlc3RpbmF0aW9uKTsKKwkJbXV0ZXhfdW5sb2NrKCZkcnZfZGF0YS0+bXV0ZXgpOwor
CQlyZXR1cm4gLUVOT01FTTsKKwl9CisKKwlkcnZfZGF0YS0+cmVhZF9kc3QgPSBkc3Q7CisJZHJ2
X2RhdGEtPnJlYWRfbGVuID0gbGVuOworCS8qIGdldCBEYXRhIFJlYWQvV3JpdGUgYWRkcmVzcyAq
LworCXNzZHJfYWRkciA9IChkcnZfZGF0YS0+cGFkZHIgKyBPRkZTRVRfU1NEUik7CisJc2V0X1NT
Q1IxX3JlZygoZHJ2X2RhdGEtPmlvYWRkciksIFJTUkUpOworCWNoYW5nZV9TU0NSMF9yZWcoKGRy
dl9kYXRhLT5pb2FkZHIpLCBSSU0sCisJCQkgKChkcnZfZGF0YS0+Y3VycmVudF9zZXR0aW5ncyku
cnhfZmlmb19pbnRlcnJ1cHQpKTsKKwlmbGFnID0gRE1BX1BSRVBfSU5URVJSVVBUIHwgRE1BX0NU
UkxfQUNLOworCS8qIFN0YXJ0IHRoZSBSWCBkbWEgdHJhbnNmZXIgKi8KKwlyeGRlc2MgPSByeGNo
YW4tPmRldmljZS0+ZGV2aWNlX3ByZXBfZG1hX21lbWNweSgKKwkJCXJ4Y2hhbiwJCS8qIERNQSBD
aGFubmVsICovCisJCQlkc3QsCQkvKiBEQVIgKi8KKwkJCXNzZHJfYWRkciwJLyogU0FSICovCisJ
CQlsZW4sCQkvKiBEYXRhIExlbmd0aCAqLworCQkJZmxhZyk7CQkvKiBGbGFnICovCisJaWYgKCFy
eGRlc2MpIHsKKwkJZGV2X1dBUk4oJmRydl9kYXRhLT5wZGV2LT5kZXYsICJjYW4gbm90IHByZXAg
ZG1hIG1lbWNweSIpOworCQltdXRleF91bmxvY2soJmRydl9kYXRhLT5tdXRleCk7CisJCXJldHVy
biAtRUZBVUxUOworCX0KKwkvKiBPbmx5IDEgUkVBRCBhdCBhIHRpbWUgYWxsb3dlZC4gZG8gaXQg
YXQgZW5kIHRvIGF2b2lkIGNsZWFyJndha2V1cCovCisJaWYgKHRlc3RfYW5kX3NldF9iaXQoSTJT
X1BPUlRfUkVBRF9CVVNZLCAmZHJ2X2RhdGEtPmZsYWdzKSkgeworCQlkbWFfdW5tYXBfc2luZ2xl
KE5VTEwsIGRzdCwgbGVuLCBETUFfRlJPTV9ERVZJQ0UpOworCQlkZXZfV0FSTigmZHJ2X2RhdGEt
PnBkZXYtPmRldiwgIlJEIHJlamVjdCBJMlNfUE9SVCBSRUFEX0JVU1kiKTsKKwkJbXV0ZXhfdW5s
b2NrKCZkcnZfZGF0YS0+bXV0ZXgpOworCQlyZXR1cm4gLUVCVVNZOworCX0KKwlkZXZfZGJnKCYo
ZHJ2X2RhdGEtPnBkZXYtPmRldiksICJSRCBkbWEgdHggc3VibWl0XG4iKTsKKwlyeGRlc2MtPmNh
bGxiYWNrID0gaTJzX3JlYWRfZG9uZTsKKwlkcnZfZGF0YS0+cmVhZF9wYXJhbSA9IHBhcmFtOwor
CXJ4ZGVzYy0+Y2FsbGJhY2tfcGFyYW0gPSBkcnZfZGF0YTsKKwlyeGRlc2MtPnR4X3N1Ym1pdChy
eGRlc2MpOworCW11dGV4X3VubG9jaygmZHJ2X2RhdGEtPm11dGV4KTsKKwlyZXR1cm4gMDsKK30K
K0VYUE9SVF9TWU1CT0xfR1BMKGludGVsX21pZF9pMnNfcmRfcmVxKTsKKworLyoqCisgKiBpbnRl
bF9taWRfaTJzX3dyX3JlcSAtIHJlcXVlc3QgYSB3cml0ZSB0byBpMnMgcGVyaXBoZXJhbAorICog
QGRydl9kYXRhIDogaGFuZGxlIG9mIGNvcnJlc3BvbmRpbmcgc3NwIGkycyAoZ2l2ZW4gYnkgaTJz
X29wZW4gZnVuY3Rpb24pCisgKiBAc3JjIDogc291cmNlIGJ1ZmZlciB3aGVyZSB0aGUgc2FtcGxl
cyB0byB3cm90ZSBzaG91bGQgYmUgZ2V0CisgKiBAbGVuIDogbnVtYmVyIG9mIHNhbXBsZSB0byBi
ZSByZWFkICgxNjAgc2FtcGxlcyBvbmx5IHJpZ2h0IG5vdykKKyAqIEBwYXJhbSA6IHByaXZhdGUg
Y29udGV4dCBwYXJhbWV0ZXIgdG8gZ2l2ZSBiYWNrIHRvIHdyaXRlIGNhbGxiYWNrCisgKgorICog
T3V0cHV0IHBhcmFtZXRlcnMKKyAqICAgICAgZXJyb3IgOiAwIG1lYW5zIG5vIGVycm9yCisgKi8K
K2ludCBpbnRlbF9taWRfaTJzX3dyX3JlcShzdHJ1Y3QgaW50ZWxfbWlkX2kyc19oZGwgKmRydl9k
YXRhLCB1MzIgKnNvdXJjZSwgc2l6ZV90IGxlbiwgdm9pZCAqcGFyYW0pCit7CisJZG1hX2FkZHJf
dCBzc2RyX2FkZHI7CisJc3RydWN0IGRtYV9hc3luY190eF9kZXNjcmlwdG9yICp0eGRlc2MgPSBO
VUxMOworCXN0cnVjdCBkbWFfY2hhbiAqdHhjaGFuID0gZHJ2X2RhdGEtPnR4Y2hhbjsKKwllbnVt
IGRtYV9jdHJsX2ZsYWdzIGZsYWc7CisJZG1hX2FkZHJfdCBzcmM7CisJV0FSTighZHJ2X2RhdGEs
ICJEcml2ZXIgZGF0YT1OVUxMXG4iKTsKKwlpZiAoIWRydl9kYXRhKQorCQlyZXR1cm4gLUVGQVVM
VDsKKwltdXRleF9sb2NrKCZkcnZfZGF0YS0+bXV0ZXgpOworCWlmICghdHhjaGFuKSB7CisJCWRl
dl9XQVJOKCYoZHJ2X2RhdGEtPnBkZXYtPmRldiksICJ3cl9yZXEgYnV0IG5vIHR4Y2hhblxuIik7
CisJCW11dGV4X3VubG9jaygmZHJ2X2RhdGEtPm11dGV4KTsKKwkJcmV0dXJuIC1FSU5WQUw7CisJ
fQorCWlmICghbGVuKSB7CisJCWRldl9XQVJOKCZkcnZfZGF0YS0+cGRldi0+ZGV2LCAiaW52YWxp
ZCBsZW4gMCIpOworCQltdXRleF91bmxvY2soJmRydl9kYXRhLT5tdXRleCk7CisJCXJldHVybiAt
RUlOVkFMOworCX0KKwlpZiAoIXRlc3RfYml0KEkyU19QT1JUX09QRU5FRCwgJmRydl9kYXRhLT5m
bGFncykpIHsKKwkJZGV2X1dBUk4oJmRydl9kYXRhLT5wZGV2LT5kZXYsICJXUiByZWplY3QgSTJT
X1BPUlQgTk9UX09QRU5FRCIpOworCQltdXRleF91bmxvY2soJmRydl9kYXRhLT5tdXRleCk7CisJ
CXJldHVybiAtRVBFUk07CisJfQorCWlmICh0ZXN0X2JpdChJMlNfUE9SVF9DTE9TSU5HLCAmZHJ2
X2RhdGEtPmZsYWdzKSkgeworCQlkZXZfV0FSTigmZHJ2X2RhdGEtPnBkZXYtPmRldiwgIldSIHJl
amVjdCBJMlNfUE9SVCBDTE9TSU5HIik7CisJCW11dGV4X3VubG9jaygmZHJ2X2RhdGEtPm11dGV4
KTsKKwkJcmV0dXJuIC1FUElQRTsKKwl9CisKKwlkZXZfZGJnKCZkcnZfZGF0YS0+cGRldi0+ZGV2
LCAiSTJTX1dSSVRFKCkgc3JjPSVwLCBsZW49JWQsIGRydl9kYXRhPSVwIiwgc291cmNlLCBsZW4s
IGRydl9kYXRhKTsKKworCXNyYyA9IGRtYV9tYXBfc2luZ2xlKE5VTEwsIHNvdXJjZSwgbGVuLCBE
TUFfVE9fREVWSUNFKTsKKwlpZiAoIXNyYykgeworCQlkZXZfV0FSTigmZHJ2X2RhdGEtPnBkZXYt
PmRldiwgImNhbid0IG1hcCBETUEgYWRkcmVzcyAlcCIsIHNvdXJjZSk7CisJCW11dGV4X3VubG9j
aygmZHJ2X2RhdGEtPm11dGV4KTsKKwkJcmV0dXJuIC1FRkFVTFQ7CisJfQorCWRydl9kYXRhLT53
cml0ZV9zcmMgPSBzcmM7CisJZHJ2X2RhdGEtPndyaXRlX2xlbiA9IGxlbjsKKwkvKiBnZXQgRGF0
YSBSZWFkL1dyaXRlIGFkZHJlc3MgKi8KKwlzc2RyX2FkZHIgPSAoZG1hX2FkZHJfdCkodTMyKShk
cnZfZGF0YS0+cGFkZHIgKyBPRkZTRVRfU1NEUik7CisJc2V0X1NTQ1IxX3JlZygoZHJ2X2RhdGEt
PmlvYWRkciksIFRTUkUpOworCWNoYW5nZV9TU0NSMF9yZWcoKGRydl9kYXRhLT5pb2FkZHIpLCBU
SU0sCisJCQkgKChkcnZfZGF0YS0+Y3VycmVudF9zZXR0aW5ncykudHhfZmlmb19pbnRlcnJ1cHQp
KTsKKwlmbGFnID0gRE1BX1BSRVBfSU5URVJSVVBUIHwgRE1BX0NUUkxfQUNLOworCXR4ZGVzYyA9
IHR4Y2hhbi0+ZGV2aWNlLT5kZXZpY2VfcHJlcF9kbWFfbWVtY3B5KAorCQkJdHhjaGFuLAkJLyog
RE1BIENoYW5uZWwgKi8KKwkJCXNzZHJfYWRkciwJLyogREFSICovCisJCQlzcmMsCQkvKiBTQVIg
Ki8KKwkJCWxlbiwJCS8qIERhdGEgTGVuZ3RoICovCisJCQlmbGFnKTsJCS8qIEZsYWcgKi8KKwlp
ZiAoIXR4ZGVzYykgeworCQlkZXZfV0FSTigmKGRydl9kYXRhLT5wZGV2LT5kZXYpLAorCQkJIndy
X3JlcSBkbWEgbWVtY3B5IEZBSUxFRChzcmM9JTA4eCxsZW49JWQsdHhjaGFuPSVwKVxuIiwKKwkJ
CXNyYywgbGVuLCB0eGNoYW4pOworCQltdXRleF91bmxvY2soJmRydl9kYXRhLT5tdXRleCk7CisJ
CXJldHVybiAtMTsKKwl9CisJZGV2X2RiZygmKGRydl9kYXRhLT5wZGV2LT5kZXYpLCAiV1IgZG1h
IHR4IHN1bW1pdFxuIik7CisJLyogT25seSAxIFdSSVRFIGF0IGEgdGltZSBhbGxvd2VkICovCisJ
aWYgKHRlc3RfYW5kX3NldF9iaXQoSTJTX1BPUlRfV1JJVEVfQlVTWSwgJmRydl9kYXRhLT5mbGFn
cykpIHsKKwkJZG1hX3VubWFwX3NpbmdsZShOVUxMLCBzcmMsIGxlbiwgRE1BX1RPX0RFVklDRSk7
CisJCWRldl9XQVJOKCZkcnZfZGF0YS0+cGRldi0+ZGV2LCAiV1IgcmVqZWN0IEkyU19QT1JUIFdS
SVRFX0JVU1kiKTsKKwkJbXV0ZXhfdW5sb2NrKCZkcnZfZGF0YS0+bXV0ZXgpOworCQlyZXR1cm4g
LUVCVVNZOworCX0KKwl0eGRlc2MtPmNhbGxiYWNrID0gaTJzX3dyaXRlX2RvbmU7CisJZHJ2X2Rh
dGEtPndyaXRlX3BhcmFtID0gcGFyYW07CisJdHhkZXNjLT5jYWxsYmFja19wYXJhbSA9IGRydl9k
YXRhOworCXR4ZGVzYy0+dHhfc3VibWl0KHR4ZGVzYyk7CisJZGV2X2RiZygmKGRydl9kYXRhLT5w
ZGV2LT5kZXYpLCAid3IgZG1hIHJlcSBwcm9ncmFtbWVkXG4iKTsKKwltdXRleF91bmxvY2soJmRy
dl9kYXRhLT5tdXRleCk7CisJcmV0dXJuIDA7Cit9CitFWFBPUlRfU1lNQk9MX0dQTChpbnRlbF9t
aWRfaTJzX3dyX3JlcSk7CisKKy8qKgorICogaW50ZWxfbWlkX2kyc19vcGVuIC0gcmVzZXJ2ZSBh
bmQgc3RhcnQgYSBTU1AgZGVwZW5kaW5nIG9mIGl0J3MgdXNhZ2UKKyAqIEB1c2FnZSA6IHNlbGVj
dCB3aGljaCBzc3AgaTJzIHlvdSBuZWVkIGJ5IGdpdmluZyB1c2FnZSAoQlQsTU9ERU0uLi4pCisg
KiBAcHNfc2V0dGluZ3MgOiBoYXJkd2FyZSBzZXR0aW5ncyB0byBjb25maWd1cmUgdGhlIFNTUCBt
b2R1bGUKKyAqCisgKiBNYXkgc2xlZXAgKGRyaXZlcl9maW5kX2RldmljZSkgOiBubyBsb2NrIHBl
cm1pdHRlZCB3aGVuIGNhbGxlZC4KKyAqCisgKiBPdXRwdXQgcGFyYW1ldGVycworICogICAgICBo
YW5kbGUgOiBoYW5kbGUgb2YgdGhlIHNlbGVjdGVkIFNTUCwgb3IgTlVMTCBpZiBub3QgZm91bmQK
KyAqLworc3RydWN0IGludGVsX21pZF9pMnNfaGRsICppbnRlbF9taWRfaTJzX29wZW4oZW51bSBp
bnRlbF9taWRfaTJzX3NzcF91c2FnZSB1c2FnZSwKKwkJCSBjb25zdCBzdHJ1Y3QgaW50ZWxfbWlk
X2kyc19zZXR0aW5ncyAqcHNfc2V0dGluZ3MpCit7CisJc3RydWN0IHBjaV9kZXYgKnBkZXY7CisJ
c3RydWN0IGludGVsX21pZF9pMnNfaGRsICpkcnZfZGF0YSA9IE5VTEw7CisJc3RydWN0IGRldmlj
ZSAqZm91bmRfZGV2aWNlID0gTlVMTDsKKwlwcl9kZWJ1ZygiJXMgOiBvcGVuIGNhbGxlZCxzZWFy
Y2hpbmcgZm9yIGRldmljZSB3aXRoIHVzYWdlPSV4ICFcbiIsIERSSVZFUl9OQU1FLCB1c2FnZSk7
CisJZm91bmRfZGV2aWNlID0gZHJpdmVyX2ZpbmRfZGV2aWNlKCYoaW50ZWxfbWlkX2kyc19kcml2
ZXIuZHJpdmVyKSwgTlVMTCwgJnVzYWdlLCBjaGVja19kZXZpY2UpOworCWlmICghZm91bmRfZGV2
aWNlKSB7CisJCXByX2RlYnVnKCIlcyA6IG9wZW4gY2FuIG5vdCBmb3VuZCB3aXRoIHVzYWdlPTB4
JTAyWFxuIiwgRFJJVkVSX05BTUUsIChpbnQpdXNhZ2UpOworCQlyZXR1cm4gTlVMTDsKKwl9CisJ
cGRldiA9IHRvX3BjaV9kZXYoZm91bmRfZGV2aWNlKTsKKwlkcnZfZGF0YSA9IHBjaV9nZXRfZHJ2
ZGF0YShwZGV2KTsKKworCWlmICghZHJ2X2RhdGEpIHsKKwkJZGV2X2Vycihmb3VuZF9kZXZpY2Us
ICJubyBkcnZfZGF0YSBpbiBvcGVuIHBkZXY9JXBcbiIsIHBkZXYpOworCQlwdXRfZGV2aWNlKGZv
dW5kX2RldmljZSk7CisJCXJldHVybiBOVUxMOworCX0KKwltdXRleF9sb2NrKCZkcnZfZGF0YS0+
bXV0ZXgpOworCWRldl9kYmcoZm91bmRfZGV2aWNlLCAiT3BlbiBmb3VuZCBwZGV2aWNlPTB4JXBc
biIsIHBkZXYpOworCS8qIHBtX3J1bnRpbWUgKi8KKwlwbV9ydW50aW1lX2dldF9zeW5jKCZkcnZf
ZGF0YS0+cGRldi0+ZGV2KTsKKwkvKiBkbWFjMSBpcyBhbHJlYWR5IHNldCBkdXJpbmcgcHJvYmUg
Ki8KKwlpZiAoaTJzX2RtYV9zdGFydChkcnZfZGF0YSkgIT0gMCkgeworCQlkZXZfZXJyKGZvdW5k
X2RldmljZSwgIkNhbiBub3Qgc3RhcnQgRE1BXG4iKTsKKwkJZ290byBvcGVuX2Vycm9yOworCX0K
KwkvKiBpZiB3ZSByZXN0YXJ0IGFmdGVyIHN0b3Agd2l0aG91dCBzdXNwZW5kLCB3ZSBzdGFydCBz
c3AgZmFzdGVyICovCisJZHJ2X2RhdGEtPmN1cnJlbnRfc2V0dGluZ3MgPSAqcHNfc2V0dGluZ3M7
CisJc2V0X3NzcF9pMnNfaHcoZHJ2X2RhdGEsIHBzX3NldHRpbmdzKTsKKworCWRydl9kYXRhLT5t
YXNrX3NyID0gKChTU1NSX0JDRV9NQVNLIDw8IFNTU1JfQkNFX1NISUZUKSB8CisJCQkoU1NTUl9F
T0NfTUFTSyA8PCBTU1NSX0VPQ19TSElGVCkgfAorCQkJKFNTU1JfUk9SX01BU0sgPDwgU1NTUl9S
T1JfU0hJRlQpIHwKKwkJCShTU1NSX1RVUl9NQVNLIDw8IFNTU1JfVFVSX1NISUZUKSB8CisJCQko
U1NTUl9USU5UX01BU0sgPDwgU1NTUl9USU5UX1NISUZUKSB8CisJCQkoU1NTUl9QSU5UX01BU0sg
PDwgU1NTUl9QSU5UX1NISUZUKSk7CisJaWYgKHRlc3RfYml0KEkyU19QT1JUX0NMT1NJTkcsICZk
cnZfZGF0YS0+ZmxhZ3MpKSB7CisJCWRldl9lcnIoJmRydl9kYXRhLT5wZGV2LT5kZXYsICJPcGVu
aW5nIGEgY2xvc2luZyBJMlMhIik7CisJCWdvdG8gb3Blbl9lcnJvcjsKKwl9CisJLyogdGhlcmUg
aXMgbm8gbmVlZCB0byAid2FrZSB1cCIgYXMgd2UgY2FuIG5vdCBjbG9zZSBhbiBvcGVuaW5nIGky
cyAqLworCWNsZWFyX2JpdChJMlNfUE9SVF9XUklURV9CVVNZLCAmZHJ2X2RhdGEtPmZsYWdzKTsK
KwljbGVhcl9iaXQoSTJTX1BPUlRfUkVBRF9CVVNZLCAmZHJ2X2RhdGEtPmZsYWdzKTsKKwltdXRl
eF91bmxvY2soJmRydl9kYXRhLT5tdXRleCk7CisJcmV0dXJuIGRydl9kYXRhOworCitvcGVuX2Vy
cm9yOgorCXB1dF9kZXZpY2UoZm91bmRfZGV2aWNlKTsKKwltdXRleF91bmxvY2soJmRydl9kYXRh
LT5tdXRleCk7CisJcmV0dXJuIE5VTEw7Cit9CitFWFBPUlRfU1lNQk9MX0dQTChpbnRlbF9taWRf
aTJzX29wZW4pOworCisvKioKKyAqIGludGVsX21pZF9pMnNfY2xvc2UgLSByZWxlYXNlIGFuZCBz
dG9wIHRoZSBTU1AKKyAqIEBkcnZfZGF0YSA6IGhhbmRsZSBvZiBjb3JyZXNwb25kaW5nIHNzcCBp
MnMgKGdpdmVuIGJ5IGkyc19vcGVuIGZ1bmN0aW9uKQorICoKKyAqIFdBUk5JTkc6IFRoaXMgaXMg
bm90IC15ZXQtIGFsbG93ZWQgdG8gY2FsbCBjbG9zZSBmcm9tIGEgcmVhZC93cml0ZSBjYWxsYmFj
ayAhCisgKgorICogT3V0cHV0IHBhcmFtZXRlcnMKKyAqICAgICAgbm9uZQorICovCit2b2lkIGlu
dGVsX21pZF9pMnNfY2xvc2Uoc3RydWN0IGludGVsX21pZF9pMnNfaGRsICpkcnZfZGF0YSkKK3sK
Kwl2b2lkIF9faW9tZW0gKnJlZzsKKwlXQVJOKCFkcnZfZGF0YSwgIkRyaXZlciBkYXRhPU5VTExc
biIpOworCWlmICghZHJ2X2RhdGEpCisJCXJldHVybjsKKwltdXRleF9sb2NrKCZkcnZfZGF0YS0+
bXV0ZXgpOworCWlmICghdGVzdF9iaXQoSTJTX1BPUlRfT1BFTkVELCAmZHJ2X2RhdGEtPmZsYWdz
KSkgeworCQlkZXZfZXJyKCZkcnZfZGF0YS0+cGRldi0+ZGV2LCAibm90IG9wZW5lZCBidXQgY2xv
c2luZz8iKTsKKwkJbXV0ZXhfdW5sb2NrKCZkcnZfZGF0YS0+bXV0ZXgpOworCQlyZXR1cm47CisJ
fQorCS8qIHRvIGJlIG1vZGlmaWVkIHRvIHdhaXRfZXZlbnRfaW50ZXJydXB0aWJsZV90aW1lb3V0
ICovCisJc2V0X2JpdChJMlNfUE9SVF9DTE9TSU5HLCAmZHJ2X2RhdGEtPmZsYWdzKTsKKwlkZXZf
ZGJnKCZkcnZfZGF0YS0+cGRldi0+ZGV2LCAiU3RhdHVzIGJpdCBwZW5kaW5nIHdyaXRlPSVkIHJl
YWQ9JWRcbiIsCisJCQl0ZXN0X2JpdChJMlNfUE9SVF9XUklURV9CVVNZLCAmZHJ2X2RhdGEtPmZs
YWdzKSwKKwkJCXRlc3RfYml0KEkyU19QT1JUX1JFQURfQlVTWSwgJmRydl9kYXRhLT5mbGFncykp
OworCWlmICh0ZXN0X2JpdChJMlNfUE9SVF9XUklURV9CVVNZLCAmZHJ2X2RhdGEtPmZsYWdzKSB8
fAorCSAgICAgdGVzdF9iaXQoSTJTX1BPUlRfUkVBRF9CVVNZLCAmZHJ2X2RhdGEtPmZsYWdzKSkg
eworCQlkZXZfZGJnKCZkcnZfZGF0YS0+cGRldi0+ZGV2LCAiUGVuZGluZyBjYWxsYmFjayBpbiBj
bG9zZS4uLlxuIik7CisJfQorCisJLyogd2FpdGluZyBiZWxvdy4gVG8gYmUgcmVwbGFjZWQgd2hl
biAiRE1BX1RFUk1JTkFURV9BTEwiIGZpeCBhdmFpbGFibGUgKi8KKwl3YWl0X2V2ZW50KGRydl9k
YXRhLT53cV9jaGFuX2Nsb3NpbmcsCisJCSgoIXRlc3RfYml0KEkyU19QT1JUX1dSSVRFX0JVU1ks
ICZkcnZfZGF0YS0+ZmxhZ3MpKSAmJgorCQkgKCF0ZXN0X2JpdChJMlNfUE9SVF9SRUFEX0JVU1ks
ICAmZHJ2X2RhdGEtPmZsYWdzKSkpKTsKKwkvKiByZWxlYXNlIERNQSBDaGFubmVsLi4gKi8KKwlp
MnNfZG1hX3N0b3AoZHJ2X2RhdGEpOworCXJlZyA9IGRydl9kYXRhLT5pb2FkZHI7CisJZGV2X2Ri
ZygmZHJ2X2RhdGEtPnBkZXYtPmRldiwgIlN0b3BwaW5nIHRoZSBTU1BcbiIpOworCWkyc19zc3Bf
c3RvcChkcnZfZGF0YSk7CisJcHV0X2RldmljZSgmZHJ2X2RhdGEtPnBkZXYtPmRldik7CisJd3Jp
dGVfU1NDUjAoMCwgcmVnKTsKKwkvKiBwbSBydW50aW1lICovCisJcG1fcnVudGltZV9wdXQoJmRy
dl9kYXRhLT5wZGV2LT5kZXYpOworCWRldl9kYmcoJihkcnZfZGF0YS0+cGRldi0+ZGV2KSwgIlNT
UCBTdG9wcGVkLlxuIik7CisJY2xlYXJfYml0KEkyU19QT1JUX0NMT1NJTkcsICZkcnZfZGF0YS0+
ZmxhZ3MpOworCWNsZWFyX2JpdChJMlNfUE9SVF9PUEVORUQsICZkcnZfZGF0YS0+ZmxhZ3MpOwor
CW11dGV4X3VubG9jaygmZHJ2X2RhdGEtPm11dGV4KTsKK30KK0VYUE9SVF9TWU1CT0xfR1BMKGlu
dGVsX21pZF9pMnNfY2xvc2UpOworLyoKKyAqIElOVEVSTkFMIEZVTkNUSU9OUworICovCisKKy8q
KgorICogY2hlY2tfZGV2aWNlIC0gIHJldHVybiBpZiB0aGUgZGV2aWNlIGlzIHRoZSB1c2FnZSB3
ZSB3YW50ICh1c2FnZSA9KmRhdGEpCisgKiBAZGV2aWNlX3B0ciA6IHBvaW50ZXIgb24gZGV2aWNl
IHN0cnVjdAorICogQGRhdGEgOiBwb2ludGVyIHBvaW50ZXIgb24gdXNhZ2Ugd2UgYXJlIGxvb2tp
bmcgZm9yCisgKgorICogdGhpcyBpcyBjYWxsZWQgZm9yIGVhY2ggZGV2aWNlIGJ5IGZpbmRfZGV2
aWNlKCkgZnJvbSBpbnRlbF9taWRfaTJzX29wZW4oKQorICogSW5mbyA6IHdoZW4gZm91bmQsIHRo
ZSBmbGFnIG9mIGRyaXZlciBpcyBzZXQgdG8gSTJTX1BPUlRfT1BFTkVECisgKgorICogT3V0cHV0
IHBhcmFtZXRlcnMKKyAqICAgICAgaW50ZWdlciA6IHJldHVybiAwIG1lYW5zIG5vdCB0aGUgZGV2
aWNlIG9yIGFscmVhZHkgc3RhcnRlZC4gZ28gbmV4dAorICoJCSAgcmV0dXJuICE9IDAgbWVhbnMg
c3RvcCB0aGUgc2VhcmNoIGFuZCByZXR1cm4gdGhpcyBkZXZpY2UKKyAqLworc3RhdGljIGludAor
Y2hlY2tfZGV2aWNlKHN0cnVjdCBkZXZpY2UgKmRldmljZV9wdHIsIHZvaWQgKmRhdGEpCit7CisJ
c3RydWN0IHBjaV9kZXYgKnBkZXY7CisJc3RydWN0IGludGVsX21pZF9pMnNfaGRsICpkcnZfZGF0
YTsKKwllbnVtIGludGVsX21pZF9pMnNfc3NwX3VzYWdlIHVzYWdlOworCWVudW0gaW50ZWxfbWlk
X2kyc19zc3BfdXNhZ2UgdXNhZ2VfdG9fZmluZDsKKworCXBkZXYgPSB0b19wY2lfZGV2KGRldmlj
ZV9wdHIpOworCVdBUk4oIXBkZXYsICJQY2kgZGV2aWNlPU5VTExcbiIpOworCWlmICghcGRldikK
KwkJcmV0dXJuIDA7CisJZHJ2X2RhdGEgPSAoc3RydWN0IGludGVsX21pZF9pMnNfaGRsICopIHBj
aV9nZXRfZHJ2ZGF0YShwZGV2KTsKKwlXQVJOKCFkcnZfZGF0YSwgIkRyaXZlciBkYXRhPU5VTExc
biIpOworCWlmICghZHJ2X2RhdGEpCisJCXJldHVybiAwOworCWRldl9kYmcoJihwZGV2LT5kZXYp
LCAiQ2hlY2sgZGV2aWNlIHBjaV9kZXYgcHRyID0gMFglcFxuIiwgcGRldik7CisJdXNhZ2VfdG9f
ZmluZCA9ICooKGVudW0gaW50ZWxfbWlkX2kyc19zc3BfdXNhZ2UgKikgZGF0YSk7CisJdXNhZ2Ug
PSBkcnZfZGF0YS0+dXNhZ2U7CisKKwkvKiBDYW4gYmUgZG9uZSBpbiBvbmUgImlmIiBidXQgc2Vw
YXJhdGVkIGluIHB1cnBvc2UgOiB0YWtlIGNhcmUgb2YKKwkgKiB0ZXN0X2FuZF9zZXRfYml0IHRo
YXQgbmVlZCB0byBiZSBkb25lIEFGVEVSIHRoZSBjaGVjayBvbiB1c2FnZS4KKwkgKi8KKwlpZiAo
dXNhZ2UgPT0gdXNhZ2VfdG9fZmluZCkgeworCQlpZiAoIXRlc3RfYW5kX3NldF9iaXQoSTJTX1BP
UlRfT1BFTkVELCAmZHJ2X2RhdGEtPmZsYWdzKSkKKwkJCXJldHVybiAxOyAgLyogQWxyZWFkeSBv
cGVuZWQsIGRvIG5vdCB1c2UgdGhpcyByZXN1bHQgKi8KKwl9OworCXJldHVybiAwOyAvKiBub3Qg
dXNhZ2Ugd2UgbG9vayBmb3IsIG9yIGFscmVhZHkgb3BlbmVkICovCit9CisKKy8qKgorICogaTJz
X3JlYWRfZG9uZSAtIGNhbGxiYWNrIGZyb20gdGhlIF9kbWEgdGFza2xldF8gYWZ0ZXIgcmVhZAor
ICogQGFyZyA6IHZvaWQgcG9pbnRlciB0byB0aGF0IHNob3VsZCBiZSBkcml2ZXIgZGF0YSAoY29u
dGV4dCkKKyAqCisgKiBPdXRwdXQgcGFyYW1ldGVycworICogICAgICBub25lCisgKi8KK3N0YXRp
YyB2b2lkIGkyc19yZWFkX2RvbmUodm9pZCAqYXJnKQoreworCWludCBzdGF0dXMgPSAwOworCisJ
c3RydWN0IGludGVsX21pZF9pMnNfaGRsICpkcnZfZGF0YSA9IGFyZzsKKwl2b2lkICpwYXJhbV9j
b21wbGV0ZTsKKwl2b2lkIF9faW9tZW0gKnJlZyA7CisKKwlXQVJOKCFkcnZfZGF0YSwgIkRyaXZl
ciBkYXRhPU5VTExcbiIpOworCWlmICghZHJ2X2RhdGEpCisJCXJldHVybjsKKwltdXRleF9sb2Nr
KCZkcnZfZGF0YS0+bXV0ZXgpOworCWlmICghdGVzdF9iaXQoSTJTX1BPUlRfUkVBRF9CVVNZLCAm
ZHJ2X2RhdGEtPmZsYWdzKSkKKwkJZGV2X1dBUk4oJmRydl9kYXRhLT5wZGV2LT5kZXYsICJzcHVy
aW91cyByZWFkIGRtYSBjb21wbGV0ZSIpOworCisJZG1hX3VubWFwX3NpbmdsZShOVUxMLCBkcnZf
ZGF0YS0+cmVhZF9kc3QsCisJCQkgZHJ2X2RhdGEtPnJlYWRfbGVuLCBETUFfRlJPTV9ERVZJQ0Up
OworCWRydl9kYXRhLT5yZWFkX2xlbiA9IDA7CisJcmVnID0gZHJ2X2RhdGEtPmlvYWRkcjsKKwkv
KiBSeCBmaWZvIG92ZXJydW4gSW50ZXJydXB0ICovCisJY2hhbmdlX1NTQ1IwX3JlZyhyZWcsIFJJ
TSwgU1NQX1JYX0ZJRk9fT1ZFUl9JTlRfRElTQUJMRSk7CisJcGFyYW1fY29tcGxldGUgPSBkcnZf
ZGF0YS0+cmVhZF9wYXJhbTsKKwkvKiBEbyBub3QgY2hhbmdlIG9yZGVyIHNlcXVlbmNlOgorCSAq
IFJFQURfQlVTWSBjbGVhciwgdGhlbiB0ZXN0IFBPUlRfQ0xPU0lORworCSAqIHdha2V1cCBmb3Ig
Y2xvc2UoKSBmdW5jdGlvbgorCSAqLworCWNsZWFyX2JpdChJMlNfUE9SVF9SRUFEX0JVU1ksICZk
cnZfZGF0YS0+ZmxhZ3MpOworCXdha2VfdXAoJmRydl9kYXRhLT53cV9jaGFuX2Nsb3NpbmcpOwor
CWlmICh0ZXN0X2JpdChJMlNfUE9SVF9DTE9TSU5HLCAmZHJ2X2RhdGEtPmZsYWdzKSkgeworCQlk
ZXZfZGJnKCZkcnZfZGF0YS0+cGRldi0+ZGV2LCAicmVhZCBkb25lIHdha2luZyB1cCBjbG9zZSIp
OworCQltdXRleF91bmxvY2soJmRydl9kYXRhLT5tdXRleCk7CisJCXJldHVybjsKKwl9CisJbXV0
ZXhfdW5sb2NrKCZkcnZfZGF0YS0+bXV0ZXgpOworCWlmIChkcnZfZGF0YS0+cmVhZF9jYWxsYmFj
ayAhPSBOVUxMKQorCQlzdGF0dXMgPSBkcnZfZGF0YS0+cmVhZF9jYWxsYmFjayhwYXJhbV9jb21w
bGV0ZSk7CisJZWxzZQorCQlkZXZfd2FybigmZHJ2X2RhdGEtPnBkZXYtPmRldiwgIlJEIGRvbmUg
YnV0IG5vdCBjYWxsYmFjayBzZXQiKTsKKworfQorCisvKioKKyAqIGkyc193cml0ZV9kb25lKCkg
OiBjYWxsYmFjayBmcm9tIHRoZSBfZG1hIHRhc2tsZXRfIGFmdGVyIHdyaXRlCisgKiBAYXJnIDog
dm9pZCBwb2ludGVyIHRvIHRoYXQgc2hvdWxkIGJlIGRyaXZlciBkYXRhIChjb250ZXh0KQorICoK
KyAqIE91dHB1dCBwYXJhbWV0ZXJzCisgKiAgICAgIG5vbmUKKyAqLworc3RhdGljIHZvaWQgaTJz
X3dyaXRlX2RvbmUodm9pZCAqYXJnKQoreworCWludCBzdGF0dXMgPSAwOworCXZvaWQgKnBhcmFt
X2NvbXBsZXRlOworCXN0cnVjdCBpbnRlbF9taWRfaTJzX2hkbCAqZHJ2X2RhdGEgPSBhcmc7CisJ
dm9pZCBfX2lvbWVtICpyZWcgOworCisJV0FSTighZHJ2X2RhdGEsICJEcml2ZXIgZGF0YT1OVUxM
XG4iKTsKKwlpZiAoIWRydl9kYXRhKQorCQlyZXR1cm47CisJbXV0ZXhfbG9jaygmZHJ2X2RhdGEt
Pm11dGV4KTsKKwlpZiAoIXRlc3RfYml0KEkyU19QT1JUX1dSSVRFX0JVU1ksICZkcnZfZGF0YS0+
ZmxhZ3MpKQorCQlkZXZfd2FybigmZHJ2X2RhdGEtPnBkZXYtPmRldiwgInNwdXJpb3VzIHdyaXRl
IGRtYSBjb21wbGV0ZSIpOworCWRtYV91bm1hcF9zaW5nbGUoTlVMTCwgZHJ2X2RhdGEtPnJlYWRf
ZHN0LAorCQkJIGRydl9kYXRhLT5yZWFkX2xlbiwgRE1BX1RPX0RFVklDRSk7CisJZHJ2X2RhdGEt
PnJlYWRfbGVuID0gMDsKKwlyZWcgPSBkcnZfZGF0YS0+aW9hZGRyOworCWNoYW5nZV9TU0NSMF9y
ZWcocmVnLCBUSU0sIFNTUF9UWF9GSUZPX1VOREVSX0lOVF9ESVNBQkxFKTsKKwlkZXZfZGJnKCYo
ZHJ2X2RhdGEtPnBkZXYtPmRldiksICJETUEgY2hhbm5lbCBkaXNhYmxlLi5cbiIpOworCXBhcmFt
X2NvbXBsZXRlID0gZHJ2X2RhdGEtPndyaXRlX3BhcmFtOworCS8qIERvIG5vdCBjaGFuZ2Ugb3Jk
ZXIgc2VxdWVuY2U6CisJICogV1JJVEVfQlVTWSBjbGVhciwgdGhlbiB0ZXN0IFBPUlRfQ0xPU0lO
RworCSAqIHdha2V1cCBmb3IgY2xvc2UoKSBmdW5jdGlvbgorCSAqLworCWNsZWFyX2JpdChJMlNf
UE9SVF9XUklURV9CVVNZLCAmZHJ2X2RhdGEtPmZsYWdzKTsKKwl3YWtlX3VwKCZkcnZfZGF0YS0+
d3FfY2hhbl9jbG9zaW5nKTsKKwlpZiAodGVzdF9iaXQoSTJTX1BPUlRfQ0xPU0lORywgJmRydl9k
YXRhLT5mbGFncykpIHsKKwkJbXV0ZXhfdW5sb2NrKCZkcnZfZGF0YS0+bXV0ZXgpOworCQlkZXZf
ZGJnKCZkcnZfZGF0YS0+cGRldi0+ZGV2LCAid3JpdGUgZG9uZSB3YWtpbmcgdXAgY2xvc2UiKTsK
KwkJcmV0dXJuOworCX0KKwltdXRleF91bmxvY2soJmRydl9kYXRhLT5tdXRleCk7CisJaWYgKGRy
dl9kYXRhLT53cml0ZV9jYWxsYmFjayAhPSBOVUxMKQorCQlzdGF0dXMgPSBkcnZfZGF0YS0+d3Jp
dGVfY2FsbGJhY2socGFyYW1fY29tcGxldGUpOworCWVsc2UKKwkJZGV2X3dhcm4oJmRydl9kYXRh
LT5wZGV2LT5kZXYsICJXUiBkb25lIGJ1dCBubyBjYWxsYmFjayBzZXQiKTsKK30KKworc3RhdGlj
IGJvb2wgY2hhbl9maWx0ZXIoc3RydWN0IGRtYV9jaGFuICpjaGFuLCB2b2lkICpwYXJhbSkKK3sK
KwlzdHJ1Y3QgaW50ZWxfbWlkX2kyc19oZGwgKmRydl9kYXRhID0gKHN0cnVjdCBpbnRlbF9taWRf
aTJzX2hkbCAqKXBhcmFtOworCWJvb2wgcmV0ID0gZmFsc2U7CisKKwlpZiAoIWRydl9kYXRhLT5k
bWFjMSkKKwkJZ290byBvdXQ7CisJaWYgKGNoYW4tPmRldmljZS0+ZGV2ID09ICZkcnZfZGF0YS0+
ZG1hYzEtPmRldikKKwkJcmV0ID0gdHJ1ZTsKK291dDoKKwlyZXR1cm4gcmV0OworfQorCisvKioK
KyAqIGkyc19kbWFfc3RhcnQgLSBwcmVwYXJlIGFuZCByZXNlcnZlIGRtYSBjaGFubmVscworICog
QGFyZyA6IGludGVsX21pZF9pMnNfaGRsIHBvaW50ZXIgdG8gdGhhdCBzaG91bGQgYmUgZHJpdmVy
IGRhdGEgKGNvbnRleHQpCisgKgorICogInNzcCBvcGVuIiBjb250ZXh0IGFuZCBkbWFjMSBzaG91
bGQgYWxyZWFkeSBiZSBmaWxsZWQgaW4gZHJ2X2RhdGEKKyAqCisgKiBPdXRwdXQgcGFyYW1ldGVy
cworICogICAgICBpbnQgOiBzaG91bGQgYmUgemVybywgZWxzZSBpdCBtZWFucyBlcnJvciBjb2Rl
CisgKi8KK3N0YXRpYyBpbnQgaTJzX2RtYV9zdGFydChzdHJ1Y3QgaW50ZWxfbWlkX2kyc19oZGwg
KmRydl9kYXRhKQoreworCXN0cnVjdCBpbnRlbF9taWRfZG1hX3NsYXZlICpyeHMsICp0eHM7CisJ
ZG1hX2NhcF9tYXNrX3QgbWFzazsKKwlpbnQgcmV0dmFsID0gMDsKKwlzdHJ1Y3QgcGNpX2RldiAq
bF9wZGV2OworCisJZGV2X2RiZygmZHJ2X2RhdGEtPnBkZXYtPmRldiwgIkRNQUMxIHN0YXJ0XG4i
KTsKKwlkcnZfZGF0YS0+dHhjaGFuID0gTlVMTDsKKwlkcnZfZGF0YS0+cnhjaGFuID0gTlVMTDsK
KwlsX3BkZXYgPSBkcnZfZGF0YS0+cGRldjsKKwkvKiAxLiBpbml0IHJ4IGNoYW5uZWwgKi8KKwly
eHMgPSAmZHJ2X2RhdGEtPmRtYXNfcng7CisJcnhzLT5kaXJuID0gRE1BX0ZST01fREVWSUNFOwor
CXJ4cy0+aHNfbW9kZSA9IExOV19ETUFfSFdfSFM7CisJcnhzLT5jZmdfbW9kZSA9IExOV19ETUFf
UEVSX1RPX01FTTsKKwlyeHMtPnNyY193aWR0aCA9IExOV19ETUFfV0lEVEhfMTZCSVQ7CisJcnhz
LT5kc3Rfd2lkdGggPSBMTldfRE1BX1dJRFRIXzMyQklUOworCXJ4cy0+c3JjX21zaXplID0gTE5X
X0RNQV9NU0laRV84OworCXJ4cy0+ZHN0X21zaXplID0gTE5XX0RNQV9NU0laRV84OworCXJ4cy0+
ZGV2aWNlX2luc3RhbmNlID0gZHJ2X2RhdGEtPmRldmljZV9pbnN0YW5jZTsKKwlkbWFfY2FwX3pl
cm8obWFzayk7CisJZG1hX2NhcF9zZXQoRE1BX01FTUNQWSwgbWFzayk7CisJZG1hX2NhcF9zZXQo
RE1BX1NMQVZFLCBtYXNrKTsKKwlkcnZfZGF0YS0+cnhjaGFuID0gZG1hX3JlcXVlc3RfY2hhbm5l
bChtYXNrLCBjaGFuX2ZpbHRlciwgZHJ2X2RhdGEpOworCWlmICghZHJ2X2RhdGEtPnJ4Y2hhbikg
eworCQlkZXZfZXJyKCYoZHJ2X2RhdGEtPnBkZXYtPmRldiksCisJCQkiQ291bGQgbm90IGdldCBS
eCBjaGFubmVsXG4iKTsKKwkJcmV0dmFsID0gLTI7CisJCWdvdG8gZXJyX2V4aXQ7CisJfQorCWRy
dl9kYXRhLT5yeGNoYW4tPnByaXZhdGUgPSByeHM7CisJLyogMi4gaW5pdCB0eCBjaGFubmVsICov
CisJdHhzID0gJmRydl9kYXRhLT5kbWFzX3R4OworCXR4cy0+ZGlybiA9IERNQV9UT19ERVZJQ0U7
CisJdHhzLT5oc19tb2RlID0gTE5XX0RNQV9IV19IUzsKKwl0eHMtPmNmZ19tb2RlID0gTE5XX0RN
QV9NRU1fVE9fUEVSOworCXR4cy0+c3JjX3dpZHRoID0gTE5XX0RNQV9XSURUSF8zMkJJVDsKKwl0
eHMtPmRzdF93aWR0aCA9IExOV19ETUFfV0lEVEhfMTZCSVQ7CisJdHhzLT5zcmNfbXNpemUgPSBM
TldfRE1BX01TSVpFXzg7CisJdHhzLT5kc3RfbXNpemUgPSBMTldfRE1BX01TSVpFXzg7CisJdHhz
LT5kZXZpY2VfaW5zdGFuY2UgPSBkcnZfZGF0YS0+ZGV2aWNlX2luc3RhbmNlOworCWRtYV9jYXBf
c2V0KERNQV9TTEFWRSwgbWFzayk7CisJZG1hX2NhcF9zZXQoRE1BX01FTUNQWSwgbWFzayk7CisJ
ZHJ2X2RhdGEtPnR4Y2hhbiA9IGRtYV9yZXF1ZXN0X2NoYW5uZWwobWFzaywgY2hhbl9maWx0ZXIs
IGRydl9kYXRhKTsKKwlpZiAoIWRydl9kYXRhLT50eGNoYW4pIHsKKwkJZGV2X2VycigmKGRydl9k
YXRhLT5wZGV2LT5kZXYpLAorCQkJIkNvdWxkIG5vdCBnZXQgVHggY2hhbm5lbFxuIik7CisJCXJl
dHZhbCA9IC0zOworCQlnb3RvIGZyZWVfcnhjaGFuOworCX0KKwlkcnZfZGF0YS0+dHhjaGFuLT5w
cml2YXRlID0gdHhzOworCXJldHVybiByZXR2YWw7CitmcmVlX3J4Y2hhbjoKKwlkbWFfcmVsZWFz
ZV9jaGFubmVsKGRydl9kYXRhLT5yeGNoYW4pOworZXJyX2V4aXQ6CisJcmV0dXJuIHJldHZhbDsK
K30KKworLyoqCisgKiBpMnNfZG1hX3N0b3AgLSByZWxlYXNlIGRtYSBjaGFubmVscworICogQGFy
ZyA6IHN0cnVjdCBpbnRlbF9taWRfaTJzX2hkbCBwb2ludGVyIHRvIHRoYXQgc2hvdWxkIGJlIGRy
aXZlciBkYXRhIChjb250ZXh0KQorICoKKyAqIGNhbGxlZCBieSBpbnRlbF9taWRfaTJzX2Nsb3Nl
KCkgY29udGV4dAorICoKKyAqIE91dHB1dCBwYXJhbWV0ZXJzCisgKiAgICAgIG5vbmUKKyAqLwor
c3RhdGljIHZvaWQgaTJzX2RtYV9zdG9wKHN0cnVjdCBpbnRlbF9taWRfaTJzX2hkbCAqZHJ2X2Rh
dGEpCit7CisJZGV2X2RiZygmZHJ2X2RhdGEtPnBkZXYtPmRldiwgIkRNQUMxIHN0b3BcbiIpOwor
CWRtYV9yZWxlYXNlX2NoYW5uZWwoZHJ2X2RhdGEtPnR4Y2hhbik7CisJZG1hX3JlbGVhc2VfY2hh
bm5lbChkcnZfZGF0YS0+cnhjaGFuKTsKK30KKworc3RhdGljIHZvaWQgaTJzX3NzcF9zdG9wKHN0
cnVjdCBpbnRlbF9taWRfaTJzX2hkbCAqZHJ2X2RhdGEpCit7CisJdm9pZCBfX2lvbWVtICpyZWcg
PSBkcnZfZGF0YS0+aW9hZGRyOworCWRldl9kYmcoJmRydl9kYXRhLT5wZGV2LT5kZXYsICJTdG9w
IFNTUFxuIik7CisJY2xlYXJfU1NDUjBfcmVnKHJlZywgU1NFKTsKK30KKworc3RhdGljIHZvaWQg
c3NwMV9kdW1wX3JlZ2lzdGVycyhzdHJ1Y3QgaW50ZWxfbWlkX2kyc19oZGwgKmRydl9kYXRhKQor
eworCXUzMiBpcnFfc3RhdHVzOworCXZvaWQgX19pb21lbSAqcmVnID0gZHJ2X2RhdGEtPmlvYWRk
cjsKKwlzdHJ1Y3QgZGV2aWNlICpkZGJnID0gJihkcnZfZGF0YS0+cGRldi0+ZGV2KTsKKwl1MzIg
c3RhdHVzOworCWlycV9zdGF0dXMgPSByZWFkX1NTU1IocmVnKTsKKwlkZXZfZGJnKGRkYmcsICJk
dW1wIFNTU1I9MHglMDhYXG4iLCBpcnFfc3RhdHVzKTsKKwlzdGF0dXMgPSByZWFkX1NTQ1IwKHJl
Zyk7CisJZGV2X2RiZyhkZGJnLCAiZHVtcCBTU0NSMD0weCUwOFhcbiIsIHN0YXR1cyk7CisJc3Rh
dHVzID0gcmVhZF9TU0NSMShyZWcpOworCWRldl9kYmcoZGRiZywgImR1bXAgU1NDUjE9MHglMDhY
XG4iLCBzdGF0dXMpOworCXN0YXR1cyA9IHJlYWRfU1NQU1AocmVnKTsKKwlkZXZfZGJnKGRkYmcs
ICJkdW1wIFNTUFNQPTB4JTA4WFxuIiwgc3RhdHVzKTsKKwlzdGF0dXMgPSByZWFkX1NTVFNBKHJl
Zyk7CisJZGV2X2RiZyhkZGJnLCAiZHVtcCBTU1RTQT0weCUwOFhcbiIsIHN0YXR1cyk7CisJc3Rh
dHVzID0gcmVhZF9TU1JTQShyZWcpOworCWRldl9kYmcoZGRiZywgImR1bXAgU1NSU0E9MHglMDhY
XG4iLCBzdGF0dXMpOworCXN0YXR1cyA9IHJlYWRfU1NUTyhyZWcpOworCWRldl9kYmcoZGRiZywg
ImR1bXAgU1NUTz0weCUwOFhcbiIsIHN0YXR1cyk7CisJc3RhdHVzID0gcmVhZF9TU0lUUihyZWcp
OworCWRldl9kYmcoZGRiZywgImR1bXAgU1NJVFI9MHglMDhYXG4iLCBzdGF0dXMpOworCXN0YXR1
cyA9IHJlYWRfU1NUU1MocmVnKTsKKwlkZXZfZGJnKGRkYmcsICJkdW1wIFNTVFNTPTB4JTA4WFxu
Iiwgc3RhdHVzKTsKKwlzdGF0dXMgPSByZWFkX1NTQUNEKHJlZyk7CisJZGV2X2RiZyhkZGJnLCAi
ZHVtcCBTU0FDRD0weCUwOFhcbiIsIHN0YXR1cyk7Cit9CisKKy8qKgorICogaTJzX2ludCgpOiBm
dW5jdGlvbiB0aGF0IGhhbmRsZXMgdGhlIFNTUCBJbnRlcnJ1cHRzIChlcnJvcnMpCisgKiBAaXJx
IDogSVJRIE51bWJlcgorICogQGRldl9pZCA6IHN0cnVjdHVyZSB0aGF0IGNvbnRhaW5zIGRyaXZl
ciBpbmZvcm1hdGlvbgorICoKKyAqIFRoaXMgaW50ZXJydXB0cyBkbyBub3RoaW5nIGJ1dCB3YXJu
aW5ncyBpbiBjYXNlIHRoZXJlIGlzIHNvbWUgcHJvYmxlbXMKKyAqIGluIEkyUyBjb25uZWN0aW9u
ICh1bmRlcnJ1bnMsIG92ZXJydW5zLi4uKS4gVGhpcyBtYXkgYmUgcmVwb3J0ZWQgYnkgYWRkaW5n
IGEKKyAqIG5ldyBpbnRlcmZhY2UgdG8gdGhlIGRyaXZlciwgYnV0IG5vdCB5ZXQgcmVxdWVzdGVk
IGJ5ICJ1c2VycyIgb2YgdGhpcyBkcml2ZXIKKyAqCisgKiBPdXRwdXQgcGFyYW1ldGVycworICog
ICAgICBOQQorICovCitzdGF0aWMgaXJxcmV0dXJuX3QgaTJzX2ludChpbnQgaXJxLCB2b2lkICpk
ZXZfaWQpCit7CisJc3RydWN0IGludGVsX21pZF9pMnNfaGRsICpkcnZfZGF0YSA9IGRldl9pZDsK
Kwl2b2lkIF9faW9tZW0gKnJlZzsKKwl1MzIgaXJxX3N0YXR1cyA9IDA7CisJdTMyIG1hc2tfc3Rh
dHVzID0gMDsKKwlzdHJ1Y3QgZGV2aWNlICpkZGJnID0gJihkcnZfZGF0YS0+cGRldi0+ZGV2KTsK
KwlyZWcgPSBkcnZfZGF0YS0+aW9hZGRyOworCWlycV9zdGF0dXMgPSByZWFkX1NTU1IocmVnKTsK
KworCWlmICghKGlycV9zdGF0dXMgJiAoZHJ2X2RhdGEtPm1hc2tfc3IpKSkgeworCQlyZXR1cm4g
SVJRX05PTkU7CisJfSBlbHNlIHsKKwkJLyogbWF5IGJlIGltcHJvdmVkIGJ5IHVzaW5nIGEgdGFz
a2xldCB0byBzZW5kIHRoZSBlcnJvcgorCQkgKiAodW5kZXJydW4sLi4uKSB0byBjbGllbnQgYnkg
dXNpbmcgY2FsbGJhY2sKKwkJICovCisJCWlmIChpcnFfc3RhdHVzICYgKFNTU1JfUk9SX01BU0sg
PDwgU1NTUl9ST1JfU0hJRlQpKSB7CisJCQlkZXZfd2FybihkZGJnLAorCQkJCSJzc3BfaW50IFJY
IEZJRk8gT1ZFUiBSVU4gU1NTUj0weCUwOFhcbiIsCisJCQkJaXJxX3N0YXR1cyk7CisJCQltYXNr
X3N0YXR1cyB8PSAoU1NTUl9ST1JfTUFTSyA8PCBTU1NSX1JPUl9TSElGVCk7CisKKwkJfQorCQlp
ZiAoaXJxX3N0YXR1cyAmIChTU1NSX1RVUl9NQVNLIDw8IFNTU1JfVFVSX1NISUZUKSkgeworCQkJ
ZGV2X3dhcm4oZGRiZywKKwkJCQkic3NwX2ludCBUWCBGSUZPIFVOREVSIFJVTiBTU1NSPTB4JTA4
WFxuIiwKKwkJCQlpcnFfc3RhdHVzKTsKKwkJCW1hc2tfc3RhdHVzIHw9IChTU1NSX1RVUl9NQVNL
IDw8IFNTU1JfVFVSX1NISUZUKTsKKworCQl9CisJCWlmIChpcnFfc3RhdHVzICYgKFNTU1JfVElO
VF9NQVNLIDw8IFNTU1JfVElOVF9TSElGVCkpIHsKKwkJCWRldl93YXJuKGRkYmcsCisJCQkJInNz
cF9pbnQgUlggVElNRSBPVVQgU1NTUj0weCUwOFhcbiIsCisJCQkJaXJxX3N0YXR1cyk7CisJCQlt
YXNrX3N0YXR1cyB8PSAoU1NTUl9USU5UX01BU0sgPDwgU1NTUl9USU5UX1NISUZUKTsKKworCQl9
CisJCWlmIChpcnFfc3RhdHVzICYgKFNTU1JfUElOVF9NQVNLIDw8IFNTU1JfUElOVF9TSElGVCkp
IHsKKwkJCWRldl93YXJuKGRkYmcsCisJCQkJInNzcF9pbnQgVFJBSUxJTkcgQllURSBTU1NSPTB4
JTA4WFxuIiwKKwkJCQlpcnFfc3RhdHVzKTsKKwkJCW1hc2tfc3RhdHVzIHw9IChTU1NSX1BJTlRf
TUFTSyA8PCBTU1NSX1BJTlRfU0hJRlQpOworCQl9CisJCWlmIChpcnFfc3RhdHVzICYgKFNTU1Jf
RU9DX01BU0sgPDwgU1NTUl9FT0NfU0hJRlQpKSB7CisJCQlkZXZfd2FybihkZGJnLAorCQkJCSJz
c3BfaW50IEVORCBPRiBDSEFJTiBTU1NSPTB4JTA4WFxuIiwKKwkJCQlpcnFfc3RhdHVzKTsKKwkJ
CW1hc2tfc3RhdHVzIHw9IChTU1NSX0VPQ19NQVNLIDw8IFNTU1JfRU9DX1NISUZUKTsKKwkJfQor
CQkvKiBjbGVhciBzdGlja3kgYml0cyAqLworCQl3cml0ZV9TU1NSKChpcnFfc3RhdHVzICYgbWFz
a19zdGF0dXMpLCByZWcpOworCX0KKwlyZXR1cm4gSVJRX0hBTkRMRUQ7Cit9CisKKy8qKgorICog
Y2FsY3VsYXRlX3NzcHNwX3BzcCAtIHNlcGFyYXRlIGZ1bmN0aW9uIHRoYXQgY2FsY3VsYXRlIHNz
cHNwIHJlZ2lzdGVyCisgKiBAcHNfc2V0dGluZ3MgOiBwb2ludGVyIG9mIHRoZSBzZXR0aW5ncyBz
dHJ1Y3QKKyAqCisgKiB0aGlzIGZ1bmN0aW9uIGlzIHRvIHNpbXBsaWZ5L2NsYXJpZnkgc2V0X3Nz
cF9pMnNfaHcgZnVuY3Rpb24KKyAqCisgKgorICogT3V0cHV0IHBhcmFtZXRlcnMKKyAqICAgICAg
dTMyIDogY2FsY3VsYXRlZCBTU1BTUCByZWdpc3RlcgorICovCit1MzIgY2FsY3VsYXRlX3NzcHNw
X3BzcChjb25zdCBzdHJ1Y3QgaW50ZWxfbWlkX2kyc19zZXR0aW5ncyAqcHNfc2V0dGluZ3MpCit7
CisJdTMyIHNzcHNwOworCXNzcHNwID0gU1NQU1BfcmVnKEZTUlQsCXBzX3NldHRpbmdzLT5zc3Bf
ZnJtc3luY190aW1pbmdfYml0KQorCQl8U1NQU1BfcmVnKEVURFMsCXBzX3NldHRpbmdzLT5zc3Bf
ZW5kX3RyYW5zZmVyX3N0YXRlKQorCQl8U1NQU1BfcmVnKFNDTU9ERSwJcHNfc2V0dGluZ3MtPnNz
cF9zZXJpYWxfY2xrX21vZGUpCisJCXxTU1BTUF9yZWcoRE1ZU1RPUCwJcHNfc2V0dGluZ3MtPnNz
cF9wc3BfVDQpCisJCXxTU1BTUF9yZWcoU0ZSTURMWSwJcHNfc2V0dGluZ3MtPnNzcF9wc3BfVDUp
CisJCXxTU1BTUF9yZWcoU0ZSTVdEVEgsCXBzX3NldHRpbmdzLT5zc3BfcHNwX1Q2KQorCQl8U1NQ
U1BfcmVnKFNGUk1QLAlwc19zZXR0aW5ncy0+c3NwX2ZybXN5bmNfcG9sX2JpdCk7CisJcmV0dXJu
IHNzcHNwOworfQorCisvKgorICogY2FsY3VsYXRlX3NzY3IwX3BzcDogc2VwYXJhdGUgZnVuY3Rp
b24gdGhhdCBjYWxjdWxhdGUgc3NjcjAgcmVnaXN0ZXIKKyAqIEBwc19zZXR0aW5ncyA6IHBvaW50
ZXIgb2YgdGhlIHNldHRpbmdzIHN0cnVjdAorICoKKyAqIHRoaXMgZnVuY3Rpb24gaXMgdG8gc2lt
cGxpZnkvY2xhcmlmeSBzZXRfc3NwX2kyc19odyBmdW5jdGlvbgorICoKKyAqIE91dHB1dCBwYXJh
bWV0ZXJzCisgKiAgICAgIHUzMiA6IGNhbGN1bGF0ZWQgU1NDUjAgcmVnaXN0ZXIKKyAqLwordTMy
IGNhbGN1bGF0ZV9zc2NyMF9wc3AoY29uc3Qgc3RydWN0IGludGVsX21pZF9pMnNfc2V0dGluZ3Mg
KnBzX3NldHRpbmdzKQoreworCXUxNiBsX3NzcF9kYXRhX3NpemUgPSBwc19zZXR0aW5ncy0+ZGF0
YV9zaXplOworCXUzMiBzc2NyMDsKKwlpZiAobF9zc3BfZGF0YV9zaXplID4gMTYpIHsKKwkJc3Nj
cjAgPSAgIFNTQ1IwX3JlZyhEU1MsIFNTQ1IwX0RhdGFTaXplKGxfc3NwX2RhdGFfc2l6ZSAtIDE2
KSkKKwkJCXwgU1NDUjBfcmVnKEVEU1MsIDEpOworCX0gZWxzZSB7CisJCXNzY3IwID0gICBTU0NS
MF9yZWcoRFNTLCBTU0NSMF9EYXRhU2l6ZShsX3NzcF9kYXRhX3NpemUpKQorCQkJfCBTU0NSMF9y
ZWcoRURTUywgMCk7CisJfQorLyoKK0NhbiBiZSByZXBsYWNlZCBieSBjb2RlIGJlbG93IDoKK3Nz
Y3IwID0gU1NDUjBfcmVnKERTUywgKGxfc3NwX2RhdGFfc2l6ZSAtIDEpICYgMHgwRikKK3wgU1ND
UjBfcmVnKEVEU1MsICgobF9zc3BfZGF0YV9zaXplIC0gMSkgJiAweDEwKSA+PiA4KTsKKyovCisJ
c3NjcjAgfD0gU1NDUjBfcmVnKE1PRCwJcHNfc2V0dGluZ3MtPm1vZGUpCisJCXxTU0NSMF9yZWco
RlJGLAlwc19zZXR0aW5ncy0+ZnJhbWVfZm9ybWF0KQorCQl8U1NDUjBfcmVnKFJJTSwJU1NQX1JY
X0ZJRk9fT1ZFUl9JTlRfRElTQUJMRSkKKwkJfFNTQ1IwX3JlZyhUSU0sCVNTUF9UWF9GSUZPX1VO
REVSX0lOVF9ESVNBQkxFKTsKKwlyZXR1cm4gc3NjcjA7Cit9CisKKy8qKgorICogY2FsY3VsYXRl
X3NzY3IxX3BzcCAtIHNlcGFyYXRlIGZ1bmN0aW9uIHRoYXQgY2FsY3VsYXRlIHNzY3IxIHJlZ2lz
dGVyCisgKiBAcHNfc2V0dGluZ3MgOiBwb2ludGVyIG9mIHRoZSBzZXR0aW5ncyBzdHJ1Y3QKKyAq
CisgKiB0aGlzIGZ1bmN0aW9uIGlzIHRvIHNpbXBsaWZ5L2NsYXJpZnkgc2V0X3NzcF9pMnNfaHcg
ZnVuY3Rpb24KKyAqCisgKiBPdXRwdXQgcGFyYW1ldGVycworICogICAgICB1MzIgOiBjYWxjdWxh
dGVkIFNTQ1IxIHJlZ2lzdGVyCisgKi8KK3UzMiBjYWxjdWxhdGVfc3NjcjFfcHNwKGNvbnN0IHN0
cnVjdCBpbnRlbF9taWRfaTJzX3NldHRpbmdzICpwc19zZXR0aW5ncykKK3sKKwl1MzIgc3NjcjE7
CisJc3NjcjEgPSBTU0NSMV9yZWcoU0ZSTURJUiwJcHNfc2V0dGluZ3MtPnNzcHNmcm1fZGlyZWN0
aW9uKQorCQl8U1NDUjFfcmVnKFNDTEtESVIsCXBzX3NldHRpbmdzLT5zc3BzbGNsa19kaXJlY3Rp
b24pCisJCXxTU0NSMV9yZWcoVFRFTFAsCXBzX3NldHRpbmdzLT50eF90cmlzdGF0ZV9waGFzZSkK
KwkJfFNTQ1IxX3JlZyhUVEUsCXBzX3NldHRpbmdzLT50eF90cmlzdGF0ZV9lbmFibGUpCisJCXxT
U0NSMV9yZWcoVFJBSUwsCXBzX3NldHRpbmdzLT5zc3BfdHJhaWxpbmdfYnl0ZV9tb2RlKQorCQl8
U1NDUjFfcmVnKFRJTlRFLAlwc19zZXR0aW5ncy0+c3NwX3J4X3RpbWVvdXRfaW50ZXJydXB0X3N0
YXR1cykKKwkJfFNTQ1IxX3JlZyhQSU5URSwJcHNfc2V0dGluZ3MtPnNzcF90cmFpbGluZ19ieXRl
X2ludGVycnVwdF9zdGF0dXMpCisJCXxTU0NSMV9yZWcoTEJNLAlwc19zZXR0aW5ncy0+c3NwX2xv
b3BiYWNrX21vZGVfc3RhdHVzKQorCQl8U1NDUjFfcmVnKFJXT1QsCXBzX3NldHRpbmdzLT5zc3Bf
ZHVwbGV4X21vZGUpCisJCXxTU0NSMV9yZWcoUkZULAlTU0NSMV9SeFRyZXNoKHBzX3NldHRpbmdz
LT5zc3BfcnhfZmlmb190aHJlc2hvbGQpKQorCQl8U1NDUjFfcmVnKFRGVCwJU1NDUjFfVHhUcmVz
aChwc19zZXR0aW5ncy0+c3NwX3R4X2ZpZm9fdGhyZXNob2xkKSk7CisJcmV0dXJuIHNzY3IxOwor
fQorCisvKioKKyAqIHNldF9zc3BfaTJzX2h3IC0gY29uZmlndXJlIHRoZSBTU1AgZHJpdmVyIGFj
Y29yZGluZyB0byB0aGUgcHNfc2V0dGluZ3MKKyAqIEBkcnZfZGF0YSA6IHN0cnVjdHVyZSB0aGF0
IGNvbnRhaW5zIGFsbCBkZXRhaWxzIGFib3V0IHRoZSBTU1AgRHJpdmVyCisgKiBAcHNfc2V0dGlu
Z3MgOiBzdHJ1Y3R1cmUgdGhhdCBjb250YWlucyBTU1AgSGFyZHdhcmUgc2V0dGluZ3MKKyAqCisg
KiBpdCBhbHNvIHN0b3JlIHBzX3NldHRpbmdzIHRoZSBkcnZfZGF0YQorICoKKyAqIE91dHB1dCBw
YXJhbWV0ZXJzCisgKiAgICAgIE5BCisgKi8KK3N0YXRpYyB2b2lkIHNldF9zc3BfaTJzX2h3KHN0
cnVjdCBpbnRlbF9taWRfaTJzX2hkbCAqZHJ2X2RhdGEsCisJCQljb25zdCBzdHJ1Y3QgaW50ZWxf
bWlkX2kyc19zZXR0aW5ncyAqcHNfc2V0dGluZ3MpCit7CisJdTMyIHNzY3IwID0gMDsKKwl1MzIg
c3NjcjEgPSAwOworCXUzMiBzc3RzYSA9IDA7CisJdTMyIHNzcnNhID0gMDsKKwl1MzIgc3Nwc3Ag
PSAwOworCXUzMiBzc3NyID0gMDsKKwkvKiBHZXQgdGhlIFNTUCBTZXR0aW5ncyAqLworCXUxNiBs
X3NzcF9jbGtfZnJtX21vZGUgPSAweEZGOworCXZvaWQgX19pb21lbSAqcmVnID0gZHJ2X2RhdGEt
PmlvYWRkcjsKKwlzdHJ1Y3QgZGV2aWNlICpkZGJnID0gJihkcnZfZGF0YS0+cGRldi0+ZGV2KTsK
KwlkZXZfZGJnKGRkYmcsCisJCSJzZXR1cCBTU1AgSTJTIFBDTTEgY29uZmlndXJhdGlvblxuIik7
CisJaWYgKChwc19zZXR0aW5ncy0+c3Nwc2ZybV9kaXJlY3Rpb24gPT0gU1NQU0ZSTV9NQVNURVJf
TU9ERSkKKwkgICAmJiAocHNfc2V0dGluZ3MtPnNzcHNsY2xrX2RpcmVjdGlvbiA9PSBTU1BTQ0xL
X01BU1RFUl9NT0RFKSkgeworCQlsX3NzcF9jbGtfZnJtX21vZGUgPSBTU1BfSU5fTUFTVEVSX01P
REU7CisJfSBlbHNlIGlmICgocHNfc2V0dGluZ3MtPnNzcHNmcm1fZGlyZWN0aW9uID09IFNTUFNG
Uk1fU0xBVkVfTU9ERSkKKwkgICAmJiAocHNfc2V0dGluZ3MtPnNzcHNsY2xrX2RpcmVjdGlvbiA9
PSBTU1BTQ0xLX1NMQVZFX01PREUpKSB7CisJCWxfc3NwX2Nsa19mcm1fbW9kZSA9IFNTUF9JTl9T
TEFWRV9NT0RFOworCX0gZWxzZSB7CisJCWRldl9lcnIoZGRiZywgIlVuc3VwcG9ydGVkIEkyUyBQ
Q00xIGNvbmZpZ3VyYXRpb25cbiIpOworCQlnb3RvIGxlYXZlOworCX0KKwlkZXZfZGJnKGRkYmcs
ICJTU1BTRlJNX0RJUkVDVElPTjolZDpcbiIsCisJCXBzX3NldHRpbmdzLT5zc3BzZnJtX2RpcmVj
dGlvbik7CisJZGV2X2RiZyhkZGJnLCAiU1NQU0NMS19ESVJFQ1RJT046JWQ6XG4iLAorCQlwc19z
ZXR0aW5ncy0+c3Nwc2xjbGtfZGlyZWN0aW9uKTsKKwlpZiAocHNfc2V0dGluZ3MtPmZyYW1lX2Zv
cm1hdCAhPSBQU1BfRk9STUFUKSB7CisJCWRldl9lcnIoZGRiZywgIlVOU1VQUE9SVEVEIEZSQU1F
IEZPUk1BVDolZDpcbiIsIHBzX3NldHRpbmdzLT5mcmFtZV9mb3JtYXQpOworCQlnb3RvIGxlYXZl
OworCX0KKwlpZiAoKHBzX3NldHRpbmdzLT5zc3BfdHhfZG1hICE9IFNTUF9UWF9ETUFfRU5BQkxF
KQorCXx8IChwc19zZXR0aW5ncy0+c3NwX3J4X2RtYSAhPSBTU1BfUlhfRE1BX0VOQUJMRSkpIHsK
KwkJZGV2X2VycihkZGJnLCAiT05MWSBETUEgTU9ERSBJUyBTVVBQT1JURUQiKTsKKwkJZ290byBs
ZWF2ZTsKKwl9CisJLyoqKioqKioqKioqIERNQSBUcmFuc2ZlciBNb2RlICoqKioqKioqKioqLwor
CWRldl9kYmcoZGRiZywgIkZPUk1BVCA6JWQ6XG4iLCBwc19zZXR0aW5ncy0+ZnJhbWVfZm9ybWF0
KTsKKwlzc2NyMCA9IGNhbGN1bGF0ZV9zc2NyMF9wc3AocHNfc2V0dGluZ3MpOworCWRldl9kYmco
ZGRiZywgIiBzc2NyMCA6MHglMDhYXG4iLCBzc2NyMCk7CisJc3NjcjEgPSBjYWxjdWxhdGVfc3Nj
cjFfcHNwKHBzX3NldHRpbmdzKTsKKwlkZXZfZGJnKGRkYmcsICIgc3NjcjEgOjB4JTA4WFxuIiwg
c3NjcjEpOworCWlmIChwc19zZXR0aW5ncy0+bW9kZSA9PSBTU1BfSU5fTkVUV09SS19NT0RFKSB7
CisJCWRldl9kYmcoZGRiZywgIk1PREUgOiVkOlxuIiwgcHNfc2V0dGluZ3MtPm1vZGUpOworCQlz
c2NyMCB8PSBTU0NSMF9yZWcoRlJEQywgU1NDUjBfU2xvdHNQZXJGcm0ocHNfc2V0dGluZ3MtPmZy
YW1lX3JhdGVfZGl2aWRlcl9jb250cm9sKSk7CisJCWRldl9kYmcoZGRiZywgInNzY3IwIDoweCUw
OFhcbiIsIHNzY3IwKTsKKwkJc3Nwc3AgPSBjYWxjdWxhdGVfc3Nwc3BfcHNwKHBzX3NldHRpbmdz
KTsKKwkJZGV2X2RiZyhkZGJnLCAic3Nwc3AgOjB4JTA4WFxuIiwgc3Nwc3ApOworCQkvKiBzZXQg
dGhlIGFjdGl2ZSBUWCB0aW1lIHNsb3QgKGJpdG1hcCkgKi8KKwkJc3N0c2EgPSBTU1RTQV9yZWco
VFRTQSwgcHNfc2V0dGluZ3MtPnNzcF9hY3RpdmVfdHhfc2xvdHNfbWFwKTsKKwkJLyogc2V0IHRo
ZSBhY3RpdmUgUlggdGltZSBzbG90IChiaXRtYXApICovCisJCXNzcnNhID0gU1NSU0FfcmVnKFJU
U0EsIHBzX3NldHRpbmdzLT5zc3BfYWN0aXZlX3J4X3Nsb3RzX21hcCk7CisJCWlmIChsX3NzcF9j
bGtfZnJtX21vZGUgPT0gU1NQX0lOX01BU1RFUl9NT0RFKSB7CisJCQlzd2l0Y2ggKHBzX3NldHRp
bmdzLT5tYXN0ZXJfbW9kZV9jbGtfc2VsZWN0aW9uKSB7CisJCQljYXNlIFNTUF9PTkNISVBfQ0xP
Q0s6CisJCQkJYnJlYWs7CisJCQljYXNlIFNTUF9ORVRXT1JLX0NMT0NLOgorCQkJCXNzY3IwIHw9
IFNTQ1IwX3JlZyhOQ1MsIDEpOworCQkJCWJyZWFrOworCQkJY2FzZSBTU1BfRVhURVJOQUxfQ0xP
Q0s6CisJCQkJc3NjcjAgfD0gU1NDUjBfcmVnKEVDUywgMSk7CisJCQkJYnJlYWs7CisJCQljYXNl
IFNTUF9PTkNISVBfQVVESU9fQ0xPQ0s6CisJCQkJc3NjcjAgfD0gU1NDUjBfcmVnKEFDUywgMSk7
CisJCQkJYnJlYWs7CisJCQlkZWZhdWx0OgorCQkJCWRldl9lcnIoZGRiZywgIk1hc3RlciBNb2Rl
IGNsayBzZWxlY3Rpb24gVU5LTk9XTiIpOworCQkJCWJyZWFrOworCQkJfQorCQkJc3Nwc3AgfD0g
U1NQU1BfcmVnKFNUUlRETFksIHBzX3NldHRpbmdzLT5zc3BfcHNwX1QxKQorCQkJCXxTU1BTUF9y
ZWcoRE1ZU1RSVCwgcHNfc2V0dGluZ3MtPnNzcF9wc3BfVDIpOworCQl9IGVsc2UgewkvKiBTZXQg
dGhlIFNsYXZlIENsb2NrIEZyZWUgUnVubmluZyBTdGF0dXMgKi8KKwkJCXNzY3IxIHw9IFNTQ1Ix
X3JlZyhTQ0ZSLCBwc19zZXR0aW5ncy0+c2xhdmVfY2xrX2ZyZWVfcnVubmluZ19zdGF0dXMpOwor
CQl9CisJfSBlbHNlIHsgIC8qIFNTUF9JTl9OT1JNQUxfTU9ERSAqLworCQlkZXZfZXJyKGRkYmcs
ICJVTlNVUFBPUlRFRCBNT0RFIik7CisJCWdvdG8gbGVhdmU7CisJfQorCisJLyogQ2xlYXIgc3Rh
dHVzICovCisJc3NzciA9IChTU1NSX0JDRV9NQVNLIDw8IFNTU1JfQkNFX1NISUZUKQorCSAgICAg
fCAoU1NTUl9UVVJfTUFTSyA8PCBTU1NSX1RVUl9TSElGVCkKKwkgICAgIHwgKFNTU1JfVElOVF9N
QVNLIDw8IFNTU1JfVElOVF9TSElGVCkKKwkgICAgIHwgKFNTU1JfUElOVF9NQVNLIDw8IFNTU1Jf
UElOVF9TSElGVCkKKwkgICAgIHwgKFNTU1JfUk9SX01BU0sgPDwgU1NTUl9ST1JfU0hJRlQpOwor
CS8qIGRpc2FibGUgU1NQICovCisJY2xlYXJfU1NDUjBfcmVnKHJlZywgU1NFKTsKKwlkZXZfZGJn
KGRkYmcsICJXUklURSBTU0NSMCBESVNBQkxFXG4iKTsKKwkvKiBDbGVhciBzdGF0dXMgKi8KKwl3
cml0ZV9TU1NSKHNzc3IsIHJlZyk7CisJZGV2X2RiZyhkZGJnLCAiV1JJVEUgU1NTUjogMHglMDhY
XG4iLCBzc3NyKTsKKwl3cml0ZV9TU0NSMChzc2NyMCwgcmVnKTsKKwlkZXZfZGJnKGRkYmcsICJX
UklURSBTU0NSMFxuIik7CisJLyogZmlyc3Qgc2V0IENSMSB3aXRob3V0IGludGVycnVwdCBhbmQg
c2VydmljZSBlbmFibGVzICovCisJd3JpdGVfU1NDUjEoc3NjcjEsIHJlZyk7CisJd3JpdGVfU1NQ
U1Aoc3Nwc3AsIHJlZyk7CisJd3JpdGVfU1NUU0Eoc3N0c2EsIHJlZyk7CisJd3JpdGVfU1NSU0Eo
c3Nyc2EsIHJlZyk7CisJLyogc2V0IHRoZSB0aW1lIG91dCBmb3IgdGhlIHJlY2VwdGlvbiAqLwor
CXdyaXRlX1NTVE8oMCwgcmVnKTsKKwlzc3AxX2R1bXBfcmVnaXN0ZXJzKGRydl9kYXRhKTsKK2xl
YXZlOgorCXJldHVybjsKK30KKworc3RhdGljIGludAoraW50ZWxfbWlkX2kyc19maW5kX3VzYWdl
KHN0cnVjdCBwY2lfZGV2ICpwZGV2LAorCQkJIHN0cnVjdCBpbnRlbF9taWRfaTJzX2hkbCAqZHJ2
X2RhdGEsCisJCQkgZW51bSBpbnRlbF9taWRfaTJzX3NzcF91c2FnZSAqdXNhZ2UpCit7CisJaW50
IHBvczsKKwl1OCAgYWRpZDsKKwlpbnQgc3RhdHVzID0gMDsKKworCSp1c2FnZSA9IFNTUF9VU0FH
RV9VTkFTU0lHTkVEOworCXBvcyA9IHBjaV9maW5kX2NhcGFiaWxpdHkocGRldiwgUENJX0NBUF9J
RF9WTkRSKTsKKwlkZXZfaW5mbygoJnBkZXYtPmRldiksCisJCSJQcm9iZS9maW5kIGNhcGFiaWxp
dHkgKFZORFIgJWQgcG9zPTB4JXgpXG4iLAorCQlQQ0lfQ0FQX0lEX1ZORFIsIHBvcyk7CisJaWYg
KHBvcyA+IDApIHsKKwkJcG9zICs9IFBDSV9DQVBfT0ZGU0VUX0FESUQ7CisJCXBjaV9yZWFkX2Nv
bmZpZ19ieXRlKHBkZXYsIHBvcywgJmFkaWQpOworCQlkZXZfaW5mbygmKHBkZXYtPmRldiksICJW
ZW5kb3IgY2FwYWJpbGl0eSBhZGlkID0gMHgleFxuIiwgYWRpZCk7CisJCWlmIChhZGlkID09IFBD
SV9DQVBfQURJRF9JMlNfQlRfRk0pCisJCQkqdXNhZ2UJPSBTU1BfVVNBR0VfQkxVRVRPT1RIX0ZN
OworCQllbHNlIGlmIChhZGlkID09IFBDSV9DQVBfQURJRF9JMlNfTU9ERU0pCisJCQkqdXNhZ2UJ
PSBTU1BfVVNBR0VfTU9ERU07CisJCWVsc2UKKwkJCSp1c2FnZQk9IFNTUF9VU0FHRV9VTkFTU0lH
TkVEOworCX0KKwkvKiBJZiB0aGVyZSBpcyBubyBjYXBhYmlsaXR5LCBjaGVjayB3aXRoIG9sZCBQ
Q0lfSUQgKi8KKyNpZmRlZiBCWVBBU1NfQURJRAorCWlmICgqdXNhZ2UgPT0gU1NQX1VTQUdFX1VO
QVNTSUdORUQpIHsKKwkJZGV2X3dhcm4oJihwZGV2LT5kZXYpLCAiVmVuZG9yIGNhcGFiaWxpdHkg
bm90IHByZXNlbnQvaW52YWxpZFxuIik7CisJCXN3aXRjaCAocGRldi0+ZGV2aWNlKSB7CisJCWNh
c2UgTUZMRF9TU1AxX0RFVklDRV9JRDoKKwkJCSp1c2FnZQk9IFNTUF9VU0FHRV9CTFVFVE9PVEhf
Rk07CisJCQlicmVhazsKKwkJY2FzZSBNRkxEX1NTUDBfREVWSUNFX0lEOgorCQkJKnVzYWdlCT0g
U1NQX1VTQUdFX01PREVNOworCQkJYnJlYWs7CisJCX0KKwl9CisjZW5kaWYKKwlpZiAoKnVzYWdl
ID09IFNTUF9VU0FHRV9VTkFTU0lHTkVEKSB7CisJCWRldl9pbmZvKCgmcGRldi0+ZGV2KSwKKwkJ
CSJObyBwcm9iZSBmb3IgSTJTIFBDSS1JRDogJTA0eDolMDR4LCBBRElEKDB4JXgpPTB4JXhcbiIs
CisJCQlwZGV2LT52ZW5kb3IsIHBkZXYtPmRldmljZSwgcG9zLCBhZGlkKTsKKwkJc3RhdHVzID0g
LUVOT0RFVjsKKwkJZ290byBlcnJfZmluZF91c2FnZTsKKwl9CisJZGV2X2RiZygmKHBkZXYtPmRl
diksCisJCSJEZXRlY3RlZCBQQ0kgU1NQIChJRDogJTA0eDolMDR4KSB1c2FnZSA9JXhcbiIsCisJ
CXBkZXYtPnZlbmRvciwgcGRldi0+ZGV2aWNlLCAqdXNhZ2UpOworCWRldl9kYmcoJihwZGV2LT5k
ZXYpLAorCQkiIGZvdW5kIFBDSSBTU1AgY29udHJvbGxlcihJRDogJTA0eDolMDR4KVxuIiwKKwkJ
cGRldi0+dmVuZG9yLCBwZGV2LT5kZXZpY2UpOworCS8qIEluaXQgdGhlIGRyaXZlciBkYXRhIHN0
cnVjdHVyZSBmaWVsZHMqLworCXN3aXRjaCAocGRldi0+ZGV2aWNlKSB7CisJY2FzZSBNRkxEX1NT
UDFfREVWSUNFX0lEOgorCQlkcnZfZGF0YS0+ZGV2aWNlX2luc3RhbmNlID0gRE1BMUNfREVWSUNF
X0lOU1RBTkNFX1NTUDE7CisJCWJyZWFrOworCWNhc2UgTUZMRF9TU1AwX0RFVklDRV9JRDoKKwkJ
ZHJ2X2RhdGEtPmRldmljZV9pbnN0YW5jZSA9IERNQTFDX0RFVklDRV9JTlNUQU5DRV9TU1AwOwor
CQlicmVhazsKKwlkZWZhdWx0OgorCQlkZXZfZXJyKCYocGRldi0+ZGV2KSwKKwkJCSJDYW4gbm90
IGRldGVybWluZSBkbWEgZGV2aWNlIGluc3RhbmNlIChQQ0kgSUQ6JTA0eClcbiIsCisJCQlwZGV2
LT5kZXZpY2UpOworCQlzdGF0dXMgPSAtRU5PREVWOworCQlnb3RvIGVycl9maW5kX3VzYWdlOwor
CX0KKwlzdGF0dXMgPSBwY2lfZW5hYmxlX2RldmljZShwZGV2KTsKKwlpZiAoc3RhdHVzKQorCQlk
ZXZfZXJyKCgmcGRldi0+ZGV2KSwgIkNhbiBub3QgZW5hYmxlIGRldmljZS5FcnI9JWRcbiIsIHN0
YXR1cyk7CitlcnJfZmluZF91c2FnZToKKwlyZXR1cm4gc3RhdHVzOworfQorCisvKioKKyAqIGlu
dGVsX21pZF9pMnNfcHJvYmUgLSBwcm9iaW5nIGZ1bmN0aW9uIGZvciB0aGUgcGNpIHNlbGVjdGVk
CisgKiBAcGRldiA6IHBjaV9kZXYgcG9pbnRlciB0aGF0IGlzIHByb2JlZAorICogQGVudCA6IHBj
aV9kZXZpY2VfaWQKKyAqCisgKiBPdXRwdXQgcGFyYW1ldGVycworICogICAgICBOQQorICovCitz
dGF0aWMgaW50IGludGVsX21pZF9pMnNfcHJvYmUoc3RydWN0IHBjaV9kZXYgKnBkZXYsCisJCQkJ
Y29uc3Qgc3RydWN0IHBjaV9kZXZpY2VfaWQgKmVudCkKK3sKKwlzdHJ1Y3QgaW50ZWxfbWlkX2ky
c19oZGwgKmRydl9kYXRhOworCWludCBzdGF0dXMgPSAwOworCWVudW0gaW50ZWxfbWlkX2kyc19z
c3BfdXNhZ2UgdXNhZ2U7CisKKwlkcnZfZGF0YSA9IGt6YWxsb2Moc2l6ZW9mKHN0cnVjdCBpbnRl
bF9taWRfaTJzX2hkbCksIEdGUF9LRVJORUwpOworCWRldl9kYmcoJihwZGV2LT5kZXYpLCAiJXMg
UHJvYmUsIGRydl9kYXRhID0lcFxuIiwgRFJJVkVSX05BTUUsIGRydl9kYXRhKTsKKwlpZiAoIWRy
dl9kYXRhKSB7CisJCWRldl9lcnIoKCZwZGV2LT5kZXYpLCAiQ2FuJ3QgYWxsb2MgZHJpdmVyIGRh
dGEgaW4gcHJvYmVcbiIpOworCQlzdGF0dXMgPSAtRU5PTUVNOworCQlnb3RvIGxlYXZlOworCX0K
KwlkZXZfaW5mbygoJnBkZXYtPmRldiksICJEZXRlY3RlZCBQQ0kgU1NQIChJRDogJTA0eDolMDR4
KVxuIiwgcGRldi0+dmVuZG9yLCBwZGV2LT5kZXZpY2UpOworCXN0YXR1cyA9IGludGVsX21pZF9p
MnNfZmluZF91c2FnZShwZGV2LCBkcnZfZGF0YSwgJnVzYWdlKTsKKwlpZiAoc3RhdHVzKQorCQln
b3RvIGVycl9pMnNfcHJvYmUwOworCW11dGV4X2luaXQoJmRydl9kYXRhLT5tdXRleCk7CisJZHJ2
X2RhdGEtPnBkZXYgPSBwZGV2OworCWRydl9kYXRhLT51c2FnZSA9IHVzYWdlOworCS8qCisJICog
R2V0IGJhc2ljIGlvIHJlc291cmNlIGFuZCBtYXAgaXQgZm9yIFNTUDEgW0JBUj0wXQorCSAqLwor
CWlmICgocGRldi0+ZGV2aWNlID09IE1GTERfU1NQMV9ERVZJQ0VfSUQpIHx8CisJICAgIChwZGV2
LT5kZXZpY2UgPT0gTUZMRF9TU1AwX0RFVklDRV9JRCkpIHsKKwkJZHJ2X2RhdGEtPnBhZGRyID0g
cGNpX3Jlc291cmNlX3N0YXJ0KHBkZXYsIE1SU1RfU1NQX0JBUik7CisJCWRydl9kYXRhLT5pb2xl
biA9IHBjaV9yZXNvdXJjZV9sZW4ocGRldiwgTVJTVF9TU1BfQkFSKTsKKwkJc3RhdHVzID0gcGNp
X3JlcXVlc3RfcmVnaW9uKHBkZXYsIE1SU1RfU1NQX0JBUiwgZGV2X25hbWUoJnBkZXYtPmRldikp
OworCQkvKiBtYXAgYnVzIG1lbW9yeSBpbnRvIENQVSBzcGFjZSAqLworCQlkcnZfZGF0YS0+aW9h
ZGRyID0gcGNpX2lvcmVtYXBfYmFyKHBkZXYsIE1SU1RfU1NQX0JBUik7CisJfSBlbHNlIHsKKwkJ
ZGV2X2VycigmcGRldi0+ZGV2LAorCQkJIkRvbid0IGtub3cgd2hpY2ggQkFSIHRvIHVzZWZvciB0
aGlzIFNTUCBQQ0RJRD0leFxuIiwKKwkJCXBkZXYtPmRldmljZSk7CisJCXN0YXR1cyA9IC1FTk9E
RVY7CisJCWdvdG8gZXJyX2kyc19wcm9iZTE7CisJfQorCWRldl9kYmcoJihwZGV2LT5kZXYpLCAi
cGFkZHIgPSA6ICV4XG4iLCBkcnZfZGF0YS0+cGFkZHIpOworCWRldl9kYmcoJihwZGV2LT5kZXYp
LCAiaW9sZW4gPSA6ICVkXG4iLCBkcnZfZGF0YS0+aW9sZW4pOworCWlmIChzdGF0dXMpIHsKKwkJ
ZGV2X2VycigoJnBkZXYtPmRldiksICJDYW4ndCByZXF1ZXN0IHJlZ2lvbi4gZXJyPSVkXG4iLCBz
dGF0dXMpOworCQlnb3RvIGVycl9pMnNfcHJvYmUxOworCX0KKwlpZiAoIWRydl9kYXRhLT5pb2Fk
ZHIpIHsKKwkJZGV2X2VycigoJnBkZXYtPmRldiksICJpb3JlbWFwX25vY2FjaGUgZXJyb3JcbiIp
OworCQlzdGF0dXMgPSAtRU5PTUVNOworCQlnb3RvIGVycl9pMnNfcHJvYmUyOworCX0KKwlkZXZf
ZGJnKCYocGRldi0+ZGV2KSwgImlvYWRkciA9IDogJXBcbiIsIGRydl9kYXRhLT5pb2FkZHIpOwor
CS8qIHByZXBhcmUgZm9yIERNQSBjaGFubmVsIGFsbG9jYXRpb24gKi8KKwkvKiBnZXQgdGhlIHBj
aV9kZXYgc3RydWN0dXJlIHBvaW50ZXIgKi8KKwkvKiBDaGVjayB0aGUgU1NQLCBpZiBTU1AzLCB0
aGVuIGFub3RoZXIgRE1BIGlzIHVzZWQgKEdQRE1BLi4pICovCisJaWYgKChwZGV2LT5kZXZpY2Ug
PT0gTUZMRF9TU1AxX0RFVklDRV9JRCkgfHwKKwkgICAgKHBkZXYtPmRldmljZSA9PSBNRkxEX1NT
UDBfREVWSUNFX0lEKSkgeworCQlkcnZfZGF0YS0+ZG1hYzEgPSBwY2lfZ2V0X2RldmljZShQQ0lf
VkVORE9SX0lEX0lOVEVMLAorCQkJCQkJIE1GTERfTFBFX0RNQV9ERVZJQ0VfSUQsCisJCQkJCQkg
TlVMTCk7CisJfSBlbHNlIHsKKwkJZGV2X2VycigmcGRldi0+ZGV2LAorCQkJIkRvbid0IGtub3cg
ZG1hIGRldmljZSBJRCBmb3IgdGhpcyBTU1AgUENESUQ9JXhcbiIsCisJCQlwZGV2LT5kZXZpY2Up
OworCQlnb3RvIGVycl9pMnNfcHJvYmUzOworCX0KKwkvKiBpbiBjYXNlIHRoZSBzdG9wIGRtYSBo
YXZlIHRvIHdhaXQgZm9yIGVuZCBvZiBjYWxsYmFja3MgICAqLworCS8qIFRoaXMgd2lsbCBiZSBy
ZW1vdmVkIHdoZW4gVEVSTUlOQVRFX0FMTCBhdmFpbGFibGUgaW4gRE1BICovCisJaW5pdF93YWl0
cXVldWVfaGVhZCgmZHJ2X2RhdGEtPndxX2NoYW5fY2xvc2luZyk7CisJaWYgKCFkcnZfZGF0YS0+
ZG1hYzEpIHsKKwkJZGV2X2VycigmKGRydl9kYXRhLT5wZGV2LT5kZXYpLCAiQ2FuJ3QgZmluZCBE
TUFDMSwgZG1hIGluaXQgZmFpbGVkXG4iKTsKKwkJc3RhdHVzID0gLUVOT0RFVjsKKwkJZ290byBl
cnJfaTJzX3Byb2JlMzsKKwl9CisJLyogaW5jcmVtZW50IHJlZiBjb3VudCBvZiBwY2kgZGV2aWNl
IHN0cnVjdHVyZSBhbHJlYWR5IGRvbmUgYnkgKi8KKwkvKiBwY2lfZ2V0X2RldmljZS4gd2lsbCBk
byBhIHBjaV9kZXZfcHV0IHdoZW4gZXhpdGluZyB0aGUgbW9kdWxlICovCisJcGNpX3NldF9kcnZk
YXRhKHBkZXYsIGRydl9kYXRhKTsKKwkvKiBzZXQgU1NQIEZyYW1lU3luYyBhbmQgQ0xLIGRpcmVj
dGlvbiBpbiBJTlBVVCBtb2RlIGluIG9yZGVyCisJICogdG8gYXZvaWQgZGlzdHVyYmluZyBwZXJp
cGhlcmFscworCSAqLworCXdyaXRlX1NTQ1IxKChTU0NSMV9TRlJNRElSX01BU0s8PFNTQ1IxX1NG
Uk1ESVJfU0hJRlQpCisJCSAgfCAoU1NDUjFfU0NMS0RJUl9NQVNLPDxTU0NSMV9TQ0xLRElSX1NI
SUZUKSwKKwlkcnZfZGF0YS0+aW9hZGRyKTsKKwkvKiBBdHRhY2ggdG8gSVJRICovCisJZHJ2X2Rh
dGEtPmlycSA9IHBkZXYtPmlycTsKKwlkZXZfZGJnKCYocGRldi0+ZGV2KSwgImF0dGFjaGluZyB0
byBJUlE6ICUwNHhcbiIsIHBkZXYtPmlycSk7CisJc3RhdHVzID0gcmVxdWVzdF9pcnEoZHJ2X2Rh
dGEtPmlycSwgaTJzX2ludCwgSVJRRl9TSEFSRUQsICJpMnMgc3NwIiwgZHJ2X2RhdGEpOworCWlm
IChzdGF0dXMgPCAwKQl7CisJCWRldl9lcnIoJnBkZXYtPmRldiwgImNhbiBub3QgZ2V0IElSUS4g
c3RhdHVzIGVycj0lZFxuIiwgc3RhdHVzKTsKKwkJZ290byBlcnJfaTJzX3Byb2JlMzsKKwl9CisJ
cG1fcnVudGltZV9lbmFibGUoJihkcnZfZGF0YS0+cGRldi0+ZGV2KSk7CisJZ290byBsZWF2ZTsK
K2Vycl9pMnNfcHJvYmUzOgorCWlvdW5tYXAoZHJ2X2RhdGEtPmlvYWRkcik7CitlcnJfaTJzX3By
b2JlMjoKKwlwY2lfcmVsZWFzZV9yZWdpb24ocGRldiwgTVJTVF9TU1BfQkFSKTsKK2Vycl9pMnNf
cHJvYmUxOgorCXBjaV9kaXNhYmxlX2RldmljZShwZGV2KTsKK2Vycl9pMnNfcHJvYmUwOgorCWtm
cmVlKGRydl9kYXRhKTsKK2xlYXZlOgorCXJldHVybiBzdGF0dXM7Cit9CisKK3N0YXRpYyB2b2lk
IF9fZGV2ZXhpdCBpbnRlbF9taWRfaTJzX3JlbW92ZShzdHJ1Y3QgcGNpX2RldiAqcGRldikKK3sK
KwlzdHJ1Y3QgaW50ZWxfbWlkX2kyc19oZGwgKmRydl9kYXRhOworCisJZHJ2X2RhdGEgPSBwY2lf
Z2V0X2RydmRhdGEocGRldik7CisJaWYgKCFkcnZfZGF0YSkgeworCQlkZXZfZXJyKCZwZGV2LT5k
ZXYsICJubyBkcnZfZGF0YSBpbiBwY2kgZGV2aWNlIHRvIHJlbW92ZSFcbiIpOworCQlnb3RvIGxl
YXZlOworCX0KKwlpZiAodGVzdF9iaXQoSTJTX1BPUlRfT1BFTkVELCAmZHJ2X2RhdGEtPmZsYWdz
KSkgeworCQlkZXZfd2FybigmcGRldi0+ZGV2LCAiTm90IGNsb3NlZCBiZWZvcmUgcmVtb3Zpbmcg
cGNpX2RldiFcbiIpOworCQlpbnRlbF9taWRfaTJzX2Nsb3NlKGRydl9kYXRhKTsKKwl9CisJcGNp
X3NldF9kcnZkYXRhKHBkZXYsIE5VTEwpOworCS8qIFN0b3AgRE1BIGlzIGFscmVhZHkgZG9uZSBk
dXJpbmcgY2xvc2UoKSAgKi8KKwlwY2lfZGV2X3B1dChkcnZfZGF0YS0+ZG1hYzEpOworCS8qIERp
c2FibGUgdGhlIFNTUCBhdCB0aGUgcGVyaXBoZXJhbCBhbmQgU09DIGxldmVsICovCisJd3JpdGVf
U1NDUjAoMCwgZHJ2X2RhdGEtPmlvYWRkcik7CisJZnJlZV9pcnEoZHJ2X2RhdGEtPmlycSwgZHJ2
X2RhdGEpOworCWlvdW5tYXAoZHJ2X2RhdGEtPmlvYWRkcik7CisJcGNpX3JlbGVhc2VfcmVnaW9u
KHBkZXYsIE1SU1RfU1NQX0JBUik7CisJcGNpX3JlbGVhc2VfcmVnaW9uKHBkZXYsIE1SU1RfTFBF
X0JBUik7CisJcGNpX2Rpc2FibGVfZGV2aWNlKHBkZXYpOworCWtmcmVlKGRydl9kYXRhKTsKK2xl
YXZlOgorCXJldHVybjsKK30KKworLyoqCisgKiBpbnRlbF9taWRfaTJzX2luaXQgLSByZWdpc3Rl
ciBwY2kgZHJpdmVyCisgKgorICovCitzdGF0aWMgaW50IF9faW5pdCBpbnRlbF9taWRfaTJzX2lu
aXQodm9pZCkKK3sKKwlyZXR1cm4gcGNpX3JlZ2lzdGVyX2RyaXZlcigmaW50ZWxfbWlkX2kyc19k
cml2ZXIpOworfQorCitzdGF0aWMgdm9pZCBfX2V4aXQgaW50ZWxfbWlkX2kyc19leGl0KHZvaWQp
Cit7CisJcGNpX3VucmVnaXN0ZXJfZHJpdmVyKCZpbnRlbF9taWRfaTJzX2RyaXZlcik7Cit9CisK
KworbW9kdWxlX2luaXQoaW50ZWxfbWlkX2kyc19pbml0KTsKK21vZHVsZV9leGl0KGludGVsX21p
ZF9pMnNfZXhpdCk7CisKKworCmRpZmYgLS1naXQgYS9zb3VuZC9wY2kvaW50ZWxfbWlkX2kycy9p
bnRlbF9taWRfaTJzLmggYi9zb3VuZC9wY2kvaW50ZWxfbWlkX2kycy9pbnRlbF9taWRfaTJzLmgK
bmV3IGZpbGUgbW9kZSAxMDA2NDQKaW5kZXggMDAwMDAwMC4uZWYyOWNlNwotLS0gL2Rldi9udWxs
CisrKyBiL3NvdW5kL3BjaS9pbnRlbF9taWRfaTJzL2ludGVsX21pZF9pMnMuaApAQCAtMCwwICsx
LDUwMCBAQAorLyoKKyAgKiA8RHJpdmVyIGZvciBJMlMgcHJvdG9jb2wgb24gU1NQIChNb29yZXN0
b3duIGFuZCBNZWRmaWVsZCBoYXJkd2FyZSk+CisgICogQ29weXJpZ2h0IChjKSAyMDEwLCBJbnRl
bCBDb3Jwb3JhdGlvbi4KKyAgKiBMb3VpcyBMRSBHQUxMIDxsb3Vpcy5sZS5nYWxsIGludGVsLmNv
bT4KKyAgKgorICAqIFRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOyB5b3UgY2FuIHJlZGlz
dHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5IGl0CisgICogdW5kZXIgdGhlIHRlcm1zIGFuZCBjb25k
aXRpb25zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSwKKyAgKiB2ZXJzaW9uIDIs
IGFzIHB1Ymxpc2hlZCBieSB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLgorICAqCisgICog
VGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIGl0IHdpbGwgYmUgdXNlZnVs
LCBidXQgV0lUSE9VVAorICAqIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVk
IHdhcnJhbnR5IG9mIE1FUkNIQU5UQUJJTElUWSBvcgorICAqIEZJVE5FU1MgRk9SIEEgUEFSVElD
VUxBUiBQVVJQT1NFLiAgU2VlIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IKKyAg
KiBtb3JlIGRldGFpbHMuCisgICoKKyAgKiBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5
IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhbG9uZyB3aXRoCisgICogdGhpcyBw
cm9ncmFtOyBpZiBub3QsIHdyaXRlIHRvIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIElu
Yy4sCisgICogNTEgRnJhbmtsaW4gU3QgLSBGaWZ0aCBGbG9vciwgQm9zdG9uLCBNQSAwMjExMC0x
MzAxIFVTQS4KKyAgKi8KKyNkZWZpbmUgRFJJVkVSX05BTUUgIkkyUyBTU1AgRHJpdmVyIgorLyoK
KyAqIERlZmluZXMKKyAqLworI2RlZmluZSBNRkxEX1NTUDFfREVWSUNFX0lEIDB4MDgyNQkvKiBG
T1IgTUZMRCAqLworI2RlZmluZSBNUlNUX1NTUDBfREVWSUNFX0lEIDB4MDgxNQkvKiBGT1IgTVJT
VCAqLworI2RlZmluZSBNRkxEX1NTUDBfREVWSUNFX0lEIDB4MDgzMgkvKiBGT1IgTUZMRCAqLwor
CisjZGVmaW5lIE1SU1RfTFBFX0RNQV9ERVZJQ0VfSUQgMHgwODE0CisjZGVmaW5lIE1GTERfTFBF
X0RNQV9ERVZJQ0VfSUQgMHgwODMwCisKKy8qIFNTUDEgUENJIGRldmljZSBCYXNlIEFkZHJlc3Mg
UmVnaXN0ZXIgKi8KKyNkZWZpbmUgTVJTVF9TU1BfQkFSCTAKKyNkZWZpbmUgTVJTVF9MUEVfQkFS
CTEKKyNkZWZpbmUgRE1BMUNfREVWSUNFX0lOU1RBTkNFX1NTUDAgMAorI2RlZmluZSBETUExQ19E
RVZJQ0VfSU5TVEFOQ0VfU1NQMSAxCisjZGVmaW5lIE9GRlNFVF9TU0NSMAkweDAwCisjZGVmaW5l
IE9GRlNFVF9TU0NSMQkweDA0CisjZGVmaW5lIE9GRlNFVF9TU1NSCQkweDA4CisjZGVmaW5lIE9G
RlNFVF9TU0lUUgkweDBjCisjZGVmaW5lIE9GRlNFVF9TU0RSCQkweDEwCisjZGVmaW5lIE9GRlNF
VF9TU1RPCQkweDI4CisjZGVmaW5lIE9GRlNFVF9TU1BTUAkweDJjCisjZGVmaW5lIE9GRlNFVF9T
U1RTQQkweDMwCS8qIFNTUCBUeCBUaW1lc2xvdCBBY3RpdmUgKi8KKyNkZWZpbmUgT0ZGU0VUX1NT
UlNBCTB4MzQJLyogU1NQIFJ4IFRpbWVzbG90IEFjdGl2ZSAqLworLyogU1NUIHJlZ2lzdGVyIG1h
cCAqLworI2RlZmluZSBPRkZTRVRfTFBFX0NTUgkJCTB4MDAKKyNkZWZpbmUgT0ZGU0VUX0xQRV9Q
SVNSCQkJMHgwOAorI2RlZmluZSBPRkZTRVRfTFBFX1BJTVIJCQkweDEwCisjZGVmaW5lIE9GRlNF
VF9MUEVfSVNSWAkJCTB4MTgKKyNkZWZpbmUgT0ZGU0VUX0xQRV9JTVJYCQkJMHgyOAorI2RlZmlu
ZSBPRkZTRVRfTFBFX0lQQ1gJCQkweDM4CS8qIElQQyBJQS1TU1QgKi8KKyNkZWZpbmUgT0ZGU0VU
X0xQRV9JUENECQkJMHg0MAkvKiBJUEMgU1NULUlBICovCisjZGVmaW5lIE9GRlNFVF9MUEVfSVNS
RAkJCTB4MjAJLyogZHVtbXkgcmVnaXN0ZXIgZm9yKi8KKwkJCQkJCS8qIHNoaW0gd29ya2Fyb3Vu
ZCAgICovCisjZGVmaW5lIE9GRlNFVF9MUEVfU0hJTV9TSVpFCTBYNDQKKworI2RlZmluZSBTU1Bf
SU5fTUFTVEVSX01PREUJCTB4MAorI2RlZmluZSBTU1BfSU5fU0xBVkVfTU9ERQkJMHgxCisKKy8q
CisgKglNYWNyb3MKKyAqLworI2RlZmluZSBERUZJTkVfU1NQX1JFRyhyZWcsIG9mZikgXAorc3Rh
dGljIGlubGluZSB1MzIgcmVhZF8jI3JlZyh2b2lkICpwKSB7IHJldHVybiBfX3Jhd19yZWFkbChw
ICsgKG9mZikpOyB9IFwKK3N0YXRpYyBpbmxpbmUgdm9pZCB3cml0ZV8jI3JlZyh1MzIgdiwgdm9p
ZCAqcCkgeyBfX3Jhd193cml0ZWwodiwgcCArIChvZmYpKTsgfQorREVGSU5FX1NTUF9SRUcoU1ND
UjAsIDB4MDApCitERUZJTkVfU1NQX1JFRyhTU0NSMSwgMHgwNCkKK0RFRklORV9TU1BfUkVHKFNT
U1IsIDB4MDgpCitERUZJTkVfU1NQX1JFRyhTU0lUUiwgMHgwYykKK0RFRklORV9TU1BfUkVHKFNT
RFIsIDB4MTApCitERUZJTkVfU1NQX1JFRyhTU1RPLCAweDI4KQorREVGSU5FX1NTUF9SRUcoU1NQ
U1AsIDB4MmMpCitERUZJTkVfU1NQX1JFRyhTU1RTQSwgMHgzMCkKK0RFRklORV9TU1BfUkVHKFNT
UlNBLCAweDM0KQorREVGSU5FX1NTUF9SRUcoU1NUU1MsIDB4MzgpCitERUZJTkVfU1NQX1JFRyhT
U0FDRCwgMHgzQykKK0RFRklORV9TU1BfUkVHKEkyQ0NUUkwsIDB4MDApOworREVGSU5FX1NTUF9S
RUcoSTJDREFUQSwgMHgwNCk7CisvKgorICogTGFuZ3dlbGwgU1NQIHNlcmlhbCBwb3J0IHJlZ2lz
dGVyIGRlZmluaXRpb25zCisgKi8KKyNkZWZpbmUgU1NDUjBfRFNTX01BU0sgICAweDBGCS8qIERh
dGEgU2l6ZSBTZWxlY3QgWzQuLjE2XSAqLworI2RlZmluZSBTU0NSMF9EU1NfU0hJRlQgIDAKKyNk
ZWZpbmUgU1NDUjBfRlJGX01BU0sgICAweDAzCS8qIEZSYW1lIEZvcm1hdCAqLworI2RlZmluZSBT
U0NSMF9GUkZfU0hJRlQgIDQKKyNkZWZpbmUgU1NDUjBfRUNTX01BU0sgICAweDAxCS8qIEV4dGVy
bmFsIGNsb2NrIHNlbGVjdCAqLworI2RlZmluZSBTU0NSMF9FQ1NfU0hJRlQgIDYKKyNkZWZpbmUg
U1NDUjBfU1NFX01BU0sgICAweDAxCS8qIFN5bmNocm9ub3VzIFNlcmlhbCBQb3J0IEVuYWJsZSAq
LworI2RlZmluZSBTU0NSMF9TU0VfU0hJRlQgIDcKKyNkZWZpbmUgU1NDUjBfU0NSX01BU0sgICAw
eEZGRgkvKiBOb3QgaW1wbGVtZW50ZWQgKi8KKyNkZWZpbmUgU1NDUjBfU0NSX1NISUZUICA4Cisj
ZGVmaW5lIFNTQ1IwX0VEU1NfTUFTSyAgMHgxCS8qIEV4dGVuZGVkIGRhdGEgc2l6ZSBzZWxlY3Qg
Ki8KKyNkZWZpbmUgU1NDUjBfRURTU19TSElGVCAyMAorI2RlZmluZSBTU0NSMF9OQ1NfTUFTSyAg
IDB4MQkvKiBOZXR3b3JrIGNsb2NrIHNlbGVjdCAqLworI2RlZmluZSBTU0NSMF9OQ1NfU0hJRlQg
IDIxCisjZGVmaW5lIFNTQ1IwX1JJTV9NQVNLICAgMHgxCS8qIFJlY2VpdmUgRklGTyBvdmVycnJ1
biBpbnQgbWFzayAqLworI2RlZmluZSBTU0NSMF9SSU1fU0hJRlQgIDIyCisjZGVmaW5lIFNTQ1Iw
X1RJTV9NQVNLICAgMHgxCS8qIFRyYW5zbWl0IEZJRk8gdW5kZXJydW4gaW50IG1hc2sgKi8KKyNk
ZWZpbmUgU1NDUjBfVElNX1NISUZUICAyMworI2RlZmluZSBTU0NSMF9GUkRDX01BU0sgIDB4Nwkv
KiBGcmFtZSBSYXRlIERpdmlkZXIgQ29udHJvbCAqLworI2RlZmluZSBTU0NSMF9GUkRDX1NISUZU
IDI0CisjZGVmaW5lIFNTQ1IwX0FDU19NQVNLICAgMHgxCS8qIEF1ZGlvIGNsb2NrIHNlbGVjdCAq
LworI2RlZmluZSBTU0NSMF9BQ1NfU0hJRlQgIDMwCisjZGVmaW5lIFNTQ1IwX01PRF9NQVNLICAg
MHgxCS8qIE1vZGUgKG5vcm1hbCBvciBuZXR3b3JrKSAqLworI2RlZmluZSBTU0NSMF9NT0RfU0hJ
RlQgIDMxCisKKyNkZWZpbmUgU1NDUjBfRGF0YVNpemUoeCkgICAgICgoeCkgLSAxKQkvKiBEYXRh
IFNpemUgU2VsZWN0IFs0Li4xNl0gKi8KKyNkZWZpbmUgU1NDUjBfU2xvdHNQZXJGcm0oeCkgICgo
eCkgLSAxKQkvKiBUaW1lIHNsb3RzIHBlciBmcmFtZSAqLworI2RlZmluZSBTU0NSMF9TZXJDbGtE
aXYoeCkgICAgKCh4KSAtIDEpCS8qIERpdmlzb3IgWzEuLjQwOTZdLC4uLiAqLworCQkJCQkgLyou
Li5ub3QgaW1wbGVtZW50ZWQgb24gTGFuZ3dlbGwgKi8KKyNkZWZpbmUgU1NDUjFfVFRFTFBfTUFT
SyAgICAgMHgxCS8qIFRYRCBUcmlzdGF0ZSBFbmFibGUgb24gTGFzdCBQaGFzZSAqLworI2RlZmlu
ZSBTU0NSMV9UVEVMUF9TSElGVCAgICAzMQorI2RlZmluZSBTU0NSMV9UVEVfTUFTSwkgICAgIDB4
MQkvKiBUWEQgVHJpc3RhdGUgRW5hYmxlICovCisjZGVmaW5lIFNTQ1IxX1RURV9TSElGVCAgICAg
IDMwCisjZGVmaW5lIFNTQ1IxX0VCQ0VJX01BU0sgICAgIDB4MQkvKiBFbmFibGUgQml0IENvdW50
IEVycm9yIEludGVycnVwdCAqLworI2RlZmluZSBTU0NSMV9FQkNFSV9TSElGVCAgICAyOQorI2Rl
ZmluZSBTU0NSMV9TQ0ZSX01BU0sgICAgICAweDEJLyogU2xhdmUgQ2xvY2sgUnVubmluZyAqLwor
I2RlZmluZSBTU0NSMV9TQ0ZSX1NISUZUICAgICAyOAorI2RlZmluZSBTU0NSMV9FQ1JBX01BU0sg
ICAgICAweDEJLyogRW5hYmxlIENsb2NrIFJlcXVlc3QgQSAqLworI2RlZmluZSBTU0NSMV9FQ1JB
X1NISUZUICAgICAyNworI2RlZmluZSBTU0NSMV9FQ1JCX01BU0sgICAgICAweDEJLyogRW5hYmxl
IENsb2NrIFJlcXVlc3QgQiAqLworI2RlZmluZSBTU0NSMV9FQ1JCX1NISUZUICAgICAyNgorI2Rl
ZmluZSBTU0NSMV9TQ0xLRElSX01BU0sgICAweDEJLyogU1NQQ0xLIERpcmVjdGlvbiAqLworI2Rl
ZmluZSBTU0NSMV9TQ0xLRElSX1NISUZUICAyNQorI2RlZmluZSBTU0NSMV9TRlJNRElSX01BU0sg
ICAweDEJLyogU1NQRlJNIERpcmVjdGlvbiAqLworI2RlZmluZSBTU0NSMV9TRlJNRElSX1NISUZU
ICAyNAorI2RlZmluZSBTU0NSMV9SV09UX01BU0sgICAgICAweDEJLyogUmVjZWl2ZSB3aXRob3V0
IFRyYW5zbWl0ICovCisjZGVmaW5lIFNTQ1IxX1JXT1RfU0hJRlQgICAgIDIzCisjZGVmaW5lIFNT
Q1IxX1RSQUlMX01BU0sgICAgIDB4MQkvKiBUcmFpbGluZyBCeXRlICovCisjZGVmaW5lIFNTQ1Ix
X1RSQUlMX1NISUZUICAgIDIyCisjZGVmaW5lIFNTQ1IxX1RTUkVfTUFTSyAgICAgIDB4MQkvKiBE
TUEgVHJhbnNtaXQgU2VydmljZSBSZXF1ZXN0IEVuYWJsZSovCisjZGVmaW5lIFNTQ1IxX1RTUkVf
U0hJRlQgICAgIDIxCisjZGVmaW5lIFNTQ1IxX1JTUkVfTUFTSyAgICAgIDB4MQkvKiBETUEgUmVj
ZWl2ZSBTZXJ2aWNlIFJlcXVlc3QgRW5hYmxlICovCisjZGVmaW5lIFNTQ1IxX1JTUkVfU0hJRlQg
ICAgIDIwCisjZGVmaW5lIFNTQ1IxX1RJTlRFX01BU0sgICAgIDB4MQkvKiBSZWNlaXZlciBUaW1l
LW91dCBJbnRlcnJ1cHQgRW5hYmxlICovCisjZGVmaW5lIFNTQ1IxX1RJTlRFX1NISUZUICAgIDE5
CisjZGVmaW5lIFNTQ1IxX1BJTlRFX01BU0sgICAgIDB4MQkvKiBQZXJpcGguIFRyYWlsaW5nIEJ5
dGUgSW50LiBFbmFibGUgKi8KKyNkZWZpbmUgU1NDUjFfUElOVEVfU0hJRlQgICAgMTgKKyNkZWZp
bmUgU1NDUjFfSUZTX01BU0sgICAgICAgMHgxCS8qIEludmVydCBGcmFtZSBTaWduYWwgKi8KKyNk
ZWZpbmUgU1NDUjFfSUZTX1NISUZUICAgICAgMTYKKyNkZWZpbmUgU1NDUjFfU1RGUl9NQVNLICAg
ICAgMHgxCS8qIFNlbGVjdCBGSUZPIGZvciBFRldSOiB0ZXN0IG1vZGUgKi8KKyNkZWZpbmUgU1ND
UjFfU1RGUl9TSElGVCAgICAgMTUKKyNkZWZpbmUgU1NDUjFfRUZXUl9NQVNLICAgICAgMHgxCS8q
IEVuYWJsZSBGSUZPIFdyaXRlL1JlYWQ6IHRlc3QgbW9kZSAqLworI2RlZmluZSBTU0NSMV9FRldS
X1NISUZUICAgICAxNAorI2RlZmluZSBTU0NSMV9SRlRfTUFTSyAgICAgICAweEYJLyogUmVjZWl2
ZSBGSUZPIFRyaWdnZXIgVGhyZXNob2xkICovCisjZGVmaW5lIFNTQ1IxX1JGVF9TSElGVCAgICAg
IDEwCisjZGVmaW5lIFNTQ1IxX1RGVF9NQVNLICAgICAgIDB4RgkvKiBUcmFuc21pdCBGSUZPIFRy
aWdnZXIgVGhyZXNob2xkICovCisjZGVmaW5lIFNTQ1IxX1RGVF9TSElGVCAgICAgIDYKKyNkZWZp
bmUgU1NDUjFfTVdEU19NQVNLICAgICAgMHgxCS8qIE1pY3Jvd2lyZSBUcmFuc21pdCBEYXRhIFNp
emUgKi8KKyNkZWZpbmUgU1NDUjFfTVdEU19TSElGVCAgICAgNQorI2RlZmluZSBTU0NSMV9TUEhf
TUFTSyAgICAgICAweDEJLyogTW90b3JvbGEgU1BJIFNTUFNDTEsgcGhhc2Ugc2V0dGluZyAqLwor
I2RlZmluZSBTU0NSMV9TUEhfU0hJRlQgICAgICA0CisjZGVmaW5lIFNTQ1IxX1NQT19NQVNLICAg
ICAgIDB4MQkvKiBNb3Rvcm9sYSBTUEkgU1NQU0NMSyBwb2xhcml0eSAqLworI2RlZmluZSBTU0NS
MV9TUE9fU0hJRlQgICAgICAzCisjZGVmaW5lIFNTQ1IxX0xCTV9NQVNLICAgICAgIDB4MQkvKiBM
b29wYmFjayBtb2RlOiB0ZXN0IG1vZGUgKi8KKyNkZWZpbmUgU1NDUjFfTEJNX1NISUZUICAgICAg
MgorI2RlZmluZSBTU0NSMV9USUVfTUFTSyAgICAgICAweDEJLyogVHJhbnNtaXQgRklGTyBJbnRl
cnJ1cHQgRW5hYmxlICovCisjZGVmaW5lIFNTQ1IxX1RJRV9TSElGVCAgICAgIDEKKyNkZWZpbmUg
U1NDUjFfUklFX01BU0sgICAgICAgMHgxCS8qIFJlY2VpdmUgRklGTyBJbnRlcnJ1cHQgRW5hYmxl
ICovCisjZGVmaW5lIFNTQ1IxX1JJRV9TSElGVCAgICAgIDAKKworI2RlZmluZSBTU0NSMV9SeFRy
ZXNoKHgpICgoeCkgLSAxKQkvKiBsZXZlbCBbMS4uMTZdICovCisjZGVmaW5lIFNTQ1IxX1R4VHJl
c2goeCkgKCh4KSAtIDEpCS8qIGxldmVsIFsxLi4xNl0gKi8KKworI2RlZmluZSBTU1BTUF9GU1JU
X01BU0sgICAgICAweDEJLyogRnJhbWUgU3luYyBSZWxhdGl2ZSBUaW1pbmcgQml0ICovCisjZGVm
aW5lIFNTUFNQX0ZTUlRfU0hJRlQgICAgIDI1CisjZGVmaW5lIFNTUFNQX0RNWVNUT1BfTUFTSyAg
IDB4MwkvKiBEdW1teSBTdG9wIGluIE51bWJlciBvZiBTU1BTQ0xLczpUNCovCisjZGVmaW5lIFNT
UFNQX0RNWVNUT1BfU0hJRlQgIDIzCisjZGVmaW5lIFNTUFNQX1NGUk1XRFRIX01BU0sgIDB4M0YJ
LyogU2VyaWFsIEZyYW1lIHdpZHRoIDogVDYgKi8KKyNkZWZpbmUgU1NQU1BfU0ZSTVdEVEhfU0hJ
RlQgMTYKKyNkZWZpbmUgU1NQU1BfU0ZSTURMWV9NQVNLICAgMHg3RgkvKiBTZXJpYWwgRnIuIERl
bGF5IGluIDEvMlNTUFNDTEtzOlQ1ICovCisjZGVmaW5lIFNTUFNQX1NGUk1ETFlfU0hJRlQgIDkK
KyNkZWZpbmUgU1NQU1BfRE1ZU1RSVF9NQVNLICAgMHgzCS8qIER1bW15IFN0YXJ0IGluIE51bWJl
ciBvZiBTU1BTQ0xLcy4uKi8KKyNkZWZpbmUgU1NQU1BfRE1ZU1RSVF9TSElGVCAgNwkgICAgLyou
Li5hZnRlciBTVFJURExZLCBUMiAobWFzdGVyIG1vZGUgb25seSkgKi8KKyNkZWZpbmUgU1NQU1Bf
U1RSVERMWV9NQVNLICAgMHg3CS8qIFN0YXJ0IERlbGF5LCBUMSAobWFzdGVyIG1vZGUgb25seSkg
Ki8KKyNkZWZpbmUgU1NQU1BfU1RSVERMWV9TSElGVCAgNAorI2RlZmluZSBTU1BTUF9FVERTX01B
U0sgICAgICAweDEJLyogRW5kIG9mIFRyYW5zZmVyIERhdGEgU3RhdGUgKi8KKyNkZWZpbmUgU1NQ
U1BfRVREU19TSElGVCAgICAgMworI2RlZmluZSBTU1BTUF9TRlJNUF9NQVNLICAgICAweDEJLyog
U2VyaWFsIEZyYW1lIFBvbGFyaXR5ICovCisjZGVmaW5lIFNTUFNQX1NGUk1QX1NISUZUICAgIDIK
KyNkZWZpbmUgU1NQU1BfU0NNT0RFX01BU0sgICAgMHgzCS8qIFNlcmlhbCBiaXQtcmF0ZSBDbG9j
ayBNb2RlICovCisjZGVmaW5lIFNTUFNQX1NDTU9ERV9TSElGVCAgIDAKKworI2RlZmluZSBTU1RT
QV9UVFNBX01BU0sgICAgICAweEZGCisjZGVmaW5lIFNTVFNBX1RUU0FfU0hJRlQgICAgIDAKKwor
I2RlZmluZSBTU1JTQV9SVFNBX01BU0sgICAgICAweEZGCisjZGVmaW5lIFNTUlNBX1JUU0FfU0hJ
RlQgICAgIDAKKworI2RlZmluZSBTU1NSX0JDRV9NQVNLICAgMHgxCS8qIEJpdCBDb3VudCBFcnJv
cjogUmVhZC9Xcml0ZSAxIHRvIENsZWFyICovCisjZGVmaW5lIFNTU1JfQkNFX1NISUZUICAyMwor
I2RlZmluZSBTU1NSX0NTU19NQVNLICAgMHgxCS8qIENsb2NrIFN5bmNocm9uaXphdGlvbiBTdGF0
dXMgKi8KKyNkZWZpbmUgU1NTUl9DU1NfU0hJRlQgIDIyCisjZGVmaW5lIFNTU1JfVFVSX01BU0sg
ICAweDEJLyogVHJhbnNtaXQgRklGTyBVbmRlclJ1bjogUmQvV3IgMSB0byBDbGVhciAqLworI2Rl
ZmluZSBTU1NSX1RVUl9TSElGVCAgMjEKKyNkZWZpbmUgU1NTUl9FT0NfTUFTSyAgIDB4MQkvKiBF
bmQgT2YgQ2hhaW46IFJlYWQvV3JpdGUgMSB0byBDbGVhciAqLworI2RlZmluZSBTU1NSX0VPQ19T
SElGVCAgMjAKKyNkZWZpbmUgU1NTUl9USU5UX01BU0sgIDB4MQkvKiBSZWNlaXZlciBUaW1lLW91
dCBJbnRlcnJ1cHQ6Li4uICovCisjZGVmaW5lIFNTU1JfVElOVF9TSElGVCAxOQkvKiAuLi5SZWFk
L1dyaXRlIDEgdG8gQ2xlYXIgKi8KKyNkZWZpbmUgU1NTUl9QSU5UX01BU0sgIDB4MQkvKiBQZXJp
cGhlcmFsIFRyYWlsaW5nIEJ5dGUgSW50ZXJydXB0Oi4uLiAqLworI2RlZmluZSBTU1NSX1BJTlRf
U0hJRlQgMTgJLyogLi4uUmVhZC9Xcml0ZSAxIHRvIENsZWFyICovCisjZGVmaW5lIFNTU1JfUkZM
X01BU0sgICAweEYJLyogUmVjZWl2ZSBGSUZPIExldmVsICovCisjZGVmaW5lIFNTU1JfUkZMX1NI
SUZUICAxMgorI2RlZmluZSBTU1NSX1RGTF9NQVNLICAgMHhGCS8qIFRyYW5zbWl0IEZJRk8gTGV2
ZWwgKi8KKyNkZWZpbmUgU1NTUl9URkxfU0hJRlQgIDgKKyNkZWZpbmUgU1NTUl9ST1JfTUFTSyAg
IDB4MQkvKiBSZWNlaXZlIEZJRk8gT3ZlcnJ1bjogUmVhZC9Xcml0ZSAxIHRvIENsZWFyKi8KKyNk
ZWZpbmUgU1NTUl9ST1JfU0hJRlQgIDcKKyNkZWZpbmUgU1NTUl9SRlNfTUFTSyAgIDB4MQkvKiBS
ZWNlaXZlIEZJRk8gU2VydmljZSBSZXF1ZXN0ICovCisjZGVmaW5lIFNTU1JfUkZTX1NISUZUICA2
CisjZGVmaW5lIFNTU1JfVEZTX01BU0sgICAweDEJLyogVHJhbnNtaXQgRklGTyBTZXJ2aWNlIFJl
cXVlc3QgKi8KKyNkZWZpbmUgU1NTUl9URlNfU0hJRlQgIDUKKyNkZWZpbmUgU1NTUl9CU1lfTUFT
SyAgIDB4MQkvKiBTU1AgQnVzeSAqLworI2RlZmluZSBTU1NSX0JTWV9TSElGVCAgNAorI2RlZmlu
ZSBTU1NSX1JORV9NQVNLICAgMHgxCS8qIFJlY2VpdmUgRklGTyBub3QgZW1wdHkgKi8KKyNkZWZp
bmUgU1NTUl9STkVfU0hJRlQgIDMKKyNkZWZpbmUgU1NTUl9URk5fTUFTSyAgIDB4MQkvKiBUcmFu
c21pdCBGSUZPIG5vdCBGdWxsICovCisjZGVmaW5lIFNTU1JfVEZOX1NISUZUICAyCisKKworI2Rl
ZmluZSBTU1BfT0ZGIDAKKyNkZWZpbmUgU1NQX09OICAxCisKKy8qIGJpdCBJMlNfUE9SVF9PUEVO
RUQgbG9jayBmb3Igb3Blbi9jbG9zZQorICogYml0IEkyU19QT1JUX1JFQURfQlVTWSBsb2NrIGZv
ciByZWFkIHJlcXVlc3RzIChzZXJpYWxpemVkKQorICogYml0IEkyU19QT1JUX1dSSVRFX0JVU1kg
bG9jayBmb3Igd3JpdGUgcmVxdWVzdHMgKHNlcmlhbGl6ZWQpCisgKiBiaXQgSTJTX1BPUlRfQ0xP
U0lORyBtZWFucyBjbG9zZSBvbiBnb2luZywgd2FpdGluZyBmb3IgcGVuZGluZyBjYWxsYmFja3Mu
CisgKi8KKworZW51bSBpMnNfZmxhZ3MgeworCUkyU19QT1JUX09QRU5FRCwKKwlJMlNfUE9SVF9X
UklURV9CVVNZLAorCUkyU19QT1JUX1JFQURfQlVTWSwKKwlJMlNfUE9SVF9DTE9TSU5HCit9Owor
CisjZGVmaW5lIEZJRk9fU0laRSAxNgorLyoKKyAqCVN0cnVjdHVyZXMgRGVmaW5pdGlvbgorICov
CisKKy8qKgorICogc3RydWN0IGludGVsX21pZF9pMnNfZGF0YSAtIGNvbnRleHQgc3RydWN0IHRv
IGtlZXAgU1NQIEkyUyBkYXRhCisgKiBAcGRldjogcGNpIGRldiBwb2ludGVyIGNvcnJlc3BvbmRp
bmcgdG8gY29udGV4dAorICogQHBhZGRyOgorICogQGlvYWRkcjoKKyAqIEBpb2xlbjoKKyAqIEBp
cnE6CisgKiBAY2xlYXJfc3I6CisgKiBAbWFza19zcjoKKyAqIEBkbWFjMToKKyAqIEBkbWFzX3R4
OiBkbWEgc2xhdmUgc3RydWN0dXJlIGZvciB0cmFuc21pdAorICogQGRtYXNfcng6IGRtYSBzbGF2
ZSBzdHJ1Y3R1cmUgZm9yIHJlY2VpdmUKKyAqIEB0eGNoYW46IERtYSBjaGFubmVsIGZvciB0cmFu
c21pdAorICogQHJ4Y2hhbjogRG1hIGNoYW5uZWwgZm9yIHJlY2VpdmUKKyAqCisgKiBAcmVhZF9k
b25lOgorICogQHJlYWRfZHN0OgorICogQHJlYWRfbGVuOgorICoKKyAqIEB3cml0ZV9kb25lOgor
ICogQHdyaXRlX3NyYzoKKyAqIEB3cml0ZV9sZW46CisgKgorICogQG11dGV4OiAgYSBtdXRleCB0
byBtYWtlIHN1cmUgd2UgaGF2ZSBvbmNlLWF0LXRpbWUgY3JpdGljYWwgZnVuY3Rpb25zLgorICoK
KyAqIExvbmdlciBkZXNjcmlwdGlvbgorICovCisKKy8qIExvY2tpbmcgcnVsZXM6CisgKgorICog
QWxsIHRoZSBmaWVsZHMsIG5vdCBsaXN0ZWQgYmVsb3csIGFyZSBzZXQgZHVyaW5nIHByb2JlLCBh
bmQgdGhlbiByZWFkIG9ubHkKKyAqIFNvIHRoZXkgZG8gbm90IHJlcXVpcmUgbG9ja2luZworICoK
KyAqIFRoZSBmaWVsZHMgdGhhdCByZXF1aXJlIGxvY2tpbmcgYXJlIHJlbGF0ZWQgdG8gdGhlIEky
UyByZWFkIGFuZCB3cml0ZQorICogcmVxdWVzdHMuCisgKgorICogV2UgYWxsb3cgb25seSAxIHJl
YWQgYXQgYSB0aW1lLCBhbmQgMSB3cml0ZSBhdCBhIHRpbWUuCisgKiBXZSBhbGxvdyByZWFkIGlu
IHBhcmFsbGVsIG9mIHdyaXRlIGJ1dCB1c2Ugc2VwYXJhdGUgdmFyaWFibGVzLgorICogV2UgYWxs
b3cgb25seSAxIHVzZXIgcGVyIFNTUC9JMlMgcG9ydC4KKyAqIFR5cGljYWxseSB0aGlzIHVzZXIg
d2lsbCBiZSBhIGRlZGljYXRlZCBQdWxzZUF1ZGlvIFJUIHRocmVhZCBjb21tdW5pY2F0aW5nCisg
KiB3aXRoIGNtdC1zcGVlY2ggZHJpdmVyIHdoaWNoIGluIHR1cm5zIGNvbW11bmljYXRlcyB3aXRo
IGludGVsX21pZF9zc3AKKyAqIGRyaXZlci4KKyAqIFBDTSBtaXhpbmcgaXMgZG9uZSBiZWZvcmUg
YWNjZXNzIHRvIGtlcm5lbCBkcml2ZXJzO3R5cGljYWxseSB3aXRoaW4KKyAqIFB1bHNlQXVkaW8g
b3IgYWZ0ZXI7IHR5cGljYWxseSB3aXRoaW4gdGhlIG1vZGVtLgorICogU28gbm8gY29uY3VycmVu
dCB1c2VycywgcGVyIEkyUyBjaGFubmVsLCB0byB0aGlzIGRyaXZlciBhcmUgYWxsb3dlZAorICog
VGhlIHJlYWQgJiB3cml0ZSBhcmUgdHJpZ2dlcmVkIGZyb20gYSBVU0VSIGNvbnRleHQKKyAqIFRo
ZSByZWFkICYgd3JpdGUgY2FsbGJhY2tzIGFyZSBjYWxsZWQgZnJvbSBhIEJIIGNvbnRleHQKKyAq
IFlvdSBzaG91bGQgaGF2ZSBub3QgY2FsbGJhY2sgcGVuZGluZyBiZWZvcmUgY2FsbGluZyBjbG9z
ZSwgY2xvc2Ugd2lsbCB3YWl0CisgKiBmb3IgcmVtYWluaW5nIGNhbGxiYWNrIGNhbGxzLgorICog
SXQgaXMgbm90IGFsbG93ZWQgdG8gY2FsbCBjbG9zZSBmdW5jdGlvbiBmcm9tIHJlYWQvd3JpdGUg
Y2FsbGJhY2sgdGhyZWFkcy4KKyAqCisgKiBMb2NraW5nIGlzIGhhbmRsZWQgdmlhIGRydl9kYXRh
LT5mbGFncyAmIGF0b21pYyBiaXR3aXNlIG9wZXJhdGlvbnMKKyAqCisgKiBJMlMwIGlzIGRlZGlj
YXRlZCBmb3IgUENNIHRyYW5zZmVyIHRvL2Zyb20gdGhlIG1vZGVtIG1vZHVsZQorICogSTJTMSBp
cyBkZWRpY2F0ZWQgZm9yIFBDTSB0cmFuc2ZlciB0by9mcm9tIHRoZSBCbHVldG9vdGggb3IgRk0g
bW9kdWxlCisgKgorICogcmVhZF9kb25lOgorICogcmVhZF9sZW46CisgKiByZWFkX2RzdDoKKyAq
CisgKiB3cml0ZV9kb25lOgorICogd3JpdGVfc3JjOgorICogd3JpdGVfbGVuOgorICoKKyAqIG11
dGV4OiAgYSBtdXRleCB0byBtYWtlIHN1cmUgd2UgaGF2ZSBvbmNlLWF0LXRpbWUgY3JpdGljYWwg
ZnVuY3Rpb25zLgorICoJCW9uY2UtYXQtYS10aW1lIGFjdGlvbnMgZnVuY3Rpb25zIGFyZToKKyAq
CQkJLWludGVsX21pZF9pMnNfb3BlbgorICoJCQktaW50ZWxfbWlkX2kyc19jbG9zZQorICoJCQkt
aW50ZWxfbWlkX2kyc19yZF9yZXEKKyAqCQkJLWludGVsX21pZF9pMnNfd3JfcmVxCisgKgkJCS1p
bnRlbF9taWRfaTJzX3NldF9yZF9jYgorICoJCQktaW50ZWxfbWlkX2kyc19zZXRfd3JfY2IKKyAq
IFRoZXNlIGZ1bmN0aW9ucyBzaG91bGQgbm90IGJlIGNhbGxlZCBkdXJpbmcgYSBsb2NrKCkgbmVp
dGhlciBpbiBpbnRlcnJ1cHQuCisgKi8KKworc3RydWN0IGludGVsX21pZF9pMnNfaGRsIHsKKwkv
KiBEcml2ZXIgbW9kZWwgaG9va3VwICovCisJc3RydWN0IHBjaV9kZXYgKnBkZXY7CisJLyogcmVn
aXN0ZXIgYWRkcmVzc2VzICovCisJZG1hX2FkZHJfdCBwYWRkcjsKKwl2b2lkIF9faW9tZW0gKmlv
YWRkcjsKKwl1MzIgaW9sZW47CisJaW50IGlycTsKKworCS8qIFNTUCBtYXNrcyAqLworCXUzMiBj
bGVhcl9zcjsKKwl1MzIgbWFza19zcjsKKworCS8qIFNTUCBDb25maWd1cmF0aW9uICovCisJLyog
RE1BIGluZm8gKi8KKwlzdHJ1Y3QgcGNpX2RldiAqZG1hYzE7CisJd2FpdF9xdWV1ZV9oZWFkX3Qg
d3FfY2hhbl9jbG9zaW5nOworCisJc3RydWN0IGludGVsX21pZF9kbWFfc2xhdmUgZG1hc190eDsK
KwlzdHJ1Y3QgaW50ZWxfbWlkX2RtYV9zbGF2ZSBkbWFzX3J4OworCXN0cnVjdCBkbWFfY2hhbiAq
dHhjaGFuOworCXN0cnVjdCBkbWFfY2hhbiAqcnhjaGFuOworCisJdW5zaWduZWQgaW50IGRldmlj
ZV9pbnN0YW5jZTsKKwkvKiBDYWxsIGJhY2sgZnVuY3Rpb25zICovCisJaW50ICgqcmVhZF9jYWxs
YmFjaykodm9pZCAqcGFyYW0pOworCWRtYV9hZGRyX3QgcmVhZF9kc3Q7CisJc2l6ZV90IHJlYWRf
bGVuOyAgICAgLyogcmVhZF9sZW4gPiAwIDw9PiByZWFkX2RtYV9ydW5uaW5nICovCisJdm9pZCAq
cmVhZF9wYXJhbTsJIC8qIGNvbnRleHQgcGFyYW0gZm9yIGNhbGxiYWNrICovCisJaW50ICgqd3Jp
dGVfY2FsbGJhY2spKHZvaWQgKnBhcmFtKTsKKwlkbWFfYWRkcl90IHdyaXRlX3NyYzsKKwlzaXpl
X3Qgd3JpdGVfbGVuOwkvKiB3cml0ZV9sZW4gPiAwIDw9PiByZWFkX2RtYV9ydW5uaW5nICovCisJ
dm9pZCAqd3JpdGVfcGFyYW07CS8qIGNvbnRleHQgcGFyYW0gZm9yIGNhbGxiYWNrICovCisKKwl1
bnNpZ25lZCBsb25nIGZsYWdzOworCXN0cnVjdCBtdXRleCBtdXRleDsKKwllbnVtIGludGVsX21p
ZF9pMnNfc3NwX3VzYWdlIHVzYWdlOworCisJc3RydWN0IGludGVsX21pZF9pMnNfc2V0dGluZ3Mg
Y3VycmVudF9zZXR0aW5nczsKKworfTsKKworc3RhdGljIHZvaWQgaTJzX3JlYWRfZG9uZSh2b2lk
ICphcmcpOworc3RhdGljIHZvaWQgaTJzX3dyaXRlX2RvbmUodm9pZCAqYXJnKTsKK3N0YXRpYyBi
b29sIGNoYW5fZmlsdGVyKHN0cnVjdCBkbWFfY2hhbiAqY2hhbiwgdm9pZCAqcGFyYW0pOworc3Rh
dGljIHZvaWQgaTJzX2RtYV9zdG9wKHN0cnVjdCBpbnRlbF9taWRfaTJzX2hkbCAqZHJ2X2RhdGEp
Oworc3RhdGljIGludCBpMnNfZG1hX3N0YXJ0KHN0cnVjdCBpbnRlbF9taWRfaTJzX2hkbCAqZHJ2
X2RhdGEpOworc3RhdGljIHZvaWQgc3NwMV9kdW1wX3JlZ2lzdGVycyhzdHJ1Y3QgaW50ZWxfbWlk
X2kyc19oZGwgKik7CitzdGF0aWMgaXJxcmV0dXJuX3QgaTJzX2ludChpbnQgaXJxLCB2b2lkICpk
ZXZfaWQpOworc3RhdGljIHZvaWQgc2V0X3NzcF9pMnNfaHcoc3RydWN0IGludGVsX21pZF9pMnNf
aGRsICpkcnZfZGF0YSwKKwkJY29uc3Qgc3RydWN0IGludGVsX21pZF9pMnNfc2V0dGluZ3MgKnBz
X3NldHRpbmdzKTsKK3N0YXRpYyBpbnQgY2hlY2tfZGV2aWNlKHN0cnVjdCBkZXZpY2UgKmRldmlj
ZV9wdHIsIHZvaWQgKmRhdGEpOworc3RhdGljIGludCBpbnRlbF9taWRfaTJzX3J1bnRpbWVfcmVz
dW1lKHN0cnVjdCBkZXZpY2UgKmRldmljZV9wdHIpOworc3RhdGljIGludCBpbnRlbF9taWRfaTJz
X3J1bnRpbWVfc3VzcGVuZChzdHJ1Y3QgZGV2aWNlICpkZXZpY2VfcHRyKTsKK3N0YXRpYyBpbnQg
aW50ZWxfbWlkX2kyc19wcm9iZShzdHJ1Y3QgcGNpX2RldiAqcGRldiwKKwkJY29uc3Qgc3RydWN0
IHBjaV9kZXZpY2VfaWQgKmVudCk7CitzdGF0aWMgdm9pZCBpbnRlbF9taWRfaTJzX3JlbW92ZShz
dHJ1Y3QgcGNpX2RldiAqcGRldik7CitzdGF0aWMgdm9pZCBpMnNfc3NwX3N0b3Aoc3RydWN0IGlu
dGVsX21pZF9pMnNfaGRsICpkcnZfZGF0YSk7CisvKnN0YXRpYyBpbnQgYnRfcGNtX2RtYV9pbml0
KHN0cnVjdCBpbnRlbF9taWRfaTJzX2hkbCAqZHJ2X2RhdGEpOyovCisKKworI2lmZGVmIENPTkZJ
R19QTQorc3RhdGljIGludCAgaW50ZWxfbWlkX2kyc19kcml2ZXJfc3VzcGVuZChzdHJ1Y3QgcGNp
X2RldiAqZGV2LAorCQkJCQkgIHBtX21lc3NhZ2VfdCBzdGF0ZSk7CitzdGF0aWMgaW50IGludGVs
X21pZF9pMnNfZHJpdmVyX3Jlc3VtZShzdHJ1Y3QgcGNpX2RldiAqZGV2KTsKKyNlbmRpZgorCisv
KgorICogVGhlc2UgZGVmaW5lIHdpbGwgY2xhcmlmeSBzb3VyY2UgY29kZSB3aGVuIGFjY2Vzc2lu
ZyBTU0NSeCByZWdpc3RlcnMKKyAqLworCisjZGVmaW5lIFNTQ1IwX3JlZyhyZWdiaXQsIHZhbHVl
KQkJCQkJXAorCSgoKHZhbHVlKSAmIFNTQ1IwXyMjcmVnYml0IyNfTUFTSykgPDwgU1NDUjBfIyNy
ZWdiaXQjI19TSElGVCkKKworI2RlZmluZSBTU0NSMV9yZWcocmVnYml0LCB2YWx1ZSkJCQkJCVwK
KwkoKCh2YWx1ZSkgJiBTU0NSMV8jI3JlZ2JpdCMjX01BU0spIDw8IFNTQ1IxXyMjcmVnYml0IyNf
U0hJRlQpCisKKyNkZWZpbmUgU1NQU1BfcmVnKHJlZ2JpdCwgdmFsdWUpCQkJCQlcCisJKCgodmFs
dWUpICYgU1NQU1BfIyNyZWdiaXQjI19NQVNLKSA8PCBTU1BTUF8jI3JlZ2JpdCMjX1NISUZUKQor
CisjZGVmaW5lIFNTUlNBX3JlZyhyZWdiaXQsIHZhbHVlKQkJCQkJXAorCSgoKHZhbHVlKSAmIFNT
UlNBXyMjcmVnYml0IyNfTUFTSykgPDwgU1NSU0FfIyNyZWdiaXQjI19TSElGVCkKKyNkZWZpbmUg
U1NUU0FfcmVnKHJlZ2JpdCwgdmFsdWUpCQkJCQlcCisJKCgodmFsdWUpICYgU1NUU0FfIyNyZWdi
aXQjI19NQVNLKSA8PCBTU1RTQV8jI3JlZ2JpdCMjX1NISUZUKQorCisKKyNkZWZpbmUgY2hhbmdl
X1NTQ1IwX3JlZyhyZWdfcG9pbnRlciwgcmVnYml0LCB2YWx1ZSkJCQkgIFwKKwl3cml0ZV9TU0NS
MCgocmVhZF9TU0NSMChyZWdfcG9pbnRlcikJCQkJICBcCisJJiAofigoU1NDUjBfIyNyZWdiaXQj
I19NQVNLIDw8IFNTQ1IwXyMjcmVnYml0IyNfU0hJRlQpKSkpCSAgXAorCXwgKCgodmFsdWUpICYg
U1NDUjBfIyNyZWdiaXQjI19NQVNLKSA8PCBTU0NSMF8jI3JlZ2JpdCMjX1NISUZUKSwgIFwKKwly
ZWdfcG9pbnRlcik7CisKKyNkZWZpbmUgc2V0X1NTQ1IwX3JlZyhyZWdfcG9pbnRlciwgcmVnYml0
KQkJCQkgIFwKKwl3cml0ZV9TU0NSMChyZWFkX1NTQ1IwKHJlZ19wb2ludGVyKQkJCQkgIFwKKwl8
IChTU0NSMF8jI3JlZ2JpdCMjX01BU0sgPDwgU1NDUjBfIyNyZWdiaXQjI19TSElGVCksCQlcCisJ
cmVnX3BvaW50ZXIpOworCisjZGVmaW5lIGNsZWFyX1NTQ1IwX3JlZyhyZWdfcG9pbnRlciwgcmVn
Yml0KQkJCQkgIFwKKwl3cml0ZV9TU0NSMCgocmVhZF9TU0NSMChyZWdfcG9pbnRlcikJCQkJICBc
CisJJiAofigoU1NDUjBfIyNyZWdiaXQjI19NQVNLIDw8IFNTQ1IwXyMjcmVnYml0IyNfU0hJRlQp
KSkpLAkgIFwKKwlyZWdfcG9pbnRlcik7CisKKyNkZWZpbmUgY2hhbmdlX1NTQ1IxX3JlZyhyZWdf
cG9pbnRlciwgcmVnYml0LCB2YWx1ZSkJCQkgIFwKKwl3cml0ZV9TU0NSMSgocmVhZF9TU0NSMShy
ZWdfcG9pbnRlcikJCQkJICBcCisJJiAofigoU1NDUjFfIyNyZWdiaXQjI19NQVNLIDw8IFNTQ1Ix
XyMjcmVnYml0IyNfU0hJRlQpKSkpCSAgXAorCXwgKCgodmFsdWUpICYgU1NDUjFfIyNyZWdiaXQj
I19NQVNLKSA8PCBTU0NSMV8jI3JlZ2JpdCMjX1NISUZUKSwgIFwKKwlyZWdfcG9pbnRlcik7CisK
KyNkZWZpbmUgc2V0X1NTQ1IxX3JlZyhyZWdfcG9pbnRlciwgcmVnYml0KQkJCQkgIFwKKwl3cml0
ZV9TU0NSMShyZWFkX1NTQ1IxKHJlZ19wb2ludGVyKQkJCQkgIFwKKwl8IChTU0NSMV8jI3JlZ2Jp
dCMjX01BU0sgPDwgU1NDUjFfIyNyZWdiaXQjI19TSElGVCksCQkgIFwKKwlyZWdfcG9pbnRlcik7
CisKKyNkZWZpbmUgY2xlYXJfU1NDUjFfcmVnKHJlZ19wb2ludGVyLCByZWdiaXQpCQkJCSAgXAor
CXdyaXRlX1NTQ1IxKChyZWFkX1NTQ1IxKHJlZ19wb2ludGVyKQkJCQkgIFwKKwkmICh+KChTU0NS
MV8jI3JlZ2JpdCMjX01BU0sgPDwgU1NDUjFfIyNyZWdiaXQjI19TSElGVCkpKSksCSAgXAorCXJl
Z19wb2ludGVyKTsKKworLyogUlggRklGTyBsZXZlbCAqLworI2RlZmluZSBHRVRfU1NTUl92YWwo
eCwgcmVnYikJCQkJCQkgIFwKKwkoKHggJiAoU1NTUl8jI3JlZ2IjI19NQVNLPDxTU1NSXyMjcmVn
YiMjX1NISUZUKSk+PlNTU1JfIyNyZWdiIyNfU0hJRlQpCisKKworLyoKKyAqIFNTUCBoYXJkd2Fy
ZSBjYW4gYmUgY29uZmlndXJlZCBhcyBJMlMsIFBDTSwgU1BJLi4uCisgKiBJbiBvcmRlciB0byBh
bGxvdyBmbGV4aWJpbGl0eSB3aXRob3V0IG1vZGlmeWluZyB0aGUgc29mdHdhcmUgZHJpdmVyLCB0
aGUKKyAqIFBDSSBoZWFkZXIgdXNlcyB0aGUgY29uZmlndXJhdGlvbiByZWdpc3RlciAnYWRpZCc6
CisgKgorICogVGhlIFBDSSBoZWFkZXIgYXNzb2NpYXRlZCB0byBTU1AgZGV2aWNlcyBpbmNsdWRl
cyBhIGNvbmZpZ3VyYXRpb24gcmVnaXN0ZXIuCisgKiBJdCBwcm92aWRlcyBpbmZvcm1hdGlvbiB0
byBhIGRyaXZlciB3aGljaCBpcyBwcm9iZWQgZm9yIHRoZSBTU1AsIHNwZWNpZnlpbmcKKyAqIGlu
IHdoaWNoIHdheSB0aGUgU1NQIGlzIHN1cHBvc2VkIHRvIGJlIHVzZWQuCisgKiBIZXJlIGlzIHRo
ZSBmb3JtYXQgb2YgdGhpcyBjb25maWd1cmF0aW9uIHJlZ2lzdGVyICg4IGJpdHMpOgorICoKKyAq
ICAgYml0cyAyLi4wOiBNb2RlCisgKiAgICAgICAwMDA6IEludmFsaWQsIHRoZSByZWdpc3RlciBz
aG91bGQgYmUgaWdub3JlZAorICogICAgICAgMDAxOiBTU1AgdG8gYmUgdXNlZCBhcyBTUEkgY29u
dHJvbGxlcgorICogICAgICAgMDEwOiBTU1AgdG8gYmUgdXNlZCBpbiBJMlMvSVNTIG1vZGUKKyAq
ICAgICAgIG90aGVyOiBSZXNlcnZlZAorICoKKyAqICAgYml0cyA1Li4zOiBDb25maWd1cmF0aW9u
CisgKiAgICAgICBJbiBJMlMvSVNTIG1vZGU6CisgKiAgICAgICAgICAgICAgIDAwMDogSW52YWxp
ZAorICogICAgICAgICAgICAgICAwMDE6IEJsdWV0b290aAorICogICAgICAgICAgICAgICAwMTA6
IE1vZGVtCisgKiAgICAgICAgICAgICAgIG90aGVyOiBSZXNlcnZlZAorICogICAgICAgSW4gU1BJ
IG1vZGU6CisgKiAgICAgICAgICAgICAgIFZhbHVlIGlzIHRoZSBTUEkgYnVzIG51bWJlciBjb25u
ZWN0ZWQgdG8gdGhlIFNTUC4KKyAqICAgICAgICAgICAgICAgVG8gYmUgdXNlZCBmb3IgcmVnaXN0
cmF0aW9uIHRvIHRoZSBMaW51eCBTUEkKKyAqICAgICAgICAgICAgICAgZnJhbWV3b3JrLgorICoK
KyAqICAgYml0IDY6IFNQSSBzbGF2ZQorICogICAgICAgUmVsZXZhbnQgaW4gU1BJIG1vZGUgb25s
eS4gSWYgc2V0LCBpbmRpY2F0ZXMgdGhlIFNQSSBjbG9jaworICogICAgICAgaXMgbm90IHByb3Zp
ZGVkIGJ5IHRoZSBTU1A6IFNQSSBzbGF2ZSBtb2RlLgorICoKKyAqICAgYml0IDc6IFJlc2VydmVk
ICgwKQorICoKKyAqICAgVGhpcyBjb25maWd1cmF0aW9uIHJlZ2lzdGVyIGlzIGltcGxlbWVudGVk
IGluIHRoZSBhZGlkIGZpZWxkIG9mIHRoZQorICogICBWZW5kb3IgU3BlY2lmaWMgUENJIGNhcGFi
aWxpdHkgYXNzb2NpYXRlZCB0byB0aGUgU1NQLiBUaGUgZm9ybWF0IG9mCisgKiAgIHRoaXMgY2Fw
YWJpbGl0eSBpczoKKyAqCisgKiAgIHVpbnQ4X3QgICAgIGNhcElkOyAgICAgICAgICAgICAgPCBD
YXBhYmlsaXR5IElEICh2ZW5kb3Itc3BlY2lmaWMpCisgKiAgIHVpbnQ4X3QgICAgIG5leHRDYXA7
ICAgICAgICAgICAgPCBOZXh0IEl0ZW0gUHRyCisgKiAgIHVpbnQ4X3QgICAgIGxlbmd0aDsgICAg
ICAgICAgICAgPCBTaXplIG9mIHRoaXMgY2FwYWJpbGl0eSAoNykKKyAqICAgdWludDhfdCAgICAg
dmVyc2lvbjsgICAgICAgICAgICA8IFZlcnNpb24gb2YgdGhpcyBjYXBhYmlsaXR5ICgxKQorICog
ICB1aW50OF90ICAgICBsc3M7ICAgICAgICAgICAgICAgIDwgTG9naWNhbCBzdWJzeXN0ZW0gaW5m
bworICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEJpdCA3ID0gUE1V
ICgwID0gTkMsIDEgPSBTQykKKyAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICBCaXRzIDY6MCA9IExTUyBJRAorICogICB1aW50OF90ICAgICBhcG1jOyAgICAgICAgICAg
ICAgIDwgQWRkaXRpb25hbCBQTSBjYXBhYmlsaXRpZXMKKyAqICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICBCaXQgNyA9IFJzdmQKKyAqICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICBCaXQgNiA9IFdha2UgY2FwYWJsZQorICogICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgIEJpdCA1ID0gRDMgc3VwcG9ydAorICogICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEJpdCA0ID0gRDIgc3VwcG9ydAorICog
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEJpdCAzID0gRDEgc3VwcG9y
dAorICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEJpdCAyID0gRDBp
MyBzdXBwb3J0CisgKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQml0
IDEgPSBEMGkyIHN1cHBvcnQKKyAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICBCaXQgMCA9IEQwaTEgc3VwcG9ydAorICogICB1aW50OF90ICAgICBhZGlkOyAgICAgICAg
ICAgICAgIDwgQWRkaXRpb25hbCBkZXZpY2UgSUQgKGRldi1zcGVjaWZpYykKKyAqICAgdWludDhf
dCAgICAgcnN2ZDsgICAgICAgICAgICAgICA8IFJlc2VydmVkIGZvciBmdXR1cmUgdXNlCisgKgor
ICogICBUaGUgY2FwYWJpbGl0eSBkYXRhIGFyZSBpbiB0aGUgUENJIGNvbmZpZ3VyYXRpb24gc3Bh
Y2UgYW5kIHRoZQorICogICBhZGlkIGZpZWxkIGNhbiBiZSBtb2RpZmllZCB1c2luZyBCTVAgdG9v
bC4KKyAqLworLyogQURESUQgPSBBZGRpdGlvbmFsIERldmljZSBJRCAqLworI2RlZmluZSBQQ0lf
Q0FQX09GRlNFVF9BRElEIDYKKworCi0tIAoxLjYuNi4xCgo=
--_002_2A84145621092446B6659B8A0F28E26F46FE77084Airsmsx501gerc_--
1
0
This patch depends on gpiolib support for h1940 latch access,
here's link to patch in ml archive:
http://www.spinics.net/lists/arm-kernel/msg98042.html
I hope Ben will find some time to merge it into his tree
before 2.6.37 merge window :)
Signed-off-by: Vasily Khoruzhick <anarsoul(a)gmail.com>
Tested-by: Arnaud Patard <arnaud.patard(a)rtp-net.org>
---
sound/soc/s3c24xx/Kconfig | 8 +
sound/soc/s3c24xx/Makefile | 2 +
sound/soc/s3c24xx/h1940_uda1380.c | 296 +++++++++++++++++++++++++++++++++++++
3 files changed, 306 insertions(+), 0 deletions(-)
create mode 100644 sound/soc/s3c24xx/h1940_uda1380.c
diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig
index 7d8235d..6b50509 100644
--- a/sound/soc/s3c24xx/Kconfig
+++ b/sound/soc/s3c24xx/Kconfig
@@ -118,6 +118,14 @@ config SND_S3C24XX_SOC_SIMTEC_HERMES
select SND_SOC_TLV320AIC3X
select SND_S3C24XX_SOC_SIMTEC
+config SND_S3C24XX_SOC_H1940_UDA1380
+ tristate "Audio support for the HP iPAQ H1940"
+ depends on SND_S3C24XX_SOC && ARCH_H1940
+ select SND_S3C24XX_SOC_I2S
+ select SND_SOC_UDA1380
+ help
+ This driver provides audio support for HP iPAQ h1940 PDA.
+
config SND_S3C24XX_SOC_RX1950_UDA1380
tristate "Audio support for the HP iPAQ RX1950"
depends on SND_S3C24XX_SOC && MACH_RX1950
diff --git a/sound/soc/s3c24xx/Makefile b/sound/soc/s3c24xx/Makefile
index dd412a9..33a7c68 100644
--- a/sound/soc/s3c24xx/Makefile
+++ b/sound/soc/s3c24xx/Makefile
@@ -28,6 +28,7 @@ snd-soc-s3c24xx-simtec-objs := s3c24xx_simtec.o
snd-soc-s3c24xx-simtec-hermes-objs := s3c24xx_simtec_hermes.o
snd-soc-s3c24xx-simtec-tlv320aic23-objs := s3c24xx_simtec_tlv320aic23.o
snd-soc-rx1950-uda1380-objs := rx1950_uda1380.o
+snd-soc-h1940-uda1380-objs := h1940_uda1380.o
snd-soc-smdk64xx-wm8580-objs := smdk64xx_wm8580.o
snd-soc-smdk-wm9713-objs := smdk_wm9713.o
snd-soc-s3c64xx-smartq-wm8987-objs := smartq_wm8987.o
@@ -44,6 +45,7 @@ obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC) += snd-soc-s3c24xx-simtec.o
obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC_HERMES) += snd-soc-s3c24xx-simtec-hermes.o
obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC_TLV320AIC23) += snd-soc-s3c24xx-simtec-tlv320aic23.o
obj-$(CONFIG_SND_S3C24XX_SOC_RX1950_UDA1380) += snd-soc-rx1950-uda1380.o
+obj-$(CONFIG_SND_S3C24XX_SOC_H1940_UDA1380) += snd-soc-h1940-uda1380.o
obj-$(CONFIG_SND_S3C64XX_SOC_WM8580) += snd-soc-smdk64xx-wm8580.o
obj-$(CONFIG_SND_SOC_SMDK_WM9713) += snd-soc-smdk-wm9713.o
obj-$(CONFIG_SND_S3C64XX_SOC_SMARTQ) += snd-soc-s3c64xx-smartq-wm8987.o
diff --git a/sound/soc/s3c24xx/h1940_uda1380.c b/sound/soc/s3c24xx/h1940_uda1380.c
new file mode 100644
index 0000000..77550fa
--- /dev/null
+++ b/sound/soc/s3c24xx/h1940_uda1380.c
@@ -0,0 +1,296 @@
+/*
+ * h1940-uda1380.c -- ALSA Soc Audio Layer
+ *
+ * Copyright (c) 2010 Arnaud Patard <arnaud.patard(a)rtp-net.org>
+ * Copyright (c) 2010 Vasily Khoruzhick <anarsoul(a)gmail.com>
+ *
+ * Based on version from Arnaud Patard <arnaud.patard(a)rtp-net.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/uda1380.h>
+#include <sound/jack.h>
+
+#include <plat/regs-iis.h>
+
+#include <mach/h1940-latch.h>
+
+#include <asm/mach-types.h>
+
+#include "s3c-dma.h"
+#include "s3c24xx-i2s.h"
+#include "../codecs/uda1380.h"
+
+static unsigned int rates[] = {
+ 11025,
+ 22050,
+ 44100,
+};
+
+static struct snd_pcm_hw_constraint_list hw_rates = {
+ .count = ARRAY_SIZE(rates),
+ .list = rates,
+ .mask = 0,
+};
+
+static struct snd_soc_jack hp_jack;
+
+static struct snd_soc_jack_pin hp_jack_pins[] = {
+ {
+ .pin = "Headphone Jack",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Speaker",
+ .mask = SND_JACK_HEADPHONE,
+ .invert = 1,
+ },
+};
+
+static struct snd_soc_jack_gpio hp_jack_gpios[] = {
+ {
+ .gpio = S3C2410_GPG(4),
+ .name = "hp-gpio",
+ .report = SND_JACK_HEADPHONE,
+ .invert = 1,
+ .debounce_time = 200,
+ },
+};
+
+static int h1940_startup(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+
+ runtime->hw.rate_min = hw_rates.list[0];
+ runtime->hw.rate_max = hw_rates.list[hw_rates.count - 1];
+ runtime->hw.rates = SNDRV_PCM_RATE_KNOT;
+
+ return snd_pcm_hw_constraint_list(runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE,
+ &hw_rates);
+}
+
+static int h1940_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ int div;
+ int ret;
+ unsigned int rate = params_rate(params);
+
+ switch (rate) {
+ case 11025:
+ case 22050:
+ case 44100:
+ div = s3c24xx_i2s_get_clockrate() / (384 * rate);
+ if (s3c24xx_i2s_get_clockrate() % (384 * rate) > (192 * rate))
+ div++;
+ break;
+ default:
+ printk(KERN_ERR "%s: rate %d is not supported\n",
+ __func__, rate);
+ return -EINVAL;
+ }
+
+ /* set codec DAI configuration */
+ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+ if (ret < 0)
+ return ret;
+
+ /* set cpu DAI configuration */
+ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+ if (ret < 0)
+ return ret;
+
+ /* select clock source */
+ ret = snd_soc_dai_set_sysclk(cpu_dai, S3C24XX_CLKSRC_PCLK, rate,
+ SND_SOC_CLOCK_OUT);
+ if (ret < 0)
+ return ret;
+
+ /* set MCLK division for sample rate */
+ ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK,
+ S3C2410_IISMOD_384FS);
+ if (ret < 0)
+ return ret;
+
+ /* set BCLK division for sample rate */
+ ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_BCLK,
+ S3C2410_IISMOD_32FS);
+ if (ret < 0)
+ return ret;
+
+ /* set prescaler division for sample rate */
+ ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER,
+ S3C24XX_PRESCALE(div, div));
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static struct snd_soc_ops h1940_ops = {
+ .startup = h1940_startup,
+ .hw_params = h1940_hw_params,
+};
+
+static int h1940_spk_power(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ if (SND_SOC_DAPM_EVENT_ON(event))
+ gpio_set_value(H1940_LATCH_AUDIO_POWER, 1);
+ else
+ gpio_set_value(H1940_LATCH_AUDIO_POWER, 0);
+
+ return 0;
+}
+
+/* h1940 machine dapm widgets */
+static const struct snd_soc_dapm_widget uda1380_dapm_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
+ SND_SOC_DAPM_MIC("Mic Jack", NULL),
+ SND_SOC_DAPM_SPK("Speaker", h1940_spk_power),
+};
+
+/* h1940 machine audio_map */
+static const struct snd_soc_dapm_route audio_map[] = {
+ /* headphone connected to VOUTLHP, VOUTRHP */
+ {"Headphone Jack", NULL, "VOUTLHP"},
+ {"Headphone Jack", NULL, "VOUTRHP"},
+
+ /* ext speaker connected to VOUTL, VOUTR */
+ {"Speaker", NULL, "VOUTL"},
+ {"Speaker", NULL, "VOUTR"},
+
+ /* mic is connected to VINM */
+ {"VINM", NULL, "Mic Jack"},
+};
+
+static struct platform_device *s3c24xx_snd_device;
+
+static int h1940_uda1380_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_codec *codec = rtd->codec;
+ int err;
+
+ /* Add h1940 specific widgets */
+ err = snd_soc_dapm_new_controls(codec, uda1380_dapm_widgets,
+ ARRAY_SIZE(uda1380_dapm_widgets));
+ if (err)
+ return err;
+
+ /* Set up h1940 specific audio path audio_mapnects */
+ err = snd_soc_dapm_add_routes(codec, audio_map,
+ ARRAY_SIZE(audio_map));
+ if (err)
+ return err;
+
+ snd_soc_dapm_enable_pin(codec, "Headphone Jack");
+ snd_soc_dapm_enable_pin(codec, "Speaker");
+ snd_soc_dapm_enable_pin(codec, "Mic Jack");
+
+ snd_soc_dapm_sync(codec);
+
+ snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE,
+ &hp_jack);
+
+ snd_soc_jack_add_pins(&hp_jack, ARRAY_SIZE(hp_jack_pins),
+ hp_jack_pins);
+
+ snd_soc_jack_add_gpios(&hp_jack, ARRAY_SIZE(hp_jack_gpios),
+ hp_jack_gpios);
+
+ return 0;
+}
+
+/* s3c24xx digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link h1940_uda1380_dai[] = {
+ {
+ .name = "uda1380",
+ .stream_name = "UDA1380 Duplex",
+ .cpu_dai_name = "s3c24xx-iis",
+ .codec_dai_name = "uda1380-hifi",
+ .init = h1940_uda1380_init,
+ .platform_name = "s3c24xx-pcm-audio",
+ .codec_name = "uda1380-codec.0-001a",
+ .ops = &h1940_ops,
+ },
+};
+
+static struct snd_soc_card h1940_asoc = {
+ .name = "h1940",
+ .dai_link = h1940_uda1380_dai,
+ .num_links = ARRAY_SIZE(h1940_uda1380_dai),
+};
+
+static int __init h1940_init(void)
+{
+ int ret;
+
+ if (!machine_is_h1940())
+ return -ENODEV;
+
+ /* configure some gpios */
+ ret = gpio_request(H1940_LATCH_AUDIO_POWER, "speaker-power");
+ if (ret)
+ goto err_out;
+
+ ret = gpio_direction_output(H1940_LATCH_AUDIO_POWER, 0);
+ if (ret)
+ goto err_gpio;
+
+ s3c24xx_snd_device = platform_device_alloc("soc-audio", -1);
+ if (!s3c24xx_snd_device) {
+ ret = -ENOMEM;
+ goto err_gpio;
+ }
+
+ platform_set_drvdata(s3c24xx_snd_device, &h1940_asoc);
+ ret = platform_device_add(s3c24xx_snd_device);
+
+ if (ret)
+ goto err_plat;
+
+ return 0;
+
+err_plat:
+ platform_device_put(s3c24xx_snd_device);
+err_gpio:
+ gpio_free(H1940_LATCH_AUDIO_POWER);
+
+err_out:
+ return ret;
+}
+
+static void __exit h1940_exit(void)
+{
+ platform_device_unregister(s3c24xx_snd_device);
+ snd_soc_jack_free_gpios(&hp_jack, ARRAY_SIZE(hp_jack_gpios),
+ hp_jack_gpios);
+ gpio_free(H1940_LATCH_AUDIO_POWER);
+}
+
+module_init(h1940_init);
+module_exit(h1940_exit);
+
+/* Module information */
+MODULE_AUTHOR("Arnaud Patard, Vasily Khoruzhick");
+MODULE_DESCRIPTION("ALSA SoC H1940");
+MODULE_LICENSE("GPL");
--
1.7.2.2
4
20

[alsa-devel] [PATCH] fbdev: sh_mobile_hdmi: fix compilation without SOUND enabled
by Guennadi Liakhovetski 15 Oct '10
by Guennadi Liakhovetski 15 Oct '10
15 Oct '10
At least two more Kconfig options have to be selected to be able to compile
sh_mobile_hdmi.
Signed-off-by: Guennadi Liakhovetski <g.liakhovetski(a)gmx.de>
Cc: Kuninori Morimoto <kuninori.morimoto.gx(a)renesas.com>
---
Liam, Mark: since this patch only touches drivers/video, although that's a
central commonly-used file there, the scope of this patch is limited to
the FB_SH_MOBILE_HDMI block, so, this should safe to go via an SH tree,
but, if Paul doesn't mind, it should also be ok to go via sound.
drivers/video/Kconfig | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 43e90b8..935cdc2 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -1919,6 +1919,8 @@ config FB_SH_MOBILE_HDMI
tristate "SuperH Mobile HDMI controller support"
depends on FB_SH_MOBILE_LCDC
select FB_MODE_HELPERS
+ select SOUND
+ select SND
select SND_SOC
---help---
Driver for the on-chip SH-Mobile HDMI controller.
--
1.7.1
3
2

15 Oct '10
This patch replace magic code with defined name,
and remove unnecessary settings which set default value
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx(a)renesas.com>
---
sound/soc/codecs/ak4642.c | 64 ++++++++++++++++++++++++++++++++------------
1 files changed, 46 insertions(+), 18 deletions(-)
diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c
index 009068f..90c90b7 100644
--- a/sound/soc/codecs/ak4642.c
+++ b/sound/soc/codecs/ak4642.c
@@ -72,6 +72,12 @@
#define AK4642_CACHEREGNUM 0x25
+/* PW_MGMT1*/
+#define PMVCM (1 << 6) /* VCOM Power Management */
+#define PMMIN (1 << 5) /* MIN Input Power Management */
+#define PMDAC (1 << 2) /* DAC Power Management */
+#define PMADL (1 << 0) /* MIC Amp Lch and ADC Lch Power Management */
+
/* PW_MGMT2 */
#define HPMTN (1 << 6)
#define PMHPL (1 << 5)
@@ -83,6 +89,23 @@
#define PMHP_MASK (PMHPL | PMHPR)
#define PMHP PMHP_MASK
+/* PW_MGMT3 */
+#define PMADR (1 << 0) /* MIC L / ADC R Power Management */
+
+/* SG_SL1 */
+#define MINS (1 << 6) /* Switch from MIN to Speaker */
+#define DACL (1 << 4) /* Switch from DAC to Stereo or Receiver */
+#define PMMP (1 << 2) /* MPWR pin Power Management */
+#define MGAIN0 (1 << 0) /* MIC amp gain*/
+
+/* TIMER */
+#define ZTM(param) ((param & 0x3) << 4) /* ALC Zoro Crossing TimeOut */
+#define WTM(param) (((param & 0x4) << 4) | ((param & 0x3) << 2))
+
+/* ALC_CTL1 */
+#define ALC (1 << 5) /* ALC Enable */
+#define LMTH0 (1 << 0) /* ALC Limiter / Recovery Level */
+
/* MD_CTL1 */
#define PLL3 (1 << 7)
#define PLL2 (1 << 6)
@@ -100,6 +123,11 @@
#define FS3 (1 << 5)
#define FS_MASK (FS0 | FS1 | FS2 | FS3)
+/* MD_CTL3 */
+#define BST1 (1 << 3)
+
+/* MD_CTL4 */
+#define DACH (1 << 0)
/*
* Playback Volume (table 39)
@@ -216,11 +244,12 @@ static int ak4642_dai_startup(struct snd_pcm_substream *substream,
* This operation came from example code of
* "ASAHI KASEI AK4642" (japanese) manual p97.
*/
- ak4642_write(codec, 0x0f, 0x09);
- ak4642_write(codec, 0x0e, 0x19);
- ak4642_write(codec, 0x09, 0x91);
- ak4642_write(codec, 0x0c, 0x91);
- snd_soc_update_bits(codec, 0x00, 0x64, 0x64);
+ snd_soc_update_bits(codec, MD_CTL4, DACH, DACH);
+ snd_soc_update_bits(codec, MD_CTL3, BST1, BST1);
+ ak4642_write(codec, L_IVC, 0x91); /* volume */
+ ak4642_write(codec, R_IVC, 0x91); /* volume */
+ snd_soc_update_bits(codec, PW_MGMT1, PMVCM | PMMIN | PMDAC,
+ PMVCM | PMMIN | PMDAC);
snd_soc_update_bits(codec, PW_MGMT2, PMHP_MASK, PMHP);
snd_soc_update_bits(codec, PW_MGMT2, HPMTN, HPMTN);
} else {
@@ -237,13 +266,12 @@ static int ak4642_dai_startup(struct snd_pcm_substream *substream,
* This operation came from example code of
* "ASAHI KASEI AK4642" (japanese) manual p94.
*/
- ak4642_write(codec, 0x02, 0x05);
- ak4642_write(codec, 0x06, 0x3c);
- ak4642_write(codec, 0x08, 0xe1);
- ak4642_write(codec, 0x0b, 0x00);
- ak4642_write(codec, 0x07, 0x21);
- snd_soc_update_bits(codec, 0x00, 0x41, 0x41);
- ak4642_write(codec, 0x10, 0x01);
+ ak4642_write(codec, SG_SL1, PMMP | MGAIN0);
+ ak4642_write(codec, TIMER, ZTM(0x3) | WTM(0x3));
+ ak4642_write(codec, ALC_CTL1, ALC | LMTH0);
+ snd_soc_update_bits(codec, PW_MGMT1, PMVCM | PMADL,
+ PMVCM | PMADL);
+ snd_soc_update_bits(codec, PW_MGMT3, PMADR, PMADR);
}
return 0;
@@ -259,14 +287,14 @@ static void ak4642_dai_shutdown(struct snd_pcm_substream *substream,
/* stop headphone output */
snd_soc_update_bits(codec, PW_MGMT2, HPMTN, 0);
snd_soc_update_bits(codec, PW_MGMT2, PMHP_MASK, 0);
- snd_soc_update_bits(codec, 0x00, 0x64, 0x40);
- ak4642_write(codec, 0x0e, 0x11);
- ak4642_write(codec, 0x0f, 0x08);
+ snd_soc_update_bits(codec, PW_MGMT1, PMMIN | PMDAC, 0);
+ snd_soc_update_bits(codec, MD_CTL3, BST1, 0);
+ snd_soc_update_bits(codec, MD_CTL4, DACH, 0);
} else {
/* stop stereo input */
- snd_soc_update_bits(codec, 0x00, 0x41, 0x40);
- ak4642_write(codec, 0x10, 0x00);
- ak4642_write(codec, 0x07, 0x01);
+ snd_soc_update_bits(codec, PW_MGMT1, PMADL, 0);
+ snd_soc_update_bits(codec, PW_MGMT3, PMADR, 0);
+ snd_soc_update_bits(codec, ALC_CTL1, ALC, 0);
}
}
--
1.7.0.4
3
2
Fixup commit 9b1a2566: Remove error loop
Signed-off-by: David Henningsson <david.henningsson(a)canonical.com>
---
speaker-test/speaker-test.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/speaker-test/speaker-test.c b/speaker-test/speaker-test.c
index 458a8d7..3029110 100644
--- a/speaker-test/speaker-test.c
+++ b/speaker-test/speaker-test.c
@@ -993,9 +993,9 @@ int main(int argc, char *argv[]) {
}
- while ((err = snd_pcm_open(&handle, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
+ if ((err = snd_pcm_open(&handle, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
printf(_("Playback open error: %d,%s\n"), err,snd_strerror(err));
- sleep(1);
+ exit(EXIT_FAILURE);
}
if ((err = set_hwparams(handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
--
1.7.1
--------------070605020506060102030305--
1
0

[alsa-devel] [PATCH] ASoC: Move soc-core module init next to functon definition
by Mark Brown 15 Oct '10
by Mark Brown 15 Oct '10
15 Oct '10
Signed-off-by: Mark Brown <broonie(a)opensource.wolfsonmicro.com>
---
sound/soc/soc-core.c | 3 +--
1 files changed, 1 insertions(+), 2 deletions(-)
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index f4286ab..4cbfe46 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -3311,6 +3311,7 @@ static int __init snd_soc_init(void)
return platform_driver_register(&soc_driver);
}
+module_init(snd_soc_init);
static void __exit snd_soc_exit(void)
{
@@ -3319,8 +3320,6 @@ static void __exit snd_soc_exit(void)
#endif
platform_driver_unregister(&soc_driver);
}
-
-module_init(snd_soc_init);
module_exit(snd_soc_exit);
/* Module information */
--
1.7.1
2
2

[alsa-devel] [PATCH 0/2] ASoC: simultaneous playback/recorde support for SH board
by Kuninori Morimoto 15 Oct '10
by Kuninori Morimoto 15 Oct '10
15 Oct '10
Dear Mark, Liam
These are simultaneous playback/recorde support for FSI and ak4642
Kuninori Morimoto (2):
ASoC: fsi: simultaneous playback/recorde support
ASoC: ak4642: simultaneous playback/recorde support
Best regards
--
Kuninori Morimoto
3
10

15 Oct '10
Signed-off-by: Mark Brown <broonie(a)opensource.wolfsonmicro.com>
---
sound/soc/soc-core.c | 51 ++++++++++++++++++++++++++++++++++---------------
1 files changed, 35 insertions(+), 16 deletions(-)
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index dc1c567..4cbfe46 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -275,15 +275,22 @@ static ssize_t codec_list_read_file(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
- ssize_t ret = 0;
+ ssize_t len, ret = 0;
struct snd_soc_codec *codec;
if (!buf)
return -ENOMEM;
- list_for_each_entry(codec, &codec_list, list)
- ret += snprintf(buf + ret, PAGE_SIZE - ret, "%s\n",
- codec->name);
+ list_for_each_entry(codec, &codec_list, list) {
+ len = snprintf(buf + ret, PAGE_SIZE - ret, "%s\n",
+ codec->name);
+ if (len >= 0)
+ ret += len;
+ if (ret > PAGE_SIZE) {
+ ret = PAGE_SIZE;
+ break;
+ }
+ }
if (ret >= 0)
ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
@@ -302,17 +309,23 @@ static ssize_t dai_list_read_file(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
- ssize_t ret = 0;
+ ssize_t len, ret = 0;
struct snd_soc_dai *dai;
if (!buf)
return -ENOMEM;
- list_for_each_entry(dai, &dai_list, list)
- ret += snprintf(buf + ret, PAGE_SIZE - ret, "%s\n", dai->name);
+ list_for_each_entry(dai, &dai_list, list) {
+ len = snprintf(buf + ret, PAGE_SIZE - ret, "%s\n", dai->name);
+ if (len >= 0)
+ ret += len;
+ if (ret > PAGE_SIZE) {
+ ret = PAGE_SIZE;
+ break;
+ }
+ }
- if (ret >= 0)
- ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
kfree(buf);
@@ -329,18 +342,24 @@ static ssize_t platform_list_read_file(struct file *file,
size_t count, loff_t *ppos)
{
char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
- ssize_t ret = 0;
+ ssize_t len, ret = 0;
struct snd_soc_platform *platform;
if (!buf)
return -ENOMEM;
- list_for_each_entry(platform, &platform_list, list)
- ret += snprintf(buf + ret, PAGE_SIZE - ret, "%s\n",
- platform->name);
+ list_for_each_entry(platform, &platform_list, list) {
+ len = snprintf(buf + ret, PAGE_SIZE - ret, "%s\n",
+ platform->name);
+ if (len >= 0)
+ ret += len;
+ if (ret > PAGE_SIZE) {
+ ret = PAGE_SIZE;
+ break;
+ }
+ }
- if (ret >= 0)
- ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
kfree(buf);
@@ -3015,11 +3034,11 @@ int snd_soc_register_dais(struct device *dev,
}
dai->dev = dev;
+ dai->driver = &dai_drv[i];
if (dai->driver->id)
dai->id = dai->driver->id;
else
dai->id = i;
- dai->driver = &dai_drv[i];
if (!dai->driver->ops)
dai->driver->ops = &null_dai_ops;
--
1.7.1
2
3
Hi Daniel and Clemens,
I have been testing the sdr-widget and when alsamixer is run, there is a
snd_mixer_load error - Invalid Argument.
The sdr-widget firmware with UAC1 descriptors works under Windows for audio
control (muting and volume). The UAC2 firmware works under Linux and OSX for
audio control as well.
However, firmware with UAC1 does not work under Linux for audio control. I
traced the error to the fact that the sdr-widget enumerates as a composite USB
device and the audio control interface is not interface #0.
The current Linux driver for UAC1 appears to assume that the audio control
interface is #0. It should not make that assumption.
Alex
1
0
hello
i've 8 hubs and each hubs has got 4 usb soundcards, i tried to install but i
cannot
[root@localhost ~]# 4 asoundinit_tx:1519 snd_pcm_hw_params() -32 Broken pipe
4 asoundinit_tx:1612 fail
/usr/sbin/safe_asterisk: line 125: 7171 Segmentation fault nice -n
$PRIORITY ${ASTSBINDIR}/asterisk -f ${CLIARGS} ${ASTARGS}
Asterisk ended with exit status 139
Asterisk exited on signal EXITSTATUS-128.
cat: /var/run/asterisk.pid: No such file or directory
how could i fix that?
2
1
hello
i've 8 hubs and each hubs has got 4 usb soundcards, i tried to install but i
cannot
[root@localhost ~]# 4 asoundinit_tx:1519 snd_pcm_hw_params() -32 Broken pipe
4 asoundinit_tx:1612 fail
/usr/sbin/safe_asterisk: line 125: 7171 Segmentation fault nice -n
$PRIORITY ${ASTSBINDIR}/asterisk -f ${CLIARGS} ${ASTARGS}
Asterisk ended with exit status 139
Asterisk exited on signal EXITSTATUS-128.
cat: /var/run/asterisk.pid: No such file or directory
1
0

15 Oct '10
Hi,
This series adds AC97 audio support for Cirrus Logic EP93xx family SoCs. Example
machine driver is for Simplemachines Sim.One (which is the only hardware that I
have which has AC97 codec).
Changes the previous version:
- rebased against latest ASoC tree (added support for
multicomponent ASoC)
- fixed according comments by Mark Brown
- patch 1/4 (DMA fix) is now in ARM tree so dropped from
this series.
Thanks,
MW
Mika Westerberg (3):
ASoC: add ep93xx AC97 audio driver
ARM: ep93xx: add AC97 platform support
ASoC: ep93xx: add Simplemachines Sim.One AC97 audio support
arch/arm/mach-ep93xx/core.c | 34 ++
arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h | 1 +
arch/arm/mach-ep93xx/include/mach/platform.h | 1 +
arch/arm/mach-ep93xx/simone.c | 1 +
sound/soc/ep93xx/Kconfig | 16 +-
sound/soc/ep93xx/Makefile | 4 +
sound/soc/ep93xx/ep93xx-ac97.c | 468 +++++++++++++++++++++++
sound/soc/ep93xx/simone.c | 89 +++++
8 files changed, 613 insertions(+), 1 deletions(-)
create mode 100644 sound/soc/ep93xx/ep93xx-ac97.c
create mode 100644 sound/soc/ep93xx/simone.c
5
9

Re: [alsa-devel] [PATCH 2/2] [v2] powerpc/85xx: add DIU support to the Freecale P1022DS reference board
by Timur Tabi 14 Oct '10
by Timur Tabi 14 Oct '10
14 Oct '10
Mark, can you pick up this patch for us? Because it depends on
"powerpc: rename immap_86xx.h to fsl_guts.h, and add 85xx support", it
will break the build if we apply to powerpc-next.
You can grab the patch from http://patchwork.ozlabs.org/patch/67095/
On Thu, Oct 7, 2010 at 2:36 PM, Timur Tabi <timur(a)freescale.com> wrote:
> The Freescale P1022DS has an on-chip video controller called the DIU, and a
> driver for this device already exists. Update the platform file for the
> P1022DS reference board to enable the driver, and update the defconfig for
> Freescale MPC85xx boards to add the driver.
>
> Signed-off-by: Timur Tabi <timur(a)freescale.com>
> ---
--
Timur Tabi
Linux kernel developer at Freescale
2
1
Hello, i've a problem about to install 32 soundcards on my linux server
(centos 5.3) i tried all ways but i fail all times to run 32 soundcards at
the same time. after that i googled on the internet then find the text about
that. is it possible to run 32 soundcards same time on my server?
if yes how could i do that
thank you for your helps...
- ALSA: Fix limit of 8 PCM devices in SNDRV_CTL_IOCTL_PCM_NEXT_DEVICE When
compiled with CONFIG_SND_DYNAMIC_MINORS the ALSA core is fineto have more
than 8 PCM devices per card, except one place -
theSNDRV_CTL_IOCTL_PCM_NEXT_DEVICE ioctl, which will not
enumeratedevices
> 7. This patch fixes the issue, changing the devices list organisation.
3
2

[alsa-devel] [PATCH v3 9/9] davinci: USB-OHCI support for Omapl138-Hawkboard
by vm.rod25@gmail.com 14 Oct '10
by vm.rod25@gmail.com 14 Oct '10
14 Oct '10
From: Victor Rodriguez <victor.rodriguez(a)sasken.com>
This patch adds USB-OHCI support for the Hawkboard-L138 system
Signed-off-by: Victor Rodriguez <victor.rodriguez(a)sasken.com>
---
Notes:
This patch works with da8xx_omapl_defconfig
In order to test it select in menuconfig like insmodule
Device Drivers --->
SCSI device support --->
SCSI device support
legacy /proc/scsi/ support
SCSI disk support
SCSI low-level drivers
USB support --->
Support for Host-side US
OHCI HCD support (NEW)
USB Mass Storage support (NEW)
USB Gadget Support --->
USB Gadget Drivers (Ethernet Gadget\
(with CDC Ethernet support)) --->
NOP USB Transceiver Driver
And you will be able to mount and USB pen drive
In order to connect a keyboard or a mouse on a USB-hub
select in menuconfig like insmodule
HID Devices --->
Generic HID support
USB Human Interface Device (full HID) support
arch/arm/mach-davinci/board-omapl138-hawk.c | 101 +++++++++++++++++++++++++++
1 files changed, 101 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-davinci/board-omapl138-hawk.c b/arch/arm/mach-davinci/board-omapl138-hawk.c
index 723ac03..bac29fc 100644
--- a/arch/arm/mach-davinci/board-omapl138-hawk.c
+++ b/arch/arm/mach-davinci/board-omapl138-hawk.c
@@ -26,6 +26,9 @@
#define DA850_HAWK_MMCSD_CD_PIN GPIO_TO_PIN(3, 12)
#define DA850_HAWK_MMCSD_WP_PIN GPIO_TO_PIN(3, 13)
+#define DA850_USB1_VBUS_PIN GPIO_TO_PIN(2, 4)
+#define DA850_USB1_OC_PIN GPIO_TO_PIN(6, 13)
+
static short omapl138_hawk_mii_pins[] __initdata = {
DA850_MII_TXEN, DA850_MII_TXCLK, DA850_MII_COL, DA850_MII_TXD_3,
DA850_MII_TXD_2, DA850_MII_TXD_1, DA850_MII_TXD_0, DA850_MII_RXER,
@@ -177,6 +180,94 @@ static struct davinci_mmc_config da850_mmc_config = {
.version = MMC_CTLR_VERSION_2,
};
+static irqreturn_t omapl138_hawk_usb_ocic_irq(int irq, void *dev_id);
+static da8xx_ocic_handler_t hawk_usb_ocic_handler;
+
+static const short da850_hawk_usb11_pins[] = {
+ DA850_GPIO2_4, DA850_GPIO6_13,
+ -1
+};
+static int hawk_usb_set_power(unsigned port, int on)
+{
+ gpio_set_value(DA850_USB1_VBUS_PIN, on);
+ return 0;
+}
+
+static int hawk_usb_get_power(unsigned port)
+{
+ return gpio_get_value(DA850_USB1_VBUS_PIN);
+}
+
+static int hawk_usb_get_oci(unsigned port)
+{
+ return !gpio_get_value(DA850_USB1_OC_PIN);
+}
+
+static int hawk_usb_ocic_notify(da8xx_ocic_handler_t handler)
+{
+ int irq = gpio_to_irq(DA850_USB1_OC_PIN);
+ int error = 0;
+
+ if (handler != NULL) {
+ hawk_usb_ocic_handler = handler;
+
+ error = request_irq(irq, omapl138_hawk_usb_ocic_irq,
+ IRQF_DISABLED | IRQF_TRIGGER_RISING |
+ IRQF_TRIGGER_FALLING,
+ "OHCI over-current indicator", NULL);
+ if (error)
+ printk(KERN_ERR "%s: could not request IRQ to watch "
+ "over-current indicator changes\n", __func__);
+ } else
+ free_irq(irq, NULL);
+
+ return error;
+}
+
+static struct da8xx_ohci_root_hub omapl138_hawk_usb11_pdata = {
+ .set_power = hawk_usb_set_power,
+ .get_power = hawk_usb_get_power,
+ .get_oci = hawk_usb_get_oci,
+ .ocic_notify = hawk_usb_ocic_notify,
+ /* TPS2087 switch @ 5V */
+ .potpgt = (3 + 1) / 2, /* 3 ms max */
+};
+
+static irqreturn_t omapl138_hawk_usb_ocic_irq(int irq, void *dev_id)
+{
+ hawk_usb_ocic_handler(&omapl138_hawk_usb11_pdata, 1);
+ return IRQ_HANDLED;
+}
+
+static __init void omapl138_hawk_usb_init(void)
+{
+ int ret;
+ u32 cfgchip2;
+ /*
+ * Setup the Ref. clock frequency for the HAWK at 24 MHz.
+ */
+ cfgchip2 = __raw_readl(DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG));
+ cfgchip2 &= ~CFGCHIP2_REFFREQ;
+ cfgchip2 |= CFGCHIP2_REFFREQ_24MHZ;
+ __raw_writel(cfgchip2, DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG));
+
+ ret = gpio_request(DA850_USB1_VBUS_PIN, "USB1 VBUS\n");
+ if (ret) {
+ printk(KERN_ERR "%s: failed to request GPIO for USB 1.1 port "
+ "power control: %d\n", __func__, ret);
+ return;
+ }
+ gpio_direction_output(DA850_USB1_VBUS_PIN, 0);
+
+ ret = gpio_request(DA850_USB1_OC_PIN, "USB1 OC");
+ if (ret) {
+ printk(KERN_ERR "%s: failed to request GPIO for USB 1.1 port "
+ "over-current indicator: %d\n", __func__, ret);
+ return;
+ }
+ gpio_direction_input(DA850_USB1_OC_PIN);
+}
+
static struct davinci_uart_config omapl138_hawk_uart_config __initdata = {
.enabled_uarts = 0x7,
};
@@ -229,6 +320,16 @@ static __init void omapl138_hawk_init(void)
pr_warning("%s: MMC/SD0 registration failed: %d\n",
__func__, ret);
+ ret = davinci_cfg_reg_list(da850_hawk_usb11_pins);
+ if (ret)
+ pr_warning("%s: USB 1.1 PinMux setup failed: %d\n",
+ __func__, ret);
+ omapl138_hawk_usb_init();
+ ret = da8xx_register_usb11(&omapl138_hawk_usb11_pdata);
+ if (ret)
+ pr_warning("%s: USB 1.1 registration failed: %d\n",
+ __func__, ret);
+
ret = da8xx_register_watchdog();
if (ret)
pr_warning("omapl138_hawk_init: "
--
1.6.0.5
2
1

[alsa-devel] [PATCH v3 6/9] davinci: MMC/SD and USB-OHCI configuration for Omapl138-Hawkboard
by vm.rod25@gmail.com 14 Oct '10
by vm.rod25@gmail.com 14 Oct '10
14 Oct '10
From: Victor Rodriguez <victor.rodriguez(a)sasken.com>
This patch defines Pin Mux configuration to enable MMC/SD
and USB-OHCI on the Hawkboard-L138 system
Signed-off-by: Victor Rodriguez <victor.rodriguez(a)sasken.com>
---
arch/arm/mach-davinci/da850.c | 4 ++++
arch/arm/mach-davinci/include/mach/mux.h | 4 ++++
2 files changed, 8 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c
index f033a0a..646e8b2 100644
--- a/arch/arm/mach-davinci/da850.c
+++ b/arch/arm/mach-davinci/da850.c
@@ -548,6 +548,10 @@ static const struct mux_config da850_pins[] = {
MUX_CFG(DA850, GPIO2_15, 5, 0, 15, 8, false)
MUX_CFG(DA850, GPIO4_0, 10, 28, 15, 8, false)
MUX_CFG(DA850, GPIO4_1, 10, 24, 15, 8, false)
+ MUX_CFG(DA850, GPIO3_12, 7, 12, 15, 8, false)
+ MUX_CFG(DA850, GPIO3_13, 7, 8, 15, 8, false)
+ MUX_CFG(DA850, GPIO2_4, 6, 12, 15, 8, false)
+ MUX_CFG(DA850, GPIO6_13, 13, 8, 15, 8, false)
MUX_CFG(DA850, RTC_ALARM, 0, 28, 15, 2, false)
#endif
};
diff --git a/arch/arm/mach-davinci/include/mach/mux.h b/arch/arm/mach-davinci/include/mach/mux.h
index de11aac..f2c2117 100644
--- a/arch/arm/mach-davinci/include/mach/mux.h
+++ b/arch/arm/mach-davinci/include/mach/mux.h
@@ -913,6 +913,10 @@ enum davinci_da850_index {
DA850_GPIO2_15,
DA850_GPIO4_0,
DA850_GPIO4_1,
+ DA850_GPIO3_12,
+ DA850_GPIO3_13,
+ DA850_GPIO2_4,
+ DA850_GPIO6_13,
DA850_RTC_ALARM,
};
--
1.6.0.5
2
1

[alsa-devel] [PATCH v3 2/9] davinci: EDMA support for Omapl138-Hawkboard
by vm.rod25@gmail.com 14 Oct '10
by vm.rod25@gmail.com 14 Oct '10
14 Oct '10
From: Victor Rodriguez <victor.rodriguez(a)sasken.com>
This patch adds EDMA support for the Hawkboard-L138 system
Signed-off-by: Victor Rodriguez <victor.rodriguez(a)sasken.com>
---
arch/arm/mach-davinci/board-omapl138-hawk.c | 55 +++++++++++++++++++++++++++
1 files changed, 55 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-davinci/board-omapl138-hawk.c b/arch/arm/mach-davinci/board-omapl138-hawk.c
index 3ae5178..358944b 100644
--- a/arch/arm/mach-davinci/board-omapl138-hawk.c
+++ b/arch/arm/mach-davinci/board-omapl138-hawk.c
@@ -66,6 +66,56 @@ static int __init omapl138_hawk_config_emac(void)
return 0;
}
+/*
+ * The following EDMA channels/slots are not being used by drivers (for
+ * example: Timer, GPIO, UART events etc) on da850/omap-l138 EVM/Hawkboard,
+ * hence they are being reserved for codecs on the DSP side.
+ */
+static const s16 da850_dma0_rsv_chans[][2] = {
+ /* (offset, number) */
+ { 8, 6},
+ {24, 4},
+ {30, 2},
+ {-1, -1}
+};
+
+static const s16 da850_dma0_rsv_slots[][2] = {
+ /* (offset, number) */
+ { 8, 6},
+ {24, 4},
+ {30, 50},
+ {-1, -1}
+};
+
+static const s16 da850_dma1_rsv_chans[][2] = {
+ /* (offset, number) */
+ { 0, 28},
+ {30, 2},
+ {-1, -1}
+};
+
+static const s16 da850_dma1_rsv_slots[][2] = {
+ /* (offset, number) */
+ { 0, 28},
+ {30, 90},
+ {-1, -1}
+};
+
+static struct edma_rsv_info da850_edma_cc0_rsv = {
+ .rsv_chans = da850_dma0_rsv_chans,
+ .rsv_slots = da850_dma0_rsv_slots,
+};
+
+static struct edma_rsv_info da850_edma_cc1_rsv = {
+ .rsv_chans = da850_dma1_rsv_chans,
+ .rsv_slots = da850_dma1_rsv_slots,
+};
+
+static struct edma_rsv_info *da850_edma_rsv[2] = {
+ &da850_edma_cc0_rsv,
+ &da850_edma_cc1_rsv,
+};
+
static struct davinci_uart_config omapl138_hawk_uart_config __initdata = {
.enabled_uarts = 0x7,
@@ -77,6 +127,11 @@ static __init void omapl138_hawk_init(void)
davinci_serial_init(&omapl138_hawk_uart_config);
+ ret = da850_register_edma(da850_edma_rsv);
+ if (ret)
+ pr_warning("omapl138_hawk_init: "
+ "edma registration failed: %d\n", ret);
+
ret = omapl138_hawk_config_emac();
ret = da8xx_register_watchdog();
--
1.6.0.5
2
1

[alsa-devel] [PATCH v3 8/9] davinci: USB clocks for Omapl138-Hawkboard
by vm.rod25@gmail.com 14 Oct '10
by vm.rod25@gmail.com 14 Oct '10
14 Oct '10
From: Victor Rodriguez <victor.rodriguez(a)sasken.com>
This patch adds USB clocks for the Hawkboard-L138 system
Signed-off-by: Victor Rodriguez <victor.rodriguez(a)sasken.com>
---
arch/arm/mach-davinci/da850.c | 17 +++++++++++++++++
1 files changed, 17 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c
index 646e8b2..77801ed 100644
--- a/arch/arm/mach-davinci/da850.c
+++ b/arch/arm/mach-davinci/da850.c
@@ -345,6 +345,21 @@ static struct clk aemif_clk = {
.flags = ALWAYS_ENABLED,
};
+static struct clk usb11_clk = {
+ .name = "usb11",
+ .parent = &pll0_sysclk4,
+ .lpsc = DA8XX_LPSC1_USB11,
+ .gpsc = 1,
+ .flags = ALWAYS_ENABLED,
+ };
+
+static struct clk usb20_clk = {
+ .name = "usb20",
+ .parent = &pll0_sysclk2,
+ .lpsc = DA8XX_LPSC1_USB20,
+ .gpsc = 1,
+ };
+
static struct clk_lookup da850_clks[] = {
CLK(NULL, "ref", &ref_clk),
CLK(NULL, "pll0", &pll0_clk),
@@ -387,6 +402,8 @@ static struct clk_lookup da850_clks[] = {
CLK("davinci_mmc.0", NULL, &mmcsd0_clk),
CLK("davinci_mmc.1", NULL, &mmcsd1_clk),
CLK(NULL, "aemif", &aemif_clk),
+ CLK(NULL, "usb11", &usb11_clk),
+ CLK(NULL, "usb20", &usb20_clk),
CLK(NULL, NULL, NULL),
};
--
1.6.0.5
1
0

[alsa-devel] [PATCH v3 7/9] davinci: MMC/SD support for Omapl138-Hawkboar
by vm.rod25@gmail.com 14 Oct '10
by vm.rod25@gmail.com 14 Oct '10
14 Oct '10
From: Victor Rodriguez <victor.rodriguez(a)sasken.com>
This patch adds MMC/SD support for the Hawkboard-L138 system
Signed-off-by: Victor Rodriguez <victor.rodriguez(a)sasken.com>
---
Notes:
This patch works with da8xx_omapl_defconfig
In order to test it select in menuconfig like insmodule
MMC/SD/SDIO card support --->
MMC block device driver
Use bounce buffer for simple hosts
TI DAVINCI Multimedia Card Interface support
arch/arm/mach-davinci/board-omapl138-hawk.c | 50 +++++++++++++++++++++++++++
1 files changed, 50 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-davinci/board-omapl138-hawk.c b/arch/arm/mach-davinci/board-omapl138-hawk.c
index c0a999a..723ac03 100644
--- a/arch/arm/mach-davinci/board-omapl138-hawk.c
+++ b/arch/arm/mach-davinci/board-omapl138-hawk.c
@@ -23,6 +23,8 @@
#include <mach/mux.h>
#define HAWKBOARD_PHY_ID "0:07"
+#define DA850_HAWK_MMCSD_CD_PIN GPIO_TO_PIN(3, 12)
+#define DA850_HAWK_MMCSD_WP_PIN GPIO_TO_PIN(3, 13)
static short omapl138_hawk_mii_pins[] __initdata = {
DA850_MII_TXEN, DA850_MII_TXCLK, DA850_MII_COL, DA850_MII_TXD_3,
@@ -149,6 +151,32 @@ static struct snd_platform_data omapl138_hawk_snd_data = {
.rxnumevt = 1,
};
+static const short hawk_mmcsd0_pins[] = {
+ DA850_MMCSD0_DAT_0, DA850_MMCSD0_DAT_1, DA850_MMCSD0_DAT_2,
+ DA850_MMCSD0_DAT_3, DA850_MMCSD0_CLK, DA850_MMCSD0_CMD,
+ DA850_GPIO3_12, DA850_GPIO3_13,
+ -1
+};
+
+static int da850_hawk_mmc_get_ro(int index)
+{
+ return gpio_get_value(DA850_HAWK_MMCSD_WP_PIN);
+}
+
+static int da850_hawk_mmc_get_cd(int index)
+{
+ return !gpio_get_value(DA850_HAWK_MMCSD_CD_PIN);
+}
+
+static struct davinci_mmc_config da850_mmc_config = {
+ .get_ro = da850_hawk_mmc_get_ro,
+ .get_cd = da850_hawk_mmc_get_cd,
+ .wires = 4,
+ .max_freq = 50000000,
+ .caps = MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED,
+ .version = MMC_CTLR_VERSION_2,
+};
+
static struct davinci_uart_config omapl138_hawk_uart_config __initdata = {
.enabled_uarts = 0x7,
};
@@ -179,6 +207,28 @@ static __init void omapl138_hawk_init(void)
pr_warning("%s: mcasp mux setup failed: %d\n", __func__, ret);
da8xx_register_mcasp(0, &omapl138_hawk_snd_data);
+ ret = davinci_cfg_reg_list(hawk_mmcsd0_pins);
+ if (ret)
+ pr_warning("%s: MMC/SD0 mux setup failed: %d\n",
+ __func__, ret);
+
+ ret = gpio_request(DA850_HAWK_MMCSD_CD_PIN, "MMC CD\n");
+ if (ret)
+ pr_warning("%s: can not open GPIO %d\n",
+ __func__, DA850_HAWK_MMCSD_CD_PIN);
+ gpio_direction_input(DA850_HAWK_MMCSD_CD_PIN);
+
+ ret = gpio_request(DA850_HAWK_MMCSD_WP_PIN, "MMC WP\n");
+ if (ret)
+ pr_warning("%s: can not open GPIO %d\n",
+ __func__, DA850_HAWK_MMCSD_WP_PIN);
+ gpio_direction_input(DA850_HAWK_MMCSD_WP_PIN);
+
+ ret = da8xx_register_mmcsd0(&da850_mmc_config);
+ if (ret)
+ pr_warning("%s: MMC/SD0 registration failed: %d\n",
+ __func__, ret);
+
ret = da8xx_register_watchdog();
if (ret)
pr_warning("omapl138_hawk_init: "
--
1.6.0.5
1
0

[alsa-devel] [PATCH v3 5/9] davinci: Audio support for Omapl138-Hawkboard
by vm.rod25@gmail.com 14 Oct '10
by vm.rod25@gmail.com 14 Oct '10
14 Oct '10
From: Victor Rodriguez <victor.rodriguez(a)sasken.com>
This patch adds sound support for the Hawkboard-L138 system
Signed-off-by: Victor Rodriguez <victor.rodriguez(a)sasken.com>
---
Notes:
This patch works with da8xx_omapl_defconfig
In order to test ALSA utils select in menuconfig like insmodule:
Sound card support --->
Advanced Linux Sound Architecture --->
ALSA for SoC audio support --->
SoC Audio for the TI DAVINCI chip
SoC Audio support for DA850/OMAP-L138 EVM/Hawkboard
arch/arm/mach-davinci/board-omapl138-hawk.c | 45 +++++++++++++++++++++++++++
1 files changed, 45 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-davinci/board-omapl138-hawk.c b/arch/arm/mach-davinci/board-omapl138-hawk.c
index 358944b..c0a999a 100644
--- a/arch/arm/mach-davinci/board-omapl138-hawk.c
+++ b/arch/arm/mach-davinci/board-omapl138-hawk.c
@@ -13,6 +13,7 @@
#include <linux/init.h>
#include <linux/console.h>
#include <linux/gpio.h>
+#include <linux/i2c.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -116,6 +117,37 @@ static struct edma_rsv_info *da850_edma_rsv[2] = {
&da850_edma_cc1_rsv,
};
+static struct i2c_board_info __initdata omapl138_hawk_i2c_devices[] = {
+ {
+ I2C_BOARD_INFO("tlv320aic3x", 0x18),
+ },
+};
+
+static struct davinci_i2c_platform_data omapl138_hawk_i2c_0_pdata = {
+ .bus_freq = 100, /* kHz */
+ .bus_delay = 0, /* usec */
+};
+
+/* davinci Hawkboard audio machine driver */
+static u8 da850_iis_serializer_direction[] = {
+ INACTIVE_MODE, INACTIVE_MODE, INACTIVE_MODE, INACTIVE_MODE,
+ INACTIVE_MODE, INACTIVE_MODE, INACTIVE_MODE, INACTIVE_MODE,
+ INACTIVE_MODE, INACTIVE_MODE, INACTIVE_MODE, INACTIVE_MODE,
+ INACTIVE_MODE, TX_MODE, RX_MODE, INACTIVE_MODE,
+};
+
+static struct snd_platform_data omapl138_hawk_snd_data = {
+ .tx_dma_offset = 0x2000,
+ .rx_dma_offset = 0x2000,
+ .op_mode = DAVINCI_MCASP_IIS_MODE,
+ .num_serializer = ARRAY_SIZE(da850_iis_serializer_direction),
+ .tdm_slots = 2,
+ .serial_dir = da850_iis_serializer_direction,
+ .asp_chan_q = EVENTQ_1,
+ .version = MCASP_VERSION_2,
+ .txnumevt = 1,
+ .rxnumevt = 1,
+};
static struct davinci_uart_config omapl138_hawk_uart_config __initdata = {
.enabled_uarts = 0x7,
@@ -134,6 +166,19 @@ static __init void omapl138_hawk_init(void)
ret = omapl138_hawk_config_emac();
+ i2c_register_board_info(1, omapl138_hawk_i2c_devices,
+ ARRAY_SIZE(omapl138_hawk_i2c_devices));
+
+ ret = da8xx_register_i2c(0, &omapl138_hawk_i2c_0_pdata);
+ if (ret)
+ pr_warning("%s: i2c0 registration failed: %d\n",
+ __func__, ret);
+
+ ret = davinci_cfg_reg_list(da850_mcasp_pins);
+ if (ret)
+ pr_warning("%s: mcasp mux setup failed: %d\n", __func__, ret);
+ da8xx_register_mcasp(0, &omapl138_hawk_snd_data);
+
ret = da8xx_register_watchdog();
if (ret)
pr_warning("omapl138_hawk_init: "
--
1.6.0.5
1
0

[alsa-devel] [PATCH v3 4/9] davinci: McASP configuration for Omapl138-Hawkboard
by vm.rod25@gmail.com 14 Oct '10
by vm.rod25@gmail.com 14 Oct '10
14 Oct '10
From: Victor Rodriguez <victor.rodriguez(a)sasken.com>
This patch defines Pin Mux configuration for MacASP
used on the Hawkboard-L138 system in order to add Audio support
Signed-off-by: Victor Rodriguez <victor.rodriguez(a)sasken.com>
---
arch/arm/mach-davinci/da850.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c
index 63916b9..f033a0a 100644
--- a/arch/arm/mach-davinci/da850.c
+++ b/arch/arm/mach-davinci/da850.c
@@ -591,7 +591,7 @@ const short da850_cpgmac_pins[] __initdata = {
const short da850_mcasp_pins[] __initdata = {
DA850_AHCLKX, DA850_ACLKX, DA850_AFSX,
DA850_AHCLKR, DA850_ACLKR, DA850_AFSR, DA850_AMUTE,
- DA850_AXR_11, DA850_AXR_12,
+ DA850_AXR_11, DA850_AXR_12, DA850_AXR_13, DA850_AXR_14,
-1
};
--
1.6.0.5
1
0

[alsa-devel] [PATCH v3 3/9] davinci: ASoC support for Omapl138-Hawkboard
by vm.rod25@gmail.com 14 Oct '10
by vm.rod25@gmail.com 14 Oct '10
14 Oct '10
From: Victor Rodriguez <victor.rodriguez(a)sasken.com>
This patch adds ASoC support for the Hawkboard-L138 system
Signed-off-by: Victor Rodriguez <victor.rodriguez(a)sasken.com>
---
sound/soc/davinci/Kconfig | 5 +++--
sound/soc/davinci/davinci-evm.c | 6 ++++--
2 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/sound/soc/davinci/Kconfig b/sound/soc/davinci/Kconfig
index 6bbf001..72c6752 100644
--- a/sound/soc/davinci/Kconfig
+++ b/sound/soc/davinci/Kconfig
@@ -76,8 +76,9 @@ config SND_DA830_SOC_EVM
DA830/OMAP-L137 EVM
config SND_DA850_SOC_EVM
- tristate "SoC Audio support for DA850/OMAP-L138 EVM"
- depends on SND_DAVINCI_SOC && MACH_DAVINCI_DA850_EVM
+ tristate "SoC Audio support for DA850/OMAP-L138 EVM/Hawkboard"
+ depends on SND_DAVINCI_SOC && (MACH_DAVINCI_DA850_EVM || \
+ MACH_OMAPL138_HAWKBOARD)
select SND_DAVINCI_SOC_MCASP
select SND_SOC_TLV320AIC3X
help
diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c
index 97f74d6..73093eb 100644
--- a/sound/soc/davinci/davinci-evm.c
+++ b/sound/soc/davinci/davinci-evm.c
@@ -59,7 +59,8 @@ static int evm_hw_params(struct snd_pcm_substream *substream,
sysclk = 12288000;
else if (machine_is_davinci_da830_evm() ||
- machine_is_davinci_da850_evm())
+ machine_is_davinci_da850_evm() ||
+ machine_is_omapl138_hawkboard())
sysclk = 24576000;
else
@@ -311,7 +312,8 @@ static int __init evm_init(void)
} else if (machine_is_davinci_da830_evm()) {
evm_snd_dev_data = &da830_evm_snd_devdata;
index = 1;
- } else if (machine_is_davinci_da850_evm()) {
+ } else if (machine_is_davinci_da850_evm() ||
+ machine_is_omapl138_hawkboard()) {
evm_snd_dev_data = &da850_evm_snd_devdata;
index = 0;
} else
--
1.6.0.5
1
0

14 Oct '10
From: Victor Rodriguez <victor.rodriguez(a)sasken.com>
This patch adds
EMAC, EDMA, ASoC, SOUND, MMC/SD and USB OHCI
support for the Hawkboard-L138 system
It is under the machine name "omapl138_hawkboard".
This system is based on the da850 davinci CPU architecture.
Victor Rodriguez (9):
davinci: EMAC support for Omapl138-Hawkboard
davinci: EDMA support for Omapl138-Hawkboard
davinci: ASoC support for Omapl138-Hawkboard
davinci: McASP configuration for Omapl138-Hawkboard
davinci: Audio support for Omapl138-Hawkboard
davinci: MMC/SD and USB-OHCI configuration for Omapl138-Hawkboard
davinci: MMC/SD support for Omapl138-Hawkboar
davinci: USB clocks for Omapl138-Hawkboard
davinci: USB-OHCI support for Omapl138-Hawkboard
arch/arm/mach-davinci/board-omapl138-hawk.c | 300 +++++++++++++++++++++++++++
arch/arm/mach-davinci/da850.c | 23 ++-
arch/arm/mach-davinci/include/mach/mux.h | 4 +
sound/soc/davinci/Kconfig | 5 +-
sound/soc/davinci/davinci-evm.c | 6 +-
5 files changed, 333 insertions(+), 5 deletions(-)
1
0
From: Vinod Koul <vinod.koul(a)intel.com>
kernel locking in ioctl was introduced when ioctl function was
moved from ioctl to unlocked ioctl
This is no longer required hence removed
Signed-off-by: Vinod Koul <vinod.koul(a)intel.com>
Signed-off-by: Alan Cox <alan(a)linux.intel.com>
---
.../staging/intel_sst/intel_sst_app_interface.c | 7 +------
1 files changed, 1 insertions(+), 6 deletions(-)
diff --git a/drivers/staging/intel_sst/intel_sst_app_interface.c b/drivers/staging/intel_sst/intel_sst_app_interface.c
index baf0ddc..82768fa 100644
--- a/drivers/staging/intel_sst/intel_sst_app_interface.c
+++ b/drivers/staging/intel_sst/intel_sst_app_interface.c
@@ -812,8 +812,6 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg)
struct ioctl_pvt_data *data = NULL;
int str_id = 0, minor = 0;
- lock_kernel();
-
data = file_ptr->private_data;
if (data) {
minor = 0;
@@ -821,10 +819,8 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg)
} else
minor = 1;
- if (sst_drv_ctx->sst_state != SST_FW_RUNNING) {
- unlock_kernel();
+ if (sst_drv_ctx->sst_state != SST_FW_RUNNING)
return -EBUSY;
- }
switch (_IOC_NR(cmd)) {
case _IOC_NR(SNDRV_SST_STREAM_PAUSE):
@@ -1227,7 +1223,6 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg)
default:
retval = -EINVAL;
}
- unlock_kernel();
pr_debug("sst: intel_sst_ioctl:complete ret code = %d\n", retval);
return retval;
}
1
1

[alsa-devel] [PATCH 2/2] ALSA: HDA: Apply SKU override for Acer aspire 7736z
by David Henningsson 14 Oct '10
by David Henningsson 14 Oct '10
14 Oct '10
BugLink: http://launchpad.net/bugs/617647
The current SKU value disables playback, so ignore the SKU value.
Signed-off-by: David Henningsson <david.henningsson(a)canonical.com>
--
David Henningsson, Canonical Ltd.
http://launchpad.net/~diwic
1
0

14 Oct '10
Realtek have ways of specifying external amps and more via a
special nid or via the Codec's subsystem ID, this is called "SKU".
The computer manufacturer sometimes gets this wrong, so we need
to be able to override or ignore the SKU customization value.
Signed-off-by: David Henningsson <david.henningsson(a)canonical.com>
--
David Henningsson, Canonical Ltd.
http://launchpad.net/~diwic
1
0

14 Oct '10
BugLink: http://launchpad.net/bugs/617647
The current SKU value disables playback, so ignore the SKU value.
Signed-off-by: David Henningsson <david.henningsson(a)canonical.com>
---
sound/pci/hda/patch_realtek.c | 5 +++++
1 files changed, 5 insertions(+), 0 deletions(-)
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index f826bad..1c82c59 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -10627,6 +10627,7 @@ static struct alc_config_preset alc882_presets[] = {
enum {
PINFIX_ABIT_AW9D_MAX,
PINFIX_PB_M5210,
+ PINFIX_ACER_ASPIRE_7736,
};
static const struct alc_fixup alc882_fixups[] = {
@@ -10644,11 +10645,15 @@ static const struct alc_fixup alc882_fixups[] = {
{}
}
},
+ [PINFIX_ACER_ASPIRE_7736] = {
+ .sku = ALC_FIXUP_SKU_IGNORE,
+ },
};
static struct snd_pci_quirk alc882_fixup_tbl[] = {
SND_PCI_QUIRK(0x1025, 0x0155, "Packard-Bell M5120", PINFIX_PB_M5210),
SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX),
+ SND_PCI_QUIRK(0x1025, 0x0296, "Acer Aspire 7736z", PINFIX_ACER_ASPIRE_7736),
{}
};
--
1.7.1
--------------010108070807070605080900--
1
0
Realtek have ways of specifying external amps and more via a
special nid or via the Codec's subsystem ID, this is called "SKU".
The computer manufacturer sometimes gets this wrong, so we need
to be able to override or ignore the SKU customization value.
Signed-off-by: David Henningsson <david.henningsson(a)canonical.com>
---
sound/pci/hda/patch_realtek.c | 34 ++++++++++++++++++++++++++++++++--
1 files changed, 32 insertions(+), 2 deletions(-)
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index b4e0959..f826bad 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -301,6 +301,7 @@ struct alc_customize_define {
unsigned int platform_type:1;
unsigned int swap:1;
unsigned int override:1;
+ unsigned int fixup:1; /* Means that this sku is set by driver, not read from hw */
};
struct alc_spec {
@@ -1464,6 +1465,10 @@ static void alc_init_auto_mic(struct hda_codec *codec)
spec->unsol_event = alc_sku_unsol_event;
}
+/* Could be any non-zero and even value. When used as fixup, tells
+ the driver to ignore any present sku defines. */
+#define ALC_FIXUP_SKU_IGNORE (2)
+
static int alc_auto_parse_customize_define(struct hda_codec *codec)
{
unsigned int ass, tmp, i;
@@ -1472,6 +1477,13 @@ static int alc_auto_parse_customize_define(struct hda_codec *codec)
spec->cdefine.enable_pcbeep = 1; /* assume always enabled */
+ if (spec->cdefine.fixup) {
+ ass = spec->cdefine.sku_cfg;
+ if (ass == ALC_FIXUP_SKU_IGNORE)
+ return -1;
+ goto do_sku;
+ }
+
ass = codec->subsystem_id & 0xffff;
if (ass != codec->bus->pci->subsystem_device && (ass & 1))
goto do_sku;
@@ -1539,6 +1551,13 @@ static int alc_subsystem_id(struct hda_codec *codec,
unsigned nid;
struct alc_spec *spec = codec->spec;
+ if (spec->cdefine.fixup) {
+ ass = spec->cdefine.sku_cfg;
+ if (ass == ALC_FIXUP_SKU_IGNORE)
+ return 0;
+ goto do_sku;
+ }
+
ass = codec->subsystem_id & 0xffff;
if ((ass != codec->bus->pci->subsystem_device) && (ass & 1))
goto do_sku;
@@ -1658,6 +1677,7 @@ struct alc_pincfg {
};
struct alc_fixup {
+ unsigned int sku;
const struct alc_pincfg *pins;
const struct hda_verb *verbs;
};
@@ -1668,12 +1688,22 @@ static void alc_pick_fixup(struct hda_codec *codec,
int pre_init)
{
const struct alc_pincfg *cfg;
+ struct alc_spec *spec;
quirk = snd_pci_quirk_lookup(codec->bus->pci, quirk);
if (!quirk)
return;
fix += quirk->value;
cfg = fix->pins;
+ if (pre_init && fix->sku) {
+#ifdef CONFIG_SND_DEBUG_VERBOSE
+ snd_printdd(KERN_INFO "hda_codec: %s: Apply sku override for %s\n",
+ codec->chip_name, quirk->name);
+#endif
+ spec = codec->spec;
+ spec->cdefine.sku_cfg = fix->sku;
+ spec->cdefine.fixup = 1;
+ }
if (pre_init && cfg) {
#ifdef CONFIG_SND_DEBUG_VERBOSE
snd_printdd(KERN_INFO "hda_codec: %s: Apply pincfg for %s\n",
@@ -10861,8 +10891,6 @@ static int patch_alc882(struct hda_codec *codec)
codec->spec = spec;
- alc_auto_parse_customize_define(codec);
-
switch (codec->vendor_id) {
case 0x10ec0882:
case 0x10ec0885:
@@ -10890,6 +10918,8 @@ static int patch_alc882(struct hda_codec *codec)
if (board_config == ALC882_AUTO)
alc_pick_fixup(codec, alc882_fixup_tbl, alc882_fixups, 1);
+ alc_auto_parse_customize_define(codec);
+
if (board_config == ALC882_AUTO) {
/* automatic parse from the BIOS config */
err = alc882_parse_auto_config(codec);
--
1.7.1
--------------060604060706050204090703--
1
0
Am Donnerstag, 14. Oktober 2010, 13:15:45 schrieb Alex:
> > Great to hear that ASYNC OUT with rate feedback is working for u now :-)
>
> Btw, are u using 12.13 format for Linux ? U can try with OSX snow leopard,
> which can understand 10.14 and 16.16. Apply Clemens' patch and linux can
> understand all formats - but users will have to wait for kernel 2.6.37 !
I changed my code to do 12.13 format now. Will try to connect it to my MacBook
later.
> I have implemented a sophisticated rate feedback with ping pong audio
> buffer, calculation of gap between USB data and i2s data, determining
> whether gap is increasing or decreasing etc.
This actually looks like a good approach. Just studying your code.
> Channel inversion is a known issue and u need to sync the channel to the
> LRCK, and resync when the USB stream is stopped and restarted and when
> doing sample rate changes (48 to 96 etc).
So far I only support one fixed sample rate (48 kHz) in the device. Regarding
the sync I am wondering how to determine the alignment of the data coming from
USB. Is there some way to be sure that the data frames do start with the left
channel when reading them from USB?
The output to the I2S is done in bigger chunks through the DMA engine of the
AT91SAM7 - it might be possible that I loose one packet in some case at this
place... This would actually cause a inversion on the channels...
> As for i2s for the DAC etc, u need to have the right timing for the various
> clocks. As Daniel suggested, u need to scope the signals with a dual
> trace scope to see whether u are giving the DAC and other chips the right
> timing.
See my other mail with the attached measurement.
> If u are interested, u can take a look at our open source project
> sdr-widget. Google for it.
Yep, I just discovered it. Really nice project. Covers even more than I want
to do. My goal is only to have a 192kHz/24bit USB->I2S brige which can be used
for high quality audio designs. If I would have seen your project before I
might not even have started working on this. Well, now it's topic of my
bachelor thesis, so I really should get this done (c:
Regards,
Julian
2
1
Hi,
I am currently working on an USB-Audio device based on a AT91SAM7 processor.
Actually I am currently trying to get the asynchronous mode working, to be
able to use the AT91SAM7 as I2S transmitter in slave mode, utilizing and
external clock.
So I added the endpoint descriptors for the Feedback pipe. I attached the
lsusb output.
Alsa detects the card properly and reports it to be async in the /proc/asound
interface. Now for a first tested I am trying to report back a constant rate
through the feedback pipe. The stream is 48kHz with 16Bit.
Reading the USB Audio 1.0 spec I assume in theory for a 48kHz stream I would
report a rate of 48 samples per frame to the host, compensated by the measured
drift. As the data should be 10.14 encoded I currently send { 0x0c, 0x00, 0x00
} on the feedback pipe whenever it is queried, which happens whenever I try to
play some stream on this device.
But unfortunately the host won't send any data to the device. I am wondering
what might be wrong and where to check that alsa received the feedback data
properly?
I would be really thankful for any help!
Regards,
Julian
3
4
The following changes since commit fe3e2e7ff2da41bd7a985c4c206e05a95ebe7a6b:
ASoC: checking kzalloc() for IS_ERR() instead of NULL (2010-10-11 12:38:21 +0100)
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound-2.6.git for-2.6.37
Kuninori Morimoto (6):
ASoC: ak4642: simultaneous playback/recorde support
ASoC: fsi: Add fsi_get_frame_width function
ASoC: fsi: remove un-necessary variable from fsi_dai_startup
ASoC: fsi: avoid un-necessary status read
ASoC: fsi: Add new macro and shift for PortA/B In/Out
ASoC: Add fsi_is_play function
Mark Brown (5):
ASoC: Add WM8962 microphone bias control
ASoC: Restore DAI ID specification for WM8994
ASoC: Move soc-core module init next to functon definition
ASoC: Check list debugfs files for PAGE_SIZE overflow
ASoC: Pay attention to driver supplied DAI IDs
Mika Westerberg (3):
ASoC: ac97: don't call snd_soc_new_ac97_codec at probe
ASoC: don't register AC97 devices twice
ASoC: ac97: add MODULE_ALIAS for the platform driver
include/sound/soc.h | 1 +
sound/soc/codecs/ac97.c | 7 +---
sound/soc/codecs/ak4642.c | 8 ++--
sound/soc/codecs/wm8962.c | 2 +
sound/soc/codecs/wm8994.c | 3 ++
sound/soc/sh/fsi.c | 74 +++++++++++++++++++++++++-------------------
sound/soc/soc-core.c | 75 ++++++++++++++++++++++++++++++++++-----------
7 files changed, 110 insertions(+), 60 deletions(-)
2
1

14 Oct '10
This patch adds warning about changing EPLL rate to notice that other
driver that controls H/W, which is using EPLL, will has unknown effects
by this EPLL rate change.
Signed-off-by: Seungwhan Youn <sw.youn(a)samsung.com>
---
This patch is re-worked to avoid conflict with previous re-worked patch(
[PATCH v3 1/6] ARM: S5P: Reduce duplicated EPLL control codes).
This patch also depends on previous v1 and v2 petch-set which was accepted,
and depends on re-workd patch v3 1/6.
--
arch/arm/mach-s5p64x0/clock-s5p6440.c | 3 +++
arch/arm/mach-s5p64x0/clock-s5p6450.c | 3 +++
arch/arm/mach-s5pc100/clock.c | 3 +++
arch/arm/mach-s5pv210/clock.c | 3 +++
4 files changed, 12 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-s5p64x0/clock-s5p6440.c b/arch/arm/mach-s5p64x0/clock-s5p6440.c
index cfccdff..0d728d3 100644
--- a/arch/arm/mach-s5p64x0/clock-s5p6440.c
+++ b/arch/arm/mach-s5p64x0/clock-s5p6440.c
@@ -79,6 +79,9 @@ static int s5p6440_epll_set_rate(struct clk *clk, unsigned long rate)
__raw_writel(epll_con, S5P64X0_EPLL_CON);
__raw_writel(epll_con_k, S5P64X0_EPLL_CON_K);
+ printk(KERN_WARNING "EPLL Rate changes from %lu to %lu\n",
+ clk->rate, rate);
+
clk->rate = rate;
return 0;
diff --git a/arch/arm/mach-s5p64x0/clock-s5p6450.c b/arch/arm/mach-s5p64x0/clock-s5p6450.c
index f1498d3..1b9b0f9 100644
--- a/arch/arm/mach-s5p64x0/clock-s5p6450.c
+++ b/arch/arm/mach-s5p64x0/clock-s5p6450.c
@@ -80,6 +80,9 @@ static int s5p6450_epll_set_rate(struct clk *clk, unsigned long rate)
__raw_writel(epll_con, S5P64X0_EPLL_CON);
__raw_writel(epll_con_k, S5P64X0_EPLL_CON_K);
+ printk(KERN_WARNING "EPLL Rate changes from %lu to %lu\n",
+ clk->rate, rate);
+
clk->rate = rate;
return 0;
diff --git a/arch/arm/mach-s5pc100/clock.c b/arch/arm/mach-s5pc100/clock.c
index 42c2636..9e192a0 100644
--- a/arch/arm/mach-s5pc100/clock.c
+++ b/arch/arm/mach-s5pc100/clock.c
@@ -323,6 +323,9 @@ static int s5pc100_epll_set_rate(struct clk *clk, unsigned long rate)
__raw_writel(epll_con, S5P_EPLL_CON);
+ printk(KERN_WARNING "EPLL Rate changes from %lu to %lu\n",
+ clk->rate, rate);
+
clk->rate = rate;
return 0;
diff --git a/arch/arm/mach-s5pv210/clock.c b/arch/arm/mach-s5pv210/clock.c
index fdfadac..25eb839 100644
--- a/arch/arm/mach-s5pv210/clock.c
+++ b/arch/arm/mach-s5pv210/clock.c
@@ -1066,6 +1066,9 @@ static int s5pv210_epll_set_rate(struct clk *clk, unsigned long rate)
__raw_writel(epll_con, S5P_EPLL_CON);
__raw_writel(epll_con_k, S5P_EPLL_CON1);
+ printk(KERN_WARNING "EPLL Rate changes from %lu to %lu\n",
+ clk->rate, rate);
+
clk->rate = rate;
return 0;
--
1.6.2.5
2
1

[alsa-devel] [PATCH v3 1/6] ARM: S5P: Reduce duplicated EPLL control codes
by Seungwhan Youn 14 Oct '10
by Seungwhan Youn 14 Oct '10
14 Oct '10
S5P Samsung SoCs has a EPLL to support various PLL clock sources for other
H/W blocks. Until now, to control EPLL, each of SoCs make their own functions
in 'mach-s5pxxx/clock.c'. But some of functions, 'xxx_epll_get_rate()' and
'xxx_epll_enable()', are exactly same in all S5P SoCs, so this patch move
these duplicated codes to common EPLL functions that use platform wide.
Signed-off-by: Seungwhan Youn <sw.youn(a)samsung.com>
---
This patch is re-worked followings, requested by Kukjin Kim, from v2 :-
o Set re-define S5P_EPLL_CON with specific EPLL definations on S5P platform.
o and, keep original EPLL definations.
And also, this patch depends on v1 patch-set which was submitted.
o [PATCH 1/10] ARM: S5PC100: Add S/PDIF platform device
o [PATCH 2/10] ARM: S5PC100: Modify SCLK_AUDIO{0,1,2} clock as sysclks
o [PATCH 3/10] ARM: S5PC100: Add SCLK_SPDIF clock
o [PATCH 4/10] ARM: S5PV210: Add S/PDIF platform device
o [PATCH 5/10] ARM: S5PV210: Add SCLK_SPDIF clock
o [PATCH 6/10] ARM: S5PV210: Add audio clocks as sysclk
--
arch/arm/mach-s5p64x0/clock-s5p6440.c | 4 ++--
arch/arm/mach-s5p64x0/clock-s5p6450.c | 4 ++--
arch/arm/mach-s5p64x0/clock.c | 18 ------------------
arch/arm/mach-s5p64x0/include/mach/regs-clock.h | 2 ++
arch/arm/mach-s5pc100/clock.c | 22 ++--------------------
arch/arm/mach-s5pv310/include/mach/regs-clock.h | 4 ++++
arch/arm/plat-s5p/clock.c | 20 ++++++++++++++++++++
arch/arm/plat-s5p/include/plat/s5p-clock.h | 4 ++++
8 files changed, 36 insertions(+), 42 deletions(-)
diff --git a/arch/arm/mach-s5p64x0/clock-s5p6440.c b/arch/arm/mach-s5p64x0/clock-s5p6440.c
index f93dcd8..cfccdff 100644
--- a/arch/arm/mach-s5p64x0/clock-s5p6440.c
+++ b/arch/arm/mach-s5p64x0/clock-s5p6440.c
@@ -85,7 +85,7 @@ static int s5p6440_epll_set_rate(struct clk *clk, unsigned long rate)
}
static struct clk_ops s5p6440_epll_ops = {
- .get_rate = s5p64x0_epll_get_rate,
+ .get_rate = s5p_epll_get_rate,
.set_rate = s5p6440_epll_set_rate,
};
@@ -548,7 +548,7 @@ void __init_or_cpufreq s5p6440_setup_clocks(void)
/* Set S5P6440 functions for clk_fout_epll */
- clk_fout_epll.enable = s5p64x0_epll_enable;
+ clk_fout_epll.enable = s5p_epll_enable;
clk_fout_epll.ops = &s5p6440_epll_ops;
clk_48m.enable = s5p64x0_clk48m_ctrl;
diff --git a/arch/arm/mach-s5p64x0/clock-s5p6450.c b/arch/arm/mach-s5p64x0/clock-s5p6450.c
index f9afb05..f1498d3 100644
--- a/arch/arm/mach-s5p64x0/clock-s5p6450.c
+++ b/arch/arm/mach-s5p64x0/clock-s5p6450.c
@@ -86,7 +86,7 @@ static int s5p6450_epll_set_rate(struct clk *clk, unsigned long rate)
}
static struct clk_ops s5p6450_epll_ops = {
- .get_rate = s5p64x0_epll_get_rate,
+ .get_rate = s5p_epll_get_rate,
.set_rate = s5p6450_epll_set_rate,
};
@@ -581,7 +581,7 @@ void __init_or_cpufreq s5p6450_setup_clocks(void)
/* Set S5P6450 functions for clk_fout_epll */
- clk_fout_epll.enable = s5p64x0_epll_enable;
+ clk_fout_epll.enable = s5p_epll_enable;
clk_fout_epll.ops = &s5p6450_epll_ops;
clk_48m.enable = s5p64x0_clk48m_ctrl;
diff --git a/arch/arm/mach-s5p64x0/clock.c b/arch/arm/mach-s5p64x0/clock.c
index 523ba80..b52c6e2 100644
--- a/arch/arm/mach-s5p64x0/clock.c
+++ b/arch/arm/mach-s5p64x0/clock.c
@@ -73,24 +73,6 @@ static const u32 clock_table[][3] = {
{L2 * 1000, (3 << ARM_DIV_RATIO_SHIFT), (0 << S5P64X0_CLKDIV0_HCLK_SHIFT)},
};
-int s5p64x0_epll_enable(struct clk *clk, int enable)
-{
- unsigned int ctrlbit = clk->ctrlbit;
- unsigned int epll_con = __raw_readl(S5P64X0_EPLL_CON) & ~ctrlbit;
-
- if (enable)
- __raw_writel(epll_con | ctrlbit, S5P64X0_EPLL_CON);
- else
- __raw_writel(epll_con, S5P64X0_EPLL_CON);
-
- return 0;
-}
-
-unsigned long s5p64x0_epll_get_rate(struct clk *clk)
-{
- return clk->rate;
-}
-
unsigned long s5p64x0_armclk_get_rate(struct clk *clk)
{
unsigned long rate = clk_get_rate(clk->parent);
diff --git a/arch/arm/mach-s5p64x0/include/mach/regs-clock.h b/arch/arm/mach-s5p64x0/include/mach/regs-clock.h
index 58e1bc8..a133f22 100644
--- a/arch/arm/mach-s5p64x0/include/mach/regs-clock.h
+++ b/arch/arm/mach-s5p64x0/include/mach/regs-clock.h
@@ -60,4 +60,6 @@
#define ARM_DIV_RATIO_SHIFT 0
#define ARM_DIV_MASK (0xF << ARM_DIV_RATIO_SHIFT)
+#define S5P_EPLL_CON S5P64X0_EPLL_CON
+
#endif /* __ASM_ARCH_REGS_CLOCK_H */
diff --git a/arch/arm/mach-s5pc100/clock.c b/arch/arm/mach-s5pc100/clock.c
index 306ae74..42c2636 100644
--- a/arch/arm/mach-s5pc100/clock.c
+++ b/arch/arm/mach-s5pc100/clock.c
@@ -273,24 +273,6 @@ static struct clksrc_clk clk_div_hdmi = {
.reg_div = { .reg = S5P_CLK_DIV3, .shift = 28, .size = 4 },
};
-static int s5pc100_epll_enable(struct clk *clk, int enable)
-{
- unsigned int ctrlbit = clk->ctrlbit;
- unsigned int epll_con = __raw_readl(S5P_EPLL_CON) & ~ctrlbit;
-
- if (enable)
- __raw_writel(epll_con | ctrlbit, S5P_EPLL_CON);
- else
- __raw_writel(epll_con, S5P_EPLL_CON);
-
- return 0;
-}
-
-static unsigned long s5pc100_epll_get_rate(struct clk *clk)
-{
- return clk->rate;
-}
-
static u32 epll_div[][4] = {
{ 32750000, 131, 3, 4 },
{ 32768000, 131, 3, 4 },
@@ -347,7 +329,7 @@ static int s5pc100_epll_set_rate(struct clk *clk, unsigned long rate)
}
static struct clk_ops s5pc100_epll_ops = {
- .get_rate = s5pc100_epll_get_rate,
+ .get_rate = s5p_epll_get_rate,
.set_rate = s5pc100_epll_set_rate,
};
@@ -1261,7 +1243,7 @@ void __init_or_cpufreq s5pc100_setup_clocks(void)
unsigned int ptr;
/* Set S5PC100 functions for clk_fout_epll */
- clk_fout_epll.enable = s5pc100_epll_enable;
+ clk_fout_epll.enable = s5p_epll_enable;
clk_fout_epll.ops = &s5pc100_epll_ops;
printk(KERN_DEBUG "%s: registering clocks\n", __func__);
diff --git a/arch/arm/mach-s5pv310/include/mach/regs-clock.h b/arch/arm/mach-s5pv310/include/mach/regs-clock.h
index 5d0bb40..9e9e44c 100644
--- a/arch/arm/mach-s5pv310/include/mach/regs-clock.h
+++ b/arch/arm/mach-s5pv310/include/mach/regs-clock.h
@@ -157,4 +157,8 @@
#define S5P_CLKDIV_BUS_GPLR_SHIFT (4)
#define S5P_CLKDIV_BUS_GPLR_MASK (0x7 << S5P_CLKDIV_BUS_GPLR_SHIFT)
+/* Compatibility defines */
+
+#define S5P_EPLL_CON S5P_EPLL_CON0
+
#endif /* __ASM_ARCH_REGS_CLOCK_H */
diff --git a/arch/arm/plat-s5p/clock.c b/arch/arm/plat-s5p/clock.c
index 8188009..8d081d9 100644
--- a/arch/arm/plat-s5p/clock.c
+++ b/arch/arm/plat-s5p/clock.c
@@ -21,6 +21,8 @@
#include <linux/io.h>
#include <asm/div64.h>
+#include <mach/regs-clock.h>
+
#include <plat/clock.h>
#include <plat/clock-clksrc.h>
#include <plat/s5p-clock.h>
@@ -148,6 +150,24 @@ int s5p_gatectrl(void __iomem *reg, struct clk *clk, int enable)
return 0;
}
+int s5p_epll_enable(struct clk *clk, int enable)
+{
+ unsigned int ctrlbit = clk->ctrlbit;
+ unsigned int epll_con = __raw_readl(S5P_EPLL_CON) & ~ctrlbit;
+
+ if (enable)
+ __raw_writel(epll_con | ctrlbit, S5P_EPLL_CON);
+ else
+ __raw_writel(epll_con, S5P_EPLL_CON);
+
+ return 0;
+}
+
+unsigned long s5p_epll_get_rate(struct clk *clk)
+{
+ return clk->rate;
+}
+
static struct clk *s5p_clks[] __initdata = {
&clk_ext_xtal_mux,
&clk_48m,
diff --git a/arch/arm/plat-s5p/include/plat/s5p-clock.h b/arch/arm/plat-s5p/include/plat/s5p-clock.h
index 17036c8..2b6dcff 100644
--- a/arch/arm/plat-s5p/include/plat/s5p-clock.h
+++ b/arch/arm/plat-s5p/include/plat/s5p-clock.h
@@ -43,4 +43,8 @@ extern struct clksrc_sources clk_src_dpll;
extern int s5p_gatectrl(void __iomem *reg, struct clk *clk, int enable);
+/* Common EPLL operations for S5P platform */
+extern int s5p_epll_enable(struct clk *clk, int enable);
+extern unsigned long s5p_epll_get_rate(struct clk *clk);
+
#endif /* __ASM_PLAT_S5P_CLOCK_H */
--
1.6.2.5
2
1

13 Oct '10
Hi,
Here is a new try to get merged sound support for the alc562[123] codecs and
HP's t5325 thin client merged. Not a lot of changes since last try. All of
them are to address the comments I had.
Thanks,
Arnaud
2
13
Work: Now through at least June 2, 2011. Provide SW Architecture for Linux and audio subsystem, detailed task planning and estimating, Linux package management, integration and direction.
Platform: System runs on an IMX51/53 class Freescale ARM Processor running Linux. Architectures and packages must fit into an embedded uC system that has MIPS and Memory limitations.
MIPS < 1600
Memory < 1GB
Test platform is X86 running Ubuntu.
Tools: Eclipse IDE for Linux debug and development. Enterprise Architect is used for Architecture documentation. Additional CM tools are being defined at this point.
Skills: The following documents the minimum skill-level/qualifications of the engineer:
Experience with Linux development (Embedded Linux preferred),
Linux Audio Package experience (ALSA source/sink, GStreamer architecture)
Linux Kernel understanding
Ability to reconfigure and rebuild kernel and kernel modules
C++ Object Oriented design, analysis
Linux Driver architecture understanding
It is preferable that the person has contributed to Open Source development (FOSS project)
CM experience required. Synergy experience preferred.
If you are interested in this contract, please send your resume ASAP in Word format. This project will begin on October 18th.
Thank you in advance for your response.
Sincerely,
Holly Foster
Professional Search Group, Inc.
14317 Miracle Ct.
Grabill, IN 46741
(260) 627-8513 Office
(954) 600-6841 Cell
holly(a)profsearchgroup.com
1
0
BugLink: http://launchpad.net/bugs/673075
According to the datasheet of 92HD87B, there is a digital mic
at nid 0x11, so enable it in order to be able to use the mic.
Cc: stable(a)kernel.org
Signed-off-by: David Henningsson <david.henningsson(a)canonical.com>
---
hda/patch_sigmatel.c | 14 ++++++++++++--
1 files changed, 12 insertions(+), 2 deletions(-)
diff --git a/hda/patch_sigmatel.c b/hda/patch_sigmatel.c
index 0144519..6764100 100644
--- a/hda/patch_sigmatel.c
+++ b/hda/patch_sigmatel.c
@@ -388,6 +388,11 @@ static hda_nid_t stac92hd83xxx_dmic_nids[STAC92HD83XXX_NUM_DMICS + 1] = {
0x11, 0x20, 0
};
+#define STAC92HD87B_NUM_DMICS 1
+static hda_nid_t stac92hd87b_dmic_nids[STAC92HD87B_NUM_DMICS + 1] = {
+ 0x11, 0
+};
+
#define STAC92HD83XXX_NUM_CAPS 2
static unsigned long stac92hd83xxx_capvols[] = {
HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT),
@@ -5370,12 +5375,17 @@ again:
stac92hd83xxx_brd_tbl[spec->board_config]);
switch (codec->vendor_id) {
+ case 0x111d76d1:
+ case 0x111d76d9:
+ spec->dmic_nids = stac92hd87b_dmic_nids;
+ spec->num_dmics = stac92xx_connected_ports(codec,
+ stac92hd87b_dmic_nids,
+ STAC92HD87B_NUM_DMICS);
+ /* Fall through */
case 0x111d7666:
case 0x111d7667:
case 0x111d7668:
case 0x111d7669:
- case 0x111d76d1:
- case 0x111d76d9:
spec->num_pins = ARRAY_SIZE(stac92hd88xxx_pin_nids);
spec->pin_nids = stac92hd88xxx_pin_nids;
spec->mono_nid = 0;
--
1.7.1
--------------060701030507010507040605--
1
0

[alsa-devel] [PATCH v2] ASoC: tlv320dac33: Control for line output gain
by Peter Ujfalusi 13 Oct '10
by Peter Ujfalusi 13 Oct '10
13 Oct '10
New control to select the line output gain.
This gain control affects the linein-to-lineout and
dac-to-loneout gain differently.
Use enum type to select the desired gain combination.
Signed-off-by: Peter Ujfalusi <peter.ujfalusi(a)nokia.com>
---
sound/soc/codecs/tlv320dac33.c | 18 ++++++++++++++++++
1 files changed, 18 insertions(+), 0 deletions(-)
diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c
index bf6d01f..58349dc 100644
--- a/sound/soc/codecs/tlv320dac33.c
+++ b/sound/soc/codecs/tlv320dac33.c
@@ -524,6 +524,22 @@ static const struct soc_enum dac33_fifo_mode_enum =
SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(dac33_fifo_mode_texts),
dac33_fifo_mode_texts);
+/* L/R Line Output Gain */
+static const char *lr_lineout_gain_texts[] = {
+ "Line -12dB DAC 0dB", "Line -6dB DAC 6dB",
+ "Line 0dB DAC 12dB", "Line 6dB DAC 18dB",
+};
+
+static const struct soc_enum l_lineout_gain_enum =
+ SOC_ENUM_SINGLE(DAC33_LDAC_PWR_CTRL, 0,
+ ARRAY_SIZE(lr_lineout_gain_texts),
+ lr_lineout_gain_texts);
+
+static const struct soc_enum r_lineout_gain_enum =
+ SOC_ENUM_SINGLE(DAC33_RDAC_PWR_CTRL, 0,
+ ARRAY_SIZE(lr_lineout_gain_texts),
+ lr_lineout_gain_texts);
+
/*
* DACL/R digital volume control:
* from 0 dB to -63.5 in 0.5 dB steps
@@ -541,6 +557,8 @@ static const struct snd_kcontrol_new dac33_snd_controls[] = {
DAC33_LDAC_DIG_VOL_CTRL, DAC33_RDAC_DIG_VOL_CTRL, 7, 1, 1),
SOC_DOUBLE_R("Line to Line Out Volume",
DAC33_LINEL_TO_LLO_VOL, DAC33_LINER_TO_RLO_VOL, 0, 127, 1),
+ SOC_ENUM("Left Line Output Gain", l_lineout_gain_enum),
+ SOC_ENUM("Right Line Output Gain", r_lineout_gain_enum),
};
static const struct snd_kcontrol_new dac33_mode_snd_controls[] = {
--
1.7.3.1
3
2
Hi,
While I was porting ep93xx-ac97 driver to multicomponent ASoC, I encountered few
issues with the generic AC97 glue driver (which we are using with Sim.One). This
series tries to fix those.
Regards,
MW
Mika Westerberg (3):
ASoC: ac97: don't call snd_soc_new_ac97_codec at probe
ASoC: don't register AC97 devices twice
ASoC: ac97: add MODULE_ALIAS for the platform driver
include/sound/soc.h | 1 +
sound/soc/codecs/ac97.c | 7 +------
sound/soc/soc-core.c | 18 ++++++++++++++++++
3 files changed, 20 insertions(+), 6 deletions(-)
3
5
This patch fixes up the au1x audio platform after the multi-component
merge:
- compile fixes and updates to get DB1200 platform audio working again,
- removal of global variables in AC97/I2S/DMA(PCM) modules.
The AC97 part is limited to one instance only for now due to issues
with getting at driver data in the soc_ac97_ops.
Signed-off-by: Manuel Lauss <manuel.lauss(a)googlemail.com>
---
v5: smaller patch
v4: fixed a bug in the previous bugfix, and added DAI drvdata accessors.
v3: fixed a bug which caused cat /proc/iomem to loop endlessly.
v2: prepare PCM,I2S for multiple card operation, use dev_name() for DAI name.
Against Liam's asoc/for-2.6.37 branch.
Tested on DB1200 and DB1300 (here both I2S and AC97 operate as
independent cards), please fold this into the other Au1x multi-component
patches.
Issues I observed with AC97:
* AC97 is limited to a single instance since I cannot get at the driver
data in the AC97 callbacks at all time (or did I miss anything?):
when the AC97 codec calls snd_ac97_mixer(), it calls into the soc_ac97_ops
callbacks; however ac97->bus->card->private_data (suggested by Mark)
is _always_ NULL, so no way to get at the dai and ultimately driver data.
* generic AC97 codec use spits out this kobject warning, which is caused by the
"device_register()" in soc-core.c::soc_ac97_dev_register():
asoc: ac97-hifi <-> au1xpsc-ac97.1 mapping ok
kobject (8fdc59b0): tried to init an initialized object, something is
seriously wrong.
Call Trace:
[<804959c4>] dump_stack+0x8/0x34
[<802a30e4>] kobject_init+0x50/0xcc
[<802ec27c>] device_initialize+0x2c/0x70
[<802ecb64>] device_register+0x14/0x28
[<8039e058>] snd_soc_instantiate_cards+0xa00/0xb10
[<8039e27c>] soc_probe+0x114/0x154
[<802ef0fc>] driver_probe_device+0xe4/0x1a0
[<802ee404>] bus_for_each_drv+0x60/0xb0
[<802ef370>] device_attach+0x74/0xa8
[<802ee1e8>] bus_probe_device+0x30/0x54
[<802ec9a0>] device_add+0x384/0x534
[<802f09a4>] platform_device_add+0x15c/0x1c8
[<805ccb14>] db1200_audio_load+0x70/0x9c
[<801004fc>] do_one_initcall+0xfc/0x1e0
[<805ba32c>] kernel_init+0xc8/0x168
[<80105904>] kernel_thread_helper+0x10/0x18
arch/mips/alchemy/devboards/db1200/platform.c | 6 ++
sound/soc/au1x/db1200.c | 16 +++---
sound/soc/au1x/dbdma2.c | 82 ++++++++-----------------
sound/soc/au1x/psc-ac97.c | 59 +++++++++++-------
sound/soc/au1x/psc-i2s.c | 42 ++++---------
sound/soc/au1x/psc.h | 7 +--
6 files changed, 91 insertions(+), 121 deletions(-)
diff --git a/arch/mips/alchemy/devboards/db1200/platform.c b/arch/mips/alchemy/devboards/db1200/platform.c
index 3fa34c3..fbb5593 100644
--- a/arch/mips/alchemy/devboards/db1200/platform.c
+++ b/arch/mips/alchemy/devboards/db1200/platform.c
@@ -429,6 +429,11 @@ static struct platform_device db1200_audio_dev = {
.resource = au1200_psc1_res,
};
+static struct platform_device db1200_stac_dev = {
+ .name = "ac97-codec",
+ .id = 1, /* on PSC1 */
+};
+
static struct platform_device *db1200_devs[] __initdata = {
NULL, /* PSC0, selected by S6.8 */
&db1200_ide_dev,
@@ -436,6 +441,7 @@ static struct platform_device *db1200_devs[] __initdata = {
&db1200_rtc_dev,
&db1200_nand_dev,
&db1200_audio_dev,
+ &db1200_stac_dev,
};
static int __init db1200_dev_init(void)
diff --git a/sound/soc/au1x/db1200.c b/sound/soc/au1x/db1200.c
index d8dc822..b62fcd3 100644
--- a/sound/soc/au1x/db1200.c
+++ b/sound/soc/au1x/db1200.c
@@ -27,10 +27,10 @@
static struct snd_soc_dai_link db1200_ac97_dai = {
.name = "AC97",
.stream_name = "AC97 HiFi",
- .cpu_dai_name = "au1xpsc-ac97",
.codec_dai_name = "ac97-hifi",
- .platform_name = "au1xpsc-pcm-audio",
- .codec_name = "ac97-codec",
+ .cpu_dai_name = "au1xpsc_ac97.1",
+ .platform_name = "au1xpsc-pcm.1",
+ .codec_name = "ac97-codec.1",
};
static struct snd_soc_card db1200_ac97_machine = {
@@ -75,10 +75,10 @@ static struct snd_soc_ops db1200_i2s_wm8731_ops = {
static struct snd_soc_dai_link db1200_i2s_dai = {
.name = "WM8731",
.stream_name = "WM8731 PCM",
- .cpu_dai_name = "au1xpsc",
- .codec_dai_name = "wm8731-hifi"
- .platform_name = "au1xpsc-pcm-audio",
- .codec_name = "wm8731-codec.0-001a",
+ .codec_dai_name = "wm8731-hifi",
+ .cpu_dai_name = "au1xpsc_i2s.1",
+ .platform_name = "au1xpsc-pcm.1",
+ .codec_name = "wm8731-codec.0-001b",
.ops = &db1200_i2s_wm8731_ops,
};
@@ -97,7 +97,7 @@ static int __init db1200_audio_load(void)
int ret;
ret = -ENOMEM;
- db1200_asoc_dev = platform_device_alloc("soc-audio", -1);
+ db1200_asoc_dev = platform_device_alloc("soc-audio", 1); /* PSC1 */
if (!db1200_asoc_dev)
goto out;
diff --git a/sound/soc/au1x/dbdma2.c b/sound/soc/au1x/dbdma2.c
index 00fdb9c..10fdd28 100644
--- a/sound/soc/au1x/dbdma2.c
+++ b/sound/soc/au1x/dbdma2.c
@@ -10,9 +10,6 @@
*
* DMA glue for Au1x-PSC audio.
*
- * NOTE: all of these drivers can only work with a SINGLE instance
- * of a PSC. Multiple independent audio devices are impossible
- * with ASoC v1.
*/
@@ -61,9 +58,6 @@ struct au1xpsc_audio_dmadata {
int msbits;
};
-/* instance data. There can be only one, MacLeod!!!! */
-static struct au1xpsc_audio_dmadata *au1xpsc_audio_pcmdma[2];
-
/*
* These settings are somewhat okay, at least on my machine audio plays
* almost skip-free. Especially the 64kB buffer seems to help a LOT.
@@ -199,6 +193,14 @@ out:
return 0;
}
+static inline struct au1xpsc_audio_dmadata *to_dmadata(struct snd_pcm_substream *ss)
+{
+ struct snd_soc_pcm_runtime *rtd = ss->private_data;
+ struct au1xpsc_audio_dmadata *pcd =
+ snd_soc_platform_get_drvdata(rtd->platform);
+ return &pcd[SUBSTREAM_TYPE(ss)];
+}
+
static int au1xpsc_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
@@ -211,7 +213,7 @@ static int au1xpsc_pcm_hw_params(struct snd_pcm_substream *substream,
goto out;
stype = SUBSTREAM_TYPE(substream);
- pcd = au1xpsc_audio_pcmdma[stype];
+ pcd = to_dmadata(substream);
DBG("runtime->dma_area = 0x%08lx dma_addr_t = 0x%08lx dma_size = %d "
"runtime->min_align %d\n",
@@ -249,8 +251,7 @@ static int au1xpsc_pcm_hw_free(struct snd_pcm_substream *substream)
static int au1xpsc_pcm_prepare(struct snd_pcm_substream *substream)
{
- struct au1xpsc_audio_dmadata *pcd =
- au1xpsc_audio_pcmdma[SUBSTREAM_TYPE(substream)];
+ struct au1xpsc_audio_dmadata *pcd = to_dmadata(substream);
au1xxx_dbdma_reset(pcd->ddma_chan);
@@ -267,7 +268,7 @@ static int au1xpsc_pcm_prepare(struct snd_pcm_substream *substream)
static int au1xpsc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
{
- u32 c = au1xpsc_audio_pcmdma[SUBSTREAM_TYPE(substream)]->ddma_chan;
+ u32 c = to_dmadata(substream)->ddma_chan;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
@@ -287,8 +288,7 @@ static int au1xpsc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
static snd_pcm_uframes_t
au1xpsc_pcm_pointer(struct snd_pcm_substream *substream)
{
- return bytes_to_frames(substream->runtime,
- au1xpsc_audio_pcmdma[SUBSTREAM_TYPE(substream)]->pos);
+ return bytes_to_frames(substream->runtime, to_dmadata(substream)->pos);
}
static int au1xpsc_pcm_open(struct snd_pcm_substream *substream)
@@ -299,7 +299,7 @@ static int au1xpsc_pcm_open(struct snd_pcm_substream *substream)
static int au1xpsc_pcm_close(struct snd_pcm_substream *substream)
{
- au1x_pcm_dbdma_free(au1xpsc_audio_pcmdma[SUBSTREAM_TYPE(substream)]);
+ au1x_pcm_dbdma_free(to_dmadata(substream));
return 0;
}
@@ -329,35 +329,21 @@ static int au1xpsc_pcm_new(struct snd_card *card,
return 0;
}
-static int au1xpsc_pcm_probe(struct snd_soc_platform *platform)
-{
- if (!au1xpsc_audio_pcmdma[PCM_TX] || !au1xpsc_audio_pcmdma[PCM_RX])
- return -ENODEV;
-
- return 0;
-}
-
/* au1xpsc audio platform */
struct snd_soc_platform_driver au1xpsc_soc_platform = {
- .probe = au1xpsc_pcm_probe,
.ops = &au1xpsc_pcm_ops,
.pcm_new = au1xpsc_pcm_new,
.pcm_free = au1xpsc_pcm_free_dma_buffers,
};
-EXPORT_SYMBOL_GPL(au1xpsc_soc_platform);
static int __devinit au1xpsc_pcm_drvprobe(struct platform_device *pdev)
{
+ struct au1xpsc_audio_dmadata *dmadata;
struct resource *r;
int ret;
- if (au1xpsc_audio_pcmdma[PCM_TX] || au1xpsc_audio_pcmdma[PCM_RX])
- return -EBUSY;
-
- /* TX DMA */
- au1xpsc_audio_pcmdma[PCM_TX]
- = kzalloc(sizeof(struct au1xpsc_audio_dmadata), GFP_KERNEL);
- if (!au1xpsc_audio_pcmdma[PCM_TX])
+ dmadata = kzalloc(2 * sizeof(struct au1xpsc_audio_dmadata), GFP_KERNEL);
+ if (!dmadata)
return -ENOMEM;
r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
@@ -365,54 +351,40 @@ static int __devinit au1xpsc_pcm_drvprobe(struct platform_device *pdev)
ret = -ENODEV;
goto out1;
}
- (au1xpsc_audio_pcmdma[PCM_TX])->ddma_id = r->start;
+ dmadata[PCM_TX].ddma_id = r->start;
/* RX DMA */
- au1xpsc_audio_pcmdma[PCM_RX]
- = kzalloc(sizeof(struct au1xpsc_audio_dmadata), GFP_KERNEL);
- if (!au1xpsc_audio_pcmdma[PCM_RX])
- return -ENOMEM;
-
r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
if (!r) {
ret = -ENODEV;
- goto out2;
+ goto out1;
}
- (au1xpsc_audio_pcmdma[PCM_RX])->ddma_id = r->start;
+ dmadata[PCM_RX].ddma_id = r->start;
+
+ platform_set_drvdata(pdev, dmadata);
ret = snd_soc_register_platform(&pdev->dev, &au1xpsc_soc_platform);
if (!ret)
return ret;
-out2:
- kfree(au1xpsc_audio_pcmdma[PCM_RX]);
- au1xpsc_audio_pcmdma[PCM_RX] = NULL;
out1:
- kfree(au1xpsc_audio_pcmdma[PCM_TX]);
- au1xpsc_audio_pcmdma[PCM_TX] = NULL;
+ kfree(dmadata);
return ret;
}
static int __devexit au1xpsc_pcm_drvremove(struct platform_device *pdev)
{
- int i;
+ struct au1xpsc_audio_dmadata *dmadata = platform_get_drvdata(pdev);
snd_soc_unregister_platform(&pdev->dev);
-
- for (i = 0; i < 2; i++) {
- if (au1xpsc_audio_pcmdma[i]) {
- au1x_pcm_dbdma_free(au1xpsc_audio_pcmdma[i]);
- kfree(au1xpsc_audio_pcmdma[i]);
- au1xpsc_audio_pcmdma[i] = NULL;
- }
- }
+ kfree(dmadata);
return 0;
}
static struct platform_driver au1xpsc_pcm_driver = {
.driver = {
- .name = "au1xpsc-pcm-audio",
+ .name = "au1xpsc-pcm",
.owner = THIS_MODULE,
},
.probe = au1xpsc_pcm_drvprobe,
@@ -421,8 +393,6 @@ static struct platform_driver au1xpsc_pcm_driver = {
static int __init au1xpsc_audio_dbdma_load(void)
{
- au1xpsc_audio_pcmdma[PCM_TX] = NULL;
- au1xpsc_audio_pcmdma[PCM_RX] = NULL;
return platform_driver_register(&au1xpsc_pcm_driver);
}
@@ -460,7 +430,7 @@ struct platform_device *au1xpsc_pcm_add(struct platform_device *pdev)
res[1].start = res[1].end = id[1];
res[0].flags = res[1].flags = IORESOURCE_DMA;
- pd = platform_device_alloc("au1xpsc-pcm", -1);
+ pd = platform_device_alloc("au1xpsc-pcm", pdev->id);
if (!pd)
goto out;
diff --git a/sound/soc/au1x/psc-ac97.c b/sound/soc/au1x/psc-ac97.c
index 6a9516c..d0db66f 100644
--- a/sound/soc/au1x/psc-ac97.c
+++ b/sound/soc/au1x/psc-ac97.c
@@ -10,9 +10,6 @@
*
* Au1xxx-PSC AC97 glue.
*
- * NOTE: all of these drivers can only work with a SINGLE instance
- * of a PSC. Multiple independent audio devices are impossible
- * with ASoC v1.
*/
#include <linux/init.h>
@@ -56,12 +53,29 @@
/* instance data. There can be only one, MacLeod!!!! */
static struct au1xpsc_audio_data *au1xpsc_ac97_workdata;
+#if 0
+
+/* this could theoretically work, but ac97->bus->card->private_data can be NULL
+ * when snd_ac97_mixer() is called; I don't know if the rest further down the
+ * chain are always valid either.
+ */
+static inline struct au1xpsc_audio_data *ac97_to_pscdata(struct snd_ac97 *x)
+{
+ struct snd_soc_card *c = x->bus->card->private_data;
+ return snd_soc_dai_get_drvdata(c->rtd->cpu_dai);
+}
+
+#else
+
+#define ac97_to_pscdata(x) au1xpsc_ac97_workdata
+
+#endif
+
/* AC97 controller reads codec register */
static unsigned short au1xpsc_ac97_read(struct snd_ac97 *ac97,
unsigned short reg)
{
- /* FIXME */
- struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata;
+ struct au1xpsc_audio_data *pscdata = ac97_to_pscdata(ac97);
unsigned short retry, tmo;
unsigned long data;
@@ -102,8 +116,7 @@ static unsigned short au1xpsc_ac97_read(struct snd_ac97 *ac97,
static void au1xpsc_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
unsigned short val)
{
- /* FIXME */
- struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata;
+ struct au1xpsc_audio_data *pscdata = ac97_to_pscdata(ac97);
unsigned int tmo, retry;
au_writel(PSC_AC97EVNT_CD, AC97_EVNT(pscdata));
@@ -134,8 +147,7 @@ static void au1xpsc_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
/* AC97 controller asserts a warm reset */
static void au1xpsc_ac97_warm_reset(struct snd_ac97 *ac97)
{
- /* FIXME */
- struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata;
+ struct au1xpsc_audio_data *pscdata = ac97_to_pscdata(ac97);
au_writel(PSC_AC97RST_SNC, AC97_RST(pscdata));
au_sync();
@@ -146,8 +158,7 @@ static void au1xpsc_ac97_warm_reset(struct snd_ac97 *ac97)
static void au1xpsc_ac97_cold_reset(struct snd_ac97 *ac97)
{
- /* FIXME */
- struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata;
+ struct au1xpsc_audio_data *pscdata = ac97_to_pscdata(ac97);
int i;
/* disable PSC during cold reset */
@@ -202,8 +213,7 @@ static int au1xpsc_ac97_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- /* FIXME */
- struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata;
+ struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(dai);
unsigned long r, ro, stat;
int chans, t, stype = SUBSTREAM_TYPE(substream);
@@ -283,8 +293,7 @@ out:
static int au1xpsc_ac97_trigger(struct snd_pcm_substream *substream,
int cmd, struct snd_soc_dai *dai)
{
- /* FIXME */
- struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata;
+ struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(dai);
int ret, stype = SUBSTREAM_TYPE(substream);
ret = 0;
@@ -325,7 +334,7 @@ static struct snd_soc_dai_ops au1xpsc_ac97_dai_ops = {
.hw_params = au1xpsc_ac97_hw_params,
};
-struct snd_soc_dai_driver au1xpsc_ac97_dai = {
+static const struct snd_soc_dai_driver au1xpsc_ac97_dai_template = {
.ac97_control = 1,
.probe = au1xpsc_ac97_probe,
.playback = {
@@ -342,7 +351,6 @@ struct snd_soc_dai_driver au1xpsc_ac97_dai = {
},
.ops = &au1xpsc_ac97_dai_ops,
};
-EXPORT_SYMBOL_GPL(au1xpsc_ac97_dai);
static int __devinit au1xpsc_ac97_drvprobe(struct platform_device *pdev)
{
@@ -351,9 +359,6 @@ static int __devinit au1xpsc_ac97_drvprobe(struct platform_device *pdev)
unsigned long sel;
struct au1xpsc_audio_data *wd;
- if (au1xpsc_ac97_workdata)
- return -EBUSY;
-
wd = kzalloc(sizeof(struct au1xpsc_audio_data), GFP_KERNEL);
if (!wd)
return -ENOMEM;
@@ -387,14 +392,20 @@ static int __devinit au1xpsc_ac97_drvprobe(struct platform_device *pdev)
au_writel(PSC_SEL_PS_AC97MODE | sel, PSC_SEL(wd));
au_sync();
- ret = snd_soc_register_dai(&pdev->dev, &au1xpsc_ac97_dai);
+ /* name the DAI like this device instance ("au1xpsc-ac97.PSCINDEX") */
+ memcpy(&wd->dai_drv, &au1xpsc_ac97_dai_template,
+ sizeof(struct snd_soc_dai_driver));
+ wd->dai_drv.name = dev_name(&pdev->dev);
+
+ platform_set_drvdata(pdev, wd);
+
+ ret = snd_soc_register_dai(&pdev->dev, &wd->dai_drv);
if (ret)
goto out1;
wd->dmapd = au1xpsc_pcm_add(pdev);
if (wd->dmapd) {
- platform_set_drvdata(pdev, wd);
- au1xpsc_ac97_workdata = wd; /* MDEV */
+ au1xpsc_ac97_workdata = wd;
return 0;
}
@@ -477,7 +488,7 @@ static struct dev_pm_ops au1xpscac97_pmops = {
static struct platform_driver au1xpsc_ac97_driver = {
.driver = {
- .name = "au1xpsc-ac97",
+ .name = "au1xpsc_ac97",
.owner = THIS_MODULE,
.pm = AU1XPSCAC97_PMOPS,
},
diff --git a/sound/soc/au1x/psc-i2s.c b/sound/soc/au1x/psc-i2s.c
index 94e560a..fca0912 100644
--- a/sound/soc/au1x/psc-i2s.c
+++ b/sound/soc/au1x/psc-i2s.c
@@ -10,9 +10,6 @@
*
* Au1xxx-PSC I2S glue.
*
- * NOTE: all of these drivers can only work with a SINGLE instance
- * of a PSC. Multiple independent audio devices are impossible
- * with ASoC v1.
* NOTE: so far only PSC slave mode (bit- and frameclock) is supported.
*/
@@ -54,13 +51,10 @@
((stype) == PCM_TX ? PSC_I2SPCR_TC : PSC_I2SPCR_RC)
-/* instance data. There can be only one, MacLeod!!!! */
-static struct au1xpsc_audio_data *au1xpsc_i2s_workdata;
-
static int au1xpsc_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
unsigned int fmt)
{
- struct au1xpsc_audio_data *pscdata = au1xpsc_i2s_workdata;
+ struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(cpu_dai);
unsigned long ct;
int ret;
@@ -120,7 +114,7 @@ static int au1xpsc_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct au1xpsc_audio_data *pscdata = au1xpsc_i2s_workdata;
+ struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(dai);
int cfgbits;
unsigned long stat;
@@ -245,7 +239,7 @@ static int au1xpsc_i2s_stop(struct au1xpsc_audio_data *pscdata, int stype)
static int au1xpsc_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
- struct au1xpsc_audio_data *pscdata = au1xpsc_i2s_workdata;
+ struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(dai);
int ret, stype = SUBSTREAM_TYPE(substream);
switch (cmd) {
@@ -263,19 +257,13 @@ static int au1xpsc_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
return ret;
}
-static int au1xpsc_i2s_probe(struct snd_soc_dai *dai)
-{
- return au1xpsc_i2s_workdata ? 0 : -ENODEV;
-}
-
static struct snd_soc_dai_ops au1xpsc_i2s_dai_ops = {
.trigger = au1xpsc_i2s_trigger,
.hw_params = au1xpsc_i2s_hw_params,
.set_fmt = au1xpsc_i2s_set_fmt,
};
-static struct snd_soc_dai_driver au1xpsc_i2s_dai = {
- .probe = au1xpsc_i2s_probe,
+static const struct snd_soc_dai_driver au1xpsc_i2s_dai_template = {
.playback = {
.rates = AU1XPSC_I2S_RATES,
.formats = AU1XPSC_I2S_FMTS,
@@ -298,9 +286,6 @@ static int __devinit au1xpsc_i2s_drvprobe(struct platform_device *pdev)
int ret;
struct au1xpsc_audio_data *wd;
- if (au1xpsc_i2s_workdata)
- return -EBUSY;
-
wd = kzalloc(sizeof(struct au1xpsc_audio_data), GFP_KERNEL);
if (!wd)
return -ENOMEM;
@@ -337,17 +322,21 @@ static int __devinit au1xpsc_i2s_drvprobe(struct platform_device *pdev)
* time out.
*/
- ret = snd_soc_register_dai(&pdev->dev, &au1xpsc_i2s_dai);
+ /* name the DAI like this device instance ("au1xpsc-i2s.PSCINDEX") */
+ memcpy(&wd->dai_drv, &au1xpsc_i2s_dai_template,
+ sizeof(struct snd_soc_dai_driver));
+ wd->dai_drv.name = dev_name(&pdev->dev);
+
+ platform_set_drvdata(pdev, wd);
+
+ ret = snd_soc_register_dai(&pdev->dev, &wd->dai_drv);
if (ret)
goto out1;
/* finally add the DMA device for this PSC */
wd->dmapd = au1xpsc_pcm_add(pdev);
- if (wd->dmapd) {
- platform_set_drvdata(pdev, wd);
- au1xpsc_i2s_workdata = wd;
+ if (wd->dmapd)
return 0;
- }
snd_soc_unregister_dai(&pdev->dev);
out1:
@@ -376,8 +365,6 @@ static int __devexit au1xpsc_i2s_drvremove(struct platform_device *pdev)
release_mem_region(r->start, resource_size(r));
kfree(wd);
- au1xpsc_i2s_workdata = NULL; /* MDEV */
-
return 0;
}
@@ -427,7 +414,7 @@ static struct dev_pm_ops au1xpsci2s_pmops = {
static struct platform_driver au1xpsc_i2s_driver = {
.driver = {
- .name = "au1xpsc",
+ .name = "au1xpsc_i2s",
.owner = THIS_MODULE,
.pm = AU1XPSCI2S_PMOPS,
},
@@ -437,7 +424,6 @@ static struct platform_driver au1xpsc_i2s_driver = {
static int __init au1xpsc_i2s_load(void)
{
- au1xpsc_i2s_workdata = NULL;
return platform_driver_register(&au1xpsc_i2s_driver);
}
diff --git a/sound/soc/au1x/psc.h b/sound/soc/au1x/psc.h
index f281443..b30eadd 100644
--- a/sound/soc/au1x/psc.h
+++ b/sound/soc/au1x/psc.h
@@ -8,16 +8,11 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
- * NOTE: all of these drivers can only work with a SINGLE instance
- * of a PSC. Multiple independent audio devices are impossible
- * with ASoC v1.
*/
#ifndef _AU1X_PCM_H
#define _AU1X_PCM_H
-extern struct snd_ac97_bus_ops soc_ac97_ops;
-
/* DBDMA helpers */
extern struct platform_device *au1xpsc_pcm_add(struct platform_device *pdev);
extern void au1xpsc_pcm_destroy(struct platform_device *dmapd);
@@ -28,6 +23,8 @@ struct au1xpsc_audio_data {
unsigned long cfg;
unsigned long rate;
+ struct snd_soc_dai_driver dai_drv;
+
unsigned long pm[2];
struct mutex lock;
struct platform_device *dmapd;
--
1.7.2
3
10

13 Oct '10
The driver can specify a DAI ID number so use that.
Signed-off-by: Mark Brown <broonie(a)opensource.wolfsonmicro.com>
---
sound/soc/soc-core.c | 5 ++++-
1 files changed, 4 insertions(+), 1 deletions(-)
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 4f6ea8c..c20cf7f 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -3015,7 +3015,10 @@ int snd_soc_register_dais(struct device *dev,
}
dai->dev = dev;
- dai->id = i;
+ if (dai->driver->id)
+ dai->id = dai->driver->id;
+ else
+ dai->id = i;
dai->driver = &dai_drv[i];
if (!dai->driver->ops)
dai->driver->ops = &null_dai_ops;
--
1.7.1
3
5
We unconditionally require SYSCLK since while only microphone detection
specifically requires SYSCLK any actual use case would enable it via
some other means but microphone detection may have nothing active other
than the bias itself.
Signed-off-by: Mark Brown <broonie(a)opensource.wolfsonmicro.com>
---
sound/soc/codecs/wm8962.c | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c
index e5009d0..894d0cd 100644
--- a/sound/soc/codecs/wm8962.c
+++ b/sound/soc/codecs/wm8962.c
@@ -2566,6 +2566,8 @@ static const struct snd_soc_dapm_route wm8962_intercon[] = {
{ "MIXINR", "IN3R Switch", "IN3R" },
{ "MIXINR", "PGA Switch", "INPGAR" },
+ { "MICBIAS", NULL, "SYSCLK" },
+
{ "ADCL", NULL, "SYSCLK" },
{ "ADCL", NULL, "TOCLK" },
{ "ADCL", NULL, "MIXINL" },
--
1.7.1
2
1

13 Oct '10
New control to select the line output gain.
This gain control affects the linein-to-lineout and
dac-to-loneout gain differently.
Use enum type to select the desired gain combination.
Signed-off-by: Peter Ujfalusi <peter.ujfalusi(a)nokia.com>
---
sound/soc/codecs/tlv320dac33.c | 18 ++++++++++++++++++
1 files changed, 18 insertions(+), 0 deletions(-)
diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c
index bf6d01f..4d86bf6 100644
--- a/sound/soc/codecs/tlv320dac33.c
+++ b/sound/soc/codecs/tlv320dac33.c
@@ -524,6 +524,22 @@ static const struct soc_enum dac33_fifo_mode_enum =
SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(dac33_fifo_mode_texts),
dac33_fifo_mode_texts);
+/* L/R Line Output Gain */
+static const char *lr_lineout_gain_texts[] = {
+ "Line 0.25V/V DAC 1V/V", "Line 0.5V/V DAC 2V/V",
+ "Line 1V/V DAC 4V/V", "Line 2V/V DAC 8V/V",
+};
+
+static const struct soc_enum l_lineout_gain_enum =
+ SOC_ENUM_SINGLE(DAC33_LDAC_PWR_CTRL, 0,
+ ARRAY_SIZE(lr_lineout_gain_texts),
+ lr_lineout_gain_texts);
+
+static const struct soc_enum r_lineout_gain_enum =
+ SOC_ENUM_SINGLE(DAC33_RDAC_PWR_CTRL, 0,
+ ARRAY_SIZE(lr_lineout_gain_texts),
+ lr_lineout_gain_texts);
+
/*
* DACL/R digital volume control:
* from 0 dB to -63.5 in 0.5 dB steps
@@ -541,6 +557,8 @@ static const struct snd_kcontrol_new dac33_snd_controls[] = {
DAC33_LDAC_DIG_VOL_CTRL, DAC33_RDAC_DIG_VOL_CTRL, 7, 1, 1),
SOC_DOUBLE_R("Line to Line Out Volume",
DAC33_LINEL_TO_LLO_VOL, DAC33_LINER_TO_RLO_VOL, 0, 127, 1),
+ SOC_ENUM("Left Line Output Gain", l_lineout_gain_enum),
+ SOC_ENUM("Right Line Output Gain", r_lineout_gain_enum),
};
static const struct snd_kcontrol_new dac33_mode_snd_controls[] = {
--
1.7.3.1
2
3

[alsa-devel] [PATCH v2 2/6] ARM: S5PV210: Fix wrong EPLL rate getting on setup clocks
by Seungwhan Youn 13 Oct '10
by Seungwhan Youn 13 Oct '10
13 Oct '10
This patch fix wrong EPLL getting on setup clocks on S5PV210.
Signed-off-by: Seungwhan Youn <sw.youn(a)samsung.com>
---
arch/arm/mach-s5pv210/clock.c | 3 ++-
arch/arm/mach-s5pv210/include/mach/regs-clock.h | 1 +
2 files changed, 3 insertions(+), 1 deletions(-)
diff --git a/arch/arm/mach-s5pv210/clock.c b/arch/arm/mach-s5pv210/clock.c
index 3f3b7ba..f1ec5bb 100644
--- a/arch/arm/mach-s5pv210/clock.c
+++ b/arch/arm/mach-s5pv210/clock.c
@@ -1040,7 +1040,8 @@ void __init_or_cpufreq s5pv210_setup_clocks(void)
apll = s5p_get_pll45xx(xtal, __raw_readl(S5P_APLL_CON), pll_4508);
mpll = s5p_get_pll45xx(xtal, __raw_readl(S5P_MPLL_CON), pll_4502);
- epll = s5p_get_pll45xx(xtal, __raw_readl(S5P_EPLL_CON), pll_4500);
+ epll = s5p_get_pll46xx(xtal, __raw_readl(S5P_EPLL_CON),
+ __raw_readl(S5P_EPLL_CON1), pll_4600);
vpllsrc = clk_get_rate(&clk_vpllsrc.clk);
vpll = s5p_get_pll45xx(vpllsrc, __raw_readl(S5P_VPLL_CON), pll_4502);
diff --git a/arch/arm/mach-s5pv210/include/mach/regs-clock.h b/arch/arm/mach-s5pv210/include/mach/regs-clock.h
index 929fd3a..eaca7bc 100644
--- a/arch/arm/mach-s5pv210/include/mach/regs-clock.h
+++ b/arch/arm/mach-s5pv210/include/mach/regs-clock.h
@@ -25,6 +25,7 @@
#define S5P_APLL_CON S5P_CLKREG(0x100)
#define S5P_MPLL_CON S5P_CLKREG(0x108)
#define S5P_EPLL_CON S5P_CLKREG(0x110)
+#define S5P_EPLL_CON1 S5P_CLKREG(0x114)
#define S5P_VPLL_CON S5P_CLKREG(0x120)
#define S5P_CLK_SRC0 S5P_CLKREG(0x200)
--
1.6.2.5
2
1

[alsa-devel] [PATCH] ASoC: OMAP4: MCPDM: Remove unnecessary include of plat/control.h
by Anand Gadiyar 12 Oct '10
by Anand Gadiyar 12 Oct '10
12 Oct '10
Commit 346a5c890 (OMAP: control: move plat-omap/control.h
to mach-omap2/control.h) in the linux-omap tree removed
plat/control.h and most of its callers. This one slipped
through - breaking the build as below when
CONFIG_SND_OMAP_SOC_MCPDM is defined. Fix this.
CC sound/soc/omap/omap-mcpdm.o
sound/soc/omap/omap-mcpdm.c:35: fatal error: plat/control.h: No such file or directory
compilation terminated.
make[3]: *** [sound/soc/omap/omap-mcpdm.o] Error 1
make[2]: *** [sound/soc/omap] Error 2
make[1]: *** [sound/soc] Error 2
make: *** [sound] Error 2
Signed-off-by: Anand Gadiyar <gadiyar(a)ti.com>
Cc: Misael Lopez Cruz <misael.lopez(a)ti.com>
Cc: Liam Girdwood <lrg(a)slimlogic.co.uk>
Cc: Mark Brown <broonie(a)opensource.wolfsonmicro.com>
Cc: Paul Walmsley <paul(a)pwsan.com>
Cc: Tony Lindgren <tony(a)atomide.com>
---
This break is reproducible on linux-next as of 20101011;
I think it also exists in mainline, but I did not check.
Probably worth taking this through the ALSA tree with Tony
or Paul's ack.
I'm not subscribed to the alsa list. Please CC me on replies.
sound/soc/omap/omap-mcpdm.c | 1 -
1 file changed, 1 deletion(-)
Index: mainline/sound/soc/omap/omap-mcpdm.c
===================================================================
--- mainline.orig/sound/soc/omap/omap-mcpdm.c
+++ mainline/sound/soc/omap/omap-mcpdm.c
@@ -32,7 +32,6 @@
#include <sound/initval.h>
#include <sound/soc.h>
-#include <plat/control.h>
#include <plat/dma.h>
#include <plat/mcbsp.h>
#include "mcpdm.h"
4
3
>> Hi,
>> I wanted to set my input
>> sources and control volume through the mixer api from a 'C' code. I am
>> required to do this without using alsa utils. Please guide me as to how I
>> can set my input source to say 'Mic' and also adjust say Front Right
>> channel volume.
>> It would also be nice if there was a mini
>> tutorial on the alsa page which explains how to do this basic stuff.
>> Thanks
>> and Regards,
>> Chandrashekhar
Are your program a mixer application or recording application ?
If the sound card does not support multi-streaming ,
the mic is one of the choice in the "Capture Source" controls
If your application can find "Input Source" in your sound card , this
mean that your sound card support multi-streaming capture
i.e. there will be more than one "Input Source" controls
1
0

12 Oct '10
In user space snprintf() returns negative on errors but the kernel
version only returns positives. It could potentially return sizes
larger than the size of the buffer so we should check for that.
Signed-off-by: Dan Carpenter <error27(a)gmail.com>
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 8751efd..8da307b 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -284,8 +284,10 @@ static ssize_t codec_list_read_file(struct file *file, char __user *user_buf,
ret += snprintf(buf + ret, PAGE_SIZE - ret, "%s\n",
codec->name);
- if (ret >= 0)
- ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+ if (ret > PAGE_SIZE)
+ ret = PAGE_SIZE;
+
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
kfree(buf);
@@ -310,8 +312,10 @@ static ssize_t dai_list_read_file(struct file *file, char __user *user_buf,
list_for_each_entry(dai, &dai_list, list)
ret += snprintf(buf + ret, PAGE_SIZE - ret, "%s\n", dai->name);
- if (ret >= 0)
- ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+ if (ret > PAGE_SIZE)
+ ret = PAGE_SIZE;
+
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
kfree(buf);
@@ -338,8 +342,10 @@ static ssize_t platform_list_read_file(struct file *file,
ret += snprintf(buf + ret, PAGE_SIZE - ret, "%s\n",
platform->name);
- if (ret >= 0)
- ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+ if (ret > PAGE_SIZE)
+ ret = PAGE_SIZE;
+
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
kfree(buf);
4
11
Dear Mark, Liam
These patches are clean up for fsi driver
Kuninori Morimoto (5):
ASoC: fsi: Add fsi_get_frame_width function
ASoC: fsi: remove un-necessary variable from fsi_dai_startup
ASoC: fsi: avoid un-necessary status read
ASoC: fsi: Add fsi_is_play function
ASoC: fsi: Add new macro and shift for PortA/B In/Out
Best regards
--
Kuninori Morimoto
3
9
On Fri, 08 Oct 2010, Valentine Sinitsyn <valentine.sinitsyn(a)gmail.com> writes:
> Looks like your Capture switch is disabled. Run alsamixer, find Capture (press
> F4) and then press Space to start capturing sound. Obviously, you will need to
> run arecord after that (I recommend using -vv to see the bar moving as you speak
> anything into mic).
Ok, this is not the first time I feel like a dumb. Thanks for the prompt
reply, it fixed the mic problem.
Can you say anything about the headphone problem? Plugging -in/-out
headphones doesn't have any effect.
Regards.
3
6

Re: [alsa-devel] [patch 1/2] OSS: soundcard: locking bug in sound_ioctl()
by Arnd Bergmann 12 Oct '10
by Arnd Bergmann 12 Oct '10
12 Oct '10
On Tuesday 12 October 2010 00:23:08 Josh Triplett wrote:
> Assuming that the underlying function only returns zero/non-zero and
> that the actual return value doesn't matter, then you can use the
> __cond_lock macro from compiler.h for this:
>
> # define __cond_lock(x,c) ((c) ? ({ __acquire(x); 1; }) : 0)
>
The return from mutex_lock_{killable,interruptible} is an error
value, not true/false, so it actually matters. We know that the only
possible error that is currently returned is -EINTR though, so we
could do a similar trick and define another
#define __cond_mutex(x, c) ((!c) ? ({ __acquire(x); 0; }) : -EINTR)
My fear was that this would impact code generation.
Arnd
2
1

[alsa-devel] [PATCH v2 05/10] davinci: Audio support for Omapl138-Hawkboard
by vm.rod25@gmail.com 12 Oct '10
by vm.rod25@gmail.com 12 Oct '10
12 Oct '10
From: Victor Rodriguez <victor.rodriguez(a)sasken.com>
This patch adds sound support for the Hawkboard-L138 system
Signed-off-by: Victor Rodriguez <victor.rodriguez(a)sasken.com>
---
Notes:
This patch works with da8xx_omapl_defconfig
In order to test ALSA utils select in menuconfig like insmodule:
Sound card support --->
Advanced Linux Sound Architecture --->
ALSA for SoC audio support --->
SoC Audio for the TI DAVINCI chip
SoC Audio support for DA850/OMAP-L138 EVM/Hawkboard
arch/arm/mach-davinci/board-omapl138-hawk.c | 45 +++++++++++++++++++++++++++
1 files changed, 45 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-davinci/board-omapl138-hawk.c b/arch/arm/mach-davinci/board-omapl138-hawk.c
index 358944b..c0a999a 100644
--- a/arch/arm/mach-davinci/board-omapl138-hawk.c
+++ b/arch/arm/mach-davinci/board-omapl138-hawk.c
@@ -13,6 +13,7 @@
#include <linux/init.h>
#include <linux/console.h>
#include <linux/gpio.h>
+#include <linux/i2c.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -116,6 +117,37 @@ static struct edma_rsv_info *da850_edma_rsv[2] = {
&da850_edma_cc1_rsv,
};
+static struct i2c_board_info __initdata omapl138_hawk_i2c_devices[] = {
+ {
+ I2C_BOARD_INFO("tlv320aic3x", 0x18),
+ },
+};
+
+static struct davinci_i2c_platform_data omapl138_hawk_i2c_0_pdata = {
+ .bus_freq = 100, /* kHz */
+ .bus_delay = 0, /* usec */
+};
+
+/* davinci Hawkboard audio machine driver */
+static u8 da850_iis_serializer_direction[] = {
+ INACTIVE_MODE, INACTIVE_MODE, INACTIVE_MODE, INACTIVE_MODE,
+ INACTIVE_MODE, INACTIVE_MODE, INACTIVE_MODE, INACTIVE_MODE,
+ INACTIVE_MODE, INACTIVE_MODE, INACTIVE_MODE, INACTIVE_MODE,
+ INACTIVE_MODE, TX_MODE, RX_MODE, INACTIVE_MODE,
+};
+
+static struct snd_platform_data omapl138_hawk_snd_data = {
+ .tx_dma_offset = 0x2000,
+ .rx_dma_offset = 0x2000,
+ .op_mode = DAVINCI_MCASP_IIS_MODE,
+ .num_serializer = ARRAY_SIZE(da850_iis_serializer_direction),
+ .tdm_slots = 2,
+ .serial_dir = da850_iis_serializer_direction,
+ .asp_chan_q = EVENTQ_1,
+ .version = MCASP_VERSION_2,
+ .txnumevt = 1,
+ .rxnumevt = 1,
+};
static struct davinci_uart_config omapl138_hawk_uart_config __initdata = {
.enabled_uarts = 0x7,
@@ -134,6 +166,19 @@ static __init void omapl138_hawk_init(void)
ret = omapl138_hawk_config_emac();
+ i2c_register_board_info(1, omapl138_hawk_i2c_devices,
+ ARRAY_SIZE(omapl138_hawk_i2c_devices));
+
+ ret = da8xx_register_i2c(0, &omapl138_hawk_i2c_0_pdata);
+ if (ret)
+ pr_warning("%s: i2c0 registration failed: %d\n",
+ __func__, ret);
+
+ ret = davinci_cfg_reg_list(da850_mcasp_pins);
+ if (ret)
+ pr_warning("%s: mcasp mux setup failed: %d\n", __func__, ret);
+ da8xx_register_mcasp(0, &omapl138_hawk_snd_data);
+
ret = da8xx_register_watchdog();
if (ret)
pr_warning("omapl138_hawk_init: "
--
1.6.0.5
1
0

[alsa-devel] [PATCH v2 04/10] davinci: McASP configuration for Omapl138-Hawkboard
by vm.rod25@gmail.com 12 Oct '10
by vm.rod25@gmail.com 12 Oct '10
12 Oct '10
From: Victor Rodriguez <victor.rodriguez(a)sasken.com>
This patch defines Pin Mux configuration for MacASP
used on the Hawkboard-L138 system in order to add Audio support
Signed-off-by: Victor Rodriguez <victor.rodriguez(a)sasken.com>
---
arch/arm/mach-davinci/da850.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c
index 63916b9..f033a0a 100644
--- a/arch/arm/mach-davinci/da850.c
+++ b/arch/arm/mach-davinci/da850.c
@@ -591,7 +591,7 @@ const short da850_cpgmac_pins[] __initdata = {
const short da850_mcasp_pins[] __initdata = {
DA850_AHCLKX, DA850_ACLKX, DA850_AFSX,
DA850_AHCLKR, DA850_ACLKR, DA850_AFSR, DA850_AMUTE,
- DA850_AXR_11, DA850_AXR_12,
+ DA850_AXR_11, DA850_AXR_12, DA850_AXR_13, DA850_AXR_14,
-1
};
--
1.6.0.5
1
0

[alsa-devel] [PATCH v2 03/10] davinci: ASoC support for Omapl138-Hawkboard
by vm.rod25@gmail.com 12 Oct '10
by vm.rod25@gmail.com 12 Oct '10
12 Oct '10
From: Victor Rodriguez <victor.rodriguez(a)sasken.com>
This patch adds ASoC support for the Hawkboard-L138 system
Signed-off-by: Victor Rodriguez <victor.rodriguez(a)sasken.com>
---
sound/soc/davinci/Kconfig | 5 +++--
sound/soc/davinci/davinci-evm.c | 6 ++++--
2 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/sound/soc/davinci/Kconfig b/sound/soc/davinci/Kconfig
index 6bbf001..72c6752 100644
--- a/sound/soc/davinci/Kconfig
+++ b/sound/soc/davinci/Kconfig
@@ -76,8 +76,9 @@ config SND_DA830_SOC_EVM
DA830/OMAP-L137 EVM
config SND_DA850_SOC_EVM
- tristate "SoC Audio support for DA850/OMAP-L138 EVM"
- depends on SND_DAVINCI_SOC && MACH_DAVINCI_DA850_EVM
+ tristate "SoC Audio support for DA850/OMAP-L138 EVM/Hawkboard"
+ depends on SND_DAVINCI_SOC && (MACH_DAVINCI_DA850_EVM || \
+ MACH_OMAPL138_HAWKBOARD)
select SND_DAVINCI_SOC_MCASP
select SND_SOC_TLV320AIC3X
help
diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c
index 97f74d6..73093eb 100644
--- a/sound/soc/davinci/davinci-evm.c
+++ b/sound/soc/davinci/davinci-evm.c
@@ -59,7 +59,8 @@ static int evm_hw_params(struct snd_pcm_substream *substream,
sysclk = 12288000;
else if (machine_is_davinci_da830_evm() ||
- machine_is_davinci_da850_evm())
+ machine_is_davinci_da850_evm() ||
+ machine_is_omapl138_hawkboard())
sysclk = 24576000;
else
@@ -311,7 +312,8 @@ static int __init evm_init(void)
} else if (machine_is_davinci_da830_evm()) {
evm_snd_dev_data = &da830_evm_snd_devdata;
index = 1;
- } else if (machine_is_davinci_da850_evm()) {
+ } else if (machine_is_davinci_da850_evm() ||
+ machine_is_omapl138_hawkboard()) {
evm_snd_dev_data = &da850_evm_snd_devdata;
index = 0;
} else
--
1.6.0.5
1
0

12 Oct '10
From: Victor Rodriguez <victor.rodriguez(a)sasken.com>
This patch adds
EMAC, EDMA, ASoC, SOUND, MMC/SD and USB OHCI
support for the Hawkboard-L138 system
It is under the machine name "omapl138_hawkboard".
This system is based on the da850 davinci CPU architecture.
Victor Rodriguez (10):
davinci: EMAC support for Omapl138-Hawkboard
davinci: EDMA support for Omapl138-Hawkboard
davinci: ASoC support for Omapl138-Hawkboard
davinci: McASP configuration for Omapl138-Hawkboard
davinci: Audio support for Omapl138-Hawkboard
davinci: MMC/SD configuration for Omapl138-Hawkboard
davinci: MMC/SD support for Omapl138-Hawkboar
davinci: USB1.1 clocks for Omapl138-Hawkboard
davinci: USB1.1 GPIOs for Omapl138-Hawkboard
davinci: USB-OHCI support for Omapl138-Hawkboard
arch/arm/mach-davinci/board-omapl138-hawk.c | 300 +++++++++++++++++++++++++++
arch/arm/mach-davinci/da850.c | 23 ++-
arch/arm/mach-davinci/include/mach/mux.h | 4 +
sound/soc/davinci/Kconfig | 5 +-
sound/soc/davinci/davinci-evm.c | 6 +-
5 files changed, 333 insertions(+), 5 deletions(-)
1
0

12 Oct '10
Hi,
This patch-set is for new S/PDIF common driver that supports S/PDIF
PCM audio on S5PC100, S5PC110 and S5PV210.
This patch-set is based on two different branches that :-
o ASoC patches are based on Mark Brown's git branch 'for-next'
(commit id - 135e44aaa47c22b66c8d2acb54da1106a6c17598)
o ARM patches are based on Kukjin Kim's git branch 'for-next'
(commit id - a9d09cac7485062c599ee8f341bb0c5ccc2cc9d6)
Based on these patches S/PDIF driver supports followings :-
o Playback supports {32, 44.1, 48 and 96}kHz sampling rates.
o Playback supports 16-bit Little-endian PCM format.
This patch-set contains followings :-
o To Kukjin Kim and Ben Dooks,
- [PATCH 1/10] ARM: S5PC100: Add S/PDIF platform device
- [PATCH 2/10] ARM: S5PC100: Modify SCLK_AUDIO{0,1,2} clock as
sysclks
- [PATCH 3/10] ARM: S5PC100: Add SCLK_SPDIF clock
- [PATCH 4/10] ARM: S5PV210: Add S/PDIF platform device
- [PATCH 5/10] ARM: S5PV210: Add SCLK_SPDIF clock
- [PATCH 6/10] ARM: S5PV210: Add audio clocks as sysclk
- [PATCH 7/10] ARM: S5PV210: Fix wrong EPLL rate getting on
setup clocks
- [PATCH 8/10] ARM: S5PV210: Add EPLL clock operations
o To Jassi Brar, Mark Brown and Liam Girdwood,
- [PATCH 9/10] ASoC: SAMSUNG: Add S/PDIF CPU driver
- [PATCH 10/10] ASoC: SAMSUNG: Add Machine driver for S/PDIF PCM audio
Best Regards,
Claude(Seungwhan Youn)
5
51

Re: [alsa-devel] [patch 1/2] OSS: soundcard: locking bug in sound_ioctl()
by Arnd Bergmann 11 Oct '10
by Arnd Bergmann 11 Oct '10
11 Oct '10
On Monday 11 October 2010 20:54:56 Josh Triplett wrote:
> On Mon, Oct 11, 2010 at 12:52:06PM +0200, Johannes Berg wrote:
>
> > I don't know. Could be related to trylock issues, could be just historic
> > since semaphores can't really be annotated, or could be something else
> > entirely... I would expect a huge amount of warnings from sparse though
> > if you "just" annotate them since there are things like rtnl_lock()
> > which would have to propagate context.
>
> As far as I know, no reason exists to not just annotate mutexes; I think
> mutexes just came along later and nobody happened to add the appropriate
> annotations. (Also, sparse does handle trylock.)
>
> But yes, annotating mutexes will then introduce a giant pile of lock
> warnings that need further annotation propagation. It will also
> introduce lock warnings that represent actual bugs, making it important
> to not just blindly propagate annotations to make warnings go away.
I've given it a try, wrapping the trylock/interruptible/killable variants
into macros and the number of additional warnings was much less than
I had feared. This is the diff for today's sparse with today's linux-next
x86_64_defconfig:
> arch/x86/kernel/smpboot.c:100:6: warning: context imbalance in 'cpu_hotplug_driver_lock' - wrong count at exit
> arch/x86/kernel/smpboot.c:105:6: warning: context imbalance in 'cpu_hotplug_driver_unlock' - unexpected unlock
> kernel/cpu.c:27:6: warning: context imbalance in 'cpu_maps_update_begin' - wrong count at exit
> kernel/cpu.c:32:6: warning: context imbalance in 'cpu_maps_update_done' - unexpected unlock
> kernel/cpu.c:110:9: warning: context imbalance in 'cpu_hotplug_begin' - wrong count at exit
> kernel/cpu.c:120:13: warning: context imbalance in 'cpu_hotplug_done' - unexpected unlock
> kernel/params.c:565:6: warning: context imbalance in '__kernel_param_lock' - wrong count at exit
> kernel/params.c:571:6: warning: context imbalance in '__kernel_param_unlock' - unexpected unlock
> kernel/irq/autoprobe.c:110:9: warning: context imbalance in 'probe_irq_on' - wrong count at exit
> kernel/irq/autoprobe.c:145:9: warning: context imbalance in 'probe_irq_mask' - unexpected unlock
> kernel/irq/autoprobe.c:189:9: warning: context imbalance in 'probe_irq_off' - unexpected unlock
> kernel/trace/trace.c:1716:26: warning: context imbalance in 's_start' - different lock contexts for basic block
> kernel/trace/trace.c:303:31: warning: context imbalance in 's_stop' - unexpected unlock
> kernel/trace/trace.c:2277:9: warning: context imbalance in 't_start' - wrong count at exit
> kernel/trace/trace.c:2280:13: warning: context imbalance in 't_stop' - unexpected unlock
> kernel/trace/trace.c:3196:28: warning: context imbalance in 'tracing_read_pipe' - different lock contexts for basic block
> kernel/trace/trace.c:3349:28: warning: context imbalance in 'tracing_splice_read_pipe' - different lock contexts for basic block
> kernel/trace/trace.c:303:31: warning: context imbalance in 'tracing_buffers_read' - unexpected unlock
> kernel/trace/trace.c:303:31: warning: context imbalance in 'tracing_buffers_splice_read' - unexpected unlock
> kernel/trace/trace_stat.c:203:13: warning: context imbalance in 'stat_seq_start' - wrong count at exit
> kernel/trace/trace_stat.c:240:13: warning: context imbalance in 'stat_seq_stop' - unexpected unlock
> kernel/trace/trace_events.c:399:9: warning: context imbalance in 't_start' - wrong count at exit
> kernel/trace/trace_events.c:430:9: warning: context imbalance in 's_start' - wrong count at exit
> kernel/trace/trace_events.c:444:13: warning: context imbalance in 't_stop' - unexpected unlock
> kernel/trace/trace_kprobe.c:1064:13: warning: context imbalance in 'probes_seq_start' - wrong count at exit
> kernel/trace/trace_kprobe.c:1075:13: warning: context imbalance in 'probes_seq_stop' - unexpected unlock
> kernel/cgroup.c:737:6: warning: context imbalance in 'cgroup_lock' - wrong count at exit
> kernel/cgroup.c:748:6: warning: context imbalance in 'cgroup_unlock' - unexpected unlock
> kernel/cgroup.c:1867:6: warning: context imbalance in 'cgroup_lock_live_group' - different lock contexts for basic block
> kernel/cgroup.c:2155:12: warning: context imbalance in 'cgroup_create_file' - different lock contexts for basic block
> kernel/cgroup.c:3273:47: warning: context imbalance in 'cgroup_lock_hierarchy' - different lock contexts for basic block
> kernel/cgroup.c:3291:25: warning: context imbalance in 'cgroup_unlock_hierarchy' - unexpected unlock
> kernel/cgroup.c:3362:9: warning: context imbalance in 'cgroup_create' - unexpected unlock
> kernel/cpuset.c:2449:6: warning: context imbalance in 'cpuset_unlock' - unexpected unlock
> kernel/audit_watch.c:439:5: warning: context imbalance in 'audit_add_watch' - unexpected unlock
> kernel/audit_tree.c:662:9: warning: context imbalance in 'audit_add_tree_rule' - unexpected unlock
> mm/shmem.c:943:9: warning: context imbalance in 'shmem_unuse_inode' - unexpected unlock
> mm/shmem.c:1029:9: warning: context imbalance in 'shmem_unuse' - wrong count at exit
> mm/mmap.c:2598:9: warning: context imbalance in 'mm_take_all_locks' - wrong count at exit
> mm/mmap.c:2657:9: warning: context imbalance in 'mm_drop_all_locks' - unexpected unlock
> mm/swapfile.c:1692:13: warning: context imbalance in 'swap_start' - wrong count at exit
> mm/swapfile.c:1737:13: warning: context imbalance in 'swap_stop' - unexpected unlock
> mm/swapfile.c:2114:17: warning: context imbalance in 'sys_swapon' - unexpected unlock
> fs/super.c:239:6: warning: context imbalance in 'lock_super' - wrong count at exit
> fs/super.c:245:6: warning: context imbalance in 'unlock_super' - unexpected unlock
> fs/exec.c:1079:5: warning: context imbalance in 'prepare_bprm_creds' - different lock contexts for basic block
> arch/x86/include/asm/current.h:14:16: warning: context imbalance in 'free_bprm' - unexpected unlock
> fs/exec.c:1105:6: warning: context imbalance in 'install_exec_creds' - unexpected unlock
> fs/pipe.c:55:9: warning: context imbalance in 'pipe_lock_nested' - wrong count at exit
> fs/pipe.c:71:17: warning: context imbalance in 'pipe_unlock' - unexpected unlock
> fs/namei.c:1346:15: warning: context imbalance in 'lock_rename' - wrong count at exit
> fs/namei.c:1376:6: warning: context imbalance in 'unlock_rename' - unexpected unlock
> fs/namei.c:1491:36: warning: context imbalance in '__open_namei_create' - unexpected unlock
> fs/namei.c:1730:20: warning: context imbalance in 'do_last' - different lock contexts for basic block
> fs/namei.c:1905:15: warning: context imbalance in 'lookup_create' - wrong count at exit
> fs/namei.c:2040:9: warning: context imbalance in 'sys_mknodat' - unexpected unlock
> fs/namei.c:2103:9: warning: context imbalance in 'sys_mkdirat' - unexpected unlock
> fs/namei.c:2391:9: warning: context imbalance in 'sys_symlinkat' - unexpected unlock
> fs/namei.c:2490:9: warning: context imbalance in 'sys_linkat' - unexpected unlock
> fs/namei.c:2577:9: warning: context imbalance in 'vfs_rename_dir' - different lock contexts for basic block
> fs/namei.c:2609:9: warning: context imbalance in 'vfs_rename_other' - different lock contexts for basic block
> fs/readdir.c:43:9: warning: context imbalance in 'vfs_readdir' - unexpected unlock
> fs/dcache.c:1792:17: warning: context imbalance in '__d_unalias' - unexpected unlock
> fs/libfs.c:783:9: warning: context imbalance in 'simple_attr_read' - unexpected unlock
> fs/libfs.c:815:9: warning: context imbalance in 'simple_attr_write' - unexpected unlock
> fs/direct-io.c:1095:17: warning: context imbalance in 'direct_io_worker' - unexpected unlock
> fs/direct-io.c:1253:9: warning: context imbalance in '__blockdev_direct_IO' - different lock contexts for basic block
> fs/autofs4/root.c:582:17: warning: context imbalance in 'autofs4_lookup' - unexpected unlock
> fs/autofs4/waitq.c:274:25: warning: context imbalance in 'validate_request' - unexpected unlock
> fs/autofs4/waitq.c:366:17: warning: context imbalance in 'autofs4_wait' - different lock contexts for basic block
> include/linux/spinlock_api_smp.h:152:27: warning: context imbalance in 'journal_lock_updates' - wrong count at exit
> fs/jbd/transaction.c:484:9: warning: context imbalance in 'journal_unlock_updates' - unexpected unlock
> fs/proc/base.c:2313:9: warning: context imbalance in 'proc_pid_attr_write' - unexpected unlock
> fs/proc/proc_tty.c:107:13: warning: context imbalance in 't_start' - wrong count at exit
> fs/proc/proc_tty.c:118:13: warning: context imbalance in 't_stop' - unexpected unlock
> fs/sysfs/dir.c:350:6: warning: context imbalance in 'sysfs_addrm_start' - wrong count at exit
> fs/sysfs/dir.c:504:6: warning: context imbalance in 'sysfs_addrm_finish' - unexpected unlock
> arch/x86/include/asm/current.h:14:16: warning: context imbalance in 'ata_eh_acquire' - wrong count at exit
> drivers/ata/libata-eh.c:495:9: warning: context imbalance in 'ata_eh_release' - unexpected unlock
> drivers/base/bus.c:181:17: warning: context imbalance in 'driver_unbind' - different lock contexts for basic block
> drivers/base/bus.c:211:17: warning: context imbalance in 'driver_bind' - different lock contexts for basic block
> drivers/base/bus.c:731:9: warning: context imbalance in 'bus_rescan_devices_helper' - different lock contexts for basic block
> drivers/base/bus.c:766:9: warning: context imbalance in 'device_reprobe' - different lock contexts for basic block
> drivers/base/dd.c:265:12: warning: context imbalance in '__driver_attach' - different lock contexts for basic block
> drivers/base/dd.c:395:17: warning: context imbalance in 'driver_detach' - different lock contexts for basic block
> drivers/base/power/main.c:73:6: warning: context imbalance in 'device_pm_lock' - wrong count at exit
> drivers/base/power/main.c:81:6: warning: context imbalance in 'device_pm_unlock' - unexpected unlock
> drivers/block/loop.c:1064:9: warning: context imbalance in 'loop_clr_fd' - unexpected unlock
> drivers/block/loop.c:1352:9: warning: context imbalance in 'lo_ioctl' - different lock contexts for basic block
> drivers/block/loop.c:1553:9: warning: context imbalance in 'lo_release' - different lock contexts for basic block
> drivers/char/tty_io.c:960:6: warning: context imbalance in 'tty_write_unlock' - unexpected unlock
> drivers/char/tty_io.c:966:5: warning: context imbalance in 'tty_write_lock' - wrong count at exit
> drivers/char/tty_io.c:1077:6: warning: context imbalance in 'tty_write_message' - wrong count at exit
> drivers/char/tty_mutex.c:31:9: warning: context imbalance in 'tty_lock' - wrong count at exit
> drivers/char/tty_mutex.c:42:9: warning: context imbalance in 'tty_unlock' - unexpected unlock
> drivers/char/misc.c:66:13: warning: context imbalance in 'misc_seq_start' - wrong count at exit
> drivers/char/misc.c:77:13: warning: context imbalance in 'misc_seq_stop' - unexpected unlock
> drivers/cpuidle/cpuidle.c:138:6: warning: context imbalance in 'cpuidle_pause_and_lock' - wrong count at exit
> drivers/cpuidle/cpuidle.c:149:6: warning: context imbalance in 'cpuidle_resume_and_unlock' - unexpected unlock
> drivers/gpu/drm/drm_pci.c:215:9: warning: context imbalance in 'drm_get_pci_dev' - unexpected unlock
> drivers/gpu/drm/i915/i915_debugfs.c:202:9: warning: context imbalance in 'i915_gem_object_info' - unexpected unlock
> drivers/gpu/drm/i915/i915_debugfs.c:827:9: warning: context imbalance in 'i915_emon_status' - unexpected unlock
> drivers/gpu/drm/i915/i915_gem.c:144:12: warning: context imbalance in 'i915_mutex_lock_interruptible' - different lock contexts for basic block
> drivers/gpu/drm/i915/i915_gem.c:417:9: warning: context imbalance in 'i915_gem_shmem_pread_fast' - unexpected unlock
> drivers/gpu/drm/i915/i915_gem.c:554:9: warning: context imbalance in 'i915_gem_shmem_pread_slow' - unexpected unlock
> drivers/gpu/drm/i915/i915_gem.c:706:17: warning: context imbalance in 'i915_gem_gtt_pwrite_fast' - unexpected unlock
> drivers/gpu/drm/i915/i915_gem.c:847:9: warning: context imbalance in 'i915_gem_gtt_pwrite_slow' - unexpected unlock
> drivers/gpu/drm/i915/i915_gem.c:918:9: warning: context imbalance in 'i915_gem_shmem_pwrite_fast' - unexpected unlock
> drivers/gpu/drm/i915/i915_gem.c:1032:9: warning: context imbalance in 'i915_gem_shmem_pwrite_slow' - unexpected unlock
> drivers/gpu/drm/i915/i915_gem.c:1184:35: warning: context imbalance in 'i915_gem_set_domain_ioctl' - unexpected unlock
> drivers/gpu/drm/i915/i915_gem.c:1217:35: warning: context imbalance in 'i915_gem_sw_finish_ioctl' - unexpected unlock
> drivers/gpu/drm/i915/i915_gem.c:1529:43: warning: context imbalance in 'i915_gem_mmap_gtt_ioctl' - unexpected unlock
> drivers/gpu/drm/i915/i915_gem.c:3770:17: warning: context imbalance in 'i915_gem_do_execbuffer' - unexpected unlock
> drivers/gpu/drm/i915/i915_gem.c:4248:43: warning: context imbalance in 'i915_gem_pin_ioctl' - unexpected unlock
> drivers/gpu/drm/i915/i915_gem.c:4310:43: warning: context imbalance in 'i915_gem_unpin_ioctl' - unexpected unlock
> drivers/gpu/drm/i915/i915_gem.c:4375:35: warning: context imbalance in 'i915_gem_busy_ioctl' - unexpected unlock
> drivers/gpu/drm/i915/i915_gem.c:4419:43: warning: context imbalance in 'i915_gem_madvise_ioctl' - unexpected unlock
> drivers/hid/usbhid/hid-core.c:127:47: warning: context imbalance in 'hid_reset' - unexpected unlock
> drivers/input/input.c:1021:13: warning: context imbalance in 'input_devices_seq_start' - different lock contexts for basic block
> drivers/input/input.c:1050:17: warning: context imbalance in 'input_seq_stop' - unexpected unlock
> drivers/input/input.c:1143:13: warning: context imbalance in 'input_handlers_seq_start' - different lock contexts for basic block
> drivers/input/mouse/psmouse-base.c:1534:9: warning: context imbalance in 'psmouse_attr_set_helper' - unexpected unlock
> drivers/input/serio/i8042.c:129:6: warning: context imbalance in 'i8042_lock_chip' - wrong count at exit
> drivers/input/serio/i8042.c:135:6: warning: context imbalance in 'i8042_unlock_chip' - unexpected unlock
> drivers/input/serio/libps2.c:62:9: warning: context imbalance in 'ps2_begin_command' - wrong count at exit
> drivers/input/serio/libps2.c:72:9: warning: context imbalance in 'ps2_end_command' - unexpected unlock
> drivers/md/dm.c:2088:6: warning: context imbalance in 'dm_lock_md_type' - wrong count at exit
> drivers/md/dm.c:2093:6: warning: context imbalance in 'dm_unlock_md_type' - unexpected unlock
> drivers/md/md.c:578:17: warning: context imbalance in 'mddev_unlock' - unexpected unlock
> drivers/md/md.c:546:19: warning: context imbalance in 'rdev_size_store' - different lock contexts for basic block
> drivers/md/md.c:546:19: warning: context imbalance in 'rdev_attr_show' - different lock contexts for basic block
> drivers/md/md.c:546:19: warning: context imbalance in 'rdev_attr_store' - different lock contexts for basic block
> drivers/md/md.c:546:19: warning: context imbalance in 'md_attr_show' - different lock contexts for basic block
> drivers/md/md.c:546:19: warning: context imbalance in 'md_attr_store' - different lock contexts for basic block
> drivers/md/md.c:4871:17: warning: context imbalance in 'autorun_devices' - different lock contexts for basic block
> drivers/md/md.c:546:19: warning: context imbalance in 'md_ioctl' - different lock contexts for basic block
> drivers/md/md.c:5911:9: warning: context imbalance in 'md_open' - different lock contexts for basic block
> drivers/md/md.c:546:19: warning: context imbalance in 'md_seq_show' - different lock contexts for basic block
> drivers/md/md.c:6985:6: warning: context imbalance in 'md_check_recovery' - different lock contexts for basic block
> drivers/md/md.c:7180:17: warning: context imbalance in 'md_notify_reboot' - different lock contexts for basic block
> drivers/pci/pci.c:2494:30: warning: context imbalance in 'pci_dev_reset' - unexpected unlock
> drivers/pcmcia/rsrc_nonstatic.c:281:17: warning: context imbalance in 'readable' - unexpected unlock
> drivers/serial/serial_core.c:1546:26: warning: context imbalance in 'uart_get' - different lock contexts for basic block
> drivers/serial/serial_core.c:1632:17: warning: context imbalance in 'uart_open' - unexpected unlock
> drivers/thermal/thermal_sys.c:74:9: warning: context imbalance in 'get_idr' - different lock contexts for basic block
> drivers/thermal/thermal_sys.c:88:9: warning: context imbalance in 'release_idr' - different lock contexts for basic block
> drivers/usb/class/usblp.c:842:9: warning: context imbalance in 'usblp_read' - unexpected unlock
> arch/x86/include/asm/current.h:14:16: warning: context imbalance in 'usblp_rwait_and_lock' - different lock contexts for basic block
> drivers/usb/core/usb.c:561:5: warning: context imbalance in 'usb_lock_device_for_reset' - different lock contexts for basic block
> drivers/usb/core/message.c:1605:17: warning: context imbalance in '__usb_queue_reset_device' - unexpected unlock
> drivers/usb/storage/transport.c:1315:17: warning: context imbalance in 'usb_stor_port_reset' - unexpected unlock
> drivers/usb/storage/usb.c:191:5: warning: context imbalance in 'usb_stor_pre_reset' - wrong count at exit
> drivers/usb/storage/usb.c:203:5: warning: context imbalance in 'usb_stor_post_reset' - unexpected unlock
> drivers/video/fbmem.c:48:5: warning: context imbalance in 'lock_fb_info' - wrong count at exit
> drivers/video/fbmem.c:1047:17: warning: context imbalance in 'do_fb_ioctl' - unexpected unlock
> drivers/video/fbmem.c:1608:9: warning: context imbalance in 'register_framebuffer' - unexpected unlock
> drivers/video/fbmem.c:1646:9: warning: context imbalance in 'unregister_framebuffer' - unexpected unlock
> drivers/video/fbmem.c:1696:23: warning: context imbalance in 'fb_set_suspend' - unexpected unlock
> drivers/video/fbmem.c:1768:17: warning: context imbalance in 'fb_new_modelist' - unexpected unlock
> drivers/video/fbcmap.c:276:23: warning: context imbalance in 'fb_set_user_cmap' - unexpected unlock
> drivers/video/console/fbcon.c:2299:9: warning: context imbalance in 'fbcon_generic_blank' - unexpected unlock
> sound/core/sound.c:124:25: warning: context imbalance in 'autoload_device' - unexpected unlock
> net/netfilter/core.c:40:9: warning: context imbalance in 'nf_register_afinfo' - unexpected unlock
> net/netfilter/core.c:71:21: warning: context imbalance in 'nf_register_hook' - unexpected unlock
> net/netfilter/nf_log.c:132:13: warning: context imbalance in 'seq_start' - wrong count at exit
> net/netfilter/nf_log.c:152:13: warning: context imbalance in 'seq_stop' - unexpected unlock
> net/netfilter/x_tables.c:710:17: warning: context imbalance in 'xt_find_table_lock' - different lock contexts for basic block
> net/netfilter/x_tables.c:726:6: warning: context imbalance in 'xt_table_unlock' - unexpected unlock
> net/netfilter/x_tables.c:733:6: warning: context imbalance in 'xt_compat_lock' - wrong count at exit
> net/netfilter/x_tables.c:739:6: warning: context imbalance in 'xt_compat_unlock' - unexpected unlock
> net/netfilter/x_tables.c:876:9: warning: context imbalance in 'xt_register_table' - unexpected unlock
> net/netfilter/x_tables.c:903:13: warning: context imbalance in 'xt_table_seq_start' - wrong count at exit
> net/netfilter/x_tables.c:922:13: warning: context imbalance in 'xt_table_seq_stop' - unexpected unlock
> net/netfilter/x_tables.c:985:13: warning: context imbalance in 'xt_mttg_seq_next' - wrong count at exit
> net/netfilter/x_tables.c:1044:17: warning: context imbalance in 'xt_mttg_seq_stop' - unexpected unlock
> net/netlink/genetlink.c:24:6: warning: context imbalance in 'genl_lock' - wrong count at exit
> net/netlink/genetlink.c:30:6: warning: context imbalance in 'genl_unlock' - unexpected unlock
> net/unix/af_unix.c:919:9: warning: context imbalance in 'unix_bind' - different lock contexts for basic block
> net/wireless/core.c:150:9: warning: context imbalance in 'cfg80211_get_dev_from_info' - different lock contexts for basic block
> net/wireless/core.c:172:9: warning: context imbalance in 'cfg80211_get_dev_from_ifindex' - wrong count at exit
> net/wireless/core.h:191:9: warning: context imbalance in 'cfg80211_wext_siwscan' - unexpected unlock
> net/wireless/core.h:191:9: warning: context imbalance in 'cfg80211_wext_giwscan' - unexpected unlock
> net/wireless/core.h:191:9: warning: context imbalance in 'nl80211_finish_netdev_dump' - unexpected unlock
> net/wireless/nl80211.c:901:12: warning: context imbalance in 'nl80211_set_wiphy' - different lock contexts for basic block
> net/wireless/core.h:191:9: warning: context imbalance in 'nl80211_pre_doit' - unexpected unlock
> net/wireless/core.h:191:9: warning: context imbalance in 'nl80211_post_doit' - unexpected unlock
And this is the patch I used for testing. There may still be some flaws in it,
but it seems to do the trick.
Signed-off-by: Arnd Bergmann <arnd(a)arndb.de>
diff --git a/include/linux/mutex.h b/include/linux/mutex.h
index f363bc8..d4940af 100644
--- a/include/linux/mutex.h
+++ b/include/linux/mutex.h
@@ -14,6 +14,7 @@
#include <linux/spinlock_types.h>
#include <linux/linkage.h>
#include <linux/lockdep.h>
+#include <linux/compiler.h>
#include <asm/atomic.h>
@@ -131,20 +132,35 @@ static inline int mutex_is_locked(struct mutex *lock)
* Also see Documentation/mutex-design.txt.
*/
#ifdef CONFIG_DEBUG_LOCK_ALLOC
-extern void mutex_lock_nested(struct mutex *lock, unsigned int subclass);
-extern int __must_check mutex_lock_interruptible_nested(struct mutex *lock,
- unsigned int subclass);
-extern int __must_check mutex_lock_killable_nested(struct mutex *lock,
- unsigned int subclass);
-
+extern void mutex_lock_nested(struct mutex *lock, unsigned int subclass)
+ __acquires(lock);
+extern int __must_check __mutex_lock_interruptible_nested(struct mutex *lock,
+ unsigned int subclass);
+extern int __must_check __mutex_lock_killable_nested(struct mutex *lock,
+ unsigned int subclass);
+#define mutex_lock_interruptible_nested(lock, subclass) ({ \
+ int __mutex_ret = __mutex_lock_interruptible_nested(lock, subclass); \
+ if (!__mutex_ret) __acquire(lock); __mutex_ret; \
+})
+#define mutex_lock_killable_nested(lock, subclass) ({ \
+ int __mutex_ret = __mutex_lock_killable_nested(lock, subclass); \
+ if (!__mutex_ret) __acquire(lock); __mutex_ret; \
+})
#define mutex_lock(lock) mutex_lock_nested(lock, 0)
#define mutex_lock_interruptible(lock) mutex_lock_interruptible_nested(lock, 0)
#define mutex_lock_killable(lock) mutex_lock_killable_nested(lock, 0)
#else
-extern void mutex_lock(struct mutex *lock);
-extern int __must_check mutex_lock_interruptible(struct mutex *lock);
-extern int __must_check mutex_lock_killable(struct mutex *lock);
-
+extern void mutex_lock(struct mutex *lock) __acquires(lock);
+extern int __must_check __mutex_lock_interruptible(struct mutex *lock);
+extern int __must_check __mutex_lock_killable(struct mutex *lock);
+#define mutex_lock_interruptible(lock) ({ \
+ int __mutex_ret = __mutex_lock_interruptible(lock); \
+ if (!__mutex_ret) __acquire(lock); __mutex_ret; \
+})
+#define mutex_lock_killable(lock) ({ \
+ int __mutex_ret = __mutex_lock_killable(lock); \
+ if (!__mutex_ret) __acquire(lock); __mutex_ret; \
+})
# define mutex_lock_nested(lock, subclass) mutex_lock(lock)
# define mutex_lock_interruptible_nested(lock, subclass) mutex_lock_interruptible(lock)
# define mutex_lock_killable_nested(lock, subclass) mutex_lock_killable(lock)
@@ -156,8 +172,16 @@ extern int __must_check mutex_lock_killable(struct mutex *lock);
*
* Returns 1 if the mutex has been acquired successfully, and 0 on contention.
*/
-extern int mutex_trylock(struct mutex *lock);
-extern void mutex_unlock(struct mutex *lock);
-extern int atomic_dec_and_mutex_lock(atomic_t *cnt, struct mutex *lock);
+extern int __mutex_trylock(struct mutex *lock);
+#define mutex_trylock(lock) ({ \
+ int __mutex_ret = __mutex_trylock(lock); \
+ if (__mutex_ret) __acquire(lock); __mutex_ret; \
+})
+extern void mutex_unlock(struct mutex *lock) __releases(lock);
+extern int __atomic_dec_and_mutex_lock(atomic_t *cnt, struct mutex *lock);
+#define atomic_dec_and_mutex_lock(cnt, lock) ({ \
+ int __mutex_ret = __atomic_dec_and_mutex_lock(cnt, lock); \
+ if (__mutex_ret) __acquire(lock); __mutex_ret; \
+})
#endif
diff --git a/kernel/mutex.c b/kernel/mutex.c
index 200407c..09b70b7 100644
--- a/kernel/mutex.c
+++ b/kernel/mutex.c
@@ -282,22 +282,22 @@ mutex_lock_nested(struct mutex *lock, unsigned int subclass)
EXPORT_SYMBOL_GPL(mutex_lock_nested);
int __sched
-mutex_lock_killable_nested(struct mutex *lock, unsigned int subclass)
+__mutex_lock_killable_nested(struct mutex *lock, unsigned int subclass)
{
might_sleep();
return __mutex_lock_common(lock, TASK_KILLABLE, subclass, _RET_IP_);
}
-EXPORT_SYMBOL_GPL(mutex_lock_killable_nested);
+EXPORT_SYMBOL_GPL(__mutex_lock_killable_nested);
int __sched
-mutex_lock_interruptible_nested(struct mutex *lock, unsigned int subclass)
+__mutex_lock_interruptible_nested(struct mutex *lock, unsigned int subclass)
{
might_sleep();
return __mutex_lock_common(lock, TASK_INTERRUPTIBLE,
subclass, _RET_IP_);
}
-EXPORT_SYMBOL_GPL(mutex_lock_interruptible_nested);
+EXPORT_SYMBOL_GPL(__mutex_lock_interruptible_nested);
#endif
/*
@@ -366,7 +366,7 @@ __mutex_lock_interruptible_slowpath(atomic_t *lock_count);
*
* This function is similar to (but not equivalent to) down_interruptible().
*/
-int __sched mutex_lock_interruptible(struct mutex *lock)
+int __sched __mutex_lock_interruptible(struct mutex *lock)
{
int ret;
@@ -379,9 +379,9 @@ int __sched mutex_lock_interruptible(struct mutex *lock)
return ret;
}
-EXPORT_SYMBOL(mutex_lock_interruptible);
+EXPORT_SYMBOL(__mutex_lock_interruptible);
-int __sched mutex_lock_killable(struct mutex *lock)
+int __sched __mutex_lock_killable(struct mutex *lock)
{
int ret;
@@ -393,7 +393,7 @@ int __sched mutex_lock_killable(struct mutex *lock)
return ret;
}
-EXPORT_SYMBOL(mutex_lock_killable);
+EXPORT_SYMBOL(__mutex_lock_killable);
static __used noinline void __sched
__mutex_lock_slowpath(atomic_t *lock_count)
@@ -461,7 +461,7 @@ static inline int __mutex_trylock_slowpath(atomic_t *lock_count)
* This function must not be used in interrupt context. The
* mutex must be released by the same task that acquired it.
*/
-int __sched mutex_trylock(struct mutex *lock)
+int __sched __mutex_trylock(struct mutex *lock)
{
int ret;
@@ -471,7 +471,7 @@ int __sched mutex_trylock(struct mutex *lock)
return ret;
}
-EXPORT_SYMBOL(mutex_trylock);
+EXPORT_SYMBOL(__mutex_trylock);
/**
* atomic_dec_and_mutex_lock - return holding mutex if we dec to 0
@@ -480,7 +480,7 @@ EXPORT_SYMBOL(mutex_trylock);
*
* return true and hold lock if we dec to 0, return false otherwise
*/
-int atomic_dec_and_mutex_lock(atomic_t *cnt, struct mutex *lock)
+int __atomic_dec_and_mutex_lock(atomic_t *cnt, struct mutex *lock)
{
/* dec if we can't possibly hit 0 */
if (atomic_add_unless(cnt, -1, 1))
@@ -495,4 +495,4 @@ int atomic_dec_and_mutex_lock(atomic_t *cnt, struct mutex *lock)
/* we hit 0, and we hold the lock */
return 1;
}
-EXPORT_SYMBOL(atomic_dec_and_mutex_lock);
+EXPORT_SYMBOL(__atomic_dec_and_mutex_lock);
1
0
hi Flo,
Thanks for your reply.
On 10/11/10 15:28, Florian Faber wrote:
> Matthew,
>
>> Of course, you can adjust the volume digitally (though since hdspmixer overwrites all your routing every time you open it, it's a bit annoying to use). However, the card appears to have a dedicated a analogue gain stage just for the headphones. It's not a full PGA, but can be set to 0db, -6db, -12dB and mute - under windows. The ALSA driver only gives the first 3 options as controls.
>
> Ah, yes, that is something special with that old cards. I actually had
> to look it up in the manual.
Are you sure? I don't have one, but it looks like the AIO is very similar:
http://www.rme-audio.de/images/products/aio_set.gif
Anyhow - hardly important! :)
>
>> I had a quick look in the code, and it seems there's a 2-bit field in the 9632 control register for controlling this. Sounds neat, as we have 4 possible values. Can anyone confirm that the unused value (0x10, IIRC) in the ALSA driver is used to mute the headphones?
>
> I only have the sources for the newer cards, sorry. Just try it out,
> nothing bad should happen there.
>
Hmmm, is there any advice you can give me on what might be affected or
need modifying to stay in sync? I've not contributed to a project like
this before...
The obvious ones to me are of course the driver itself, and adding a new
radio button to hdspconf. Is there anything else?
Thanks a lot,
Matt
1
0
Hello again
After an almost complete rewrite to support separate channels views
in the main sliders and switches areas, Alsamixer-Qt4 0.5.0 is now
available.
http://xwmw.org/alsamixer-qt4/
http://sourceforge.net/projects/alsamixer-qt4/files/
This is a snapshot from the CHANGELOG file.
* The channels mixer dialog is gone
* Mixer elements can be toggled between joined and channels view
* Automated switch from joined to channels view if channels values
differ for a certain time
* New context menus for mixer elements
* New dynamic support for the Alsa is_active element flag
* New command line arguments similar to the console alsamixer ones
* The card selection widget got basic support for Alsa plugins
* GUI cleanups and slight style changes
* Reduced CPU usage by showing QSpinBox widgets only on demand
(mouse over)
* Fixed a forgotten debug timer that was always running
in 0.4.1 (constant 1% CPU usage)
I ran several tests but since a lot of code has been rewritten
there still may be regressions or even new bugs.
There're also some implemented features I couldn't test at all
because my rather basic hardware doesn't support it.
- Mixer elements with more than two channels.
If the sliders arrangement or some graphics for your card
with 32 channels per element look weird, please drop me a
note and/or a screenshot.
- Is-active flag
In theory the mixer should support dynamic hiding and
revealing of elements whose is-active flag changes.
If it doesn't or even crashes, please tell.
Any comments are welcome.
Best,
Sebastian H.
3
3
On Mon, Oct 11, 2010 at 04:50:56PM +0400, Vasiliy Kulikov wrote:
> It is not greppable situation to simply change the behavior of all
> drivers. I was looking for memory leak bugs in drivers/net/ and fixed
> some of them. Manual looking through _all_ drivers takes much more
> time. In general I try to search for repeatable bugs with coccinelle,
> but it is rare case.
The method you're using to generate the patches is pretty much
orthogonal to anything else, except of course in the case where you're
also submitting the automation for checking (which is useful where
possible).
1
0
On Mon, Oct 11, 2010 at 04:15:55PM +0400, Vasiliy Kulikov wrote:
> On Mon, Oct 11, 2010 at 13:00 +0100, Mark Brown wrote:
> > ...it's not clear to me that this change is an improvement - it'll make
> > the driver more fragile in the face of errors, I don't see a benefit in
> > refusing to register the variant for one bus if the other fails?
> I tried to implement your variant with depca driver in past, but it was
> rejected by David Miller:
> http://lists.openwall.net/netdev/2010/07/12/9
I disagree with David here, and in any case if you're going to make a
style change like this they really ought to be applied over all drivers
rather than just a few individual ones.
1
0
The following changes since commit 9d9641ec891a53ef93a8972c7913605aeb8127c7:
Merge branch 'for-2.6.36' into for-2.6.37 (2010-10-07 13:44:20 -0700)
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound-2.6.git for-2.6.37
Dan Carpenter (1):
ASoC: checking kzalloc() for IS_ERR() instead of NULL
Mark Brown (2):
ASoC: Shrink code size for WM8962 register defaults table
ASoC: Compress WM8962 register access map
sound/soc/codecs/Makefile | 2 +-
sound/soc/codecs/wm8804.c | 8 +-
sound/soc/codecs/wm8962-tables.c |42299 --------------------------------------
sound/soc/codecs/wm8962.c | 1834 ++
sound/soc/codecs/wm8962.h | 11 -
sound/soc/codecs/wm8985.c | 8 +-
6 files changed, 1843 insertions(+), 42319 deletions(-)
delete mode 100644 sound/soc/codecs/wm8962-tables.c
2
3

11 Oct '10
Hello,
This series adds AC97 audio support for Cirrus Logic EP93xx family SoCs. Example
machine driver is for Simplemachines Sim.One (which is the only hardware that I
have which has AC97 codec).
The first patch is a bugfix for the DMA code. Without the patch audio DMA
transfers may corrupt if playing application is killed while playing. This
results weird noise playback when application is started again. I would like
Ryan Mallon to confirm that this is indeed correct fix and if possible to check
that I2S transfers still work after this patch is applied.
Please review.
Thanks,
MW
Mika Westerberg (4):
ARM: ep93xx: DMA: fix channel_disable
ASoC: add ep93xx AC97 audio driver
ARM: ep93xx: add AC97 platform support
ASoC: ep93xx: add Simplemachines Sim.One AC97 audio support
arch/arm/mach-ep93xx/core.c | 32 ++
arch/arm/mach-ep93xx/dma-m2p.c | 2 +-
arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h | 1 +
arch/arm/mach-ep93xx/include/mach/platform.h | 1 +
arch/arm/mach-ep93xx/simone.c | 1 +
sound/soc/ep93xx/Kconfig | 17 +-
sound/soc/ep93xx/Makefile | 4 +
sound/soc/ep93xx/ep93xx-ac97.c | 476 +++++++++++++++++++++++
sound/soc/ep93xx/ep93xx-ac97.h | 17 +
sound/soc/ep93xx/simone.c | 80 ++++
10 files changed, 629 insertions(+), 2 deletions(-)
create mode 100644 sound/soc/ep93xx/ep93xx-ac97.c
create mode 100644 sound/soc/ep93xx/ep93xx-ac97.h
create mode 100644 sound/soc/ep93xx/simone.c
4
15
From: Luke Yelavich <luke.yelavich(a)canonical.com>
BugLink: https://bugs.launchpad.net/bugs/653420
Add another HP DV6 notebook (103c:363e) to use STAC_HP_DV5.
Signed-off-by: Luke Yelavich <luke.yelavich(a)canonical.com>
---
sound/pci/hda/patch_sigmatel.c | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index d8dfafe..f3577ed 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -1750,6 +1750,8 @@ static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = {
"HP dv6", STAC_HP_DV5), /* HP dv6-1110ax */
SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x7010,
"HP", STAC_HP_DV5),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x363e,
+ "HP DV6", STAC_HP_DV5),
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0233,
"unknown Dell", STAC_DELL_M4_1),
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0234,
--
1.7.1
2
1
Simplify conditional: (a || (!a && b)) => (a || b)
Signed-off-by: Nicolas Kaiser <nikai(a)nikai.net>
---
sound/usb/usx2y/usx2yhwdeppcm.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/sound/usb/usx2y/usx2yhwdeppcm.c b/sound/usb/usx2y/usx2yhwdeppcm.c
index 2a528e5..3146a81 100644
--- a/sound/usb/usx2y/usx2yhwdeppcm.c
+++ b/sound/usb/usx2y/usx2yhwdeppcm.c
@@ -54,7 +54,7 @@
#include <linux/gfp.h>
#include "usbusx2yaudio.c"
-#if defined(USX2Y_NRPACKS_VARIABLE) || (!defined(USX2Y_NRPACKS_VARIABLE) && USX2Y_NRPACKS == 1)
+#if defined(USX2Y_NRPACKS_VARIABLE) || USX2Y_NRPACKS == 1
#include <sound/hwdep.h>
--
1.7.2.2
2
1
kzalloc() returns NULL on error, not ERR_PTR().
Also wm8804_modinit() didn't called i2c_del_driver() if
spi_register_driver() failed.
Signed-off-by: Vasiliy Kulikov <segooon(a)gmail.com>
---
Compile tested.
sound/soc/codecs/wm8804.c | 15 +++++++++++----
1 files changed, 11 insertions(+), 4 deletions(-)
diff --git a/sound/soc/codecs/wm8804.c b/sound/soc/codecs/wm8804.c
index 642b07c..ff4dffd 100644
--- a/sound/soc/codecs/wm8804.c
+++ b/sound/soc/codecs/wm8804.c
@@ -720,8 +720,8 @@ static int __devinit wm8804_spi_probe(struct spi_device *spi)
int ret;
wm8804 = kzalloc(sizeof *wm8804, GFP_KERNEL);
- if (IS_ERR(wm8804))
- return PTR_ERR(wm8804);
+ if (!wm8804)
+ return -ENOMEM;
wm8804->control_type = SND_SOC_SPI;
spi_set_drvdata(spi, wm8804);
@@ -758,8 +758,8 @@ static __devinit int wm8804_i2c_probe(struct i2c_client *i2c,
int ret;
wm8804 = kzalloc(sizeof *wm8804, GFP_KERNEL);
- if (IS_ERR(wm8804))
- return PTR_ERR(wm8804);
+ if (!wm8804)
+ return -ENOMEM;
wm8804->control_type = SND_SOC_I2C;
i2c_set_clientdata(i2c, wm8804);
@@ -804,6 +804,7 @@ static int __init wm8804_modinit(void)
if (ret) {
printk(KERN_ERR "Failed to register wm8804 I2C driver: %d\n",
ret);
+ goto err;
}
#endif
#if defined(CONFIG_SPI_MASTER)
@@ -811,7 +812,13 @@ static int __init wm8804_modinit(void)
if (ret != 0) {
printk(KERN_ERR "Failed to register wm8804 SPI driver: %d\n",
ret);
+ goto err_i2c;
}
+err_i2c:
+#endif
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+ i2c_del_driver(&wm8804_i2c_driver);
+err:
#endif
return ret;
}
--
1.7.0.4
2
1

[alsa-devel] [patch 2/2] OSS: soundcard: fix return value of sound_open()
by Dan Carpenter 11 Oct '10
by Dan Carpenter 11 Oct '10
11 Oct '10
Signed-off-by: Dan Carpenter <error27(a)gmail.com>
diff --git a/sound/oss/soundcard.c b/sound/oss/soundcard.c
index a5ab61e..46c0d03 100644
--- a/sound/oss/soundcard.c
+++ b/sound/oss/soundcard.c
@@ -249,7 +249,7 @@ static int sound_open(struct inode *inode, struct file *file)
}
mutex_unlock(&soundcard_mutex);
- return 0;
+ return retval;
}
static int sound_release(struct inode *inode, struct file *file)
2
1

11 Oct '10
We shouldn't return directly here because we're still holding the
&soundcard_mutex.
This bug goes all the way back to the start of git. It's strange that
no one has complained about it as a runtime bug.
CC: stable(a)kernel.org
Signed-off-by: Dan Carpenter <error27(a)gmail.com>
diff --git a/sound/oss/soundcard.c b/sound/oss/soundcard.c
index 938ed94..a5ab61e 100644
--- a/sound/oss/soundcard.c
+++ b/sound/oss/soundcard.c
@@ -392,11 +392,11 @@ static long sound_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
case SND_DEV_DSP:
case SND_DEV_DSP16:
case SND_DEV_AUDIO:
- return audio_ioctl(dev, file, cmd, p);
+ ret = audio_ioctl(dev, file, cmd, p);
break;
case SND_DEV_MIDIN:
- return MIDIbuf_ioctl(dev, file, cmd, p);
+ ret = MIDIbuf_ioctl(dev, file, cmd, p);
break;
}
4
6
The following changes since commit ad5e4655f9a920b1cc13972e0389eaf9e0ba10b3:
ASoC: remove duplicated include for nuc900 (2010-10-05 19:26:00 -0700)
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound-2.6.git for-2.6.37
Mark Brown (6):
ASoC: Add Dimitris Papastamos to Wolfson maintainers
ASoC: Update links for Wolfson MAINTAINERS entry
ASoC: Staticise AD1980 DAI
ASoC: Use delayed work for debounce of GPIO based jacks
ASoC: Staticise CS4270 DAI
Merge branch 'for-2.6.36' into for-2.6.37
MAINTAINERS | 4 +++-
include/sound/soc.h | 2 +-
sound/soc/codecs/ad1980.c | 2 +-
sound/soc/codecs/cs4270.c | 2 +-
sound/soc/soc-jack.c | 11 +++++------
5 files changed, 11 insertions(+), 10 deletions(-)
2
1
The following changes since commit 0077ca0b5c986477e33451b797b6e7dc92a8bbc0:
ASoC: Fix multi-componentism (2010-09-22 18:47:40 +0100)
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound-2.6.git for-2.6.36
Just a few MAINTAINERS updates.
Mark Brown (3):
ASoC: Add Jassi Brar as Samsung maintainer
ASoC: Add Dimitris Papastamos to Wolfson maintainers
ASoC: Update links for Wolfson MAINTAINERS entry
MAINTAINERS | 10 +++++++++-
1 files changed, 9 insertions(+), 1 deletions(-)
2
1

[alsa-devel] [patch] ASoC: checking kzalloc() for IS_ERR() instead of NULL
by Dan Carpenter 11 Oct '10
by Dan Carpenter 11 Oct '10
11 Oct '10
There is a typo here that got copy and pasted to several probe
functions. kzalloc() returns NULL on allocation failures and not an
ERR_PTR.
Signed-off-by: Dan Carpenter <error27(a)gmail.com>
diff --git a/sound/soc/codecs/wm8804.c b/sound/soc/codecs/wm8804.c
index 642b07c..4599e8e 100644
--- a/sound/soc/codecs/wm8804.c
+++ b/sound/soc/codecs/wm8804.c
@@ -720,8 +720,8 @@ static int __devinit wm8804_spi_probe(struct spi_device *spi)
int ret;
wm8804 = kzalloc(sizeof *wm8804, GFP_KERNEL);
- if (IS_ERR(wm8804))
- return PTR_ERR(wm8804);
+ if (!wm8804)
+ return -ENOMEM;
wm8804->control_type = SND_SOC_SPI;
spi_set_drvdata(spi, wm8804);
@@ -758,8 +758,8 @@ static __devinit int wm8804_i2c_probe(struct i2c_client *i2c,
int ret;
wm8804 = kzalloc(sizeof *wm8804, GFP_KERNEL);
- if (IS_ERR(wm8804))
- return PTR_ERR(wm8804);
+ if (!wm8804)
+ return -ENOMEM;
wm8804->control_type = SND_SOC_I2C;
i2c_set_clientdata(i2c, wm8804);
diff --git a/sound/soc/codecs/wm8985.c b/sound/soc/codecs/wm8985.c
index ae9020a..fd2e7cc 100644
--- a/sound/soc/codecs/wm8985.c
+++ b/sound/soc/codecs/wm8985.c
@@ -1079,8 +1079,8 @@ static int __devinit wm8985_spi_probe(struct spi_device *spi)
int ret;
wm8985 = kzalloc(sizeof *wm8985, GFP_KERNEL);
- if (IS_ERR(wm8985))
- return PTR_ERR(wm8985);
+ if (!wm8985)
+ return -ENOMEM;
wm8985->control_type = SND_SOC_SPI;
spi_set_drvdata(spi, wm8985);
@@ -1117,8 +1117,8 @@ static __devinit int wm8985_i2c_probe(struct i2c_client *i2c,
int ret;
wm8985 = kzalloc(sizeof *wm8985, GFP_KERNEL);
- if (IS_ERR(wm8985))
- return PTR_ERR(wm8985);
+ if (!wm8985)
+ return -ENOMEM;
wm8985->control_type = SND_SOC_I2C;
i2c_set_clientdata(i2c, wm8985);
4
3
Hi all,
I've just acquired myself a HDSP9632 and noticed what I think is a
missing feature from the drivers (compared to Windows, at least): the
ability to set the headphones to "mute", in addition to -6dB and -12dB
of gain. I would find this feature useful.
Is there a reason it is missing or has it just been overlooked? Or,
alternatively, am I doing something stupid?
I'm using the alsa that comes with kernel 2.6.36-rc5 (I think it is
1.0.21?).
Thanks a lot,
Matt
2
2

11 Oct '10
BugLink: https://bugs.launchpad.net/bugs/656625
Add clause for handling Acer Aspire 8943G's subwoofer as additional
speaker pin for automuting.
Reported-by: RussianNeuroMancer
Cc: stable(a)kernel.org
Signed-off-by: Daniel T Chen <crimsun(a)ubuntu.com>
Signed-off-by: David Henningsson <david.henningsson(a)canonical.com>
---
sound/pci/hda/patch_realtek.c | 8 ++++++++
1 files changed, 8 insertions(+), 0 deletions(-)
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index b4e0959..c41ac30 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -19233,10 +19233,17 @@ static void alc662_auto_init(struct hda_codec *codec)
}
enum {
+ ALC662_FIXUP_ASPIRE,
ALC662_FIXUP_IDEAPAD,
};
static const struct alc_fixup alc662_fixups[] = {
+ [ALC662_FIXUP_ASPIRE] = {
+ .pins = (const struct alc_pincfg[]) {
+ { 0x15, 0x99130112 }, /* subwoofer */
+ { }
+ }
+ },
[ALC662_FIXUP_IDEAPAD] = {
.pins = (const struct alc_pincfg[]) {
{ 0x17, 0x99130112 }, /* subwoofer */
@@ -19246,6 +19253,7 @@ static const struct alc_fixup alc662_fixups[] = {
};
static struct snd_pci_quirk alc662_fixup_tbl[] = {
+ SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE),
SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo Ideapad Y550P", ALC662_FIXUP_IDEAPAD),
SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Ideapad Y550", ALC662_FIXUP_IDEAPAD),
{}
--
1.7.0.4
--------------050408050300090409070003--
1
0

10 Oct '10
Hello,
This series adds AC97 audio support for Cirrus Logic EP93xx family SoCs. Example
machine driver is for Simplemachines Sim.One (which is the only hardware that I
have which has AC97 codec).
The first patch is a bugfix for the DMA code. Without the patch audio DMA
transfers may corrupt if playing application is killed while playing. This
results weird noise playback when application is started again. I would like
Ryan Mallon to confirm that this is indeed correct fix and if possible to check
that I2S transfers still work after this patch is applied.
Please review.
Changes to previous revision:
- patches are taken from the correct branch so they should apply on top
of latest mainline
- increased cold reset sleep time
Thanks,
MW
Mika Westerberg (4):
ARM: ep93xx: DMA: fix channel_disable
ASoC: add ep93xx AC97 audio driver
ARM: ep93xx: add AC97 platform support
ASoC: ep93xx: add Simplemachines Sim.One AC97 audio support
arch/arm/mach-ep93xx/core.c | 32 ++
arch/arm/mach-ep93xx/dma-m2p.c | 2 +-
arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h | 1 +
arch/arm/mach-ep93xx/include/mach/platform.h | 1 +
arch/arm/mach-ep93xx/simone.c | 1 +
sound/soc/ep93xx/Kconfig | 17 +-
sound/soc/ep93xx/Makefile | 4 +
sound/soc/ep93xx/ep93xx-ac97.c | 476 +++++++++++++++++++++++
sound/soc/ep93xx/ep93xx-ac97.h | 17 +
sound/soc/ep93xx/simone.c | 80 ++++
10 files changed, 629 insertions(+), 2 deletions(-)
create mode 100644 sound/soc/ep93xx/ep93xx-ac97.c
create mode 100644 sound/soc/ep93xx/ep93xx-ac97.h
create mode 100644 sound/soc/ep93xx/simone.c
1
4
Hi,
I wanted to set my input
sources and control volume through the mixer api from a 'C' code. I am
required to do this without using alsa utils. Please guide me as to how I
can set my input source to say 'Mic' and also adjust say Front Right
channel volume.
It would also be nice if there was a mini
tutorial on the alsa page which explains how to do this basic stuff.
Thanks
and Regards,
Chandrashekhar
1
0

[alsa-devel] [PATCH] alsaucm: Report failure to set a device due to missing verb setup
by Mark Brown 10 Oct '10
by Mark Brown 10 Oct '10
10 Oct '10
Signed-off-by: Mark Brown <broonie(a)opensource.wolfsonmicro.com>
---
alsaucm/usecase.c | 4 +++-
1 files changed, 3 insertions(+), 1 deletions(-)
diff --git a/alsaucm/usecase.c b/alsaucm/usecase.c
index 2db26f1..d1420c0 100644
--- a/alsaucm/usecase.c
+++ b/alsaucm/usecase.c
@@ -94,8 +94,10 @@ static int list_verb_device_status(snd_use_case_mgr_t *uc_mgr)
int i, enabled, num;
verb = snd_use_case_get_verb(uc_mgr);
- if (verb == NULL)
+ if (verb == NULL) {
+ printf(" no verb currently enabled.\n");
return -ENODEV;
+ }
num = snd_use_case_get_device_list(uc_mgr, verb, &device_list);
if (num <= 0) {
--
1.7.1
2
1

[alsa-devel] [PATCH] ASoC: Use delayed work for debounce of GPIO based jacks
by Mark Brown 10 Oct '10
by Mark Brown 10 Oct '10
10 Oct '10
Rather than block the workqueue by sleeping to do the debounce use delayed
work to implement the debounce time. This should also mean that we extend
the debounce time on each new bounce, potentially allowing shorter debounce
times for clean insertions.
Signed-off-by: Mark Brown <broonie(a)opensource.wolfsonmicro.com>
---
This is completely untested as I do not have any systems to hand which
can make use of this functionality but I believe it should work - I've
CCed a couple of the OMAP people since they seem to be the main users.
include/sound/soc.h | 2 +-
sound/soc/soc-jack.c | 11 +++++------
2 files changed, 6 insertions(+), 7 deletions(-)
diff --git a/include/sound/soc.h b/include/sound/soc.h
index 493b3a4..4fb079e 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -385,7 +385,7 @@ struct snd_soc_jack_gpio {
int invert;
int debounce_time;
struct snd_soc_jack *jack;
- struct work_struct work;
+ struct delayed_work work;
int (*jack_status_check)(void);
};
diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c
index 8862770..8a0a920 100644
--- a/sound/soc/soc-jack.c
+++ b/sound/soc/soc-jack.c
@@ -188,9 +188,6 @@ static void snd_soc_jack_gpio_detect(struct snd_soc_jack_gpio *gpio)
int enable;
int report;
- if (gpio->debounce_time > 0)
- mdelay(gpio->debounce_time);
-
enable = gpio_get_value(gpio->gpio);
if (gpio->invert)
enable = !enable;
@@ -211,7 +208,8 @@ static irqreturn_t gpio_handler(int irq, void *data)
{
struct snd_soc_jack_gpio *gpio = data;
- schedule_work(&gpio->work);
+ schedule_delayed_work(&gpio->work,
+ msecs_to_jiffies(gpio->debounce_time));
return IRQ_HANDLED;
}
@@ -221,7 +219,7 @@ static void gpio_work(struct work_struct *work)
{
struct snd_soc_jack_gpio *gpio;
- gpio = container_of(work, struct snd_soc_jack_gpio, work);
+ gpio = container_of(work, struct snd_soc_jack_gpio, work.work);
snd_soc_jack_gpio_detect(gpio);
}
@@ -262,7 +260,7 @@ int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count,
if (ret)
goto err;
- INIT_WORK(&gpios[i].work, gpio_work);
+ INIT_DELAYED_WORK(&gpios[i].work, gpio_work);
gpios[i].jack = jack;
ret = request_irq(gpio_to_irq(gpios[i].gpio),
@@ -312,6 +310,7 @@ void snd_soc_jack_free_gpios(struct snd_soc_jack *jack, int count,
gpio_unexport(gpios[i].gpio);
#endif
free_irq(gpio_to_irq(gpios[i].gpio), &gpios[i]);
+ cancel_delayed_work_sync(&gpios[i].work);
gpio_free(gpios[i].gpio);
gpios[i].jack = NULL;
}
--
1.7.1
3
3

[alsa-devel] [PATCH] ASoC: omap: Remove needless prints from machine drivers
by Jarkko Nikula 10 Oct '10
by Jarkko Nikula 10 Oct '10
10 Oct '10
It is currently completely normal to execute these machine drivers code on
different boards if the kernel includes support for multiple boards so no
error message should be printed if the machine_is_xxx does not match with
the machine driver.
Therefore remove these pr_err and pr_debug prints in those cases.
Signed-off-by: Jarkko Nikula <jhnikula(a)gmail.com>
---
sound/soc/omap/am3517evm.c | 4 +---
sound/soc/omap/igep0020.c | 4 +---
sound/soc/omap/omap2evm.c | 4 +---
sound/soc/omap/omap3beagle.c | 4 +---
sound/soc/omap/omap3evm.c | 4 +---
sound/soc/omap/sdp3430.c | 4 +---
sound/soc/omap/sdp4430.c | 4 +---
sound/soc/omap/zoom2.c | 4 +---
8 files changed, 8 insertions(+), 24 deletions(-)
diff --git a/sound/soc/omap/am3517evm.c b/sound/soc/omap/am3517evm.c
index 68bd902..979dd50 100644
--- a/sound/soc/omap/am3517evm.c
+++ b/sound/soc/omap/am3517evm.c
@@ -157,10 +157,8 @@ static int __init am3517evm_soc_init(void)
{
int ret;
- if (!machine_is_omap3517evm()) {
- pr_err("Not OMAP3517 / AM3517 EVM!\n");
+ if (!machine_is_omap3517evm())
return -ENODEV;
- }
pr_info("OMAP3517 / AM3517 EVM SoC init\n");
am3517evm_snd_device = platform_device_alloc("soc-audio", -1);
diff --git a/sound/soc/omap/igep0020.c b/sound/soc/omap/igep0020.c
index d296cfc..fd3a40f 100644
--- a/sound/soc/omap/igep0020.c
+++ b/sound/soc/omap/igep0020.c
@@ -101,10 +101,8 @@ static int __init igep2_soc_init(void)
{
int ret;
- if (!machine_is_igep0020()) {
- pr_debug("Not IGEP v2!\n");
+ if (!machine_is_igep0020())
return -ENODEV;
- }
printk(KERN_INFO "IGEP v2 SoC init\n");
igep2_snd_device = platform_device_alloc("soc-audio", -1);
diff --git a/sound/soc/omap/omap2evm.c b/sound/soc/omap/omap2evm.c
index 38cd189..cf3fc8a 100644
--- a/sound/soc/omap/omap2evm.c
+++ b/sound/soc/omap/omap2evm.c
@@ -103,10 +103,8 @@ static int __init omap2evm_soc_init(void)
{
int ret;
- if (!machine_is_omap2evm()) {
- pr_debug("Not omap2evm!\n");
+ if (!machine_is_omap2evm())
return -ENODEV;
- }
printk(KERN_INFO "omap2evm SoC init\n");
omap2evm_snd_device = platform_device_alloc("soc-audio", -1);
diff --git a/sound/soc/omap/omap3beagle.c b/sound/soc/omap/omap3beagle.c
index 7c11e1a..e56832b 100644
--- a/sound/soc/omap/omap3beagle.c
+++ b/sound/soc/omap/omap3beagle.c
@@ -112,10 +112,8 @@ static int __init omap3beagle_soc_init(void)
{
int ret;
- if (!(machine_is_omap3_beagle() || machine_is_devkit8000())) {
- pr_debug("Not OMAP3 Beagle or Devkit8000!\n");
+ if (!(machine_is_omap3_beagle() || machine_is_devkit8000()))
return -ENODEV;
- }
pr_info("OMAP3 Beagle/Devkit8000 SoC init\n");
omap3beagle_snd_device = platform_device_alloc("soc-audio", -1);
diff --git a/sound/soc/omap/omap3evm.c b/sound/soc/omap/omap3evm.c
index 1ac5bab..810f1e3 100644
--- a/sound/soc/omap/omap3evm.c
+++ b/sound/soc/omap/omap3evm.c
@@ -99,10 +99,8 @@ static int __init omap3evm_soc_init(void)
{
int ret;
- if (!machine_is_omap3evm()) {
- pr_err("Not OMAP3 EVM!\n");
+ if (!machine_is_omap3evm())
return -ENODEV;
- }
pr_info("OMAP3 EVM SoC init\n");
omap3evm_snd_device = platform_device_alloc("soc-audio", -1);
diff --git a/sound/soc/omap/sdp3430.c b/sound/soc/omap/sdp3430.c
index 76ce77b..07fbcf7 100644
--- a/sound/soc/omap/sdp3430.c
+++ b/sound/soc/omap/sdp3430.c
@@ -296,10 +296,8 @@ static int __init sdp3430_soc_init(void)
int ret;
u8 pin_mux;
- if (!machine_is_omap_3430sdp()) {
- pr_debug("Not SDP3430!\n");
+ if (!machine_is_omap_3430sdp())
return -ENODEV;
- }
printk(KERN_INFO "SDP3430 SoC init\n");
sdp3430_snd_device = platform_device_alloc("soc-audio", -1);
diff --git a/sound/soc/omap/sdp4430.c b/sound/soc/omap/sdp4430.c
index 62f6a62..4b4463d 100644
--- a/sound/soc/omap/sdp4430.c
+++ b/sound/soc/omap/sdp4430.c
@@ -186,10 +186,8 @@ static int __init sdp4430_soc_init(void)
{
int ret;
- if (!machine_is_omap_4430sdp()) {
- pr_debug("Not SDP4430!\n");
+ if (!machine_is_omap_4430sdp())
return -ENODEV;
- }
printk(KERN_INFO "SDP4430 SoC init\n");
sdp4430_snd_device = platform_device_alloc("soc-audio", -1);
diff --git a/sound/soc/omap/zoom2.c b/sound/soc/omap/zoom2.c
index 338dc95..718031e 100644
--- a/sound/soc/omap/zoom2.c
+++ b/sound/soc/omap/zoom2.c
@@ -245,10 +245,8 @@ static int __init zoom2_soc_init(void)
{
int ret;
- if (!machine_is_omap_zoom2()) {
- pr_debug("Not Zoom2!\n");
+ if (!machine_is_omap_zoom2())
return -ENODEV;
- }
printk(KERN_INFO "Zoom2 SoC init\n");
zoom2_snd_device = platform_device_alloc("soc-audio", -1);
--
1.7.1
3
2
It's not needed with multi-component.
Signed-off-by: Mark Brown <broonie(a)opensource.wolfsonmicro.com>
---
sound/soc/codecs/cs4270.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c
index 5fd8e0d..6d4bdc6 100644
--- a/sound/soc/codecs/cs4270.c
+++ b/sound/soc/codecs/cs4270.c
@@ -518,7 +518,7 @@ static struct snd_soc_dai_ops cs4270_dai_ops = {
.digital_mute = cs4270_dai_mute,
};
-struct snd_soc_dai_driver cs4270_dai = {
+static struct snd_soc_dai_driver cs4270_dai = {
.name = "cs4270-hifi",
.playback = {
.stream_name = "Playback",
--
1.7.1
3
4

Re: [alsa-devel] [PATCH 1/2] ASoC: Shrink code size for WM8962 register defaults table
by Liam Girdwood 10 Oct '10
by Liam Girdwood 10 Oct '10
10 Oct '10
On Thu, 2010-10-07 at 20:50 -0700, Mark Brown wrote:
> Dramatically reduce the code size for the WM8962 register defaults
> table
> by switching to explicitly initialise only defined registers, relying
> on
> static defaulting to zero for the overwelming bulk of the register
> map.
>
> Similar treatement for the register access table will come later and
> will
> produce a similarly dramatic code size shrink.
>
> Signed-off-by: Mark Brown <broonie(a)opensource.wolfsonmicro.com>
Both
Acked-by: Liam Girdwood <lrg(a)slimlogic.co.uk>
--
Freelance Developer, SlimLogic Ltd
ASoC and Voltage Regulator Maintainer.
http://www.slimlogic.co.uk
1
0
ALSA Developers,
Proposed change to amidi: allow data from stdin.
A simple addition to amidi to allow midi commands from standard input
would facilitate a MIDI-over-IP setup in which amidi and netcat together
could send/receive raw MIDI over a network, or the internet. I'm
thinking of something as simple as
nc host port | amidi -p hw:1,0
to receive raw midi from someone on the internet and pipe the midi
commands to one of my tone generators. This would further the effort to
realize the "online jamming" idea with MIDI.
Currently, amidi will read raw MIDI commands from a file using the "-s"
flag. I have tried this with a named pipe, but amidi tries to get the
file size causing an error. Perhaps fixing this would be one solution.
Al Steffens
apsteffe(a)netwood.net
1
0

[alsa-devel] bug report: aloop: potential signedness bug in loopback_prepare()
by Dan Carpenter 09 Oct '10
by Dan Carpenter 09 Oct '10
09 Oct '10
Hi Jaroslav,
sound/drivers/aloop.c +287 loopback_prepare(10)
warn: bogus compare against zero: 'bps'
282 unsigned int bps, salign;
283
284 salign = (snd_pcm_format_width(runtime->format) *
285 runtime->channels) / 8;
286 bps = salign * runtime->rate;
287 if (bps <= 0 || salign <= 0)
^^^^^^^^^^^^^^^^^^^^^^^
Both "bps" and "salign" are unsigned and are never less than
zero. Should this just be checking for == 0? Or was the check
supposed to catch integer overflows?
288 return -EINVAL;
289
regards,
dan carpenter
2
2

[alsa-devel] [PATCH v1 4/6] davinci: SOUND support for Omapl138-Hawkboard
by vm.rod25@gmail.com 09 Oct '10
by vm.rod25@gmail.com 09 Oct '10
09 Oct '10
From: Victor Rodriguez <victor.rodriguez(a)sasken.com>
This patch adds sound support for the Hawkboard-L138 system
It is under the machine name "omapl138_hawkboard".
This system is based on the da850 davinci CPU architecture.
Signed-off-by: Victor Rodriguez <victor.rodriguez(a)sasken.com>
---
Notes:
This patch works with da8xx_omapl_defconfig
In order to test ALSA utils select in menuconfig like insmodule:
Sound card support --->
Advanced Linux Sound Architecture --->
ALSA for SoC audio support --->
SoC Audio for the TI DAVINCI chip
SoC Audio support for DA850/OMAP-L138 EVM/Hawkboard
arch/arm/mach-davinci/board-omapl138-hawk.c | 46 +++++++++++++++++++++++++++
arch/arm/mach-davinci/da850.c | 2 +-
2 files changed, 47 insertions(+), 1 deletions(-)
diff --git a/arch/arm/mach-davinci/board-omapl138-hawk.c b/arch/arm/mach-davinci/board-omapl138-hawk.c
index 01eef73..ba3718a 100644
--- a/arch/arm/mach-davinci/board-omapl138-hawk.c
+++ b/arch/arm/mach-davinci/board-omapl138-hawk.c
@@ -13,6 +13,7 @@
#include <linux/init.h>
#include <linux/console.h>
#include <linux/gpio.h>
+#include <linux/i2c.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -116,6 +117,37 @@ static struct edma_rsv_info *da850_edma_rsv[2] = {
&da850_edma_cc1_rsv,
};
+static struct i2c_board_info __initdata omapl138_hawk_i2c_devices[] = {
+ {
+ I2C_BOARD_INFO("tlv320aic3x", 0x18),
+ },
+};
+
+static struct davinci_i2c_platform_data omapl138_hawk_i2c_0_pdata = {
+ .bus_freq = 100, /* kHz */
+ .bus_delay = 0, /* usec */
+};
+
+/* davinci da850 evm audio machine driver */
+static u8 da850_iis_serializer_direction[] = {
+ INACTIVE_MODE, INACTIVE_MODE, INACTIVE_MODE, INACTIVE_MODE,
+ INACTIVE_MODE, INACTIVE_MODE, INACTIVE_MODE, INACTIVE_MODE,
+ INACTIVE_MODE, INACTIVE_MODE, INACTIVE_MODE, INACTIVE_MODE,
+ INACTIVE_MODE, TX_MODE, RX_MODE, INACTIVE_MODE,
+};
+
+static struct snd_platform_data omapl138_hawk_snd_data = {
+ .tx_dma_offset = 0x2000,
+ .rx_dma_offset = 0x2000,
+ .op_mode = DAVINCI_MCASP_IIS_MODE,
+ .num_serializer = ARRAY_SIZE(da850_iis_serializer_direction),
+ .tdm_slots = 2,
+ .serial_dir = da850_iis_serializer_direction,
+ .asp_chan_q = EVENTQ_1,
+ .version = MCASP_VERSION_2,
+ .txnumevt = 1,
+ .rxnumevt = 1,
+};
static struct davinci_uart_config omapl138_hawk_uart_config __initdata = {
.enabled_uarts = 0x7,
@@ -134,6 +166,20 @@ static __init void omapl138_hawk_init(void)
ret = omapl138_hawk_config_emac();
+ i2c_register_board_info(1, omapl138_hawk_i2c_devices,
+ ARRAY_SIZE(omapl138_hawk_i2c_devices));
+
+ ret = da8xx_register_i2c(0, &omapl138_hawk_i2c_0_pdata);
+ if (ret)
+ pr_warning("omapl138_hawk_init: "
+ "i2c0 registration failed: %d\n", ret);
+
+ ret = davinci_cfg_reg_list(da850_mcasp_pins);
+ if (ret)
+ pr_warning("omapl138_hawk_init: "
+ "mcasp mux setup failed: %d\n", ret);
+ da8xx_register_mcasp(0, &omapl138_hawk_snd_data);
+
ret = da8xx_register_watchdog();
if (ret)
pr_warning("omapl138_hawk_init: "
diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c
index 63916b9..f033a0a 100644
--- a/arch/arm/mach-davinci/da850.c
+++ b/arch/arm/mach-davinci/da850.c
@@ -591,7 +591,7 @@ const short da850_cpgmac_pins[] __initdata = {
const short da850_mcasp_pins[] __initdata = {
DA850_AHCLKX, DA850_ACLKX, DA850_AFSX,
DA850_AHCLKR, DA850_ACLKR, DA850_AFSR, DA850_AMUTE,
- DA850_AXR_11, DA850_AXR_12,
+ DA850_AXR_11, DA850_AXR_12, DA850_AXR_13, DA850_AXR_14,
-1
};
--
1.6.0.5
2
1

[alsa-devel] [PATCH v1 3/6] ASoC: davinci: ASoC support for Omapl138-Hawkboard
by vm.rod25@gmail.com 09 Oct '10
by vm.rod25@gmail.com 09 Oct '10
09 Oct '10
From: Victor Rodriguez <victor.rodriguez(a)sasken.com>
This patch adds ASoC support for the Hawkboard-L138 system
It is under the machine name "omapl138_hawkboard".
This system is based on the da850 davinci CPU architecture.
Signed-off-by: Victor Rodriguez <victor.rodriguez(a)sasken.com>
---
sound/soc/davinci/Kconfig | 5 +++--
sound/soc/davinci/davinci-evm.c | 6 ++++--
2 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/sound/soc/davinci/Kconfig b/sound/soc/davinci/Kconfig
index 6bbf001..d6cb394 100644
--- a/sound/soc/davinci/Kconfig
+++ b/sound/soc/davinci/Kconfig
@@ -76,8 +76,9 @@ config SND_DA830_SOC_EVM
DA830/OMAP-L137 EVM
config SND_DA850_SOC_EVM
- tristate "SoC Audio support for DA850/OMAP-L138 EVM"
- depends on SND_DAVINCI_SOC && MACH_DAVINCI_DA850_EVM
+ tristate "SoC Audio support for DA850/OMAP-L138 EVM/Hawkboard"
+ depends on SND_DAVINCI_SOC&& (MACH_DAVINCI_DA850_EVM \
+ || MACH_OMAPL138_HAWKBOARD)
select SND_DAVINCI_SOC_MCASP
select SND_SOC_TLV320AIC3X
help
diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c
index 97f74d6..73093eb 100644
--- a/sound/soc/davinci/davinci-evm.c
+++ b/sound/soc/davinci/davinci-evm.c
@@ -59,7 +59,8 @@ static int evm_hw_params(struct snd_pcm_substream *substream,
sysclk = 12288000;
else if (machine_is_davinci_da830_evm() ||
- machine_is_davinci_da850_evm())
+ machine_is_davinci_da850_evm() ||
+ machine_is_omapl138_hawkboard())
sysclk = 24576000;
else
@@ -311,7 +312,8 @@ static int __init evm_init(void)
} else if (machine_is_davinci_da830_evm()) {
evm_snd_dev_data = &da830_evm_snd_devdata;
index = 1;
- } else if (machine_is_davinci_da850_evm()) {
+ } else if (machine_is_davinci_da850_evm() ||
+ machine_is_omapl138_hawkboard()) {
evm_snd_dev_data = &da850_evm_snd_devdata;
index = 0;
} else
--
1.6.0.5
2
1
Good day
I'm new to this list (though I've done some searching, I'm sure I could have
missed something), so please bear with me.
I filed a bug report recently against Ubuntu with respect to the problem I'm
experiencing (as per the subject: jacking in my headphones doesn't mute the
speaker output) and was informed that the decision had been made upstream as
a design intention. I was linked off to:
http://mailman.alsa-project.org/pipermail/alsa-devel/2010-August/030071.html
with respect to the thread on this topic. I'd like to raise it again though,
perhaps as a configurable feature, for the following reasons:
1) headphones muting the speakers used to work some time ago (before Ubuntu
9.04, iirc), so we have an established user expectation even under Linux
distros.
2) headphones mute the built-in speakers of my laptop (windows and ubuntu)
-- why the inconsistent behaviour for a desktop? Just because the speakers
in the laptop are bolted into the frame of the machine?
3) Windows "gets it right": plugging in headphones mutes external speakers
-- it's convenient (Though I think you can disable that feature if you
want). I'm told by a person at work that his Mac does the same. Again, the
user expectation is unmet under a newish Linux distro.
4) The user expectation theory is held up by the number of bug reports
against this design choice on Ubuntu Launchpad alone (I haven't looked at
other bug lists). The average user is not expecting the current behaviour,
obviously
5) For people without hardware volume controls on their speakers, the
problem is exacerbated: instead of being able to plug in headphones to
disturb others around them less (ie: contain their music/noises), they have
to unplug their speakers too -- which may not be trivial since speakers are
normally plugged in at the back of the machine, not at the front where the
headphone jack would be found. On a machine in an enclosure, this is
especially troublesome.
So I'd really like to know if it would be possible to allow the behaviour
most users are expecting. Sometimes it's useful to be able to output to both
speakers and headphones, but I would say that the average user doesn't want
both at the same time.
-d
--
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
The competent programmer is fully aware of the limited size of his own
skull. He therefore approaches his task with full humility, and avoids
clever tricks like the plague.
- Djikstra.
3
6

[alsa-devel] [PATCH v1 4/6] davinci: SOUND support for Omapl138-Hawkboard
by vm.rod25@gmail.com 09 Oct '10
by vm.rod25@gmail.com 09 Oct '10
09 Oct '10
From: Victor Rodriguez <victor.rodriguez(a)sasken.com>
This patch adds sound support for the Hawkboard-L138 system
It is under the machine name "omapl138_hawkboard".
This system is based on the da850 davinci CPU architecture.
Signed-off-by: Victor Rodriguez <victor.rodriguez(a)sasken.com>
---
Notes:
This patch works with da8xx_omapl_defconfig
In order to test ALSA utils select in menuconfig like insmodule:
Sound card support --->
Advanced Linux Sound Architecture --->
ALSA for SoC audio support --->
SoC Audio for the TI DAVINCI chip
SoC Audio support for DA850/OMAP-L138 EVM/Hawkboard
arch/arm/mach-davinci/board-omapl138-hawk.c | 46 +++++++++++++++++++++++++++
arch/arm/mach-davinci/da850.c | 2 +-
2 files changed, 47 insertions(+), 1 deletions(-)
diff --git a/arch/arm/mach-davinci/board-omapl138-hawk.c b/arch/arm/mach-davinci/board-omapl138-hawk.c
index 01eef73..ba3718a 100644
--- a/arch/arm/mach-davinci/board-omapl138-hawk.c
+++ b/arch/arm/mach-davinci/board-omapl138-hawk.c
@@ -13,6 +13,7 @@
#include <linux/init.h>
#include <linux/console.h>
#include <linux/gpio.h>
+#include <linux/i2c.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -116,6 +117,37 @@ static struct edma_rsv_info *da850_edma_rsv[2] = {
&da850_edma_cc1_rsv,
};
+static struct i2c_board_info __initdata omapl138_hawk_i2c_devices[] = {
+ {
+ I2C_BOARD_INFO("tlv320aic3x", 0x18),
+ },
+};
+
+static struct davinci_i2c_platform_data omapl138_hawk_i2c_0_pdata = {
+ .bus_freq = 100, /* kHz */
+ .bus_delay = 0, /* usec */
+};
+
+/* davinci da850 evm audio machine driver */
+static u8 da850_iis_serializer_direction[] = {
+ INACTIVE_MODE, INACTIVE_MODE, INACTIVE_MODE, INACTIVE_MODE,
+ INACTIVE_MODE, INACTIVE_MODE, INACTIVE_MODE, INACTIVE_MODE,
+ INACTIVE_MODE, INACTIVE_MODE, INACTIVE_MODE, INACTIVE_MODE,
+ INACTIVE_MODE, TX_MODE, RX_MODE, INACTIVE_MODE,
+};
+
+static struct snd_platform_data omapl138_hawk_snd_data = {
+ .tx_dma_offset = 0x2000,
+ .rx_dma_offset = 0x2000,
+ .op_mode = DAVINCI_MCASP_IIS_MODE,
+ .num_serializer = ARRAY_SIZE(da850_iis_serializer_direction),
+ .tdm_slots = 2,
+ .serial_dir = da850_iis_serializer_direction,
+ .asp_chan_q = EVENTQ_1,
+ .version = MCASP_VERSION_2,
+ .txnumevt = 1,
+ .rxnumevt = 1,
+};
static struct davinci_uart_config omapl138_hawk_uart_config __initdata = {
.enabled_uarts = 0x7,
@@ -134,6 +166,20 @@ static __init void omapl138_hawk_init(void)
ret = omapl138_hawk_config_emac();
+ i2c_register_board_info(1, omapl138_hawk_i2c_devices,
+ ARRAY_SIZE(omapl138_hawk_i2c_devices));
+
+ ret = da8xx_register_i2c(0, &omapl138_hawk_i2c_0_pdata);
+ if (ret)
+ pr_warning("omapl138_hawk_init: "
+ "i2c0 registration failed: %d\n", ret);
+
+ ret = davinci_cfg_reg_list(da850_mcasp_pins);
+ if (ret)
+ pr_warning("omapl138_hawk_init: "
+ "mcasp mux setup failed: %d\n", ret);
+ da8xx_register_mcasp(0, &omapl138_hawk_snd_data);
+
ret = da8xx_register_watchdog();
if (ret)
pr_warning("omapl138_hawk_init: "
diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c
index 63916b9..f033a0a 100644
--- a/arch/arm/mach-davinci/da850.c
+++ b/arch/arm/mach-davinci/da850.c
@@ -591,7 +591,7 @@ const short da850_cpgmac_pins[] __initdata = {
const short da850_mcasp_pins[] __initdata = {
DA850_AHCLKX, DA850_ACLKX, DA850_AFSX,
DA850_AHCLKR, DA850_ACLKR, DA850_AFSR, DA850_AMUTE,
- DA850_AXR_11, DA850_AXR_12,
+ DA850_AXR_11, DA850_AXR_12, DA850_AXR_13, DA850_AXR_14,
-1
};
--
1.6.0.5
1
0

[alsa-devel] [PATCH v1 3/6] ASoC: davinci: ASoC support for Omapl138-Hawkboard
by vm.rod25@gmail.com 09 Oct '10
by vm.rod25@gmail.com 09 Oct '10
09 Oct '10
From: Victor Rodriguez <victor.rodriguez(a)sasken.com>
This patch adds ASoC support for the Hawkboard-L138 system
It is under the machine name "omapl138_hawkboard".
This system is based on the da850 davinci CPU architecture.
Signed-off-by: Victor Rodriguez <victor.rodriguez(a)sasken.com>
---
sound/soc/davinci/Kconfig | 5 +++--
sound/soc/davinci/davinci-evm.c | 6 ++++--
2 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/sound/soc/davinci/Kconfig b/sound/soc/davinci/Kconfig
index 6bbf001..d6cb394 100644
--- a/sound/soc/davinci/Kconfig
+++ b/sound/soc/davinci/Kconfig
@@ -76,8 +76,9 @@ config SND_DA830_SOC_EVM
DA830/OMAP-L137 EVM
config SND_DA850_SOC_EVM
- tristate "SoC Audio support for DA850/OMAP-L138 EVM"
- depends on SND_DAVINCI_SOC && MACH_DAVINCI_DA850_EVM
+ tristate "SoC Audio support for DA850/OMAP-L138 EVM/Hawkboard"
+ depends on SND_DAVINCI_SOC&& (MACH_DAVINCI_DA850_EVM \
+ || MACH_OMAPL138_HAWKBOARD)
select SND_DAVINCI_SOC_MCASP
select SND_SOC_TLV320AIC3X
help
diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c
index 97f74d6..73093eb 100644
--- a/sound/soc/davinci/davinci-evm.c
+++ b/sound/soc/davinci/davinci-evm.c
@@ -59,7 +59,8 @@ static int evm_hw_params(struct snd_pcm_substream *substream,
sysclk = 12288000;
else if (machine_is_davinci_da830_evm() ||
- machine_is_davinci_da850_evm())
+ machine_is_davinci_da850_evm() ||
+ machine_is_omapl138_hawkboard())
sysclk = 24576000;
else
@@ -311,7 +312,8 @@ static int __init evm_init(void)
} else if (machine_is_davinci_da830_evm()) {
evm_snd_dev_data = &da830_evm_snd_devdata;
index = 1;
- } else if (machine_is_davinci_da850_evm()) {
+ } else if (machine_is_davinci_da850_evm() ||
+ machine_is_omapl138_hawkboard()) {
evm_snd_dev_data = &da850_evm_snd_devdata;
index = 0;
} else
--
1.6.0.5
1
0

09 Oct '10
Mostly for the benefit of alsaucm which passes the specified verb (if
any) straight through, but the robustness fix seems better here.
Signed-off-by: Mark Brown <broonie(a)opensource.wolfsonmicro.com>
---
src/use-case.c | 3 +++
1 files changed, 3 insertions(+), 0 deletions(-)
diff --git a/src/use-case.c b/src/use-case.c
index b45fe1f..ee44275 100644
--- a/src/use-case.c
+++ b/src/use-case.c
@@ -2786,6 +2786,9 @@ int snd_use_case_set_verb(snd_use_case_mgr_t *uc_mgr,
{
int i = 0, ret = -EINVAL, inactive = 0;
+ if (!verb_name)
+ return -EINVAL;
+
pthread_mutex_lock(&uc_mgr->mutex);
uc_dbg("uc_mgr %p, verb_name %s", uc_mgr, verb_name);
--
1.7.1
1
0

[alsa-devel] [PATCH 1/2] mfd: Factor out WM831x I2C I/O from the core driver
by Mark Brown 08 Oct '10
by Mark Brown 08 Oct '10
08 Oct '10
In preparation for the addition of SPI support for the WM831x move the I2C
specific code into a separate file with a separate Kconfig option so the
I2C support can be excluded from the build.
Also update the 1133-EV1 PMIC module support for SMDK6410 to use the new
symbol.
Signed-off-by: Mark Brown <broonie(a)opensource.wolfsonmicro.com>
---
arch/arm/mach-s3c64xx/Kconfig | 1 +
drivers/mfd/Kconfig | 14 +++--
drivers/mfd/Makefile | 1 +
drivers/mfd/wm831x-core.c | 138 +------------------------------------
drivers/mfd/wm831x-i2c.c | 143 +++++++++++++++++++++++++++++++++++++++
include/linux/mfd/wm831x/core.h | 12 +++
6 files changed, 170 insertions(+), 139 deletions(-)
create mode 100644 drivers/mfd/wm831x-i2c.c
diff --git a/arch/arm/mach-s3c64xx/Kconfig b/arch/arm/mach-s3c64xx/Kconfig
index 1e4d78a..546db5c 100644
--- a/arch/arm/mach-s3c64xx/Kconfig
+++ b/arch/arm/mach-s3c64xx/Kconfig
@@ -185,6 +185,7 @@ config SMDK6410_WM1192_EV1
select REGULATOR_WM831X
select S3C24XX_GPIO_EXTRA64
select MFD_WM831X
+ select MFD_WM831X_I2C
help
The Wolfson Microelectronics 1192-EV1 is a WM831x based PMIC
daughtercard for the Samsung SMDK6410 reference platform.
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 6c6b9f0..608a277 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -315,14 +315,18 @@ config MFD_WM8400
the functionality of the device.
config MFD_WM831X
- bool "Support Wolfson Microelectronics WM831x/2x PMICs"
+ bool
+ depends on GENERIC_HARDIRQS
+
+config MFD_WM831X_I2C
+ bool "Support Wolfson Microelectronics WM831x/2x PMICs with I2C"
select MFD_CORE
depends on I2C=y && GENERIC_HARDIRQS
help
- Support for the Wolfson Microelecronics WM831x and WM832x PMICs.
- This driver provides common support for accessing the device,
- additional drivers must be enabled in order to use the
- functionality of the device.
+ Support for the Wolfson Microelecronics WM831x and WM832x PMICs
+ when controlled using I2C. This driver provides common support
+ for accessing the device, additional drivers must be enabled in
+ order to use the functionality of the device.
config MFD_WM8350
bool
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 70b2699..c9ef41b 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -24,6 +24,7 @@ obj-$(CONFIG_MFD_TC6393XB) += tc6393xb.o tmio_core.o
obj-$(CONFIG_MFD_WM8400) += wm8400-core.o
wm831x-objs := wm831x-core.o wm831x-irq.o wm831x-otp.o
obj-$(CONFIG_MFD_WM831X) += wm831x.o
+obj-$(CONFIG_MFD_WM831X_I2C) += wm831x-i2c.o
wm8350-objs := wm8350-core.o wm8350-regmap.o wm8350-gpio.o
wm8350-objs += wm8350-irq.o
obj-$(CONFIG_MFD_WM8350) += wm8350.o
diff --git a/drivers/mfd/wm831x-core.c b/drivers/mfd/wm831x-core.c
index ad36579..7d2563f 100644
--- a/drivers/mfd/wm831x-core.c
+++ b/drivers/mfd/wm831x-core.c
@@ -14,7 +14,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/i2c.h>
#include <linux/bcd.h>
#include <linux/delay.h>
#include <linux/mfd/core.h>
@@ -90,15 +89,6 @@ int wm831x_isinkv_values[WM831X_ISINK_MAX_ISEL + 1] = {
};
EXPORT_SYMBOL_GPL(wm831x_isinkv_values);
-enum wm831x_parent {
- WM8310 = 0x8310,
- WM8311 = 0x8311,
- WM8312 = 0x8312,
- WM8320 = 0x8320,
- WM8321 = 0x8321,
- WM8325 = 0x8325,
-};
-
static int wm831x_reg_locked(struct wm831x *wm831x, unsigned short reg)
{
if (!wm831x->locked)
@@ -1447,7 +1437,7 @@ static struct mfd_cell backlight_devs[] = {
/*
* Instantiate the generic non-control parts of the device.
*/
-static int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
+int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
{
struct wm831x_pdata *pdata = wm831x->dev->platform_data;
int rev;
@@ -1673,7 +1663,7 @@ err:
return ret;
}
-static void wm831x_device_exit(struct wm831x *wm831x)
+void wm831x_device_exit(struct wm831x *wm831x)
{
wm831x_otp_exit(wm831x);
mfd_remove_devices(wm831x->dev);
@@ -1683,7 +1673,7 @@ static void wm831x_device_exit(struct wm831x *wm831x)
kfree(wm831x);
}
-static int wm831x_device_suspend(struct wm831x *wm831x)
+int wm831x_device_suspend(struct wm831x *wm831x)
{
int reg, mask;
@@ -1719,126 +1709,6 @@ static int wm831x_device_suspend(struct wm831x *wm831x)
return 0;
}
-static int wm831x_i2c_read_device(struct wm831x *wm831x, unsigned short reg,
- int bytes, void *dest)
-{
- struct i2c_client *i2c = wm831x->control_data;
- int ret;
- u16 r = cpu_to_be16(reg);
-
- ret = i2c_master_send(i2c, (unsigned char *)&r, 2);
- if (ret < 0)
- return ret;
- if (ret != 2)
- return -EIO;
-
- ret = i2c_master_recv(i2c, dest, bytes);
- if (ret < 0)
- return ret;
- if (ret != bytes)
- return -EIO;
- return 0;
-}
-
-/* Currently we allocate the write buffer on the stack; this is OK for
- * small writes - if we need to do large writes this will need to be
- * revised.
- */
-static int wm831x_i2c_write_device(struct wm831x *wm831x, unsigned short reg,
- int bytes, void *src)
-{
- struct i2c_client *i2c = wm831x->control_data;
- unsigned char msg[bytes + 2];
- int ret;
-
- reg = cpu_to_be16(reg);
- memcpy(&msg[0], ®, 2);
- memcpy(&msg[2], src, bytes);
-
- ret = i2c_master_send(i2c, msg, bytes + 2);
- if (ret < 0)
- return ret;
- if (ret < bytes + 2)
- return -EIO;
-
- return 0;
-}
-
-static int wm831x_i2c_probe(struct i2c_client *i2c,
- const struct i2c_device_id *id)
-{
- struct wm831x *wm831x;
-
- wm831x = kzalloc(sizeof(struct wm831x), GFP_KERNEL);
- if (wm831x == NULL)
- return -ENOMEM;
-
- i2c_set_clientdata(i2c, wm831x);
- wm831x->dev = &i2c->dev;
- wm831x->control_data = i2c;
- wm831x->read_dev = wm831x_i2c_read_device;
- wm831x->write_dev = wm831x_i2c_write_device;
-
- return wm831x_device_init(wm831x, id->driver_data, i2c->irq);
-}
-
-static int wm831x_i2c_remove(struct i2c_client *i2c)
-{
- struct wm831x *wm831x = i2c_get_clientdata(i2c);
-
- wm831x_device_exit(wm831x);
-
- return 0;
-}
-
-static int wm831x_i2c_suspend(struct i2c_client *i2c, pm_message_t mesg)
-{
- struct wm831x *wm831x = i2c_get_clientdata(i2c);
-
- return wm831x_device_suspend(wm831x);
-}
-
-static const struct i2c_device_id wm831x_i2c_id[] = {
- { "wm8310", WM8310 },
- { "wm8311", WM8311 },
- { "wm8312", WM8312 },
- { "wm8320", WM8320 },
- { "wm8321", WM8321 },
- { "wm8325", WM8325 },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, wm831x_i2c_id);
-
-
-static struct i2c_driver wm831x_i2c_driver = {
- .driver = {
- .name = "wm831x",
- .owner = THIS_MODULE,
- },
- .probe = wm831x_i2c_probe,
- .remove = wm831x_i2c_remove,
- .suspend = wm831x_i2c_suspend,
- .id_table = wm831x_i2c_id,
-};
-
-static int __init wm831x_i2c_init(void)
-{
- int ret;
-
- ret = i2c_add_driver(&wm831x_i2c_driver);
- if (ret != 0)
- pr_err("Failed to register wm831x I2C driver: %d\n", ret);
-
- return ret;
-}
-subsys_initcall(wm831x_i2c_init);
-
-static void __exit wm831x_i2c_exit(void)
-{
- i2c_del_driver(&wm831x_i2c_driver);
-}
-module_exit(wm831x_i2c_exit);
-
-MODULE_DESCRIPTION("I2C support for the WM831X AudioPlus PMIC");
+MODULE_DESCRIPTION("Core support for the WM831X AudioPlus PMIC");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Mark Brown");
diff --git a/drivers/mfd/wm831x-i2c.c b/drivers/mfd/wm831x-i2c.c
new file mode 100644
index 0000000..156b198
--- /dev/null
+++ b/drivers/mfd/wm831x-i2c.c
@@ -0,0 +1,143 @@
+/*
+ * wm831x-i2c.c -- I2C access for Wolfson WM831x PMICs
+ *
+ * Copyright 2009,2010 Wolfson Microelectronics PLC.
+ *
+ * Author: Mark Brown <broonie(a)opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/mfd/core.h>
+#include <linux/slab.h>
+
+#include <linux/mfd/wm831x/core.h>
+#include <linux/mfd/wm831x/pdata.h>
+
+static int wm831x_i2c_read_device(struct wm831x *wm831x, unsigned short reg,
+ int bytes, void *dest)
+{
+ struct i2c_client *i2c = wm831x->control_data;
+ int ret;
+ u16 r = cpu_to_be16(reg);
+
+ ret = i2c_master_send(i2c, (unsigned char *)&r, 2);
+ if (ret < 0)
+ return ret;
+ if (ret != 2)
+ return -EIO;
+
+ ret = i2c_master_recv(i2c, dest, bytes);
+ if (ret < 0)
+ return ret;
+ if (ret != bytes)
+ return -EIO;
+ return 0;
+}
+
+/* Currently we allocate the write buffer on the stack; this is OK for
+ * small writes - if we need to do large writes this will need to be
+ * revised.
+ */
+static int wm831x_i2c_write_device(struct wm831x *wm831x, unsigned short reg,
+ int bytes, void *src)
+{
+ struct i2c_client *i2c = wm831x->control_data;
+ unsigned char msg[bytes + 2];
+ int ret;
+
+ reg = cpu_to_be16(reg);
+ memcpy(&msg[0], ®, 2);
+ memcpy(&msg[2], src, bytes);
+
+ ret = i2c_master_send(i2c, msg, bytes + 2);
+ if (ret < 0)
+ return ret;
+ if (ret < bytes + 2)
+ return -EIO;
+
+ return 0;
+}
+
+static int wm831x_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct wm831x *wm831x;
+
+ wm831x = kzalloc(sizeof(struct wm831x), GFP_KERNEL);
+ if (wm831x == NULL)
+ return -ENOMEM;
+
+ i2c_set_clientdata(i2c, wm831x);
+ wm831x->dev = &i2c->dev;
+ wm831x->control_data = i2c;
+ wm831x->read_dev = wm831x_i2c_read_device;
+ wm831x->write_dev = wm831x_i2c_write_device;
+
+ return wm831x_device_init(wm831x, id->driver_data, i2c->irq);
+}
+
+static int wm831x_i2c_remove(struct i2c_client *i2c)
+{
+ struct wm831x *wm831x = i2c_get_clientdata(i2c);
+
+ wm831x_device_exit(wm831x);
+
+ return 0;
+}
+
+static int wm831x_i2c_suspend(struct i2c_client *i2c, pm_message_t mesg)
+{
+ struct wm831x *wm831x = i2c_get_clientdata(i2c);
+
+ return wm831x_device_suspend(wm831x);
+}
+
+static const struct i2c_device_id wm831x_i2c_id[] = {
+ { "wm8310", WM8310 },
+ { "wm8311", WM8311 },
+ { "wm8312", WM8312 },
+ { "wm8320", WM8320 },
+ { "wm8321", WM8321 },
+ { "wm8325", WM8325 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, wm831x_i2c_id);
+
+
+static struct i2c_driver wm831x_i2c_driver = {
+ .driver = {
+ .name = "wm831x",
+ .owner = THIS_MODULE,
+ },
+ .probe = wm831x_i2c_probe,
+ .remove = wm831x_i2c_remove,
+ .suspend = wm831x_i2c_suspend,
+ .id_table = wm831x_i2c_id,
+};
+
+static int __init wm831x_i2c_init(void)
+{
+ int ret;
+
+ ret = i2c_add_driver(&wm831x_i2c_driver);
+ if (ret != 0)
+ pr_err("Failed to register wm831x I2C driver: %d\n", ret);
+
+ return ret;
+}
+subsys_initcall(wm831x_i2c_init);
+
+static void __exit wm831x_i2c_exit(void)
+{
+ i2c_del_driver(&wm831x_i2c_driver);
+}
+module_exit(wm831x_i2c_exit);
diff --git a/include/linux/mfd/wm831x/core.h b/include/linux/mfd/wm831x/core.h
index eb5bd4e..a1239c4 100644
--- a/include/linux/mfd/wm831x/core.h
+++ b/include/linux/mfd/wm831x/core.h
@@ -238,6 +238,15 @@ struct regulator_dev;
#define WM831X_NUM_IRQ_REGS 5
+enum wm831x_parent {
+ WM8310 = 0x8310,
+ WM8311 = 0x8311,
+ WM8312 = 0x8312,
+ WM8320 = 0x8320,
+ WM8321 = 0x8321,
+ WM8325 = 0x8325,
+};
+
struct wm831x {
struct mutex io_lock;
@@ -285,6 +294,9 @@ int wm831x_set_bits(struct wm831x *wm831x, unsigned short reg,
int wm831x_bulk_read(struct wm831x *wm831x, unsigned short reg,
int count, u16 *buf);
+int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq);
+void wm831x_device_exit(struct wm831x *wm831x);
+int wm831x_device_suspend(struct wm831x *wm831x);
int wm831x_irq_init(struct wm831x *wm831x, int irq);
void wm831x_irq_exit(struct wm831x *wm831x);
--
1.7.1
1
1
Hi,
I'm struggling with mic+headphone issues in Samsung R540. I posted below
message to alsa-user, but couldn't get any response. I'll be really
appreciated for any help. BTW, I can provide any other information to
fix the problem. (Even remote access maybe.) I'm really in need to solve
this issue.
Regards.
On Tue, 05 Oct 2010, Volkan YAZICI <yazicivo(a)ttmail.com> writes:
> This is a damn Samsung R540 notebook with kernel 2.6.5.37 and ALSA
> 1.0.23 installed. (See here[1] for details.) I couldn't get mic and
> headphone work. Setting model=basic brings much more configurations to
> the alsamixer screen and I can hear my sound and that ssshhhh noise from
> the speakers (which means mic directs sound to speakers somehow), but I
> couldn't make arecord to record anything. In any configuration
> combination I tried, I couldn't make headphone work. Any ideas?
>
> [1] http://www.alsa-project.org/db/?f=3571a643ab90e53100fa319edaa32b8b0dabfd00
2
1

08 Oct '10
Hi,
I'm building and installing the alsa libs for an embedded system.
My current process runs as follows:
1) the alsa-lib package is crosscompiled on my PC host system (x86);
2) the alsa-lib package is installed on a special prefix (say '/tmp/dest') on the host system;
3) some installed files are copied from the dir. '/tmp/dest' to the final target root filesystem
tree (say '/tmp/emb_root');
Now there are a couple of details that do not work with this process:
in point 1) I configure the alsa-lib package with the option --prefix=/tmp/dest because I want
to install the package there and use it later to compile other packages against it (alsa-utils for
example); at the same time I want also to use the alsa libs in my target system but it is not
possible because, at runtime, the init functions in the libasound.so looks for its configuration
file under '/tmp/dest/share/alsa/alsa.conf'!
The same problem happens with the plugins dir.
I tracked back this problems to the fact that, in the configure.in, the variable ALSA_CONFIG_DIR is
used both to be substituted in the Makefile.am's (AC_SUBST(ALSA_CONFIG_DIR)) and to define the
preprocessor constant in the 'include/config.h' (C_DEFINE_UNQUOTED(ALSA_CONFIG_DIR,...)). There is
currently no way to have two independent values for the two cases.
My current 'best' solution is to patch the header 'include/config.h' after running the configure script.
Is there any standard solution to this without patching the configure results ?
Regards,
-Simon.
1
0
From: Alexander Sverdlin <subaparts(a)yandex.ru>
Added support for Cirrus CS4271 codec to ALSA SoC subsystem.
Applies on: 2.6.36-rc6
Signed-off-by: Alexander Sverdlin <subaparts(a)yandex.ru>
---
sound/soc/codecs/Kconfig | 3 +
sound/soc/codecs/Makefile | 2 +
sound/soc/codecs/cs4271.c | 840 +++++++++++++++++++++++++++++++++++++++++++++
sound/soc/codecs/cs4271.h | 27 ++
4 files changed, 872 insertions(+), 0 deletions(-)
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 83f5c67..608cf88 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -138,6 +138,9 @@ config SND_SOC_CS4270_VD33_ERRATA
bool
depends on SND_SOC_CS4270
+config SND_SOC_CS4271
+ tristate
+
config SND_SOC_CX20442
tristate
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 5352409..d7dd676 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -11,6 +11,7 @@ snd-soc-ak4671-objs := ak4671.o
snd-soc-cq93vc-objs := cq93vc.o
snd-soc-cs42l51-objs := cs42l51.o
snd-soc-cs4270-objs := cs4270.o
+snd-soc-cs4271-objs := cs4271.o
snd-soc-cx20442-objs := cx20442.o
snd-soc-da7210-objs := da7210.o
snd-soc-l3-objs := l3.o
@@ -79,6 +80,7 @@ obj-$(CONFIG_SND_SOC_AK4671) += snd-soc-ak4671.o
obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.o
obj-$(CONFIG_SND_SOC_CS42L51) += snd-soc-cs42l51.o
obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o
+obj-$(CONFIG_SND_SOC_CS4271) += snd-soc-cs4271.o
obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o
obj-$(CONFIG_SND_SOC_DA7210) += snd-soc-da7210.o
obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o
diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c
new file mode 100644
index 0000000..305281a
--- /dev/null
+++ b/sound/soc/codecs/cs4271.c
@@ -0,0 +1,840 @@
+/*
+ * CS4271 ALSA SoC (ASoC) codec driver
+ *
+ * Copyright (c) 2010 Alexander Sverdlin <subaparts(a)yandex.ru>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ *
+ * This is an ASoC device driver for the Cirrus Logic CS4271 codec.
+ *
+ * Current features/limitations:
+ *
+ * - I2C and SPI are supported
+ * - Software mode is supported. Stand-alone mode is not supported
+ * - Support for master and slave mode
+ * - The machine driver's 'startup' function must call
+ * cs4271_set_dai_sysclk() with the value of MCLK
+ * - Only I2S and left-justified modes are supported
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <linux/i2c.h>
+#include <linux/spi/spi.h>
+
+#include "cs4271.h"
+
+#define CS4271_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+/*
+ * CS4271 registers addresses
+ * High byte represents SPI address (0x10) + write command (0)
+ */
+#define CS4271_MODE1 0x2001 /* Mode Control 1 */
+#define CS4271_DACCTL 0x2002 /* DAC Control */
+#define CS4271_DACVOL 0x2003 /* DAC Volume & Mixing Control */
+#define CS4271_VOLA 0x2004 /* DAC Channel A Volume Control */
+#define CS4271_VOLB 0x2005 /* DAC Channel B Volume Control */
+#define CS4271_ADCCTL 0x2006 /* ADC Control */
+#define CS4271_MODE2 0x2007 /* Mode Control 2 */
+#define CS4271_CHIPID 0x2008 /* Chip ID */
+
+#define CS4271_FIRSTREG CS4271_MODE1
+#define CS4271_LASTREG CS4271_MODE2
+#define CS4271_NR_REGS ((CS4271_LASTREG & 0xFF) + 1)
+
+/* Bit masks for the CS4271 registers */
+#define CS4271_MODE1_FUNCMODE_MASK 0xC0
+#define CS4271_MODE1_FUNCMODE_1X 0x00
+#define CS4271_MODE1_FUNCMODE_2X 0x80
+#define CS4271_MODE1_FUNCMODE_4X 0xC0
+
+#define CS4271_MODE1_DIV_MASK 0x30
+#define CS4271_MODE1_DIV_1 0x00
+#define CS4271_MODE1_DIV_15 0x10
+#define CS4271_MODE1_DIV_2 0x20
+#define CS4271_MODE1_DIV_3 0x30
+
+#define CS4271_MODE1_MASTER 0x08
+
+#define CS4271_MODE1_DAC_DIF_MASK 0x07
+#define CS4271_MODE1_DAC_DIF_LJ 0x00
+#define CS4271_MODE1_DAC_DIF_I2S 0x01
+#define CS4271_MODE1_DAC_DIF_RJ16 0x02
+#define CS4271_MODE1_DAC_DIF_RJ24 0x03
+#define CS4271_MODE1_DAC_DIF_RJ20 0x04
+#define CS4271_MODE1_DAC_DIF_RJ18 0x05
+
+#define CS4271_DACCTL_AMUTE 0x80
+#define CS4271_DACCTL_IF_SLOW 0x40
+
+#define CS4271_DACCTL_DEM_MASK 0x30
+#define CS4271_DACCTL_DEM_DIS 0x00
+#define CS4271_DACCTL_DEM_441 0x10
+#define CS4271_DACCTL_DEM_48 0x20
+#define CS4271_DACCTL_DEM_32 0x30
+
+#define CS4271_DACCTL_SVRU 0x08
+#define CS4271_DACCTL_SRD 0x04
+#define CS4271_DACCTL_INVA 0x02
+#define CS4271_DACCTL_INVB 0x01
+
+#define CS4271_DACVOL_BEQUA 0x40
+#define CS4271_DACVOL_SOFT 0x20
+#define CS4271_DACVOL_ZEROC 0x10
+
+#define CS4271_DACVOL_ATAPI_MASK 0x0F
+#define CS4271_DACVOL_ATAPI_M_M 0x00
+#define CS4271_DACVOL_ATAPI_M_BR 0x01
+#define CS4271_DACVOL_ATAPI_M_BL 0x02
+#define CS4271_DACVOL_ATAPI_M_BLR2 0x03
+#define CS4271_DACVOL_ATAPI_AR_M 0x04
+#define CS4271_DACVOL_ATAPI_AR_BR 0x05
+#define CS4271_DACVOL_ATAPI_AR_BL 0x06
+#define CS4271_DACVOL_ATAPI_AR_BLR2 0x07
+#define CS4271_DACVOL_ATAPI_AL_M 0x08
+#define CS4271_DACVOL_ATAPI_AL_BR 0x09
+#define CS4271_DACVOL_ATAPI_AL_BL 0x0A
+#define CS4271_DACVOL_ATAPI_AL_BLR2 0x0B
+#define CS4271_DACVOL_ATAPI_ALR2_M 0x0C
+#define CS4271_DACVOL_ATAPI_ALR2_BR 0x0D
+#define CS4271_DACVOL_ATAPI_ALR2_BL 0x0E
+#define CS4271_DACVOL_ATAPI_ALR2_BLR2 0x0F
+
+#define CS4271_VOLA_MUTE 0x80
+#define CS4271_VOLA_VOL_MASK 0x7F
+#define CS4271_VOLB_MUTE 0x80
+#define CS4271_VOLB_VOL_MASK 0x7F
+
+#define CS4271_ADCCTL_DITHER16 0x20
+
+#define CS4271_ADCCTL_ADC_DIF_MASK 0x10
+#define CS4271_ADCCTL_ADC_DIF_LJ 0x00
+#define CS4271_ADCCTL_ADC_DIF_I2S 0x10
+
+#define CS4271_ADCCTL_MUTEA 0x08
+#define CS4271_ADCCTL_MUTEB 0x04
+#define CS4271_ADCCTL_HPFDA 0x02
+#define CS4271_ADCCTL_HPFDB 0x01
+
+#define CS4271_MODE2_LOOP 0x10
+#define CS4271_MODE2_MUTECAEQUB 0x08
+#define CS4271_MODE2_FREEZE 0x04
+#define CS4271_MODE2_CPEN 0x02
+#define CS4271_MODE2_PDN 0x01
+
+#define CS4271_CHIPID_PART_MASK 0xF0
+#define CS4271_CHIPID_REV_MASK 0x0F
+
+/* Private data for the CS4271 */
+struct cs4271_private {
+ struct snd_soc_codec codec;
+ u8 reg_cache[CS4271_NR_REGS];
+ unsigned int mclk; /* Input frequency of the MCLK pin */
+ unsigned int mode; /* The mode (I2S or left-justified) */
+ unsigned int slave_mode;
+};
+
+/*
+ * struct cs4271_mode_ratios - clock ratio tables
+ * @ratio: the ratio of MCLK to the sample rate
+ * @speed_mode: the Speed Mode bits to set in the Mode Control register for
+ * this ratio
+ * @mclk_master: the Ratio Select bits to set in the Mode Control register
+ * for this ratio while in Master mode
+ * @mclk_slave: the Ratio Select bits to set in the Mode Control register
+ * for this ratio while in Slave mode
+ *
+ * This table is used to determine how to program the Mode Control register
+ * It is also used by cs4271_set_dai_sysclk() to tell ALSA which sampling
+ * rates the CS4271 currently supports.
+ */
+struct cs4271_mode_ratios {
+ unsigned int ratio;
+ u8 speed_mode;
+ u8 mclk_master;
+ u8 mclk_slave;
+};
+
+static struct cs4271_mode_ratios cs4271_mode_ratios[] = {
+ {64, CS4271_MODE1_FUNCMODE_4X, CS4271_MODE1_DIV_1, CS4271_MODE1_DIV_1},
+ {96, CS4271_MODE1_FUNCMODE_4X, CS4271_MODE1_DIV_15, CS4271_MODE1_DIV_1},
+ {128, CS4271_MODE1_FUNCMODE_2X, CS4271_MODE1_DIV_1, CS4271_MODE1_DIV_1},
+ {192, CS4271_MODE1_FUNCMODE_2X, CS4271_MODE1_DIV_15, CS4271_MODE1_DIV_1},
+ {256, CS4271_MODE1_FUNCMODE_1X, CS4271_MODE1_DIV_1, CS4271_MODE1_DIV_1},
+ {384, CS4271_MODE1_FUNCMODE_1X, CS4271_MODE1_DIV_15, CS4271_MODE1_DIV_1},
+ {512, CS4271_MODE1_FUNCMODE_1X, CS4271_MODE1_DIV_2, CS4271_MODE1_DIV_1},
+ {768, CS4271_MODE1_FUNCMODE_1X, CS4271_MODE1_DIV_3, CS4271_MODE1_DIV_3},
+ {1024, CS4271_MODE1_FUNCMODE_1X, CS4271_MODE1_DIV_3, CS4271_MODE1_DIV_3}
+};
+
+/* The number of MCLK/LRCK ratios supported by the CS4271 */
+#define NUM_MCLK_RATIOS ARRAY_SIZE(cs4271_mode_ratios)
+
+/*
+ * cs4271_set_dai_sysclk - determine the CS4271 MCLK rate.
+ * @codec_dai: the codec DAI
+ * @clk_id: the clock ID (ignored)
+ * @freq: the MCLK input frequency
+ * @dir: the clock direction (ignored)
+ *
+ * This function is used to tell the codec driver what the input MCLK
+ * frequency is.
+ *
+ * The value of MCLK is used to determine which sample rates are supported
+ * by the CS4271. The ratio of MCLK / Fs must be equal to one of
+ * supported values - 64, 96, 128, 192, 256, 384, 512, 768 and
+ * for Slave mode 1024. 256 is the best value and widely recommended.
+ *
+ * This function must be called by the machine driver's 'startup' function,
+ * otherwise the list of supported sample rates will not be available in
+ * time for ALSA.
+ *
+ * For setups with variable MCLKs, pass 0 as 'freq' argument. This will cause
+ * theoretically possible sample rates to be enabled. Call it again with a
+ * proper value set one the external clock is set (most probably you would do
+ * that from a machine's driver 'hw_param' hook.
+ */
+static int cs4271_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 cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
+ unsigned int rates = 0;
+ unsigned int rate_min = -1;
+ unsigned int rate_max = 0;
+ unsigned int i;
+
+ cs4271->mclk = freq;
+
+ if (cs4271->mclk) {
+ for (i = 0; i < NUM_MCLK_RATIOS; i++) {
+ unsigned int rate = freq / cs4271_mode_ratios[i].ratio;
+ rates |= snd_pcm_rate_to_rate_bit(rate);
+ if (rate < rate_min)
+ rate_min = rate;
+ if (rate > rate_max)
+ rate_max = rate;
+ }
+
+ rates &= ~SNDRV_PCM_RATE_KNOT;
+
+ if (!rates) {
+ dev_err(codec->dev, "could not find a valid sample rate\n");
+ return -EINVAL;
+ }
+ } else {
+ /* enable all possible rates */
+ rates = SNDRV_PCM_RATE_8000_96000;
+ rate_min = 8000;
+ rate_max = 96000;
+ }
+
+ codec_dai->playback.rates = rates;
+ codec_dai->playback.rate_min = rate_min;
+ codec_dai->playback.rate_max = rate_max;
+
+ codec_dai->capture.rates = rates;
+ codec_dai->capture.rate_min = rate_min;
+ codec_dai->capture.rate_max = rate_max;
+
+ return 0;
+}
+
+/*
+ * cs4271_set_dai_fmt - configure the codec for the selected audio format
+ * @codec_dai: the codec DAI
+ * @format: a SND_SOC_DAIFMT_x value indicating the data format
+ *
+ * Currently, this function only supports SND_SOC_DAIFMT_I2S and
+ * SND_SOC_DAIFMT_LEFT_J.
+ */
+static int cs4271_set_dai_fmt(struct snd_soc_dai *codec_dai,
+ unsigned int format)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
+ int ret = 0;
+
+ /* set DAI format */
+ switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ case SND_SOC_DAIFMT_LEFT_J:
+ cs4271->mode = format & SND_SOC_DAIFMT_FORMAT_MASK;
+ break;
+ default:
+ dev_err(codec->dev, "invalid dai format\n");
+ ret = -EINVAL;
+ }
+
+ /* set master/slave audio interface */
+ switch (format & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ cs4271->slave_mode = 1;
+ break;
+ case SND_SOC_DAIFMT_CBM_CFM:
+ cs4271->slave_mode = 0;
+ break;
+ default:
+ /* all other modes are unsupported by the hardware */
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+/*
+ * cs4271_hw_params - program the CS4271 with the given hardware parameters.
+ * @substream: the audio stream
+ * @params: the hardware parameters to set
+ * @dai: the SOC DAI (ignored)
+ */
+static int cs4271_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 cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
+ int ret;
+ unsigned int i, ratio;
+
+ /* Figure out which MCLK/LRCK ratio to use */
+ ratio = cs4271->mclk / params_rate(params);
+
+ for (i = 0; i < NUM_MCLK_RATIOS; i++)
+ if (cs4271_mode_ratios[i].ratio == ratio)
+ break;
+
+ if ((i == NUM_MCLK_RATIOS) || ((ratio == 1024) && (!cs4271->slave_mode))) {
+ dev_err(codec->dev, "could not find matching ratio\n");
+ return -EINVAL;
+ }
+
+ /* Set the sample rate */
+ ret = snd_soc_read(codec, CS4271_MODE1);
+ ret &= ~(CS4271_MODE1_FUNCMODE_MASK | CS4271_MODE1_DIV_MASK | CS4271_MODE1_DAC_DIF_MASK);
+ ret |= cs4271_mode_ratios[i].speed_mode;
+
+ if (cs4271->slave_mode) {
+ ret &= ~CS4271_MODE1_MASTER;
+ ret |= cs4271_mode_ratios[i].mclk_slave;
+ }
+ else {
+ ret |= CS4271_MODE1_MASTER;
+ ret |= cs4271_mode_ratios[i].mclk_master;
+ }
+
+ switch (cs4271->mode) {
+ case SND_SOC_DAIFMT_I2S:
+ ret |= CS4271_MODE1_DAC_DIF_I2S;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ ret |= CS4271_MODE1_DAC_DIF_LJ;
+ break;
+ default:
+ dev_err(codec->dev, "unknown dai format\n");
+ return -EINVAL;
+ }
+
+ ret = snd_soc_write(codec, CS4271_MODE1, ret);
+ if (ret < 0) {
+ dev_err(codec->dev, "Codec write failed\n");
+ return ret;
+ }
+
+ /* Set the DAI format */
+ ret = snd_soc_read(codec, CS4271_ADCCTL);
+ ret &= ~CS4271_ADCCTL_ADC_DIF_MASK;
+ ret |= (cs4271->mode == SND_SOC_DAIFMT_I2S) ? CS4271_ADCCTL_ADC_DIF_I2S : CS4271_ADCCTL_ADC_DIF_LJ;
+ ret = snd_soc_write(codec, CS4271_ADCCTL, ret);
+ if (ret < 0)
+ dev_err(codec->dev, "Codec write failed\n");
+
+ return ret;
+}
+
+/*
+ * cs4271_dai_mute - enable/disable the CS4271 external mute
+ * @dai: the SOC DAI
+ * @mute: 0 = disable mute, 1 = enable mute
+ */
+static int cs4271_dai_mute(struct snd_soc_dai *dai, int mute)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ int ret1, ret2;
+
+ ret1 = snd_soc_read(codec, CS4271_VOLA);
+ ret2 = snd_soc_read(codec, CS4271_VOLB);
+
+ if (mute) {
+ ret1 |= CS4271_VOLA_MUTE;
+ ret2 |= CS4271_VOLB_MUTE;
+ }
+ else {
+ ret1 &= ~(CS4271_VOLA_MUTE);
+ ret2 &= ~(CS4271_VOLB_MUTE);
+ }
+
+ ret1 = snd_soc_write(codec, CS4271_VOLA, ret1);
+ if (ret1)
+ return ret1;
+ return snd_soc_write(codec, CS4271_VOLB, ret2);
+}
+
+/*
+ * A list of non-DAPM controls that the CS4271 supports
+ */
+static const char *cs4271_de_texts[] = {"None", "44.1KHz", "48KHz", "32KHz"};
+static const struct soc_enum cs4271_de_enum =
+ SOC_ENUM_SINGLE(CS4271_DACCTL, 4, 4, cs4271_de_texts);
+
+static const struct snd_kcontrol_new cs4271_snd_controls[] = {
+ SOC_DOUBLE_R("Master Playback Volume", CS4271_VOLA, CS4271_VOLB, 0, 0x7F, 1),
+ SOC_SINGLE("Digital Loopback Switch", CS4271_MODE2, 4, 1, 0),
+ SOC_SINGLE("Soft Ramp Switch", CS4271_DACVOL, 5, 1, 0),
+ SOC_SINGLE("Zero Cross Switch", CS4271_DACVOL, 4, 1, 0),
+ SOC_ENUM("De-emphasis filter", cs4271_de_enum),
+ SOC_SINGLE("Auto-Mute Switch", CS4271_DACCTL, 7, 1, 0),
+ SOC_SINGLE("Slow Roll Off Filter Switch", CS4271_DACCTL, 6, 1, 0),
+ SOC_SINGLE("Soft Volume Ramp-Up Switch", CS4271_DACCTL, 3, 1, 0),
+ SOC_SINGLE("Soft Ramp-Down Switch", CS4271_DACCTL, 2, 1, 0),
+ SOC_SINGLE("Left Channel Inversion Switch", CS4271_DACCTL, 1, 1, 0),
+ SOC_SINGLE("Right Channel Inversion Switch", CS4271_DACCTL, 0, 1, 0),
+ SOC_DOUBLE("Master Capture Switch", CS4271_ADCCTL, 3, 2, 1, 1),
+ SOC_SINGLE("Dither 16-Bit Data Switch", CS4271_ADCCTL, 5, 1, 0),
+ SOC_DOUBLE("High Pass Filter Switch", CS4271_ADCCTL, 1, 0, 1, 1),
+ SOC_DOUBLE_R("Master Playback Switch", CS4271_VOLA, CS4271_VOLB, 7, 1, 1),
+};
+
+/*
+ * cs4271_codec - global variable to store codec for the ASoC probe function
+ *
+ * For now, we also only allow cs4271_i2c_probe() to be run once. That means
+ * that we do not support more than one cs4271 device in the system, at least
+ * for now.
+ */
+static struct snd_soc_codec *cs4271_codec;
+
+static struct snd_soc_dai_ops cs4271_dai_ops = {
+ .hw_params = cs4271_hw_params,
+ .set_sysclk = cs4271_set_dai_sysclk,
+ .set_fmt = cs4271_set_dai_fmt,
+ .digital_mute = cs4271_dai_mute,
+};
+
+struct snd_soc_dai cs4271_dai = {
+ .name = "cs4271",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = 0,
+ .formats = CS4271_FORMATS,
+ },
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = 0,
+ .formats = CS4271_FORMATS,
+ },
+ .ops = &cs4271_dai_ops,
+};
+EXPORT_SYMBOL_GPL(cs4271_dai);
+
+/*
+ * This function writes all writeble registers from cache to codec.
+ * It's used te setup initial config and restore after suspend.
+ */
+static int cs4271_write_cache(struct snd_soc_codec *codec)
+{
+ int i, ret;
+
+ for (i = CS4271_FIRSTREG; i <= CS4271_LASTREG; i++) {
+ ret = snd_soc_write(codec, i, snd_soc_read(codec, i));
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+/*
+ * cs4271_probe - ASoC probe function
+ * @pdev: platform device
+ *
+ * This function is called when ASoC has all the pieces it needs to
+ * instantiate a sound driver.
+ * This function actually configure the codec, so MCLK must be enabled
+ * already and reset must be inactive. This is probably done by
+ * machine drivers.
+ */
+static int cs4271_probe(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_codec *codec = cs4271_codec;
+ int ret;
+ u8 *cache;
+
+ /* Turn control port on and set power down mode for a while */
+ ret = snd_soc_write(codec, CS4271_MODE2, CS4271_MODE2_CPEN | CS4271_MODE2_PDN);
+ if (ret < 0) {
+ dev_err(codec->dev, "Codec write failed\n");
+ return ret;
+ }
+
+ cache = codec->reg_cache;
+ /*
+ * Almost default power up configuration of codec, except auto
+ * mute feature which is turned off.
+ * We need to mask register address, because it contains
+ * SPI address also.
+ */
+ cache[CS4271_MODE1 & 0xFF] = 0x00;
+ cache[CS4271_DACCTL & 0xFF] = 0x00;
+ cache[CS4271_DACVOL & 0xFF] = CS4271_DACVOL_ATAPI_AL_BR;
+ cache[CS4271_VOLA & 0xFF] = 0x00;
+ cache[CS4271_VOLB & 0xFF] = 0x00;
+ cache[CS4271_ADCCTL & 0xFF] = 0x00;
+ cache[CS4271_MODE2 & 0xFF] = CS4271_MODE2_CPEN;
+
+ ret = cs4271_write_cache(codec);
+ if (ret < 0) {
+ dev_err(codec->dev, "Cache write failed\n");
+ return ret;
+ }
+
+ /* Connect the codec to the socdev. snd_soc_new_pcms() needs this. */
+ socdev->card->codec = 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\n");
+ return ret;
+ }
+
+ /* Add the non-DAPM controls */
+ ret = snd_soc_add_controls(codec, cs4271_snd_controls,
+ ARRAY_SIZE(cs4271_snd_controls));
+ if (ret < 0) {
+ dev_err(codec->dev, "failed to add controls\n");
+ goto error_free_pcms;
+ }
+
+ return 0;
+
+error_free_pcms:
+ snd_soc_free_pcms(socdev);
+
+ return ret;
+}
+
+/*
+ * cs4271_remove - ASoC remove function
+ * @pdev: platform device
+ *
+ * This function is the counterpart to cs4271_probe().
+ */
+static int cs4271_remove(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+
+ snd_soc_free_pcms(socdev);
+
+ return 0;
+};
+
+#ifdef CONFIG_PM
+
+/*
+ * The codec's own power saving features are enabled in the suspend callback,
+ * and all registers are written back to the hardware when resuming.
+ */
+static int cs4271_soc_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+ struct snd_soc_codec *codec = cs4271_codec;
+ struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
+ int ret;
+
+ ret = snd_soc_read(codec, CS4271_MODE2);
+ ret |= CS4271_MODE2_PDN;
+
+ return snd_soc_write(codec, CS4271_MODE2, ret);
+}
+
+static int cs4271_soc_resume(struct platform_device *pdev)
+{
+ struct snd_soc_codec *codec = cs4271_codec;
+ struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
+ int ret;
+
+ ret = cs4271_write_cache(codec);
+ if (ret < 0) {
+ dev_err(pdev, "Cache write failed\n");
+ return ret;
+ }
+
+ /* ... then disable the power-down bits */
+ ret = snd_soc_read(codec, CS4271_MODE2);
+ ret &= ~CS4271_MODE2_PDN;
+
+ return snd_soc_write(codec, CS4271_MODE2, ret);
+}
+#else
+#define cs4271_soc_suspend NULL
+#define cs4271_soc_resume NULL
+#endif /* CONFIG_PM */
+
+/*
+ * ASoC codec device structure
+ *
+ * Assign this variable to the codec_dev field of the machine driver's
+ * snd_soc_device structure.
+ */
+struct snd_soc_codec_device soc_codec_device_cs4271 = {
+ .probe = cs4271_probe,
+ .remove = cs4271_remove,
+ .suspend = cs4271_soc_suspend,
+ .resume = cs4271_soc_resume,
+};
+EXPORT_SYMBOL_GPL(soc_codec_device_cs4271);
+
+/*
+ * Serial bus independent probe function. It's called both for
+ * I2C and SPI -connected codecs.
+ */
+static int cs4271_bus_probe(struct device *dev, void *ctrl_data, int bus_type)
+{
+ struct cs4271_private *cs4271;
+ struct snd_soc_codec *codec;
+ int ret;
+
+ /*
+ * For now, we only support one cs4271 device in the system. See the
+ * comment for cs4271_codec.
+ */
+ if (cs4271_codec) {
+ dev_err(dev, "Only one CS4271 per board allowed\n");
+ return -ENODEV;
+ }
+
+ /*
+ * Allocate enough space for the snd_soc_codec structure
+ * and our private data together.
+ */
+ cs4271 = kzalloc(sizeof(struct cs4271_private), GFP_KERNEL);
+ if (!cs4271) {
+ dev_err(dev, "Could not allocate codec\n");
+ return -ENOMEM;
+ }
+
+ dev_set_drvdata(dev, cs4271);
+
+ codec = &cs4271->codec;
+ mutex_init(&codec->mutex);
+ INIT_LIST_HEAD(&codec->dapm_widgets);
+ INIT_LIST_HEAD(&codec->dapm_paths);
+
+ codec->dev = dev;
+ codec->name = "CS4271";
+ codec->owner = THIS_MODULE;
+ codec->dai = &cs4271_dai;
+ codec->num_dai = 1;
+ snd_soc_codec_set_drvdata(codec, cs4271);
+ codec->control_data = ctrl_data;
+ codec->reg_cache = cs4271->reg_cache;
+ codec->reg_cache_size = ARRAY_SIZE(cs4271->reg_cache);
+
+ /*
+ * In case of I2C, chip address specified in board data.
+ * So cache IO operations use 8 bit codec register address.
+ * In case of SPI, chip address and register address
+ * passed together as 16 bit value.
+ * Anyway, register address is masked with 0xFF inside
+ * soc_cache code.
+ */
+ ret = snd_soc_codec_set_cache_io(codec,
+ (bus_type == SND_SOC_SPI) ? 16 : 8, 8, bus_type);
+ if (ret) {
+ dev_err(dev, "Failed to set cache I/O: %d\n", ret);
+ goto error_free_codec;
+ }
+
+ /*
+ * Initialize the DAI. Normally, we'd prefer to have a kmalloc'd DAI
+ * structure for each CS4271 device, but the machine driver needs to
+ * have a pointer to the DAI structure, so for now it must be a global
+ * variable.
+ */
+ cs4271_dai.dev = dev;
+
+ /*
+ * Register the DAI. If all the other ASoC driver have already
+ * registered, then this will call our probe function, so
+ * cs4271_codec needs to be ready.
+ */
+ cs4271_codec = codec;
+
+ ret = snd_soc_register_codec(codec);
+ if (ret) {
+ dev_err(dev, "Failed to register codec: %d\n", ret);
+ goto error_free_codec;
+ }
+
+ ret = snd_soc_register_dai(&cs4271_dai);
+ if (ret) {
+ dev_err(dev, "failed to register DAI\n");
+ goto error_reg;
+ }
+
+ return 0;
+
+error_reg:
+ snd_soc_unregister_codec(codec);
+error_free_codec:
+ kfree(cs4271);
+ cs4271_codec = NULL;
+ cs4271_dai.dev = NULL;
+
+ return ret;
+}
+
+static int cs4271_bus_remove(struct device *dev)
+{
+ struct cs4271_private *cs4271 = dev_get_drvdata(dev);
+
+ snd_soc_unregister_dai(&cs4271_dai);
+ kfree(cs4271);
+ cs4271_codec = NULL;
+ cs4271_dai.dev = NULL;
+
+ return 0;
+}
+
+
+#if defined(CONFIG_SPI_MASTER)
+
+static struct spi_device_id cs4271_spi_id[] = {
+ {"cs4271", 0},
+ {}
+};
+MODULE_DEVICE_TABLE(spi, cs4271_spi_id);
+
+static int __devinit cs4271_spi_probe(struct spi_device *spi)
+{
+ return cs4271_bus_probe(&spi->dev, spi, SND_SOC_SPI);
+}
+
+static int __devexit cs4271_spi_remove(struct spi_device *spi)
+{
+ return cs4271_bus_remove(&spi->dev);
+}
+
+static struct spi_driver cs4271_spi_driver = {
+ .driver = {
+ .name = "cs4271",
+ .owner = THIS_MODULE,
+ },
+ .id_table = cs4271_spi_id,
+ .probe = cs4271_spi_probe,
+ .remove = __devexit_p(cs4271_spi_remove),
+};
+
+#endif
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+/*
+ * cs4271_id - I2C device IDs supported by this driver
+ */
+static struct i2c_device_id cs4271_i2c_id[] = {
+ {"cs4271", 0},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, cs4271_i2c_id);
+
+static int __devinit cs4271_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ return cs4271_bus_probe(&client->dev, client, SND_SOC_I2C);
+}
+
+static int __devexit cs4271_i2c_remove(struct i2c_client *client)
+{
+ return cs4271_bus_remove(&client->dev);
+}
+
+/*
+ * cs4271_i2c_driver - I2C device identification
+ *
+ * This structure tells the I2C subsystem how to identify and support a
+ * given I2C device type.
+ */
+static struct i2c_driver cs4271_i2c_driver = {
+ .driver = {
+ .name = "cs4271",
+ .owner = THIS_MODULE,
+ },
+ .id_table = cs4271_i2c_id,
+ .probe = cs4271_i2c_probe,
+ .remove = __devexit_p(cs4271_i2c_remove),
+};
+
+#endif
+
+/*
+ * We only register our serial bus driver here without
+ * assignment to particular chip. So if any of the below
+ * fails, there is some problem with I2C or SPI subsystem.
+ * In most cases this module will be compiled with support
+ * of only one serial bus.
+ */
+static int __init cs4271_modinit(void)
+{
+ int ret;
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+ ret = i2c_add_driver(&cs4271_i2c_driver);
+ if (ret) {
+ pr_err("Failed to register CS4271 I2C driver: %d\n", ret);
+ return ret;
+ }
+#endif
+
+#if defined(CONFIG_SPI_MASTER)
+ ret = spi_register_driver(&cs4271_spi_driver);
+ if (ret) {
+ pr_err("Failed to register CS4271 SPI driver: %d\n", ret);
+ return ret;
+ }
+#endif
+
+ return 0;
+}
+module_init(cs4271_modinit);
+
+static void __exit cs4271_modexit(void)
+{
+#if defined(CONFIG_SPI_MASTER)
+ spi_unregister_driver(&cs4271_spi_driver);
+#endif
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+ i2c_del_driver(&cs4271_i2c_driver);
+#endif
+}
+module_exit(cs4271_modexit);
+
+MODULE_AUTHOR("Alexander Sverdlin <subaparts(a)yandex.ru>");
+MODULE_DESCRIPTION("Cirrus Logic CS4271 ALSA SoC Codec Driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs4271.h b/sound/soc/codecs/cs4271.h
new file mode 100644
index 0000000..7cf6af2
--- /dev/null
+++ b/sound/soc/codecs/cs4271.h
@@ -0,0 +1,27 @@
+/*
+ * Cirrus Logic CS4271 ALSA SoC Codec Driver
+ *
+ * Copyright (c) 2010 Alexander Sverdlin <subaparts(a)yandex.ru>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#ifndef _CS4271_H
+#define _CS4271_H
+
+/*
+ * The ASoC codec DAI structure for the CS4271. Assign this structure to
+ * the .codec_dai field of your machine driver's snd_soc_dai_link structure.
+ */
+extern struct snd_soc_dai cs4271_dai;
+
+/*
+ * The ASoC codec device structure for the CS4271. Assign this structure
+ * to the .codec_dev field of your machine driver's snd_soc_device
+ * structure.
+ */
+extern struct snd_soc_codec_device soc_codec_device_cs4271;
+
+#endif
3
7
Hello.
I have thinkpad x201i.
Hardware and software info located at:
http://www.alsa-project.org/db/?f=fe6a745fc2fa12cd082914aac2a9d810e978cb55
In mixer Master & PCM is set to 100%.
But sound volume in internal laptops speakers and headphones too low
:( In win7 sound volume much higher.
Please help.
1
0
Hi all,
I'm struggling with getting the correct names for controls, so that they
show up correctly in the Playback or Capture modes of alsamixer
E.g. "PCM 3 Capture Meter" appears in the playback controls?
How is capture vs playback display determined?
or to put it another way: What are the rules for creating control names.
Here is a reduced schematic of one of our cards (in reality more
channels e.g. 4 physical stereo ins and outs, 12 players, 8 recorders)
All players and inputs are mixed to outputs.
All inputs and players multiplexed to each capture.
How should all these controls be named?
(1)-[vol]--+
(2)-[vol]--+
[play0]--[vol]--[meter]--[mode]--,-[vol]--+----[vol]-[meter]--[level]--[lineout0]
`-[vol]--|-.
| |
.-[vol]--' |
[play1]--[vol]--[meter]--[mode]--'-[vol]----+--[vol]-[meter]--[level]--[lineout1]
(1)-[vol]----+
(2)-[vol]----+
[linein0]-[level]-\ \
mux>-[meter]-(1)-,-------|\
[digitalin0]------/ | mux >--[mode]--[meter]--[cap0]
| ,../
| |
`--|--\
[linein1]-[level]-\ | >--[mode]--[meter]--[cap1]
mux>-[meter]-(2)-----'--/
[digitalin1]------/
notes
[level] means calibrated reference level setting in dBu
[mode] stereo channel modifier
+ summing junction
--|-- wires cross, no join
(1) connect from input to matrix mix output
thanks and regards
--
Eliot Blennerhassett
AudioScience Inc.
8
21

[alsa-devel] [PATCH 1/2] ASoC: Add Dimitris Papastamos to Wolfson maintainers
by Mark Brown 06 Oct '10
by Mark Brown 06 Oct '10
06 Oct '10
Add Dimitris Papastamos as a contact for Wolfson device drivers.
Signed-off-by: Mark Brown <broonie(a)opensource.wolfsonmicro.com>
Signed-off-by: Dimitris Papastamos <dp(a)opensource.wolfsonmicro.com>
---
MAINTAINERS | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/MAINTAINERS b/MAINTAINERS
index f51409b..8c1180f 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6411,6 +6411,7 @@ F: include/linux/wm97xx.h
WOLFSON MICROELECTRONICS DRIVERS
M: Mark Brown <broonie(a)opensource.wolfsonmicro.com>
M: Ian Lartey <ian(a)opensource.wolfsonmicro.com>
+M: Dimitris Papastamos <dp(a)opensource.wolfsonmicro.com>
T: git git://opensource.wolfsonmicro.com/linux-2.6-audioplus
W: http://opensource.wolfsonmicro.com/node/8
S: Supported
--
1.7.1
1
1
The following changes since commit 45605a87b3f34fb71bbc6446e2d49a469e9e10dd:
Merge branch 'for-2.6.37' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound-2.6 into topic/asoc (2010-10-05 07:50:11 +0200)
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound-2.6.git for-2.6.37
Dimitris Papastamos (2):
ASoC: soc-cache: Add spi_write support for all I/O types
ASoC: WM8804: Retrieve the device revision and print it
Guennadi Liakhovetski (1):
ASoC: sh: fix build error: terminate the platform device ID list
Mark Brown (1):
Merge branch 'topic/asoc' of git://git.kernel.org/.../tiwai/sound-2.6 into for-2.6.37
Nicolas Kaiser (1):
ASoC: remove duplicated include for nuc900
Troy Kisky (1):
ALSA: ASoc: DaVinci Delay start of ASP to trigger
sound/soc/codecs/wm8804.c | 8 +++
sound/soc/davinci/davinci-i2s.c | 6 ---
sound/soc/nuc900/nuc900-ac97.c | 1 -
sound/soc/sh/fsi.c | 1 +
sound/soc/soc-cache.c | 96 +++++++++++++++++++++++++++++++++++++++
5 files changed, 105 insertions(+), 7 deletions(-)
3
13
Hello Alsa developers:
We have 500 linux servers with X-Fi Xtreme Audio PCIe. The audio card is properly detected by kernel. The card is unmuted, the sound applications works fine. But the card doesn't sound.
Googling I discover the same case on several forums, no solution.
First Question: The driver is finished? Is it on development? Is it abandoned?
Second Question: Can I join to driver development. I need to make work this soundcard.
----------------------------------------------------------------------------------
Distribution: Fedora 13
kernel 2.6.34.7-56.fc13.i686.PAE
alsa version: alsa-lib-1.0.23
01:00.0 PCI bridge: Creative Labs [SB X-Fi Xtreme Audio] CA0110-IBG PCI to PCIe Bridge
[root@localhost ~]# lsmod
Module Size Used by
snd_ctxfi 69769 0
fuse 47907 2
sunrpc 163601 1
ip6t_REJECT 3310 2
nf_conntrack_ipv6 14223 2
ip6table_filter 1199 1
ip6_tables 9774 1 ip6table_filter
ipv6 221726 88 ip6t_REJECT,nf_conntrack_ipv6
uinput 5287 0
snd_hda_codec_ca0110 4769 1
snd_hda_intel 19995 0
iTCO_wdt 8940 0
iTCO_vendor_support 2027 1 iTCO_wdt
snd_hda_codec 70968 2 snd_hda_codec_ca0110,snd_hda_intel
snd_hwdep 4860 1 snd_hda_codec
snd_seq 42775 0
snd_seq_device 5035 1 snd_seq
dcdbas 6552 0
snd_pcm 62185 3 snd_ctxfi,snd_hda_intel,snd_hda_codec
bnx2 57069 0
snd_timer 15391 2 snd_seq,snd_pcm
power_meter 7602 0
snd 46591 9 snd_ctxfi,snd_hda_codec_ca0110,snd_hda_intel,snd_hda_codec,snd_hwdep,snd_seq,snd_seq_device,snd_pcm,snd_timer
soundcore 4934 1 snd
snd_page_alloc 6097 3 snd_ctxfi,snd_hda_intel,snd_pcm
microcode 10249 0
2
3
Hello Folks,
I am wondering if someone can help clarify how the hw pointer is used by the
ALSA layer.
I have a 24 channel soundcard that we have developed, using a Xilinx fpga.
The system is working, in that I can receive inbound samples on all 24
inputs and transmit samples on all 24 outputs.
But something isn't completely right.
We can xrun's and reports of very high cpu utilization.even though I know we
are in and out of our interrupts within 100uS for a 2.7mS interrupt period.
Interesting that our xruns cite a "0mS delay" or sometimes a 4mS delay (1.5
periods?)
I think the issue has to do with how we are presenting the response to the
hw-pointer request OR how/when we are calling the pcm_snd_elapsed.
I think the flow should be as follows (lets consider the dac part)
Step #1 ) interrupt occurs
Step #2) dma/transfer begins as kicked off in interrupt routine
Step #3) we advance the buffer pointer for the alsa buffer
Step #4) we exit the interrupt
. then the hardware should start advancing its pointer as it is reading the
new samples
.. then sometime later, the alsa layer calls the "hw_pointer" function
And then we return the current value of the hardware pointer from the board?
So alsa knows how many samples the board has processed from the interrupt?
We should be pretty close, because it is working for the most part..but I
think this pointer is not right.
Can someone explain how this pointer/etc is supposed to flow and what alsa
may be using it for? Maybe some latency calculation in a an upper layer?
Thanks again
Steve Spano
3
2

06 Oct '10
Remove duplicated include.
Signed-off-by: Nicolas Kaiser <nikai(a)nikai.net>
---
sound/soc/nuc900/nuc900-ac97.c | 1 -
1 files changed, 0 insertions(+), 1 deletions(-)
diff --git a/sound/soc/nuc900/nuc900-ac97.c b/sound/soc/nuc900/nuc900-ac97.c
index caa7c90..265a950 100644
--- a/sound/soc/nuc900/nuc900-ac97.c
+++ b/sound/soc/nuc900/nuc900-ac97.c
@@ -20,7 +20,6 @@
#include <sound/pcm.h>
#include <sound/initval.h>
#include <sound/soc.h>
-#include <linux/device.h>
#include <linux/clk.h>
#include <mach/mfp.h>
--
1.7.2.2
4
3
My X-FI Surround USB card is barely usable. pulseaudio will let me
control the volume levels, alsa support cannot view any volume controls.
How can I contribute to better support for this card under alsa? I would
like to get to the point where amixer can control the analog
input/output volume levels.
I am a capable programmer, but know very little about alsa, where should
I start?
Matti
2
5

[alsa-devel] [PATCH] ASoC: sh: fix build error: terminate the platform device ID list
by Guennadi Liakhovetski 05 Oct '10
by Guennadi Liakhovetski 05 Oct '10
05 Oct '10
Platform driver ID table must be zero-element terminated.
Signed-off-by: Guennadi Liakhovetski <g.liakhovetski(a)gmx.de>
---
sound/soc/sh/fsi.c | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c
index 82c6190..dd99633 100644
--- a/sound/soc/sh/fsi.c
+++ b/sound/soc/sh/fsi.c
@@ -1216,6 +1216,7 @@ static struct fsi_core fsi2_core = {
static struct platform_device_id fsi_id_table[] = {
{ "sh_fsi", (kernel_ulong_t)&fsi1_core },
{ "sh_fsi2", (kernel_ulong_t)&fsi2_core },
+ {},
};
MODULE_DEVICE_TABLE(platform, fsi_id_table);
--
1.7.1
3
2

[alsa-devel] [PATCH] ASoC: WM8804: Retrieve the device revision and print it
by Dimitris Papastamos 05 Oct '10
by Dimitris Papastamos 05 Oct '10
05 Oct '10
Be verbose and print out the device revision.
Signed-off-by: Dimitris Papastamos <dp(a)opensource.wolfsonmicro.com>
---
sound/soc/codecs/wm8804.c | 8 ++++++++
1 files changed, 8 insertions(+), 0 deletions(-)
diff --git a/sound/soc/codecs/wm8804.c b/sound/soc/codecs/wm8804.c
index 2657f5c..642b07c 100644
--- a/sound/soc/codecs/wm8804.c
+++ b/sound/soc/codecs/wm8804.c
@@ -643,6 +643,14 @@ static int wm8804_probe(struct snd_soc_codec *codec)
goto err_reg_enable;
}
+ ret = snd_soc_read(codec, WM8804_DEVREV);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to read device revision: %d\n",
+ ret);
+ goto err_reg_enable;
+ }
+ dev_info(codec->dev, "revision %c\n", ret + 'A');
+
ret = wm8804_reset(codec);
if (ret < 0) {
dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
--
1.7.3.1
3
2

[alsa-devel] [PATCH] ASoC: soc-cache: Add spi_write support for all I/O types
by Dimitris Papastamos 05 Oct '10
by Dimitris Papastamos 05 Oct '10
05 Oct '10
Ensure that all drivers that use SPI and I2C will work properly
by providing SPI write functions for all different I/O types.
Signed-off-by: Dimitris Papastamos <dp(a)opensource.wolfsonmicro.com>
---
sound/soc/soc-cache.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 96 insertions(+), 0 deletions(-)
diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c
index 62f1e2b..d214f02 100644
--- a/sound/soc/soc-cache.c
+++ b/sound/soc/soc-cache.c
@@ -211,6 +211,36 @@ static unsigned int snd_soc_8_8_read(struct snd_soc_codec *codec,
return cache[reg];
}
+#if defined(CONFIG_SPI_MASTER)
+static int snd_soc_8_8_spi_write(void *control_data, const char *data,
+ int len)
+{
+ struct spi_device *spi = control_data;
+ struct spi_transfer t;
+ struct spi_message m;
+ u8 msg[2];
+
+ if (len <= 0)
+ return 0;
+
+ msg[0] = data[0];
+ msg[1] = data[1];
+
+ spi_message_init(&m);
+ memset(&t, 0, (sizeof t));
+
+ t.tx_buf = &msg[0];
+ t.len = len;
+
+ spi_message_add_tail(&t, &m);
+ spi_sync(spi, &m);
+
+ return len;
+}
+#else
+#define snd_soc_8_8_spi_write NULL
+#endif
+
static int snd_soc_8_16_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int value)
{
@@ -254,6 +284,37 @@ static unsigned int snd_soc_8_16_read(struct snd_soc_codec *codec,
}
}
+#if defined(CONFIG_SPI_MASTER)
+static int snd_soc_8_16_spi_write(void *control_data, const char *data,
+ int len)
+{
+ struct spi_device *spi = control_data;
+ struct spi_transfer t;
+ struct spi_message m;
+ u8 msg[3];
+
+ if (len <= 0)
+ return 0;
+
+ msg[0] = data[0];
+ msg[1] = data[1];
+ msg[2] = data[2];
+
+ spi_message_init(&m);
+ memset(&t, 0, (sizeof t));
+
+ t.tx_buf = &msg[0];
+ t.len = len;
+
+ spi_message_add_tail(&t, &m);
+ spi_sync(spi, &m);
+
+ return len;
+}
+#else
+#define snd_soc_8_16_spi_write NULL
+#endif
+
#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
static unsigned int snd_soc_8_8_read_i2c(struct snd_soc_codec *codec,
unsigned int r)
@@ -518,6 +579,38 @@ static int snd_soc_16_16_write(struct snd_soc_codec *codec, unsigned int reg,
return -EIO;
}
+#if defined(CONFIG_SPI_MASTER)
+static int snd_soc_16_16_spi_write(void *control_data, const char *data,
+ int len)
+{
+ struct spi_device *spi = control_data;
+ struct spi_transfer t;
+ struct spi_message m;
+ u8 msg[4];
+
+ if (len <= 0)
+ return 0;
+
+ msg[0] = data[0];
+ msg[1] = data[1];
+ msg[2] = data[2];
+ msg[3] = data[3];
+
+ spi_message_init(&m);
+ memset(&t, 0, (sizeof t));
+
+ t.tx_buf = &msg[0];
+ t.len = len;
+
+ spi_message_add_tail(&t, &m);
+ spi_sync(spi, &m);
+
+ return len;
+}
+#else
+#define snd_soc_16_16_spi_write NULL
+#endif
+
static struct {
int addr_bits;
int data_bits;
@@ -540,11 +633,13 @@ static struct {
.addr_bits = 8, .data_bits = 8,
.write = snd_soc_8_8_write, .read = snd_soc_8_8_read,
.i2c_read = snd_soc_8_8_read_i2c,
+ .spi_write = snd_soc_8_8_spi_write,
},
{
.addr_bits = 8, .data_bits = 16,
.write = snd_soc_8_16_write, .read = snd_soc_8_16_read,
.i2c_read = snd_soc_8_16_read_i2c,
+ .spi_write = snd_soc_8_16_spi_write,
},
{
.addr_bits = 16, .data_bits = 8,
@@ -556,6 +651,7 @@ static struct {
.addr_bits = 16, .data_bits = 16,
.write = snd_soc_16_16_write, .read = snd_soc_16_16_read,
.i2c_read = snd_soc_16_16_read_i2c,
+ .spi_write = snd_soc_16_16_spi_write,
},
};
--
1.7.3.1
3
2
From: Vinod Koul <vinod.koul(a)intel.com>
This is the Intel SST audio driver.
As compared to the previous versions it has all the printks and other stuff
noted cleaned up and more hardware support. The Aava support is disabled in
this patch (is_aava resolves to 0) because the Aava board detection logic
is not yet upstream.
The driver itself is a combination of a traditional ALSA driver and a
hardware assisted offload driver which can play audio while the processor
is asleep but which can't do all the more interactive stuff.
In the general case most software would use the ALSA interface, but the
other interface is needed for certain classes of use such as music playback
on highly power consumption sensitive devices.
This is going to staging primarily because it depends upon the staging memrar
driver.
Signed-off-by: Vinod Koul <vinod.koul(a)intel.com>
Signed-off-by: Harsha Priya <priya.harsha(a)intel.com>
[Merged together and tweaked for -next]
Signed-off-by: Alan Cox <alan(a)linux.intel.com>
---
drivers/staging/Kconfig | 2
drivers/staging/Makefile | 1
drivers/staging/intel_sst/TODO | 12
drivers/staging/intel_sst/intel_sst.c | 512 ++++++++
drivers/staging/intel_sst/intel_sst.h | 131 ++
.../staging/intel_sst/intel_sst_app_interface.c | 1234 +++++++++++++++++++
drivers/staging/intel_sst/intel_sst_common.h | 618 ++++++++++
.../staging/intel_sst/intel_sst_drv_interface.c | 492 ++++++++
drivers/staging/intel_sst/intel_sst_dsp.c | 486 ++++++++
drivers/staging/intel_sst/intel_sst_fw_ipc.h | 393 ++++++
drivers/staging/intel_sst/intel_sst_ioctl.h | 435 +++++++
drivers/staging/intel_sst/intel_sst_ipc.c | 656 ++++++++++
drivers/staging/intel_sst/intel_sst_pvt.c | 311 +++++
drivers/staging/intel_sst/intel_sst_stream.c | 575 +++++++++
.../staging/intel_sst/intel_sst_stream_encoded.c | 1275 ++++++++++++++++++++
drivers/staging/intel_sst/intelmid.c | 1233 +++++++++++++++++++
drivers/staging/intel_sst/intelmid.h | 186 +++
drivers/staging/intel_sst/intelmid_ctrl.c | 629 ++++++++++
drivers/staging/intel_sst/intelmid_msic_control.c | 410 ++++++
drivers/staging/intel_sst/intelmid_pvt.c | 174 +++
drivers/staging/intel_sst/intelmid_snd_control.h | 114 ++
drivers/staging/intel_sst/intelmid_v0_control.c | 771 ++++++++++++
drivers/staging/intel_sst/intelmid_v1_control.c | 1072 +++++++++++++++++
drivers/staging/intel_sst/intelmid_v2_control.c | 1001 ++++++++++++++++
drivers/staging/intel_sst/jack.h | 10
25 files changed, 12733 insertions(+), 0 deletions(-)
create mode 100644 drivers/staging/intel_sst/TODO
create mode 100644 drivers/staging/intel_sst/intel_sst.c
create mode 100644 drivers/staging/intel_sst/intel_sst.h
create mode 100644 drivers/staging/intel_sst/intel_sst_app_interface.c
create mode 100644 drivers/staging/intel_sst/intel_sst_common.h
create mode 100644 drivers/staging/intel_sst/intel_sst_drv_interface.c
create mode 100644 drivers/staging/intel_sst/intel_sst_dsp.c
create mode 100644 drivers/staging/intel_sst/intel_sst_fw_ipc.h
create mode 100644 drivers/staging/intel_sst/intel_sst_ioctl.h
create mode 100644 drivers/staging/intel_sst/intel_sst_ipc.c
create mode 100644 drivers/staging/intel_sst/intel_sst_pvt.c
create mode 100644 drivers/staging/intel_sst/intel_sst_stream.c
create mode 100644 drivers/staging/intel_sst/intel_sst_stream_encoded.c
create mode 100644 drivers/staging/intel_sst/intelmid.c
create mode 100644 drivers/staging/intel_sst/intelmid.h
create mode 100644 drivers/staging/intel_sst/intelmid_ctrl.c
create mode 100644 drivers/staging/intel_sst/intelmid_msic_control.c
create mode 100644 drivers/staging/intel_sst/intelmid_pvt.c
create mode 100644 drivers/staging/intel_sst/intelmid_snd_control.h
create mode 100644 drivers/staging/intel_sst/intelmid_v0_control.c
create mode 100644 drivers/staging/intel_sst/intelmid_v1_control.c
create mode 100644 drivers/staging/intel_sst/intelmid_v2_control.c
create mode 100644 drivers/staging/intel_sst/jack.h
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index e00ef92..bb069cf 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -165,5 +165,7 @@ source "drivers/staging/bcm/Kconfig"
source "drivers/staging/ft1000/Kconfig"
+source "drivers/staging/intel_sst/Kconfig"
+
endif # !STAGING_EXCLUDE_BUILD
endif # STAGING
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index 35eacc9..9457e07 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -63,3 +63,4 @@ obj-$(CONFIG_ATH6K_LEGACY) += ath6kl/
obj-$(CONFIG_USB_ENESTORAGE) += keucr/
obj-$(CONFIG_BCM_WIMAX) += bcm/
obj-$(CONFIG_FT1000) += ft1000/
+obj-$(CONFIG_SND_INTEL_SST) += intel_sst/
diff --git a/drivers/staging/intel_sst/TODO b/drivers/staging/intel_sst/TODO
new file mode 100644
index 0000000..58d6d2d
--- /dev/null
+++ b/drivers/staging/intel_sst/TODO
@@ -0,0 +1,12 @@
+TODO
+----
+
+Get the memrar driver cleaned up and upstream (dependancy blocking SST)
+Get the jack header entries accepted
+Review the printks and kill off any left over ST_ERR: messages
+Review the misc device ioctls for 32/64bit safety and sanity
+Review the misc device ioctls for size safety depending on config and decide
+ if space/unused areas should be left
+
+Anything the sound folks turn up on full review
+
diff --git a/drivers/staging/intel_sst/intel_sst.c b/drivers/staging/intel_sst/intel_sst.c
new file mode 100644
index 0000000..24d3928
--- /dev/null
+++ b/drivers/staging/intel_sst/intel_sst.c
@@ -0,0 +1,512 @@
+/*
+ * intel_sst.c - Intel SST Driver for audio engine
+ *
+ * Copyright (C) 2008-10 Intel Corp
+ * Authors: Vinod Koul <vinod.koul(a)intel.com>
+ * Harsha Priya <priya.harsha(a)intel.com>
+ * Dharageswari R <dharageswari.r(a)intel.com>
+ * KP Jeeja <jeeja.kp(a)intel.com>
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This driver exposes the audio engine functionalities to the ALSA
+ * and middleware.
+ *
+ * This file contains all init functions
+ */
+
+#include <linux/pci.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/firmware.h>
+#include <linux/miscdevice.h>
+#include <asm/mrst.h>
+#include "intel_sst.h"
+#include "intel_sst_ioctl.h"
+#include "intel_sst_fw_ipc.h"
+#include "intel_sst_common.h"
+
+
+MODULE_AUTHOR("Vinod Koul <vinod.koul(a)intel.com>");
+MODULE_AUTHOR("Harsha Priya <priya.harsha(a)intel.com>");
+MODULE_AUTHOR("Dharageswari R <dharageswari.r(a)intel.com>");
+MODULE_AUTHOR("KP Jeeja <jeeja.kp(a)intel.com>");
+MODULE_DESCRIPTION("Intel (R) SST(R) Audio Engine Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION(SST_DRIVER_VERSION);
+
+struct intel_sst_drv *sst_drv_ctx;
+static struct mutex drv_ctx_lock;
+struct class *sst_class;
+
+/* fops Routines */
+static const struct file_operations intel_sst_fops = {
+ .owner = THIS_MODULE,
+ .open = intel_sst_open,
+ .release = intel_sst_release,
+ .read = intel_sst_read,
+ .write = intel_sst_write,
+ .unlocked_ioctl = intel_sst_ioctl,
+ .mmap = intel_sst_mmap,
+ .aio_read = intel_sst_aio_read,
+ .aio_write = intel_sst_aio_write,
+};
+static const struct file_operations intel_sst_fops_cntrl = {
+ .owner = THIS_MODULE,
+ .open = intel_sst_open_cntrl,
+ .release = intel_sst_release_cntrl,
+ .unlocked_ioctl = intel_sst_ioctl,
+};
+
+static struct miscdevice lpe_dev = {
+ .minor = MISC_DYNAMIC_MINOR,/* dynamic allocation */
+ .name = "intel_sst",/* /dev/intel_sst */
+ .fops = &intel_sst_fops
+};
+
+
+static struct miscdevice lpe_ctrl = {
+ .minor = MISC_DYNAMIC_MINOR,/* dynamic allocation */
+ .name = "intel_sst_ctrl",/* /dev/intel_sst_ctrl */
+ .fops = &intel_sst_fops_cntrl
+};
+
+/**
+* intel_sst_interrupt - Interrupt service routine for SST
+*
+* @irq: irq number of interrupt
+* @context: pointer to device structre
+*
+* This function is called by OS when SST device raises
+* an interrupt. This will be result of write in IPC register
+* Source can be busy or done interrupt
+*/
+static irqreturn_t intel_sst_interrupt(int irq, void *context)
+{
+ union interrupt_reg isr;
+ union ipc_header header;
+ union interrupt_reg imr;
+ struct intel_sst_drv *drv = (struct intel_sst_drv *) context;
+ unsigned int size = 0, str_id;
+ struct stream_info *stream ;
+
+ /* Interrupt arrived, check src */
+ isr.full = sst_shim_read(drv->shim, SST_ISRX);
+
+ if (isr.part.busy_interrupt) {
+ header.full = sst_shim_read(drv->shim, SST_IPCD);
+ if (header.part.msg_id == IPC_SST_PERIOD_ELAPSED) {
+ sst_clear_interrupt();
+ str_id = header.part.str_id;
+ stream = &sst_drv_ctx->streams[str_id];
+ if (stream->period_elapsed)
+ stream->period_elapsed(stream->pcm_substream);
+ return IRQ_HANDLED;
+ }
+ if (header.part.large)
+ size = header.part.data;
+ if (header.part.msg_id & REPLY_MSG) {
+ sst_drv_ctx->ipc_process_msg.header = header;
+ memcpy_fromio(sst_drv_ctx->ipc_process_msg.mailbox,
+ drv->mailbox + SST_MAILBOX_RCV, size);
+ queue_work(sst_drv_ctx->process_msg_wq,
+ &sst_drv_ctx->ipc_process_msg.wq);
+ } else {
+ sst_drv_ctx->ipc_process_reply.header = header;
+ memcpy_fromio(sst_drv_ctx->ipc_process_reply.mailbox,
+ drv->mailbox + SST_MAILBOX_RCV, size);
+ queue_work(sst_drv_ctx->process_reply_wq,
+ &sst_drv_ctx->ipc_process_reply.wq);
+ }
+ /* mask busy inetrrupt */
+ imr.full = sst_shim_read(drv->shim, SST_IMRX);
+ imr.part.busy_interrupt = 1;
+ sst_shim_write(sst_drv_ctx->shim, SST_IMRX, imr.full);
+ return IRQ_HANDLED;
+ } else if (isr.part.done_interrupt) {
+ /* Clear done bit */
+ header.full = sst_shim_read(drv->shim, SST_IPCX);
+ header.part.done = 0;
+ sst_shim_write(sst_drv_ctx->shim, SST_IPCX, header.full);
+ /* write 1 to clear status register */;
+ isr.part.done_interrupt = 1;
+ /* dummy register for shim workaround */
+ sst_shim_write(sst_drv_ctx->shim, SST_ISRX, isr.full);
+ queue_work(sst_drv_ctx->post_msg_wq,
+ &sst_drv_ctx->ipc_post_msg.wq);
+ return IRQ_HANDLED;
+ } else
+ return IRQ_NONE;
+
+}
+
+
+/*
+* intel_sst_probe - PCI probe function
+*
+* @pci: PCI device structure
+* @pci_id: PCI device ID structure
+*
+* This function is called by OS when a device is found
+* This enables the device, interrupt etc
+*/
+static int __devinit intel_sst_probe(struct pci_dev *pci,
+ const struct pci_device_id *pci_id)
+{
+ int i, ret = 0;
+
+ pr_debug("sst: Probe for DID %x\n", pci->device);
+ mutex_lock(&drv_ctx_lock);
+ if (sst_drv_ctx) {
+ pr_err("sst: Only one sst handle is supported\n");
+ mutex_unlock(&drv_ctx_lock);
+ return -EBUSY;
+ }
+
+ sst_drv_ctx = kzalloc(sizeof(*sst_drv_ctx), GFP_KERNEL);
+ if (!sst_drv_ctx) {
+ pr_err("sst: intel_sst malloc fail\n");
+ mutex_unlock(&drv_ctx_lock);
+ return -ENOMEM;
+ }
+ mutex_unlock(&drv_ctx_lock);
+
+ sst_drv_ctx->pci_id = pci->device;
+
+ mutex_init(&sst_drv_ctx->stream_lock);
+ mutex_init(&sst_drv_ctx->sst_lock);
+ sst_drv_ctx->pmic_state = SND_MAD_UN_INIT;
+
+ sst_drv_ctx->stream_cnt = 0;
+ sst_drv_ctx->encoded_cnt = 0;
+ sst_drv_ctx->am_cnt = 0;
+ sst_drv_ctx->pb_streams = 0;
+ sst_drv_ctx->cp_streams = 0;
+ sst_drv_ctx->unique_id = 0;
+ sst_drv_ctx->pmic_port_instance = SST_DEFAULT_PMIC_PORT;
+
+ INIT_LIST_HEAD(&sst_drv_ctx->ipc_dispatch_list);
+ INIT_WORK(&sst_drv_ctx->ipc_post_msg.wq, sst_post_message);
+ INIT_WORK(&sst_drv_ctx->ipc_process_msg.wq, sst_process_message);
+ INIT_WORK(&sst_drv_ctx->ipc_process_reply.wq, sst_process_reply);
+ INIT_WORK(&sst_drv_ctx->mad_ops.wq, sst_process_mad_ops);
+ init_waitqueue_head(&sst_drv_ctx->wait_queue);
+
+ sst_drv_ctx->mad_wq = create_workqueue("sst_mad_wq");
+ if (!sst_drv_ctx->mad_wq)
+ goto do_free_drv_ctx;
+ sst_drv_ctx->post_msg_wq = create_workqueue("sst_post_msg_wq");
+ if (!sst_drv_ctx->post_msg_wq)
+ goto free_mad_wq;
+ sst_drv_ctx->process_msg_wq = create_workqueue("sst_process_msg_wqq");
+ if (!sst_drv_ctx->process_msg_wq)
+ goto free_post_msg_wq;
+ sst_drv_ctx->process_reply_wq = create_workqueue("sst_proces_reply_wq");
+ if (!sst_drv_ctx->process_reply_wq)
+ goto free_process_msg_wq;
+
+ for (i = 0; i < MAX_ACTIVE_STREAM; i++) {
+ sst_drv_ctx->alloc_block[i].sst_id = BLOCK_UNINIT;
+ sst_drv_ctx->alloc_block[i].ops_block.condition = false;
+ }
+ spin_lock_init(&sst_drv_ctx->list_spin_lock);
+
+ sst_drv_ctx->max_streams = pci_id->driver_data;
+ pr_debug("sst: Got drv data max stream %d\n",
+ sst_drv_ctx->max_streams);
+ for (i = 1; i <= sst_drv_ctx->max_streams; i++) {
+ struct stream_info *stream = &sst_drv_ctx->streams[i];
+ INIT_LIST_HEAD(&stream->bufs);
+ mutex_init(&stream->lock);
+ spin_lock_init(&stream->pcm_lock);
+ }
+ if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID) {
+ sst_drv_ctx->mmap_mem = NULL;
+ sst_drv_ctx->mmap_len = SST_MMAP_PAGES * PAGE_SIZE;
+ while (sst_drv_ctx->mmap_len > 0) {
+ sst_drv_ctx->mmap_mem =
+ kzalloc(sst_drv_ctx->mmap_len, GFP_KERNEL);
+ if (sst_drv_ctx->mmap_mem) {
+ pr_debug("sst: Got memory %p size 0x%x\n",
+ sst_drv_ctx->mmap_mem,
+ sst_drv_ctx->mmap_len);
+ break;
+ }
+ if (sst_drv_ctx->mmap_len < (SST_MMAP_STEP*PAGE_SIZE)) {
+ pr_err("sst: mem alloc fail...abort!!\n");
+ ret = -ENOMEM;
+ goto free_process_reply_wq;
+ }
+ sst_drv_ctx->mmap_len -= (SST_MMAP_STEP * PAGE_SIZE);
+ pr_debug("sst:mem alloc failed...trying %d\n",
+ sst_drv_ctx->mmap_len);
+ }
+ }
+
+ /* Init the device */
+ ret = pci_enable_device(pci);
+ if (ret) {
+ pr_err("sst: device cant be enabled\n");
+ goto do_free_mem;
+ }
+ sst_drv_ctx->pci = pci_dev_get(pci);
+ ret = pci_request_regions(pci, SST_DRV_NAME);
+ if (ret)
+ goto do_disable_device;
+ /* map registers */
+ /* SST Shim */
+ sst_drv_ctx->shim_phy_add = pci_resource_start(pci, 1);
+ sst_drv_ctx->shim = pci_ioremap_bar(pci, 1);
+ if (!sst_drv_ctx->shim)
+ goto do_release_regions;
+ pr_debug("sst: SST Shim Ptr %p\n", sst_drv_ctx->shim);
+
+ /* Shared SRAM */
+ sst_drv_ctx->mailbox = pci_ioremap_bar(pci, 2);
+ if (!sst_drv_ctx->mailbox)
+ goto do_unmap_shim;
+ pr_debug("sst: SRAM Ptr %p\n", sst_drv_ctx->mailbox);
+
+ /* IRAM */
+ sst_drv_ctx->iram = pci_ioremap_bar(pci, 3);
+ if (!sst_drv_ctx->iram)
+ goto do_unmap_sram;
+ pr_debug("sst:IRAM Ptr %p\n", sst_drv_ctx->iram);
+
+ /* DRAM */
+ sst_drv_ctx->dram = pci_ioremap_bar(pci, 4);
+ if (!sst_drv_ctx->dram)
+ goto do_unmap_iram;
+ pr_debug("sst: DRAM Ptr %p\n", sst_drv_ctx->dram);
+
+ mutex_lock(&sst_drv_ctx->sst_lock);
+ sst_drv_ctx->sst_state = SST_UN_INIT;
+ mutex_unlock(&sst_drv_ctx->sst_lock);
+ /* Register the ISR */
+ ret = request_irq(pci->irq, intel_sst_interrupt,
+ IRQF_SHARED, SST_DRV_NAME, sst_drv_ctx);
+ if (ret)
+ goto do_unmap_dram;
+ pr_debug("sst: Registered IRQ 0x%x\n", pci->irq);
+
+ if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID) {
+ ret = misc_register(&lpe_dev);
+ if (ret) {
+ pr_err("sst: couldn't register LPE device\n");
+ goto do_free_irq;
+ }
+
+ /*Register LPE Control as misc driver*/
+ ret = misc_register(&lpe_ctrl);
+ if (ret) {
+ pr_err("sst: couldn't register misc driver\n");
+ goto do_free_irq;
+ }
+ }
+ sst_drv_ctx->lpe_stalled = 0;
+ pr_debug("sst: ...successfully done!!!\n");
+ return ret;
+
+do_free_irq:
+ free_irq(pci->irq, sst_drv_ctx);
+do_unmap_dram:
+ iounmap(sst_drv_ctx->dram);
+do_unmap_iram:
+ iounmap(sst_drv_ctx->iram);
+do_unmap_sram:
+ iounmap(sst_drv_ctx->mailbox);
+do_unmap_shim:
+ iounmap(sst_drv_ctx->shim);
+do_release_regions:
+ pci_release_regions(pci);
+do_disable_device:
+ pci_disable_device(pci);
+do_free_mem:
+ kfree(sst_drv_ctx->mmap_mem);
+free_process_reply_wq:
+ destroy_workqueue(sst_drv_ctx->process_reply_wq);
+free_process_msg_wq:
+ destroy_workqueue(sst_drv_ctx->process_msg_wq);
+free_post_msg_wq:
+ destroy_workqueue(sst_drv_ctx->post_msg_wq);
+free_mad_wq:
+ destroy_workqueue(sst_drv_ctx->mad_wq);
+do_free_drv_ctx:
+ kfree(sst_drv_ctx);
+ pr_err("sst: Probe failed with 0x%x\n", ret);
+ return ret;
+}
+
+/**
+* intel_sst_remove - PCI remove function
+*
+* @pci: PCI device structure
+*
+* This function is called by OS when a device is unloaded
+* This frees the interrupt etc
+*/
+static void __devexit intel_sst_remove(struct pci_dev *pci)
+{
+ pci_dev_put(sst_drv_ctx->pci);
+ mutex_lock(&sst_drv_ctx->sst_lock);
+ sst_drv_ctx->sst_state = SST_UN_INIT;
+ mutex_unlock(&sst_drv_ctx->sst_lock);
+ if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID) {
+ misc_deregister(&lpe_dev);
+ misc_deregister(&lpe_ctrl);
+ }
+ free_irq(pci->irq, sst_drv_ctx);
+ iounmap(sst_drv_ctx->dram);
+ iounmap(sst_drv_ctx->iram);
+ iounmap(sst_drv_ctx->mailbox);
+ iounmap(sst_drv_ctx->shim);
+ sst_drv_ctx->pmic_state = SND_MAD_UN_INIT;
+ if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID)
+ kfree(sst_drv_ctx->mmap_mem);
+ flush_scheduled_work();
+ destroy_workqueue(sst_drv_ctx->process_reply_wq);
+ destroy_workqueue(sst_drv_ctx->process_msg_wq);
+ destroy_workqueue(sst_drv_ctx->post_msg_wq);
+ destroy_workqueue(sst_drv_ctx->mad_wq);
+ kfree(sst_drv_ctx);
+ pci_release_region(pci, 1);
+ pci_release_region(pci, 2);
+ pci_release_region(pci, 3);
+ pci_release_region(pci, 4);
+ pci_release_region(pci, 5);
+ pci_set_drvdata(pci, NULL);
+}
+
+/* Power Management */
+/*
+* intel_sst_suspend - PCI suspend function
+*
+* @pci: PCI device structure
+* @state: PM message
+*
+* This function is called by OS when a power event occurs
+*/
+int intel_sst_suspend(struct pci_dev *pci, pm_message_t state)
+{
+ union config_status_reg csr;
+
+ pr_debug("sst: intel_sst_suspend called\n");
+
+ if (sst_drv_ctx->pb_streams != 0 || sst_drv_ctx->cp_streams != 0)
+ return -EPERM;
+ /*Assert RESET on LPE Processor*/
+ csr.full = sst_shim_read(sst_drv_ctx->shim, SST_CSR);
+ csr.full = csr.full | 0x2;
+ /* Move the SST state to Suspended */
+ mutex_lock(&sst_drv_ctx->sst_lock);
+ sst_drv_ctx->sst_state = SST_SUSPENDED;
+ sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full);
+ mutex_unlock(&sst_drv_ctx->sst_lock);
+ pci_set_drvdata(pci, sst_drv_ctx);
+ pci_save_state(pci);
+ pci_disable_device(pci);
+ pci_set_power_state(pci, PCI_D3hot);
+ return 0;
+}
+
+/**
+* intel_sst_resume - PCI resume function
+*
+* @pci: PCI device structure
+*
+* This function is called by OS when a power event occurs
+*/
+int intel_sst_resume(struct pci_dev *pci)
+{
+ int ret = 0;
+
+ pr_debug("sst: intel_sst_resume called\n");
+ if (sst_drv_ctx->sst_state != SST_SUSPENDED) {
+ pr_err("sst: SST is not in suspended state\n");
+ return -EPERM;
+ }
+ sst_drv_ctx = pci_get_drvdata(pci);
+ pci_set_power_state(pci, PCI_D0);
+ pci_restore_state(pci);
+ ret = pci_enable_device(pci);
+ if (ret)
+ pr_err("sst: device cant be enabled\n");
+
+ mutex_lock(&sst_drv_ctx->sst_lock);
+ sst_drv_ctx->sst_state = SST_UN_INIT;
+ mutex_unlock(&sst_drv_ctx->sst_lock);
+ return 0;
+}
+
+/* PCI Routines */
+static struct pci_device_id intel_sst_ids[] = {
+ { PCI_VDEVICE(INTEL, SST_MRST_PCI_ID), 3},
+ { PCI_VDEVICE(INTEL, SST_MFLD_PCI_ID), 6},
+ { 0, }
+};
+MODULE_DEVICE_TABLE(pci, intel_sst_ids);
+
+static struct pci_driver driver = {
+ .name = SST_DRV_NAME,
+ .id_table = intel_sst_ids,
+ .probe = intel_sst_probe,
+ .remove = __devexit_p(intel_sst_remove),
+#ifdef CONFIG_PM
+ .suspend = intel_sst_suspend,
+ .resume = intel_sst_resume,
+#endif
+};
+
+/**
+* intel_sst_init - Module init function
+*
+* Registers with PCI
+* Registers with /dev
+* Init all data strutures
+*/
+static int __init intel_sst_init(void)
+{
+ /* Init all variables, data structure etc....*/
+ int ret = 0;
+ pr_debug("sst: INFO: ******** SST DRIVER loading.. Ver: %s\n",
+ SST_DRIVER_VERSION);
+
+ mutex_init(&drv_ctx_lock);
+ /* Register with PCI */
+ ret = pci_register_driver(&driver);
+ if (ret)
+ pr_err("sst: PCI register failed\n");
+ return ret;
+}
+
+/**
+* intel_sst_exit - Module exit function
+*
+* Unregisters with PCI
+* Unregisters with /dev
+* Frees all data strutures
+*/
+static void __exit intel_sst_exit(void)
+{
+ pci_unregister_driver(&driver);
+
+ pr_debug("sst: driver unloaded\n");
+ return;
+}
+
+module_init(intel_sst_init);
+module_exit(intel_sst_exit);
diff --git a/drivers/staging/intel_sst/intel_sst.h b/drivers/staging/intel_sst/intel_sst.h
new file mode 100644
index 0000000..1f19f0d
--- /dev/null
+++ b/drivers/staging/intel_sst/intel_sst.h
@@ -0,0 +1,131 @@
+#ifndef __INTEL_SST_H__
+#define __INTEL_SST_H__
+/*
+ * intel_sst.h - Intel SST Driver for audio engine
+ *
+ * Copyright (C) 2008-10 Intel Corporation
+ * Authors: Vinod Koul <vinod.koul(a)intel.com>
+ * Harsha Priya <priya.harsha(a)intel.com>
+ * Dharageswari R <dharageswari.r(a)intel.com>
+ * KP Jeeja <jeeja.kp(a)intel.com>
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This driver exposes the audio engine functionalities to the ALSA
+ * and middleware.
+ * This file is shared between the SST and MAD drivers
+ */
+
+#define SST_CARD_NAMES "intel_mid_card"
+
+/* control list Pmic & Lpe */
+/* Input controls */
+enum port_status {
+ ACTIVATE = 1,
+ DEACTIVATE,
+};
+
+/* Card states */
+enum sst_card_states {
+ SND_CARD_UN_INIT = 0,
+ SND_CARD_INIT_DONE,
+};
+
+enum sst_controls {
+ SST_SND_ALLOC = 0x1000,
+ SST_SND_PAUSE = 0x1001,
+ SST_SND_RESUME = 0x1002,
+ SST_SND_DROP = 0x1003,
+ SST_SND_FREE = 0x1004,
+ SST_SND_BUFFER_POINTER = 0x1005,
+ SST_SND_STREAM_INIT = 0x1006,
+ SST_SND_START = 0x1007,
+ SST_SND_STREAM_PROCESS = 0x1008,
+ SST_MAX_CONTROLS = 0x1008,
+ SST_CONTROL_BASE = 0x1000,
+ SST_ENABLE_RX_TIME_SLOT = 0x1009,
+};
+
+enum SND_CARDS {
+ SND_FS = 0,
+ SND_MX,
+ SND_NC,
+ SND_MSIC
+};
+
+struct pcm_stream_info {
+ int str_id;
+ void *mad_substream;
+ void (*period_elapsed) (void *mad_substream);
+ unsigned long long buffer_ptr;
+ int sfreq;
+};
+
+struct snd_pmic_ops {
+ int card_status;
+ int master_mute;
+ int num_channel;
+ int input_dev_id;
+ int mute_status;
+ int pb_on;
+ int cap_on;
+ int output_dev_id;
+ int (*set_input_dev) (u8 value);
+ int (*set_output_dev) (u8 value);
+
+ int (*set_mute) (int dev_id, u8 value);
+ int (*get_mute) (int dev_id, u8 *value);
+
+ int (*set_vol) (int dev_id, int value);
+ int (*get_vol) (int dev_id, int *value);
+
+ int (*init_card) (void);
+ int (*set_pcm_audio_params)
+ (int sfreq, int word_size , int num_channel);
+ int (*set_pcm_voice_params) (void);
+ int (*set_voice_port) (int status);
+ int (*set_audio_port) (int status);
+
+ int (*power_up_pmic_pb) (unsigned int port);
+ int (*power_up_pmic_cp) (unsigned int port);
+ int (*power_down_pmic_pb) (void);
+ int (*power_down_pmic_cp) (void);
+ int (*power_down_pmic) (void);
+};
+
+struct intel_sst_card_ops {
+ char *module_name;
+ unsigned int vendor_id;
+ int (*control_set) (int control_element, void *value);
+ struct snd_pmic_ops *scard_ops;
+};
+
+/* modified for generic access */
+struct sc_reg_access {
+ u16 reg_addr;
+ u8 value;
+ u8 mask;
+};
+enum sc_reg_access_type {
+ PMIC_READ = 0,
+ PMIC_WRITE,
+ PMIC_READ_MODIFY,
+};
+
+int register_sst_card(struct intel_sst_card_ops *card);
+void unregister_sst_card(struct intel_sst_card_ops *card);
+#endif /* __INTEL_SST_H__ */
diff --git a/drivers/staging/intel_sst/intel_sst_app_interface.c b/drivers/staging/intel_sst/intel_sst_app_interface.c
new file mode 100644
index 0000000..9f31dc5
--- /dev/null
+++ b/drivers/staging/intel_sst/intel_sst_app_interface.c
@@ -0,0 +1,1234 @@
+/*
+ * intel_sst_interface.c - Intel SST Driver for audio engine
+ *
+ * Copyright (C) 2008-10 Intel Corp
+ * Authors: Vinod Koul <vinod.koul(a)intel.com>
+ * Harsha Priya <priya.harsha(a)intel.com>
+ * Dharageswari R <dharageswari.r(a)intel.com>
+ * Jeeja KP <jeeja.kp(a)intel.com>
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * This driver exposes the audio engine functionalities to the ALSA
+ * and middleware.
+ * Upper layer interfaces (MAD driver, MMF) to SST driver
+ */
+
+#include <linux/pci.h>
+#include <linux/fs.h>
+#include <linux/uio.h>
+#include <linux/aio.h>
+#include <linux/uaccess.h>
+#include <linux/firmware.h>
+#include <linux/ioctl.h>
+#include <linux/smp_lock.h>
+#ifdef CONFIG_MRST_RAR_HANDLER
+#include <linux/rar_register.h>
+#include "../../../drivers/staging/memrar/memrar.h"
+#endif
+#include "intel_sst.h"
+#include "intel_sst_ioctl.h"
+#include "intel_sst_fw_ipc.h"
+#include "intel_sst_common.h"
+
+#define AM_MODULE 1
+#define STREAM_MODULE 0
+
+
+/**
+* intel_sst_check_device - checks SST device
+*
+* This utility function checks the state of SST device and downlaods FW if
+* not done, or resumes the device if suspended
+*/
+
+static int intel_sst_check_device(void)
+{
+ int retval = 0;
+ if (sst_drv_ctx->pmic_state != SND_MAD_INIT_DONE) {
+ pr_warn("sst: Sound card not availble\n ");
+ return -EIO;
+ }
+ if (sst_drv_ctx->sst_state == SST_SUSPENDED) {
+ pr_debug("sst: Resuming from Suspended state\n");
+ retval = intel_sst_resume(sst_drv_ctx->pci);
+ if (retval) {
+ pr_debug("sst: Resume Failed= %#x,abort\n", retval);
+ return retval;
+ }
+ }
+
+ if (sst_drv_ctx->sst_state == SST_UN_INIT) {
+ /* FW is not downloaded */
+ retval = sst_download_fw();
+ if (retval)
+ return -ENODEV;
+ if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID) {
+ retval = sst_drv_ctx->rx_time_slot_status;
+ if (retval != RX_TIMESLOT_UNINIT
+ && sst_drv_ctx->pmic_vendor != SND_NC)
+ sst_enable_rx_timeslot(retval);
+ }
+ }
+ return 0;
+}
+
+/**
+ * intel_sst_open - opens a handle to driver
+ *
+ * @i_node: inode structure
+ * @file_ptr:pointer to file
+ *
+ * This function is called by OS when a user space component
+ * tries to get a driver handle. Only one handle at a time
+ * will be allowed
+ */
+int intel_sst_open(struct inode *i_node, struct file *file_ptr)
+{
+ unsigned int retval = intel_sst_check_device();
+ if (retval)
+ return retval;
+
+ mutex_lock(&sst_drv_ctx->stream_lock);
+ if (sst_drv_ctx->encoded_cnt < MAX_ENC_STREAM) {
+ struct ioctl_pvt_data *data =
+ kzalloc(sizeof(struct ioctl_pvt_data), GFP_KERNEL);
+ if (!data) {
+ mutex_unlock(&sst_drv_ctx->stream_lock);
+ return -ENOMEM;
+ }
+
+ sst_drv_ctx->encoded_cnt++;
+ mutex_unlock(&sst_drv_ctx->stream_lock);
+ data->pvt_id = sst_assign_pvt_id(sst_drv_ctx);
+ data->str_id = 0;
+ file_ptr->private_data = (void *)data;
+ pr_debug("sst: pvt_id handle = %d!\n", data->pvt_id);
+ } else {
+ retval = -EUSERS;
+ mutex_unlock(&sst_drv_ctx->stream_lock);
+ }
+ return retval;
+}
+
+/**
+ * intel_sst_open_cntrl - opens a handle to driver
+ *
+ * @i_node: inode structure
+ * @file_ptr:pointer to file
+ *
+ * This function is called by OS when a user space component
+ * tries to get a driver handle to /dev/intel_sst_control.
+ * Only one handle at a time will be allowed
+ * This is for control operations only
+ */
+int intel_sst_open_cntrl(struct inode *i_node, struct file *file_ptr)
+{
+ unsigned int retval = intel_sst_check_device();
+ if (retval)
+ return retval;
+
+ /* audio manager open */
+ mutex_lock(&sst_drv_ctx->stream_lock);
+ if (sst_drv_ctx->am_cnt < MAX_AM_HANDLES) {
+ sst_drv_ctx->am_cnt++;
+ pr_debug("sst: AM handle opened...\n");
+ file_ptr->private_data = NULL;
+ } else
+ retval = -EACCES;
+
+ mutex_unlock(&sst_drv_ctx->stream_lock);
+ return retval;
+}
+
+/**
+ * intel_sst_release - releases a handle to driver
+ *
+ * @i_node: inode structure
+ * @file_ptr: pointer to file
+ *
+ * This function is called by OS when a user space component
+ * tries to release a driver handle.
+ */
+int intel_sst_release(struct inode *i_node, struct file *file_ptr)
+{
+ struct ioctl_pvt_data *data = file_ptr->private_data;
+
+ pr_debug("sst: Release called, closing app handle\n");
+ mutex_lock(&sst_drv_ctx->stream_lock);
+ sst_drv_ctx->encoded_cnt--;
+ sst_drv_ctx->stream_cnt--;
+ mutex_unlock(&sst_drv_ctx->stream_lock);
+ free_stream_context(data->str_id);
+ kfree(data);
+ return 0;
+}
+
+int intel_sst_release_cntrl(struct inode *i_node, struct file *file_ptr)
+{
+ /* audio manager close */
+ mutex_lock(&sst_drv_ctx->stream_lock);
+ sst_drv_ctx->am_cnt--;
+ mutex_unlock(&sst_drv_ctx->stream_lock);
+ pr_debug("sst: AM handle closed\n");
+ return 0;
+}
+
+/**
+* intel_sst_mmap - mmaps a kernel buffer to user space for copying data
+*
+* @vma: vm area structure instance
+* @file_ptr: pointer to file
+*
+* This function is called by OS when a user space component
+* tries to get mmap memory from driver
+*/
+int intel_sst_mmap(struct file *file_ptr, struct vm_area_struct *vma)
+{
+ int retval, length;
+ struct ioctl_pvt_data *data =
+ (struct ioctl_pvt_data *)file_ptr->private_data;
+ int str_id = data->str_id;
+ void *mem_area;
+
+ retval = sst_validate_strid(str_id);
+ if (retval)
+ return -EINVAL;
+
+ length = vma->vm_end - vma->vm_start;
+ pr_debug("sst: called for stream %d length 0x%x\n", str_id, length);
+
+ if (length > sst_drv_ctx->mmap_len)
+ return -ENOMEM;
+ if (!sst_drv_ctx->mmap_mem)
+ return -EIO;
+
+ /* round it up to the page bondary */
+ /*mem_area = (void *)((((unsigned long)sst_drv_ctx->mmap_mem)
+ + PAGE_SIZE - 1) & PAGE_MASK);*/
+ mem_area = (void *) PAGE_ALIGN((unsigned int) sst_drv_ctx->mmap_mem);
+
+ /* map the whole physically contiguous area in one piece */
+ retval = remap_pfn_range(vma,
+ vma->vm_start,
+ virt_to_phys((void *)mem_area) >> PAGE_SHIFT,
+ length,
+ vma->vm_page_prot);
+ if (retval)
+ sst_drv_ctx->streams[str_id].mmapped = false;
+ else
+ sst_drv_ctx->streams[str_id].mmapped = true;
+
+ pr_debug("sst: mmap ret 0x%x\n", retval);
+ return retval;
+}
+
+/* sets mmap data buffers to play/capture*/
+static int intel_sst_mmap_play_capture(u32 str_id,
+ struct snd_sst_mmap_buffs *mmap_buf)
+{
+ struct sst_stream_bufs *bufs;
+ int retval, i;
+ struct stream_info *stream;
+ struct snd_sst_mmap_buff_entry *buf_entry;
+
+ pr_debug("sst:called for str_id %d\n", str_id);
+ retval = sst_validate_strid(str_id);
+ if (retval)
+ return -EINVAL;
+ BUG_ON(!mmap_buf);
+
+ stream = &sst_drv_ctx->streams[str_id];
+ if (stream->mmapped != true)
+ return -EIO;
+
+ if (stream->status == STREAM_UN_INIT ||
+ stream->status == STREAM_DECODE) {
+ return -EBADRQC;
+ }
+ stream->curr_bytes = 0;
+ stream->cumm_bytes = 0;
+
+ pr_debug("sst:new buffers count %d status %d\n",
+ mmap_buf->entries, stream->status);
+ buf_entry = mmap_buf->buff;
+ for (i = 0; i < mmap_buf->entries; i++) {
+ BUG_ON(!buf_entry);
+ bufs = kzalloc(sizeof(*bufs), GFP_KERNEL);
+ if (!bufs)
+ return -ENOMEM;
+ bufs->size = buf_entry->size;
+ bufs->offset = buf_entry->offset;
+ bufs->addr = sst_drv_ctx->mmap_mem;
+ bufs->in_use = false;
+ buf_entry++;
+ /* locking here */
+ mutex_lock(&stream->lock);
+ list_add_tail(&bufs->node, &stream->bufs);
+ mutex_unlock(&stream->lock);
+ }
+
+ mutex_lock(&stream->lock);
+ stream->data_blk.condition = false;
+ stream->data_blk.ret_code = 0;
+ if (stream->status == STREAM_INIT &&
+ stream->prev != STREAM_UN_INIT &&
+ stream->need_draining != true) {
+ stream->prev = stream->status;
+ stream->status = STREAM_RUNNING;
+ if (stream->ops == STREAM_OPS_PLAYBACK) {
+ if (sst_play_frame(str_id) < 0) {
+ pr_warn("sst: play frames fail\n");
+ mutex_unlock(&stream->lock);
+ return -EIO;
+ }
+ } else if (stream->ops == STREAM_OPS_CAPTURE) {
+ if (sst_capture_frame(str_id) < 0) {
+ pr_warn("sst: capture frame fail\n");
+ mutex_unlock(&stream->lock);
+ return -EIO;
+ }
+ }
+ }
+ mutex_unlock(&stream->lock);
+ /* Block the call for reply */
+ if (!list_empty(&stream->bufs)) {
+ stream->data_blk.on = true;
+ retval = sst_wait_interruptible(sst_drv_ctx,
+ &stream->data_blk);
+ }
+
+ if (retval >= 0)
+ retval = stream->cumm_bytes;
+ pr_debug("sst:end of play/rec ioctl bytes = %d!!\n", retval);
+ return retval;
+}
+
+/*sets user data buffers to play/capture*/
+static int intel_sst_play_capture(struct stream_info *stream, int str_id)
+{
+ int retval;
+
+ stream->data_blk.ret_code = 0;
+ stream->data_blk.on = true;
+ stream->data_blk.condition = false;
+
+ mutex_lock(&stream->lock);
+ if (stream->status == STREAM_INIT && stream->prev != STREAM_UN_INIT) {
+ /* stream is started */
+ stream->prev = stream->status;
+ stream->status = STREAM_RUNNING;
+ }
+
+ if (stream->status == STREAM_INIT && stream->prev == STREAM_UN_INIT) {
+ /* stream is not started yet */
+ pr_debug("sst: Stream isn't in started state %d, prev %d\n",
+ stream->status, stream->prev);
+ } else if ((stream->status == STREAM_RUNNING ||
+ stream->status == STREAM_PAUSED) &&
+ stream->need_draining != true) {
+ /* stream is started */
+ if (stream->ops == STREAM_OPS_PLAYBACK ||
+ stream->ops == STREAM_OPS_PLAYBACK_DRM) {
+ if (sst_play_frame(str_id) < 0) {
+ pr_warn("sst: play frames failed\n");
+ mutex_unlock(&stream->lock);
+ return -EIO;
+ }
+ } else if (stream->ops == STREAM_OPS_CAPTURE) {
+ if (sst_capture_frame(str_id) < 0) {
+ pr_warn("sst: capture frames failed\n ");
+ mutex_unlock(&stream->lock);
+ return -EIO;
+ }
+ }
+ } else {
+ mutex_unlock(&stream->lock);
+ return -EIO;
+ }
+ mutex_unlock(&stream->lock);
+ /* Block the call for reply */
+
+ retval = sst_wait_interruptible(sst_drv_ctx, &stream->data_blk);
+ if (retval) {
+ stream->status = STREAM_INIT;
+ pr_debug("sst: wait returned error...\n");
+ }
+ return retval;
+}
+
+/* fills kernel list with buffer addresses for SST DSP driver to process*/
+static int snd_sst_fill_kernel_list(struct stream_info *stream,
+ const struct iovec *iovec, unsigned long nr_segs,
+ struct list_head *copy_to_list)
+{
+ struct sst_stream_bufs *stream_bufs;
+ unsigned long index, data_not_copied, mmap_len;
+ unsigned char *bufp;
+ unsigned long size, copied_size;
+ int retval = 0, add_to_list = 0;
+ static int sent_offset;
+ static unsigned long sent_index;
+
+ stream_bufs = kzalloc(sizeof(*stream_bufs), GFP_KERNEL);
+ if (!stream_bufs)
+ return -ENOMEM;
+ stream_bufs->addr = sst_drv_ctx->mmap_mem;
+#ifdef CONFIG_MRST_RAR_HANDLER
+ if (stream->ops == STREAM_OPS_PLAYBACK_DRM) {
+ for (index = stream->sg_index; index < nr_segs; index++) {
+ __u32 rar_handle;
+ struct sst_stream_bufs *stream_bufs =
+ kzalloc(sizeof(*stream_bufs), GFP_KERNEL);
+
+ stream->sg_index = index;
+ if (!stream_bufs)
+ return -ENOMEM;
+ retval = copy_from_user((void *) &rar_handle,
+ iovec[index].iov_base,
+ sizeof(__u32));
+ if (retval != 0)
+ return -EFAULT;
+ stream_bufs->addr = (char *)rar_handle;
+ stream_bufs->in_use = false;
+ stream_bufs->size = iovec[0].iov_len;
+ /* locking here */
+ mutex_lock(&stream->lock);
+ list_add_tail(&stream_bufs->node, &stream->bufs);
+ mutex_unlock(&stream->lock);
+ }
+ stream->sg_index = index;
+ return retval;
+ }
+#endif
+ mmap_len = sst_drv_ctx->mmap_len;
+ stream_bufs->addr = sst_drv_ctx->mmap_mem;
+ bufp = stream->cur_ptr;
+
+ copied_size = 0;
+
+ if (!stream->sg_index)
+ sent_index = sent_offset = 0;
+
+ for (index = stream->sg_index; index < nr_segs; index++) {
+ stream->sg_index = index;
+ if (!stream->cur_ptr)
+ bufp = iovec[index].iov_base;
+
+ size = ((unsigned long)iovec[index].iov_base
+ + iovec[index].iov_len) - (unsigned long) bufp;
+
+ if ((copied_size + size) > mmap_len)
+ size = mmap_len - copied_size;
+
+
+ if (stream->ops == STREAM_OPS_PLAYBACK) {
+ data_not_copied = copy_from_user(
+ (void *)(stream_bufs->addr + copied_size),
+ bufp, size);
+ if (data_not_copied > 0) {
+ /* Clean up the list and return error code */
+ retval = -EFAULT;
+ break;
+ }
+ } else if (stream->ops == STREAM_OPS_CAPTURE) {
+ struct snd_sst_user_cap_list *entry =
+ kzalloc(sizeof(*entry), GFP_KERNEL);
+
+ if (!entry) {
+ kfree(stream_bufs);
+ return -ENOMEM;
+ }
+ entry->iov_index = index;
+ entry->iov_offset = (unsigned long) bufp -
+ (unsigned long)iovec[index].iov_base;
+ entry->offset = copied_size;
+ entry->size = size;
+ list_add_tail(&entry->node, copy_to_list);
+ }
+
+ stream->cur_ptr = bufp + size;
+
+ if (((unsigned long)iovec[index].iov_base
+ + iovec[index].iov_len) <
+ ((unsigned long)iovec[index].iov_base)) {
+ pr_debug("sst: Buffer overflows");
+ kfree(stream_bufs);
+ return -EINVAL;
+ }
+
+ if (((unsigned long)iovec[index].iov_base
+ + iovec[index].iov_len) ==
+ (unsigned long)stream->cur_ptr) {
+ stream->cur_ptr = NULL;
+ stream->sg_index++;
+ }
+
+ copied_size += size;
+ pr_debug("sst: copied_size - %lx\n", copied_size);
+ if ((copied_size >= mmap_len) ||
+ (stream->sg_index == nr_segs)) {
+ add_to_list = 1;
+ }
+
+ if (add_to_list) {
+ stream_bufs->in_use = false;
+ stream_bufs->size = copied_size;
+ /* locking here */
+ mutex_lock(&stream->lock);
+ list_add_tail(&stream_bufs->node, &stream->bufs);
+ mutex_unlock(&stream->lock);
+ break;
+ }
+ }
+ return retval;
+}
+
+/* This function copies the captured data returned from SST DSP engine
+ * to the user buffers*/
+static int snd_sst_copy_userbuf_capture(struct stream_info *stream,
+ const struct iovec *iovec,
+ struct list_head *copy_to_list)
+{
+ struct snd_sst_user_cap_list *entry, *_entry;
+ struct sst_stream_bufs *kbufs = NULL, *_kbufs;
+ int retval = 0;
+ unsigned long data_not_copied;
+
+ /* copy sent buffers */
+ pr_debug("sst: capture stream copying to user now...\n");
+ list_for_each_entry_safe(kbufs, _kbufs, &stream->bufs, node) {
+ if (kbufs->in_use == true) {
+ /* copy to user */
+ list_for_each_entry_safe(entry, _entry,
+ copy_to_list, node) {
+ data_not_copied = copy_to_user((void *)
+ iovec[entry->iov_index].iov_base +
+ entry->iov_offset,
+ kbufs->addr + entry->offset,
+ entry->size);
+ if (data_not_copied > 0) {
+ /* Clean up the list and return error */
+ retval = -EFAULT;
+ break;
+ }
+ list_del(&entry->node);
+ kfree(entry);
+ }
+ }
+ }
+ pr_debug("sst: end of cap copy\n");
+ return retval;
+}
+
+/*
+ * snd_sst_userbufs_play_cap - constructs the list from user buffers
+ *
+ * @iovec:pointer to iovec structure
+ * @nr_segs:number entries in the iovec structure
+ * @str_id:stream id
+ * @stream:pointer to stream_info structure
+ *
+ * This function will traverse the user list and copy the data to the kernel
+ * space buffers.
+ */
+static int snd_sst_userbufs_play_cap(const struct iovec *iovec,
+ unsigned long nr_segs, unsigned int str_id,
+ struct stream_info *stream)
+{
+ int retval;
+ LIST_HEAD(copy_to_list);
+
+
+ retval = snd_sst_fill_kernel_list(stream, iovec, nr_segs,
+ ©_to_list);
+
+ retval = intel_sst_play_capture(stream, str_id);
+ if (retval < 0)
+ return retval;
+
+ if (stream->ops == STREAM_OPS_CAPTURE) {
+ retval = snd_sst_copy_userbuf_capture(stream, iovec,
+ ©_to_list);
+ }
+ return retval;
+}
+
+/* This function is common function across read/write
+ for user buffers called from system calls*/
+static int intel_sst_read_write(unsigned int str_id, char __user *buf,
+ size_t count)
+{
+ int retval;
+ struct stream_info *stream;
+ struct iovec iovec;
+ unsigned long nr_segs;
+
+ retval = sst_validate_strid(str_id);
+ if (retval)
+ return -EINVAL;
+ stream = &sst_drv_ctx->streams[str_id];
+ if (stream->mmapped == true) {
+ pr_warn("sst: user write and stream is mapped");
+ return -EIO;
+ }
+ if (!count)
+ return -EINVAL;
+ stream->curr_bytes = 0;
+ stream->cumm_bytes = 0;
+ /* copy user buf details */
+ pr_debug("sst: new buffers %p, copy size %d, status %d\n" ,
+ buf, (int) count, (int) stream->status);
+
+ stream->buf_type = SST_BUF_USER_STATIC;
+ iovec.iov_base = (void *)buf;
+ iovec.iov_len = count;
+ nr_segs = 1;
+
+ do {
+ retval = snd_sst_userbufs_play_cap(
+ &iovec, nr_segs, str_id, stream);
+ if (retval < 0)
+ break;
+
+ } while (stream->sg_index < nr_segs);
+
+ stream->sg_index = 0;
+ stream->cur_ptr = NULL;
+ if (retval >= 0)
+ retval = stream->cumm_bytes;
+ pr_debug("sst: end of play/rec bytes = %d!!\n", retval);
+ return retval;
+}
+
+/***
+ * intel_sst_write - This function is called when user tries to play out data
+ *
+ * @file_ptr:pointer to file
+ * @buf:user buffer to be played out
+ * @count:size of tthe buffer
+ * @offset:offset to start from
+ *
+ * writes the encoded data into DSP
+ */
+int intel_sst_write(struct file *file_ptr, const char __user *buf,
+ size_t count, loff_t *offset)
+{
+ struct ioctl_pvt_data *data = file_ptr->private_data;
+ int str_id = data->str_id;
+ struct stream_info *stream = &sst_drv_ctx->streams[str_id];
+
+ pr_debug("sst: called for %d\n", str_id);
+ if (stream->status == STREAM_UN_INIT ||
+ stream->status == STREAM_DECODE) {
+ return -EBADRQC;
+ }
+ return intel_sst_read_write(str_id, (char __user *)buf, count);
+}
+
+/*
+ * intel_sst_aio_write - write buffers
+ *
+ * @kiocb:pointer to a structure containing file pointer
+ * @iov:list of user buffer to be played out
+ * @nr_segs:number of entries
+ * @offset:offset to start from
+ *
+ * This function is called when user tries to play out multiple data buffers
+ */
+ssize_t intel_sst_aio_write(struct kiocb *kiocb, const struct iovec *iov,
+ unsigned long nr_segs, loff_t offset)
+{
+ int retval;
+ struct ioctl_pvt_data *data = kiocb->ki_filp->private_data;
+ int str_id = data->str_id;
+ struct stream_info *stream;
+
+ pr_debug("sst: entry - %ld\n", nr_segs);
+
+ if (is_sync_kiocb(kiocb) == false)
+ return -EINVAL;
+
+ pr_debug("sst: called for str_id %d\n", str_id);
+ retval = sst_validate_strid(str_id);
+ if (retval)
+ return -EINVAL;
+ stream = &sst_drv_ctx->streams[str_id];
+ if (stream->mmapped == true)
+ return -EIO;
+ if (stream->status == STREAM_UN_INIT ||
+ stream->status == STREAM_DECODE) {
+ return -EBADRQC;
+ }
+ stream->curr_bytes = 0;
+ stream->cumm_bytes = 0;
+ pr_debug("sst: new segs %ld, offset %d, status %d\n" ,
+ nr_segs, (int) offset, (int) stream->status);
+ stream->buf_type = SST_BUF_USER_STATIC;
+ do {
+ retval = snd_sst_userbufs_play_cap(iov, nr_segs,
+ str_id, stream);
+ if (retval < 0)
+ break;
+
+ } while (stream->sg_index < nr_segs);
+
+ stream->sg_index = 0;
+ stream->cur_ptr = NULL;
+ if (retval >= 0)
+ retval = stream->cumm_bytes;
+ pr_debug("sst: end of play/rec bytes = %d!!\n", retval);
+ return retval;
+}
+
+/*
+ * intel_sst_read - read the encoded data
+ *
+ * @file_ptr: pointer to file
+ * @buf: user buffer to be filled with captured data
+ * @count: size of tthe buffer
+ * @offset: offset to start from
+ *
+ * This function is called when user tries to capture data
+ */
+int intel_sst_read(struct file *file_ptr, char __user *buf,
+ size_t count, loff_t *offset)
+{
+ struct ioctl_pvt_data *data = file_ptr->private_data;
+ int str_id = data->str_id;
+ struct stream_info *stream = &sst_drv_ctx->streams[str_id];
+
+ pr_debug("sst: called for %d\n", str_id);
+ if (stream->status == STREAM_UN_INIT ||
+ stream->status == STREAM_DECODE)
+ return -EBADRQC;
+ return intel_sst_read_write(str_id, buf, count);
+}
+
+/*
+ * intel_sst_aio_read - aio read
+ *
+ * @kiocb: pointer to a structure containing file pointer
+ * @iov: list of user buffer to be filled with captured
+ * @nr_segs: number of entries
+ * @offset: offset to start from
+ *
+ * This function is called when user tries to capture out multiple data buffers
+ */
+ssize_t intel_sst_aio_read(struct kiocb *kiocb, const struct iovec *iov,
+ unsigned long nr_segs, loff_t offset)
+{
+ int retval;
+ struct ioctl_pvt_data *data = kiocb->ki_filp->private_data;
+ int str_id = data->str_id;
+ struct stream_info *stream;
+
+ pr_debug("sst: entry - %ld\n", nr_segs);
+
+ if (is_sync_kiocb(kiocb) == false) {
+ pr_debug("sst: aio_read from user space is not allowed\n");
+ return -EINVAL;
+ }
+
+ pr_debug("sst: called for str_id %d\n", str_id);
+ retval = sst_validate_strid(str_id);
+ if (retval)
+ return -EINVAL;
+ stream = &sst_drv_ctx->streams[str_id];
+ if (stream->mmapped == true)
+ return -EIO;
+ if (stream->status == STREAM_UN_INIT ||
+ stream->status == STREAM_DECODE)
+ return -EBADRQC;
+ stream->curr_bytes = 0;
+ stream->cumm_bytes = 0;
+
+ pr_debug("sst: new segs %ld, offset %d, status %d\n" ,
+ nr_segs, (int) offset, (int) stream->status);
+ stream->buf_type = SST_BUF_USER_STATIC;
+ do {
+ retval = snd_sst_userbufs_play_cap(iov, nr_segs,
+ str_id, stream);
+ if (retval < 0)
+ break;
+
+ } while (stream->sg_index < nr_segs);
+
+ stream->sg_index = 0;
+ stream->cur_ptr = NULL;
+ if (retval >= 0)
+ retval = stream->cumm_bytes;
+ pr_debug("sst: end of play/rec bytes = %d!!\n", retval);
+ return retval;
+}
+
+/* sst_print_stream_params - prints the stream parameters (debug fn)*/
+static void sst_print_stream_params(struct snd_sst_get_stream_params *get_prm)
+{
+ pr_debug("sst: codec params:result =%d\n",
+ get_prm->codec_params.result);
+ pr_debug("sst: codec params:stream = %d\n",
+ get_prm->codec_params.stream_id);
+ pr_debug("sst: codec params:codec = %d\n",
+ get_prm->codec_params.codec);
+ pr_debug("sst: codec params:ops = %d\n",
+ get_prm->codec_params.ops);
+ pr_debug("sst: codec params:stream_type= %d\n",
+ get_prm->codec_params.stream_type);
+ pr_debug("sst: pcmparams:sfreq= %d\n",
+ get_prm->pcm_params.sfreq);
+ pr_debug("sst: pcmparams:num_chan= %d\n",
+ get_prm->pcm_params.num_chan);
+ pr_debug("sst: pcmparams:pcm_wd_sz= %d\n",
+ get_prm->pcm_params.pcm_wd_sz);
+ return;
+}
+
+/**
+ * intel_sst_ioctl - recieves the device ioctl's
+ * @file_ptr:pointer to file
+ * @cmd:Ioctl cmd
+ * @arg:data
+ *
+ * This function is called by OS when a user space component
+ * sends an Ioctl to SST driver
+ */
+long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg)
+{
+ int retval = 0;
+ struct ioctl_pvt_data *data = NULL;
+ int str_id = 0, minor = 0;
+
+ lock_kernel();
+
+ data = file_ptr->private_data;
+ if (data) {
+ minor = 0;
+ str_id = data->str_id;
+ } else
+ minor = 1;
+
+ if (sst_drv_ctx->sst_state != SST_FW_RUNNING) {
+ unlock_kernel();
+ return -EBUSY;
+ }
+
+ switch (_IOC_NR(cmd)) {
+ case _IOC_NR(SNDRV_SST_STREAM_PAUSE):
+ pr_debug("sst: IOCTL_PAUSE recieved for %d!\n", str_id);
+ if (minor != STREAM_MODULE) {
+ retval = -EBADRQC;
+ break;
+ }
+ retval = sst_pause_stream(str_id);
+ break;
+
+ case _IOC_NR(SNDRV_SST_STREAM_RESUME):
+ pr_debug("sst: SNDRV_SST_IOCTL_RESUME recieved!\n");
+ if (minor != STREAM_MODULE) {
+ retval = -EBADRQC;
+ break;
+ }
+ retval = sst_resume_stream(str_id);
+ break;
+
+ case _IOC_NR(SNDRV_SST_STREAM_SET_PARAMS): {
+ struct snd_sst_params *str_param = (struct snd_sst_params *)arg;
+
+ pr_debug("sst: IOCTL_SET_PARAMS recieved!\n");
+ if (minor != STREAM_MODULE) {
+ retval = -EBADRQC;
+ break;
+ }
+
+ if (!str_id) {
+
+ retval = sst_get_stream(str_param);
+ if (retval > 0) {
+ struct stream_info *str_info;
+ sst_drv_ctx->stream_cnt++;
+ data->str_id = retval;
+ str_info = &sst_drv_ctx->streams[retval];
+ str_info->src = SST_DRV;
+ retval = copy_to_user(&str_param->stream_id,
+ &retval, sizeof(__u32));
+ } else {
+ if (retval == -SST_ERR_INVALID_PARAMS)
+ retval = -EINVAL;
+ }
+ } else {
+ pr_debug("sst: SET_STREAM_PARAMS recieved!\n");
+ /* allocated set params only */
+ retval = sst_set_stream_param(str_id, str_param);
+ /* Block the call for reply */
+ if (!retval) {
+ int sfreq = 0, word_size = 0, num_channel = 0;
+ sfreq = str_param->sparams.uc.pcm_params.sfreq;
+ word_size = str_param->sparams.
+ uc.pcm_params.pcm_wd_sz;
+ num_channel = str_param->
+ sparams.uc.pcm_params.num_chan;
+ if (str_param->ops == STREAM_OPS_CAPTURE) {
+ sst_drv_ctx->scard_ops->\
+ set_pcm_audio_params(sfreq,
+ word_size, num_channel);
+ }
+ }
+ }
+ break;
+ }
+ case _IOC_NR(SNDRV_SST_SET_VOL): {
+ struct snd_sst_vol *set_vol;
+ struct snd_sst_vol *rec_vol = (struct snd_sst_vol *)arg;
+ pr_debug("sst: SET_VOLUME recieved for %d!\n",
+ rec_vol->stream_id);
+ if (minor == STREAM_MODULE && rec_vol->stream_id == 0) {
+ pr_debug("sst: invalid operation!\n");
+ retval = -EPERM;
+ break;
+ }
+ set_vol = kzalloc(sizeof(*set_vol), GFP_ATOMIC);
+ if (!set_vol) {
+ pr_debug("sst: mem allocation failed\n");
+ retval = -ENOMEM;
+ break;
+ }
+ retval = copy_from_user(set_vol, rec_vol, sizeof(*set_vol));
+ if (retval) {
+ pr_debug("sst: copy failed\n");
+ retval = -EAGAIN;
+ break;
+ }
+ retval = sst_set_vol(set_vol);
+ kfree(set_vol);
+ break;
+ }
+ case _IOC_NR(SNDRV_SST_GET_VOL): {
+ struct snd_sst_vol *rec_vol = (struct snd_sst_vol *)arg;
+ struct snd_sst_vol get_vol;
+ pr_debug("sst: IOCTL_GET_VOLUME recieved for stream = %d!\n",
+ rec_vol->stream_id);
+ if (minor == STREAM_MODULE && rec_vol->stream_id == 0) {
+ pr_debug("sst: invalid operation!\n");
+ retval = -EPERM;
+ break;
+ }
+ get_vol.stream_id = rec_vol->stream_id;
+ retval = sst_get_vol(&get_vol);
+ if (retval) {
+ retval = -EIO;
+ break;
+ }
+ pr_debug("sst: id:%d\n, vol:%d, ramp_dur:%d, ramp_type:%d\n",
+ get_vol.stream_id, get_vol.volume,
+ get_vol.ramp_duration, get_vol.ramp_type);
+ retval = copy_to_user((struct snd_sst_vol *)arg,
+ &get_vol, sizeof(get_vol));
+ if (retval) {
+ retval = -EIO;
+ break;
+ }
+ /*sst_print_get_vol_info(str_id, &get_vol);*/
+ break;
+ }
+
+ case _IOC_NR(SNDRV_SST_MUTE): {
+ struct snd_sst_mute *set_mute;
+ struct snd_sst_vol *rec_mute = (struct snd_sst_vol *)arg;
+ pr_debug("sst: SNDRV_SST_SET_VOLUME recieved for %d!\n",
+ rec_mute->stream_id);
+ if (minor == STREAM_MODULE && rec_mute->stream_id == 0) {
+ retval = -EPERM;
+ break;
+ }
+ set_mute = kzalloc(sizeof(*set_mute), GFP_ATOMIC);
+ if (!set_mute) {
+ retval = -ENOMEM;
+ break;
+ }
+ retval = copy_from_user(set_mute, rec_mute, sizeof(*set_mute));
+ if (retval) {
+ retval = -EFAULT;
+ break;
+ }
+ retval = sst_set_mute(set_mute);
+ kfree(set_mute);
+ break;
+ }
+ case _IOC_NR(SNDRV_SST_STREAM_GET_PARAMS): {
+ struct snd_sst_get_stream_params get_params;
+
+ pr_debug("sst: IOCTL_GET_PARAMS recieved!\n");
+ if (minor != 0) {
+ retval = -EBADRQC;
+ break;
+ }
+
+ retval = sst_get_stream_params(str_id, &get_params);
+ if (retval) {
+ retval = -EIO;
+ break;
+ }
+ retval = copy_to_user((struct snd_sst_get_stream_params *)arg,
+ &get_params, sizeof(get_params));
+ if (retval) {
+ retval = -EBUSY;
+ break;
+ }
+ sst_print_stream_params(&get_params);
+ break;
+ }
+
+ case _IOC_NR(SNDRV_SST_MMAP_PLAY):
+ case _IOC_NR(SNDRV_SST_MMAP_CAPTURE):
+ pr_debug("sst: SNDRV_SST_MMAP_PLAY/CAPTURE recieved!\n");
+ if (minor != STREAM_MODULE) {
+ retval = -EBADRQC;
+ break;
+ }
+ retval = intel_sst_mmap_play_capture(str_id,
+ (struct snd_sst_mmap_buffs *)arg);
+ break;
+
+ case _IOC_NR(SNDRV_SST_STREAM_DROP):
+ pr_debug("sst: SNDRV_SST_IOCTL_DROP recieved!\n");
+ if (minor != STREAM_MODULE) {
+ retval = -EINVAL;
+ break;
+ }
+ retval = sst_drop_stream(str_id);
+ break;
+
+ case _IOC_NR(SNDRV_SST_STREAM_GET_TSTAMP): {
+ unsigned long long *ms = (unsigned long long *)arg;
+ struct snd_sst_tstamp tstamp = {0};
+ unsigned long long time, freq, mod;
+
+ pr_debug("sst: SNDRV_SST_STREAM_GET_TSTAMP recieved!\n");
+ if (minor != STREAM_MODULE) {
+ retval = -EBADRQC;
+ break;
+ }
+ memcpy_fromio(&tstamp,
+ ((void *)(sst_drv_ctx->mailbox + SST_TIME_STAMP)
+ +(str_id * sizeof(tstamp))),
+ sizeof(tstamp));
+ time = tstamp.samples_rendered;
+ freq = (unsigned long long) tstamp.sampling_frequency;
+ time = time * 1000; /* converting it to ms */
+ mod = do_div(time, freq);
+ retval = copy_to_user(ms, &time, sizeof(*ms));
+ if (retval)
+ retval = -EFAULT;
+ break;
+ }
+
+ case _IOC_NR(SNDRV_SST_STREAM_START):{
+ struct stream_info *stream;
+
+ pr_debug("sst: SNDRV_SST_STREAM_START recieved!\n");
+ if (minor != STREAM_MODULE) {
+ retval = -EINVAL;
+ break;
+ }
+ retval = sst_validate_strid(str_id);
+ if (retval)
+ break;
+ stream = &sst_drv_ctx->streams[str_id];
+ mutex_lock(&stream->lock);
+ if (stream->status == STREAM_INIT &&
+ stream->need_draining != true) {
+ stream->prev = stream->status;
+ stream->status = STREAM_RUNNING;
+ if (stream->ops == STREAM_OPS_PLAYBACK ||
+ stream->ops == STREAM_OPS_PLAYBACK_DRM) {
+ retval = sst_play_frame(str_id);
+ } else if (stream->ops == STREAM_OPS_CAPTURE)
+ retval = sst_capture_frame(str_id);
+ else {
+ retval = -EINVAL;
+ mutex_unlock(
+ &sst_drv_ctx->streams[str_id].lock);
+ break;
+ }
+ if (retval < 0) {
+ stream->status = STREAM_INIT;
+ mutex_unlock(
+ &sst_drv_ctx->streams[str_id].lock);
+ break;
+ }
+ } else {
+ retval = -EINVAL;
+ }
+ mutex_unlock(&sst_drv_ctx->streams[str_id].lock);
+ break;
+ }
+
+ case _IOC_NR(SNDRV_SST_SET_TARGET_DEVICE): {
+ struct snd_sst_target_device *target_device;
+
+ pr_debug("sst: SET_TARGET_DEVICE recieved!\n");
+ target_device = (struct snd_sst_target_device *)arg;
+ BUG_ON(!target_device);
+ if (minor != AM_MODULE) {
+ retval = -EBADRQC;
+ break;
+ }
+ retval = sst_target_device_select(target_device);
+ break;
+ }
+
+ case _IOC_NR(SNDRV_SST_DRIVER_INFO): {
+ struct snd_sst_driver_info *info =
+ (struct snd_sst_driver_info *)arg;
+
+ pr_debug("sst: SNDRV_SST_DRIVER_INFO recived\n");
+ info->version = SST_VERSION_NUM;
+ /* hard coding, shud get sumhow later */
+ info->active_pcm_streams = sst_drv_ctx->stream_cnt -
+ sst_drv_ctx->encoded_cnt;
+ info->active_enc_streams = sst_drv_ctx->encoded_cnt;
+ info->max_pcm_streams = MAX_ACTIVE_STREAM - MAX_ENC_STREAM;
+ info->max_enc_streams = MAX_ENC_STREAM;
+ info->buf_per_stream = sst_drv_ctx->mmap_len;
+ break;
+ }
+
+ case _IOC_NR(SNDRV_SST_STREAM_DECODE): {
+ struct snd_sst_dbufs *param =
+ (struct snd_sst_dbufs *)arg, dbufs_local;
+ int i;
+ struct snd_sst_buffs ibufs, obufs;
+ struct snd_sst_buff_entry ibuf_temp[param->ibufs->entries],
+ obuf_temp[param->obufs->entries];
+
+ pr_debug("sst: SNDRV_SST_STREAM_DECODE recived\n");
+ if (minor != STREAM_MODULE) {
+ retval = -EBADRQC;
+ break;
+ }
+ if (!param) {
+ retval = -EINVAL;
+ break;
+ }
+
+ dbufs_local.input_bytes_consumed = param->input_bytes_consumed;
+ dbufs_local.output_bytes_produced =
+ param->output_bytes_produced;
+ dbufs_local.ibufs = &ibufs;
+ dbufs_local.obufs = &obufs;
+ dbufs_local.ibufs->entries = param->ibufs->entries;
+ dbufs_local.ibufs->type = param->ibufs->type;
+ dbufs_local.obufs->entries = param->obufs->entries;
+ dbufs_local.obufs->type = param->obufs->type;
+
+ dbufs_local.ibufs->buff_entry = ibuf_temp;
+ for (i = 0; i < dbufs_local.ibufs->entries; i++) {
+ ibuf_temp[i].buffer =
+ param->ibufs->buff_entry[i].buffer;
+ ibuf_temp[i].size =
+ param->ibufs->buff_entry[i].size;
+ }
+ dbufs_local.obufs->buff_entry = obuf_temp;
+ for (i = 0; i < dbufs_local.obufs->entries; i++) {
+ obuf_temp[i].buffer =
+ param->obufs->buff_entry[i].buffer;
+ obuf_temp[i].size =
+ param->obufs->buff_entry[i].size;
+ }
+ retval = sst_decode(str_id, &dbufs_local);
+ if (retval)
+ retval = -EAGAIN;
+ retval = copy_to_user(¶m->input_bytes_consumed,
+ &dbufs_local.input_bytes_consumed,
+ sizeof(unsigned long long));
+ if (retval) {
+ retval = -EFAULT;
+ break;
+ }
+ retval = copy_to_user(¶m->output_bytes_produced,
+ &dbufs_local.output_bytes_produced,
+ sizeof(unsigned long long));
+ if (retval) {
+ retval = -EFAULT;
+ break;
+ }
+ break;
+ }
+
+ case _IOC_NR(SNDRV_SST_STREAM_DRAIN):
+ pr_debug("sst: SNDRV_SST_STREAM_DRAIN recived\n");
+ if (minor != STREAM_MODULE) {
+ retval = -EINVAL;
+ break;
+ }
+ retval = sst_drain_stream(str_id);
+ break;
+
+ case _IOC_NR(SNDRV_SST_STREAM_BYTES_DECODED): {
+ unsigned long long *bytes = (unsigned long long *)arg;
+ struct snd_sst_tstamp tstamp = {0};
+
+ pr_debug("sst: STREAM_BYTES_DECODED recieved!\n");
+ if (minor != STREAM_MODULE) {
+ retval = -EINVAL;
+ break;
+ }
+ memcpy_fromio(&tstamp,
+ ((void *)(sst_drv_ctx->mailbox + SST_TIME_STAMP)
+ +(str_id * sizeof(tstamp))),
+ sizeof(tstamp));
+ retval = copy_to_user(bytes, &tstamp.bytes_processed,
+ sizeof(*bytes));
+ if (retval)
+ retval = -EFAULT;
+ break;
+ }
+ case _IOC_NR(SNDRV_SST_FW_INFO): {
+ struct snd_sst_fw_info *fw_info;
+
+ pr_debug("sst: SNDRV_SST_FW_INFO recived\n");
+
+ fw_info = kzalloc(sizeof(*fw_info), GFP_ATOMIC);
+ if (!fw_info) {
+ retval = -ENOMEM;
+ break;
+ }
+ retval = sst_get_fw_info(fw_info);
+ if (retval) {
+ retval = -EIO;
+ kfree(fw_info);
+ break;
+ }
+ retval = copy_to_user((struct snd_sst_dbufs *)arg,
+ fw_info, sizeof(*fw_info));
+ if (retval) {
+ kfree(fw_info);
+ retval = -EFAULT;
+ break;
+ }
+ /*sst_print_fw_info(fw_info);*/
+ kfree(fw_info);
+ break;
+ }
+ default:
+ retval = -EINVAL;
+ }
+ unlock_kernel();
+ pr_debug("sst: intel_sst_ioctl:complete ret code = %d\n", retval);
+ return retval;
+}
+
diff --git a/drivers/staging/intel_sst/intel_sst_common.h b/drivers/staging/intel_sst/intel_sst_common.h
new file mode 100644
index 0000000..73a98c8
--- /dev/null
+++ b/drivers/staging/intel_sst/intel_sst_common.h
@@ -0,0 +1,618 @@
+#ifndef __INTEL_SST_COMMON_H__
+#define __INTEL_SST_COMMON_H__
+/*
+ * intel_sst_common.h - Intel SST Driver for audio engine
+ *
+ * Copyright (C) 2008-10 Intel Corporation
+ * Authors: Vinod Koul <vinod.koul(a)intel.com>
+ * Harsha Priya <priya.harsha(a)intel.com>
+ * Dharageswari R <dharageswari.r(a)intel.com>
+ * KP Jeeja <jeeja.kp(a)intel.com>
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * Common private declarations for SST
+ */
+
+#define SST_DRIVER_VERSION "1.2.05"
+#define SST_VERSION_NUM 0x1205
+
+/* driver names */
+#define SST_DRV_NAME "intel_sst_driver"
+#define SST_FW_FILENAME_MRST "fw_sst_080a.bin"
+#define SST_FW_FILENAME_MFLD "fw_sst_082f.bin"
+#define SST_MRST_PCI_ID 0x080A
+#define SST_MFLD_PCI_ID 0x082F
+
+enum sst_states {
+ SST_FW_LOADED = 1,
+ SST_FW_RUNNING,
+ SST_UN_INIT,
+ SST_ERROR,
+ SST_SUSPENDED
+};
+
+#define MAX_ACTIVE_STREAM 3
+#define MAX_ENC_STREAM 1
+#define MAX_AM_HANDLES 1
+#define ALLOC_TIMEOUT 5000
+/* SST numbers */
+#define SST_BLOCK_TIMEOUT 5000
+#define TARGET_DEV_BLOCK_TIMEOUT 5000
+
+#define BLOCK_UNINIT -1
+#define RX_TIMESLOT_UNINIT -1
+
+/* SST register map */
+#define SST_CSR 0x00
+#define SST_PISR 0x08
+#define SST_PIMR 0x10
+#define SST_ISRX 0x18
+#define SST_IMRX 0x28
+#define SST_IPCX 0x38 /* IPC IA-SST */
+#define SST_IPCD 0x40 /* IPC SST-IA */
+#define SST_ISRD 0x20 /* dummy register for shim workaround */
+#define SST_SHIM_SIZE 0X44
+
+#define SPI_MODE_ENABLE_BASE_ADDR 0xffae4000
+#define FW_SIGNATURE_SIZE 4
+
+/* PMIC and SST hardware states */
+enum sst_mad_states {
+ SND_MAD_UN_INIT = 0,
+ SND_MAD_INIT_DONE,
+};
+
+/* stream states */
+enum sst_stream_states {
+ STREAM_UN_INIT = 0, /* Freed/Not used stream */
+ STREAM_RUNNING = 1, /* Running */
+ STREAM_PAUSED = 2, /* Paused stream */
+ STREAM_DECODE = 3, /* stream is in decoding only state */
+ STREAM_INIT = 4, /* stream init, waiting for data */
+};
+
+
+enum sst_ram_type {
+ SST_IRAM = 1,
+ SST_DRAM = 2,
+};
+/* SST shim registers to structure mapping */
+union config_status_reg {
+ struct {
+ u32 rsvd0:1;
+ u32 sst_reset:1;
+ u32 hw_rsvd:3;
+ u32 sst_clk:2;
+ u32 bypass:3;
+ u32 run_stall:1;
+ u32 rsvd1:2;
+ u32 strb_cntr_rst:1;
+ u32 rsvd:18;
+ } part;
+ u32 full;
+};
+
+union interrupt_reg {
+ struct {
+ u32 done_interrupt:1;
+ u32 busy_interrupt:1;
+ u32 rsvd:30;
+ } part;
+ u32 full;
+};
+
+union sst_pisr_reg {
+ struct {
+ u32 pssp0:1;
+ u32 pssp1:1;
+ u32 rsvd0:3;
+ u32 dmac:1;
+ u32 rsvd1:26;
+ } part;
+ u32 full;
+};
+
+union sst_pimr_reg {
+ struct {
+ u32 ssp0:1;
+ u32 ssp1:1;
+ u32 rsvd0:3;
+ u32 dmac:1;
+ u32 rsvd1:10;
+ u32 ssp0_sc:1;
+ u32 ssp1_sc:1;
+ u32 rsvd2:3;
+ u32 dmac_sc:1;
+ u32 rsvd3:10;
+ } part;
+ u32 full;
+};
+
+
+struct sst_stream_bufs {
+ struct list_head node;
+ u32 size;
+ const char *addr;
+ u32 data_copied;
+ bool in_use;
+ u32 offset;
+};
+
+struct snd_sst_user_cap_list {
+ unsigned int iov_index; /* index of iov */
+ unsigned long iov_offset; /* offset in iov */
+ unsigned long offset; /* offset in kmem */
+ unsigned long size; /* size copied */
+ struct list_head node;
+};
+/*
+This structure is used to block a user/fw data call to another
+fw/user call
+*/
+struct sst_block {
+ bool condition; /* condition for blocking check */
+ int ret_code; /* ret code when block is released */
+ void *data; /* data to be appsed for block if any */
+ bool on;
+};
+
+enum snd_sst_buf_type {
+ SST_BUF_USER_STATIC = 1,
+ SST_BUF_USER_DYNAMIC,
+ SST_BUF_MMAP_STATIC,
+ SST_BUF_MMAP_DYNAMIC,
+};
+
+enum snd_src {
+ SST_DRV = 1,
+ MAD_DRV = 2
+};
+
+/**
+ * struct stream_info - structure that holds the stream information
+ *
+ * @status : stream current state
+ * @prev : stream prev state
+ * @codec : stream codec
+ * @sst_id : stream id
+ * @ops : stream operation pb/cp/drm...
+ * @bufs: stream buffer list
+ * @lock : stream mutex for protecting state
+ * @pcm_lock : spinlock for pcm path only
+ * @mmapped : is stream mmapped
+ * @sg_index : current stream user buffer index
+ * @cur_ptr : stream user buffer pointer
+ * @buf_entry : current user buffer
+ * @data_blk : stream block for data operations
+ * @ctrl_blk : stream block for ctrl operations
+ * @buf_type : stream user buffer type
+ * @pcm_substream : PCM substream
+ * @period_elapsed : PCM period elapsed callback
+ * @sfreq : stream sampling freq
+ * @decode_ibuf : Decoded i/p buffers pointer
+ * @decode_obuf : Decoded o/p buffers pointer
+ * @decode_isize : Decoded i/p buffers size
+ * @decode_osize : Decoded o/p buffers size
+ * @decode_ibuf_type : Decoded i/p buffer type
+ * @decode_obuf_type : Decoded o/p buffer type
+ * @idecode_alloc : Decode alloc index
+ * @need_draining : stream set for drain
+ * @str_type : stream type
+ * @curr_bytes : current bytes decoded
+ * @cumm_bytes : cummulative bytes decoded
+ * @str_type : stream type
+ * @src : stream source
+ * @device : output device type (medfield only)
+ * @pcm_slot : pcm slot value
+ */
+struct stream_info {
+ unsigned int status;
+ unsigned int prev;
+ u8 codec;
+ unsigned int sst_id;
+ unsigned int ops;
+ struct list_head bufs;
+ struct mutex lock; /* mutex */
+ spinlock_t pcm_lock;
+ bool mmapped;
+ unsigned int sg_index; /* current buf Index */
+ unsigned char *cur_ptr; /* Current static bufs */
+ struct snd_sst_buf_entry *buf_entry;
+ struct sst_block data_blk; /* stream ops block */
+ struct sst_block ctrl_blk; /* stream control cmd block */
+ enum snd_sst_buf_type buf_type;
+ void *pcm_substream;
+ void (*period_elapsed) (void *pcm_substream);
+ unsigned int sfreq;
+ void *decode_ibuf, *decode_obuf;
+ unsigned int decode_isize, decode_osize;
+ u8 decode_ibuf_type, decode_obuf_type;
+ unsigned int idecode_alloc;
+ unsigned int need_draining;
+ unsigned int str_type;
+ u32 curr_bytes;
+ u32 cumm_bytes;
+ u32 src;
+ enum snd_sst_audio_device_type device;
+ u8 pcm_slot;
+};
+
+/*
+ * struct stream_alloc_bloc - this structure is used for blocking the user's
+ * alloc calls to fw's response to alloc calls
+ *
+ * @sst_id : session id of blocked stream
+ * @ops_block : ops block struture
+ */
+struct stream_alloc_block {
+ int sst_id; /* session id of blocked stream */
+ struct sst_block ops_block; /* ops block struture */
+};
+
+#define SST_FW_SIGN "$SST"
+#define SST_FW_LIB_SIGN "$LIB"
+
+/*
+ * struct fw_header - FW file headers
+ *
+ * @signature : FW signature
+ * @modules : # of modules
+ * @file_format : version of header format
+ * @reserved : reserved fields
+ */
+struct fw_header {
+ unsigned char signature[FW_SIGNATURE_SIZE]; /* FW signature */
+ u32 file_size; /* size of fw minus this header */
+ u32 modules; /* # of modules */
+ u32 file_format; /* version of header format */
+ u32 reserved[4];
+};
+
+struct fw_module_header {
+ unsigned char signature[FW_SIGNATURE_SIZE]; /* module signature */
+ u32 mod_size; /* size of module */
+ u32 blocks; /* # of blocks */
+ u32 type; /* codec type, pp lib */
+ u32 entry_point;
+};
+
+struct dma_block_info {
+ enum sst_ram_type type; /* IRAM/DRAM */
+ u32 size; /* Bytes */
+ u32 ram_offset; /* Offset in I/DRAM */
+ u32 rsvd; /* Reserved field */
+};
+
+struct ioctl_pvt_data {
+ int str_id;
+ int pvt_id;
+};
+
+struct sst_ipc_msg_wq {
+ union ipc_header header;
+ char mailbox[SST_MAILBOX_SIZE];
+ struct work_struct wq;
+};
+
+struct mad_ops_wq {
+ int stream_id;
+ enum sst_controls control_op;
+ struct work_struct wq;
+
+};
+
+#define SST_MMAP_PAGES (640*1024 / PAGE_SIZE)
+#define SST_MMAP_STEP (40*1024 / PAGE_SIZE)
+
+/***
+ * struct intel_sst_drv - driver ops
+ *
+ * @pmic_state : pmic state
+ * @pmic_vendor : pmic vendor detected
+ * @sst_state : current sst device state
+ * @pci_id : PCI device id loaded
+ * @shim : SST shim pointer
+ * @mailbox : SST mailbox pointer
+ * @iram : SST IRAM pointer
+ * @dram : SST DRAM pointer
+ * @shim_phy_add : SST shim phy addr
+ * @ipc_dispatch_list : ipc messages dispatched
+ * @ipc_post_msg_wq : wq to post IPC messages context
+ * @ipc_process_msg : wq to process msgs from FW context
+ * @ipc_process_reply : wq to process reply from FW context
+ * @ipc_post_msg : wq to post reply from FW context
+ * @mad_ops : MAD driver operations registered
+ * @mad_wq : MAD driver wq
+ * @post_msg_wq : wq to post IPC messages
+ * @process_msg_wq : wq to process msgs from FW
+ * @process_reply_wq : wq to process reply from FW
+ * @streams : sst stream contexts
+ * @alloc_block : block structure for alloc
+ * @tgt_dev_blk : block structure for target device
+ * @fw_info_blk : block structure for fw info block
+ * @vol_info_blk : block structure for vol info block
+ * @mute_info_blk : block structure for mute info block
+ * @hs_info_blk : block structure for hs info block
+ * @list_lock : sst driver list lock (deprecated)
+ * @list_spin_lock : sst driver spin lock block
+ * @scard_ops : sst card ops
+ * @pci : sst pci device struture
+ * @active_streams : sst active streams
+ * @sst_lock : sst device lock
+ * @stream_lock : sst stream lock
+ * @unique_id : sst unique id
+ * @stream_cnt : total sst active stream count
+ * @pb_streams : total active pb streams
+ * @cp_streams : total active cp streams
+ * @lpe_stalled : lpe stall status
+ * @pmic_port_instance : active pmic port instance
+ * @rx_time_slot_status : active rx slot
+ * @lpaudio_start : lpaudio status
+ * @audio_start : audio status
+ * @devt_d : pointer to /dev/lpe node
+ * @devt_c : pointer to /dev/lpe_ctrl node
+ * @max_streams : max streams allowed
+ */
+struct intel_sst_drv {
+ bool pmic_state;
+ int pmic_vendor;
+ int sst_state;
+ unsigned int pci_id;
+ void __iomem *shim;
+ void __iomem *mailbox;
+ void __iomem *iram;
+ void __iomem *dram;
+ unsigned int shim_phy_add;
+ struct list_head ipc_dispatch_list;
+ struct work_struct ipc_post_msg_wq;
+ struct sst_ipc_msg_wq ipc_process_msg;
+ struct sst_ipc_msg_wq ipc_process_reply;
+ struct sst_ipc_msg_wq ipc_post_msg;
+ struct mad_ops_wq mad_ops;
+ wait_queue_head_t wait_queue;
+ struct workqueue_struct *mad_wq;
+ struct workqueue_struct *post_msg_wq;
+ struct workqueue_struct *process_msg_wq;
+ struct workqueue_struct *process_reply_wq;
+
+ struct stream_info streams[MAX_NUM_STREAMS];
+ struct stream_alloc_block alloc_block[MAX_ACTIVE_STREAM];
+ struct sst_block tgt_dev_blk, fw_info_blk,
+ vol_info_blk, mute_info_blk, hs_info_blk;
+ struct mutex list_lock;/* mutex for IPC list locking */
+ spinlock_t list_spin_lock; /* mutex for IPC list locking */
+ struct snd_pmic_ops *scard_ops;
+ struct pci_dev *pci;
+ int active_streams[MAX_NUM_STREAMS];
+ void *mmap_mem;
+ struct mutex sst_lock;
+ struct mutex stream_lock;
+ unsigned int mmap_len;
+ unsigned int unique_id;
+ unsigned int stream_cnt; /* total streams */
+ unsigned int encoded_cnt; /* enocded streams only */
+ unsigned int am_cnt;
+ unsigned int pb_streams; /* pb streams active */
+ unsigned int cp_streams; /* cp streams active */
+ unsigned int lpe_stalled; /* LPE is stalled or not */
+ unsigned int pmic_port_instance; /*pmic port instance*/
+ int rx_time_slot_status;
+ unsigned int lpaudio_start;
+ /* 1 - LPA stream(MP3 pb) in progress*/
+ unsigned int audio_start;
+ dev_t devt_d, devt_c;
+ unsigned int max_streams;
+};
+
+extern struct intel_sst_drv *sst_drv_ctx;
+
+#define CHIP_REV_REG 0xff108000
+#define CHIP_REV_ADDR 0x78
+
+/* misc definitions */
+#define FW_DWNL_ID 0xFF
+#define LOOP1 0x11111111
+#define LOOP2 0x22222222
+#define LOOP3 0x33333333
+#define LOOP4 0x44444444
+
+#define SST_DEFAULT_PMIC_PORT 1 /*audio port*/
+/* NOTE: status will have +ve for good cases and -ve for error ones */
+#define MAX_STREAM_FIELD 255
+
+int sst_alloc_stream(char *params, unsigned int stream_ops, u8 codec,
+ unsigned int session_id);
+int sst_alloc_stream_response(unsigned int str_id,
+ struct snd_sst_alloc_response *response);
+int sst_stalled(void);
+int sst_pause_stream(int id);
+int sst_resume_stream(int id);
+int sst_enable_rx_timeslot(int status);
+int sst_drop_stream(int id);
+int sst_free_stream(int id);
+int sst_start_stream(int streamID);
+int sst_play_frame(int streamID);
+int sst_pcm_play_frame(int str_id, struct sst_stream_bufs *sst_buf);
+int sst_capture_frame(int streamID);
+int sst_set_stream_param(int streamID, struct snd_sst_params *str_param);
+int sst_target_device_select(struct snd_sst_target_device *target_device);
+int sst_decode(int str_id, struct snd_sst_dbufs *dbufs);
+int sst_get_decoded_bytes(int str_id, unsigned long long *bytes);
+int sst_get_fw_info(struct snd_sst_fw_info *info);
+int sst_get_stream_params(int str_id,
+ struct snd_sst_get_stream_params *get_params);
+int sst_get_stream(struct snd_sst_params *str_param);
+int sst_get_stream_allocated(struct snd_sst_params *str_param,
+ struct snd_sst_lib_download **lib_dnld);
+int sst_drain_stream(int str_id);
+int sst_get_vol(struct snd_sst_vol *set_vol);
+int sst_set_vol(struct snd_sst_vol *set_vol);
+int sst_set_mute(struct snd_sst_mute *set_mute);
+
+
+void sst_post_message(struct work_struct *work);
+void sst_process_message(struct work_struct *work);
+void sst_process_reply(struct work_struct *work);
+void sst_process_mad_ops(struct work_struct *work);
+void sst_process_mad_jack_detection(struct work_struct *work);
+
+long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd,
+ unsigned long arg);
+int intel_sst_open(struct inode *i_node, struct file *file_ptr);
+int intel_sst_open_cntrl(struct inode *i_node, struct file *file_ptr);
+int intel_sst_release(struct inode *i_node, struct file *file_ptr);
+int intel_sst_release_cntrl(struct inode *i_node, struct file *file_ptr);
+int intel_sst_read(struct file *file_ptr, char __user *buf,
+ size_t count, loff_t *ppos);
+int intel_sst_write(struct file *file_ptr, const char __user *buf,
+ size_t count, loff_t *ppos);
+int intel_sst_mmap(struct file *fp, struct vm_area_struct *vma);
+ssize_t intel_sst_aio_write(struct kiocb *kiocb, const struct iovec *iov,
+ unsigned long nr_segs, loff_t offset);
+ssize_t intel_sst_aio_read(struct kiocb *kiocb, const struct iovec *iov,
+ unsigned long nr_segs, loff_t offset);
+
+int sst_load_fw(const struct firmware *fw, void *context);
+int sst_load_library(struct snd_sst_lib_download *lib, u8 ops);
+int sst_spi_mode_enable(void);
+int sst_get_block_stream(struct intel_sst_drv *sst_drv_ctx);
+
+int sst_wait_interruptible(struct intel_sst_drv *sst_drv_ctx,
+ struct sst_block *block);
+int sst_wait_interruptible_timeout(struct intel_sst_drv *sst_drv_ctx,
+ struct sst_block *block, int timeout);
+int sst_wait_timeout(struct intel_sst_drv *sst_drv_ctx,
+ struct stream_alloc_block *block);
+int sst_create_large_msg(struct ipc_post **arg);
+int sst_create_short_msg(struct ipc_post **arg);
+void sst_wake_up_alloc_block(struct intel_sst_drv *sst_drv_ctx,
+ u8 sst_id, int status, void *data);
+void sst_clear_interrupt(void);
+int intel_sst_resume(struct pci_dev *pci);
+int sst_download_fw(void);
+void free_stream_context(unsigned int str_id);
+void sst_clean_stream(struct stream_info *stream);
+
+/*
+ * sst_fill_header - inline to fill sst header
+ *
+ * @header : ipc header
+ * @msg : IPC message to be sent
+ * @large : is ipc large msg
+ * @str_id : stream id
+ *
+ * this function is an inline function that sets the headers before
+ * sending a message
+ */
+static inline void sst_fill_header(union ipc_header *header,
+ int msg, int large, int str_id)
+{
+ header->part.msg_id = msg;
+ header->part.str_id = str_id;
+ header->part.large = large;
+ header->part.done = 0;
+ header->part.busy = 1;
+ header->part.data = 0;
+}
+
+/*
+ * sst_assign_pvt_id - assign a pvt id for stream
+ *
+ * @sst_drv_ctx : driver context
+ *
+ * this inline function assigns a private id for calls that dont have stream
+ * context yet, should be called with lock held
+ */
+static inline unsigned int sst_assign_pvt_id(struct intel_sst_drv *sst_drv_ctx)
+{
+ sst_drv_ctx->unique_id++;
+ if (sst_drv_ctx->unique_id >= MAX_NUM_STREAMS)
+ sst_drv_ctx->unique_id = 1;
+ return sst_drv_ctx->unique_id;
+}
+
+/*
+ * sst_init_stream - this function initialzes stream context
+ *
+ * @stream : stream struture
+ * @codec : codec for stream
+ * @sst_id : stream id
+ * @ops : stream operation
+ * @slot : stream pcm slot
+ * @device : device type
+ *
+ * this inline function initialzes stream context for allocated stream
+ */
+static inline void sst_init_stream(struct stream_info *stream,
+ int codec, int sst_id, int ops, u8 slot,
+ enum snd_sst_audio_device_type device)
+{
+ stream->status = STREAM_INIT;
+ stream->prev = STREAM_UN_INIT;
+ stream->codec = codec;
+ stream->sst_id = sst_id;
+ stream->str_type = 0;
+ stream->ops = ops;
+ stream->data_blk.on = false;
+ stream->data_blk.condition = false;
+ stream->data_blk.ret_code = 0;
+ stream->data_blk.data = NULL;
+ stream->ctrl_blk.on = false;
+ stream->ctrl_blk.condition = false;
+ stream->ctrl_blk.ret_code = 0;
+ stream->ctrl_blk.data = NULL;
+ stream->need_draining = false;
+ stream->decode_ibuf = NULL;
+ stream->decode_isize = 0;
+ stream->mmapped = false;
+ stream->pcm_slot = slot;
+ stream->device = device;
+}
+
+
+/*
+ * sst_validate_strid - this function validates the stream id
+ *
+ * @str_id : stream id to be validated
+ *
+ * returns 0 if valid stream
+ */
+static inline int sst_validate_strid(int str_id)
+{
+ if (str_id <= 0 || str_id > sst_drv_ctx->max_streams) {
+ pr_err("SST ERR: invalid stream id : %d MAX_STREAMS:%d\n",
+ str_id, sst_drv_ctx->max_streams);
+ return -EINVAL;
+ } else
+ return 0;
+}
+
+static inline int sst_shim_write(void __iomem *addr, int offset, int value)
+{
+
+ if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID)
+ writel(value, addr + SST_ISRD); /*dummy*/
+ writel(value, addr + offset);
+ return 0;
+}
+
+static inline int sst_shim_read(void __iomem *addr, int offset)
+{
+ return readl(addr + offset);
+}
+#endif /* __INTEL_SST_COMMON_H__ */
diff --git a/drivers/staging/intel_sst/intel_sst_drv_interface.c b/drivers/staging/intel_sst/intel_sst_drv_interface.c
new file mode 100644
index 0000000..715c2d8
--- /dev/null
+++ b/drivers/staging/intel_sst/intel_sst_drv_interface.c
@@ -0,0 +1,492 @@
+/*
+ * intel_sst_interface.c - Intel SST Driver for audio engine
+ *
+ * Copyright (C) 2008-10 Intel Corp
+ * Authors: Vinod Koul <vinod.koul(a)intel.com>
+ * Harsha Priya <priya.harsha(a)intel.com>
+ * Dharageswari R <dharageswari.r(a)intel.com)
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * This driver exposes the audio engine functionalities to the ALSA
+ * and middleware.
+ * Upper layer interfaces (MAD driver, MMF) to SST driver
+ */
+
+#include <linux/pci.h>
+#include <linux/fs.h>
+#include <linux/firmware.h>
+#include "intel_sst.h"
+#include "intel_sst_ioctl.h"
+#include "intel_sst_fw_ipc.h"
+#include "intel_sst_common.h"
+
+
+/*
+ * sst_download_fw - download the audio firmware to DSP
+ *
+ * This function is called when the FW needs to be downloaded to SST DSP engine
+ */
+int sst_download_fw(void)
+{
+ int retval;
+ const struct firmware *fw_sst;
+ const char *name;
+ if (sst_drv_ctx->sst_state != SST_UN_INIT)
+ return -EPERM;
+ if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID)
+ name = SST_FW_FILENAME_MRST;
+ else
+ name = SST_FW_FILENAME_MFLD;
+ pr_debug("sst: Downloading %s FW now...\n", name);
+ retval = request_firmware(&fw_sst, name, &sst_drv_ctx->pci->dev);
+ if (retval) {
+ pr_err("sst: request fw failed %d\n", retval);
+ return retval;
+ }
+ sst_drv_ctx->alloc_block[0].sst_id = FW_DWNL_ID;
+ sst_drv_ctx->alloc_block[0].ops_block.condition = false;
+ retval = sst_load_fw(fw_sst, NULL);
+ if (retval)
+ goto end_restore;
+
+ retval = sst_wait_timeout(sst_drv_ctx, &sst_drv_ctx->alloc_block[0]);
+ if (retval)
+ pr_err("sst: fw download failed %d\n" , retval);
+end_restore:
+ release_firmware(fw_sst);
+ sst_drv_ctx->alloc_block[0].sst_id = BLOCK_UNINIT;
+ return retval;
+}
+
+
+/*
+ * sst_stalled - this function checks if the lpe is in stalled state
+ */
+int sst_stalled(void)
+{
+ int retry = 1000;
+ int retval = -1;
+
+ while (retry) {
+ if (!sst_drv_ctx->lpe_stalled)
+ return 0;
+ /*wait for time and re-check*/
+ msleep(1);
+
+ retry--;
+ }
+ pr_debug("sst: in Stalled State\n");
+ return retval;
+}
+
+void free_stream_context(unsigned int str_id)
+{
+ struct stream_info *stream;
+
+ if (!sst_validate_strid(str_id)) {
+ /* str_id is valid, so stream is alloacted */
+ stream = &sst_drv_ctx->streams[str_id];
+ if (stream->ops == STREAM_OPS_PLAYBACK ||
+ stream->ops == STREAM_OPS_PLAYBACK_DRM) {
+ sst_drv_ctx->pb_streams--;
+ if (sst_drv_ctx->pb_streams == 0)
+ sst_drv_ctx->scard_ops->power_down_pmic_pb();
+ } else if (stream->ops == STREAM_OPS_CAPTURE) {
+ sst_drv_ctx->cp_streams--;
+ if (sst_drv_ctx->cp_streams == 0)
+ sst_drv_ctx->scard_ops->power_down_pmic_cp();
+ }
+ if (sst_drv_ctx->pb_streams == 0
+ && sst_drv_ctx->cp_streams == 0)
+ sst_drv_ctx->scard_ops->power_down_pmic();
+ if (sst_free_stream(str_id))
+ sst_clean_stream(&sst_drv_ctx->streams[str_id]);
+ }
+}
+
+/*
+ * sst_get_stream_allocated - this function gets a stream allocated with
+ * the given params
+ *
+ * @str_param : stream params
+ * @lib_dnld : pointer to pointer of lib downlaod struct
+ *
+ * This creates new stream id for a stream, in case lib is to be downloaded to
+ * DSP, it downloads that
+ */
+int sst_get_stream_allocated(struct snd_sst_params *str_param,
+ struct snd_sst_lib_download **lib_dnld)
+{
+ int retval, str_id;
+ struct stream_info *str_info;
+
+ retval = sst_alloc_stream((char *) &str_param->sparams, str_param->ops,
+ str_param->codec, str_param->device_type);
+ if (retval < 0) {
+ pr_err("sst: sst_alloc_stream failed %d\n", retval);
+ return retval;
+ }
+ pr_debug("sst: Stream allocated %d\n", retval);
+ str_id = retval;
+ str_info = &sst_drv_ctx->streams[str_id];
+ /* Block the call for reply */
+ retval = sst_wait_interruptible_timeout(sst_drv_ctx,
+ &str_info->ctrl_blk, SST_BLOCK_TIMEOUT);
+ if ((retval != 0) || (str_info->ctrl_blk.ret_code != 0)) {
+ pr_debug("sst: FW alloc failed retval %d, ret_code %d\n",
+ retval, str_info->ctrl_blk.ret_code);
+ str_id = -str_info->ctrl_blk.ret_code; /*return error*/
+ *lib_dnld = str_info->ctrl_blk.data;
+ sst_clean_stream(str_info);
+ } else
+ pr_debug("sst: FW Stream allocated sucess\n");
+ return str_id; /*will ret either error (in above if) or correct str id*/
+}
+
+/*
+ * sst_get_sfreq - this function returns the frequency of the stream
+ *
+ * @str_param : stream params
+ */
+static int sst_get_sfreq(struct snd_sst_params *str_param)
+{
+ switch (str_param->codec) {
+ case SST_CODEC_TYPE_PCM:
+ return 48000; /*str_param->sparams.uc.pcm_params.sfreq;*/
+ case SST_CODEC_TYPE_MP3:
+ return str_param->sparams.uc.mp3_params.sfreq;
+ case SST_CODEC_TYPE_AAC:
+ return str_param->sparams.uc.aac_params.sfreq;;
+ case SST_CODEC_TYPE_WMA9:
+ return str_param->sparams.uc.wma_params.sfreq;;
+ default:
+ return 0;
+ }
+}
+
+/*
+ * sst_get_stream - this function prepares for stream allocation
+ *
+ * @str_param : stream param
+ */
+int sst_get_stream(struct snd_sst_params *str_param)
+{
+ int i, retval;
+ struct stream_info *str_info;
+ struct snd_sst_lib_download *lib_dnld;
+
+ /* stream is not allocated, we are allocating */
+ retval = sst_get_stream_allocated(str_param, &lib_dnld);
+ if (retval == -(SST_LIB_ERR_LIB_DNLD_REQUIRED)) {
+ /* codec download is required */
+ struct snd_sst_alloc_response *response;
+
+ pr_debug("sst: Codec is required.... trying that\n");
+ if (lib_dnld == NULL) {
+ pr_err("sst: lib download null!!! abort\n");
+ return -EIO;
+ }
+ i = sst_get_block_stream(sst_drv_ctx);
+ response = sst_drv_ctx->alloc_block[i].ops_block.data;
+ pr_debug("sst: alloc block allocated = %d\n", i);
+ if (i < 0) {
+ kfree(lib_dnld);
+ return -ENOMEM;
+ }
+ retval = sst_load_library(lib_dnld, str_param->ops);
+ kfree(lib_dnld);
+
+ sst_drv_ctx->alloc_block[i].sst_id = BLOCK_UNINIT;
+ if (!retval) {
+ pr_debug("sst: codec was downloaded sucesfully\n");
+
+ retval = sst_get_stream_allocated(str_param, &lib_dnld);
+ if (retval <= 0)
+ goto err;
+
+ pr_debug("sst: Alloc done stream id %d\n", retval);
+ } else {
+ pr_debug("sst: codec download failed\n");
+ retval = -EIO;
+ goto err;
+ }
+ } else if (retval <= 0)
+ goto err;
+ /*else
+ set_port_params(str_param, str_param->ops);*/
+
+ /* store sampling freq */
+ str_info = &sst_drv_ctx->streams[retval];
+ str_info->sfreq = sst_get_sfreq(str_param);
+
+ /* power on the analog, if reqd */
+ if (str_param->ops == STREAM_OPS_PLAYBACK ||
+ str_param->ops == STREAM_OPS_PLAYBACK_DRM) {
+ if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID)
+ sst_drv_ctx->scard_ops->power_up_pmic_pb(
+ sst_drv_ctx->pmic_port_instance);
+ else
+ sst_drv_ctx->scard_ops->power_up_pmic_pb(
+ str_info->device);
+ /*Only if the playback is MP3 - Send a message*/
+ sst_drv_ctx->pb_streams++;
+ } else if (str_param->ops == STREAM_OPS_CAPTURE) {
+
+ sst_drv_ctx->scard_ops->power_up_pmic_cp(
+ sst_drv_ctx->pmic_port_instance);
+ /*Send a messageif not sent already*/
+ sst_drv_ctx->cp_streams++;
+ }
+
+err:
+ return retval;
+}
+
+void sst_process_mad_ops(struct work_struct *work)
+{
+
+ struct mad_ops_wq *mad_ops =
+ container_of(work, struct mad_ops_wq, wq);
+ int retval = 0;
+
+ switch (mad_ops->control_op) {
+ case SST_SND_PAUSE:
+ retval = sst_pause_stream(mad_ops->stream_id);
+ break;
+ case SST_SND_RESUME:
+ retval = sst_resume_stream(mad_ops->stream_id);
+ break;
+ case SST_SND_DROP:
+/* retval = sst_drop_stream(mad_ops->stream_id);
+*/ break;
+ case SST_SND_START:
+ pr_debug("SST Debug: start stream\n");
+ retval = sst_start_stream(mad_ops->stream_id);
+ break;
+ case SST_SND_STREAM_PROCESS:
+ pr_debug("sst: play/capt frames...\n");
+ break;
+ default:
+ pr_err("sst: wrong control_ops reported\n");
+ }
+ return;
+}
+/*
+ * sst_control_set - Set Control params
+ *
+ * @control_list: list of controls to be set
+ *
+ * This function is called by MID sound card driver to set
+ * SST/Sound card controls. This is registered with MID driver
+ */
+int sst_control_set(int control_element, void *value)
+{
+ int retval = 0, str_id = 0;
+ struct stream_info *stream;
+
+ if (sst_drv_ctx->sst_state == SST_SUSPENDED) {
+ /*LPE is suspended, resume it before proceding*/
+ pr_debug("sst: Resuming from Suspended state\n");
+ retval = intel_sst_resume(sst_drv_ctx->pci);
+ if (retval) {
+ pr_err("sst: Resume Failed = %#x, abort\n", retval);
+ return retval;
+ }
+ }
+ if (sst_drv_ctx->sst_state == SST_UN_INIT) {
+ /* FW is not downloaded */
+ pr_debug("sst: DSP Downloading FW now...\n");
+ retval = sst_download_fw();
+ if (retval) {
+ pr_err("sst: FW download fail %x, abort\n", retval);
+ return retval;
+ }
+ if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID &&
+ sst_drv_ctx->rx_time_slot_status != RX_TIMESLOT_UNINIT
+ && sst_drv_ctx->pmic_vendor != SND_NC)
+ sst_enable_rx_timeslot(
+ sst_drv_ctx->rx_time_slot_status);
+ }
+
+ switch (control_element) {
+ case SST_SND_ALLOC: {
+ struct snd_sst_params *str_param;
+ struct stream_info *str_info;
+
+ str_param = (struct snd_sst_params *)value;
+ BUG_ON(!str_param);
+ retval = sst_get_stream(str_param);
+ if (retval >= 0)
+ sst_drv_ctx->stream_cnt++;
+ str_info = &sst_drv_ctx->streams[retval];
+ str_info->src = MAD_DRV;
+ break;
+ }
+
+ case SST_SND_PAUSE:
+ case SST_SND_RESUME:
+ case SST_SND_DROP:
+ case SST_SND_START:
+ sst_drv_ctx->mad_ops.control_op = control_element;
+ sst_drv_ctx->mad_ops.stream_id = *(int *)value;
+ queue_work(sst_drv_ctx->mad_wq, &sst_drv_ctx->mad_ops.wq);
+ break;
+
+ case SST_SND_FREE:
+ str_id = *(int *)value;
+ stream = &sst_drv_ctx->streams[str_id];
+ free_stream_context(str_id);
+ stream->pcm_substream = NULL;
+ stream->status = STREAM_UN_INIT;
+ stream->period_elapsed = NULL;
+ sst_drv_ctx->stream_cnt--;
+ break;
+
+ case SST_SND_STREAM_INIT: {
+ struct pcm_stream_info *str_info;
+ struct stream_info *stream;
+
+ pr_debug("sst: stream init called\n");
+ str_info = (struct pcm_stream_info *)value;
+ str_id = str_info->str_id;
+ retval = sst_validate_strid(str_id);
+ if (retval)
+ break;
+
+ stream = &sst_drv_ctx->streams[str_id];
+ pr_debug("sst: setting the period ptrs\n");
+ stream->pcm_substream = str_info->mad_substream;
+ stream->period_elapsed = str_info->period_elapsed;
+ stream->sfreq = str_info->sfreq;
+ stream->prev = stream->status;
+ stream->status = STREAM_INIT;
+ break;
+ }
+
+ case SST_SND_BUFFER_POINTER: {
+ struct pcm_stream_info *stream_info;
+ struct snd_sst_tstamp fw_tstamp = {0,};
+ struct stream_info *stream;
+
+
+ stream_info = (struct pcm_stream_info *)value;
+ str_id = stream_info->str_id;
+ retval = sst_validate_strid(str_id);
+ if (retval)
+ break;
+ stream = &sst_drv_ctx->streams[str_id];
+
+ if (!stream->pcm_substream)
+ break;
+ memcpy_fromio(&fw_tstamp,
+ ((void *)(sst_drv_ctx->mailbox + SST_TIME_STAMP)
+ +(str_id * sizeof(fw_tstamp))),
+ sizeof(fw_tstamp));
+
+ pr_debug("sst: Pointer Query on strid = %d ops %d\n",
+ str_id, stream->ops);
+
+ if (stream->ops == STREAM_OPS_PLAYBACK)
+ stream_info->buffer_ptr = fw_tstamp.samples_rendered;
+ else
+ stream_info->buffer_ptr = fw_tstamp.samples_processed;
+ pr_debug("sst: Samples rendered = %llu, buffer ptr %llu\n",
+ fw_tstamp.samples_rendered, stream_info->buffer_ptr);
+ break;
+ }
+ case SST_ENABLE_RX_TIME_SLOT: {
+ int status = *(int *)value;
+ sst_drv_ctx->rx_time_slot_status = status ;
+ sst_enable_rx_timeslot(status);
+ break;
+ }
+ default:
+ /* Illegal case */
+ pr_warn("sst: illegal req\n");
+ return -EINVAL;
+ }
+
+ return retval;
+}
+
+
+struct intel_sst_card_ops sst_pmic_ops = {
+ .control_set = sst_control_set,
+};
+
+/*
+ * register_sst_card - function for sound card to register
+ *
+ * @card: pointer to structure of operations
+ *
+ * This function is called card driver loads and is ready for registration
+ */
+int register_sst_card(struct intel_sst_card_ops *card)
+{
+ if (!sst_drv_ctx) {
+ pr_err("sst: No SST driver register card reject\n");
+ return -ENODEV;
+ }
+
+ if (!card || !card->module_name) {
+ pr_err("sst: Null Pointer Passed\n");
+ return -EINVAL;
+ }
+ if (sst_drv_ctx->pmic_state == SND_MAD_UN_INIT) {
+ /* register this driver */
+ if ((strncmp(SST_CARD_NAMES, card->module_name,
+ strlen(SST_CARD_NAMES))) == 0) {
+ sst_drv_ctx->pmic_vendor = card->vendor_id;
+ sst_drv_ctx->scard_ops = card->scard_ops;
+ sst_pmic_ops.module_name = card->module_name;
+ sst_drv_ctx->pmic_state = SND_MAD_INIT_DONE;
+ sst_drv_ctx->rx_time_slot_status = 0; /*default AMIC*/
+ card->control_set = sst_pmic_ops.control_set;
+ sst_drv_ctx->scard_ops->card_status = SND_CARD_UN_INIT;
+ return 0;
+ } else {
+ pr_err("sst: strcmp fail %s\n", card->module_name);
+ return -EINVAL;
+ }
+
+ } else {
+ /* already registered a driver */
+ pr_err("sst: Repeat for registeration..denied\n");
+ return -EBADRQC;
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(register_sst_card);
+
+/*
+ * unregister_sst_card- function for sound card to un-register
+ *
+ * @card: pointer to structure of operations
+ *
+ * This function is called when card driver unloads
+ */
+void unregister_sst_card(struct intel_sst_card_ops *card)
+{
+ if (sst_pmic_ops.control_set == card->control_set) {
+ /* unreg */
+ sst_pmic_ops.module_name = "";
+ sst_drv_ctx->pmic_state = SND_MAD_UN_INIT;
+ pr_debug("sst: Unregistered %s\n", card->module_name);
+ }
+ return;
+}
+EXPORT_SYMBOL_GPL(unregister_sst_card);
diff --git a/drivers/staging/intel_sst/intel_sst_dsp.c b/drivers/staging/intel_sst/intel_sst_dsp.c
new file mode 100644
index 0000000..d80a6ee
--- /dev/null
+++ b/drivers/staging/intel_sst/intel_sst_dsp.c
@@ -0,0 +1,486 @@
+/*
+ * intel_sst_dsp.c - Intel SST Driver for audio engine
+ *
+ * Copyright (C) 2008-10 Intel Corp
+ * Authors: Vinod Koul <vinod.koul(a)intel.com>
+ * Harsha Priya <priya.harsha(a)intel.com>
+ * Dharageswari R <dharageswari.r(a)intel.com>
+ * KP Jeeja <jeeja.kp(a)intel.com>
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This driver exposes the audio engine functionalities to the ALSA
+ * and middleware.
+ *
+ * This file contains all dsp controlling functions like firmware download,
+ * setting/resetting dsp cores, etc
+ */
+#include <linux/pci.h>
+#include <linux/fs.h>
+#include <linux/firmware.h>
+#include "intel_sst.h"
+#include "intel_sst_ioctl.h"
+#include "intel_sst_fw_ipc.h"
+#include "intel_sst_common.h"
+
+
+/**
+ * intel_sst_reset_dsp_mrst - Resetting SST DSP
+ *
+ * This resets DSP in case of MRST platfroms
+ */
+static int intel_sst_reset_dsp_mrst(void)
+{
+ union config_status_reg csr;
+
+ pr_debug("sst: Resetting the DSP in mrst\n");
+ csr.full = 0x3a2;
+ sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full);
+ csr.full = sst_shim_read(sst_drv_ctx->shim, SST_CSR);
+ csr.part.strb_cntr_rst = 0;
+ csr.part.run_stall = 0x1;
+ csr.part.bypass = 0x7;
+ csr.part.sst_reset = 0x1;
+ sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full);
+ return 0;
+}
+
+/**
+ * intel_sst_reset_dsp_medfield - Resetting SST DSP
+ *
+ * This resets DSP in case of Medfield platfroms
+ */
+static int intel_sst_reset_dsp_medfield(void)
+{
+ union config_status_reg csr;
+
+ pr_debug("sst: Resetting the DSP in medfield\n");
+ csr.full = 0x048303E2;
+ sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full);
+
+ return 0;
+}
+
+/**
+ * sst_start_mrst - Start the SST DSP processor
+ *
+ * This starts the DSP in MRST platfroms
+ */
+static int sst_start_mrst(void)
+{
+ union config_status_reg csr;
+
+ csr.full = sst_shim_read(sst_drv_ctx->shim, SST_CSR);
+ csr.part.bypass = 0;
+ sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full);
+ csr.part.run_stall = 0;
+ csr.part.sst_reset = 0;
+ csr.part.strb_cntr_rst = 1;
+ pr_debug("sst: Setting SST to execute_mrst 0x%x\n", csr.full);
+ sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full);
+
+ return 0;
+}
+
+/**
+ * sst_start_medfield - Start the SST DSP processor
+ *
+ * This starts the DSP in MRST platfroms
+ */
+static int sst_start_medfield(void)
+{
+ union config_status_reg csr;
+
+ csr.full = 0x04830062;
+ sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full);
+ csr.full = 0x04830063;
+ sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full);
+ csr.full = 0x04830061;
+ sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full);
+ pr_debug("sst: Starting the DSP_medfld\n");
+
+ return 0;
+}
+
+/**
+ * sst_parse_module - Parse audio FW modules
+ *
+ * @module: FW module header
+ *
+ * Parses modules that need to be placed in SST IRAM and DRAM
+ * returns error or 0 if module sizes are proper
+ */
+static int sst_parse_module(struct fw_module_header *module)
+{
+ struct dma_block_info *block;
+ u32 count;
+ void __iomem *ram;
+
+ pr_debug("sst: module sign %s size %x blocks %x type %x\n",
+ module->signature, module->mod_size,
+ module->blocks, module->type);
+ pr_debug("sst: module entrypoint 0x%x\n", module->entry_point);
+
+ block = (void *)module + sizeof(*module);
+
+ for (count = 0; count < module->blocks; count++) {
+ if (block->size <= 0) {
+ pr_err("sst: block size invalid\n");
+ return -EINVAL;
+ }
+ switch (block->type) {
+ case SST_IRAM:
+ ram = sst_drv_ctx->iram;
+ break;
+ case SST_DRAM:
+ ram = sst_drv_ctx->dram;
+ break;
+ default:
+ pr_err("sst: wrong ram type0x%x in block0x%x\n",
+ block->type, count);
+ return -EINVAL;
+ }
+ memcpy_toio(ram + block->ram_offset,
+ (void *)block + sizeof(*block), block->size);
+ block = (void *)block + sizeof(*block) + block->size;
+ }
+ return 0;
+}
+
+/**
+ * sst_parse_fw_image - parse and load FW
+ *
+ * @sst_fw: pointer to audio fw
+ *
+ * This function is called to parse and download the FW image
+ */
+static int sst_parse_fw_image(const struct firmware *sst_fw)
+{
+ struct fw_header *header;
+ u32 count;
+ int ret_val;
+ struct fw_module_header *module;
+
+ BUG_ON(!sst_fw);
+
+ /* Read the header information from the data pointer */
+ header = (struct fw_header *)sst_fw->data;
+
+ /* verify FW */
+ if ((strncmp(header->signature, SST_FW_SIGN, 4) != 0) ||
+ (sst_fw->size != header->file_size + sizeof(*header))) {
+ /* Invalid FW signature */
+ pr_err("sst: InvalidFW sign/filesize mismatch\n");
+ return -EINVAL;
+ }
+ pr_debug("sst: header sign=%s size=%x modules=%x fmt=%x size=%x\n",
+ header->signature, header->file_size, header->modules,
+ header->file_format, sizeof(*header));
+ module = (void *)sst_fw->data + sizeof(*header);
+ for (count = 0; count < header->modules; count++) {
+ /* module */
+ ret_val = sst_parse_module(module);
+ if (ret_val)
+ return ret_val;
+ module = (void *)module + sizeof(*module) + module->mod_size ;
+ }
+
+ return 0;
+}
+
+/**
+ * sst_load_fw - function to load FW into DSP
+ *
+ * @fw: Pointer to driver loaded FW
+ * @context: driver context
+ *
+ * This function is called by OS when the FW is loaded into kernel
+ */
+int sst_load_fw(const struct firmware *fw, void *context)
+{
+ int ret_val;
+
+ pr_debug("sst: load_fw called\n");
+ BUG_ON(!fw);
+
+ if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID)
+ ret_val = intel_sst_reset_dsp_mrst();
+ else if (sst_drv_ctx->pci_id == SST_MFLD_PCI_ID)
+ ret_val = intel_sst_reset_dsp_medfield();
+ if (ret_val)
+ return ret_val;
+
+ ret_val = sst_parse_fw_image(fw);
+ if (ret_val)
+ return ret_val;
+ mutex_lock(&sst_drv_ctx->sst_lock);
+ sst_drv_ctx->sst_state = SST_FW_LOADED;
+ mutex_unlock(&sst_drv_ctx->sst_lock);
+ /* 7. ask scu to reset the bypass bits */
+ /* 8.bring sst out of reset */
+ if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID)
+ ret_val = sst_start_mrst();
+ else if (sst_drv_ctx->pci_id == SST_MFLD_PCI_ID)
+ ret_val = sst_start_medfield();
+ if (ret_val)
+ return ret_val;
+
+ pr_debug("sst: fw loaded successful!!!\n");
+ return ret_val;
+}
+
+/*This function is called when any codec/post processing library
+ needs to be downloaded*/
+static int sst_download_library(const struct firmware *fw_lib,
+ struct snd_sst_lib_download_info *lib)
+{
+ /* send IPC message and wait */
+ int i;
+ u8 pvt_id;
+ struct ipc_post *msg = NULL;
+ union config_status_reg csr;
+ struct snd_sst_str_type str_type = {0};
+ int retval = 0;
+
+ if (sst_create_large_msg(&msg))
+ return -ENOMEM;
+
+ pvt_id = sst_assign_pvt_id(sst_drv_ctx);
+ i = sst_get_block_stream(sst_drv_ctx);
+ pr_debug("sst: alloc block allocated = %d, pvt_id %d\n", i, pvt_id);
+ if (i < 0) {
+ kfree(msg);
+ return -ENOMEM;
+ }
+ sst_drv_ctx->alloc_block[i].sst_id = pvt_id;
+ sst_fill_header(&msg->header, IPC_IA_PREP_LIB_DNLD, 1, pvt_id);
+ msg->header.part.data = sizeof(u32) + sizeof(str_type);
+ str_type.codec_type = lib->dload_lib.lib_info.lib_type;
+ /*str_type.pvt_id = pvt_id;*/
+ memcpy(msg->mailbox_data, &msg->header, sizeof(u32));
+ memcpy(msg->mailbox_data + sizeof(u32), &str_type, sizeof(str_type));
+ spin_lock(&sst_drv_ctx->list_spin_lock);
+ list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list);
+ spin_unlock(&sst_drv_ctx->list_spin_lock);
+ sst_post_message(&sst_drv_ctx->ipc_post_msg_wq);
+ retval = sst_wait_timeout(sst_drv_ctx, &sst_drv_ctx->alloc_block[i]);
+ if (retval) {
+ /* error */
+ sst_drv_ctx->alloc_block[i].sst_id = BLOCK_UNINIT;
+ pr_err("sst: Prep codec downloaded failed %d\n",
+ retval);
+ return -EIO;
+ }
+ pr_debug("sst: FW responded, ready for download now...\n");
+ /* downloading on success */
+ mutex_lock(&sst_drv_ctx->sst_lock);
+ sst_drv_ctx->sst_state = SST_FW_LOADED;
+ mutex_unlock(&sst_drv_ctx->sst_lock);
+ csr.full = readl(sst_drv_ctx->shim + SST_CSR);
+ csr.part.run_stall = 1;
+ sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full);
+
+ csr.full = sst_shim_read(sst_drv_ctx->shim, SST_CSR);
+ csr.part.bypass = 0x7;
+ sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full);
+
+ sst_parse_fw_image(fw_lib);
+
+ /* set the FW to running again */
+ csr.full = sst_shim_read(sst_drv_ctx->shim, SST_CSR);
+ csr.part.bypass = 0x0;
+ sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full);
+
+ csr.full = sst_shim_read(sst_drv_ctx->shim, SST_CSR);
+ csr.part.run_stall = 0;
+ sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full);
+
+ /* send download complete and wait */
+ if (sst_create_large_msg(&msg)) {
+ sst_drv_ctx->alloc_block[i].sst_id = BLOCK_UNINIT;
+ return -ENOMEM;
+ }
+
+ sst_fill_header(&msg->header, IPC_IA_LIB_DNLD_CMPLT, 1, pvt_id);
+ sst_drv_ctx->alloc_block[i].sst_id = pvt_id;
+ msg->header.part.data = sizeof(u32) + sizeof(*lib);
+ lib->pvt_id = pvt_id;
+ memcpy(msg->mailbox_data, &msg->header, sizeof(u32));
+ memcpy(msg->mailbox_data + sizeof(u32), lib, sizeof(*lib));
+ spin_lock(&sst_drv_ctx->list_spin_lock);
+ list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list);
+ spin_unlock(&sst_drv_ctx->list_spin_lock);
+ sst_post_message(&sst_drv_ctx->ipc_post_msg_wq);
+ pr_debug("sst: Waiting for FW response Download complete\n");
+ sst_drv_ctx->alloc_block[i].ops_block.condition = false;
+ retval = sst_wait_timeout(sst_drv_ctx, &sst_drv_ctx->alloc_block[i]);
+ if (retval) {
+ /* error */
+ mutex_lock(&sst_drv_ctx->sst_lock);
+ sst_drv_ctx->sst_state = SST_UN_INIT;
+ mutex_unlock(&sst_drv_ctx->sst_lock);
+ sst_drv_ctx->alloc_block[i].sst_id = BLOCK_UNINIT;
+ return -EIO;
+ }
+
+ pr_debug("sst: FW sucess on Download complete\n");
+ sst_drv_ctx->alloc_block[i].sst_id = BLOCK_UNINIT;
+ mutex_lock(&sst_drv_ctx->sst_lock);
+ sst_drv_ctx->sst_state = SST_FW_RUNNING;
+ mutex_unlock(&sst_drv_ctx->sst_lock);
+ return 0;
+
+}
+
+/* This function is called befoer downloading the codec/postprocessing
+library is set for download to SST DSP*/
+static int sst_validate_library(const struct firmware *fw_lib,
+ struct lib_slot_info *slot,
+ u32 *entry_point)
+{
+ struct fw_header *header;
+ struct fw_module_header *module;
+ struct dma_block_info *block;
+ unsigned int n_blk, isize = 0, dsize = 0;
+ int err = 0;
+
+ header = (struct fw_header *)fw_lib->data;
+ if (header->modules != 1) {
+ pr_err("sst: Module no mismatch found\n ");
+ err = -EINVAL;
+ goto exit;
+ }
+ module = (void *)fw_lib->data + sizeof(*header);
+ *entry_point = module->entry_point;
+ pr_debug("sst: Module entry point 0x%x\n", *entry_point);
+ pr_debug("sst: Module Sign %s, Size 0x%x, Blocks 0x%x Type 0x%x\n",
+ module->signature, module->mod_size,
+ module->blocks, module->type);
+
+ block = (void *)module + sizeof(*module);
+ for (n_blk = 0; n_blk < module->blocks; n_blk++) {
+ switch (block->type) {
+ case SST_IRAM:
+ isize += block->size;
+ break;
+ case SST_DRAM:
+ dsize += block->size;
+ break;
+ default:
+ pr_err("sst: Invalid block type for 0x%x\n", n_blk);
+ err = -EINVAL;
+ goto exit;
+ }
+ block = (void *)block + sizeof(*block) + block->size;
+ }
+ if (isize > slot->iram_size || dsize > slot->dram_size) {
+ pr_err("sst: library exceeds size allocated\n");
+ err = -EINVAL;
+ goto exit;
+ } else
+ pr_debug("sst: Library is safe for download...\n");
+
+ pr_debug("sst: iram 0x%x, dram 0x%x, iram 0x%x, dram 0x%x\n",
+ isize, dsize, slot->iram_size, slot->dram_size);
+exit:
+ return err;
+
+}
+
+/* This function is called when FW requests for a particular libary download
+This function prepares the library to download*/
+int sst_load_library(struct snd_sst_lib_download *lib, u8 ops)
+{
+ char buf[20];
+ const char *type, *dir;
+ int len = 0, error = 0;
+ u32 entry_point;
+ const struct firmware *fw_lib;
+ struct snd_sst_lib_download_info dload_info = {{{0},},};
+
+ memset(buf, 0, sizeof(buf));
+
+ pr_debug("sst: Lib Type 0x%x, Slot 0x%x, ops 0x%x\n",
+ lib->lib_info.lib_type, lib->slot_info.slot_num, ops);
+ pr_debug("sst: Version 0x%x, name %s, caps 0x%x media type 0x%x\n",
+ lib->lib_info.lib_version, lib->lib_info.lib_name,
+ lib->lib_info.lib_caps, lib->lib_info.media_type);
+
+ pr_debug("sst: IRAM Size 0x%x, offset 0x%x\n",
+ lib->slot_info.iram_size, lib->slot_info.iram_offset);
+ pr_debug("sst: DRAM Size 0x%x, offset 0x%x\n",
+ lib->slot_info.dram_size, lib->slot_info.dram_offset);
+
+ switch (lib->lib_info.lib_type) {
+ case SST_CODEC_TYPE_MP3:
+ type = "mp3_";
+ break;
+ case SST_CODEC_TYPE_AAC:
+ type = "aac_";
+ break;
+ case SST_CODEC_TYPE_AACP:
+ type = "aac_v1_";
+ break;
+ case SST_CODEC_TYPE_eAACP:
+ type = "aac_v2_";
+ break;
+ case SST_CODEC_TYPE_WMA9:
+ type = "wma9_";
+ break;
+ default:
+ pr_err("sst: Invalid codec type\n");
+ error = -EINVAL;
+ goto wake;
+ }
+
+ if (ops == STREAM_OPS_CAPTURE)
+ dir = "enc_";
+ else
+ dir = "dec_";
+ len = strlen(type) + strlen(dir);
+ strncpy(buf, type, sizeof(buf)-1);
+ strncpy(buf + strlen(type), dir, sizeof(buf)-strlen(type)-1);
+ len += snprintf(buf + len, sizeof(buf) - len, "%d",
+ lib->slot_info.slot_num);
+ len += snprintf(buf + len, sizeof(buf) - len, ".bin");
+
+ pr_debug("sst: Requesting %s\n", buf);
+
+ error = request_firmware(&fw_lib, buf, &sst_drv_ctx->pci->dev);
+ if (error) {
+ pr_err("sst: library load failed %d\n", error);
+ goto wake;
+ }
+ error = sst_validate_library(fw_lib, &lib->slot_info, &entry_point);
+ if (error)
+ goto wake_free;
+
+ lib->mod_entry_pt = entry_point;
+ memcpy(&dload_info.dload_lib, lib, sizeof(*lib));
+ error = sst_download_library(fw_lib, &dload_info);
+ if (error)
+ goto wake_free;
+
+ /* lib is downloaded and init send alloc again */
+ pr_debug("sst: Library is downloaded now...\n");
+wake_free:
+ /* sst_wake_up_alloc_block(sst_drv_ctx, pvt_id, error, NULL); */
+ release_firmware(fw_lib);
+wake:
+ return error;
+}
+
diff --git a/drivers/staging/intel_sst/intel_sst_fw_ipc.h b/drivers/staging/intel_sst/intel_sst_fw_ipc.h
new file mode 100644
index 0000000..1a2f67f
--- /dev/null
+++ b/drivers/staging/intel_sst/intel_sst_fw_ipc.h
@@ -0,0 +1,393 @@
+#ifndef __INTEL_SST_FW_IPC_H__
+#define __INTEL_SST_FW_IPC_H__
+/*
+* intel_sst_fw_ipc.h - Intel SST Driver for audio engine
+*
+* Copyright (C) 2008-10 Intel Corporation
+* Author: Vinod Koul <vinod.koul(a)intel.com>
+* Harsha Priya <priya.harsha(a)intel.com>
+* Dharageswari R <dharageswari.r(a)intel.com>
+* KP Jeeja <jeeja.kp(a)intel.com>
+* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; version 2 of the License.
+*
+* This program is distributed in the hope that it will be useful, but
+* WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License along
+* with this program; if not, write to the Free Software Foundation, Inc.,
+* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+*
+* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+*
+* This driver exposes the audio engine functionalities to the ALSA
+* and middleware.
+* This file has definitions shared between the firmware and driver
+*/
+
+#define MAX_NUM_STREAMS_MRST 3
+#define MAX_NUM_STREAMS_MFLD 6
+#define MAX_NUM_STREAMS 6
+#define MAX_DBG_RW_BYTES 80
+#define MAX_NUM_SCATTER_BUFFERS 8
+#define MAX_LOOP_BACK_DWORDS 8
+/* IPC base address and mailbox, timestamp offsets */
+#define SST_MAILBOX_SIZE 0x0400
+#define SST_MAILBOX_SEND 0x0000
+#define SST_MAILBOX_RCV 0x0804
+#define SST_TIME_STAMP 0x1800
+#define SST_RESERVED_OFFSET 0x1A00
+#define SST_CHEKPOINT_OFFSET 0x1C00
+#define REPLY_MSG 0x80
+
+/* Message ID's for IPC messages */
+/* Bits B7: SST or IA/SC ; B6-B4: Msg Category; B3-B0: Msg Type */
+
+/* I2L Firmware/Codec Download msgs */
+#define IPC_IA_PREP_LIB_DNLD 0x01
+#define IPC_IA_LIB_DNLD_CMPLT 0x02
+
+#define IPC_IA_SET_PMIC_TYPE 0x03
+#define IPC_IA_GET_FW_VERSION 0x04
+#define IPC_IA_GET_FW_BUILD_INF 0x05
+#define IPC_IA_GET_FW_INFO 0x06
+
+/* I2L Codec Config/control msgs */
+#define IPC_IA_SET_CODEC_PARAMS 0x10
+#define IPC_IA_GET_CODEC_PARAMS 0x11
+#define IPC_IA_SET_PPP_PARAMS 0x12
+#define IPC_IA_GET_PPP_PARAMS 0x13
+#define IPC_IA_PLAY_FRAMES 0x14
+#define IPC_IA_CAPT_FRAMES 0x15
+#define IPC_IA_PLAY_VOICE 0x16
+#define IPC_IA_CAPT_VOICE 0x17
+#define IPC_IA_DECODE_FRAMES 0x18
+
+/* I2L Stream config/control msgs */
+#define IPC_IA_ALLOC_STREAM 0x20 /* Allocate a stream ID */
+#define IPC_IA_FREE_STREAM 0x21 /* Free the stream ID */
+#define IPC_IA_SET_STREAM_PARAMS 0x22
+#define IPC_IA_GET_STREAM_PARAMS 0x23
+#define IPC_IA_PAUSE_STREAM 0x24
+#define IPC_IA_RESUME_STREAM 0x25
+#define IPC_IA_DROP_STREAM 0x26
+#define IPC_IA_DRAIN_STREAM 0x27 /* Short msg with str_id */
+#define IPC_IA_TARGET_DEV_SELECT 0x28
+#define IPC_IA_CONTROL_ROUTING 0x29
+
+#define IPC_IA_SET_STREAM_VOL 0x2A /*Vol for stream, pre mixer */
+#define IPC_IA_GET_STREAM_VOL 0x2B
+#define IPC_IA_SET_STREAM_MUTE 0x2C
+#define IPC_IA_GET_STREAM_MUTE 0x2D
+#define IPC_IA_ENABLE_RX_TIME_SLOT 0x2E /* Enable Rx time slot 0 or 1 */
+
+#define IPC_IA_START_STREAM 0x30 /* Short msg with str_id */
+
+/* Debug msgs */
+#define IPC_IA_DBG_MEM_READ 0x40
+#define IPC_IA_DBG_MEM_WRITE 0x41
+#define IPC_IA_DBG_LOOP_BACK 0x42
+
+/* L2I Firmware/Codec Download msgs */
+#define IPC_IA_FW_INIT_CMPLT 0x81
+#define IPC_IA_LPE_GETTING_STALLED 0x82
+#define IPC_IA_LPE_UNSTALLED 0x83
+
+/* L2I Codec Config/control msgs */
+#define IPC_SST_GET_PLAY_FRAMES 0x90 /* Request IA more data */
+#define IPC_SST_GET_CAPT_FRAMES 0x91 /* Request IA more data */
+#define IPC_SST_BUF_UNDER_RUN 0x92 /* PB Under run and stopped */
+#define IPC_SST_BUF_OVER_RUN 0x93 /* CAP Under run and stopped */
+#define IPC_SST_DRAIN_END 0x94 /* PB Drain complete and stopped */
+#define IPC_SST_CHNGE_SSP_PARAMS 0x95 /* PB SSP parameters changed */
+#define IPC_SST_STREAM_PROCESS_FATAL_ERR 0x96/* error in processing a stream */
+#define IPC_SST_PERIOD_ELAPSED 0x97 /* period elapsed */
+#define IPC_IA_TARGET_DEV_CHNGD 0x98 /* error in processing a stream */
+
+#define IPC_SST_ERROR_EVENT 0x99 /* Buffer over run occured */
+/* L2S messages */
+#define IPC_SC_DDR_LINK_UP 0xC0
+#define IPC_SC_DDR_LINK_DOWN 0xC1
+#define IPC_SC_SET_LPECLK_REQ 0xC2
+#define IPC_SC_SSP_BIT_BANG 0xC3
+
+/* L2I Error reporting msgs */
+#define IPC_IA_MEM_ALLOC_FAIL 0xE0
+#define IPC_IA_PROC_ERR 0xE1 /* error in processing a
+ stream can be used by playback and
+ capture modules */
+
+/* L2I Debug msgs */
+#define IPC_IA_PRINT_STRING 0xF0
+
+
+
+/* Command Response or Acknowledge message to any IPC message will have
+ * same message ID and stream ID information which is sent.
+ * There is no specific Ack message ID. The data field is used as response
+ * meaning.
+ */
+enum ackData {
+ IPC_ACK_SUCCESS = 0,
+ IPC_ACK_FAILURE
+};
+
+
+enum sst_error_codes {
+ /* Error code,response to msgId: Description */
+ /* Common error codes */
+ SST_SUCCESS = 0, /* Success */
+ SST_ERR_INVALID_STREAM_ID, /* Invalid stream ID */
+ SST_ERR_INVALID_MSG_ID, /* Invalid message ID */
+ SST_ERR_INVALID_STREAM_OP, /* Invalid stream operation request */
+ SST_ERR_INVALID_PARAMS, /* Invalid params */
+ SST_ERR_INVALID_CODEC, /* Invalid codec type */
+ SST_ERR_INVALID_MEDIA_TYPE, /* Invalid media type */
+ SST_ERR_STREAM_ERR, /* ANY: Stream control or config or
+ processing error */
+
+ /* IPC specific error codes */
+ SST_IPC_ERR_CALL_BACK_NOT_REGD, /* Call back for msg not regd */
+ SST_IPC_ERR_STREAM_NOT_ALLOCATED, /* Stream is not allocated */
+ SST_IPC_ERR_STREAM_ALLOC_FAILED, /* ALLOC:Stream alloc failed */
+ SST_IPC_ERR_GET_STREAM_FAILED, /* ALLOC:Get stream id failed*/
+ SST_ERR_MOD_NOT_AVAIL, /* SET/GET: Mod(AEC/AGC/ALC) not available */
+ SST_ERR_MOD_DNLD_RQD, /* SET/GET: Mod(AEC/AGC/ALC) download required */
+ SST_ERR_STREAM_STOPPED, /* ANY: Stream is in stopped state */
+ SST_ERR_STREAM_IN_USE, /* ANY: Stream is already in use */
+
+ /* Capture specific error codes */
+ SST_CAP_ERR_INCMPLTE_CAPTURE_MSG,/* ANY:Incomplete message */
+ SST_CAP_ERR_CAPTURE_FAIL, /* ANY:Capture op failed */
+ SST_CAP_ERR_GET_DDR_NEW_SGLIST,
+ SST_CAP_ERR_UNDER_RUN, /* lack of input data */
+ SST_CAP_ERR_OVERFLOW, /* lack of output space */
+
+ /* Playback specific error codes*/
+ SST_PB_ERR_INCMPLTE_PLAY_MSG, /* ANY: Incomplete message */
+ SST_PB_ERR_PLAY_FAIL, /* ANY: Playback operation failed */
+ SST_PB_ERR_GET_DDR_NEW_SGLIST,
+
+ /* Codec manager specific error codes */
+ SST_LIB_ERR_LIB_DNLD_REQUIRED, /* ALLOC: Codec download required */
+ SST_LIB_ERR_LIB_NOT_SUPPORTED, /* Library is not supported */
+
+ /* Library manager specific error codes */
+ SST_SCC_ERR_PREP_DNLD_FAILED, /* Failed to prepare for codec download */
+ SST_SCC_ERR_LIB_DNLD_RES_FAILED, /* Lib download resume failed */
+ /* Scheduler specific error codes */
+ SST_SCH_ERR_FAIL, /* REPORT: */
+
+ /* DMA specific error codes */
+ SST_DMA_ERR_NO_CHNL_AVAILABLE, /* DMA Ch not available */
+ SST_DMA_ERR_INVALID_INPUT_PARAMS, /* Invalid input params */
+ SST_DMA_ERR_CHNL_ALREADY_SUSPENDED, /* Ch is suspended */
+ SST_DMA_ERR_CHNL_ALREADY_STARTED, /* Ch already started */
+ SST_DMA_ERR_CHNL_NOT_ENABLED, /* Ch not enabled */
+ SST_DMA_ERR_TRANSFER_FAILED, /* Transfer failed */
+ SST_SSP_ERR_ALREADY_ENABLED, /* REPORT: SSP already enabled */
+ SST_SSP_ERR_ALREADY_DISABLED, /* REPORT: SSP already disabled */
+ SST_SSP_ERR_NOT_INITIALIZED,
+
+ /* Other error codes */
+ SST_ERR_MOD_INIT_FAIL, /* Firmware Module init failed */
+
+ /* FW init error codes */
+ SST_RDR_ERR_IO_DEV_SEL_NOT_ALLOWED,
+ SST_RDR_ERR_ROUTE_ALREADY_STARTED,
+ SST_RDR_PREP_CODEC_DNLD_FAILED,
+
+ /* Memory debug error codes */
+ SST_ERR_DBG_MEM_READ_FAIL,
+ SST_ERR_DBG_MEM_WRITE_FAIL,
+
+ /* Decode error codes */
+ SST_ERR_DEC_NEED_INPUT_BUF,
+
+};
+
+enum dbg_mem_data_type {
+ /* Data type of debug read/write */
+ DATA_TYPE_U32,
+ DATA_TYPE_U16,
+ DATA_TYPE_U8,
+};
+
+/* CAUTION NOTE: All IPC message body must be multiple of 32 bits.*/
+
+/* IPC Header */
+union ipc_header {
+ struct {
+ u32 msg_id:8; /* Message ID - Max 256 Message Types */
+ u32 str_id:5;
+ u32 large:1; /* Large Message if large = 1 */
+ u32 reserved:2; /* Reserved for future use */
+ u32 data:14; /* Ack/Info for msg, size of msg in Mailbox */
+ u32 done:1; /* bit 30 */
+ u32 busy:1; /* bit 31 */
+ } part;
+ u32 full;
+} __attribute__ ((packed));
+
+/* Firmware build info */
+struct sst_fw_build_info {
+ unsigned char date[16]; /* Firmware build date */
+ unsigned char time[16]; /* Firmware build time */
+} __attribute__ ((packed));
+
+struct ipc_header_fw_init {
+ struct snd_sst_fw_version fw_version;/* Firmware version details */
+ struct sst_fw_build_info build_info;
+ u16 result; /* Fw init result */
+ u8 module_id; /* Module ID in case of error */
+ u8 debug_info; /* Debug info from Module ID in case of fail */
+} __attribute__ ((packed));
+
+/* Address and size info of a frame buffer in DDR */
+struct sst_address_info {
+ u32 addr; /* Address at IA */
+ u32 size; /* Size of the buffer */
+} __attribute__ ((packed));
+
+/* Time stamp */
+struct snd_sst_tstamp {
+ u64 samples_processed;/* capture - data in DDR */
+ u64 samples_rendered;/* playback - data rendered */
+ u64 bytes_processed;/* bytes decoded or encoded */
+ u32 sampling_frequency;/* eg: 48000, 44100 */
+ u32 dma_base_address;/* DMA base address */
+ u16 dma_channel_no;/* DMA Channel used for the data transfer*/
+ u16 reserved;/* 32 bit alignment */
+};
+
+/* Frame info to play or capture */
+struct sst_frame_info {
+ u16 num_entries; /* number of entries to follow */
+ u16 rsrvd;
+ struct sst_address_info addr[MAX_NUM_SCATTER_BUFFERS];
+} __attribute__ ((packed));
+
+/* Frames info for decode */
+struct snd_sst_decode_info {
+ unsigned long long input_bytes_consumed;
+ unsigned long long output_bytes_produced;
+ struct sst_frame_info frames_in;
+ struct sst_frame_info frames_out;
+} __attribute__ ((packed));
+
+/* SST to IA print debug message*/
+struct ipc_sst_ia_print_params {
+ u32 string_size;/* Max value is 160 */
+ u8 prt_string[160];/* Null terminated Char string */
+} __attribute__ ((packed));
+
+/* Voice data message */
+struct snd_sst_voice_data {
+ u16 num_bytes;/* Number of valid voice data bytes */
+ u8 pcm_wd_size;/* 0=8 bit, 1=16 bit 2=32 bit */
+ u8 reserved;/* Reserved */
+ u8 voice_data_buf[0];/* Voice data buffer in bytes, little endian */
+} __attribute__ ((packed));
+
+/* SST to IA memory read debug message */
+struct ipc_sst_ia_dbg_mem_rw {
+ u16 num_bytes;/* Maximum of MAX_DBG_RW_BYTES */
+ u16 data_type;/* enum: dbg_mem_data_type */
+ u32 address; /* Memory address of data memory of data_type */
+ u8 rw_bytes[MAX_DBG_RW_BYTES];/* Maximum of 64 bytes can be RW */
+} __attribute__ ((packed));
+
+struct ipc_sst_ia_dbg_loop_back {
+ u16 num_dwords; /* Maximum of MAX_DBG_RW_BYTES */
+ u16 increment_val;/* Increments dwords by this value, 0- no increment */
+ u32 lpbk_dwords[MAX_LOOP_BACK_DWORDS];/* Maximum of 8 dwords loopback */
+} __attribute__ ((packed));
+
+/* Stream type params struture for Alloc stream */
+struct snd_sst_str_type {
+ u8 codec_type; /* Codec type */
+ u8 str_type; /* 1 = voice 2 = music */
+ u8 operation; /* Playback or Capture */
+ u8 protected_str; /* 0=Non DRM, 1=DRM */
+ u8 time_slots;
+ u8 reserved; /* Reserved */
+ u16 result; /* Result used for acknowledgment */
+} __attribute__ ((packed));
+
+/* Library info structure */
+struct module_info {
+ u32 lib_version;
+ u32 lib_type;/*TBD- KLOCKWORK u8 lib_type;*/
+ u32 media_type;
+ u8 lib_name[12];
+ u32 lib_caps;
+ unsigned char b_date[16]; /* Lib build date */
+ unsigned char b_time[16]; /* Lib build time */
+} __attribute__ ((packed));
+
+/* Library slot info */
+struct lib_slot_info {
+ u8 slot_num; /* 1 or 2 */
+ u8 reserved1;
+ u16 reserved2;
+ u32 iram_size; /* slot size in IRAM */
+ u32 dram_size; /* slot size in DRAM */
+ u32 iram_offset; /* starting offset of slot in IRAM */
+ u32 dram_offset; /* starting offset of slot in DRAM */
+} __attribute__ ((packed));
+
+struct snd_sst_lib_download {
+ struct module_info lib_info; /* library info type, capabilities etc */
+ struct lib_slot_info slot_info; /* slot info to be downloaded */
+ u32 mod_entry_pt;
+};
+
+struct snd_sst_lib_download_info {
+ struct snd_sst_lib_download dload_lib;
+ u16 result; /* Result used for acknowledgment */
+ u8 pvt_id; /* Private ID */
+ u8 reserved; /* for alignment */
+};
+
+/* Alloc stream params structure */
+struct snd_sst_alloc_params {
+ struct snd_sst_str_type str_type;
+ struct snd_sst_stream_params stream_params;
+};
+
+struct snd_sst_fw_get_stream_params {
+ struct snd_sst_stream_params codec_params;
+ struct snd_sst_pmic_config pcm_params;
+};
+
+/* Alloc stream response message */
+struct snd_sst_alloc_response {
+ struct snd_sst_str_type str_type; /* Stream type for allocation */
+ struct snd_sst_lib_download lib_dnld; /* Valid only for codec dnld */
+};
+
+/* Drop response */
+struct snd_sst_drop_response {
+ u32 result;
+ u32 bytes;
+};
+
+/* CSV Voice call routing structure */
+struct snd_sst_control_routing {
+ u8 control; /* 0=start, 1=Stop */
+ u8 reserved[3]; /* Reserved- for 32 bit alignment */
+};
+
+
+struct ipc_post {
+ struct list_head node;
+ union ipc_header header; /* driver specific */
+ char *mailbox_data;
+};
+
+#endif /* __INTEL_SST_FW_IPC_H__ */
diff --git a/drivers/staging/intel_sst/intel_sst_ioctl.h b/drivers/staging/intel_sst/intel_sst_ioctl.h
new file mode 100644
index 0000000..03b9316
--- /dev/null
+++ b/drivers/staging/intel_sst/intel_sst_ioctl.h
@@ -0,0 +1,435 @@
+#ifndef __INTEL_SST_IOCTL_H__
+#define __INTEL_SST_IOCTL_H__
+/*
+ * intel_sst_ioctl.h - Intel SST Driver for audio engine
+ *
+ * Copyright (C) 2008-10 Intel Corporation
+ * Authors: Vinod Koul <vinod.koul(a)intel.com>
+ * Harsha Priya <priya.harsha(a)intel.com>
+ * Dharageswari R <dharageswari.r(a)intel.com>
+ * KP Jeeja <jeeja.kp(a)intel.com>
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This file defines all sst ioctls
+ */
+
+/* codec and post/pre processing related info */
+
+#include <linux/types.h>
+
+enum sst_codec_types {
+/* AUDIO/MUSIC CODEC Type Definitions */
+ SST_CODEC_TYPE_UNKNOWN = 0,
+ SST_CODEC_TYPE_PCM, /* Pass through Audio codec */
+ SST_CODEC_TYPE_MP3,
+ SST_CODEC_TYPE_MP24,
+ SST_CODEC_TYPE_AAC,
+ SST_CODEC_TYPE_AACP,
+ SST_CODEC_TYPE_eAACP,
+ SST_CODEC_TYPE_WMA9,
+ SST_CODEC_TYPE_WMA10,
+ SST_CODEC_TYPE_WMA10P,
+ SST_CODEC_TYPE_RA,
+ SST_CODEC_TYPE_DDAC3,
+ SST_CODEC_TYPE_STEREO_TRUE_HD,
+ SST_CODEC_TYPE_STEREO_HD_PLUS,
+
+ /* VOICE CODEC Type Definitions */
+ SST_CODEC_TYPE_VOICE_PCM = 0x21, /* Pass through voice codec */
+};
+
+enum sst_algo_types {
+ SST_CODEC_SRC = 0x64,
+ SST_CODEC_MIXER = 0x65,
+ SST_CODEC_DOWN_MIXER = 0x66,
+ SST_CODEC_VOLUME_CONTROL = 0x67,
+ SST_CODEC_OEM1 = 0xC8,
+ SST_CODEC_OEM2 = 0xC9,
+};
+
+enum snd_sst_stream_ops {
+ STREAM_OPS_PLAYBACK = 0, /* Decode */
+ STREAM_OPS_CAPTURE, /* Encode */
+ STREAM_OPS_PLAYBACK_DRM, /* Play Audio/Voice */
+ STREAM_OPS_PLAYBACK_ALERT, /* Play Audio/Voice */
+ STREAM_OPS_CAPTURE_VOICE_CALL, /* CSV Voice recording */
+};
+
+enum stream_mode {
+ SST_STREAM_MODE_NONE = 0,
+ SST_STREAM_MODE_DNR = 1,
+ SST_STREAM_MODE_FNF = 2,
+ SST_STREAM_MODE_CAPTURE = 3
+};
+
+enum stream_type {
+ SST_STREAM_TYPE_NONE = 0,
+ SST_STREAM_TYPE_MUSIC = 1,
+ SST_STREAM_TYPE_NORMAL = 2,
+ SST_STREAM_TYPE_LONG_PB = 3,
+ SST_STREAM_TYPE_LOW_LATENCY = 4,
+};
+
+enum snd_sst_audio_device_type {
+ SND_SST_DEVICE_HEADSET = 1,
+ SND_SST_DEVICE_IHF,
+ SND_SST_DEVICE_VIBRA,
+ SND_SST_DEVICE_HAPTIC,
+ SND_SST_DEVICE_CAPTURE,
+};
+
+/* Firmware Version info */
+struct snd_sst_fw_version {
+ __u8 build; /* build number*/
+ __u8 minor; /* minor number*/
+ __u8 major; /* major number*/
+ __u8 type; /* build type */
+};
+
+/* Port info structure */
+struct snd_sst_port_info {
+ __u16 port_type;
+ __u16 reserved;
+};
+
+/* Mixer info structure */
+struct snd_sst_mix_info {
+ __u16 max_streams;
+ __u16 reserved;
+};
+
+/* PCM Parameters */
+struct snd_pcm_params {
+ __u16 codec; /* codec type */
+ __u8 num_chan; /* 1=Mono, 2=Stereo */
+ __u8 pcm_wd_sz; /* 16/24 - bit*/
+ __u32 reserved; /* Bitrate in bits per second */
+ __u32 sfreq; /* Sampling rate in Hz */
+ __u32 ring_buffer_size;
+ __u32 period_count; /* period elapsed in samples*/
+ __u32 ring_buffer_addr;
+};
+
+/* MP3 Music Parameters Message */
+struct snd_mp3_params {
+ __u16 codec;
+ __u8 num_chan; /* 1=Mono, 2=Stereo */
+ __u8 pcm_wd_sz; /* 16/24 - bit*/
+ __u32 brate; /* Use the hard coded value. */
+ __u32 sfreq; /* Sampling freq eg. 8000, 441000, 48000 */
+ __u8 crc_check; /* crc_check - disable (0) or enable (1) */
+ __u8 op_align; /* op align 0- 16 bit, 1- MSB, 2 LSB*/
+ __u16 reserved; /* Unused */
+};
+
+#define AAC_BIT_STREAM_ADTS 0
+#define AAC_BIT_STREAM_ADIF 1
+#define AAC_BIT_STREAM_RAW 2
+
+/* AAC Music Parameters Message */
+struct snd_aac_params {
+ __u16 codec;
+ __u8 num_chan; /* 1=Mono, 2=Stereo*/
+ __u8 pcm_wd_sz; /* 16/24 - bit*/
+ __u32 brate;
+ __u32 sfreq; /* Sampling freq eg. 8000, 441000, 48000 */
+ __u32 aac_srate; /* Plain AAC decoder operating sample rate */
+ __u8 mpg_id; /* 0=MPEG-2, 1=MPEG-4 */
+ __u8 bs_format; /* input bit stream format adts=0, adif=1, raw=2 */
+ __u8 aac_profile; /* 0=Main Profile, 1=LC profile, 3=SSR profile */
+ __u8 ext_chl; /* No.of external channels */
+ __u8 aot; /* Audio object type. 1=Main , 2=LC , 3=SSR, 4=SBR*/
+ __u8 op_align; /* output alignment 0=16 bit , 1=MSB, 2= LSB align */
+ __u8 brate_type; /* 0=CBR, 1=VBR */
+ __u8 crc_check; /* crc check 0= disable, 1=enable */
+ __s8 bit_stream_format[8]; /* input bit stream format adts/adif/raw */
+ __u8 jstereo; /* Joint stereo Flag */
+ __u8 sbr_present; /* 1 = SBR Present, 0 = SBR absent, for RAW */
+ __u8 downsample; /* 1 = Downsampling ON, 0 = Downsampling OFF */
+ __u8 num_syntc_elems; /* 1- Mono/stereo, 0 - Dual Mono, 0 - for raw */
+ __s8 syntc_id[2]; /* 0 for ID_SCE(Dula Mono), -1 for raw */
+ __s8 syntc_tag[2]; /* raw - -1 and 0 -16 for rest of the streams */
+ __u8 pce_present; /* Flag. 1- present 0 - not present, for RAW */
+ __u8 sbr_type; /* sbr_type: 0-plain aac, 1-aac-v1, 2-aac-v2 */
+ __u8 outchmode; /*0- mono, 1-stereo, 2-dual mono 3-Parametric stereo */
+ __u8 ps_present;
+};
+
+/* WMA Music Parameters Message */
+struct snd_wma_params {
+ __u16 codec;
+ __u8 num_chan; /* 1=Mono, 2=Stereo */
+ __u8 pcm_wd_sz; /* 16/24 - bit*/
+ __u32 brate; /* Use the hard coded value. */
+ __u32 sfreq; /* Sampling freq eg. 8000, 441000, 48000 */
+ __u32 channel_mask; /* Channel Mask */
+ __u16 format_tag; /* Format Tag */
+ __u16 block_align; /* packet size */
+ __u16 wma_encode_opt;/* Encoder option */
+ __u8 op_align; /* op align 0- 16 bit, 1- MSB, 2 LSB */
+ __u8 pcm_src; /* input pcm bit width */
+};
+
+/* Pre processing param structure */
+struct snd_prp_params {
+ __u32 reserved; /* No pre-processing defined yet */
+};
+
+struct snd_params_block {
+ __u32 type; /*Type of the parameter*/
+ __u32 size; /*size of the parameters in the block*/
+ __u8 params[0]; /*Parameters of the algorithm*/
+};
+
+/* Pre and post processing params structure */
+struct snd_ppp_params {
+ enum sst_algo_types algo_id;/* Post/Pre processing algorithm ID */
+ __u8 str_id; /*Only 5 bits used 0 - 31 are valid*/
+ __u8 enable; /* 0= disable, 1= enable*/
+ __u8 reserved;
+ __u32 size; /*Size of parameters for all blocks*/
+ struct snd_params_block params[0];
+};
+
+struct snd_sst_postproc_info {
+ __u32 src_min; /* Supported SRC Min sampling freq */
+ __u32 src_max; /* Supported SRC Max sampling freq */
+ __u8 src; /* 0=Not supported, 1=Supported */
+ __u8 bass_boost; /* 0=Not Supported, 1=Supported */
+ __u8 stereo_widening; /* 0=Not Supported, 1=Supported */
+ __u8 volume_control; /* 0=Not Supported, 1=Supported */
+ __s16 min_vol; /* Minimum value of Volume in dB */
+ __s16 max_vol; /* Maximum value of Volume in dB */
+ __u8 mute_control; /* 0=No Mute, 1=Mute */
+ __u8 reserved1;
+ __u16 reserved2;
+};
+
+/* pre processing Capability info structure */
+struct snd_sst_prp_info {
+ __s16 min_vol; /* Minimum value of Volume in dB */
+ __s16 max_vol; /* Maximum value of Volume in dB */
+ __u8 volume_control; /* 0=Not Supported, 1=Supported */
+ __u8 reserved1; /* for 32 bit alignment */
+ __u16 reserved2; /* for 32 bit alignment */
+} __attribute__ ((packed));
+
+/*Pre / Post processing algorithms support*/
+struct snd_sst_ppp_info {
+ __u32 src:1; /* 0=Not supported, 1=Supported */
+ __u32 mixer:1; /* 0=Not supported, 1=Supported */
+ __u32 volume_control:1; /* 0=Not Supported, 1=Supported */
+ __u32 mute_control:1; /* 0=Not Supported, 1=Supported */
+ __u32 anc:1; /* 0=Not Supported, 1=Supported */
+ __u32 side_tone:1; /* 0=Not Supported, 1=Supported */
+ __u32 dc_removal:1; /* 0=Not Supported, 1=Supported */
+ __u32 equalizer:1; /* 0=Not Supported, 1=Supported */
+ __u32 spkr_prot:1; /* 0=Not Supported, 1=Supported */
+ __u32 bass_boost:1; /* 0=Not Supported, 1=Supported */
+ __u32 stereo_widening:1;/* 0=Not Supported, 1=Supported */
+ __u32 rsvd1:21;
+ __u32 rsvd2;
+};
+
+/* Firmware capabilities info */
+struct snd_sst_fw_info {
+ struct snd_sst_fw_version fw_version; /* Firmware version */
+ __u8 audio_codecs_supported[8]; /* Codecs supported by FW */
+ __u32 recommend_min_duration; /* Min duration for Lowpower Playback */
+ __u8 max_pcm_streams_supported; /* Max num of PCM streams supported */
+ __u8 max_enc_streams_supported; /* Max number of Encoded streams */
+ __u16 reserved; /* 32 bit alignment*/
+ struct snd_sst_ppp_info ppp_info; /* pre_processing mod cap info */
+ struct snd_sst_postproc_info pop_info; /* Post processing cap info*/
+ struct snd_sst_port_info port_info[3]; /* Port info */
+ struct snd_sst_mix_info mix_info;/* Mixer info */
+ __u32 min_input_buf; /* minmum i/p buffer for decode */
+};
+
+/* Codec params struture */
+union snd_sst_codec_params {
+ struct snd_pcm_params pcm_params;
+ struct snd_mp3_params mp3_params;
+ struct snd_aac_params aac_params;
+ struct snd_wma_params wma_params;
+};
+
+
+struct snd_sst_stream_params {
+ union snd_sst_codec_params uc;
+} __attribute__ ((packed));
+
+struct snd_sst_params {
+ __u32 result;
+ __u32 stream_id;
+ __u8 codec;
+ __u8 ops;
+ __u8 stream_type;
+ __u8 device_type;
+ struct snd_sst_stream_params sparams;
+};
+
+struct snd_sst_vol {
+ __u32 stream_id;
+ __s32 volume;
+ __u32 ramp_duration;
+ __u32 ramp_type; /* Ramp type, default=0 */
+};
+
+struct snd_sst_mute {
+ __u32 stream_id;
+ __u32 mute;
+};
+
+/* ioctl related stuff here */
+struct snd_sst_pmic_config {
+ __u32 sfreq; /* Sampling rate in Hz */
+ __u16 num_chan; /* Mono =1 or Stereo =2 */
+ __u16 pcm_wd_sz; /* Number of bits per sample */
+} __attribute__ ((packed));
+
+struct snd_sst_get_stream_params {
+ struct snd_sst_params codec_params;
+ struct snd_sst_pmic_config pcm_params;
+};
+
+enum snd_sst_target_type {
+ SND_SST_TARGET_PMIC = 1,
+ SND_SST_TARGET_LPE,
+ SND_SST_TARGET_MODEM,
+ SND_SST_TARGET_BT,
+ SND_SST_TARGET_FM,
+ SND_SST_TARGET_NONE,
+};
+
+enum snd_sst_device_type {
+ SND_SST_DEVICE_SSP = 1,
+ SND_SST_DEVICE_PCM,
+ SND_SST_DEVICE_OTHER,
+};
+
+enum snd_sst_device_mode {
+
+ SND_SST_DEV_MODE_PCM_MODE1 = 1, /*(16-bit word, bit-length frame sync)*/
+ SND_SST_DEV_MODE_PCM_MODE2,
+ SND_SST_DEV_MODE_PCM_MODE3,
+ SND_SST_DEV_MODE_PCM_MODE4_RIGHT_JUSTIFIED,
+ SND_SST_DEV_MODE_PCM_MODE4_LEFT_JUSTIFIED,
+ SND_SST_DEV_MODE_PCM_MODE4_I2S, /*(I2S mode, 16-bit words)*/
+ SND_SST_DEV_MODE_PCM_MODE5,
+ SND_SST_DEV_MODE_PCM_MODE6,
+};
+
+enum snd_sst_port_action {
+ SND_SST_PORT_PREPARE = 1,
+ SND_SST_PORT_ACTIVATE,
+};
+
+/* Target selection per device structure */
+struct snd_sst_slot_info {
+ __u8 mix_enable; /* Mixer enable or disable */
+ __u8 device_type;
+ __u8 device_instance; /* 0, 1, 2 */
+ __u8 target_device;
+ __u16 target_sink;
+ __u8 slot[2];
+ __u8 master;
+ __u8 action;
+ __u8 device_mode;
+ __u8 reserved;
+ struct snd_sst_pmic_config pcm_params;
+} __attribute__ ((packed));
+
+#define SST_MAX_TARGET_DEVICES 3
+/* Target device list structure */
+struct snd_sst_target_device {
+ __u32 device_route;
+ struct snd_sst_slot_info devices[SST_MAX_TARGET_DEVICES];
+} __attribute__ ((packed));
+
+struct snd_sst_driver_info {
+ __u32 version; /* Version of the driver */
+ __u32 active_pcm_streams;
+ __u32 active_enc_streams;
+ __u32 max_pcm_streams;
+ __u32 max_enc_streams;
+ __u32 buf_per_stream;
+};
+
+enum snd_sst_buff_type {
+ SST_BUF_USER = 1,
+ SST_BUF_MMAP,
+ SST_BUF_RAR,
+};
+
+struct snd_sst_mmap_buff_entry {
+ unsigned int offset;
+ unsigned int size;
+};
+
+struct snd_sst_mmap_buffs {
+ unsigned int entries;
+ enum snd_sst_buff_type type;
+ struct snd_sst_mmap_buff_entry *buff;
+};
+
+struct snd_sst_buff_entry {
+ void *buffer;
+ unsigned int size;
+};
+
+struct snd_sst_buffs {
+ unsigned int entries;
+ __u8 type;
+ struct snd_sst_buff_entry *buff_entry;
+};
+
+struct snd_sst_dbufs {
+ unsigned long long input_bytes_consumed;
+ unsigned long long output_bytes_produced;
+ struct snd_sst_buffs *ibufs;
+ struct snd_sst_buffs *obufs;
+};
+
+/*IOCTL defined here */
+/*SST MMF IOCTLS only */
+#define SNDRV_SST_STREAM_SET_PARAMS _IOR('L', 0x00, \
+ struct snd_sst_stream_params *)
+#define SNDRV_SST_STREAM_GET_PARAMS _IOWR('L', 0x01, \
+ struct snd_sst_get_stream_params *)
+#define SNDRV_SST_STREAM_GET_TSTAMP _IOWR('L', 0x02, __u64 *)
+#define SNDRV_SST_STREAM_DECODE _IOWR('L', 0x03, struct snd_sst_dbufs *)
+#define SNDRV_SST_STREAM_BYTES_DECODED _IOWR('L', 0x04, __u64 *)
+#define SNDRV_SST_STREAM_START _IO('A', 0x42)
+#define SNDRV_SST_STREAM_DROP _IO('A', 0x43)
+#define SNDRV_SST_STREAM_DRAIN _IO('A', 0x44)
+#define SNDRV_SST_STREAM_PAUSE _IOW('A', 0x45, int)
+#define SNDRV_SST_STREAM_RESUME _IO('A', 0x47)
+#define SNDRV_SST_MMAP_PLAY _IOW('L', 0x05, struct snd_sst_mmap_buffs *)
+#define SNDRV_SST_MMAP_CAPTURE _IOW('L', 0x06, struct snd_sst_mmap_buffs *)
+/*SST common ioctls */
+#define SNDRV_SST_DRIVER_INFO _IOR('L', 0x10, struct snd_sst_driver_info *)
+#define SNDRV_SST_SET_VOL _IOW('L', 0x11, struct snd_sst_vol *)
+#define SNDRV_SST_GET_VOL _IOW('L', 0x12, struct snd_sst_vol *)
+#define SNDRV_SST_MUTE _IOW('L', 0x13, struct snd_sst_mute *)
+/*AM Ioctly only */
+#define SNDRV_SST_FW_INFO _IOR('L', 0x20, struct snd_sst_fw_info *)
+#define SNDRV_SST_SET_TARGET_DEVICE _IOW('L', 0x21, \
+ struct snd_sst_target_device *)
+
+#endif /* __INTEL_SST_IOCTL_H__ */
diff --git a/drivers/staging/intel_sst/intel_sst_ipc.c b/drivers/staging/intel_sst/intel_sst_ipc.c
new file mode 100644
index 0000000..39c67fa
--- /dev/null
+++ b/drivers/staging/intel_sst/intel_sst_ipc.c
@@ -0,0 +1,656 @@
+/*
+ * intel_sst_ipc.c - Intel SST Driver for audio engine
+ *
+ * Copyright (C) 2008-10 Intel Corporation
+ * Authors: Vinod Koul <vinod.koul(a)intel.com>
+ * Harsha Priya <priya.harsha(a)intel.com>
+ * Dharageswari R <dharageswari.r(a)intel.com>
+ * KP Jeeja <jeeja.kp(a)intel.com>
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This file defines all ipc functions
+ */
+
+#include <linux/pci.h>
+#include <linux/firmware.h>
+#include <linux/sched.h>
+#include "intel_sst.h"
+#include "intel_sst_ioctl.h"
+#include "intel_sst_fw_ipc.h"
+#include "intel_sst_common.h"
+
+/*
+ * sst_send_sound_card_type - send sound card type
+ *
+ * this function sends the sound card type to sst dsp engine
+ */
+static void sst_send_sound_card_type(void)
+{
+ struct ipc_post *msg = NULL;
+
+ if (sst_create_short_msg(&msg))
+ return;
+
+ sst_fill_header(&msg->header, IPC_IA_SET_PMIC_TYPE, 0, 0);
+ msg->header.part.data = sst_drv_ctx->pmic_vendor;
+ spin_lock(&sst_drv_ctx->list_spin_lock);
+ list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list);
+ spin_unlock(&sst_drv_ctx->list_spin_lock);
+ sst_post_message(&sst_drv_ctx->ipc_post_msg_wq);
+ return;
+}
+
+/**
+* sst_post_message - Posts message to SST
+*
+* @work: Pointer to work structure
+*
+* This function is called by any component in driver which
+* wants to send an IPC message. This will post message only if
+* busy bit is free
+*/
+void sst_post_message(struct work_struct *work)
+{
+ struct ipc_post *msg;
+ union ipc_header header;
+ union interrupt_reg imr;
+ int retval = 0;
+ imr.full = 0;
+
+ /*To check if LPE is in stalled state.*/
+ retval = sst_stalled();
+ if (retval < 0) {
+ pr_err("sst: in stalled state\n");
+ return;
+ }
+ pr_debug("sst: post message called\n");
+ spin_lock(&sst_drv_ctx->list_spin_lock);
+
+ /* check list */
+ if (list_empty(&sst_drv_ctx->ipc_dispatch_list)) {
+ /* list is empty, mask imr */
+ pr_debug("sst: Empty msg queue... masking\n");
+ imr.full = readl(sst_drv_ctx->shim + SST_IMRX);
+ imr.part.done_interrupt = 1;
+ /* dummy register for shim workaround */
+ sst_shim_write(sst_drv_ctx->shim, SST_IMRX, imr.full);
+ spin_unlock(&sst_drv_ctx->list_spin_lock);
+ return;
+ }
+
+ /* check busy bit */
+ header.full = sst_shim_read(sst_drv_ctx->shim, SST_IPCX);
+ if (header.part.busy) {
+ /* busy, unmask */
+ pr_debug("sst: Busy not free... unmasking\n");
+ imr.full = readl(sst_drv_ctx->shim + SST_IMRX);
+ imr.part.done_interrupt = 0;
+ /* dummy register for shim workaround */
+ sst_shim_write(sst_drv_ctx->shim, SST_IMRX, imr.full);
+ spin_unlock(&sst_drv_ctx->list_spin_lock);
+ return;
+ }
+ /* copy msg from list */
+ msg = list_entry(sst_drv_ctx->ipc_dispatch_list.next,
+ struct ipc_post, node);
+ list_del(&msg->node);
+ pr_debug("sst: Post message: header = %x\n", msg->header.full);
+ pr_debug("sst: size: = %x\n", msg->header.part.data);
+ if (msg->header.part.large)
+ memcpy_toio(sst_drv_ctx->mailbox + SST_MAILBOX_SEND,
+ msg->mailbox_data, msg->header.part.data);
+ /* dummy register for shim workaround */
+
+ sst_shim_write(sst_drv_ctx->shim, SST_IPCX, msg->header.full);
+ spin_unlock(&sst_drv_ctx->list_spin_lock);
+
+ kfree(msg->mailbox_data);
+ kfree(msg);
+ return;
+}
+
+/*
+ * sst_clear_interrupt - clear the SST FW interrupt
+ *
+ * This function clears the interrupt register after the interrupt
+ * bottom half is complete allowing next interrupt to arrive
+ */
+void sst_clear_interrupt(void)
+{
+ union interrupt_reg isr;
+ union interrupt_reg imr;
+ union ipc_header clear_ipc;
+
+ imr.full = sst_shim_read(sst_drv_ctx->shim, SST_IMRX);
+ isr.full = sst_shim_read(sst_drv_ctx->shim, SST_ISRX);
+ /* write 1 to clear */;
+ isr.part.busy_interrupt = 1;
+ sst_shim_write(sst_drv_ctx->shim, SST_ISRX, isr.full);
+ /* Set IA done bit */
+ clear_ipc.full = sst_shim_read(sst_drv_ctx->shim, SST_IPCD);
+ clear_ipc.part.busy = 0;
+ clear_ipc.part.done = 1;
+ clear_ipc.part.data = IPC_ACK_SUCCESS;
+ sst_shim_write(sst_drv_ctx->shim, SST_IPCD, clear_ipc.full);
+ /* un mask busy interrupt */
+ imr.part.busy_interrupt = 0;
+ sst_shim_write(sst_drv_ctx->shim, SST_IMRX, imr.full);
+}
+
+/*
+ * process_fw_init - process the FW init msg
+ *
+ * @msg: IPC message from FW
+ *
+ * This function processes the FW init msg from FW
+ * marks FW state and prints debug info of loaded FW
+ */
+int process_fw_init(struct sst_ipc_msg_wq *msg)
+{
+ struct ipc_header_fw_init *init =
+ (struct ipc_header_fw_init *)msg->mailbox;
+ int retval = 0;
+
+ pr_debug("sst: *** FW Init msg came***\n");
+ if (init->result) {
+ mutex_lock(&sst_drv_ctx->sst_lock);
+ sst_drv_ctx->sst_state = SST_ERROR;
+ mutex_unlock(&sst_drv_ctx->sst_lock);
+ pr_debug("sst: FW Init failed, Error %x\n", init->result);
+ pr_err("sst: FW Init failed, Error %x\n", init->result);
+ retval = -init->result;
+ return retval;
+ }
+ if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID)
+ sst_send_sound_card_type();
+ mutex_lock(&sst_drv_ctx->sst_lock);
+ sst_drv_ctx->sst_state = SST_FW_RUNNING;
+ mutex_unlock(&sst_drv_ctx->sst_lock);
+ pr_debug("sst: FW Version %x.%x\n",
+ init->fw_version.major, init->fw_version.minor);
+ pr_debug("sst: Build No %x Type %x\n",
+ init->fw_version.build, init->fw_version.type);
+ pr_debug("sst: Build date %s Time %s\n",
+ init->build_info.date, init->build_info.time);
+ sst_wake_up_alloc_block(sst_drv_ctx, FW_DWNL_ID, retval, NULL);
+ return retval;
+}
+/**
+* sst_process_message - Processes message from SST
+*
+* @work: Pointer to work structure
+*
+* This function is scheduled by ISR
+* It take a msg from process_queue and does action based on msg
+*/
+void sst_process_message(struct work_struct *work)
+{
+ struct sst_ipc_msg_wq *msg =
+ container_of(work, struct sst_ipc_msg_wq, wq);
+ int str_id = msg->header.part.str_id;
+
+ pr_debug("sst: IPC process for %x\n", msg->header.full);
+
+ /* based on msg in list call respective handler */
+ switch (msg->header.part.msg_id) {
+ case IPC_SST_BUF_UNDER_RUN:
+ case IPC_SST_BUF_OVER_RUN:
+ if (sst_validate_strid(str_id)) {
+ pr_err("sst: stream id %d invalid\n", str_id);
+ break;
+ }
+ pr_err("sst: Buffer under/overrun for%d\n",
+ msg->header.part.str_id);
+ pr_err("sst: Got Underrun & not to send data...ignore\n");
+ break;
+
+ case IPC_SST_GET_PLAY_FRAMES:
+ if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID) {
+ struct stream_info *stream ;
+
+ if (sst_validate_strid(str_id)) {
+ pr_err("sst: strid %d invalid\n", str_id);
+ break;
+ }
+ /* call sst_play_frame */
+ stream = &sst_drv_ctx->streams[str_id];
+ pr_debug("sst: sst_play_frames for %d\n",
+ msg->header.part.str_id);
+ mutex_lock(&sst_drv_ctx->streams[str_id].lock);
+ sst_play_frame(msg->header.part.str_id);
+ mutex_unlock(&sst_drv_ctx->streams[str_id].lock);
+ break;
+ } else
+ pr_err("sst: sst_play_frames for Penwell!!\n");
+
+ case IPC_SST_GET_CAPT_FRAMES:
+ if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID) {
+ struct stream_info *stream;
+ /* call sst_capture_frame */
+ if (sst_validate_strid(str_id)) {
+ pr_err("sst: str id %d invalid\n", str_id);
+ break;
+ }
+ stream = &sst_drv_ctx->streams[str_id];
+ pr_debug("sst: sst_capture_frames for %d\n",
+ msg->header.part.str_id);
+ mutex_lock(&stream->lock);
+ if (stream->mmapped == false &&
+ stream->src == SST_DRV) {
+ pr_debug("sst: waking up block for copy.\n");
+ stream->data_blk.ret_code = 0;
+ stream->data_blk.condition = true;
+ stream->data_blk.on = false;
+ wake_up(&sst_drv_ctx->wait_queue);
+ } else
+ sst_capture_frame(msg->header.part.str_id);
+ mutex_unlock(&stream->lock);
+ } else
+ pr_err("sst: sst_play_frames for Penwell!!\n");
+ break;
+
+ case IPC_IA_PRINT_STRING:
+ pr_debug("sst: been asked to print something by fw\n");
+ /* TBD */
+ break;
+
+ case IPC_IA_FW_INIT_CMPLT: {
+ /* send next data to FW */
+ process_fw_init(msg);
+ break;
+ }
+
+ case IPC_SST_STREAM_PROCESS_FATAL_ERR:
+ if (sst_validate_strid(str_id)) {
+ pr_err("sst: stream id %d invalid\n", str_id);
+ break;
+ }
+ pr_err("sst: codec fatal error %x stream %d...\n",
+ msg->header.full, msg->header.part.str_id);
+ pr_err("sst: Dropping the stream\n");
+ sst_drop_stream(msg->header.part.str_id);
+ break;
+ case IPC_IA_LPE_GETTING_STALLED:
+ sst_drv_ctx->lpe_stalled = 1;
+ break;
+ case IPC_IA_LPE_UNSTALLED:
+ sst_drv_ctx->lpe_stalled = 0;
+ break;
+ default:
+ /* Illegal case */
+ pr_err("sst: Unhandled msg %x header %x\n",
+ msg->header.part.msg_id, msg->header.full);
+ }
+ sst_clear_interrupt();
+ return;
+}
+
+/**
+* sst_process_reply - Processes reply message from SST
+*
+* @work: Pointer to work structure
+*
+* This function is scheduled by ISR
+* It take a reply msg from response_queue and
+* does action based on msg
+*/
+void sst_process_reply(struct work_struct *work)
+{
+ struct sst_ipc_msg_wq *msg =
+ container_of(work, struct sst_ipc_msg_wq, wq);
+
+ int str_id = msg->header.part.str_id;
+ struct stream_info *str_info;
+
+ switch (msg->header.part.msg_id) {
+ case IPC_IA_TARGET_DEV_SELECT:
+ if (!msg->header.part.data) {
+ sst_drv_ctx->tgt_dev_blk.ret_code = 0;
+ } else {
+ pr_err("sst: Msg %x reply error %x\n",
+ msg->header.part.msg_id, msg->header.part.data);
+ sst_drv_ctx->tgt_dev_blk.ret_code =
+ -msg->header.part.data;
+ }
+
+ if (sst_drv_ctx->tgt_dev_blk.on == true) {
+ sst_drv_ctx->tgt_dev_blk.condition = true;
+ wake_up(&sst_drv_ctx->wait_queue);
+ }
+ break;
+ case IPC_IA_GET_FW_INFO: {
+ struct snd_sst_fw_info *fw_info =
+ (struct snd_sst_fw_info *)msg->mailbox;
+ if (msg->header.part.large) {
+ int major = fw_info->fw_version.major;
+ int minor = fw_info->fw_version.minor;
+ int build = fw_info->fw_version.build;
+ pr_debug("sst: Msg succedded %x\n",
+ msg->header.part.msg_id);
+ pr_debug("INFO: ***FW*** = %02d.%02d.%02d\n",
+ major, minor, build);
+ memcpy_fromio(sst_drv_ctx->fw_info_blk.data,
+ ((struct snd_sst_fw_info *)(msg->mailbox)),
+ sizeof(struct snd_sst_fw_info));
+ sst_drv_ctx->fw_info_blk.ret_code = 0;
+ } else {
+ pr_err("sst: Msg %x reply error %x\n",
+ msg->header.part.msg_id, msg->header.part.data);
+ sst_drv_ctx->fw_info_blk.ret_code =
+ -msg->header.part.data;
+ }
+ if (sst_drv_ctx->fw_info_blk.on == true) {
+ pr_debug("sst: Memcopy succedded\n");
+ sst_drv_ctx->fw_info_blk.on = false;
+ sst_drv_ctx->fw_info_blk.condition = true;
+ wake_up(&sst_drv_ctx->wait_queue);
+ }
+ break;
+ }
+ case IPC_IA_SET_STREAM_MUTE:
+ if (!msg->header.part.data) {
+ pr_debug("sst: Msg succedded %x\n",
+ msg->header.part.msg_id);
+ sst_drv_ctx->mute_info_blk.ret_code = 0;
+ } else {
+ pr_err("sst: Msg %x reply error %x\n",
+ msg->header.part.msg_id, msg->header.part.data);
+ sst_drv_ctx->mute_info_blk.ret_code =
+ -msg->header.part.data;
+
+ }
+ if (sst_drv_ctx->mute_info_blk.on == true) {
+ sst_drv_ctx->mute_info_blk.on = false;
+ sst_drv_ctx->mute_info_blk.condition = true;
+ wake_up(&sst_drv_ctx->wait_queue);
+ }
+ break;
+ case IPC_IA_SET_STREAM_VOL:
+ if (!msg->header.part.data) {
+ pr_debug("sst: Msg succedded %x\n",
+ msg->header.part.msg_id);
+ sst_drv_ctx->vol_info_blk.ret_code = 0;
+ } else {
+ pr_err("sst: Msg %x reply error %x\n",
+ msg->header.part.msg_id,
+ msg->header.part.data);
+ sst_drv_ctx->vol_info_blk.ret_code =
+ -msg->header.part.data;
+
+ }
+
+ if (sst_drv_ctx->vol_info_blk.on == true) {
+ sst_drv_ctx->vol_info_blk.on = false;
+ sst_drv_ctx->vol_info_blk.condition = true;
+ wake_up(&sst_drv_ctx->wait_queue);
+ }
+ break;
+ case IPC_IA_GET_STREAM_VOL:
+ if (msg->header.part.large) {
+ pr_debug("sst: Large Msg Received Successfully\n");
+ pr_debug("sst: Msg succedded %x\n",
+ msg->header.part.msg_id);
+ memcpy_fromio(sst_drv_ctx->vol_info_blk.data,
+ (void *) msg->mailbox,
+ sizeof(struct snd_sst_vol));
+ sst_drv_ctx->vol_info_blk.ret_code = 0;
+ } else {
+ pr_err("sst: Msg %x reply error %x\n",
+ msg->header.part.msg_id, msg->header.part.data);
+ sst_drv_ctx->vol_info_blk.ret_code =
+ -msg->header.part.data;
+ }
+ if (sst_drv_ctx->vol_info_blk.on == true) {
+ sst_drv_ctx->vol_info_blk.on = false;
+ sst_drv_ctx->vol_info_blk.condition = true;
+ wake_up(&sst_drv_ctx->wait_queue);
+ }
+ break;
+
+ case IPC_IA_GET_STREAM_PARAMS:
+ if (sst_validate_strid(str_id)) {
+ pr_err("sst: stream id %d invalid\n", str_id);
+ break;
+ }
+ str_info = &sst_drv_ctx->streams[str_id];
+ if (msg->header.part.large) {
+ pr_debug("sst: Get stream large success\n");
+ memcpy_fromio(str_info->ctrl_blk.data,
+ ((void *)(msg->mailbox)),
+ sizeof(struct snd_sst_fw_get_stream_params));
+ str_info->ctrl_blk.ret_code = 0;
+ } else {
+ pr_err("sst: Msg %x reply error %x\n",
+ msg->header.part.msg_id, msg->header.part.data);
+ str_info->ctrl_blk.ret_code = -msg->header.part.data;
+ }
+ if (str_info->ctrl_blk.on == true) {
+ str_info->ctrl_blk.on = false;
+ str_info->ctrl_blk.condition = true;
+ wake_up(&sst_drv_ctx->wait_queue);
+ }
+ break;
+ case IPC_IA_DECODE_FRAMES:
+ if (sst_validate_strid(str_id)) {
+ pr_err("sst: stream id %d invalid\n", str_id);
+ break;
+ }
+ str_info = &sst_drv_ctx->streams[str_id];
+ if (msg->header.part.large) {
+ pr_debug("sst: Msg succedded %x\n",
+ msg->header.part.msg_id);
+ memcpy_fromio(str_info->data_blk.data,
+ ((void *)(msg->mailbox)),
+ sizeof(struct snd_sst_decode_info));
+ str_info->data_blk.ret_code = 0;
+ } else {
+ pr_err("sst: Msg %x reply error %x\n",
+ msg->header.part.msg_id, msg->header.part.data);
+ str_info->data_blk.ret_code = -msg->header.part.data;
+ }
+ if (str_info->data_blk.on == true) {
+ str_info->data_blk.on = false;
+ str_info->data_blk.condition = true;
+ wake_up(&sst_drv_ctx->wait_queue);
+ }
+ break;
+ case IPC_IA_DRAIN_STREAM:
+ if (sst_validate_strid(str_id)) {
+ pr_err("sst: stream id %d invalid\n", str_id);
+ break;
+ }
+ str_info = &sst_drv_ctx->streams[str_id];
+ if (!msg->header.part.data) {
+ pr_debug("sst: Msg succedded %x\n",
+ msg->header.part.msg_id);
+ str_info->ctrl_blk.ret_code = 0;
+
+ } else {
+ pr_err("sst: Msg %x reply error %x\n",
+ msg->header.part.msg_id, msg->header.part.data);
+ str_info->ctrl_blk.ret_code = -msg->header.part.data;
+
+ }
+ str_info = &sst_drv_ctx->streams[str_id];
+ if (str_info->data_blk.on == true) {
+ str_info->data_blk.on = false;
+ str_info->data_blk.condition = true;
+ wake_up(&sst_drv_ctx->wait_queue);
+ }
+ break;
+
+ case IPC_IA_DROP_STREAM:
+ if (sst_validate_strid(str_id)) {
+ pr_err("sst: str id %d invalid\n", str_id);
+ break;
+ }
+ str_info = &sst_drv_ctx->streams[str_id];
+ if (msg->header.part.large) {
+ struct snd_sst_drop_response *drop_resp =
+ (struct snd_sst_drop_response *)msg->mailbox;
+
+ pr_debug("sst: Drop ret bytes %x\n", drop_resp->bytes);
+
+ str_info->curr_bytes = drop_resp->bytes;
+ str_info->ctrl_blk.ret_code = 0;
+ } else {
+ pr_err("sst: Msg %x reply error %x\n",
+ msg->header.part.msg_id, msg->header.part.data);
+ str_info->ctrl_blk.ret_code = -msg->header.part.data;
+ }
+ if (str_info->ctrl_blk.on == true) {
+ str_info->ctrl_blk.on = false;
+ str_info->ctrl_blk.condition = true;
+ wake_up(&sst_drv_ctx->wait_queue);
+ }
+ break;
+ case IPC_IA_ENABLE_RX_TIME_SLOT:
+ if (!msg->header.part.data) {
+ pr_debug("sst: RX_TIME_SLOT success\n");
+ sst_drv_ctx->hs_info_blk.ret_code = 0;
+ } else {
+ pr_err("sst: Msg %x reply error %x\n",
+ msg->header.part.msg_id,
+ msg->header.part.data);
+ sst_drv_ctx->hs_info_blk.ret_code =
+ -msg->header.part.data;
+ }
+ if (sst_drv_ctx->hs_info_blk.on == true) {
+ sst_drv_ctx->hs_info_blk.on = false;
+ sst_drv_ctx->hs_info_blk.condition = true;
+ wake_up(&sst_drv_ctx->wait_queue);
+ }
+ break;
+ case IPC_IA_PAUSE_STREAM:
+ case IPC_IA_RESUME_STREAM:
+ case IPC_IA_SET_STREAM_PARAMS:
+ str_info = &sst_drv_ctx->streams[str_id];
+ if (!msg->header.part.data) {
+ pr_debug("sst: Msg succedded %x\n",
+ msg->header.part.msg_id);
+ str_info->ctrl_blk.ret_code = 0;
+ } else {
+ pr_err("sst: Msg %x reply error %x\n",
+ msg->header.part.msg_id,
+ msg->header.part.data);
+ str_info->ctrl_blk.ret_code = -msg->header.part.data;
+ }
+ if (sst_validate_strid(str_id)) {
+ pr_err("sst: stream id %d invalid\n", str_id);
+ break;
+ }
+
+ if (str_info->ctrl_blk.on == true) {
+ str_info->ctrl_blk.on = false;
+ str_info->ctrl_blk.condition = true;
+ wake_up(&sst_drv_ctx->wait_queue);
+ }
+ break;
+
+ case IPC_IA_FREE_STREAM:
+ if (!msg->header.part.data) {
+ pr_debug("sst: Stream %d freed\n", str_id);
+ } else {
+ pr_err("sst: Free for %d ret error %x\n",
+ str_id, msg->header.part.data);
+ }
+ break;
+ case IPC_IA_ALLOC_STREAM: {
+ /* map to stream, call play */
+ struct snd_sst_alloc_response *resp =
+ (struct snd_sst_alloc_response *)msg->mailbox;
+ if (resp->str_type.result)
+ pr_err("sst: error alloc stream = %x\n",
+ resp->str_type.result);
+ sst_alloc_stream_response(str_id, resp);
+ break;
+ }
+
+ case IPC_IA_PLAY_FRAMES:
+ case IPC_IA_CAPT_FRAMES:
+ if (sst_validate_strid(str_id)) {
+ pr_err("sst: stream id %d invalid\n" , str_id);
+ break;
+ }
+ pr_debug("sst: Ack for play/capt frames recived\n");
+ break;
+
+ case IPC_IA_PREP_LIB_DNLD: {
+ struct snd_sst_str_type *str_type =
+ (struct snd_sst_str_type *)msg->mailbox;
+ pr_debug("sst: Prep Lib download %x\n",
+ msg->header.part.msg_id);
+ if (str_type->result)
+ pr_err("sst: Prep lib download %x\n", str_type->result);
+ else
+ pr_debug("sst: Can download codec now...\n");
+ sst_wake_up_alloc_block(sst_drv_ctx, str_id,
+ str_type->result, NULL);
+ break;
+ }
+
+ case IPC_IA_LIB_DNLD_CMPLT: {
+ struct snd_sst_lib_download_info *resp =
+ (struct snd_sst_lib_download_info *)msg->mailbox;
+ int retval = resp->result;
+
+ pr_debug("sst: Lib downloaded %x\n", msg->header.part.msg_id);
+ if (resp->result) {
+ pr_err("sst: err in lib dload %x\n", resp->result);
+ } else {
+ pr_debug("sst: Codec download complete...\n");
+ pr_debug("sst: codec Type %d Ver %d Built %s: %s\n",
+ resp->dload_lib.lib_info.lib_type,
+ resp->dload_lib.lib_info.lib_version,
+ resp->dload_lib.lib_info.b_date,
+ resp->dload_lib.lib_info.b_time);
+ }
+ sst_wake_up_alloc_block(sst_drv_ctx, str_id,
+ retval, NULL);
+ break;
+ }
+
+ case IPC_IA_GET_FW_VERSION: {
+ struct ipc_header_fw_init *version =
+ (struct ipc_header_fw_init *)msg->mailbox;
+ int major = version->fw_version.major;
+ int minor = version->fw_version.minor;
+ int build = version->fw_version.build;
+ dev_info(&sst_drv_ctx->pci->dev,
+ "INFO: ***LOADED SST FW VERSION*** = %02d.%02d.%02d\n",
+ major, minor, build);
+ break;
+ }
+ case IPC_IA_GET_FW_BUILD_INF: {
+ struct sst_fw_build_info *build =
+ (struct sst_fw_build_info *)msg->mailbox;
+ pr_debug("sst: Build date:%sTime:%s", build->date, build->time);
+ break;
+ }
+ case IPC_IA_SET_PMIC_TYPE:
+ break;
+ case IPC_IA_START_STREAM:
+ pr_debug("sst: reply for START STREAM %x\n", msg->header.full);
+ break;
+ default:
+ /* Illegal case */
+ pr_err("sst: process reply:default = %x\n", msg->header.full);
+ }
+ sst_clear_interrupt();
+ return;
+}
diff --git a/drivers/staging/intel_sst/intel_sst_pvt.c b/drivers/staging/intel_sst/intel_sst_pvt.c
new file mode 100644
index 0000000..6487e19
--- /dev/null
+++ b/drivers/staging/intel_sst/intel_sst_pvt.c
@@ -0,0 +1,311 @@
+/*
+ * intel_sst_pvt.c - Intel SST Driver for audio engine
+ *
+ * Copyright (C) 2008-10 Intel Corp
+ * Authors: Vinod Koul <vinod.koul(a)intel.com>
+ * Harsha Priya <priya.harsha(a)intel.com>
+ * Dharageswari R <dharageswari.r(a)intel.com>
+ * KP Jeeja <jeeja.kp(a)intel.com>
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This driver exposes the audio engine functionalities to the ALSA
+ * and middleware.
+ *
+ * This file contains all private functions
+ */
+
+#include <linux/pci.h>
+#include <linux/fs.h>
+#include <linux/firmware.h>
+#include <linux/sched.h>
+#include "intel_sst.h"
+#include "intel_sst_ioctl.h"
+#include "intel_sst_fw_ipc.h"
+#include "intel_sst_common.h"
+
+/*
+ * sst_get_block_stream - get a new block stream
+ *
+ * @sst_drv_ctx: Driver context structure
+ *
+ * This function assigns a block for the calls that dont have stream context yet
+ * the blocks are used for waiting on Firmware's response for any operation
+ * Should be called with stream lock held
+ */
+int sst_get_block_stream(struct intel_sst_drv *sst_drv_ctx)
+{
+ int i;
+
+ for (i = 0; i < MAX_ACTIVE_STREAM; i++) {
+ if (sst_drv_ctx->alloc_block[i].sst_id == BLOCK_UNINIT) {
+ sst_drv_ctx->alloc_block[i].ops_block.condition = false;
+ sst_drv_ctx->alloc_block[i].ops_block.ret_code = 0;
+ sst_drv_ctx->alloc_block[i].sst_id = 0;
+ break;
+ }
+ }
+ if (i == MAX_ACTIVE_STREAM) {
+ pr_err("sst: max alloc_stream reached");
+ i = -EBUSY; /* active stream limit reached */
+ }
+ return i;
+}
+
+/*
+ * sst_wait_interruptible - wait on event
+ *
+ * @sst_drv_ctx: Driver context
+ * @block: Driver block to wait on
+ *
+ * This function waits without a timeout (and is interruptable) for a
+ * given block event
+ */
+int sst_wait_interruptible(struct intel_sst_drv *sst_drv_ctx,
+ struct sst_block *block)
+{
+ int retval = 0;
+
+ if (!wait_event_interruptible(sst_drv_ctx->wait_queue,
+ block->condition)) {
+ /* event wake */
+ if (block->ret_code < 0) {
+ pr_err("sst: stream failed %d\n", block->ret_code);
+ retval = -EBUSY;
+ } else {
+ pr_debug("sst: event up\n");
+ retval = 0;
+ }
+ } else {
+ pr_err("sst: signal interrupted\n");
+ retval = -EINTR;
+ }
+ return retval;
+
+}
+
+
+/*
+ * sst_wait_interruptible_timeout - wait on event interruptable
+ *
+ * @sst_drv_ctx: Driver context
+ * @block: Driver block to wait on
+ * @timeout: time for wait on
+ *
+ * This function waits with a timeout value (and is interruptible) on a
+ * given block event
+ */
+int sst_wait_interruptible_timeout(
+ struct intel_sst_drv *sst_drv_ctx,
+ struct sst_block *block, int timeout)
+{
+ int retval = 0;
+
+ pr_debug("sst: sst_wait_interruptible_timeout - waiting....\n");
+ if (wait_event_interruptible_timeout(sst_drv_ctx->wait_queue,
+ block->condition,
+ msecs_to_jiffies(timeout))) {
+ if (block->ret_code < 0)
+ pr_err("sst: stream failed %d\n", block->ret_code);
+ else
+ pr_debug("sst: event up\n");
+ retval = block->ret_code;
+ } else {
+ block->on = false;
+ pr_err("sst: timeout occured...\n");
+ /*setting firmware state as uninit so that the
+ firmware will get re-downloaded on next request
+ this is because firmare not responding for 5 sec
+ is equalant to some unrecoverable error of FW
+ sst_drv_ctx->sst_state = SST_UN_INIT;*/
+ retval = -EBUSY;
+ }
+ return retval;
+
+}
+
+
+/*
+ * sst_wait_timeout - wait on event for timeout
+ *
+ * @sst_drv_ctx: Driver context
+ * @block: Driver block to wait on
+ *
+ * This function waits with a timeout value (and is not interruptible) on a
+ * given block event
+ */
+int sst_wait_timeout(struct intel_sst_drv *sst_drv_ctx,
+ struct stream_alloc_block *block)
+{
+ int retval = 0;
+
+ /* NOTE:
+ Observed that FW processes the alloc msg and replies even
+ before the alloc thread has finished execution */
+ pr_debug("sst: waiting for %x, condition %x\n",
+ block->sst_id, block->ops_block.condition);
+ if (wait_event_interruptible_timeout(sst_drv_ctx->wait_queue,
+ block->ops_block.condition,
+ msecs_to_jiffies(SST_BLOCK_TIMEOUT))) {
+ /* event wake */
+ pr_debug("sst: Event wake %x\n", block->ops_block.condition);
+ pr_debug("sst: message ret: %d\n", block->ops_block.ret_code);
+ retval = block->ops_block.ret_code;
+ } else {
+ block->ops_block.on = false;
+ pr_err("sst: Wait timed-out %x\n", block->ops_block.condition);
+ /* settign firmware state as uninit so that the
+ firmware will get redownloaded on next request
+ this is because firmare not responding for 5 sec
+ is equalant to some unrecoverable error of FW
+ sst_drv_ctx->sst_state = SST_UN_INIT;*/
+ retval = -EBUSY;
+ }
+ return retval;
+
+}
+
+/*
+ * sst_create_large_msg - create a large IPC message
+ *
+ * @arg: ipc message
+ *
+ * this function allocates structures to send a large message to the firmware
+ */
+int sst_create_large_msg(struct ipc_post **arg)
+{
+ struct ipc_post *msg;
+
+ msg = kzalloc(sizeof(struct ipc_post), GFP_ATOMIC);
+ if (!msg) {
+ pr_err("sst: kzalloc msg failed\n");
+ return -ENOMEM;
+ }
+
+ msg->mailbox_data = kzalloc(SST_MAILBOX_SIZE, GFP_ATOMIC);
+ if (!msg->mailbox_data) {
+ kfree(msg);
+ pr_err("sst: kzalloc mailbox_data failed");
+ return -ENOMEM;
+ };
+ *arg = msg;
+ return 0;
+}
+
+/*
+ * sst_create_short_msg - create a short IPC message
+ *
+ * @arg: ipc message
+ *
+ * this function allocates structures to send a short message to the firmware
+ */
+int sst_create_short_msg(struct ipc_post **arg)
+{
+ struct ipc_post *msg;
+
+ msg = kzalloc(sizeof(*msg), GFP_ATOMIC);
+ if (!msg) {
+ pr_err("sst: kzalloc msg failed\n");
+ return -ENOMEM;
+ }
+ msg->mailbox_data = NULL;
+ *arg = msg;
+ return 0;
+}
+
+/*
+ * sst_clean_stream - clean the stream context
+ *
+ * @stream: stream structure
+ *
+ * this function resets the stream contexts
+ * should be called in free
+ */
+void sst_clean_stream(struct stream_info *stream)
+{
+ struct sst_stream_bufs *bufs = NULL, *_bufs;
+ stream->status = STREAM_UN_INIT;
+ stream->prev = STREAM_UN_INIT;
+ mutex_lock(&stream->lock);
+ list_for_each_entry_safe(bufs, _bufs, &stream->bufs, node) {
+ list_del(&bufs->node);
+ kfree(bufs);
+ }
+ mutex_unlock(&stream->lock);
+
+ if (stream->ops != STREAM_OPS_PLAYBACK_DRM)
+ kfree(stream->decode_ibuf);
+}
+
+/*
+ * sst_wake_up_alloc_block - wake up waiting block
+ *
+ * @sst_drv_ctx: Driver context
+ * @sst_id: stream id
+ * @status: status of wakeup
+ * @data: data pointer of wakeup
+ *
+ * This function wakes up a sleeping block event based on the response
+ */
+void sst_wake_up_alloc_block(struct intel_sst_drv *sst_drv_ctx,
+ u8 sst_id, int status, void *data)
+{
+ int i;
+
+ /* Unblock with retval code */
+ for (i = 0; i < MAX_ACTIVE_STREAM; i++) {
+ if (sst_id == sst_drv_ctx->alloc_block[i].sst_id) {
+ sst_drv_ctx->alloc_block[i].ops_block.condition = true;
+ sst_drv_ctx->alloc_block[i].ops_block.ret_code = status;
+ sst_drv_ctx->alloc_block[i].ops_block.data = data;
+ wake_up(&sst_drv_ctx->wait_queue);
+ break;
+ }
+ }
+}
+
+/*
+ * sst_enable_rx_timeslot - Send msg to query for stream parameters
+ * @status: rx timeslot to be enabled
+ *
+ * This function is called when the RX timeslot is required to be enabled
+ */
+int sst_enable_rx_timeslot(int status)
+{
+ int retval = 0;
+ struct ipc_post *msg = NULL;
+
+ if (sst_create_short_msg(&msg)) {
+ pr_err("sst: mem allocation failed\n");
+ return -ENOMEM;
+ }
+ pr_debug("sst: ipc message sending: ENABLE_RX_TIME_SLOT\n");
+ sst_fill_header(&msg->header, IPC_IA_ENABLE_RX_TIME_SLOT, 0, 0);
+ msg->header.part.data = status;
+ sst_drv_ctx->hs_info_blk.condition = false;
+ sst_drv_ctx->hs_info_blk.ret_code = 0;
+ sst_drv_ctx->hs_info_blk.on = true;
+ spin_lock(&sst_drv_ctx->list_spin_lock);
+ list_add_tail(&msg->node,
+ &sst_drv_ctx->ipc_dispatch_list);
+ spin_unlock(&sst_drv_ctx->list_spin_lock);
+ sst_post_message(&sst_drv_ctx->ipc_post_msg_wq);
+ retval = sst_wait_interruptible_timeout(sst_drv_ctx,
+ &sst_drv_ctx->hs_info_blk, SST_BLOCK_TIMEOUT);
+ return retval;
+}
+
diff --git a/drivers/staging/intel_sst/intel_sst_stream.c b/drivers/staging/intel_sst/intel_sst_stream.c
new file mode 100644
index 0000000..ff46d5c
--- /dev/null
+++ b/drivers/staging/intel_sst/intel_sst_stream.c
@@ -0,0 +1,575 @@
+/*
+ * intel_sst_stream.c - Intel SST Driver for audio engine
+ *
+ * Copyright (C) 2008-10 Intel Corp
+ * Authors: Vinod Koul <vinod.koul(a)intel.com>
+ * Harsha Priya <priya.harsha(a)intel.com>
+ * Dharageswari R <dharageswari.r(a)intel.com>
+ * KP Jeeja <jeeja.kp(a)intel.com>
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This file contains the stream operations of SST driver
+ */
+
+#include <linux/pci.h>
+#include <linux/firmware.h>
+#include <linux/sched.h>
+#include "intel_sst_ioctl.h"
+#include "intel_sst.h"
+#include "intel_sst_fw_ipc.h"
+#include "intel_sst_common.h"
+
+/*
+ * sst_check_device_type - Check the medfield device type
+ *
+ * @device: Device to be checked
+ * @num_ch: Number of channels queried
+ * @pcm_slot: slot to be enabled for this device
+ *
+ * This checks the deivce against the map and calculates pcm_slot value
+ */
+int sst_check_device_type(u32 device, u32 num_chan, u32 *pcm_slot)
+{
+ if (device > MAX_NUM_STREAMS_MFLD) {
+ pr_debug("sst: device type invalid %d\n", device);
+ return -EINVAL;
+ }
+ if (sst_drv_ctx->streams[device].status == STREAM_UN_INIT) {
+ if (device == SND_SST_DEVICE_VIBRA && num_chan == 1)
+ *pcm_slot = 0x10;
+ else if (device == SND_SST_DEVICE_HAPTIC && num_chan == 1)
+ *pcm_slot = 0x20;
+ else if (device == SND_SST_DEVICE_IHF && num_chan == 1)
+ *pcm_slot = 0x04;
+ else if (device == SND_SST_DEVICE_IHF && num_chan == 2)
+ *pcm_slot = 0x0C;
+ else if (device == SND_SST_DEVICE_HEADSET && num_chan == 1)
+ *pcm_slot = 0x01;
+ else if (device == SND_SST_DEVICE_HEADSET && num_chan == 2)
+ *pcm_slot = 0x03;
+ else if (device == SND_SST_DEVICE_CAPTURE && num_chan == 1)
+ *pcm_slot = 0x01;
+ else if (device == SND_SST_DEVICE_CAPTURE && num_chan == 2)
+ *pcm_slot = 0x03;
+ else if (device == SND_SST_DEVICE_CAPTURE && num_chan == 3)
+ *pcm_slot = 0x07;
+ else if (device == SND_SST_DEVICE_CAPTURE && num_chan == 4)
+ *pcm_slot = 0x0F;
+ else {
+ pr_debug("sst: No condition satisfied.. ret err\n");
+ return -EINVAL;
+ }
+ } else {
+ pr_debug("sst: this stream state is not uni-init, is %d\n",
+ sst_drv_ctx->streams[device].status);
+ return -EBADRQC;
+ }
+ pr_debug("sst: returning slot %x\n", *pcm_slot);
+ return 0;
+}
+/**
+ * get_mrst_stream_id - gets a new stream id for use
+ *
+ * This functions searches the current streams and allocated an empty stream
+ * lock stream_lock required to be held before calling this
+ */
+static unsigned int get_mrst_stream_id(void)
+{
+ int i;
+
+ for (i = 1; i <= MAX_NUM_STREAMS_MRST; i++) {
+ if (sst_drv_ctx->streams[i].status == STREAM_UN_INIT)
+ return i;
+ }
+ pr_debug("sst: Didnt find empty stream for mrst\n");
+ return -EBUSY;
+}
+
+/**
+ * sst_alloc_stream - Send msg for a new stream ID
+ *
+ * @params: stream params
+ * @stream_ops: operation of stream PB/capture
+ * @codec: codec for stream
+ * @device: device stream to be allocated for
+ *
+ * This function is called by any function which wants to start
+ * a new stream. This also check if a stream exists which is idle
+ * it initializes idle stream id to this request
+ */
+int sst_alloc_stream(char *params, unsigned int stream_ops,
+ u8 codec, unsigned int device)
+{
+ struct ipc_post *msg = NULL;
+ struct snd_sst_alloc_params alloc_param;
+ unsigned int pcm_slot = 0, num_ch, str_id;
+ struct snd_sst_stream_params *sparams;
+ struct stream_info *str_info;
+
+ pr_debug("SST DBG:entering sst_alloc_stream\n");
+ pr_debug("SST DBG:%d %d %d\n", stream_ops, codec, device);
+
+ BUG_ON(!params);
+ sparams = (struct snd_sst_stream_params *)params;
+ num_ch = sparams->uc.pcm_params.num_chan;
+ /*check the device type*/
+ if (sst_drv_ctx->pci_id == SST_MFLD_PCI_ID) {
+ if (sst_check_device_type(device, num_ch, &pcm_slot))
+ return -EINVAL;
+ mutex_lock(&sst_drv_ctx->stream_lock);
+ str_id = device;
+ mutex_unlock(&sst_drv_ctx->stream_lock);
+ pr_debug("SST_DBG: slot %x\n", pcm_slot);
+ } else {
+ mutex_lock(&sst_drv_ctx->stream_lock);
+ str_id = get_mrst_stream_id();
+ mutex_unlock(&sst_drv_ctx->stream_lock);
+ if (str_id <= 0)
+ return -EBUSY;
+ }
+ /*allocate device type context*/
+ sst_init_stream(&sst_drv_ctx->streams[str_id], codec,
+ str_id, stream_ops, pcm_slot, device);
+ /* send msg to FW to allocate a stream */
+ if (sst_create_large_msg(&msg))
+ return -ENOMEM;
+
+ sst_fill_header(&msg->header, IPC_IA_ALLOC_STREAM, 1, str_id);
+ msg->header.part.data = sizeof(alloc_param) + sizeof(u32);
+ alloc_param.str_type.codec_type = codec;
+ alloc_param.str_type.str_type = SST_STREAM_TYPE_MUSIC;
+ alloc_param.str_type.operation = stream_ops;
+ alloc_param.str_type.protected_str = 0; /* non drm */
+ alloc_param.str_type.time_slots = pcm_slot;
+ alloc_param.str_type.result = alloc_param.str_type.reserved = 0;
+ memcpy(&alloc_param.stream_params, params,
+ sizeof(struct snd_sst_stream_params));
+
+ memcpy(msg->mailbox_data, &msg->header, sizeof(u32));
+ memcpy(msg->mailbox_data + sizeof(u32), &alloc_param,
+ sizeof(alloc_param));
+ str_info = &sst_drv_ctx->streams[str_id];
+ str_info->ctrl_blk.condition = false;
+ str_info->ctrl_blk.ret_code = 0;
+ str_info->ctrl_blk.on = true;
+ spin_lock(&sst_drv_ctx->list_spin_lock);
+ list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list);
+ spin_unlock(&sst_drv_ctx->list_spin_lock);
+ sst_post_message(&sst_drv_ctx->ipc_post_msg_wq);
+ pr_debug("SST DBG:alloc stream done\n");
+ return str_id;
+}
+
+
+/*
+ * sst_alloc_stream_response - process alloc reply
+ *
+ * @str_id: stream id for which the stream has been allocated
+ * @resp the stream response from firware
+ *
+ * This function is called by firmware as a response to stream allcoation
+ * request
+ */
+int sst_alloc_stream_response(unsigned int str_id,
+ struct snd_sst_alloc_response *resp)
+{
+ int retval = 0;
+ struct stream_info *str_info;
+ struct snd_sst_lib_download *lib_dnld;
+
+ pr_debug("SST DEBUG: stream number given = %d\n", str_id);
+ str_info = &sst_drv_ctx->streams[str_id];
+ if (resp->str_type.result == SST_LIB_ERR_LIB_DNLD_REQUIRED) {
+ lib_dnld = kzalloc(sizeof(*lib_dnld), GFP_KERNEL);
+ memcpy(lib_dnld, &resp->lib_dnld, sizeof(*lib_dnld));
+ } else
+ lib_dnld = NULL;
+ if (str_info->ctrl_blk.on == true) {
+ str_info->ctrl_blk.on = false;
+ str_info->ctrl_blk.data = lib_dnld;
+ str_info->ctrl_blk.condition = true;
+ str_info->ctrl_blk.ret_code = resp->str_type.result;
+ pr_debug("SST DEBUG: sst_alloc_stream_response: waking up.\n");
+ wake_up(&sst_drv_ctx->wait_queue);
+ }
+ return retval;
+}
+
+
+/**
+* sst_get_fw_info - Send msg to query for firmware configurations
+* @info: out param that holds the firmare configurations
+*
+* This function is called when the firmware configurations are queiried for
+*/
+int sst_get_fw_info(struct snd_sst_fw_info *info)
+{
+ int retval = 0;
+ struct ipc_post *msg = NULL;
+
+ pr_debug("SST DBG:sst_get_fw_info called\n");
+
+ if (sst_create_short_msg(&msg)) {
+ pr_err("SST ERR: message creation failed\n");
+ return -ENOMEM;
+ }
+
+ sst_fill_header(&msg->header, IPC_IA_GET_FW_INFO, 0, 0);
+ sst_drv_ctx->fw_info_blk.condition = false;
+ sst_drv_ctx->fw_info_blk.ret_code = 0;
+ sst_drv_ctx->fw_info_blk.on = true;
+ sst_drv_ctx->fw_info_blk.data = info;
+ spin_lock(&sst_drv_ctx->list_spin_lock);
+ list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list);
+ spin_unlock(&sst_drv_ctx->list_spin_lock);
+ sst_post_message(&sst_drv_ctx->ipc_post_msg_wq);
+ retval = sst_wait_interruptible_timeout(sst_drv_ctx,
+ &sst_drv_ctx->fw_info_blk, SST_BLOCK_TIMEOUT);
+ if (retval) {
+ pr_err("SST ERR: error in fw_info = %d\n", retval);
+ retval = -EIO;
+ }
+ return retval;
+}
+
+
+/**
+* sst_pause_stream - Send msg for a pausing stream
+* @str_id: stream ID
+*
+* This function is called by any function which wants to pause
+* an already running stream.
+*/
+int sst_start_stream(int str_id)
+{
+ int retval = 0;
+ struct ipc_post *msg = NULL;
+ struct stream_info *str_info;
+
+ pr_debug("sst_start_stream for %d\n", str_id);
+ retval = sst_validate_strid(str_id);
+ if (retval)
+ return retval;
+ str_info = &sst_drv_ctx->streams[str_id];
+ if (str_info->status != STREAM_INIT)
+ return -EBADRQC;
+ if (sst_create_short_msg(&msg))
+ return -ENOMEM;
+
+ sst_fill_header(&msg->header, IPC_IA_START_STREAM, 0, str_id);
+ spin_lock(&sst_drv_ctx->list_spin_lock);
+ list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list);
+ spin_unlock(&sst_drv_ctx->list_spin_lock);
+ sst_post_message(&sst_drv_ctx->ipc_post_msg_wq);
+ return retval;
+}
+
+/*
+ * sst_pause_stream - Send msg for a pausing stream
+ * @str_id: stream ID
+ *
+ * This function is called by any function which wants to pause
+ * an already running stream.
+ */
+int sst_pause_stream(int str_id)
+{
+ int retval = 0;
+ struct ipc_post *msg = NULL;
+ struct stream_info *str_info;
+
+ pr_debug("SST DBG:sst_pause_stream for %d\n", str_id);
+ retval = sst_validate_strid(str_id);
+ if (retval)
+ return retval;
+ str_info = &sst_drv_ctx->streams[str_id];
+ if (str_info->status == STREAM_PAUSED)
+ return 0;
+ if (str_info->status == STREAM_RUNNING ||
+ str_info->status == STREAM_INIT) {
+ if (str_info->prev == STREAM_UN_INIT)
+ return -EBADRQC;
+ if (str_info->ctrl_blk.on == true) {
+ pr_err("SST ERR: control path is in use\n ");
+ return -EINVAL;
+ }
+ if (sst_create_short_msg(&msg))
+ return -ENOMEM;
+
+ sst_fill_header(&msg->header, IPC_IA_PAUSE_STREAM, 0, str_id);
+ str_info->ctrl_blk.condition = false;
+ str_info->ctrl_blk.ret_code = 0;
+ str_info->ctrl_blk.on = true;
+ spin_lock(&sst_drv_ctx->list_spin_lock);
+ list_add_tail(&msg->node,
+ &sst_drv_ctx->ipc_dispatch_list);
+ spin_unlock(&sst_drv_ctx->list_spin_lock);
+ sst_post_message(&sst_drv_ctx->ipc_post_msg_wq);
+ retval = sst_wait_interruptible_timeout(sst_drv_ctx,
+ &str_info->ctrl_blk, SST_BLOCK_TIMEOUT);
+ if (retval == 0) {
+ str_info->prev = str_info->status;
+ str_info->status = STREAM_PAUSED;
+ } else if (retval == SST_ERR_INVALID_STREAM_ID) {
+ retval = -EINVAL;
+ mutex_lock(&sst_drv_ctx->stream_lock);
+ sst_clean_stream(str_info);
+ mutex_unlock(&sst_drv_ctx->stream_lock);
+ }
+ } else {
+ retval = -EBADRQC;
+ pr_err("SST ERR:BADQRC for stream\n ");
+ }
+
+ return retval;
+}
+
+/**
+ * sst_resume_stream - Send msg for resuming stream
+ * @str_id: stream ID
+ *
+ * This function is called by any function which wants to resume
+ * an already paused stream.
+ */
+int sst_resume_stream(int str_id)
+{
+ int retval = 0;
+ struct ipc_post *msg = NULL;
+ struct stream_info *str_info;
+
+ pr_debug("SST DBG:sst_resume_stream for %d\n", str_id);
+ retval = sst_validate_strid(str_id);
+ if (retval)
+ return retval;
+ str_info = &sst_drv_ctx->streams[str_id];
+ if (str_info->status == STREAM_RUNNING)
+ return 0;
+ if (str_info->status == STREAM_PAUSED) {
+ if (str_info->ctrl_blk.on == true) {
+ pr_err("SST ERR: control path in use\n");
+ return -EINVAL;
+ }
+ if (sst_create_short_msg(&msg)) {
+ pr_err("SST ERR: mem allocation failed\n");
+ return -ENOMEM;
+ }
+ sst_fill_header(&msg->header, IPC_IA_RESUME_STREAM, 0, str_id);
+ str_info->ctrl_blk.condition = false;
+ str_info->ctrl_blk.ret_code = 0;
+ str_info->ctrl_blk.on = true;
+ spin_lock(&sst_drv_ctx->list_spin_lock);
+ list_add_tail(&msg->node,
+ &sst_drv_ctx->ipc_dispatch_list);
+ spin_unlock(&sst_drv_ctx->list_spin_lock);
+ sst_post_message(&sst_drv_ctx->ipc_post_msg_wq);
+ retval = sst_wait_interruptible_timeout(sst_drv_ctx,
+ &str_info->ctrl_blk, SST_BLOCK_TIMEOUT);
+ if (!retval) {
+ if (str_info->prev == STREAM_RUNNING)
+ str_info->status = STREAM_RUNNING;
+ else
+ str_info->status = STREAM_INIT;
+ str_info->prev = STREAM_PAUSED;
+ } else if (retval == -SST_ERR_INVALID_STREAM_ID) {
+ retval = -EINVAL;
+ mutex_lock(&sst_drv_ctx->stream_lock);
+ sst_clean_stream(str_info);
+ mutex_unlock(&sst_drv_ctx->stream_lock);
+ }
+ } else {
+ retval = -EBADRQC;
+ pr_err("SST ERR: BADQRC for stream\n");
+ }
+
+ return retval;
+}
+
+
+/**
+ * sst_drop_stream - Send msg for stopping stream
+ * @str_id: stream ID
+ *
+ * This function is called by any function which wants to stop
+ * a stream.
+ */
+int sst_drop_stream(int str_id)
+{
+ int retval = 0;
+ struct ipc_post *msg = NULL;
+ struct sst_stream_bufs *bufs = NULL, *_bufs;
+ struct stream_info *str_info;
+
+ pr_debug("SST DBG:sst_drop_stream for %d\n", str_id);
+ retval = sst_validate_strid(str_id);
+ if (retval)
+ return retval;
+ str_info = &sst_drv_ctx->streams[str_id];
+
+ if (str_info->status != STREAM_UN_INIT &&
+ str_info->status != STREAM_DECODE) {
+ if (str_info->ctrl_blk.on == true) {
+ pr_err("SST ERR: control path in use\n");
+ return -EINVAL;
+ }
+ if (sst_create_short_msg(&msg)) {
+ pr_err("SST ERR: mem allocation failed\n");
+ return -ENOMEM;
+ }
+ sst_fill_header(&msg->header, IPC_IA_DROP_STREAM, 0, str_id);
+ str_info->ctrl_blk.condition = false;
+ str_info->ctrl_blk.ret_code = 0;
+ str_info->ctrl_blk.on = true;
+ spin_lock(&sst_drv_ctx->list_spin_lock);
+ list_add_tail(&msg->node,
+ &sst_drv_ctx->ipc_dispatch_list);
+ spin_unlock(&sst_drv_ctx->list_spin_lock);
+ sst_post_message(&sst_drv_ctx->ipc_post_msg_wq);
+ retval = sst_wait_interruptible_timeout(sst_drv_ctx,
+ &str_info->ctrl_blk, SST_BLOCK_TIMEOUT);
+ if (!retval) {
+ pr_debug("SST DBG:drop success\n");
+ str_info->prev = STREAM_UN_INIT;
+ str_info->status = STREAM_INIT;
+ if (str_info->src != MAD_DRV) {
+ mutex_lock(&str_info->lock);
+ list_for_each_entry_safe(bufs, _bufs,
+ &str_info->bufs, node) {
+ list_del(&bufs->node);
+ kfree(bufs);
+ }
+ mutex_unlock(&str_info->lock);
+ }
+ str_info->cumm_bytes += str_info->curr_bytes;
+ } else if (retval == -SST_ERR_INVALID_STREAM_ID) {
+ retval = -EINVAL;
+ mutex_lock(&sst_drv_ctx->stream_lock);
+ sst_clean_stream(str_info);
+ mutex_unlock(&sst_drv_ctx->stream_lock);
+ }
+ if (str_info->data_blk.on == true) {
+ str_info->data_blk.condition = true;
+ str_info->data_blk.ret_code = retval;
+ wake_up(&sst_drv_ctx->wait_queue);
+ }
+ } else {
+ retval = -EBADRQC;
+ pr_err("SST ERR:BADQRC for stream\n");
+ }
+ return retval;
+}
+
+/**
+* sst_drain_stream - Send msg for draining stream
+* @str_id: stream ID
+*
+* This function is called by any function which wants to drain
+* a stream.
+*/
+int sst_drain_stream(int str_id)
+{
+ int retval = 0;
+ struct ipc_post *msg = NULL;
+ struct stream_info *str_info;
+
+ pr_debug("SST DBG:sst_drain_stream for %d\n", str_id);
+ retval = sst_validate_strid(str_id);
+ if (retval)
+ return retval;
+ str_info = &sst_drv_ctx->streams[str_id];
+
+ if (str_info->status != STREAM_RUNNING &&
+ str_info->status != STREAM_INIT &&
+ str_info->status != STREAM_PAUSED) {
+ pr_err("SST ERR: BADQRC for stream = %d\n",
+ str_info->status);
+ return -EBADRQC;
+ }
+
+ if (str_info->status == STREAM_INIT) {
+ if (sst_create_short_msg(&msg)) {
+ pr_err("SST ERR: mem allocation failed\n");
+ return -ENOMEM;
+ }
+ sst_fill_header(&msg->header, IPC_IA_DRAIN_STREAM, 0, str_id);
+ spin_lock(&sst_drv_ctx->list_spin_lock);
+ list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list);
+ spin_unlock(&sst_drv_ctx->list_spin_lock);
+ sst_post_message(&sst_drv_ctx->ipc_post_msg_wq);
+ } else
+ str_info->need_draining = true;
+ str_info->data_blk.condition = false;
+ str_info->data_blk.ret_code = 0;
+ str_info->data_blk.on = true;
+ retval = sst_wait_interruptible(sst_drv_ctx, &str_info->data_blk);
+ str_info->need_draining = false;
+ if (retval == -SST_ERR_INVALID_STREAM_ID) {
+ retval = -EINVAL;
+ sst_clean_stream(str_info);
+ }
+ return retval;
+}
+
+/**
+ * sst_free_stream - Frees a stream
+ * @str_id: stream ID
+ *
+ * This function is called by any function which wants to free
+ * a stream.
+ */
+int sst_free_stream(int str_id)
+{
+ int retval = 0;
+ struct ipc_post *msg = NULL;
+ struct stream_info *str_info;
+
+ pr_debug("SST DBG:sst_free_stream for %d\n", str_id);
+
+ retval = sst_validate_strid(str_id);
+ if (retval)
+ return retval;
+ str_info = &sst_drv_ctx->streams[str_id];
+
+ if (str_info->status != STREAM_UN_INIT) {
+ if (sst_create_short_msg(&msg)) {
+ pr_err("SST ERR: mem allocation failed\n");
+ return -ENOMEM;
+ }
+ sst_fill_header(&msg->header, IPC_IA_FREE_STREAM, 0, str_id);
+ spin_lock(&sst_drv_ctx->list_spin_lock);
+ list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list);
+ spin_unlock(&sst_drv_ctx->list_spin_lock);
+ sst_post_message(&sst_drv_ctx->ipc_post_msg_wq);
+ str_info->prev = str_info->status;
+ str_info->status = STREAM_UN_INIT;
+ if (str_info->data_blk.on == true) {
+ str_info->data_blk.condition = true;
+ str_info->data_blk.ret_code = 0;
+ wake_up(&sst_drv_ctx->wait_queue);
+ }
+ mutex_lock(&sst_drv_ctx->stream_lock);
+ sst_clean_stream(str_info);
+ mutex_unlock(&sst_drv_ctx->stream_lock);
+ pr_debug("SST DBG:Stream freed\n");
+ } else {
+ retval = -EBADRQC;
+ pr_debug("SST DBG:BADQRC for stream\n");
+ }
+
+ return retval;
+}
+
+
diff --git a/drivers/staging/intel_sst/intel_sst_stream_encoded.c b/drivers/staging/intel_sst/intel_sst_stream_encoded.c
new file mode 100644
index 0000000..fbae39f
--- /dev/null
+++ b/drivers/staging/intel_sst/intel_sst_stream_encoded.c
@@ -0,0 +1,1275 @@
+/*
+ * intel_sst_stream.c - Intel SST Driver for audio engine
+ *
+ * Copyright (C) 2008-10 Intel Corp
+ * Authors: Vinod Koul <vinod.koul(a)intel.com>
+ * Harsha Priya <priya.harsha(a)intel.com>
+ * Dharageswari R <dharageswari.r(a)intel.com>
+ * KP Jeeja <jeeja.kp(a)intel.com>
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This file contains the stream operations of SST driver
+ */
+
+#include <linux/pci.h>
+#include <linux/syscalls.h>
+#include <linux/firmware.h>
+#include <linux/sched.h>
+#include <linux/rar_register.h>
+#ifdef CONFIG_MRST_RAR_HANDLER
+#include "../../../drivers/staging/memrar/memrar.h"
+#endif
+#include "intel_sst_ioctl.h"
+#include "intel_sst.h"
+#include "intel_sst_fw_ipc.h"
+#include "intel_sst_common.h"
+/**
+* sst_get_stream_params - Send msg to query for stream parameters
+* @str_id: stream id for which the parameters are queried for
+* @get_params: out parameters to which the parameters are copied to
+*
+* This function is called when the stream parameters are queiried for
+*/
+int sst_get_stream_params(int str_id,
+ struct snd_sst_get_stream_params *get_params)
+{
+ int retval = 0;
+ struct ipc_post *msg = NULL;
+ struct stream_info *str_info;
+ struct snd_sst_fw_get_stream_params *fw_params;
+
+ pr_debug("sst: get_stream for %d\n", str_id);
+ retval = sst_validate_strid(str_id);
+ if (retval)
+ return retval;
+
+ str_info = &sst_drv_ctx->streams[str_id];
+ if (str_info->status != STREAM_UN_INIT) {
+ if (str_info->ctrl_blk.on == true) {
+ pr_err("sst: control path in use\n");
+ return -EINVAL;
+ }
+ if (sst_create_short_msg(&msg)) {
+ pr_err("sst: message creation failed\n");
+ return -ENOMEM;
+ }
+ fw_params = kzalloc(sizeof(*fw_params), GFP_ATOMIC);
+ if (!fw_params) {
+ pr_err("sst: mem allcoation failed\n ");
+ kfree(msg);
+ return -ENOMEM;
+ }
+
+ sst_fill_header(&msg->header, IPC_IA_GET_STREAM_PARAMS,
+ 0, str_id);
+ str_info->ctrl_blk.condition = false;
+ str_info->ctrl_blk.ret_code = 0;
+ str_info->ctrl_blk.on = true;
+ str_info->ctrl_blk.data = (void *) fw_params;
+ spin_lock(&sst_drv_ctx->list_spin_lock);
+ list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list);
+ spin_unlock(&sst_drv_ctx->list_spin_lock);
+ sst_post_message(&sst_drv_ctx->ipc_post_msg_wq);
+ retval = sst_wait_interruptible_timeout(sst_drv_ctx,
+ &str_info->ctrl_blk, SST_BLOCK_TIMEOUT);
+ if (retval) {
+ get_params->codec_params.result = retval;
+ kfree(fw_params);
+ return -EIO;
+ }
+ memcpy(&get_params->pcm_params, &fw_params->pcm_params,
+ sizeof(fw_params->pcm_params));
+ memcpy(&get_params->codec_params.sparams,
+ &fw_params->codec_params,
+ sizeof(fw_params->codec_params));
+ get_params->codec_params.result = 0;
+ get_params->codec_params.stream_id = str_id;
+ get_params->codec_params.codec = str_info->codec;
+ get_params->codec_params.ops = str_info->ops;
+ get_params->codec_params.stream_type = str_info->str_type;
+ kfree(fw_params);
+ } else {
+ pr_debug("sst: Stream is not in the init state\n");
+ }
+ return retval;
+}
+
+/**
+ * sst_set_stream_param - Send msg for setting stream parameters
+ *
+ * @str_id: stream id
+ * @str_param: stream params
+ *
+ * This function sets stream params during runtime
+ */
+int sst_set_stream_param(int str_id, struct snd_sst_params *str_param)
+{
+ int retval = 0;
+ struct ipc_post *msg = NULL;
+ struct stream_info *str_info;
+
+ BUG_ON(!str_param);
+ if (sst_drv_ctx->streams[str_id].ops != str_param->ops) {
+ pr_err("sst: Invalid operation\n");
+ return -EINVAL;
+ }
+ retval = sst_validate_strid(str_id);
+ if (retval)
+ return retval;
+ pr_debug("sst: set_stream for %d\n", str_id);
+ str_info = &sst_drv_ctx->streams[str_id];
+ if (sst_drv_ctx->streams[str_id].status == STREAM_INIT) {
+ if (str_info->ctrl_blk.on == true) {
+ pr_err("sst: control path in use\n");
+ return -EAGAIN;
+ }
+ if (sst_create_large_msg(&msg))
+ return -ENOMEM;
+
+ sst_fill_header(&msg->header,
+ IPC_IA_SET_STREAM_PARAMS, 1, str_id);
+ str_info->ctrl_blk.condition = false;
+ str_info->ctrl_blk.ret_code = 0;
+ str_info->ctrl_blk.on = true;
+ msg->header.part.data = sizeof(u32) +
+ sizeof(str_param->sparams);
+ memcpy(msg->mailbox_data, &msg->header, sizeof(u32));
+ memcpy(msg->mailbox_data + sizeof(u32), &str_param->sparams,
+ sizeof(str_param->sparams));
+ spin_lock(&sst_drv_ctx->list_spin_lock);
+ list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list);
+ spin_unlock(&sst_drv_ctx->list_spin_lock);
+ sst_post_message(&sst_drv_ctx->ipc_post_msg_wq);
+ retval = sst_wait_interruptible_timeout(sst_drv_ctx,
+ &str_info->ctrl_blk, SST_BLOCK_TIMEOUT);
+ if (retval < 0) {
+ retval = -EIO;
+ sst_clean_stream(str_info);
+ }
+ } else {
+ retval = -EBADRQC;
+ pr_err("sst: BADQRC for stream\n");
+ }
+ return retval;
+}
+
+/**
+* sst_get_vol - This fuction allows to get the premix gain or gain of a stream
+*
+* @get_vol: this is an output param through which the volume
+* structure is passed back to user
+*
+* This function is called when the premix gain or stream gain is queried for
+*/
+int sst_get_vol(struct snd_sst_vol *get_vol)
+{
+ int retval = 0;
+ struct ipc_post *msg = NULL;
+ struct snd_sst_vol *fw_get_vol;
+ int str_id = get_vol->stream_id;
+
+ pr_debug("sst: get vol called\n");
+
+ if (sst_create_short_msg(&msg))
+ return -ENOMEM;
+
+ sst_fill_header(&msg->header,
+ IPC_IA_GET_STREAM_VOL, 0, str_id);
+ sst_drv_ctx->vol_info_blk.condition = false;
+ sst_drv_ctx->vol_info_blk.ret_code = 0;
+ sst_drv_ctx->vol_info_blk.on = true;
+ fw_get_vol = kzalloc(sizeof(*fw_get_vol), GFP_ATOMIC);
+ if (!fw_get_vol) {
+ pr_err("sst: mem allocation failed\n");
+ kfree(msg);
+ return -ENOMEM;
+ }
+ sst_drv_ctx->vol_info_blk.data = (void *)fw_get_vol;
+ spin_lock(&sst_drv_ctx->list_spin_lock);
+ list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list);
+ spin_unlock(&sst_drv_ctx->list_spin_lock);
+ sst_post_message(&sst_drv_ctx->ipc_post_msg_wq);
+ retval = sst_wait_interruptible_timeout(sst_drv_ctx,
+ &sst_drv_ctx->vol_info_blk, SST_BLOCK_TIMEOUT);
+ if (retval)
+ retval = -EIO;
+ else {
+ pr_debug("sst: stream id %d\n", fw_get_vol->stream_id);
+ pr_debug("sst: volume %d\n", fw_get_vol->volume);
+ pr_debug("sst: ramp duration %d\n", fw_get_vol->ramp_duration);
+ pr_debug("sst: ramp_type %d\n", fw_get_vol->ramp_type);
+ memcpy(get_vol, fw_get_vol, sizeof(*fw_get_vol));
+ }
+ return retval;
+}
+
+/**
+* sst_set_vol - This fuction allows to set the premix gain or gain of a stream
+*
+* @set_vol: this holds the volume structure that needs to be set
+*
+* This function is called when premix gain or stream gain is requested to be set
+*/
+int sst_set_vol(struct snd_sst_vol *set_vol)
+{
+
+ int retval = 0;
+ struct ipc_post *msg = NULL;
+
+ pr_debug("sst: set vol called\n");
+
+ if (sst_create_large_msg(&msg)) {
+ pr_err("sst: message creation failed\n");
+ return -ENOMEM;
+ }
+ sst_fill_header(&msg->header, IPC_IA_SET_STREAM_VOL, 1,
+ set_vol->stream_id);
+
+ msg->header.part.data = sizeof(u32) + sizeof(*set_vol);
+ memcpy(msg->mailbox_data, &msg->header, sizeof(u32));
+ memcpy(msg->mailbox_data + sizeof(u32), set_vol, sizeof(*set_vol));
+ sst_drv_ctx->vol_info_blk.condition = false;
+ sst_drv_ctx->vol_info_blk.ret_code = 0;
+ sst_drv_ctx->vol_info_blk.on = true;
+ sst_drv_ctx->vol_info_blk.data = set_vol;
+ spin_lock(&sst_drv_ctx->list_spin_lock);
+ list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list);
+ spin_unlock(&sst_drv_ctx->list_spin_lock);
+ sst_post_message(&sst_drv_ctx->ipc_post_msg_wq);
+ retval = sst_wait_interruptible_timeout(sst_drv_ctx,
+ &sst_drv_ctx->vol_info_blk, SST_BLOCK_TIMEOUT);
+ if (retval) {
+ pr_err("sst: error in set_vol = %d\n", retval);
+ retval = -EIO;
+ }
+ return retval;
+}
+
+/**
+* sst_set_mute - This fuction sets premix mute or soft mute of a stream
+*
+* @set_mute: this holds the mute structure that needs to be set
+*
+* This function is called when premix mute or stream mute requested to be set
+*/
+int sst_set_mute(struct snd_sst_mute *set_mute)
+{
+
+ int retval = 0;
+ struct ipc_post *msg = NULL;
+
+ pr_debug("sst: set mute called\n");
+
+ if (sst_create_large_msg(&msg)) {
+ pr_err("sst: message creation failed\n");
+ return -ENOMEM;
+ }
+ sst_fill_header(&msg->header, IPC_IA_SET_STREAM_MUTE, 1,
+ set_mute->stream_id);
+ sst_drv_ctx->mute_info_blk.condition = false;
+ sst_drv_ctx->mute_info_blk.ret_code = 0;
+ sst_drv_ctx->mute_info_blk.on = true;
+ sst_drv_ctx->mute_info_blk.data = set_mute;
+
+ msg->header.part.data = sizeof(u32) + sizeof(*set_mute);
+ memcpy(msg->mailbox_data, &msg->header, sizeof(u32));
+ memcpy(msg->mailbox_data + sizeof(u32), set_mute,
+ sizeof(*set_mute));
+ spin_lock(&sst_drv_ctx->list_spin_lock);
+ list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list);
+ spin_unlock(&sst_drv_ctx->list_spin_lock);
+ sst_post_message(&sst_drv_ctx->ipc_post_msg_wq);
+ retval = sst_wait_interruptible_timeout(sst_drv_ctx,
+ &sst_drv_ctx->mute_info_blk, SST_BLOCK_TIMEOUT);
+ if (retval) {
+ pr_err("sst: error in set_mute = %d\n", retval);
+ retval = -EIO;
+ }
+ return retval;
+}
+
+int sst_prepare_target(struct snd_sst_slot_info *slot)
+{
+ if (slot->target_device == SND_SST_TARGET_PMIC
+ && slot->device_instance == 1) {
+ /*music mode*/
+ if (sst_drv_ctx->pmic_port_instance == 0)
+ sst_drv_ctx->scard_ops->set_voice_port(
+ DEACTIVATE);
+ } else if ((slot->target_device == SND_SST_TARGET_PMIC ||
+ slot->target_device == SND_SST_TARGET_MODEM) &&
+ slot->device_instance == 0) {
+ /*voip mode where pcm0 is active*/
+ if (sst_drv_ctx->pmic_port_instance == 1)
+ sst_drv_ctx->scard_ops->set_audio_port(
+ DEACTIVATE);
+ }
+ return 0;
+}
+
+int sst_activate_target(struct snd_sst_slot_info *slot)
+{
+ if (slot->target_device == SND_SST_TARGET_PMIC &&
+ slot->device_instance == 1) {
+ /*music mode*/
+ sst_drv_ctx->pmic_port_instance = 1;
+ sst_drv_ctx->scard_ops->set_audio_port(ACTIVATE);
+ sst_drv_ctx->scard_ops->set_pcm_audio_params(
+ slot->pcm_params.sfreq,
+ slot->pcm_params.pcm_wd_sz,
+ slot->pcm_params.num_chan);
+ if (sst_drv_ctx->pb_streams)
+ sst_drv_ctx->scard_ops->power_up_pmic_pb(1);
+ if (sst_drv_ctx->cp_streams)
+ sst_drv_ctx->scard_ops->power_up_pmic_cp(1);
+ } else if ((slot->target_device == SND_SST_TARGET_PMIC ||
+ slot->target_device == SND_SST_TARGET_MODEM) &&
+ slot->device_instance == 0) {
+ /*voip mode where pcm0 is active*/
+ sst_drv_ctx->pmic_port_instance = 0;
+ sst_drv_ctx->scard_ops->set_voice_port(
+ ACTIVATE);
+ sst_drv_ctx->scard_ops->power_up_pmic_pb(0);
+ /*sst_drv_ctx->scard_ops->power_up_pmic_cp(0);*/
+ }
+ return 0;
+}
+
+int sst_parse_target(struct snd_sst_slot_info *slot)
+{
+ int retval = 0;
+
+ if (slot->action == SND_SST_PORT_ACTIVATE &&
+ slot->device_type == SND_SST_DEVICE_PCM) {
+ retval = sst_activate_target(slot);
+ if (retval)
+ pr_err("sst: SST_Activate_target_fail\n");
+ else
+ pr_err("sst: SST_Activate_target_pass\n");
+ return retval;
+ } else if (slot->action == SND_SST_PORT_PREPARE &&
+ slot->device_type == SND_SST_DEVICE_PCM) {
+ retval = sst_prepare_target(slot);
+ if (retval)
+ pr_err("sst: SST_prepare_target_fail\n");
+ else
+ pr_err("sst: SST_prepare_target_pass\n");
+ return retval;
+ } else {
+ pr_err("sst: slot_action : %d, device_type: %d\n",
+ slot->action, slot->device_type);
+ return retval;
+ }
+}
+
+int sst_send_target(struct snd_sst_target_device *target)
+{
+ int retval;
+ struct ipc_post *msg;
+
+ if (sst_create_large_msg(&msg)) {
+ pr_err("sst: message creation failed\n");
+ return -ENOMEM;
+ }
+ sst_fill_header(&msg->header, IPC_IA_TARGET_DEV_SELECT, 1, 0);
+ sst_drv_ctx->tgt_dev_blk.condition = false;
+ sst_drv_ctx->tgt_dev_blk.ret_code = 0;
+ sst_drv_ctx->tgt_dev_blk.on = true;
+
+ msg->header.part.data = sizeof(u32) + sizeof(*target);
+ memcpy(msg->mailbox_data, &msg->header, sizeof(u32));
+ memcpy(msg->mailbox_data + sizeof(u32), target,
+ sizeof(*target));
+ spin_lock(&sst_drv_ctx->list_spin_lock);
+ list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list);
+ spin_unlock(&sst_drv_ctx->list_spin_lock);
+ sst_post_message(&sst_drv_ctx->ipc_post_msg_wq);
+ pr_debug("sst: message sent- waiting\n");
+ retval = sst_wait_interruptible_timeout(sst_drv_ctx,
+ &sst_drv_ctx->tgt_dev_blk, TARGET_DEV_BLOCK_TIMEOUT);
+ if (retval)
+ pr_err("sst: target device ipc failed = 0x%x\n", retval);
+ return retval;
+
+}
+
+int sst_target_device_validate(struct snd_sst_target_device *target)
+{
+ int retval = 0;
+ int i;
+
+ for (i = 0; i < SST_MAX_TARGET_DEVICES; i++) {
+ if (target->devices[i].device_type == SND_SST_DEVICE_PCM) {
+ /*pcm device, check params*/
+ if (target->devices[i].device_instance == 1) {
+ if ((target->devices[i].device_mode !=
+ SND_SST_DEV_MODE_PCM_MODE4_I2S) &&
+ (target->devices[i].device_mode !=
+ SND_SST_DEV_MODE_PCM_MODE4_RIGHT_JUSTIFIED)
+ && (target->devices[i].device_mode !=
+ SND_SST_DEV_MODE_PCM_MODE1))
+ goto err;
+ } else if (target->devices[i].device_instance == 0) {
+ if ((target->devices[i].device_mode !=
+ SND_SST_DEV_MODE_PCM_MODE2)
+ && (target->devices[i].device_mode !=
+ SND_SST_DEV_MODE_PCM_MODE4_I2S)
+ && (target->devices[i].device_mode !=
+ SND_SST_DEV_MODE_PCM_MODE1))
+ goto err;
+ if (target->devices[i].pcm_params.sfreq != 8000
+ || target->devices[i].pcm_params.num_chan != 1
+ || target->devices[i].pcm_params.pcm_wd_sz !=
+ 16)
+ goto err;
+ } else {
+err:
+ pr_err("sst: i/p params incorrect\n");
+ return -EINVAL;
+ }
+ }
+ }
+ return retval;
+}
+
+/**
+ * sst_target_device_select - This fuction sets the target device configurations
+ *
+ * @target: this parameter holds the configurations to be set
+ *
+ * This function is called when the user layer wants to change the target
+ * device's configurations
+ */
+
+int sst_target_device_select(struct snd_sst_target_device *target)
+{
+ int retval, i, prepare_count = 0;
+
+ pr_debug("sst: Target Device Select\n");
+
+ if (target->device_route < 0 || target->device_route > 2) {
+ pr_err("sst: device route is invalid\n");
+ return -EINVAL;
+ }
+
+ if (target->device_route != 0) {
+ pr_err("sst: Unsupported config\n");
+ return -EIO;
+ }
+ retval = sst_target_device_validate(target);
+ if (retval)
+ return retval;
+
+ retval = sst_send_target(target);
+ if (retval)
+ return retval;
+ for (i = 0; i < SST_MAX_TARGET_DEVICES; i++) {
+ if (target->devices[i].action == SND_SST_PORT_ACTIVATE) {
+ pr_debug("sst: activate called in %d\n", i);
+ retval = sst_parse_target(&target->devices[i]);
+ if (retval)
+ return retval;
+ } else if (target->devices[i].action == SND_SST_PORT_PREPARE) {
+ pr_debug("sst: PREPARE in %d, Forwading\n", i);
+ retval = sst_parse_target(&target->devices[i]);
+ if (retval) {
+ pr_err("sst: Parse Target fail %d", retval);
+ return retval;
+ }
+ pr_debug("sst: Parse Target successful %d", retval);
+ if (target->devices[i].device_type ==
+ SND_SST_DEVICE_PCM)
+ prepare_count++;
+ }
+ }
+ if (target->devices[0].action == SND_SST_PORT_PREPARE &&
+ prepare_count == 0)
+ sst_drv_ctx->scard_ops->power_down_pmic();
+
+ return retval;
+}
+#ifdef CONFIG_MRST_RAR_HANDLER
+/*This function gets the physical address of the secure memory from the handle*/
+static inline int sst_get_RAR(struct RAR_buffer *buffers, int count)
+{
+ int retval = 0, rar_status = 0;
+
+ rar_status = rar_handle_to_bus(buffers, count);
+
+ if (count != rar_status) {
+ pr_err("sst: The rar CALL Failed");
+ retval = -EIO;
+ }
+ if (buffers->info.type != RAR_TYPE_AUDIO) {
+ pr_err("sst: Invalid RAR type\n");
+ return -EINVAL;
+ }
+ return retval;
+}
+
+#endif
+
+/* This function creates the scatter gather list to be sent to firmware to
+capture/playback data*/
+static int sst_create_sg_list(struct stream_info *stream,
+ struct sst_frame_info *sg_list)
+{
+ struct sst_stream_bufs *kbufs = NULL;
+#ifdef CONFIG_MRST_RAR_HANDLER
+ struct RAR_buffer rar_buffers;
+ int retval = 0;
+#endif
+ int i = 0;
+ list_for_each_entry(kbufs, &stream->bufs, node) {
+ if (kbufs->in_use == false) {
+#ifdef CONFIG_MRST_RAR_HANDLER
+ if (stream->ops == STREAM_OPS_PLAYBACK_DRM) {
+ pr_debug("sst: DRM playback handling\n");
+ rar_buffers.info.handle = (__u32)kbufs->addr;
+ rar_buffers.info.size = kbufs->size;
+ pr_debug("sst: rar handle 0x%x size=0x%x",
+ rar_buffers.info.handle,
+ rar_buffers.info.size);
+ retval = sst_get_RAR(&rar_buffers, 1);
+
+ if (retval)
+ return retval;
+ sg_list->addr[i].addr = rar_buffers.bus_address;
+ /* rar_buffers.info.size; */
+ sg_list->addr[i].size = (__u32)kbufs->size;
+ pr_debug("sst: phyaddr[%d] 0x%x Size:0x%x\n"
+ , i, sg_list->addr[i].addr,
+ sg_list->addr[i].size);
+ }
+#endif
+ if (stream->ops != STREAM_OPS_PLAYBACK_DRM) {
+ sg_list->addr[i].addr =
+ virt_to_phys((void *)
+ kbufs->addr + kbufs->offset);
+ sg_list->addr[i].size = kbufs->size;
+ pr_debug("sst: phyaddr[%d]:0x%x Size:0x%x\n"
+ , i , sg_list->addr[i].addr, kbufs->size);
+ }
+ stream->curr_bytes += sg_list->addr[i].size;
+ kbufs->in_use = true;
+ i++;
+ }
+ if (i >= MAX_NUM_SCATTER_BUFFERS)
+ break;
+ }
+
+ sg_list->num_entries = i;
+ pr_debug("sst:sg list entries = %d\n", sg_list->num_entries);
+ return i;
+}
+
+
+/**
+ * sst_play_frame - Send msg for sending stream frames
+ *
+ * @str_id: ID of stream
+ *
+ * This function is called to send data to be played out
+ * to the firmware
+ */
+int sst_play_frame(int str_id)
+{
+ int i = 0, retval = 0;
+ struct ipc_post *msg = NULL;
+ struct sst_frame_info sg_list = {0};
+ struct sst_stream_bufs *kbufs = NULL, *_kbufs;
+ struct stream_info *stream;
+
+ pr_debug("sst: play frame for %d\n", str_id);
+ retval = sst_validate_strid(str_id);
+ if (retval)
+ return retval;
+
+ stream = &sst_drv_ctx->streams[str_id];
+ /* clear prev sent buffers */
+ list_for_each_entry_safe(kbufs, _kbufs, &stream->bufs, node) {
+ if (kbufs->in_use == true) {
+ spin_lock(&stream->pcm_lock);
+ list_del(&kbufs->node);
+ spin_unlock(&stream->pcm_lock);
+ kfree(kbufs);
+ }
+ }
+ /* update bytes sent */
+ stream->cumm_bytes += stream->curr_bytes;
+ stream->curr_bytes = 0;
+ if (list_empty(&stream->bufs)) {
+ /* no user buffer available */
+ pr_debug("sst: Null buffer stream status %d\n", stream->status);
+ stream->prev = stream->status;
+ stream->status = STREAM_INIT;
+ pr_debug("sst:new stream status = %d\n", stream->status);
+ if (stream->need_draining == true) {
+ pr_debug("sst:draining stream\n");
+ if (sst_create_short_msg(&msg)) {
+ pr_err("sst: mem alloc failed\n");
+ return -ENOMEM;
+ }
+ sst_fill_header(&msg->header, IPC_IA_DRAIN_STREAM,
+ 0, str_id);
+ spin_lock(&sst_drv_ctx->list_spin_lock);
+ list_add_tail(&msg->node,
+ &sst_drv_ctx->ipc_dispatch_list);
+ spin_unlock(&sst_drv_ctx->list_spin_lock);
+ sst_post_message(&sst_drv_ctx->ipc_post_msg_wq);
+ } else if (stream->data_blk.on == true) {
+ pr_debug("sst:user list empty.. wake\n");
+ /* unblock */
+ stream->data_blk.ret_code = 0;
+ stream->data_blk.condition = true;
+ stream->data_blk.on = false;
+ wake_up(&sst_drv_ctx->wait_queue);
+ }
+ return 0;
+ }
+
+ /* create list */
+ i = sst_create_sg_list(stream, &sg_list);
+
+ /* post msg */
+ if (sst_create_large_msg(&msg))
+ return -ENOMEM;
+
+ sst_fill_header(&msg->header, IPC_IA_PLAY_FRAMES, 1, str_id);
+ msg->header.part.data = sizeof(u32) + sizeof(sg_list);
+ memcpy(msg->mailbox_data, &msg->header, sizeof(u32));
+ memcpy(msg->mailbox_data + sizeof(u32), &sg_list, sizeof(sg_list));
+ spin_lock(&sst_drv_ctx->list_spin_lock);
+ list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list);
+ spin_unlock(&sst_drv_ctx->list_spin_lock);
+ sst_post_message(&sst_drv_ctx->ipc_post_msg_wq);
+ return 0;
+
+}
+
+/**
+ * sst_capture_frame - Send msg for sending stream frames
+ *
+ * @str_id: ID of stream
+ *
+ * This function is called to capture data from the firmware
+ */
+int sst_capture_frame(int str_id)
+{
+ int i = 0, retval = 0;
+ struct ipc_post *msg = NULL;
+ struct sst_frame_info sg_list = {0};
+ struct sst_stream_bufs *kbufs = NULL, *_kbufs;
+ struct stream_info *stream;
+
+
+ pr_debug("sst:capture frame for %d\n", str_id);
+ retval = sst_validate_strid(str_id);
+ if (retval)
+ return retval;
+ stream = &sst_drv_ctx->streams[str_id];
+ /* clear prev sent buffers */
+ list_for_each_entry_safe(kbufs, _kbufs, &stream->bufs, node) {
+ if (kbufs->in_use == true) {
+ list_del(&kbufs->node);
+ kfree(kbufs);
+ pr_debug("sst:del node\n");
+ }
+ }
+ if (list_empty(&stream->bufs)) {
+ /* no user buffer available */
+ pr_debug("sst:Null buffer!!!!stream status %d\n",
+ stream->status);
+ stream->prev = stream->status;
+ stream->status = STREAM_INIT;
+ pr_debug("sst:new stream status = %d\n",
+ stream->status);
+ if (stream->data_blk.on == true) {
+ pr_debug("sst:user list empty.. wake\n");
+ /* unblock */
+ stream->data_blk.ret_code = 0;
+ stream->data_blk.condition = true;
+ stream->data_blk.on = false;
+ wake_up(&sst_drv_ctx->wait_queue);
+
+ }
+ return 0;
+ }
+ /* create new sg list */
+ i = sst_create_sg_list(stream, &sg_list);
+
+ /* post msg */
+ if (sst_create_large_msg(&msg))
+ return -ENOMEM;
+
+ sst_fill_header(&msg->header, IPC_IA_CAPT_FRAMES, 1, str_id);
+ msg->header.part.data = sizeof(u32) + sizeof(sg_list);
+ memcpy(msg->mailbox_data, &msg->header, sizeof(u32));
+ memcpy(msg->mailbox_data + sizeof(u32), &sg_list, sizeof(sg_list));
+ spin_lock(&sst_drv_ctx->list_spin_lock);
+ list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list);
+ spin_unlock(&sst_drv_ctx->list_spin_lock);
+ sst_post_message(&sst_drv_ctx->ipc_post_msg_wq);
+
+
+ /*update bytes recevied*/
+ stream->cumm_bytes += stream->curr_bytes;
+ stream->curr_bytes = 0;
+
+ pr_debug("sst:Cum bytes = %d\n", stream->cumm_bytes);
+ return 0;
+}
+
+/*This function is used to calculate the minimum size of input buffers given*/
+static unsigned int calculate_min_size(struct snd_sst_buffs *bufs)
+{
+ int i, min_val = bufs->buff_entry[0].size;
+ for (i = 1 ; i < bufs->entries; i++) {
+ if (bufs->buff_entry[i].size < min_val)
+ min_val = bufs->buff_entry[i].size;
+ }
+ pr_debug("sst:min_val = %d\n", min_val);
+ return min_val;
+}
+
+static unsigned int calculate_max_size(struct snd_sst_buffs *bufs)
+{
+ int i, max_val = bufs->buff_entry[0].size;
+ for (i = 1 ; i < bufs->entries; i++) {
+ if (bufs->buff_entry[i].size > max_val)
+ max_val = bufs->buff_entry[i].size;
+ }
+ pr_debug("sst:max_val = %d\n", max_val);
+ return max_val;
+}
+
+/*This function is used to allocate input and output buffers to be sent to
+the firmware that will take encoded data and return decoded data*/
+static int sst_allocate_decode_buf(struct stream_info *str_info,
+ struct snd_sst_dbufs *dbufs,
+ unsigned int cum_input_given,
+ unsigned int cum_output_given)
+{
+#ifdef CONFIG_MRST_RAR_HANDLER
+ if (str_info->ops == STREAM_OPS_PLAYBACK_DRM) {
+
+ if (dbufs->ibufs->type == SST_BUF_RAR &&
+ dbufs->obufs->type == SST_BUF_RAR) {
+ if (dbufs->ibufs->entries == dbufs->obufs->entries)
+ return 0;
+ else {
+ pr_err("sst: RAR entries dont match\n");
+ return -EINVAL;
+ }
+ } else
+ str_info->decode_osize = cum_output_given;
+ return 0;
+
+ }
+#endif
+ if (!str_info->decode_ibuf) {
+ pr_debug("sst:no i/p buffers, trying full size\n");
+ str_info->decode_isize = cum_input_given;
+ str_info->decode_ibuf = kzalloc(str_info->decode_isize,
+ GFP_KERNEL);
+ str_info->idecode_alloc = str_info->decode_isize;
+ }
+ if (!str_info->decode_ibuf) {
+ pr_debug("sst:buff alloc failed, try max size\n");
+ str_info->decode_isize = calculate_max_size(dbufs->ibufs);
+ str_info->decode_ibuf = kzalloc(
+ str_info->decode_isize, GFP_KERNEL);
+ str_info->idecode_alloc = str_info->decode_isize;
+ }
+ if (!str_info->decode_ibuf) {
+ pr_debug("sst:buff alloc failed, try min size\n");
+ str_info->decode_isize = calculate_min_size(dbufs->ibufs);
+ str_info->decode_ibuf = kzalloc(str_info->decode_isize,
+ GFP_KERNEL);
+ if (!str_info->decode_ibuf) {
+ pr_err("sst: mem allocation failed\n");
+ return -ENOMEM;
+ }
+ str_info->idecode_alloc = str_info->decode_isize;
+ }
+ str_info->decode_osize = cum_output_given;
+ if (str_info->decode_osize > sst_drv_ctx->mmap_len)
+ str_info->decode_osize = sst_drv_ctx->mmap_len;
+ return 0;
+}
+
+/*This function is used to send the message to firmware to decode the data*/
+static int sst_send_decode_mess(int str_id, struct stream_info *str_info,
+ struct snd_sst_decode_info *dec_info)
+{
+ struct ipc_post *msg = NULL;
+ int retval = 0;
+
+ pr_debug("SST DBGsst_set_mute:called\n");
+
+ if (str_info->decode_ibuf_type == SST_BUF_RAR) {
+#ifdef CONFIG_MRST_RAR_HANDLER
+ dec_info->frames_in.addr[0].addr =
+ (unsigned long)str_info->decode_ibuf;
+ dec_info->frames_in.addr[0].size =
+ str_info->decode_isize;
+#endif
+
+ } else {
+ dec_info->frames_in.addr[0].addr = virt_to_phys((void *)
+ str_info->decode_ibuf);
+ dec_info->frames_in.addr[0].size = str_info->decode_isize;
+ }
+
+
+ if (str_info->decode_obuf_type == SST_BUF_RAR) {
+#ifdef CONFIG_MRST_RAR_HANDLER
+ dec_info->frames_out.addr[0].addr =
+ (unsigned long)str_info->decode_obuf;
+ dec_info->frames_out.addr[0].size = str_info->decode_osize;
+#endif
+
+ } else {
+ dec_info->frames_out.addr[0].addr = virt_to_phys((void *)
+ str_info->decode_obuf) ;
+ dec_info->frames_out.addr[0].size = str_info->decode_osize;
+ }
+
+ dec_info->frames_in.num_entries = 1;
+ dec_info->frames_out.num_entries = 1;
+ dec_info->frames_in.rsrvd = 0;
+ dec_info->frames_out.rsrvd = 0;
+ dec_info->input_bytes_consumed = 0;
+ dec_info->output_bytes_produced = 0;
+ if (sst_create_large_msg(&msg)) {
+ pr_err("sst: message creation failed\n");
+ return -ENOMEM;
+ }
+
+ sst_fill_header(&msg->header, IPC_IA_DECODE_FRAMES, 1, str_id);
+ msg->header.part.data = sizeof(u32) + sizeof(*dec_info);
+ memcpy(msg->mailbox_data, &msg->header, sizeof(u32));
+ memcpy(msg->mailbox_data + sizeof(u32), dec_info,
+ sizeof(*dec_info));
+ spin_lock(&sst_drv_ctx->list_spin_lock);
+ list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list);
+ spin_unlock(&sst_drv_ctx->list_spin_lock);
+ str_info->data_blk.condition = false;
+ str_info->data_blk.ret_code = 0;
+ str_info->data_blk.on = true;
+ str_info->data_blk.data = dec_info;
+ sst_post_message(&sst_drv_ctx->ipc_post_msg_wq);
+ retval = sst_wait_interruptible(sst_drv_ctx, &str_info->data_blk);
+ return retval;
+}
+
+static int sst_prepare_input_buffers_rar(struct stream_info *str_info,
+ struct snd_sst_dbufs *dbufs,
+ int *input_index, int *in_copied,
+ int *input_index_valid_size, int *new_entry_flag)
+{
+ int retval = 0;
+#ifdef CONFIG_MRST_RAR_HANDLER
+ int i;
+
+ if (str_info->ops == STREAM_OPS_PLAYBACK_DRM) {
+ struct RAR_buffer rar_buffers;
+ __u32 info;
+ retval = copy_from_user((void *) &info,
+ dbufs->ibufs->buff_entry[i].buffer,
+ sizeof(__u32));
+ if (retval) {
+ pr_err("sst:cpy from user fail\n");
+ return -EAGAIN;
+ }
+ rar_buffers.info.type = dbufs->ibufs->type;
+ rar_buffers.info.size = dbufs->ibufs->buff_entry[i].size;
+ rar_buffers.info.handle = info;
+ pr_debug("rar in DnR(input buffer function)=0x%x size=0x%x",
+ rar_buffers.info.handle,
+ rar_buffers.info.size);
+ retval = sst_get_RAR(&rar_buffers, 1);
+ if (retval) {
+ pr_debug("SST ERR: RAR API failed\n");
+ return retval;
+ }
+ str_info->decode_ibuf =
+ (void *) ((unsigned long) rar_buffers.bus_address);
+ pr_debug("RAR buf addr in DnR (input buffer function)0x%lu",
+ (unsigned long) str_info->decode_ibuf);
+ pr_debug("rar in DnR decode funtion/output b_add rar =0x%lu",
+ (unsigned long) rar_buffers.bus_address);
+ *input_index = i + 1;
+ str_info->decode_isize = dbufs->ibufs->buff_entry[i].size;
+ str_info->decode_ibuf_type = dbufs->ibufs->type;
+ *in_copied = str_info->decode_isize;
+ }
+#endif
+ return retval;
+}
+/*This function is used to prepare the kernel input buffers with contents
+before sending for decode*/
+static int sst_prepare_input_buffers(struct stream_info *str_info,
+ struct snd_sst_dbufs *dbufs,
+ int *input_index, int *in_copied,
+ int *input_index_valid_size, int *new_entry_flag)
+{
+ int i, cpy_size, retval = 0;
+
+ pr_debug("sst:input_index = %d, input entries = %d\n",
+ *input_index, dbufs->ibufs->entries);
+ for (i = *input_index; i < dbufs->ibufs->entries; i++) {
+#ifdef CONFIG_MRST_RAR_HANDLER
+ retval = sst_prepare_input_buffers_rar(str_info,
+ dbufs, input_index, in_copied,
+ input_index_valid_size, new_entry_flag);
+ if (retval) {
+ pr_err("sst: In prepare input buffers for RAR\n");
+ return -EIO;
+ }
+#endif
+ *input_index = i;
+ if (*input_index_valid_size == 0)
+ *input_index_valid_size =
+ dbufs->ibufs->buff_entry[i].size;
+ pr_debug("sst:inout addr = %p, size = %d\n",
+ dbufs->ibufs->buff_entry[i].buffer,
+ *input_index_valid_size);
+ pr_debug("sst:decode_isize = %d, in_copied %d\n",
+ str_info->decode_isize, *in_copied);
+ if (*input_index_valid_size <=
+ (str_info->decode_isize - *in_copied))
+ cpy_size = *input_index_valid_size;
+ else
+ cpy_size = str_info->decode_isize - *in_copied;
+
+ pr_debug("sst:cpy size = %d\n", cpy_size);
+ if (!dbufs->ibufs->buff_entry[i].buffer) {
+ pr_err("sst: i/p buffer is null\n");
+ return -EINVAL;
+ }
+ pr_debug("sst:Try copy To %p, From %p, size %d\n",
+ str_info->decode_ibuf + *in_copied,
+ dbufs->ibufs->buff_entry[i].buffer, cpy_size);
+
+ retval =
+ copy_from_user((void *)(str_info->decode_ibuf + *in_copied),
+ (void *) dbufs->ibufs->buff_entry[i].buffer,
+ cpy_size);
+ if (retval) {
+ pr_err("sst: copy from user failed\n");
+ return -EIO;
+ }
+ *in_copied += cpy_size;
+ *input_index_valid_size -= cpy_size;
+ pr_debug("sst:in buff size = %d, in_copied = %d\n",
+ *input_index_valid_size, *in_copied);
+ if (*input_index_valid_size != 0) {
+ pr_debug("sst:more input buffers left\n");
+ dbufs->ibufs->buff_entry[i].buffer += cpy_size;
+ break;
+ }
+ if (*in_copied == str_info->decode_isize &&
+ *input_index_valid_size == 0 &&
+ (i+1) <= dbufs->ibufs->entries) {
+ pr_debug("sst:all input buffers copied\n");
+ *new_entry_flag = true;
+ *input_index = i + 1;
+ break;
+ }
+ }
+ return retval;
+}
+
+/* This function is used to copy the decoded data from kernel buffers to
+the user output buffers with contents after decode*/
+static int sst_prepare_output_buffers(struct stream_info *str_info,
+ struct snd_sst_dbufs *dbufs,
+ int *output_index, int output_size,
+ int *out_copied)
+
+{
+ int i, cpy_size, retval = 0;
+ pr_debug("sst:output_index = %d, output entries = %d\n",
+ *output_index,
+ dbufs->obufs->entries);
+ for (i = *output_index; i < dbufs->obufs->entries; i++) {
+ *output_index = i;
+ pr_debug("sst:output addr = %p, size = %d\n",
+ dbufs->obufs->buff_entry[i].buffer,
+ dbufs->obufs->buff_entry[i].size);
+ pr_debug("sst:output_size = %d, out_copied = %d\n",
+ output_size, *out_copied);
+ if (dbufs->obufs->buff_entry[i].size <
+ (output_size - *out_copied))
+ cpy_size = dbufs->obufs->buff_entry[i].size;
+ else
+ cpy_size = output_size - *out_copied;
+ pr_debug("sst:cpy size = %d\n", cpy_size);
+ pr_debug("sst:Try copy To: %p, From %p, size %d\n",
+ dbufs->obufs->buff_entry[i].buffer,
+ sst_drv_ctx->mmap_mem + *out_copied,
+ cpy_size);
+ retval = copy_to_user(dbufs->obufs->buff_entry[i].buffer,
+ sst_drv_ctx->mmap_mem + *out_copied,
+ cpy_size);
+ if (retval) {
+ pr_err("sst: copy to user failed\n");
+ return -EIO;
+ } else
+ pr_debug("sst:copy to user passed\n");
+ *out_copied += cpy_size;
+ dbufs->obufs->buff_entry[i].size -= cpy_size;
+ pr_debug("sst:o/p buff size %d, out_copied %d\n",
+ dbufs->obufs->buff_entry[i].size, *out_copied);
+ if (dbufs->obufs->buff_entry[i].size != 0) {
+ *output_index = i;
+ dbufs->obufs->buff_entry[i].buffer += cpy_size;
+ break;
+ } else if (*out_copied == output_size) {
+ *output_index = i + 1;
+ break;
+ }
+ }
+ return retval;
+}
+
+/**
+ * sst_decode - Send msg for decoding frames
+ *
+ * @str_id: ID of stream
+ * @dbufs: param that holds the user input and output buffers and size
+ *
+ * This function is called to decode data from the firmware
+ */
+int sst_decode(int str_id, struct snd_sst_dbufs *dbufs)
+{
+ int retval = 0, i;
+ unsigned long long total_input = 0 , total_output = 0;
+ unsigned int cum_input_given = 0 , cum_output_given = 0;
+ int copy_in_done = false, copy_out_done = false;
+ int input_index = 0, output_index = 0;
+ int input_index_valid_size = 0;
+ int in_copied, out_copied;
+ int new_entry_flag;
+ u64 output_size;
+ struct stream_info *str_info;
+ struct snd_sst_decode_info dec_info;
+ unsigned long long input_bytes, output_bytes;
+
+ sst_drv_ctx->scard_ops->power_down_pmic();
+ pr_debug("sst: Powering_down_PMIC...\n");
+
+ retval = sst_validate_strid(str_id);
+ if (retval)
+ return retval;
+
+ str_info = &sst_drv_ctx->streams[str_id];
+ if (str_info->status != STREAM_INIT) {
+ pr_err("sst: invalid stream state = %d\n",
+ str_info->status);
+ return -EINVAL;
+ }
+
+ str_info->prev = str_info->status;
+ str_info->status = STREAM_DECODE;
+
+ for (i = 0; i < dbufs->ibufs->entries; i++)
+ cum_input_given += dbufs->ibufs->buff_entry[i].size;
+ for (i = 0; i < dbufs->obufs->entries; i++)
+ cum_output_given += dbufs->obufs->buff_entry[i].size;
+
+ /* input and output buffer allocation */
+ retval = sst_allocate_decode_buf(str_info, dbufs,
+ cum_input_given, cum_output_given);
+ if (retval) {
+ pr_err("sst: mem allocation failed, abort!!!\n");
+ retval = -ENOMEM;
+ goto finish;
+ }
+
+ str_info->decode_isize = str_info->idecode_alloc;
+ str_info->decode_ibuf_type = dbufs->ibufs->type;
+ str_info->decode_obuf_type = dbufs->obufs->type;
+
+ while ((copy_out_done == false) && (copy_in_done == false)) {
+ in_copied = 0;
+ new_entry_flag = false;
+ retval = sst_prepare_input_buffers(str_info,\
+ dbufs, &input_index, &in_copied,
+ &input_index_valid_size, &new_entry_flag);
+ if (retval) {
+ pr_err("sst: prepare in buffers failed\n");
+ goto finish;
+ }
+
+ if (str_info->ops != STREAM_OPS_PLAYBACK_DRM)
+ str_info->decode_obuf = sst_drv_ctx->mmap_mem;
+
+#ifdef CONFIG_MRST_RAR_HANDLER
+ else {
+ if (dbufs->obufs->type == SST_BUF_RAR) {
+ struct RAR_buffer rar_buffers;
+ __u32 info;
+
+ pr_debug("DRM");
+ retval = copy_from_user((void *) &info,
+ dbufs->obufs->
+ buff_entry[output_index].buffer,
+ sizeof(__u32));
+
+ rar_buffers.info.size = dbufs->obufs->
+ buff_entry[output_index].size;
+ rar_buffers.info.handle = info;
+ retval = sst_get_RAR(&rar_buffers, 1);
+ if (retval)
+ return retval;
+
+ str_info->decode_obuf = (void *)((unsigned long)
+ rar_buffers.bus_address);
+ str_info->decode_osize = dbufs->obufs->
+ buff_entry[output_index].size;
+ str_info->decode_obuf_type = dbufs->obufs->type;
+ pr_debug("sst:DRM handling\n");
+ pr_debug("o/p_add=0x%lu Size=0x%x",
+ (unsigned long) str_info->decode_obuf,
+ str_info->decode_osize);
+ } else {
+ str_info->decode_obuf = sst_drv_ctx->mmap_mem;
+ str_info->decode_osize = dbufs->obufs->
+ buff_entry[output_index].size;
+
+ }
+ }
+#endif
+ if (str_info->ops != STREAM_OPS_PLAYBACK_DRM) {
+ if (str_info->decode_isize > in_copied) {
+ str_info->decode_isize = in_copied;
+ pr_debug("sst:i/p size = %d\n",
+ str_info->decode_isize);
+ }
+ }
+
+
+ retval = sst_send_decode_mess(str_id, str_info, &dec_info);
+ if (retval || dec_info.input_bytes_consumed == 0) {
+ pr_err(
+ "SST ERR: mess failed or no input consumed\n");
+ goto finish;
+ }
+ input_bytes = dec_info.input_bytes_consumed;
+ output_bytes = dec_info.output_bytes_produced;
+
+ pr_debug("sst:in_copied=%d, con=%lld, prod=%lld\n",
+ in_copied, input_bytes, output_bytes);
+ if (dbufs->obufs->type == SST_BUF_RAR) {
+ output_index += 1;
+ if (output_index == dbufs->obufs->entries) {
+ copy_in_done = true;
+ pr_debug("sst:all i/p cpy done\n");
+ }
+ total_output += output_bytes;
+ } else {
+ out_copied = 0;
+ output_size = output_bytes;
+ retval = sst_prepare_output_buffers(str_info, dbufs,
+ &output_index, output_size, &out_copied);
+ if (retval) {
+ pr_err("sst:prep out buff fail\n");
+ goto finish;
+ }
+ if (str_info->ops != STREAM_OPS_PLAYBACK_DRM) {
+ if (in_copied != input_bytes) {
+ int bytes_left = in_copied -
+ input_bytes;
+ pr_debug("sst:bytes %d\n",
+ bytes_left);
+ if (new_entry_flag == true)
+ input_index--;
+ while (bytes_left) {
+ struct snd_sst_buffs *ibufs;
+ struct snd_sst_buff_entry
+ *buff_entry;
+ unsigned int size_sent;
+
+ ibufs = dbufs->ibufs;
+ buff_entry =
+ &ibufs->buff_entry[input_index];
+ size_sent = buff_entry->size -\
+ input_index_valid_size;
+ if (bytes_left == size_sent) {
+ bytes_left = 0;
+ } else if (bytes_left <
+ size_sent) {
+ buff_entry->buffer +=
+ (size_sent -
+ bytes_left);
+ buff_entry->size -=
+ (size_sent -
+ bytes_left);
+ bytes_left = 0;
+ } else {
+ bytes_left -= size_sent;
+ input_index--;
+ input_index_valid_size =
+ 0;
+ }
+ }
+
+ }
+ }
+
+ total_output += out_copied;
+ if (str_info->decode_osize != out_copied) {
+ str_info->decode_osize -= out_copied;
+ pr_debug("sst:output size modified = %d\n",
+ str_info->decode_osize);
+ }
+ }
+ total_input += input_bytes;
+
+ if (str_info->ops == STREAM_OPS_PLAYBACK_DRM) {
+ if (total_input == cum_input_given)
+ copy_in_done = true;
+ copy_out_done = true;
+
+ } else {
+ if (total_output == cum_output_given) {
+ copy_out_done = true;
+ pr_debug("sst:all o/p cpy done\n");
+ }
+
+ if (total_input == cum_input_given) {
+ copy_in_done = true;
+ pr_debug("sst:all i/p cpy done\n");
+ }
+ }
+
+ pr_debug("sst:copy_out = %d, copy_in = %d\n",
+ copy_out_done, copy_in_done);
+ }
+
+finish:
+ dbufs->input_bytes_consumed = total_input;
+ dbufs->output_bytes_produced = total_output;
+ str_info->status = str_info->prev;
+ str_info->prev = STREAM_DECODE;
+ str_info->decode_ibuf = NULL;
+ kfree(str_info->decode_ibuf);
+ return retval;
+}
diff --git a/drivers/staging/intel_sst/intelmid.c b/drivers/staging/intel_sst/intelmid.c
new file mode 100644
index 0000000..63138b3
--- /dev/null
+++ b/drivers/staging/intel_sst/intelmid.c
@@ -0,0 +1,1233 @@
+/*
+ * intelmid.c - Intel Sound card driver for MID
+ *
+ * Copyright (C) 2008-10 Intel Corp
+ * Authors: Harsha Priya <priya.harsha(a)intel.com>
+ * Vinod Koul <vinod.koul(a)intel.com>
+ * Dharageswari R <dharageswari.r(a)intel.com>
+ * KP Jeeja <jeeja.kp(a)intel.com>
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * ALSA driver for Intel MID sound card chipset
+ */
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <sound/control.h>
+#include <asm/mrst.h>
+#include <sound/pcm.h>
+#include "jack.h"
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include "intel_sst.h"
+#include "intel_sst_ioctl.h"
+#include "intelmid_snd_control.h"
+#include "intelmid.h"
+
+MODULE_AUTHOR("Vinod Koul <vinod.koul(a)intel.com>");
+MODULE_AUTHOR("Harsha Priya <priya.harsha(a)intel.com>");
+MODULE_AUTHOR("Dharageswari R <dharageswari.r(a)intel.com>");
+MODULE_AUTHOR("KP Jeeja <jeeja.kp(a)intel.com>");
+MODULE_DESCRIPTION("Intel MAD Sound card driver");
+MODULE_LICENSE("GPL v2");
+MODULE_SUPPORTED_DEVICE("{Intel,Intel_MAD}");
+
+
+static int card_index = SNDRV_DEFAULT_IDX1;/* Index 0-MAX */
+static char *card_id = SNDRV_DEFAULT_STR1; /* ID for this card */
+
+module_param(card_index, int, 0444);
+MODULE_PARM_DESC(card_index, "Index value for INTELMAD soundcard.");
+module_param(card_id, charp, 0444);
+MODULE_PARM_DESC(card_id, "ID string for INTELMAD soundcard.");
+
+int sst_card_vendor_id;
+int intelmid_audio_interrupt_enable;/*checkpatch fix*/
+
+/* Data path functionalities */
+static struct snd_pcm_hardware snd_intelmad_stream = {
+ .info = (SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_DOUBLE |
+ SNDRV_PCM_INFO_PAUSE |
+ SNDRV_PCM_INFO_RESUME |
+ SNDRV_PCM_INFO_MMAP|
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_SYNC_START),
+ .formats = (SNDRV_PCM_FMTBIT_S16 | SNDRV_PCM_FMTBIT_U16 |
+ SNDRV_PCM_FMTBIT_S24 | SNDRV_PCM_FMTBIT_U24 |
+ SNDRV_PCM_FMTBIT_S32 | SNDRV_PCM_FMTBIT_U32),
+ .rates = (SNDRV_PCM_RATE_8000|
+ SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000),
+ .rate_min = MIN_RATE,
+
+ .rate_max = MAX_RATE,
+ .channels_min = MIN_CHANNEL,
+ .channels_max = MAX_CHANNEL_AMIC,
+ .buffer_bytes_max = MAX_BUFFER,
+ .period_bytes_min = MIN_PERIOD_BYTES,
+ .period_bytes_max = MAX_PERIOD_BYTES,
+ .periods_min = MIN_PERIODS,
+ .periods_max = MAX_PERIODS,
+ .fifo_size = FIFO_SIZE,
+};
+
+
+/**
+ * snd_intelmad_pcm_trigger - stream activities are handled here
+ *
+ * @substream:substream for which the stream function is called
+ * @cmd:the stream commamd that requested from upper layer
+ *
+ * This function is called whenever an a stream activity is invoked
+ */
+static int snd_intelmad_pcm_trigger(struct snd_pcm_substream *substream,
+ int cmd)
+{
+ int ret_val = 0;
+ struct snd_intelmad *intelmaddata;
+ struct mad_stream_pvt *stream;
+ /*struct stream_buffer buffer_to_sst;*/
+
+
+
+ WARN_ON(!substream);
+
+ intelmaddata = snd_pcm_substream_chip(substream);
+ stream = substream->runtime->private_data;
+
+ WARN_ON(!intelmaddata->sstdrv_ops);
+ WARN_ON(!intelmaddata->sstdrv_ops->scard_ops);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ pr_debug("sst: Trigger Start\n");
+ ret_val = intelmaddata->sstdrv_ops->control_set(SST_SND_START,
+ &stream->stream_info.str_id);
+ if (ret_val)
+ return ret_val;
+ stream->stream_status = RUNNING;
+ stream->substream = substream;
+ stream->stream_status = RUNNING;
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ pr_debug("sst: in stop\n");
+ ret_val = intelmaddata->sstdrv_ops->control_set(SST_SND_DROP,
+ &stream->stream_info.str_id);
+ if (ret_val)
+ return ret_val;
+ stream->stream_status = DROPPED;
+ break;
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ pr_debug("sst: in pause\n");
+ ret_val = intelmaddata->sstdrv_ops->control_set(SST_SND_PAUSE,
+ &stream->stream_info.str_id);
+ if (ret_val)
+ return ret_val;
+ stream->stream_status = PAUSED;
+ break;
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ pr_debug("sst: in pause release\n");
+ ret_val = intelmaddata->sstdrv_ops->control_set(SST_SND_RESUME,
+ &stream->stream_info.str_id);
+ if (ret_val)
+ return ret_val;
+ stream->stream_status = RUNNING;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return ret_val;
+}
+
+/**
+* snd_intelmad_pcm_prepare- internal preparation before starting a stream
+*
+* @substream: substream for which the function is called
+*
+* This function is called when a stream is started for internal preparation.
+*/
+static int snd_intelmad_pcm_prepare(struct snd_pcm_substream *substream)
+{
+ struct mad_stream_pvt *stream;
+ int ret_val = 0;
+ struct snd_intelmad *intelmaddata;
+
+ pr_debug("sst: pcm_prepare called\n");
+
+ WARN_ON(!substream);
+ stream = substream->runtime->private_data;
+ intelmaddata = snd_pcm_substream_chip(substream);
+ pr_debug("sst: pb cnt = %d cap cnt = %d\n",\
+ intelmaddata->playback_cnt,
+ intelmaddata->capture_cnt);
+
+ if (stream->stream_info.str_id) {
+ pr_debug("sst: Prepare called for already set stream\n");
+ ret_val = intelmaddata->sstdrv_ops->control_set(SST_SND_DROP,
+ &stream->stream_info.str_id);
+ return ret_val;
+ }
+
+ ret_val = snd_intelmad_alloc_stream(substream);
+ if (ret_val < 0)
+ return ret_val;
+ stream->dbg_cum_bytes = 0;
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ intelmaddata->playback_cnt++;
+ else
+ intelmaddata->capture_cnt++;
+ /* return back the stream id */
+ snprintf(substream->pcm->id, sizeof(substream->pcm->id),
+ "%d", stream->stream_info.str_id);
+ pr_debug("sst: stream id to user = %s\n",
+ substream->pcm->id);
+
+ ret_val = snd_intelmad_init_stream(substream);
+ if (ret_val)
+ return ret_val;
+ substream->runtime->hw.info = SNDRV_PCM_INFO_BLOCK_TRANSFER;
+ return ret_val;
+}
+
+static int snd_intelmad_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params)
+{
+ int ret_val;
+
+ pr_debug("sst: snd_intelmad_hw_params called\n");
+ ret_val = snd_pcm_lib_malloc_pages(substream,
+ params_buffer_bytes(hw_params));
+ memset(substream->runtime->dma_area, 0,
+ params_buffer_bytes(hw_params));
+
+ return ret_val;
+}
+
+static int snd_intelmad_hw_free(struct snd_pcm_substream *substream)
+{
+ pr_debug("sst: snd_intelmad_hw_free called\n");
+ return snd_pcm_lib_free_pages(substream);
+}
+
+/**
+ * snd_intelmad_pcm_pointer- to send the current buffer pointer processed by hw
+ *
+ * @substream: substream for which the function is called
+ *
+ * This function is called by ALSA framework to get the current hw buffer ptr
+ * when a period is elapsed
+ */
+static snd_pcm_uframes_t snd_intelmad_pcm_pointer
+ (struct snd_pcm_substream *substream)
+{
+ /* struct snd_pcm_runtime *runtime = substream->runtime; */
+ struct mad_stream_pvt *stream;
+ struct snd_intelmad *intelmaddata;
+ int ret_val;
+
+ WARN_ON(!substream);
+
+ intelmaddata = snd_pcm_substream_chip(substream);
+ stream = substream->runtime->private_data;
+ if (stream->stream_status == INIT)
+ return 0;
+
+ ret_val = intelmaddata->sstdrv_ops->control_set(SST_SND_BUFFER_POINTER,
+ &stream->stream_info);
+ if (ret_val) {
+ pr_err("sst: error code = 0x%x\n", ret_val);
+ return ret_val;
+ }
+ pr_debug("sst: samples reported out 0x%llx\n",
+ stream->stream_info.buffer_ptr);
+ pr_debug("sst: Frame bits:: %d period_count :: %d\n",
+ (int)substream->runtime->frame_bits,
+ (int)substream->runtime->period_size);
+
+ return stream->stream_info.buffer_ptr;
+
+}
+
+/**
+ * snd_intelmad_close- to free parameteres when stream is stopped
+ *
+ * @substream: substream for which the function is called
+ *
+ * This function is called by ALSA framework when stream is stopped
+ */
+static int snd_intelmad_close(struct snd_pcm_substream *substream)
+{
+ struct snd_intelmad *intelmaddata;
+ struct mad_stream_pvt *stream;
+ int ret_val = 0;
+
+ WARN_ON(!substream);
+
+ stream = substream->runtime->private_data;
+
+ pr_debug("sst: snd_intelmad_close called\n");
+ intelmaddata = snd_pcm_substream_chip(substream);
+
+ pr_debug("sst: str id = %d\n", stream->stream_info.str_id);
+ if (stream->stream_info.str_id) {
+ /* SST API to actually stop/free the stream */
+ ret_val = intelmaddata->sstdrv_ops->control_set(SST_SND_FREE,
+ &stream->stream_info.str_id);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ intelmaddata->playback_cnt--;
+ else
+ intelmaddata->capture_cnt--;
+ }
+ pr_debug("sst: snd_intelmad_close : pb cnt = %d cap cnt = %d\n",
+ intelmaddata->playback_cnt, intelmaddata->capture_cnt);
+ kfree(substream->runtime->private_data);
+ return ret_val;
+}
+
+/**
+ * snd_intelmad_open- to set runtime parameters during stream start
+ *
+ * @substream: substream for which the function is called
+ * @type: audio device type
+ *
+ * This function is called by ALSA framework when stream is started
+ */
+static int snd_intelmad_open(struct snd_pcm_substream *substream,
+ enum snd_sst_audio_device_type type)
+{
+ struct snd_intelmad *intelmaddata;
+ struct snd_pcm_runtime *runtime;
+ struct mad_stream_pvt *stream;
+
+ WARN_ON(!substream);
+
+ pr_debug("sst: snd_intelmad_open called\n");
+
+ intelmaddata = snd_pcm_substream_chip(substream);
+ runtime = substream->runtime;
+ /* set the runtime hw parameter with local snd_pcm_hardware struct */
+ runtime->hw = snd_intelmad_stream;
+ if (intelmaddata->cpu_id == CPU_CHIP_PENWELL) {
+ runtime->hw = snd_intelmad_stream;
+ runtime->hw.rates = SNDRV_PCM_RATE_48000;
+ runtime->hw.rate_min = MAX_RATE;
+ runtime->hw.formats = (SNDRV_PCM_FMTBIT_S24 |
+ SNDRV_PCM_FMTBIT_U24);
+ if (intelmaddata->sstdrv_ops->scard_ops->input_dev_id == AMIC)
+ runtime->hw.channels_max = MAX_CHANNEL_AMIC;
+ else
+ runtime->hw.channels_max = MAX_CHANNEL_DMIC;
+
+ }
+ /* setup the internal datastruture stream pointers based on it being
+ playback or capture stream */
+ stream = kzalloc(sizeof(*stream), GFP_KERNEL);
+ if (!stream)
+ return -ENOMEM;
+ stream->stream_info.str_id = 0;
+ stream->device = type;
+ stream->stream_status = INIT;
+ runtime->private_data = stream;
+ return snd_pcm_hw_constraint_integer(runtime,
+ SNDRV_PCM_HW_PARAM_PERIODS);
+}
+
+static int snd_intelmad_headset_open(struct snd_pcm_substream *substream)
+{
+ return snd_intelmad_open(substream, SND_SST_DEVICE_HEADSET);
+}
+
+static int snd_intelmad_ihf_open(struct snd_pcm_substream *substream)
+{
+ return snd_intelmad_open(substream, SND_SST_DEVICE_IHF);
+}
+
+static int snd_intelmad_vibra_open(struct snd_pcm_substream *substream)
+{
+ return snd_intelmad_open(substream, SND_SST_DEVICE_VIBRA);
+}
+
+static int snd_intelmad_haptic_open(struct snd_pcm_substream *substream)
+{
+ return snd_intelmad_open(substream, SND_SST_DEVICE_HAPTIC);
+}
+
+static struct snd_pcm_ops snd_intelmad_headset_ops = {
+ .open = snd_intelmad_headset_open,
+ .close = snd_intelmad_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = snd_intelmad_hw_params,
+ .hw_free = snd_intelmad_hw_free,
+ .prepare = snd_intelmad_pcm_prepare,
+ .trigger = snd_intelmad_pcm_trigger,
+ .pointer = snd_intelmad_pcm_pointer,
+};
+
+static struct snd_pcm_ops snd_intelmad_ihf_ops = {
+ .open = snd_intelmad_ihf_open,
+ .close = snd_intelmad_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = snd_intelmad_hw_params,
+ .hw_free = snd_intelmad_hw_free,
+ .prepare = snd_intelmad_pcm_prepare,
+ .trigger = snd_intelmad_pcm_trigger,
+ .pointer = snd_intelmad_pcm_pointer,
+};
+
+static struct snd_pcm_ops snd_intelmad_vibra_ops = {
+ .open = snd_intelmad_vibra_open,
+ .close = snd_intelmad_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = snd_intelmad_hw_params,
+ .hw_free = snd_intelmad_hw_free,
+ .prepare = snd_intelmad_pcm_prepare,
+ .trigger = snd_intelmad_pcm_trigger,
+ .pointer = snd_intelmad_pcm_pointer,
+};
+
+static struct snd_pcm_ops snd_intelmad_haptic_ops = {
+ .open = snd_intelmad_haptic_open,
+ .close = snd_intelmad_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = snd_intelmad_hw_params,
+ .hw_free = snd_intelmad_hw_free,
+ .prepare = snd_intelmad_pcm_prepare,
+ .trigger = snd_intelmad_pcm_trigger,
+ .pointer = snd_intelmad_pcm_pointer,
+};
+
+static struct snd_pcm_ops snd_intelmad_capture_ops = {
+ .open = snd_intelmad_headset_open,
+ .close = snd_intelmad_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = snd_intelmad_hw_params,
+ .hw_free = snd_intelmad_hw_free,
+ .prepare = snd_intelmad_pcm_prepare,
+ .trigger = snd_intelmad_pcm_trigger,
+ .pointer = snd_intelmad_pcm_pointer,
+};
+
+
+/**
+ * snd_intelmad_intr_handler- interrupt handler
+ *
+ * @irq : irq number of the interrupt received
+ * @dev: device context
+ *
+ * This function is called when an interrupt is raised at the sound card
+ */
+static irqreturn_t snd_intelmad_intr_handler(int irq, void *dev)
+{
+ struct snd_intelmad *intelmaddata =
+ (struct snd_intelmad *)dev;
+ u8 intsts;
+
+ memcpy_fromio(&intsts,
+ ((void *)(intelmaddata->int_base)),
+ sizeof(u8));
+ intelmaddata->mad_jack_msg.intsts = intsts;
+ intelmaddata->mad_jack_msg.intelmaddata = intelmaddata;
+
+ queue_work(intelmaddata->mad_jack_wq, &intelmaddata->mad_jack_msg.wq);
+
+ return IRQ_HANDLED;
+}
+
+void sst_mad_send_jack_report(struct snd_jack *jack,
+ int buttonpressevent , int status)
+{
+
+ if (!jack) {
+ pr_debug("sst: MAD error jack empty\n");
+
+ } else {
+ pr_debug("sst: MAD send jack report for = %d!!!\n", status);
+ pr_debug("sst: MAD send jack report %d\n", jack->type);
+ snd_jack_report(jack, status);
+
+ /*button pressed and released */
+ if (buttonpressevent)
+ snd_jack_report(jack, 0);
+ pr_debug("sst: MAD sending jack report Done !!!\n");
+ }
+
+
+
+}
+
+void sst_mad_jackdetection_fs(u8 intsts , struct snd_intelmad *intelmaddata)
+{
+ struct snd_jack *jack = NULL;
+ unsigned int present = 0, jack_event_flag = 0, buttonpressflag = 0;
+ struct sc_reg_access sc_access[] = {
+ {0x187, 0x00, MASK7},
+ {0x188, 0x10, MASK4},
+ {0x18b, 0x10, MASK4},
+ };
+
+ struct sc_reg_access sc_access_write[] = {
+ {0x198, 0x00, 0x0},
+ };
+
+ if (intsts & 0x4) {
+
+ if (!(intelmid_audio_interrupt_enable)) {
+ pr_debug("sst: Audio interrupt enable\n");
+ sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 3);
+
+ sst_sc_reg_access(sc_access_write, PMIC_WRITE, 1);
+ intelmid_audio_interrupt_enable = 1;
+ intelmaddata->jack[0].jack_status = 0;
+ intelmaddata->jack[1].jack_status = 0;
+
+ }
+ /* send headphone detect */
+ pr_debug("sst: MAD headphone %d\n", intsts & 0x4);
+ jack = &intelmaddata->jack[0].jack;
+ present = !(intelmaddata->jack[0].jack_status);
+ intelmaddata->jack[0].jack_status = present;
+ jack_event_flag = 1;
+
+ }
+
+ if (intsts & 0x2) {
+ /* send short push */
+ pr_debug("sst: MAD short push %d\n", intsts & 0x2);
+ jack = &intelmaddata->jack[2].jack;
+ present = 1;
+ jack_event_flag = 1;
+ buttonpressflag = 1;
+ }
+ if (intsts & 0x1) {
+ /* send long push */
+ pr_debug("sst: MAD long push %d\n", intsts & 0x1);
+ jack = &intelmaddata->jack[3].jack;
+ present = 1;
+ jack_event_flag = 1;
+ buttonpressflag = 1;
+ }
+ if (intsts & 0x8) {
+ if (!(intelmid_audio_interrupt_enable)) {
+ pr_debug("sst: Audio interrupt enable\n");
+ sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 3);
+
+ sst_sc_reg_access(sc_access_write, PMIC_WRITE, 1);
+ intelmid_audio_interrupt_enable = 1;
+ intelmaddata->jack[0].jack_status = 0;
+ intelmaddata->jack[1].jack_status = 0;
+ }
+ /* send headset detect */
+ pr_debug("sst: MAD headset = %d\n", intsts & 0x8);
+ jack = &intelmaddata->jack[1].jack;
+ present = !(intelmaddata->jack[1].jack_status);
+ intelmaddata->jack[1].jack_status = present;
+ jack_event_flag = 1;
+ }
+
+ if (jack_event_flag)
+ sst_mad_send_jack_report(jack, buttonpressflag, present);
+}
+
+
+void sst_mad_jackdetection_mx(u8 intsts, struct snd_intelmad *intelmaddata)
+{
+ u8 value = 0, jack_prev_state = 0;
+ struct snd_jack *jack = NULL;
+ unsigned int present = 0, jack_event_flag = 0, buttonpressflag = 0;
+ time_t timediff;
+ struct sc_reg_access sc_access_read = {0,};
+ struct snd_pmic_ops *scard_ops;
+
+ scard_ops = intelmaddata->sstdrv_ops->scard_ops;
+
+ pr_debug("sst: previous value: %x\n", intelmaddata->jack_prev_state);
+
+ if (!(intelmid_audio_interrupt_enable)) {
+ pr_debug("sst: Audio interrupt enable\n");
+ intelmaddata->jack_prev_state = 0xC0;
+ intelmid_audio_interrupt_enable = 1;
+ }
+
+ if (intsts & 0x2) {
+ jack_prev_state = intelmaddata->jack_prev_state;
+ if (intelmaddata->pmic_status == PMIC_INIT) {
+ sc_access_read.reg_addr = 0x201;
+ sst_sc_reg_access(&sc_access_read, PMIC_READ, 1);
+ value = (sc_access_read.value);
+ pr_debug("sst: value returned = 0x%x\n", value);
+ }
+
+ if (jack_prev_state == 0xc0 && value == 0x40) {
+ /*headset detected. */
+ pr_debug("sst: MAD headset inserted\n");
+ jack = &intelmaddata->jack[1].jack;
+ present = 1;
+ jack_event_flag = 1;
+ intelmaddata->jack[1].jack_status = 1;
+
+ }
+
+ if (jack_prev_state == 0xc0 && value == 0x00) {
+ /* headphone detected. */
+ pr_debug("sst: MAD headphone inserted\n");
+ jack = &intelmaddata->jack[0].jack;
+ present = 1;
+ jack_event_flag = 1;
+
+ }
+
+ if (jack_prev_state == 0x40 && value == 0xc0) {
+ /*headset removed*/
+ pr_debug("sst: Jack headset status %d\n",
+ intelmaddata->jack[1].jack_status);
+ pr_debug("sst: MAD headset removed\n");
+ jack = &intelmaddata->jack[1].jack;
+ present = 0;
+ jack_event_flag = 1;
+ intelmaddata->jack[1].jack_status = 0;
+ }
+
+ if (jack_prev_state == 0x00 && value == 0xc0) {
+ /* headphone detected. */
+ pr_debug("sst: Jack headphone status %d\n",
+ intelmaddata->jack[0].jack_status);
+ pr_debug("sst: headphone removed\n");
+ jack = &intelmaddata->jack[0].jack;
+ present = 0;
+ jack_event_flag = 1;
+ }
+
+ if (jack_prev_state == 0x40 && value == 0x00) {
+ /*button pressed*/
+ do_gettimeofday(&intelmaddata->jack[1].buttonpressed);
+ pr_debug("sst: MAD button press detected n");
+ }
+
+
+ if (jack_prev_state == 0x00 && value == 0x40) {
+ if (intelmaddata->jack[1].jack_status) {
+ /*button pressed*/
+ do_gettimeofday(
+ &intelmaddata->jack[1].buttonreleased);
+ /*button pressed */
+ pr_debug("sst: Button Released detected\n");
+ timediff = intelmaddata->jack[1].
+ buttonreleased.tv_sec - intelmaddata->
+ jack[1].buttonpressed.tv_sec;
+ buttonpressflag = 1;
+ if (timediff > 1) {
+ pr_debug("sst: long press detected\n");
+ /* send headphone detect/undetect */
+ jack = &intelmaddata->jack[3].jack;
+ present = 1;
+ jack_event_flag = 1;
+ } else {
+ pr_debug("sst: short press detected\n");
+ /* send headphone detect/undetect */
+ jack = &intelmaddata->jack[2].jack;
+ present = 1;
+ jack_event_flag = 1;
+ }
+ }
+
+ }
+ intelmaddata->jack_prev_state = value ;
+
+ }
+ if (is_aava() && jack) {
+ if (present) {
+ pr_debug("sst: Jack... YES\n");
+ scard_ops->set_output_dev(STEREO_HEADPHONE);
+
+ } else {
+ pr_debug("sst: Jack... NO\n");
+ scard_ops->set_output_dev(INTERNAL_SPKR);
+
+ }
+ }
+
+ if (jack_event_flag)
+ sst_mad_send_jack_report(jack, buttonpressflag, present);
+}
+
+
+void sst_mad_jackdetection_nec(u8 intsts, struct snd_intelmad *intelmaddata)
+{
+ u8 value = 0;
+ struct snd_jack *jack = NULL;
+ unsigned int present = 0, jack_event_flag = 0, buttonpressflag = 0;
+ struct sc_reg_access sc_access_read = {0,};
+
+ if (intelmaddata->pmic_status == PMIC_INIT) {
+ sc_access_read.reg_addr = 0x132;
+ sst_sc_reg_access(&sc_access_read, PMIC_READ, 1);
+ value = (sc_access_read.value);
+ pr_debug("sst: value returned = 0x%x\n", value);
+ }
+ if (intsts & 0x1) {
+ pr_debug("sst: headset detected\n");
+ /* send headset detect/undetect */
+ jack = &intelmaddata->jack[1].jack;
+ present = (value == 0x1) ? 1 : 0;
+ jack_event_flag = 1;
+ }
+ if (intsts & 0x2) {
+ pr_debug("sst: headphone detected\n");
+ /* send headphone detect/undetect */
+ jack = &intelmaddata->jack[0].jack;
+ present = (value == 0x2) ? 1 : 0;
+ jack_event_flag = 1;
+ }
+ if (intsts & 0x4) {
+ pr_debug("sst: short push detected\n");
+ /* send short push */
+ jack = &intelmaddata->jack[2].jack;
+ present = 1;
+ jack_event_flag = 1;
+ buttonpressflag = 1;
+ }
+ if (intsts & 0x8) {
+ pr_debug("sst: long push detected\n");
+ /* send long push */
+ jack = &intelmaddata->jack[3].jack;
+ present = 1;
+ jack_event_flag = 1;
+ buttonpressflag = 1;
+ }
+
+ if (jack_event_flag)
+ sst_mad_send_jack_report(jack, buttonpressflag, present);
+
+
+}
+
+void sst_process_mad_jack_detection(struct work_struct *work)
+{
+ u8 intsts;
+ struct mad_jack_msg_wq *mad_jack_detect =
+ container_of(work, struct mad_jack_msg_wq, wq);
+
+ struct snd_intelmad *intelmaddata =
+ mad_jack_detect->intelmaddata;
+
+ intsts = mad_jack_detect->intsts;
+
+ switch (intelmaddata->sstdrv_ops->vendor_id) {
+ case SND_FS:
+ sst_mad_jackdetection_fs(intsts , intelmaddata);
+ break;
+ case SND_MX:
+ sst_mad_jackdetection_mx(intsts , intelmaddata);
+ break;
+ case SND_NC:
+ sst_mad_jackdetection_nec(intsts , intelmaddata);
+ break;
+ }
+}
+
+
+static int __devinit snd_intelmad_register_irq(
+ struct snd_intelmad *intelmaddata)
+{
+ int ret_val;
+ u32 regbase = AUDINT_BASE, regsize = 8;
+ char *drv_name;
+
+ pr_debug("sst: irq reg done, regbase 0x%x, regsize 0x%x\n",
+ regbase, regsize);
+ intelmaddata->int_base = ioremap_nocache(regbase, regsize);
+ if (!intelmaddata->int_base)
+ pr_err("sst: Mapping of cache failed\n");
+ pr_debug("sst: irq = 0x%x\n", intelmaddata->irq);
+ if (intelmaddata->cpu_id == CPU_CHIP_PENWELL)
+ drv_name = DRIVER_NAME_MFLD;
+ else
+ drv_name = DRIVER_NAME_MRST;
+ ret_val = request_irq(intelmaddata->irq,
+ snd_intelmad_intr_handler,
+ IRQF_SHARED, drv_name,
+ intelmaddata);
+ if (ret_val)
+ pr_err("sst: cannot register IRQ\n");
+ return ret_val;
+}
+
+static int __devinit snd_intelmad_sst_register(
+ struct snd_intelmad *intelmaddata)
+{
+ int ret_val = 0;
+ struct snd_pmic_ops *intelmad_vendor_ops[MAX_VENDORS] = {
+ &snd_pmic_ops_fs,
+ &snd_pmic_ops_mx,
+ &snd_pmic_ops_nc,
+ &snd_msic_ops
+ };
+
+ struct sc_reg_access vendor_addr = {0x00, 0x00, 0x00};
+
+ if (intelmaddata->cpu_id == CPU_CHIP_LINCROFT) {
+ ret_val = sst_sc_reg_access(&vendor_addr, PMIC_READ, 1);
+ if (ret_val)
+ return ret_val;
+ sst_card_vendor_id = (vendor_addr.value & (MASK2|MASK1|MASK0));
+ pr_debug("sst: orginal n extrated vendor id = 0x%x %d\n",
+ vendor_addr.value, sst_card_vendor_id);
+ if (sst_card_vendor_id < 0 || sst_card_vendor_id > 2) {
+ pr_err("sst: vendor card not supported!!\n");
+ return -EIO;
+ }
+ } else
+ sst_card_vendor_id = 0x3;
+
+ intelmaddata->sstdrv_ops->module_name = SST_CARD_NAMES;
+ intelmaddata->sstdrv_ops->vendor_id = sst_card_vendor_id;
+ BUG_ON(!intelmad_vendor_ops[sst_card_vendor_id]);
+ intelmaddata->sstdrv_ops->scard_ops =
+ intelmad_vendor_ops[sst_card_vendor_id];
+
+ if (intelmaddata->cpu_id == CPU_CHIP_PENWELL) {
+ intelmaddata->sstdrv_ops->scard_ops->pb_on = 0;
+ intelmaddata->sstdrv_ops->scard_ops->cap_on = 0;
+ intelmaddata->sstdrv_ops->scard_ops->input_dev_id = DMIC;
+ intelmaddata->sstdrv_ops->scard_ops->output_dev_id =
+ STEREO_HEADPHONE;
+ }
+
+ /* registering with SST driver to get access to SST APIs to use */
+ ret_val = register_sst_card(intelmaddata->sstdrv_ops);
+ if (ret_val) {
+ pr_err("sst: sst card registration failed\n");
+ return ret_val;
+ }
+
+ sst_card_vendor_id = intelmaddata->sstdrv_ops->vendor_id;
+ intelmaddata->pmic_status = PMIC_UNINIT;
+ return ret_val;
+}
+
+/* Driver Init/exit functionalities */
+/**
+ * snd_intelmad_pcm_new - to setup pcm for the card
+ *
+ * @card: pointer to the sound card structure
+ * @intelmaddata: pointer to internal context
+ * @pb: playback count for this card
+ * @cap: capture count for this card
+ * @index: device index
+ *
+ * This function is called from probe function to set up pcm params
+ * and functions
+ */
+static int __devinit snd_intelmad_pcm_new(struct snd_card *card,
+ struct snd_intelmad *intelmaddata,
+ unsigned int pb, unsigned int cap, unsigned int index)
+{
+ int ret_val = 0;
+ struct snd_pcm *pcm;
+ char name[32] = INTEL_MAD;
+ struct snd_pcm_ops *pb_ops = NULL, *cap_ops = NULL;
+
+ pr_debug("sst: called for pb %d, cp %d, idx %d\n", pb, cap, index);
+ ret_val = snd_pcm_new(card, name, index, pb, cap, &pcm);
+ if (ret_val)
+ return ret_val;
+ /* setup the ops for playback and capture streams */
+ switch (index) {
+ case 0:
+ pb_ops = &snd_intelmad_headset_ops;
+ cap_ops = &snd_intelmad_capture_ops;
+ break;
+ case 1:
+ pb_ops = &snd_intelmad_ihf_ops;
+ cap_ops = &snd_intelmad_capture_ops;
+ break;
+ case 2:
+ pb_ops = &snd_intelmad_vibra_ops;
+ cap_ops = &snd_intelmad_capture_ops;
+ break;
+ case 3:
+ pb_ops = &snd_intelmad_haptic_ops;
+ cap_ops = &snd_intelmad_capture_ops;
+ break;
+ }
+ if (pb)
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, pb_ops);
+ if (cap)
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, cap_ops);
+ /* setup private data which can be retrieved when required */
+ pcm->private_data = intelmaddata;
+ pcm->info_flags = 0;
+ strncpy(pcm->name, card->shortname, strlen(card->shortname));
+ /* allocate dma pages for ALSA stream operations */
+ snd_pcm_lib_preallocate_pages_for_all(pcm,
+ SNDRV_DMA_TYPE_CONTINUOUS,
+ snd_dma_continuous_data(GFP_KERNEL),
+ MIN_BUFFER, MAX_BUFFER);
+ return ret_val;
+}
+
+static int __devinit snd_intelmad_pcm(struct snd_card *card,
+ struct snd_intelmad *intelmaddata)
+{
+ int ret_val = 0;
+
+ WARN_ON(!card);
+ WARN_ON(!intelmaddata);
+ pr_debug("sst: snd_intelmad_pcm called\n");
+ ret_val = snd_intelmad_pcm_new(card, intelmaddata, 1, 1, 0);
+ if (intelmaddata->cpu_id == CPU_CHIP_LINCROFT)
+ return ret_val;
+ ret_val = snd_intelmad_pcm_new(card, intelmaddata, 1, 0, 1);
+ if (ret_val)
+ return ret_val;
+ ret_val = snd_intelmad_pcm_new(card, intelmaddata, 1, 0, 2);
+ if (ret_val)
+ return ret_val;
+ return snd_intelmad_pcm_new(card, intelmaddata, 1, 0, 3);
+}
+
+/**
+ * snd_intelmad_jack- to setup jack settings of the card
+ *
+ * @intelmaddata: pointer to internal context
+ *
+ * This function is called send jack events
+ */
+static int snd_intelmad_jack(struct snd_intelmad *intelmaddata)
+{
+ struct snd_jack *jack;
+ int retval;
+
+ pr_debug("sst: snd_intelmad_jack called\n");
+ jack = &intelmaddata->jack[0].jack;
+ retval = snd_jack_new(intelmaddata->card, "Headphone",
+ SND_JACK_HEADPHONE, &jack);
+ if (retval < 0)
+ return retval;
+ snd_jack_report(jack, 0);
+
+ jack->private_data = jack;
+ intelmaddata->jack[0].jack = *jack;
+
+
+ jack = &intelmaddata->jack[1].jack;
+ retval = snd_jack_new(intelmaddata->card, "Headset",
+ SND_JACK_HEADSET, &jack);
+ if (retval < 0)
+ return retval;
+
+
+
+ jack->private_data = jack;
+ intelmaddata->jack[1].jack = *jack;
+
+
+ jack = &intelmaddata->jack[2].jack;
+ retval = snd_jack_new(intelmaddata->card, "Short Press",
+ SND_JACK_HS_SHORT_PRESS, &jack);
+ if (retval < 0)
+ return retval;
+
+
+ jack->private_data = jack;
+ intelmaddata->jack[2].jack = *jack;
+
+
+ jack = &intelmaddata->jack[3].jack;
+ retval = snd_jack_new(intelmaddata->card, "Long Press",
+ SND_JACK_HS_LONG_PRESS, &jack);
+ if (retval < 0)
+ return retval;
+
+
+ jack->private_data = jack;
+ intelmaddata->jack[3].jack = *jack;
+
+ return retval;
+}
+
+/**
+ * snd_intelmad_mixer- to setup mixer settings of the card
+ *
+ * @intelmaddata: pointer to internal context
+ *
+ * This function is called from probe function to set up mixer controls
+ */
+static int __devinit snd_intelmad_mixer(struct snd_intelmad *intelmaddata)
+{
+ struct snd_card *card;
+ unsigned int idx;
+ int ret_val = 0, max_controls = 0;
+ char *mixername = "IntelMAD Controls";
+ struct snd_kcontrol_new *controls;
+
+ WARN_ON(!intelmaddata);
+
+ card = intelmaddata->card;
+ strncpy(card->mixername, mixername, sizeof(card->mixername)-1);
+ /* add all widget controls and expose the same */
+ if (intelmaddata->cpu_id == CPU_CHIP_PENWELL) {
+ max_controls = MAX_CTRL_MFLD;
+ controls = snd_intelmad_controls_mfld;
+ } else {
+ max_controls = MAX_CTRL_MRST;
+ controls = snd_intelmad_controls_mrst;
+ }
+ for (idx = 0; idx < max_controls; idx++) {
+ ret_val = snd_ctl_add(card,
+ snd_ctl_new1(&controls[idx],
+ intelmaddata));
+ pr_debug("sst: mixer[idx]=%d added\n", idx);
+ if (ret_val) {
+ pr_err("sst: in adding of control index = %d\n", idx);
+ break;
+ }
+ }
+ return ret_val;
+}
+
+static int snd_intelmad_dev_free(struct snd_device *device)
+{
+ struct snd_intelmad *intelmaddata;
+
+ WARN_ON(!device);
+
+ intelmaddata = device->device_data;
+
+ pr_debug("sst: snd_intelmad_dev_free called\n");
+ snd_card_free(intelmaddata->card);
+ /*genl_unregister_family(&audio_event_genl_family);*/
+ unregister_sst_card(intelmaddata->sstdrv_ops);
+
+ /* free allocated memory for internal context */
+ destroy_workqueue(intelmaddata->mad_jack_wq);
+ kfree(intelmaddata->sstdrv_ops);
+ kfree(intelmaddata);
+ return 0;
+}
+
+static int __devinit snd_intelmad_create(
+ struct snd_intelmad *intelmaddata,
+ struct snd_card *card)
+{
+ int ret_val;
+ static struct snd_device_ops ops = {
+ .dev_free = snd_intelmad_dev_free,
+ };
+
+ WARN_ON(!intelmaddata);
+ WARN_ON(!card);
+ /* ALSA api to register for the device */
+ ret_val = snd_device_new(card, SNDRV_DEV_LOWLEVEL, intelmaddata, &ops);
+ return ret_val;
+}
+
+/**
+* snd_intelmad_probe- function registred for init
+* @pdev : pointer to the device struture
+* This function is called when the device is initialized
+*/
+int __devinit snd_intelmad_probe(struct platform_device *pdev)
+{
+ struct snd_card *card;
+ int ret_val;
+ struct snd_intelmad *intelmaddata;
+ const struct platform_device_id *id = platform_get_device_id(pdev);
+ unsigned int cpu_id = (unsigned int)id->driver_data;
+
+ pr_debug("sst: probe for %s cpu_id %d\n", pdev->name, cpu_id);
+ if (!strcmp(pdev->name, DRIVER_NAME_MRST))
+ pr_debug("sst: detected MRST\n");
+ else if (!strcmp(pdev->name, DRIVER_NAME_MFLD))
+ pr_debug("sst: detected MFLD\n");
+ else {
+ pr_err("sst: detected unknown device abort!!\n");
+ return -EIO;
+ }
+ if ((cpu_id < CPU_CHIP_LINCROFT) || (cpu_id > CPU_CHIP_PENWELL)) {
+ pr_err("sst: detected unknown cpu_id abort!!\n");
+ return -EIO;
+ }
+ /* allocate memory for saving internal context and working */
+ intelmaddata = kzalloc(sizeof(*intelmaddata), GFP_KERNEL);
+ if (!intelmaddata) {
+ pr_debug("sst: mem alloctn fail\n");
+ return -ENOMEM;
+ }
+
+ /* allocate memory for LPE API set */
+ intelmaddata->sstdrv_ops = kzalloc(sizeof(struct intel_sst_card_ops),
+ GFP_KERNEL);
+ if (!intelmaddata->sstdrv_ops) {
+ pr_err("sst: mem allocation for ops fail\n");
+ kfree(intelmaddata);
+ return -ENOMEM;
+ }
+
+ intelmaddata->cpu_id = cpu_id;
+ /* create a card instance with ALSA framework */
+ ret_val = snd_card_create(card_index, card_id, THIS_MODULE, 0, &card);
+ if (ret_val) {
+ pr_err("sst: snd_card_create fail\n");
+ goto free_allocs;
+ }
+
+ intelmaddata->pdev = pdev;
+ intelmaddata->irq = platform_get_irq(pdev, 0);
+ platform_set_drvdata(pdev, intelmaddata);
+ intelmaddata->card = card;
+ intelmaddata->card_id = card_id;
+ intelmaddata->card_index = card_index;
+ intelmaddata->master_mute = UNMUTE;
+ intelmaddata->playback_cnt = intelmaddata->capture_cnt = 0;
+ strncpy(card->driver, INTEL_MAD, strlen(INTEL_MAD));
+ strncpy(card->shortname, INTEL_MAD, strlen(INTEL_MAD));
+
+ intelmaddata->sstdrv_ops->module_name = SST_CARD_NAMES;
+ /* registering with LPE driver to get access to SST APIs to use */
+ ret_val = snd_intelmad_sst_register(intelmaddata);
+ if (ret_val) {
+ pr_err("sst: snd_intelmad_sst_register failed\n");
+ goto free_allocs;
+ }
+
+ intelmaddata->pmic_status = PMIC_INIT;
+
+ ret_val = snd_intelmad_pcm(card, intelmaddata);
+ if (ret_val) {
+ pr_err("sst: snd_intelmad_pcm failed\n");
+ goto free_allocs;
+ }
+
+ ret_val = snd_intelmad_mixer(intelmaddata);
+ if (ret_val) {
+ pr_err("sst: snd_intelmad_mixer failed\n");
+ goto free_allocs;
+ }
+
+ ret_val = snd_intelmad_jack(intelmaddata);
+ if (ret_val) {
+ pr_err("sst: snd_intelmad_jack failed\n");
+ goto free_allocs;
+ }
+
+ /*create work queue for jack interrupt*/
+ INIT_WORK(&intelmaddata->mad_jack_msg.wq,
+ sst_process_mad_jack_detection);
+
+ intelmaddata->mad_jack_wq = create_workqueue("sst_mad_jack_wq");
+ if (!intelmaddata->mad_jack_wq)
+ goto free_mad_jack_wq;
+
+ ret_val = snd_intelmad_register_irq(intelmaddata);
+ if (ret_val) {
+ pr_err("sst: snd_intelmad_register_irq fail\n");
+ goto free_allocs;
+ }
+
+ /* internal function call to register device with ALSA */
+ ret_val = snd_intelmad_create(intelmaddata, card);
+ if (ret_val) {
+ pr_err("sst: snd_intelmad_create failed\n");
+ goto free_allocs;
+ }
+ card->private_data = &intelmaddata;
+ snd_card_set_dev(card, &pdev->dev);
+ ret_val = snd_card_register(card);
+ if (ret_val) {
+ pr_err("sst: snd_card_register failed\n");
+ goto free_allocs;
+ }
+
+ pr_debug("sst:snd_intelmad_probe complete\n");
+ return ret_val;
+
+free_mad_jack_wq:
+ destroy_workqueue(intelmaddata->mad_jack_wq);
+free_allocs:
+ pr_err("sst: probe failed\n");
+ snd_card_free(card);
+ kfree(intelmaddata->sstdrv_ops);
+ kfree(intelmaddata);
+ return ret_val;
+}
+
+
+static int snd_intelmad_remove(struct platform_device *pdev)
+{
+ struct snd_intelmad *intelmaddata = platform_get_drvdata(pdev);
+
+ if (intelmaddata) {
+ snd_card_free(intelmaddata->card);
+ unregister_sst_card(intelmaddata->sstdrv_ops);
+ /* free allocated memory for internal context */
+ destroy_workqueue(intelmaddata->mad_jack_wq);
+ kfree(intelmaddata->sstdrv_ops);
+ kfree(intelmaddata);
+ }
+ return 0;
+}
+
+/*********************************************************************
+ * Driver initialization and exit
+ *********************************************************************/
+static const struct platform_device_id snd_intelmad_ids[] = {
+ {DRIVER_NAME_MRST, CPU_CHIP_LINCROFT},
+ {DRIVER_NAME_MFLD, CPU_CHIP_PENWELL},
+ {"", 0},
+
+};
+
+static struct platform_driver snd_intelmad_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "intel_mid_sound_card",
+ },
+ .id_table = snd_intelmad_ids,
+ .probe = snd_intelmad_probe,
+ .remove = __devexit_p(snd_intelmad_remove),
+};
+
+/*
+ * alsa_card_intelmad_init- driver init function
+ *
+ * This function is called when driver module is inserted
+ */
+static int __init alsa_card_intelmad_init(void)
+{
+ pr_debug("sst: mad_init called\n");
+ return platform_driver_register(&snd_intelmad_driver);
+}
+
+/**
+ * alsa_card_intelmad_exit- driver exit function
+ *
+ * This function is called when driver module is removed
+ */
+static void __exit alsa_card_intelmad_exit(void)
+{
+ pr_debug("sst:mad_exit called\n");
+ return platform_driver_unregister(&snd_intelmad_driver);
+}
+
+module_init(alsa_card_intelmad_init)
+module_exit(alsa_card_intelmad_exit)
+
diff --git a/drivers/staging/intel_sst/intelmid.h b/drivers/staging/intel_sst/intelmid.h
new file mode 100644
index 0000000..81e7448
--- /dev/null
+++ b/drivers/staging/intel_sst/intelmid.h
@@ -0,0 +1,186 @@
+/*
+ * intelmid.h - Intel Sound card driver for MID
+ *
+ * Copyright (C) 2008-10 Intel Corp
+ * Authors: Harsha Priya <priya.harsha(a)intel.com>
+ * Vinod Koul <vinod.koul(a)intel.com>
+ * Dharageswari R <dharageswari.r(a)intel.com>
+ * KP Jeeja <jeeja.kp(a)intel.com>
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * ALSA driver header for Intel MAD chipset
+ */
+#ifndef __INTELMID_H
+#define __INTELMID_H
+
+#include <linux/time.h>
+
+#define DRIVER_NAME_MFLD "msic_audio"
+#define DRIVER_NAME_MRST "pmic_audio"
+#define DRIVER_NAME "intelmid_audio"
+#define PMIC_SOUND_IRQ_TYPE_MASK (1 << 15)
+#define AUDINT_BASE (0xFFFFEFF8 + (6 * sizeof(u8)))
+#define REG_IRQ
+/* values #defined */
+/* will differ for different hw - to be taken from config */
+#define MAX_DEVICES 1
+#define MIN_RATE 8000
+#define MAX_RATE 48000
+#define MAX_BUFFER (800*1024) /* for PCM */
+#define MIN_BUFFER (800*1024)
+#define MAX_PERIODS (1024*2)
+#define MIN_PERIODS 1
+#define MAX_PERIOD_BYTES MAX_BUFFER
+#define MIN_PERIOD_BYTES 32
+/*#define MIN_PERIOD_BYTES 160*/
+#define MAX_MUTE 1
+#define MIN_MUTE 0
+#define MONO_CNTL 1
+#define STEREO_CNTL 2
+#define MIN_CHANNEL 1
+#define MAX_CHANNEL_AMIC 2
+#define MAX_CHANNEL_DMIC 4
+#define FIFO_SIZE 0 /* fifo not being used */
+#define INTEL_MAD "Intel MAD"
+#define MAX_CTRL_MRST 7
+#define MAX_CTRL_MFLD 2
+#define MAX_CTRL 7
+#define MAX_VENDORS 4
+/* TODO +6 db */
+#define MAX_VOL 64
+/* TODO -57 db */
+#define MIN_VOL 0
+#define PLAYBACK_COUNT 1
+#define CAPTURE_COUNT 1
+
+extern int sst_card_vendor_id;
+
+struct mad_jack {
+ struct snd_jack jack;
+ int jack_status;
+ struct timeval buttonpressed;
+ struct timeval buttonreleased;
+};
+
+struct mad_jack_msg_wq {
+ u8 intsts;
+ struct snd_intelmad *intelmaddata;
+ struct work_struct wq;
+
+};
+
+/**
+ * struct snd_intelmad - intelmad driver structure
+ *
+ * @card: ptr to the card details
+ * @card_index: sound card index
+ * @card_id: sound card id detected
+ * @sstdrv_ops: ptr to sst driver ops
+ * @pdev: ptr to platfrom device
+ * @irq: interrupt number detected
+ * @pmic_status: Device status of sound card
+ * @int_base: ptr to MMIO interrupt region
+ * @output_sel: device slected as o/p
+ * @input_sel: device slected as i/p
+ * @master_mute: master mute status
+ * @jack: jack status
+ * @playback_cnt: active pb streams
+ * @capture_cnt: active cp streams
+ * @mad_jack_msg: wq struct for jack interrupt processing
+ * @mad_jack_wq: wq for jack interrupt processing
+ * @jack_prev_state: Previos state of jack detected
+ * @cpu_id: current cpu id loaded for
+ */
+struct snd_intelmad {
+ struct snd_card *card; /* ptr to the card details */
+ int card_index;/* card index */
+ char *card_id; /* card id */
+ struct intel_sst_card_ops *sstdrv_ops;/* ptr to sst driver ops */
+ struct platform_device *pdev;
+ int irq;
+ int pmic_status;
+ void __iomem *int_base;
+ int output_sel;
+ int input_sel;
+ int master_mute;
+ struct mad_jack jack[4];
+ int playback_cnt;
+ int capture_cnt;
+ struct mad_jack_msg_wq mad_jack_msg;
+ struct workqueue_struct *mad_jack_wq;
+ u8 jack_prev_state;
+ unsigned int cpu_id;
+};
+
+struct snd_control_val {
+ int playback_vol_max;
+ int playback_vol_min;
+ int capture_vol_max;
+ int capture_vol_min;
+};
+
+struct mad_stream_pvt {
+ int stream_status;
+ int stream_ops;
+ struct snd_pcm_substream *substream;
+ struct pcm_stream_info stream_info;
+ ssize_t dbg_cum_bytes;
+ enum snd_sst_device_type device;
+};
+
+enum mad_drv_status {
+ INIT = 1,
+ STARTED,
+ RUNNING,
+ PAUSED,
+ DROPPED,
+};
+
+enum mad_pmic_status {
+ PMIC_UNINIT = 1,
+ PMIC_INIT,
+};
+enum _widget_ctrl {
+ OUTPUT_SEL = 1,
+ INPUT_SEL,
+ PLAYBACK_VOL,
+ PLAYBACK_MUTE,
+ CAPTURE_VOL,
+ CAPTURE_MUTE,
+ MASTER_MUTE
+};
+
+void period_elapsed(void *mad_substream);
+int snd_intelmad_alloc_stream(struct snd_pcm_substream *substream);
+int snd_intelmad_init_stream(struct snd_pcm_substream *substream);
+
+int sst_sc_reg_access(struct sc_reg_access *sc_access,
+ int type, int num_val);
+#define CPU_CHIP_LINCROFT 1 /* System running lincroft */
+#define CPU_CHIP_PENWELL 2 /* System running penwell */
+
+extern struct snd_control_val intelmad_ctrl_val[];
+extern struct snd_kcontrol_new snd_intelmad_controls_mrst[];
+extern struct snd_kcontrol_new snd_intelmad_controls_mfld[];
+extern struct snd_pmic_ops *intelmad_vendor_ops[];
+
+/* This is an enabler hook as the platform detection logic isn't yet
+ present and depends on some firmware and DMI support to detect AAVA
+ devices. It will vanish once the AAVA platform support is merged */
+#define is_aava() 0
+
+#endif /* __INTELMID_H */
diff --git a/drivers/staging/intel_sst/intelmid_ctrl.c b/drivers/staging/intel_sst/intelmid_ctrl.c
new file mode 100644
index 0000000..03b4ece
--- /dev/null
+++ b/drivers/staging/intel_sst/intelmid_ctrl.c
@@ -0,0 +1,629 @@
+/*
+ * intelmid_ctrl.c - Intel Sound card driver for MID
+ *
+ * Copyright (C) 2008-10 Intel Corp
+ * Authors: Harsha Priya <priya.harsha(a)intel.com>
+ * Vinod Koul <vinod.koul(a)intel.com>
+ * Dharageswari R <dharageswari.r(a)intel.com>
+ * KP Jeeja <jeeja.kp(a)intel.com>
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * ALSA driver handling mixer controls for Intel MAD chipset
+ */
+#include <sound/core.h>
+#include <sound/control.h>
+#include "jack.h"
+#include "intel_sst.h"
+#include "intel_sst_ioctl.h"
+#include "intelmid_snd_control.h"
+#include "intelmid.h"
+
+static char *out_names_mrst[] = {"Headphones",
+ "Internal speakers"};
+static char *in_names_mrst[] = {"AMIC",
+ "DMIC",
+ "HS_MIC"};
+static char *out_names_mfld[] = {"Headset ",
+ "EarPiece "};
+static char *in_names_mfld[] = {"AMIC",
+ "DMIC"};
+
+struct snd_control_val intelmad_ctrl_val[MAX_VENDORS] = {
+ {
+ .playback_vol_max = 63,
+ .playback_vol_min = 0,
+ .capture_vol_max = 63,
+ .capture_vol_min = 0,
+ },
+ {
+ .playback_vol_max = 0,
+ .playback_vol_min = -31,
+ .capture_vol_max = 0,
+ .capture_vol_min = -20,
+ },
+ {
+ .playback_vol_max = 0,
+ .playback_vol_min = -126,
+ .capture_vol_max = 0,
+ .capture_vol_min = -31,
+ },
+};
+
+/* control path functionalities */
+
+static inline int snd_intelmad_volume_info(struct snd_ctl_elem_info *uinfo,
+ int control_type, int max, int min)
+{
+ WARN_ON(!uinfo);
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = control_type;
+ uinfo->value.integer.min = min;
+ uinfo->value.integer.max = max;
+ return 0;
+}
+
+/**
+* snd_intelmad_mute_info - provides information about the mute controls
+*
+* @kcontrol: pointer to the control
+* @uinfo: pointer to the structure where the control's info need
+* to be filled
+*
+* This function is called when a mixer application requests for control's info
+*/
+static int snd_intelmad_mute_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ WARN_ON(!uinfo);
+ WARN_ON(!kcontrol);
+
+ /* set up the mute as a boolean mono control with min-max values */
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = MONO_CNTL;
+ uinfo->value.integer.min = MIN_MUTE;
+ uinfo->value.integer.max = MAX_MUTE;
+ return 0;
+}
+
+/**
+* snd_intelmad_capture_volume_info - provides info about the volume control
+*
+* @kcontrol: pointer to the control
+* @uinfo: pointer to the structure where the control's info need
+* to be filled
+*
+* This function is called when a mixer application requests for control's info
+*/
+static int snd_intelmad_capture_volume_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ snd_intelmad_volume_info(uinfo, MONO_CNTL,
+ intelmad_ctrl_val[sst_card_vendor_id].capture_vol_max,
+ intelmad_ctrl_val[sst_card_vendor_id].capture_vol_min);
+ return 0;
+}
+
+/**
+* snd_intelmad_playback_volume_info - provides info about the volume control
+*
+* @kcontrol: pointer to the control
+* @uinfo: pointer to the structure where the control's info need
+* to be filled
+*
+* This function is called when a mixer application requests for control's info
+*/
+static int snd_intelmad_playback_volume_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ snd_intelmad_volume_info(uinfo, STEREO_CNTL,
+ intelmad_ctrl_val[sst_card_vendor_id].playback_vol_max,
+ intelmad_ctrl_val[sst_card_vendor_id].playback_vol_min);
+ return 0;
+}
+
+/**
+* snd_intelmad_device_info_mrst - provides information about the devices available
+*
+* @kcontrol: pointer to the control
+* @uinfo: pointer to the structure where the devices's info need
+* to be filled
+*
+* This function is called when a mixer application requests for device's info
+*/
+static int snd_intelmad_device_info_mrst(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+
+ WARN_ON(!kcontrol);
+ WARN_ON(!uinfo);
+
+ /* setup device select as drop down controls with different values */
+ if (kcontrol->id.numid == OUTPUT_SEL)
+ uinfo->value.enumerated.items = ARRAY_SIZE(out_names_mrst);
+ else
+ uinfo->value.enumerated.items = ARRAY_SIZE(in_names_mrst);
+ uinfo->count = MONO_CNTL;
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+
+ if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+ uinfo->value.enumerated.item = 1;
+ if (kcontrol->id.numid == OUTPUT_SEL)
+ strncpy(uinfo->value.enumerated.name,
+ out_names_mrst[uinfo->value.enumerated.item],
+ sizeof(uinfo->value.enumerated.name)-1);
+ else
+ strncpy(uinfo->value.enumerated.name,
+ in_names_mrst[uinfo->value.enumerated.item],
+ sizeof(uinfo->value.enumerated.name)-1);
+ return 0;
+}
+
+static int snd_intelmad_device_info_mfld(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ WARN_ON(!kcontrol);
+ WARN_ON(!uinfo);
+ /* setup device select as drop down controls with different values */
+ if (kcontrol->id.numid == OUTPUT_SEL)
+ uinfo->value.enumerated.items = ARRAY_SIZE(out_names_mfld);
+ else
+ uinfo->value.enumerated.items = ARRAY_SIZE(in_names_mfld);
+ uinfo->count = MONO_CNTL;
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+
+ if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+ uinfo->value.enumerated.item = 1;
+ if (kcontrol->id.numid == OUTPUT_SEL)
+ strncpy(uinfo->value.enumerated.name,
+ out_names_mfld[uinfo->value.enumerated.item],
+ sizeof(uinfo->value.enumerated.name)-1);
+ else
+ strncpy(uinfo->value.enumerated.name,
+ in_names_mfld[uinfo->value.enumerated.item],
+ sizeof(uinfo->value.enumerated.name)-1);
+ return 0;
+}
+
+/**
+* snd_intelmad_volume_get - gets the current volume for the control
+*
+* @kcontrol: pointer to the control
+* @uval: pointer to the structure where the control's info need
+* to be filled
+*
+* This function is called when .get function of a control is invoked from app
+*/
+static int snd_intelmad_volume_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uval)
+{
+ int ret_val = 0, cntl_list[2] = {0,};
+ int value = 0;
+ struct snd_intelmad *intelmaddata;
+ struct snd_pmic_ops *scard_ops;
+
+ pr_debug("sst: snd_intelmad_volume_get called\n");
+
+ WARN_ON(!uval);
+ WARN_ON(!kcontrol);
+
+ intelmaddata = kcontrol->private_data;
+
+ WARN_ON(!intelmaddata->sstdrv_ops);
+
+ scard_ops = intelmaddata->sstdrv_ops->scard_ops;
+
+ WARN_ON(!scard_ops);
+
+ switch (kcontrol->id.numid) {
+ case PLAYBACK_VOL:
+ cntl_list[0] = PMIC_SND_RIGHT_PB_VOL;
+ cntl_list[1] = PMIC_SND_LEFT_PB_VOL;
+ break;
+
+ case CAPTURE_VOL:
+ cntl_list[0] = PMIC_SND_CAPTURE_VOL;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret_val = scard_ops->get_vol(cntl_list[0], &value);
+ uval->value.integer.value[0] = value;
+
+ if (ret_val)
+ return ret_val;
+
+ if (kcontrol->id.numid == PLAYBACK_VOL) {
+ ret_val = scard_ops->get_vol(cntl_list[1], &value);
+ uval->value.integer.value[1] = value;
+ }
+ return ret_val;
+}
+
+/**
+* snd_intelmad_mute_get - gets the current mute status for the control
+*
+* @kcontrol: pointer to the control
+* @uval: pointer to the structure where the control's info need
+* to be filled
+*
+* This function is called when .get function of a control is invoked from app
+*/
+static int snd_intelmad_mute_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uval)
+{
+
+ int cntl_list = 0, ret_val = 0;
+ u8 value = 0;
+ struct snd_intelmad *intelmaddata;
+ struct snd_pmic_ops *scard_ops;
+
+ pr_debug("sst: Mute_get called\n");
+
+ WARN_ON(!uval);
+ WARN_ON(!kcontrol);
+
+ intelmaddata = kcontrol->private_data;
+
+ WARN_ON(!intelmaddata->sstdrv_ops);
+
+ scard_ops = intelmaddata->sstdrv_ops->scard_ops;
+
+ WARN_ON(!scard_ops);
+
+ switch (kcontrol->id.numid) {
+ case PLAYBACK_MUTE:
+ if (intelmaddata->output_sel == STEREO_HEADPHONE)
+ cntl_list = PMIC_SND_LEFT_HP_MUTE;
+ else if ((intelmaddata->output_sel == INTERNAL_SPKR) ||
+ (intelmaddata->output_sel == MONO_EARPIECE))
+ cntl_list = PMIC_SND_LEFT_SPEAKER_MUTE;
+ break;
+
+ case CAPTURE_MUTE:
+ if (intelmaddata->input_sel == DMIC)
+ cntl_list = PMIC_SND_DMIC_MUTE;
+ else if (intelmaddata->input_sel == AMIC)
+ cntl_list = PMIC_SND_AMIC_MUTE;
+ else if (intelmaddata->input_sel == HS_MIC)
+ cntl_list = PMIC_SND_HP_MIC_MUTE;
+ break;
+ case MASTER_MUTE:
+ uval->value.integer.value[0] = intelmaddata->master_mute;
+ return 0;
+ default:
+ return -EINVAL;
+ }
+
+ ret_val = scard_ops->get_mute(cntl_list, &value);
+ uval->value.integer.value[0] = value;
+ return ret_val;
+}
+
+/**
+* snd_intelmad_volume_set - sets the volume control's info
+*
+* @kcontrol: pointer to the control
+* @uval: pointer to the structure where the control's info is
+* available to be set
+*
+* This function is called when .set function of a control is invoked from app
+*/
+static int snd_intelmad_volume_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uval)
+{
+
+ int ret_val, cntl_list[2] = {0,};
+ struct snd_intelmad *intelmaddata;
+ struct snd_pmic_ops *scard_ops;
+
+ pr_debug("sst: volume set called:%ld %ld\n",
+ uval->value.integer.value[0],
+ uval->value.integer.value[1]);
+
+ WARN_ON(!uval);
+ WARN_ON(!kcontrol);
+
+ intelmaddata = kcontrol->private_data;
+
+ WARN_ON(!intelmaddata->sstdrv_ops);
+
+ scard_ops = intelmaddata->sstdrv_ops->scard_ops;
+
+ WARN_ON(!scard_ops);
+
+ switch (kcontrol->id.numid) {
+ case PLAYBACK_VOL:
+ cntl_list[0] = PMIC_SND_LEFT_PB_VOL;
+ cntl_list[1] = PMIC_SND_RIGHT_PB_VOL;
+ break;
+
+ case CAPTURE_VOL:
+ cntl_list[0] = PMIC_SND_CAPTURE_VOL;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret_val = scard_ops->set_vol(cntl_list[0],
+ uval->value.integer.value[0]);
+ if (ret_val)
+ return ret_val;
+
+ if (kcontrol->id.numid == PLAYBACK_VOL)
+ ret_val = scard_ops->set_vol(cntl_list[1],
+ uval->value.integer.value[1]);
+ return ret_val;
+}
+
+/**
+* snd_intelmad_mute_set - sets the mute control's info
+*
+* @kcontrol: pointer to the control
+* @uval: pointer to the structure where the control's info is
+* available to be set
+*
+* This function is called when .set function of a control is invoked from app
+*/
+static int snd_intelmad_mute_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uval)
+{
+ int cntl_list[2] = {0,}, ret_val;
+ struct snd_intelmad *intelmaddata;
+ struct snd_pmic_ops *scard_ops;
+
+ pr_debug("sst: snd_intelmad_mute_set called\n");
+
+ WARN_ON(!uval);
+ WARN_ON(!kcontrol);
+
+ intelmaddata = kcontrol->private_data;
+
+ WARN_ON(!intelmaddata->sstdrv_ops);
+
+ scard_ops = intelmaddata->sstdrv_ops->scard_ops;
+
+ WARN_ON(!scard_ops);
+
+ kcontrol->private_value = uval->value.integer.value[0];
+
+ switch (kcontrol->id.numid) {
+ case PLAYBACK_MUTE:
+ if (intelmaddata->output_sel == STEREO_HEADPHONE) {
+ cntl_list[0] = PMIC_SND_LEFT_HP_MUTE;
+ cntl_list[1] = PMIC_SND_RIGHT_HP_MUTE;
+ } else if ((intelmaddata->output_sel == INTERNAL_SPKR) ||
+ (intelmaddata->output_sel == MONO_EARPIECE)) {
+ cntl_list[0] = PMIC_SND_LEFT_SPEAKER_MUTE;
+ cntl_list[1] = PMIC_SND_RIGHT_SPEAKER_MUTE;
+ }
+ break;
+
+ case CAPTURE_MUTE:/*based on sel device mute the i/p dev*/
+ if (intelmaddata->input_sel == DMIC)
+ cntl_list[0] = PMIC_SND_DMIC_MUTE;
+ else if (intelmaddata->input_sel == AMIC)
+ cntl_list[0] = PMIC_SND_AMIC_MUTE;
+ else if (intelmaddata->input_sel == HS_MIC)
+ cntl_list[0] = PMIC_SND_HP_MIC_MUTE;
+ break;
+ case MASTER_MUTE:
+ cntl_list[0] = PMIC_SND_MUTE_ALL;
+ intelmaddata->master_mute = uval->value.integer.value[0];
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret_val = scard_ops->set_mute(cntl_list[0],
+ uval->value.integer.value[0]);
+ if (ret_val)
+ return ret_val;
+
+ if (kcontrol->id.numid == PLAYBACK_MUTE)
+ ret_val = scard_ops->set_mute(cntl_list[1],
+ uval->value.integer.value[0]);
+ return ret_val;
+}
+
+/**
+* snd_intelmad_device_get - get the device select control's info
+*
+* @kcontrol: pointer to the control
+* @uval: pointer to the structure where the control's info is
+* to be filled
+*
+* This function is called when .get function of a control is invoked from app
+*/
+static int snd_intelmad_device_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uval)
+{
+ struct snd_intelmad *intelmaddata;
+ struct snd_pmic_ops *scard_ops;
+ pr_debug("sst: device_get called\n");
+
+ WARN_ON(!uval);
+ WARN_ON(!kcontrol);
+
+ intelmaddata = kcontrol->private_data;
+ if (intelmaddata->cpu_id == CPU_CHIP_PENWELL) {
+ scard_ops = intelmaddata->sstdrv_ops->scard_ops;
+ if (kcontrol->id.numid == OUTPUT_SEL)
+ uval->value.enumerated.item[0] =
+ scard_ops->output_dev_id;
+ else if (kcontrol->id.numid == INPUT_SEL)
+ uval->value.enumerated.item[0] =
+ scard_ops->input_dev_id;
+ else
+ return -EINVAL;
+ } else
+ uval->value.enumerated.item[0] = kcontrol->private_value;
+ return 0;
+}
+
+/**
+* snd_intelmad_device_set - set the device select control's info
+*
+* @kcontrol: pointer to the control
+* @uval: pointer to the structure where the control's info is
+* available to be set
+*
+* This function is called when .set function of a control is invoked from app
+*/
+static int snd_intelmad_device_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uval)
+{
+ struct snd_intelmad *intelmaddata;
+ struct snd_pmic_ops *scard_ops;
+ int ret_val = 0, vendor, status;
+
+ pr_debug("sst: snd_intelmad_device_set called\n");
+
+ WARN_ON(!uval);
+ WARN_ON(!kcontrol);
+ status = -1;
+
+ intelmaddata = kcontrol->private_data;
+
+ WARN_ON(!intelmaddata->sstdrv_ops);
+
+ scard_ops = intelmaddata->sstdrv_ops->scard_ops;
+
+ WARN_ON(!scard_ops);
+
+ /* store value with driver */
+ kcontrol->private_value = uval->value.enumerated.item[0];
+
+ switch (kcontrol->id.numid) {
+ case OUTPUT_SEL:
+ ret_val = scard_ops->set_output_dev(
+ uval->value.enumerated.item[0]);
+ intelmaddata->output_sel = uval->value.enumerated.item[0];
+ break;
+ case INPUT_SEL:
+ vendor = intelmaddata->sstdrv_ops->vendor_id;
+ if ((vendor == SND_MX) || (vendor == SND_FS)) {
+ if (uval->value.enumerated.item[0] == HS_MIC) {
+ status = 1;
+ intelmaddata->sstdrv_ops->
+ control_set(SST_ENABLE_RX_TIME_SLOT, &status);
+ } else {
+ status = 0;
+ intelmaddata->sstdrv_ops->
+ control_set(SST_ENABLE_RX_TIME_SLOT, &status);
+ }
+ }
+ ret_val = scard_ops->set_input_dev(
+ uval->value.enumerated.item[0]);
+ intelmaddata->input_sel = uval->value.enumerated.item[0];
+ break;
+ default:
+ return -EINVAL;
+ }
+ kcontrol->private_value = uval->value.enumerated.item[0];
+ return ret_val;
+}
+
+struct snd_kcontrol_new snd_intelmad_controls_mrst[MAX_CTRL] __devinitdata = {
+{
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "PCM Playback Source",
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = snd_intelmad_device_info_mrst,
+ .get = snd_intelmad_device_get,
+ .put = snd_intelmad_device_set,
+ .private_value = 0,
+},
+{
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "PCM Capture Source",
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = snd_intelmad_device_info_mrst,
+ .get = snd_intelmad_device_get,
+ .put = snd_intelmad_device_set,
+ .private_value = 0,
+},
+{
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "PCM Playback Volume",
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = snd_intelmad_playback_volume_info,
+ .get = snd_intelmad_volume_get,
+ .put = snd_intelmad_volume_set,
+ .private_value = 0,
+},
+{
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "PCM Playback Switch",
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = snd_intelmad_mute_info,
+ .get = snd_intelmad_mute_get,
+ .put = snd_intelmad_mute_set,
+ .private_value = 0,
+},
+{
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "PCM Capture Volume",
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = snd_intelmad_capture_volume_info,
+ .get = snd_intelmad_volume_get,
+ .put = snd_intelmad_volume_set,
+ .private_value = 0,
+},
+{
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "PCM Capture Switch",
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = snd_intelmad_mute_info,
+ .get = snd_intelmad_mute_get,
+ .put = snd_intelmad_mute_set,
+ .private_value = 0,
+},
+{
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Master Playback Switch",
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = snd_intelmad_mute_info,
+ .get = snd_intelmad_mute_get,
+ .put = snd_intelmad_mute_set,
+ .private_value = 0,
+},
+};
+
+struct snd_kcontrol_new
+snd_intelmad_controls_mfld[MAX_CTRL_MFLD] __devinitdata = {
+{
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "PCM Playback Source",
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = snd_intelmad_device_info_mfld,
+ .get = snd_intelmad_device_get,
+ .put = snd_intelmad_device_set,
+ .private_value = 0,
+},
+{
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "PCM Capture Source",
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = snd_intelmad_device_info_mfld,
+ .get = snd_intelmad_device_get,
+ .put = snd_intelmad_device_set,
+ .private_value = 0,
+},
+};
+
diff --git a/drivers/staging/intel_sst/intelmid_msic_control.c b/drivers/staging/intel_sst/intelmid_msic_control.c
new file mode 100644
index 0000000..4d1755e
--- /dev/null
+++ b/drivers/staging/intel_sst/intelmid_msic_control.c
@@ -0,0 +1,410 @@
+/*
+ * intelmid_vm_control.c - Intel Sound card driver for MID
+ *
+ * Copyright (C) 2010 Intel Corp
+ * Authors: Vinod Koul <vinod.koul(a)intel.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This file contains the control operations of msic vendors
+ */
+
+#include <linux/pci.h>
+#include <linux/file.h>
+#include "intel_sst.h"
+#include "intel_sst_ioctl.h"
+#include "intelmid_snd_control.h"
+
+static int msic_init_card(void)
+{
+ struct sc_reg_access sc_access[] = {
+ /* dmic configuration */
+ {0x241, 0x85, 0},
+ {0x242, 0x02, 0},
+ /* audio paths config */
+ {0x24C, 0x10, 0},
+ {0x24D, 0x32, 0},
+ /* PCM2 interface slots */
+ /* preconfigured slots for 0-5 both tx, rx */
+ {0x272, 0x10, 0},
+ {0x273, 0x32, 0},
+ {0x274, 0xFF, 0},
+ {0x275, 0x10, 0},
+ {0x276, 0x32, 0},
+ {0x277, 0x54, 0},
+ /*Sinc5 decimator*/
+ {0x24E, 0x28, 0},
+ /*TI vibra w/a settings*/
+ {0x384, 0x80, 0},
+ {0x385, 0x80, 0},
+ /*vibra settings*/
+ {0x267, 0x00, 0},
+ {0x26A, 0x10, 0},
+ {0x261, 0x00, 0},
+ {0x264, 0x10, 0},
+ /* pcm port setting */
+ {0x278, 0x00, 0},
+ {0x27B, 0x01, 0},
+ {0x27C, 0x0a, 0},
+ /* Set vol HSLRVOLCTRL, IHFVOL */
+ {0x259, 0x04, 0},
+ {0x25A, 0x04, 0},
+ {0x25B, 0x04, 0},
+ {0x25C, 0x04, 0},
+ /* HSEPRXCTRL Enable the headset left and right FIR filters */
+ {0x250, 0x30, 0},
+ /* HSMIXER */
+ {0x256, 0x11, 0},
+ /* amic configuration */
+ {0x249, 0x09, 0x0},
+ {0x24A, 0x09, 0x0},
+ /* unmask ocaudio/accdet interrupts */
+ {0x1d, 0x00, 0x00},
+ {0x1e, 0x00, 0x00},
+ };
+ snd_msic_ops.card_status = SND_CARD_INIT_DONE;
+ sst_sc_reg_access(sc_access, PMIC_WRITE, 30);
+ snd_msic_ops.pb_on = 0;
+ snd_msic_ops.cap_on = 0;
+ snd_msic_ops.input_dev_id = DMIC; /*def dev*/
+ snd_msic_ops.output_dev_id = STEREO_HEADPHONE;
+ pr_debug("sst: msic init complete!!\n");
+ return 0;
+}
+
+static int msic_power_up_pb(unsigned int device)
+{
+ struct sc_reg_access sc_access1[] = {
+ /* turn on the audio power supplies */
+ {0x0DB, 0x05, 0},
+ /* VHSP */
+ {0x0DC, 0xFF, 0},
+ /* VHSN */
+ {0x0DD, 0x3F, 0},
+ /* turn on PLL */
+ {0x240, 0x21, 0},
+ };
+ struct sc_reg_access sc_access2[] = {
+ /* disable driver */
+ {0x25D, 0x0, 0x43},
+ /* DAC CONFIG ; both HP, LP on */
+ {0x257, 0x03, 0x03},
+ };
+ struct sc_reg_access sc_access3[] = {
+ /* HSEPRXCTRL Enable the headset left and right FIR filters */
+ {0x250, 0x30, 0},
+ /* HSMIXER */
+ {0x256, 0x11, 0},
+ };
+ struct sc_reg_access sc_access4[] = {
+ /* enable driver */
+ {0x25D, 0x3, 0x3},
+ /* unmute the headset */
+ { 0x259, 0x80, 0x80},
+ { 0x25A, 0x80, 0x80},
+ };
+ struct sc_reg_access sc_access_vihf[] = {
+ /* VIHF ON */
+ {0x0C9, 0x2D, 0x00},
+ };
+ struct sc_reg_access sc_access22[] = {
+ /* disable driver */
+ {0x25D, 0x00, 0x0C},
+ /*Filer DAC enable*/
+ {0x251, 0x03, 0x03},
+ {0x257, 0x0C, 0x0C},
+ };
+ struct sc_reg_access sc_access32[] = {
+ /*enable drv*/
+ {0x25D, 0x0C, 0x0c},
+ };
+ struct sc_reg_access sc_access42[] = {
+ /*unmute headset*/
+ {0x25B, 0x80, 0x80},
+ {0x25C, 0x80, 0x80},
+ };
+ struct sc_reg_access sc_access23[] = {
+ /* disable driver */
+ {0x25D, 0x0, 0x43},
+ /* DAC CONFIG ; both HP, LP on */
+ {0x257, 0x03, 0x03},
+ };
+ struct sc_reg_access sc_access43[] = {
+ /* enable driver */
+ {0x25D, 0x40, 0x40},
+ /* unmute the headset */
+ { 0x259, 0x80, 0x80},
+ { 0x25A, 0x80, 0x80},
+ };
+ struct sc_reg_access sc_access_vib[] = {
+ /* enable driver, ADC */
+ {0x25D, 0x10, 0x10},
+ {0x264, 0x02, 0x02},
+ };
+ struct sc_reg_access sc_access_hap[] = {
+ /* enable driver, ADC */
+ {0x25D, 0x20, 0x20},
+ {0x26A, 0x02, 0x02},
+ };
+ struct sc_reg_access sc_access_pcm2[] = {
+ /* enable pcm 2 */
+ {0x27C, 0x1, 0x1},
+ };
+ int retval = 0;
+
+ if (snd_msic_ops.card_status == SND_CARD_UN_INIT) {
+ retval = msic_init_card();
+ if (retval)
+ return retval;
+ }
+
+ pr_debug("sst: powering up pb.... Device %d\n", device);
+ sst_sc_reg_access(sc_access1, PMIC_WRITE, 4);
+ switch (device) {
+ case SND_SST_DEVICE_HEADSET:
+ if (snd_msic_ops.output_dev_id == STEREO_HEADPHONE) {
+ sst_sc_reg_access(sc_access2, PMIC_READ_MODIFY, 2);
+ sst_sc_reg_access(sc_access3, PMIC_WRITE, 2);
+ sst_sc_reg_access(sc_access4, PMIC_READ_MODIFY, 3);
+ } else {
+ sst_sc_reg_access(sc_access23, PMIC_READ_MODIFY, 2);
+ sst_sc_reg_access(sc_access3, PMIC_WRITE, 2);
+ sst_sc_reg_access(sc_access43, PMIC_READ_MODIFY, 3);
+ }
+ snd_msic_ops.pb_on = 1;
+ break;
+
+ case SND_SST_DEVICE_IHF:
+ sst_sc_reg_access(sc_access_vihf, PMIC_WRITE, 1);
+ sst_sc_reg_access(sc_access22, PMIC_READ_MODIFY, 3);
+ sst_sc_reg_access(sc_access32, PMIC_READ_MODIFY, 1);
+ sst_sc_reg_access(sc_access42, PMIC_READ_MODIFY, 2);
+ break;
+
+ case SND_SST_DEVICE_VIBRA:
+ sst_sc_reg_access(sc_access_vib, PMIC_READ_MODIFY, 2);
+ break;
+
+ case SND_SST_DEVICE_HAPTIC:
+ sst_sc_reg_access(sc_access_hap, PMIC_READ_MODIFY, 2);
+ break;
+
+ default:
+ pr_warn("sst: Wrong Device %d, selected %d\n",
+ device, snd_msic_ops.output_dev_id);
+ }
+ return sst_sc_reg_access(sc_access_pcm2, PMIC_READ_MODIFY, 1);
+}
+
+static int msic_power_up_cp(unsigned int device)
+{
+ struct sc_reg_access sc_access[] = {
+ /* turn on the audio power supplies */
+ {0x0DB, 0x05, 0},
+ /* VHSP */
+ {0x0DC, 0xFF, 0},
+ /* VHSN */
+ {0x0DD, 0x3F, 0},
+ /* turn on PLL */
+ {0x240, 0x21, 0},
+
+ /* Turn on DMIC supply */
+ {0x247, 0xA0, 0x0},
+ {0x240, 0x21, 0x0},
+ {0x24C, 0x10, 0x0},
+
+ /* mic demux enable */
+ {0x245, 0x3F, 0x0},
+ {0x246, 0x7, 0x0},
+
+ };
+ struct sc_reg_access sc_access_amic[] = {
+ /* turn on the audio power supplies */
+ {0x0DB, 0x05, 0},
+ /* VHSP */
+ {0x0DC, 0xFF, 0},
+ /* VHSN */
+ {0x0DD, 0x3F, 0},
+ /* turn on PLL */
+ {0x240, 0x21, 0},
+ /*ADC EN*/
+ {0x248, 0x05, 0x0},
+ {0x24C, 0x76, 0x0},
+ /*MIC EN*/
+ {0x249, 0x09, 0x0},
+ {0x24A, 0x09, 0x0},
+ /* Turn on AMIC supply */
+ {0x247, 0xFC, 0x0},
+
+ };
+ struct sc_reg_access sc_access2[] = {
+ /* enable pcm 2 */
+ {0x27C, 0x1, 0x1},
+ };
+ struct sc_reg_access sc_access3[] = {
+ /*wait for mic to stabalize before turning on audio channels*/
+ {0x24F, 0x3C, 0x0},
+ };
+ int retval = 0;
+
+ if (snd_msic_ops.card_status == SND_CARD_UN_INIT) {
+ retval = msic_init_card();
+ if (retval)
+ return retval;
+ }
+
+ pr_debug("sst: powering up cp....%d\n", snd_msic_ops.input_dev_id);
+ sst_sc_reg_access(sc_access2, PMIC_READ_MODIFY, 1);
+ snd_msic_ops.cap_on = 1;
+ if (snd_msic_ops.input_dev_id == AMIC)
+ sst_sc_reg_access(sc_access_amic, PMIC_WRITE, 9);
+ else
+ sst_sc_reg_access(sc_access, PMIC_WRITE, 9);
+ return sst_sc_reg_access(sc_access3, PMIC_WRITE, 1);
+
+}
+
+static int msic_power_down(void)
+{
+ int retval = 0;
+
+ pr_debug("sst: powering dn msic\n");
+ snd_msic_ops.pb_on = 0;
+ snd_msic_ops.cap_on = 0;
+ return retval;
+}
+
+static int msic_power_down_pb(void)
+{
+ int retval = 0;
+
+ pr_debug("sst: powering dn pb....\n");
+ snd_msic_ops.pb_on = 0;
+ return retval;
+}
+
+static int msic_power_down_cp(void)
+{
+ int retval = 0;
+
+ pr_debug("sst: powering dn cp....\n");
+ snd_msic_ops.cap_on = 0;
+ return retval;
+}
+
+static int msic_set_selected_output_dev(u8 value)
+{
+ int retval = 0;
+
+ pr_debug("sst: msic set selected output:%d\n", value);
+ snd_msic_ops.output_dev_id = value;
+ if (snd_msic_ops.pb_on)
+ msic_power_up_pb(SND_SST_DEVICE_HEADSET);
+ return retval;
+}
+
+static int msic_set_selected_input_dev(u8 value)
+{
+
+ struct sc_reg_access sc_access_dmic[] = {
+ {0x24C, 0x10, 0x0},
+ };
+ struct sc_reg_access sc_access_amic[] = {
+ {0x24C, 0x76, 0x0},
+
+ };
+ int retval = 0;
+
+ pr_debug("sst: msic_set_selected_input_dev:%d\n", value);
+ snd_msic_ops.input_dev_id = value;
+ switch (value) {
+ case AMIC:
+ pr_debug("sst: Selecting AMIC1\n");
+ retval = sst_sc_reg_access(sc_access_amic, PMIC_WRITE, 1);
+ break;
+ case DMIC:
+ pr_debug("sst: Selecting DMIC1\n");
+ retval = sst_sc_reg_access(sc_access_dmic, PMIC_WRITE, 1);
+ break;
+ default:
+ return -EINVAL;
+
+ }
+ if (snd_msic_ops.cap_on)
+ retval = msic_power_up_cp(SND_SST_DEVICE_CAPTURE);
+ return retval;
+}
+
+static int msic_set_pcm_voice_params(void)
+{
+ return 0;
+}
+
+static int msic_set_pcm_audio_params(int sfreq, int word_size, int num_channel)
+{
+ return 0;
+}
+
+static int msic_set_audio_port(int status)
+{
+ return 0;
+}
+
+static int msic_set_voice_port(int status)
+{
+ return 0;
+}
+
+static int msic_set_mute(int dev_id, u8 value)
+{
+ return 0;
+}
+
+static int msic_set_vol(int dev_id, int value)
+{
+ return 0;
+}
+
+static int msic_get_mute(int dev_id, u8 *value)
+{
+ return 0;
+}
+
+static int msic_get_vol(int dev_id, int *value)
+{
+ return 0;
+}
+
+struct snd_pmic_ops snd_msic_ops = {
+ .set_input_dev = msic_set_selected_input_dev,
+ .set_output_dev = msic_set_selected_output_dev,
+ .set_mute = msic_set_mute,
+ .get_mute = msic_get_mute,
+ .set_vol = msic_set_vol,
+ .get_vol = msic_get_vol,
+ .init_card = msic_init_card,
+ .set_pcm_audio_params = msic_set_pcm_audio_params,
+ .set_pcm_voice_params = msic_set_pcm_voice_params,
+ .set_voice_port = msic_set_voice_port,
+ .set_audio_port = msic_set_audio_port,
+ .power_up_pmic_pb = msic_power_up_pb,
+ .power_up_pmic_cp = msic_power_up_cp,
+ .power_down_pmic_pb = msic_power_down_pb,
+ .power_down_pmic_cp = msic_power_down_cp,
+ .power_down_pmic = msic_power_down,
+};
diff --git a/drivers/staging/intel_sst/intelmid_pvt.c b/drivers/staging/intel_sst/intelmid_pvt.c
new file mode 100644
index 0000000..9ed9475
--- /dev/null
+++ b/drivers/staging/intel_sst/intelmid_pvt.c
@@ -0,0 +1,174 @@
+/*
+ * intelmid_pvt.h - Intel Sound card driver for MID
+ *
+ * Copyright (C) 2008-10 Intel Corp
+ * Authors: Harsha Priya <priya.harsha(a)intel.com>
+ * Vinod Koul <vinod.koul(a)intel.com>
+ * KP Jeeja <jeeja.kp(a)intel.com>
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * ALSA driver for Intel MID sound card chipset - holding private functions
+ */
+#include <linux/io.h>
+#include <asm/intel_scu_ipc.h>
+#include <sound/core.h>
+#include <sound/control.h>
+#include <sound/pcm.h>
+#include "jack.h"
+#include "intel_sst.h"
+#include "intel_sst_ioctl.h"
+#include "intelmid_snd_control.h"
+#include "intelmid.h"
+
+
+void period_elapsed(void *mad_substream)
+{
+ struct snd_pcm_substream *substream = mad_substream;
+ struct mad_stream_pvt *stream;
+
+
+
+ if (!substream || !substream->runtime)
+ return;
+ stream = substream->runtime->private_data;
+ if (!stream)
+ return;
+
+ if (stream->stream_status != RUNNING)
+ return;
+ pr_debug("sst: calling period elapsed\n");
+ snd_pcm_period_elapsed(substream);
+ return;
+}
+
+
+int snd_intelmad_alloc_stream(struct snd_pcm_substream *substream)
+{
+ struct snd_intelmad *intelmaddata = snd_pcm_substream_chip(substream);
+ struct mad_stream_pvt *stream = substream->runtime->private_data;
+ struct snd_sst_stream_params param = {{{0,},},};
+ struct snd_sst_params str_params = {0};
+ int ret_val;
+
+ /* set codec params and inform SST driver the same */
+
+ param.uc.pcm_params.codec = SST_CODEC_TYPE_PCM;
+ param.uc.pcm_params.num_chan = (u8) substream->runtime->channels;
+ param.uc.pcm_params.pcm_wd_sz = substream->runtime->sample_bits;
+ param.uc.pcm_params.reserved = 0;
+ param.uc.pcm_params.sfreq = substream->runtime->rate;
+ param.uc.pcm_params.ring_buffer_size =
+ snd_pcm_lib_buffer_bytes(substream);
+ param.uc.pcm_params.period_count = substream->runtime->period_size;
+ param.uc.pcm_params.ring_buffer_addr =
+ virt_to_phys(substream->runtime->dma_area);
+ pr_debug("sst: period_cnt = %d\n", param.uc.pcm_params.period_count);
+ pr_debug("sst: sfreq= %d, wd_sz = %d\n",
+ param.uc.pcm_params.sfreq, param.uc.pcm_params.pcm_wd_sz);
+
+ str_params.sparams = param;
+ str_params.codec = SST_CODEC_TYPE_PCM;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ str_params.ops = STREAM_OPS_PLAYBACK;
+ pr_debug("sst: Playbck stream,Device %d\n", stream->device);
+ } else {
+ str_params.ops = STREAM_OPS_CAPTURE;
+ stream->device = SND_SST_DEVICE_CAPTURE;
+ pr_debug("sst: Capture stream,Device %d\n", stream->device);
+ }
+ str_params.device_type = stream->device;
+ ret_val = intelmaddata->sstdrv_ops->control_set(SST_SND_ALLOC,
+ &str_params);
+ pr_debug("sst: SST_SND_PLAY/CAPTURE ret_val = %x\n",
+ ret_val);
+ if (ret_val < 0)
+ return ret_val;
+
+ stream->stream_info.str_id = ret_val;
+ stream->stream_status = INIT;
+ stream->stream_info.buffer_ptr = 0;
+ pr_debug("sst: str id : %d\n", stream->stream_info.str_id);
+
+ return ret_val;
+}
+
+int snd_intelmad_init_stream(struct snd_pcm_substream *substream)
+{
+ struct mad_stream_pvt *stream = substream->runtime->private_data;
+ struct snd_intelmad *intelmaddata = snd_pcm_substream_chip(substream);
+ int ret_val;
+
+ pr_debug("sst: setting buffer ptr param\n");
+ stream->stream_info.period_elapsed = period_elapsed;
+ stream->stream_info.mad_substream = substream;
+ stream->stream_info.buffer_ptr = 0;
+ stream->stream_info.sfreq = substream->runtime->rate;
+ ret_val = intelmaddata->sstdrv_ops->control_set(SST_SND_STREAM_INIT,
+ &stream->stream_info);
+ if (ret_val)
+ pr_err("sst: control_set ret error %d\n", ret_val);
+ return ret_val;
+
+}
+
+
+/**
+ * sst_sc_reg_access - IPC read/write wrapper
+ *
+ * @sc_access: array of data, addresses and mask
+ * @type: operation type
+ * @num_val: number of reg to opertae on
+ *
+ * Reads/writes/read-modify operations on registers accessed through SCU (sound
+ * card and few SST DSP regsisters that are not accissible to IA)
+ */
+int sst_sc_reg_access(struct sc_reg_access *sc_access,
+ int type, int num_val)
+{
+ int i, retval = 0;
+ if (type == PMIC_WRITE) {
+ for (i = 0; i < num_val; i++) {
+ retval = intel_scu_ipc_iowrite8(sc_access[i].reg_addr,
+ sc_access[i].value);
+ if (retval) {
+ pr_err("sst: IPC write failed!!! %d\n", retval);
+ return retval;
+ }
+ }
+ } else if (type == PMIC_READ) {
+ for (i = 0; i < num_val; i++) {
+ retval = intel_scu_ipc_ioread8(sc_access[i].reg_addr,
+ &(sc_access[i].value));
+ if (retval) {
+ pr_err("sst: IPC read failed!!!!!%d\n", retval);
+ return retval;
+ }
+ }
+ } else {
+ for (i = 0; i < num_val; i++) {
+ retval = intel_scu_ipc_update_register(
+ sc_access[i].reg_addr, sc_access[i].value,
+ sc_access[i].mask);
+ if (retval) {
+ pr_err("sst: IPC Modify failed!!!%d\n", retval);
+ return retval;
+ }
+ }
+ }
+ return retval;
+}
diff --git a/drivers/staging/intel_sst/intelmid_snd_control.h b/drivers/staging/intel_sst/intelmid_snd_control.h
new file mode 100644
index 0000000..a4565f3
--- /dev/null
+++ b/drivers/staging/intel_sst/intelmid_snd_control.h
@@ -0,0 +1,114 @@
+#ifndef __INTELMID_SND_CTRL_H__
+#define __INTELMID_SND_CTRL_H__
+/*
+ * intelmid_snd_control.h - Intel Sound card driver for MID
+ *
+ * Copyright (C) 2008-10 Intel Corporation
+ * Authors: Vinod Koul <vinod.koul(a)intel.com>
+ * Harsha Priya <priya.harsha(a)intel.com>
+ * Dharageswari R <dharageswari.r(a)intel.com>
+ * KP Jeeja <jeeja.kp(a)intel.com>
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This file defines all snd control functions
+ */
+
+/*
+Mask bits
+*/
+#define MASK0 0x01 /* 0000 0001 */
+#define MASK1 0x02 /* 0000 0010 */
+#define MASK2 0x04 /* 0000 0100 */
+#define MASK3 0x08 /* 0000 1000 */
+#define MASK4 0x10 /* 0001 0000 */
+#define MASK5 0x20 /* 0010 0000 */
+#define MASK6 0x40 /* 0100 0000 */
+#define MASK7 0x80 /* 1000 0000 */
+/*
+value bits
+*/
+#define VALUE0 0x01 /* 0000 0001 */
+#define VALUE1 0x02 /* 0000 0010 */
+#define VALUE2 0x04 /* 0000 0100 */
+#define VALUE3 0x08 /* 0000 1000 */
+#define VALUE4 0x10 /* 0001 0000 */
+#define VALUE5 0x20 /* 0010 0000 */
+#define VALUE6 0x40 /* 0100 0000 */
+#define VALUE7 0x80 /* 1000 0000 */
+
+#define MUTE 0 /* ALSA Passes 0 for mute */
+#define UNMUTE 1 /* ALSA Passes 1 for unmute */
+
+#define MAX_VOL_PMIC_VENDOR0 0x3f /* max vol in dB for stereo & voice DAC */
+#define MIN_VOL_PMIC_VENDOR0 0 /* min vol in dB for stereo & voice DAC */
+/* Head phone volume control */
+#define MAX_HP_VOL_PMIC_VENDOR1 6 /* max volume in dB for HP */
+#define MIN_HP_VOL_PMIC_VENDOR1 (-84) /* min volume in dB for HP */
+#define MAX_HP_VOL_INDX_PMIC_VENDOR1 40 /* Number of HP volume control values */
+
+/* Mono Earpiece Volume control */
+#define MAX_EP_VOL_PMIC_VENDOR1 0 /* max volume in dB for EP */
+#define MIN_EP_VOL_PMIC_VENDOR1 (-75) /* min volume in dB for EP */
+#define MAX_EP_VOL_INDX_PMIC_VENDOR1 32 /* Number of EP volume control values */
+
+int sst_sc_reg_access(struct sc_reg_access *sc_access,
+ int type, int num_val);
+extern struct snd_pmic_ops snd_pmic_ops_fs;
+extern struct snd_pmic_ops snd_pmic_ops_mx;
+extern struct snd_pmic_ops snd_pmic_ops_nc;
+extern struct snd_pmic_ops snd_msic_ops;
+
+/* device */
+enum SND_INPUT_DEVICE {
+ AMIC,
+ DMIC,
+ HS_MIC,
+ IN_UNDEFINED
+};
+
+enum SND_OUTPUT_DEVICE {
+ STEREO_HEADPHONE,
+ MONO_EARPIECE,
+
+ INTERNAL_SPKR,
+ RECEIVER,
+ OUT_UNDEFINED
+};
+
+enum pmic_controls {
+ PMIC_SND_HP_MIC_MUTE = 0x0001,
+ PMIC_SND_AMIC_MUTE = 0x0002,
+ PMIC_SND_DMIC_MUTE = 0x0003,
+ PMIC_SND_CAPTURE_VOL = 0x0004,
+/* Output controls */
+ PMIC_SND_LEFT_PB_VOL = 0x0010,
+ PMIC_SND_RIGHT_PB_VOL = 0x0011,
+ PMIC_SND_LEFT_HP_MUTE = 0x0012,
+ PMIC_SND_RIGHT_HP_MUTE = 0x0013,
+ PMIC_SND_LEFT_SPEAKER_MUTE = 0x0014,
+ PMIC_SND_RIGHT_SPEAKER_MUTE = 0x0015,
+ PMIC_SND_RECEIVER_VOL = 0x0016,
+ PMIC_SND_RECEIVER_MUTE = 0x0017,
+/* Other controls */
+ PMIC_SND_MUTE_ALL = 0x0020,
+ PMIC_MAX_CONTROLS = 0x0020,
+};
+
+#endif /* __INTELMID_SND_CTRL_H__ */
+
+
diff --git a/drivers/staging/intel_sst/intelmid_v0_control.c b/drivers/staging/intel_sst/intelmid_v0_control.c
new file mode 100644
index 0000000..f586d62
--- /dev/null
+++ b/drivers/staging/intel_sst/intelmid_v0_control.c
@@ -0,0 +1,771 @@
+/*
+ * intel_sst_v0_control.c - Intel SST Driver for audio engine
+ *
+ * Copyright (C) 2008-10 Intel Corporation
+ * Authors: Vinod Koul <vinod.koul(a)intel.com>
+ * Harsha Priya <priya.harsha(a)intel.com>
+ * Dharageswari R <dharageswari.r(a)intel.com>
+ * KP Jeeja <jeeja.kp(a)intel.com>
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This file contains the control operations of vendor 1
+ */
+
+#include <linux/pci.h>
+#include <linux/file.h>
+#include "intel_sst.h"
+#include "intelmid_snd_control.h"
+
+
+enum _reg_v1 {
+ VOICEPORT1 = 0x180,
+ VOICEPORT2 = 0x181,
+ AUDIOPORT1 = 0x182,
+ AUDIOPORT2 = 0x183,
+ MISCVOICECTRL = 0x184,
+ MISCAUDCTRL = 0x185,
+ DMICCTRL1 = 0x186,
+ AUDIOBIAS = 0x187,
+ MICCTRL = 0x188,
+ MICLICTRL1 = 0x189,
+ MICLICTRL2 = 0x18A,
+ MICLICTRL3 = 0x18B,
+ VOICEDACCTRL1 = 0x18C,
+ STEREOADCCTRL = 0x18D,
+ AUD15 = 0x18E,
+ AUD16 = 0x18F,
+ AUD17 = 0x190,
+ AUD18 = 0x191,
+ RMIXOUTSEL = 0x192,
+ ANALOGLBR = 0x193,
+ ANALOGLBL = 0x194,
+ POWERCTRL1 = 0x195,
+ POWERCTRL2 = 0x196,
+ HEADSETDETECTINT = 0x197,
+ HEADSETDETECTINTMASK = 0x198,
+ TRIMENABLE = 0x199,
+};
+
+int rev_id = 0x20;
+
+/****
+ * fs_init_card - initialize the sound card
+ *
+ * This initilizes the audio paths to know values in case of this sound card
+ */
+static int fs_init_card(void)
+{
+ struct sc_reg_access sc_access[] = {
+ {0x180, 0x00, 0x0},
+ {0x181, 0x00, 0x0},
+ {0x182, 0xF8, 0x0},
+ {0x183, 0x08, 0x0},
+ {0x184, 0x00, 0x0},
+ {0x185, 0x40, 0x0},
+ {0x186, 0x06, 0x0},
+ {0x187, 0x80, 0x0},
+ {0x188, 0x40, 0x0},
+ {0x189, 0x39, 0x0},
+ {0x18a, 0x39, 0x0},
+ {0x18b, 0x1F, 0x0},
+ {0x18c, 0x00, 0x0},
+ {0x18d, 0x00, 0x0},
+ {0x18e, 0x39, 0x0},
+ {0x18f, 0x39, 0x0},
+ {0x190, 0x39, 0x0},
+ {0x191, 0x11, 0x0},
+ {0x192, 0x0E, 0x0},
+ {0x193, 0x00, 0x0},
+ {0x194, 0x00, 0x0},
+ {0x195, 0x00, 0x0},
+ {0x196, 0x7C, 0x0},
+ {0x197, 0x00, 0x0},
+ {0x198, 0x0B, 0x0},
+ {0x199, 0x00, 0x0},
+ {0x037, 0x3F, 0x0},
+ };
+
+ snd_pmic_ops_fs.card_status = SND_CARD_INIT_DONE;
+ snd_pmic_ops_fs.master_mute = UNMUTE;
+ snd_pmic_ops_fs.mute_status = UNMUTE;
+ snd_pmic_ops_fs.num_channel = 2;
+ return sst_sc_reg_access(sc_access, PMIC_WRITE, 27);
+}
+
+static int fs_enable_audiodac(int value)
+{
+ struct sc_reg_access sc_access[3];
+ sc_access[0].reg_addr = AUD16;
+ sc_access[1].reg_addr = AUD17;
+ sc_access[2].reg_addr = AUD15;
+ sc_access[0].mask = sc_access[1].mask = sc_access[2].mask = MASK7;
+
+ if (snd_pmic_ops_fs.mute_status == MUTE)
+ return 0;
+ if (value == MUTE) {
+ sc_access[0].value = sc_access[1].value =
+ sc_access[2].value = 0x80;
+
+ } else {
+ sc_access[0].value = sc_access[1].value =
+ sc_access[2].value = 0x0;
+ }
+ if (snd_pmic_ops_fs.num_channel == 1)
+ sc_access[1].value = sc_access[2].value = 0x80;
+ return sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 3);
+
+}
+
+static int fs_power_up_pb(unsigned int port)
+{
+ struct sc_reg_access sc_access[] = {
+ {AUDIOBIAS, 0x00, MASK7},
+ {POWERCTRL1, 0xC6, 0xC6},
+ {POWERCTRL2, 0x30, 0x30},
+
+ };
+ int retval = 0;
+
+ if (snd_pmic_ops_fs.card_status == SND_CARD_UN_INIT)
+ retval = fs_init_card();
+ if (retval)
+ return retval;
+ retval = fs_enable_audiodac(MUTE);
+ retval = sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 3);
+
+ if (retval)
+ return retval;
+
+ pr_debug("sst: in fs power up pb\n");
+ return fs_enable_audiodac(UNMUTE);
+}
+
+static int fs_power_down_pb(void)
+{
+ struct sc_reg_access sc_access[] = {
+ {POWERCTRL1, 0x00, 0xC6},
+ {POWERCTRL2, 0x00, 0x30},
+ };
+ int retval = 0;
+
+ if (snd_pmic_ops_fs.card_status == SND_CARD_UN_INIT)
+ retval = fs_init_card();
+ if (retval)
+ return retval;
+ retval = fs_enable_audiodac(MUTE);
+ retval = sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 2);
+
+ if (retval)
+ return retval;
+
+ pr_debug("sst: in fsl power down pb\n");
+ return fs_enable_audiodac(UNMUTE);
+}
+
+static int fs_power_up_cp(unsigned int port)
+{
+ struct sc_reg_access sc_access[] = {
+ {POWERCTRL2, 0x32, 0x32}, /*NOTE power up A ADC only as*/
+ {AUDIOBIAS, 0x00, MASK7},
+ /*as turning on V ADC causes noise*/
+ };
+ int retval = 0;
+
+ if (snd_pmic_ops_fs.card_status == SND_CARD_UN_INIT)
+ retval = fs_init_card();
+ if (retval)
+ return retval;
+ return sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 2);
+}
+
+static int fs_power_down_cp(void)
+{
+ struct sc_reg_access sc_access[] = {
+ {POWERCTRL2, 0x00, 0x03},
+ };
+ int retval = 0;
+
+ if (snd_pmic_ops_fs.card_status == SND_CARD_UN_INIT)
+ retval = fs_init_card();
+ if (retval)
+ return retval;
+ return sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 1);
+}
+
+static int fs_power_down(void)
+{
+ int retval = 0;
+ struct sc_reg_access sc_access[] = {
+ {AUDIOBIAS, MASK7, MASK7},
+ };
+
+ if (snd_pmic_ops_fs.card_status == SND_CARD_UN_INIT)
+ retval = fs_init_card();
+ if (retval)
+ return retval;
+ return sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 1);
+}
+
+static int fs_set_pcm_voice_params(void)
+{
+ struct sc_reg_access sc_access[] = {
+ {0x180, 0xA0, 0},
+ {0x181, 0x04, 0},
+ {0x182, 0x0, 0},
+ {0x183, 0x0, 0},
+ {0x184, 0x18, 0},
+ {0x185, 0x40, 0},
+ {0x186, 0x06, 0},
+ {0x187, 0x0, 0},
+ {0x188, 0x10, 0},
+ {0x189, 0x39, 0},
+ {0x18a, 0x39, 0},
+ {0x18b, 0x02, 0},
+ {0x18c, 0x0, 0},
+ {0x18d, 0x0, 0},
+ {0x18e, 0x39, 0},
+ {0x18f, 0x0, 0},
+ {0x190, 0x0, 0},
+ {0x191, 0x20, 0},
+ {0x192, 0x20, 0},
+ {0x193, 0x0, 0},
+ {0x194, 0x0, 0},
+ {0x195, 0x06, 0},
+ {0x196, 0x25, 0},
+ {0x197, 0x0, 0},
+ {0x198, 0xF, 0},
+ {0x199, 0x0, 0},
+ };
+ int retval = 0;
+
+ if (snd_pmic_ops_fs.card_status == SND_CARD_UN_INIT)
+ retval = fs_init_card();
+ if (retval)
+ return retval;
+ return sst_sc_reg_access(sc_access, PMIC_WRITE, 26);
+}
+
+static int fs_set_audio_port(int status)
+{
+ struct sc_reg_access sc_access[2];
+ int retval = 0;
+
+ if (snd_pmic_ops_fs.card_status == SND_CARD_UN_INIT)
+ retval = fs_init_card();
+ if (retval)
+ return retval;
+ if (status == DEACTIVATE) {
+ /* Deactivate audio port-tristate and power */
+ sc_access[0].value = 0x00;
+ sc_access[0].mask = MASK6|MASK7;
+ sc_access[0].reg_addr = AUDIOPORT1;
+ sc_access[1].value = 0x00;
+ sc_access[1].mask = MASK4|MASK5;
+ sc_access[1].reg_addr = POWERCTRL2;
+ return sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 2);
+ } else if (status == ACTIVATE) {
+ /* activate audio port */
+ sc_access[0].value = 0xC0;
+ sc_access[0].mask = MASK6|MASK7;
+ sc_access[0].reg_addr = AUDIOPORT1;
+ sc_access[1].value = 0x30;
+ sc_access[1].mask = MASK4|MASK5;
+ sc_access[1].reg_addr = POWERCTRL2;
+ return sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 2);
+ } else
+ return -EINVAL;
+}
+
+static int fs_set_voice_port(int status)
+{
+ struct sc_reg_access sc_access[2];
+ int retval = 0;
+
+ if (snd_pmic_ops_fs.card_status == SND_CARD_UN_INIT)
+ retval = fs_init_card();
+ if (retval)
+ return retval;
+ if (status == DEACTIVATE) {
+ /* Deactivate audio port-tristate and power */
+ sc_access[0].value = 0x00;
+ sc_access[0].mask = MASK6|MASK7;
+ sc_access[0].reg_addr = VOICEPORT1;
+ sc_access[1].value = 0x00;
+ sc_access[1].mask = MASK0|MASK1;
+ sc_access[1].reg_addr = POWERCTRL2;
+ return sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 2);
+ } else if (status == ACTIVATE) {
+ /* activate audio port */
+ sc_access[0].value = 0xC0;
+ sc_access[0].mask = MASK6|MASK7;
+ sc_access[0].reg_addr = VOICEPORT1;
+ sc_access[1].value = 0x03;
+ sc_access[1].mask = MASK0|MASK1;
+ sc_access[1].reg_addr = POWERCTRL2;
+ return sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 2);
+ } else
+ return -EINVAL;
+}
+
+static int fs_set_pcm_audio_params(int sfreq, int word_size, int num_channel)
+{
+ u8 config1 = 0;
+ struct sc_reg_access sc_access[4];
+ int retval = 0, num_value = 0;
+
+ if (snd_pmic_ops_fs.card_status == SND_CARD_UN_INIT)
+ retval = fs_init_card();
+ if (retval)
+ return retval;
+ switch (sfreq) {
+ case 8000:
+ config1 = 0x00;
+ break;
+ case 11025:
+ config1 = 0x01;
+ break;
+ case 12000:
+ config1 = 0x02;
+ break;
+ case 16000:
+ config1 = 0x03;
+ break;
+ case 22050:
+ config1 = 0x04;
+ break;
+ case 24000:
+ config1 = 0x05;
+ break;
+ case 26000:
+ config1 = 0x06;
+ break;
+ case 32000:
+ config1 = 0x07;
+ break;
+ case 44100:
+ config1 = 0x08;
+ break;
+ case 48000:
+ config1 = 0x09;
+ break;
+ }
+ snd_pmic_ops_fs.num_channel = num_channel;
+ if (snd_pmic_ops_fs.num_channel == 1) {
+ sc_access[0].reg_addr = AUD17;
+ sc_access[1].reg_addr = AUD15;
+ sc_access[0].mask = sc_access[1].mask = MASK7;
+ sc_access[0].value = sc_access[1].value = 0x80;
+ sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 2);
+
+ } else {
+ sc_access[0].reg_addr = AUD17;
+ sc_access[1].reg_addr = AUD15;
+ sc_access[0].mask = sc_access[1].mask = MASK7;
+ sc_access[0].value = sc_access[1].value = 0x00;
+ sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 2);
+
+ }
+ pr_debug("sst: sfreq:%d,Register value = %x\n", sfreq, config1);
+
+ if (word_size == 24) {
+ sc_access[0].reg_addr = AUDIOPORT1;
+ sc_access[0].mask = MASK0|MASK1|MASK2|MASK3;
+ sc_access[0].value = 0xFB;
+
+
+ sc_access[1].reg_addr = AUDIOPORT2;
+ sc_access[1].value = config1 | 0x10;
+ sc_access[1].mask = MASK0 | MASK1 | MASK2 | MASK3
+ | MASK4 | MASK5 | MASK6;
+
+ sc_access[2].reg_addr = MISCAUDCTRL;
+ sc_access[2].value = 0x02;
+ sc_access[2].mask = 0x02;
+
+ num_value = 3 ;
+
+ } else {
+
+ sc_access[0].reg_addr = AUDIOPORT2;
+ sc_access[0].value = config1;
+ sc_access[0].mask = MASK0|MASK1|MASK2|MASK3;
+
+ sc_access[1].reg_addr = MISCAUDCTRL;
+ sc_access[1].value = 0x00;
+ sc_access[1].mask = 0x02;
+ num_value = 2;
+ }
+ return sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, num_value);
+
+}
+
+static int fs_set_selected_input_dev(u8 value)
+{
+ struct sc_reg_access sc_access_dmic[] = {
+ {MICCTRL, 0x81, 0xf7},
+ {MICLICTRL3, 0x00, 0xE0},
+ };
+ struct sc_reg_access sc_access_mic[] = {
+ {MICCTRL, 0x40, MASK2|MASK4|MASK5|MASK6|MASK7},
+ {MICLICTRL3, 0x00, 0xE0},
+ };
+ struct sc_reg_access sc_access_hsmic[] = {
+ {MICCTRL, 0x10, MASK2|MASK4|MASK5|MASK6|MASK7},
+ {MICLICTRL3, 0x00, 0xE0},
+ };
+
+ int retval = 0;
+
+ if (snd_pmic_ops_fs.card_status == SND_CARD_UN_INIT)
+ retval = fs_init_card();
+ if (retval)
+ return retval;
+
+ switch (value) {
+ case AMIC:
+ pr_debug("sst: Selecting amic not supported in mono cfg\n");
+ return sst_sc_reg_access(sc_access_mic, PMIC_READ_MODIFY, 2);
+ break;
+
+ case HS_MIC:
+ pr_debug("sst: Selecting hsmic\n");
+ return sst_sc_reg_access(sc_access_hsmic,
+ PMIC_READ_MODIFY, 2);
+ break;
+
+ case DMIC:
+ pr_debug("sst: Selecting dmic\n");
+ return sst_sc_reg_access(sc_access_dmic, PMIC_READ_MODIFY, 2);
+ break;
+
+ default:
+ return -EINVAL;
+
+ }
+}
+
+static int fs_set_selected_output_dev(u8 value)
+{
+ struct sc_reg_access sc_access_hp[] = {
+ {0x191, 0x11, 0x0},
+ {0x192, 0x0E, 0x0},
+ };
+ struct sc_reg_access sc_access_is[] = {
+ {0x191, 0x17, 0xFF},
+ {0x192, 0x08, 0xFF},
+ };
+ int retval = 0;
+
+ if (snd_pmic_ops_fs.card_status == SND_CARD_UN_INIT)
+ retval = fs_init_card();
+ if (retval)
+ return retval;
+
+ switch (value) {
+ case STEREO_HEADPHONE:
+ pr_debug("SST DBG:Selecting headphone\n");
+ return sst_sc_reg_access(sc_access_hp, PMIC_WRITE, 2);
+ break;
+ case MONO_EARPIECE:
+ case INTERNAL_SPKR:
+ pr_debug("SST DBG:Selecting internal spkr\n");
+ return sst_sc_reg_access(sc_access_is, PMIC_READ_MODIFY, 2);
+ break;
+
+ default:
+ return -EINVAL;
+
+ }
+}
+
+static int fs_set_mute(int dev_id, u8 value)
+{
+ struct sc_reg_access sc_access[6] = {{0,},};
+ int reg_num = 0;
+ int retval = 0;
+
+ if (snd_pmic_ops_fs.card_status == SND_CARD_UN_INIT)
+ retval = fs_init_card();
+ if (retval)
+ return retval;
+
+
+ pr_debug("sst: dev_id:0x%x value:0x%x\n", dev_id, value);
+ switch (dev_id) {
+ case PMIC_SND_DMIC_MUTE:
+ sc_access[0].reg_addr = MICCTRL;
+ sc_access[1].reg_addr = MICLICTRL1;
+ sc_access[2].reg_addr = MICLICTRL2;
+ sc_access[0].mask = MASK5;
+ sc_access[1].mask = sc_access[2].mask = MASK6;
+ if (value == MUTE) {
+ sc_access[0].value = 0x20;
+ sc_access[2].value = sc_access[1].value = 0x40;
+ } else
+ sc_access[0].value = sc_access[1].value
+ = sc_access[2].value = 0x0;
+ reg_num = 3;
+ break;
+ case PMIC_SND_HP_MIC_MUTE:
+ case PMIC_SND_AMIC_MUTE:
+ sc_access[0].reg_addr = MICLICTRL1;
+ sc_access[1].reg_addr = MICLICTRL2;
+ sc_access[0].mask = sc_access[1].mask = MASK6;
+ if (value == MUTE)
+ sc_access[0].value = sc_access[1].value = 0x40;
+ else
+ sc_access[0].value = sc_access[1].value = 0x0;
+ reg_num = 2;
+ break;
+ case PMIC_SND_LEFT_SPEAKER_MUTE:
+ case PMIC_SND_LEFT_HP_MUTE:
+ sc_access[0].reg_addr = AUD16;
+ sc_access[1].reg_addr = AUD15;
+
+ sc_access[0].mask = sc_access[1].mask = MASK7;
+ if (value == MUTE)
+ sc_access[0].value = sc_access[1].value = 0x80;
+ else
+ sc_access[0].value = sc_access[1].value = 0x0;
+ reg_num = 2;
+ snd_pmic_ops_fs.mute_status = value;
+ break;
+ case PMIC_SND_RIGHT_HP_MUTE:
+ case PMIC_SND_RIGHT_SPEAKER_MUTE:
+ sc_access[0].reg_addr = AUD17;
+ sc_access[1].reg_addr = AUD15;
+ sc_access[0].mask = sc_access[1].mask = MASK7;
+ if (value == MUTE)
+ sc_access[0].value = sc_access[1].value = 0x80;
+ else
+ sc_access[0].value = sc_access[1].value = 0x0;
+ snd_pmic_ops_fs.mute_status = value;
+ if (snd_pmic_ops_fs.num_channel == 1)
+ sc_access[0].value = sc_access[1].value = 0x80;
+ reg_num = 2;
+ break;
+ case PMIC_SND_MUTE_ALL:
+ sc_access[0].reg_addr = AUD16;
+ sc_access[1].reg_addr = AUD17;
+ sc_access[2].reg_addr = AUD15;
+ sc_access[3].reg_addr = MICCTRL;
+ sc_access[4].reg_addr = MICLICTRL1;
+ sc_access[5].reg_addr = MICLICTRL2;
+ sc_access[0].mask = sc_access[1].mask =
+ sc_access[2].mask = MASK7;
+ sc_access[3].mask = MASK5;
+ sc_access[4].mask = sc_access[5].mask = MASK6;
+
+ if (value == MUTE) {
+ sc_access[0].value =
+ sc_access[1].value = sc_access[2].value = 0x80;
+ sc_access[3].value = 0x20;
+ sc_access[4].value = sc_access[5].value = 0x40;
+
+ } else {
+ sc_access[0].value = sc_access[1].value =
+ sc_access[2].value = sc_access[3].value =
+ sc_access[4].value = sc_access[5].value = 0x0;
+ }
+ if (snd_pmic_ops_fs.num_channel == 1)
+ sc_access[1].value = sc_access[2].value = 0x80;
+ reg_num = 6;
+ snd_pmic_ops_fs.mute_status = value;
+ snd_pmic_ops_fs.master_mute = value;
+ break;
+
+ }
+ return sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, reg_num);
+}
+
+static int fs_set_vol(int dev_id, int value)
+{
+ struct sc_reg_access sc_acces, sc_access[4] = {{0},};
+ int reg_num = 0;
+ int retval = 0;
+
+ if (snd_pmic_ops_fs.card_status == SND_CARD_UN_INIT)
+ retval = fs_init_card();
+ if (retval)
+ return retval;
+
+ switch (dev_id) {
+ case PMIC_SND_LEFT_PB_VOL:
+ pr_debug("sst: PMIC_SND_LEFT_PB_VOL:%d\n", value);
+ sc_access[0].value = sc_access[1].value = value;
+ sc_access[0].reg_addr = AUD16;
+ sc_access[1].reg_addr = AUD15;
+ sc_access[0].mask = sc_access[1].mask =
+ (MASK0|MASK1|MASK2|MASK3|MASK4|MASK5);
+ reg_num = 2;
+ break;
+
+ case PMIC_SND_RIGHT_PB_VOL:
+ pr_debug("sst: PMIC_SND_RIGHT_PB_VOL:%d\n", value);
+ sc_access[0].value = sc_access[1].value = value;
+ sc_access[0].reg_addr = AUD17;
+ sc_access[1].reg_addr = AUD15;
+ sc_access[0].mask = sc_access[1].mask =
+ (MASK0|MASK1|MASK2|MASK3|MASK4|MASK5);
+ if (snd_pmic_ops_fs.num_channel == 1) {
+ sc_access[0].value = sc_access[1].value = 0x80;
+ sc_access[0].mask = sc_access[1].mask = MASK7;
+ }
+ reg_num = 2;
+ break;
+ case PMIC_SND_CAPTURE_VOL:
+ pr_debug("sst: PMIC_SND_CAPTURE_VOL:%d\n", value);
+ sc_access[0].reg_addr = MICLICTRL1;
+ sc_access[1].reg_addr = MICLICTRL2;
+ sc_access[2].reg_addr = DMICCTRL1;
+ sc_access[2].value = value;
+ sc_access[0].value = sc_access[1].value = value;
+ sc_acces.reg_addr = MICLICTRL3;
+ sc_acces.value = value;
+ sc_acces.mask = (MASK0|MASK1|MASK2|MASK3|MASK5|MASK6|MASK7);
+ retval = sst_sc_reg_access(&sc_acces, PMIC_READ_MODIFY, 1);
+ sc_access[0].mask = sc_access[1].mask =
+ sc_access[2].mask = (MASK0|MASK1|MASK2|MASK3|MASK4|MASK5);
+ reg_num = 3;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, reg_num);
+}
+
+static int fs_get_mute(int dev_id, u8 *value)
+{
+ struct sc_reg_access sc_access[6] = {{0,},};
+
+ int retval = 0, temp_value = 0, mask = 0;
+
+ if (snd_pmic_ops_fs.card_status == SND_CARD_UN_INIT)
+ retval = fs_init_card();
+ if (retval)
+ return retval;
+
+ switch (dev_id) {
+
+ case PMIC_SND_AMIC_MUTE:
+ case PMIC_SND_HP_MIC_MUTE:
+ sc_access[0].reg_addr = MICLICTRL1;
+ mask = MASK6;
+ retval = sst_sc_reg_access(sc_access, PMIC_READ, 1);
+ if (sc_access[0].value & mask)
+ *value = MUTE;
+ else
+ *value = UNMUTE;
+ break;
+ case PMIC_SND_DMIC_MUTE:
+ sc_access[0].reg_addr = MICCTRL;
+ mask = MASK5;
+ retval = sst_sc_reg_access(sc_access, PMIC_READ, 1);
+ temp_value = (sc_access[0].value & mask);
+ if (temp_value == 0)
+ *value = UNMUTE;
+ else
+ *value = MUTE;
+ break;
+
+ case PMIC_SND_LEFT_HP_MUTE:
+ case PMIC_SND_LEFT_SPEAKER_MUTE:
+ sc_access[0].reg_addr = AUD16;
+ mask = MASK7;
+ retval = sst_sc_reg_access(sc_access, PMIC_READ, 1);
+ temp_value = sc_access[0].value & mask;
+ if (temp_value == 0)
+ *value = UNMUTE;
+ else
+ *value = MUTE;
+ break;
+ case PMIC_SND_RIGHT_HP_MUTE:
+ case PMIC_SND_RIGHT_SPEAKER_MUTE:
+ sc_access[0].reg_addr = AUD17;
+ mask = MASK7;
+ retval = sst_sc_reg_access(sc_access, PMIC_READ, 1);
+ temp_value = sc_access[0].value & mask;
+ if (temp_value == 0)
+ *value = UNMUTE;
+ else
+ *value = MUTE;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return retval;
+}
+
+static int fs_get_vol(int dev_id, int *value)
+{
+ struct sc_reg_access sc_access = {0,};
+ int retval = 0, mask = 0;
+
+ if (snd_pmic_ops_fs.card_status == SND_CARD_UN_INIT)
+ retval = fs_init_card();
+ if (retval)
+ return retval;
+
+ switch (dev_id) {
+ case PMIC_SND_CAPTURE_VOL:
+ pr_debug("sst: PMIC_SND_CAPTURE_VOL\n");
+ sc_access.reg_addr = MICLICTRL1;
+ mask = (MASK5|MASK4|MASK3|MASK2|MASK1|MASK0);
+ break;
+ case PMIC_SND_LEFT_PB_VOL:
+ pr_debug("sst: PMIC_SND_LEFT_PB_VOL\n");
+ sc_access.reg_addr = AUD16;
+ mask = (MASK5|MASK4|MASK3|MASK2|MASK1|MASK0);
+ break;
+ case PMIC_SND_RIGHT_PB_VOL:
+ pr_debug("sst: PMIC_SND_RT_PB_VOL\n");
+ sc_access.reg_addr = AUD17;
+ mask = (MASK5|MASK4|MASK3|MASK2|MASK1|MASK0);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ retval = sst_sc_reg_access(&sc_access, PMIC_READ, 1);
+ pr_debug("sst: value read = 0x%x\n", sc_access.value);
+ *value = (int) (sc_access.value & mask);
+ pr_debug("sst: value returned = 0x%x\n", *value);
+ return retval;
+}
+
+struct snd_pmic_ops snd_pmic_ops_fs = {
+ .set_input_dev = fs_set_selected_input_dev,
+ .set_output_dev = fs_set_selected_output_dev,
+ .set_mute = fs_set_mute,
+ .get_mute = fs_get_mute,
+ .set_vol = fs_set_vol,
+ .get_vol = fs_get_vol,
+ .init_card = fs_init_card,
+ .set_pcm_audio_params = fs_set_pcm_audio_params,
+ .set_pcm_voice_params = fs_set_pcm_voice_params,
+ .set_voice_port = fs_set_voice_port,
+ .set_audio_port = fs_set_audio_port,
+ .power_up_pmic_pb = fs_power_up_pb,
+ .power_up_pmic_cp = fs_power_up_cp,
+ .power_down_pmic_pb = fs_power_down_pb,
+ .power_down_pmic_cp = fs_power_down_cp,
+ .power_down_pmic = fs_power_down,
+};
diff --git a/drivers/staging/intel_sst/intelmid_v1_control.c b/drivers/staging/intel_sst/intelmid_v1_control.c
new file mode 100644
index 0000000..94d30a9
--- /dev/null
+++ b/drivers/staging/intel_sst/intelmid_v1_control.c
@@ -0,0 +1,1072 @@
+/* intel_sst_v1_control.c - Intel SST Driver for audio engine
+ *
+ * Copyright (C) 2008-10 Intel Corp
+ * Authors: Vinod Koul <vinod.koul(a)intel.com>
+ * Harsha Priya <priya.harsha(a)intel.com>
+ * Dharageswari R <dharageswari.r(a)intel.com>
+ * KP Jeeja <jeeja.kp(a)intel.com>
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This file contains the control operations of vendor 2
+ */
+
+#include <linux/pci.h>
+#include <linux/file.h>
+#include <asm/mrst.h>
+#include <sound/pcm.h>
+#include "jack.h"
+#include <sound/pcm_params.h>
+#include <sound/control.h>
+#include <sound/initval.h>
+#include "intel_sst.h"
+#include "intel_sst_ioctl.h"
+#include "intelmid.h"
+#include "intelmid_snd_control.h"
+
+#include <linux/gpio.h>
+#define KOSKI_VOICE_CODEC_ENABLE 46
+
+enum _reg_v2 {
+
+ MASTER_CLOCK_PRESCALAR = 0x205,
+ SET_MASTER_AND_LR_CLK1 = 0x20b,
+ SET_MASTER_AND_LR_CLK2 = 0x20c,
+ MASTER_MODE_AND_DATA_DELAY = 0x20d,
+ DIGITAL_INTERFACE_TO_DAI2 = 0x20e,
+ CLK_AND_FS1 = 0x208,
+ CLK_AND_FS2 = 0x209,
+ DAI2_TO_DAC_HP = 0x210,
+ HP_OP_SINGLE_ENDED = 0x224,
+ ENABLE_OPDEV_CTRL = 0x226,
+ ENABLE_DEV_AND_USE_XTAL = 0x227,
+
+ /* Max audio subsystem (PQ49) MAX 8921 */
+ AS_IP_MODE_CTL = 0xF9,
+ AS_LEFT_SPKR_VOL_CTL = 0xFA, /* Mono Earpiece volume control */
+ AS_RIGHT_SPKR_VOL_CTL = 0xFB,
+ AS_LEFT_HP_VOL_CTL = 0xFC,
+ AS_RIGHT_HP_VOL_CTL = 0xFD,
+ AS_OP_MIX_CTL = 0xFE,
+ AS_CONFIG = 0xFF,
+
+ /* Headphone volume control & mute registers */
+ VOL_CTRL_LT = 0x21c,
+ VOL_CTRL_RT = 0x21d,
+
+};
+/**
+ * mx_init_card - initilize the sound card
+ *
+ * This initilizes the audio paths to know values in case of this sound card
+ */
+static int mx_init_card(void)
+{
+ if (is_aava()) {
+
+ struct sc_reg_access sc_access[] = {
+ {0x200, 0x00, 0x0},
+ {0x201, 0xC0, 0x0},
+ {0x202, 0x00, 0x0},
+ {0x203, 0x00, 0x0},
+ {0x204, 0x0e, 0x0},
+ {0x205, 0x20, 0x0},
+ {0x206, 0x00, 0x0},
+ {0x207, 0x00, 0x0},
+ {0x208, 0x00, 0x0},
+ {0x209, 0x51, 0x0},
+ {0x20a, 0x00, 0x0},
+ {0x20b, 0x5a, 0x0},
+ {0x20c, 0xbe, 0x0},
+ {0x20d, 0x90, 0x0},
+ {0x20e, 0x51, 0x0},
+ {0x20f, 0x00, 0x0},
+ {0x210, 0x21, 0x0},
+ {0x211, 0x00, 0x0},
+ {0x212, 0x00, 0x0},
+ {0x213, 0x00, 0x0},
+ {0x214, 0x41, 0x0},
+ {0x215, 0x81, 0x0},
+ {0x216, 0x00, 0x0},
+ {0x217, 0x00, 0x0},
+ {0x218, 0x00, 0x0},
+ {0x219, 0x00, 0x0},
+ {0x21a, 0x00, 0x0},
+ {0x21b, 0x00, 0x0},
+ {0x21c, 0x00, 0x0},
+ {0x21d, 0x00, 0x0},
+ {0x21e, 0x00, 0x0},
+ {0x21f, 0x00, 0x0},
+ {0x220, 0x00, 0x0},
+ {0x221, 0x00, 0x0},
+ {0x222, 0x51, 0x0},
+ {0x223, 0x20, 0x0}, /* Jack detection: 00 -> 01 */
+ {0x224, 0x40, 0x0},
+ {0x225, 0x80, 0x0}, /* JAck detection: 00 -> 80 */
+ {0x226, 0x00, 0x0},
+ {0x227, 0x00, 0x0},
+ {0xf9, 0x40, 0x0},
+ {0xfa, 0x1F, 0x0},
+ {0xfb, 0x1F, 0x0},
+ {0xfc, 0x1F, 0x0},
+ {0xfd, 0x1F, 0x0},
+ {0xfe, 0x00, 0x0},
+ {0xff, 0x00, 0x0}, /* Removed sel_output */
+ };
+ int retval;
+
+ /*init clock sig to voice codec*/
+ retval = gpio_request(KOSKI_VOICE_CODEC_ENABLE,
+ "sound_voice_codec");
+ if (retval) {
+ pr_err("sst: Error enabling voice codec clock\n");
+ } else {
+ gpio_direction_output(KOSKI_VOICE_CODEC_ENABLE, 1);
+ pr_debug("sst: Voice codec clock enabled\n");
+ }
+
+ snd_pmic_ops_mx.card_status = SND_CARD_INIT_DONE;
+ snd_pmic_ops_mx.master_mute = UNMUTE;
+ snd_pmic_ops_mx.mute_status = UNMUTE;
+ snd_pmic_ops_mx.num_channel = 2;
+ pr_debug("**************inside aava\n");
+ return sst_sc_reg_access(sc_access, PMIC_WRITE, 47);
+ } else {
+ struct sc_reg_access sc_access[] = {
+ {0x200, 0x80, 0x00},
+ {0x201, 0xC0, 0x00},
+ {0x202, 0x00, 0x00},
+ {0x203, 0x00, 0x00},
+ {0x204, 0x02, 0x00},
+ {0x205, 0x10, 0x00},
+ {0x206, 0x60, 0x00},
+ {0x207, 0x00, 0x00},
+ {0x208, 0x90, 0x00},
+ {0x209, 0x51, 0x00},
+ {0x20a, 0x00, 0x00},
+ {0x20b, 0x10, 0x00},
+ {0x20c, 0x00, 0x00},
+ {0x20d, 0x00, 0x00},
+ {0x20e, 0x21, 0x00},
+ {0x20f, 0x00, 0x00},
+ {0x210, 0x84, 0x00},
+ {0x211, 0xB3, 0x00},
+ {0x212, 0x00, 0x00},
+ {0x213, 0x00, 0x00},
+ {0x214, 0x41, 0x00},
+ {0x215, 0x00, 0x00},
+ {0x216, 0x00, 0x00},
+ {0x217, 0x00, 0x00},
+ {0x218, 0x03, 0x00},
+ {0x219, 0x03, 0x00},
+ {0x21a, 0x00, 0x00},
+ {0x21b, 0x00, 0x00},
+ {0x21c, 0x00, 0x00},
+ {0x21d, 0x00, 0x00},
+ {0x21e, 0x00, 0x00},
+ {0x21f, 0x00, 0x00},
+ {0x220, 0x20, 0x00},
+ {0x221, 0x20, 0x00},
+ {0x222, 0x51, 0x00},
+ {0x223, 0x20, 0x00},
+ {0x224, 0x04, 0x00},
+ {0x225, 0x80, 0x00},
+ {0x226, 0x0F, 0x00},
+ {0x227, 0x08, 0x00},
+ {0xf9, 0x40, 0x00},
+ {0xfa, 0x1f, 0x00},
+ {0xfb, 0x1f, 0x00},
+ {0xfc, 0x1f, 0x00},
+ {0xfd, 0x1f, 0x00},
+ {0xfe, 0x00, 0x00},
+ {0xff, 0x0c, 0x00},
+ };
+ snd_pmic_ops_mx.card_status = SND_CARD_INIT_DONE;
+ snd_pmic_ops_mx.num_channel = 2;
+ snd_pmic_ops_mx.master_mute = UNMUTE;
+ snd_pmic_ops_mx.mute_status = UNMUTE;
+ return sst_sc_reg_access(sc_access, PMIC_WRITE, 47);
+ }
+}
+
+static int mx_init_capture_card(void)
+{
+ struct sc_reg_access sc_access[] = {
+ {0x206, 0x5a, 0x0},
+ {0x207, 0xbe, 0x0},
+ {0x208, 0x90, 0x0},
+ {0x209, 0x32, 0x0},
+ {0x20e, 0x22, 0x0},
+ {0x210, 0x84, 0x0},
+ {0x223, 0x20, 0x0},
+ {0x226, 0xC0, 0x0},
+ };
+
+ int retval = 0;
+
+ retval = sst_sc_reg_access(sc_access, PMIC_WRITE, 8);
+ if (0 != retval) {
+ /* pmic communication fails */
+ pr_debug("sst: pmic commn failed\n");
+ return retval;
+ }
+
+ pr_debug("sst: Capture configuration complete!!\n");
+ return 0;
+}
+
+static int mx_init_playback_card(void)
+{
+ struct sc_reg_access sc_access[] = {
+ {0x206, 0x00, 0x0},
+ {0x207, 0x00, 0x0},
+ {0x208, 0x00, 0x0},
+ {0x209, 0x51, 0x0},
+ {0x20e, 0x51, 0x0},
+ {0x210, 0x21, 0x0},
+ {0x223, 0x01, 0x0},
+ };
+ int retval = 0;
+
+ retval = sst_sc_reg_access(sc_access, PMIC_WRITE, 9);
+ if (0 != retval) {
+ /* pmic communication fails */
+ pr_debug("sst: pmic commn failed\n");
+ return retval;
+ }
+
+ pr_debug("sst: Playback configuration complete!!\n");
+ return 0;
+}
+
+static int mx_enable_audiodac(int value)
+{
+ struct sc_reg_access sc_access[3];
+ int mute_val = 0;
+ int mute_val1 = 0;
+ int retval = 0;
+
+ sc_access[0].reg_addr = AS_LEFT_HP_VOL_CTL;
+ sc_access[1].reg_addr = AS_RIGHT_HP_VOL_CTL;
+
+ if (value == UNMUTE) {
+ mute_val = 0x1F;
+ mute_val1 = 0x00;
+ } else {
+ mute_val = 0x00;
+ mute_val1 = 0x40;
+ }
+ sc_access[0].mask = sc_access[1].mask = MASK0|MASK1|MASK2|MASK3|MASK4;
+ sc_access[0].value = sc_access[1].value = (u8)mute_val;
+ retval = sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 2);
+ if (retval)
+ return retval;
+ pr_debug("sst: mute status = %d", snd_pmic_ops_mx.mute_status);
+ if (snd_pmic_ops_mx.mute_status == MUTE ||
+ snd_pmic_ops_mx.master_mute == MUTE)
+ return retval;
+
+ sc_access[0].reg_addr = VOL_CTRL_LT;
+ sc_access[1].reg_addr = VOL_CTRL_RT;
+ sc_access[0].mask = sc_access[1].mask = MASK6;
+ sc_access[0].value = sc_access[1].value = mute_val1;
+ if (snd_pmic_ops_mx.num_channel == 1)
+ sc_access[1].value = 0x40;
+ return sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 2);
+}
+
+static int mx_power_up_pb(unsigned int port)
+{
+
+ int retval = 0;
+ struct sc_reg_access sc_access[3];
+
+ if (snd_pmic_ops_mx.card_status == SND_CARD_UN_INIT) {
+ retval = mx_init_card();
+ if (retval)
+ return retval;
+ }
+ if ((is_aava()) && port == 1)
+ mx_init_playback_card();
+ retval = mx_enable_audiodac(MUTE);
+ if (retval)
+ return retval;
+
+ msleep(10);
+
+ sc_access[0].reg_addr = AS_CONFIG;
+ sc_access[0].mask = MASK7;
+ sc_access[0].value = 0x80;
+ retval = sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 1);
+ if (retval)
+ return retval;
+
+ sc_access[0].reg_addr = ENABLE_OPDEV_CTRL;
+ sc_access[0].mask = 0xff;
+ sc_access[0].value = 0x3C;
+ retval = sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 1);
+ if (retval)
+ return retval;
+
+ sc_access[0].reg_addr = ENABLE_DEV_AND_USE_XTAL;
+ sc_access[0].mask = 0x80;
+ sc_access[0].value = 0x80;
+ retval = sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 1);
+ if (retval)
+ return retval;
+
+ return mx_enable_audiodac(UNMUTE);
+}
+
+static int mx_power_down_pb(void)
+{
+ struct sc_reg_access sc_access[3];
+ int retval = 0;
+
+ if (snd_pmic_ops_mx.card_status == SND_CARD_UN_INIT) {
+ retval = mx_init_card();
+ if (retval)
+ return retval;
+ }
+
+ retval = mx_enable_audiodac(MUTE);
+ if (retval)
+ return retval;
+
+ sc_access[0].reg_addr = ENABLE_OPDEV_CTRL;
+ sc_access[0].mask = MASK3|MASK2;
+ sc_access[0].value = 0x00;
+
+ retval = sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 1);
+ if (retval)
+ return retval;
+
+ return mx_enable_audiodac(UNMUTE);
+}
+
+static int mx_power_up_cp(unsigned int port)
+{
+ int retval = 0;
+ struct sc_reg_access sc_access[] = {
+ {ENABLE_DEV_AND_USE_XTAL, 0x80, MASK7},
+ {ENABLE_OPDEV_CTRL, 0x3, 0x3},
+ };
+
+ if (snd_pmic_ops_mx.card_status == SND_CARD_UN_INIT) {
+ retval = mx_init_card();
+ if (retval)
+ return retval;
+ }
+
+ if (is_aava()) {
+ retval = mx_init_capture_card();
+ if (retval)
+ return retval;
+ return sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 1);
+ } else
+ return sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 2);
+}
+
+static int mx_power_down_cp(void)
+{
+ struct sc_reg_access sc_access[] = {
+ {ENABLE_OPDEV_CTRL, 0x00, MASK1|MASK0},
+ };
+ int retval = 0;
+
+ if (snd_pmic_ops_mx.card_status == SND_CARD_UN_INIT) {
+ retval = mx_init_card();
+ if (retval)
+ return retval;
+ }
+
+ return sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 1);
+}
+
+static int mx_power_down(void)
+{
+ int retval = 0;
+ struct sc_reg_access sc_access[3];
+
+ if (snd_pmic_ops_mx.card_status == SND_CARD_UN_INIT) {
+ retval = mx_init_card();
+ if (retval)
+ return retval;
+ }
+
+ retval = mx_enable_audiodac(MUTE);
+ if (retval)
+ return retval;
+
+ sc_access[0].reg_addr = AS_CONFIG;
+ sc_access[0].mask = MASK7;
+ sc_access[0].value = 0x00;
+ retval = sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 1);
+ if (retval)
+ return retval;
+
+ sc_access[0].reg_addr = ENABLE_DEV_AND_USE_XTAL;
+ sc_access[0].mask = MASK7;
+ sc_access[0].value = 0x00;
+ retval = sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 1);
+ if (retval)
+ return retval;
+
+ sc_access[0].reg_addr = ENABLE_OPDEV_CTRL;
+ sc_access[0].mask = MASK3|MASK2;
+ sc_access[0].value = 0x00;
+ retval = sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 1);
+ if (retval)
+ return retval;
+
+ return mx_enable_audiodac(UNMUTE);
+}
+
+static int mx_set_pcm_voice_params(void)
+{
+ int retval = 0;
+ struct sc_reg_access sc_access[] = {
+ {0x200, 0x80, 0x00},
+ {0x201, 0xC0, 0x00},
+ {0x202, 0x00, 0x00},
+ {0x203, 0x00, 0x00},
+ {0x204, 0x0e, 0x00},
+ {0x205, 0x20, 0x00},
+ {0x206, 0x8f, 0x00},
+ {0x207, 0x21, 0x00},
+ {0x208, 0x18, 0x00},
+ {0x209, 0x32, 0x00},
+ {0x20a, 0x00, 0x00},
+ {0x20b, 0x5A, 0x00},
+ {0x20c, 0xBE, 0x00},/* 0x00 -> 0xBE Koski */
+ {0x20d, 0x00, 0x00}, /* DAI2 'off' */
+ {0x20e, 0x40, 0x00},
+ {0x20f, 0x00, 0x00},
+ {0x210, 0x84, 0x00},
+ {0x211, 0x33, 0x00}, /* Voice filter */
+ {0x212, 0x00, 0x00},
+ {0x213, 0x00, 0x00},
+ {0x214, 0x41, 0x00},
+ {0x215, 0x00, 0x00},
+ {0x216, 0x00, 0x00},
+ {0x217, 0x20, 0x00},
+ {0x218, 0x00, 0x00},
+ {0x219, 0x00, 0x00},
+ {0x21a, 0x40, 0x00},
+ {0x21b, 0x40, 0x00},
+ {0x21c, 0x09, 0x00},
+ {0x21d, 0x09, 0x00},
+ {0x21e, 0x00, 0x00},
+ {0x21f, 0x00, 0x00},
+ {0x220, 0x00, 0x00}, /* Microphone configurations */
+ {0x221, 0x00, 0x00}, /* Microphone configurations */
+ {0x222, 0x50, 0x00}, /* Microphone configurations */
+ {0x223, 0x21, 0x00}, /* Microphone configurations */
+ {0x224, 0x00, 0x00},
+ {0x225, 0x80, 0x00},
+ {0xf9, 0x40, 0x00},
+ {0xfa, 0x19, 0x00},
+ {0xfb, 0x19, 0x00},
+ {0xfc, 0x12, 0x00},
+ {0xfd, 0x12, 0x00},
+ {0xfe, 0x00, 0x00},
+ };
+
+ if (snd_pmic_ops_mx.card_status == SND_CARD_UN_INIT) {
+ retval = mx_init_card();
+ if (retval)
+ return retval;
+ }
+ pr_debug("sst: SST DBG mx_set_pcm_voice_params called\n");
+ return sst_sc_reg_access(sc_access, PMIC_WRITE, 44);
+}
+
+static int mx_set_pcm_audio_params(int sfreq, int word_size, int num_channel)
+{
+ int retval = 0;
+
+ if (!is_aava()) {
+ int config1 = 0, config2 = 0, filter = 0xB3;
+ struct sc_reg_access sc_access[5];
+
+ if (snd_pmic_ops_mx.card_status == SND_CARD_UN_INIT) {
+ retval = mx_init_card();
+ if (retval)
+ return retval;
+ }
+
+ switch (sfreq) {
+ case 8000:
+ config1 = 0x10;
+ config2 = 0x00;
+ filter = 0x33;
+ break;
+ case 11025:
+ config1 = 0x16;
+ config2 = 0x0d;
+ break;
+ case 12000:
+ config1 = 0x18;
+ config2 = 0x00;
+ break;
+ case 16000:
+ config1 = 0x20;
+ config2 = 0x00;
+ break;
+ case 22050:
+ config1 = 0x2c;
+ config2 = 0x1a;
+ break;
+ case 24000:
+ config1 = 0x30;
+ config2 = 0x00;
+ break;
+ case 32000:
+ config1 = 0x40;
+ config2 = 0x00;
+ break;
+ case 44100:
+ config1 = 0x58;
+ config2 = 0x33;
+ break;
+ case 48000:
+ config1 = 0x60;
+ config2 = 0x00;
+ break;
+ }
+
+ snd_pmic_ops_mx.num_channel = num_channel;
+ /*mute the right channel if MONO*/
+ if (snd_pmic_ops_mx.num_channel == 1) {
+
+ sc_access[0].reg_addr = VOL_CTRL_RT;
+ sc_access[0].value = 0x40;
+ sc_access[0].mask = MASK6;
+
+ sc_access[1].reg_addr = 0x224;
+ sc_access[1].value = 0x05;
+ sc_access[1].mask = MASK0|MASK1|MASK2;
+
+ retval = sst_sc_reg_access(sc_access,
+ PMIC_READ_MODIFY, 2);
+ if (retval)
+ return retval;
+ } else {
+ sc_access[0].reg_addr = VOL_CTRL_RT;
+ sc_access[0].value = 0x00;
+ sc_access[0].mask = MASK6;
+
+ sc_access[1].reg_addr = 0x224;
+ sc_access[1].value = 0x04;
+ sc_access[1].mask = MASK0|MASK1|MASK2;
+
+ retval = sst_sc_reg_access(sc_access,
+ PMIC_READ_MODIFY, 2);
+ if (retval)
+ return retval;
+ }
+ sc_access[0].reg_addr = 0x206;
+ sc_access[0].value = config1;
+ sc_access[1].reg_addr = 0x207;
+ sc_access[1].value = config2;
+
+ if (word_size == 16) {
+ sc_access[2].value = 0x51;
+ sc_access[3].value = 0x31;
+ } else if (word_size == 24) {
+ sc_access[2].value = 0x52;
+ sc_access[3].value = 0x92;
+ }
+
+ sc_access[2].reg_addr = 0x209;
+ sc_access[3].reg_addr = 0x20e;
+
+ sc_access[4].reg_addr = 0x211;
+ sc_access[4].value = filter;
+
+ return sst_sc_reg_access(sc_access, PMIC_WRITE, 5);
+ } else {
+ int config1 = 0, config2 = 0, filter = 0x00;
+ struct sc_reg_access sc_access[5];
+
+ pr_debug("sst: mx_set_pcm_audio_params - inside AAVA\n");
+
+ if (snd_pmic_ops_mx.card_status == SND_CARD_UN_INIT) {
+ retval = mx_init_card();
+ if (retval)
+ return retval;
+ }
+
+ switch (sfreq) {
+ case 8000:
+ config1 = 0x20;
+ config2 = 0x0f;
+ filter = 0x33;
+ break;
+ case 11025:
+ config1 = 0x14;
+ config2 = 0xd8;
+ break;
+ case 12000:
+ config1 = 0x16;
+ config2 = 0xaf;
+ break;
+ case 16000:
+ config1 = 0x1e;
+ config2 = 0x3f;
+ break;
+ case 22050:
+ config1 = 0x29;
+ config2 = 0xaf;
+ break;
+ case 24000:
+ config1 = 0x2d;
+ config2 = 0x5f;
+ break;
+ case 32000:
+ config1 = 0x3c;
+ config2 = 0x7f;
+ break;
+ case 44100:
+ config1 = 0x53;
+ config2 = 0x5f;
+ break;
+ case 48000:
+ config1 = 0x5a;
+ config2 = 0xbe;
+ break;
+ }
+
+ snd_pmic_ops_mx.num_channel = num_channel;
+ /*mute the right channel if MONO*/
+ sc_access[0].reg_addr = 0x20b;
+ sc_access[0].value = config1;
+ sc_access[1].reg_addr = 0x20c;
+ sc_access[1].value = config2;
+ if (word_size == 16) {
+ sc_access[2].value = 0x51;
+ sc_access[3].value = 0x51;
+ } else if (word_size == 24) {
+ sc_access[2].value = 0x52;
+ sc_access[3].value = 0x92;
+
+ }
+
+ sc_access[2].reg_addr = 0x209;
+ sc_access[3].reg_addr = 0x20e;
+ sc_access[4].reg_addr = 0x211;
+ sc_access[4].value = filter;
+
+ return sst_sc_reg_access(sc_access, PMIC_WRITE, 5);
+ }
+ return 0;
+}
+
+static int mx_set_selected_output_dev(u8 dev_id)
+{
+ struct sc_reg_access sc_access[2];
+ int num_reg = 0;
+ int retval = 0;
+
+ if (snd_pmic_ops_mx.card_status == SND_CARD_UN_INIT) {
+ retval = mx_init_card();
+ if (retval)
+ return retval;
+ }
+
+ pr_debug("sst: mx_set_selected_output_dev dev_id:0x%x\n", dev_id);
+ snd_pmic_ops_mx.output_dev_id = dev_id;
+ switch (dev_id) {
+ case STEREO_HEADPHONE:
+ sc_access[0].reg_addr = 0xFF;
+ sc_access[0].value = 0x8C;
+ sc_access[0].mask =
+ MASK2|MASK3|MASK5|MASK6|MASK4;
+
+ num_reg = 1;
+ break;
+ case MONO_EARPIECE:
+ case INTERNAL_SPKR:
+ sc_access[0].reg_addr = 0xFF;
+ sc_access[0].value = 0xb0;
+ sc_access[0].mask = MASK2|MASK3|MASK5|MASK6|MASK4;
+
+ num_reg = 1;
+ break;
+ case RECEIVER:
+ pr_debug("sst: RECEIVER Koski selected\n");
+
+ /* configuration - AS enable, receiver enable */
+ sc_access[0].reg_addr = 0xFF;
+ sc_access[0].value = 0x81;
+ sc_access[0].mask = 0xff;
+
+ num_reg = 1;
+ break;
+ default:
+ pr_err("sst: Not a valid output dev\n");
+ return 0;
+ }
+ return sst_sc_reg_access(sc_access, PMIC_WRITE, num_reg);
+}
+
+
+static int mx_set_voice_port(int status)
+{
+ int retval = 0;
+
+ if (snd_pmic_ops_mx.card_status == SND_CARD_UN_INIT) {
+ retval = mx_init_card();
+ if (retval)
+ return retval;
+ }
+ if (status == ACTIVATE)
+ retval = mx_set_pcm_voice_params();
+
+ return retval;
+}
+
+static int mx_set_audio_port(int status)
+{
+ int retval = 0;
+ if (is_aava()) {
+ if (snd_pmic_ops_mx.card_status == SND_CARD_UN_INIT)
+ retval = mx_init_card();
+ if (retval)
+ return retval;
+ if (status == ACTIVATE) {
+ mx_init_card();
+ mx_set_selected_output_dev
+ (snd_pmic_ops_mx.output_dev_id);
+ }
+ }
+ return retval;
+
+}
+
+static int mx_set_selected_input_dev(u8 dev_id)
+{
+ struct sc_reg_access sc_access[2];
+ int num_reg = 0;
+ int retval = 0;
+
+ if (snd_pmic_ops_mx.card_status == SND_CARD_UN_INIT) {
+ retval = mx_init_card();
+ if (retval)
+ return retval;
+ }
+ snd_pmic_ops_mx.input_dev_id = dev_id;
+ pr_debug("sst: mx_set_selected_input_dev dev_id:0x%x\n", dev_id);
+
+ switch (dev_id) {
+ case AMIC:
+ sc_access[0].reg_addr = 0x223;
+ sc_access[0].value = 0x00;
+ sc_access[0].mask = MASK7|MASK6|MASK5|MASK4|MASK0;
+ sc_access[1].reg_addr = 0x222;
+ sc_access[1].value = 0x50;
+ sc_access[1].mask = MASK7|MASK6|MASK5|MASK4;
+ num_reg = 2;
+ break;
+
+ case HS_MIC:
+ sc_access[0].reg_addr = 0x223;
+ sc_access[0].value = 0x20;
+ sc_access[0].mask = MASK7|MASK6|MASK5|MASK4|MASK0;
+ sc_access[1].reg_addr = 0x222;
+ sc_access[1].value = 0x51;
+ sc_access[1].mask = MASK7|MASK6|MASK5|MASK4;
+ num_reg = 2;
+ break;
+ case DMIC:
+ sc_access[1].reg_addr = 0x222;
+ sc_access[1].value = 0x00;
+ sc_access[1].mask = MASK7|MASK6|MASK5|MASK4|MASK0;
+ sc_access[0].reg_addr = 0x223;
+ sc_access[0].value = 0x20;
+ sc_access[0].mask = MASK7|MASK6|MASK5|MASK4|MASK0;
+ num_reg = 2;
+ break;
+ }
+ return sst_sc_reg_access(sc_access, PMIC_WRITE, num_reg);
+}
+
+static int mx_set_mute(int dev_id, u8 value)
+{
+ struct sc_reg_access sc_access[5];
+ int num_reg = 0;
+ int retval = 0;
+
+ if (snd_pmic_ops_mx.card_status == SND_CARD_UN_INIT) {
+ retval = mx_init_card();
+ if (retval)
+ return retval;
+ }
+
+
+ pr_debug("sst: set_mute dev_id:0x%x , value:%d\n", dev_id, value);
+
+ switch (dev_id) {
+ case PMIC_SND_DMIC_MUTE:
+ case PMIC_SND_AMIC_MUTE:
+ case PMIC_SND_HP_MIC_MUTE:
+ sc_access[0].reg_addr = 0x220;
+ sc_access[1].reg_addr = 0x221;
+ sc_access[2].reg_addr = 0x223;
+ if (value == MUTE) {
+ sc_access[0].value = 0x00;
+ sc_access[1].value = 0x00;
+ if (snd_pmic_ops_mx.input_dev_id == DMIC)
+ sc_access[2].value = 0x00;
+ else
+ sc_access[2].value = 0x20;
+ } else {
+ sc_access[0].value = 0x20;
+ sc_access[1].value = 0x20;
+ if (snd_pmic_ops_mx.input_dev_id == DMIC)
+ sc_access[2].value = 0x20;
+ else
+ sc_access[2].value = 0x00;
+ }
+ sc_access[0].mask = MASK5|MASK6;
+ sc_access[1].mask = MASK5|MASK6;
+ sc_access[2].mask = MASK5|MASK6;
+ num_reg = 3;
+ break;
+ case PMIC_SND_LEFT_SPEAKER_MUTE:
+ case PMIC_SND_LEFT_HP_MUTE:
+ sc_access[0].reg_addr = VOL_CTRL_LT;
+ if (value == MUTE)
+ sc_access[0].value = 0x40;
+ else
+ sc_access[0].value = 0x00;
+ sc_access[0].mask = MASK6;
+ num_reg = 1;
+ snd_pmic_ops_mx.mute_status = value;
+ break;
+ case PMIC_SND_RIGHT_SPEAKER_MUTE:
+ case PMIC_SND_RIGHT_HP_MUTE:
+ sc_access[0].reg_addr = VOL_CTRL_RT;
+ if (snd_pmic_ops_mx.num_channel == 1)
+ value = MUTE;
+ if (value == MUTE)
+ sc_access[0].value = 0x40;
+ else
+ sc_access[0].value = 0x00;
+ sc_access[0].mask = MASK6;
+ num_reg = 1;
+ snd_pmic_ops_mx.mute_status = value;
+ break;
+ case PMIC_SND_MUTE_ALL:
+ sc_access[0].reg_addr = VOL_CTRL_RT;
+ sc_access[1].reg_addr = VOL_CTRL_LT;
+ sc_access[2].reg_addr = 0x220;
+ sc_access[3].reg_addr = 0x221;
+ sc_access[4].reg_addr = 0x223;
+ snd_pmic_ops_mx.master_mute = value;
+ if (value == MUTE) {
+ sc_access[0].value = sc_access[1].value = 0x40;
+ sc_access[2].value = 0x00;
+ sc_access[3].value = 0x00;
+ if (snd_pmic_ops_mx.input_dev_id == DMIC)
+ sc_access[4].value = 0x00;
+ else
+ sc_access[4].value = 0x20;
+
+ } else {
+ sc_access[0].value = sc_access[1].value = 0x00;
+ sc_access[2].value = sc_access[3].value = 0x20;
+ sc_access[4].value = 0x20;
+ if (snd_pmic_ops_mx.input_dev_id == DMIC)
+ sc_access[4].value = 0x20;
+ else
+ sc_access[4].value = 0x00;
+
+
+ }
+ if (snd_pmic_ops_mx.num_channel == 1)
+ sc_access[0].value = 0x40;
+ sc_access[0].mask = sc_access[1].mask = MASK6;
+ sc_access[2].mask = MASK5|MASK6;
+ sc_access[3].mask = MASK5|MASK6|MASK2|MASK4;
+ sc_access[4].mask = MASK5|MASK6|MASK4;
+
+ num_reg = 5;
+ break;
+ case PMIC_SND_RECEIVER_MUTE:
+ sc_access[0].reg_addr = VOL_CTRL_RT;
+ if (value == MUTE)
+ sc_access[0].value = 0x40;
+ else
+ sc_access[0].value = 0x00;
+ sc_access[0].mask = MASK6;
+ num_reg = 1;
+ break;
+ }
+
+ return sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, num_reg);
+}
+
+static int mx_set_vol(int dev_id, int value)
+{
+ struct sc_reg_access sc_access[2] = {{0},};
+ int num_reg = 0;
+ int retval = 0;
+
+ if (snd_pmic_ops_mx.card_status == SND_CARD_UN_INIT) {
+ retval = mx_init_card();
+ if (retval)
+ return retval;
+ }
+ pr_debug("sst: set_vol dev_id:0x%x ,value:%d\n", dev_id, value);
+ switch (dev_id) {
+ case PMIC_SND_RECEIVER_VOL:
+ return 0;
+ break;
+ case PMIC_SND_CAPTURE_VOL:
+ sc_access[0].reg_addr = 0x220;
+ sc_access[1].reg_addr = 0x221;
+ sc_access[0].value = sc_access[1].value = -value;
+ sc_access[0].mask = sc_access[1].mask =
+ (MASK0|MASK1|MASK2|MASK3|MASK4);
+ num_reg = 2;
+ break;
+ case PMIC_SND_LEFT_PB_VOL:
+ sc_access[0].value = -value;
+ sc_access[0].reg_addr = VOL_CTRL_LT;
+ sc_access[0].mask = (MASK0|MASK1|MASK2|MASK3|MASK4|MASK5);
+ num_reg = 1;
+ break;
+ case PMIC_SND_RIGHT_PB_VOL:
+ sc_access[0].value = -value;
+ sc_access[0].reg_addr = VOL_CTRL_RT;
+ sc_access[0].mask = (MASK0|MASK1|MASK2|MASK3|MASK4|MASK5);
+ if (snd_pmic_ops_mx.num_channel == 1) {
+ sc_access[0].value = 0x40;
+ sc_access[0].mask = MASK6;
+ sc_access[0].reg_addr = VOL_CTRL_RT;
+ }
+ num_reg = 1;
+ break;
+ }
+ return sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, num_reg);
+}
+
+static int mx_get_mute(int dev_id, u8 *value)
+{
+ struct sc_reg_access sc_access[4] = {{0},};
+ int retval = 0, num_reg = 0, mask = 0;
+
+ if (snd_pmic_ops_mx.card_status == SND_CARD_UN_INIT) {
+ retval = mx_init_card();
+ if (retval)
+ return retval;
+ }
+ switch (dev_id) {
+ case PMIC_SND_DMIC_MUTE:
+ case PMIC_SND_AMIC_MUTE:
+ case PMIC_SND_HP_MIC_MUTE:
+ sc_access[0].reg_addr = 0x220;
+ mask = MASK5|MASK6;
+ num_reg = 1;
+ retval = sst_sc_reg_access(sc_access, PMIC_READ, num_reg);
+ if (retval)
+ return retval;
+ *value = sc_access[0].value & mask;
+ if (*value)
+ *value = UNMUTE;
+ else
+ *value = MUTE;
+ return retval;
+ case PMIC_SND_LEFT_HP_MUTE:
+ case PMIC_SND_LEFT_SPEAKER_MUTE:
+ sc_access[0].reg_addr = VOL_CTRL_LT;
+ num_reg = 1;
+ mask = MASK6;
+ break;
+ case PMIC_SND_RIGHT_HP_MUTE:
+ case PMIC_SND_RIGHT_SPEAKER_MUTE:
+ sc_access[0].reg_addr = VOL_CTRL_RT;
+ num_reg = 1;
+ mask = MASK6;
+ break;
+ }
+ retval = sst_sc_reg_access(sc_access, PMIC_READ, num_reg);
+ if (retval)
+ return retval;
+ *value = sc_access[0].value & mask;
+ if (*value)
+ *value = MUTE;
+ else
+ *value = UNMUTE;
+ return retval;
+}
+
+static int mx_get_vol(int dev_id, int *value)
+{
+ struct sc_reg_access sc_access = {0,};
+ int retval = 0, mask = 0, num_reg = 0;
+
+ if (snd_pmic_ops_mx.card_status == SND_CARD_UN_INIT) {
+ retval = mx_init_card();
+ if (retval)
+ return retval;
+ }
+ switch (dev_id) {
+ case PMIC_SND_CAPTURE_VOL:
+ sc_access.reg_addr = 0x220;
+ mask = MASK0|MASK1|MASK2|MASK3|MASK4;
+ num_reg = 1;
+ break;
+ case PMIC_SND_LEFT_PB_VOL:
+ sc_access.reg_addr = VOL_CTRL_LT;
+ mask = MASK0|MASK1|MASK2|MASK3|MASK4|MASK5;
+ num_reg = 1;
+ break;
+ case PMIC_SND_RIGHT_PB_VOL:
+ sc_access.reg_addr = VOL_CTRL_RT;
+ mask = MASK0|MASK1|MASK2|MASK3|MASK4|MASK5;
+ num_reg = 1;
+ break;
+ }
+ retval = sst_sc_reg_access(&sc_access, PMIC_READ, num_reg);
+ if (retval)
+ return retval;
+ *value = -(sc_access.value & mask);
+ pr_debug("sst: get volume value extracted %d\n", *value);
+ return retval;
+}
+
+struct snd_pmic_ops snd_pmic_ops_mx = {
+ .set_input_dev = mx_set_selected_input_dev,
+ .set_output_dev = mx_set_selected_output_dev,
+ .set_mute = mx_set_mute,
+ .get_mute = mx_get_mute,
+ .set_vol = mx_set_vol,
+ .get_vol = mx_get_vol,
+ .init_card = mx_init_card,
+ .set_pcm_audio_params = mx_set_pcm_audio_params,
+ .set_pcm_voice_params = mx_set_pcm_voice_params,
+ .set_voice_port = mx_set_voice_port,
+ .set_audio_port = mx_set_audio_port,
+ .power_up_pmic_pb = mx_power_up_pb,
+ .power_up_pmic_cp = mx_power_up_cp,
+ .power_down_pmic_pb = mx_power_down_pb,
+ .power_down_pmic_cp = mx_power_down_cp,
+ .power_down_pmic = mx_power_down,
+};
+
diff --git a/drivers/staging/intel_sst/intelmid_v2_control.c b/drivers/staging/intel_sst/intelmid_v2_control.c
new file mode 100644
index 0000000..3a7de76
--- /dev/null
+++ b/drivers/staging/intel_sst/intelmid_v2_control.c
@@ -0,0 +1,1001 @@
+/*
+ * intelmid_v2_control.c - Intel Sound card driver for MID
+ *
+ * Copyright (C) 2008-10 Intel Corp
+ * Authors: Vinod Koul <vinod.koul(a)intel.com>
+ * Harsha Priya <priya.harsha(a)intel.com>
+ * KP Jeeja <jeeja.kp(a)intel.com>
+ * Dharageswari R <dharageswari.r(a)intel.com>
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This file contains the control operations of vendor 3
+ */
+
+#include <linux/pci.h>
+#include <linux/file.h>
+#include "intel_sst.h"
+#include "intelmid_snd_control.h"
+
+enum reg_v3 {
+ VAUDIOCNT = 0x51,
+ VOICEPORT1 = 0x100,
+ VOICEPORT2 = 0x101,
+ AUDIOPORT1 = 0x102,
+ AUDIOPORT2 = 0x103,
+ ADCSAMPLERATE = 0x104,
+ DMICCTRL1 = 0x105,
+ DMICCTRL2 = 0x106,
+ MICCTRL = 0x107,
+ MICSELVOL = 0x108,
+ LILSEL = 0x109,
+ LIRSEL = 0x10a,
+ VOICEVOL = 0x10b,
+ AUDIOLVOL = 0x10c,
+ AUDIORVOL = 0x10d,
+ LMUTE = 0x10e,
+ RMUTE = 0x10f,
+ POWERCTRL1 = 0x110,
+ POWERCTRL2 = 0x111,
+ DRVPOWERCTRL = 0x112,
+ VREFPLL = 0x113,
+ PCMBUFCTRL = 0x114,
+ SOFTMUTE = 0x115,
+ DTMFPATH = 0x116,
+ DTMFVOL = 0x117,
+ DTMFFREQ = 0x118,
+ DTMFHFREQ = 0x119,
+ DTMFLFREQ = 0x11a,
+ DTMFCTRL = 0x11b,
+ DTMFASON = 0x11c,
+ DTMFASOFF = 0x11d,
+ DTMFASINUM = 0x11e,
+ CLASSDVOL = 0x11f,
+ VOICEDACAVOL = 0x120,
+ AUDDACAVOL = 0x121,
+ LOMUTEVOL = 0x122,
+ HPLVOL = 0x123,
+ HPRVOL = 0x124,
+ MONOVOL = 0x125,
+ LINEOUTMIXVOL = 0x126,
+ EPMIXVOL = 0x127,
+ LINEOUTLSEL = 0x128,
+ LINEOUTRSEL = 0x129,
+ EPMIXOUTSEL = 0x12a,
+ HPLMIXSEL = 0x12b,
+ HPRMIXSEL = 0x12c,
+ LOANTIPOP = 0x12d,
+};
+
+/****
+ * nc_init_card - initilize the sound card
+ *
+ * This initilizes the audio paths to know values in case of this sound card
+ */
+static int nc_init_card(void)
+{
+ struct sc_reg_access sc_access[] = {
+ {VAUDIOCNT, 0x25, 0},
+ {VOICEPORT1, 0x00, 0},
+ {VOICEPORT2, 0x00, 0},
+ {AUDIOPORT1, 0x98, 0},
+ {AUDIOPORT2, 0x09, 0},
+ {AUDIOLVOL, 0x00, 0},
+ {AUDIORVOL, 0x00, 0},
+ {LMUTE, 0x03, 0},
+ {RMUTE, 0x03, 0},
+ {POWERCTRL1, 0x00, 0},
+ {POWERCTRL2, 0x00, 0},
+ {DRVPOWERCTRL, 0x00, 0},
+ {VREFPLL, 0x10, 0},
+ {HPLMIXSEL, 0xee, 0},
+ {HPRMIXSEL, 0xf6, 0},
+ {PCMBUFCTRL, 0x0, 0},
+ {VOICEVOL, 0x0e, 0},
+ {HPLVOL, 0x06, 0},
+ {HPRVOL, 0x06, 0},
+ {MICCTRL, 0x41, 0x00},
+ {ADCSAMPLERATE, 0x8B, 0x00},
+ {MICSELVOL, 0x5B, 0x00},
+ {LILSEL, 0x06, 0},
+ {LIRSEL, 0x46, 0},
+ {LOANTIPOP, 0x00, 0},
+ {DMICCTRL1, 0x40, 0},
+ };
+ snd_pmic_ops_nc.card_status = SND_CARD_INIT_DONE;
+ snd_pmic_ops_nc.master_mute = UNMUTE;
+ snd_pmic_ops_nc.mute_status = UNMUTE;
+ sst_sc_reg_access(sc_access, PMIC_WRITE, 26);
+ pr_debug("sst: init complete!!\n");
+ return 0;
+}
+
+static int nc_enable_audiodac(int value)
+{
+ struct sc_reg_access sc_access[3];
+ int mute_val = 0;
+
+ if (snd_pmic_ops_nc.mute_status == MUTE)
+ return 0;
+
+ if (((snd_pmic_ops_nc.output_dev_id == MONO_EARPIECE) ||
+ (snd_pmic_ops_nc.output_dev_id == INTERNAL_SPKR)) &&
+ (value == UNMUTE))
+ return 0;
+ if (value == UNMUTE) {
+ /* unmute the system, set the 7th bit to zero */
+ mute_val = 0x00;
+ } else {
+ /* MUTE:Set the seventh bit */
+ mute_val = 0x04;
+
+ }
+ sc_access[0].reg_addr = LMUTE;
+ sc_access[1].reg_addr = RMUTE;
+ sc_access[0].mask = sc_access[1].mask = MASK2;
+ sc_access[0].value = sc_access[1].value = mute_val;
+
+ if (snd_pmic_ops_nc.num_channel == 1)
+ sc_access[1].value = 0x04;
+ return sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 2);
+
+}
+
+static int nc_power_up_pb(unsigned int port)
+{
+ struct sc_reg_access sc_access[7];
+ int retval = 0;
+
+ if (snd_pmic_ops_nc.card_status == SND_CARD_UN_INIT)
+ retval = nc_init_card();
+ if (retval)
+ return retval;
+ if (port == 0xFF)
+ return 0;
+ nc_enable_audiodac(MUTE);
+ msleep(30);
+
+ pr_debug("sst: powering up pb....\n");
+
+ sc_access[0].reg_addr = VAUDIOCNT;
+ sc_access[0].value = 0x27;
+ sc_access[0].mask = 0x27;
+ sc_access[1].reg_addr = VREFPLL;
+ if (port == 0) {
+ sc_access[1].value = 0x3A;
+ sc_access[1].mask = 0x3A;
+ } else if (port == 1) {
+ sc_access[1].value = 0x35;
+ sc_access[1].mask = 0x35;
+ }
+ retval = sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 2);
+
+
+
+ sc_access[0].reg_addr = POWERCTRL1;
+ if (port == 0) {
+ sc_access[0].value = 0x40;
+ sc_access[0].mask = 0x40;
+ } else if (port == 1) {
+ sc_access[0].value = 0x01;
+ sc_access[0].mask = 0x01;
+ }
+ sc_access[1].reg_addr = POWERCTRL2;
+ sc_access[1].value = 0x0C;
+ sc_access[1].mask = 0x0C;
+
+ sc_access[2].reg_addr = DRVPOWERCTRL;
+ sc_access[2].value = 0x86;
+ sc_access[2].mask = 0x86;
+
+ sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 3);
+
+ msleep(30);
+
+ return nc_enable_audiodac(UNMUTE);
+
+}
+
+static int nc_power_up_cp(unsigned int port)
+{
+ struct sc_reg_access sc_access[5];
+ int retval = 0;
+
+
+ if (snd_pmic_ops_nc.card_status == SND_CARD_UN_INIT)
+ retval = nc_init_card();
+ if (retval)
+ return retval;
+
+
+ pr_debug("sst: powering up cp....\n");
+
+ if (port == 0xFF)
+ return 0;
+ sc_access[0].reg_addr = VAUDIOCNT;
+ sc_access[0].value = 0x27;
+ sc_access[0].mask = 0x27;
+ sc_access[1].reg_addr = VREFPLL;
+ if (port == 0) {
+ sc_access[1].value = 0x3E;
+ sc_access[1].mask = 0x3E;
+ } else if (port == 1) {
+ sc_access[1].value = 0x35;
+ sc_access[1].mask = 0x35;
+ }
+
+ retval = sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 2);
+
+
+ sc_access[0].reg_addr = POWERCTRL1;
+ if (port == 0) {
+ sc_access[0].value = 0xB4;
+ sc_access[0].mask = 0xB4;
+ } else if (port == 1) {
+ sc_access[0].value = 0xBF;
+ sc_access[0].mask = 0xBF;
+ }
+ sc_access[1].reg_addr = POWERCTRL2;
+ if (port == 0) {
+ sc_access[1].value = 0x0C;
+ sc_access[1].mask = 0x0C;
+ } else if (port == 1) {
+ sc_access[1].value = 0x02;
+ sc_access[1].mask = 0x02;
+ }
+
+ return sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 2);
+
+}
+
+static int nc_power_down(void)
+{
+ int retval = 0;
+ struct sc_reg_access sc_access[5];
+
+
+ if (snd_pmic_ops_nc.card_status == SND_CARD_UN_INIT)
+ retval = nc_init_card();
+ if (retval)
+ return retval;
+ nc_enable_audiodac(MUTE);
+
+
+ pr_debug("sst: powering dn nc_power_down ....\n");
+
+ msleep(30);
+
+ sc_access[0].reg_addr = DRVPOWERCTRL;
+ sc_access[0].value = 0x00;
+ sc_access[0].mask = 0x00;
+
+ sst_sc_reg_access(sc_access, PMIC_WRITE, 1);
+
+ sc_access[0].reg_addr = POWERCTRL1;
+ sc_access[0].value = 0x00;
+ sc_access[0].mask = 0x00;
+
+ sc_access[1].reg_addr = POWERCTRL2;
+ sc_access[1].value = 0x00;
+ sc_access[1].mask = 0x00;
+
+
+
+ sst_sc_reg_access(sc_access, PMIC_WRITE, 2);
+
+ msleep(30);
+ sc_access[0].reg_addr = VREFPLL;
+ sc_access[0].value = 0x10;
+ sc_access[0].mask = 0x10;
+
+ sc_access[1].reg_addr = VAUDIOCNT;
+ sc_access[1].value = 0x25;
+ sc_access[1].mask = 0x25;
+
+
+ retval = sst_sc_reg_access(sc_access, PMIC_WRITE, 2);
+
+ msleep(30);
+ return nc_enable_audiodac(UNMUTE);
+}
+
+static int nc_power_down_pb(void)
+{
+
+ int retval = 0;
+ struct sc_reg_access sc_access[5];
+
+ if (snd_pmic_ops_nc.card_status == SND_CARD_UN_INIT)
+ retval = nc_init_card();
+ if (retval)
+ return retval;
+
+ pr_debug("sst: powering dn pb....\n");
+
+ nc_enable_audiodac(MUTE);
+
+
+ msleep(30);
+
+
+ sc_access[0].reg_addr = DRVPOWERCTRL;
+ sc_access[0].value = 0x00;
+ sc_access[0].mask = 0x00;
+
+ sst_sc_reg_access(sc_access, PMIC_WRITE, 1);
+
+ msleep(30);
+
+ sc_access[0].reg_addr = POWERCTRL1;
+ sc_access[0].value = 0x00;
+ sc_access[0].mask = 0x41;
+
+ sc_access[1].reg_addr = POWERCTRL2;
+ sc_access[1].value = 0x00;
+ sc_access[1].mask = 0x0C;
+
+ sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 2);
+
+ msleep(30);
+
+ return nc_enable_audiodac(UNMUTE);
+
+
+}
+
+static int nc_power_down_cp(void)
+{
+ struct sc_reg_access sc_access[] = {
+ {POWERCTRL1, 0x00, 0xBE},
+ {POWERCTRL2, 0x00, 0x02},
+ };
+ int retval = 0;
+
+ if (snd_pmic_ops_nc.card_status == SND_CARD_UN_INIT)
+ retval = nc_init_card();
+ if (retval)
+ return retval;
+
+ pr_debug("sst: powering dn cp....\n");
+ return sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 1);
+}
+
+static int nc_set_pcm_voice_params(void)
+{
+ struct sc_reg_access sc_access[] = {
+ {0x100, 0xD5, 0},
+ {0x101, 0x08, 0},
+ {0x104, 0x03, 0},
+ {0x107, 0x10, 0},
+ {0x10B, 0x0E, 0},
+ {0x10E, 0x03, 0},
+ {0x10F, 0x03, 0},
+ {0x114, 0x13, 0},
+ {0x115, 0x00, 0},
+ {0x128, 0xFE, 0},
+ {0x129, 0xFE, 0},
+ {0x12A, 0xFE, 0},
+ {0x12B, 0xDE, 0},
+ {0x12C, 0xDE, 0},
+ };
+ int retval = 0;
+
+ if (snd_pmic_ops_nc.card_status == SND_CARD_UN_INIT)
+ retval = nc_init_card();
+ if (retval)
+ return retval;
+
+ sst_sc_reg_access(sc_access, PMIC_WRITE, 14);
+ pr_debug("sst: Voice parameters set successfully!!\n");
+ return 0;
+}
+
+
+static int nc_set_pcm_audio_params(int sfreq, int word_size, int num_channel)
+{
+ int config2 = 0;
+ struct sc_reg_access sc_access;
+ int retval = 0;
+
+ if (snd_pmic_ops_nc.card_status == SND_CARD_UN_INIT)
+ retval = nc_init_card();
+ if (retval)
+ return retval;
+
+ switch (sfreq) {
+ case 8000:
+ config2 = 0x00;
+ break;
+ case 11025:
+ config2 = 0x01;
+ break;
+ case 12000:
+ config2 = 0x02;
+ break;
+ case 16000:
+ config2 = 0x03;
+ break;
+ case 22050:
+ config2 = 0x04;
+ break;
+ case 24000:
+ config2 = 0x05;
+ break;
+ case 32000:
+ config2 = 0x07;
+ break;
+ case 44100:
+ config2 = 0x08;
+ break;
+ case 48000:
+ config2 = 0x09;
+ break;
+ }
+
+ snd_pmic_ops_nc.num_channel = num_channel;
+ if (snd_pmic_ops_nc.num_channel == 1) {
+
+ sc_access.value = 0x07;
+ sc_access.reg_addr = RMUTE;
+ pr_debug("sst: RIGHT_HP_MUTE value%d\n", sc_access.value);
+ sc_access.mask = MASK2;
+ sst_sc_reg_access(&sc_access, PMIC_READ_MODIFY, 1);
+ } else {
+ sc_access.value = 0x00;
+ sc_access.reg_addr = RMUTE;
+ pr_debug("sst: RIGHT_HP_MUTE value %d\n", sc_access.value);
+ sc_access.mask = MASK2;
+ sst_sc_reg_access(&sc_access, PMIC_READ_MODIFY, 1);
+
+
+ }
+
+ pr_debug("sst: word_size = %d\n", word_size);
+
+ if (word_size == 24) {
+ sc_access.reg_addr = AUDIOPORT2;
+ sc_access.value = config2 | 0x10;
+ sc_access.mask = 0x1F;
+ } else {
+ sc_access.value = config2;
+ sc_access.mask = 0x1F;
+ sc_access.reg_addr = AUDIOPORT2;
+ }
+ sst_sc_reg_access(&sc_access, PMIC_READ_MODIFY, 1);
+
+ pr_debug("sst: word_size = %d\n", word_size);
+ sc_access.reg_addr = AUDIOPORT1;
+ sc_access.mask = MASK5|MASK4|MASK1|MASK0;
+ if (word_size == 16)
+ sc_access.value = 0x98;
+ else if (word_size == 24)
+ sc_access.value = 0xAB;
+
+ return sst_sc_reg_access(&sc_access, PMIC_READ_MODIFY, 1);
+
+
+
+}
+
+static int nc_set_selected_output_dev(u8 value)
+{
+ struct sc_reg_access sc_access_HP[] = {
+ {LMUTE, 0x02, 0x06},
+ {RMUTE, 0x02, 0x06}
+ };
+ struct sc_reg_access sc_access_IS[] = {
+ {LMUTE, 0x04, 0x06},
+ {RMUTE, 0x04, 0x06}
+ };
+ int retval = 0;
+
+ snd_pmic_ops_nc.output_dev_id = value;
+ if (snd_pmic_ops_nc.card_status == SND_CARD_UN_INIT)
+ retval = nc_init_card();
+ if (retval)
+ return retval;
+ pr_debug("sst: nc set selected output:%d\n", value);
+ switch (value) {
+ case STEREO_HEADPHONE:
+ retval = sst_sc_reg_access(sc_access_HP, PMIC_WRITE, 2);
+ break;
+ case INTERNAL_SPKR:
+ retval = sst_sc_reg_access(sc_access_IS, PMIC_WRITE, 2);
+ break;
+ default:
+ pr_err("sst: rcvd illegal request: %d\n", value);
+ return -EINVAL;
+ }
+ return retval;
+}
+
+static int nc_audio_init(void)
+{
+ struct sc_reg_access sc_acces, sc_access[] = {
+ {0x100, 0x00, 0},
+ {0x101, 0x00, 0},
+ {0x104, 0x8B, 0},
+ {0x107, 0x11, 0},
+ {0x10B, 0x0E, 0},
+ {0x114, 0x00, 0},
+ {0x115, 0x00, 0},
+ {0x128, 0x00, 0},
+ {0x129, 0x00, 0},
+ {0x12A, 0x00, 0},
+ {0x12B, 0xee, 0},
+ {0x12C, 0xf6, 0},
+ };
+
+ sst_sc_reg_access(sc_access, PMIC_WRITE, 12);
+ pr_debug("sst: Audio Init successfully!!\n");
+
+ /*set output device */
+ nc_set_selected_output_dev(snd_pmic_ops_nc.output_dev_id);
+
+ if (snd_pmic_ops_nc.num_channel == 1) {
+ sc_acces.value = 0x07;
+ sc_acces.reg_addr = RMUTE;
+ pr_debug("sst: RIGHT_HP_MUTE value%d\n", sc_acces.value);
+ sc_acces.mask = MASK2;
+ sst_sc_reg_access(&sc_acces, PMIC_READ_MODIFY, 1);
+ } else {
+ sc_acces.value = 0x00;
+ sc_acces.reg_addr = RMUTE;
+ pr_debug("sst: RIGHT_HP_MUTE value%d\n", sc_acces.value);
+ sc_acces.mask = MASK2;
+ sst_sc_reg_access(&sc_acces, PMIC_READ_MODIFY, 1);
+ }
+
+ return 0;
+}
+
+static int nc_set_audio_port(int status)
+{
+ struct sc_reg_access sc_access[2] = {{0,},};
+ int retval = 0;
+
+ if (snd_pmic_ops_nc.card_status == SND_CARD_UN_INIT)
+ retval = nc_init_card();
+ if (retval)
+ return retval;
+
+ if (status == DEACTIVATE) {
+ /* Deactivate audio port-tristate and power */
+ sc_access[0].value = 0x00;
+ sc_access[0].mask = MASK4|MASK5;
+ sc_access[0].reg_addr = AUDIOPORT1;
+ return sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 1);
+ } else if (status == ACTIVATE) {
+ /* activate audio port */
+ nc_audio_init();
+ sc_access[0].value = 0x10;
+ sc_access[0].mask = MASK4|MASK5 ;
+ sc_access[0].reg_addr = AUDIOPORT1;
+ return sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 1);
+ } else
+ return -EINVAL;
+
+}
+
+static int nc_set_voice_port(int status)
+{
+ struct sc_reg_access sc_access[2] = {{0,},};
+ int retval = 0;
+
+ if (snd_pmic_ops_nc.card_status == SND_CARD_UN_INIT)
+ retval = nc_init_card();
+ if (retval)
+ return retval;
+
+ if (status == DEACTIVATE) {
+ /* Activate Voice port */
+ sc_access[0].value = 0x00;
+ sc_access[0].mask = MASK4;
+ sc_access[0].reg_addr = VOICEPORT1;
+ return sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 1);
+ } else if (status == ACTIVATE) {
+ /* Deactivate voice port */
+ nc_set_pcm_voice_params();
+ sc_access[0].value = 0x10;
+ sc_access[0].mask = MASK4;
+ sc_access[0].reg_addr = VOICEPORT1;
+ return sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 1);
+ } else
+ return -EINVAL;
+}
+
+static int nc_set_mute(int dev_id, u8 value)
+{
+ struct sc_reg_access sc_access[3];
+ u8 mute_val, cap_mute;
+ int retval = 0;
+
+ if (snd_pmic_ops_nc.card_status == SND_CARD_UN_INIT)
+ retval = nc_init_card();
+ if (retval)
+ return retval;
+
+ pr_debug("sst: set device id::%d, value %d\n", dev_id, value);
+
+ switch (dev_id) {
+ case PMIC_SND_MUTE_ALL:
+ pr_debug("sst: PMIC_SND_MUTE_ALL value %d\n", value);
+ snd_pmic_ops_nc.mute_status = value;
+ snd_pmic_ops_nc.master_mute = value;
+ if (value == UNMUTE) {
+ /* unmute the system, set the 7th bit to zero */
+ mute_val = cap_mute = 0x00;
+ } else {
+ /* MUTE:Set the seventh bit */
+ mute_val = 0x80;
+ cap_mute = 0x40;
+ }
+ sc_access[0].reg_addr = AUDIOLVOL;
+ sc_access[1].reg_addr = AUDIORVOL;
+ sc_access[0].mask = sc_access[1].mask = MASK7;
+ sc_access[0].value = sc_access[1].value = mute_val;
+ if (snd_pmic_ops_nc.num_channel == 1)
+ sc_access[1].value = 0x80;
+ if (!sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 2)) {
+ sc_access[0].reg_addr = 0x109;
+ sc_access[1].reg_addr = 0x10a;
+ sc_access[2].reg_addr = 0x105;
+ sc_access[0].mask = sc_access[1].mask =
+ sc_access[2].mask = MASK6;
+ sc_access[0].value = sc_access[1].value =
+ sc_access[2].value = cap_mute;
+
+ if ((snd_pmic_ops_nc.input_dev_id == AMIC) ||
+ (snd_pmic_ops_nc.input_dev_id == DMIC))
+ sc_access[1].value = 0x40;
+ if (snd_pmic_ops_nc.input_dev_id == HS_MIC)
+ sc_access[0].value = 0x40;
+ retval = sst_sc_reg_access(sc_access,
+ PMIC_READ_MODIFY, 3);
+ }
+ break;
+ case PMIC_SND_HP_MIC_MUTE:
+ pr_debug("sst: PMIC_SND_HPMIC_MUTE value %d\n", value);
+ if (value == UNMUTE) {
+ /* unmute the system, set the 6th bit to one */
+ sc_access[0].value = 0x00;
+ } else {
+ /* mute the system, reset the 6th bit to zero */
+ sc_access[0].value = 0x40;
+ }
+ sc_access[0].reg_addr = LIRSEL;
+ sc_access[0].mask = MASK6;
+ retval = sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 1);
+ break;
+ case PMIC_SND_AMIC_MUTE:
+ pr_debug("sst: PMIC_SND_AMIC_MUTE value %d\n", value);
+ if (value == UNMUTE) {
+ /* unmute the system, set the 6th bit to one */
+ sc_access[0].value = 0x00;
+ } else {
+ /* mute the system, reset the 6th bit to zero */
+ sc_access[0].value = 0x40;
+ }
+ sc_access[0].reg_addr = LILSEL;
+ sc_access[0].mask = MASK6;
+ retval = sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 1);
+ break;
+
+ case PMIC_SND_DMIC_MUTE:
+ pr_debug("sst: INPUT_MUTE_DMIC value%d\n", value);
+ if (value == UNMUTE) {
+ /* unmute the system, set the 6th bit to one */
+ sc_access[1].value = 0x00;
+ sc_access[0].value = 0x00;
+ } else {
+ /* mute the system, reset the 6th bit to zero */
+ sc_access[1].value = 0x40;
+ sc_access[0].value = 0x40;
+ }
+ sc_access[0].reg_addr = DMICCTRL1;
+ sc_access[0].mask = MASK6;
+ sc_access[1].reg_addr = LILSEL;
+ sc_access[1].mask = MASK6;
+ retval = sst_sc_reg_access(sc_access,
+ PMIC_READ_MODIFY, 2);
+ break;
+
+ case PMIC_SND_LEFT_HP_MUTE:
+ case PMIC_SND_RIGHT_HP_MUTE:
+ snd_pmic_ops_nc.mute_status = value;
+ if (value == UNMUTE)
+ sc_access[0].value = 0x0;
+ else
+ sc_access[0].value = 0x04;
+
+ if (dev_id == PMIC_SND_LEFT_HP_MUTE) {
+ sc_access[0].reg_addr = LMUTE;
+ pr_debug("sst: LEFT_HP_MUTE value %d\n",
+ sc_access[0].value);
+ } else {
+ if (snd_pmic_ops_nc.num_channel == 1)
+ sc_access[0].value = 0x04;
+ sc_access[0].reg_addr = RMUTE;
+ pr_debug("sst: RIGHT_HP_MUTE value %d\n",
+ sc_access[0].value);
+ }
+ sc_access[0].mask = MASK2;
+ retval = sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 1);
+ break;
+ case PMIC_SND_LEFT_SPEAKER_MUTE:
+ case PMIC_SND_RIGHT_SPEAKER_MUTE:
+ if (value == UNMUTE)
+ sc_access[0].value = 0x00;
+ else
+ sc_access[0].value = 0x03;
+ sc_access[0].reg_addr = LMUTE;
+ pr_debug("sst: SPEAKER_MUTE %d\n", sc_access[0].value);
+ sc_access[0].mask = MASK1;
+ retval = sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 1);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return retval ;
+
+}
+
+static int nc_set_vol(int dev_id, int value)
+{
+ struct sc_reg_access sc_access[3];
+ int retval = 0, entries = 0;
+
+ if (snd_pmic_ops_nc.card_status == SND_CARD_UN_INIT)
+ retval = nc_init_card();
+ if (retval)
+ return retval;
+
+ pr_debug("sst: set volume:%d\n", dev_id);
+ switch (dev_id) {
+ case PMIC_SND_CAPTURE_VOL:
+ pr_debug("sst: PMIC_SND_CAPTURE_VOL:value::%d\n", value);
+ sc_access[0].value = sc_access[1].value =
+ sc_access[2].value = -value;
+ sc_access[0].mask = sc_access[1].mask = sc_access[2].mask =
+ (MASK0|MASK1|MASK2|MASK3|MASK4|MASK5);
+ sc_access[0].reg_addr = 0x10a;
+ sc_access[1].reg_addr = 0x109;
+ sc_access[2].reg_addr = 0x105;
+ entries = 3;
+ break;
+
+ case PMIC_SND_LEFT_PB_VOL:
+ pr_debug("sst: PMIC_SND_LEFT_HP_VOL %d\n", value);
+ sc_access[0].value = -value;
+ sc_access[0].reg_addr = AUDIOLVOL;
+ sc_access[0].mask =
+ (MASK0|MASK1|MASK2|MASK3|MASK4|MASK5|MASK6);
+ entries = 1;
+ break;
+
+ case PMIC_SND_RIGHT_PB_VOL:
+ pr_debug("sst: PMIC_SND_RIGHT_HP_VOL value %d\n", value);
+ if (snd_pmic_ops_nc.num_channel == 1) {
+ sc_access[0].value = 0x04;
+ sc_access[0].reg_addr = RMUTE;
+ sc_access[0].mask = MASK2;
+ } else {
+ sc_access[0].value = -value;
+ sc_access[0].reg_addr = AUDIORVOL;
+ sc_access[0].mask =
+ (MASK0|MASK1|MASK2|MASK3|MASK4|MASK5|MASK6);
+ entries = 1;
+ }
+ break;
+
+ default:
+ return -EINVAL;
+
+ }
+ return sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, entries);
+}
+
+static int nc_set_selected_input_dev(u8 value)
+{
+ struct sc_reg_access sc_access[6];
+ u8 num_val;
+ int retval = 0;
+
+ if (snd_pmic_ops_nc.card_status == SND_CARD_UN_INIT)
+ retval = nc_init_card();
+ if (retval)
+ return retval;
+ snd_pmic_ops_nc.input_dev_id = value;
+
+ pr_debug("sst: nc set selected input:%d\n", value);
+
+ switch (value) {
+ case AMIC:
+ pr_debug("sst: Selecting AMIC\n");
+ sc_access[0].reg_addr = 0x107;
+ sc_access[0].value = 0x40;
+ sc_access[0].mask = MASK6|MASK4|MASK3|MASK1|MASK0;
+ sc_access[1].reg_addr = 0x10a;
+ sc_access[1].value = 0x40;
+ sc_access[1].mask = MASK6;
+ sc_access[2].reg_addr = 0x109;
+ sc_access[2].value = 0x00;
+ sc_access[2].mask = MASK6;
+ sc_access[3].reg_addr = 0x105;
+ sc_access[3].value = 0x40;
+ sc_access[3].mask = MASK6;
+ num_val = 4;
+ break;
+
+ case HS_MIC:
+ pr_debug("sst: Selecting HS_MIC\n");
+ sc_access[0].reg_addr = 0x107;
+ sc_access[0].mask = MASK6|MASK4|MASK3|MASK1|MASK0;
+ sc_access[0].value = 0x10;
+ sc_access[1].reg_addr = 0x109;
+ sc_access[1].mask = MASK6;
+ sc_access[1].value = 0x40;
+ sc_access[2].reg_addr = 0x10a;
+ sc_access[2].mask = MASK6;
+ sc_access[2].value = 0x00;
+ sc_access[3].reg_addr = 0x105;
+ sc_access[3].value = 0x40;
+ sc_access[3].mask = MASK6;
+ num_val = 4;
+ break;
+
+ case DMIC:
+ pr_debug("sst: DMIC\n");
+ sc_access[0].reg_addr = 0x107;
+ sc_access[0].mask = MASK6|MASK4|MASK3|MASK1|MASK0;
+ sc_access[0].value = 0x0B;
+ sc_access[1].reg_addr = 0x105;
+ sc_access[1].value = 0x80;
+ sc_access[1].mask = MASK7|MASK6;
+ sc_access[2].reg_addr = 0x10a;
+ sc_access[2].value = 0x40;
+ sc_access[2].mask = MASK6;
+ sc_access[3].reg_addr = 0x109;
+ sc_access[3].mask = MASK6;
+ sc_access[3].value = 0x40;
+ num_val = 4;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, num_val);
+}
+
+static int nc_get_mute(int dev_id, u8 *value)
+{
+ int retval = 0, mask = 0;
+ struct sc_reg_access sc_access = {0,};
+
+ if (snd_pmic_ops_nc.card_status == SND_CARD_UN_INIT)
+ retval = nc_init_card();
+ if (retval)
+ return retval;
+
+ pr_debug("sst: get mute::%d\n", dev_id);
+
+ switch (dev_id) {
+ case PMIC_SND_AMIC_MUTE:
+ pr_debug("sst: PMIC_SND_INPUT_MUTE_MIC1\n");
+ sc_access.reg_addr = LILSEL;
+ mask = MASK6;
+ break;
+ case PMIC_SND_HP_MIC_MUTE:
+ pr_debug("sst: PMIC_SND_INPUT_MUTE_MIC2\n");
+ sc_access.reg_addr = LIRSEL;
+ mask = MASK6;
+ break;
+ case PMIC_SND_LEFT_HP_MUTE:
+ case PMIC_SND_RIGHT_HP_MUTE:
+ mask = MASK2;
+ pr_debug("sst: PMIC_SN_LEFT/RIGHT_HP_MUTE\n");
+ if (dev_id == PMIC_SND_RIGHT_HP_MUTE)
+ sc_access.reg_addr = RMUTE;
+ else
+ sc_access.reg_addr = LMUTE;
+ break;
+
+ case PMIC_SND_LEFT_SPEAKER_MUTE:
+ pr_debug("sst: PMIC_MONO_EARPIECE_MUTE\n");
+ sc_access.reg_addr = RMUTE;
+ mask = MASK1;
+ break;
+ case PMIC_SND_DMIC_MUTE:
+ pr_debug("sst: PMIC_SND_INPUT_MUTE_DMIC\n");
+ sc_access.reg_addr = 0x105;
+ mask = MASK6;
+ break;
+ default:
+ return -EINVAL;
+
+ }
+ retval = sst_sc_reg_access(&sc_access, PMIC_READ, 1);
+ pr_debug("sst: reg value = %d\n", sc_access.value);
+ if (retval)
+ return retval;
+ *value = (sc_access.value) & mask;
+ pr_debug("sst: masked value = %d\n", *value);
+ if (*value)
+ *value = 0;
+ else
+ *value = 1;
+ pr_debug("sst: value returned = 0x%x\n", *value);
+ return retval;
+}
+
+static int nc_get_vol(int dev_id, int *value)
+{
+ int retval = 0, mask = 0;
+ struct sc_reg_access sc_access = {0,};
+
+ if (snd_pmic_ops_nc.card_status == SND_CARD_UN_INIT)
+ retval = nc_init_card();
+ if (retval)
+ return retval;
+
+ switch (dev_id) {
+ case PMIC_SND_CAPTURE_VOL:
+ pr_debug("sst: PMIC_SND_INPUT_CAPTURE_VOL\n");
+ sc_access.reg_addr = LILSEL;
+ mask = (MASK0|MASK1|MASK2|MASK3|MASK4|MASK5);
+ break;
+
+ case PMIC_SND_RIGHT_PB_VOL:
+ pr_debug("sst: GET_VOLUME_PMIC_LEFT_HP_VOL\n");
+ sc_access.reg_addr = AUDIOLVOL;
+ mask = (MASK0|MASK1|MASK2|MASK3|MASK4|MASK5|MASK6);
+ break;
+
+ case PMIC_SND_LEFT_PB_VOL:
+ pr_debug("sst: GET_VOLUME_PMIC_RIGHT_HP_VOL\n");
+ sc_access.reg_addr = AUDIORVOL;
+ mask = (MASK0|MASK1|MASK2|MASK3|MASK4|MASK5|MASK6);
+ break;
+
+ default:
+ return -EINVAL;
+
+ }
+ retval = sst_sc_reg_access(&sc_access, PMIC_READ, 1);
+ pr_debug("sst: value read = 0x%x\n", sc_access.value);
+ *value = -((sc_access.value) & mask);
+ pr_debug("sst: get vol value returned = %d\n", *value);
+ return retval;
+}
+
+struct snd_pmic_ops snd_pmic_ops_nc = {
+ .set_input_dev = nc_set_selected_input_dev,
+ .set_output_dev = nc_set_selected_output_dev,
+ .set_mute = nc_set_mute,
+ .get_mute = nc_get_mute,
+ .set_vol = nc_set_vol,
+ .get_vol = nc_get_vol,
+ .init_card = nc_init_card,
+ .set_pcm_audio_params = nc_set_pcm_audio_params,
+ .set_pcm_voice_params = nc_set_pcm_voice_params,
+ .set_voice_port = nc_set_voice_port,
+ .set_audio_port = nc_set_audio_port,
+ .power_up_pmic_pb = nc_power_up_pb,
+ .power_up_pmic_cp = nc_power_up_cp,
+ .power_down_pmic_pb = nc_power_down_pb,
+ .power_down_pmic_cp = nc_power_down_cp,
+ .power_down_pmic = nc_power_down,
+};
diff --git a/drivers/staging/intel_sst/jack.h b/drivers/staging/intel_sst/jack.h
new file mode 100644
index 0000000..9a6e483
--- /dev/null
+++ b/drivers/staging/intel_sst/jack.h
@@ -0,0 +1,10 @@
+/* Temporary staging glue */
+
+#include <sound/jack.h>
+
+/* These want adding to jack.h as enum entries once approved */
+
+#define SND_JACK_HS_SHORT_PRESS (SND_JACK_HEADSET | 0x0020)
+#define SND_JACK_HS_LONG_PRESS (SND_JACK_HEADSET | 0x0040)
+
+
3
2

Re: [alsa-devel] [Alsa-user] Creative Sound Blaster X-Fi Titanium PCIe support
by Clemens Ladisch 05 Oct '10
by Clemens Ladisch 05 Oct '10
05 Oct '10
Thor Kristoffersen wrote:
> James Le Cuirot <chewi(a)aura-online.co.uk> writes:
> > Sounds like the ASUS Xonar D2X could work for you.
>
> Is it known to work perfectly in ALSA?
Yes.
Regards,
Clemens
2
2
The following changes since commit 0b452f2efa35c48219d1ad3cbebdd786ec39ef06:
Merge branch 'for-2.6.37' of git://git.kernel.org/pub/scm/linux/kernel/git/lrg/asoc-2.6 into topic/asoc (2010-10-03 11:10:01 +0200)
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound-2.6.git for-2.6.37
Dimitris Papastamos (3):
ASoC: WM8804: Use a proper DAI name
ASoC: WM8804: Refactor set_pll code to avoid GCC warnings
ASoC: WM8804: Power down the PLL correctly
Mark Brown (5):
ASoC: Relax restrictions on WM8962 BCLK configuration
ASoC: Remove -dai suffix from i.MX SSI driver
ASoC: Add support for WM8962 GPIO outputs
ASoC: Implement interrupt based jack detection
ASoC: Put WM8962 GPIO2/3 into GPIO mode when configuring platform data too
arch/arm/mach-mx3/clock-imx31.c | 4 +-
arch/arm/mach-mx3/clock-imx35.c | 4 +-
arch/arm/mach-mx3/devices.c | 4 +-
arch/arm/plat-mxc/audmux-v2.c | 4 +-
include/sound/wm8962.h | 1 +
sound/soc/codecs/wm8804.c | 49 +++++----
sound/soc/codecs/wm8962.c | 228 +++++++++++++++++++++++++++++++++++++--
sound/soc/codecs/wm8962.h | 4 +
sound/soc/imx/eukrea-tlv320.c | 2 +-
sound/soc/imx/imx-ssi.c | 2 +-
sound/soc/imx/phycore-ac97.c | 2 +-
sound/soc/imx/wm1133-ev1.c | 2 +-
12 files changed, 265 insertions(+), 41 deletions(-)
2
1

[alsa-devel] [PATCH] ALSA: hda - Add a quirk for MacBookPro 7, 1 with a CS4206 codec
by Luke Yelavich 05 Oct '10
by Luke Yelavich 05 Oct '10
05 Oct '10
From: Luke Yelavich <luke.yelavich(a)canonical.com>
BugLink: https://bugs.launchpad.net/bugs/647389
Add an SSID for MacBookPro 7,1 (10de,cb89) to use CS420X_MBP55.
Cc: stable(a)kernel.org
Signed-off-by: Luke Yelavich <luke.yelavich(a)canonical.com>
---
sound/pci/hda/patch_cirrus.c | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c
index 5c00106..d9a3dbc 100644
--- a/sound/pci/hda/patch_cirrus.c
+++ b/sound/pci/hda/patch_cirrus.c
@@ -1140,6 +1140,7 @@ static const char *cs420x_models[CS420X_MODELS] = {
static struct snd_pci_quirk cs420x_cfg_tbl[] = {
SND_PCI_QUIRK(0x10de, 0x0ac0, "MacBookPro 5,3", CS420X_MBP53),
SND_PCI_QUIRK(0x10de, 0xcb79, "MacBookPro 5,5", CS420X_MBP55),
+ SND_PCI_QUIRK(0x10de, 0xcb89, "MacBookPro 7,1", CS420X_MBP55),
SND_PCI_QUIRK(0x8086, 0x7270, "IMac 27 Inch", CS420X_IMAC27),
{} /* terminator */
};
--
1.7.1
1
0