0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/clk.h>
0011 #include <linux/regmap.h>
0012 #include <linux/module.h>
0013 #include <linux/of_platform.h>
0014 #include <sound/pcm_params.h>
0015 #include <sound/soc.h>
0016 #include <sound/soc-dai.h>
0017
0018 #include "axg-fifo.h"
0019
0020 #define CTRL0_FRDDR_PP_MODE BIT(30)
0021 #define CTRL0_SEL1_EN_SHIFT 3
0022 #define CTRL0_SEL2_SHIFT 4
0023 #define CTRL0_SEL2_EN_SHIFT 7
0024 #define CTRL0_SEL3_SHIFT 8
0025 #define CTRL0_SEL3_EN_SHIFT 11
0026 #define CTRL1_FRDDR_FORCE_FINISH BIT(12)
0027 #define CTRL2_SEL1_SHIFT 0
0028 #define CTRL2_SEL1_EN_SHIFT 4
0029 #define CTRL2_SEL2_SHIFT 8
0030 #define CTRL2_SEL2_EN_SHIFT 12
0031 #define CTRL2_SEL3_SHIFT 16
0032 #define CTRL2_SEL3_EN_SHIFT 20
0033
0034 static int g12a_frddr_dai_prepare(struct snd_pcm_substream *substream,
0035 struct snd_soc_dai *dai)
0036 {
0037 struct axg_fifo *fifo = snd_soc_dai_get_drvdata(dai);
0038
0039
0040 regmap_update_bits(fifo->map, FIFO_CTRL1,
0041 CTRL1_FRDDR_FORCE_FINISH, 0);
0042 regmap_update_bits(fifo->map, FIFO_CTRL1,
0043 CTRL1_FRDDR_FORCE_FINISH, CTRL1_FRDDR_FORCE_FINISH);
0044 regmap_update_bits(fifo->map, FIFO_CTRL1,
0045 CTRL1_FRDDR_FORCE_FINISH, 0);
0046
0047 return 0;
0048 }
0049
0050 static int axg_frddr_dai_hw_params(struct snd_pcm_substream *substream,
0051 struct snd_pcm_hw_params *params,
0052 struct snd_soc_dai *dai)
0053 {
0054 struct axg_fifo *fifo = snd_soc_dai_get_drvdata(dai);
0055 unsigned int period, depth, val;
0056
0057 period = params_period_bytes(params);
0058
0059
0060 depth = min(period, fifo->depth);
0061 val = (depth / AXG_FIFO_BURST) - 1;
0062 regmap_update_bits(fifo->map, FIFO_CTRL1, CTRL1_FRDDR_DEPTH_MASK,
0063 CTRL1_FRDDR_DEPTH(val));
0064
0065 return 0;
0066 }
0067
0068 static int axg_frddr_dai_startup(struct snd_pcm_substream *substream,
0069 struct snd_soc_dai *dai)
0070 {
0071 struct axg_fifo *fifo = snd_soc_dai_get_drvdata(dai);
0072 int ret;
0073
0074
0075 ret = clk_prepare_enable(fifo->pclk);
0076 if (ret)
0077 return ret;
0078
0079
0080 regmap_update_bits(fifo->map, FIFO_CTRL0, CTRL0_FRDDR_PP_MODE, 0);
0081
0082 return 0;
0083 }
0084
0085 static void axg_frddr_dai_shutdown(struct snd_pcm_substream *substream,
0086 struct snd_soc_dai *dai)
0087 {
0088 struct axg_fifo *fifo = snd_soc_dai_get_drvdata(dai);
0089
0090 clk_disable_unprepare(fifo->pclk);
0091 }
0092
0093 static int axg_frddr_pcm_new(struct snd_soc_pcm_runtime *rtd,
0094 struct snd_soc_dai *dai)
0095 {
0096 return axg_fifo_pcm_new(rtd, SNDRV_PCM_STREAM_PLAYBACK);
0097 }
0098
0099 static const struct snd_soc_dai_ops axg_frddr_ops = {
0100 .hw_params = axg_frddr_dai_hw_params,
0101 .startup = axg_frddr_dai_startup,
0102 .shutdown = axg_frddr_dai_shutdown,
0103 };
0104
0105 static struct snd_soc_dai_driver axg_frddr_dai_drv = {
0106 .name = "FRDDR",
0107 .playback = {
0108 .stream_name = "Playback",
0109 .channels_min = 1,
0110 .channels_max = AXG_FIFO_CH_MAX,
0111 .rates = AXG_FIFO_RATES,
0112 .formats = AXG_FIFO_FORMATS,
0113 },
0114 .ops = &axg_frddr_ops,
0115 .pcm_new = axg_frddr_pcm_new,
0116 };
0117
0118 static const char * const axg_frddr_sel_texts[] = {
0119 "OUT 0", "OUT 1", "OUT 2", "OUT 3", "OUT 4", "OUT 5", "OUT 6", "OUT 7",
0120 };
0121
0122 static SOC_ENUM_SINGLE_DECL(axg_frddr_sel_enum, FIFO_CTRL0, CTRL0_SEL_SHIFT,
0123 axg_frddr_sel_texts);
0124
0125 static const struct snd_kcontrol_new axg_frddr_out_demux =
0126 SOC_DAPM_ENUM("Output Sink", axg_frddr_sel_enum);
0127
0128 static const struct snd_soc_dapm_widget axg_frddr_dapm_widgets[] = {
0129 SND_SOC_DAPM_DEMUX("SINK SEL", SND_SOC_NOPM, 0, 0,
0130 &axg_frddr_out_demux),
0131 SND_SOC_DAPM_AIF_OUT("OUT 0", NULL, 0, SND_SOC_NOPM, 0, 0),
0132 SND_SOC_DAPM_AIF_OUT("OUT 1", NULL, 0, SND_SOC_NOPM, 0, 0),
0133 SND_SOC_DAPM_AIF_OUT("OUT 2", NULL, 0, SND_SOC_NOPM, 0, 0),
0134 SND_SOC_DAPM_AIF_OUT("OUT 3", NULL, 0, SND_SOC_NOPM, 0, 0),
0135 SND_SOC_DAPM_AIF_OUT("OUT 4", NULL, 0, SND_SOC_NOPM, 0, 0),
0136 SND_SOC_DAPM_AIF_OUT("OUT 5", NULL, 0, SND_SOC_NOPM, 0, 0),
0137 SND_SOC_DAPM_AIF_OUT("OUT 6", NULL, 0, SND_SOC_NOPM, 0, 0),
0138 SND_SOC_DAPM_AIF_OUT("OUT 7", NULL, 0, SND_SOC_NOPM, 0, 0),
0139 };
0140
0141 static const struct snd_soc_dapm_route axg_frddr_dapm_routes[] = {
0142 { "SINK SEL", NULL, "Playback" },
0143 { "OUT 0", "OUT 0", "SINK SEL" },
0144 { "OUT 1", "OUT 1", "SINK SEL" },
0145 { "OUT 2", "OUT 2", "SINK SEL" },
0146 { "OUT 3", "OUT 3", "SINK SEL" },
0147 { "OUT 4", "OUT 4", "SINK SEL" },
0148 { "OUT 5", "OUT 5", "SINK SEL" },
0149 { "OUT 6", "OUT 6", "SINK SEL" },
0150 { "OUT 7", "OUT 7", "SINK SEL" },
0151 };
0152
0153 static const struct snd_soc_component_driver axg_frddr_component_drv = {
0154 .dapm_widgets = axg_frddr_dapm_widgets,
0155 .num_dapm_widgets = ARRAY_SIZE(axg_frddr_dapm_widgets),
0156 .dapm_routes = axg_frddr_dapm_routes,
0157 .num_dapm_routes = ARRAY_SIZE(axg_frddr_dapm_routes),
0158 .open = axg_fifo_pcm_open,
0159 .close = axg_fifo_pcm_close,
0160 .hw_params = axg_fifo_pcm_hw_params,
0161 .hw_free = axg_fifo_pcm_hw_free,
0162 .pointer = axg_fifo_pcm_pointer,
0163 .trigger = axg_fifo_pcm_trigger,
0164 .legacy_dai_naming = 1,
0165 };
0166
0167 static const struct axg_fifo_match_data axg_frddr_match_data = {
0168 .field_threshold = REG_FIELD(FIFO_CTRL1, 16, 23),
0169 .component_drv = &axg_frddr_component_drv,
0170 .dai_drv = &axg_frddr_dai_drv
0171 };
0172
0173 static const struct snd_soc_dai_ops g12a_frddr_ops = {
0174 .prepare = g12a_frddr_dai_prepare,
0175 .hw_params = axg_frddr_dai_hw_params,
0176 .startup = axg_frddr_dai_startup,
0177 .shutdown = axg_frddr_dai_shutdown,
0178 };
0179
0180 static struct snd_soc_dai_driver g12a_frddr_dai_drv = {
0181 .name = "FRDDR",
0182 .playback = {
0183 .stream_name = "Playback",
0184 .channels_min = 1,
0185 .channels_max = AXG_FIFO_CH_MAX,
0186 .rates = AXG_FIFO_RATES,
0187 .formats = AXG_FIFO_FORMATS,
0188 },
0189 .ops = &g12a_frddr_ops,
0190 .pcm_new = axg_frddr_pcm_new,
0191 };
0192
0193 static SOC_ENUM_SINGLE_DECL(g12a_frddr_sel1_enum, FIFO_CTRL0, CTRL0_SEL_SHIFT,
0194 axg_frddr_sel_texts);
0195 static SOC_ENUM_SINGLE_DECL(g12a_frddr_sel2_enum, FIFO_CTRL0, CTRL0_SEL2_SHIFT,
0196 axg_frddr_sel_texts);
0197 static SOC_ENUM_SINGLE_DECL(g12a_frddr_sel3_enum, FIFO_CTRL0, CTRL0_SEL3_SHIFT,
0198 axg_frddr_sel_texts);
0199
0200 static const struct snd_kcontrol_new g12a_frddr_out1_demux =
0201 SOC_DAPM_ENUM("Output Src 1", g12a_frddr_sel1_enum);
0202 static const struct snd_kcontrol_new g12a_frddr_out2_demux =
0203 SOC_DAPM_ENUM("Output Src 2", g12a_frddr_sel2_enum);
0204 static const struct snd_kcontrol_new g12a_frddr_out3_demux =
0205 SOC_DAPM_ENUM("Output Src 3", g12a_frddr_sel3_enum);
0206
0207 static const struct snd_kcontrol_new g12a_frddr_out1_enable =
0208 SOC_DAPM_SINGLE_AUTODISABLE("Switch", FIFO_CTRL0,
0209 CTRL0_SEL1_EN_SHIFT, 1, 0);
0210 static const struct snd_kcontrol_new g12a_frddr_out2_enable =
0211 SOC_DAPM_SINGLE_AUTODISABLE("Switch", FIFO_CTRL0,
0212 CTRL0_SEL2_EN_SHIFT, 1, 0);
0213 static const struct snd_kcontrol_new g12a_frddr_out3_enable =
0214 SOC_DAPM_SINGLE_AUTODISABLE("Switch", FIFO_CTRL0,
0215 CTRL0_SEL3_EN_SHIFT, 1, 0);
0216
0217 static const struct snd_soc_dapm_widget g12a_frddr_dapm_widgets[] = {
0218 SND_SOC_DAPM_AIF_OUT("SRC 1", NULL, 0, SND_SOC_NOPM, 0, 0),
0219 SND_SOC_DAPM_AIF_OUT("SRC 2", NULL, 0, SND_SOC_NOPM, 0, 0),
0220 SND_SOC_DAPM_AIF_OUT("SRC 3", NULL, 0, SND_SOC_NOPM, 0, 0),
0221 SND_SOC_DAPM_SWITCH("SRC 1 EN", SND_SOC_NOPM, 0, 0,
0222 &g12a_frddr_out1_enable),
0223 SND_SOC_DAPM_SWITCH("SRC 2 EN", SND_SOC_NOPM, 0, 0,
0224 &g12a_frddr_out2_enable),
0225 SND_SOC_DAPM_SWITCH("SRC 3 EN", SND_SOC_NOPM, 0, 0,
0226 &g12a_frddr_out3_enable),
0227 SND_SOC_DAPM_DEMUX("SINK 1 SEL", SND_SOC_NOPM, 0, 0,
0228 &g12a_frddr_out1_demux),
0229 SND_SOC_DAPM_DEMUX("SINK 2 SEL", SND_SOC_NOPM, 0, 0,
0230 &g12a_frddr_out2_demux),
0231 SND_SOC_DAPM_DEMUX("SINK 3 SEL", SND_SOC_NOPM, 0, 0,
0232 &g12a_frddr_out3_demux),
0233 SND_SOC_DAPM_AIF_OUT("OUT 0", NULL, 0, SND_SOC_NOPM, 0, 0),
0234 SND_SOC_DAPM_AIF_OUT("OUT 1", NULL, 0, SND_SOC_NOPM, 0, 0),
0235 SND_SOC_DAPM_AIF_OUT("OUT 2", NULL, 0, SND_SOC_NOPM, 0, 0),
0236 SND_SOC_DAPM_AIF_OUT("OUT 3", NULL, 0, SND_SOC_NOPM, 0, 0),
0237 SND_SOC_DAPM_AIF_OUT("OUT 4", NULL, 0, SND_SOC_NOPM, 0, 0),
0238 SND_SOC_DAPM_AIF_OUT("OUT 5", NULL, 0, SND_SOC_NOPM, 0, 0),
0239 SND_SOC_DAPM_AIF_OUT("OUT 6", NULL, 0, SND_SOC_NOPM, 0, 0),
0240 SND_SOC_DAPM_AIF_OUT("OUT 7", NULL, 0, SND_SOC_NOPM, 0, 0),
0241 };
0242
0243 static const struct snd_soc_dapm_route g12a_frddr_dapm_routes[] = {
0244 { "SRC 1", NULL, "Playback" },
0245 { "SRC 2", NULL, "Playback" },
0246 { "SRC 3", NULL, "Playback" },
0247 { "SRC 1 EN", "Switch", "SRC 1" },
0248 { "SRC 2 EN", "Switch", "SRC 2" },
0249 { "SRC 3 EN", "Switch", "SRC 3" },
0250 { "SINK 1 SEL", NULL, "SRC 1 EN" },
0251 { "SINK 2 SEL", NULL, "SRC 2 EN" },
0252 { "SINK 3 SEL", NULL, "SRC 3 EN" },
0253 { "OUT 0", "OUT 0", "SINK 1 SEL" },
0254 { "OUT 1", "OUT 1", "SINK 1 SEL" },
0255 { "OUT 2", "OUT 2", "SINK 1 SEL" },
0256 { "OUT 3", "OUT 3", "SINK 1 SEL" },
0257 { "OUT 4", "OUT 4", "SINK 1 SEL" },
0258 { "OUT 5", "OUT 5", "SINK 1 SEL" },
0259 { "OUT 6", "OUT 6", "SINK 1 SEL" },
0260 { "OUT 7", "OUT 7", "SINK 1 SEL" },
0261 { "OUT 0", "OUT 0", "SINK 2 SEL" },
0262 { "OUT 1", "OUT 1", "SINK 2 SEL" },
0263 { "OUT 2", "OUT 2", "SINK 2 SEL" },
0264 { "OUT 3", "OUT 3", "SINK 2 SEL" },
0265 { "OUT 4", "OUT 4", "SINK 2 SEL" },
0266 { "OUT 5", "OUT 5", "SINK 2 SEL" },
0267 { "OUT 6", "OUT 6", "SINK 2 SEL" },
0268 { "OUT 7", "OUT 7", "SINK 2 SEL" },
0269 { "OUT 0", "OUT 0", "SINK 3 SEL" },
0270 { "OUT 1", "OUT 1", "SINK 3 SEL" },
0271 { "OUT 2", "OUT 2", "SINK 3 SEL" },
0272 { "OUT 3", "OUT 3", "SINK 3 SEL" },
0273 { "OUT 4", "OUT 4", "SINK 3 SEL" },
0274 { "OUT 5", "OUT 5", "SINK 3 SEL" },
0275 { "OUT 6", "OUT 6", "SINK 3 SEL" },
0276 { "OUT 7", "OUT 7", "SINK 3 SEL" },
0277 };
0278
0279 static const struct snd_soc_component_driver g12a_frddr_component_drv = {
0280 .dapm_widgets = g12a_frddr_dapm_widgets,
0281 .num_dapm_widgets = ARRAY_SIZE(g12a_frddr_dapm_widgets),
0282 .dapm_routes = g12a_frddr_dapm_routes,
0283 .num_dapm_routes = ARRAY_SIZE(g12a_frddr_dapm_routes),
0284 .open = axg_fifo_pcm_open,
0285 .close = axg_fifo_pcm_close,
0286 .hw_params = g12a_fifo_pcm_hw_params,
0287 .hw_free = axg_fifo_pcm_hw_free,
0288 .pointer = axg_fifo_pcm_pointer,
0289 .trigger = axg_fifo_pcm_trigger,
0290 .legacy_dai_naming = 1,
0291 };
0292
0293 static const struct axg_fifo_match_data g12a_frddr_match_data = {
0294 .field_threshold = REG_FIELD(FIFO_CTRL1, 16, 23),
0295 .component_drv = &g12a_frddr_component_drv,
0296 .dai_drv = &g12a_frddr_dai_drv
0297 };
0298
0299
0300 static const struct snd_kcontrol_new sm1_frddr_out1_enable =
0301 SOC_DAPM_SINGLE_AUTODISABLE("Switch", FIFO_CTRL2,
0302 CTRL2_SEL1_EN_SHIFT, 1, 0);
0303 static const struct snd_kcontrol_new sm1_frddr_out2_enable =
0304 SOC_DAPM_SINGLE_AUTODISABLE("Switch", FIFO_CTRL2,
0305 CTRL2_SEL2_EN_SHIFT, 1, 0);
0306 static const struct snd_kcontrol_new sm1_frddr_out3_enable =
0307 SOC_DAPM_SINGLE_AUTODISABLE("Switch", FIFO_CTRL2,
0308 CTRL2_SEL3_EN_SHIFT, 1, 0);
0309
0310 static SOC_ENUM_SINGLE_DECL(sm1_frddr_sel1_enum, FIFO_CTRL2, CTRL2_SEL1_SHIFT,
0311 axg_frddr_sel_texts);
0312 static SOC_ENUM_SINGLE_DECL(sm1_frddr_sel2_enum, FIFO_CTRL2, CTRL2_SEL2_SHIFT,
0313 axg_frddr_sel_texts);
0314 static SOC_ENUM_SINGLE_DECL(sm1_frddr_sel3_enum, FIFO_CTRL2, CTRL2_SEL3_SHIFT,
0315 axg_frddr_sel_texts);
0316
0317 static const struct snd_kcontrol_new sm1_frddr_out1_demux =
0318 SOC_DAPM_ENUM("Output Src 1", sm1_frddr_sel1_enum);
0319 static const struct snd_kcontrol_new sm1_frddr_out2_demux =
0320 SOC_DAPM_ENUM("Output Src 2", sm1_frddr_sel2_enum);
0321 static const struct snd_kcontrol_new sm1_frddr_out3_demux =
0322 SOC_DAPM_ENUM("Output Src 3", sm1_frddr_sel3_enum);
0323
0324 static const struct snd_soc_dapm_widget sm1_frddr_dapm_widgets[] = {
0325 SND_SOC_DAPM_AIF_OUT("SRC 1", NULL, 0, SND_SOC_NOPM, 0, 0),
0326 SND_SOC_DAPM_AIF_OUT("SRC 2", NULL, 0, SND_SOC_NOPM, 0, 0),
0327 SND_SOC_DAPM_AIF_OUT("SRC 3", NULL, 0, SND_SOC_NOPM, 0, 0),
0328 SND_SOC_DAPM_SWITCH("SRC 1 EN", SND_SOC_NOPM, 0, 0,
0329 &sm1_frddr_out1_enable),
0330 SND_SOC_DAPM_SWITCH("SRC 2 EN", SND_SOC_NOPM, 0, 0,
0331 &sm1_frddr_out2_enable),
0332 SND_SOC_DAPM_SWITCH("SRC 3 EN", SND_SOC_NOPM, 0, 0,
0333 &sm1_frddr_out3_enable),
0334 SND_SOC_DAPM_DEMUX("SINK 1 SEL", SND_SOC_NOPM, 0, 0,
0335 &sm1_frddr_out1_demux),
0336 SND_SOC_DAPM_DEMUX("SINK 2 SEL", SND_SOC_NOPM, 0, 0,
0337 &sm1_frddr_out2_demux),
0338 SND_SOC_DAPM_DEMUX("SINK 3 SEL", SND_SOC_NOPM, 0, 0,
0339 &sm1_frddr_out3_demux),
0340 SND_SOC_DAPM_AIF_OUT("OUT 0", NULL, 0, SND_SOC_NOPM, 0, 0),
0341 SND_SOC_DAPM_AIF_OUT("OUT 1", NULL, 0, SND_SOC_NOPM, 0, 0),
0342 SND_SOC_DAPM_AIF_OUT("OUT 2", NULL, 0, SND_SOC_NOPM, 0, 0),
0343 SND_SOC_DAPM_AIF_OUT("OUT 3", NULL, 0, SND_SOC_NOPM, 0, 0),
0344 SND_SOC_DAPM_AIF_OUT("OUT 4", NULL, 0, SND_SOC_NOPM, 0, 0),
0345 SND_SOC_DAPM_AIF_OUT("OUT 5", NULL, 0, SND_SOC_NOPM, 0, 0),
0346 SND_SOC_DAPM_AIF_OUT("OUT 6", NULL, 0, SND_SOC_NOPM, 0, 0),
0347 SND_SOC_DAPM_AIF_OUT("OUT 7", NULL, 0, SND_SOC_NOPM, 0, 0),
0348 };
0349
0350 static const struct snd_soc_component_driver sm1_frddr_component_drv = {
0351 .dapm_widgets = sm1_frddr_dapm_widgets,
0352 .num_dapm_widgets = ARRAY_SIZE(sm1_frddr_dapm_widgets),
0353 .dapm_routes = g12a_frddr_dapm_routes,
0354 .num_dapm_routes = ARRAY_SIZE(g12a_frddr_dapm_routes),
0355 .open = axg_fifo_pcm_open,
0356 .close = axg_fifo_pcm_close,
0357 .hw_params = g12a_fifo_pcm_hw_params,
0358 .hw_free = axg_fifo_pcm_hw_free,
0359 .pointer = axg_fifo_pcm_pointer,
0360 .trigger = axg_fifo_pcm_trigger,
0361 .legacy_dai_naming = 1,
0362 };
0363
0364 static const struct axg_fifo_match_data sm1_frddr_match_data = {
0365 .field_threshold = REG_FIELD(FIFO_CTRL1, 16, 23),
0366 .component_drv = &sm1_frddr_component_drv,
0367 .dai_drv = &g12a_frddr_dai_drv
0368 };
0369
0370 static const struct of_device_id axg_frddr_of_match[] = {
0371 {
0372 .compatible = "amlogic,axg-frddr",
0373 .data = &axg_frddr_match_data,
0374 }, {
0375 .compatible = "amlogic,g12a-frddr",
0376 .data = &g12a_frddr_match_data,
0377 }, {
0378 .compatible = "amlogic,sm1-frddr",
0379 .data = &sm1_frddr_match_data,
0380 }, {}
0381 };
0382 MODULE_DEVICE_TABLE(of, axg_frddr_of_match);
0383
0384 static struct platform_driver axg_frddr_pdrv = {
0385 .probe = axg_fifo_probe,
0386 .driver = {
0387 .name = "axg-frddr",
0388 .of_match_table = axg_frddr_of_match,
0389 },
0390 };
0391 module_platform_driver(axg_frddr_pdrv);
0392
0393 MODULE_DESCRIPTION("Amlogic AXG/G12A playback fifo driver");
0394 MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
0395 MODULE_LICENSE("GPL v2");