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

imx-sgtl5000.c (5947B)


      1// SPDX-License-Identifier: GPL-2.0+
      2//
      3// Copyright 2012 Freescale Semiconductor, Inc.
      4// Copyright 2012 Linaro Ltd.
      5
      6#include <linux/module.h>
      7#include <linux/of.h>
      8#include <linux/of_platform.h>
      9#include <linux/i2c.h>
     10#include <linux/clk.h>
     11#include <sound/soc.h>
     12
     13#include "../codecs/sgtl5000.h"
     14#include "imx-audmux.h"
     15
     16#define DAI_NAME_SIZE	32
     17
     18struct imx_sgtl5000_data {
     19	struct snd_soc_dai_link dai;
     20	struct snd_soc_card card;
     21	char codec_dai_name[DAI_NAME_SIZE];
     22	char platform_name[DAI_NAME_SIZE];
     23	struct clk *codec_clk;
     24	unsigned int clk_frequency;
     25};
     26
     27static int imx_sgtl5000_dai_init(struct snd_soc_pcm_runtime *rtd)
     28{
     29	struct imx_sgtl5000_data *data = snd_soc_card_get_drvdata(rtd->card);
     30	struct device *dev = rtd->card->dev;
     31	int ret;
     32
     33	ret = snd_soc_dai_set_sysclk(asoc_rtd_to_codec(rtd, 0), SGTL5000_SYSCLK,
     34				     data->clk_frequency, SND_SOC_CLOCK_IN);
     35	if (ret) {
     36		dev_err(dev, "could not set codec driver clock params\n");
     37		return ret;
     38	}
     39
     40	return 0;
     41}
     42
     43static const struct snd_soc_dapm_widget imx_sgtl5000_dapm_widgets[] = {
     44	SND_SOC_DAPM_MIC("Mic Jack", NULL),
     45	SND_SOC_DAPM_LINE("Line In Jack", NULL),
     46	SND_SOC_DAPM_HP("Headphone Jack", NULL),
     47	SND_SOC_DAPM_SPK("Line Out Jack", NULL),
     48	SND_SOC_DAPM_SPK("Ext Spk", NULL),
     49};
     50
     51static int imx_sgtl5000_probe(struct platform_device *pdev)
     52{
     53	struct device_node *np = pdev->dev.of_node;
     54	struct device_node *ssi_np, *codec_np;
     55	struct platform_device *ssi_pdev;
     56	struct i2c_client *codec_dev;
     57	struct imx_sgtl5000_data *data = NULL;
     58	struct snd_soc_dai_link_component *comp;
     59	int int_port, ext_port;
     60	int ret;
     61
     62	ret = of_property_read_u32(np, "mux-int-port", &int_port);
     63	if (ret) {
     64		dev_err(&pdev->dev, "mux-int-port missing or invalid\n");
     65		return ret;
     66	}
     67	ret = of_property_read_u32(np, "mux-ext-port", &ext_port);
     68	if (ret) {
     69		dev_err(&pdev->dev, "mux-ext-port missing or invalid\n");
     70		return ret;
     71	}
     72
     73	/*
     74	 * The port numbering in the hardware manual starts at 1, while
     75	 * the audmux API expects it starts at 0.
     76	 */
     77	int_port--;
     78	ext_port--;
     79	ret = imx_audmux_v2_configure_port(int_port,
     80			IMX_AUDMUX_V2_PTCR_SYN |
     81			IMX_AUDMUX_V2_PTCR_TFSEL(ext_port) |
     82			IMX_AUDMUX_V2_PTCR_TCSEL(ext_port) |
     83			IMX_AUDMUX_V2_PTCR_TFSDIR |
     84			IMX_AUDMUX_V2_PTCR_TCLKDIR,
     85			IMX_AUDMUX_V2_PDCR_RXDSEL(ext_port));
     86	if (ret) {
     87		dev_err(&pdev->dev, "audmux internal port setup failed\n");
     88		return ret;
     89	}
     90	ret = imx_audmux_v2_configure_port(ext_port,
     91			IMX_AUDMUX_V2_PTCR_SYN,
     92			IMX_AUDMUX_V2_PDCR_RXDSEL(int_port));
     93	if (ret) {
     94		dev_err(&pdev->dev, "audmux external port setup failed\n");
     95		return ret;
     96	}
     97
     98	ssi_np = of_parse_phandle(pdev->dev.of_node, "ssi-controller", 0);
     99	codec_np = of_parse_phandle(pdev->dev.of_node, "audio-codec", 0);
    100	if (!ssi_np || !codec_np) {
    101		dev_err(&pdev->dev, "phandle missing or invalid\n");
    102		ret = -EINVAL;
    103		goto fail;
    104	}
    105
    106	ssi_pdev = of_find_device_by_node(ssi_np);
    107	if (!ssi_pdev) {
    108		dev_dbg(&pdev->dev, "failed to find SSI platform device\n");
    109		ret = -EPROBE_DEFER;
    110		goto fail;
    111	}
    112	put_device(&ssi_pdev->dev);
    113	codec_dev = of_find_i2c_device_by_node(codec_np);
    114	if (!codec_dev) {
    115		dev_dbg(&pdev->dev, "failed to find codec platform device\n");
    116		ret = -EPROBE_DEFER;
    117		goto fail;
    118	}
    119
    120	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
    121	if (!data) {
    122		ret = -ENOMEM;
    123		goto put_device;
    124	}
    125
    126	comp = devm_kzalloc(&pdev->dev, 3 * sizeof(*comp), GFP_KERNEL);
    127	if (!comp) {
    128		ret = -ENOMEM;
    129		goto put_device;
    130	}
    131
    132	data->codec_clk = clk_get(&codec_dev->dev, NULL);
    133	if (IS_ERR(data->codec_clk)) {
    134		ret = PTR_ERR(data->codec_clk);
    135		goto put_device;
    136	}
    137
    138	data->clk_frequency = clk_get_rate(data->codec_clk);
    139
    140	data->dai.cpus		= &comp[0];
    141	data->dai.codecs	= &comp[1];
    142	data->dai.platforms	= &comp[2];
    143
    144	data->dai.num_cpus	= 1;
    145	data->dai.num_codecs	= 1;
    146	data->dai.num_platforms	= 1;
    147
    148	data->dai.name = "HiFi";
    149	data->dai.stream_name = "HiFi";
    150	data->dai.codecs->dai_name = "sgtl5000";
    151	data->dai.codecs->of_node = codec_np;
    152	data->dai.cpus->of_node = ssi_np;
    153	data->dai.platforms->of_node = ssi_np;
    154	data->dai.init = &imx_sgtl5000_dai_init;
    155	data->dai.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
    156			    SND_SOC_DAIFMT_CBP_CFP;
    157
    158	data->card.dev = &pdev->dev;
    159	ret = snd_soc_of_parse_card_name(&data->card, "model");
    160	if (ret)
    161		goto put_device;
    162	ret = snd_soc_of_parse_audio_routing(&data->card, "audio-routing");
    163	if (ret)
    164		goto put_device;
    165	data->card.num_links = 1;
    166	data->card.owner = THIS_MODULE;
    167	data->card.dai_link = &data->dai;
    168	data->card.dapm_widgets = imx_sgtl5000_dapm_widgets;
    169	data->card.num_dapm_widgets = ARRAY_SIZE(imx_sgtl5000_dapm_widgets);
    170
    171	platform_set_drvdata(pdev, &data->card);
    172	snd_soc_card_set_drvdata(&data->card, data);
    173
    174	ret = devm_snd_soc_register_card(&pdev->dev, &data->card);
    175	if (ret) {
    176		dev_err_probe(&pdev->dev, ret, "snd_soc_register_card failed\n");
    177		goto put_device;
    178	}
    179
    180	of_node_put(ssi_np);
    181	of_node_put(codec_np);
    182
    183	return 0;
    184
    185put_device:
    186	put_device(&codec_dev->dev);
    187fail:
    188	if (data && !IS_ERR(data->codec_clk))
    189		clk_put(data->codec_clk);
    190	of_node_put(ssi_np);
    191	of_node_put(codec_np);
    192
    193	return ret;
    194}
    195
    196static int imx_sgtl5000_remove(struct platform_device *pdev)
    197{
    198	struct snd_soc_card *card = platform_get_drvdata(pdev);
    199	struct imx_sgtl5000_data *data = snd_soc_card_get_drvdata(card);
    200
    201	clk_put(data->codec_clk);
    202
    203	return 0;
    204}
    205
    206static const struct of_device_id imx_sgtl5000_dt_ids[] = {
    207	{ .compatible = "fsl,imx-audio-sgtl5000", },
    208	{ /* sentinel */ }
    209};
    210MODULE_DEVICE_TABLE(of, imx_sgtl5000_dt_ids);
    211
    212static struct platform_driver imx_sgtl5000_driver = {
    213	.driver = {
    214		.name = "imx-sgtl5000",
    215		.pm = &snd_soc_pm_ops,
    216		.of_match_table = imx_sgtl5000_dt_ids,
    217	},
    218	.probe = imx_sgtl5000_probe,
    219	.remove = imx_sgtl5000_remove,
    220};
    221module_platform_driver(imx_sgtl5000_driver);
    222
    223MODULE_AUTHOR("Shawn Guo <shawn.guo@linaro.org>");
    224MODULE_DESCRIPTION("Freescale i.MX SGTL5000 ASoC machine driver");
    225MODULE_LICENSE("GPL v2");
    226MODULE_ALIAS("platform:imx-sgtl5000");