brintos

brintos / linux-shallow public Read only

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