^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");