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