brintos

brintos / linux-shallow public Read only

0
0
Text · 4.3 KiB · 8341a6e Raw
177 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * ASoC driver for PROTO AudioCODEC (with a WM8731)4 *5 * Author:      Florian Meier, <koalo@koalo.de>6 *	      Copyright 20137 */8 9#include <linux/module.h>10#include <linux/platform_device.h>11 12#include <sound/core.h>13#include <sound/pcm.h>14#include <sound/soc.h>15#include <sound/jack.h>16 17#include "../codecs/wm8731.h"18 19#define XTAL_RATE 12288000	/* This is fixed on this board */20 21static int snd_proto_init(struct snd_soc_pcm_runtime *rtd)22{23	struct snd_soc_card *card = rtd->card;24	struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);25 26	/* Set proto sysclk */27	int ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL,28					 XTAL_RATE, SND_SOC_CLOCK_IN);29	if (ret < 0) {30		dev_err(card->dev, "Failed to set WM8731 SYSCLK: %d\n",31			ret);32		return ret;33	}34 35	return 0;36}37 38static const struct snd_soc_dapm_widget snd_proto_widget[] = {39	SND_SOC_DAPM_MIC("Microphone Jack", NULL),40	SND_SOC_DAPM_HP("Headphone Jack", NULL),41};42 43static const struct snd_soc_dapm_route snd_proto_route[] = {44	/* speaker connected to LHPOUT/RHPOUT */45	{"Headphone Jack", NULL, "LHPOUT"},46	{"Headphone Jack", NULL, "RHPOUT"},47 48	/* mic is connected to Mic Jack, with WM8731 Mic Bias */49	{"MICIN", NULL, "Mic Bias"},50	{"Mic Bias", NULL, "Microphone Jack"},51};52 53/* audio machine driver */54static struct snd_soc_card snd_proto = {55	.name		= "snd_mikroe_proto",56	.owner		= THIS_MODULE,57	.dapm_widgets	= snd_proto_widget,58	.num_dapm_widgets = ARRAY_SIZE(snd_proto_widget),59	.dapm_routes	= snd_proto_route,60	.num_dapm_routes = ARRAY_SIZE(snd_proto_route),61};62 63static int snd_proto_probe(struct platform_device *pdev)64{65	struct snd_soc_dai_link *dai;66	struct snd_soc_dai_link_component *comp;67	struct device_node *np = pdev->dev.of_node;68	struct device_node *codec_np, *cpu_np;69	struct device_node *bitclkmaster = NULL;70	struct device_node *framemaster = NULL;71	unsigned int dai_fmt;72	int ret = 0;73 74	if (!np) {75		dev_err(&pdev->dev, "No device node supplied\n");76		return -EINVAL;77	}78 79	snd_proto.dev = &pdev->dev;80	ret = snd_soc_of_parse_card_name(&snd_proto, "model");81	if (ret)82		return ret;83 84	dai = devm_kzalloc(&pdev->dev, sizeof(*dai), GFP_KERNEL);85	if (!dai)86		return -ENOMEM;87 88	/* for cpus/codecs/platforms */89	comp = devm_kzalloc(&pdev->dev, 3 * sizeof(*comp), GFP_KERNEL);90	if (!comp)91		return -ENOMEM;92 93	snd_proto.dai_link = dai;94	snd_proto.num_links = 1;95 96	dai->cpus = &comp[0];97	dai->num_cpus = 1;98	dai->codecs = &comp[1];99	dai->num_codecs = 1;100	dai->platforms = &comp[2];101	dai->num_platforms = 1;102 103	dai->name = "WM8731";104	dai->stream_name = "WM8731 HiFi";105	dai->codecs->dai_name = "wm8731-hifi";106	dai->init = &snd_proto_init;107 108	codec_np = of_parse_phandle(np, "audio-codec", 0);109	if (!codec_np) {110		dev_err(&pdev->dev, "audio-codec node missing\n");111		return -EINVAL;112	}113	dai->codecs->of_node = codec_np;114 115	cpu_np = of_parse_phandle(np, "i2s-controller", 0);116	if (!cpu_np) {117		dev_err(&pdev->dev, "i2s-controller missing\n");118		ret = -EINVAL;119		goto put_codec_node;120	}121	dai->cpus->of_node = cpu_np;122	dai->platforms->of_node = cpu_np;123 124	dai_fmt = snd_soc_daifmt_parse_format(np, NULL);125	snd_soc_daifmt_parse_clock_provider_as_phandle(np, NULL,126						       &bitclkmaster, &framemaster);127	if (bitclkmaster != framemaster) {128		dev_err(&pdev->dev, "Must be the same bitclock and frame master\n");129		ret = -EINVAL;130		goto put_cpu_node;131	}132	if (bitclkmaster) {133		if (codec_np == bitclkmaster)134			dai_fmt |= SND_SOC_DAIFMT_CBP_CFP;135		else136			dai_fmt |= SND_SOC_DAIFMT_CBC_CFC;137	} else {138		dai_fmt |= snd_soc_daifmt_parse_clock_provider_as_flag(np, NULL);139	}140 141 142	dai->dai_fmt = dai_fmt;143	ret = devm_snd_soc_register_card(&pdev->dev, &snd_proto);144	if (ret)145		dev_err_probe(&pdev->dev, ret,146			"snd_soc_register_card() failed\n");147 148 149put_cpu_node:150	of_node_put(bitclkmaster);151	of_node_put(framemaster);152	of_node_put(cpu_np);153put_codec_node:154	of_node_put(codec_np);155	return ret;156}157 158static const struct of_device_id snd_proto_of_match[] = {159	{ .compatible = "mikroe,mikroe-proto", },160	{},161};162MODULE_DEVICE_TABLE(of, snd_proto_of_match);163 164static struct platform_driver snd_proto_driver = {165	.driver = {166		.name   = "snd-mikroe-proto",167		.of_match_table = snd_proto_of_match,168	},169	.probe	  = snd_proto_probe,170};171 172module_platform_driver(snd_proto_driver);173 174MODULE_AUTHOR("Florian Meier");175MODULE_DESCRIPTION("ASoC Driver for PROTO board (WM8731)");176MODULE_LICENSE("GPL");177