0001
0002
0003
0004
0005
0006 #include <linux/bitfield.h>
0007 #include <linux/clk.h>
0008 #include <linux/module.h>
0009 #include <sound/pcm_params.h>
0010 #include <linux/regmap.h>
0011 #include <linux/regulator/consumer.h>
0012 #include <linux/reset.h>
0013 #include <sound/soc.h>
0014 #include <sound/soc-dai.h>
0015
0016 #include <dt-bindings/sound/meson-g12a-toacodec.h>
0017 #include "axg-tdm.h"
0018 #include "meson-codec-glue.h"
0019
0020 #define G12A_TOACODEC_DRV_NAME "g12a-toacodec"
0021
0022 #define TOACODEC_CTRL0 0x0
0023 #define CTRL0_ENABLE_SHIFT 31
0024 #define CTRL0_DAT_SEL_SM1_MSB 19
0025 #define CTRL0_DAT_SEL_SM1_LSB 18
0026 #define CTRL0_DAT_SEL_MSB 15
0027 #define CTRL0_DAT_SEL_LSB 14
0028 #define CTRL0_LANE_SEL_SM1 16
0029 #define CTRL0_LANE_SEL 12
0030 #define CTRL0_LRCLK_SEL_SM1_MSB 14
0031 #define CTRL0_LRCLK_SEL_SM1_LSB 12
0032 #define CTRL0_LRCLK_SEL_MSB 9
0033 #define CTRL0_LRCLK_SEL_LSB 8
0034 #define CTRL0_LRCLK_INV_SM1 BIT(10)
0035 #define CTRL0_BLK_CAP_INV_SM1 BIT(9)
0036 #define CTRL0_BLK_CAP_INV BIT(7)
0037 #define CTRL0_BCLK_O_INV_SM1 BIT(8)
0038 #define CTRL0_BCLK_O_INV BIT(6)
0039 #define CTRL0_BCLK_SEL_SM1_MSB 6
0040 #define CTRL0_BCLK_SEL_MSB 5
0041 #define CTRL0_BCLK_SEL_LSB 4
0042 #define CTRL0_MCLK_SEL GENMASK(2, 0)
0043
0044 #define TOACODEC_OUT_CHMAX 2
0045
0046 struct g12a_toacodec {
0047 struct regmap_field *field_dat_sel;
0048 struct regmap_field *field_lrclk_sel;
0049 struct regmap_field *field_bclk_sel;
0050 };
0051
0052 struct g12a_toacodec_match_data {
0053 const struct snd_soc_component_driver *component_drv;
0054 struct reg_field field_dat_sel;
0055 struct reg_field field_lrclk_sel;
0056 struct reg_field field_bclk_sel;
0057 };
0058
0059 static const char * const g12a_toacodec_mux_texts[] = {
0060 "I2S A", "I2S B", "I2S C",
0061 };
0062
0063 static int g12a_toacodec_mux_put_enum(struct snd_kcontrol *kcontrol,
0064 struct snd_ctl_elem_value *ucontrol)
0065 {
0066 struct snd_soc_component *component =
0067 snd_soc_dapm_kcontrol_component(kcontrol);
0068 struct g12a_toacodec *priv = snd_soc_component_get_drvdata(component);
0069 struct snd_soc_dapm_context *dapm =
0070 snd_soc_dapm_kcontrol_dapm(kcontrol);
0071 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
0072 unsigned int mux, reg;
0073
0074 mux = snd_soc_enum_item_to_val(e, ucontrol->value.enumerated.item[0]);
0075 regmap_field_read(priv->field_dat_sel, ®);
0076
0077 if (mux == reg)
0078 return 0;
0079
0080
0081 snd_soc_dapm_mux_update_power(dapm, kcontrol, 0, NULL, NULL);
0082
0083 regmap_field_write(priv->field_dat_sel, mux);
0084 regmap_field_write(priv->field_lrclk_sel, mux);
0085 regmap_field_write(priv->field_bclk_sel, mux);
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098 snd_soc_component_update_bits(component, e->reg,
0099 CTRL0_MCLK_SEL,
0100 FIELD_PREP(CTRL0_MCLK_SEL, mux));
0101
0102 snd_soc_dapm_mux_update_power(dapm, kcontrol, mux, e, NULL);
0103
0104 return 0;
0105 }
0106
0107 static SOC_ENUM_SINGLE_DECL(g12a_toacodec_mux_enum, TOACODEC_CTRL0,
0108 CTRL0_DAT_SEL_LSB,
0109 g12a_toacodec_mux_texts);
0110
0111 static SOC_ENUM_SINGLE_DECL(sm1_toacodec_mux_enum, TOACODEC_CTRL0,
0112 CTRL0_DAT_SEL_SM1_LSB,
0113 g12a_toacodec_mux_texts);
0114
0115 static const struct snd_kcontrol_new g12a_toacodec_mux =
0116 SOC_DAPM_ENUM_EXT("Source", g12a_toacodec_mux_enum,
0117 snd_soc_dapm_get_enum_double,
0118 g12a_toacodec_mux_put_enum);
0119
0120 static const struct snd_kcontrol_new sm1_toacodec_mux =
0121 SOC_DAPM_ENUM_EXT("Source", sm1_toacodec_mux_enum,
0122 snd_soc_dapm_get_enum_double,
0123 g12a_toacodec_mux_put_enum);
0124
0125 static const struct snd_kcontrol_new g12a_toacodec_out_enable =
0126 SOC_DAPM_SINGLE_AUTODISABLE("Switch", TOACODEC_CTRL0,
0127 CTRL0_ENABLE_SHIFT, 1, 0);
0128
0129 static const struct snd_soc_dapm_widget g12a_toacodec_widgets[] = {
0130 SND_SOC_DAPM_MUX("SRC", SND_SOC_NOPM, 0, 0,
0131 &g12a_toacodec_mux),
0132 SND_SOC_DAPM_SWITCH("OUT EN", SND_SOC_NOPM, 0, 0,
0133 &g12a_toacodec_out_enable),
0134 };
0135
0136 static const struct snd_soc_dapm_widget sm1_toacodec_widgets[] = {
0137 SND_SOC_DAPM_MUX("SRC", SND_SOC_NOPM, 0, 0,
0138 &sm1_toacodec_mux),
0139 SND_SOC_DAPM_SWITCH("OUT EN", SND_SOC_NOPM, 0, 0,
0140 &g12a_toacodec_out_enable),
0141 };
0142
0143 static int g12a_toacodec_input_hw_params(struct snd_pcm_substream *substream,
0144 struct snd_pcm_hw_params *params,
0145 struct snd_soc_dai *dai)
0146 {
0147 struct meson_codec_glue_input *data;
0148 int ret;
0149
0150 ret = meson_codec_glue_input_hw_params(substream, params, dai);
0151 if (ret)
0152 return ret;
0153
0154
0155 data = meson_codec_glue_input_get_data(dai);
0156 data->params.channels_min = min_t(unsigned int, TOACODEC_OUT_CHMAX,
0157 data->params.channels_min);
0158 data->params.channels_max = min_t(unsigned int, TOACODEC_OUT_CHMAX,
0159 data->params.channels_max);
0160
0161 return 0;
0162 }
0163
0164 static const struct snd_soc_dai_ops g12a_toacodec_input_ops = {
0165 .hw_params = g12a_toacodec_input_hw_params,
0166 .set_fmt = meson_codec_glue_input_set_fmt,
0167 };
0168
0169 static const struct snd_soc_dai_ops g12a_toacodec_output_ops = {
0170 .startup = meson_codec_glue_output_startup,
0171 };
0172
0173 #define TOACODEC_STREAM(xname, xsuffix, xchmax) \
0174 { \
0175 .stream_name = xname " " xsuffix, \
0176 .channels_min = 1, \
0177 .channels_max = (xchmax), \
0178 .rate_min = 5512, \
0179 .rate_max = 192000, \
0180 .formats = AXG_TDM_FORMATS, \
0181 }
0182
0183 #define TOACODEC_INPUT(xname, xid) { \
0184 .name = xname, \
0185 .id = (xid), \
0186 .playback = TOACODEC_STREAM(xname, "Playback", 8), \
0187 .ops = &g12a_toacodec_input_ops, \
0188 .probe = meson_codec_glue_input_dai_probe, \
0189 .remove = meson_codec_glue_input_dai_remove, \
0190 }
0191
0192 #define TOACODEC_OUTPUT(xname, xid) { \
0193 .name = xname, \
0194 .id = (xid), \
0195 .capture = TOACODEC_STREAM(xname, "Capture", TOACODEC_OUT_CHMAX), \
0196 .ops = &g12a_toacodec_output_ops, \
0197 }
0198
0199 static struct snd_soc_dai_driver g12a_toacodec_dai_drv[] = {
0200 TOACODEC_INPUT("IN A", TOACODEC_IN_A),
0201 TOACODEC_INPUT("IN B", TOACODEC_IN_B),
0202 TOACODEC_INPUT("IN C", TOACODEC_IN_C),
0203 TOACODEC_OUTPUT("OUT", TOACODEC_OUT),
0204 };
0205
0206 static int g12a_toacodec_component_probe(struct snd_soc_component *c)
0207 {
0208
0209 return snd_soc_component_write(c, TOACODEC_CTRL0,
0210 CTRL0_BLK_CAP_INV);
0211 }
0212
0213 static int sm1_toacodec_component_probe(struct snd_soc_component *c)
0214 {
0215
0216 return snd_soc_component_write(c, TOACODEC_CTRL0,
0217 CTRL0_BLK_CAP_INV_SM1);
0218 }
0219
0220 static const struct snd_soc_dapm_route g12a_toacodec_routes[] = {
0221 { "SRC", "I2S A", "IN A Playback" },
0222 { "SRC", "I2S B", "IN B Playback" },
0223 { "SRC", "I2S C", "IN C Playback" },
0224 { "OUT EN", "Switch", "SRC" },
0225 { "OUT Capture", NULL, "OUT EN" },
0226 };
0227
0228 static const struct snd_kcontrol_new g12a_toacodec_controls[] = {
0229 SOC_SINGLE("Lane Select", TOACODEC_CTRL0, CTRL0_LANE_SEL, 3, 0),
0230 };
0231
0232 static const struct snd_kcontrol_new sm1_toacodec_controls[] = {
0233 SOC_SINGLE("Lane Select", TOACODEC_CTRL0, CTRL0_LANE_SEL_SM1, 3, 0),
0234 };
0235
0236 static const struct snd_soc_component_driver g12a_toacodec_component_drv = {
0237 .probe = g12a_toacodec_component_probe,
0238 .controls = g12a_toacodec_controls,
0239 .num_controls = ARRAY_SIZE(g12a_toacodec_controls),
0240 .dapm_widgets = g12a_toacodec_widgets,
0241 .num_dapm_widgets = ARRAY_SIZE(g12a_toacodec_widgets),
0242 .dapm_routes = g12a_toacodec_routes,
0243 .num_dapm_routes = ARRAY_SIZE(g12a_toacodec_routes),
0244 .endianness = 1,
0245 };
0246
0247 static const struct snd_soc_component_driver sm1_toacodec_component_drv = {
0248 .probe = sm1_toacodec_component_probe,
0249 .controls = sm1_toacodec_controls,
0250 .num_controls = ARRAY_SIZE(sm1_toacodec_controls),
0251 .dapm_widgets = sm1_toacodec_widgets,
0252 .num_dapm_widgets = ARRAY_SIZE(sm1_toacodec_widgets),
0253 .dapm_routes = g12a_toacodec_routes,
0254 .num_dapm_routes = ARRAY_SIZE(g12a_toacodec_routes),
0255 .endianness = 1,
0256 };
0257
0258 static const struct regmap_config g12a_toacodec_regmap_cfg = {
0259 .reg_bits = 32,
0260 .val_bits = 32,
0261 .reg_stride = 4,
0262 };
0263
0264 static const struct g12a_toacodec_match_data g12a_toacodec_match_data = {
0265 .component_drv = &g12a_toacodec_component_drv,
0266 .field_dat_sel = REG_FIELD(TOACODEC_CTRL0, 14, 15),
0267 .field_lrclk_sel = REG_FIELD(TOACODEC_CTRL0, 8, 9),
0268 .field_bclk_sel = REG_FIELD(TOACODEC_CTRL0, 4, 5),
0269 };
0270
0271 static const struct g12a_toacodec_match_data sm1_toacodec_match_data = {
0272 .component_drv = &sm1_toacodec_component_drv,
0273 .field_dat_sel = REG_FIELD(TOACODEC_CTRL0, 18, 19),
0274 .field_lrclk_sel = REG_FIELD(TOACODEC_CTRL0, 12, 14),
0275 .field_bclk_sel = REG_FIELD(TOACODEC_CTRL0, 4, 6),
0276 };
0277
0278 static const struct of_device_id g12a_toacodec_of_match[] = {
0279 {
0280 .compatible = "amlogic,g12a-toacodec",
0281 .data = &g12a_toacodec_match_data,
0282 },
0283 {
0284 .compatible = "amlogic,sm1-toacodec",
0285 .data = &sm1_toacodec_match_data,
0286 },
0287 {}
0288 };
0289 MODULE_DEVICE_TABLE(of, g12a_toacodec_of_match);
0290
0291 static int g12a_toacodec_probe(struct platform_device *pdev)
0292 {
0293 const struct g12a_toacodec_match_data *data;
0294 struct device *dev = &pdev->dev;
0295 struct g12a_toacodec *priv;
0296 void __iomem *regs;
0297 struct regmap *map;
0298 int ret;
0299
0300 data = device_get_match_data(dev);
0301 if (!data) {
0302 dev_err(dev, "failed to match device\n");
0303 return -ENODEV;
0304 }
0305
0306 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
0307 if (!priv)
0308 return -ENOMEM;
0309
0310 platform_set_drvdata(pdev, priv);
0311
0312 ret = device_reset(dev);
0313 if (ret)
0314 return ret;
0315
0316 regs = devm_platform_ioremap_resource(pdev, 0);
0317 if (IS_ERR(regs))
0318 return PTR_ERR(regs);
0319
0320 map = devm_regmap_init_mmio(dev, regs, &g12a_toacodec_regmap_cfg);
0321 if (IS_ERR(map)) {
0322 dev_err(dev, "failed to init regmap: %ld\n",
0323 PTR_ERR(map));
0324 return PTR_ERR(map);
0325 }
0326
0327 priv->field_dat_sel = devm_regmap_field_alloc(dev, map, data->field_dat_sel);
0328 if (IS_ERR(priv->field_dat_sel))
0329 return PTR_ERR(priv->field_dat_sel);
0330
0331 priv->field_lrclk_sel = devm_regmap_field_alloc(dev, map, data->field_lrclk_sel);
0332 if (IS_ERR(priv->field_lrclk_sel))
0333 return PTR_ERR(priv->field_lrclk_sel);
0334
0335 priv->field_bclk_sel = devm_regmap_field_alloc(dev, map, data->field_bclk_sel);
0336 if (IS_ERR(priv->field_bclk_sel))
0337 return PTR_ERR(priv->field_bclk_sel);
0338
0339 return devm_snd_soc_register_component(dev,
0340 data->component_drv, g12a_toacodec_dai_drv,
0341 ARRAY_SIZE(g12a_toacodec_dai_drv));
0342 }
0343
0344 static struct platform_driver g12a_toacodec_pdrv = {
0345 .driver = {
0346 .name = G12A_TOACODEC_DRV_NAME,
0347 .of_match_table = g12a_toacodec_of_match,
0348 },
0349 .probe = g12a_toacodec_probe,
0350 };
0351 module_platform_driver(g12a_toacodec_pdrv);
0352
0353 MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
0354 MODULE_DESCRIPTION("Amlogic G12a To Internal DAC Codec Driver");
0355 MODULE_LICENSE("GPL v2");