diff options
author | Nicolin Chen <b42378@freescale.com> | 2013-08-23 07:55:00 -0400 |
---|---|---|
committer | Nitin Garg <nitin.garg@freescale.com> | 2014-04-16 09:01:32 -0400 |
commit | a80597788c18a800efbee9ec7fc9c8e5dbb550e2 (patch) | |
tree | c860d80cdb95eccb86d8c946fb5bcbdc78c93d6a | |
parent | 23e369b88b546d7b699ca9ec46e195a05c61b717 (diff) |
ENGR00276567-7 ASoC: fsl: Add si476x machine driver
Add si476x machine dirver for i.MX series SoC and binding doc.
Signed-off-by: Nicolin Chen <b42378@freescale.com>
-rw-r--r-- | Documentation/devicetree/bindings/sound/imx-audio-si476x.txt | 24 | ||||
-rw-r--r-- | sound/soc/fsl/Kconfig | 12 | ||||
-rw-r--r-- | sound/soc/fsl/Makefile | 2 | ||||
-rw-r--r-- | sound/soc/fsl/imx-si476x.c | 164 |
4 files changed, 202 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/sound/imx-audio-si476x.txt b/Documentation/devicetree/bindings/sound/imx-audio-si476x.txt new file mode 100644 index 000000000000..53cd34afe6b8 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/imx-audio-si476x.txt | |||
@@ -0,0 +1,24 @@ | |||
1 | Freescale i.MX audio complex with si476x codec | ||
2 | |||
3 | Required properties: | ||
4 | - compatible : "fsl,imx-audio-si476x" | ||
5 | - model : The user-visible name of this sound complex | ||
6 | - ssi-controller : The phandle of the i.MX SSI controller | ||
7 | |||
8 | - mux-int-port : The internal port of the i.MX audio muxer (AUDMUX) | ||
9 | - mux-ext-port : The external port of the i.MX audio muxer | ||
10 | |||
11 | Note: The AUDMUX port numbering should start at 1, which is consistent with | ||
12 | hardware manual. | ||
13 | |||
14 | Example: | ||
15 | |||
16 | sound { | ||
17 | compatible = "fsl,imx-audio-si476x", | ||
18 | "fsl,imx-tuner-si476x"; | ||
19 | model = "imx-radio-si476x"; | ||
20 | |||
21 | ssi-controller = <&ssi1>; | ||
22 | mux-int-port = <2>; | ||
23 | mux-ext-port = <5>; | ||
24 | }; | ||
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index d3d54e565d64..0c9f147da49f 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig | |||
@@ -221,4 +221,16 @@ config SND_SOC_IMX_MC13783 | |||
221 | select SND_SOC_MC13783 | 221 | select SND_SOC_MC13783 |
222 | select SND_SOC_IMX_PCM_DMA | 222 | select SND_SOC_IMX_PCM_DMA |
223 | 223 | ||
224 | config SND_SOC_IMX_SI476X | ||
225 | tristate "SoC Audio support for i.MX boards with si476x" | ||
226 | select SND_SOC_IMX_PCM_DMA | ||
227 | select SND_SOC_IMX_AUDMUX | ||
228 | select SND_SOC_FSL_SSI | ||
229 | select SND_SOC_FSL_UTILS | ||
230 | select SND_SOC_SI476X | ||
231 | help | ||
232 | SoC Audio support for i.MX boards with SI476x | ||
233 | Say Y if you want to add support for Soc audio for the AMFM Tuner chip | ||
234 | SI476x module. | ||
235 | |||
224 | endif # SND_IMX_SOC | 236 | endif # SND_IMX_SOC |
diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile index 79a6858bb61d..72f812e8cdb6 100644 --- a/sound/soc/fsl/Makefile +++ b/sound/soc/fsl/Makefile | |||
@@ -53,6 +53,7 @@ snd-soc-imx-cs42888-objs := imx-cs42888.o | |||
53 | snd-soc-imx-sgtl5000-objs := imx-sgtl5000.o | 53 | snd-soc-imx-sgtl5000-objs := imx-sgtl5000.o |
54 | snd-soc-imx-wm8962-objs := imx-wm8962.o | 54 | snd-soc-imx-wm8962-objs := imx-wm8962.o |
55 | snd-soc-imx-mc13783-objs := imx-mc13783.o | 55 | snd-soc-imx-mc13783-objs := imx-mc13783.o |
56 | snd-soc-imx-si476x-objs := imx-si476x.o | ||
56 | 57 | ||
57 | obj-$(CONFIG_SND_SOC_EUKREA_TLV320) += snd-soc-eukrea-tlv320.o | 58 | obj-$(CONFIG_SND_SOC_EUKREA_TLV320) += snd-soc-eukrea-tlv320.o |
58 | obj-$(CONFIG_SND_SOC_PHYCORE_AC97) += snd-soc-phycore-ac97.o | 59 | obj-$(CONFIG_SND_SOC_PHYCORE_AC97) += snd-soc-phycore-ac97.o |
@@ -62,3 +63,4 @@ obj-$(CONFIG_SND_SOC_IMX_CS42888) += snd-soc-imx-cs42888.o | |||
62 | obj-$(CONFIG_SND_SOC_IMX_SGTL5000) += snd-soc-imx-sgtl5000.o | 63 | obj-$(CONFIG_SND_SOC_IMX_SGTL5000) += snd-soc-imx-sgtl5000.o |
63 | obj-$(CONFIG_SND_SOC_IMX_WM8962) += snd-soc-imx-wm8962.o | 64 | obj-$(CONFIG_SND_SOC_IMX_WM8962) += snd-soc-imx-wm8962.o |
64 | obj-$(CONFIG_SND_SOC_IMX_MC13783) += snd-soc-imx-mc13783.o | 65 | obj-$(CONFIG_SND_SOC_IMX_MC13783) += snd-soc-imx-mc13783.o |
66 | obj-$(CONFIG_SND_SOC_IMX_SI476X) += snd-soc-imx-si476x.o | ||
diff --git a/sound/soc/fsl/imx-si476x.c b/sound/soc/fsl/imx-si476x.c new file mode 100644 index 000000000000..d3febf80af59 --- /dev/null +++ b/sound/soc/fsl/imx-si476x.c | |||
@@ -0,0 +1,164 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2008-2013 Freescale Semiconductor, Inc. All Rights Reserved. | ||
3 | */ | ||
4 | |||
5 | /* | ||
6 | * The code contained herein is licensed under the GNU General Public | ||
7 | * License. You may obtain a copy of the GNU General Public License | ||
8 | * Version 2 or later at the following locations: | ||
9 | * | ||
10 | * http://www.opensource.org/licenses/gpl-license.html | ||
11 | * http://www.gnu.org/copyleft/gpl.html | ||
12 | */ | ||
13 | |||
14 | #include <linux/module.h> | ||
15 | #include <linux/of_platform.h> | ||
16 | #include <sound/soc.h> | ||
17 | |||
18 | #include "imx-audmux.h" | ||
19 | |||
20 | static int imx_audmux_config(int slave, int master) | ||
21 | { | ||
22 | unsigned int ptcr, pdcr; | ||
23 | slave = slave - 1; | ||
24 | master = master - 1; | ||
25 | |||
26 | ptcr = IMX_AUDMUX_V2_PTCR_SYN | | ||
27 | IMX_AUDMUX_V2_PTCR_TFSDIR | | ||
28 | IMX_AUDMUX_V2_PTCR_TFSEL(slave) | | ||
29 | IMX_AUDMUX_V2_PTCR_TCLKDIR | | ||
30 | IMX_AUDMUX_V2_PTCR_TCSEL(slave); | ||
31 | pdcr = IMX_AUDMUX_V2_PDCR_RXDSEL(slave); | ||
32 | imx_audmux_v2_configure_port(master, ptcr, pdcr); | ||
33 | |||
34 | ptcr = IMX_AUDMUX_V2_PTCR_SYN; | ||
35 | pdcr = IMX_AUDMUX_V2_PDCR_RXDSEL(master); | ||
36 | imx_audmux_v2_configure_port(slave, ptcr, pdcr); | ||
37 | |||
38 | return 0; | ||
39 | } | ||
40 | |||
41 | static int imx_si476x_hw_params(struct snd_pcm_substream *substream, | ||
42 | struct snd_pcm_hw_params *params) | ||
43 | { | ||
44 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
45 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
46 | u32 channels = params_channels(params); | ||
47 | u32 rate = params_rate(params); | ||
48 | u32 bclk = rate * channels * 32; | ||
49 | int ret = 0; | ||
50 | |||
51 | /* set cpu DAI configuration */ | ||
52 | ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | ||
53 | | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); | ||
54 | if (ret) { | ||
55 | dev_err(cpu_dai->dev, "failed to set dai fmt\n"); | ||
56 | return ret; | ||
57 | } | ||
58 | |||
59 | ret = snd_soc_dai_set_sysclk(cpu_dai, 0, bclk, SND_SOC_CLOCK_OUT); | ||
60 | if (ret) | ||
61 | dev_err(cpu_dai->dev, "failed to set sysclk\n"); | ||
62 | |||
63 | return ret; | ||
64 | } | ||
65 | |||
66 | static struct snd_soc_ops imx_si476x_ops = { | ||
67 | .hw_params = imx_si476x_hw_params, | ||
68 | }; | ||
69 | |||
70 | static struct snd_soc_dai_link imx_dai = { | ||
71 | .name = "imx-si476x", | ||
72 | .stream_name = "imx-si476x", | ||
73 | .codec_dai_name = "si476x-codec", | ||
74 | .codec_name = "si476x-codec.99", | ||
75 | .ops = &imx_si476x_ops, | ||
76 | }; | ||
77 | |||
78 | static struct snd_soc_card snd_soc_card_imx_3stack = { | ||
79 | .name = "imx-audio-si476x", | ||
80 | .dai_link = &imx_dai, | ||
81 | .num_links = 1, | ||
82 | }; | ||
83 | |||
84 | static int imx_si476x_probe(struct platform_device *pdev) | ||
85 | { | ||
86 | struct snd_soc_card *card = &snd_soc_card_imx_3stack; | ||
87 | struct device_node *ssi_np, *np = pdev->dev.of_node; | ||
88 | struct platform_device *ssi_pdev; | ||
89 | int int_port, ext_port, ret; | ||
90 | |||
91 | ret = of_property_read_u32(np, "mux-int-port", &int_port); | ||
92 | if (ret) { | ||
93 | dev_err(&pdev->dev, "mux-int-port missing or invalid\n"); | ||
94 | return ret; | ||
95 | } | ||
96 | |||
97 | ret = of_property_read_u32(np, "mux-ext-port", &ext_port); | ||
98 | if (ret) { | ||
99 | dev_err(&pdev->dev, "mux-ext-port missing or invalid\n"); | ||
100 | return ret; | ||
101 | } | ||
102 | |||
103 | imx_audmux_config(int_port, ext_port); | ||
104 | |||
105 | ssi_np = of_parse_phandle(pdev->dev.of_node, "ssi-controller", 0); | ||
106 | if (!ssi_np) { | ||
107 | dev_err(&pdev->dev, "phandle missing or invalid\n"); | ||
108 | return -EINVAL; | ||
109 | } | ||
110 | |||
111 | ssi_pdev = of_find_device_by_node(ssi_np); | ||
112 | if (!ssi_pdev) { | ||
113 | dev_err(&pdev->dev, "failed to find SSI platform device\n"); | ||
114 | ret = -EINVAL; | ||
115 | goto end; | ||
116 | } | ||
117 | |||
118 | card->dev = &pdev->dev; | ||
119 | card->dai_link->cpu_dai_name = dev_name(&ssi_pdev->dev); | ||
120 | card->dai_link->platform_of_node = ssi_np; | ||
121 | |||
122 | ret = snd_soc_register_card(card); | ||
123 | if (ret) | ||
124 | dev_err(&pdev->dev, "Failed to register card: %d\n", ret); | ||
125 | |||
126 | end: | ||
127 | if (ssi_np) | ||
128 | of_node_put(ssi_np); | ||
129 | |||
130 | return ret; | ||
131 | } | ||
132 | |||
133 | static int imx_si476x_remove(struct platform_device *pdev) | ||
134 | { | ||
135 | struct snd_soc_card *card = &snd_soc_card_imx_3stack; | ||
136 | |||
137 | snd_soc_unregister_card(card); | ||
138 | |||
139 | return 0; | ||
140 | } | ||
141 | |||
142 | static const struct of_device_id imx_si476x_dt_ids[] = { | ||
143 | { .compatible = "fsl,imx-audio-si476x", }, | ||
144 | { /* sentinel */ } | ||
145 | }; | ||
146 | MODULE_DEVICE_TABLE(of, imx_si476x_dt_ids); | ||
147 | |||
148 | static struct platform_driver imx_si476x_driver = { | ||
149 | .driver = { | ||
150 | .name = "imx-tuner-si476x", | ||
151 | .owner = THIS_MODULE, | ||
152 | .of_match_table = imx_si476x_dt_ids, | ||
153 | }, | ||
154 | .probe = imx_si476x_probe, | ||
155 | .remove = imx_si476x_remove, | ||
156 | }; | ||
157 | |||
158 | module_platform_driver(imx_si476x_driver); | ||
159 | |||
160 | /* Module information */ | ||
161 | MODULE_AUTHOR("Freescale Semiconductor, Inc."); | ||
162 | MODULE_DESCRIPTION("ALSA SoC i.MX si476x"); | ||
163 | MODULE_LICENSE("GPL"); | ||
164 | MODULE_ALIAS("platform:imx-tuner-si476x"); | ||