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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }