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

sam9g20_wm8731.c (5430B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * sam9g20_wm8731  --  SoC audio for AT91SAM9G20-based
      4 * 			ATMEL AT91SAM9G20ek board.
      5 *
      6 *  Copyright (C) 2005 SAN People
      7 *  Copyright (C) 2008 Atmel
      8 *
      9 * Authors: Sedji Gaouaou <sedji.gaouaou@atmel.com>
     10 *
     11 * Based on ati_b1_wm8731.c by:
     12 * Frank Mandarino <fmandarino@endrelia.com>
     13 * Copyright 2006 Endrelia Technologies Inc.
     14 * Based on corgi.c by:
     15 * Copyright 2005 Wolfson Microelectronics PLC.
     16 * Copyright 2005 Openedhand Ltd.
     17 */
     18
     19#include <linux/module.h>
     20#include <linux/moduleparam.h>
     21#include <linux/kernel.h>
     22#include <linux/clk.h>
     23#include <linux/timer.h>
     24#include <linux/interrupt.h>
     25#include <linux/platform_device.h>
     26#include <linux/i2c.h>
     27#include <linux/of.h>
     28
     29#include <linux/atmel-ssc.h>
     30
     31#include <sound/core.h>
     32#include <sound/pcm.h>
     33#include <sound/pcm_params.h>
     34#include <sound/soc.h>
     35
     36#include "../codecs/wm8731.h"
     37#include "atmel-pcm.h"
     38#include "atmel_ssc_dai.h"
     39
     40#define MCLK_RATE 12000000
     41
     42/*
     43 * As shipped the board does not have inputs.  However, it is relatively
     44 * straightforward to modify the board to hook them up so support is left
     45 * in the driver.
     46 */
     47#undef ENABLE_MIC_INPUT
     48
     49static const struct snd_soc_dapm_widget at91sam9g20ek_dapm_widgets[] = {
     50	SND_SOC_DAPM_MIC("Int Mic", NULL),
     51	SND_SOC_DAPM_SPK("Ext Spk", NULL),
     52};
     53
     54static const struct snd_soc_dapm_route intercon[] = {
     55
     56	/* speaker connected to LHPOUT/RHPOUT */
     57	{"Ext Spk", NULL, "LHPOUT"},
     58	{"Ext Spk", NULL, "RHPOUT"},
     59
     60	/* mic is connected to Mic Jack, with WM8731 Mic Bias */
     61	{"MICIN", NULL, "Mic Bias"},
     62	{"Mic Bias", NULL, "Int Mic"},
     63};
     64
     65/*
     66 * Logic for a wm8731 as connected on a at91sam9g20ek board.
     67 */
     68static int at91sam9g20ek_wm8731_init(struct snd_soc_pcm_runtime *rtd)
     69{
     70	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
     71	struct device *dev = rtd->dev;
     72	int ret;
     73
     74	dev_dbg(dev, "%s called\n", __func__);
     75
     76	ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_MCLK,
     77				     MCLK_RATE, SND_SOC_CLOCK_IN);
     78	if (ret < 0) {
     79		dev_err(dev, "Failed to set WM8731 SYSCLK: %d\n", ret);
     80		return ret;
     81	}
     82
     83#ifndef ENABLE_MIC_INPUT
     84	snd_soc_dapm_nc_pin(&rtd->card->dapm, "Int Mic");
     85#endif
     86
     87	return 0;
     88}
     89
     90SND_SOC_DAILINK_DEFS(pcm,
     91	DAILINK_COMP_ARRAY(COMP_CPU("at91rm9200_ssc.0")),
     92	DAILINK_COMP_ARRAY(COMP_CODEC("wm8731.0-001b", "wm8731-hifi")),
     93	DAILINK_COMP_ARRAY(COMP_PLATFORM("at91rm9200_ssc.0")));
     94
     95static struct snd_soc_dai_link at91sam9g20ek_dai = {
     96	.name = "WM8731",
     97	.stream_name = "WM8731 PCM",
     98	.init = at91sam9g20ek_wm8731_init,
     99	.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
    100		   SND_SOC_DAIFMT_CBP_CFP,
    101	SND_SOC_DAILINK_REG(pcm),
    102};
    103
    104static struct snd_soc_card snd_soc_at91sam9g20ek = {
    105	.name = "AT91SAMG20-EK",
    106	.owner = THIS_MODULE,
    107	.dai_link = &at91sam9g20ek_dai,
    108	.num_links = 1,
    109
    110	.dapm_widgets = at91sam9g20ek_dapm_widgets,
    111	.num_dapm_widgets = ARRAY_SIZE(at91sam9g20ek_dapm_widgets),
    112	.dapm_routes = intercon,
    113	.num_dapm_routes = ARRAY_SIZE(intercon),
    114	.fully_routed = true,
    115};
    116
    117static int at91sam9g20ek_audio_probe(struct platform_device *pdev)
    118{
    119	struct device_node *np = pdev->dev.of_node;
    120	struct device_node *codec_np, *cpu_np;
    121	struct snd_soc_card *card = &snd_soc_at91sam9g20ek;
    122	int ret;
    123
    124	if (!np) {
    125		return -ENODEV;
    126	}
    127
    128	ret = atmel_ssc_set_audio(0);
    129	if (ret) {
    130		dev_err(&pdev->dev, "ssc channel is not valid: %d\n", ret);
    131		return ret;
    132	}
    133
    134	card->dev = &pdev->dev;
    135
    136	/* Parse device node info */
    137	ret = snd_soc_of_parse_card_name(card, "atmel,model");
    138	if (ret)
    139		goto err;
    140
    141	ret = snd_soc_of_parse_audio_routing(card,
    142		"atmel,audio-routing");
    143	if (ret)
    144		goto err;
    145
    146	/* Parse codec info */
    147	at91sam9g20ek_dai.codecs->name = NULL;
    148	codec_np = of_parse_phandle(np, "atmel,audio-codec", 0);
    149	if (!codec_np) {
    150		dev_err(&pdev->dev, "codec info missing\n");
    151		ret = -EINVAL;
    152		goto err;
    153	}
    154	at91sam9g20ek_dai.codecs->of_node = codec_np;
    155
    156	/* Parse dai and platform info */
    157	at91sam9g20ek_dai.cpus->dai_name = NULL;
    158	at91sam9g20ek_dai.platforms->name = NULL;
    159	cpu_np = of_parse_phandle(np, "atmel,ssc-controller", 0);
    160	if (!cpu_np) {
    161		dev_err(&pdev->dev, "dai and pcm info missing\n");
    162		of_node_put(codec_np);
    163		ret = -EINVAL;
    164		goto err;
    165	}
    166	at91sam9g20ek_dai.cpus->of_node = cpu_np;
    167	at91sam9g20ek_dai.platforms->of_node = cpu_np;
    168
    169	of_node_put(codec_np);
    170	of_node_put(cpu_np);
    171
    172	ret = snd_soc_register_card(card);
    173	if (ret) {
    174		dev_err_probe(&pdev->dev, ret,
    175			      "snd_soc_register_card() failed: %d\n", ret);
    176		goto err;
    177	}
    178
    179	return 0;
    180
    181err:
    182	atmel_ssc_put_audio(0);
    183	return ret;
    184}
    185
    186static int at91sam9g20ek_audio_remove(struct platform_device *pdev)
    187{
    188	struct snd_soc_card *card = platform_get_drvdata(pdev);
    189
    190	snd_soc_unregister_card(card);
    191	atmel_ssc_put_audio(0);
    192
    193	return 0;
    194}
    195
    196#ifdef CONFIG_OF
    197static const struct of_device_id at91sam9g20ek_wm8731_dt_ids[] = {
    198	{ .compatible = "atmel,at91sam9g20ek-wm8731-audio", },
    199	{ }
    200};
    201MODULE_DEVICE_TABLE(of, at91sam9g20ek_wm8731_dt_ids);
    202#endif
    203
    204static struct platform_driver at91sam9g20ek_audio_driver = {
    205	.driver = {
    206		.name	= "at91sam9g20ek-audio",
    207		.of_match_table = of_match_ptr(at91sam9g20ek_wm8731_dt_ids),
    208	},
    209	.probe	= at91sam9g20ek_audio_probe,
    210	.remove	= at91sam9g20ek_audio_remove,
    211};
    212
    213module_platform_driver(at91sam9g20ek_audio_driver);
    214
    215/* Module information */
    216MODULE_AUTHOR("Sedji Gaouaou <sedji.gaouaou@atmel.com>");
    217MODULE_DESCRIPTION("ALSA SoC AT91SAM9G20EK_WM8731");
    218MODULE_ALIAS("platform:at91sam9g20ek-audio");
    219MODULE_LICENSE("GPL");