]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - sound/soc/fsl/imx-si476x.c
ARM: dts: imx6-tx6*: fix 'flexcan' labels
[karo-tx-linux.git] / sound / soc / fsl / imx-si476x.c
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_tdm_slot(cpu_dai,
60                         channels == 1 ? 0xfffffffe : 0xfffffffc,
61                         channels == 1 ? 0xfffffffe : 0xfffffffc,
62                         2, 32);
63         if (ret) {
64                 dev_err(cpu_dai->dev, "failed to set dai tdm slot\n");
65                 return ret;
66         }
67
68         ret = snd_soc_dai_set_sysclk(cpu_dai, 0, bclk, SND_SOC_CLOCK_OUT);
69         if (ret)
70                 dev_err(cpu_dai->dev, "failed to set sysclk\n");
71
72         return ret;
73 }
74
75 static struct snd_soc_ops imx_si476x_ops = {
76         .hw_params = imx_si476x_hw_params,
77 };
78
79 static struct snd_soc_dai_link imx_dai = {
80         .name = "imx-si476x",
81         .stream_name = "imx-si476x",
82         .codec_dai_name = "si476x-codec",
83         .codec_name = "si476x-codec.99",
84         .ops = &imx_si476x_ops,
85 };
86
87 static struct snd_soc_card snd_soc_card_imx_3stack = {
88         .name = "imx-audio-si476x",
89         .dai_link = &imx_dai,
90         .num_links = 1,
91 };
92
93 static int imx_si476x_probe(struct platform_device *pdev)
94 {
95         struct snd_soc_card *card = &snd_soc_card_imx_3stack;
96         struct device_node *ssi_np, *np = pdev->dev.of_node;
97         struct platform_device *ssi_pdev;
98         int int_port, ext_port, ret;
99
100         ret = of_property_read_u32(np, "mux-int-port", &int_port);
101         if (ret) {
102                 dev_err(&pdev->dev, "mux-int-port missing or invalid\n");
103                 return ret;
104         }
105
106         ret = of_property_read_u32(np, "mux-ext-port", &ext_port);
107         if (ret) {
108                 dev_err(&pdev->dev, "mux-ext-port missing or invalid\n");
109                 return ret;
110         }
111
112         imx_audmux_config(int_port, ext_port);
113
114         ssi_np = of_parse_phandle(pdev->dev.of_node, "ssi-controller", 0);
115         if (!ssi_np) {
116                 dev_err(&pdev->dev, "phandle missing or invalid\n");
117                 return -EINVAL;
118         }
119
120         ssi_pdev = of_find_device_by_node(ssi_np);
121         if (!ssi_pdev) {
122                 dev_err(&pdev->dev, "failed to find SSI platform device\n");
123                 ret = -EINVAL;
124                 goto end;
125         }
126
127         card->dev = &pdev->dev;
128         card->dai_link->cpu_dai_name = dev_name(&ssi_pdev->dev);
129         card->dai_link->platform_of_node = ssi_np;
130
131         ret = snd_soc_register_card(card);
132         if (ret)
133                 dev_err(&pdev->dev, "Failed to register card: %d\n", ret);
134
135 end:
136         if (ssi_np)
137                 of_node_put(ssi_np);
138
139         return ret;
140 }
141
142 static int imx_si476x_remove(struct platform_device *pdev)
143 {
144         struct snd_soc_card *card = &snd_soc_card_imx_3stack;
145
146         snd_soc_unregister_card(card);
147
148         return 0;
149 }
150
151 static const struct of_device_id imx_si476x_dt_ids[] = {
152         { .compatible = "fsl,imx-audio-si476x", },
153         { /* sentinel */ }
154 };
155 MODULE_DEVICE_TABLE(of, imx_si476x_dt_ids);
156
157 static struct platform_driver imx_si476x_driver = {
158         .driver = {
159                 .name = "imx-tuner-si476x",
160                 .owner = THIS_MODULE,
161                 .of_match_table = imx_si476x_dt_ids,
162         },
163         .probe = imx_si476x_probe,
164         .remove = imx_si476x_remove,
165 };
166
167 module_platform_driver(imx_si476x_driver);
168
169 /* Module information */
170 MODULE_AUTHOR("Freescale Semiconductor, Inc.");
171 MODULE_DESCRIPTION("ALSA SoC i.MX si476x");
172 MODULE_LICENSE("GPL");
173 MODULE_ALIAS("platform:imx-tuner-si476x");