18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci//
38c2ecf20Sopenharmony_ci// Copyright (c) 2020 BayLibre, SAS.
48c2ecf20Sopenharmony_ci// Author: Jerome Brunet <jbrunet@baylibre.com>
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include <linux/bitfield.h>
78c2ecf20Sopenharmony_ci#include <linux/clk.h>
88c2ecf20Sopenharmony_ci#include <linux/module.h>
98c2ecf20Sopenharmony_ci#include <linux/of_platform.h>
108c2ecf20Sopenharmony_ci#include <linux/regmap.h>
118c2ecf20Sopenharmony_ci#include <linux/reset.h>
128c2ecf20Sopenharmony_ci#include <sound/soc.h>
138c2ecf20Sopenharmony_ci#include <sound/soc-dai.h>
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#include <dt-bindings/sound/meson-aiu.h>
168c2ecf20Sopenharmony_ci#include "aiu.h"
178c2ecf20Sopenharmony_ci#include "aiu-fifo.h"
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#define AIU_I2S_MISC_958_SRC_SHIFT 3
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_cistatic const char * const aiu_spdif_encode_sel_texts[] = {
228c2ecf20Sopenharmony_ci	"SPDIF", "I2S",
238c2ecf20Sopenharmony_ci};
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(aiu_spdif_encode_sel_enum, AIU_I2S_MISC,
268c2ecf20Sopenharmony_ci			    AIU_I2S_MISC_958_SRC_SHIFT,
278c2ecf20Sopenharmony_ci			    aiu_spdif_encode_sel_texts);
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new aiu_spdif_encode_mux =
308c2ecf20Sopenharmony_ci	SOC_DAPM_ENUM("SPDIF Buffer Src", aiu_spdif_encode_sel_enum);
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_widget aiu_cpu_dapm_widgets[] = {
338c2ecf20Sopenharmony_ci	SND_SOC_DAPM_MUX("SPDIF SRC SEL", SND_SOC_NOPM, 0, 0,
348c2ecf20Sopenharmony_ci			 &aiu_spdif_encode_mux),
358c2ecf20Sopenharmony_ci};
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_route aiu_cpu_dapm_routes[] = {
388c2ecf20Sopenharmony_ci	{ "I2S Encoder Playback", NULL, "I2S FIFO Playback" },
398c2ecf20Sopenharmony_ci	{ "SPDIF SRC SEL", "SPDIF", "SPDIF FIFO Playback" },
408c2ecf20Sopenharmony_ci	{ "SPDIF SRC SEL", "I2S", "I2S FIFO Playback" },
418c2ecf20Sopenharmony_ci	{ "SPDIF Encoder Playback", NULL, "SPDIF SRC SEL" },
428c2ecf20Sopenharmony_ci};
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ciint aiu_of_xlate_dai_name(struct snd_soc_component *component,
458c2ecf20Sopenharmony_ci			  struct of_phandle_args *args,
468c2ecf20Sopenharmony_ci			  const char **dai_name,
478c2ecf20Sopenharmony_ci			  unsigned int component_id)
488c2ecf20Sopenharmony_ci{
498c2ecf20Sopenharmony_ci	struct snd_soc_dai *dai;
508c2ecf20Sopenharmony_ci	int id;
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	if (args->args_count != 2)
538c2ecf20Sopenharmony_ci		return -EINVAL;
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	if (args->args[0] != component_id)
568c2ecf20Sopenharmony_ci		return -EINVAL;
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	id = args->args[1];
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	if (id < 0 || id >= component->num_dai)
618c2ecf20Sopenharmony_ci		return -EINVAL;
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	for_each_component_dais(component, dai) {
648c2ecf20Sopenharmony_ci		if (id == 0)
658c2ecf20Sopenharmony_ci			break;
668c2ecf20Sopenharmony_ci		id--;
678c2ecf20Sopenharmony_ci	}
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	*dai_name = dai->driver->name;
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci	return 0;
728c2ecf20Sopenharmony_ci}
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_cistatic int aiu_cpu_of_xlate_dai_name(struct snd_soc_component *component,
758c2ecf20Sopenharmony_ci				     struct of_phandle_args *args,
768c2ecf20Sopenharmony_ci				     const char **dai_name)
778c2ecf20Sopenharmony_ci{
788c2ecf20Sopenharmony_ci	return aiu_of_xlate_dai_name(component, args, dai_name, AIU_CPU);
798c2ecf20Sopenharmony_ci}
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_cistatic int aiu_cpu_component_probe(struct snd_soc_component *component)
828c2ecf20Sopenharmony_ci{
838c2ecf20Sopenharmony_ci	struct aiu *aiu = snd_soc_component_get_drvdata(component);
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	/* Required for the SPDIF Source control operation */
868c2ecf20Sopenharmony_ci	return clk_prepare_enable(aiu->i2s.clks[PCLK].clk);
878c2ecf20Sopenharmony_ci}
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_cistatic void aiu_cpu_component_remove(struct snd_soc_component *component)
908c2ecf20Sopenharmony_ci{
918c2ecf20Sopenharmony_ci	struct aiu *aiu = snd_soc_component_get_drvdata(component);
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	clk_disable_unprepare(aiu->i2s.clks[PCLK].clk);
948c2ecf20Sopenharmony_ci}
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_cistatic const struct snd_soc_component_driver aiu_cpu_component = {
978c2ecf20Sopenharmony_ci	.name			= "AIU CPU",
988c2ecf20Sopenharmony_ci	.dapm_widgets		= aiu_cpu_dapm_widgets,
998c2ecf20Sopenharmony_ci	.num_dapm_widgets	= ARRAY_SIZE(aiu_cpu_dapm_widgets),
1008c2ecf20Sopenharmony_ci	.dapm_routes		= aiu_cpu_dapm_routes,
1018c2ecf20Sopenharmony_ci	.num_dapm_routes	= ARRAY_SIZE(aiu_cpu_dapm_routes),
1028c2ecf20Sopenharmony_ci	.of_xlate_dai_name	= aiu_cpu_of_xlate_dai_name,
1038c2ecf20Sopenharmony_ci	.pointer		= aiu_fifo_pointer,
1048c2ecf20Sopenharmony_ci	.probe			= aiu_cpu_component_probe,
1058c2ecf20Sopenharmony_ci	.remove			= aiu_cpu_component_remove,
1068c2ecf20Sopenharmony_ci};
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_cistatic struct snd_soc_dai_driver aiu_cpu_dai_drv[] = {
1098c2ecf20Sopenharmony_ci	[CPU_I2S_FIFO] = {
1108c2ecf20Sopenharmony_ci		.name = "I2S FIFO",
1118c2ecf20Sopenharmony_ci		.playback = {
1128c2ecf20Sopenharmony_ci			.stream_name	= "I2S FIFO Playback",
1138c2ecf20Sopenharmony_ci			.channels_min	= 2,
1148c2ecf20Sopenharmony_ci			.channels_max	= 8,
1158c2ecf20Sopenharmony_ci			.rates		= SNDRV_PCM_RATE_CONTINUOUS,
1168c2ecf20Sopenharmony_ci			.rate_min	= 5512,
1178c2ecf20Sopenharmony_ci			.rate_max	= 192000,
1188c2ecf20Sopenharmony_ci			.formats	= AIU_FORMATS,
1198c2ecf20Sopenharmony_ci		},
1208c2ecf20Sopenharmony_ci		.ops		= &aiu_fifo_i2s_dai_ops,
1218c2ecf20Sopenharmony_ci		.pcm_new	= aiu_fifo_pcm_new,
1228c2ecf20Sopenharmony_ci		.probe		= aiu_fifo_i2s_dai_probe,
1238c2ecf20Sopenharmony_ci		.remove		= aiu_fifo_dai_remove,
1248c2ecf20Sopenharmony_ci	},
1258c2ecf20Sopenharmony_ci	[CPU_SPDIF_FIFO] = {
1268c2ecf20Sopenharmony_ci		.name = "SPDIF FIFO",
1278c2ecf20Sopenharmony_ci		.playback = {
1288c2ecf20Sopenharmony_ci			.stream_name	= "SPDIF FIFO Playback",
1298c2ecf20Sopenharmony_ci			.channels_min	= 2,
1308c2ecf20Sopenharmony_ci			.channels_max	= 2,
1318c2ecf20Sopenharmony_ci			.rates		= SNDRV_PCM_RATE_CONTINUOUS,
1328c2ecf20Sopenharmony_ci			.rate_min	= 5512,
1338c2ecf20Sopenharmony_ci			.rate_max	= 192000,
1348c2ecf20Sopenharmony_ci			.formats	= AIU_FORMATS,
1358c2ecf20Sopenharmony_ci		},
1368c2ecf20Sopenharmony_ci		.ops		= &aiu_fifo_spdif_dai_ops,
1378c2ecf20Sopenharmony_ci		.pcm_new	= aiu_fifo_pcm_new,
1388c2ecf20Sopenharmony_ci		.probe		= aiu_fifo_spdif_dai_probe,
1398c2ecf20Sopenharmony_ci		.remove		= aiu_fifo_dai_remove,
1408c2ecf20Sopenharmony_ci	},
1418c2ecf20Sopenharmony_ci	[CPU_I2S_ENCODER] = {
1428c2ecf20Sopenharmony_ci		.name = "I2S Encoder",
1438c2ecf20Sopenharmony_ci		.playback = {
1448c2ecf20Sopenharmony_ci			.stream_name = "I2S Encoder Playback",
1458c2ecf20Sopenharmony_ci			.channels_min = 2,
1468c2ecf20Sopenharmony_ci			.channels_max = 8,
1478c2ecf20Sopenharmony_ci			.rates = SNDRV_PCM_RATE_8000_192000,
1488c2ecf20Sopenharmony_ci			.formats = AIU_FORMATS,
1498c2ecf20Sopenharmony_ci		},
1508c2ecf20Sopenharmony_ci		.ops = &aiu_encoder_i2s_dai_ops,
1518c2ecf20Sopenharmony_ci	},
1528c2ecf20Sopenharmony_ci	[CPU_SPDIF_ENCODER] = {
1538c2ecf20Sopenharmony_ci		.name = "SPDIF Encoder",
1548c2ecf20Sopenharmony_ci		.playback = {
1558c2ecf20Sopenharmony_ci			.stream_name = "SPDIF Encoder Playback",
1568c2ecf20Sopenharmony_ci			.channels_min = 2,
1578c2ecf20Sopenharmony_ci			.channels_max = 2,
1588c2ecf20Sopenharmony_ci			.rates = (SNDRV_PCM_RATE_32000  |
1598c2ecf20Sopenharmony_ci				  SNDRV_PCM_RATE_44100  |
1608c2ecf20Sopenharmony_ci				  SNDRV_PCM_RATE_48000  |
1618c2ecf20Sopenharmony_ci				  SNDRV_PCM_RATE_88200  |
1628c2ecf20Sopenharmony_ci				  SNDRV_PCM_RATE_96000  |
1638c2ecf20Sopenharmony_ci				  SNDRV_PCM_RATE_176400 |
1648c2ecf20Sopenharmony_ci				  SNDRV_PCM_RATE_192000),
1658c2ecf20Sopenharmony_ci			.formats = AIU_FORMATS,
1668c2ecf20Sopenharmony_ci		},
1678c2ecf20Sopenharmony_ci		.ops = &aiu_encoder_spdif_dai_ops,
1688c2ecf20Sopenharmony_ci	}
1698c2ecf20Sopenharmony_ci};
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_cistatic const struct regmap_config aiu_regmap_cfg = {
1728c2ecf20Sopenharmony_ci	.reg_bits	= 32,
1738c2ecf20Sopenharmony_ci	.val_bits	= 32,
1748c2ecf20Sopenharmony_ci	.reg_stride	= 4,
1758c2ecf20Sopenharmony_ci	.max_register	= 0x2ac,
1768c2ecf20Sopenharmony_ci};
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_cistatic int aiu_clk_bulk_get(struct device *dev,
1798c2ecf20Sopenharmony_ci			    const char * const *ids,
1808c2ecf20Sopenharmony_ci			    unsigned int num,
1818c2ecf20Sopenharmony_ci			    struct aiu_interface *interface)
1828c2ecf20Sopenharmony_ci{
1838c2ecf20Sopenharmony_ci	struct clk_bulk_data *clks;
1848c2ecf20Sopenharmony_ci	int i, ret;
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	clks = devm_kcalloc(dev, num, sizeof(*clks), GFP_KERNEL);
1878c2ecf20Sopenharmony_ci	if (!clks)
1888c2ecf20Sopenharmony_ci		return -ENOMEM;
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	for (i = 0; i < num; i++)
1918c2ecf20Sopenharmony_ci		clks[i].id = ids[i];
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	ret = devm_clk_bulk_get(dev, num, clks);
1948c2ecf20Sopenharmony_ci	if (ret < 0)
1958c2ecf20Sopenharmony_ci		return ret;
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	interface->clks = clks;
1988c2ecf20Sopenharmony_ci	interface->clk_num = num;
1998c2ecf20Sopenharmony_ci	return 0;
2008c2ecf20Sopenharmony_ci}
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_cistatic const char * const aiu_i2s_ids[] = {
2038c2ecf20Sopenharmony_ci	[PCLK]	= "i2s_pclk",
2048c2ecf20Sopenharmony_ci	[AOCLK]	= "i2s_aoclk",
2058c2ecf20Sopenharmony_ci	[MCLK]	= "i2s_mclk",
2068c2ecf20Sopenharmony_ci	[MIXER]	= "i2s_mixer",
2078c2ecf20Sopenharmony_ci};
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_cistatic const char * const aiu_spdif_ids[] = {
2108c2ecf20Sopenharmony_ci	[PCLK]	= "spdif_pclk",
2118c2ecf20Sopenharmony_ci	[AOCLK]	= "spdif_aoclk",
2128c2ecf20Sopenharmony_ci	[MCLK]	= "spdif_mclk_sel"
2138c2ecf20Sopenharmony_ci};
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_cistatic int aiu_clk_get(struct device *dev)
2168c2ecf20Sopenharmony_ci{
2178c2ecf20Sopenharmony_ci	struct aiu *aiu = dev_get_drvdata(dev);
2188c2ecf20Sopenharmony_ci	int ret;
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	aiu->pclk = devm_clk_get(dev, "pclk");
2218c2ecf20Sopenharmony_ci	if (IS_ERR(aiu->pclk)) {
2228c2ecf20Sopenharmony_ci		if (PTR_ERR(aiu->pclk) != -EPROBE_DEFER)
2238c2ecf20Sopenharmony_ci			dev_err(dev, "Can't get the aiu pclk\n");
2248c2ecf20Sopenharmony_ci		return PTR_ERR(aiu->pclk);
2258c2ecf20Sopenharmony_ci	}
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci	aiu->spdif_mclk = devm_clk_get(dev, "spdif_mclk");
2288c2ecf20Sopenharmony_ci	if (IS_ERR(aiu->spdif_mclk)) {
2298c2ecf20Sopenharmony_ci		if (PTR_ERR(aiu->spdif_mclk) != -EPROBE_DEFER)
2308c2ecf20Sopenharmony_ci			dev_err(dev, "Can't get the aiu spdif master clock\n");
2318c2ecf20Sopenharmony_ci		return PTR_ERR(aiu->spdif_mclk);
2328c2ecf20Sopenharmony_ci	}
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci	ret = aiu_clk_bulk_get(dev, aiu_i2s_ids, ARRAY_SIZE(aiu_i2s_ids),
2358c2ecf20Sopenharmony_ci			       &aiu->i2s);
2368c2ecf20Sopenharmony_ci	if (ret) {
2378c2ecf20Sopenharmony_ci		if (ret != -EPROBE_DEFER)
2388c2ecf20Sopenharmony_ci			dev_err(dev, "Can't get the i2s clocks\n");
2398c2ecf20Sopenharmony_ci		return ret;
2408c2ecf20Sopenharmony_ci	}
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci	ret = aiu_clk_bulk_get(dev, aiu_spdif_ids, ARRAY_SIZE(aiu_spdif_ids),
2438c2ecf20Sopenharmony_ci			       &aiu->spdif);
2448c2ecf20Sopenharmony_ci	if (ret) {
2458c2ecf20Sopenharmony_ci		if (ret != -EPROBE_DEFER)
2468c2ecf20Sopenharmony_ci			dev_err(dev, "Can't get the spdif clocks\n");
2478c2ecf20Sopenharmony_ci		return ret;
2488c2ecf20Sopenharmony_ci	}
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	ret = clk_prepare_enable(aiu->pclk);
2518c2ecf20Sopenharmony_ci	if (ret) {
2528c2ecf20Sopenharmony_ci		dev_err(dev, "peripheral clock enable failed\n");
2538c2ecf20Sopenharmony_ci		return ret;
2548c2ecf20Sopenharmony_ci	}
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci	ret = devm_add_action_or_reset(dev,
2578c2ecf20Sopenharmony_ci				       (void(*)(void *))clk_disable_unprepare,
2588c2ecf20Sopenharmony_ci				       aiu->pclk);
2598c2ecf20Sopenharmony_ci	if (ret)
2608c2ecf20Sopenharmony_ci		dev_err(dev, "failed to add reset action on pclk");
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci	return ret;
2638c2ecf20Sopenharmony_ci}
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_cistatic int aiu_probe(struct platform_device *pdev)
2668c2ecf20Sopenharmony_ci{
2678c2ecf20Sopenharmony_ci	struct device *dev = &pdev->dev;
2688c2ecf20Sopenharmony_ci	void __iomem *regs;
2698c2ecf20Sopenharmony_ci	struct regmap *map;
2708c2ecf20Sopenharmony_ci	struct aiu *aiu;
2718c2ecf20Sopenharmony_ci	int ret;
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci	aiu = devm_kzalloc(dev, sizeof(*aiu), GFP_KERNEL);
2748c2ecf20Sopenharmony_ci	if (!aiu)
2758c2ecf20Sopenharmony_ci		return -ENOMEM;
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	aiu->platform = device_get_match_data(dev);
2788c2ecf20Sopenharmony_ci	if (!aiu->platform)
2798c2ecf20Sopenharmony_ci		return -ENODEV;
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci	platform_set_drvdata(pdev, aiu);
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	ret = device_reset(dev);
2848c2ecf20Sopenharmony_ci	if (ret) {
2858c2ecf20Sopenharmony_ci		if (ret != -EPROBE_DEFER)
2868c2ecf20Sopenharmony_ci			dev_err(dev, "Failed to reset device\n");
2878c2ecf20Sopenharmony_ci		return ret;
2888c2ecf20Sopenharmony_ci	}
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci	regs = devm_platform_ioremap_resource(pdev, 0);
2918c2ecf20Sopenharmony_ci	if (IS_ERR(regs))
2928c2ecf20Sopenharmony_ci		return PTR_ERR(regs);
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci	map = devm_regmap_init_mmio(dev, regs, &aiu_regmap_cfg);
2958c2ecf20Sopenharmony_ci	if (IS_ERR(map)) {
2968c2ecf20Sopenharmony_ci		dev_err(dev, "failed to init regmap: %ld\n",
2978c2ecf20Sopenharmony_ci			PTR_ERR(map));
2988c2ecf20Sopenharmony_ci		return PTR_ERR(map);
2998c2ecf20Sopenharmony_ci	}
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	aiu->i2s.irq = platform_get_irq_byname(pdev, "i2s");
3028c2ecf20Sopenharmony_ci	if (aiu->i2s.irq < 0)
3038c2ecf20Sopenharmony_ci		return aiu->i2s.irq;
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	aiu->spdif.irq = platform_get_irq_byname(pdev, "spdif");
3068c2ecf20Sopenharmony_ci	if (aiu->spdif.irq < 0)
3078c2ecf20Sopenharmony_ci		return aiu->spdif.irq;
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci	ret = aiu_clk_get(dev);
3108c2ecf20Sopenharmony_ci	if (ret)
3118c2ecf20Sopenharmony_ci		return ret;
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	/* Register the cpu component of the aiu */
3148c2ecf20Sopenharmony_ci	ret = snd_soc_register_component(dev, &aiu_cpu_component,
3158c2ecf20Sopenharmony_ci					 aiu_cpu_dai_drv,
3168c2ecf20Sopenharmony_ci					 ARRAY_SIZE(aiu_cpu_dai_drv));
3178c2ecf20Sopenharmony_ci	if (ret) {
3188c2ecf20Sopenharmony_ci		dev_err(dev, "Failed to register cpu component\n");
3198c2ecf20Sopenharmony_ci		return ret;
3208c2ecf20Sopenharmony_ci	}
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	/* Register the hdmi codec control component */
3238c2ecf20Sopenharmony_ci	ret = aiu_hdmi_ctrl_register_component(dev);
3248c2ecf20Sopenharmony_ci	if (ret) {
3258c2ecf20Sopenharmony_ci		dev_err(dev, "Failed to register hdmi control component\n");
3268c2ecf20Sopenharmony_ci		goto err;
3278c2ecf20Sopenharmony_ci	}
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	/* Register the internal dac control component on gxl */
3308c2ecf20Sopenharmony_ci	if (aiu->platform->has_acodec) {
3318c2ecf20Sopenharmony_ci		ret = aiu_acodec_ctrl_register_component(dev);
3328c2ecf20Sopenharmony_ci		if (ret) {
3338c2ecf20Sopenharmony_ci			dev_err(dev,
3348c2ecf20Sopenharmony_ci			    "Failed to register acodec control component\n");
3358c2ecf20Sopenharmony_ci			goto err;
3368c2ecf20Sopenharmony_ci		}
3378c2ecf20Sopenharmony_ci	}
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	return 0;
3408c2ecf20Sopenharmony_cierr:
3418c2ecf20Sopenharmony_ci	snd_soc_unregister_component(dev);
3428c2ecf20Sopenharmony_ci	return ret;
3438c2ecf20Sopenharmony_ci}
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_cistatic int aiu_remove(struct platform_device *pdev)
3468c2ecf20Sopenharmony_ci{
3478c2ecf20Sopenharmony_ci	snd_soc_unregister_component(&pdev->dev);
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	return 0;
3508c2ecf20Sopenharmony_ci}
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_cistatic const struct aiu_platform_data aiu_gxbb_pdata = {
3538c2ecf20Sopenharmony_ci	.has_acodec = false,
3548c2ecf20Sopenharmony_ci	.has_clk_ctrl_more_i2s_div = true,
3558c2ecf20Sopenharmony_ci};
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_cistatic const struct aiu_platform_data aiu_gxl_pdata = {
3588c2ecf20Sopenharmony_ci	.has_acodec = true,
3598c2ecf20Sopenharmony_ci	.has_clk_ctrl_more_i2s_div = true,
3608c2ecf20Sopenharmony_ci};
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_cistatic const struct aiu_platform_data aiu_meson8_pdata = {
3638c2ecf20Sopenharmony_ci	.has_acodec = false,
3648c2ecf20Sopenharmony_ci	.has_clk_ctrl_more_i2s_div = false,
3658c2ecf20Sopenharmony_ci};
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_cistatic const struct of_device_id aiu_of_match[] = {
3688c2ecf20Sopenharmony_ci	{ .compatible = "amlogic,aiu-gxbb", .data = &aiu_gxbb_pdata },
3698c2ecf20Sopenharmony_ci	{ .compatible = "amlogic,aiu-gxl", .data = &aiu_gxl_pdata },
3708c2ecf20Sopenharmony_ci	{ .compatible = "amlogic,aiu-meson8", .data = &aiu_meson8_pdata },
3718c2ecf20Sopenharmony_ci	{ .compatible = "amlogic,aiu-meson8b", .data = &aiu_meson8_pdata },
3728c2ecf20Sopenharmony_ci	{}
3738c2ecf20Sopenharmony_ci};
3748c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, aiu_of_match);
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_cistatic struct platform_driver aiu_pdrv = {
3778c2ecf20Sopenharmony_ci	.probe = aiu_probe,
3788c2ecf20Sopenharmony_ci	.remove = aiu_remove,
3798c2ecf20Sopenharmony_ci	.driver = {
3808c2ecf20Sopenharmony_ci		.name = "meson-aiu",
3818c2ecf20Sopenharmony_ci		.of_match_table = aiu_of_match,
3828c2ecf20Sopenharmony_ci	},
3838c2ecf20Sopenharmony_ci};
3848c2ecf20Sopenharmony_cimodule_platform_driver(aiu_pdrv);
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Meson AIU Driver");
3878c2ecf20Sopenharmony_ciMODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
3888c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
389