~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/sound/soc/fsl/imx-es8328.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0+
  2 //
  3 // Copyright 2012 Freescale Semiconductor, Inc.
  4 // Copyright 2012 Linaro Ltd.
  5 
  6 #include <linux/gpio/consumer.h>
  7 #include <linux/module.h>
  8 #include <linux/of.h>
  9 #include <linux/of_platform.h>
 10 #include <linux/i2c.h>
 11 #include <sound/soc.h>
 12 #include <sound/jack.h>
 13 
 14 #include "imx-audmux.h"
 15 
 16 #define DAI_NAME_SIZE   32
 17 #define MUX_PORT_MAX    7
 18 
 19 struct imx_es8328_data {
 20         struct device *dev;
 21         struct snd_soc_dai_link dai;
 22         struct snd_soc_card card;
 23         char codec_dai_name[DAI_NAME_SIZE];
 24         char platform_name[DAI_NAME_SIZE];
 25         struct gpio_desc *jack_gpiod;
 26 };
 27 
 28 static struct snd_soc_jack_gpio headset_jack_gpios[] = {
 29         {
 30                 .name = "headset-gpio",
 31                 .report = SND_JACK_HEADSET,
 32                 .invert = 0,
 33                 .debounce_time = 200,
 34         },
 35 };
 36 
 37 static struct snd_soc_jack headset_jack;
 38 static struct snd_soc_jack_pin headset_jack_pins[] = {
 39         {
 40                 .pin = "Headphone",
 41                 .mask = SND_JACK_HEADPHONE,
 42         },
 43         {
 44                 .pin = "Mic Jack",
 45                 .mask = SND_JACK_MICROPHONE,
 46         },
 47 };
 48 
 49 static int imx_es8328_dai_init(struct snd_soc_pcm_runtime *rtd)
 50 {
 51         struct imx_es8328_data *data = container_of(rtd->card,
 52                                         struct imx_es8328_data, card);
 53         int ret = 0;
 54 
 55         if (data->jack_gpiod) {
 56                 /* Headphone jack detection */
 57                 ret = snd_soc_card_jack_new_pins(rtd->card, "Headphone",
 58                                                  SND_JACK_HEADSET | SND_JACK_BTN_0,
 59                                                  &headset_jack,
 60                                                  headset_jack_pins,
 61                                                  ARRAY_SIZE(headset_jack_pins));
 62                 if (ret)
 63                         return ret;
 64 
 65                 headset_jack_gpios[0].desc = data->jack_gpiod;
 66                 ret = snd_soc_jack_add_gpios(&headset_jack,
 67                                              ARRAY_SIZE(headset_jack_gpios),
 68                                              headset_jack_gpios);
 69         }
 70 
 71         return ret;
 72 }
 73 
 74 static const struct snd_soc_dapm_widget imx_es8328_dapm_widgets[] = {
 75         SND_SOC_DAPM_MIC("Mic Jack", NULL),
 76         SND_SOC_DAPM_HP("Headphone", NULL),
 77         SND_SOC_DAPM_SPK("Speaker", NULL),
 78         SND_SOC_DAPM_REGULATOR_SUPPLY("audio-amp", 1, 0),
 79 };
 80 
 81 static const struct snd_kcontrol_new imx_es8328_controls[] = {
 82         SOC_DAPM_PIN_SWITCH("Headphone"),
 83         SOC_DAPM_PIN_SWITCH("Mic Jack"),
 84 };
 85 
 86 static int imx_es8328_probe(struct platform_device *pdev)
 87 {
 88         struct device_node *np = pdev->dev.of_node;
 89         struct device_node *ssi_np = NULL, *codec_np = NULL;
 90         struct platform_device *ssi_pdev;
 91         struct imx_es8328_data *data;
 92         struct snd_soc_dai_link_component *comp;
 93         u32 int_port, ext_port;
 94         int ret;
 95         struct device *dev = &pdev->dev;
 96 
 97         ret = of_property_read_u32(np, "mux-int-port", &int_port);
 98         if (ret) {
 99                 dev_err(dev, "mux-int-port missing or invalid\n");
100                 goto fail;
101         }
102         if (int_port > MUX_PORT_MAX || int_port == 0) {
103                 dev_err(dev, "mux-int-port: hardware only has %d mux ports\n",
104                         MUX_PORT_MAX);
105                 ret = -EINVAL;
106                 goto fail;
107         }
108 
109         ret = of_property_read_u32(np, "mux-ext-port", &ext_port);
110         if (ret) {
111                 dev_err(dev, "mux-ext-port missing or invalid\n");
112                 goto fail;
113         }
114         if (ext_port > MUX_PORT_MAX || ext_port == 0) {
115                 dev_err(dev, "mux-ext-port: hardware only has %d mux ports\n",
116                         MUX_PORT_MAX);
117                 ret = -EINVAL;
118                 goto fail;
119         }
120 
121         /*
122          * The port numbering in the hardware manual starts at 1, while
123          * the audmux API expects it starts at 0.
124          */
125         int_port--;
126         ext_port--;
127         ret = imx_audmux_v2_configure_port(int_port,
128                         IMX_AUDMUX_V2_PTCR_SYN |
129                         IMX_AUDMUX_V2_PTCR_TFSEL(ext_port) |
130                         IMX_AUDMUX_V2_PTCR_TCSEL(ext_port) |
131                         IMX_AUDMUX_V2_PTCR_TFSDIR |
132                         IMX_AUDMUX_V2_PTCR_TCLKDIR,
133                         IMX_AUDMUX_V2_PDCR_RXDSEL(ext_port));
134         if (ret) {
135                 dev_err(dev, "audmux internal port setup failed\n");
136                 return ret;
137         }
138         ret = imx_audmux_v2_configure_port(ext_port,
139                         IMX_AUDMUX_V2_PTCR_SYN,
140                         IMX_AUDMUX_V2_PDCR_RXDSEL(int_port));
141         if (ret) {
142                 dev_err(dev, "audmux external port setup failed\n");
143                 return ret;
144         }
145 
146         ssi_np = of_parse_phandle(pdev->dev.of_node, "ssi-controller", 0);
147         codec_np = of_parse_phandle(pdev->dev.of_node, "audio-codec", 0);
148         if (!ssi_np || !codec_np) {
149                 dev_err(dev, "phandle missing or invalid\n");
150                 ret = -EINVAL;
151                 goto fail;
152         }
153 
154         ssi_pdev = of_find_device_by_node(ssi_np);
155         if (!ssi_pdev) {
156                 dev_err(dev, "failed to find SSI platform device\n");
157                 ret = -EINVAL;
158                 goto fail;
159         }
160 
161         data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
162         if (!data) {
163                 ret = -ENOMEM;
164                 goto put_device;
165         }
166 
167         comp = devm_kzalloc(dev, 2 * sizeof(*comp), GFP_KERNEL);
168         if (!comp) {
169                 ret = -ENOMEM;
170                 goto put_device;
171         }
172 
173         data->dev = dev;
174 
175         data->jack_gpiod = devm_gpiod_get_optional(dev, "jack", GPIOD_IN);
176         if (IS_ERR(data->jack_gpiod)) {
177                 ret = PTR_ERR(data->jack_gpiod);
178                 goto put_device;
179         }
180 
181         /*
182          * CPU == Platform
183          * platform is using soc-generic-dmaengine-pcm
184          */
185         data->dai.cpus          =
186         data->dai.platforms     = &comp[0];
187         data->dai.codecs        = &comp[1];
188 
189         data->dai.num_cpus      = 1;
190         data->dai.num_codecs    = 1;
191         data->dai.num_platforms = 1;
192 
193         data->dai.name = "hifi";
194         data->dai.stream_name = "hifi";
195         data->dai.codecs->dai_name = "es8328-hifi-analog";
196         data->dai.codecs->of_node = codec_np;
197         data->dai.cpus->of_node = ssi_np;
198         data->dai.init = &imx_es8328_dai_init;
199         data->dai.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
200                             SND_SOC_DAIFMT_CBP_CFP;
201 
202         data->card.dev = dev;
203         data->card.dapm_widgets = imx_es8328_dapm_widgets;
204         data->card.num_dapm_widgets = ARRAY_SIZE(imx_es8328_dapm_widgets);
205         data->card.controls = imx_es8328_controls;
206         data->card.num_controls = ARRAY_SIZE(imx_es8328_controls);
207         ret = snd_soc_of_parse_card_name(&data->card, "model");
208         if (ret) {
209                 dev_err(dev, "Unable to parse card name\n");
210                 goto put_device;
211         }
212         ret = snd_soc_of_parse_audio_routing(&data->card, "audio-routing");
213         if (ret) {
214                 dev_err(dev, "Unable to parse routing: %d\n", ret);
215                 goto put_device;
216         }
217         data->card.num_links = 1;
218         data->card.owner = THIS_MODULE;
219         data->card.dai_link = &data->dai;
220 
221         ret = devm_snd_soc_register_card(&pdev->dev, &data->card);
222         if (ret) {
223                 dev_err(dev, "Unable to register: %d\n", ret);
224                 goto put_device;
225         }
226 
227         platform_set_drvdata(pdev, data);
228 put_device:
229         put_device(&ssi_pdev->dev);
230 fail:
231         of_node_put(ssi_np);
232         of_node_put(codec_np);
233 
234         return ret;
235 }
236 
237 static const struct of_device_id imx_es8328_dt_ids[] = {
238         { .compatible = "fsl,imx-audio-es8328", },
239         { /* sentinel */ }
240 };
241 MODULE_DEVICE_TABLE(of, imx_es8328_dt_ids);
242 
243 static struct platform_driver imx_es8328_driver = {
244         .driver = {
245                 .name = "imx-es8328",
246                 .of_match_table = imx_es8328_dt_ids,
247         },
248         .probe = imx_es8328_probe,
249 };
250 module_platform_driver(imx_es8328_driver);
251 
252 MODULE_AUTHOR("Sean Cross <xobs@kosagi.com>");
253 MODULE_DESCRIPTION("Kosagi i.MX6 ES8328 ASoC machine driver");
254 MODULE_LICENSE("GPL v2");
255 MODULE_ALIAS("platform:imx-audio-es8328");
256 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php