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-es8328.c (5888B)


      1// SPDX-License-Identifier: GPL-2.0+
      2//
      3// Copyright 2012 Freescale Semiconductor, Inc.
      4// Copyright 2012 Linaro Ltd.
      5
      6#include <linux/gpio.h>
      7#include <linux/module.h>
      8#include <linux/of.h>
      9#include <linux/of_platform.h>
     10#include <linux/i2c.h>
     11#include <linux/of_gpio.h>
     12#include <sound/soc.h>
     13#include <sound/jack.h>
     14
     15#include "imx-audmux.h"
     16
     17#define DAI_NAME_SIZE	32
     18#define MUX_PORT_MAX	7
     19
     20struct imx_es8328_data {
     21	struct device *dev;
     22	struct snd_soc_dai_link dai;
     23	struct snd_soc_card card;
     24	char codec_dai_name[DAI_NAME_SIZE];
     25	char platform_name[DAI_NAME_SIZE];
     26	int jack_gpio;
     27};
     28
     29static struct snd_soc_jack_gpio headset_jack_gpios[] = {
     30	{
     31		.gpio = -1,
     32		.name = "headset-gpio",
     33		.report = SND_JACK_HEADSET,
     34		.invert = 0,
     35		.debounce_time = 200,
     36	},
     37};
     38
     39static struct snd_soc_jack headset_jack;
     40
     41static int imx_es8328_dai_init(struct snd_soc_pcm_runtime *rtd)
     42{
     43	struct imx_es8328_data *data = container_of(rtd->card,
     44					struct imx_es8328_data, card);
     45	int ret = 0;
     46
     47	/* Headphone jack detection */
     48	if (gpio_is_valid(data->jack_gpio)) {
     49		ret = snd_soc_card_jack_new(rtd->card, "Headphone",
     50					    SND_JACK_HEADPHONE | SND_JACK_BTN_0,
     51					    &headset_jack);
     52		if (ret)
     53			return ret;
     54
     55		headset_jack_gpios[0].gpio = data->jack_gpio;
     56		ret = snd_soc_jack_add_gpios(&headset_jack,
     57					     ARRAY_SIZE(headset_jack_gpios),
     58					     headset_jack_gpios);
     59	}
     60
     61	return ret;
     62}
     63
     64static const struct snd_soc_dapm_widget imx_es8328_dapm_widgets[] = {
     65	SND_SOC_DAPM_MIC("Mic Jack", NULL),
     66	SND_SOC_DAPM_HP("Headphone", NULL),
     67	SND_SOC_DAPM_SPK("Speaker", NULL),
     68	SND_SOC_DAPM_REGULATOR_SUPPLY("audio-amp", 1, 0),
     69};
     70
     71static int imx_es8328_probe(struct platform_device *pdev)
     72{
     73	struct device_node *np = pdev->dev.of_node;
     74	struct device_node *ssi_np = NULL, *codec_np = NULL;
     75	struct platform_device *ssi_pdev;
     76	struct imx_es8328_data *data;
     77	struct snd_soc_dai_link_component *comp;
     78	u32 int_port, ext_port;
     79	int ret;
     80	struct device *dev = &pdev->dev;
     81
     82	ret = of_property_read_u32(np, "mux-int-port", &int_port);
     83	if (ret) {
     84		dev_err(dev, "mux-int-port missing or invalid\n");
     85		goto fail;
     86	}
     87	if (int_port > MUX_PORT_MAX || int_port == 0) {
     88		dev_err(dev, "mux-int-port: hardware only has %d mux ports\n",
     89			MUX_PORT_MAX);
     90		ret = -EINVAL;
     91		goto fail;
     92	}
     93
     94	ret = of_property_read_u32(np, "mux-ext-port", &ext_port);
     95	if (ret) {
     96		dev_err(dev, "mux-ext-port missing or invalid\n");
     97		goto fail;
     98	}
     99	if (ext_port > MUX_PORT_MAX || ext_port == 0) {
    100		dev_err(dev, "mux-ext-port: hardware only has %d mux ports\n",
    101			MUX_PORT_MAX);
    102		ret = -EINVAL;
    103		goto fail;
    104	}
    105
    106	/*
    107	 * The port numbering in the hardware manual starts at 1, while
    108	 * the audmux API expects it starts at 0.
    109	 */
    110	int_port--;
    111	ext_port--;
    112	ret = imx_audmux_v2_configure_port(int_port,
    113			IMX_AUDMUX_V2_PTCR_SYN |
    114			IMX_AUDMUX_V2_PTCR_TFSEL(ext_port) |
    115			IMX_AUDMUX_V2_PTCR_TCSEL(ext_port) |
    116			IMX_AUDMUX_V2_PTCR_TFSDIR |
    117			IMX_AUDMUX_V2_PTCR_TCLKDIR,
    118			IMX_AUDMUX_V2_PDCR_RXDSEL(ext_port));
    119	if (ret) {
    120		dev_err(dev, "audmux internal port setup failed\n");
    121		return ret;
    122	}
    123	ret = imx_audmux_v2_configure_port(ext_port,
    124			IMX_AUDMUX_V2_PTCR_SYN,
    125			IMX_AUDMUX_V2_PDCR_RXDSEL(int_port));
    126	if (ret) {
    127		dev_err(dev, "audmux external port setup failed\n");
    128		return ret;
    129	}
    130
    131	ssi_np = of_parse_phandle(pdev->dev.of_node, "ssi-controller", 0);
    132	codec_np = of_parse_phandle(pdev->dev.of_node, "audio-codec", 0);
    133	if (!ssi_np || !codec_np) {
    134		dev_err(dev, "phandle missing or invalid\n");
    135		ret = -EINVAL;
    136		goto fail;
    137	}
    138
    139	ssi_pdev = of_find_device_by_node(ssi_np);
    140	if (!ssi_pdev) {
    141		dev_err(dev, "failed to find SSI platform device\n");
    142		ret = -EINVAL;
    143		goto fail;
    144	}
    145
    146	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
    147	if (!data) {
    148		ret = -ENOMEM;
    149		goto put_device;
    150	}
    151
    152	comp = devm_kzalloc(dev, 3 * sizeof(*comp), GFP_KERNEL);
    153	if (!comp) {
    154		ret = -ENOMEM;
    155		goto put_device;
    156	}
    157
    158	data->dev = dev;
    159
    160	data->jack_gpio = of_get_named_gpio(pdev->dev.of_node, "jack-gpio", 0);
    161
    162	data->dai.cpus		= &comp[0];
    163	data->dai.codecs	= &comp[1];
    164	data->dai.platforms	= &comp[2];
    165
    166	data->dai.num_cpus	= 1;
    167	data->dai.num_codecs	= 1;
    168	data->dai.num_platforms	= 1;
    169
    170	data->dai.name = "hifi";
    171	data->dai.stream_name = "hifi";
    172	data->dai.codecs->dai_name = "es8328-hifi-analog";
    173	data->dai.codecs->of_node = codec_np;
    174	data->dai.cpus->of_node = ssi_np;
    175	data->dai.platforms->of_node = ssi_np;
    176	data->dai.init = &imx_es8328_dai_init;
    177	data->dai.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
    178			    SND_SOC_DAIFMT_CBP_CFP;
    179
    180	data->card.dev = dev;
    181	data->card.dapm_widgets = imx_es8328_dapm_widgets;
    182	data->card.num_dapm_widgets = ARRAY_SIZE(imx_es8328_dapm_widgets);
    183	ret = snd_soc_of_parse_card_name(&data->card, "model");
    184	if (ret) {
    185		dev_err(dev, "Unable to parse card name\n");
    186		goto put_device;
    187	}
    188	ret = snd_soc_of_parse_audio_routing(&data->card, "audio-routing");
    189	if (ret) {
    190		dev_err(dev, "Unable to parse routing: %d\n", ret);
    191		goto put_device;
    192	}
    193	data->card.num_links = 1;
    194	data->card.owner = THIS_MODULE;
    195	data->card.dai_link = &data->dai;
    196
    197	ret = devm_snd_soc_register_card(&pdev->dev, &data->card);
    198	if (ret) {
    199		dev_err(dev, "Unable to register: %d\n", ret);
    200		goto put_device;
    201	}
    202
    203	platform_set_drvdata(pdev, data);
    204put_device:
    205	put_device(&ssi_pdev->dev);
    206fail:
    207	of_node_put(ssi_np);
    208	of_node_put(codec_np);
    209
    210	return ret;
    211}
    212
    213static const struct of_device_id imx_es8328_dt_ids[] = {
    214	{ .compatible = "fsl,imx-audio-es8328", },
    215	{ /* sentinel */ }
    216};
    217MODULE_DEVICE_TABLE(of, imx_es8328_dt_ids);
    218
    219static struct platform_driver imx_es8328_driver = {
    220	.driver = {
    221		.name = "imx-es8328",
    222		.of_match_table = imx_es8328_dt_ids,
    223	},
    224	.probe = imx_es8328_probe,
    225};
    226module_platform_driver(imx_es8328_driver);
    227
    228MODULE_AUTHOR("Sean Cross <xobs@kosagi.com>");
    229MODULE_DESCRIPTION("Kosagi i.MX6 ES8328 ASoC machine driver");
    230MODULE_LICENSE("GPL v2");
    231MODULE_ALIAS("platform:imx-audio-es8328");