diff options
Diffstat (limited to 'sound')
-rw-r--r-- | sound/soc/fsl/Kconfig | 12 | ||||
-rw-r--r-- | sound/soc/fsl/Makefile | 2 | ||||
-rw-r--r-- | sound/soc/fsl/imx-si476x.c | 164 |
3 files changed, 178 insertions, 0 deletions
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index d3d54e565d64..0c9f147da49f 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -221,4 +221,16 @@ config SND_SOC_IMX_MC13783 select SND_SOC_MC13783 select SND_SOC_IMX_PCM_DMA +config SND_SOC_IMX_SI476X + tristate "SoC Audio support for i.MX boards with si476x" + select SND_SOC_IMX_PCM_DMA + select SND_SOC_IMX_AUDMUX + select SND_SOC_FSL_SSI + select SND_SOC_FSL_UTILS + select SND_SOC_SI476X + help + SoC Audio support for i.MX boards with SI476x + Say Y if you want to add support for Soc audio for the AMFM Tuner chip + SI476x module. + endif # SND_IMX_SOC diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile index 79a6858bb61d..72f812e8cdb6 100644 --- a/sound/soc/fsl/Makefile +++ b/sound/soc/fsl/Makefile @@ -53,6 +53,7 @@ snd-soc-imx-cs42888-objs := imx-cs42888.o snd-soc-imx-sgtl5000-objs := imx-sgtl5000.o snd-soc-imx-wm8962-objs := imx-wm8962.o snd-soc-imx-mc13783-objs := imx-mc13783.o +snd-soc-imx-si476x-objs := imx-si476x.o obj-$(CONFIG_SND_SOC_EUKREA_TLV320) += snd-soc-eukrea-tlv320.o obj-$(CONFIG_SND_SOC_PHYCORE_AC97) += snd-soc-phycore-ac97.o @@ -62,3 +63,4 @@ obj-$(CONFIG_SND_SOC_IMX_CS42888) += snd-soc-imx-cs42888.o obj-$(CONFIG_SND_SOC_IMX_SGTL5000) += snd-soc-imx-sgtl5000.o obj-$(CONFIG_SND_SOC_IMX_WM8962) += snd-soc-imx-wm8962.o obj-$(CONFIG_SND_SOC_IMX_MC13783) += snd-soc-imx-mc13783.o +obj-$(CONFIG_SND_SOC_IMX_SI476X) += snd-soc-imx-si476x.o diff --git a/sound/soc/fsl/imx-si476x.c b/sound/soc/fsl/imx-si476x.c new file mode 100644 index 000000000000..d3febf80af59 --- /dev/null +++ b/sound/soc/fsl/imx-si476x.c @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2008-2013 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include <linux/module.h> +#include <linux/of_platform.h> +#include <sound/soc.h> + +#include "imx-audmux.h" + +static int imx_audmux_config(int slave, int master) +{ + unsigned int ptcr, pdcr; + slave = slave - 1; + master = master - 1; + + ptcr = IMX_AUDMUX_V2_PTCR_SYN | + IMX_AUDMUX_V2_PTCR_TFSDIR | + IMX_AUDMUX_V2_PTCR_TFSEL(slave) | + IMX_AUDMUX_V2_PTCR_TCLKDIR | + IMX_AUDMUX_V2_PTCR_TCSEL(slave); + pdcr = IMX_AUDMUX_V2_PDCR_RXDSEL(slave); + imx_audmux_v2_configure_port(master, ptcr, pdcr); + + ptcr = IMX_AUDMUX_V2_PTCR_SYN; + pdcr = IMX_AUDMUX_V2_PDCR_RXDSEL(master); + imx_audmux_v2_configure_port(slave, ptcr, pdcr); + + return 0; +} + +static int imx_si476x_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + u32 channels = params_channels(params); + u32 rate = params_rate(params); + u32 bclk = rate * channels * 32; + int ret = 0; + + /* set cpu DAI configuration */ + ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S + | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); + if (ret) { + dev_err(cpu_dai->dev, "failed to set dai fmt\n"); + return ret; + } + + ret = snd_soc_dai_set_sysclk(cpu_dai, 0, bclk, SND_SOC_CLOCK_OUT); + if (ret) + dev_err(cpu_dai->dev, "failed to set sysclk\n"); + + return ret; +} + +static struct snd_soc_ops imx_si476x_ops = { + .hw_params = imx_si476x_hw_params, +}; + +static struct snd_soc_dai_link imx_dai = { + .name = "imx-si476x", + .stream_name = "imx-si476x", + .codec_dai_name = "si476x-codec", + .codec_name = "si476x-codec.99", + .ops = &imx_si476x_ops, +}; + +static struct snd_soc_card snd_soc_card_imx_3stack = { + .name = "imx-audio-si476x", + .dai_link = &imx_dai, + .num_links = 1, +}; + +static int imx_si476x_probe(struct platform_device *pdev) +{ + struct snd_soc_card *card = &snd_soc_card_imx_3stack; + struct device_node *ssi_np, *np = pdev->dev.of_node; + struct platform_device *ssi_pdev; + int int_port, ext_port, ret; + + ret = of_property_read_u32(np, "mux-int-port", &int_port); + if (ret) { + dev_err(&pdev->dev, "mux-int-port missing or invalid\n"); + return ret; + } + + ret = of_property_read_u32(np, "mux-ext-port", &ext_port); + if (ret) { + dev_err(&pdev->dev, "mux-ext-port missing or invalid\n"); + return ret; + } + + imx_audmux_config(int_port, ext_port); + + ssi_np = of_parse_phandle(pdev->dev.of_node, "ssi-controller", 0); + if (!ssi_np) { + dev_err(&pdev->dev, "phandle missing or invalid\n"); + return -EINVAL; + } + + ssi_pdev = of_find_device_by_node(ssi_np); + if (!ssi_pdev) { + dev_err(&pdev->dev, "failed to find SSI platform device\n"); + ret = -EINVAL; + goto end; + } + + card->dev = &pdev->dev; + card->dai_link->cpu_dai_name = dev_name(&ssi_pdev->dev); + card->dai_link->platform_of_node = ssi_np; + + ret = snd_soc_register_card(card); + if (ret) + dev_err(&pdev->dev, "Failed to register card: %d\n", ret); + +end: + if (ssi_np) + of_node_put(ssi_np); + + return ret; +} + +static int imx_si476x_remove(struct platform_device *pdev) +{ + struct snd_soc_card *card = &snd_soc_card_imx_3stack; + + snd_soc_unregister_card(card); + + return 0; +} + +static const struct of_device_id imx_si476x_dt_ids[] = { + { .compatible = "fsl,imx-audio-si476x", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, imx_si476x_dt_ids); + +static struct platform_driver imx_si476x_driver = { + .driver = { + .name = "imx-tuner-si476x", + .owner = THIS_MODULE, + .of_match_table = imx_si476x_dt_ids, + }, + .probe = imx_si476x_probe, + .remove = imx_si476x_remove, +}; + +module_platform_driver(imx_si476x_driver); + +/* Module information */ +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("ALSA SoC i.MX si476x"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:imx-tuner-si476x"); |