RE: [PATCH v2] ASoC: rt722-sdca: Add RT722 SDCA driver

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



> -----Original Message-----
> From: Pierre-Louis Bossart <pierre-louis.bossart@xxxxxxxxxxxxxxx>
> Sent: Wednesday, April 19, 2023 10:24 PM
> To: Jack Yu <jack.yu@xxxxxxxxxxx>; broonie@xxxxxxxxxx;
> lgirdwood@xxxxxxxxx
> Cc: alsa-devel@xxxxxxxxxxxxxxxx; lars@xxxxxxxxxx; Flove(HsinFu)
> <flove@xxxxxxxxxxx>; Oder Chiou <oder_chiou@xxxxxxxxxxx>; Shuming [范書
> 銘] <shumingf@xxxxxxxxxxx>; Derek [方德義] <derek.fang@xxxxxxxxxxx>;
> Bard Liao <yung-chuan.liao@xxxxxxxxxxxxxxx>
> Subject: Re: [PATCH v2] ASoC: rt722-sdca: Add RT722 SDCA driver
> 
> 
> External mail.
> 
> 
> 
> On 4/19/23 05:15, Jack Yu wrote:
> > This is the initial codec driver for rt722-sdca.
> >
> > Patch v2 is to fix warning message from kernel test robot.
> 
> this version information should go below the --- line ...
> >

Ok, I'll fix it.

> > Signed-off-by: Jack Yu <jack.yu@xxxxxxxxxxx>
> > ---
> 
> ... here
> 
> 
> > +static int rt722_sdca_read_prop(struct sdw_slave *slave) {
> > +     struct sdw_slave_prop *prop = &slave->prop;
> > +     int nval;
> > +     int i, j;
> > +     u32 bit;
> > +     unsigned long addr;
> > +     struct sdw_dpn_prop *dpn;
> > +
> > +     prop->scp_int1_mask = SDW_SCP_INT1_BUS_CLASH |
> SDW_SCP_INT1_PARITY;
> > +     prop->quirks = SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY;
> > +
> > +     prop->paging_support = true;
> > +
> > +     /* first we need to allocate memory for set bits in port lists */
> > +     prop->source_ports = BIT(6) | BIT(2); /* BITMAP: 01000100 */
> > +     prop->sink_ports = BIT(3) | BIT(1); /* BITMAP:  00001010 */
> 
> which port is used for what?

I'll add some information regarding to port configuration.

> 
> > +
> > +     nval = hweight32(prop->source_ports);
> > +     prop->src_dpn_prop = devm_kcalloc(&slave->dev, nval,
> > +             sizeof(*prop->src_dpn_prop), GFP_KERNEL);
> > +     if (!prop->src_dpn_prop)
> > +             return -ENOMEM;
> > +
> > +     i = 0;
> > +     dpn = prop->src_dpn_prop;
> > +     addr = prop->source_ports;
> > +     for_each_set_bit(bit, &addr, 32) {
> > +             dpn[i].num = bit;
> > +             dpn[i].type = SDW_DPN_FULL;
> > +             dpn[i].simple_ch_prep_sm = true;
> > +             dpn[i].ch_prep_timeout = 10;
> > +             i++;
> > +     }
> > +
> > +     /* do this again for sink now */
> > +     nval = hweight32(prop->sink_ports);
> > +     prop->sink_dpn_prop = devm_kcalloc(&slave->dev, nval,
> > +             sizeof(*prop->sink_dpn_prop), GFP_KERNEL);
> > +     if (!prop->sink_dpn_prop)
> > +             return -ENOMEM;
> > +
> > +     j = 0;
> > +     dpn = prop->sink_dpn_prop;
> > +     addr = prop->sink_ports;
> > +     for_each_set_bit(bit, &addr, 32) {
> > +             dpn[j].num = bit;
> > +             dpn[j].type = SDW_DPN_FULL;
> > +             dpn[j].simple_ch_prep_sm = true;
> > +             dpn[j].ch_prep_timeout = 10;
> > +             j++;
> > +     }
> > +
> > +     /* set the timeout values */
> > +     prop->clk_stop_timeout = 200;
> > +
> > +     /* wake-up event */
> > +     prop->wake_capable = 1;
> > +
> > +     return 0;
> > +}
> 
> > +static int rt722_sdca_pcm_hw_params(struct snd_pcm_substream
> *substream,
> > +                             struct snd_pcm_hw_params *params,
> > +                             struct snd_soc_dai *dai) {
> > +     struct snd_soc_component *component = dai->component;
> > +     struct rt722_sdca_priv *rt722 =
> snd_soc_component_get_drvdata(component);
> > +     struct sdw_stream_config stream_config;
> > +     struct sdw_port_config port_config;
> > +     enum sdw_data_direction direction;
> > +     struct sdw_stream_runtime *sdw_stream;
> > +     int retval, port, num_channels;
> > +     unsigned int sampling_rate;
> > +
> > +     dev_dbg(dai->dev, "%s %s", __func__, dai->name);
> > +     sdw_stream = snd_soc_dai_get_dma_data(dai, substream);
> > +
> > +     if (!sdw_stream)
> > +             return -EINVAL;
> > +
> > +     if (!rt722->slave)
> > +             return -EINVAL;
> > +
> > +     /*
> > +      * RT722_AIF1 with port = 1 for headphone playback
> > +      * RT722_AIF1 with port = 2 for headset-mic capture
> > +      * RT722_AIF2 with port = 3 for speaker playback
> > +      * RT722_AIF2 with port = 6 for digital-mic capture
> > +      */
> 
> I guess the answer is here...
> 
> It wouldn't hurt to have the information above as well.
> 
> It's also an interesting partition because in theory the amplifier and mic
> 'functions' are supposed to be independent, yet they are on the same DAI.
>

I can separate these two functions (dmic and speaker) into two DAIs like below

static struct snd_soc_dai_driver rt722_sdca_dai[] = {
	...
	{
		.name = "rt722-sdca-aif2",
		.id = RT722_AIF2,
		.playback = {
			.stream_name = "DP3 Speaker Playback",
			.channels_min = 1,
			.channels_max = 2,
			.rates = RT722_STEREO_RATES,
			.formats = RT722_FORMATS,
		},
		.ops = &rt722_sdca_ops,
	},
	{
		.name = "rt722-sdca-aif3",
		.id = RT722_AIF3,
		.capture = {
			.stream_name = "DP6 DMic Capture",
			.channels_min = 1,
			.channels_max = 2,
			.rates = RT722_STEREO_RATES,
			.formats = RT722_FORMATS,
		},
		.ops = &rt722_sdca_ops,
	}
...
};

> Bard, would this work for the machine driver integration?
> 
> > +     if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
> > +             direction = SDW_DATA_DIR_RX;
> > +             if (dai->id == RT722_AIF1)
> > +                     port = 1;
> > +             else if (dai->id == RT722_AIF2)
> > +                     port = 3;
> > +             else
> > +                     return -EINVAL;
> > +     } else {
> > +             direction = SDW_DATA_DIR_TX;
> > +             if (dai->id == RT722_AIF1)
> > +                     port = 2;
> > +             else if (dai->id == RT722_AIF2)
> > +                     port = 6;
> > +             else
> > +                     return -EINVAL;
> > +     }
> > +     stream_config.frame_rate = params_rate(params);
> > +     stream_config.ch_count = params_channels(params);
> > +     stream_config.bps =
> snd_pcm_format_width(params_format(params));
> > +     stream_config.direction = direction;
> > +
> > +     num_channels = params_channels(params);
> > +     port_config.ch_mask = GENMASK(num_channels - 1, 0);
> > +     port_config.num = port;
> > +
> > +     retval = sdw_stream_add_slave(rt722->slave, &stream_config,
> > +                                     &port_config, 1, sdw_stream);
> > +     if (retval) {
> > +             dev_err(dai->dev, "Unable to configure port\n");
> > +             return retval;
> > +     }
> > +
> > +     if (params_channels(params) > 16) {
> > +             dev_err(component->dev, "Unsupported channels %d\n",
> > +                     params_channels(params));
> > +             return -EINVAL;
> > +     }
> > +
> > +     /* sampling rate configuration */
> > +     switch (params_rate(params)) {
> > +     case 44100:
> > +             sampling_rate = RT722_SDCA_RATE_44100HZ;
> > +             break;
> > +     case 48000:
> > +             sampling_rate = RT722_SDCA_RATE_48000HZ;
> > +             break;
> > +     case 96000:
> > +             sampling_rate = RT722_SDCA_RATE_96000HZ;
> > +             break;
> > +     case 192000:
> > +             sampling_rate = RT722_SDCA_RATE_192000HZ;
> > +             break;
> > +     default:
> > +             dev_err(component->dev, "Rate %d is not supported\n",
> > +                     params_rate(params));
> > +             return -EINVAL;
> > +     }
> > +
> > +     /* set sampling frequency */
> > +     if (dai->id == RT722_AIF1) {
> > +             regmap_write(rt722->regmap,
> > +                     SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC,
> RT722_SDCA_ENT_CS01,
> > +
> RT722_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), sampling_rate);
> > +             regmap_write(rt722->regmap,
> > +                     SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC,
> RT722_SDCA_ENT_CS11,
> > +
> RT722_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), sampling_rate);
> > +     }
> > +
> > +     if (dai->id == RT722_AIF2) {
> > +             regmap_write(rt722->regmap,
> > +                     SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY,
> RT722_SDCA_ENT_CS1F,
> > +
> RT722_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), sampling_rate);
> > +             regmap_write(rt722->regmap,
> > +                     SDW_SDCA_CTL(FUNC_NUM_AMP,
> RT722_SDCA_ENT_CS31,
> > +
> RT722_SDCA_CTL_SAMPLE_FREQ_INDEX, 0),
> > + sampling_rate);
> 
> and that's precisely the sort of problems I had in mind earlier. Why would the
> sample-rate be aligned for both amplifier and dmic?
> 
> I don't think this follows the intent of the SDCA spec. The functions are
> supposed to be independent, so when we set hw_params for e.g.
> amplifiers we can't touch the microphone function.
> 
> I would recommend splitting the DAIs here to have self-contained operations
> that preserve the independence between functions - if the hardware can deal
> with independent functions we have no reason to rejoin these functions at the
> driver level, do we?

I'll separate the DAIs for dmic/speaker and hw_param settings will be independent as well.

> 
> > +     }
> > +
> > +     return 0;
> > +}
> > +
> > +static int rt722_sdca_pcm_hw_free(struct snd_pcm_substream *substream,
> > +                             struct snd_soc_dai *dai) {
> > +     struct snd_soc_component *component = dai->component;
> > +     struct rt722_sdca_priv *rt722 =
> snd_soc_component_get_drvdata(component);
> > +     struct sdw_stream_runtime *sdw_stream =
> > +             snd_soc_dai_get_dma_data(dai, substream);
> > +
> > +     if (!rt722->slave)
> > +             return -EINVAL;
> > +
> > +     sdw_stream_remove_slave(rt722->slave, sdw_stream);
> > +     return 0;
> > +}
> > +
> > +#define RT722_STEREO_RATES (SNDRV_PCM_RATE_44100 |
> SNDRV_PCM_RATE_48000 | \
> > +                     SNDRV_PCM_RATE_96000 |
> SNDRV_PCM_RATE_192000)
> > +#define RT722_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |
> SNDRV_PCM_FMTBIT_S20_3LE | \
> > +                     SNDRV_PCM_FMTBIT_S24_LE)
> > +
> > +static const struct snd_soc_dai_ops rt722_sdca_ops = {
> > +     .hw_params      = rt722_sdca_pcm_hw_params,
> > +     .hw_free        = rt722_sdca_pcm_hw_free,
> > +     .set_stream     = rt722_sdca_set_sdw_stream,
> > +     .shutdown       = rt722_sdca_shutdown,
> > +};
> > +
> > +static struct snd_soc_dai_driver rt722_sdca_dai[] = {
> > +     {
> > +             .name = "rt722-sdca-aif1",
> > +             .id = RT722_AIF1,
> > +             .playback = {
> > +                     .stream_name = "DP1 Headphone Playback",
> > +                     .channels_min = 1,
> > +                     .channels_max = 2,
> > +                     .rates = RT722_STEREO_RATES,
> > +                     .formats = RT722_FORMATS,
> > +             },
> > +             .capture = {
> > +                     .stream_name = "DP2 Headset Capture",
> > +                     .channels_min = 1,
> > +                     .channels_max = 2,
> > +                     .rates = RT722_STEREO_RATES,
> > +                     .formats = RT722_FORMATS,
> > +             },
> > +             .ops = &rt722_sdca_ops,
> > +     },
> > +     {
> > +             .name = "rt722-sdca-aif2",
> > +             .id = RT722_AIF2,
> > +             .playback = {
> > +                     .stream_name = "DP3 Speaker Playback",
> > +                     .channels_min = 1,
> > +                     .channels_max = 2,
> > +                     .rates = RT722_STEREO_RATES,
> > +                     .formats = RT722_FORMATS,
> > +             },
> > +             .capture = {
> > +                     .stream_name = "DP6 DMic Capture",
> > +                     .channels_min = 1,
> > +                     .channels_max = 2,
> > +                     .rates = RT722_STEREO_RATES,
> > +                     .formats = RT722_FORMATS,
> > +             },
> > +             .ops = &rt722_sdca_ops,
> > +     }
> > +};
> 
> 
> ------Please consider the environment before printing this e-mail.




[Index of Archives]     [ALSA User]     [Linux Audio Users]     [Pulse Audio]     [Kernel Archive]     [Asterisk PBX]     [Photo Sharing]     [Linux Sound]     [Video 4 Linux]     [Gimp]     [Yosemite News]

  Powered by Linux