Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   1) // SPDX-License-Identifier: GPL-2.0+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   2) //
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   3) // siu_dai.c - ALSA SoC driver for Renesas SH7343, SH7722 SIU peripheral.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   4) //
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   5) // Copyright (C) 2009-2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   6) // Copyright (C) 2006 Carlos Munoz <carlos@kenati.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   7) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   8) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   9) #include <linux/firmware.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  10) #include <linux/pm_runtime.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  11) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  12) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  13) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  14) #include <asm/clock.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  15) #include <asm/siu.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  16) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  17) #include <sound/control.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  18) #include <sound/soc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  19) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  20) #include "siu.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  21) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  22) /* Board specifics */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  23) #if defined(CONFIG_CPU_SUBTYPE_SH7722)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  24) # define SIU_MAX_VOLUME		0x1000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  25) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  26) # define SIU_MAX_VOLUME		0x7fff
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  27) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  28) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  29) #define PRAM_SIZE	0x2000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  30) #define XRAM_SIZE	0x800
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  31) #define YRAM_SIZE	0x800
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  32) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  33) #define XRAM_OFFSET	0x4000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  34) #define YRAM_OFFSET	0x6000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  35) #define REG_OFFSET	0xc000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  36) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  37) #define PLAYBACK_ENABLED	1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  38) #define CAPTURE_ENABLED		2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  39) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  40) #define VOLUME_CAPTURE		0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  41) #define VOLUME_PLAYBACK		1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  42) #define DFLT_VOLUME_LEVEL	0x08000800
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  43) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  44) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  45)  * SPDIF is only available on port A and on some SIU implementations it is only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  46)  * available for input. Due to the lack of hardware to test it, SPDIF is left
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  47)  * disabled in this driver version
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  48)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  49) struct format_flag {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  50) 	u32	i2s;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  51) 	u32	pcm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  52) 	u32	spdif;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  53) 	u32	mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  54) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  55) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  56) struct port_flag {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  57) 	struct format_flag	playback;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  58) 	struct format_flag	capture;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  59) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  60) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  61) struct siu_info *siu_i2s_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  62) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  63) static struct port_flag siu_flags[SIU_PORT_NUM] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  64) 	[SIU_PORT_A] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  65) 		.playback = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  66) 			.i2s	= 0x50000000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  67) 			.pcm	= 0x40000000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  68) 			.spdif	= 0x80000000,	/* not on all SIU versions */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  69) 			.mask	= 0xd0000000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  70) 		},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  71) 		.capture = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  72) 			.i2s	= 0x05000000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  73) 			.pcm	= 0x04000000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  74) 			.spdif	= 0x08000000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  75) 			.mask	= 0x0d000000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  76) 		},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  77) 	},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  78) 	[SIU_PORT_B] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  79) 		.playback = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  80) 			.i2s	= 0x00500000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  81) 			.pcm	= 0x00400000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  82) 			.spdif	= 0,		/* impossible - turn off */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  83) 			.mask	= 0x00500000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  84) 		},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  85) 		.capture = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  86) 			.i2s	= 0x00050000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  87) 			.pcm	= 0x00040000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  88) 			.spdif	= 0,		/* impossible - turn off */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  89) 			.mask	= 0x00050000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  90) 		},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  91) 	},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  92) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  93) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  94) static void siu_dai_start(struct siu_port *port_info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  95) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  96) 	struct siu_info *info = siu_i2s_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  97) 	u32 __iomem *base = info->reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  98) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  99) 	dev_dbg(port_info->pcm->card->dev, "%s\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) 	/* Issue software reset to siu */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) 	siu_write32(base + SIU_SRCTL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) 	/* Wait for the reset to take effect */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) 	udelay(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) 	port_info->stfifo = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) 	port_info->trdat = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) 	/* portA, portB, SIU operate */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) 	siu_write32(base + SIU_SRCTL, 0x301);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) 	/* portA=256fs, portB=256fs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) 	siu_write32(base + SIU_CKCTL, 0x40400000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) 	/* portA's BRG does not divide SIUCKA */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) 	siu_write32(base + SIU_BRGASEL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) 	siu_write32(base + SIU_BRRA, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) 	/* portB's BRG divides SIUCKB by half */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) 	siu_write32(base + SIU_BRGBSEL, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) 	siu_write32(base + SIU_BRRB, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) 	siu_write32(base + SIU_IFCTL, 0x44440000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) 	/* portA: 32 bit/fs, master; portB: 32 bit/fs, master */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) 	siu_write32(base + SIU_SFORM, 0x0c0c0000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) 	/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) 	 * Volume levels: looks like the DSP firmware implements volume controls
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) 	 * differently from what's described in the datasheet
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) 	siu_write32(base + SIU_SBDVCA, port_info->playback.volume);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) 	siu_write32(base + SIU_SBDVCB, port_info->capture.volume);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) static void siu_dai_stop(struct siu_port *port_info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) 	struct siu_info *info = siu_i2s_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) 	u32 __iomem *base = info->reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) 	/* SIU software reset */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) 	siu_write32(base + SIU_SRCTL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) static void siu_dai_spbAselect(struct siu_port *port_info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) 	struct siu_info *info = siu_i2s_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) 	struct siu_firmware *fw = &info->fw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) 	u32 *ydef = fw->yram0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) 	u32 idx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) 	/* path A use */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) 	if (!info->port_id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) 		idx = 1;		/* portA */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) 	else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) 		idx = 2;		/* portB */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) 	ydef[0] = (fw->spbpar[idx].ab1a << 16) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) 		(fw->spbpar[idx].ab0a << 8) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) 		(fw->spbpar[idx].dir << 7) | 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) 	ydef[1] = fw->yram0[1];	/* 0x03000300 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) 	ydef[2] = (16 / 2) << 24;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) 	ydef[3] = fw->yram0[3];	/* 0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) 	ydef[4] = fw->yram0[4];	/* 0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) 	ydef[7] = fw->spbpar[idx].event;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) 	port_info->stfifo |= fw->spbpar[idx].stfifo;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) 	port_info->trdat |= fw->spbpar[idx].trdat;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) static void siu_dai_spbBselect(struct siu_port *port_info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) 	struct siu_info *info = siu_i2s_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) 	struct siu_firmware *fw = &info->fw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) 	u32 *ydef = fw->yram0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) 	u32 idx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) 	/* path B use */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) 	if (!info->port_id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) 		idx = 7;		/* portA */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) 	else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) 		idx = 8;		/* portB */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) 	ydef[5] = (fw->spbpar[idx].ab1a << 16) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) 		(fw->spbpar[idx].ab0a << 8) | 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) 	ydef[6] = fw->spbpar[idx].event;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) 	port_info->stfifo |= fw->spbpar[idx].stfifo;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) 	port_info->trdat |= fw->spbpar[idx].trdat;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) static void siu_dai_open(struct siu_stream *siu_stream)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) 	struct siu_info *info = siu_i2s_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) 	u32 __iomem *base = info->reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) 	u32 srctl, ifctl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) 	srctl = siu_read32(base + SIU_SRCTL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) 	ifctl = siu_read32(base + SIU_IFCTL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) 	switch (info->port_id) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) 	case SIU_PORT_A:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) 		/* portA operates */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) 		srctl |= 0x200;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) 		ifctl &= ~0xc2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) 	case SIU_PORT_B:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) 		/* portB operates */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) 		srctl |= 0x100;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) 		ifctl &= ~0x31;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) 	siu_write32(base + SIU_SRCTL, srctl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) 	/* Unmute and configure portA */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) 	siu_write32(base + SIU_IFCTL, ifctl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219)  * At the moment only fixed Left-upper, Left-lower, Right-upper, Right-lower
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220)  * packing is supported
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) static void siu_dai_pcmdatapack(struct siu_stream *siu_stream)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) 	struct siu_info *info = siu_i2s_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) 	u32 __iomem *base = info->reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) 	u32 dpak;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) 	dpak = siu_read32(base + SIU_DPAK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) 	switch (info->port_id) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) 	case SIU_PORT_A:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) 		dpak &= ~0xc0000000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) 	case SIU_PORT_B:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) 		dpak &= ~0x00c00000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) 	siu_write32(base + SIU_DPAK, dpak);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) static int siu_dai_spbstart(struct siu_port *port_info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) 	struct siu_info *info = siu_i2s_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) 	u32 __iomem *base = info->reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) 	struct siu_firmware *fw = &info->fw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) 	u32 *ydef = fw->yram0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) 	int cnt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) 	u32 __iomem *add;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) 	u32 *ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) 	/* Load SPB Program in PRAM */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) 	ptr = fw->pram0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) 	add = info->pram;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) 	for (cnt = 0; cnt < PRAM0_SIZE; cnt++, add++, ptr++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) 		siu_write32(add, *ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) 	ptr = fw->pram1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) 	add = info->pram + (0x0100 / sizeof(u32));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) 	for (cnt = 0; cnt < PRAM1_SIZE; cnt++, add++, ptr++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) 		siu_write32(add, *ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) 	/* XRAM initialization */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) 	add = info->xram;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) 	for (cnt = 0; cnt < XRAM0_SIZE + XRAM1_SIZE + XRAM2_SIZE; cnt++, add++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) 		siu_write32(add, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) 	/* YRAM variable area initialization */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) 	add = info->yram;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) 	for (cnt = 0; cnt < YRAM_DEF_SIZE; cnt++, add++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) 		siu_write32(add, ydef[cnt]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) 	/* YRAM FIR coefficient area initialization */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) 	add = info->yram + (0x0200 / sizeof(u32));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) 	for (cnt = 0; cnt < YRAM_FIR_SIZE; cnt++, add++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) 		siu_write32(add, fw->yram_fir_coeff[cnt]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) 	/* YRAM IIR coefficient area initialization */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) 	add = info->yram + (0x0600 / sizeof(u32));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) 	for (cnt = 0; cnt < YRAM_IIR_SIZE; cnt++, add++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) 		siu_write32(add, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) 	siu_write32(base + SIU_TRDAT, port_info->trdat);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) 	port_info->trdat = 0x0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) 	/* SPB start condition: software */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) 	siu_write32(base + SIU_SBACTIV, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) 	/* Start SPB */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) 	siu_write32(base + SIU_SBCTL, 0xc0000000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) 	/* Wait for program to halt */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) 	cnt = 0x10000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) 	while (--cnt && siu_read32(base + SIU_SBCTL) != 0x80000000)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) 		cpu_relax();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) 	if (!cnt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) 		return -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) 	/* SPB program start address setting */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) 	siu_write32(base + SIU_SBPSET, 0x00400000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) 	/* SPB hardware start(FIFOCTL source) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) 	siu_write32(base + SIU_SBACTIV, 0xc0000000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) static void siu_dai_spbstop(struct siu_port *port_info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) 	struct siu_info *info = siu_i2s_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) 	u32 __iomem *base = info->reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) 	siu_write32(base + SIU_SBACTIV, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) 	/* SPB stop */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) 	siu_write32(base + SIU_SBCTL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) 	port_info->stfifo = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) /*		API functions		*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) /* Playback and capture hardware properties are identical */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) static const struct snd_pcm_hardware siu_dai_pcm_hw = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) 	.info			= SNDRV_PCM_INFO_INTERLEAVED,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) 	.formats		= SNDRV_PCM_FMTBIT_S16,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) 	.rates			= SNDRV_PCM_RATE_8000_48000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) 	.rate_min		= 8000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) 	.rate_max		= 48000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) 	.channels_min		= 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) 	.channels_max		= 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) 	.buffer_bytes_max	= SIU_BUFFER_BYTES_MAX,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) 	.period_bytes_min	= SIU_PERIOD_BYTES_MIN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) 	.period_bytes_max	= SIU_PERIOD_BYTES_MAX,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) 	.periods_min		= SIU_PERIODS_MIN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) 	.periods_max		= SIU_PERIODS_MAX,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) static int siu_dai_info_volume(struct snd_kcontrol *kctrl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) 			       struct snd_ctl_elem_info *uinfo)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) 	struct siu_port *port_info = snd_kcontrol_chip(kctrl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) 	dev_dbg(port_info->pcm->card->dev, "%s\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) 	uinfo->count = 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) 	uinfo->value.integer.min = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) 	uinfo->value.integer.max = SIU_MAX_VOLUME;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) static int siu_dai_get_volume(struct snd_kcontrol *kctrl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) 			      struct snd_ctl_elem_value *ucontrol)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) 	struct siu_port *port_info = snd_kcontrol_chip(kctrl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) 	struct device *dev = port_info->pcm->card->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) 	u32 vol;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) 	dev_dbg(dev, "%s\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) 	switch (kctrl->private_value) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) 	case VOLUME_PLAYBACK:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) 		/* Playback is always on port 0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) 		vol = port_info->playback.volume;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) 		ucontrol->value.integer.value[0] = vol & 0xffff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) 		ucontrol->value.integer.value[1] = vol >> 16 & 0xffff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) 	case VOLUME_CAPTURE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) 		/* Capture is always on port 1 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) 		vol = port_info->capture.volume;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) 		ucontrol->value.integer.value[0] = vol & 0xffff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) 		ucontrol->value.integer.value[1] = vol >> 16 & 0xffff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) 	default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) 		dev_err(dev, "%s() invalid private_value=%ld\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) 			__func__, kctrl->private_value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) static int siu_dai_put_volume(struct snd_kcontrol *kctrl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) 			      struct snd_ctl_elem_value *ucontrol)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) 	struct siu_port *port_info = snd_kcontrol_chip(kctrl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) 	struct device *dev = port_info->pcm->card->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) 	struct siu_info *info = siu_i2s_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) 	u32 __iomem *base = info->reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) 	u32 new_vol;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) 	u32 cur_vol;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) 	dev_dbg(dev, "%s\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) 	if (ucontrol->value.integer.value[0] < 0 ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) 	    ucontrol->value.integer.value[0] > SIU_MAX_VOLUME ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) 	    ucontrol->value.integer.value[1] < 0 ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) 	    ucontrol->value.integer.value[1] > SIU_MAX_VOLUME)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) 	new_vol = ucontrol->value.integer.value[0] |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) 		ucontrol->value.integer.value[1] << 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) 	/* See comment above - DSP firmware implementation */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) 	switch (kctrl->private_value) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) 	case VOLUME_PLAYBACK:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) 		/* Playback is always on port 0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) 		cur_vol = port_info->playback.volume;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) 		siu_write32(base + SIU_SBDVCA, new_vol);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) 		port_info->playback.volume = new_vol;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) 	case VOLUME_CAPTURE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) 		/* Capture is always on port 1 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) 		cur_vol = port_info->capture.volume;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) 		siu_write32(base + SIU_SBDVCB, new_vol);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) 		port_info->capture.volume = new_vol;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) 	default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) 		dev_err(dev, "%s() invalid private_value=%ld\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) 			__func__, kctrl->private_value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) 	if (cur_vol != new_vol)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) 		return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) static const struct snd_kcontrol_new playback_controls = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) 	.iface		= SNDRV_CTL_ELEM_IFACE_MIXER,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) 	.name		= "PCM Playback Volume",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) 	.index		= 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) 	.info		= siu_dai_info_volume,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) 	.get		= siu_dai_get_volume,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) 	.put		= siu_dai_put_volume,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) 	.private_value	= VOLUME_PLAYBACK,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) static const struct snd_kcontrol_new capture_controls = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) 	.iface		= SNDRV_CTL_ELEM_IFACE_MIXER,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) 	.name		= "PCM Capture Volume",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) 	.index		= 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) 	.info		= siu_dai_info_volume,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) 	.get		= siu_dai_get_volume,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) 	.put		= siu_dai_put_volume,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) 	.private_value	= VOLUME_CAPTURE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) int siu_init_port(int port, struct siu_port **port_info, struct snd_card *card)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) 	struct device *dev = card->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) 	struct snd_kcontrol *kctrl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) 	int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) 	*port_info = kzalloc(sizeof(**port_info), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) 	if (!*port_info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) 		return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) 	dev_dbg(dev, "%s: port #%d@%p\n", __func__, port, *port_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) 	(*port_info)->playback.volume = DFLT_VOLUME_LEVEL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) 	(*port_info)->capture.volume = DFLT_VOLUME_LEVEL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) 	/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) 	 * Add mixer support. The SPB is used to change the volume. Both
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) 	 * ports use the same SPB. Therefore, we only register one
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) 	 * control instance since it will be used by both channels.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) 	 * In error case we continue without controls.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) 	kctrl = snd_ctl_new1(&playback_controls, *port_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) 	ret = snd_ctl_add(card, kctrl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) 	if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) 		dev_err(dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) 			"failed to add playback controls %p port=%d err=%d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) 			kctrl, port, ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) 	kctrl = snd_ctl_new1(&capture_controls, *port_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) 	ret = snd_ctl_add(card, kctrl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) 	if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) 		dev_err(dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) 			"failed to add capture controls %p port=%d err=%d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) 			kctrl, port, ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) void siu_free_port(struct siu_port *port_info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) 	kfree(port_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) static int siu_dai_startup(struct snd_pcm_substream *substream,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) 			   struct snd_soc_dai *dai)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) 	struct siu_info *info = snd_soc_dai_get_drvdata(dai);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) 	struct snd_pcm_runtime *rt = substream->runtime;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) 	struct siu_port	*port_info = siu_port_info(substream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) 	int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) 	dev_dbg(substream->pcm->card->dev, "%s: port=%d@%p\n", __func__,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) 		info->port_id, port_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) 	snd_soc_set_runtime_hwparams(substream, &siu_dai_pcm_hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) 	ret = snd_pcm_hw_constraint_integer(rt, SNDRV_PCM_HW_PARAM_PERIODS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) 	if (unlikely(ret < 0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) 		return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) 	siu_dai_start(port_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) static void siu_dai_shutdown(struct snd_pcm_substream *substream,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) 			     struct snd_soc_dai *dai)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) 	struct siu_info *info = snd_soc_dai_get_drvdata(dai);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) 	struct siu_port	*port_info = siu_port_info(substream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) 	dev_dbg(substream->pcm->card->dev, "%s: port=%d@%p\n", __func__,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) 		info->port_id, port_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) 		port_info->play_cap &= ~PLAYBACK_ENABLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) 	else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) 		port_info->play_cap &= ~CAPTURE_ENABLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) 	/* Stop the siu if the other stream is not using it */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) 	if (!port_info->play_cap) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) 		/* during stmread or stmwrite ? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) 		if (WARN_ON(port_info->playback.rw_flg || port_info->capture.rw_flg))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) 			return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) 		siu_dai_spbstop(port_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) 		siu_dai_stop(port_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) /* PCM part of siu_dai_playback_prepare() / siu_dai_capture_prepare() */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) static int siu_dai_prepare(struct snd_pcm_substream *substream,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) 			   struct snd_soc_dai *dai)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) 	struct siu_info *info = snd_soc_dai_get_drvdata(dai);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) 	struct snd_pcm_runtime *rt = substream->runtime;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) 	struct siu_port *port_info = siu_port_info(substream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) 	struct siu_stream *siu_stream;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) 	int self, ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) 	dev_dbg(substream->pcm->card->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) 		"%s: port %d, active streams %lx, %d channels\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) 		__func__, info->port_id, port_info->play_cap, rt->channels);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) 		self = PLAYBACK_ENABLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) 		siu_stream = &port_info->playback;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) 	} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) 		self = CAPTURE_ENABLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) 		siu_stream = &port_info->capture;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) 	/* Set up the siu if not already done */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) 	if (!port_info->play_cap) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) 		siu_stream->rw_flg = 0;	/* stream-data transfer flag */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) 		siu_dai_spbAselect(port_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) 		siu_dai_spbBselect(port_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) 		siu_dai_open(siu_stream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) 		siu_dai_pcmdatapack(siu_stream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) 		ret = siu_dai_spbstart(port_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) 		if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) 			goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) 	} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) 		ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) 	port_info->play_cap |= self;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) fail:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) 	return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586)  * SIU can set bus format to I2S / PCM / SPDIF independently for playback and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587)  * capture, however, the current API sets the bus format globally for a DAI.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) static int siu_dai_set_fmt(struct snd_soc_dai *dai,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) 			   unsigned int fmt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) 	struct siu_info *info = snd_soc_dai_get_drvdata(dai);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) 	u32 __iomem *base = info->reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) 	u32 ifctl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) 	dev_dbg(dai->dev, "%s: fmt 0x%x on port %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) 		__func__, fmt, info->port_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) 	if (info->port_id < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) 		return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) 	/* Here select between I2S / PCM / SPDIF */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) 	case SND_SOC_DAIFMT_I2S:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) 		ifctl = siu_flags[info->port_id].playback.i2s |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) 			siu_flags[info->port_id].capture.i2s;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) 	case SND_SOC_DAIFMT_LEFT_J:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) 		ifctl = siu_flags[info->port_id].playback.pcm |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) 			siu_flags[info->port_id].capture.pcm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) 	/* SPDIF disabled - see comment at the top */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) 	default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) 	ifctl |= ~(siu_flags[info->port_id].playback.mask |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) 		   siu_flags[info->port_id].capture.mask) &
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) 		siu_read32(base + SIU_IFCTL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) 	siu_write32(base + SIU_IFCTL, ifctl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) static int siu_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) 			      unsigned int freq, int dir)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) 	struct clk *siu_clk, *parent_clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) 	char *siu_name, *parent_name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) 	int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) 	if (dir != SND_SOC_CLOCK_IN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) 	dev_dbg(dai->dev, "%s: using clock %d\n", __func__, clk_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) 	switch (clk_id) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) 	case SIU_CLKA_PLL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) 		siu_name = "siua_clk";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) 		parent_name = "pll_clk";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) 	case SIU_CLKA_EXT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) 		siu_name = "siua_clk";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) 		parent_name = "siumcka_clk";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) 	case SIU_CLKB_PLL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) 		siu_name = "siub_clk";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) 		parent_name = "pll_clk";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) 	case SIU_CLKB_EXT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) 		siu_name = "siub_clk";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) 		parent_name = "siumckb_clk";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) 	default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) 	siu_clk = clk_get(dai->dev, siu_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) 	if (IS_ERR(siu_clk)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) 		dev_err(dai->dev, "%s: cannot get a SIU clock: %ld\n", __func__,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) 			PTR_ERR(siu_clk));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) 		return PTR_ERR(siu_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) 	parent_clk = clk_get(dai->dev, parent_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) 	if (IS_ERR(parent_clk)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) 		ret = PTR_ERR(parent_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) 		dev_err(dai->dev, "cannot get a SIU clock parent: %d\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) 		goto epclkget;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) 	ret = clk_set_parent(siu_clk, parent_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) 	if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) 		dev_err(dai->dev, "cannot reparent the SIU clock: %d\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) 		goto eclksetp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) 	ret = clk_set_rate(siu_clk, freq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) 	if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) 		dev_err(dai->dev, "cannot set SIU clock rate: %d\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) 	/* TODO: when clkdev gets reference counting we'll move these to siu_dai_shutdown() */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) eclksetp:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) 	clk_put(parent_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) epclkget:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) 	clk_put(siu_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) 	return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) static const struct snd_soc_dai_ops siu_dai_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) 	.startup	= siu_dai_startup,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) 	.shutdown	= siu_dai_shutdown,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) 	.prepare	= siu_dai_prepare,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) 	.set_sysclk	= siu_dai_set_sysclk,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) 	.set_fmt	= siu_dai_set_fmt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) static struct snd_soc_dai_driver siu_i2s_dai = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) 	.name	= "siu-i2s-dai",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) 	.playback = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) 		.channels_min = 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) 		.channels_max = 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) 		.formats = SNDRV_PCM_FMTBIT_S16,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) 		.rates = SNDRV_PCM_RATE_8000_48000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) 	},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) 	.capture = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) 		.channels_min = 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) 		.channels_max = 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) 		.formats = SNDRV_PCM_FMTBIT_S16,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) 		.rates = SNDRV_PCM_RATE_8000_48000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) 	 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) 	.ops = &siu_dai_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) static int siu_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) 	const struct firmware *fw_entry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) 	struct resource *res, *region;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) 	struct siu_info *info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) 	int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) 	info = devm_kmalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) 	if (!info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) 		return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) 	siu_i2s_data = info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) 	info->dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) 	ret = request_firmware(&fw_entry, "siu_spb.bin", &pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) 	if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) 		return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) 	/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) 	 * Loaded firmware is "const" - read only, but we have to modify it in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) 	 * snd_siu_sh7343_spbAselect() and snd_siu_sh7343_spbBselect()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) 	memcpy(&info->fw, fw_entry->data, fw_entry->size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) 	release_firmware(fw_entry);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) 	if (!res)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) 		return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) 	region = devm_request_mem_region(&pdev->dev, res->start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) 					 resource_size(res), pdev->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) 	if (!region) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) 		dev_err(&pdev->dev, "SIU region already claimed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) 		return -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) 	info->pram = devm_ioremap(&pdev->dev, res->start, PRAM_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) 	if (!info->pram)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) 		return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) 	info->xram = devm_ioremap(&pdev->dev, res->start + XRAM_OFFSET,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) 				  XRAM_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) 	if (!info->xram)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) 		return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) 	info->yram = devm_ioremap(&pdev->dev, res->start + YRAM_OFFSET,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) 				  YRAM_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) 	if (!info->yram)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) 		return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) 	info->reg = devm_ioremap(&pdev->dev, res->start + REG_OFFSET,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) 			    resource_size(res) - REG_OFFSET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) 	if (!info->reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) 		return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) 	dev_set_drvdata(&pdev->dev, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) 	/* register using ARRAY version so we can keep dai name */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) 	ret = devm_snd_soc_register_component(&pdev->dev, &siu_component,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) 					      &siu_i2s_dai, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) 	if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) 		return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) 	pm_runtime_enable(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) static int siu_remove(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) 	pm_runtime_disable(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) static struct platform_driver siu_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) 	.driver 	= {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) 		.name	= "siu-pcm-audio",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) 	},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) 	.probe		= siu_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) 	.remove		= siu_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) module_platform_driver(siu_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) MODULE_AUTHOR("Carlos Munoz <carlos@kenati.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) MODULE_DESCRIPTION("ALSA SoC SH7722 SIU driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) MODULE_LICENSE("GPL");