1// SPDX-License-Identifier: GPL-2.0+ 2// 3// imx-mc13783.c -- SoC audio for imx based boards with mc13783 codec 4// 5// Copyright 2012 Philippe Retornaz, <philippe.retornaz@epfl.ch> 6// 7// Heavly based on phycore-mc13783: 8// Copyright 2009 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de> 9 10#include <linux/module.h> 11#include <linux/moduleparam.h> 12#include <linux/device.h> 13#include <sound/core.h> 14#include <sound/pcm.h> 15#include <sound/soc.h> 16#include <sound/soc-dapm.h> 17#include <asm/mach-types.h> 18 19#include "../codecs/mc13783.h" 20#include "imx-ssi.h" 21#include "imx-audmux.h" 22 23#define FMT_SSI (SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF | \ 24 SND_SOC_DAIFMT_CBM_CFM) 25 26static int imx_mc13783_hifi_hw_params(struct snd_pcm_substream *substream, 27 struct snd_pcm_hw_params *params) 28{ 29 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 30 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); 31 struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); 32 int ret; 33 34 ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x3, 0x3, 4, 16); 35 if (ret) 36 return ret; 37 38 ret = snd_soc_dai_set_sysclk(codec_dai, MC13783_CLK_CLIA, 26000000, 0); 39 if (ret) 40 return ret; 41 42 return snd_soc_dai_set_tdm_slot(cpu_dai, 0x3, 0x3, 2, 16); 43} 44 45static const struct snd_soc_ops imx_mc13783_hifi_ops = { 46 .hw_params = imx_mc13783_hifi_hw_params, 47}; 48 49SND_SOC_DAILINK_DEFS(hifi, 50 DAILINK_COMP_ARRAY(COMP_CPU("imx-ssi.0")), 51 DAILINK_COMP_ARRAY(COMP_CODEC("mc13783-codec", "mc13783-hifi")), 52 DAILINK_COMP_ARRAY(COMP_PLATFORM("imx-ssi.0"))); 53 54static struct snd_soc_dai_link imx_mc13783_dai_mc13783[] = { 55 { 56 .name = "MC13783", 57 .stream_name = "Sound", 58 .ops = &imx_mc13783_hifi_ops, 59 .symmetric_rates = 1, 60 .dai_fmt = FMT_SSI, 61 SND_SOC_DAILINK_REG(hifi), 62 }, 63}; 64 65static const struct snd_soc_dapm_widget imx_mc13783_widget[] = { 66 SND_SOC_DAPM_MIC("Mic", NULL), 67 SND_SOC_DAPM_HP("Headphone", NULL), 68 SND_SOC_DAPM_SPK("Speaker", NULL), 69}; 70 71static const struct snd_soc_dapm_route imx_mc13783_routes[] = { 72 {"Speaker", NULL, "LSP"}, 73 {"Headphone", NULL, "HSL"}, 74 {"Headphone", NULL, "HSR"}, 75 76 {"MC1LIN", NULL, "MC1 Bias"}, 77 {"MC2IN", NULL, "MC2 Bias"}, 78 {"MC1 Bias", NULL, "Mic"}, 79 {"MC2 Bias", NULL, "Mic"}, 80}; 81 82static struct snd_soc_card imx_mc13783 = { 83 .name = "imx_mc13783", 84 .owner = THIS_MODULE, 85 .dai_link = imx_mc13783_dai_mc13783, 86 .num_links = ARRAY_SIZE(imx_mc13783_dai_mc13783), 87 .dapm_widgets = imx_mc13783_widget, 88 .num_dapm_widgets = ARRAY_SIZE(imx_mc13783_widget), 89 .dapm_routes = imx_mc13783_routes, 90 .num_dapm_routes = ARRAY_SIZE(imx_mc13783_routes), 91}; 92 93static int imx_mc13783_probe(struct platform_device *pdev) 94{ 95 int ret; 96 97 imx_mc13783.dev = &pdev->dev; 98 99 ret = devm_snd_soc_register_card(&pdev->dev, &imx_mc13783); 100 if (ret) { 101 dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", 102 ret); 103 return ret; 104 } 105 106 if (machine_is_mx31_3ds() || machine_is_mx31moboard()) { 107 imx_audmux_v2_configure_port(MX31_AUDMUX_PORT4_SSI_PINS_4, 108 IMX_AUDMUX_V2_PTCR_SYN, 109 IMX_AUDMUX_V2_PDCR_RXDSEL(MX31_AUDMUX_PORT1_SSI0) | 110 IMX_AUDMUX_V2_PDCR_MODE(1) | 111 IMX_AUDMUX_V2_PDCR_INMMASK(0xfc)); 112 imx_audmux_v2_configure_port(MX31_AUDMUX_PORT1_SSI0, 113 IMX_AUDMUX_V2_PTCR_SYN | 114 IMX_AUDMUX_V2_PTCR_TFSDIR | 115 IMX_AUDMUX_V2_PTCR_TFSEL(MX31_AUDMUX_PORT4_SSI_PINS_4) | 116 IMX_AUDMUX_V2_PTCR_TCLKDIR | 117 IMX_AUDMUX_V2_PTCR_TCSEL(MX31_AUDMUX_PORT4_SSI_PINS_4) | 118 IMX_AUDMUX_V2_PTCR_RFSDIR | 119 IMX_AUDMUX_V2_PTCR_RFSEL(MX31_AUDMUX_PORT4_SSI_PINS_4) | 120 IMX_AUDMUX_V2_PTCR_RCLKDIR | 121 IMX_AUDMUX_V2_PTCR_RCSEL(MX31_AUDMUX_PORT4_SSI_PINS_4), 122 IMX_AUDMUX_V2_PDCR_RXDSEL(MX31_AUDMUX_PORT4_SSI_PINS_4)); 123 } else if (machine_is_mx27_3ds()) { 124 imx_audmux_v1_configure_port(MX27_AUDMUX_HPCR1_SSI0, 125 IMX_AUDMUX_V1_PCR_SYN | 126 IMX_AUDMUX_V1_PCR_TFSDIR | 127 IMX_AUDMUX_V1_PCR_TCLKDIR | 128 IMX_AUDMUX_V1_PCR_RFSDIR | 129 IMX_AUDMUX_V1_PCR_RCLKDIR | 130 IMX_AUDMUX_V1_PCR_TFCSEL(MX27_AUDMUX_HPCR3_SSI_PINS_4) | 131 IMX_AUDMUX_V1_PCR_RFCSEL(MX27_AUDMUX_HPCR3_SSI_PINS_4) | 132 IMX_AUDMUX_V1_PCR_RXDSEL(MX27_AUDMUX_HPCR3_SSI_PINS_4) 133 ); 134 imx_audmux_v1_configure_port(MX27_AUDMUX_HPCR3_SSI_PINS_4, 135 IMX_AUDMUX_V1_PCR_SYN | 136 IMX_AUDMUX_V1_PCR_RXDSEL(MX27_AUDMUX_HPCR1_SSI0) 137 ); 138 } 139 140 return ret; 141} 142 143static struct platform_driver imx_mc13783_audio_driver = { 144 .driver = { 145 .name = "imx_mc13783", 146 }, 147 .probe = imx_mc13783_probe, 148}; 149 150module_platform_driver(imx_mc13783_audio_driver); 151 152MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>"); 153MODULE_AUTHOR("Philippe Retornaz <philippe.retornaz@epfl.ch"); 154MODULE_DESCRIPTION("imx with mc13783 codec ALSA SoC driver"); 155MODULE_LICENSE("GPL"); 156MODULE_ALIAS("platform:imx_mc13783"); 157