0001
0002
0003
0004
0005
0006
0007 #ifndef _MESON_AXG_TDM_H
0008 #define _MESON_AXG_TDM_H
0009
0010 #include <linux/clk.h>
0011 #include <linux/regmap.h>
0012 #include <sound/pcm.h>
0013 #include <sound/soc.h>
0014 #include <sound/soc-dai.h>
0015
0016 #define AXG_TDM_NUM_LANES 4
0017 #define AXG_TDM_CHANNEL_MAX 128
0018 #define AXG_TDM_RATES (SNDRV_PCM_RATE_5512 | \
0019 SNDRV_PCM_RATE_8000_192000)
0020 #define AXG_TDM_FORMATS (SNDRV_PCM_FMTBIT_S8 | \
0021 SNDRV_PCM_FMTBIT_S16_LE | \
0022 SNDRV_PCM_FMTBIT_S20_LE | \
0023 SNDRV_PCM_FMTBIT_S24_LE | \
0024 SNDRV_PCM_FMTBIT_S32_LE)
0025
0026 struct axg_tdm_iface {
0027 struct clk *sclk;
0028 struct clk *lrclk;
0029 struct clk *mclk;
0030 unsigned long mclk_rate;
0031
0032
0033 unsigned int fmt;
0034 unsigned int slots;
0035 unsigned int slot_width;
0036
0037
0038 int rate;
0039 };
0040
0041 static inline bool axg_tdm_lrclk_invert(unsigned int fmt)
0042 {
0043 return ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_I2S) ^
0044 !!(fmt & (SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_NB_IF));
0045 }
0046
0047 static inline bool axg_tdm_sclk_invert(unsigned int fmt)
0048 {
0049 return fmt & (SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_IB_NF);
0050 }
0051
0052 struct axg_tdm_stream {
0053 struct axg_tdm_iface *iface;
0054 struct list_head formatter_list;
0055 struct mutex lock;
0056 unsigned int channels;
0057 unsigned int width;
0058 unsigned int physical_width;
0059 u32 *mask;
0060 bool ready;
0061 };
0062
0063 struct axg_tdm_stream *axg_tdm_stream_alloc(struct axg_tdm_iface *iface);
0064 void axg_tdm_stream_free(struct axg_tdm_stream *ts);
0065 int axg_tdm_stream_start(struct axg_tdm_stream *ts);
0066 void axg_tdm_stream_stop(struct axg_tdm_stream *ts);
0067
0068 static inline int axg_tdm_stream_reset(struct axg_tdm_stream *ts)
0069 {
0070 axg_tdm_stream_stop(ts);
0071 return axg_tdm_stream_start(ts);
0072 }
0073
0074 int axg_tdm_set_tdm_slots(struct snd_soc_dai *dai, u32 *tx_mask,
0075 u32 *rx_mask, unsigned int slots,
0076 unsigned int slot_width);
0077
0078 #endif