162306a36Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0 OR MIT) 262306a36Sopenharmony_ci// 362306a36Sopenharmony_ci// Copyright (c) 2018 BayLibre, SAS. 462306a36Sopenharmony_ci// Author: Jerome Brunet <jbrunet@baylibre.com> 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <linux/module.h> 762306a36Sopenharmony_ci#include <linux/of_platform.h> 862306a36Sopenharmony_ci#include <linux/regmap.h> 962306a36Sopenharmony_ci#include <sound/soc.h> 1062306a36Sopenharmony_ci#include <sound/soc-dai.h> 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include "axg-tdm-formatter.h" 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#define TDMOUT_CTRL0 0x00 1562306a36Sopenharmony_ci#define TDMOUT_CTRL0_BITNUM_MASK GENMASK(4, 0) 1662306a36Sopenharmony_ci#define TDMOUT_CTRL0_BITNUM(x) ((x) << 0) 1762306a36Sopenharmony_ci#define TDMOUT_CTRL0_SLOTNUM_MASK GENMASK(9, 5) 1862306a36Sopenharmony_ci#define TDMOUT_CTRL0_SLOTNUM(x) ((x) << 5) 1962306a36Sopenharmony_ci#define TDMOUT_CTRL0_INIT_BITNUM_MASK GENMASK(19, 15) 2062306a36Sopenharmony_ci#define TDMOUT_CTRL0_INIT_BITNUM(x) ((x) << 15) 2162306a36Sopenharmony_ci#define TDMOUT_CTRL0_ENABLE BIT(31) 2262306a36Sopenharmony_ci#define TDMOUT_CTRL0_RST_OUT BIT(29) 2362306a36Sopenharmony_ci#define TDMOUT_CTRL0_RST_IN BIT(28) 2462306a36Sopenharmony_ci#define TDMOUT_CTRL1 0x04 2562306a36Sopenharmony_ci#define TDMOUT_CTRL1_TYPE_MASK GENMASK(6, 4) 2662306a36Sopenharmony_ci#define TDMOUT_CTRL1_TYPE(x) ((x) << 4) 2762306a36Sopenharmony_ci#define SM1_TDMOUT_CTRL1_GAIN_EN 7 2862306a36Sopenharmony_ci#define TDMOUT_CTRL1_MSB_POS_MASK GENMASK(12, 8) 2962306a36Sopenharmony_ci#define TDMOUT_CTRL1_MSB_POS(x) ((x) << 8) 3062306a36Sopenharmony_ci#define TDMOUT_CTRL1_SEL_SHIFT 24 3162306a36Sopenharmony_ci#define TDMOUT_CTRL1_GAIN_EN 26 3262306a36Sopenharmony_ci#define TDMOUT_CTRL1_WS_INV BIT(28) 3362306a36Sopenharmony_ci#define TDMOUT_SWAP 0x08 3462306a36Sopenharmony_ci#define TDMOUT_MASK0 0x0c 3562306a36Sopenharmony_ci#define TDMOUT_MASK1 0x10 3662306a36Sopenharmony_ci#define TDMOUT_MASK2 0x14 3762306a36Sopenharmony_ci#define TDMOUT_MASK3 0x18 3862306a36Sopenharmony_ci#define TDMOUT_STAT 0x1c 3962306a36Sopenharmony_ci#define TDMOUT_GAIN0 0x20 4062306a36Sopenharmony_ci#define TDMOUT_GAIN1 0x24 4162306a36Sopenharmony_ci#define TDMOUT_MUTE_VAL 0x28 4262306a36Sopenharmony_ci#define TDMOUT_MUTE0 0x2c 4362306a36Sopenharmony_ci#define TDMOUT_MUTE1 0x30 4462306a36Sopenharmony_ci#define TDMOUT_MUTE2 0x34 4562306a36Sopenharmony_ci#define TDMOUT_MUTE3 0x38 4662306a36Sopenharmony_ci#define TDMOUT_MASK_VAL 0x3c 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_cistatic const struct regmap_config axg_tdmout_regmap_cfg = { 4962306a36Sopenharmony_ci .reg_bits = 32, 5062306a36Sopenharmony_ci .val_bits = 32, 5162306a36Sopenharmony_ci .reg_stride = 4, 5262306a36Sopenharmony_ci .max_register = TDMOUT_MASK_VAL, 5362306a36Sopenharmony_ci}; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_cistatic struct snd_soc_dai * 5662306a36Sopenharmony_ciaxg_tdmout_get_be(struct snd_soc_dapm_widget *w) 5762306a36Sopenharmony_ci{ 5862306a36Sopenharmony_ci struct snd_soc_dapm_path *p; 5962306a36Sopenharmony_ci struct snd_soc_dai *be; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci snd_soc_dapm_widget_for_each_sink_path(w, p) { 6262306a36Sopenharmony_ci if (!p->connect) 6362306a36Sopenharmony_ci continue; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci if (p->sink->id == snd_soc_dapm_dai_in) 6662306a36Sopenharmony_ci return (struct snd_soc_dai *)p->sink->priv; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci be = axg_tdmout_get_be(p->sink); 6962306a36Sopenharmony_ci if (be) 7062306a36Sopenharmony_ci return be; 7162306a36Sopenharmony_ci } 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci return NULL; 7462306a36Sopenharmony_ci} 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_cistatic struct axg_tdm_stream * 7762306a36Sopenharmony_ciaxg_tdmout_get_tdm_stream(struct snd_soc_dapm_widget *w) 7862306a36Sopenharmony_ci{ 7962306a36Sopenharmony_ci struct snd_soc_dai *be = axg_tdmout_get_be(w); 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci if (!be) 8262306a36Sopenharmony_ci return NULL; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci return snd_soc_dai_dma_data_get_playback(be); 8562306a36Sopenharmony_ci} 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_cistatic void axg_tdmout_enable(struct regmap *map) 8862306a36Sopenharmony_ci{ 8962306a36Sopenharmony_ci /* Apply both reset */ 9062306a36Sopenharmony_ci regmap_update_bits(map, TDMOUT_CTRL0, 9162306a36Sopenharmony_ci TDMOUT_CTRL0_RST_OUT | TDMOUT_CTRL0_RST_IN, 0); 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci /* Clear out reset before in reset */ 9462306a36Sopenharmony_ci regmap_update_bits(map, TDMOUT_CTRL0, 9562306a36Sopenharmony_ci TDMOUT_CTRL0_RST_OUT, TDMOUT_CTRL0_RST_OUT); 9662306a36Sopenharmony_ci regmap_update_bits(map, TDMOUT_CTRL0, 9762306a36Sopenharmony_ci TDMOUT_CTRL0_RST_IN, TDMOUT_CTRL0_RST_IN); 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci /* Actually enable tdmout */ 10062306a36Sopenharmony_ci regmap_update_bits(map, TDMOUT_CTRL0, 10162306a36Sopenharmony_ci TDMOUT_CTRL0_ENABLE, TDMOUT_CTRL0_ENABLE); 10262306a36Sopenharmony_ci} 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_cistatic void axg_tdmout_disable(struct regmap *map) 10562306a36Sopenharmony_ci{ 10662306a36Sopenharmony_ci regmap_update_bits(map, TDMOUT_CTRL0, TDMOUT_CTRL0_ENABLE, 0); 10762306a36Sopenharmony_ci} 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_cistatic int axg_tdmout_prepare(struct regmap *map, 11062306a36Sopenharmony_ci const struct axg_tdm_formatter_hw *quirks, 11162306a36Sopenharmony_ci struct axg_tdm_stream *ts) 11262306a36Sopenharmony_ci{ 11362306a36Sopenharmony_ci unsigned int val, skew = quirks->skew_offset; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci /* Set the stream skew */ 11662306a36Sopenharmony_ci switch (ts->iface->fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 11762306a36Sopenharmony_ci case SND_SOC_DAIFMT_I2S: 11862306a36Sopenharmony_ci case SND_SOC_DAIFMT_DSP_A: 11962306a36Sopenharmony_ci break; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci case SND_SOC_DAIFMT_LEFT_J: 12262306a36Sopenharmony_ci case SND_SOC_DAIFMT_DSP_B: 12362306a36Sopenharmony_ci skew += 1; 12462306a36Sopenharmony_ci break; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci default: 12762306a36Sopenharmony_ci pr_err("Unsupported format: %u\n", 12862306a36Sopenharmony_ci ts->iface->fmt & SND_SOC_DAIFMT_FORMAT_MASK); 12962306a36Sopenharmony_ci return -EINVAL; 13062306a36Sopenharmony_ci } 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci val = TDMOUT_CTRL0_INIT_BITNUM(skew); 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci /* Set the slot width */ 13562306a36Sopenharmony_ci val |= TDMOUT_CTRL0_BITNUM(ts->iface->slot_width - 1); 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci /* Set the slot number */ 13862306a36Sopenharmony_ci val |= TDMOUT_CTRL0_SLOTNUM(ts->iface->slots - 1); 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci regmap_update_bits(map, TDMOUT_CTRL0, 14162306a36Sopenharmony_ci TDMOUT_CTRL0_INIT_BITNUM_MASK | 14262306a36Sopenharmony_ci TDMOUT_CTRL0_BITNUM_MASK | 14362306a36Sopenharmony_ci TDMOUT_CTRL0_SLOTNUM_MASK, val); 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci /* Set the sample width */ 14662306a36Sopenharmony_ci val = TDMOUT_CTRL1_MSB_POS(ts->width - 1); 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci /* FIFO data are arranged in chunks of 64bits */ 14962306a36Sopenharmony_ci switch (ts->physical_width) { 15062306a36Sopenharmony_ci case 8: 15162306a36Sopenharmony_ci /* 8 samples of 8 bits */ 15262306a36Sopenharmony_ci val |= TDMOUT_CTRL1_TYPE(0); 15362306a36Sopenharmony_ci break; 15462306a36Sopenharmony_ci case 16: 15562306a36Sopenharmony_ci /* 4 samples of 16 bits - right justified */ 15662306a36Sopenharmony_ci val |= TDMOUT_CTRL1_TYPE(2); 15762306a36Sopenharmony_ci break; 15862306a36Sopenharmony_ci case 32: 15962306a36Sopenharmony_ci /* 2 samples of 32 bits - right justified */ 16062306a36Sopenharmony_ci val |= TDMOUT_CTRL1_TYPE(4); 16162306a36Sopenharmony_ci break; 16262306a36Sopenharmony_ci default: 16362306a36Sopenharmony_ci pr_err("Unsupported physical width: %u\n", 16462306a36Sopenharmony_ci ts->physical_width); 16562306a36Sopenharmony_ci return -EINVAL; 16662306a36Sopenharmony_ci } 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci /* If the sample clock is inverted, invert it back for the formatter */ 16962306a36Sopenharmony_ci if (axg_tdm_lrclk_invert(ts->iface->fmt)) 17062306a36Sopenharmony_ci val |= TDMOUT_CTRL1_WS_INV; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci regmap_update_bits(map, TDMOUT_CTRL1, 17362306a36Sopenharmony_ci (TDMOUT_CTRL1_TYPE_MASK | TDMOUT_CTRL1_MSB_POS_MASK | 17462306a36Sopenharmony_ci TDMOUT_CTRL1_WS_INV), val); 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci /* Set static swap mask configuration */ 17762306a36Sopenharmony_ci regmap_write(map, TDMOUT_SWAP, 0x76543210); 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci return axg_tdm_formatter_set_channel_masks(map, ts, TDMOUT_MASK0); 18062306a36Sopenharmony_ci} 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_cistatic const struct snd_kcontrol_new axg_tdmout_controls[] = { 18362306a36Sopenharmony_ci SOC_DOUBLE("Lane 0 Volume", TDMOUT_GAIN0, 0, 8, 255, 0), 18462306a36Sopenharmony_ci SOC_DOUBLE("Lane 1 Volume", TDMOUT_GAIN0, 16, 24, 255, 0), 18562306a36Sopenharmony_ci SOC_DOUBLE("Lane 2 Volume", TDMOUT_GAIN1, 0, 8, 255, 0), 18662306a36Sopenharmony_ci SOC_DOUBLE("Lane 3 Volume", TDMOUT_GAIN1, 16, 24, 255, 0), 18762306a36Sopenharmony_ci SOC_SINGLE("Gain Enable Switch", TDMOUT_CTRL1, 18862306a36Sopenharmony_ci TDMOUT_CTRL1_GAIN_EN, 1, 0), 18962306a36Sopenharmony_ci}; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_cistatic const char * const axg_tdmout_sel_texts[] = { 19262306a36Sopenharmony_ci "IN 0", "IN 1", "IN 2", 19362306a36Sopenharmony_ci}; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(axg_tdmout_sel_enum, TDMOUT_CTRL1, 19662306a36Sopenharmony_ci TDMOUT_CTRL1_SEL_SHIFT, axg_tdmout_sel_texts); 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_cistatic const struct snd_kcontrol_new axg_tdmout_in_mux = 19962306a36Sopenharmony_ci SOC_DAPM_ENUM("Input Source", axg_tdmout_sel_enum); 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_cistatic const struct snd_soc_dapm_widget axg_tdmout_dapm_widgets[] = { 20262306a36Sopenharmony_ci SND_SOC_DAPM_AIF_IN("IN 0", NULL, 0, SND_SOC_NOPM, 0, 0), 20362306a36Sopenharmony_ci SND_SOC_DAPM_AIF_IN("IN 1", NULL, 0, SND_SOC_NOPM, 0, 0), 20462306a36Sopenharmony_ci SND_SOC_DAPM_AIF_IN("IN 2", NULL, 0, SND_SOC_NOPM, 0, 0), 20562306a36Sopenharmony_ci SND_SOC_DAPM_MUX("SRC SEL", SND_SOC_NOPM, 0, 0, &axg_tdmout_in_mux), 20662306a36Sopenharmony_ci SND_SOC_DAPM_PGA_E("ENC", SND_SOC_NOPM, 0, 0, NULL, 0, 20762306a36Sopenharmony_ci axg_tdm_formatter_event, 20862306a36Sopenharmony_ci (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD)), 20962306a36Sopenharmony_ci SND_SOC_DAPM_AIF_OUT("OUT", NULL, 0, SND_SOC_NOPM, 0, 0), 21062306a36Sopenharmony_ci}; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_cistatic const struct snd_soc_dapm_route axg_tdmout_dapm_routes[] = { 21362306a36Sopenharmony_ci { "SRC SEL", "IN 0", "IN 0" }, 21462306a36Sopenharmony_ci { "SRC SEL", "IN 1", "IN 1" }, 21562306a36Sopenharmony_ci { "SRC SEL", "IN 2", "IN 2" }, 21662306a36Sopenharmony_ci { "ENC", NULL, "SRC SEL" }, 21762306a36Sopenharmony_ci { "OUT", NULL, "ENC" }, 21862306a36Sopenharmony_ci}; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_cistatic const struct snd_soc_component_driver axg_tdmout_component_drv = { 22162306a36Sopenharmony_ci .controls = axg_tdmout_controls, 22262306a36Sopenharmony_ci .num_controls = ARRAY_SIZE(axg_tdmout_controls), 22362306a36Sopenharmony_ci .dapm_widgets = axg_tdmout_dapm_widgets, 22462306a36Sopenharmony_ci .num_dapm_widgets = ARRAY_SIZE(axg_tdmout_dapm_widgets), 22562306a36Sopenharmony_ci .dapm_routes = axg_tdmout_dapm_routes, 22662306a36Sopenharmony_ci .num_dapm_routes = ARRAY_SIZE(axg_tdmout_dapm_routes), 22762306a36Sopenharmony_ci}; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_cistatic const struct axg_tdm_formatter_ops axg_tdmout_ops = { 23062306a36Sopenharmony_ci .get_stream = axg_tdmout_get_tdm_stream, 23162306a36Sopenharmony_ci .prepare = axg_tdmout_prepare, 23262306a36Sopenharmony_ci .enable = axg_tdmout_enable, 23362306a36Sopenharmony_ci .disable = axg_tdmout_disable, 23462306a36Sopenharmony_ci}; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_cistatic const struct axg_tdm_formatter_driver axg_tdmout_drv = { 23762306a36Sopenharmony_ci .component_drv = &axg_tdmout_component_drv, 23862306a36Sopenharmony_ci .regmap_cfg = &axg_tdmout_regmap_cfg, 23962306a36Sopenharmony_ci .ops = &axg_tdmout_ops, 24062306a36Sopenharmony_ci .quirks = &(const struct axg_tdm_formatter_hw) { 24162306a36Sopenharmony_ci .skew_offset = 1, 24262306a36Sopenharmony_ci }, 24362306a36Sopenharmony_ci}; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_cistatic const struct axg_tdm_formatter_driver g12a_tdmout_drv = { 24662306a36Sopenharmony_ci .component_drv = &axg_tdmout_component_drv, 24762306a36Sopenharmony_ci .regmap_cfg = &axg_tdmout_regmap_cfg, 24862306a36Sopenharmony_ci .ops = &axg_tdmout_ops, 24962306a36Sopenharmony_ci .quirks = &(const struct axg_tdm_formatter_hw) { 25062306a36Sopenharmony_ci .skew_offset = 2, 25162306a36Sopenharmony_ci }, 25262306a36Sopenharmony_ci}; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_cistatic const struct snd_kcontrol_new sm1_tdmout_controls[] = { 25562306a36Sopenharmony_ci SOC_DOUBLE("Lane 0 Volume", TDMOUT_GAIN0, 0, 8, 255, 0), 25662306a36Sopenharmony_ci SOC_DOUBLE("Lane 1 Volume", TDMOUT_GAIN0, 16, 24, 255, 0), 25762306a36Sopenharmony_ci SOC_DOUBLE("Lane 2 Volume", TDMOUT_GAIN1, 0, 8, 255, 0), 25862306a36Sopenharmony_ci SOC_DOUBLE("Lane 3 Volume", TDMOUT_GAIN1, 16, 24, 255, 0), 25962306a36Sopenharmony_ci SOC_SINGLE("Gain Enable Switch", TDMOUT_CTRL1, 26062306a36Sopenharmony_ci SM1_TDMOUT_CTRL1_GAIN_EN, 1, 0), 26162306a36Sopenharmony_ci}; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_cistatic const char * const sm1_tdmout_sel_texts[] = { 26462306a36Sopenharmony_ci "IN 0", "IN 1", "IN 2", "IN 3", "IN 4", 26562306a36Sopenharmony_ci}; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(sm1_tdmout_sel_enum, TDMOUT_CTRL1, 26862306a36Sopenharmony_ci TDMOUT_CTRL1_SEL_SHIFT, sm1_tdmout_sel_texts); 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_cistatic const struct snd_kcontrol_new sm1_tdmout_in_mux = 27162306a36Sopenharmony_ci SOC_DAPM_ENUM("Input Source", sm1_tdmout_sel_enum); 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_cistatic const struct snd_soc_dapm_widget sm1_tdmout_dapm_widgets[] = { 27462306a36Sopenharmony_ci SND_SOC_DAPM_AIF_IN("IN 0", NULL, 0, SND_SOC_NOPM, 0, 0), 27562306a36Sopenharmony_ci SND_SOC_DAPM_AIF_IN("IN 1", NULL, 0, SND_SOC_NOPM, 0, 0), 27662306a36Sopenharmony_ci SND_SOC_DAPM_AIF_IN("IN 2", NULL, 0, SND_SOC_NOPM, 0, 0), 27762306a36Sopenharmony_ci SND_SOC_DAPM_AIF_IN("IN 3", NULL, 0, SND_SOC_NOPM, 0, 0), 27862306a36Sopenharmony_ci SND_SOC_DAPM_AIF_IN("IN 4", NULL, 0, SND_SOC_NOPM, 0, 0), 27962306a36Sopenharmony_ci SND_SOC_DAPM_MUX("SRC SEL", SND_SOC_NOPM, 0, 0, &sm1_tdmout_in_mux), 28062306a36Sopenharmony_ci SND_SOC_DAPM_PGA_E("ENC", SND_SOC_NOPM, 0, 0, NULL, 0, 28162306a36Sopenharmony_ci axg_tdm_formatter_event, 28262306a36Sopenharmony_ci (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD)), 28362306a36Sopenharmony_ci SND_SOC_DAPM_AIF_OUT("OUT", NULL, 0, SND_SOC_NOPM, 0, 0), 28462306a36Sopenharmony_ci}; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_cistatic const struct snd_soc_dapm_route sm1_tdmout_dapm_routes[] = { 28762306a36Sopenharmony_ci { "SRC SEL", "IN 0", "IN 0" }, 28862306a36Sopenharmony_ci { "SRC SEL", "IN 1", "IN 1" }, 28962306a36Sopenharmony_ci { "SRC SEL", "IN 2", "IN 2" }, 29062306a36Sopenharmony_ci { "SRC SEL", "IN 3", "IN 3" }, 29162306a36Sopenharmony_ci { "SRC SEL", "IN 4", "IN 4" }, 29262306a36Sopenharmony_ci { "ENC", NULL, "SRC SEL" }, 29362306a36Sopenharmony_ci { "OUT", NULL, "ENC" }, 29462306a36Sopenharmony_ci}; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_cistatic const struct snd_soc_component_driver sm1_tdmout_component_drv = { 29762306a36Sopenharmony_ci .controls = sm1_tdmout_controls, 29862306a36Sopenharmony_ci .num_controls = ARRAY_SIZE(sm1_tdmout_controls), 29962306a36Sopenharmony_ci .dapm_widgets = sm1_tdmout_dapm_widgets, 30062306a36Sopenharmony_ci .num_dapm_widgets = ARRAY_SIZE(sm1_tdmout_dapm_widgets), 30162306a36Sopenharmony_ci .dapm_routes = sm1_tdmout_dapm_routes, 30262306a36Sopenharmony_ci .num_dapm_routes = ARRAY_SIZE(sm1_tdmout_dapm_routes), 30362306a36Sopenharmony_ci}; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_cistatic const struct axg_tdm_formatter_driver sm1_tdmout_drv = { 30662306a36Sopenharmony_ci .component_drv = &sm1_tdmout_component_drv, 30762306a36Sopenharmony_ci .regmap_cfg = &axg_tdmout_regmap_cfg, 30862306a36Sopenharmony_ci .ops = &axg_tdmout_ops, 30962306a36Sopenharmony_ci .quirks = &(const struct axg_tdm_formatter_hw) { 31062306a36Sopenharmony_ci .skew_offset = 2, 31162306a36Sopenharmony_ci }, 31262306a36Sopenharmony_ci}; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_cistatic const struct of_device_id axg_tdmout_of_match[] = { 31562306a36Sopenharmony_ci { 31662306a36Sopenharmony_ci .compatible = "amlogic,axg-tdmout", 31762306a36Sopenharmony_ci .data = &axg_tdmout_drv, 31862306a36Sopenharmony_ci }, { 31962306a36Sopenharmony_ci .compatible = "amlogic,g12a-tdmout", 32062306a36Sopenharmony_ci .data = &g12a_tdmout_drv, 32162306a36Sopenharmony_ci }, { 32262306a36Sopenharmony_ci .compatible = "amlogic,sm1-tdmout", 32362306a36Sopenharmony_ci .data = &sm1_tdmout_drv, 32462306a36Sopenharmony_ci }, {} 32562306a36Sopenharmony_ci}; 32662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, axg_tdmout_of_match); 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_cistatic struct platform_driver axg_tdmout_pdrv = { 32962306a36Sopenharmony_ci .probe = axg_tdm_formatter_probe, 33062306a36Sopenharmony_ci .driver = { 33162306a36Sopenharmony_ci .name = "axg-tdmout", 33262306a36Sopenharmony_ci .of_match_table = axg_tdmout_of_match, 33362306a36Sopenharmony_ci }, 33462306a36Sopenharmony_ci}; 33562306a36Sopenharmony_cimodule_platform_driver(axg_tdmout_pdrv); 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ciMODULE_DESCRIPTION("Amlogic AXG TDM output formatter driver"); 33862306a36Sopenharmony_ciMODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>"); 33962306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 340