/* McASP specific data */
int tdm_slots;
++ +++ u32 tdm_mask[2];
++ +++ int slot_width;
u8 op_mode;
u8 num_serializer;
u8 *serial_dir;
u8 version;
u8 bclk_div;
-- --- u16 bclk_lrclk_ratio;
int streams;
u32 irq_request[2];
int dma_request[2];
mcasp->bclk_div = div;
break;
-- --- case 2: /* BCLK/LRCLK ratio */
-- --- mcasp->bclk_lrclk_ratio = div;
++ +++ case 2: /*
++ +++ * BCLK/LRCLK ratio descries how many bit-clock cycles
++ +++ * fit into one frame. The clock ratio is given for a
++ +++ * full period of data (for I2S format both left and
++ +++ * right channels), so it has to be divided by number
++ +++ * of tdm-slots (for I2S - divided by 2).
++ +++ * Instead of storing this ratio, we calculate a new
++ +++ * tdm_slot width by dividing the the ratio by the
++ +++ * number of configured tdm slots.
++ +++ */
++ +++ mcasp->slot_width = div / mcasp->tdm_slots;
++ +++ if (div % mcasp->tdm_slots)
++ +++ dev_warn(mcasp->dev,
++ +++ "%s(): BCLK/LRCLK %d is not divisible by %d tdm slots",
++ +++ __func__, div, mcasp->tdm_slots);
break;
default:
return 0;
}
++ +++/* All serializers must have equal number of channels */
++ +++static int davinci_mcasp_ch_constraint(struct davinci_mcasp *mcasp, int stream,
++ +++ int serializers)
++ +++{
++ +++ struct snd_pcm_hw_constraint_list *cl = &mcasp->chconstr[stream];
++ +++ unsigned int *list = (unsigned int *) cl->list;
++ +++ int slots = mcasp->tdm_slots;
++ +++ int i, count = 0;
++ +++
++ +++ if (mcasp->tdm_mask[stream])
++ +++ slots = hweight32(mcasp->tdm_mask[stream]);
++ +++
++ +++ for (i = 2; i <= slots; i++)
++ +++ list[count++] = i;
++ +++
++ +++ for (i = 2; i <= serializers; i++)
++ +++ list[count++] = i*slots;
++ +++
++ +++ cl->count = count;
++ +++
++ +++ return 0;
++ +++}
++ +++
++ +++static int davinci_mcasp_set_ch_constraints(struct davinci_mcasp *mcasp)
++ +++{
++ +++ int rx_serializers = 0, tx_serializers = 0, ret, i;
++ +++
++ +++ for (i = 0; i < mcasp->num_serializer; i++)
++ +++ if (mcasp->serial_dir[i] == TX_MODE)
++ +++ tx_serializers++;
++ +++ else if (mcasp->serial_dir[i] == RX_MODE)
++ +++ rx_serializers++;
++ +++
++ +++ ret = davinci_mcasp_ch_constraint(mcasp, SNDRV_PCM_STREAM_PLAYBACK,
++ +++ tx_serializers);
++ +++ if (ret)
++ +++ return ret;
++ +++
++ +++ ret = davinci_mcasp_ch_constraint(mcasp, SNDRV_PCM_STREAM_CAPTURE,
++ +++ rx_serializers);
++ +++
++ +++ return ret;
++ +++}
++ +++
++ +++
++ +++static int davinci_mcasp_set_tdm_slot(struct snd_soc_dai *dai,
++ +++ unsigned int tx_mask,
++ +++ unsigned int rx_mask,
++ +++ int slots, int slot_width)
++ +++{
++ +++ struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
++ +++
++ +++ dev_dbg(mcasp->dev,
++ +++ "%s() tx_mask 0x%08x rx_mask 0x%08x slots %d width %d\n",
++ +++ __func__, tx_mask, rx_mask, slots, slot_width);
++ +++
++ +++ if (tx_mask >= (1<<slots) || rx_mask >= (1<<slots)) {
++ +++ dev_err(mcasp->dev,
++ +++ "Bad tdm mask tx: 0x%08x rx: 0x%08x slots %d\n",
++ +++ tx_mask, rx_mask, slots);
++ +++ return -EINVAL;
++ +++ }
++ +++
++ +++ if (slot_width &&
++ +++ (slot_width < 8 || slot_width > 32 || slot_width % 4 != 0)) {
++ +++ dev_err(mcasp->dev, "%s: Unsupported slot_width %d\n",
++ +++ __func__, slot_width);
++ +++ return -EINVAL;
++ +++ }
++ +++
++ +++ mcasp->tdm_slots = slots;
++ +++ mcasp->tdm_mask[SNDRV_PCM_STREAM_PLAYBACK] = rx_mask;
++ +++ mcasp->tdm_mask[SNDRV_PCM_STREAM_CAPTURE] = tx_mask;
++ +++ mcasp->slot_width = slot_width;
++ +++
++ +++ return davinci_mcasp_set_ch_constraints(mcasp);
++ +++}
++ +++
static int davinci_config_channel_size(struct davinci_mcasp *mcasp,
-- --- int word_length)
++ +++ int sample_width)
{
u32 fmt;
-- --- u32 tx_rotate = (word_length / 4) & 0x7;
-- --- u32 mask = (1ULL << word_length) - 1;
++ +++ u32 tx_rotate = (sample_width / 4) & 0x7;
++ +++ u32 mask = (1ULL << sample_width) - 1;
++ +++ u32 slot_width = sample_width;
++ +++
/*
* For captured data we should not rotate, inversion and masking is
* enoguh to get the data to the right position:
u32 rx_rotate = 0;
/*
-- --- * if s BCLK-to-LRCLK ratio has been configured via the set_clkdiv()
-- --- * callback, take it into account here. That allows us to for example
-- --- * send 32 bits per channel to the codec, while only 16 of them carry
-- --- * audio payload.
-- --- * The clock ratio is given for a full period of data (for I2S format
-- --- * both left and right channels), so it has to be divided by number of
-- --- * tdm-slots (for I2S - divided by 2).
++ +++ * Setting the tdm slot width either with set_clkdiv() or
++ +++ * set_tdm_slot() allows us to for example send 32 bits per
++ +++ * channel to the codec, while only 16 of them carry audio
++ +++ * payload.
*/
-- --- if (mcasp->bclk_lrclk_ratio) {
-- --- u32 slot_length = mcasp->bclk_lrclk_ratio / mcasp->tdm_slots;
-- ---
++ +++ if (mcasp->slot_width) {
/*
-- --- * When we have more bclk then it is needed for the data, we
-- --- * need to use the rotation to move the received samples to have
-- --- * correct alignment.
++ +++ * When we have more bclk then it is needed for the
++ +++ * data, we need to use the rotation to move the
++ +++ * received samples to have correct alignment.
*/
-- --- rx_rotate = (slot_length - word_length) / 4;
-- --- word_length = slot_length;
++ +++ slot_width = mcasp->slot_width;
++ +++ rx_rotate = (slot_width - sample_width) / 4;
}
/* mapping of the XSSZ bit-field as described in the datasheet */
-- --- fmt = (word_length >> 1) - 1;
++ +++ fmt = (slot_width >> 1) - 1;
if (mcasp->op_mode != DAVINCI_MCASP_DIT_MODE) {
mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, RXSSZ(fmt),
u8 rx_ser = 0;
u8 slots = mcasp->tdm_slots;
u8 max_active_serializers = (channels + slots - 1) / slots;
----- int active_serializers, numevt, n;
+++++ int active_serializers, numevt;
u32 reg;
/* Default configuration */
if (mcasp->version < MCASP_VERSION_3)
* The number of words for numevt need to be in steps of active
* serializers.
*/
----- n = numevt % active_serializers;
----- if (n)
----- numevt += (active_serializers - n);
+++++ numevt = (numevt / active_serializers) * active_serializers;
+++++
while (period_words % numevt && numevt > 0)
numevt -= active_serializers;
if (numevt <= 0)
/*
* If more than one serializer is needed, then use them with
-- --- * their specified tdm_slots count. Otherwise, one serializer
-- --- * can cope with the transaction using as many slots as channels
-- --- * in the stream, requires channels symmetry
++ +++ * all the specified tdm_slots. Otherwise, one serializer can
++ +++ * cope with the transaction using just as many slots as there
++ +++ * are channels in the stream.
*/
-- --- active_serializers = (channels + total_slots - 1) / total_slots;
-- --- if (active_serializers == 1)
-- --- active_slots = channels;
-- --- else
-- --- active_slots = total_slots;
-- ---
-- --- for (i = 0; i < active_slots; i++)
-- --- mask |= (1 << i);
++ +++ if (mcasp->tdm_mask[stream]) {
++ +++ active_slots = hweight32(mcasp->tdm_mask[stream]);
++ +++ active_serializers = (channels + active_slots - 1) /
++ +++ active_slots;
++ +++ if (active_serializers == 1) {
++ +++ active_slots = channels;
++ +++ for (i = 0; i < total_slots; i++) {
++ +++ if ((1 << i) & mcasp->tdm_mask[stream]) {
++ +++ mask |= (1 << i);
++ +++ if (--active_slots <= 0)
++ +++ break;
++ +++ }
++ +++ }
++ +++ }
++ +++ } else {
++ +++ active_serializers = (channels + total_slots - 1) / total_slots;
++ +++ if (active_serializers == 1)
++ +++ active_slots = channels;
++ +++ else
++ +++ active_slots = total_slots;
++ +++ for (i = 0; i < active_slots; i++)
++ +++ mask |= (1 << i);
++ +++ }
mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, TX_ASYNC);
if (!mcasp->dat_port)
busel = TXSEL;
-- --- mcasp_set_reg(mcasp, DAVINCI_MCASP_TXTDM_REG, mask);
-- --- mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, busel | TXORD);
-- --- mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG,
-- --- FSXMOD(total_slots), FSXMOD(0x1FF));
-- ---
-- --- mcasp_set_reg(mcasp, DAVINCI_MCASP_RXTDM_REG, mask);
-- --- mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, busel | RXORD);
-- --- mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG,
-- --- FSRMOD(total_slots), FSRMOD(0x1FF));
++ +++ if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
++ +++ mcasp_set_reg(mcasp, DAVINCI_MCASP_TXTDM_REG, mask);
++ +++ mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, busel | TXORD);
++ +++ mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG,
++ +++ FSXMOD(total_slots), FSXMOD(0x1FF));
++ +++ } else if (stream == SNDRV_PCM_STREAM_CAPTURE) {
++ +++ mcasp_set_reg(mcasp, DAVINCI_MCASP_RXTDM_REG, mask);
++ +++ mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, busel | RXORD);
++ +++ mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG,
++ +++ FSRMOD(total_slots), FSRMOD(0x1FF));
++ +++ }
return 0;
}
int sbits = params_width(params);
int ppm, div;
++ +++ if (mcasp->slot_width)
++ +++ sbits = mcasp->slot_width;
++ +++
div = davinci_mcasp_calc_clk_div(mcasp, rate*sbits*slots,
&ppm);
if (ppm)
struct snd_interval range;
int i;
++ +++ if (rd->mcasp->slot_width)
++ +++ sbits = rd->mcasp->slot_width;
++ +++
snd_interval_any(&range);
range.empty = 1;
for (i = 0; i < SNDRV_PCM_FORMAT_LAST; i++) {
if (snd_mask_test(fmt, i)) {
-- --- uint bclk_freq = snd_pcm_format_width(i)*slots*rate;
++ +++ uint sbits = snd_pcm_format_width(i);
int ppm;
-- --- davinci_mcasp_calc_clk_div(rd->mcasp, bclk_freq, &ppm);
++ +++ if (rd->mcasp->slot_width)
++ +++ sbits = rd->mcasp->slot_width;
++ +++
++ +++ davinci_mcasp_calc_clk_div(rd->mcasp, sbits*slots*rate,
++ +++ &ppm);
if (abs(ppm) < DAVINCI_MAX_RATE_ERROR_PPM) {
snd_mask_set(&nfmt, i);
count++;
&mcasp->ruledata[substream->stream];
u32 max_channels = 0;
int i, dir;
++ +++ int tdm_slots = mcasp->tdm_slots;
++ +++
++ +++ if (mcasp->tdm_mask[substream->stream])
++ +++ tdm_slots = hweight32(mcasp->tdm_mask[substream->stream]);
mcasp->substreams[substream->stream] = substream;
max_channels++;
}
ruledata->serializers = max_channels;
-- --- max_channels *= mcasp->tdm_slots;
++ +++ max_channels *= tdm_slots;
/*
* If the already active stream has less channels than the calculated
* limnit based on the seirializers * tdm_slots, we need to use that as
*/
if (mcasp->channels && mcasp->channels < max_channels)
max_channels = mcasp->channels;
++ +++ /*
++ +++ * But we can always allow channels upto the amount of
++ +++ * the available tdm_slots.
++ +++ */
++ +++ if (max_channels < tdm_slots)
++ +++ max_channels = tdm_slots;
snd_pcm_hw_constraint_minmax(substream->runtime,
SNDRV_PCM_HW_PARAM_CHANNELS,
2, max_channels);
-- --- if (mcasp->chconstr[substream->stream].count)
-- --- snd_pcm_hw_constraint_list(substream->runtime,
-- --- 0, SNDRV_PCM_HW_PARAM_CHANNELS,
-- --- &mcasp->chconstr[substream->stream]);
++ +++ snd_pcm_hw_constraint_list(substream->runtime,
++ +++ 0, SNDRV_PCM_HW_PARAM_CHANNELS,
++ +++ &mcasp->chconstr[substream->stream]);
++ +++
++ +++ if (mcasp->slot_width)
++ +++ snd_pcm_hw_constraint_minmax(substream->runtime,
++ +++ SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
++ +++ 8, mcasp->slot_width);
/*
* If we rely on implicit BCLK divider setting we should
.set_fmt = davinci_mcasp_set_dai_fmt,
.set_clkdiv = davinci_mcasp_set_clkdiv,
.set_sysclk = davinci_mcasp_set_sysclk,
++ +++ .set_tdm_slot = davinci_mcasp_set_tdm_slot,
};
static int davinci_mcasp_dai_probe(struct snd_soc_dai *dai)
.ops = &davinci_mcasp_dai_ops,
.symmetric_samplebits = 1,
+++++ .symmetric_rates = 1,
},
{
.name = "davinci-mcasp.1",
return pdata;
}
-- ---/* All serializers must have equal number of channels */
-- ---static int davinci_mcasp_ch_constraint(struct davinci_mcasp *mcasp,
-- --- struct snd_pcm_hw_constraint_list *cl,
-- --- int serializers)
-- ---{
-- --- unsigned int *list;
-- --- int i, count = 0;
-- ---
-- --- if (serializers <= 1)
-- --- return 0;
-- ---
-- --- list = devm_kzalloc(mcasp->dev, sizeof(unsigned int) *
-- --- (mcasp->tdm_slots + serializers - 2),
-- --- GFP_KERNEL);
-- --- if (!list)
-- --- return -ENOMEM;
-- ---
-- --- for (i = 2; i <= mcasp->tdm_slots; i++)
-- --- list[count++] = i;
-- ---
-- --- for (i = 2; i <= serializers; i++)
-- --- list[count++] = i*mcasp->tdm_slots;
-- ---
-- --- cl->count = count;
-- --- cl->list = list;
-- ---
-- --- return 0;
-- ---}
-- ---
-- ---
-- ---static int davinci_mcasp_init_ch_constraints(struct davinci_mcasp *mcasp)
-- ---{
-- --- int rx_serializers = 0, tx_serializers = 0, ret, i;
-- ---
-- --- for (i = 0; i < mcasp->num_serializer; i++)
-- --- if (mcasp->serial_dir[i] == TX_MODE)
-- --- tx_serializers++;
-- --- else if (mcasp->serial_dir[i] == RX_MODE)
-- --- rx_serializers++;
-- ---
-- --- ret = davinci_mcasp_ch_constraint(mcasp, &mcasp->chconstr[
-- --- SNDRV_PCM_STREAM_PLAYBACK],
-- --- tx_serializers);
-- --- if (ret)
-- --- return ret;
-- ---
-- --- ret = davinci_mcasp_ch_constraint(mcasp, &mcasp->chconstr[
-- --- SNDRV_PCM_STREAM_CAPTURE],
-- --- rx_serializers);
-- ---
-- --- return ret;
-- ---}
-- ---
enum {
PCM_EDMA,
PCM_SDMA,
irq = platform_get_irq_byname(pdev, "common");
if (irq >= 0) {
----- irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_common\n",
+++++ irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_common",
dev_name(&pdev->dev));
ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
davinci_mcasp_common_irq_handler,
irq = platform_get_irq_byname(pdev, "rx");
if (irq >= 0) {
----- irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_rx\n",
+++++ irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_rx",
dev_name(&pdev->dev));
ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
davinci_mcasp_rx_irq_handler,
irq = platform_get_irq_byname(pdev, "tx");
if (irq >= 0) {
----- irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_tx\n",
+++++ irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_tx",
dev_name(&pdev->dev));
ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
davinci_mcasp_tx_irq_handler,
mcasp->fifo_base = DAVINCI_MCASP_V3_AFIFO_BASE;
}
-- --- ret = davinci_mcasp_init_ch_constraints(mcasp);
++ +++ /* Allocate memory for long enough list for all possible
++ +++ * scenarios. Maximum number tdm slots is 32 and there cannot
++ +++ * be more serializers than given in the configuration. The
++ +++ * serializer directions could be taken into account, but it
++ +++ * would make code much more complex and save only couple of
++ +++ * bytes.
++ +++ */
++ +++ mcasp->chconstr[SNDRV_PCM_STREAM_PLAYBACK].list =
++ +++ devm_kzalloc(mcasp->dev, sizeof(unsigned int) *
++ +++ (32 + mcasp->num_serializer - 2),
++ +++ GFP_KERNEL);
++ +++
++ +++ mcasp->chconstr[SNDRV_PCM_STREAM_CAPTURE].list =
++ +++ devm_kzalloc(mcasp->dev, sizeof(unsigned int) *
++ +++ (32 + mcasp->num_serializer - 2),
++ +++ GFP_KERNEL);
++ +++
++ +++ if (!mcasp->chconstr[SNDRV_PCM_STREAM_PLAYBACK].list ||
++ +++ !mcasp->chconstr[SNDRV_PCM_STREAM_CAPTURE].list)
++ +++ return -ENOMEM;
++ +++
++ +++ ret = davinci_mcasp_set_ch_constraints(mcasp);
if (ret)
goto err;