linux/sound/soc/meson/axg-tdm.h
Jerome Brunet d60e4f1e4b
ASoC: meson: add tdm interface driver
Add Amlogic's axg TDM interface driver. This driver manages the format
and clocks provided on the pads.

On this SoC, each stream direction provides 4 serial lanes. This makes
a maximum of 8 channels in i2s modes and 128 channels in DSP modes.

While each lanes operate on the same slot number (same bit clock), they
may have different TDM masks. This requires to provide a function to let
the card set the 4 masks, in lieu of the usual set_tdm_slots() callback
of the dai driver.

Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
2018-07-20 17:38:33 +01:00

79 lines
1.9 KiB
C

/* SPDX-License-Identifier: (GPL-2.0 OR MIT)
*
* Copyright (c) 2018 Baylibre SAS.
* Author: Jerome Brunet <jbrunet@baylibre.com>
*/
#ifndef _MESON_AXG_TDM_H
#define _MESON_AXG_TDM_H
#include <linux/clk.h>
#include <linux/regmap.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/soc-dai.h>
#define AXG_TDM_NUM_LANES 4
#define AXG_TDM_CHANNEL_MAX 128
#define AXG_TDM_RATES (SNDRV_PCM_RATE_5512 | \
SNDRV_PCM_RATE_8000_192000)
#define AXG_TDM_FORMATS (SNDRV_PCM_FMTBIT_S8 | \
SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FMTBIT_S20_LE | \
SNDRV_PCM_FMTBIT_S24_LE | \
SNDRV_PCM_FMTBIT_S32_LE)
struct axg_tdm_iface {
struct clk *sclk;
struct clk *lrclk;
struct clk *mclk;
unsigned long mclk_rate;
/* format is common to all the DAIs of the iface */
unsigned int fmt;
unsigned int slots;
unsigned int slot_width;
/* For component wide symmetry */
int rate;
};
static inline bool axg_tdm_lrclk_invert(unsigned int fmt)
{
return (fmt & SND_SOC_DAIFMT_I2S) ^
!!(fmt & (SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_NB_IF));
}
static inline bool axg_tdm_sclk_invert(unsigned int fmt)
{
return fmt & (SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_IB_NF);
}
struct axg_tdm_stream {
struct axg_tdm_iface *iface;
struct list_head formatter_list;
struct mutex lock;
unsigned int channels;
unsigned int width;
unsigned int physical_width;
u32 *mask;
bool ready;
};
struct axg_tdm_stream *axg_tdm_stream_alloc(struct axg_tdm_iface *iface);
void axg_tdm_stream_free(struct axg_tdm_stream *ts);
int axg_tdm_stream_start(struct axg_tdm_stream *ts);
void axg_tdm_stream_stop(struct axg_tdm_stream *ts);
static inline int axg_tdm_stream_reset(struct axg_tdm_stream *ts)
{
axg_tdm_stream_stop(ts);
return axg_tdm_stream_start(ts);
}
int axg_tdm_set_tdm_slots(struct snd_soc_dai *dai, u32 *tx_mask,
u32 *rx_mask, unsigned int slots,
unsigned int slot_width);
#endif /* _MESON_AXG_TDM_H */