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

omap3pandora.c (8218B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * omap3pandora.c  --  SoC audio for Pandora Handheld Console
      4 *
      5 * Author: GraÅžvydas Ignotas <notasas@gmail.com>
      6 */
      7
      8#include <linux/clk.h>
      9#include <linux/platform_device.h>
     10#include <linux/gpio.h>
     11#include <linux/delay.h>
     12#include <linux/regulator/consumer.h>
     13#include <linux/module.h>
     14
     15#include <sound/core.h>
     16#include <sound/pcm.h>
     17#include <sound/soc.h>
     18
     19#include <asm/mach-types.h>
     20#include <linux/platform_data/asoc-ti-mcbsp.h>
     21
     22#include "omap-mcbsp.h"
     23
     24#define OMAP3_PANDORA_DAC_POWER_GPIO	118
     25#define OMAP3_PANDORA_AMP_POWER_GPIO	14
     26
     27#define PREFIX "ASoC omap3pandora: "
     28
     29static struct regulator *omap3pandora_dac_reg;
     30
     31static int omap3pandora_hw_params(struct snd_pcm_substream *substream,
     32	struct snd_pcm_hw_params *params)
     33{
     34	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
     35	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
     36	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
     37	int ret;
     38
     39	/* Set the codec system clock for DAC and ADC */
     40	ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000,
     41					    SND_SOC_CLOCK_IN);
     42	if (ret < 0) {
     43		pr_err(PREFIX "can't set codec system clock\n");
     44		return ret;
     45	}
     46
     47	/* Set McBSP clock to external */
     48	ret = snd_soc_dai_set_sysclk(cpu_dai, OMAP_MCBSP_SYSCLK_CLKS_EXT,
     49				     256 * params_rate(params),
     50				     SND_SOC_CLOCK_IN);
     51	if (ret < 0) {
     52		pr_err(PREFIX "can't set cpu system clock\n");
     53		return ret;
     54	}
     55
     56	ret = snd_soc_dai_set_clkdiv(cpu_dai, OMAP_MCBSP_CLKGDV, 8);
     57	if (ret < 0) {
     58		pr_err(PREFIX "can't set SRG clock divider\n");
     59		return ret;
     60	}
     61
     62	return 0;
     63}
     64
     65static int omap3pandora_dac_event(struct snd_soc_dapm_widget *w,
     66	struct snd_kcontrol *k, int event)
     67{
     68	int ret;
     69
     70	/*
     71	 * The PCM1773 DAC datasheet requires 1ms delay between switching
     72	 * VCC power on/off and /PD pin high/low
     73	 */
     74	if (SND_SOC_DAPM_EVENT_ON(event)) {
     75		ret = regulator_enable(omap3pandora_dac_reg);
     76		if (ret) {
     77			dev_err(w->dapm->dev, "Failed to power DAC: %d\n", ret);
     78			return ret;
     79		}
     80		mdelay(1);
     81		gpio_set_value(OMAP3_PANDORA_DAC_POWER_GPIO, 1);
     82	} else {
     83		gpio_set_value(OMAP3_PANDORA_DAC_POWER_GPIO, 0);
     84		mdelay(1);
     85		regulator_disable(omap3pandora_dac_reg);
     86	}
     87
     88	return 0;
     89}
     90
     91static int omap3pandora_hp_event(struct snd_soc_dapm_widget *w,
     92	struct snd_kcontrol *k, int event)
     93{
     94	if (SND_SOC_DAPM_EVENT_ON(event))
     95		gpio_set_value(OMAP3_PANDORA_AMP_POWER_GPIO, 1);
     96	else
     97		gpio_set_value(OMAP3_PANDORA_AMP_POWER_GPIO, 0);
     98
     99	return 0;
    100}
    101
    102/*
    103 * Audio paths on Pandora board:
    104 *
    105 *  |O| ---> PCM DAC +-> AMP -> Headphone Jack
    106 *  |M|         A    +--------> Line Out
    107 *  |A| <~~clk~~+
    108 *  |P| <--- TWL4030 <--------- Line In and MICs
    109 */
    110static const struct snd_soc_dapm_widget omap3pandora_dapm_widgets[] = {
    111	SND_SOC_DAPM_DAC_E("PCM DAC", "HiFi Playback", SND_SOC_NOPM,
    112			   0, 0, omap3pandora_dac_event,
    113			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
    114	SND_SOC_DAPM_PGA_E("Headphone Amplifier", SND_SOC_NOPM,
    115			   0, 0, NULL, 0, omap3pandora_hp_event,
    116			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
    117	SND_SOC_DAPM_HP("Headphone Jack", NULL),
    118	SND_SOC_DAPM_LINE("Line Out", NULL),
    119
    120	SND_SOC_DAPM_MIC("Mic (internal)", NULL),
    121	SND_SOC_DAPM_MIC("Mic (external)", NULL),
    122	SND_SOC_DAPM_LINE("Line In", NULL),
    123};
    124
    125static const struct snd_soc_dapm_route omap3pandora_map[] = {
    126	{"PCM DAC", NULL, "APLL Enable"},
    127	{"Headphone Amplifier", NULL, "PCM DAC"},
    128	{"Line Out", NULL, "PCM DAC"},
    129	{"Headphone Jack", NULL, "Headphone Amplifier"},
    130
    131	{"AUXL", NULL, "Line In"},
    132	{"AUXR", NULL, "Line In"},
    133
    134	{"MAINMIC", NULL, "Mic (internal)"},
    135	{"Mic (internal)", NULL, "Mic Bias 1"},
    136
    137	{"SUBMIC", NULL, "Mic (external)"},
    138	{"Mic (external)", NULL, "Mic Bias 2"},
    139};
    140
    141static int omap3pandora_out_init(struct snd_soc_pcm_runtime *rtd)
    142{
    143	struct snd_soc_dapm_context *dapm = &rtd->card->dapm;
    144
    145	/* All TWL4030 output pins are floating */
    146	snd_soc_dapm_nc_pin(dapm, "EARPIECE");
    147	snd_soc_dapm_nc_pin(dapm, "PREDRIVEL");
    148	snd_soc_dapm_nc_pin(dapm, "PREDRIVER");
    149	snd_soc_dapm_nc_pin(dapm, "HSOL");
    150	snd_soc_dapm_nc_pin(dapm, "HSOR");
    151	snd_soc_dapm_nc_pin(dapm, "CARKITL");
    152	snd_soc_dapm_nc_pin(dapm, "CARKITR");
    153	snd_soc_dapm_nc_pin(dapm, "HFL");
    154	snd_soc_dapm_nc_pin(dapm, "HFR");
    155	snd_soc_dapm_nc_pin(dapm, "VIBRA");
    156
    157	return 0;
    158}
    159
    160static int omap3pandora_in_init(struct snd_soc_pcm_runtime *rtd)
    161{
    162	struct snd_soc_dapm_context *dapm = &rtd->card->dapm;
    163
    164	/* Not comnnected */
    165	snd_soc_dapm_nc_pin(dapm, "HSMIC");
    166	snd_soc_dapm_nc_pin(dapm, "CARKITMIC");
    167	snd_soc_dapm_nc_pin(dapm, "DIGIMIC0");
    168	snd_soc_dapm_nc_pin(dapm, "DIGIMIC1");
    169
    170	return 0;
    171}
    172
    173static const struct snd_soc_ops omap3pandora_ops = {
    174	.hw_params = omap3pandora_hw_params,
    175};
    176
    177/* Digital audio interface glue - connects codec <--> CPU */
    178SND_SOC_DAILINK_DEFS(out,
    179	DAILINK_COMP_ARRAY(COMP_CPU("omap-mcbsp.2")),
    180	DAILINK_COMP_ARRAY(COMP_CODEC("twl4030-codec", "twl4030-hifi")),
    181	DAILINK_COMP_ARRAY(COMP_PLATFORM("omap-mcbsp.2")));
    182
    183SND_SOC_DAILINK_DEFS(in,
    184	DAILINK_COMP_ARRAY(COMP_CPU("omap-mcbsp.4")),
    185	DAILINK_COMP_ARRAY(COMP_CODEC("twl4030-codec", "twl4030-hifi")),
    186	DAILINK_COMP_ARRAY(COMP_PLATFORM("omap-mcbsp.4")));
    187
    188static struct snd_soc_dai_link omap3pandora_dai[] = {
    189	{
    190		.name = "PCM1773",
    191		.stream_name = "HiFi Out",
    192		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
    193			   SND_SOC_DAIFMT_CBS_CFS,
    194		.ops = &omap3pandora_ops,
    195		.init = omap3pandora_out_init,
    196		SND_SOC_DAILINK_REG(out),
    197	}, {
    198		.name = "TWL4030",
    199		.stream_name = "Line/Mic In",
    200		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
    201			   SND_SOC_DAIFMT_CBS_CFS,
    202		.ops = &omap3pandora_ops,
    203		.init = omap3pandora_in_init,
    204		SND_SOC_DAILINK_REG(in),
    205	}
    206};
    207
    208/* SoC card */
    209static struct snd_soc_card snd_soc_card_omap3pandora = {
    210	.name = "omap3pandora",
    211	.owner = THIS_MODULE,
    212	.dai_link = omap3pandora_dai,
    213	.num_links = ARRAY_SIZE(omap3pandora_dai),
    214
    215	.dapm_widgets = omap3pandora_dapm_widgets,
    216	.num_dapm_widgets = ARRAY_SIZE(omap3pandora_dapm_widgets),
    217	.dapm_routes = omap3pandora_map,
    218	.num_dapm_routes = ARRAY_SIZE(omap3pandora_map),
    219};
    220
    221static struct platform_device *omap3pandora_snd_device;
    222
    223static int __init omap3pandora_soc_init(void)
    224{
    225	int ret;
    226
    227	if (!machine_is_omap3_pandora())
    228		return -ENODEV;
    229
    230	pr_info("OMAP3 Pandora SoC init\n");
    231
    232	ret = gpio_request(OMAP3_PANDORA_DAC_POWER_GPIO, "dac_power");
    233	if (ret) {
    234		pr_err(PREFIX "Failed to get DAC power GPIO\n");
    235		return ret;
    236	}
    237
    238	ret = gpio_direction_output(OMAP3_PANDORA_DAC_POWER_GPIO, 0);
    239	if (ret) {
    240		pr_err(PREFIX "Failed to set DAC power GPIO direction\n");
    241		goto fail0;
    242	}
    243
    244	ret = gpio_request(OMAP3_PANDORA_AMP_POWER_GPIO, "amp_power");
    245	if (ret) {
    246		pr_err(PREFIX "Failed to get amp power GPIO\n");
    247		goto fail0;
    248	}
    249
    250	ret = gpio_direction_output(OMAP3_PANDORA_AMP_POWER_GPIO, 0);
    251	if (ret) {
    252		pr_err(PREFIX "Failed to set amp power GPIO direction\n");
    253		goto fail1;
    254	}
    255
    256	omap3pandora_snd_device = platform_device_alloc("soc-audio", -1);
    257	if (omap3pandora_snd_device == NULL) {
    258		pr_err(PREFIX "Platform device allocation failed\n");
    259		ret = -ENOMEM;
    260		goto fail1;
    261	}
    262
    263	platform_set_drvdata(omap3pandora_snd_device, &snd_soc_card_omap3pandora);
    264
    265	ret = platform_device_add(omap3pandora_snd_device);
    266	if (ret) {
    267		pr_err(PREFIX "Unable to add platform device\n");
    268		goto fail2;
    269	}
    270
    271	omap3pandora_dac_reg = regulator_get(&omap3pandora_snd_device->dev, "vcc");
    272	if (IS_ERR(omap3pandora_dac_reg)) {
    273		pr_err(PREFIX "Failed to get DAC regulator from %s: %ld\n",
    274			dev_name(&omap3pandora_snd_device->dev),
    275			PTR_ERR(omap3pandora_dac_reg));
    276		ret = PTR_ERR(omap3pandora_dac_reg);
    277		goto fail3;
    278	}
    279
    280	return 0;
    281
    282fail3:
    283	platform_device_del(omap3pandora_snd_device);
    284fail2:
    285	platform_device_put(omap3pandora_snd_device);
    286fail1:
    287	gpio_free(OMAP3_PANDORA_AMP_POWER_GPIO);
    288fail0:
    289	gpio_free(OMAP3_PANDORA_DAC_POWER_GPIO);
    290	return ret;
    291}
    292module_init(omap3pandora_soc_init);
    293
    294static void __exit omap3pandora_soc_exit(void)
    295{
    296	regulator_put(omap3pandora_dac_reg);
    297	platform_device_unregister(omap3pandora_snd_device);
    298	gpio_free(OMAP3_PANDORA_AMP_POWER_GPIO);
    299	gpio_free(OMAP3_PANDORA_DAC_POWER_GPIO);
    300}
    301module_exit(omap3pandora_soc_exit);
    302
    303MODULE_AUTHOR("Grazvydas Ignotas <notasas@gmail.com>");
    304MODULE_DESCRIPTION("ALSA SoC OMAP3 Pandora");
    305MODULE_LICENSE("GPL");