cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

mikroe-proto.c (4513B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * ASoC driver for PROTO AudioCODEC (with a WM8731)
      4 *
      5 * Author:      Florian Meier, <koalo@koalo.de>
      6 *	      Copyright 2013
      7 */
      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 = asoc_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		else
    136			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 = snd_soc_register_card(&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 int snd_proto_remove(struct platform_device *pdev)
    159{
    160	return snd_soc_unregister_card(&snd_proto);
    161}
    162
    163static const struct of_device_id snd_proto_of_match[] = {
    164	{ .compatible = "mikroe,mikroe-proto", },
    165	{},
    166};
    167MODULE_DEVICE_TABLE(of, snd_proto_of_match);
    168
    169static struct platform_driver snd_proto_driver = {
    170	.driver = {
    171		.name   = "snd-mikroe-proto",
    172		.of_match_table = snd_proto_of_match,
    173	},
    174	.probe	  = snd_proto_probe,
    175	.remove	 = snd_proto_remove,
    176};
    177
    178module_platform_driver(snd_proto_driver);
    179
    180MODULE_AUTHOR("Florian Meier");
    181MODULE_DESCRIPTION("ASoC Driver for PROTO board (WM8731)");
    182MODULE_LICENSE("GPL");