diff options
author | Takashi Iwai <tiwai@suse.de> | 2012-05-21 20:58:55 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2012-05-21 20:58:55 -0400 |
commit | 85e184e4c3cd3e2285ceab91ff8f0cac094e8a85 (patch) | |
tree | 1c1cf2d82a62bf0bef4ee390f578dcec35f4b427 | |
parent | 382e6a859e6622de0aa62c01976ae8ebd90e986d (diff) | |
parent | 766812e6d5e2e23be1e212cf84902d5e834dd865 (diff) |
Merge tag 'asoc-3.5' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into for-linus
ASoC: Last minute updates
These are all new code, they've been in -next already so should be OK
for merge this time round. I'd been planning to send a pull request
today after they'd had a bit of exposure there to make sure breakage
didn't propagate into your tree.
-rw-r--r-- | Documentation/devicetree/bindings/sound/tegra-audio-wm8753.txt | 54 | ||||
-rw-r--r-- | include/sound/sh_fsi.h | 6 | ||||
-rw-r--r-- | sound/soc/codecs/Kconfig | 4 | ||||
-rw-r--r-- | sound/soc/codecs/Makefile | 2 | ||||
-rw-r--r-- | sound/soc/codecs/omap-hdmi.c | 69 | ||||
-rw-r--r-- | sound/soc/omap/Kconfig | 1 | ||||
-rw-r--r-- | sound/soc/sh/fsi.c | 224 | ||||
-rw-r--r-- | sound/soc/tegra/Kconfig | 10 | ||||
-rw-r--r-- | sound/soc/tegra/Makefile | 2 | ||||
-rw-r--r-- | sound/soc/tegra/tegra_wm8753.c | 224 |
10 files changed, 529 insertions, 67 deletions
diff --git a/Documentation/devicetree/bindings/sound/tegra-audio-wm8753.txt b/Documentation/devicetree/bindings/sound/tegra-audio-wm8753.txt new file mode 100644 index 000000000000..c4dd39ce6165 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/tegra-audio-wm8753.txt | |||
@@ -0,0 +1,54 @@ | |||
1 | NVIDIA Tegra audio complex | ||
2 | |||
3 | Required properties: | ||
4 | - compatible : "nvidia,tegra-audio-wm8753" | ||
5 | - nvidia,model : The user-visible name of this sound complex. | ||
6 | - nvidia,audio-routing : A list of the connections between audio components. | ||
7 | Each entry is a pair of strings, the first being the connection's sink, | ||
8 | the second being the connection's source. Valid names for sources and | ||
9 | sinks are the WM8753's pins, and the jacks on the board: | ||
10 | |||
11 | WM8753 pins: | ||
12 | |||
13 | * LOUT1 | ||
14 | * LOUT2 | ||
15 | * ROUT1 | ||
16 | * ROUT2 | ||
17 | * MONO1 | ||
18 | * MONO2 | ||
19 | * OUT3 | ||
20 | * OUT4 | ||
21 | * LINE1 | ||
22 | * LINE2 | ||
23 | * RXP | ||
24 | * RXN | ||
25 | * ACIN | ||
26 | * ACOP | ||
27 | * MIC1N | ||
28 | * MIC1 | ||
29 | * MIC2N | ||
30 | * MIC2 | ||
31 | * Mic Bias | ||
32 | |||
33 | Board connectors: | ||
34 | |||
35 | * Headphone Jack | ||
36 | * Mic Jack | ||
37 | |||
38 | - nvidia,i2s-controller : The phandle of the Tegra I2S1 controller | ||
39 | - nvidia,audio-codec : The phandle of the WM8753 audio codec | ||
40 | Example: | ||
41 | |||
42 | sound { | ||
43 | compatible = "nvidia,tegra-audio-wm8753-whistler", | ||
44 | "nvidia,tegra-audio-wm8753" | ||
45 | nvidia,model = "tegra-wm8753-harmony"; | ||
46 | |||
47 | nvidia,audio-routing = | ||
48 | "Headphone Jack", "LOUT1", | ||
49 | "Headphone Jack", "ROUT1"; | ||
50 | |||
51 | nvidia,i2s-controller = <&i2s1>; | ||
52 | nvidia,audio-codec = <&wm8753>; | ||
53 | }; | ||
54 | |||
diff --git a/include/sound/sh_fsi.h b/include/sound/sh_fsi.h index 956e30e89ea8..906010344dd7 100644 --- a/include/sound/sh_fsi.h +++ b/include/sound/sh_fsi.h | |||
@@ -21,10 +21,11 @@ | |||
21 | /* | 21 | /* |
22 | * flags format | 22 | * flags format |
23 | * | 23 | * |
24 | * 0x000000BA | 24 | * 0x00000CBA |
25 | * | 25 | * |
26 | * A: inversion | 26 | * A: inversion |
27 | * B: format mode | 27 | * B: format mode |
28 | * C: chip specific | ||
28 | */ | 29 | */ |
29 | 30 | ||
30 | /* A: clock inversion */ | 31 | /* A: clock inversion */ |
@@ -39,6 +40,9 @@ | |||
39 | #define SH_FSI_FMT_DAI (0 << 4) | 40 | #define SH_FSI_FMT_DAI (0 << 4) |
40 | #define SH_FSI_FMT_SPDIF (1 << 4) | 41 | #define SH_FSI_FMT_SPDIF (1 << 4) |
41 | 42 | ||
43 | /* C: chip specific */ | ||
44 | #define SH_FSI_OPTION_MASK 0x00000F00 | ||
45 | #define SH_FSI_ENABLE_STREAM_MODE (1 << 8) /* for 16bit data */ | ||
42 | 46 | ||
43 | /* | 47 | /* |
44 | * set_rate return value | 48 | * set_rate return value |
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 22c686444633..1e1613a438dd 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig | |||
@@ -46,6 +46,7 @@ config SND_SOC_ALL_CODECS | |||
46 | select SND_SOC_MAX9877 if I2C | 46 | select SND_SOC_MAX9877 if I2C |
47 | select SND_SOC_MC13783 if MFD_MC13XXX | 47 | select SND_SOC_MC13783 if MFD_MC13XXX |
48 | select SND_SOC_ML26124 if I2C | 48 | select SND_SOC_ML26124 if I2C |
49 | select SND_SOC_OMAP_HDMI_CODEC if OMAP4_DSS_HDMI | ||
49 | select SND_SOC_PCM3008 | 50 | select SND_SOC_PCM3008 |
50 | select SND_SOC_RT5631 if I2C | 51 | select SND_SOC_RT5631 if I2C |
51 | select SND_SOC_SGTL5000 if I2C | 52 | select SND_SOC_SGTL5000 if I2C |
@@ -236,6 +237,9 @@ config SND_SOC_MAX98095 | |||
236 | config SND_SOC_MAX9850 | 237 | config SND_SOC_MAX9850 |
237 | tristate | 238 | tristate |
238 | 239 | ||
240 | config SND_SOC_OMAP_HDMI_CODEC | ||
241 | tristate | ||
242 | |||
239 | config SND_SOC_PCM3008 | 243 | config SND_SOC_PCM3008 |
240 | tristate | 244 | tristate |
241 | 245 | ||
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index a9663e9c375b..fc27fec39487 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile | |||
@@ -33,6 +33,7 @@ snd-soc-max98095-objs := max98095.o | |||
33 | snd-soc-max9850-objs := max9850.o | 33 | snd-soc-max9850-objs := max9850.o |
34 | snd-soc-mc13783-objs := mc13783.o | 34 | snd-soc-mc13783-objs := mc13783.o |
35 | snd-soc-ml26124-objs := ml26124.o | 35 | snd-soc-ml26124-objs := ml26124.o |
36 | snd-soc-omap-hdmi-codec-objs := omap-hdmi.o | ||
36 | snd-soc-pcm3008-objs := pcm3008.o | 37 | snd-soc-pcm3008-objs := pcm3008.o |
37 | snd-soc-rt5631-objs := rt5631.o | 38 | snd-soc-rt5631-objs := rt5631.o |
38 | snd-soc-sgtl5000-objs := sgtl5000.o | 39 | snd-soc-sgtl5000-objs := sgtl5000.o |
@@ -143,6 +144,7 @@ obj-$(CONFIG_SND_SOC_MAX98095) += snd-soc-max98095.o | |||
143 | obj-$(CONFIG_SND_SOC_MAX9850) += snd-soc-max9850.o | 144 | obj-$(CONFIG_SND_SOC_MAX9850) += snd-soc-max9850.o |
144 | obj-$(CONFIG_SND_SOC_MC13783) += snd-soc-mc13783.o | 145 | obj-$(CONFIG_SND_SOC_MC13783) += snd-soc-mc13783.o |
145 | obj-$(CONFIG_SND_SOC_ML26124) += snd-soc-ml26124.o | 146 | obj-$(CONFIG_SND_SOC_ML26124) += snd-soc-ml26124.o |
147 | obj-$(CONFIG_SND_SOC_OMAP_HDMI_CODEC) += snd-soc-omap-hdmi-codec.o | ||
146 | obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o | 148 | obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o |
147 | obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o | 149 | obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o |
148 | obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o | 150 | obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o |
diff --git a/sound/soc/codecs/omap-hdmi.c b/sound/soc/codecs/omap-hdmi.c new file mode 100644 index 000000000000..1bf5c74f5f96 --- /dev/null +++ b/sound/soc/codecs/omap-hdmi.c | |||
@@ -0,0 +1,69 @@ | |||
1 | /* | ||
2 | * ALSA SoC codec driver for HDMI audio on OMAP processors. | ||
3 | * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ | ||
4 | * Author: Ricardo Neri <ricardo.neri@ti.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * version 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
18 | * 02110-1301 USA | ||
19 | * | ||
20 | */ | ||
21 | #include <linux/module.h> | ||
22 | #include <sound/soc.h> | ||
23 | |||
24 | #define DRV_NAME "hdmi-audio-codec" | ||
25 | |||
26 | static struct snd_soc_codec_driver omap_hdmi_codec; | ||
27 | |||
28 | static struct snd_soc_dai_driver omap_hdmi_codec_dai = { | ||
29 | .name = "omap-hdmi-hifi", | ||
30 | .playback = { | ||
31 | .channels_min = 2, | ||
32 | .channels_max = 8, | ||
33 | .rates = SNDRV_PCM_RATE_32000 | | ||
34 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | | ||
35 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | | ||
36 | SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000, | ||
37 | .formats = SNDRV_PCM_FMTBIT_S16_LE | | ||
38 | SNDRV_PCM_FMTBIT_S24_LE, | ||
39 | }, | ||
40 | }; | ||
41 | |||
42 | static __devinit int omap_hdmi_codec_probe(struct platform_device *pdev) | ||
43 | { | ||
44 | return snd_soc_register_codec(&pdev->dev, &omap_hdmi_codec, | ||
45 | &omap_hdmi_codec_dai, 1); | ||
46 | } | ||
47 | |||
48 | static __devexit int omap_hdmi_codec_remove(struct platform_device *pdev) | ||
49 | { | ||
50 | snd_soc_unregister_codec(&pdev->dev); | ||
51 | return 0; | ||
52 | } | ||
53 | |||
54 | static struct platform_driver omap_hdmi_codec_driver = { | ||
55 | .driver = { | ||
56 | .name = DRV_NAME, | ||
57 | .owner = THIS_MODULE, | ||
58 | }, | ||
59 | |||
60 | .probe = omap_hdmi_codec_probe, | ||
61 | .remove = __devexit_p(omap_hdmi_codec_remove), | ||
62 | }; | ||
63 | |||
64 | module_platform_driver(omap_hdmi_codec_driver); | ||
65 | |||
66 | MODULE_AUTHOR("Ricardo Neri <ricardo.neri@ti.com>"); | ||
67 | MODULE_DESCRIPTION("ASoC OMAP HDMI codec driver"); | ||
68 | MODULE_LICENSE("GPL"); | ||
69 | MODULE_ALIAS("platform:" DRV_NAME); | ||
diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig index deafbfaacdbf..9ccfa5e1c11b 100644 --- a/sound/soc/omap/Kconfig +++ b/sound/soc/omap/Kconfig | |||
@@ -113,6 +113,7 @@ config SND_OMAP_SOC_OMAP4_HDMI | |||
113 | tristate "SoC Audio support for Texas Instruments OMAP4 HDMI" | 113 | tristate "SoC Audio support for Texas Instruments OMAP4 HDMI" |
114 | depends on SND_OMAP_SOC && OMAP4_DSS_HDMI && OMAP2_DSS && ARCH_OMAP4 | 114 | depends on SND_OMAP_SOC && OMAP4_DSS_HDMI && OMAP2_DSS && ARCH_OMAP4 |
115 | select SND_OMAP_SOC_HDMI | 115 | select SND_OMAP_SOC_HDMI |
116 | select SND_SOC_OMAP_HDMI_CODEC | ||
116 | help | 117 | help |
117 | Say Y if you want to add support for SoC HDMI audio on Texas Instruments | 118 | Say Y if you want to add support for SoC HDMI audio on Texas Instruments |
118 | OMAP4 chips | 119 | OMAP4 chips |
diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index 74ed2dffbffd..7cee22515d9d 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c | |||
@@ -132,6 +132,25 @@ | |||
132 | typedef int (*set_rate_func)(struct device *dev, int rate, int enable); | 132 | typedef int (*set_rate_func)(struct device *dev, int rate, int enable); |
133 | 133 | ||
134 | /* | 134 | /* |
135 | * bus options | ||
136 | * | ||
137 | * 0x000000BA | ||
138 | * | ||
139 | * A : sample widtht 16bit setting | ||
140 | * B : sample widtht 24bit setting | ||
141 | */ | ||
142 | |||
143 | #define SHIFT_16DATA 0 | ||
144 | #define SHIFT_24DATA 4 | ||
145 | |||
146 | #define PACKAGE_24BITBUS_BACK 0 | ||
147 | #define PACKAGE_24BITBUS_FRONT 1 | ||
148 | #define PACKAGE_16BITBUS_STREAM 2 | ||
149 | |||
150 | #define BUSOP_SET(s, a) ((a) << SHIFT_ ## s ## DATA) | ||
151 | #define BUSOP_GET(s, a) (((a) >> SHIFT_ ## s ## DATA) & 0xF) | ||
152 | |||
153 | /* | ||
135 | * FSI driver use below type name for variable | 154 | * FSI driver use below type name for variable |
136 | * | 155 | * |
137 | * xxx_num : number of data | 156 | * xxx_num : number of data |
@@ -189,6 +208,11 @@ struct fsi_stream { | |||
189 | int oerr_num; | 208 | int oerr_num; |
190 | 209 | ||
191 | /* | 210 | /* |
211 | * bus options | ||
212 | */ | ||
213 | u32 bus_option; | ||
214 | |||
215 | /* | ||
192 | * thse are initialized by fsi_handler_init() | 216 | * thse are initialized by fsi_handler_init() |
193 | */ | 217 | */ |
194 | struct fsi_stream_handler *handler; | 218 | struct fsi_stream_handler *handler; |
@@ -211,8 +235,7 @@ struct fsi_priv { | |||
211 | struct fsi_stream playback; | 235 | struct fsi_stream playback; |
212 | struct fsi_stream capture; | 236 | struct fsi_stream capture; |
213 | 237 | ||
214 | u32 do_fmt; | 238 | u32 fmt; |
215 | u32 di_fmt; | ||
216 | 239 | ||
217 | int chan_num:16; | 240 | int chan_num:16; |
218 | int clk_master:1; | 241 | int clk_master:1; |
@@ -321,6 +344,10 @@ static void _fsi_master_mask_set(struct fsi_master *master, | |||
321 | /* | 344 | /* |
322 | * basic function | 345 | * basic function |
323 | */ | 346 | */ |
347 | static int fsi_version(struct fsi_master *master) | ||
348 | { | ||
349 | return master->core->ver; | ||
350 | } | ||
324 | 351 | ||
325 | static struct fsi_master *fsi_get_master(struct fsi_priv *fsi) | 352 | static struct fsi_master *fsi_get_master(struct fsi_priv *fsi) |
326 | { | 353 | { |
@@ -495,6 +522,7 @@ static void fsi_stream_init(struct fsi_priv *fsi, | |||
495 | io->period_samples = fsi_frame2sample(fsi, runtime->period_size); | 522 | io->period_samples = fsi_frame2sample(fsi, runtime->period_size); |
496 | io->period_pos = 0; | 523 | io->period_pos = 0; |
497 | io->sample_width = samples_to_bytes(runtime, 1); | 524 | io->sample_width = samples_to_bytes(runtime, 1); |
525 | io->bus_option = 0; | ||
498 | io->oerr_num = -1; /* ignore 1st err */ | 526 | io->oerr_num = -1; /* ignore 1st err */ |
499 | io->uerr_num = -1; /* ignore 1st err */ | 527 | io->uerr_num = -1; /* ignore 1st err */ |
500 | fsi_stream_handler_call(io, init, fsi, io); | 528 | fsi_stream_handler_call(io, init, fsi, io); |
@@ -522,6 +550,7 @@ static void fsi_stream_quit(struct fsi_priv *fsi, struct fsi_stream *io) | |||
522 | io->period_samples = 0; | 550 | io->period_samples = 0; |
523 | io->period_pos = 0; | 551 | io->period_pos = 0; |
524 | io->sample_width = 0; | 552 | io->sample_width = 0; |
553 | io->bus_option = 0; | ||
525 | io->oerr_num = 0; | 554 | io->oerr_num = 0; |
526 | io->uerr_num = 0; | 555 | io->uerr_num = 0; |
527 | spin_unlock_irqrestore(&master->lock, flags); | 556 | spin_unlock_irqrestore(&master->lock, flags); |
@@ -581,6 +610,53 @@ static int fsi_stream_remove(struct fsi_priv *fsi) | |||
581 | } | 610 | } |
582 | 611 | ||
583 | /* | 612 | /* |
613 | * format/bus/dma setting | ||
614 | */ | ||
615 | static void fsi_format_bus_setup(struct fsi_priv *fsi, struct fsi_stream *io, | ||
616 | u32 bus, struct device *dev) | ||
617 | { | ||
618 | struct fsi_master *master = fsi_get_master(fsi); | ||
619 | int is_play = fsi_stream_is_play(fsi, io); | ||
620 | u32 fmt = fsi->fmt; | ||
621 | |||
622 | if (fsi_version(master) >= 2) { | ||
623 | u32 dma = 0; | ||
624 | |||
625 | /* | ||
626 | * FSI2 needs DMA/Bus setting | ||
627 | */ | ||
628 | switch (bus) { | ||
629 | case PACKAGE_24BITBUS_FRONT: | ||
630 | fmt |= CR_BWS_24; | ||
631 | dma |= VDMD_FRONT; | ||
632 | dev_dbg(dev, "24bit bus / package in front\n"); | ||
633 | break; | ||
634 | case PACKAGE_16BITBUS_STREAM: | ||
635 | fmt |= CR_BWS_16; | ||
636 | dma |= VDMD_STREAM; | ||
637 | dev_dbg(dev, "16bit bus / stream mode\n"); | ||
638 | break; | ||
639 | case PACKAGE_24BITBUS_BACK: | ||
640 | default: | ||
641 | fmt |= CR_BWS_24; | ||
642 | dma |= VDMD_BACK; | ||
643 | dev_dbg(dev, "24bit bus / package in back\n"); | ||
644 | break; | ||
645 | } | ||
646 | |||
647 | if (is_play) | ||
648 | fsi_reg_write(fsi, OUT_DMAC, dma); | ||
649 | else | ||
650 | fsi_reg_write(fsi, IN_DMAC, dma); | ||
651 | } | ||
652 | |||
653 | if (is_play) | ||
654 | fsi_reg_write(fsi, DO_FMT, fmt); | ||
655 | else | ||
656 | fsi_reg_write(fsi, DI_FMT, fmt); | ||
657 | } | ||
658 | |||
659 | /* | ||
584 | * irq function | 660 | * irq function |
585 | */ | 661 | */ |
586 | 662 | ||
@@ -629,11 +705,6 @@ static void fsi_spdif_clk_ctrl(struct fsi_priv *fsi, int enable) | |||
629 | struct fsi_master *master = fsi_get_master(fsi); | 705 | struct fsi_master *master = fsi_get_master(fsi); |
630 | u32 mask, val; | 706 | u32 mask, val; |
631 | 707 | ||
632 | if (master->core->ver < 2) { | ||
633 | pr_err("fsi: register access err (%s)\n", __func__); | ||
634 | return; | ||
635 | } | ||
636 | |||
637 | mask = BP | SE; | 708 | mask = BP | SE; |
638 | val = enable ? mask : 0; | 709 | val = enable ? mask : 0; |
639 | 710 | ||
@@ -648,9 +719,7 @@ static void fsi_spdif_clk_ctrl(struct fsi_priv *fsi, int enable) | |||
648 | static int fsi_set_master_clk(struct device *dev, struct fsi_priv *fsi, | 719 | static int fsi_set_master_clk(struct device *dev, struct fsi_priv *fsi, |
649 | long rate, int enable) | 720 | long rate, int enable) |
650 | { | 721 | { |
651 | struct fsi_master *master = fsi_get_master(fsi); | ||
652 | set_rate_func set_rate = fsi_get_info_set_rate(fsi); | 722 | set_rate_func set_rate = fsi_get_info_set_rate(fsi); |
653 | int fsi_ver = master->core->ver; | ||
654 | int ret; | 723 | int ret; |
655 | 724 | ||
656 | if (!set_rate) | 725 | if (!set_rate) |
@@ -682,10 +751,7 @@ static int fsi_set_master_clk(struct device *dev, struct fsi_priv *fsi, | |||
682 | data |= (0x3 << 12); | 751 | data |= (0x3 << 12); |
683 | break; | 752 | break; |
684 | case SH_FSI_ACKMD_32: | 753 | case SH_FSI_ACKMD_32: |
685 | if (fsi_ver < 2) | 754 | data |= (0x4 << 12); |
686 | dev_err(dev, "unsupported ACKMD\n"); | ||
687 | else | ||
688 | data |= (0x4 << 12); | ||
689 | break; | 755 | break; |
690 | } | 756 | } |
691 | 757 | ||
@@ -708,10 +774,7 @@ static int fsi_set_master_clk(struct device *dev, struct fsi_priv *fsi, | |||
708 | data |= (0x4 << 8); | 774 | data |= (0x4 << 8); |
709 | break; | 775 | break; |
710 | case SH_FSI_BPFMD_16: | 776 | case SH_FSI_BPFMD_16: |
711 | if (fsi_ver < 2) | 777 | data |= (0x7 << 8); |
712 | dev_err(dev, "unsupported ACKMD\n"); | ||
713 | else | ||
714 | data |= (0x7 << 8); | ||
715 | break; | 778 | break; |
716 | } | 779 | } |
717 | 780 | ||
@@ -728,11 +791,26 @@ static int fsi_set_master_clk(struct device *dev, struct fsi_priv *fsi, | |||
728 | */ | 791 | */ |
729 | static void fsi_pio_push16(struct fsi_priv *fsi, u8 *_buf, int samples) | 792 | static void fsi_pio_push16(struct fsi_priv *fsi, u8 *_buf, int samples) |
730 | { | 793 | { |
731 | u16 *buf = (u16 *)_buf; | 794 | u32 enable_stream = fsi_get_info_flags(fsi) & SH_FSI_ENABLE_STREAM_MODE; |
732 | int i; | 795 | int i; |
733 | 796 | ||
734 | for (i = 0; i < samples; i++) | 797 | if (enable_stream) { |
735 | fsi_reg_write(fsi, DODT, ((u32)*(buf + i) << 8)); | 798 | /* |
799 | * stream mode | ||
800 | * see | ||
801 | * fsi_pio_push_init() | ||
802 | */ | ||
803 | u32 *buf = (u32 *)_buf; | ||
804 | |||
805 | for (i = 0; i < samples / 2; i++) | ||
806 | fsi_reg_write(fsi, DODT, buf[i]); | ||
807 | } else { | ||
808 | /* normal mode */ | ||
809 | u16 *buf = (u16 *)_buf; | ||
810 | |||
811 | for (i = 0; i < samples; i++) | ||
812 | fsi_reg_write(fsi, DODT, ((u32)*(buf + i) << 8)); | ||
813 | } | ||
736 | } | 814 | } |
737 | 815 | ||
738 | static void fsi_pio_pop16(struct fsi_priv *fsi, u8 *_buf, int samples) | 816 | static void fsi_pio_pop16(struct fsi_priv *fsi, u8 *_buf, int samples) |
@@ -872,12 +950,44 @@ static void fsi_pio_start_stop(struct fsi_priv *fsi, struct fsi_stream *io, | |||
872 | fsi_master_mask_set(master, CLK_RST, clk, (enable) ? clk : 0); | 950 | fsi_master_mask_set(master, CLK_RST, clk, (enable) ? clk : 0); |
873 | } | 951 | } |
874 | 952 | ||
953 | static int fsi_pio_push_init(struct fsi_priv *fsi, struct fsi_stream *io) | ||
954 | { | ||
955 | u32 enable_stream = fsi_get_info_flags(fsi) & SH_FSI_ENABLE_STREAM_MODE; | ||
956 | |||
957 | /* | ||
958 | * we can use 16bit stream mode | ||
959 | * when "playback" and "16bit data" | ||
960 | * and platform allows "stream mode" | ||
961 | * see | ||
962 | * fsi_pio_push16() | ||
963 | */ | ||
964 | if (enable_stream) | ||
965 | io->bus_option = BUSOP_SET(24, PACKAGE_24BITBUS_BACK) | | ||
966 | BUSOP_SET(16, PACKAGE_16BITBUS_STREAM); | ||
967 | else | ||
968 | io->bus_option = BUSOP_SET(24, PACKAGE_24BITBUS_BACK) | | ||
969 | BUSOP_SET(16, PACKAGE_24BITBUS_BACK); | ||
970 | return 0; | ||
971 | } | ||
972 | |||
973 | static int fsi_pio_pop_init(struct fsi_priv *fsi, struct fsi_stream *io) | ||
974 | { | ||
975 | /* | ||
976 | * always 24bit bus, package back when "capture" | ||
977 | */ | ||
978 | io->bus_option = BUSOP_SET(24, PACKAGE_24BITBUS_BACK) | | ||
979 | BUSOP_SET(16, PACKAGE_24BITBUS_BACK); | ||
980 | return 0; | ||
981 | } | ||
982 | |||
875 | static struct fsi_stream_handler fsi_pio_push_handler = { | 983 | static struct fsi_stream_handler fsi_pio_push_handler = { |
984 | .init = fsi_pio_push_init, | ||
876 | .transfer = fsi_pio_push, | 985 | .transfer = fsi_pio_push, |
877 | .start_stop = fsi_pio_start_stop, | 986 | .start_stop = fsi_pio_start_stop, |
878 | }; | 987 | }; |
879 | 988 | ||
880 | static struct fsi_stream_handler fsi_pio_pop_handler = { | 989 | static struct fsi_stream_handler fsi_pio_pop_handler = { |
990 | .init = fsi_pio_pop_init, | ||
881 | .transfer = fsi_pio_pop, | 991 | .transfer = fsi_pio_pop, |
882 | .start_stop = fsi_pio_start_stop, | 992 | .start_stop = fsi_pio_start_stop, |
883 | }; | 993 | }; |
@@ -919,6 +1029,13 @@ static int fsi_dma_init(struct fsi_priv *fsi, struct fsi_stream *io) | |||
919 | enum dma_data_direction dir = fsi_stream_is_play(fsi, io) ? | 1029 | enum dma_data_direction dir = fsi_stream_is_play(fsi, io) ? |
920 | DMA_TO_DEVICE : DMA_FROM_DEVICE; | 1030 | DMA_TO_DEVICE : DMA_FROM_DEVICE; |
921 | 1031 | ||
1032 | /* | ||
1033 | * 24bit data : 24bit bus / package in back | ||
1034 | * 16bit data : 16bit bus / stream mode | ||
1035 | */ | ||
1036 | io->bus_option = BUSOP_SET(24, PACKAGE_24BITBUS_BACK) | | ||
1037 | BUSOP_SET(16, PACKAGE_16BITBUS_STREAM); | ||
1038 | |||
922 | io->dma = dma_map_single(dai->dev, runtime->dma_area, | 1039 | io->dma = dma_map_single(dai->dev, runtime->dma_area, |
923 | snd_pcm_lib_buffer_bytes(io->substream), dir); | 1040 | snd_pcm_lib_buffer_bytes(io->substream), dir); |
924 | return 0; | 1041 | return 0; |
@@ -1055,25 +1172,9 @@ static int fsi_dma_transfer(struct fsi_priv *fsi, struct fsi_stream *io) | |||
1055 | static void fsi_dma_push_start_stop(struct fsi_priv *fsi, struct fsi_stream *io, | 1172 | static void fsi_dma_push_start_stop(struct fsi_priv *fsi, struct fsi_stream *io, |
1056 | int start) | 1173 | int start) |
1057 | { | 1174 | { |
1058 | u32 bws; | 1175 | u32 enable = start ? DMA_ON : 0; |
1059 | u32 dma; | ||
1060 | 1176 | ||
1061 | switch (io->sample_width * start) { | 1177 | fsi_reg_mask_set(fsi, OUT_DMAC, DMA_ON, enable); |
1062 | case 2: | ||
1063 | bws = CR_BWS_16; | ||
1064 | dma = VDMD_STREAM | DMA_ON; | ||
1065 | break; | ||
1066 | case 4: | ||
1067 | bws = CR_BWS_24; | ||
1068 | dma = VDMD_BACK | DMA_ON; | ||
1069 | break; | ||
1070 | default: | ||
1071 | bws = 0; | ||
1072 | dma = 0; | ||
1073 | } | ||
1074 | |||
1075 | fsi_reg_mask_set(fsi, DO_FMT, CR_BWS_MASK, bws); | ||
1076 | fsi_reg_write(fsi, OUT_DMAC, dma); | ||
1077 | } | 1178 | } |
1078 | 1179 | ||
1079 | static int fsi_dma_probe(struct fsi_priv *fsi, struct fsi_stream *io) | 1180 | static int fsi_dma_probe(struct fsi_priv *fsi, struct fsi_stream *io) |
@@ -1176,8 +1277,6 @@ static int fsi_hw_startup(struct fsi_priv *fsi, | |||
1176 | struct fsi_stream *io, | 1277 | struct fsi_stream *io, |
1177 | struct device *dev) | 1278 | struct device *dev) |
1178 | { | 1279 | { |
1179 | struct fsi_master *master = fsi_get_master(fsi); | ||
1180 | int fsi_ver = master->core->ver; | ||
1181 | u32 flags = fsi_get_info_flags(fsi); | 1280 | u32 flags = fsi_get_info_flags(fsi); |
1182 | u32 data = 0; | 1281 | u32 data = 0; |
1183 | 1282 | ||
@@ -1200,10 +1299,6 @@ static int fsi_hw_startup(struct fsi_priv *fsi, | |||
1200 | 1299 | ||
1201 | fsi_reg_write(fsi, CKG2, data); | 1300 | fsi_reg_write(fsi, CKG2, data); |
1202 | 1301 | ||
1203 | /* set format */ | ||
1204 | fsi_reg_write(fsi, DO_FMT, fsi->do_fmt); | ||
1205 | fsi_reg_write(fsi, DI_FMT, fsi->di_fmt); | ||
1206 | |||
1207 | /* spdif ? */ | 1302 | /* spdif ? */ |
1208 | if (fsi_is_spdif(fsi)) { | 1303 | if (fsi_is_spdif(fsi)) { |
1209 | fsi_spdif_clk_ctrl(fsi, 1); | 1304 | fsi_spdif_clk_ctrl(fsi, 1); |
@@ -1211,15 +1306,18 @@ static int fsi_hw_startup(struct fsi_priv *fsi, | |||
1211 | } | 1306 | } |
1212 | 1307 | ||
1213 | /* | 1308 | /* |
1214 | * FIXME | 1309 | * get bus settings |
1215 | * | ||
1216 | * FSI driver assumed that data package is in-back. | ||
1217 | * FSI2 chip can select it. | ||
1218 | */ | 1310 | */ |
1219 | if (fsi_ver >= 2) { | 1311 | data = 0; |
1220 | fsi_reg_write(fsi, OUT_DMAC, (1 << 4)); | 1312 | switch (io->sample_width) { |
1221 | fsi_reg_write(fsi, IN_DMAC, (1 << 4)); | 1313 | case 2: |
1314 | data = BUSOP_GET(16, io->bus_option); | ||
1315 | break; | ||
1316 | case 4: | ||
1317 | data = BUSOP_GET(24, io->bus_option); | ||
1318 | break; | ||
1222 | } | 1319 | } |
1320 | fsi_format_bus_setup(fsi, io, data, dev); | ||
1223 | 1321 | ||
1224 | /* irq clear */ | 1322 | /* irq clear */ |
1225 | fsi_irq_disable(fsi, io); | 1323 | fsi_irq_disable(fsi, io); |
@@ -1243,7 +1341,9 @@ static int fsi_dai_startup(struct snd_pcm_substream *substream, | |||
1243 | { | 1341 | { |
1244 | struct fsi_priv *fsi = fsi_get_priv(substream); | 1342 | struct fsi_priv *fsi = fsi_get_priv(substream); |
1245 | 1343 | ||
1246 | return fsi_hw_startup(fsi, fsi_stream_get(fsi, substream), dai->dev); | 1344 | fsi->rate = 0; |
1345 | |||
1346 | return 0; | ||
1247 | } | 1347 | } |
1248 | 1348 | ||
1249 | static void fsi_dai_shutdown(struct snd_pcm_substream *substream, | 1349 | static void fsi_dai_shutdown(struct snd_pcm_substream *substream, |
@@ -1251,7 +1351,6 @@ static void fsi_dai_shutdown(struct snd_pcm_substream *substream, | |||
1251 | { | 1351 | { |
1252 | struct fsi_priv *fsi = fsi_get_priv(substream); | 1352 | struct fsi_priv *fsi = fsi_get_priv(substream); |
1253 | 1353 | ||
1254 | fsi_hw_shutdown(fsi, dai->dev); | ||
1255 | fsi->rate = 0; | 1354 | fsi->rate = 0; |
1256 | } | 1355 | } |
1257 | 1356 | ||
@@ -1265,11 +1364,13 @@ static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd, | |||
1265 | switch (cmd) { | 1364 | switch (cmd) { |
1266 | case SNDRV_PCM_TRIGGER_START: | 1365 | case SNDRV_PCM_TRIGGER_START: |
1267 | fsi_stream_init(fsi, io, substream); | 1366 | fsi_stream_init(fsi, io, substream); |
1367 | fsi_hw_startup(fsi, io, dai->dev); | ||
1268 | ret = fsi_stream_transfer(io); | 1368 | ret = fsi_stream_transfer(io); |
1269 | if (0 == ret) | 1369 | if (0 == ret) |
1270 | fsi_stream_start(fsi, io); | 1370 | fsi_stream_start(fsi, io); |
1271 | break; | 1371 | break; |
1272 | case SNDRV_PCM_TRIGGER_STOP: | 1372 | case SNDRV_PCM_TRIGGER_STOP: |
1373 | fsi_hw_shutdown(fsi, dai->dev); | ||
1273 | fsi_stream_stop(fsi, io); | 1374 | fsi_stream_stop(fsi, io); |
1274 | fsi_stream_quit(fsi, io); | 1375 | fsi_stream_quit(fsi, io); |
1275 | break; | 1376 | break; |
@@ -1280,42 +1381,33 @@ static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd, | |||
1280 | 1381 | ||
1281 | static int fsi_set_fmt_dai(struct fsi_priv *fsi, unsigned int fmt) | 1382 | static int fsi_set_fmt_dai(struct fsi_priv *fsi, unsigned int fmt) |
1282 | { | 1383 | { |
1283 | u32 data = 0; | ||
1284 | |||
1285 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | 1384 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
1286 | case SND_SOC_DAIFMT_I2S: | 1385 | case SND_SOC_DAIFMT_I2S: |
1287 | data = CR_I2S; | 1386 | fsi->fmt = CR_I2S; |
1288 | fsi->chan_num = 2; | 1387 | fsi->chan_num = 2; |
1289 | break; | 1388 | break; |
1290 | case SND_SOC_DAIFMT_LEFT_J: | 1389 | case SND_SOC_DAIFMT_LEFT_J: |
1291 | data = CR_PCM; | 1390 | fsi->fmt = CR_PCM; |
1292 | fsi->chan_num = 2; | 1391 | fsi->chan_num = 2; |
1293 | break; | 1392 | break; |
1294 | default: | 1393 | default: |
1295 | return -EINVAL; | 1394 | return -EINVAL; |
1296 | } | 1395 | } |
1297 | 1396 | ||
1298 | fsi->do_fmt = data; | ||
1299 | fsi->di_fmt = data; | ||
1300 | |||
1301 | return 0; | 1397 | return 0; |
1302 | } | 1398 | } |
1303 | 1399 | ||
1304 | static int fsi_set_fmt_spdif(struct fsi_priv *fsi) | 1400 | static int fsi_set_fmt_spdif(struct fsi_priv *fsi) |
1305 | { | 1401 | { |
1306 | struct fsi_master *master = fsi_get_master(fsi); | 1402 | struct fsi_master *master = fsi_get_master(fsi); |
1307 | u32 data = 0; | ||
1308 | 1403 | ||
1309 | if (master->core->ver < 2) | 1404 | if (fsi_version(master) < 2) |
1310 | return -EINVAL; | 1405 | return -EINVAL; |
1311 | 1406 | ||
1312 | data = CR_BWS_16 | CR_DTMD_SPDIF_PCM | CR_PCM; | 1407 | fsi->fmt = CR_DTMD_SPDIF_PCM | CR_PCM; |
1313 | fsi->chan_num = 2; | 1408 | fsi->chan_num = 2; |
1314 | fsi->spdif = 1; | 1409 | fsi->spdif = 1; |
1315 | 1410 | ||
1316 | fsi->do_fmt = data; | ||
1317 | fsi->di_fmt = data; | ||
1318 | |||
1319 | return 0; | 1411 | return 0; |
1320 | } | 1412 | } |
1321 | 1413 | ||
diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig index 5331c61faf01..c1c8e955f4d3 100644 --- a/sound/soc/tegra/Kconfig +++ b/sound/soc/tegra/Kconfig | |||
@@ -48,6 +48,16 @@ config SND_SOC_TEGRA30_I2S | |||
48 | Tegra30 I2S interface. You will also need to select the individual | 48 | Tegra30 I2S interface. You will also need to select the individual |
49 | machine drivers to support below. | 49 | machine drivers to support below. |
50 | 50 | ||
51 | config SND_SOC_TEGRA_WM8753 | ||
52 | tristate "SoC Audio support for Tegra boards using a WM8753 codec" | ||
53 | depends on SND_SOC_TEGRA && I2C | ||
54 | select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC | ||
55 | select SND_SOC_TEGRA30_I2S if ARCH_TEGRA_3x_SOC | ||
56 | select SND_SOC_WM8753 | ||
57 | help | ||
58 | Say Y or M here if you want to add support for SoC audio on Tegra | ||
59 | boards using the WM8753 codec, such as Whistler. | ||
60 | |||
51 | config MACH_HAS_SND_SOC_TEGRA_WM8903 | 61 | config MACH_HAS_SND_SOC_TEGRA_WM8903 |
52 | bool | 62 | bool |
53 | help | 63 | help |
diff --git a/sound/soc/tegra/Makefile b/sound/soc/tegra/Makefile index 98704b48b62a..391e78a34c06 100644 --- a/sound/soc/tegra/Makefile +++ b/sound/soc/tegra/Makefile | |||
@@ -16,10 +16,12 @@ obj-$(CONFIG_SND_SOC_TEGRA30_AHUB) += snd-soc-tegra30-ahub.o | |||
16 | obj-$(CONFIG_SND_SOC_TEGRA30_I2S) += snd-soc-tegra30-i2s.o | 16 | obj-$(CONFIG_SND_SOC_TEGRA30_I2S) += snd-soc-tegra30-i2s.o |
17 | 17 | ||
18 | # Tegra machine Support | 18 | # Tegra machine Support |
19 | snd-soc-tegra-wm8753-objs := tegra_wm8753.o | ||
19 | snd-soc-tegra-wm8903-objs := tegra_wm8903.o | 20 | snd-soc-tegra-wm8903-objs := tegra_wm8903.o |
20 | snd-soc-tegra-trimslice-objs := trimslice.o | 21 | snd-soc-tegra-trimslice-objs := trimslice.o |
21 | snd-soc-tegra-alc5632-objs := tegra_alc5632.o | 22 | snd-soc-tegra-alc5632-objs := tegra_alc5632.o |
22 | 23 | ||
24 | obj-$(CONFIG_SND_SOC_TEGRA_WM8753) += snd-soc-tegra-wm8753.o | ||
23 | obj-$(CONFIG_SND_SOC_TEGRA_WM8903) += snd-soc-tegra-wm8903.o | 25 | obj-$(CONFIG_SND_SOC_TEGRA_WM8903) += snd-soc-tegra-wm8903.o |
24 | obj-$(CONFIG_SND_SOC_TEGRA_TRIMSLICE) += snd-soc-tegra-trimslice.o | 26 | obj-$(CONFIG_SND_SOC_TEGRA_TRIMSLICE) += snd-soc-tegra-trimslice.o |
25 | obj-$(CONFIG_SND_SOC_TEGRA_ALC5632) += snd-soc-tegra-alc5632.o | 27 | obj-$(CONFIG_SND_SOC_TEGRA_ALC5632) += snd-soc-tegra-alc5632.o |
diff --git a/sound/soc/tegra/tegra_wm8753.c b/sound/soc/tegra/tegra_wm8753.c new file mode 100644 index 000000000000..4e77026807a2 --- /dev/null +++ b/sound/soc/tegra/tegra_wm8753.c | |||
@@ -0,0 +1,224 @@ | |||
1 | /* | ||
2 | * tegra_wm8753.c - Tegra machine ASoC driver for boards using WM8753 codec. | ||
3 | * | ||
4 | * Author: Stephen Warren <swarren@nvidia.com> | ||
5 | * Copyright (C) 2010-2012 - NVIDIA, Inc. | ||
6 | * | ||
7 | * Based on code copyright/by: | ||
8 | * | ||
9 | * (c) 2009, 2010 Nvidia Graphics Pvt. Ltd. | ||
10 | * | ||
11 | * Copyright 2007 Wolfson Microelectronics PLC. | ||
12 | * Author: Graeme Gregory | ||
13 | * graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com | ||
14 | * | ||
15 | * This program is free software; you can redistribute it and/or | ||
16 | * modify it under the terms of the GNU General Public License | ||
17 | * version 2 as published by the Free Software Foundation. | ||
18 | * | ||
19 | * This program is distributed in the hope that it will be useful, but | ||
20 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
22 | * General Public License for more details. | ||
23 | * | ||
24 | * You should have received a copy of the GNU General Public License | ||
25 | * along with this program; if not, write to the Free Software | ||
26 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
27 | * 02110-1301 USA | ||
28 | * | ||
29 | */ | ||
30 | |||
31 | #include <asm/mach-types.h> | ||
32 | |||
33 | #include <linux/module.h> | ||
34 | #include <linux/platform_device.h> | ||
35 | #include <linux/slab.h> | ||
36 | #include <linux/gpio.h> | ||
37 | #include <linux/of_gpio.h> | ||
38 | |||
39 | #include <sound/core.h> | ||
40 | #include <sound/jack.h> | ||
41 | #include <sound/pcm.h> | ||
42 | #include <sound/pcm_params.h> | ||
43 | #include <sound/soc.h> | ||
44 | |||
45 | #include "../codecs/wm8753.h" | ||
46 | |||
47 | #include "tegra_asoc_utils.h" | ||
48 | |||
49 | #define DRV_NAME "tegra-snd-wm8753" | ||
50 | |||
51 | struct tegra_wm8753 { | ||
52 | struct tegra_asoc_utils_data util_data; | ||
53 | }; | ||
54 | |||
55 | static int tegra_wm8753_hw_params(struct snd_pcm_substream *substream, | ||
56 | struct snd_pcm_hw_params *params) | ||
57 | { | ||
58 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
59 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
60 | struct snd_soc_codec *codec = rtd->codec; | ||
61 | struct snd_soc_card *card = codec->card; | ||
62 | struct tegra_wm8753 *machine = snd_soc_card_get_drvdata(card); | ||
63 | int srate, mclk; | ||
64 | int err; | ||
65 | |||
66 | srate = params_rate(params); | ||
67 | switch (srate) { | ||
68 | case 11025: | ||
69 | case 22050: | ||
70 | case 44100: | ||
71 | case 88200: | ||
72 | mclk = 11289600; | ||
73 | break; | ||
74 | default: | ||
75 | mclk = 12288000; | ||
76 | break; | ||
77 | } | ||
78 | |||
79 | err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk); | ||
80 | if (err < 0) { | ||
81 | dev_err(card->dev, "Can't configure clocks\n"); | ||
82 | return err; | ||
83 | } | ||
84 | |||
85 | err = snd_soc_dai_set_sysclk(codec_dai, WM8753_MCLK, mclk, | ||
86 | SND_SOC_CLOCK_IN); | ||
87 | if (err < 0) { | ||
88 | dev_err(card->dev, "codec_dai clock not set\n"); | ||
89 | return err; | ||
90 | } | ||
91 | |||
92 | return 0; | ||
93 | } | ||
94 | |||
95 | static struct snd_soc_ops tegra_wm8753_ops = { | ||
96 | .hw_params = tegra_wm8753_hw_params, | ||
97 | }; | ||
98 | |||
99 | static const struct snd_soc_dapm_widget tegra_wm8753_dapm_widgets[] = { | ||
100 | SND_SOC_DAPM_HP("Headphone Jack", NULL), | ||
101 | SND_SOC_DAPM_MIC("Mic Jack", NULL), | ||
102 | }; | ||
103 | |||
104 | static struct snd_soc_dai_link tegra_wm8753_dai = { | ||
105 | .name = "WM8753", | ||
106 | .stream_name = "WM8753 PCM", | ||
107 | .codec_dai_name = "wm8753-hifi", | ||
108 | .ops = &tegra_wm8753_ops, | ||
109 | .dai_fmt = SND_SOC_DAIFMT_I2S | | ||
110 | SND_SOC_DAIFMT_NB_NF | | ||
111 | SND_SOC_DAIFMT_CBS_CFS, | ||
112 | }; | ||
113 | |||
114 | static struct snd_soc_card snd_soc_tegra_wm8753 = { | ||
115 | .name = "tegra-wm8753", | ||
116 | .owner = THIS_MODULE, | ||
117 | .dai_link = &tegra_wm8753_dai, | ||
118 | .num_links = 1, | ||
119 | |||
120 | .dapm_widgets = tegra_wm8753_dapm_widgets, | ||
121 | .num_dapm_widgets = ARRAY_SIZE(tegra_wm8753_dapm_widgets), | ||
122 | .fully_routed = true, | ||
123 | }; | ||
124 | |||
125 | static __devinit int tegra_wm8753_driver_probe(struct platform_device *pdev) | ||
126 | { | ||
127 | struct snd_soc_card *card = &snd_soc_tegra_wm8753; | ||
128 | struct tegra_wm8753 *machine; | ||
129 | int ret; | ||
130 | |||
131 | machine = devm_kzalloc(&pdev->dev, sizeof(struct tegra_wm8753), | ||
132 | GFP_KERNEL); | ||
133 | if (!machine) { | ||
134 | dev_err(&pdev->dev, "Can't allocate tegra_wm8753 struct\n"); | ||
135 | ret = -ENOMEM; | ||
136 | goto err; | ||
137 | } | ||
138 | |||
139 | card->dev = &pdev->dev; | ||
140 | platform_set_drvdata(pdev, card); | ||
141 | snd_soc_card_set_drvdata(card, machine); | ||
142 | |||
143 | ret = snd_soc_of_parse_card_name(card, "nvidia,model"); | ||
144 | if (ret) | ||
145 | goto err; | ||
146 | |||
147 | ret = snd_soc_of_parse_audio_routing(card, "nvidia,audio-routing"); | ||
148 | if (ret) | ||
149 | goto err; | ||
150 | |||
151 | tegra_wm8753_dai.codec_of_node = of_parse_phandle( | ||
152 | pdev->dev.of_node, "nvidia,audio-codec", 0); | ||
153 | if (!tegra_wm8753_dai.codec_of_node) { | ||
154 | dev_err(&pdev->dev, | ||
155 | "Property 'nvidia,audio-codec' missing or invalid\n"); | ||
156 | ret = -EINVAL; | ||
157 | goto err; | ||
158 | } | ||
159 | |||
160 | tegra_wm8753_dai.cpu_dai_of_node = of_parse_phandle( | ||
161 | pdev->dev.of_node, "nvidia,i2s-controller", 0); | ||
162 | if (!tegra_wm8753_dai.cpu_dai_of_node) { | ||
163 | dev_err(&pdev->dev, | ||
164 | "Property 'nvidia,i2s-controller' missing or invalid\n"); | ||
165 | ret = -EINVAL; | ||
166 | goto err; | ||
167 | } | ||
168 | |||
169 | tegra_wm8753_dai.platform_of_node = | ||
170 | tegra_wm8753_dai.cpu_dai_of_node; | ||
171 | |||
172 | ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev); | ||
173 | if (ret) | ||
174 | goto err; | ||
175 | |||
176 | ret = snd_soc_register_card(card); | ||
177 | if (ret) { | ||
178 | dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", | ||
179 | ret); | ||
180 | goto err_fini_utils; | ||
181 | } | ||
182 | |||
183 | return 0; | ||
184 | |||
185 | err_fini_utils: | ||
186 | tegra_asoc_utils_fini(&machine->util_data); | ||
187 | err: | ||
188 | return ret; | ||
189 | } | ||
190 | |||
191 | static int __devexit tegra_wm8753_driver_remove(struct platform_device *pdev) | ||
192 | { | ||
193 | struct snd_soc_card *card = platform_get_drvdata(pdev); | ||
194 | struct tegra_wm8753 *machine = snd_soc_card_get_drvdata(card); | ||
195 | |||
196 | snd_soc_unregister_card(card); | ||
197 | |||
198 | tegra_asoc_utils_fini(&machine->util_data); | ||
199 | |||
200 | return 0; | ||
201 | } | ||
202 | |||
203 | static const struct of_device_id tegra_wm8753_of_match[] __devinitconst = { | ||
204 | { .compatible = "nvidia,tegra-audio-wm8753", }, | ||
205 | {}, | ||
206 | }; | ||
207 | |||
208 | static struct platform_driver tegra_wm8753_driver = { | ||
209 | .driver = { | ||
210 | .name = DRV_NAME, | ||
211 | .owner = THIS_MODULE, | ||
212 | .pm = &snd_soc_pm_ops, | ||
213 | .of_match_table = tegra_wm8753_of_match, | ||
214 | }, | ||
215 | .probe = tegra_wm8753_driver_probe, | ||
216 | .remove = __devexit_p(tegra_wm8753_driver_remove), | ||
217 | }; | ||
218 | module_platform_driver(tegra_wm8753_driver); | ||
219 | |||
220 | MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>"); | ||
221 | MODULE_DESCRIPTION("Tegra+WM8753 machine ASoC driver"); | ||
222 | MODULE_LICENSE("GPL"); | ||
223 | MODULE_ALIAS("platform:" DRV_NAME); | ||
224 | MODULE_DEVICE_TABLE(of, tegra_wm8753_of_match); | ||