2 * sam9x5_wm8731 -- SoC audio for AT91SAM9X5-based boards
3 * that are using WM8731 as codec.
5 * Copyright (C) 2011 Atmel,
6 * Nicolas Ferre <nicolas.ferre@atmel.com>
8 * Copyright (C) 2013 Paratronic,
9 * Richard Genoud <richard.genoud@gmail.com>
11 * Based on sam9g20_wm8731.c by:
12 * Sedji Gaouaou <sedji.gaouaou@atmel.com>
14 * This program is free software; you can redistribute it and/or modify it
15 * under the terms of the GNU General Public License as published by the
16 * Free Software Foundation; either version 2 of the License, or (at your
17 * option) any later version.
21 #include <linux/export.h>
22 #include <linux/module.h>
23 #include <linux/mod_devicetable.h>
24 #include <linux/platform_device.h>
25 #include <linux/device.h>
27 #include <sound/soc.h>
28 #include <sound/soc-dai.h>
29 #include <sound/soc-dapm.h>
31 #include "../codecs/wm8731.h"
32 #include "atmel_ssc_dai.h"
35 #define MCLK_RATE 12288000
37 #define DRV_NAME "sam9x5-snd-wm8731"
39 struct sam9x5_drvdata
{
44 * Logic for a wm8731 as connected on a at91sam9x5ek based board.
46 static int sam9x5_wm8731_init(struct snd_soc_pcm_runtime
*rtd
)
48 struct snd_soc_dai
*codec_dai
= rtd
->codec_dai
;
49 struct device
*dev
= rtd
->dev
;
52 dev_dbg(dev
, "%s called\n", __func__
);
54 /* set the codec system clock for DAC and ADC */
55 ret
= snd_soc_dai_set_sysclk(codec_dai
, WM8731_SYSCLK_XTAL
,
56 MCLK_RATE
, SND_SOC_CLOCK_IN
);
58 dev_err(dev
, "Failed to set WM8731 SYSCLK: %d\n", ret
);
66 * Audio paths on at91sam9x5ek board:
68 * |A| ------------> | | ---R----> Headphone Jack
69 * |T| <----\ | WM | ---L--/
70 * |9| ---> CLK <--> | 8731 | <--R----- Line In Jack
71 * |1| <------------ | | <--L--/
73 static const struct snd_soc_dapm_widget sam9x5_dapm_widgets
[] = {
74 SND_SOC_DAPM_HP("Headphone Jack", NULL
),
75 SND_SOC_DAPM_LINE("Line In Jack", NULL
),
78 static int sam9x5_wm8731_driver_probe(struct platform_device
*pdev
)
80 struct device_node
*np
= pdev
->dev
.of_node
;
81 struct device_node
*codec_np
, *cpu_np
;
82 struct snd_soc_card
*card
;
83 struct snd_soc_dai_link
*dai
;
84 struct sam9x5_drvdata
*priv
;
88 dev_err(&pdev
->dev
, "No device node supplied\n");
92 card
= devm_kzalloc(&pdev
->dev
, sizeof(*card
), GFP_KERNEL
);
93 priv
= devm_kzalloc(&pdev
->dev
, sizeof(*priv
), GFP_KERNEL
);
94 dai
= devm_kzalloc(&pdev
->dev
, sizeof(*dai
), GFP_KERNEL
);
95 if (!dai
|| !card
|| !priv
) {
100 snd_soc_card_set_drvdata(card
, priv
);
102 card
->dev
= &pdev
->dev
;
103 card
->owner
= THIS_MODULE
;
104 card
->dai_link
= dai
;
106 card
->dapm_widgets
= sam9x5_dapm_widgets
;
107 card
->num_dapm_widgets
= ARRAY_SIZE(sam9x5_dapm_widgets
);
108 dai
->name
= "WM8731";
109 dai
->stream_name
= "WM8731 PCM";
110 dai
->codec_dai_name
= "wm8731-hifi";
111 dai
->init
= sam9x5_wm8731_init
;
112 dai
->dai_fmt
= SND_SOC_DAIFMT_DSP_A
| SND_SOC_DAIFMT_NB_NF
113 | SND_SOC_DAIFMT_CBM_CFM
;
115 ret
= snd_soc_of_parse_card_name(card
, "atmel,model");
117 dev_err(&pdev
->dev
, "atmel,model node missing\n");
121 ret
= snd_soc_of_parse_audio_routing(card
, "atmel,audio-routing");
123 dev_err(&pdev
->dev
, "atmel,audio-routing node missing\n");
127 codec_np
= of_parse_phandle(np
, "atmel,audio-codec", 0);
129 dev_err(&pdev
->dev
, "atmel,audio-codec node missing\n");
134 dai
->codec_of_node
= codec_np
;
136 cpu_np
= of_parse_phandle(np
, "atmel,ssc-controller", 0);
138 dev_err(&pdev
->dev
, "atmel,ssc-controller node missing\n");
142 dai
->cpu_of_node
= cpu_np
;
143 dai
->platform_of_node
= cpu_np
;
145 priv
->ssc_id
= of_alias_get_id(cpu_np
, "ssc");
147 ret
= atmel_ssc_set_audio(priv
->ssc_id
);
149 dev_err(&pdev
->dev
, "Failed to set SSC %d for audio: %d\n",
154 of_node_put(codec_np
);
157 ret
= snd_soc_register_card(card
);
159 dev_err(&pdev
->dev
, "Platform device allocation failed\n");
163 dev_dbg(&pdev
->dev
, "%s ok\n", __func__
);
168 atmel_ssc_put_audio(priv
->ssc_id
);
173 static int sam9x5_wm8731_driver_remove(struct platform_device
*pdev
)
175 struct snd_soc_card
*card
= platform_get_drvdata(pdev
);
176 struct sam9x5_drvdata
*priv
= card
->drvdata
;
178 snd_soc_unregister_card(card
);
179 atmel_ssc_put_audio(priv
->ssc_id
);
184 static const struct of_device_id sam9x5_wm8731_of_match
[] = {
185 { .compatible
= "atmel,sam9x5-wm8731-audio", },
188 MODULE_DEVICE_TABLE(of
, sam9x5_wm8731_of_match
);
190 static struct platform_driver sam9x5_wm8731_driver
= {
193 .of_match_table
= of_match_ptr(sam9x5_wm8731_of_match
),
195 .probe
= sam9x5_wm8731_driver_probe
,
196 .remove
= sam9x5_wm8731_driver_remove
,
198 module_platform_driver(sam9x5_wm8731_driver
);
200 /* Module information */
201 MODULE_AUTHOR("Nicolas Ferre <nicolas.ferre@atmel.com>");
202 MODULE_AUTHOR("Richard Genoud <richard.genoud@gmail.com>");
203 MODULE_DESCRIPTION("ALSA SoC machine driver for AT91SAM9x5 - WM8731");
204 MODULE_LICENSE("GPL");
205 MODULE_ALIAS("platform:" DRV_NAME
);