^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) // ALSA Soc Audio Layer - I2S core for newer Samsung SoCs.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) //
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) // Copyright (c) 2006 Wolfson Microelectronics PLC.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) // Graeme Gregory graeme.gregory@wolfsonmicro.com
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) // linux@wolfsonmicro.com
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) //
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) // Copyright (c) 2008, 2007, 2004-2005 Simtec Electronics
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) // http://armlinux.simtec.co.uk/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) // Ben Dooks <ben@simtec.co.uk>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/clk.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <sound/soc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <sound/pcm_params.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include "regs-i2s-v2.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include "s3c-i2s-v2.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #undef S3C_IIS_V2_SUPPORTED
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #if defined(CONFIG_CPU_S3C2412) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) || defined(CONFIG_ARCH_S3C64XX) || defined(CONFIG_CPU_S5PV210)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #define S3C_IIS_V2_SUPPORTED
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #ifndef S3C_IIS_V2_SUPPORTED
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #error Unsupported CPU model
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #define S3C2412_I2S_DEBUG_CON 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) static inline struct s3c_i2sv2_info *to_info(struct snd_soc_dai *cpu_dai)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) return snd_soc_dai_get_drvdata(cpu_dai);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) #define bit_set(v, b) (((v) & (b)) ? 1 : 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) #if S3C2412_I2S_DEBUG_CON
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) static void dbg_showcon(const char *fn, u32 con)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) printk(KERN_DEBUG "%s: LRI=%d, TXFEMPT=%d, RXFEMPT=%d, TXFFULL=%d, RXFFULL=%d\n", fn,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) bit_set(con, S3C2412_IISCON_LRINDEX),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) bit_set(con, S3C2412_IISCON_TXFIFO_EMPTY),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) bit_set(con, S3C2412_IISCON_RXFIFO_EMPTY),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) bit_set(con, S3C2412_IISCON_TXFIFO_FULL),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) bit_set(con, S3C2412_IISCON_RXFIFO_FULL));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) printk(KERN_DEBUG "%s: PAUSE: TXDMA=%d, RXDMA=%d, TXCH=%d, RXCH=%d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) fn,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) bit_set(con, S3C2412_IISCON_TXDMA_PAUSE),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) bit_set(con, S3C2412_IISCON_RXDMA_PAUSE),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) bit_set(con, S3C2412_IISCON_TXCH_PAUSE),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) bit_set(con, S3C2412_IISCON_RXCH_PAUSE));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) printk(KERN_DEBUG "%s: ACTIVE: TXDMA=%d, RXDMA=%d, IIS=%d\n", fn,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) bit_set(con, S3C2412_IISCON_TXDMA_ACTIVE),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) bit_set(con, S3C2412_IISCON_RXDMA_ACTIVE),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) bit_set(con, S3C2412_IISCON_IIS_ACTIVE));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) static inline void dbg_showcon(const char *fn, u32 con)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) /* Turn on or off the transmission path. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) static void s3c2412_snd_txctrl(struct s3c_i2sv2_info *i2s, int on)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) void __iomem *regs = i2s->regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) u32 fic, con, mod;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) pr_debug("%s(%d)\n", __func__, on);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) fic = readl(regs + S3C2412_IISFIC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) con = readl(regs + S3C2412_IISCON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) mod = readl(regs + S3C2412_IISMOD);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) pr_debug("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) if (on) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) con |= S3C2412_IISCON_TXDMA_ACTIVE | S3C2412_IISCON_IIS_ACTIVE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) con &= ~S3C2412_IISCON_TXDMA_PAUSE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) con &= ~S3C2412_IISCON_TXCH_PAUSE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) switch (mod & S3C2412_IISMOD_MODE_MASK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) case S3C2412_IISMOD_MODE_TXONLY:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) case S3C2412_IISMOD_MODE_TXRX:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) /* do nothing, we are in the right mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) case S3C2412_IISMOD_MODE_RXONLY:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) mod &= ~S3C2412_IISMOD_MODE_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) mod |= S3C2412_IISMOD_MODE_TXRX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) dev_err(i2s->dev, "TXEN: Invalid MODE %x in IISMOD\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) mod & S3C2412_IISMOD_MODE_MASK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) writel(con, regs + S3C2412_IISCON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) writel(mod, regs + S3C2412_IISMOD);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) /* Note, we do not have any indication that the FIFO problems
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) * tha the S3C2410/2440 had apply here, so we should be able
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) * to disable the DMA and TX without resetting the FIFOS.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) con |= S3C2412_IISCON_TXDMA_PAUSE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) con |= S3C2412_IISCON_TXCH_PAUSE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) con &= ~S3C2412_IISCON_TXDMA_ACTIVE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) switch (mod & S3C2412_IISMOD_MODE_MASK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) case S3C2412_IISMOD_MODE_TXRX:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) mod &= ~S3C2412_IISMOD_MODE_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) mod |= S3C2412_IISMOD_MODE_RXONLY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) case S3C2412_IISMOD_MODE_TXONLY:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) mod &= ~S3C2412_IISMOD_MODE_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) con &= ~S3C2412_IISCON_IIS_ACTIVE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) dev_err(i2s->dev, "TXDIS: Invalid MODE %x in IISMOD\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) mod & S3C2412_IISMOD_MODE_MASK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) writel(mod, regs + S3C2412_IISMOD);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) writel(con, regs + S3C2412_IISCON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) fic = readl(regs + S3C2412_IISFIC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) dbg_showcon(__func__, con);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) pr_debug("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) static void s3c2412_snd_rxctrl(struct s3c_i2sv2_info *i2s, int on)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) void __iomem *regs = i2s->regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) u32 fic, con, mod;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) pr_debug("%s(%d)\n", __func__, on);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) fic = readl(regs + S3C2412_IISFIC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) con = readl(regs + S3C2412_IISCON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) mod = readl(regs + S3C2412_IISMOD);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) pr_debug("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) if (on) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) con |= S3C2412_IISCON_RXDMA_ACTIVE | S3C2412_IISCON_IIS_ACTIVE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) con &= ~S3C2412_IISCON_RXDMA_PAUSE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) con &= ~S3C2412_IISCON_RXCH_PAUSE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) switch (mod & S3C2412_IISMOD_MODE_MASK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) case S3C2412_IISMOD_MODE_TXRX:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) case S3C2412_IISMOD_MODE_RXONLY:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) /* do nothing, we are in the right mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) case S3C2412_IISMOD_MODE_TXONLY:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) mod &= ~S3C2412_IISMOD_MODE_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) mod |= S3C2412_IISMOD_MODE_TXRX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) dev_err(i2s->dev, "RXEN: Invalid MODE %x in IISMOD\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) mod & S3C2412_IISMOD_MODE_MASK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) writel(mod, regs + S3C2412_IISMOD);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) writel(con, regs + S3C2412_IISCON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) /* See txctrl notes on FIFOs. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) con &= ~S3C2412_IISCON_RXDMA_ACTIVE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) con |= S3C2412_IISCON_RXDMA_PAUSE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) con |= S3C2412_IISCON_RXCH_PAUSE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) switch (mod & S3C2412_IISMOD_MODE_MASK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) case S3C2412_IISMOD_MODE_RXONLY:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) con &= ~S3C2412_IISCON_IIS_ACTIVE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) mod &= ~S3C2412_IISMOD_MODE_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) case S3C2412_IISMOD_MODE_TXRX:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) mod &= ~S3C2412_IISMOD_MODE_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) mod |= S3C2412_IISMOD_MODE_TXONLY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) dev_err(i2s->dev, "RXDIS: Invalid MODE %x in IISMOD\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) mod & S3C2412_IISMOD_MODE_MASK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) writel(con, regs + S3C2412_IISCON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) writel(mod, regs + S3C2412_IISMOD);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) fic = readl(regs + S3C2412_IISFIC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) pr_debug("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) #define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) * Wait for the LR signal to allow synchronisation to the L/R clock
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) * from the codec. May only be needed for slave mode.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) static int s3c2412_snd_lrsync(struct s3c_i2sv2_info *i2s)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) u32 iiscon;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) unsigned long loops = msecs_to_loops(5);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) pr_debug("Entered %s\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) while (--loops) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) iiscon = readl(i2s->regs + S3C2412_IISCON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) if (iiscon & S3C2412_IISCON_LRINDEX)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) cpu_relax();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) if (!loops) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) printk(KERN_ERR "%s: timeout\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) return -ETIMEDOUT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) }
^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) * Set S3C2412 I2S DAI format
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) static int s3c2412_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) unsigned int fmt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) struct s3c_i2sv2_info *i2s = to_info(cpu_dai);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) u32 iismod;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) pr_debug("Entered %s\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) iismod = readl(i2s->regs + S3C2412_IISMOD);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) pr_debug("hw_params r: IISMOD: %x \n", iismod);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) case SND_SOC_DAIFMT_CBM_CFM:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) i2s->master = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) iismod |= S3C2412_IISMOD_SLAVE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) case SND_SOC_DAIFMT_CBS_CFS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) i2s->master = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) iismod &= ~S3C2412_IISMOD_SLAVE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) pr_err("unknown master/slave format\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) iismod &= ~S3C2412_IISMOD_SDF_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) case SND_SOC_DAIFMT_RIGHT_J:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) iismod |= S3C2412_IISMOD_LR_RLOW;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) iismod |= S3C2412_IISMOD_SDF_MSB;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) case SND_SOC_DAIFMT_LEFT_J:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) iismod |= S3C2412_IISMOD_LR_RLOW;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) iismod |= S3C2412_IISMOD_SDF_LSB;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) case SND_SOC_DAIFMT_I2S:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) iismod &= ~S3C2412_IISMOD_LR_RLOW;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) iismod |= S3C2412_IISMOD_SDF_IIS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) pr_err("Unknown data format\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) writel(iismod, i2s->regs + S3C2412_IISMOD);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) pr_debug("hw_params w: IISMOD: %x \n", iismod);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) static int s3c_i2sv2_hw_params(struct snd_pcm_substream *substream,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) struct snd_pcm_hw_params *params,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) struct snd_soc_dai *dai)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) struct s3c_i2sv2_info *i2s = to_info(dai);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) struct snd_dmaengine_dai_dma_data *dma_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) u32 iismod;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) pr_debug("Entered %s\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) dma_data = i2s->dma_playback;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) dma_data = i2s->dma_capture;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) snd_soc_dai_set_dma_data(dai, substream, dma_data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) /* Working copies of register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) iismod = readl(i2s->regs + S3C2412_IISMOD);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) pr_debug("%s: r: IISMOD: %x\n", __func__, iismod);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) iismod &= ~S3C64XX_IISMOD_BLC_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) /* Sample size */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) switch (params_width(params)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) case 8:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) iismod |= S3C64XX_IISMOD_BLC_8BIT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) case 16:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) case 24:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) iismod |= S3C64XX_IISMOD_BLC_24BIT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) writel(iismod, i2s->regs + S3C2412_IISMOD);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) pr_debug("%s: w: IISMOD: %x\n", __func__, iismod);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) static int s3c_i2sv2_set_sysclk(struct snd_soc_dai *cpu_dai,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) int clk_id, unsigned int freq, int dir)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) struct s3c_i2sv2_info *i2s = to_info(cpu_dai);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) u32 iismod = readl(i2s->regs + S3C2412_IISMOD);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) pr_debug("Entered %s\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) pr_debug("%s r: IISMOD: %x\n", __func__, iismod);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) switch (clk_id) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) case S3C_I2SV2_CLKSRC_PCLK:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) iismod &= ~S3C2412_IISMOD_IMS_SYSMUX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) case S3C_I2SV2_CLKSRC_AUDIOBUS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) iismod |= S3C2412_IISMOD_IMS_SYSMUX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) case S3C_I2SV2_CLKSRC_CDCLK:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) /* Error if controller doesn't have the CDCLKCON bit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) if (!(i2s->feature & S3C_FEATURE_CDCLKCON))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) switch (dir) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) case SND_SOC_CLOCK_IN:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) iismod |= S3C64XX_IISMOD_CDCLKCON;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) case SND_SOC_CLOCK_OUT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) iismod &= ~S3C64XX_IISMOD_CDCLKCON;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) writel(iismod, i2s->regs + S3C2412_IISMOD);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) pr_debug("%s w: IISMOD: %x\n", __func__, iismod);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) static int s3c2412_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) struct snd_soc_dai *dai)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) struct s3c_i2sv2_info *i2s = to_info(asoc_rtd_to_cpu(rtd, 0));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) unsigned long irqs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) pr_debug("Entered %s\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) switch (cmd) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) case SNDRV_PCM_TRIGGER_START:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) /* On start, ensure that the FIFOs are cleared and reset. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) writel(capture ? S3C2412_IISFIC_RXFLUSH : S3C2412_IISFIC_TXFLUSH,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) i2s->regs + S3C2412_IISFIC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) /* clear again, just in case */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) writel(0x0, i2s->regs + S3C2412_IISFIC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) case SNDRV_PCM_TRIGGER_RESUME:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) if (!i2s->master) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) ret = s3c2412_snd_lrsync(i2s);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) goto exit_err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) local_irq_save(irqs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) if (capture)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) s3c2412_snd_rxctrl(i2s, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) s3c2412_snd_txctrl(i2s, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) local_irq_restore(irqs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) case SNDRV_PCM_TRIGGER_STOP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) case SNDRV_PCM_TRIGGER_SUSPEND:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) local_irq_save(irqs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) if (capture)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) s3c2412_snd_rxctrl(i2s, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) s3c2412_snd_txctrl(i2s, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) local_irq_restore(irqs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) exit_err:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) return ret;
^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) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) * Set S3C2412 Clock dividers
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) static int s3c2412_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) int div_id, int div)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) struct s3c_i2sv2_info *i2s = to_info(cpu_dai);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) u32 reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) pr_debug("%s(%p, %d, %d)\n", __func__, cpu_dai, div_id, div);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) switch (div_id) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) case S3C_I2SV2_DIV_BCLK:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) switch (div) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) case 16:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) div = S3C2412_IISMOD_BCLK_16FS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) case 32:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) div = S3C2412_IISMOD_BCLK_32FS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) case 24:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) div = S3C2412_IISMOD_BCLK_24FS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) case 48:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) div = S3C2412_IISMOD_BCLK_48FS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) reg = readl(i2s->regs + S3C2412_IISMOD);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) reg &= ~S3C2412_IISMOD_BCLK_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) writel(reg | div, i2s->regs + S3C2412_IISMOD);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) pr_debug("%s: MOD=%08x\n", __func__, readl(i2s->regs + S3C2412_IISMOD));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) case S3C_I2SV2_DIV_RCLK:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) switch (div) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) case 256:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) div = S3C2412_IISMOD_RCLK_256FS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) case 384:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) div = S3C2412_IISMOD_RCLK_384FS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) case 512:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) div = S3C2412_IISMOD_RCLK_512FS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) case 768:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) div = S3C2412_IISMOD_RCLK_768FS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) reg = readl(i2s->regs + S3C2412_IISMOD);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) reg &= ~S3C2412_IISMOD_RCLK_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) writel(reg | div, i2s->regs + S3C2412_IISMOD);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) pr_debug("%s: MOD=%08x\n", __func__, readl(i2s->regs + S3C2412_IISMOD));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) case S3C_I2SV2_DIV_PRESCALER:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) if (div >= 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) writel((div << 8) | S3C2412_IISPSR_PSREN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) i2s->regs + S3C2412_IISPSR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) writel(0x0, i2s->regs + S3C2412_IISPSR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) pr_debug("%s: PSR=%08x\n", __func__, readl(i2s->regs + S3C2412_IISPSR));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) static snd_pcm_sframes_t s3c2412_i2s_delay(struct snd_pcm_substream *substream,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) struct snd_soc_dai *dai)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) struct s3c_i2sv2_info *i2s = to_info(dai);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) u32 reg = readl(i2s->regs + S3C2412_IISFIC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) snd_pcm_sframes_t delay;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) delay = S3C2412_IISFIC_TXCOUNT(reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) delay = S3C2412_IISFIC_RXCOUNT(reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) return delay;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) struct clk *s3c_i2sv2_get_clock(struct snd_soc_dai *cpu_dai)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) struct s3c_i2sv2_info *i2s = to_info(cpu_dai);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) u32 iismod = readl(i2s->regs + S3C2412_IISMOD);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) if (iismod & S3C2412_IISMOD_IMS_SYSMUX)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) return i2s->iis_cclk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) return i2s->iis_pclk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) EXPORT_SYMBOL_GPL(s3c_i2sv2_get_clock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) /* default table of all avaialable root fs divisors */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) static unsigned int iis_fs_tab[] = { 256, 512, 384, 768 };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) int s3c_i2sv2_iis_calc_rate(struct s3c_i2sv2_rate_calc *info,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) unsigned int *fstab,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) unsigned int rate, struct clk *clk)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) unsigned long clkrate = clk_get_rate(clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) unsigned int div;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) unsigned int fsclk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) unsigned int actual;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) unsigned int fs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) unsigned int fsdiv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) signed int deviation = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) unsigned int best_fs = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) unsigned int best_div = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) unsigned int best_rate = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) unsigned int best_deviation = INT_MAX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) pr_debug("Input clock rate %ldHz\n", clkrate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) if (fstab == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) fstab = iis_fs_tab;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) for (fs = 0; fs < ARRAY_SIZE(iis_fs_tab); fs++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) fsdiv = iis_fs_tab[fs];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) fsclk = clkrate / fsdiv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) div = fsclk / rate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) if ((fsclk % rate) > (rate / 2))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) div++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) if (div <= 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) actual = clkrate / (fsdiv * div);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) deviation = actual - rate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) printk(KERN_DEBUG "%ufs: div %u => result %u, deviation %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) fsdiv, div, actual, deviation);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) deviation = abs(deviation);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) if (deviation < best_deviation) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) best_fs = fsdiv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) best_div = div;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) best_rate = actual;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) best_deviation = deviation;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) if (deviation == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) printk(KERN_DEBUG "best: fs=%u, div=%u, rate=%u\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) best_fs, best_div, best_rate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) info->fs_div = best_fs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) info->clk_div = best_div;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) EXPORT_SYMBOL_GPL(s3c_i2sv2_iis_calc_rate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) int s3c_i2sv2_probe(struct snd_soc_dai *dai,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) struct s3c_i2sv2_info *i2s)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) struct device *dev = dai->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) unsigned int iismod;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) i2s->dev = dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) /* record our i2s structure for later use in the callbacks */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) snd_soc_dai_set_drvdata(dai, i2s);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) i2s->iis_pclk = clk_get(dev, "iis");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) if (IS_ERR(i2s->iis_pclk)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) dev_err(dev, "failed to get iis_clock\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) return -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) clk_prepare_enable(i2s->iis_pclk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) /* Mark ourselves as in TXRX mode so we can run through our cleanup
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) * process without warnings. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) iismod = readl(i2s->regs + S3C2412_IISMOD);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) iismod |= S3C2412_IISMOD_MODE_TXRX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) writel(iismod, i2s->regs + S3C2412_IISMOD);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) s3c2412_snd_txctrl(i2s, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) s3c2412_snd_rxctrl(i2s, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) EXPORT_SYMBOL_GPL(s3c_i2sv2_probe);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) void s3c_i2sv2_cleanup(struct snd_soc_dai *dai,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) struct s3c_i2sv2_info *i2s)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) clk_disable_unprepare(i2s->iis_pclk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) clk_put(i2s->iis_pclk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) i2s->iis_pclk = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) EXPORT_SYMBOL_GPL(s3c_i2sv2_cleanup);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) int s3c_i2sv2_register_component(struct device *dev, int id,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) const struct snd_soc_component_driver *cmp_drv,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) struct snd_soc_dai_driver *dai_drv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) struct snd_soc_dai_ops *ops = (struct snd_soc_dai_ops *)dai_drv->ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) ops->trigger = s3c2412_i2s_trigger;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) if (!ops->hw_params)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) ops->hw_params = s3c_i2sv2_hw_params;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) ops->set_fmt = s3c2412_i2s_set_fmt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) ops->set_clkdiv = s3c2412_i2s_set_clkdiv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) ops->set_sysclk = s3c_i2sv2_set_sysclk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) /* Allow overriding by (for example) IISv4 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) if (!ops->delay)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) ops->delay = s3c2412_i2s_delay;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) return devm_snd_soc_register_component(dev, cmp_drv, dai_drv, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) EXPORT_SYMBOL_GPL(s3c_i2sv2_register_component);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) MODULE_LICENSE("GPL");