root/sound/soc/atmel/sam9x5_wm8731.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sam9x5_wm8731_init
  2. sam9x5_wm8731_driver_probe
  3. sam9x5_wm8731_driver_remove

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * sam9x5_wm8731   --   SoC audio for AT91SAM9X5-based boards
   4  *                      that are using WM8731 as codec.
   5  *
   6  *  Copyright (C) 2011 Atmel,
   7  *                Nicolas Ferre <nicolas.ferre@atmel.com>
   8  *
   9  *  Copyright (C) 2013 Paratronic,
  10  *                Richard Genoud <richard.genoud@gmail.com>
  11  *
  12  * Based on sam9g20_wm8731.c by:
  13  * Sedji Gaouaou <sedji.gaouaou@atmel.com>
  14  */
  15 #include <linux/of.h>
  16 #include <linux/export.h>
  17 #include <linux/module.h>
  18 #include <linux/mod_devicetable.h>
  19 #include <linux/platform_device.h>
  20 #include <linux/device.h>
  21 
  22 #include <sound/soc.h>
  23 #include <sound/soc-dai.h>
  24 #include <sound/soc-dapm.h>
  25 
  26 #include "../codecs/wm8731.h"
  27 #include "atmel_ssc_dai.h"
  28 
  29 
  30 #define MCLK_RATE 12288000
  31 
  32 #define DRV_NAME "sam9x5-snd-wm8731"
  33 
  34 struct sam9x5_drvdata {
  35         int ssc_id;
  36 };
  37 
  38 /*
  39  * Logic for a wm8731 as connected on a at91sam9x5ek based board.
  40  */
  41 static int sam9x5_wm8731_init(struct snd_soc_pcm_runtime *rtd)
  42 {
  43         struct snd_soc_dai *codec_dai = rtd->codec_dai;
  44         struct device *dev = rtd->dev;
  45         int ret;
  46 
  47         dev_dbg(dev, "%s called\n", __func__);
  48 
  49         /* set the codec system clock for DAC and ADC */
  50         ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL,
  51                                      MCLK_RATE, SND_SOC_CLOCK_IN);
  52         if (ret < 0) {
  53                 dev_err(dev, "Failed to set WM8731 SYSCLK: %d\n", ret);
  54                 return ret;
  55         }
  56 
  57         return 0;
  58 }
  59 
  60 /*
  61  * Audio paths on at91sam9x5ek board:
  62  *
  63  *  |A| ------------> |      | ---R----> Headphone Jack
  64  *  |T| <----\        |  WM  | ---L--/
  65  *  |9| ---> CLK <--> | 8731 | <--R----- Line In Jack
  66  *  |1| <------------ |      | <--L--/
  67  */
  68 static const struct snd_soc_dapm_widget sam9x5_dapm_widgets[] = {
  69         SND_SOC_DAPM_HP("Headphone Jack", NULL),
  70         SND_SOC_DAPM_LINE("Line In Jack", NULL),
  71 };
  72 
  73 static int sam9x5_wm8731_driver_probe(struct platform_device *pdev)
  74 {
  75         struct device_node *np = pdev->dev.of_node;
  76         struct device_node *codec_np, *cpu_np;
  77         struct snd_soc_card *card;
  78         struct snd_soc_dai_link *dai;
  79         struct sam9x5_drvdata *priv;
  80         struct snd_soc_dai_link_component *comp;
  81         int ret;
  82 
  83         if (!np) {
  84                 dev_err(&pdev->dev, "No device node supplied\n");
  85                 return -EINVAL;
  86         }
  87 
  88         card = devm_kzalloc(&pdev->dev, sizeof(*card), GFP_KERNEL);
  89         priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
  90         dai = devm_kzalloc(&pdev->dev, sizeof(*dai), GFP_KERNEL);
  91         comp = devm_kzalloc(&pdev->dev, 3 * sizeof(*comp), GFP_KERNEL);
  92         if (!dai || !card || !priv || !comp) {
  93                 ret = -ENOMEM;
  94                 goto out;
  95         }
  96 
  97         snd_soc_card_set_drvdata(card, priv);
  98 
  99         card->dev = &pdev->dev;
 100         card->owner = THIS_MODULE;
 101         card->dai_link = dai;
 102         card->num_links = 1;
 103         card->dapm_widgets = sam9x5_dapm_widgets;
 104         card->num_dapm_widgets = ARRAY_SIZE(sam9x5_dapm_widgets);
 105 
 106         dai->cpus = &comp[0];
 107         dai->num_cpus = 1;
 108         dai->codecs = &comp[1];
 109         dai->num_codecs = 1;
 110         dai->platforms = &comp[2];
 111         dai->num_platforms = 1;
 112 
 113         dai->name = "WM8731";
 114         dai->stream_name = "WM8731 PCM";
 115         dai->codecs->dai_name = "wm8731-hifi";
 116         dai->init = sam9x5_wm8731_init;
 117         dai->dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF
 118                 | SND_SOC_DAIFMT_CBM_CFM;
 119 
 120         ret = snd_soc_of_parse_card_name(card, "atmel,model");
 121         if (ret) {
 122                 dev_err(&pdev->dev, "atmel,model node missing\n");
 123                 goto out;
 124         }
 125 
 126         ret = snd_soc_of_parse_audio_routing(card, "atmel,audio-routing");
 127         if (ret) {
 128                 dev_err(&pdev->dev, "atmel,audio-routing node missing\n");
 129                 goto out;
 130         }
 131 
 132         codec_np = of_parse_phandle(np, "atmel,audio-codec", 0);
 133         if (!codec_np) {
 134                 dev_err(&pdev->dev, "atmel,audio-codec node missing\n");
 135                 ret = -EINVAL;
 136                 goto out;
 137         }
 138 
 139         dai->codecs->of_node = codec_np;
 140 
 141         cpu_np = of_parse_phandle(np, "atmel,ssc-controller", 0);
 142         if (!cpu_np) {
 143                 dev_err(&pdev->dev, "atmel,ssc-controller node missing\n");
 144                 ret = -EINVAL;
 145                 goto out;
 146         }
 147         dai->cpus->of_node = cpu_np;
 148         dai->platforms->of_node = cpu_np;
 149 
 150         priv->ssc_id = of_alias_get_id(cpu_np, "ssc");
 151 
 152         ret = atmel_ssc_set_audio(priv->ssc_id);
 153         if (ret != 0) {
 154                 dev_err(&pdev->dev, "Failed to set SSC %d for audio: %d\n",
 155                         ret, priv->ssc_id);
 156                 goto out;
 157         }
 158 
 159         of_node_put(codec_np);
 160         of_node_put(cpu_np);
 161 
 162         ret = snd_soc_register_card(card);
 163         if (ret) {
 164                 dev_err(&pdev->dev, "Platform device allocation failed\n");
 165                 goto out_put_audio;
 166         }
 167 
 168         dev_dbg(&pdev->dev, "%s ok\n", __func__);
 169 
 170         return ret;
 171 
 172 out_put_audio:
 173         atmel_ssc_put_audio(priv->ssc_id);
 174 out:
 175         return ret;
 176 }
 177 
 178 static int sam9x5_wm8731_driver_remove(struct platform_device *pdev)
 179 {
 180         struct snd_soc_card *card = platform_get_drvdata(pdev);
 181         struct sam9x5_drvdata *priv = card->drvdata;
 182 
 183         snd_soc_unregister_card(card);
 184         atmel_ssc_put_audio(priv->ssc_id);
 185 
 186         return 0;
 187 }
 188 
 189 static const struct of_device_id sam9x5_wm8731_of_match[] = {
 190         { .compatible = "atmel,sam9x5-wm8731-audio", },
 191         {},
 192 };
 193 MODULE_DEVICE_TABLE(of, sam9x5_wm8731_of_match);
 194 
 195 static struct platform_driver sam9x5_wm8731_driver = {
 196         .driver = {
 197                 .name = DRV_NAME,
 198                 .of_match_table = of_match_ptr(sam9x5_wm8731_of_match),
 199         },
 200         .probe = sam9x5_wm8731_driver_probe,
 201         .remove = sam9x5_wm8731_driver_remove,
 202 };
 203 module_platform_driver(sam9x5_wm8731_driver);
 204 
 205 /* Module information */
 206 MODULE_AUTHOR("Nicolas Ferre <nicolas.ferre@atmel.com>");
 207 MODULE_AUTHOR("Richard Genoud <richard.genoud@gmail.com>");
 208 MODULE_DESCRIPTION("ALSA SoC machine driver for AT91SAM9x5 - WM8731");
 209 MODULE_LICENSE("GPL");
 210 MODULE_ALIAS("platform:" DRV_NAME);

/* [<][>][^][v][top][bottom][index][help] */