Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ASoC: Add driver for PROTO Audio CODEC (with a WM8731)

Add support for the MikroElektronika PROTO audio codec board.

URL to the audio chip:
http://www.mikroe.com/add-on-boards/audio-voice/audio-codec-proto/

Signed-off-by: Florian Meier <florian.meier@koalo.de>
Signed-off-by: Codrin Ciubotariu <codrin.ciubotariu@microchip.com>
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

Codrin Ciubotariu and committed by
Mark Brown
a45f8853 6ab6a247

+178
+11
sound/soc/atmel/Kconfig
··· 97 97 help 98 98 Say Y or M if you want to add support for Atmel ASoc driver for boards 99 99 using I2S. 100 + 101 + config SND_SOC_MIKROE_PROTO 102 + tristate "Support for Mikroe-PROTO board" 103 + depends on OF 104 + select SND_SOC_WM8731 105 + help 106 + Say Y or M if you want to add support for MikroElektronika PROTO Audio 107 + Board. This board contains the WM8731 codec, which can be configured 108 + using I2C over SDA (MPU Data Input) and SCL (MPU Clock Input) pins. 109 + Both playback and capture are supported. 110 + 100 111 endif
+2
sound/soc/atmel/Makefile
··· 17 17 snd-atmel-soc-classd-objs := atmel-classd.o 18 18 snd-atmel-soc-pdmic-objs := atmel-pdmic.o 19 19 snd-atmel-soc-tse850-pcm5142-objs := tse850-pcm5142.o 20 + snd-soc-mikroe-proto-objs := mikroe-proto.o 20 21 21 22 obj-$(CONFIG_SND_AT91_SOC_SAM9G20_WM8731) += snd-soc-sam9g20-wm8731.o 22 23 obj-$(CONFIG_SND_ATMEL_SOC_WM8904) += snd-atmel-soc-wm8904.o ··· 25 24 obj-$(CONFIG_SND_ATMEL_SOC_CLASSD) += snd-atmel-soc-classd.o 26 25 obj-$(CONFIG_SND_ATMEL_SOC_PDMIC) += snd-atmel-soc-pdmic.o 27 26 obj-$(CONFIG_SND_ATMEL_SOC_TSE850_PCM5142) += snd-atmel-soc-tse850-pcm5142.o 27 + obj-$(CONFIG_SND_SOC_MIKROE_PROTO) += snd-soc-mikroe-proto.o
+165
sound/soc/atmel/mikroe-proto.c
··· 1 + /* 2 + * ASoC driver for PROTO AudioCODEC (with a WM8731) 3 + * 4 + * Author: Florian Meier, <koalo@koalo.de> 5 + * Copyright 2013 6 + * 7 + * This program is free software; you can redistribute it and/or modify 8 + * it under the terms of the GNU General Public License version 2 as 9 + * published by the Free Software Foundation. 10 + */ 11 + 12 + #include <linux/module.h> 13 + #include <linux/platform_device.h> 14 + 15 + #include <sound/core.h> 16 + #include <sound/pcm.h> 17 + #include <sound/soc.h> 18 + #include <sound/jack.h> 19 + 20 + #include "../codecs/wm8731.h" 21 + 22 + #define XTAL_RATE 12288000 /* This is fixed on this board */ 23 + 24 + static int snd_proto_init(struct snd_soc_pcm_runtime *rtd) 25 + { 26 + struct snd_soc_card *card = rtd->card; 27 + struct snd_soc_dai *codec_dai = rtd->codec_dai; 28 + 29 + /* Set proto sysclk */ 30 + int ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL, 31 + XTAL_RATE, SND_SOC_CLOCK_IN); 32 + if (ret < 0) { 33 + dev_err(card->dev, "Failed to set WM8731 SYSCLK: %d\n", 34 + ret); 35 + return ret; 36 + } 37 + 38 + return 0; 39 + } 40 + 41 + static const struct snd_soc_dapm_widget snd_proto_widget[] = { 42 + SND_SOC_DAPM_MIC("Microphone Jack", NULL), 43 + SND_SOC_DAPM_HP("Headphone Jack", NULL), 44 + }; 45 + 46 + static const struct snd_soc_dapm_route snd_proto_route[] = { 47 + /* speaker connected to LHPOUT/RHPOUT */ 48 + {"Headphone Jack", NULL, "LHPOUT"}, 49 + {"Headphone Jack", NULL, "RHPOUT"}, 50 + 51 + /* mic is connected to Mic Jack, with WM8731 Mic Bias */ 52 + {"MICIN", NULL, "Mic Bias"}, 53 + {"Mic Bias", NULL, "Microphone Jack"}, 54 + }; 55 + 56 + /* audio machine driver */ 57 + static struct snd_soc_card snd_proto = { 58 + .name = "snd_mikroe_proto", 59 + .owner = THIS_MODULE, 60 + .dapm_widgets = snd_proto_widget, 61 + .num_dapm_widgets = ARRAY_SIZE(snd_proto_widget), 62 + .dapm_routes = snd_proto_route, 63 + .num_dapm_routes = ARRAY_SIZE(snd_proto_route), 64 + }; 65 + 66 + static int snd_proto_probe(struct platform_device *pdev) 67 + { 68 + struct snd_soc_dai_link *dai; 69 + struct device_node *np = pdev->dev.of_node; 70 + struct device_node *codec_np, *cpu_np; 71 + struct device_node *bitclkmaster = NULL; 72 + struct device_node *framemaster = NULL; 73 + unsigned int dai_fmt; 74 + int ret = 0; 75 + 76 + if (!np) { 77 + dev_err(&pdev->dev, "No device node supplied\n"); 78 + return -EINVAL; 79 + } 80 + 81 + snd_proto.dev = &pdev->dev; 82 + ret = snd_soc_of_parse_card_name(&snd_proto, "model"); 83 + if (ret) 84 + return ret; 85 + 86 + dai = devm_kzalloc(&pdev->dev, sizeof(*dai), GFP_KERNEL); 87 + if (!dai) 88 + return -ENOMEM; 89 + 90 + snd_proto.dai_link = dai; 91 + snd_proto.num_links = 1; 92 + 93 + dai->name = "WM8731"; 94 + dai->stream_name = "WM8731 HiFi"; 95 + dai->codec_dai_name = "wm8731-hifi"; 96 + dai->init = &snd_proto_init; 97 + 98 + codec_np = of_parse_phandle(np, "audio-codec", 0); 99 + if (!codec_np) { 100 + dev_err(&pdev->dev, "audio-codec node missing\n"); 101 + return -EINVAL; 102 + } 103 + dai->codec_of_node = codec_np; 104 + 105 + cpu_np = of_parse_phandle(np, "i2s-controller", 0); 106 + if (!cpu_np) { 107 + dev_err(&pdev->dev, "i2s-controller missing\n"); 108 + return -EINVAL; 109 + } 110 + dai->cpu_of_node = cpu_np; 111 + dai->platform_of_node = cpu_np; 112 + 113 + dai_fmt = snd_soc_of_parse_daifmt(np, NULL, 114 + &bitclkmaster, &framemaster); 115 + if (bitclkmaster != framemaster) { 116 + dev_err(&pdev->dev, "Must be the same bitclock and frame master\n"); 117 + return -EINVAL; 118 + } 119 + if (bitclkmaster) { 120 + dai_fmt &= ~SND_SOC_DAIFMT_MASTER_MASK; 121 + if (codec_np == bitclkmaster) 122 + dai_fmt |= SND_SOC_DAIFMT_CBM_CFM; 123 + else 124 + dai_fmt |= SND_SOC_DAIFMT_CBS_CFS; 125 + } 126 + of_node_put(bitclkmaster); 127 + of_node_put(framemaster); 128 + dai->dai_fmt = dai_fmt; 129 + 130 + of_node_put(codec_np); 131 + of_node_put(cpu_np); 132 + 133 + ret = snd_soc_register_card(&snd_proto); 134 + if (ret && ret != -EPROBE_DEFER) 135 + dev_err(&pdev->dev, 136 + "snd_soc_register_card() failed: %d\n", ret); 137 + 138 + return ret; 139 + } 140 + 141 + static int snd_proto_remove(struct platform_device *pdev) 142 + { 143 + return snd_soc_unregister_card(&snd_proto); 144 + } 145 + 146 + static const struct of_device_id snd_proto_of_match[] = { 147 + { .compatible = "mikroe,mikroe-proto", }, 148 + {}, 149 + }; 150 + MODULE_DEVICE_TABLE(of, snd_proto_of_match); 151 + 152 + static struct platform_driver snd_proto_driver = { 153 + .driver = { 154 + .name = "snd-mikroe-proto", 155 + .of_match_table = snd_proto_of_match, 156 + }, 157 + .probe = snd_proto_probe, 158 + .remove = snd_proto_remove, 159 + }; 160 + 161 + module_platform_driver(snd_proto_driver); 162 + 163 + MODULE_AUTHOR("Florian Meier"); 164 + MODULE_DESCRIPTION("ASoC Driver for PROTO board (WM8731)"); 165 + MODULE_LICENSE("GPL");