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

migor.c (4969B)


      1// SPDX-License-Identifier: GPL-2.0
      2//
      3// ALSA SoC driver for Migo-R
      4//
      5// Copyright (C) 2009-2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
      6
      7#include <linux/clkdev.h>
      8#include <linux/device.h>
      9#include <linux/firmware.h>
     10#include <linux/module.h>
     11
     12#include <asm/clock.h>
     13
     14#include <cpu/sh7722.h>
     15
     16#include <sound/core.h>
     17#include <sound/pcm.h>
     18#include <sound/soc.h>
     19
     20#include "../codecs/wm8978.h"
     21#include "siu.h"
     22
     23/* Default 8000Hz sampling frequency */
     24static unsigned long codec_freq = 8000 * 512;
     25
     26static unsigned int use_count;
     27
     28/* External clock, sourced from the codec at the SIUMCKB pin */
     29static unsigned long siumckb_recalc(struct clk *clk)
     30{
     31	return codec_freq;
     32}
     33
     34static struct sh_clk_ops siumckb_clk_ops = {
     35	.recalc = siumckb_recalc,
     36};
     37
     38static struct clk siumckb_clk = {
     39	.ops		= &siumckb_clk_ops,
     40	.rate		= 0, /* initialised at run-time */
     41};
     42
     43static struct clk_lookup *siumckb_lookup;
     44
     45static int migor_hw_params(struct snd_pcm_substream *substream,
     46			   struct snd_pcm_hw_params *params)
     47{
     48	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
     49	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
     50	int ret;
     51	unsigned int rate = params_rate(params);
     52
     53	ret = snd_soc_dai_set_sysclk(codec_dai, WM8978_PLL, 13000000,
     54				     SND_SOC_CLOCK_IN);
     55	if (ret < 0)
     56		return ret;
     57
     58	ret = snd_soc_dai_set_clkdiv(codec_dai, WM8978_OPCLKRATE, rate * 512);
     59	if (ret < 0)
     60		return ret;
     61
     62	codec_freq = rate * 512;
     63	/*
     64	 * This propagates the parent frequency change to children and
     65	 * recalculates the frequency table
     66	 */
     67	clk_set_rate(&siumckb_clk, codec_freq);
     68	dev_dbg(codec_dai->dev, "%s: configure %luHz\n", __func__, codec_freq);
     69
     70	ret = snd_soc_dai_set_sysclk(asoc_rtd_to_cpu(rtd, 0), SIU_CLKB_EXT,
     71				     codec_freq / 2, SND_SOC_CLOCK_IN);
     72
     73	if (!ret)
     74		use_count++;
     75
     76	return ret;
     77}
     78
     79static int migor_hw_free(struct snd_pcm_substream *substream)
     80{
     81	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
     82	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
     83
     84	if (use_count) {
     85		use_count--;
     86
     87		if (!use_count)
     88			snd_soc_dai_set_sysclk(codec_dai, WM8978_PLL, 0,
     89					       SND_SOC_CLOCK_IN);
     90	} else {
     91		dev_dbg(codec_dai->dev, "Unbalanced hw_free!\n");
     92	}
     93
     94	return 0;
     95}
     96
     97static const struct snd_soc_ops migor_dai_ops = {
     98	.hw_params = migor_hw_params,
     99	.hw_free = migor_hw_free,
    100};
    101
    102static const struct snd_soc_dapm_widget migor_dapm_widgets[] = {
    103	SND_SOC_DAPM_HP("Headphone", NULL),
    104	SND_SOC_DAPM_MIC("Onboard Microphone", NULL),
    105	SND_SOC_DAPM_MIC("External Microphone", NULL),
    106};
    107
    108static const struct snd_soc_dapm_route audio_map[] = {
    109	/* Headphone output connected to LHP/RHP, enable OUT4 for VMID */
    110	{ "Headphone", NULL,  "OUT4 VMID" },
    111	{ "OUT4 VMID", NULL,  "LHP" },
    112	{ "OUT4 VMID", NULL,  "RHP" },
    113
    114	/* On-board microphone */
    115	{ "RMICN", NULL, "Mic Bias" },
    116	{ "RMICP", NULL, "Mic Bias" },
    117	{ "Mic Bias", NULL, "Onboard Microphone" },
    118
    119	/* External microphone */
    120	{ "LMICN", NULL, "Mic Bias" },
    121	{ "LMICP", NULL, "Mic Bias" },
    122	{ "Mic Bias", NULL, "External Microphone" },
    123};
    124
    125/* migor digital audio interface glue - connects codec <--> CPU */
    126SND_SOC_DAILINK_DEFS(wm8978,
    127	DAILINK_COMP_ARRAY(COMP_CPU("siu-pcm-audio")),
    128	DAILINK_COMP_ARRAY(COMP_CODEC("wm8978.0-001a", "wm8978-hifi")),
    129	DAILINK_COMP_ARRAY(COMP_PLATFORM("siu-pcm-audio")));
    130
    131static struct snd_soc_dai_link migor_dai = {
    132	.name = "wm8978",
    133	.stream_name = "WM8978",
    134	.dai_fmt = SND_SOC_DAIFMT_NB_IF | SND_SOC_DAIFMT_I2S |
    135		   SND_SOC_DAIFMT_CBS_CFS,
    136	.ops = &migor_dai_ops,
    137	SND_SOC_DAILINK_REG(wm8978),
    138};
    139
    140/* migor audio machine driver */
    141static struct snd_soc_card snd_soc_migor = {
    142	.name = "Migo-R",
    143	.owner = THIS_MODULE,
    144	.dai_link = &migor_dai,
    145	.num_links = 1,
    146
    147	.dapm_widgets = migor_dapm_widgets,
    148	.num_dapm_widgets = ARRAY_SIZE(migor_dapm_widgets),
    149	.dapm_routes = audio_map,
    150	.num_dapm_routes = ARRAY_SIZE(audio_map),
    151};
    152
    153static struct platform_device *migor_snd_device;
    154
    155static int __init migor_init(void)
    156{
    157	int ret;
    158
    159	ret = clk_register(&siumckb_clk);
    160	if (ret < 0)
    161		return ret;
    162
    163	siumckb_lookup = clkdev_create(&siumckb_clk, "siumckb_clk", NULL);
    164	if (!siumckb_lookup) {
    165		ret = -ENOMEM;
    166		goto eclkdevalloc;
    167	}
    168
    169	/* Port number used on this machine: port B */
    170	migor_snd_device = platform_device_alloc("soc-audio", 1);
    171	if (!migor_snd_device) {
    172		ret = -ENOMEM;
    173		goto epdevalloc;
    174	}
    175
    176	platform_set_drvdata(migor_snd_device, &snd_soc_migor);
    177
    178	ret = platform_device_add(migor_snd_device);
    179	if (ret)
    180		goto epdevadd;
    181
    182	return 0;
    183
    184epdevadd:
    185	platform_device_put(migor_snd_device);
    186epdevalloc:
    187	clkdev_drop(siumckb_lookup);
    188eclkdevalloc:
    189	clk_unregister(&siumckb_clk);
    190	return ret;
    191}
    192
    193static void __exit migor_exit(void)
    194{
    195	clkdev_drop(siumckb_lookup);
    196	clk_unregister(&siumckb_clk);
    197	platform_device_unregister(migor_snd_device);
    198}
    199
    200module_init(migor_init);
    201module_exit(migor_exit);
    202
    203MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
    204MODULE_DESCRIPTION("ALSA SoC Migor");
    205MODULE_LICENSE("GPL v2");