18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0 OR MIT) 28c2ecf20Sopenharmony_ci// 38c2ecf20Sopenharmony_ci// Copyright (c) 2018 BayLibre, SAS. 48c2ecf20Sopenharmony_ci// Author: Jerome Brunet <jbrunet@baylibre.com> 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci/* 78c2ecf20Sopenharmony_ci * This driver implements the frontend playback DAI of AXG and G12A based SoCs 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/clk.h> 118c2ecf20Sopenharmony_ci#include <linux/regmap.h> 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci#include <linux/of_platform.h> 148c2ecf20Sopenharmony_ci#include <sound/soc.h> 158c2ecf20Sopenharmony_ci#include <sound/soc-dai.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include "axg-fifo.h" 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#define CTRL0_FRDDR_PP_MODE BIT(30) 208c2ecf20Sopenharmony_ci#define CTRL0_SEL1_EN_SHIFT 3 218c2ecf20Sopenharmony_ci#define CTRL0_SEL2_SHIFT 4 228c2ecf20Sopenharmony_ci#define CTRL0_SEL2_EN_SHIFT 7 238c2ecf20Sopenharmony_ci#define CTRL0_SEL3_SHIFT 8 248c2ecf20Sopenharmony_ci#define CTRL0_SEL3_EN_SHIFT 11 258c2ecf20Sopenharmony_ci#define CTRL1_FRDDR_FORCE_FINISH BIT(12) 268c2ecf20Sopenharmony_ci#define CTRL2_SEL1_SHIFT 0 278c2ecf20Sopenharmony_ci#define CTRL2_SEL1_EN_SHIFT 4 288c2ecf20Sopenharmony_ci#define CTRL2_SEL2_SHIFT 8 298c2ecf20Sopenharmony_ci#define CTRL2_SEL2_EN_SHIFT 12 308c2ecf20Sopenharmony_ci#define CTRL2_SEL3_SHIFT 16 318c2ecf20Sopenharmony_ci#define CTRL2_SEL3_EN_SHIFT 20 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cistatic int g12a_frddr_dai_prepare(struct snd_pcm_substream *substream, 348c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 358c2ecf20Sopenharmony_ci{ 368c2ecf20Sopenharmony_ci struct axg_fifo *fifo = snd_soc_dai_get_drvdata(dai); 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci /* Reset the read pointer to the FIFO_INIT_ADDR */ 398c2ecf20Sopenharmony_ci regmap_update_bits(fifo->map, FIFO_CTRL1, 408c2ecf20Sopenharmony_ci CTRL1_FRDDR_FORCE_FINISH, 0); 418c2ecf20Sopenharmony_ci regmap_update_bits(fifo->map, FIFO_CTRL1, 428c2ecf20Sopenharmony_ci CTRL1_FRDDR_FORCE_FINISH, CTRL1_FRDDR_FORCE_FINISH); 438c2ecf20Sopenharmony_ci regmap_update_bits(fifo->map, FIFO_CTRL1, 448c2ecf20Sopenharmony_ci CTRL1_FRDDR_FORCE_FINISH, 0); 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci return 0; 478c2ecf20Sopenharmony_ci} 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_cistatic int axg_frddr_dai_startup(struct snd_pcm_substream *substream, 508c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 518c2ecf20Sopenharmony_ci{ 528c2ecf20Sopenharmony_ci struct axg_fifo *fifo = snd_soc_dai_get_drvdata(dai); 538c2ecf20Sopenharmony_ci unsigned int val; 548c2ecf20Sopenharmony_ci int ret; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci /* Enable pclk to access registers and clock the fifo ip */ 578c2ecf20Sopenharmony_ci ret = clk_prepare_enable(fifo->pclk); 588c2ecf20Sopenharmony_ci if (ret) 598c2ecf20Sopenharmony_ci return ret; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci /* Apply single buffer mode to the interface */ 628c2ecf20Sopenharmony_ci regmap_update_bits(fifo->map, FIFO_CTRL0, CTRL0_FRDDR_PP_MODE, 0); 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci /* Use all fifo depth */ 658c2ecf20Sopenharmony_ci val = (fifo->depth / AXG_FIFO_BURST) - 1; 668c2ecf20Sopenharmony_ci regmap_update_bits(fifo->map, FIFO_CTRL1, CTRL1_FRDDR_DEPTH_MASK, 678c2ecf20Sopenharmony_ci CTRL1_FRDDR_DEPTH(val)); 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci return 0; 708c2ecf20Sopenharmony_ci} 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistatic void axg_frddr_dai_shutdown(struct snd_pcm_substream *substream, 738c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 748c2ecf20Sopenharmony_ci{ 758c2ecf20Sopenharmony_ci struct axg_fifo *fifo = snd_soc_dai_get_drvdata(dai); 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci clk_disable_unprepare(fifo->pclk); 788c2ecf20Sopenharmony_ci} 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_cistatic int axg_frddr_pcm_new(struct snd_soc_pcm_runtime *rtd, 818c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 828c2ecf20Sopenharmony_ci{ 838c2ecf20Sopenharmony_ci return axg_fifo_pcm_new(rtd, SNDRV_PCM_STREAM_PLAYBACK); 848c2ecf20Sopenharmony_ci} 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_cistatic const struct snd_soc_dai_ops axg_frddr_ops = { 878c2ecf20Sopenharmony_ci .startup = axg_frddr_dai_startup, 888c2ecf20Sopenharmony_ci .shutdown = axg_frddr_dai_shutdown, 898c2ecf20Sopenharmony_ci}; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_cistatic struct snd_soc_dai_driver axg_frddr_dai_drv = { 928c2ecf20Sopenharmony_ci .name = "FRDDR", 938c2ecf20Sopenharmony_ci .playback = { 948c2ecf20Sopenharmony_ci .stream_name = "Playback", 958c2ecf20Sopenharmony_ci .channels_min = 1, 968c2ecf20Sopenharmony_ci .channels_max = AXG_FIFO_CH_MAX, 978c2ecf20Sopenharmony_ci .rates = AXG_FIFO_RATES, 988c2ecf20Sopenharmony_ci .formats = AXG_FIFO_FORMATS, 998c2ecf20Sopenharmony_ci }, 1008c2ecf20Sopenharmony_ci .ops = &axg_frddr_ops, 1018c2ecf20Sopenharmony_ci .pcm_new = axg_frddr_pcm_new, 1028c2ecf20Sopenharmony_ci}; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_cistatic const char * const axg_frddr_sel_texts[] = { 1058c2ecf20Sopenharmony_ci "OUT 0", "OUT 1", "OUT 2", "OUT 3", "OUT 4", "OUT 5", "OUT 6", "OUT 7", 1068c2ecf20Sopenharmony_ci}; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(axg_frddr_sel_enum, FIFO_CTRL0, CTRL0_SEL_SHIFT, 1098c2ecf20Sopenharmony_ci axg_frddr_sel_texts); 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new axg_frddr_out_demux = 1128c2ecf20Sopenharmony_ci SOC_DAPM_ENUM("Output Sink", axg_frddr_sel_enum); 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_widget axg_frddr_dapm_widgets[] = { 1158c2ecf20Sopenharmony_ci SND_SOC_DAPM_DEMUX("SINK SEL", SND_SOC_NOPM, 0, 0, 1168c2ecf20Sopenharmony_ci &axg_frddr_out_demux), 1178c2ecf20Sopenharmony_ci SND_SOC_DAPM_AIF_OUT("OUT 0", NULL, 0, SND_SOC_NOPM, 0, 0), 1188c2ecf20Sopenharmony_ci SND_SOC_DAPM_AIF_OUT("OUT 1", NULL, 0, SND_SOC_NOPM, 0, 0), 1198c2ecf20Sopenharmony_ci SND_SOC_DAPM_AIF_OUT("OUT 2", NULL, 0, SND_SOC_NOPM, 0, 0), 1208c2ecf20Sopenharmony_ci SND_SOC_DAPM_AIF_OUT("OUT 3", NULL, 0, SND_SOC_NOPM, 0, 0), 1218c2ecf20Sopenharmony_ci SND_SOC_DAPM_AIF_OUT("OUT 4", NULL, 0, SND_SOC_NOPM, 0, 0), 1228c2ecf20Sopenharmony_ci SND_SOC_DAPM_AIF_OUT("OUT 5", NULL, 0, SND_SOC_NOPM, 0, 0), 1238c2ecf20Sopenharmony_ci SND_SOC_DAPM_AIF_OUT("OUT 6", NULL, 0, SND_SOC_NOPM, 0, 0), 1248c2ecf20Sopenharmony_ci SND_SOC_DAPM_AIF_OUT("OUT 7", NULL, 0, SND_SOC_NOPM, 0, 0), 1258c2ecf20Sopenharmony_ci}; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_route axg_frddr_dapm_routes[] = { 1288c2ecf20Sopenharmony_ci { "SINK SEL", NULL, "Playback" }, 1298c2ecf20Sopenharmony_ci { "OUT 0", "OUT 0", "SINK SEL" }, 1308c2ecf20Sopenharmony_ci { "OUT 1", "OUT 1", "SINK SEL" }, 1318c2ecf20Sopenharmony_ci { "OUT 2", "OUT 2", "SINK SEL" }, 1328c2ecf20Sopenharmony_ci { "OUT 3", "OUT 3", "SINK SEL" }, 1338c2ecf20Sopenharmony_ci { "OUT 4", "OUT 4", "SINK SEL" }, 1348c2ecf20Sopenharmony_ci { "OUT 5", "OUT 5", "SINK SEL" }, 1358c2ecf20Sopenharmony_ci { "OUT 6", "OUT 6", "SINK SEL" }, 1368c2ecf20Sopenharmony_ci { "OUT 7", "OUT 7", "SINK SEL" }, 1378c2ecf20Sopenharmony_ci}; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_cistatic const struct snd_soc_component_driver axg_frddr_component_drv = { 1408c2ecf20Sopenharmony_ci .dapm_widgets = axg_frddr_dapm_widgets, 1418c2ecf20Sopenharmony_ci .num_dapm_widgets = ARRAY_SIZE(axg_frddr_dapm_widgets), 1428c2ecf20Sopenharmony_ci .dapm_routes = axg_frddr_dapm_routes, 1438c2ecf20Sopenharmony_ci .num_dapm_routes = ARRAY_SIZE(axg_frddr_dapm_routes), 1448c2ecf20Sopenharmony_ci .open = axg_fifo_pcm_open, 1458c2ecf20Sopenharmony_ci .close = axg_fifo_pcm_close, 1468c2ecf20Sopenharmony_ci .hw_params = axg_fifo_pcm_hw_params, 1478c2ecf20Sopenharmony_ci .hw_free = axg_fifo_pcm_hw_free, 1488c2ecf20Sopenharmony_ci .pointer = axg_fifo_pcm_pointer, 1498c2ecf20Sopenharmony_ci .trigger = axg_fifo_pcm_trigger, 1508c2ecf20Sopenharmony_ci}; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_cistatic const struct axg_fifo_match_data axg_frddr_match_data = { 1538c2ecf20Sopenharmony_ci .field_threshold = REG_FIELD(FIFO_CTRL1, 16, 23), 1548c2ecf20Sopenharmony_ci .component_drv = &axg_frddr_component_drv, 1558c2ecf20Sopenharmony_ci .dai_drv = &axg_frddr_dai_drv 1568c2ecf20Sopenharmony_ci}; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_cistatic const struct snd_soc_dai_ops g12a_frddr_ops = { 1598c2ecf20Sopenharmony_ci .prepare = g12a_frddr_dai_prepare, 1608c2ecf20Sopenharmony_ci .startup = axg_frddr_dai_startup, 1618c2ecf20Sopenharmony_ci .shutdown = axg_frddr_dai_shutdown, 1628c2ecf20Sopenharmony_ci}; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_cistatic struct snd_soc_dai_driver g12a_frddr_dai_drv = { 1658c2ecf20Sopenharmony_ci .name = "FRDDR", 1668c2ecf20Sopenharmony_ci .playback = { 1678c2ecf20Sopenharmony_ci .stream_name = "Playback", 1688c2ecf20Sopenharmony_ci .channels_min = 1, 1698c2ecf20Sopenharmony_ci .channels_max = AXG_FIFO_CH_MAX, 1708c2ecf20Sopenharmony_ci .rates = AXG_FIFO_RATES, 1718c2ecf20Sopenharmony_ci .formats = AXG_FIFO_FORMATS, 1728c2ecf20Sopenharmony_ci }, 1738c2ecf20Sopenharmony_ci .ops = &g12a_frddr_ops, 1748c2ecf20Sopenharmony_ci .pcm_new = axg_frddr_pcm_new, 1758c2ecf20Sopenharmony_ci}; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(g12a_frddr_sel1_enum, FIFO_CTRL0, CTRL0_SEL_SHIFT, 1788c2ecf20Sopenharmony_ci axg_frddr_sel_texts); 1798c2ecf20Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(g12a_frddr_sel2_enum, FIFO_CTRL0, CTRL0_SEL2_SHIFT, 1808c2ecf20Sopenharmony_ci axg_frddr_sel_texts); 1818c2ecf20Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(g12a_frddr_sel3_enum, FIFO_CTRL0, CTRL0_SEL3_SHIFT, 1828c2ecf20Sopenharmony_ci axg_frddr_sel_texts); 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new g12a_frddr_out1_demux = 1858c2ecf20Sopenharmony_ci SOC_DAPM_ENUM("Output Src 1", g12a_frddr_sel1_enum); 1868c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new g12a_frddr_out2_demux = 1878c2ecf20Sopenharmony_ci SOC_DAPM_ENUM("Output Src 2", g12a_frddr_sel2_enum); 1888c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new g12a_frddr_out3_demux = 1898c2ecf20Sopenharmony_ci SOC_DAPM_ENUM("Output Src 3", g12a_frddr_sel3_enum); 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new g12a_frddr_out1_enable = 1928c2ecf20Sopenharmony_ci SOC_DAPM_SINGLE_AUTODISABLE("Switch", FIFO_CTRL0, 1938c2ecf20Sopenharmony_ci CTRL0_SEL1_EN_SHIFT, 1, 0); 1948c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new g12a_frddr_out2_enable = 1958c2ecf20Sopenharmony_ci SOC_DAPM_SINGLE_AUTODISABLE("Switch", FIFO_CTRL0, 1968c2ecf20Sopenharmony_ci CTRL0_SEL2_EN_SHIFT, 1, 0); 1978c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new g12a_frddr_out3_enable = 1988c2ecf20Sopenharmony_ci SOC_DAPM_SINGLE_AUTODISABLE("Switch", FIFO_CTRL0, 1998c2ecf20Sopenharmony_ci CTRL0_SEL3_EN_SHIFT, 1, 0); 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_widget g12a_frddr_dapm_widgets[] = { 2028c2ecf20Sopenharmony_ci SND_SOC_DAPM_AIF_OUT("SRC 1", NULL, 0, SND_SOC_NOPM, 0, 0), 2038c2ecf20Sopenharmony_ci SND_SOC_DAPM_AIF_OUT("SRC 2", NULL, 0, SND_SOC_NOPM, 0, 0), 2048c2ecf20Sopenharmony_ci SND_SOC_DAPM_AIF_OUT("SRC 3", NULL, 0, SND_SOC_NOPM, 0, 0), 2058c2ecf20Sopenharmony_ci SND_SOC_DAPM_SWITCH("SRC 1 EN", SND_SOC_NOPM, 0, 0, 2068c2ecf20Sopenharmony_ci &g12a_frddr_out1_enable), 2078c2ecf20Sopenharmony_ci SND_SOC_DAPM_SWITCH("SRC 2 EN", SND_SOC_NOPM, 0, 0, 2088c2ecf20Sopenharmony_ci &g12a_frddr_out2_enable), 2098c2ecf20Sopenharmony_ci SND_SOC_DAPM_SWITCH("SRC 3 EN", SND_SOC_NOPM, 0, 0, 2108c2ecf20Sopenharmony_ci &g12a_frddr_out3_enable), 2118c2ecf20Sopenharmony_ci SND_SOC_DAPM_DEMUX("SINK 1 SEL", SND_SOC_NOPM, 0, 0, 2128c2ecf20Sopenharmony_ci &g12a_frddr_out1_demux), 2138c2ecf20Sopenharmony_ci SND_SOC_DAPM_DEMUX("SINK 2 SEL", SND_SOC_NOPM, 0, 0, 2148c2ecf20Sopenharmony_ci &g12a_frddr_out2_demux), 2158c2ecf20Sopenharmony_ci SND_SOC_DAPM_DEMUX("SINK 3 SEL", SND_SOC_NOPM, 0, 0, 2168c2ecf20Sopenharmony_ci &g12a_frddr_out3_demux), 2178c2ecf20Sopenharmony_ci SND_SOC_DAPM_AIF_OUT("OUT 0", NULL, 0, SND_SOC_NOPM, 0, 0), 2188c2ecf20Sopenharmony_ci SND_SOC_DAPM_AIF_OUT("OUT 1", NULL, 0, SND_SOC_NOPM, 0, 0), 2198c2ecf20Sopenharmony_ci SND_SOC_DAPM_AIF_OUT("OUT 2", NULL, 0, SND_SOC_NOPM, 0, 0), 2208c2ecf20Sopenharmony_ci SND_SOC_DAPM_AIF_OUT("OUT 3", NULL, 0, SND_SOC_NOPM, 0, 0), 2218c2ecf20Sopenharmony_ci SND_SOC_DAPM_AIF_OUT("OUT 4", NULL, 0, SND_SOC_NOPM, 0, 0), 2228c2ecf20Sopenharmony_ci SND_SOC_DAPM_AIF_OUT("OUT 5", NULL, 0, SND_SOC_NOPM, 0, 0), 2238c2ecf20Sopenharmony_ci SND_SOC_DAPM_AIF_OUT("OUT 6", NULL, 0, SND_SOC_NOPM, 0, 0), 2248c2ecf20Sopenharmony_ci SND_SOC_DAPM_AIF_OUT("OUT 7", NULL, 0, SND_SOC_NOPM, 0, 0), 2258c2ecf20Sopenharmony_ci}; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_route g12a_frddr_dapm_routes[] = { 2288c2ecf20Sopenharmony_ci { "SRC 1", NULL, "Playback" }, 2298c2ecf20Sopenharmony_ci { "SRC 2", NULL, "Playback" }, 2308c2ecf20Sopenharmony_ci { "SRC 3", NULL, "Playback" }, 2318c2ecf20Sopenharmony_ci { "SRC 1 EN", "Switch", "SRC 1" }, 2328c2ecf20Sopenharmony_ci { "SRC 2 EN", "Switch", "SRC 2" }, 2338c2ecf20Sopenharmony_ci { "SRC 3 EN", "Switch", "SRC 3" }, 2348c2ecf20Sopenharmony_ci { "SINK 1 SEL", NULL, "SRC 1 EN" }, 2358c2ecf20Sopenharmony_ci { "SINK 2 SEL", NULL, "SRC 2 EN" }, 2368c2ecf20Sopenharmony_ci { "SINK 3 SEL", NULL, "SRC 3 EN" }, 2378c2ecf20Sopenharmony_ci { "OUT 0", "OUT 0", "SINK 1 SEL" }, 2388c2ecf20Sopenharmony_ci { "OUT 1", "OUT 1", "SINK 1 SEL" }, 2398c2ecf20Sopenharmony_ci { "OUT 2", "OUT 2", "SINK 1 SEL" }, 2408c2ecf20Sopenharmony_ci { "OUT 3", "OUT 3", "SINK 1 SEL" }, 2418c2ecf20Sopenharmony_ci { "OUT 4", "OUT 4", "SINK 1 SEL" }, 2428c2ecf20Sopenharmony_ci { "OUT 5", "OUT 5", "SINK 1 SEL" }, 2438c2ecf20Sopenharmony_ci { "OUT 6", "OUT 6", "SINK 1 SEL" }, 2448c2ecf20Sopenharmony_ci { "OUT 7", "OUT 7", "SINK 1 SEL" }, 2458c2ecf20Sopenharmony_ci { "OUT 0", "OUT 0", "SINK 2 SEL" }, 2468c2ecf20Sopenharmony_ci { "OUT 1", "OUT 1", "SINK 2 SEL" }, 2478c2ecf20Sopenharmony_ci { "OUT 2", "OUT 2", "SINK 2 SEL" }, 2488c2ecf20Sopenharmony_ci { "OUT 3", "OUT 3", "SINK 2 SEL" }, 2498c2ecf20Sopenharmony_ci { "OUT 4", "OUT 4", "SINK 2 SEL" }, 2508c2ecf20Sopenharmony_ci { "OUT 5", "OUT 5", "SINK 2 SEL" }, 2518c2ecf20Sopenharmony_ci { "OUT 6", "OUT 6", "SINK 2 SEL" }, 2528c2ecf20Sopenharmony_ci { "OUT 7", "OUT 7", "SINK 2 SEL" }, 2538c2ecf20Sopenharmony_ci { "OUT 0", "OUT 0", "SINK 3 SEL" }, 2548c2ecf20Sopenharmony_ci { "OUT 1", "OUT 1", "SINK 3 SEL" }, 2558c2ecf20Sopenharmony_ci { "OUT 2", "OUT 2", "SINK 3 SEL" }, 2568c2ecf20Sopenharmony_ci { "OUT 3", "OUT 3", "SINK 3 SEL" }, 2578c2ecf20Sopenharmony_ci { "OUT 4", "OUT 4", "SINK 3 SEL" }, 2588c2ecf20Sopenharmony_ci { "OUT 5", "OUT 5", "SINK 3 SEL" }, 2598c2ecf20Sopenharmony_ci { "OUT 6", "OUT 6", "SINK 3 SEL" }, 2608c2ecf20Sopenharmony_ci { "OUT 7", "OUT 7", "SINK 3 SEL" }, 2618c2ecf20Sopenharmony_ci}; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_cistatic const struct snd_soc_component_driver g12a_frddr_component_drv = { 2648c2ecf20Sopenharmony_ci .dapm_widgets = g12a_frddr_dapm_widgets, 2658c2ecf20Sopenharmony_ci .num_dapm_widgets = ARRAY_SIZE(g12a_frddr_dapm_widgets), 2668c2ecf20Sopenharmony_ci .dapm_routes = g12a_frddr_dapm_routes, 2678c2ecf20Sopenharmony_ci .num_dapm_routes = ARRAY_SIZE(g12a_frddr_dapm_routes), 2688c2ecf20Sopenharmony_ci .open = axg_fifo_pcm_open, 2698c2ecf20Sopenharmony_ci .close = axg_fifo_pcm_close, 2708c2ecf20Sopenharmony_ci .hw_params = g12a_fifo_pcm_hw_params, 2718c2ecf20Sopenharmony_ci .hw_free = axg_fifo_pcm_hw_free, 2728c2ecf20Sopenharmony_ci .pointer = axg_fifo_pcm_pointer, 2738c2ecf20Sopenharmony_ci .trigger = axg_fifo_pcm_trigger, 2748c2ecf20Sopenharmony_ci}; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_cistatic const struct axg_fifo_match_data g12a_frddr_match_data = { 2778c2ecf20Sopenharmony_ci .field_threshold = REG_FIELD(FIFO_CTRL1, 16, 23), 2788c2ecf20Sopenharmony_ci .component_drv = &g12a_frddr_component_drv, 2798c2ecf20Sopenharmony_ci .dai_drv = &g12a_frddr_dai_drv 2808c2ecf20Sopenharmony_ci}; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci/* On SM1, the output selection in on CTRL2 */ 2838c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new sm1_frddr_out1_enable = 2848c2ecf20Sopenharmony_ci SOC_DAPM_SINGLE_AUTODISABLE("Switch", FIFO_CTRL2, 2858c2ecf20Sopenharmony_ci CTRL2_SEL1_EN_SHIFT, 1, 0); 2868c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new sm1_frddr_out2_enable = 2878c2ecf20Sopenharmony_ci SOC_DAPM_SINGLE_AUTODISABLE("Switch", FIFO_CTRL2, 2888c2ecf20Sopenharmony_ci CTRL2_SEL2_EN_SHIFT, 1, 0); 2898c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new sm1_frddr_out3_enable = 2908c2ecf20Sopenharmony_ci SOC_DAPM_SINGLE_AUTODISABLE("Switch", FIFO_CTRL2, 2918c2ecf20Sopenharmony_ci CTRL2_SEL3_EN_SHIFT, 1, 0); 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(sm1_frddr_sel1_enum, FIFO_CTRL2, CTRL2_SEL1_SHIFT, 2948c2ecf20Sopenharmony_ci axg_frddr_sel_texts); 2958c2ecf20Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(sm1_frddr_sel2_enum, FIFO_CTRL2, CTRL2_SEL2_SHIFT, 2968c2ecf20Sopenharmony_ci axg_frddr_sel_texts); 2978c2ecf20Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(sm1_frddr_sel3_enum, FIFO_CTRL2, CTRL2_SEL3_SHIFT, 2988c2ecf20Sopenharmony_ci axg_frddr_sel_texts); 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new sm1_frddr_out1_demux = 3018c2ecf20Sopenharmony_ci SOC_DAPM_ENUM("Output Src 1", sm1_frddr_sel1_enum); 3028c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new sm1_frddr_out2_demux = 3038c2ecf20Sopenharmony_ci SOC_DAPM_ENUM("Output Src 2", sm1_frddr_sel2_enum); 3048c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new sm1_frddr_out3_demux = 3058c2ecf20Sopenharmony_ci SOC_DAPM_ENUM("Output Src 3", sm1_frddr_sel3_enum); 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_widget sm1_frddr_dapm_widgets[] = { 3088c2ecf20Sopenharmony_ci SND_SOC_DAPM_AIF_OUT("SRC 1", NULL, 0, SND_SOC_NOPM, 0, 0), 3098c2ecf20Sopenharmony_ci SND_SOC_DAPM_AIF_OUT("SRC 2", NULL, 0, SND_SOC_NOPM, 0, 0), 3108c2ecf20Sopenharmony_ci SND_SOC_DAPM_AIF_OUT("SRC 3", NULL, 0, SND_SOC_NOPM, 0, 0), 3118c2ecf20Sopenharmony_ci SND_SOC_DAPM_SWITCH("SRC 1 EN", SND_SOC_NOPM, 0, 0, 3128c2ecf20Sopenharmony_ci &sm1_frddr_out1_enable), 3138c2ecf20Sopenharmony_ci SND_SOC_DAPM_SWITCH("SRC 2 EN", SND_SOC_NOPM, 0, 0, 3148c2ecf20Sopenharmony_ci &sm1_frddr_out2_enable), 3158c2ecf20Sopenharmony_ci SND_SOC_DAPM_SWITCH("SRC 3 EN", SND_SOC_NOPM, 0, 0, 3168c2ecf20Sopenharmony_ci &sm1_frddr_out3_enable), 3178c2ecf20Sopenharmony_ci SND_SOC_DAPM_DEMUX("SINK 1 SEL", SND_SOC_NOPM, 0, 0, 3188c2ecf20Sopenharmony_ci &sm1_frddr_out1_demux), 3198c2ecf20Sopenharmony_ci SND_SOC_DAPM_DEMUX("SINK 2 SEL", SND_SOC_NOPM, 0, 0, 3208c2ecf20Sopenharmony_ci &sm1_frddr_out2_demux), 3218c2ecf20Sopenharmony_ci SND_SOC_DAPM_DEMUX("SINK 3 SEL", SND_SOC_NOPM, 0, 0, 3228c2ecf20Sopenharmony_ci &sm1_frddr_out3_demux), 3238c2ecf20Sopenharmony_ci SND_SOC_DAPM_AIF_OUT("OUT 0", NULL, 0, SND_SOC_NOPM, 0, 0), 3248c2ecf20Sopenharmony_ci SND_SOC_DAPM_AIF_OUT("OUT 1", NULL, 0, SND_SOC_NOPM, 0, 0), 3258c2ecf20Sopenharmony_ci SND_SOC_DAPM_AIF_OUT("OUT 2", NULL, 0, SND_SOC_NOPM, 0, 0), 3268c2ecf20Sopenharmony_ci SND_SOC_DAPM_AIF_OUT("OUT 3", NULL, 0, SND_SOC_NOPM, 0, 0), 3278c2ecf20Sopenharmony_ci SND_SOC_DAPM_AIF_OUT("OUT 4", NULL, 0, SND_SOC_NOPM, 0, 0), 3288c2ecf20Sopenharmony_ci SND_SOC_DAPM_AIF_OUT("OUT 5", NULL, 0, SND_SOC_NOPM, 0, 0), 3298c2ecf20Sopenharmony_ci SND_SOC_DAPM_AIF_OUT("OUT 6", NULL, 0, SND_SOC_NOPM, 0, 0), 3308c2ecf20Sopenharmony_ci SND_SOC_DAPM_AIF_OUT("OUT 7", NULL, 0, SND_SOC_NOPM, 0, 0), 3318c2ecf20Sopenharmony_ci}; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_cistatic const struct snd_soc_component_driver sm1_frddr_component_drv = { 3348c2ecf20Sopenharmony_ci .dapm_widgets = sm1_frddr_dapm_widgets, 3358c2ecf20Sopenharmony_ci .num_dapm_widgets = ARRAY_SIZE(sm1_frddr_dapm_widgets), 3368c2ecf20Sopenharmony_ci .dapm_routes = g12a_frddr_dapm_routes, 3378c2ecf20Sopenharmony_ci .num_dapm_routes = ARRAY_SIZE(g12a_frddr_dapm_routes), 3388c2ecf20Sopenharmony_ci .open = axg_fifo_pcm_open, 3398c2ecf20Sopenharmony_ci .close = axg_fifo_pcm_close, 3408c2ecf20Sopenharmony_ci .hw_params = g12a_fifo_pcm_hw_params, 3418c2ecf20Sopenharmony_ci .hw_free = axg_fifo_pcm_hw_free, 3428c2ecf20Sopenharmony_ci .pointer = axg_fifo_pcm_pointer, 3438c2ecf20Sopenharmony_ci .trigger = axg_fifo_pcm_trigger, 3448c2ecf20Sopenharmony_ci}; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_cistatic const struct axg_fifo_match_data sm1_frddr_match_data = { 3478c2ecf20Sopenharmony_ci .field_threshold = REG_FIELD(FIFO_CTRL1, 16, 23), 3488c2ecf20Sopenharmony_ci .component_drv = &sm1_frddr_component_drv, 3498c2ecf20Sopenharmony_ci .dai_drv = &g12a_frddr_dai_drv 3508c2ecf20Sopenharmony_ci}; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_cistatic const struct of_device_id axg_frddr_of_match[] = { 3538c2ecf20Sopenharmony_ci { 3548c2ecf20Sopenharmony_ci .compatible = "amlogic,axg-frddr", 3558c2ecf20Sopenharmony_ci .data = &axg_frddr_match_data, 3568c2ecf20Sopenharmony_ci }, { 3578c2ecf20Sopenharmony_ci .compatible = "amlogic,g12a-frddr", 3588c2ecf20Sopenharmony_ci .data = &g12a_frddr_match_data, 3598c2ecf20Sopenharmony_ci }, { 3608c2ecf20Sopenharmony_ci .compatible = "amlogic,sm1-frddr", 3618c2ecf20Sopenharmony_ci .data = &sm1_frddr_match_data, 3628c2ecf20Sopenharmony_ci }, {} 3638c2ecf20Sopenharmony_ci}; 3648c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, axg_frddr_of_match); 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_cistatic struct platform_driver axg_frddr_pdrv = { 3678c2ecf20Sopenharmony_ci .probe = axg_fifo_probe, 3688c2ecf20Sopenharmony_ci .driver = { 3698c2ecf20Sopenharmony_ci .name = "axg-frddr", 3708c2ecf20Sopenharmony_ci .of_match_table = axg_frddr_of_match, 3718c2ecf20Sopenharmony_ci }, 3728c2ecf20Sopenharmony_ci}; 3738c2ecf20Sopenharmony_cimodule_platform_driver(axg_frddr_pdrv); 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Amlogic AXG/G12A playback fifo driver"); 3768c2ecf20Sopenharmony_ciMODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>"); 3778c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 378