Exemplo n.º 1
0
static int snd_stm_conv_i2sspdif_disable(struct snd_stm_conv_i2sspdif
		*conv_i2sspdif)
{
	snd_stm_printd(1, "snd_stm_conv_i2sspdif_disable(conv_i2sspdif=%p)\n",
			conv_i2sspdif);

	BUG_ON(!conv_i2sspdif);
	BUG_ON(!snd_stm_magic_valid(conv_i2sspdif));
	BUG_ON(!conv_i2sspdif->enabled);

	if (snd_stm_conv_i2sspdif_iec958_set(conv_i2sspdif,
			&snd_stm_conv_i2sspdif_iec958_zeroed) != 0)
		snd_stm_printe("WARNING! Failed to clear channel status "
				"registers!\n");

	set__AUD_SPDIFPC_CFG(conv_i2sspdif,
		mask__AUD_SPDIFPC_CFG__DEVICE_EN__DISABLED(conv_i2sspdif) |
		mask__AUD_SPDIFPC_CFG__SW_RESET__RESET(conv_i2sspdif) |
		mask__AUD_SPDIFPC_CFG__FIFO_EN__DISABLED(conv_i2sspdif) |
		mask__AUD_SPDIFPC_CFG__REQ_ACK_EN__DISABLED(conv_i2sspdif));
	set__AUD_SPDIFPC_CTRL(conv_i2sspdif,
		mask__AUD_SPDIFPC_CTRL__OPERATION__OFF(conv_i2sspdif));

	conv_i2sspdif->enabled = 0;

	return 0;
}
Exemplo n.º 2
0
static int __init snd_stm_fli75xx_init(void)
{
	int result;

	snd_stm_printd(0, "%s()\n", __func__);

	switch (cpu_data->type) {
	case CPU_FLI7510:
	case CPU_FLI7520:
	case CPU_FLI7530:
	case CPU_FLI7540:
	case CPU_FLI7560:
		break;
	default:
		snd_stm_printe("Unsupported (non-Freeman) SOC detected!\n");
		result = -EINVAL;
		goto error_soc_type;
	}

	result = platform_driver_register(&snd_stm_fli75xx_glue_driver);
	if (result != 0) {
		snd_stm_printe("Failed to register audio glue driver!\n");
		goto error_glue_driver_register;
	}

	result = snd_stm_card_register();
	if (result != 0) {
		snd_stm_printe("Failed to register ALSA cards!\n");
		goto error_card_register;
	}

	return 0;

error_card_register:
	platform_driver_unregister(&snd_stm_fli75xx_glue_driver);
error_glue_driver_register:
error_soc_type:
	return result;
}
Exemplo n.º 3
0
static int snd_stm_conv_i2sspdif_register(struct snd_device *snd_device)
{
	struct snd_stm_conv_i2sspdif *conv_i2sspdif = snd_device->device_data;
	int i;

	snd_stm_printd(1, "%s(snd_device=0x%p)\n", __func__, snd_device);

	BUG_ON(!conv_i2sspdif);
	BUG_ON(!snd_stm_magic_valid(conv_i2sspdif));
	BUG_ON(conv_i2sspdif->enabled);

	/* Initialize converter's input & SPDIF player as disabled */

	set__AUD_SPDIFPC_CFG(conv_i2sspdif,
		mask__AUD_SPDIFPC_CFG__DEVICE_EN__DISABLED(conv_i2sspdif) |
		mask__AUD_SPDIFPC_CFG__SW_RESET__RESET(conv_i2sspdif) |
		mask__AUD_SPDIFPC_CFG__FIFO_EN__DISABLED(conv_i2sspdif) |
		mask__AUD_SPDIFPC_CFG__REQ_ACK_EN__DISABLED(conv_i2sspdif));

	set__AUD_SPDIFPC_CTRL(conv_i2sspdif,
		mask__AUD_SPDIFPC_CTRL__OPERATION__OFF(conv_i2sspdif));

	/* Additional procfs info */

	snd_stm_info_register(&conv_i2sspdif->proc_entry,
			dev_name(conv_i2sspdif->device),
			snd_stm_conv_i2sspdif_dump_registers,
			conv_i2sspdif);

	/* Create ALSA controls */

	for (i = 0; i < ARRAY_SIZE(snd_stm_conv_i2sspdif_ctls); i++) {
		int result;

		snd_stm_conv_i2sspdif_ctls[i].device =
				snd_stm_conv_get_card_device(
				conv_i2sspdif->converter);
		snd_stm_conv_i2sspdif_ctls[i].index = conv_i2sspdif->index;
		result = snd_ctl_add(snd_stm_card_get(),
				snd_ctl_new1(&snd_stm_conv_i2sspdif_ctls[i],
				conv_i2sspdif));
		if (result < 0) {
			snd_stm_printe("Failed to add I2S-SPDIF converter "
					"ALSA control!\n");
			return result;
		}
	}

	return 0;
}
Exemplo n.º 4
0
static int snd_stm_conv_i2sspdif_enable(struct snd_stm_conv_i2sspdif
		*conv_i2sspdif)
{
	int oversampling;
	struct snd_aes_iec958 iec958;

	snd_stm_printd(1, "snd_stm_conv_i2sspdif_enable(conv_i2sspdif=%p)\n",
			conv_i2sspdif);

	BUG_ON(!conv_i2sspdif);
	BUG_ON(!snd_stm_magic_valid(conv_i2sspdif));
	BUG_ON(conv_i2sspdif->enabled);

	oversampling = snd_stm_conv_i2sspdif_oversampling(conv_i2sspdif);
	BUG_ON(oversampling <= 0);
	BUG_ON((oversampling % 128) != 0);

	set__AUD_SPDIFPC_CFG(conv_i2sspdif,
		mask__AUD_SPDIFPC_CFG__DEVICE_EN__ENABLED(conv_i2sspdif) |
		mask__AUD_SPDIFPC_CFG__SW_RESET__RUNNING(conv_i2sspdif) |
		mask__AUD_SPDIFPC_CFG__FIFO_EN__ENABLED(conv_i2sspdif) |
		mask__AUD_SPDIFPC_CFG__AUDIO_WORD_SIZE__24_BITS(conv_i2sspdif)
		| mask__AUD_SPDIFPC_CFG__REQ_ACK_EN__ENABLED(conv_i2sspdif));
	set__AUD_SPDIFPC_CTRL(conv_i2sspdif,
		mask__AUD_SPDIFPC_CTRL__OPERATION__PCM(conv_i2sspdif) |
		mask__AUD_SPDIFPC_CTRL__ROUNDING__NO_ROUNDING(conv_i2sspdif));
	set__AUD_SPDIFPC_CTRL__DIVIDER(conv_i2sspdif, oversampling / 128);

	/* Full channel status processing - an undocumented feature that
	 * exists in some hardware... Normally channel status registers
	 * provides bits for each subframe, so only for 96 frames (a half
	 * of SPDIF block) - pathetic! ;-) Setting bit 6 of config register
	 * enables a mode in which channel status bits in L/R subframes
	 * are identical, and whole block is served... */
	if (conv_i2sspdif->ver >= 4)
		set__AUD_SPDIFPC_CFG__CHA_STA_BITS__FRAME(conv_i2sspdif);

	spin_lock(&conv_i2sspdif->iec958_default_lock);
	iec958 = conv_i2sspdif->iec958_default;
	spin_unlock(&conv_i2sspdif->iec958_default_lock);
	if (snd_stm_conv_i2sspdif_iec958_set(conv_i2sspdif, &iec958) != 0)
		snd_stm_printe("WARNING! Can't set channel status "
				"registers!\n");

	conv_i2sspdif->enabled = 1;

	return 0;
}
Exemplo n.º 5
0
static irqreturn_t snd_stm_pcm_player_irq_handler(int irq, void *dev_id)
{
	irqreturn_t result = IRQ_NONE;
	struct snd_stm_pcm_player *pcm_player = dev_id;
	unsigned int status;

	snd_stm_printd(2, "snd_stm_pcm_player_irq_handler(irq=%d, "
			"dev_id=0x%p)\n", irq, dev_id);

	BUG_ON(!pcm_player);
	BUG_ON(!snd_stm_magic_valid(pcm_player));

	/* Get interrupt status & clear them immediately */
	preempt_disable();
	status = get__AUD_PCMOUT_ITS(pcm_player);
	set__AUD_PCMOUT_ITS_CLR(pcm_player, status);
	preempt_enable();

	/* Underflow? */
	if (unlikely(status & mask__AUD_PCMOUT_ITS__UNF__PENDING(pcm_player))) {
		snd_stm_printe("Underflow detected in PCM player '%s'!\n",
			       dev_name(pcm_player->device));

		snd_pcm_stop(pcm_player->substream, SNDRV_PCM_STATE_XRUN);

		result = IRQ_HANDLED;
	} else if (likely(status &
			mask__AUD_PCMOUT_ITS__NSAMPLE__PENDING(pcm_player))) {
		/* Period successfully played */
		do {
			BUG_ON(!pcm_player->substream);

			snd_stm_printd(2, "Period elapsed ('%s')\n",
					dev_name(pcm_player->device));
			snd_pcm_period_elapsed(pcm_player->substream);

			result = IRQ_HANDLED;
		} while (0);
	}

	/* Some alien interrupt??? */
	BUG_ON(result != IRQ_HANDLED);

	return result;
}
Exemplo n.º 6
0
static int snd_stm_pcm_player_register(struct snd_device *snd_device)
{
	struct snd_stm_pcm_player *pcm_player = snd_device->device_data;

	snd_stm_printd(1, "%s(snd_device=0x%p)\n", __func__, snd_device);

	BUG_ON(!pcm_player);
	BUG_ON(!snd_stm_magic_valid(pcm_player));

	/* Set reset mode */

	set__AUD_PCMOUT_RST__SRSTP__RESET(pcm_player);

	/* TODO: well, hardcoded - shall anyone use it?
	 * And what does it actually mean? */

	if (pcm_player->ver > 5)
		set__AUD_PCMOUT_FMT__BACK_STALLING__DISABLED(pcm_player);
	set__AUD_PCMOUT_CTRL__RND__NO_ROUNDING(pcm_player);

	/* Get frequency synthesizer channel */

	pcm_player->clock = snd_stm_clk_get(pcm_player->device,
			"pcm_player_clk", snd_device->card,
			pcm_player->info->card_device);
	if (!pcm_player->clock || IS_ERR(pcm_player->clock)) {
		snd_stm_printe("Failed to get a clock for '%s'!\n",
				dev_name(pcm_player->device));
		return -EINVAL;
	}

	/* Registers view in ALSA's procfs */

	snd_stm_info_register(&pcm_player->proc_entry,
			dev_name(pcm_player->device),
			snd_stm_pcm_player_dump_registers, pcm_player);

	return 0;
}
Exemplo n.º 7
0
static int snd_stm_conv_dac_sc_probe(struct platform_device *pdev)
{
	int result = 0;
	struct snd_stm_conv_dac_sc_info *info =
			pdev->dev.platform_data;
	struct snd_stm_conv_dac_sc *conv_dac_sc;
	struct snd_card *card = snd_stm_card_get();

	snd_stm_printd(0, "%s('%s')\n", __func__, dev_name(&pdev->dev));

	BUG_ON(!card);
	BUG_ON(!info);

	conv_dac_sc = kzalloc(sizeof(*conv_dac_sc), GFP_KERNEL);
	if (!conv_dac_sc) {
		snd_stm_printe("Can't allocate memory "
				"for a device description!\n");
		result = -ENOMEM;
		goto error_alloc;
	}
	snd_stm_magic_set(conv_dac_sc);
	conv_dac_sc->bus_id = dev_name(&pdev->dev);

	/* Get resources */

	conv_dac_sc->nrst = sysconf_claim(info->nrst.group, info->nrst.num,
			info->nrst.lsb, info->nrst.msb, "NRST");
	BUG_ON(!conv_dac_sc->nrst);
	conv_dac_sc->mode = sysconf_claim(info->mode.group, info->mode.num,
			info->mode.lsb, info->mode.msb, "MODE");
	BUG_ON(!conv_dac_sc->mode);
	conv_dac_sc->nsb = sysconf_claim(info->nsb.group, info->nsb.num,
			info->nsb.lsb, info->nsb.msb, "NSB");
	BUG_ON(!conv_dac_sc->nsb);
	conv_dac_sc->softmute = sysconf_claim(info->softmute.group,
			info->softmute.num, info->softmute.lsb,
			info->softmute.msb, "SOFTMUTE");
	BUG_ON(!conv_dac_sc->softmute);
	conv_dac_sc->pdana = sysconf_claim(info->pdana.group, info->pdana.num,
			info->pdana.lsb, info->pdana.msb, "PDANA");
	BUG_ON(!conv_dac_sc->pdana);
	conv_dac_sc->pndbg = sysconf_claim(info->pndbg.group, info->pndbg.num,
			info->pndbg.lsb, info->pndbg.msb, "PNDBG");
	BUG_ON(!conv_dac_sc->pndbg);

	/* Get connections */

	BUG_ON(!info->source_bus_id);
	snd_stm_printd(0, "This DAC is attached to PCM player '%s'.\n",
			info->source_bus_id);
	conv_dac_sc->converter = snd_stm_conv_register_converter(
			"Analog Output", &snd_stm_conv_dac_sc_ops, conv_dac_sc,
			&platform_bus_type, info->source_bus_id,
			info->channel_from, info->channel_to, NULL);
	if (!conv_dac_sc->converter) {
		snd_stm_printe("Can't attach to PCM player!\n");
		goto error_attach;
	}

	/* Create ALSA lowlevel device*/

	result = snd_device_new(card, SNDRV_DEV_LOWLEVEL, conv_dac_sc,
			&snd_stm_conv_dac_sc_snd_device_ops);
	if (result < 0) {
		snd_stm_printe("ALSA low level device creation failed!\n");
		goto error_device;
	}

	/* Done now */

	platform_set_drvdata(pdev, conv_dac_sc);

	return 0;

error_device:
error_attach:
	snd_stm_magic_clear(conv_dac_sc);
	kfree(conv_dac_sc);
error_alloc:
	return result;
}
Exemplo n.º 8
0
static int snd_stm_conv_dac_mem_probe(struct platform_device *pdev)
{
	int result = 0;
	struct snd_stm_conv_dac_mem_info *conv_dac_mem_info =
			pdev->dev.platform_data;
	struct snd_stm_conv_dac_mem *conv_dac_mem;
	struct snd_card *card = snd_stm_card_get();

	snd_stm_printd(0, "%s('%s')\n", __func__, dev_name(&pdev->dev));

	BUG_ON(!card);
	BUG_ON(!conv_dac_mem_info);

	conv_dac_mem = kzalloc(sizeof(*conv_dac_mem), GFP_KERNEL);
	if (!conv_dac_mem) {
		snd_stm_printe("Can't allocate memory "
				"for a device description!\n");
		result = -ENOMEM;
		goto error_alloc;
	}
	snd_stm_magic_set(conv_dac_mem);
	conv_dac_mem->dev_name = dev_name(&pdev->dev);

	/* Get resources */

	result = snd_stm_memory_request(pdev, &conv_dac_mem->mem_region,
			&conv_dac_mem->base);
	if (result < 0) {
		snd_stm_printe("Memory region request failed!\n");
		goto error_memory_request;
	}

	/* Get connections */

	BUG_ON(!conv_dac_mem_info->source_bus_id);
	snd_stm_printd(0, "This DAC is attached to PCM player '%s'.\n",
			conv_dac_mem_info->source_bus_id);
	conv_dac_mem->converter = snd_stm_conv_register_converter(
			"Analog Output",
			&snd_stm_conv_dac_mem_ops, conv_dac_mem,
			&platform_bus_type, conv_dac_mem_info->source_bus_id,
			conv_dac_mem_info->channel_from,
			conv_dac_mem_info->channel_to, NULL);
	if (!conv_dac_mem->converter) {
		snd_stm_printe("Can't attach to PCM player!\n");
		goto error_attach;
	}

	/* Create ALSA lowlevel device*/

	result = snd_device_new(card, SNDRV_DEV_LOWLEVEL, conv_dac_mem,
			&snd_stm_conv_dac_mem_snd_device_ops);
	if (result < 0) {
		snd_stm_printe("ALSA low level device creation failed!\n");
		goto error_device;
	}

	/* Done now */

	platform_set_drvdata(pdev, conv_dac_mem);

	return 0;

error_device:
error_attach:
	snd_stm_memory_release(conv_dac_mem->mem_region,
			conv_dac_mem->base);
error_memory_request:
	snd_stm_magic_clear(conv_dac_mem);
	kfree(conv_dac_mem);
error_alloc:
	return result;
}
Exemplo n.º 9
0
static int __init snd_stm_fli75xx_glue_probe(struct platform_device *pdev)
{
	int result = 0;
	struct snd_stm_fli75xx_glue *fli75xx_glue;
	unsigned int value;

	snd_stm_printd(0, "%s('%s')\n", __func__, dev_name(&pdev->dev));

	fli75xx_glue = kzalloc(sizeof(*fli75xx_glue), GFP_KERNEL);
	if (!fli75xx_glue) {
		snd_stm_printe("Can't allocate memory "
				"for a device description!\n");
		result = -ENOMEM;
		goto error_alloc;
	}
	snd_stm_magic_set(fli75xx_glue);

	result = snd_stm_memory_request(pdev, &fli75xx_glue->mem_region,
			&fli75xx_glue->base);
	if (result < 0) {
		snd_stm_printe("Memory region request failed!\n");
		goto error_memory_request;
	}

	/* Clocking configuration:
	 *
	 * clk_256fs_free_run --> SPDIF clock
	 *
	 * clk_256fs_dec_1 -----> MAIN (LS) clock
	 *
	 *                    ,-> ENCODER clock
	 * clk_256fs_dec_2 --<
	 *                    `-> DAC (HP, AUX) clock
	 */
	value = SPDIF_CLK__CLK_256FS_FREE_RUN;
	value |= MAIN_CLK__CLK_256FS_DEC_1;
	value |= ENC_CLK__CLK_256FS_DEC_2;
	value |= DAC_CLK__CLK_256FS_DEC_2;
	value |= SPDIF_CLK_DIV2_EN__DISABLED;
	value |= SPDIF_IN_PAD_HYST_EN__DISABLED;
	writel(value, AUD_CONFIG_REG1(fli75xx_glue->base));

	value = SPDIF__PLAYER;

	switch (cpu_data->type) {
	case CPU_FLI7510:
	case CPU_FLI7560:
		value |= FLI7510_MAIN_I2S__PCM_PLAYER_0;
		value |= FLI7510_SEC_I2S__PCM_PLAYER_1;
		break;
	case CPU_FLI7520:
	case CPU_FLI7530:
	case CPU_FLI7540:
		value |= FLI7520_MAIN_I2S__PCM_PLAYER_0;
		value |= FLI7520_SEC_I2S__PCM_PLAYER_1;
	default:
		BUG();
	}

	value |= SPDIF_PLAYER_EN__ENABLED;
	writel(value, AUD_CONFIG_REG2(fli75xx_glue->base));

	/* Additional procfs info */
	snd_stm_info_register(&fli75xx_glue->proc_entry, "fli75xx_glue",
			snd_stm_fli75xx_glue_dump_registers, fli75xx_glue);

	platform_set_drvdata(pdev, fli75xx_glue);

	return result;

error_memory_request:
	snd_stm_magic_clear(fli75xx_glue);
	kfree(fli75xx_glue);
error_alloc:
	return result;
}
Exemplo n.º 10
0
static int snd_stm_conv_i2sspdif_probe(struct platform_device *pdev)
{
	int result = 0;
	struct snd_stm_conv_i2sspdif_info *conv_i2sspdif_info =
			pdev->dev.platform_data;
	struct snd_stm_conv_i2sspdif *conv_i2sspdif;

	snd_stm_printd(0, "%s('%s')\n", __func__, dev_name(&pdev->dev));

	BUG_ON(!conv_i2sspdif_info);

	conv_i2sspdif = kzalloc(sizeof(*conv_i2sspdif), GFP_KERNEL);
	if (!conv_i2sspdif) {
		snd_stm_printe("Can't allocate memory "
				"for a device description!\n");
		result = -ENOMEM;
		goto error_alloc;
	}
	snd_stm_magic_set(conv_i2sspdif);
	conv_i2sspdif->ver = conv_i2sspdif_info->ver;
	BUG_ON(conv_i2sspdif->ver <= 0);
	conv_i2sspdif->info = conv_i2sspdif_info;
	conv_i2sspdif->device = &pdev->dev;
	spin_lock_init(&conv_i2sspdif->iec958_default_lock);

	/* Get resources */

	result = snd_stm_memory_request(pdev, &conv_i2sspdif->mem_region,
			&conv_i2sspdif->base);
	if (result < 0) {
		snd_stm_printe("Memory region request failed!\n");
		goto error_memory_request;
	}

	/* Get connections */

	BUG_ON(!conv_i2sspdif_info->source_bus_id);
	snd_stm_printd(0, "This I2S-SPDIF converter is attached to PCM player"
			" '%s'.\n",
			conv_i2sspdif_info->source_bus_id);
	conv_i2sspdif->converter = snd_stm_conv_register_converter(
			"HDMI Output",
			&snd_stm_conv_i2sspdif_ops, conv_i2sspdif,
			&platform_bus_type, conv_i2sspdif_info->source_bus_id,
			conv_i2sspdif_info->channel_from,
			conv_i2sspdif_info->channel_to,
			&conv_i2sspdif->index);
	if (!conv_i2sspdif->converter) {
		snd_stm_printe("Can't attach to PCM player!\n");
		result = -EINVAL;
		goto error_attach;
	}

	/* Create ALSA lowlevel device*/

	result = snd_device_new(snd_stm_card_get(), SNDRV_DEV_LOWLEVEL,
			conv_i2sspdif, &snd_stm_conv_i2sspdif_snd_device_ops);
	if (result < 0) {
		snd_stm_printe("ALSA low level device creation failed!\n");
		goto error_device;
	}

	/* Done now */

	platform_set_drvdata(pdev, conv_i2sspdif);

	return result;

error_device:
error_attach:
	snd_stm_memory_release(conv_i2sspdif->mem_region,
			conv_i2sspdif->base);
error_memory_request:
	snd_stm_magic_clear(conv_i2sspdif);
	kfree(conv_i2sspdif);
error_alloc:
	return result;
}
Exemplo n.º 11
0
static int snd_stm_conv_i2sspdif_iec958_set(struct snd_stm_conv_i2sspdif
		*conv_i2sspdif, struct snd_aes_iec958 *iec958)
{
	int i, j, ok;
	unsigned long status[6];

	snd_stm_printd(1, "snd_stm_conv_i2sspdif_iec958_set(conv_i2sspdif=%p"
			", iec958=%p)\n", conv_i2sspdif, iec958);

	BUG_ON(!conv_i2sspdif);
	BUG_ON(!snd_stm_magic_valid(conv_i2sspdif));

	/* I2S to SPDIF converter should be used only for playing
	 * PCM (non compressed) data, so validity bit should be always
	 * zero... (it means "valid linear PCM data") */
	set__AUD_SPDIFPC_VAL__VALIDITY_BITS(conv_i2sspdif, 0);

	/* Well... User data bit... Frankly speaking there is no way
	 * of correctly setting them with a mechanism provided by
	 * converter hardware, so it is better not to do this at all... */
	set__AUD_SPDIFPC_DATA__USER_DATA_BITS(conv_i2sspdif, 0);

	BUG_ON(memcmp(snd_stm_conv_i2sspdif_iec958_zeroed.subcode,
			  iec958->subcode, sizeof(iec958->subcode)) != 0);

	if (conv_i2sspdif->ver < 4) {
		/* Converter hardware by default puts every single bit of
		 * status to separate SPDIF subframe (instead of putting
		 * the same bit to both left and right subframes).
		 * So we have to prepare a "duplicated" version of
		 * status bits... Note that in such way status will be
		 * transmitted twice in every block! This is definitely
		 * out of spec, but fortunately most of receivers pay
		 * attention only to first 36 bits... */

		for (i = 0; i < 6; i++) {
			unsigned long word = 0;

			for (j = 1; j >= 0; j--) {
				unsigned char byte = iec958->status[i * 2 + j];
				int k;

				for (k = 0; k < 8; k++) {
					word |= ((byte & 0x80) != 0);
					if (!(j == 0 && k == 7)) {
						word <<= 2;
						byte <<= 1;
					}
				}
			}

			status[i] = word | (word << 1);
		}

		/* Set converter's channel status registers - they are realised
		 * in such a ridiculous way that write to them is enabled only
		 * in (about) 300us time window after CHL_STS_BUFF_EMPTY bit
		 * is asserted... And this happens once every 2ms (only when
		 * converter is enabled and gets data...) */

		for (i = 0; i < CHA_STA_TRIES; i++) {

			if (get__AUD_SPDIFPC_STA__CHL_STS_BUFF_EMPTY(
							conv_i2sspdif)) {

				ok = snd_stm_conv_i2sspdif_set_cha_sta(
								conv_i2sspdif,
								status);

				if (ok)
					break;
			}
		}
	} else {
		/* Fortunately in some hardware there is a "sane" mode
		 * of channel status registers operation... :-) */

		for (i = 0; i < 6; i++)
			status[i] = iec958->status[i * 4] |
					iec958->status[i * 4 + 1] << 8 |
					iec958->status[i * 4 + 2] << 16 |
					iec958->status[i * 4 + 3] << 24;

		/* Set converter's channel status registers */
		ok = snd_stm_conv_i2sspdif_set_cha_sta(conv_i2sspdif, status);
	}


	if (!ok) {
		snd_stm_printe("WARNING! Failed to set channel status registers"
				" for converter %s! (tried %d times)\n",
			       dev_name(conv_i2sspdif->device), i);
		return -EINVAL;
	}

	snd_stm_printd(1, "Channel status registers set successfully "
			"in %i tries.\n", i);

	/* Set SPDIF player's VUC registers (these are used only
	 * for mute data formatting, and it should never happen ;-) */

	set__AUD_SPDIFPC_SUV__VAL_LEFT(conv_i2sspdif, 0);
	set__AUD_SPDIFPC_SUV__VAL_RIGHT(conv_i2sspdif, 0);

	set__AUD_SPDIFPC_SUV__DATA_LEFT(conv_i2sspdif, 0);
	set__AUD_SPDIFPC_SUV__DATA_RIGHT(conv_i2sspdif, 0);

	/* And this time the problem is that SPDIF player lets
	 * to set only first 36 bits of channel status bits...
	 * Hopefully no one needs more ever ;-) And well - at least
	 * it puts channel status bits to both subframes :-) */
	status[0] = iec958->status[0] | iec958->status[1] << 8 |
		iec958->status[2] << 16 | iec958->status[3] << 24;
	set__AUD_SPDIFPC_CL1__CHANNEL_STATUS(conv_i2sspdif, status[0]);
	set__AUD_SPDIFPC_SUV__CH_STA_LEFT(conv_i2sspdif,
			iec958->status[4] & 0xf);
	set__AUD_SPDIFPC_CR1__CH_STA(conv_i2sspdif, status[0]);
	set__AUD_SPDIFPC_SUV__CH_STA_RIGHT(conv_i2sspdif,
			iec958->status[4] & 0xf);

	return 0;
}
Exemplo n.º 12
0
static int snd_stm_pcm_player_probe(struct platform_device *pdev)
{
	int result = 0;
	struct snd_stm_pcm_player *pcm_player;
	struct snd_card *card = snd_stm_card_get();
	int i;

	snd_stm_printd(0, "%s('%s')\n", __func__, dev_name(&pdev->dev));

	BUG_ON(!card);

	pcm_player = kzalloc(sizeof(*pcm_player), GFP_KERNEL);
	if (!pcm_player) {
		snd_stm_printe("Can't allocate memory "
				"for a device description!\n");
		result = -ENOMEM;
		goto error_alloc;
	}
	snd_stm_magic_set(pcm_player);
	pcm_player->info = pdev->dev.platform_data;
	BUG_ON(!pcm_player->info);
	pcm_player->ver = pcm_player->info->ver;
	BUG_ON(pcm_player->ver <= 0);
	pcm_player->device = &pdev->dev;

	/* Get resources */

	result = snd_stm_memory_request(pdev, &pcm_player->mem_region,
			&pcm_player->base);
	if (result < 0) {
		snd_stm_printe("Memory region request failed!\n");
		goto error_memory_request;
	}
	pcm_player->fifo_phys_address = pcm_player->mem_region->start +
		offset__AUD_PCMOUT_DATA(pcm_player);
	snd_stm_printd(0, "FIFO physical address: 0x%lx.\n",
			pcm_player->fifo_phys_address);

	result = snd_stm_irq_request(pdev, &pcm_player->irq,
			snd_stm_pcm_player_irq_handler, pcm_player);
	if (result < 0) {
		snd_stm_printe("IRQ request failed!\n");
		goto error_irq_request;
	}

	result = snd_stm_fdma_request(pdev, &pcm_player->fdma_channel);
	if (result < 0) {
		snd_stm_printe("FDMA request failed!\n");
		goto error_fdma_request;
	}

	/* FDMA transfer size depends (among others ;-) on FIFO length,
	 * which is:
	 * - 30 cells (120 bytes) in STx7100/9 and STx7200 cut 1.0
	 * - 70 cells (280 bytes) in STx7111 and STx7200 cut 2.0. */

	if (pcm_player->ver < 5)
		pcm_player->fdma_max_transfer_size = 2;
	else if (pcm_player->ver == 5)
		pcm_player->fdma_max_transfer_size = 20;
	else
		pcm_player->fdma_max_transfer_size = 30;

	/* Get player capabilities */

	snd_stm_printd(0, "Player's name is '%s'\n", pcm_player->info->name);

	BUG_ON(pcm_player->info->channels <= 0);
	BUG_ON(pcm_player->info->channels > 10);
	BUG_ON(pcm_player->info->channels % 2 != 0);
	if (pcm_player->ver > 1) {
		static unsigned int channels_2_10[] = { 2, 4, 6, 8, 10 };

		pcm_player->channels_constraint.list = channels_2_10;
		pcm_player->channels_constraint.count =
			pcm_player->info->channels / 2;
	} else {
		/* In STx7100 cut < 3.0 PCM player ignored NUM_CH setting in
		 * AUD_PCMOUT_FMT register (and it was always in 10 channels
		 * mode...) */
		static unsigned int channels_10[] = { 10 };

		pcm_player->channels_constraint.list = channels_10;
		pcm_player->channels_constraint.count = 1;
	}
	pcm_player->channels_constraint.mask = 0;
	for (i = 0; i < pcm_player->channels_constraint.count; i++)
		snd_stm_printd(0, "Player capable of playing %u-channels PCM."
				"\n", pcm_player->channels_constraint.list[i]);

	/* STx7100 has a problem with 16/16 bits FIFO organization,
	 * so we disable the 16 bits samples capability... */
	if (pcm_player->ver <= 2)
		snd_stm_pcm_player_hw.formats &= ~SNDRV_PCM_FMTBIT_S16_LE;

	/* Create ALSA lowlevel device */

	result = snd_device_new(card, SNDRV_DEV_LOWLEVEL, pcm_player,
			&snd_stm_pcm_player_snd_device_ops);
	if (result < 0) {
		snd_stm_printe("ALSA low level device creation failed!\n");
		goto error_device;
	}

	/* Create ALSA PCM device */

	result = snd_pcm_new(card, NULL, pcm_player->info->card_device, 1, 0,
			&pcm_player->pcm);
	if (result < 0) {
		snd_stm_printe("ALSA PCM instance creation failed!\n");
		goto error_pcm;
	}
	pcm_player->pcm->private_data = pcm_player;
	strcpy(pcm_player->pcm->name, pcm_player->info->name);

	snd_pcm_set_ops(pcm_player->pcm, SNDRV_PCM_STREAM_PLAYBACK,
			&snd_stm_pcm_player_pcm_ops);

	/* Initialize buffer */

	pcm_player->buffer = snd_stm_buffer_create(pcm_player->pcm,
			pcm_player->device,
			snd_stm_pcm_player_hw.buffer_bytes_max);
	if (!pcm_player->buffer) {
		snd_stm_printe("Cannot initialize buffer!\n");
		result = -ENOMEM;
		goto error_buffer_init;
	}

	/* Register in converters router */

	pcm_player->conv_source = snd_stm_conv_register_source(
		&platform_bus_type, dev_name(&pdev->dev),
			pcm_player->info->channels,
			card, pcm_player->info->card_device);
	if (!pcm_player->conv_source) {
		snd_stm_printe("Cannot register in converters router!\n");
		result = -ENOMEM;
		goto error_conv_register_source;
	}

	/* Claim the pads */

	if (pcm_player->info->pad_config) {
		pcm_player->pads = stm_pad_claim(pcm_player->info->pad_config,
				dev_name(&pdev->dev));
		if (!pcm_player->pads) {
			snd_stm_printe("Failed to claimed pads for '%s'!\n",
					dev_name(&pdev->dev));
			result = -EBUSY;
			goto error_pad_claim;
		}
	}

	/* Done now */

	platform_set_drvdata(pdev, pcm_player);

	return 0;

error_pad_claim:
	snd_stm_conv_unregister_source(pcm_player->conv_source);
error_conv_register_source:
	snd_stm_buffer_dispose(pcm_player->buffer);
error_buffer_init:
	/* snd_pcm_free() is not available - PCM device will be released
	 * during card release */
error_pcm:
	snd_device_free(card, pcm_player);
error_device:
	snd_stm_fdma_release(pcm_player->fdma_channel);
error_fdma_request:
	snd_stm_irq_release(pcm_player->irq, pcm_player);
error_irq_request:
	snd_stm_memory_release(pcm_player->mem_region, pcm_player->base);
error_memory_request:
	snd_stm_magic_clear(pcm_player);
	kfree(pcm_player);
error_alloc:
	return result;
}
Exemplo n.º 13
0
static int snd_stm_pcm_player_hw_params(struct snd_pcm_substream *substream,
		struct snd_pcm_hw_params *hw_params)
{
	int result;
	struct snd_stm_pcm_player *pcm_player =
			snd_pcm_substream_chip(substream);
	struct snd_pcm_runtime *runtime = substream->runtime;
	int buffer_bytes, frame_bytes, transfer_bytes;
	unsigned int transfer_size;
	struct stm_dma_req_config fdma_req_config = {
		.rw        = REQ_CONFIG_WRITE,
		.opcode    = REQ_CONFIG_OPCODE_4,
		.increment = 0,
		.hold_off  = 0,
		.initiator = pcm_player->info->fdma_initiator,
	};

	snd_stm_printd(1, "snd_stm_pcm_player_hw_params(substream=0x%p,"
			" hw_params=0x%p)\n", substream, hw_params);

	BUG_ON(!pcm_player);
	BUG_ON(!snd_stm_magic_valid(pcm_player));
	BUG_ON(!runtime);

	/* This function may be called many times, so let's be prepared... */
	if (snd_stm_buffer_is_allocated(pcm_player->buffer))
		snd_stm_pcm_player_hw_free(substream);

	/* Allocate buffer */

	buffer_bytes = params_buffer_bytes(hw_params);
	result = snd_stm_buffer_alloc(pcm_player->buffer, substream,
			buffer_bytes);
	if (result != 0) {
		snd_stm_printe("Can't allocate %d bytes buffer for '%s'!\n",
			       buffer_bytes, dev_name(pcm_player->device));
		result = -ENOMEM;
		goto error_buf_alloc;
	}

	/* Set FDMA transfer size (number of opcodes generated
	 * after request line assertion) */

	frame_bytes = snd_pcm_format_physical_width(params_format(hw_params)) *
			params_channels(hw_params) / 8;
	transfer_bytes = snd_stm_pcm_transfer_bytes(frame_bytes,
			pcm_player->fdma_max_transfer_size * 4);
	transfer_size = transfer_bytes / 4;
	snd_stm_printd(1, "FDMA request trigger limit and transfer size set "
			"to %d.\n", transfer_size);

	BUG_ON(buffer_bytes % transfer_bytes != 0);
	BUG_ON(transfer_size > pcm_player->fdma_max_transfer_size);
	fdma_req_config.count = transfer_size;

	BUG_ON(transfer_size != 1 && transfer_size % 2 != 0);
	BUG_ON(transfer_size >
	       mask__AUD_PCMOUT_FMT__DMA_REQ_TRIG_LMT(pcm_player));
	set__AUD_PCMOUT_FMT__DMA_REQ_TRIG_LMT(pcm_player, transfer_size);

	/* Configure FDMA transfer */

	pcm_player->fdma_request = dma_req_config(pcm_player->fdma_channel,
			pcm_player->info->fdma_request_line, &fdma_req_config);
	if (!pcm_player->fdma_request) {
		snd_stm_printe("Can't configure FDMA pacing channel for player"
			       " '%s'!\n", dev_name(pcm_player->device));
		result = -EINVAL;
		goto error_req_config;
	}

	dma_params_init(&pcm_player->fdma_params, MODE_PACED,
			STM_DMA_LIST_CIRC);

	dma_params_DIM_1_x_0(&pcm_player->fdma_params);

	dma_params_req(&pcm_player->fdma_params, pcm_player->fdma_request);

	dma_params_addrs(&pcm_player->fdma_params, runtime->dma_addr,
			pcm_player->fifo_phys_address, buffer_bytes);

	result = dma_compile_list(pcm_player->fdma_channel,
				&pcm_player->fdma_params, GFP_KERNEL);
	if (result < 0) {
		snd_stm_printe("Can't compile FDMA parameters for player"
			       " '%s'!\n", dev_name(pcm_player->device));
		goto error_compile_list;
	}

	return 0;

error_compile_list:
	dma_req_free(pcm_player->fdma_channel,
			pcm_player->fdma_request);
error_req_config:
	snd_stm_buffer_free(pcm_player->buffer);
error_buf_alloc:
	return result;
}

static int snd_stm_pcm_player_prepare(struct snd_pcm_substream *substream)
{
	struct snd_stm_pcm_player *pcm_player =
			snd_pcm_substream_chip(substream);
	struct snd_pcm_runtime *runtime = substream->runtime;
	unsigned int format, lr_pol;
	int oversampling, bits_in_output_frame;
	int result;

	snd_stm_printd(1, "snd_stm_pcm_player_prepare(substream=0x%p)\n",
			substream);

	BUG_ON(!pcm_player);
	BUG_ON(!snd_stm_magic_valid(pcm_player));
	BUG_ON(!runtime);
	BUG_ON(runtime->period_size * runtime->channels >=
	       MAX_SAMPLES_PER_PERIOD);

	/* Configure SPDIF synchronisation */

	/* TODO */

	/* Get format & oversampling value from connected converter */

	if (pcm_player->conv_group) {
		format = snd_stm_conv_get_format(pcm_player->conv_group);
		oversampling = snd_stm_conv_get_oversampling(
				pcm_player->conv_group);
		if (oversampling == 0)
			oversampling = DEFAULT_OVERSAMPLING;
	} else {
		format = DEFAULT_FORMAT;
		oversampling = DEFAULT_OVERSAMPLING;
	}

	snd_stm_printd(1, "Player %s: sampling frequency %d, oversampling %d\n",
			dev_name(pcm_player->device), runtime->rate,
			oversampling);

	BUG_ON(oversampling < 0);

	/* For 32 bits subframe oversampling must be a multiple of 128,
	 * for 16 bits - of 64 */
	BUG_ON((format & SND_STM_FORMAT__SUBFRAME_32_BITS) &&
		(oversampling % 128 != 0));
	BUG_ON(!(format & SND_STM_FORMAT__SUBFRAME_16_BITS) &&
		(oversampling % 64 != 0));

	/* Set up frequency synthesizer */

	result = clk_enable(pcm_player->clock);
	if (result != 0) {
		snd_stm_printe("Can't enable clock for player '%s'!\n",
				dev_name(pcm_player->device));
		return result;
	}

	result = clk_set_rate(pcm_player->clock,
				runtime->rate * oversampling);
	if (result != 0) {
		snd_stm_printe("Can't configure clock for player '%s'!\n",
				dev_name(pcm_player->device));
		clk_disable(pcm_player->clock);
		return result;
	}

	/* Set up player hardware */

	snd_stm_printd(1, "Player %s format configuration:\n",
			dev_name(pcm_player->device));

	/* Number of bits per subframe (which is one channel sample)
	 * on output - it determines serial clock frequency, which is
	 * 64 times sampling rate for 32 bits subframe (2 channels 32
	 * bits each means 64 bits per frame) and 32 times sampling
	 * rate for 16 bits subframe
	 * (you know why, don't you? :-) */

	switch (format & SND_STM_FORMAT__SUBFRAME_MASK) {
	case SND_STM_FORMAT__SUBFRAME_32_BITS:
		snd_stm_printd(1, "- 32 bits per subframe\n");
		set__AUD_PCMOUT_FMT__NBIT__32_BITS(pcm_player);
		if (pcm_player->ver > 5)
			set__AUD_PCMOUT_FMT__DATA_SIZE__32_BITS(pcm_player);
		else
			set__AUD_PCMOUT_FMT__DATA_SIZE__24_BITS(pcm_player);
		bits_in_output_frame = 64; /* frame = 2 * subframe */
		break;
	case SND_STM_FORMAT__SUBFRAME_16_BITS:
		snd_stm_printd(1, "- 16 bits per subframe\n");
		set__AUD_PCMOUT_FMT__NBIT__16_BITS(pcm_player);
		set__AUD_PCMOUT_FMT__DATA_SIZE__16_BITS(pcm_player);
		bits_in_output_frame = 32; /* frame = 2 * subframe */
		break;
	default:
		snd_BUG();
		return -EINVAL;
	}

	/* Serial audio interface format - for detailed explanation
	 * see ie.:
	 * http://www.cirrus.com/en/pubs/appNote/AN282REV1.pdf */

	set__AUD_PCMOUT_FMT__ORDER__MSB_FIRST(pcm_player);

	/* Value FALLING of SCLK_EDGE bit in AUD_PCMOUT_FMT register that
	 * actually means "data clocking (changing) on the falling edge"
	 * (and we usually want this...) - STx7100 and cuts < 3.0 of
	 * STx7109 have this bit inverted comparing to what their
	 * datasheets claim... (specs say 1) */

	set__AUD_PCMOUT_FMT__SCLK_EDGE__FALLING(pcm_player);

	switch (format & SND_STM_FORMAT__MASK) {
	case SND_STM_FORMAT__I2S:
		snd_stm_printd(1, "- I2S\n");
		set__AUD_PCMOUT_FMT__ALIGN__LEFT(pcm_player);
		set__AUD_PCMOUT_FMT__PADDING__1_CYCLE_DELAY(pcm_player);
		lr_pol = value__AUD_PCMOUT_FMT__LR_POL__LEFT_LOW(pcm_player);
		break;
	case SND_STM_FORMAT__LEFT_JUSTIFIED:
		snd_stm_printd(1, "- left justified\n");
		set__AUD_PCMOUT_FMT__ALIGN__LEFT(pcm_player);
		set__AUD_PCMOUT_FMT__PADDING__NO_DELAY(pcm_player);
		lr_pol = value__AUD_PCMOUT_FMT__LR_POL__LEFT_HIGH(pcm_player);
		break;
	case SND_STM_FORMAT__RIGHT_JUSTIFIED:
		snd_stm_printd(1, "- right justified\n");
		set__AUD_PCMOUT_FMT__ALIGN__RIGHT(pcm_player);
		set__AUD_PCMOUT_FMT__PADDING__NO_DELAY(pcm_player);
		lr_pol = value__AUD_PCMOUT_FMT__LR_POL__LEFT_HIGH(pcm_player);
		break;
	default:
		snd_BUG();
		return -EINVAL;
	}

	/* Configure PCM player frequency divider
	 *
	 *             Fdacclk             Fs * oversampling
	 * divider = ----------- = ------------------------------- =
	 *            2 * Fsclk     2 * Fs * bits_in_output_frame
	 *
	 *                  oversampling
	 *         = --------------------------
	 *            2 * bits_in_output_frame
	 * where:
	 *   - Fdacclk - frequency of DAC clock signal, known also as PCMCLK,
	 *               MCLK (master clock), "system clock" etc.
	 *   - Fsclk - frequency of SCLK (serial clock) aka BICK (bit clock)
	 *   - Fs - sampling rate (frequency)
	 *   - bits_in_output_frame - number of bits in output signal _frame_
	 *                (32 or 64, depending on NBIT field of FMT register)
	 */

	set__AUD_PCMOUT_CTRL__CLK_DIV(pcm_player,
			oversampling / (2 * bits_in_output_frame));

	/* Configure data memory format & NSAMPLE interrupt */

	switch (runtime->format) {
	case SNDRV_PCM_FORMAT_S16_LE:
		/* One data word contains two samples */
		set__AUD_PCMOUT_CTRL__MEM_FMT__16_BITS_16_BITS(pcm_player);

		/* Workaround for a problem with L/R channels swap in case of
		 * 16/16 memory model: PCM player expects left channel data in
		 * word's upper two bytes, but due to little endianess
		 * character of our memory there is right channel data there;
		 * the workaround is to invert L/R signal, however it is
		 * cheating, because in such case channel phases are shifted
		 * by one sample...
		 * (ask me for more details if above is not clear ;-)
		 * TODO this somehow better... */
		set__AUD_PCMOUT_FMT__LR_POL(pcm_player, !lr_pol);

		/* One word of data is two samples (two channels...) */
		set__AUD_PCMOUT_CTRL__NSAMPLE(pcm_player,
				runtime->period_size * runtime->channels / 2);
		break;

	case SNDRV_PCM_FORMAT_S32_LE:
		/* Actually "16 bits/0 bits" means "32/28/24/20/18/16 bits
		 * on the left than zeros (if less than 32 bites)"... ;-) */
		set__AUD_PCMOUT_CTRL__MEM_FMT__16_BITS_0_BITS(pcm_player);

		/* In x/0 bits memory mode there is no problem with
		 * L/R polarity */
		set__AUD_PCMOUT_FMT__LR_POL(pcm_player, lr_pol);

		/* One word of data is one sample, so period size
		 * times channels */
		set__AUD_PCMOUT_CTRL__NSAMPLE(pcm_player,
				runtime->period_size * runtime->channels);
		break;

	default:
		snd_BUG();
		return -EINVAL;
	}

	/* Number of channels... */

	BUG_ON(runtime->channels % 2 != 0);
	BUG_ON(runtime->channels < 2);
	BUG_ON(runtime->channels > 10);

	set__AUD_PCMOUT_FMT__NUM_CH(pcm_player, runtime->channels / 2);

	return 0;
}

static int snd_stm_pcm_player_start(struct snd_pcm_substream *substream)
{
	int result;
	struct snd_stm_pcm_player *pcm_player =
			snd_pcm_substream_chip(substream);

	snd_stm_printd(1, "snd_stm_pcm_player_start(substream=0x%p)\n",
			substream);

	BUG_ON(!pcm_player);
	BUG_ON(!snd_stm_magic_valid(pcm_player));

	/* Un-reset PCM player */

	set__AUD_PCMOUT_RST__SRSTP__RUNNING(pcm_player);

	/* Launch FDMA transfer */

	result = dma_xfer_list(pcm_player->fdma_channel,
			&pcm_player->fdma_params);
	if (result != 0) {
		snd_stm_printe("Can't launch FDMA transfer for player '%s'!\n",
			       dev_name(pcm_player->device));
		clk_disable(pcm_player->clock);
		return -EINVAL;
	}
	while (dma_get_status(pcm_player->fdma_channel) !=
			DMA_CHANNEL_STATUS_RUNNING)
		udelay(5);

	/* Enable player interrupts (and clear possible stalled ones) */

	enable_irq(pcm_player->irq);
	set__AUD_PCMOUT_ITS_CLR__NSAMPLE__CLEAR(pcm_player);
	set__AUD_PCMOUT_IT_EN_SET__NSAMPLE__SET(pcm_player);
	set__AUD_PCMOUT_ITS_CLR__UNF__CLEAR(pcm_player);
	set__AUD_PCMOUT_IT_EN_SET__UNF__SET(pcm_player);

	/* Launch the player */

	set__AUD_PCMOUT_CTRL__MODE__PCM(pcm_player);

	/* Wake up & unmute DAC */

	if (pcm_player->conv_group) {
		snd_stm_conv_enable(pcm_player->conv_group,
				0, substream->runtime->channels - 1);
		snd_stm_conv_unmute(pcm_player->conv_group);
	}

	return 0;
}
Exemplo n.º 14
0
static int snd_stm_pcm_player_open(struct snd_pcm_substream *substream)
{
	int result;
	struct snd_stm_pcm_player *pcm_player =
			snd_pcm_substream_chip(substream);
	struct snd_pcm_runtime *runtime = substream->runtime;

	snd_stm_printd(1, "snd_stm_pcm_player_open(substream=0x%p)\n",
			substream);

	BUG_ON(!pcm_player);
	BUG_ON(!snd_stm_magic_valid(pcm_player));
	BUG_ON(!runtime);

	snd_pcm_set_sync(substream);  /* TODO: ??? */

	/* Get attached converters handle */

	pcm_player->conv_group =
			snd_stm_conv_request_group(pcm_player->conv_source);
	if (pcm_player->conv_group)
		snd_stm_printd(1, "'%s' is attached to '%s' converter(s)...\n",
				dev_name(pcm_player->device),
				snd_stm_conv_get_name(pcm_player->conv_group));
	else
		snd_stm_printd(1, "No converter attached to '%s'!\n",
				dev_name(pcm_player->device));

	/* Set up constraints & pass hardware capabilities info to ALSA */

	result = snd_pcm_hw_constraint_list(runtime, 0,
			SNDRV_PCM_HW_PARAM_CHANNELS,
			&pcm_player->channels_constraint);
	if (result < 0) {
		snd_stm_printe("Can't set channels constraint!\n");
		return result;
	}

	/* It is better when buffer size is an integer multiple of period
	 * size... Such thing will ensure this :-O */
	result = snd_pcm_hw_constraint_integer(runtime,
			SNDRV_PCM_HW_PARAM_PERIODS);
	if (result < 0) {
		snd_stm_printe("Can't set periods constraint!\n");
		return result;
	}

	/* Make the period (so buffer as well) length (in bytes) a multiply
	 * of a FDMA transfer bytes (which varies depending on channels
	 * number and sample bytes) */
	result = snd_stm_pcm_hw_constraint_transfer_bytes(runtime,
			pcm_player->fdma_max_transfer_size * 4);
	if (result < 0) {
		snd_stm_printe("Can't set buffer bytes constraint!\n");
		return result;
	}

	runtime->hw = snd_stm_pcm_player_hw;

	/* Interrupt handler will need the substream pointer... */
	pcm_player->substream = substream;

	return 0;
}