Skip to content

Commit 679de7b

Browse files
jernejskbroonie
authored andcommitted
ASoC: sunxi: sun4i-spdif: Implement IEC958 control
SPDIF core is capable of sending custom status. Implement IEC958 control handling. Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com> Link: https://lore.kernel.org/r/20211117194458.2249643-1-jernej.skrabec@gmail.com Signed-off-by: Mark Brown <broonie@kernel.org>
1 parent 425c5fc commit 679de7b

1 file changed

Lines changed: 115 additions & 0 deletions

File tree

sound/soc/sunxi/sun4i-spdif.c

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
#include <linux/platform_device.h>
2222
#include <linux/pm_runtime.h>
2323
#include <linux/reset.h>
24+
#include <linux/spinlock.h>
25+
#include <sound/asoundef.h>
2426
#include <sound/dmaengine_pcm.h>
2527
#include <sound/pcm_params.h>
2628
#include <sound/soc.h>
@@ -186,6 +188,7 @@ struct sun4i_spdif_dev {
186188
struct regmap *regmap;
187189
struct snd_dmaengine_dai_dma_data dma_params_tx;
188190
const struct sun4i_spdif_quirks *quirks;
191+
spinlock_t lock;
189192
};
190193

191194
static void sun4i_spdif_configure(struct sun4i_spdif_dev *host)
@@ -385,11 +388,122 @@ static int sun4i_spdif_trigger(struct snd_pcm_substream *substream, int cmd,
385388
return ret;
386389
}
387390

391+
static int sun4i_spdif_info(struct snd_kcontrol *kcontrol,
392+
struct snd_ctl_elem_info *uinfo)
393+
{
394+
uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
395+
uinfo->count = 1;
396+
397+
return 0;
398+
}
399+
400+
static int sun4i_spdif_get_status_mask(struct snd_kcontrol *kcontrol,
401+
struct snd_ctl_elem_value *ucontrol)
402+
{
403+
u8 *status = ucontrol->value.iec958.status;
404+
405+
status[0] = 0xff;
406+
status[1] = 0xff;
407+
status[2] = 0xff;
408+
status[3] = 0xff;
409+
status[4] = 0xff;
410+
status[5] = 0x03;
411+
412+
return 0;
413+
}
414+
415+
static int sun4i_spdif_get_status(struct snd_kcontrol *kcontrol,
416+
struct snd_ctl_elem_value *ucontrol)
417+
{
418+
struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
419+
struct sun4i_spdif_dev *host = snd_soc_dai_get_drvdata(cpu_dai);
420+
u8 *status = ucontrol->value.iec958.status;
421+
unsigned long flags;
422+
unsigned int reg;
423+
424+
spin_lock_irqsave(&host->lock, flags);
425+
426+
regmap_read(host->regmap, SUN4I_SPDIF_TXCHSTA0, &reg);
427+
428+
status[0] = reg & 0xff;
429+
status[1] = (reg >> 8) & 0xff;
430+
status[2] = (reg >> 16) & 0xff;
431+
status[3] = (reg >> 24) & 0xff;
432+
433+
regmap_read(host->regmap, SUN4I_SPDIF_TXCHSTA1, &reg);
434+
435+
status[4] = reg & 0xff;
436+
status[5] = (reg >> 8) & 0x3;
437+
438+
spin_unlock_irqrestore(&host->lock, flags);
439+
440+
return 0;
441+
}
442+
443+
static int sun4i_spdif_set_status(struct snd_kcontrol *kcontrol,
444+
struct snd_ctl_elem_value *ucontrol)
445+
{
446+
struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
447+
struct sun4i_spdif_dev *host = snd_soc_dai_get_drvdata(cpu_dai);
448+
u8 *status = ucontrol->value.iec958.status;
449+
unsigned long flags;
450+
unsigned int reg;
451+
bool chg0, chg1;
452+
453+
spin_lock_irqsave(&host->lock, flags);
454+
455+
reg = (u32)status[3] << 24;
456+
reg |= (u32)status[2] << 16;
457+
reg |= (u32)status[1] << 8;
458+
reg |= (u32)status[0];
459+
460+
regmap_update_bits_check(host->regmap, SUN4I_SPDIF_TXCHSTA0,
461+
GENMASK(31,0), reg, &chg0);
462+
463+
reg = (u32)status[5] << 8;
464+
reg |= (u32)status[4];
465+
466+
regmap_update_bits_check(host->regmap, SUN4I_SPDIF_TXCHSTA1,
467+
GENMASK(9,0), reg, &chg1);
468+
469+
reg = SUN4I_SPDIF_TXCFG_CHSTMODE;
470+
if (status[0] & IEC958_AES0_NONAUDIO)
471+
reg |= SUN4I_SPDIF_TXCFG_NONAUDIO;
472+
473+
regmap_update_bits(host->regmap, SUN4I_SPDIF_TXCFG,
474+
SUN4I_SPDIF_TXCFG_CHSTMODE |
475+
SUN4I_SPDIF_TXCFG_NONAUDIO, reg);
476+
477+
spin_unlock_irqrestore(&host->lock, flags);
478+
479+
return chg0 || chg1;
480+
}
481+
482+
static struct snd_kcontrol_new sun4i_spdif_controls[] = {
483+
{
484+
.access = SNDRV_CTL_ELEM_ACCESS_READ,
485+
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
486+
.name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, MASK),
487+
.info = sun4i_spdif_info,
488+
.get = sun4i_spdif_get_status_mask
489+
},
490+
{
491+
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
492+
.name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
493+
.info = sun4i_spdif_info,
494+
.get = sun4i_spdif_get_status,
495+
.put = sun4i_spdif_set_status
496+
}
497+
};
498+
388499
static int sun4i_spdif_soc_dai_probe(struct snd_soc_dai *dai)
389500
{
390501
struct sun4i_spdif_dev *host = snd_soc_dai_get_drvdata(dai);
391502

392503
snd_soc_dai_init_dma_data(dai, &host->dma_params_tx, NULL);
504+
snd_soc_add_dai_controls(dai, sun4i_spdif_controls,
505+
ARRAY_SIZE(sun4i_spdif_controls));
506+
393507
return 0;
394508
}
395509

@@ -512,6 +626,7 @@ static int sun4i_spdif_probe(struct platform_device *pdev)
512626
return -ENOMEM;
513627

514628
host->pdev = pdev;
629+
spin_lock_init(&host->lock);
515630

516631
/* Initialize this copy of the CPU DAI driver structure */
517632
memcpy(&host->cpu_dai_drv, &sun4i_spdif_dai, sizeof(sun4i_spdif_dai));

0 commit comments

Comments
 (0)