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

n810.c (9141B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * n810.c  --  SoC audio for Nokia N810
      4 *
      5 * Copyright (C) 2008 Nokia Corporation
      6 *
      7 * Contact: Jarkko Nikula <jarkko.nikula@bitmer.com>
      8 */
      9
     10#include <linux/clk.h>
     11#include <linux/i2c.h>
     12#include <linux/platform_device.h>
     13#include <sound/core.h>
     14#include <sound/pcm.h>
     15#include <sound/soc.h>
     16
     17#include <asm/mach-types.h>
     18#include <linux/gpio.h>
     19#include <linux/module.h>
     20#include <linux/platform_data/asoc-ti-mcbsp.h>
     21
     22#include "omap-mcbsp.h"
     23
     24#define N810_HEADSET_AMP_GPIO	10
     25#define N810_SPEAKER_AMP_GPIO	101
     26
     27enum {
     28	N810_JACK_DISABLED,
     29	N810_JACK_HP,
     30	N810_JACK_HS,
     31	N810_JACK_MIC,
     32};
     33
     34static struct clk *sys_clkout2;
     35static struct clk *sys_clkout2_src;
     36static struct clk *func96m_clk;
     37
     38static int n810_spk_func;
     39static int n810_jack_func;
     40static int n810_dmic_func;
     41
     42static void n810_ext_control(struct snd_soc_dapm_context *dapm)
     43{
     44	int hp = 0, line1l = 0;
     45
     46	switch (n810_jack_func) {
     47	case N810_JACK_HS:
     48		line1l = 1;
     49		fallthrough;
     50	case N810_JACK_HP:
     51		hp = 1;
     52		break;
     53	case N810_JACK_MIC:
     54		line1l = 1;
     55		break;
     56	}
     57
     58	snd_soc_dapm_mutex_lock(dapm);
     59
     60	if (n810_spk_func)
     61		snd_soc_dapm_enable_pin_unlocked(dapm, "Ext Spk");
     62	else
     63		snd_soc_dapm_disable_pin_unlocked(dapm, "Ext Spk");
     64
     65	if (hp)
     66		snd_soc_dapm_enable_pin_unlocked(dapm, "Headphone Jack");
     67	else
     68		snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack");
     69	if (line1l)
     70		snd_soc_dapm_enable_pin_unlocked(dapm, "HS Mic");
     71	else
     72		snd_soc_dapm_disable_pin_unlocked(dapm, "HS Mic");
     73
     74	if (n810_dmic_func)
     75		snd_soc_dapm_enable_pin_unlocked(dapm, "DMic");
     76	else
     77		snd_soc_dapm_disable_pin_unlocked(dapm, "DMic");
     78
     79	snd_soc_dapm_sync_unlocked(dapm);
     80
     81	snd_soc_dapm_mutex_unlock(dapm);
     82}
     83
     84static int n810_startup(struct snd_pcm_substream *substream)
     85{
     86	struct snd_pcm_runtime *runtime = substream->runtime;
     87	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
     88
     89	snd_pcm_hw_constraint_single(runtime, SNDRV_PCM_HW_PARAM_CHANNELS, 2);
     90
     91	n810_ext_control(&rtd->card->dapm);
     92	return clk_prepare_enable(sys_clkout2);
     93}
     94
     95static void n810_shutdown(struct snd_pcm_substream *substream)
     96{
     97	clk_disable_unprepare(sys_clkout2);
     98}
     99
    100static int n810_hw_params(struct snd_pcm_substream *substream,
    101	struct snd_pcm_hw_params *params)
    102{
    103	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
    104	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
    105	int err;
    106
    107	/* Set the codec system clock for DAC and ADC */
    108	err = snd_soc_dai_set_sysclk(codec_dai, 0, 12000000,
    109					    SND_SOC_CLOCK_IN);
    110
    111	return err;
    112}
    113
    114static const struct snd_soc_ops n810_ops = {
    115	.startup = n810_startup,
    116	.hw_params = n810_hw_params,
    117	.shutdown = n810_shutdown,
    118};
    119
    120static int n810_get_spk(struct snd_kcontrol *kcontrol,
    121			struct snd_ctl_elem_value *ucontrol)
    122{
    123	ucontrol->value.enumerated.item[0] = n810_spk_func;
    124
    125	return 0;
    126}
    127
    128static int n810_set_spk(struct snd_kcontrol *kcontrol,
    129			struct snd_ctl_elem_value *ucontrol)
    130{
    131	struct snd_soc_card *card =  snd_kcontrol_chip(kcontrol);
    132
    133	if (n810_spk_func == ucontrol->value.enumerated.item[0])
    134		return 0;
    135
    136	n810_spk_func = ucontrol->value.enumerated.item[0];
    137	n810_ext_control(&card->dapm);
    138
    139	return 1;
    140}
    141
    142static int n810_get_jack(struct snd_kcontrol *kcontrol,
    143			 struct snd_ctl_elem_value *ucontrol)
    144{
    145	ucontrol->value.enumerated.item[0] = n810_jack_func;
    146
    147	return 0;
    148}
    149
    150static int n810_set_jack(struct snd_kcontrol *kcontrol,
    151			 struct snd_ctl_elem_value *ucontrol)
    152{
    153	struct snd_soc_card *card =  snd_kcontrol_chip(kcontrol);
    154
    155	if (n810_jack_func == ucontrol->value.enumerated.item[0])
    156		return 0;
    157
    158	n810_jack_func = ucontrol->value.enumerated.item[0];
    159	n810_ext_control(&card->dapm);
    160
    161	return 1;
    162}
    163
    164static int n810_get_input(struct snd_kcontrol *kcontrol,
    165			  struct snd_ctl_elem_value *ucontrol)
    166{
    167	ucontrol->value.enumerated.item[0] = n810_dmic_func;
    168
    169	return 0;
    170}
    171
    172static int n810_set_input(struct snd_kcontrol *kcontrol,
    173			  struct snd_ctl_elem_value *ucontrol)
    174{
    175	struct snd_soc_card *card =  snd_kcontrol_chip(kcontrol);
    176
    177	if (n810_dmic_func == ucontrol->value.enumerated.item[0])
    178		return 0;
    179
    180	n810_dmic_func = ucontrol->value.enumerated.item[0];
    181	n810_ext_control(&card->dapm);
    182
    183	return 1;
    184}
    185
    186static int n810_spk_event(struct snd_soc_dapm_widget *w,
    187			  struct snd_kcontrol *k, int event)
    188{
    189	if (SND_SOC_DAPM_EVENT_ON(event))
    190		gpio_set_value(N810_SPEAKER_AMP_GPIO, 1);
    191	else
    192		gpio_set_value(N810_SPEAKER_AMP_GPIO, 0);
    193
    194	return 0;
    195}
    196
    197static int n810_jack_event(struct snd_soc_dapm_widget *w,
    198			   struct snd_kcontrol *k, int event)
    199{
    200	if (SND_SOC_DAPM_EVENT_ON(event))
    201		gpio_set_value(N810_HEADSET_AMP_GPIO, 1);
    202	else
    203		gpio_set_value(N810_HEADSET_AMP_GPIO, 0);
    204
    205	return 0;
    206}
    207
    208static const struct snd_soc_dapm_widget aic33_dapm_widgets[] = {
    209	SND_SOC_DAPM_SPK("Ext Spk", n810_spk_event),
    210	SND_SOC_DAPM_HP("Headphone Jack", n810_jack_event),
    211	SND_SOC_DAPM_MIC("DMic", NULL),
    212	SND_SOC_DAPM_MIC("HS Mic", NULL),
    213};
    214
    215static const struct snd_soc_dapm_route audio_map[] = {
    216	{"Headphone Jack", NULL, "HPLOUT"},
    217	{"Headphone Jack", NULL, "HPROUT"},
    218
    219	{"Ext Spk", NULL, "LLOUT"},
    220	{"Ext Spk", NULL, "RLOUT"},
    221
    222	{"DMic Rate 64", NULL, "DMic"},
    223	{"DMic", NULL, "Mic Bias"},
    224
    225	/*
    226	 * Note that the mic bias is coming from Retu/Vilma and we don't have
    227	 * control over it atm. The analog HS mic is not working. <- TODO
    228	 */
    229	{"LINE1L", NULL, "HS Mic"},
    230};
    231
    232static const char *spk_function[] = {"Off", "On"};
    233static const char *jack_function[] = {"Off", "Headphone", "Headset", "Mic"};
    234static const char *input_function[] = {"ADC", "Digital Mic"};
    235static const struct soc_enum n810_enum[] = {
    236	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(spk_function), spk_function),
    237	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(jack_function), jack_function),
    238	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(input_function), input_function),
    239};
    240
    241static const struct snd_kcontrol_new aic33_n810_controls[] = {
    242	SOC_ENUM_EXT("Speaker Function", n810_enum[0],
    243		     n810_get_spk, n810_set_spk),
    244	SOC_ENUM_EXT("Jack Function", n810_enum[1],
    245		     n810_get_jack, n810_set_jack),
    246	SOC_ENUM_EXT("Input Select",  n810_enum[2],
    247		     n810_get_input, n810_set_input),
    248};
    249
    250/* Digital audio interface glue - connects codec <--> CPU */
    251SND_SOC_DAILINK_DEFS(aic33,
    252	DAILINK_COMP_ARRAY(COMP_CPU("48076000.mcbsp")),
    253	DAILINK_COMP_ARRAY(COMP_CODEC("tlv320aic3x-codec.1-0018",
    254				      "tlv320aic3x-hifi")),
    255	DAILINK_COMP_ARRAY(COMP_PLATFORM("48076000.mcbsp")));
    256
    257static struct snd_soc_dai_link n810_dai = {
    258	.name = "TLV320AIC33",
    259	.stream_name = "AIC33",
    260	.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
    261		   SND_SOC_DAIFMT_CBM_CFM,
    262	.ops = &n810_ops,
    263	SND_SOC_DAILINK_REG(aic33),
    264};
    265
    266/* Audio machine driver */
    267static struct snd_soc_card snd_soc_n810 = {
    268	.name = "N810",
    269	.owner = THIS_MODULE,
    270	.dai_link = &n810_dai,
    271	.num_links = 1,
    272
    273	.controls = aic33_n810_controls,
    274	.num_controls = ARRAY_SIZE(aic33_n810_controls),
    275	.dapm_widgets = aic33_dapm_widgets,
    276	.num_dapm_widgets = ARRAY_SIZE(aic33_dapm_widgets),
    277	.dapm_routes = audio_map,
    278	.num_dapm_routes = ARRAY_SIZE(audio_map),
    279	.fully_routed = true,
    280};
    281
    282static struct platform_device *n810_snd_device;
    283
    284static int __init n810_soc_init(void)
    285{
    286	int err;
    287	struct device *dev;
    288
    289	if (!of_have_populated_dt() ||
    290	    (!of_machine_is_compatible("nokia,n810") &&
    291	     !of_machine_is_compatible("nokia,n810-wimax")))
    292		return -ENODEV;
    293
    294	n810_snd_device = platform_device_alloc("soc-audio", -1);
    295	if (!n810_snd_device)
    296		return -ENOMEM;
    297
    298	platform_set_drvdata(n810_snd_device, &snd_soc_n810);
    299	err = platform_device_add(n810_snd_device);
    300	if (err)
    301		goto err1;
    302
    303	dev = &n810_snd_device->dev;
    304
    305	sys_clkout2_src = clk_get(dev, "sys_clkout2_src");
    306	if (IS_ERR(sys_clkout2_src)) {
    307		dev_err(dev, "Could not get sys_clkout2_src clock\n");
    308		err = PTR_ERR(sys_clkout2_src);
    309		goto err2;
    310	}
    311	sys_clkout2 = clk_get(dev, "sys_clkout2");
    312	if (IS_ERR(sys_clkout2)) {
    313		dev_err(dev, "Could not get sys_clkout2\n");
    314		err = PTR_ERR(sys_clkout2);
    315		goto err3;
    316	}
    317	/*
    318	 * Configure 12 MHz output on SYS_CLKOUT2. Therefore we must use
    319	 * 96 MHz as its parent in order to get 12 MHz
    320	 */
    321	func96m_clk = clk_get(dev, "func_96m_ck");
    322	if (IS_ERR(func96m_clk)) {
    323		dev_err(dev, "Could not get func 96M clock\n");
    324		err = PTR_ERR(func96m_clk);
    325		goto err4;
    326	}
    327	clk_set_parent(sys_clkout2_src, func96m_clk);
    328	clk_set_rate(sys_clkout2, 12000000);
    329
    330	if (WARN_ON((gpio_request(N810_HEADSET_AMP_GPIO, "hs_amp") < 0) ||
    331		    (gpio_request(N810_SPEAKER_AMP_GPIO, "spk_amp") < 0))) {
    332		err = -EINVAL;
    333		goto err4;
    334	}
    335
    336	gpio_direction_output(N810_HEADSET_AMP_GPIO, 0);
    337	gpio_direction_output(N810_SPEAKER_AMP_GPIO, 0);
    338
    339	return 0;
    340err4:
    341	clk_put(sys_clkout2);
    342err3:
    343	clk_put(sys_clkout2_src);
    344err2:
    345	platform_device_del(n810_snd_device);
    346err1:
    347	platform_device_put(n810_snd_device);
    348
    349	return err;
    350}
    351
    352static void __exit n810_soc_exit(void)
    353{
    354	gpio_free(N810_SPEAKER_AMP_GPIO);
    355	gpio_free(N810_HEADSET_AMP_GPIO);
    356	clk_put(sys_clkout2_src);
    357	clk_put(sys_clkout2);
    358	clk_put(func96m_clk);
    359
    360	platform_device_unregister(n810_snd_device);
    361}
    362
    363module_init(n810_soc_init);
    364module_exit(n810_soc_exit);
    365
    366MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@bitmer.com>");
    367MODULE_DESCRIPTION("ALSA SoC Nokia N810");
    368MODULE_LICENSE("GPL");