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

poodle.c (7756B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * poodle.c  --  SoC audio for Poodle
      4 *
      5 * Copyright 2005 Wolfson Microelectronics PLC.
      6 * Copyright 2005 Openedhand Ltd.
      7 *
      8 * Authors: Liam Girdwood <lrg@slimlogic.co.uk>
      9 *          Richard Purdie <richard@openedhand.com>
     10 */
     11
     12#include <linux/module.h>
     13#include <linux/moduleparam.h>
     14#include <linux/timer.h>
     15#include <linux/i2c.h>
     16#include <linux/interrupt.h>
     17#include <linux/platform_device.h>
     18#include <sound/core.h>
     19#include <sound/pcm.h>
     20#include <sound/soc.h>
     21
     22#include <asm/mach-types.h>
     23#include <asm/hardware/locomo.h>
     24#include <linux/platform_data/asoc-pxa.h>
     25#include <linux/platform_data/asoc-poodle.h>
     26
     27#include "../codecs/wm8731.h"
     28#include "pxa2xx-i2s.h"
     29
     30#define POODLE_HP        1
     31#define POODLE_HP_OFF    0
     32#define POODLE_SPK_ON    1
     33#define POODLE_SPK_OFF   0
     34
     35 /* audio clock in Hz - rounded from 12.235MHz */
     36#define POODLE_AUDIO_CLOCK 12288000
     37
     38static int poodle_jack_func;
     39static int poodle_spk_func;
     40
     41static struct poodle_audio_platform_data *poodle_pdata;
     42
     43static void poodle_ext_control(struct snd_soc_dapm_context *dapm)
     44{
     45	/* set up jack connection */
     46	if (poodle_jack_func == POODLE_HP) {
     47		/* set = unmute headphone */
     48		locomo_gpio_write(poodle_pdata->locomo_dev,
     49			poodle_pdata->gpio_mute_l, 1);
     50		locomo_gpio_write(poodle_pdata->locomo_dev,
     51			poodle_pdata->gpio_mute_r, 1);
     52		snd_soc_dapm_enable_pin(dapm, "Headphone Jack");
     53	} else {
     54		locomo_gpio_write(poodle_pdata->locomo_dev,
     55			poodle_pdata->gpio_mute_l, 0);
     56		locomo_gpio_write(poodle_pdata->locomo_dev,
     57			poodle_pdata->gpio_mute_r, 0);
     58		snd_soc_dapm_disable_pin(dapm, "Headphone Jack");
     59	}
     60
     61	/* set the endpoints to their new connection states */
     62	if (poodle_spk_func == POODLE_SPK_ON)
     63		snd_soc_dapm_enable_pin(dapm, "Ext Spk");
     64	else
     65		snd_soc_dapm_disable_pin(dapm, "Ext Spk");
     66
     67	/* signal a DAPM event */
     68	snd_soc_dapm_sync(dapm);
     69}
     70
     71static int poodle_startup(struct snd_pcm_substream *substream)
     72{
     73	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
     74
     75	/* check the jack status at stream startup */
     76	poodle_ext_control(&rtd->card->dapm);
     77
     78	return 0;
     79}
     80
     81/* we need to unmute the HP at shutdown as the mute burns power on poodle */
     82static void poodle_shutdown(struct snd_pcm_substream *substream)
     83{
     84	/* set = unmute headphone */
     85	locomo_gpio_write(poodle_pdata->locomo_dev,
     86		poodle_pdata->gpio_mute_l, 1);
     87	locomo_gpio_write(poodle_pdata->locomo_dev,
     88		poodle_pdata->gpio_mute_r, 1);
     89}
     90
     91static int poodle_hw_params(struct snd_pcm_substream *substream,
     92	struct snd_pcm_hw_params *params)
     93{
     94	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
     95	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
     96	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
     97	unsigned int clk = 0;
     98	int ret = 0;
     99
    100	switch (params_rate(params)) {
    101	case 8000:
    102	case 16000:
    103	case 48000:
    104	case 96000:
    105		clk = 12288000;
    106		break;
    107	case 11025:
    108	case 22050:
    109	case 44100:
    110		clk = 11289600;
    111		break;
    112	}
    113
    114	/* set the codec system clock for DAC and ADC */
    115	ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL, clk,
    116		SND_SOC_CLOCK_IN);
    117	if (ret < 0)
    118		return ret;
    119
    120	/* set the I2S system clock as input (unused) */
    121	ret = snd_soc_dai_set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0,
    122		SND_SOC_CLOCK_IN);
    123	if (ret < 0)
    124		return ret;
    125
    126	return 0;
    127}
    128
    129static const struct snd_soc_ops poodle_ops = {
    130	.startup = poodle_startup,
    131	.hw_params = poodle_hw_params,
    132	.shutdown = poodle_shutdown,
    133};
    134
    135static int poodle_get_jack(struct snd_kcontrol *kcontrol,
    136	struct snd_ctl_elem_value *ucontrol)
    137{
    138	ucontrol->value.enumerated.item[0] = poodle_jack_func;
    139	return 0;
    140}
    141
    142static int poodle_set_jack(struct snd_kcontrol *kcontrol,
    143	struct snd_ctl_elem_value *ucontrol)
    144{
    145	struct snd_soc_card *card =  snd_kcontrol_chip(kcontrol);
    146
    147	if (poodle_jack_func == ucontrol->value.enumerated.item[0])
    148		return 0;
    149
    150	poodle_jack_func = ucontrol->value.enumerated.item[0];
    151	poodle_ext_control(&card->dapm);
    152	return 1;
    153}
    154
    155static int poodle_get_spk(struct snd_kcontrol *kcontrol,
    156	struct snd_ctl_elem_value *ucontrol)
    157{
    158	ucontrol->value.enumerated.item[0] = poodle_spk_func;
    159	return 0;
    160}
    161
    162static int poodle_set_spk(struct snd_kcontrol *kcontrol,
    163	struct snd_ctl_elem_value *ucontrol)
    164{
    165	struct snd_soc_card *card =  snd_kcontrol_chip(kcontrol);
    166
    167	if (poodle_spk_func == ucontrol->value.enumerated.item[0])
    168		return 0;
    169
    170	poodle_spk_func = ucontrol->value.enumerated.item[0];
    171	poodle_ext_control(&card->dapm);
    172	return 1;
    173}
    174
    175static int poodle_amp_event(struct snd_soc_dapm_widget *w,
    176	struct snd_kcontrol *k, int event)
    177{
    178	if (SND_SOC_DAPM_EVENT_ON(event))
    179		locomo_gpio_write(poodle_pdata->locomo_dev,
    180			poodle_pdata->gpio_amp_on, 0);
    181	else
    182		locomo_gpio_write(poodle_pdata->locomo_dev,
    183			poodle_pdata->gpio_amp_on, 1);
    184
    185	return 0;
    186}
    187
    188/* poodle machine dapm widgets */
    189static const struct snd_soc_dapm_widget wm8731_dapm_widgets[] = {
    190SND_SOC_DAPM_HP("Headphone Jack", NULL),
    191SND_SOC_DAPM_SPK("Ext Spk", poodle_amp_event),
    192SND_SOC_DAPM_MIC("Microphone", NULL),
    193};
    194
    195/* Corgi machine connections to the codec pins */
    196static const struct snd_soc_dapm_route poodle_audio_map[] = {
    197
    198	/* headphone connected to LHPOUT1, RHPOUT1 */
    199	{"Headphone Jack", NULL, "LHPOUT"},
    200	{"Headphone Jack", NULL, "RHPOUT"},
    201
    202	/* speaker connected to LOUT, ROUT */
    203	{"Ext Spk", NULL, "ROUT"},
    204	{"Ext Spk", NULL, "LOUT"},
    205
    206	{"MICIN", NULL, "Microphone"},
    207};
    208
    209static const char * const jack_function[] = {"Off", "Headphone"};
    210static const char * const spk_function[] = {"Off", "On"};
    211static const struct soc_enum poodle_enum[] = {
    212	SOC_ENUM_SINGLE_EXT(2, jack_function),
    213	SOC_ENUM_SINGLE_EXT(2, spk_function),
    214};
    215
    216static const struct snd_kcontrol_new wm8731_poodle_controls[] = {
    217	SOC_ENUM_EXT("Jack Function", poodle_enum[0], poodle_get_jack,
    218		poodle_set_jack),
    219	SOC_ENUM_EXT("Speaker Function", poodle_enum[1], poodle_get_spk,
    220		poodle_set_spk),
    221};
    222
    223/* poodle digital audio interface glue - connects codec <--> CPU */
    224SND_SOC_DAILINK_DEFS(wm8731,
    225	DAILINK_COMP_ARRAY(COMP_CPU("pxa2xx-i2s")),
    226	DAILINK_COMP_ARRAY(COMP_CODEC("wm8731.0-001b", "wm8731-hifi")),
    227	DAILINK_COMP_ARRAY(COMP_PLATFORM("pxa-pcm-audio")));
    228
    229static struct snd_soc_dai_link poodle_dai = {
    230	.name = "WM8731",
    231	.stream_name = "WM8731",
    232	.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
    233		   SND_SOC_DAIFMT_CBS_CFS,
    234	.ops = &poodle_ops,
    235	SND_SOC_DAILINK_REG(wm8731),
    236};
    237
    238/* poodle audio machine driver */
    239static struct snd_soc_card poodle = {
    240	.name = "Poodle",
    241	.dai_link = &poodle_dai,
    242	.num_links = 1,
    243	.owner = THIS_MODULE,
    244
    245	.controls = wm8731_poodle_controls,
    246	.num_controls = ARRAY_SIZE(wm8731_poodle_controls),
    247	.dapm_widgets = wm8731_dapm_widgets,
    248	.num_dapm_widgets = ARRAY_SIZE(wm8731_dapm_widgets),
    249	.dapm_routes = poodle_audio_map,
    250	.num_dapm_routes = ARRAY_SIZE(poodle_audio_map),
    251	.fully_routed = true,
    252};
    253
    254static int poodle_probe(struct platform_device *pdev)
    255{
    256	struct snd_soc_card *card = &poodle;
    257	int ret;
    258
    259	poodle_pdata = pdev->dev.platform_data;
    260	locomo_gpio_set_dir(poodle_pdata->locomo_dev,
    261		poodle_pdata->gpio_amp_on, 0);
    262	/* should we mute HP at startup - burning power ?*/
    263	locomo_gpio_set_dir(poodle_pdata->locomo_dev,
    264		poodle_pdata->gpio_mute_l, 0);
    265	locomo_gpio_set_dir(poodle_pdata->locomo_dev,
    266		poodle_pdata->gpio_mute_r, 0);
    267
    268	card->dev = &pdev->dev;
    269
    270	ret = devm_snd_soc_register_card(&pdev->dev, card);
    271	if (ret)
    272		dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
    273			ret);
    274	return ret;
    275}
    276
    277static struct platform_driver poodle_driver = {
    278	.driver		= {
    279		.name	= "poodle-audio",
    280		.pm     = &snd_soc_pm_ops,
    281	},
    282	.probe		= poodle_probe,
    283};
    284
    285module_platform_driver(poodle_driver);
    286
    287/* Module information */
    288MODULE_AUTHOR("Richard Purdie");
    289MODULE_DESCRIPTION("ALSA SoC Poodle");
    290MODULE_LICENSE("GPL");
    291MODULE_ALIAS("platform:poodle-audio");