--- linux-mvl-dove-2.6.32.orig/Makefile +++ linux-mvl-dove-2.6.32/Makefile @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 6 SUBLEVEL = 32 -EXTRAVERSION = +EXTRAVERSION = .44+drm33.19 NAME = Man-Eating Seals of Antiquity # *DOCUMENTATION* @@ -331,14 +331,23 @@ AFLAGS_KERNEL = CFLAGS_GCOV = -fprofile-arcs -ftest-coverage +# Prefer linux-backports-modules +ifneq ($(KBUILD_SRC),) +ifneq ($(shell if test -e $(KBUILD_OUTPUT)/ubuntu-build; then echo yes; fi),yes) +UBUNTUINCLUDE := -I/usr/src/linux-headers-lbm-$(KERNELRELEASE) +endif +endif # Use LINUXINCLUDE when you must reference the include/ directory. # Needed to be compatible with the O= option -LINUXINCLUDE := -Iinclude \ +LINUXINCLUDE := $(UBUNTUINCLUDE) -Iinclude \ $(if $(KBUILD_SRC),-Iinclude2 -I$(srctree)/include) \ -I$(srctree)/arch/$(hdr-arch)/include \ -include include/linux/autoconf.h +# UBUNTU: Include our third party driver stuff too +LINUXINCLUDE += -Iubuntu/include $(if $(KBUILD_SRC),-I$(srctree)/ubuntu/include) + KBUILD_CPPFLAGS := -D__KERNEL__ KBUILD_CFLAGS := -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs \ @@ -464,12 +473,12 @@ # Carefully list dependencies so we do not try to build scripts twice # in parallel PHONY += scripts -scripts: scripts_basic include/config/auto.conf +scripts: scripts_basic include/config/auto.conf include/config/tristate.conf $(Q)$(MAKE) $(build)=$(@) # Objects we will link into vmlinux / subdirs we need to visit init-y := init/ -drivers-y := drivers/ sound/ firmware/ +drivers-y := drivers/ sound/ firmware/ ubuntu/ net-y := net/ libs-y := lib/ core-y := usr/ @@ -491,7 +500,7 @@ # with it and forgot to run make oldconfig. # if auto.conf.cmd is missing then we are probably in a cleaned tree so # we execute the config step to be sure to catch updated Kconfig files -include/config/auto.conf: $(KCONFIG_CONFIG) include/config/auto.conf.cmd +include/config/%.conf: $(KCONFIG_CONFIG) include/config/auto.conf.cmd $(Q)$(MAKE) -f $(srctree)/Makefile silentoldconfig else # external modules needs include/linux/autoconf.h and include/config/auto.conf @@ -876,6 +885,9 @@ PHONY += $(vmlinux-dirs) $(vmlinux-dirs): prepare scripts $(Q)$(MAKE) $(build)=$@ +ifdef CONFIG_MODULES + $(Q)$(MAKE) $(modbuiltin)=$@ +endif # Build the kernel release string # @@ -1126,6 +1138,7 @@ PHONY += modules modules: $(vmlinux-dirs) $(if $(KBUILD_BUILTIN),vmlinux) $(Q)$(AWK) '!x[$$0]++' $(vmlinux-dirs:%=$(objtree)/%/modules.order) > $(objtree)/modules.order + $(Q)$(AWK) '!x[$$0]++' $(vmlinux-dirs:%=$(objtree)/%/modules.builtin) > $(objtree)/modules.builtin @$(kecho) ' Building modules, stage 2.'; $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.fwinst obj=firmware __fw_modbuild @@ -1155,6 +1168,7 @@ ln -s $(objtree) $(MODLIB)/build ; \ fi @cp -f $(objtree)/modules.order $(MODLIB)/ + @cp -f $(objtree)/modules.builtin $(MODLIB)/ $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modinst # This depmod is only for convenience to give the initial @@ -1218,6 +1232,7 @@ -o -name '.*.d' -o -name '.*.tmp' -o -name '*.mod.c' \ -o -name '*.symtypes' -o -name 'modules.order' \ -o -name 'Module.markers' -o -name '.tmp_*.o.*' \ + -o -name 'modules.builtin' \ -o -name '*.gcno' \) -type f -print | xargs rm -f # mrproper - Delete all generated files, including .config @@ -1416,7 +1431,8 @@ clean: rm-dirs := $(MODVERDIR) clean: rm-files := $(KBUILD_EXTMOD)/Module.symvers \ $(KBUILD_EXTMOD)/Module.markers \ - $(KBUILD_EXTMOD)/modules.order + $(KBUILD_EXTMOD)/modules.order \ + $(KBUILD_EXTMOD)/modules.builtin clean: $(clean-dirs) $(call cmd,rmdirs) $(call cmd,rmfiles) --- linux-mvl-dove-2.6.32.orig/MAINTAINERS +++ linux-mvl-dove-2.6.32/MAINTAINERS @@ -1974,6 +1974,12 @@ S: Maintained F: drivers/platform/x86/eeepc-laptop.c +EFIFB FRAMEBUFFER DRIVER +L: linux-fbdev@vger.kernel.org +M: Peter Jones +S: Maintained +F: drivers/video/efifb.c + EFS FILESYSTEM W: http://aeschi.ch.eu.org/efs/ S: Orphan @@ -5004,7 +5010,6 @@ STABLE BRANCH M: Greg Kroah-Hartman -M: Chris Wright L: stable@kernel.org S: Maintained @@ -5594,9 +5599,11 @@ F: drivers/net/wireless/rndis_wlan.c USB XHCI DRIVER -M: Sarah Sharp +M: Sarah Sharp L: linux-usb@vger.kernel.org S: Supported +F: drivers/usb/host/xhci* +F: drivers/usb/host/pci-quirks* USB ZC0301 DRIVER M: Luca Risolia @@ -5718,6 +5725,14 @@ S: Maintained F: drivers/net/vmxnet3/ +VMware PVSCSI driver +M: Alok Kataria +M: VMware PV-Drivers +L: linux-scsi@vger.kernel.org +S: Maintained +F: drivers/scsi/vmw_pvscsi.c +F: drivers/scsi/vmw_pvscsi.h + VOLTAGE AND CURRENT REGULATOR FRAMEWORK M: Liam Girdwood M: Mark Brown --- linux-mvl-dove-2.6.32.orig/sound/synth/emux/emux_hwdep.c +++ linux-mvl-dove-2.6.32/sound/synth/emux/emux_hwdep.c @@ -128,6 +128,9 @@ strcpy(hw->name, SNDRV_EMUX_HWDEP_NAME); hw->iface = SNDRV_HWDEP_IFACE_EMUX_WAVETABLE; hw->ops.ioctl = snd_emux_hwdep_ioctl; + /* The ioctl parameter types are compatible between 32- and + * 64-bit architectures, so use the same function. */ + hw->ops.ioctl_compat = snd_emux_hwdep_ioctl; hw->exclusive = 1; hw->private_data = emu; if ((err = snd_card_register(emu->card)) < 0) --- linux-mvl-dove-2.6.32.orig/sound/mips/sgio2audio.c +++ linux-mvl-dove-2.6.32/sound/mips/sgio2audio.c @@ -609,7 +609,7 @@ /* alloc virtual 'dma' area */ if (runtime->dma_area) vfree(runtime->dma_area); - runtime->dma_area = vmalloc(size); + runtime->dma_area = vmalloc_user(size); if (runtime->dma_area == NULL) return -ENOMEM; runtime->dma_bytes = size; --- linux-mvl-dove-2.6.32.orig/sound/arm/pxa2xx-ac97-lib.c +++ linux-mvl-dove-2.6.32/sound/arm/pxa2xx-ac97-lib.c @@ -16,14 +16,19 @@ #include #include #include +#include +#include #include #include #include +#include #include #include +#ifndef CONFIG_ARCH_DOVE #include +#endif static DEFINE_MUTEX(car_mutex); static DECLARE_WAIT_QUEUE_HEAD(gsr_wq); @@ -48,6 +53,7 @@ RESETGPIO_NORMAL_ALTFUNC }; +#ifdef CONFIG_PXA27x /** * set_resetgpio_mode - computes and sets the AC97_RESET gpio mode on PXA * @mode: chosen action @@ -80,19 +86,29 @@ if (mode) pxa_gpio_mode(mode); } - +#endif unsigned short pxa2xx_ac97_read(struct snd_ac97 *ac97, unsigned short reg) { unsigned short val = -1; volatile u32 *reg_addr; +#ifdef CONFIG_ARCH_DOVE + u16 dummy_read_timeout=0; +#endif mutex_lock(&car_mutex); +#ifndef CONFIG_ARCH_DOVE /* set up primary or secondary codec space */ if (cpu_is_pxa25x() && reg == AC97_GPIO_STATUS) reg_addr = ac97->num ? &SMC_REG_BASE : &PMC_REG_BASE; else reg_addr = ac97->num ? &SAC_REG_BASE : &PAC_REG_BASE; +#else + if (reg == AC97_GPIO_STATUS) + reg_addr = ac97->num ? &SMC_REG_BASE : &PMC_REG_BASE; + else + reg_addr = ac97->num ? &SAC_REG_BASE : &PAC_REG_BASE; +#endif reg_addr += (reg >> 1); /* start read access across the ac97 link */ @@ -103,10 +119,14 @@ goto out; if (wait_event_timeout(gsr_wq, (GSR | gsr_bits) & GSR_SDONE, 1) <= 0 && !((GSR | gsr_bits) & GSR_SDONE)) { +#ifndef CONFIG_ARCH_DOVE printk(KERN_ERR "%s: read error (ac97_reg=%d GSR=%#lx)\n", __func__, reg, GSR | gsr_bits); val = -1; goto out; +#else + dummy_read_timeout=1; +#endif } /* valid data now */ @@ -116,6 +136,16 @@ /* but we've just started another cycle... */ wait_event_timeout(gsr_wq, (GSR | gsr_bits) & GSR_SDONE, 1); +#ifdef CONFIG_ARCH_DOVE + if (val==0xffff && dummy_read_timeout) + { + //The controller times out the read operation if the codec fails to respond in 4 AC97_SYNC frames. + //In this case, the second read operation return a time-out data vaule of 0x0000_FFFF + printk(KERN_ERR "%s: read error (ac97_reg=%d GSR=%#lx)\n", + __func__, reg, GSR | gsr_bits); + } +#endif + out: mutex_unlock(&car_mutex); return val; } @@ -129,10 +159,18 @@ mutex_lock(&car_mutex); /* set up primary or secondary codec space */ +#ifndef CONFIG_ARCH_DOVE if (cpu_is_pxa25x() && reg == AC97_GPIO_STATUS) reg_addr = ac97->num ? &SMC_REG_BASE : &PMC_REG_BASE; else reg_addr = ac97->num ? &SAC_REG_BASE : &PAC_REG_BASE; +#else + if (reg == AC97_GPIO_STATUS) + reg_addr = ac97->num ? &SMC_REG_BASE : &PMC_REG_BASE; + else + reg_addr = ac97->num ? &SAC_REG_BASE : &PAC_REG_BASE; +#endif + reg_addr += (reg >> 1); GSR = GSR_CDONE | GSR_SDONE; @@ -199,7 +237,7 @@ } #endif -#ifdef CONFIG_PXA3xx +#if defined(CONFIG_PXA3xx) || defined(CONFIG_ARCH_DOVE) static inline void pxa_ac97_warm_pxa3xx(void) { int timeout = 100; @@ -240,6 +278,7 @@ { unsigned long gsr; +#ifndef CONFIG_ARCH_DOVE #ifdef CONFIG_PXA25x if (cpu_is_pxa25x()) pxa_ac97_warm_pxa25x(); @@ -256,6 +295,10 @@ else #endif BUG(); +#else + pxa_ac97_warm_pxa3xx(); +#endif + gsr = GSR | gsr_bits; if (!(gsr & (GSR_PCR | GSR_SCR))) { printk(KERN_INFO "%s: warm reset timeout (GSR=%#lx)\n", @@ -272,6 +315,7 @@ { unsigned long gsr; +#ifndef CONFIG_ARCH_DOVE #ifdef CONFIG_PXA25x if (cpu_is_pxa25x()) pxa_ac97_cold_pxa25x(); @@ -288,6 +332,9 @@ else #endif BUG(); +#else + pxa_ac97_cold_pxa3xx(); +#endif gsr = GSR | gsr_bits; if (!(gsr & (GSR_PCR | GSR_SCR))) { @@ -319,6 +366,7 @@ gsr_bits |= status; wake_up(&gsr_wq); +#ifndef CONFIG_ARCH_DOVE /* Although we don't use those we still need to clear them since they tend to spuriously trigger when MMC is used (hardware bug? go figure)... */ @@ -327,6 +375,7 @@ PISR = PISR_EOC; MCSR = MCSR_EOC; } +#endif return IRQ_HANDLED; } @@ -345,6 +394,7 @@ int pxa2xx_ac97_hw_resume(void) { +#ifndef CONFIG_ARCH_DOVE if (cpu_is_pxa25x() || cpu_is_pxa27x()) { pxa_gpio_mode(GPIO31_SYNC_AC97_MD); pxa_gpio_mode(GPIO30_SDATA_OUT_AC97_MD); @@ -355,7 +405,9 @@ /* Use GPIO 113 or 95 as AC97 Reset on Bulverde */ set_resetgpio_mode(RESETGPIO_NORMAL_ALTFUNC); } +#endif clk_enable(ac97_clk); + GCR &= ~GCR_ACLINK_OFF; return 0; } EXPORT_SYMBOL_GPL(pxa2xx_ac97_hw_resume); @@ -364,6 +416,7 @@ int __devinit pxa2xx_ac97_hw_probe(struct platform_device *dev) { int ret; +#ifndef CONFIG_ARCH_DOVE pxa2xx_audio_ops_t *pdata = dev->dev.platform_data; if (pdata) { @@ -403,7 +456,7 @@ goto err_conf; } } - +#endif ac97_clk = clk_get(&dev->dev, "AC97CLK"); if (IS_ERR(ac97_clk)) { ret = PTR_ERR(ac97_clk); --- linux-mvl-dove-2.6.32.orig/sound/arm/Kconfig +++ linux-mvl-dove-2.6.32/sound/arm/Kconfig @@ -1,3 +1,4 @@ + # ALSA ARM drivers menuconfig SND_ARM @@ -39,5 +40,5 @@ Say Y or M if you want to support any AC97 codec attached to the PXA2xx AC97 interface. -endif # SND_ARM +endif # SND_ARM --- linux-mvl-dove-2.6.32.orig/sound/arm/pxa2xx-pcm.h +++ linux-mvl-dove-2.6.32/sound/arm/pxa2xx-pcm.h @@ -9,7 +9,11 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ +#ifndef CONFIG_ARCH_DOVE #include +#else +#include +#endif struct pxa2xx_runtime_data { int dma_ch; --- linux-mvl-dove-2.6.32.orig/sound/arm/Makefile +++ linux-mvl-dove-2.6.32/sound/arm/Makefile @@ -14,3 +14,5 @@ obj-$(CONFIG_SND_PXA2XX_AC97) += snd-pxa2xx-ac97.o snd-pxa2xx-ac97-objs := pxa2xx-ac97.o + +obj-$(CONFIG_MV_INCLUDE_AUDIO) += ../../arch/arm/plat-orion/mv_hal_drivers/mv_drivers_lsp/mv_audio/ \ No newline at end of file --- linux-mvl-dove-2.6.32.orig/sound/arm/pxa2xx-ac97.c +++ linux-mvl-dove-2.6.32/sound/arm/pxa2xx-ac97.c @@ -20,6 +20,8 @@ #include #include +#include +#include #include #include --- linux-mvl-dove-2.6.32.orig/sound/arm/pxa2xx-pcm-lib.c +++ linux-mvl-dove-2.6.32/sound/arm/pxa2xx-pcm-lib.c @@ -12,7 +12,8 @@ #include #include -#include +#include +#include #include "pxa2xx-pcm.h" @@ -54,9 +55,11 @@ dma_desc->ddadr = next_desc_phys; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { dma_desc->dsadr = dma_buff_phys; - dma_desc->dtadr = rtd->params->dev_addr; + dma_desc->dtadr = + AC97_REG_4_PDMA(rtd->params->dev_addr); } else { - dma_desc->dsadr = rtd->params->dev_addr; + dma_desc->dsadr = + AC97_REG_4_PDMA(rtd->params->dev_addr); dma_desc->dtadr = dma_buff_phys; } if (period > totsize) @@ -204,7 +207,7 @@ &rtd->dma_desc_array_phys, GFP_KERNEL); if (!rtd->dma_desc_array) goto err1; - + rtd->dma_ch = -1; runtime->private_data = rtd; return 0; --- linux-mvl-dove-2.6.32.orig/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c +++ linux-mvl-dove-2.6.32/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c @@ -51,7 +51,7 @@ return 0; /* already enough large */ vfree(runtime->dma_area); } - runtime->dma_area = vmalloc_32(size); + runtime->dma_area = vmalloc_32_user(size); if (! runtime->dma_area) return -ENOMEM; runtime->dma_bytes = size; --- linux-mvl-dove-2.6.32.orig/sound/pci/cmipci.c +++ linux-mvl-dove-2.6.32/sound/pci/cmipci.c @@ -941,13 +941,21 @@ struct snd_pcm_substream *substream) { size_t ptr; - unsigned int reg; + unsigned int reg, rem, tries; + if (!rec->running) return 0; #if 1 // this seems better.. reg = rec->ch ? CM_REG_CH1_FRAME2 : CM_REG_CH0_FRAME2; - ptr = rec->dma_size - (snd_cmipci_read_w(cm, reg) + 1); - ptr >>= rec->shift; + for (tries = 0; tries < 3; tries++) { + rem = snd_cmipci_read_w(cm, reg); + if (rem < rec->dma_size) + goto ok; + } + printk(KERN_ERR "cmipci: invalid PCM pointer: %#x\n", rem); + return SNDRV_PCM_POS_XRUN; +ok: + ptr = (rec->dma_size - (rem + 1)) >> rec->shift; #else reg = rec->ch ? CM_REG_CH1_FRAME1 : CM_REG_CH0_FRAME1; ptr = snd_cmipci_read(cm, reg) - rec->offset; --- linux-mvl-dove-2.6.32.orig/sound/pci/via82xx.c +++ linux-mvl-dove-2.6.32/sound/pci/via82xx.c @@ -1791,6 +1791,12 @@ .type = AC97_TUNE_HP_ONLY }, { + .subvendor = 0x110a, + .subdevice = 0x0079, + .name = "Fujitsu Siemens D1289", + .type = AC97_TUNE_HP_ONLY + }, + { .subvendor = 0x1019, .subdevice = 0x0a81, .name = "ECS K7VTA3", --- linux-mvl-dove-2.6.32.orig/sound/pci/ens1370.c +++ linux-mvl-dove-2.6.32/sound/pci/ens1370.c @@ -229,6 +229,7 @@ #define ES_REG_1371_CODEC 0x14 /* W/R: Codec Read/Write register address */ #define ES_1371_CODEC_RDY (1<<31) /* codec ready */ #define ES_1371_CODEC_WIP (1<<30) /* codec register access in progress */ +#define EV_1938_CODEC_MAGIC (1<<26) #define ES_1371_CODEC_PIRD (1<<23) /* codec read/write select register */ #define ES_1371_CODEC_WRITE(a,d) ((((a)&0x7f)<<16)|(((d)&0xffff)<<0)) #define ES_1371_CODEC_READS(a) ((((a)&0x7f)<<16)|ES_1371_CODEC_PIRD) @@ -603,12 +604,18 @@ #ifdef CHIP1371 +static inline bool is_ev1938(struct ensoniq *ensoniq) +{ + return ensoniq->pci->device == 0x8938; +} + static void snd_es1371_codec_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short val) { struct ensoniq *ensoniq = ac97->private_data; - unsigned int t, x; + unsigned int t, x, flag; + flag = is_ev1938(ensoniq) ? EV_1938_CODEC_MAGIC : 0; mutex_lock(&ensoniq->src_mutex); for (t = 0; t < POLL_COUNT; t++) { if (!(inl(ES_REG(ensoniq, 1371_CODEC)) & ES_1371_CODEC_WIP)) { @@ -630,7 +637,8 @@ 0x00010000) break; } - outl(ES_1371_CODEC_WRITE(reg, val), ES_REG(ensoniq, 1371_CODEC)); + outl(ES_1371_CODEC_WRITE(reg, val) | flag, + ES_REG(ensoniq, 1371_CODEC)); /* restore SRC reg */ snd_es1371_wait_src_ready(ensoniq); outl(x, ES_REG(ensoniq, 1371_SMPRATE)); @@ -647,8 +655,9 @@ unsigned short reg) { struct ensoniq *ensoniq = ac97->private_data; - unsigned int t, x, fail = 0; + unsigned int t, x, flag, fail = 0; + flag = is_ev1938(ensoniq) ? EV_1938_CODEC_MAGIC : 0; __again: mutex_lock(&ensoniq->src_mutex); for (t = 0; t < POLL_COUNT; t++) { @@ -671,7 +680,8 @@ 0x00010000) break; } - outl(ES_1371_CODEC_READS(reg), ES_REG(ensoniq, 1371_CODEC)); + outl(ES_1371_CODEC_READS(reg) | flag, + ES_REG(ensoniq, 1371_CODEC)); /* restore SRC reg */ snd_es1371_wait_src_ready(ensoniq); outl(x, ES_REG(ensoniq, 1371_SMPRATE)); @@ -683,6 +693,11 @@ /* now wait for the stinkin' data (RDY) */ for (t = 0; t < POLL_COUNT; t++) { if ((x = inl(ES_REG(ensoniq, 1371_CODEC))) & ES_1371_CODEC_RDY) { + if (is_ev1938(ensoniq)) { + for (t = 0; t < 100; t++) + inl(ES_REG(ensoniq, CONTROL)); + x = inl(ES_REG(ensoniq, 1371_CODEC)); + } mutex_unlock(&ensoniq->src_mutex); return ES_1371_CODEC_READ(x); } --- linux-mvl-dove-2.6.32.orig/sound/pci/intel8x0.c +++ linux-mvl-dove-2.6.32/sound/pci/intel8x0.c @@ -1776,6 +1776,12 @@ }, { .subvendor = 0x1014, + .subdevice = 0x0534, + .name = "ThinkPad X31", + .type = AC97_TUNE_INV_EAPD + }, + { + .subvendor = 0x1014, .subdevice = 0x1f00, .name = "MS-9128", .type = AC97_TUNE_ALC_JACK @@ -1860,6 +1866,12 @@ }, { .subvendor = 0x1028, + .subdevice = 0x0182, + .name = "Dell Latitude D610", /* STAC9750/51 */ + .type = AC97_TUNE_HP_ONLY + }, + { + .subvendor = 0x1028, .subdevice = 0x0186, .name = "Dell Latitude D810", /* cf. Malone #41015 */ .type = AC97_TUNE_HP_MUTE_LED --- linux-mvl-dove-2.6.32.orig/sound/pci/maestro3.c +++ linux-mvl-dove-2.6.32/sound/pci/maestro3.c @@ -849,6 +849,7 @@ struct snd_kcontrol *master_switch; struct snd_kcontrol *master_volume; struct tasklet_struct hwvol_tq; + unsigned int in_suspend; #ifdef CONFIG_PM u16 *suspend_mem; @@ -884,6 +885,7 @@ MODULE_DEVICE_TABLE(pci, snd_m3_ids); static struct snd_pci_quirk m3_amp_quirk_list[] __devinitdata = { + SND_PCI_QUIRK(0x0E11, 0x0094, "Compaq Evo N600c", 0x0c), SND_PCI_QUIRK(0x10f7, 0x833e, "Panasonic CF-28", 0x0d), SND_PCI_QUIRK(0x10f7, 0x833d, "Panasonic CF-72", 0x0d), SND_PCI_QUIRK(0x1033, 0x80f1, "NEC LM800J/7", 0x03), @@ -1613,6 +1615,11 @@ outb(0x88, chip->iobase + SHADOW_MIX_REG_MASTER); outb(0x88, chip->iobase + HW_VOL_COUNTER_MASTER); + /* Ignore spurious HV interrupts during suspend / resume, this avoids + mistaking them for a mute button press. */ + if (chip->in_suspend) + return; + if (!chip->master_switch || !chip->master_volume) return; @@ -2424,6 +2431,7 @@ if (chip->suspend_mem == NULL) return 0; + chip->in_suspend = 1; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); snd_pcm_suspend_all(chip->pcm); snd_ac97_suspend(chip->ac97); @@ -2497,6 +2505,7 @@ snd_m3_hv_init(chip); snd_power_change_state(card, SNDRV_CTL_POWER_D0); + chip->in_suspend = 0; return 0; } #endif /* CONFIG_PM */ --- linux-mvl-dove-2.6.32.orig/sound/pci/atiixp.c +++ linux-mvl-dove-2.6.32/sound/pci/atiixp.c @@ -297,6 +297,7 @@ MODULE_DEVICE_TABLE(pci, snd_atiixp_ids); static struct snd_pci_quirk atiixp_quirks[] __devinitdata = { + SND_PCI_QUIRK(0x105b, 0x0c81, "Foxconn RC4107MA-RS2", 0), SND_PCI_QUIRK(0x15bd, 0x3100, "DFI RS482", 0), { } /* terminator */ }; --- linux-mvl-dove-2.6.32.orig/sound/pci/ice1712/maya44.c +++ linux-mvl-dove-2.6.32/sound/pci/ice1712/maya44.c @@ -347,7 +347,7 @@ /* known working input slots (0-4) */ #define MAYA_LINE_IN 1 /* in-2 */ -#define MAYA_MIC_IN 4 /* in-5 */ +#define MAYA_MIC_IN 3 /* in-4 */ static void wm8776_select_input(struct snd_maya44 *chip, int idx, int line) { @@ -393,8 +393,8 @@ int changed; mutex_lock(&chip->mutex); - changed = maya_set_gpio_bits(chip->ice, GPIO_MIC_RELAY, - sel ? GPIO_MIC_RELAY : 0); + changed = maya_set_gpio_bits(chip->ice, 1 << GPIO_MIC_RELAY, + sel ? (1 << GPIO_MIC_RELAY) : 0); wm8776_select_input(chip, 0, sel ? MAYA_MIC_IN : MAYA_LINE_IN); mutex_unlock(&chip->mutex); return changed; --- linux-mvl-dove-2.6.32.orig/sound/pci/ice1712/juli.c +++ linux-mvl-dove-2.6.32/sound/pci/ice1712/juli.c @@ -504,6 +504,31 @@ } /* + * suspend/resume + * */ + +#ifdef CONFIG_PM +static int juli_resume(struct snd_ice1712 *ice) +{ + struct snd_akm4xxx *ak = ice->akm; + struct juli_spec *spec = ice->spec; + /* akm4358 un-reset, un-mute */ + snd_akm4xxx_reset(ak, 0); + /* reinit ak4114 */ + snd_ak4114_reinit(spec->ak4114); + return 0; +} + +static int juli_suspend(struct snd_ice1712 *ice) +{ + struct snd_akm4xxx *ak = ice->akm; + /* akm4358 reset and soft-mute */ + snd_akm4xxx_reset(ak, 1); + return 0; +} +#endif + +/* * initialize the chip */ @@ -646,6 +671,13 @@ ice->set_spdif_clock = juli_set_spdif_clock; ice->spdif.ops.open = juli_spdif_in_open; + +#ifdef CONFIG_PM + ice->pm_resume = juli_resume; + ice->pm_suspend = juli_suspend; + ice->pm_suspend_enabled = 1; +#endif + return 0; } --- linux-mvl-dove-2.6.32.orig/sound/pci/au88x0/au88x0_pcm.c +++ linux-mvl-dove-2.6.32/sound/pci/au88x0/au88x0_pcm.c @@ -42,11 +42,7 @@ .rate_min = 5000, .rate_max = 48000, .channels_min = 1, -#ifdef CHIP_AU8830 - .channels_max = 4, -#else .channels_max = 2, -#endif .buffer_bytes_max = 0x10000, .period_bytes_min = 0x1, .period_bytes_max = 0x1000, @@ -115,6 +111,17 @@ .periods_max = 64, }; #endif +#ifdef CHIP_AU8830 +static unsigned int au8830_channels[3] = { + 1, 2, 4, +}; + +static struct snd_pcm_hw_constraint_list hw_constraints_au8830_channels = { + .count = ARRAY_SIZE(au8830_channels), + .list = au8830_channels, + .mask = 0, +}; +#endif /* open callback */ static int snd_vortex_pcm_open(struct snd_pcm_substream *substream) { @@ -156,6 +163,15 @@ if (VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_ADB || VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_I2S) runtime->hw = snd_vortex_playback_hw_adb; +#ifdef CHIP_AU8830 + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && + VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_ADB) { + runtime->hw.channels_max = 4; + snd_pcm_hw_constraint_list(runtime, 0, + SNDRV_PCM_HW_PARAM_CHANNELS, + &hw_constraints_au8830_channels); + } +#endif substream->runtime->private_data = NULL; } #ifndef CHIP_AU8810 --- linux-mvl-dove-2.6.32.orig/sound/pci/rme9652/hdsp.c +++ linux-mvl-dove-2.6.32/sound/pci/rme9652/hdsp.c @@ -4610,6 +4610,7 @@ if (err < 0) return err; + memset(&info, 0, sizeof(info)); spin_lock_irqsave(&hdsp->lock, flags); info.pref_sync_ref = (unsigned char)hdsp_pref_sync_ref(hdsp); info.wordclock_sync_check = (unsigned char)hdsp_wc_sync_check(hdsp); --- linux-mvl-dove-2.6.32.orig/sound/pci/rme9652/hdspm.c +++ linux-mvl-dove-2.6.32/sound/pci/rme9652/hdspm.c @@ -4127,6 +4127,7 @@ case SNDRV_HDSPM_IOCTL_GET_CONFIG_INFO: + memset(&info, 0, sizeof(info)); spin_lock_irq(&hdspm->lock); info.pref_sync_ref = hdspm_pref_sync_ref(hdspm); info.wordclock_sync_check = hdspm_wc_sync_check(hdspm); --- linux-mvl-dove-2.6.32.orig/sound/pci/ctxfi/ctatc.c +++ linux-mvl-dove-2.6.32/sound/pci/ctxfi/ctatc.c @@ -166,18 +166,7 @@ static unsigned long atc_get_ptp_phys(struct ct_atc *atc, int index) { - struct ct_vm *vm; - void *kvirt_addr; - unsigned long phys_addr; - - vm = atc->vm; - kvirt_addr = vm->get_ptp_virt(vm, index); - if (kvirt_addr == NULL) - phys_addr = (~0UL); - else - phys_addr = virt_to_phys(kvirt_addr); - - return phys_addr; + return atc->vm->get_ptp_phys(atc->vm, index); } static unsigned int convert_format(snd_pcm_format_t snd_format) @@ -879,7 +868,7 @@ mutex_lock(&atc->atc_mutex); dao->ops->get_spos(dao, &status); if (((status >> 24) & IEC958_AES3_CON_FS) != iec958_con_fs) { - status &= ((~IEC958_AES3_CON_FS) << 24); + status &= ~(IEC958_AES3_CON_FS << 24); status |= (iec958_con_fs << 24); dao->ops->set_spos(dao, status); dao->ops->commit_write(dao); @@ -1669,7 +1658,7 @@ } /* Set up device virtual memory management object */ - err = ct_vm_create(&atc->vm); + err = ct_vm_create(&atc->vm, pci); if (err < 0) goto error1; --- linux-mvl-dove-2.6.32.orig/sound/pci/ctxfi/ctdaio.c +++ linux-mvl-dove-2.6.32/sound/pci/ctxfi/ctdaio.c @@ -176,6 +176,7 @@ if (!entry) return -ENOMEM; + dao->ops->clear_left_input(dao); /* Program master and conjugate resources */ input->ops->master(input); daio->rscl.ops->master(&daio->rscl); @@ -204,6 +205,7 @@ if (!entry) return -ENOMEM; + dao->ops->clear_right_input(dao); /* Program master and conjugate resources */ input->ops->master(input); daio->rscr.ops->master(&daio->rscr); --- linux-mvl-dove-2.6.32.orig/sound/pci/ctxfi/ctvmem.c +++ linux-mvl-dove-2.6.32/sound/pci/ctxfi/ctvmem.c @@ -138,7 +138,7 @@ return NULL; } - ptp = vm->ptp[0]; + ptp = (unsigned long *)vm->ptp[0].area; pte_start = (block->addr >> CT_PAGE_SHIFT); pages = block->size >> CT_PAGE_SHIFT; for (i = 0; i < pages; i++) { @@ -158,25 +158,25 @@ } /* * - * return the host (kmalloced) addr of the @index-th device - * page talbe page on success, or NULL on failure. - * The first returned NULL indicates the termination. + * return the host physical addr of the @index-th device + * page table page on success, or ~0UL on failure. + * The first returned ~0UL indicates the termination. * */ -static void * -ct_get_ptp_virt(struct ct_vm *vm, int index) +static dma_addr_t +ct_get_ptp_phys(struct ct_vm *vm, int index) { - void *addr; + dma_addr_t addr; - addr = (index >= CT_PTP_NUM) ? NULL : vm->ptp[index]; + addr = (index >= CT_PTP_NUM) ? ~0UL : vm->ptp[index].addr; return addr; } -int ct_vm_create(struct ct_vm **rvm) +int ct_vm_create(struct ct_vm **rvm, struct pci_dev *pci) { struct ct_vm *vm; struct ct_vm_block *block; - int i; + int i, err = 0; *rvm = NULL; @@ -188,23 +188,21 @@ /* Allocate page table pages */ for (i = 0; i < CT_PTP_NUM; i++) { - vm->ptp[i] = kmalloc(PAGE_SIZE, GFP_KERNEL); - if (!vm->ptp[i]) + err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, + snd_dma_pci_data(pci), + PAGE_SIZE, &vm->ptp[i]); + if (err < 0) break; } - if (!i) { + if (err < 0) { /* no page table pages are allocated */ - kfree(vm); + ct_vm_destroy(vm); return -ENOMEM; } vm->size = CT_ADDRS_PER_PAGE * i; - /* Initialise remaining ptps */ - for (; i < CT_PTP_NUM; i++) - vm->ptp[i] = NULL; - vm->map = ct_vm_map; vm->unmap = ct_vm_unmap; - vm->get_ptp_virt = ct_get_ptp_virt; + vm->get_ptp_phys = ct_get_ptp_phys; INIT_LIST_HEAD(&vm->unused); INIT_LIST_HEAD(&vm->used); block = kzalloc(sizeof(*block), GFP_KERNEL); @@ -242,7 +240,7 @@ /* free allocated page table pages */ for (i = 0; i < CT_PTP_NUM; i++) - kfree(vm->ptp[i]); + snd_dma_free_pages(&vm->ptp[i]); vm->size = 0; --- linux-mvl-dove-2.6.32.orig/sound/pci/ctxfi/ctmixer.c +++ linux-mvl-dove-2.6.32/sound/pci/ctxfi/ctmixer.c @@ -566,19 +566,6 @@ return 0; } -static int ct_spdif_default_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - unsigned int status = SNDRV_PCM_DEFAULT_CON_SPDIF; - - ucontrol->value.iec958.status[0] = (status >> 0) & 0xff; - ucontrol->value.iec958.status[1] = (status >> 8) & 0xff; - ucontrol->value.iec958.status[2] = (status >> 16) & 0xff; - ucontrol->value.iec958.status[3] = (status >> 24) & 0xff; - - return 0; -} - static int ct_spdif_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -586,6 +573,10 @@ unsigned int status; atc->spdif_out_get_status(atc, &status); + + if (status == 0) + status = SNDRV_PCM_DEFAULT_CON_SPDIF; + ucontrol->value.iec958.status[0] = (status >> 0) & 0xff; ucontrol->value.iec958.status[1] = (status >> 8) & 0xff; ucontrol->value.iec958.status[2] = (status >> 16) & 0xff; @@ -629,7 +620,7 @@ .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT), .count = 1, .info = ct_spdif_info, - .get = ct_spdif_default_get, + .get = ct_spdif_get, .put = ct_spdif_put, .private_value = MIXER_IEC958_DEFAULT }; --- linux-mvl-dove-2.6.32.orig/sound/pci/ctxfi/ctvmem.h +++ linux-mvl-dove-2.6.32/sound/pci/ctxfi/ctvmem.h @@ -22,6 +22,8 @@ #include #include +#include +#include /* The chip can handle the page table of 4k pages * (emu20k1 can handle even 8k pages, but we don't use it right now) @@ -41,7 +43,7 @@ /* Virtual memory management object for card device */ struct ct_vm { - void *ptp[CT_PTP_NUM]; /* Device page table pages */ + struct snd_dma_buffer ptp[CT_PTP_NUM]; /* Device page table pages */ unsigned int size; /* Available addr space in bytes */ struct list_head unused; /* List of unused blocks */ struct list_head used; /* List of used blocks */ @@ -52,10 +54,10 @@ int size); /* Unmap device logical addr area. */ void (*unmap)(struct ct_vm *, struct ct_vm_block *block); - void *(*get_ptp_virt)(struct ct_vm *vm, int index); + dma_addr_t (*get_ptp_phys)(struct ct_vm *vm, int index); }; -int ct_vm_create(struct ct_vm **rvm); +int ct_vm_create(struct ct_vm **rvm, struct pci_dev *pci); void ct_vm_destroy(struct ct_vm *vm); #endif /* CTVMEM_H */ --- linux-mvl-dove-2.6.32.orig/sound/pci/hda/hda_local.h +++ linux-mvl-dove-2.6.32/sound/pci/hda/hda_local.h @@ -437,6 +437,15 @@ static inline int snd_hda_create_hwdep(struct hda_codec *codec) { return 0; } #endif +#ifdef CONFIG_SND_HDA_POWER_SAVE +int snd_hda_hwdep_add_power_sysfs(struct hda_codec *codec); +#else +static inline int snd_hda_hwdep_add_power_sysfs(struct hda_codec *codec) +{ + return 0; +} +#endif + #ifdef CONFIG_SND_HDA_RECONFIG int snd_hda_hwdep_add_sysfs(struct hda_codec *codec); #else --- linux-mvl-dove-2.6.32.orig/sound/pci/hda/hda_codec.c +++ linux-mvl-dove-2.6.32/sound/pci/hda/hda_codec.c @@ -515,6 +515,7 @@ struct hda_codec *codec; list_for_each_entry(codec, &bus->codec_list, list) { snd_hda_hwdep_add_sysfs(codec); + snd_hda_hwdep_add_power_sysfs(codec); } return 0; } @@ -2452,9 +2453,11 @@ codec->afg ? codec->afg : codec->mfg, AC_PWRST_D3); #ifdef CONFIG_SND_HDA_POWER_SAVE + snd_hda_update_power_acct(codec); cancel_delayed_work(&codec->power_work); codec->power_on = 0; codec->power_transition = 0; + codec->power_jiffies = jiffies; #endif } @@ -3207,6 +3210,17 @@ { codec->power_count++; codec->power_on = 1; + codec->power_jiffies = jiffies; +} + +void snd_hda_update_power_acct(struct hda_codec *codec) +{ + unsigned long delta = jiffies - codec->power_jiffies; + if (codec->power_on) + codec->power_on_acct += delta; + else + codec->power_off_acct += delta; + codec->power_jiffies += delta; } void snd_hda_power_up(struct hda_codec *codec) @@ -3217,7 +3231,9 @@ if (codec->power_on || codec->power_transition) return; + snd_hda_update_power_acct(codec); codec->power_on = 1; + codec->power_jiffies = jiffies; if (bus->ops.pm_notify) bus->ops.pm_notify(bus); hda_call_codec_resume(codec); --- linux-mvl-dove-2.6.32.orig/sound/pci/hda/patch_conexant.c +++ linux-mvl-dove-2.6.32/sound/pci/hda/patch_conexant.c @@ -366,10 +366,16 @@ struct conexant_spec *spec; struct conexant_jack *jack; const char *name; - int err; + int i, err; spec = codec->spec; snd_array_init(&spec->jacks, sizeof(*jack), 32); + + jack = spec->jacks.list; + for (i = 0; i < spec->jacks.used; i++, jack++) + if (jack->nid == nid) + return 0 ; /* already present */ + jack = snd_array_new(&spec->jacks); name = (type == SND_JACK_HEADPHONE) ? "Headphone" : "Mic" ; @@ -1175,9 +1181,12 @@ switch (codec->subsystem_id >> 16) { case 0x103c: - /* HP laptop has a really bad sound over 0dB on NID 0x17. - * Fix max PCM level to 0 dB - * (originall it has 0x2b steps with 0dB offset 0x14) + case 0x1631: + case 0x1734: + case 0x17aa: + /* HP, Packard Bell, Fujitsu-Siemens & Lenovo laptops have + * really bad sound over 0dB on NID 0x17. Fix max PCM level to + * 0 dB (originally it has 0x2b steps with 0dB offset 0x14) */ snd_hda_override_amp_caps(codec, 0x17, HDA_INPUT, (0x14 << AC_AMPCAP_OFFSET_SHIFT) | @@ -1581,6 +1590,21 @@ #endif } spec->vmaster_nid = 0x13; + + switch (codec->subsystem_id >> 16) { + case 0x103c: + /* HP laptops have really bad sound over 0 dB on NID 0x10. + * Fix max PCM level to 0 dB (originally it has 0x1e steps + * with 0 dB offset 0x17) + */ + snd_hda_override_amp_caps(codec, 0x10, HDA_INPUT, + (0x17 << AC_AMPCAP_OFFSET_SHIFT) | + (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) | + (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) | + (1 << AC_AMPCAP_MUTE_SHIFT)); + break; + } + return 0; } @@ -2333,6 +2357,8 @@ SND_PCI_QUIRK(0x1028, 0x02f5, "Dell", CXT5066_DELL_LAPTOP), SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT5066_OLPC_XO_1_5), + SND_PCI_QUIRK(0x1179, 0xff50, "Toshiba Satellite P500-PSPGSC-01800T", CXT5066_OLPC_XO_1_5), + SND_PCI_QUIRK(0x1179, 0xffe0, "Toshiba Satellite Pro T130-15F", CXT5066_OLPC_XO_1_5), {} }; --- linux-mvl-dove-2.6.32.orig/sound/pci/hda/hda_codec.h +++ linux-mvl-dove-2.6.32/sound/pci/hda/hda_codec.h @@ -811,6 +811,9 @@ unsigned int power_transition :1; /* power-state in transition */ int power_count; /* current (global) power refcount */ struct delayed_work power_work; /* delayed task for powerdown */ + unsigned long power_on_acct; + unsigned long power_off_acct; + unsigned long power_jiffies; #endif /* codec-specific additional proc output */ @@ -933,6 +936,7 @@ void snd_hda_power_up(struct hda_codec *codec); void snd_hda_power_down(struct hda_codec *codec); #define snd_hda_codec_needs_resume(codec) codec->power_count +void snd_hda_update_power_acct(struct hda_codec *codec); #else static inline void snd_hda_power_up(struct hda_codec *codec) {} static inline void snd_hda_power_down(struct hda_codec *codec) {} --- linux-mvl-dove-2.6.32.orig/sound/pci/hda/hda_hwdep.c +++ linux-mvl-dove-2.6.32/sound/pci/hda/hda_hwdep.c @@ -154,6 +154,44 @@ return 0; } +#ifdef CONFIG_SND_HDA_POWER_SAVE +static ssize_t power_on_acct_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct snd_hwdep *hwdep = dev_get_drvdata(dev); + struct hda_codec *codec = hwdep->private_data; + snd_hda_update_power_acct(codec); + return sprintf(buf, "%u\n", jiffies_to_msecs(codec->power_on_acct)); +} + +static ssize_t power_off_acct_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct snd_hwdep *hwdep = dev_get_drvdata(dev); + struct hda_codec *codec = hwdep->private_data; + snd_hda_update_power_acct(codec); + return sprintf(buf, "%u\n", jiffies_to_msecs(codec->power_off_acct)); +} + +static struct device_attribute power_attrs[] = { + __ATTR_RO(power_on_acct), + __ATTR_RO(power_off_acct), +}; + +int snd_hda_hwdep_add_power_sysfs(struct hda_codec *codec) +{ + struct snd_hwdep *hwdep = codec->hwdep; + int i; + + for (i = 0; i < ARRAY_SIZE(power_attrs); i++) + snd_add_device_sysfs_file(SNDRV_DEVICE_TYPE_HWDEP, hwdep->card, + hwdep->device, &power_attrs[i]); + return 0; +} +#endif /* CONFIG_SND_HDA_POWER_SAVE */ + #ifdef CONFIG_SND_HDA_RECONFIG /* --- linux-mvl-dove-2.6.32.orig/sound/pci/hda/patch_intelhdmi.c +++ linux-mvl-dove-2.6.32/sound/pci/hda/patch_intelhdmi.c @@ -684,7 +684,7 @@ { .id = 0x80862801, .name = "G45 DEVBLC", .patch = patch_intel_hdmi }, { .id = 0x80862802, .name = "G45 DEVCTG", .patch = patch_intel_hdmi }, { .id = 0x80862803, .name = "G45 DEVELK", .patch = patch_intel_hdmi }, - { .id = 0x80862804, .name = "G45 DEVIBX", .patch = patch_intel_hdmi }, + { .id = 0x80862804, .name = "G45 DEVIBX", .patch = patch_intel_hdmi_ibexpeak }, { .id = 0x80860054, .name = "Q57 DEVIBX", .patch = patch_intel_hdmi_ibexpeak }, { .id = 0x10951392, .name = "SiI1392 HDMI", .patch = patch_intel_hdmi }, {} /* terminator */ --- linux-mvl-dove-2.6.32.orig/sound/pci/hda/hda_eld.c +++ linux-mvl-dove-2.6.32/sound/pci/hda/hda_eld.c @@ -383,7 +383,7 @@ snd_print_pcm_rates(a->rates, buf, sizeof(buf)); if (a->format == AUDIO_CODING_TYPE_LPCM) - snd_print_pcm_bits(a->sample_bits, buf2 + 8, sizeof(buf2 - 8)); + snd_print_pcm_bits(a->sample_bits, buf2 + 8, sizeof(buf2) - 8); else if (a->max_bitrate) snprintf(buf2, sizeof(buf2), ", max bitrate = %d", a->max_bitrate); --- linux-mvl-dove-2.6.32.orig/sound/pci/hda/patch_realtek.c +++ linux-mvl-dove-2.6.32/sound/pci/hda/patch_realtek.c @@ -400,6 +400,8 @@ unsigned int mux_idx = snd_ctl_get_ioffidx(kcontrol, &uinfo->id); if (mux_idx >= spec->num_mux_defs) mux_idx = 0; + if (!spec->input_mux[mux_idx].num_items && mux_idx > 0) + mux_idx = 0; return snd_hda_input_mux_info(&spec->input_mux[mux_idx], uinfo); } @@ -428,6 +430,8 @@ mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx; imux = &spec->input_mux[mux_idx]; + if (!imux->num_items && mux_idx > 0) + imux = &spec->input_mux[0]; type = get_wcaps_type(get_wcaps(codec, nid)); if (type == AC_WID_AUD_MIX) { @@ -1149,7 +1153,7 @@ case 0x10ec0883: case 0x10ec0885: case 0x10ec0887: - case 0x10ec0889: + /*case 0x10ec0889:*/ /* this causes an SPDIF problem */ alc889_coef_init(codec); break; case 0x10ec0888: @@ -2401,6 +2405,8 @@ "Speaker Playback Switch", "Mono Playback Switch", "IEC958 Playback Switch", + "Line-Out Playback Switch", + "PCM Playback Switch", NULL, }; @@ -3965,10 +3971,11 @@ SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_5ST_DIG), SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_F1734), SND_PCI_QUIRK(0x1734, 0x1094, "FSC Amilo M1451G", ALC880_FUJITSU), - SND_PCI_QUIRK(0x1734, 0x10ac, "FSC", ALC880_UNIWILL), + SND_PCI_QUIRK(0x1734, 0x10ac, "FSC AMILO Xi 1526", ALC880_F1734), SND_PCI_QUIRK(0x1734, 0x10b0, "Fujitsu", ALC880_FUJITSU), SND_PCI_QUIRK(0x1854, 0x0018, "LG LW20", ALC880_LG_LW), SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_LG), + SND_PCI_QUIRK(0x1854, 0x005f, "LG P1 Express", ALC880_LG), SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_LG), SND_PCI_QUIRK(0x1854, 0x0077, "LG LW25", ALC880_LG_LW), SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_TCL_S700), @@ -6246,6 +6253,7 @@ static struct snd_pci_quirk alc260_cfg_tbl[] = { SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_ACER), + SND_PCI_QUIRK(0x1025, 0x007f, "Acer", ALC260_WILL), SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_ACER), SND_PCI_QUIRK(0x1509, 0x4540, "Favorit 100XS", ALC260_FAVORIT100), SND_PCI_QUIRK(0x103c, 0x2808, "HP d5700", ALC260_HP_3013), @@ -6275,7 +6283,7 @@ .num_dacs = ARRAY_SIZE(alc260_dac_nids), .dac_nids = alc260_dac_nids, .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids), - .adc_nids = alc260_adc_nids, + .adc_nids = alc260_dual_adc_nids, .num_channel_mode = ARRAY_SIZE(alc260_modes), .channel_mode = alc260_modes, .input_mux = &alc260_capture_source, @@ -6448,6 +6456,7 @@ spec->stream_analog_playback = &alc260_pcm_analog_playback; spec->stream_analog_capture = &alc260_pcm_analog_capture; + spec->stream_analog_alt_capture = &alc260_pcm_analog_capture; spec->stream_digital_playback = &alc260_pcm_digital_playback; spec->stream_digital_capture = &alc260_pcm_digital_capture; @@ -6581,7 +6590,7 @@ .num_items = 4, .items = { { "Mic", 0x0 }, - { "iMic", 0x1 }, + { "Int Mic", 0x1 }, { "Line", 0x2 }, { "CD", 0x4 }, }, @@ -7040,8 +7049,8 @@ HDA_BIND_MUTE ("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT), HDA_CODEC_VOLUME("LFE Playback Volume", 0x0e, 0x00, HDA_OUTPUT), HDA_BIND_MUTE ("LFE Playback Switch", 0x0e, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("HP Playback Volume", 0x0f, 0x00, HDA_OUTPUT), - HDA_BIND_MUTE ("HP Playback Switch", 0x0f, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0f, 0x00, HDA_OUTPUT), + HDA_BIND_MUTE ("Headphone Playback Switch", 0x0f, 0x02, HDA_INPUT), HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), @@ -7428,6 +7437,7 @@ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, {0x14, AC_VERB_SET_CONNECT_SEL, 0x03}, + {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, /* Front Mic pin: input vref at 80% */ {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, @@ -7552,6 +7562,27 @@ spec->autocfg.speaker_pins[0] = 0x14; } +static void alc885_mb5_automute(struct hda_codec *codec) +{ + unsigned int present; + + present = snd_hda_codec_read(codec, 0x14, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + snd_hda_codec_amp_stereo(codec, 0x18, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); + snd_hda_codec_amp_stereo(codec, 0x1a, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); + +} + +static void alc885_mb5_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + /* Headphone insertion or removal. */ + if ((res >> 26) == ALC880_HP_EVENT) + alc885_mb5_automute(codec); +} + static struct hda_verb alc882_targa_verbs[] = { {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, @@ -8008,8 +8039,8 @@ HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("iMic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("iMic Playback Switch", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), { } /* end */ }; @@ -8839,7 +8870,7 @@ SND_PCI_QUIRK(0x1462, 0x040d, "MSI", ALC883_TARGA_2ch_DIG), SND_PCI_QUIRK(0x1462, 0x0579, "MSI", ALC883_TARGA_2ch_DIG), SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8 */ - SND_PCI_QUIRK(0x1462, 0x2fb3, "MSI", ALC883_TARGA_2ch_DIG), + SND_PCI_QUIRK(0x1462, 0x2fb3, "MSI", ALC882_AUTO), SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG), SND_PCI_QUIRK(0x1462, 0x3729, "MSI S420", ALC883_TARGA_DIG), SND_PCI_QUIRK(0x1462, 0x3783, "NEC S970", ALC883_TARGA_DIG), @@ -8866,6 +8897,7 @@ SND_PCI_QUIRK(0x1462, 0xaa08, "MSI", ALC883_TARGA_2ch_DIG), SND_PCI_QUIRK(0x147b, 0x1083, "Abit IP35-PRO", ALC883_6ST_DIG), + SND_PCI_QUIRK(0x1558, 0x0571, "Clevo laptop M570U", ALC883_3ST_6ch_DIG), SND_PCI_QUIRK(0x1558, 0x0721, "Clevo laptop M720R", ALC883_CLEVO_M720), SND_PCI_QUIRK(0x1558, 0x0722, "Clevo laptop M720SR", ALC883_CLEVO_M720), SND_PCI_QUIRK(0x1558, 0x5409, "Clevo laptop M540R", ALC883_CLEVO_M540R), @@ -8893,7 +8925,7 @@ SND_PCI_QUIRK(0x8086, 0x0022, "DX58SO", ALC889_INTEL), SND_PCI_QUIRK(0x8086, 0x0021, "Intel IbexPeak", ALC889A_INTEL), SND_PCI_QUIRK(0x8086, 0x3b56, "Intel IbexPeak", ALC889A_INTEL), - SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC883_3ST_6ch), + SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC882_6ST_DIG), {} }; @@ -8907,10 +8939,12 @@ SND_PCI_QUIRK(0x106b, 0x1000, "iMac 24", ALC885_IMAC24), SND_PCI_QUIRK(0x106b, 0x2800, "AppleTV", ALC885_IMAC24), SND_PCI_QUIRK(0x106b, 0x2c00, "MacbookPro rev3", ALC885_MBP3), + SND_PCI_QUIRK(0x106b, 0x3000, "iMac", ALC889A_MB31), SND_PCI_QUIRK(0x106b, 0x3600, "Macbook 3,1", ALC889A_MB31), SND_PCI_QUIRK(0x106b, 0x3800, "MacbookPro 4,1", ALC885_MBP3), SND_PCI_QUIRK(0x106b, 0x3e00, "iMac 24 Aluminum", ALC885_IMAC24), SND_PCI_QUIRK(0x106b, 0x3f00, "Macbook 5,1", ALC885_MB5), + SND_PCI_QUIRK(0x106b, 0x4a00, "Macbook 5,2", ALC885_MB5), /* FIXME: HP jack sense seems not working for MBP 5,1 or 5,2, * so apparently no perfect solution yet */ @@ -8994,6 +9028,8 @@ .input_mux = &mb5_capture_source, .dig_out_nid = ALC882_DIGOUT_NID, .dig_in_nid = ALC882_DIGIN_NID, + .unsol_event = alc885_mb5_unsol_event, + .init_hook = alc885_mb5_automute, }, [ALC885_MACPRO] = { .mixers = { alc882_macpro_mixer }, @@ -9141,6 +9177,8 @@ .dac_nids = alc883_dac_nids, .num_adc_nids = ARRAY_SIZE(alc889_adc_nids), .adc_nids = alc889_adc_nids, + .capsrc_nids = alc889_capsrc_nids, + .capsrc_nids = alc889_capsrc_nids, .dig_out_nid = ALC883_DIGOUT_NID, .dig_in_nid = ALC883_DIGIN_NID, .slave_dig_outs = alc883_slave_dig_outs, @@ -9187,6 +9225,7 @@ .dac_nids = alc883_dac_nids, .adc_nids = alc883_adc_nids_alt, .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt), + .capsrc_nids = alc883_capsrc_nids, .dig_out_nid = ALC883_DIGOUT_NID, .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), .channel_mode = alc883_3ST_2ch_modes, @@ -9333,6 +9372,7 @@ .dac_nids = alc883_dac_nids, .adc_nids = alc883_adc_nids_alt, .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt), + .capsrc_nids = alc883_capsrc_nids, .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes), .channel_mode = alc883_sixstack_modes, .input_mux = &alc883_capture_source, @@ -9394,6 +9434,7 @@ .dac_nids = alc883_dac_nids, .adc_nids = alc883_adc_nids_alt, .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt), + .capsrc_nids = alc883_capsrc_nids, .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), .channel_mode = alc883_3ST_2ch_modes, .input_mux = &alc883_lenovo_101e_capture_source, @@ -9573,6 +9614,7 @@ alc880_gpio1_init_verbs }, .adc_nids = alc883_adc_nids, .num_adc_nids = ARRAY_SIZE(alc883_adc_nids), + .capsrc_nids = alc883_capsrc_nids, .dac_nids = alc883_dac_nids, .num_dacs = ARRAY_SIZE(alc883_dac_nids), .channel_mode = alc889A_mb31_6ch_modes, @@ -9711,6 +9753,8 @@ continue; mux_idx = c >= spec->num_mux_defs ? 0 : c; imux = &spec->input_mux[mux_idx]; + if (!imux->num_items && mux_idx > 0) + imux = &spec->input_mux[0]; for (idx = 0; idx < conns; idx++) { /* if the current connection is the selected one, * unmute it as default - otherwise mute it @@ -10146,7 +10190,7 @@ struct alc_spec *spec = codec->spec; spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x0c; /* HACK: not actually a pin */ + spec->autocfg.speaker_pins[0] = 0x14; } static struct snd_kcontrol_new alc262_hp_t5735_mixer[] = { @@ -10581,6 +10625,13 @@ {} }; +static struct hda_verb alc262_lenovo_3000_init_verbs[] = { + /* Front Mic pin: input vref at 50% */ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {} +}; + static struct hda_input_mux alc262_fujitsu_capture_source = { .num_items = 3, .items = { @@ -11580,9 +11631,9 @@ .num_channel_mode = ARRAY_SIZE(alc262_modes), .channel_mode = alc262_modes, .input_mux = &alc262_capture_source, - .unsol_event = alc_automute_amp_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc262_hp_t5735_setup, - .init_hook = alc_automute_amp, + .init_hook = alc_inithook, }, [ALC262_HP_RP5700] = { .mixers = { alc262_hp_rp5700_mixer }, @@ -11648,7 +11699,8 @@ [ALC262_LENOVO_3000] = { .mixers = { alc262_lenovo_3000_mixer }, .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs, - alc262_lenovo_3000_unsol_verbs }, + alc262_lenovo_3000_unsol_verbs, + alc262_lenovo_3000_init_verbs }, .num_dacs = ARRAY_SIZE(alc262_dac_nids), .dac_nids = alc262_dac_nids, .hp_nid = 0x03, @@ -12338,6 +12390,9 @@ dac = 0x02; break; case 0x15: + case 0x1a: /* ALC259/269 only */ + case 0x1b: /* ALC259/269 only */ + case 0x21: /* ALC269vb has this pin, too */ dac = 0x03; break; default: @@ -12607,6 +12662,7 @@ SND_PCI_QUIRK(0x1025, 0x015b, "Acer Aspire One", ALC268_ACER_ASPIRE_ONE), SND_PCI_QUIRK(0x1028, 0x0253, "Dell OEM", ALC268_DELL), + SND_PCI_QUIRK(0x1028, 0x02b0, "Dell Inspiron 910", ALC268_AUTO), SND_PCI_QUIRK_MASK(0x1028, 0xfff0, 0x02b0, "Dell Inspiron Mini9/Vostro A90", ALC268_DELL), /* almost compatible with toshiba but with optional digital outs; @@ -14679,6 +14735,8 @@ spec->stream_digital_playback = &alc861_pcm_digital_playback; spec->stream_digital_capture = &alc861_pcm_digital_capture; + if (!spec->cap_mixer) + set_capture_mixer(codec); set_beep_amp(spec, 0x23, 0, HDA_OUTPUT); spec->vmaster_nid = 0x03; @@ -15317,7 +15375,7 @@ static int alc861vd_auto_create_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) { - return alc_auto_create_input_ctls(codec, cfg, 0x15, 0x09, 0); + return alc_auto_create_input_ctls(codec, cfg, 0x15, 0x22, 0); } @@ -17204,6 +17262,8 @@ return 0x02; else if (nid >= 0x0c && nid <= 0x0e) return nid - 0x0c + 0x02; + else if (nid == 0x26) /* ALC887-VD has this DAC too */ + return 0x25; else return 0; } @@ -17212,7 +17272,7 @@ static hda_nid_t alc662_dac_to_mix(struct hda_codec *codec, hda_nid_t pin, hda_nid_t dac) { - hda_nid_t mix[4]; + hda_nid_t mix[5]; int i, num; num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix)); --- linux-mvl-dove-2.6.32.orig/sound/pci/hda/patch_cirrus.c +++ linux-mvl-dove-2.6.32/sound/pci/hda/patch_cirrus.c @@ -65,7 +65,9 @@ /* available models */ enum { + CS420X_MBP53, CS420X_MBP55, + CS420X_IMAC27, CS420X_AUTO, CS420X_MODELS }; @@ -832,7 +834,9 @@ AC_VERB_SET_PIN_WIDGET_CONTROL, hp_present ? 0 : PIN_OUT); } - if (spec->board_config == CS420X_MBP55) { + if (spec->board_config == CS420X_MBP53 || + spec->board_config == CS420X_MBP55 || + spec->board_config == CS420X_IMAC27) { unsigned int gpio = hp_present ? 0x02 : 0x08; snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, gpio); @@ -1077,13 +1081,19 @@ } static const char *cs420x_models[CS420X_MODELS] = { + [CS420X_MBP53] = "mbp53", [CS420X_MBP55] = "mbp55", + [CS420X_IMAC27] = "imac27", [CS420X_AUTO] = "auto", }; static struct snd_pci_quirk cs420x_cfg_tbl[] = { + SND_PCI_QUIRK(0x10de, 0x0ac0, "MacBookPro 5,3", CS420X_MBP53), + SND_PCI_QUIRK(0x10de, 0x0d94, "MacBookAir 3,1(2)", CS420X_MBP55), SND_PCI_QUIRK(0x10de, 0xcb79, "MacBookPro 5,5", CS420X_MBP55), + SND_PCI_QUIRK(0x10de, 0xcb89, "MacBookPro 7,1", CS420X_MBP55), + SND_PCI_QUIRK(0x8086, 0x7270, "IMac 27 Inch", CS420X_IMAC27), {} /* terminator */ }; @@ -1092,6 +1102,20 @@ u32 val; }; +static struct cs_pincfg mbp53_pincfgs[] = { + { 0x09, 0x012b4050 }, + { 0x0a, 0x90100141 }, + { 0x0b, 0x90100140 }, + { 0x0c, 0x018b3020 }, + { 0x0d, 0x90a00110 }, + { 0x0e, 0x400000f0 }, + { 0x0f, 0x01cbe030 }, + { 0x10, 0x014be060 }, + { 0x12, 0x400000f0 }, + { 0x15, 0x400000f0 }, + {} /* terminator */ +}; + static struct cs_pincfg mbp55_pincfgs[] = { { 0x09, 0x012b4030 }, { 0x0a, 0x90100121 }, @@ -1106,8 +1130,24 @@ {} /* terminator */ }; +static struct cs_pincfg imac27_pincfgs[] = { + { 0x09, 0x012b4050 }, + { 0x0a, 0x90100140 }, + { 0x0b, 0x90100142 }, + { 0x0c, 0x018b3020 }, + { 0x0d, 0x90a00110 }, + { 0x0e, 0x400000f0 }, + { 0x0f, 0x01cbe030 }, + { 0x10, 0x014be060 }, + { 0x12, 0x01ab9070 }, + { 0x15, 0x400000f0 }, + {} /* terminator */ +}; + static struct cs_pincfg *cs_pincfgs[CS420X_MODELS] = { + [CS420X_MBP53] = mbp53_pincfgs, [CS420X_MBP55] = mbp55_pincfgs, + [CS420X_IMAC27] = imac27_pincfgs, }; static void fix_pincfg(struct hda_codec *codec, int model) @@ -1137,6 +1177,8 @@ fix_pincfg(codec, spec->board_config); switch (spec->board_config) { + case CS420X_IMAC27: + case CS420X_MBP53: case CS420X_MBP55: /* GPIO1 = headphones */ /* GPIO3 = speakers */ --- linux-mvl-dove-2.6.32.orig/sound/pci/hda/patch_analog.c +++ linux-mvl-dove-2.6.32/sound/pci/hda/patch_analog.c @@ -1003,7 +1003,7 @@ SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS M2N", AD1986A_3STACK), SND_PCI_QUIRK(0x1043, 0x8234, "ASUS M2N", AD1986A_3STACK), SND_PCI_QUIRK(0x10de, 0xcb84, "ASUS A8N-VM", AD1986A_3STACK), - SND_PCI_QUIRK(0x1179, 0xff40, "Toshiba", AD1986A_LAPTOP_EAPD), + SND_PCI_QUIRK(0x1179, 0xff40, "Toshiba Satellite L40-10Q", AD1986A_3STACK), SND_PCI_QUIRK(0x144d, 0xb03c, "Samsung R55", AD1986A_3STACK), SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_LAPTOP), SND_PCI_QUIRK(0x144d, 0xc024, "Samsung P50", AD1986A_SAMSUNG_P50), @@ -1789,6 +1789,14 @@ case AD1981_THINKPAD: spec->mixers[0] = ad1981_thinkpad_mixers; spec->input_mux = &ad1981_thinkpad_capture_source; + /* set the upper-limit for mixer amp to 0dB for avoiding the + * possible damage by overloading + */ + snd_hda_override_amp_caps(codec, 0x11, HDA_INPUT, + (0x17 << AC_AMPCAP_OFFSET_SHIFT) | + (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) | + (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) | + (1 << AC_AMPCAP_MUTE_SHIFT)); break; case AD1981_TOSHIBA: spec->mixers[0] = ad1981_hp_mixers; @@ -3502,6 +3510,7 @@ /* Lenovo Thinkpad T61/X61 */ SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1984_THINKPAD), SND_PCI_QUIRK(0x1028, 0x0214, "Dell T3400", AD1984_DELL_DESKTOP), + SND_PCI_QUIRK(0x1028, 0x0233, "Dell Latitude E6400", AD1984_DELL_DESKTOP), {} }; --- linux-mvl-dove-2.6.32.orig/sound/pci/hda/patch_sigmatel.c +++ linux-mvl-dove-2.6.32/sound/pci/hda/patch_sigmatel.c @@ -727,7 +727,7 @@ struct sigmatel_spec *spec = codec->spec; unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); const struct hda_input_mux *imux = spec->input_mux; - unsigned int idx, prev_idx; + unsigned int idx, prev_idx, didx; idx = ucontrol->value.enumerated.item[0]; if (idx >= imux->num_items) @@ -739,7 +739,8 @@ snd_hda_codec_write_cache(codec, spec->mux_nids[adc_idx], 0, AC_VERB_SET_CONNECT_SEL, imux->items[idx].index); - if (prev_idx >= spec->num_analog_muxes) { + if (prev_idx >= spec->num_analog_muxes && + spec->mux_nids[adc_idx] != spec->dmux_nids[adc_idx]) { imux = spec->dinput_mux; /* 0 = analog */ snd_hda_codec_write_cache(codec, @@ -749,9 +750,13 @@ } } else { imux = spec->dinput_mux; + /* first dimux item is hardcoded to select analog imux, + * so lets skip it + */ + didx = idx - spec->num_analog_muxes + 1; snd_hda_codec_write_cache(codec, spec->dmux_nids[adc_idx], 0, AC_VERB_SET_CONNECT_SEL, - imux->items[idx - 1].index); + imux->items[didx].index); } spec->cur_mux[adc_idx] = idx; return 1; @@ -1592,12 +1597,18 @@ "Dell Studio 1555", STAC_DELL_M6_DMIC), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02bd, "Dell Studio 1557", STAC_DELL_M6_DMIC), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02fe, + "Dell Studio XPS 1645", STAC_DELL_M6_BOTH), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0413, + "Dell Studio 1558", STAC_DELL_M6_DMIC), {} /* terminator */ }; static struct snd_pci_quirk stac92hd73xx_codec_id_cfg_tbl[] = { SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02a1, "Alienware M17x", STAC_ALIENWARE_M17X), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x043a, + "Alienware M17x", STAC_ALIENWARE_M17X), {} /* terminator */ }; @@ -1712,6 +1723,8 @@ "HP HDX", STAC_HP_HDX), /* HDX16 */ SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x3620, "HP dv6", STAC_HP_DV5), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3061, + "HP dv6", STAC_HP_DV5), /* HP dv6-1110ax */ SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x7010, "HP", STAC_HP_DV5), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0233, @@ -2053,12 +2066,12 @@ SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_INTEL, 0xff00, 0x2000, "Intel D965", STAC_D965_3ST), /* Dell 3 stack systems */ - SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f7, "Dell XPS M1730", STAC_DELL_3ST), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01dd, "Dell Dimension E520", STAC_DELL_3ST), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ed, "Dell ", STAC_DELL_3ST), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f4, "Dell ", STAC_DELL_3ST), /* Dell 3 stack systems with verb table in BIOS */ SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f3, "Dell Inspiron 1420", STAC_DELL_BIOS), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f7, "Dell XPS M1730", STAC_DELL_BIOS), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0227, "Dell Vostro 1400 ", STAC_DELL_BIOS), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x022e, "Dell ", STAC_DELL_BIOS), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x022f, "Dell Inspiron 1525", STAC_DELL_BIOS), --- linux-mvl-dove-2.6.32.orig/sound/pci/hda/hda_intel.c +++ linux-mvl-dove-2.6.32/sound/pci/hda/hda_intel.c @@ -116,6 +116,7 @@ "{Intel, ICH9}," "{Intel, ICH10}," "{Intel, PCH}," + "{Intel, CPT}," "{Intel, SCH}," "{ATI, SB450}," "{ATI, SB600}," @@ -437,6 +438,7 @@ /* driver types */ enum { AZX_DRIVER_ICH, + AZX_DRIVER_PCH, AZX_DRIVER_SCH, AZX_DRIVER_ATI, AZX_DRIVER_ATIHDMI, @@ -451,6 +453,7 @@ static char *driver_short_names[] __devinitdata = { [AZX_DRIVER_ICH] = "HDA Intel", + [AZX_DRIVER_PCH] = "HDA Intel PCH", [AZX_DRIVER_SCH] = "HDA Intel MID", [AZX_DRIVER_ATI] = "HDA ATI SB", [AZX_DRIVER_ATIHDMI] = "HDA ATI HDMI", @@ -1039,6 +1042,7 @@ 0x01, NVIDIA_HDA_ENABLE_COHBIT); break; case AZX_DRIVER_SCH: + case AZX_DRIVER_PCH: pci_read_config_word(chip->pci, INTEL_SCH_HDA_DEVC, &snoop); if (snoop & INTEL_SCH_HDA_DEVC_NOSNOOP) { pci_write_config_word(chip->pci, INTEL_SCH_HDA_DEVC, @@ -1858,6 +1862,9 @@ if (!bdl_pos_adj[chip->dev_index]) return 1; /* no delayed ack */ + if (WARN_ONCE(!azx_dev->period_bytes, + "hda-intel: zero azx_dev->period_bytes")) + return 0; /* this shouldn't happen! */ if (pos % azx_dev->period_bytes > azx_dev->period_bytes / 2) return 0; /* NG - it's below the period boundary */ return 1; /* OK, it's fine */ @@ -1944,6 +1951,7 @@ struct azx_pcm *apcm; int pcm_dev = cpcm->device; int s, err; + size_t prealloc_min = 64*1024; /* 64KB */ if (pcm_dev >= AZX_MAX_PCMS) { snd_printk(KERN_ERR SFX "Invalid PCM device number %d\n", @@ -1977,10 +1985,21 @@ if (cpcm->stream[s].substreams) snd_pcm_set_ops(pcm, s, &azx_pcm_ops); } + /* buffer pre-allocation */ + + /* subtle, don't allocate a big buffer for modems... + * also, don't just test 32BIT_MASK, since azx supports + * 64-bit DMA in some cases. + */ + /* lennart wants a 2.2MB buffer for 2sec of 48khz */ + if (pcm->dev_class == SNDRV_PCM_CLASS_GENERIC && + chip->pci->dma_mask >= DMA_32BIT_MASK) + prealloc_min = 4 * 1024 * 1024; /* 4MB */ + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG, snd_dma_pci_data(chip->pci), - 1024 * 64, 32 * 1024 * 1024); + prealloc_min, 32 * 1024 * 1024); return 0; } @@ -2219,9 +2238,27 @@ * white/black-listing for position_fix */ static struct snd_pci_quirk position_fix_list[] __devinitdata = { + SND_PCI_QUIRK(0x1025, 0x009f, "Acer Aspire 5110", POS_FIX_LPIB), SND_PCI_QUIRK(0x1028, 0x01cc, "Dell D820", POS_FIX_LPIB), SND_PCI_QUIRK(0x1028, 0x01de, "Dell Precision 390", POS_FIX_LPIB), + SND_PCI_QUIRK(0x1028, 0x01f6, "Dell Latitude 131L", POS_FIX_LPIB), + SND_PCI_QUIRK(0x1028, 0x0470, "Dell Inspiron 1120", POS_FIX_LPIB), + SND_PCI_QUIRK(0x103c, 0x306d, "HP dv3", POS_FIX_LPIB), + SND_PCI_QUIRK(0x1028, 0x01f6, "Dell Latitude 131L", POS_FIX_LPIB), SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", POS_FIX_LPIB), + SND_PCI_QUIRK(0x1043, 0x81b3, "ASUS", POS_FIX_LPIB), + SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS M2V", POS_FIX_LPIB), + SND_PCI_QUIRK(0x1043, 0x8410, "ASUS", POS_FIX_LPIB), + SND_PCI_QUIRK(0x104d, 0x9069, "Sony VPCS11V9E", POS_FIX_LPIB), + SND_PCI_QUIRK(0x1106, 0x3288, "ASUS M2V-MX SE", POS_FIX_LPIB), + SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba A100-259", POS_FIX_LPIB), + SND_PCI_QUIRK(0x1297, 0x3166, "Shuttle", POS_FIX_LPIB), + SND_PCI_QUIRK(0x1458, 0xa022, "ga-ma770-ud3", POS_FIX_LPIB), + SND_PCI_QUIRK(0x1462, 0x1002, "MSI Wind U115", POS_FIX_LPIB), + SND_PCI_QUIRK(0x1565, 0x820f, "Biostar Microtech", POS_FIX_LPIB), + SND_PCI_QUIRK(0x1565, 0x8218, "Biostar Microtech", POS_FIX_LPIB), + SND_PCI_QUIRK(0x8086, 0x2503, "DG965OT AAD63733-203", POS_FIX_LPIB), + SND_PCI_QUIRK(0x8086, 0xd601, "eMachines T5212", POS_FIX_LPIB), {} }; @@ -2309,6 +2346,7 @@ static struct snd_pci_quirk msi_white_list[] __devinitdata = { SND_PCI_QUIRK(0x103c, 0x30f7, "HP Pavilion dv4t-1300", 1), SND_PCI_QUIRK(0x103c, 0x3607, "HP Compa CQ40", 1), + SND_PCI_QUIRK(0x107b, 0x0380, "Gateway M-6866", 1), {} }; @@ -2325,6 +2363,13 @@ "hda_intel: msi for device %04x:%04x set to %d\n", q->subvendor, q->subdevice, q->value); chip->msi = q->value; + return; + } + + /* NVidia chipsets seem to cause troubles with MSI */ + if (chip->driver_type == AZX_DRIVER_NVIDIA) { + printk(KERN_INFO "hda_intel: Disable MSI for Nvidia chipset\n"); + chip->msi = 0; } } @@ -2374,6 +2419,7 @@ if (bdl_pos_adj[dev] < 0) { switch (chip->driver_type) { case AZX_DRIVER_ICH: + case AZX_DRIVER_PCH: bdl_pos_adj[dev] = 1; break; default: @@ -2436,6 +2482,11 @@ } } + /* disable 64bit DMA address for Teradici */ + /* it does not work with device 6549:1200 subsys e4a2:040b */ + if (chip->driver_type == AZX_DRIVER_TERA) + gcap &= ~ICH6_GCAP_64OK; + /* allow 64bit DMA address if supported by H/W */ if ((gcap & ICH6_GCAP_64OK) && !pci_set_dma_mask(pci, DMA_BIT_MASK(64))) pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(64)); @@ -2643,6 +2694,9 @@ { PCI_DEVICE(0x8086, 0x3a6e), .driver_data = AZX_DRIVER_ICH }, /* PCH */ { PCI_DEVICE(0x8086, 0x3b56), .driver_data = AZX_DRIVER_ICH }, + { PCI_DEVICE(0x8086, 0x3b57), .driver_data = AZX_DRIVER_ICH }, + /* CPT */ + { PCI_DEVICE(0x8086, 0x1c20), .driver_data = AZX_DRIVER_PCH }, /* SCH */ { PCI_DEVICE(0x8086, 0x811b), .driver_data = AZX_DRIVER_SCH }, /* ATI SB 450/600 */ @@ -2689,6 +2743,9 @@ { PCI_DEVICE(0x10de, 0x0ac1), .driver_data = AZX_DRIVER_NVIDIA }, { PCI_DEVICE(0x10de, 0x0ac2), .driver_data = AZX_DRIVER_NVIDIA }, { PCI_DEVICE(0x10de, 0x0ac3), .driver_data = AZX_DRIVER_NVIDIA }, + { PCI_DEVICE(0x10de, 0x0be2), .driver_data = AZX_DRIVER_NVIDIA }, + { PCI_DEVICE(0x10de, 0x0be3), .driver_data = AZX_DRIVER_NVIDIA }, + { PCI_DEVICE(0x10de, 0x0be4), .driver_data = AZX_DRIVER_NVIDIA }, { PCI_DEVICE(0x10de, 0x0d94), .driver_data = AZX_DRIVER_NVIDIA }, { PCI_DEVICE(0x10de, 0x0d95), .driver_data = AZX_DRIVER_NVIDIA }, { PCI_DEVICE(0x10de, 0x0d96), .driver_data = AZX_DRIVER_NVIDIA }, --- linux-mvl-dove-2.6.32.orig/sound/pci/ac97/ac97_patch.c +++ linux-mvl-dove-2.6.32/sound/pci/ac97/ac97_patch.c @@ -1867,11 +1867,14 @@ 0x10140523, /* Thinkpad R40 */ 0x10140534, /* Thinkpad X31 */ 0x10140537, /* Thinkpad T41p */ + 0x1014053e, /* Thinkpad R40e */ 0x10140554, /* Thinkpad T42p/R50p */ 0x10140567, /* Thinkpad T43p 2668-G7U */ 0x10140581, /* Thinkpad X41-2527 */ + 0x10280160, /* Dell Dimension 2400 */ 0x104380b0, /* Asus A7V8X-MX */ 0x11790241, /* Toshiba Satellite A-15 S127 */ + 0x1179ff10, /* Toshiba P500 */ 0x144dc01a, /* Samsung NP-X20C004/SEG */ 0 /* end */ }; --- linux-mvl-dove-2.6.32.orig/sound/pci/riptide/riptide.c +++ linux-mvl-dove-2.6.32/sound/pci/riptide/riptide.c @@ -1224,15 +1224,14 @@ firmware.firmware.ASIC, firmware.firmware.CODEC, firmware.firmware.AUXDSP, firmware.firmware.PROG); + if (!chip) + return 1; + for (i = 0; i < FIRMWARE_VERSIONS; i++) { if (!memcmp(&firmware_versions[i], &firmware, sizeof(firmware))) - break; - } - if (i >= FIRMWARE_VERSIONS) - return 0; /* no match */ + return 1; /* OK */ - if (!chip) - return 1; /* OK */ + } snd_printdd("Writing Firmware\n"); if (!chip->fw_entry) { --- linux-mvl-dove-2.6.32.orig/sound/pci/emu10k1/emu10k1.c +++ linux-mvl-dove-2.6.32/sound/pci/emu10k1/emu10k1.c @@ -52,6 +52,7 @@ static int max_buffer_size[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 128}; static int enable_ir[SNDRV_CARDS]; static uint subsystem[SNDRV_CARDS]; /* Force card subsystem model */ +static uint delay_pcm_irq[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 2}; module_param_array(index, int, NULL, 0444); MODULE_PARM_DESC(index, "Index value for the EMU10K1 soundcard."); @@ -73,6 +74,8 @@ MODULE_PARM_DESC(enable_ir, "Enable IR."); module_param_array(subsystem, uint, NULL, 0444); MODULE_PARM_DESC(subsystem, "Force card subsystem model."); +module_param_array(delay_pcm_irq, uint, NULL, 0444); +MODULE_PARM_DESC(delay_pcm_irq, "Delay PCM interrupt by specified number of samples (default 0)."); /* * Class 0401: 1102:0008 (rev 00) Subsystem: 1102:1001 -> Audigy2 Value Model:SB0400 */ @@ -127,6 +130,7 @@ &emu)) < 0) goto error; card->private_data = emu; + emu->delay_pcm_irq = delay_pcm_irq[dev] & 0x1f; if ((err = snd_emu10k1_pcm(emu, 0, NULL)) < 0) goto error; if ((err = snd_emu10k1_pcm_mic(emu, 1, NULL)) < 0) --- linux-mvl-dove-2.6.32.orig/sound/pci/emu10k1/memory.c +++ linux-mvl-dove-2.6.32/sound/pci/emu10k1/memory.c @@ -309,8 +309,10 @@ if (snd_BUG_ON(!hdr)) return NULL; + idx = runtime->period_size >= runtime->buffer_size ? + (emu->delay_pcm_irq * 2) : 0; mutex_lock(&hdr->block_mutex); - blk = search_empty(emu, runtime->dma_bytes); + blk = search_empty(emu, runtime->dma_bytes + idx); if (blk == NULL) { mutex_unlock(&hdr->block_mutex); return NULL; --- linux-mvl-dove-2.6.32.orig/sound/pci/emu10k1/emupcm.c +++ linux-mvl-dove-2.6.32/sound/pci/emu10k1/emupcm.c @@ -332,7 +332,7 @@ evoice->epcm->ccca_start_addr = start_addr + ccis; if (extra) { start_addr += ccis; - end_addr += ccis; + end_addr += ccis + emu->delay_pcm_irq; } if (stereo && !extra) { snd_emu10k1_ptr_write(emu, CPF, voice, CPF_STEREO_MASK); @@ -360,7 +360,9 @@ /* Assumption that PT is already 0 so no harm overwriting */ snd_emu10k1_ptr_write(emu, PTRX, voice, (send_amount[0] << 8) | send_amount[1]); snd_emu10k1_ptr_write(emu, DSL, voice, end_addr | (send_amount[3] << 24)); - snd_emu10k1_ptr_write(emu, PSST, voice, start_addr | (send_amount[2] << 24)); + snd_emu10k1_ptr_write(emu, PSST, voice, + (start_addr + (extra ? emu->delay_pcm_irq : 0)) | + (send_amount[2] << 24)); if (emu->card_capabilities->emu_model) pitch_target = PITCH_48000; /* Disable interpolators on emu1010 card */ else @@ -732,6 +734,23 @@ snd_emu10k1_ptr_write(emu, IP, voice, 0); } +static inline void snd_emu10k1_playback_mangle_extra(struct snd_emu10k1 *emu, + struct snd_emu10k1_pcm *epcm, + struct snd_pcm_substream *substream, + struct snd_pcm_runtime *runtime) +{ + unsigned int ptr, period_pos; + + /* try to sychronize the current position for the interrupt + source voice */ + period_pos = runtime->status->hw_ptr - runtime->hw_ptr_interrupt; + period_pos %= runtime->period_size; + ptr = snd_emu10k1_ptr_read(emu, CCCA, epcm->extra->number); + ptr &= ~0x00ffffff; + ptr |= epcm->ccca_start_addr + period_pos; + snd_emu10k1_ptr_write(emu, CCCA, epcm->extra->number, ptr); +} + static int snd_emu10k1_playback_trigger(struct snd_pcm_substream *substream, int cmd) { @@ -753,6 +772,8 @@ /* follow thru */ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: case SNDRV_PCM_TRIGGER_RESUME: + if (cmd == SNDRV_PCM_TRIGGER_PAUSE_RELEASE) + snd_emu10k1_playback_mangle_extra(emu, epcm, substream, runtime); mix = &emu->pcm_mixer[substream->number]; snd_emu10k1_playback_prepare_voice(emu, epcm->voices[0], 1, 0, mix); snd_emu10k1_playback_prepare_voice(emu, epcm->voices[1], 0, 0, mix); @@ -869,8 +890,9 @@ #endif /* printk(KERN_DEBUG - "ptr = 0x%x, buffer_size = 0x%x, period_size = 0x%x\n", - ptr, runtime->buffer_size, runtime->period_size); + "ptr = 0x%lx, buffer_size = 0x%lx, period_size = 0x%lx\n", + (long)ptr, (long)runtime->buffer_size, + (long)runtime->period_size); */ return ptr; } --- linux-mvl-dove-2.6.32.orig/sound/pci/oxygen/oxygen.c +++ linux-mvl-dove-2.6.32/sound/pci/oxygen/oxygen.c @@ -393,6 +393,10 @@ chip->model.suspend = claro_suspend; chip->model.resume = claro_resume; chip->model.set_adc_params = set_ak5385_params; + chip->model.device_config = PLAYBACK_0_TO_I2S | + PLAYBACK_1_TO_SPDIF | + CAPTURE_0_FROM_I2S_2 | + CAPTURE_1_FROM_SPDIF; break; } if (id->driver_data == MODEL_MERIDIAN || --- linux-mvl-dove-2.6.32.orig/sound/pci/echoaudio/echoaudio.c +++ linux-mvl-dove-2.6.32/sound/pci/echoaudio/echoaudio.c @@ -1821,7 +1821,9 @@ /* The hardware doesn't tell us which substream caused the irq, thus we have to check all running substreams. */ for (ss = 0; ss < DSP_MAXPIPES; ss++) { - if ((substream = chip->substream[ss])) { + substream = chip->substream[ss]; + if (substream && ((struct audiopipe *)substream->runtime-> + private_data)->state == PIPE_STATE_STARTED) { period = pcm_pointer(substream) / substream->runtime->period_size; if (period != chip->last_period[ss]) { --- linux-mvl-dove-2.6.32.orig/sound/pci/mixart/mixart.c +++ linux-mvl-dove-2.6.32/sound/pci/mixart/mixart.c @@ -1161,13 +1161,15 @@ unsigned long count, unsigned long pos) { struct mixart_mgr *mgr = entry->private_data; + unsigned long maxsize; - count = count & ~3; /* make sure the read size is a multiple of 4 bytes */ - if(count <= 0) + if (pos >= MIXART_BA0_SIZE) return 0; - if(pos + count > MIXART_BA0_SIZE) - count = (long)(MIXART_BA0_SIZE - pos); - if(copy_to_user_fromio(buf, MIXART_MEM( mgr, pos ), count)) + maxsize = MIXART_BA0_SIZE - pos; + if (count > maxsize) + count = maxsize; + count = count & ~3; /* make sure the read size is a multiple of 4 bytes */ + if (copy_to_user_fromio(buf, MIXART_MEM(mgr, pos), count)) return -EFAULT; return count; } @@ -1180,13 +1182,15 @@ unsigned long count, unsigned long pos) { struct mixart_mgr *mgr = entry->private_data; + unsigned long maxsize; - count = count & ~3; /* make sure the read size is a multiple of 4 bytes */ - if(count <= 0) + if (pos > MIXART_BA1_SIZE) return 0; - if(pos + count > MIXART_BA1_SIZE) - count = (long)(MIXART_BA1_SIZE - pos); - if(copy_to_user_fromio(buf, MIXART_REG( mgr, pos ), count)) + maxsize = MIXART_BA1_SIZE - pos; + if (count > maxsize) + count = maxsize; + count = count & ~3; /* make sure the read size is a multiple of 4 bytes */ + if (copy_to_user_fromio(buf, MIXART_REG(mgr, pos), count)) return -EFAULT; return count; } --- linux-mvl-dove-2.6.32.orig/sound/soc/Kconfig +++ linux-mvl-dove-2.6.32/sound/soc/Kconfig @@ -36,6 +36,7 @@ source "sound/soc/s6000/Kconfig" source "sound/soc/sh/Kconfig" source "sound/soc/txx9/Kconfig" +source "sound/soc/orion/Kconfig" # Supported codecs source "sound/soc/codecs/Kconfig" --- linux-mvl-dove-2.6.32.orig/sound/soc/Makefile +++ linux-mvl-dove-2.6.32/sound/soc/Makefile @@ -14,3 +14,4 @@ obj-$(CONFIG_SND_SOC) += s6000/ obj-$(CONFIG_SND_SOC) += sh/ obj-$(CONFIG_SND_SOC) += txx9/ +obj-$(CONFIG_SND_SOC) += orion/ --- linux-mvl-dove-2.6.32.orig/sound/soc/soc-core.c +++ linux-mvl-dove-2.6.32/sound/soc/soc-core.c @@ -275,6 +275,7 @@ mutex_unlock(&pcm_mutex); return 0; +#if 0 machine_err: if (machine->ops && machine->ops->shutdown) machine->ops->shutdown(substream); @@ -286,6 +287,11 @@ platform_err: if (cpu_dai->ops->shutdown) cpu_dai->ops->shutdown(substream, cpu_dai); +#else +machine_err: +codec_dai_err: +platform_err: +#endif out: mutex_unlock(&pcm_mutex); return ret; @@ -1107,19 +1113,21 @@ dai_link->pcm = pcm; pcm->private_data = rtd; - soc_pcm_ops.mmap = platform->pcm_ops->mmap; - soc_pcm_ops.pointer = platform->pcm_ops->pointer; - soc_pcm_ops.ioctl = platform->pcm_ops->ioctl; - soc_pcm_ops.copy = platform->pcm_ops->copy; - soc_pcm_ops.silence = platform->pcm_ops->silence; - soc_pcm_ops.ack = platform->pcm_ops->ack; - soc_pcm_ops.page = platform->pcm_ops->page; + + memcpy(&rtd->pcm_ops, &soc_pcm_ops, sizeof(struct snd_pcm_ops)); + rtd->pcm_ops.mmap = platform->pcm_ops->mmap; + rtd->pcm_ops.pointer = platform->pcm_ops->pointer; + rtd->pcm_ops.ioctl = platform->pcm_ops->ioctl; + rtd->pcm_ops.copy = platform->pcm_ops->copy; + rtd->pcm_ops.silence = platform->pcm_ops->silence; + rtd->pcm_ops.ack = platform->pcm_ops->ack; + rtd->pcm_ops.page = platform->pcm_ops->page; if (playback) - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &soc_pcm_ops); + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &rtd->pcm_ops); if (capture) - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &soc_pcm_ops); + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &rtd->pcm_ops); ret = platform->pcm_new(codec->card, codec_dai, pcm); if (ret < 0) { --- linux-mvl-dove-2.6.32.orig/sound/soc/orion/Kconfig +++ linux-mvl-dove-2.6.32/sound/soc/orion/Kconfig @@ -0,0 +1,75 @@ +menu "SoC Audio for the Marvell SoC's" + +config SND_DOVE_AC97 + tristate "Marvell Dove AC97 interface support" + depends on ARCH_DOVE && SND_SOC + select SND_AC97_CODEC + select AC97_BUS + help + Say Y or M if you want to add support for the AC97 interface in Marvell + SoC's. + +config SND_DOVE_SOC_DB + tristate "SoC AC97 Audio support for Marvell Dove DB" + depends on SND_DOVE_AC97 && (MACH_DOVE_DB || MACH_DOVE_DB_Z0) + select SND_PXA2XX_SOC + select SND_PXA2XX_LIB + select SND_PXA2XX_SOC_AC97 + select SND_PXA2XX_SOC_AC97_SURROUND + select SND_SOC_AD1980 + help + Say Y if you want to add support for SoC audio on Marvell + Dove Development Board. + +config SND_DOVE_SOC_DB_B + tristate "SoC AC97 Audio support for Marvell Dove DB-B" + depends on SND_DOVE_AC97 && MACH_DOVE_DB_B + select SND_PXA2XX_SOC + select SND_PXA2XX_LIB + select SND_PXA2XX_SOC_AC97 + select SND_PXA2XX_SOC_AC97_SURROUND + select SND_SOC_RT655 + select SND_SOC_AC97_CODEC + help + Say Y if you want to add support for SoC audio on Marvell + Dove Development Board. + + +config SND_DOVE_SOC_AC97_AVD1 + tristate "SoC AC97 Audio support for AVD1" + depends on SND_DOVE_AC97 + select SND_PXA2XX_SOC + select SND_PXA2XX_LIB + select SND_PXA2XX_SOC_AC97 + select SND_PXA2XX_SOC_AC97_SURROUND + select SND_SOC_RT5610 + + +config SND_DOVE_SOC_MRVL_AUDIO + tristate "Marvell mv88fx Audio ALSA SOC driver" + depends on MV_INCLUDE_AUDIO && SND_SOC + help + Say Y if you want to add support for SoC audio on Marvell + Dove Development Board. + +menu "Select Codecs for the mv88fx i2s" + depends on SND_DOVE_SOC_MRVL_AUDIO + +config CODEC_CS42L51 + bool "CS42L51 codec" + depends on SND_DOVE_SOC_MRVL_AUDIO + select SND_SOC_CS42L51 + +config CODEC_RT5623 + bool "RT5623 codec" + depends on SND_DOVE_SOC_MRVL_AUDIO + select SND_SOC_RT5623 + +config CODEC_RT5630 + bool "RT5630 codec" + depends on SND_DOVE_SOC_MRVL_AUDIO + select SND_SOC_RT5630 + +endmenu +endmenu + --- linux-mvl-dove-2.6.32.orig/sound/soc/orion/dove_ac97_avng.c +++ linux-mvl-dove-2.6.32/sound/soc/orion/dove_ac97_avng.c @@ -0,0 +1,130 @@ +/* + * dove_ac97avng.c -- SoC audio for Dove Avengers MID board + * + * Marvell Orion Alsa SOC Sound driver + * + * Author: Brian Hsu + * Copyright (C) 2009 Marvell Ltd. + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include +#include +#include + +#include +#include +#include +#include + +#include +//#include +//#include + +#include "../codecs/rt5610.h" +#include "../pxa/pxa2xx-pcm.h" +#include "../pxa/pxa2xx-ac97.h" + +static struct platform_device *dove_ac97_snd_device; + +static struct snd_soc_dai_link dove_ac97_dai[] = { + { + .name = "AC97", + .stream_name = "AC97 HiFi", + .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI], + .codec_dai = &rt5610_dai, + }, +}; + +static struct snd_soc_card dove = { + .name = "Dove-AC97-RT5611", + .platform = &pxa2xx_soc_platform, + .dai_link = dove_ac97_dai, + .num_links = ARRAY_SIZE(dove_ac97_dai), +}; + +static struct snd_soc_device dove_ac97_snd_devdata = { + .card = &dove, + .codec_dev = &soc_codec_dev_rt5610, +}; + +struct platform_device rt5610_codec_dev = { + .name = "rt5610-codec", + .id = 0, +}; + +static int dove_ac97_snd_probe(struct platform_device *pdev) +{ + struct resource *res; + int ret = 0; + + if (!machine_is_dove_rd_avng() && !machine_is_dove_rd_avng_z0()) + return -ENODEV; + + dove_ac97_snd_device = platform_device_alloc("soc-audio", 1); + if (!dove_ac97_snd_device) + return -ENOMEM; + + platform_set_drvdata(dove_ac97_snd_device, &dove_ac97_snd_devdata); + dove_ac97_snd_devdata.dev = &dove_ac97_snd_device->dev; + + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + ret = platform_device_add_resources(dove_ac97_snd_device, res, 1); + + //printk(KERN_ERR "dove_ac97_avng: add resource ret=%x\n", ret); + + + ret = platform_device_add(dove_ac97_snd_device); + + if (ret) + platform_device_put(dove_ac97_snd_device); + + ret = platform_device_register(&rt5610_codec_dev); + if(ret) + platform_device_unregister(&rt5610_codec_dev); + + + return ret; + +} + +static int dove_ac97_snd_remove(struct platform_device *pdev) + +{ + platform_device_unregister(&rt5610_codec_dev); + platform_device_unregister(dove_ac97_snd_device); + return 0; +} +static struct platform_driver dove_ac97_snd_driver = { + .probe = dove_ac97_snd_probe, + .remove = dove_ac97_snd_remove, + .driver = { + .name = "rt5611_snd", + }, + +}; +static int __init dove_ac97_snd_init(void) +{ + if (!machine_is_dove_rd_avng()) + return -ENODEV; + + return platform_driver_register(&dove_ac97_snd_driver); +} + +static void __exit dove_ac97_snd_exit(void) +{ + platform_driver_unregister(&dove_ac97_snd_driver); + +} +module_init(dove_ac97_snd_init); +module_exit(dove_ac97_snd_exit); + +/* Module information */ +MODULE_AUTHOR(" Brian Hsu "); +MODULE_DESCRIPTION("ALSA SoC Dove-AC97"); +MODULE_LICENSE("GPL"); --- linux-mvl-dove-2.6.32.orig/sound/soc/orion/Makefile +++ linux-mvl-dove-2.6.32/sound/soc/orion/Makefile @@ -0,0 +1,12 @@ +# Dove Machine Support +snd-soc-dovedb-objs := dove_db.o +snd-soc-dove-db-b-objs := dove_db_b.o +snd-soc-dove-avng-objs := dove_ac97_avng.o + +obj-$(CONFIG_SND_DOVE_SOC_DB) += snd-soc-dovedb.o +obj-$(CONFIG_SND_DOVE_SOC_DB_B) += snd-soc-dove-db-b.o + +obj-$(CONFIG_SND_DOVE_SOC_MRVL_AUDIO) += ../../../arch/arm/plat-orion/mv_hal_drivers/mv_drivers_lsp/mv_audio_soc/ +obj-$(CONFIG_SND_DOVE_SOC_AC97_AVD1) += snd-soc-dove-avng.o + + --- linux-mvl-dove-2.6.32.orig/sound/soc/orion/dove_db.c +++ linux-mvl-dove-2.6.32/sound/soc/orion/dove_db.c @@ -0,0 +1,94 @@ +/* + * dove_db.c -- SoC audio for Dove development board + * + */ + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +//#include + +#include "../codecs/ad1980.h" +#include "../pxa/pxa2xx-pcm.h" +#include "../pxa/pxa2xx-ac97.h" +#include + +static struct snd_soc_card dovedb; + +static struct snd_soc_dai_link dovedb_dai[] = { +{ + .name = "AC97", + .stream_name = "AC97 HiFi", + .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI], + .codec_dai = &ad1980_dai, +}, +{ + .name = "AC97", + .stream_name = "AC97 LFE", + .cpu_dai = &pxa_ac97_surround_dai[PXA3XX_DAI_AC97_LFE], + .codec_dai = &ad1980_dai, +}, +{ + .name = "AC97", + .stream_name = "AC97 Surround", + .cpu_dai = &pxa_ac97_surround_dai[PXA3XX_DAI_AC97_SURROUND], + .codec_dai = &ad1980_dai, +}, +}; + +static struct snd_soc_card dovedb = { + .name = "DoveDB", + .platform = &pxa2xx_soc_platform, + .dai_link = dovedb_dai, + .num_links = ARRAY_SIZE(dovedb_dai), +}; + +static struct snd_soc_device dovedb_snd_devdata = { + .card = &dovedb, + .codec_dev = &soc_codec_dev_ad1888, +}; + +static struct platform_device *dovedb_snd_device; + +extern u32 chip_rev; +static int __init dovedb_init(void) +{ + int ret; + + if (!(machine_is_dove_db() && (chip_rev < DOVE_REV_A0)) && !machine_is_dove_db_z0()) + return -ENODEV; + + dovedb_snd_device = platform_device_alloc("soc-audio", 0); + if (!dovedb_snd_device) + return -ENOMEM; + + platform_set_drvdata(dovedb_snd_device, &dovedb_snd_devdata); + dovedb_snd_devdata.dev = &dovedb_snd_device->dev; + ret = platform_device_add(dovedb_snd_device); + + if (ret) + platform_device_put(dovedb_snd_device); + + return ret; +} + +static void __exit dovedb_exit(void) +{ + platform_device_unregister(dovedb_snd_device); +} + +module_init(dovedb_init); +module_exit(dovedb_exit); + +/* Module information */ +MODULE_AUTHOR("Shadi Ammouri"); +MODULE_DESCRIPTION("ALSA SoC Dove-DB"); +MODULE_LICENSE("GPL"); --- linux-mvl-dove-2.6.32.orig/sound/soc/orion/dove_db_b.c +++ linux-mvl-dove-2.6.32/sound/soc/orion/dove_db_b.c @@ -0,0 +1,109 @@ +/* + * dove_db_b.c -- AC97 SoC audio for Dove DB-88AP510-BP-B + * + * Marvell Orion Alsa SOC Sound driver + * + * Author: Saeed Bishara + * Copyright (C) 2010 Marvell Ltd. + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include "../codecs/ac97.h" +#include "../pxa/pxa2xx-pcm.h" +#include "../pxa/pxa2xx-ac97.h" + +static struct platform_device *dove_ac97_snd_device; + +static int machine_init(struct snd_soc_codec *codec) +{ + snd_soc_dapm_sync(codec); + return 0; +} + +static struct snd_soc_dai_link dove_ac97_dai[] = { + { + .name = "AC97", + .stream_name = "AC97 HiFi", + .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI], + .codec_dai = &ac97_dai, + .init = machine_init, + }, + { + .name = "AC97", + .stream_name = "AC97 LFE", + .cpu_dai = &pxa_ac97_surround_dai[PXA3XX_DAI_AC97_LFE], + .codec_dai = &ac97_dai, + }, + { + .name = "AC97", + .stream_name = "AC97 Surround", + .cpu_dai = &pxa_ac97_surround_dai[PXA3XX_DAI_AC97_SURROUND], + .codec_dai = &ac97_dai, + }, +}; + +static struct snd_soc_card dove = { + .name = "Dove-AC97-RT655", + .platform = &pxa2xx_soc_platform, + .dai_link = dove_ac97_dai, + .num_links = ARRAY_SIZE(dove_ac97_dai), +}; + +static struct snd_soc_device dove_ac97_snd_devdata = { + .card = &dove, + .codec_dev = &soc_codec_dev_ac97, +}; + +extern u32 chip_rev; +static int __init dove_db_b_init(void) +{ + int ret = 0; + + if (!machine_is_dove_db_b() && !(machine_is_dove_db() && (chip_rev >= DOVE_REV_A0))) + return -ENODEV; + + ac97_dai.playback.rates = SNDRV_PCM_RATE_48000; + ac97_dai.capture.rates = SNDRV_PCM_RATE_48000; + dove_ac97_snd_device = platform_device_alloc("soc-audio", 0); + if (!dove_ac97_snd_device) + return -ENOMEM; + + platform_set_drvdata(dove_ac97_snd_device, &dove_ac97_snd_devdata); + dove_ac97_snd_devdata.dev = &dove_ac97_snd_device->dev; + + ret = platform_device_add(dove_ac97_snd_device); + if (ret) + platform_device_put(dove_ac97_snd_device); + + return ret; +} + +static void __exit dove_db_b_exit(void) +{ + platform_device_unregister(dove_ac97_snd_device); +} + +module_init(dove_db_b_init); +module_exit(dove_db_b_exit); + +/* Module information */ +MODULE_AUTHOR(" Brian Hsu "); +MODULE_DESCRIPTION("ALSA SoC Dove-AC97"); +MODULE_LICENSE("GPL"); --- linux-mvl-dove-2.6.32.orig/sound/soc/codecs/ad1980.h +++ linux-mvl-dove-2.6.32/sound/soc/codecs/ad1980.h @@ -19,5 +19,6 @@ extern struct snd_soc_dai ad1980_dai; extern struct snd_soc_codec_device soc_codec_dev_ad1980; +extern struct snd_soc_codec_device soc_codec_dev_ad1888; #endif --- linux-mvl-dove-2.6.32.orig/sound/soc/codecs/cs42l51.h +++ linux-mvl-dove-2.6.32/sound/soc/codecs/cs42l51.h @@ -0,0 +1,62 @@ +/* + * + * Marvell Alsa SoC Codec driver + * + * Author: Yuval Elmaliah + * Copyright (C) 2008 Marvell Ltd. + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ +#ifndef _CS42l51_H +#define _CS42l51_H + +/* register assignement */ +#define CS42L51_REG_ID 0x1 +#define CS42L51_REG_POWER_CNTRL 0x2 +#define CS42L51_REG_MIC_POWER_CNTRL 0x3 +#define CS42L51_REG_IF_CNTRL 0x4 +#define CS42L51_REG_MIC_CNTRL 0x5 +#define CS42L51_REG_ADC_CNTRL 0x6 +#define CS42L51_REG_ADC_INPUT_INV_MUTE 0x7 +#define CS42L51_REG_DAC_OUTPUT_CTRL 0x8 +#define CS42L51_REG_DAC_CTRL 0x9 +#define CS42L51_REG_ALCA_PGAA_CTRL 0xa +#define CS42L51_REG_ALCB_PGAB_CTRL 0xb +#define CS42L51_REG_ADCA_ATTENUATOR 0xc +#define CS42L51_REG_ADCB_ATTENUATOR 0xd +#define CS42L51_REG_ADCA_MIXER_VOL_CNTRL 0xe +#define CS42L51_REG_ADCB_MIXER_VOL_CNTRL 0xf +#define CS42L51_REG_PCMA_MIXER_VOL_CNTRL 0x10 +#define CS42L51_REG_PCMB_MIXER_VOL_CNTRL 0x11 +#define CS42L51_REG_BEEP_FREQ_TIMING_CFG 0x12 +#define CS42L51_REG_BEEP_OFF_TIME 0x13 +#define CS42L51_REG_BEEP_TONE_CFG 0x14 +#define CS42L51_REG_TONE_CTRL 0x15 +#define CS42L51_REG_VOL_OUTA_CTRL 0x16 +#define CS42L51_REG_VOL_OUTB_CTRL 0x17 +#define CS42L51_REG_CHANNEL_MIXER 0x18 +#define CS42L51_REG_LIMITER_THRESHOLD 0x19 +#define CS42L51_REG_LIMITER_RELEASE_RATE 0x1a +#define CS42L51_REG_LIMITER_ATTACK_RATE 0x1b +#define CS42L51_REG_ALC_ENABLE_ATTACK_RATE 0x1c +#define CS42L51_REG_ALC_RELEASE_RATE 0x1d +#define CS42L51_REG_ALC_THRESHOLD 0x1e +#define CS42L51_REG_NOISE_GATE_CFG 0x1f +#define CS42L51_REG_STATUS 0x20 +#define CS42L51_REG_CHARGE_PUMP_FREQ 0x21 + +#define CS42L51_REG_MAX CS42L51_REG_CHARGE_PUMP_FREQ + +struct cs42l51_setup_data { + unsigned short i2c_address; +}; + +/* ASoC DAI */ +extern struct snd_soc_dai cs42l51_dai; +extern struct snd_soc_codec_device soc_codec_dev_cs42l51; + +#endif --- linux-mvl-dove-2.6.32.orig/sound/soc/codecs/rt5610.c +++ linux-mvl-dove-2.6.32/sound/soc/codecs/rt5610.c @@ -0,0 +1,1455 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rt5610.h" +#define AUDIO_NAME "rt5610" +#define RT5610_VERSION "0.03" +//#define RT5610_DEBUG +#ifdef RT5610_DEBUG +#define dbg(format, args...) \ + printk(KERN_ERR "%s(%d): "format"\n", __FUNCTION__, __LINE__, ##args) +#else +#define dbg(format, arg...) do {} while (0) +#endif +#define err(format, arg...) \ + printk(KERN_ERR AUDIO_NAME ": " format "\n" , ## arg) +#define info(format, arg...) \ + printk(KERN_INFO AUDIO_NAME ": " format "\n" , ## arg) +#define warn(format, arg...) \ + printk(KERN_WARNING AUDIO_NAME ": " format "\n" , ## arg) + +static struct snd_soc_codec *codec; +bool rt5610_codec_resumed=0; +bool spk_enable=0; +bool hs_det=0; +unsigned int hs_irq; +struct work_struct hsdet_event_work; +struct workqueue_struct *hsdet_workq; + +/* codec private data */ +struct rt5610_priv { + unsigned int pll_id; + unsigned int pll_in; + unsigned int pll_out; + unsigned int vpcm_sysclk; +}; + + + +#define USE_DAPM_CONTROL 0 + +struct rt5610_init_reg { + char name[30]; + u16 reg_value; + u8 reg_index; +}; + +static struct rt5610_init_reg init_data_list[] = +{ + {"HP Output Volume", 0x9090, RT5610_HP_OUT_VOL}, + {"SPK Output Volume", 0x8080, RT5610_SPK_OUT_VOL}, + {"Stereo DAC Volume", 0x6808, RT5610_STEREO_DAC_VOL}, + {"Output Mixer Control", 0x6b40, RT5610_OUTPUT_MIXER_CTRL}, + {"Mic Control", 0x0500, RT5610_MIC_CTRL}, + {"Voice DAC Volume", 0x6800, RT5610_VOICE_DAC_OUT_VOL}, + {"ADC Rec Mixer", 0x3f3f, RT5610_ADC_REC_MIXER}, + {"General Control", 0x00e8, RT5610_GEN_CTRL_REG1}, + +}; +#define RT5610_INIT_REG_NUM ARRAY_SIZE(init_data_list) + +/* + * rt5610 register cache + * We can't read the RT5610 register space when we + * are using 2 wire for device control, so we cache them instead. + */ +static const u16 rt5610_reg[] = { + 0x59b4, 0x8080, 0x8080, 0x0000, // 6 + 0xc880, 0xe808, 0xe808, 0x0808, // e + 0xe0e0, 0xf58b, 0x7f7f, 0x0000, // 16 + 0xe800, 0x0000, 0x0000, 0x0000, // 1e + 0x0000, 0x0000, 0x0000, 0xef00, // 26 + 0x0000, 0x0000, 0xbb80, 0x0000, // 2e + 0x0000, 0xbb80, 0x0000, 0x0000, // 36 + 0x0000, 0x0000, 0x0000, 0x0000, // 3e + 0x0428, 0x0000, 0x0000, 0x0000, // 46 + 0x0000, 0x0000, 0x2e3e, 0x2e3e, // 4e + 0x0000, 0x0000, 0x003a, 0x0000, // 56 + 0x0cff, 0x0000, 0x0000, 0x0000, // 5e + 0x0000, 0x0000, 0x2130, 0x0010, // 66 + 0x0053, 0x0000, 0x0000, 0x0000, // 6e + 0x0000, 0x0000, 0x008c, 0x3f00, // 76 + 0x0000, 0x0000, 0x10ec, 0x1003, // 7e +}; + + + +/* virtual HP mixers regs */ +#define HPL_MIXER 0x80 +#define HPR_MIXER 0x82 + +static u16 reg80=0x2,reg82=0x2; + +/* + * read rt5610 register cache + */ +static inline unsigned int rt5610_read_reg_cache(struct snd_soc_codec *codec, + unsigned int reg) +{ + u16 *cache = codec->reg_cache; + if (reg < 1 || reg > (ARRAY_SIZE(rt5610_reg) + 1)) + return -1; + return cache[reg/2]; +} + + +/* + * write rt5610 register cache + */ + +static inline void rt5610_write_reg_cache(struct snd_soc_codec *codec, + unsigned int reg, unsigned int value) +{ + u16 *cache = codec->reg_cache; + if (reg < 0 || reg > 0x7e) + return; + cache[reg/2] = value; +} + + + +static unsigned int rt5610_read(struct snd_soc_codec *codec, + unsigned int reg) +{ + if (reg == 0x80) + return reg80; + else if (reg == 0x82) + return reg82; + + return soc_ac97_ops.read(codec->ac97, reg); +} + + +static int rt5610_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int val) +{ + u16 *cache = codec->reg_cache; + + dbg("reg=0x%x, val=0x%x\n", reg, val); + if (reg == 0x80) { + reg80 = val; + return 0; + } + else if (reg == 0x82){ + reg82 = val; + return 0; + } + + if (reg < 0x7c) + soc_ac97_ops.write(codec->ac97, reg, val); + reg = reg >> 1; + if (reg < (ARRAY_SIZE(rt5610_reg))) + cache[reg] = val; + return 0; +} + +int rt5610_reset(struct snd_soc_codec *codec, int try_warm) +{ + if (try_warm && soc_ac97_ops.warm_reset) { + soc_ac97_ops.warm_reset(codec->ac97); + if (rt5610_read(codec, 0) == rt5610_reg[0]) + return 1; + } + + soc_ac97_ops.reset(codec->ac97); + if(rt5610_read(codec, 0) != rt5610_reg[0]) + return -EIO; + mdelay(10); + return 0; +} +EXPORT_SYMBOL_GPL(rt5610_reset); + +#define rt5610_write_mask(c, reg, value, mask) snd_soc_update_bits(c, reg, mask, value) + +static int rt5610_reg_init(struct snd_soc_codec *codec) +{ + int i; + + for (i = 0; i < RT5610_INIT_REG_NUM; i++) + rt5610_write(codec, init_data_list[i].reg_index, init_data_list[i].reg_value); + return 0; +} + +static const char *rt5610_spkl_pga[] = {"Vmid","HPL mixer","SPK mixer","Mono Mixer"}; +static const char *rt5610_spkr_pga[] = {"Vmid","HPR mixer","SPK mixer","Mono Mixer"}; +static const char *rt5610_hpl_pga[] = {"Vmid","HPL mixer"}; +static const char *rt5610_hpr_pga[] = {"Vmid","HPR mixer"}; +static const char *rt5610_mono_pga[] = {"Vmid","HP mixer","SPK mixer","Mono Mixer"}; +static const char *rt5610_amp_type_sel[] = {"Class AB","Class D"}; +static const char *rt5610_mic_boost_sel[] = {"Bypass","20db","30db","40db"}; + +static const struct soc_enum rt5610_enum[] = { +SOC_ENUM_SINGLE(RT5610_OUTPUT_MIXER_CTRL, 14, 4, rt5610_spkl_pga), /* spk left input sel 0 */ +SOC_ENUM_SINGLE(RT5610_OUTPUT_MIXER_CTRL, 11, 4, rt5610_spkr_pga), /* spk right input sel 1 */ +SOC_ENUM_SINGLE(RT5610_OUTPUT_MIXER_CTRL, 9, 2, rt5610_hpl_pga), /* hp left input sel 2 */ +SOC_ENUM_SINGLE(RT5610_OUTPUT_MIXER_CTRL, 8, 2, rt5610_hpr_pga), /* hp right input sel 3 */ +SOC_ENUM_SINGLE(RT5610_OUTPUT_MIXER_CTRL, 6, 4, rt5610_mono_pga), /* mono input sel 4 */ +SOC_ENUM_SINGLE(RT5610_MIC_CTRL , 10,4, rt5610_mic_boost_sel), /*Mic1 boost sel 5 */ +SOC_ENUM_SINGLE(RT5610_MIC_CTRL , 8,4,rt5610_mic_boost_sel), /*Mic2 boost sel 6 */ +SOC_ENUM_SINGLE(RT5610_OUTPUT_MIXER_CTRL,13,2,rt5610_amp_type_sel), /*Speaker AMP sel 7 */ +}; + +static int rt5610_amp_sel_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned short val; + unsigned short mask, bitmask; + + for (bitmask = 1; bitmask < e->max; bitmask <<= 1) + ; + if (ucontrol->value.enumerated.item[0] > e->max - 1) + return -EINVAL; + val = ucontrol->value.enumerated.item[0] << e->shift_l; + mask = (bitmask - 1) << e->shift_l; + if (e->shift_l != e->shift_r) { + if (ucontrol->value.enumerated.item[1] > e->max - 1) + return -EINVAL; + val |= ucontrol->value.enumerated.item[1] << e->shift_r; + mask |= (bitmask - 1) << e->shift_r; + } + + snd_soc_update_bits(codec, e->reg, mask, val); + val &= (0x1 << 13); + if (val == 0) + rt5610_write_mask(codec, 0x3c, 0x4000, 0x4000); + else + rt5610_write_mask(codec, 0x3c, 0x0000, 0x4000); + + return 0; +} + +static int rt5610_vpcm_enable_control(struct snd_soc_codec *codec, int enable) +{ + return 0; +} + +/*extend interface for voice pcm control*/ +static int rt5610_vpcm_state_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + int mode = rt5610_read(codec, HPL_MIXER); + + if (((mode & 0x8000) >> 15) == (ucontrol->value.integer.value[0])) + return 0; + mode &= 0x7fff; + mode |= (ucontrol->value.integer.value[0] << 15); + rt5610_write(codec, HPL_MIXER, mode); + rt5610_vpcm_enable_control(codec, ucontrol->value.integer.value[0]); + return 0; +} + +static const struct snd_kcontrol_new rt5610_snd_controls[] = { +SOC_DOUBLE("SPKOUT Playback Volume", RT5610_SPK_OUT_VOL, 8, 0, 31, 1), +SOC_DOUBLE("SPKOUT Playback Switch", RT5610_SPK_OUT_VOL, 15, 7, 1, 1), +SOC_DOUBLE("HPOUT Playback Volume", RT5610_HP_OUT_VOL, 8, 0, 31, 1), +SOC_DOUBLE("HPOUT Playback Switch", RT5610_HP_OUT_VOL,15, 7, 1, 1), +//SOC_SINGLE("Mono Playback Volume", RT5610_PHONEIN_MONO_OUT_VOL, 0, 31, 1), +//SOC_SINGLE("Mono Playback Switch", RT5610_PHONEIN_MONO_OUT_VOL, 7, 1, 1), +SOC_DOUBLE("PCM Playback Volume", RT5610_STEREO_DAC_VOL, 8, 0, 31, 1), +SOC_DOUBLE("PCM Playback Switch", RT5610_STEREO_DAC_VOL,15, 7, 1, 1), +//SOC_DOUBLE("Line In Volume", RT5610_LINE_IN_VOL, 8, 0, 31, 1), +SOC_SINGLE("Mic Playback Volume", RT5610_MIC_VOL, 8, 31, 1), +//SOC_SINGLE("Mic 2 Volume", RT5610_MIC_VOL, 0, 31, 1), +//SOC_ENUM("Mic 1 Boost", rt5610_enum[5]), +//SOC_ENUM("Mic 2 Boost", rt5610_enum[6]), +//SOC_ENUM_EXT("Speaker Amp Type", rt5610_enum[7], snd_soc_get_enum_double, rt5610_amp_sel_put), +//SOC_SINGLE("Phone In Volume", RT5610_PHONEIN_MONO_OUT_VOL, 8, 31, 1), +SOC_DOUBLE("PCM Capture Volume", RT5610_ADC_REC_GAIN, 7, 0, 31, 0), +//SOC_SINGLE_EXT("Voice PCM Switch", HPL_MIXER, 15, 1, 1, snd_soc_get_volsw, rt5610_vpcm_state_put), +}; + + + +/* add non dapm controls */ +static int rt5610_add_controls(struct snd_soc_codec *codec) +{ + int err, i; + + for (i = 0; i < ARRAY_SIZE(rt5610_snd_controls); i++) { + err = snd_ctl_add(codec->card, + snd_soc_cnew(&rt5610_snd_controls[i],codec, NULL)); + if (err < 0) + return err; + } + return 0; +} + +#if USE_DAPM_CONTROL + +/* + * _DAPM_ Controls + */ + +/* We have to create a fake left and right HP mixers because + * the codec only has a single control that is shared by both channels. + * This makes it impossible to determine the audio path using the current + * register map, thus we add a new (virtual) register to help determine the + * audio route within the device. + */ + static int mixer_event (struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + + u16 l, r, lineIn,mic1,mic2, phone, pcm,voice; + + l = rt5610_read(w->codec, HPL_MIXER); + r = rt5610_read(w->codec, HPR_MIXER); + lineIn = rt5610_read(w->codec, RT5610_LINE_IN_VOL); + mic2 = rt5610_read(w->codec, RT5610_MIC_ROUTING_CTRL); + phone = rt5610_read(w->codec,RT5610_PHONEIN_MONO_OUT_VOL); + pcm = rt5610_read(w->codec, RT5610_STEREO_DAC_VOL); + voice = rt5610_read(w->codec, RT5610_VOICE_DAC_OUT_VOL); + + if (event & SND_SOC_DAPM_PRE_REG) + return 0; + if (l & 0x1 || r & 0x1) + rt5610_write(w->codec, RT5610_VOICE_DAC_OUT_VOL, voice & 0x7fff); + else + rt5610_write(w->codec, RT5610_VOICE_DAC_OUT_VOL, voice | 0x8000); + + if (l & 0x2 || r & 0x2) + rt5610_write(w->codec, RT5610_STEREO_DAC_VOL, pcm & 0x7fff); + else + rt5610_write(w->codec, RT5610_STEREO_DAC_VOL, pcm | 0x8000); + + if (l & 0x4 || r & 0x4) + rt5610_write(w->codec, RT5610_MIC_ROUTING_CTRL, mic2 & 0xff7f); + else + rt5610_write(w->codec, RT5610_MIC_ROUTING_CTRL, mic2 | 0x0080); + + mic1 = rt5610_read(w->codec, RT5610_MIC_ROUTING_CTRL); + if (l & 0x8 || r & 0x8) + rt5610_write(w->codec, RT5610_MIC_ROUTING_CTRL, mic1 & 0x7fff); + else + rt5610_write(w->codec, RT5610_MIC_ROUTING_CTRL, mic1 | 0x8000); + + if (l & 0x10 || r & 0x10) + rt5610_write(w->codec, RT5610_PHONEIN_MONO_OUT_VOL, phone & 0x7fff); + else + rt5610_write(w->codec, RT5610_PHONEIN_MONO_OUT_VOL, phone | 0x8000); + + if (l & 0x20 || r & 0x20) + rt5610_write(w->codec, RT5610_LINE_IN_VOL, lineIn & 0x7fff); + else + rt5610_write(w->codec, RT5610_LINE_IN_VOL, lineIn | 0x8000); + + return 0; +} + +/* Left Headphone Mixers */ +static const struct snd_kcontrol_new rt5610_hpl_mixer_controls[] = { +SOC_DAPM_SINGLE("LineIn Playback Switch", HPL_MIXER, 5, 1, 0), +SOC_DAPM_SINGLE("PhoneIn Playback Switch", HPL_MIXER, 4, 1, 0), +SOC_DAPM_SINGLE("Mic1 Playback Switch", HPL_MIXER, 3, 1, 0), +SOC_DAPM_SINGLE("Mic2 Playback Switch", HPL_MIXER, 2, 1, 0), +SOC_DAPM_SINGLE("PCM Playback Switch", HPL_MIXER, 1, 1, 0), +SOC_DAPM_SINGLE("Voice Playback Switch", HPL_MIXER, 0, 1, 0), +SOC_DAPM_SINGLE("RecordL Playback Switch", RT5610_ADC_REC_GAIN, 15, 1,1), +}; + +/* Right Headphone Mixers */ +static const struct snd_kcontrol_new rt5610_hpr_mixer_controls[] = { +SOC_DAPM_SINGLE("LineIn Playback Switch", HPR_MIXER, 5, 1, 0), +SOC_DAPM_SINGLE("PhoneIn Playback Switch", HPR_MIXER, 4, 1, 0), +SOC_DAPM_SINGLE("Mic1 Playback Switch", HPR_MIXER, 3, 1, 0), +SOC_DAPM_SINGLE("Mic2 Playback Switch", HPR_MIXER, 2, 1, 0), +SOC_DAPM_SINGLE("PCM Playback Switch", HPR_MIXER, 1, 1, 0), +SOC_DAPM_SINGLE("Voice Playback Switch", HPR_MIXER, 0, 1, 0), +SOC_DAPM_SINGLE("RecordR Playback Switch", RT5610_ADC_REC_GAIN, 14, 1,1), +}; + +//Left Record Mixer +static const struct snd_kcontrol_new rt5610_captureL_mixer_controls[] = { +SOC_DAPM_SINGLE("Mic1 Capture Switch", RT5610_ADC_REC_MIXER, 14, 1, 1), +SOC_DAPM_SINGLE("Mic2 Capture Switch", RT5610_ADC_REC_MIXER, 13, 1, 1), +SOC_DAPM_SINGLE("LineInL Capture Switch",RT5610_ADC_REC_MIXER,12, 1, 1), +SOC_DAPM_SINGLE("Phone Capture Switch", RT5610_ADC_REC_MIXER, 11, 1, 1), +SOC_DAPM_SINGLE("HPMixerL Capture Switch", RT5610_ADC_REC_MIXER,10, 1, 1), +SOC_DAPM_SINGLE("SPKMixer Capture Switch",RT5610_ADC_REC_MIXER,9, 1, 1), +SOC_DAPM_SINGLE("MonoMixer Capture Switch",RT5610_ADC_REC_MIXER,8, 1, 1), +}; + + +//Right Record Mixer +static const struct snd_kcontrol_new rt5610_captureR_mixer_controls[] = { +SOC_DAPM_SINGLE("Mic1 Capture Switch", RT5610_ADC_REC_MIXER, 6, 1, 1), +SOC_DAPM_SINGLE("Mic2 Capture Switch", RT5610_ADC_REC_MIXER, 5, 1, 1), +SOC_DAPM_SINGLE("LineInR Capture Switch",RT5610_ADC_REC_MIXER,4, 1, 1), +SOC_DAPM_SINGLE("Phone Capture Switch", RT5610_ADC_REC_MIXER, 3, 1, 1), +SOC_DAPM_SINGLE("HPMixerR Capture Switch", RT5610_ADC_REC_MIXER,2, 1, 1), +SOC_DAPM_SINGLE("SPKMixer Capture Switch",RT5610_ADC_REC_MIXER,1, 1, 1), +SOC_DAPM_SINGLE("MonoMixer Capture Switch",RT5610_ADC_REC_MIXER,0, 1, 1), +}; + +/* Speaker Mixer */ +static const struct snd_kcontrol_new rt5610_speaker_mixer_controls[] = { +SOC_DAPM_SINGLE("LineIn Playback Switch", RT5610_LINE_IN_VOL, 14, 1, 1), +SOC_DAPM_SINGLE("PhoneIn Playback Switch", RT5610_PHONEIN_MONO_OUT_VOL, 14, 1, 1), +SOC_DAPM_SINGLE("Mic1 Playback Switch", RT5610_MIC_ROUTING_CTRL, 14, 1, 1), +SOC_DAPM_SINGLE("Mic2 Playback Switch", RT5610_MIC_ROUTING_CTRL, 6, 1, 1), +SOC_DAPM_SINGLE("PCM Playback Switch", RT5610_STEREO_DAC_VOL, 14, 1, 1), +SOC_DAPM_SINGLE("Voice Playback Switch", RT5610_VOICE_DAC_OUT_VOL, 14, 1, 1), +}; + + +/* Mono Mixer */ +static const struct snd_kcontrol_new rt5610_mono_mixer_controls[] = { +SOC_DAPM_SINGLE("LineIn Playback Switch", RT5610_LINE_IN_VOL, 13, 1, 1), +SOC_DAPM_SINGLE("Mic1 Playback Switch", RT5610_MIC_ROUTING_CTRL, 13, 1, 1), +SOC_DAPM_SINGLE("Mic2 Playback Switch", RT5610_MIC_ROUTING_CTRL, 5, 1, 1), +SOC_DAPM_SINGLE("PCM Playback Switch", RT5610_STEREO_DAC_VOL, 13, 1, 1), +SOC_DAPM_SINGLE("Voice Playback Switch", RT5610_VOICE_DAC_OUT_VOL, 13, 1, 1), +SOC_DAPM_SINGLE("RecordL Playback Switch", RT5610_ADC_REC_GAIN, 13, 1,1), +SOC_DAPM_SINGLE("RecordR Playback Switch", RT5610_ADC_REC_GAIN, 12, 1,1), +}; + +/* mono output mux */ +static const struct snd_kcontrol_new rt5610_mono_mux_controls = +SOC_DAPM_ENUM("Route", rt5610_enum[4]); + +/* speaker left output mux */ +static const struct snd_kcontrol_new rt5610_hp_spkl_mux_controls = +SOC_DAPM_ENUM("Route", rt5610_enum[0]); + +/* speaker right output mux */ +static const struct snd_kcontrol_new rt5610_hp_spkr_mux_controls = +SOC_DAPM_ENUM("Route", rt5610_enum[1]); + +/* headphone left output mux */ +static const struct snd_kcontrol_new rt5610_hpl_out_mux_controls = +SOC_DAPM_ENUM("Route", rt5610_enum[2]); + +/* headphone right output mux */ +static const struct snd_kcontrol_new rt5610_hpr_out_mux_controls = +SOC_DAPM_ENUM("Route", rt5610_enum[3]); + +static const struct snd_soc_dapm_widget rt5610_dapm_widgets[] = { +SND_SOC_DAPM_MUX("Mono Out Mux", SND_SOC_NOPM, 0, 0, + &rt5610_mono_mux_controls), +SND_SOC_DAPM_MUX("Left Speaker Out Mux", SND_SOC_NOPM, 0, 0, + &rt5610_hp_spkl_mux_controls), +SND_SOC_DAPM_MUX("Right Speaker Out Mux", SND_SOC_NOPM, 0, 0, + &rt5610_hp_spkr_mux_controls), +SND_SOC_DAPM_MUX("Left Headphone Out Mux", SND_SOC_NOPM, 0, 0, + &rt5610_hpl_out_mux_controls), +SND_SOC_DAPM_MUX("Right Headphone Out Mux", SND_SOC_NOPM, 0, 0, + &rt5610_hpr_out_mux_controls), +SND_SOC_DAPM_MIXER_E("Left HP Mixer",RT5610_PWR_MANAG_ADD2, 5, 0, + &rt5610_hpl_mixer_controls[0], ARRAY_SIZE(rt5610_hpl_mixer_controls), + mixer_event, SND_SOC_DAPM_POST_REG), +SND_SOC_DAPM_MIXER_E("Right HP Mixer",RT5610_PWR_MANAG_ADD2, 4, 0, + &rt5610_hpr_mixer_controls[0], ARRAY_SIZE(rt5610_hpr_mixer_controls), + mixer_event, SND_SOC_DAPM_POST_REG), +SND_SOC_DAPM_MIXER("Mono Mixer", RT5610_PWR_MANAG_ADD2, 2, 0, + &rt5610_mono_mixer_controls[0], ARRAY_SIZE(rt5610_mono_mixer_controls)), +SND_SOC_DAPM_MIXER("Speaker Mixer", RT5610_PWR_MANAG_ADD2,3,0, + &rt5610_speaker_mixer_controls[0], + ARRAY_SIZE(rt5610_speaker_mixer_controls)), +SND_SOC_DAPM_MIXER("Left Record Mixer", RT5610_PWR_MANAG_ADD2,1,0, + &rt5610_captureL_mixer_controls[0], + ARRAY_SIZE(rt5610_captureL_mixer_controls)), +SND_SOC_DAPM_MIXER("Right Record Mixer", RT5610_PWR_MANAG_ADD2,0,0, + &rt5610_captureR_mixer_controls[0], + ARRAY_SIZE(rt5610_captureR_mixer_controls)), +SND_SOC_DAPM_DAC("Left DAC", "Left HiFi Playback", RT5610_PWR_MANAG_ADD2,9, 0), +SND_SOC_DAPM_DAC("Right DAC", "Right HiFi Playback", RT5610_PWR_MANAG_ADD2, 8, 0), +/*rory add 090706*/ +SND_SOC_DAPM_DAC("Voice DAC", "Voice Playback", RT5610_PWR_MANAG_ADD2, 10, 0), +/*rory end*/ +SND_SOC_DAPM_MIXER("IIS Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), +SND_SOC_DAPM_MIXER("HP Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), +/*rory add 090706*/ +SND_SOC_DAPM_MIXER("Line Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), +/*rory end*/ +SND_SOC_DAPM_ADC("Left ADC", "Left HiFi Capture", RT5610_PWR_MANAG_ADD2, 7, 0), +SND_SOC_DAPM_ADC("Right ADC", "Right HiFi Capture", RT5610_PWR_MANAG_ADD2, 6, 0), +SND_SOC_DAPM_PGA("Left Headphone", RT5610_PWR_MANAG_ADD3, 11, 0, NULL, 0), +SND_SOC_DAPM_PGA("Right Headphone", RT5610_PWR_MANAG_ADD3, 10, 0, NULL, 0), +SND_SOC_DAPM_PGA("Left Speaker", RT5610_PWR_MANAG_ADD3, 9, 0, NULL, 0), +SND_SOC_DAPM_PGA("Right Speaker", RT5610_PWR_MANAG_ADD3, 8, 0, NULL, 0), +SND_SOC_DAPM_PGA("Mono Out", RT5610_PWR_MANAG_ADD3, 14, 0, NULL, 0), +SND_SOC_DAPM_PGA("Left Line In", RT5610_PWR_MANAG_ADD3, 7, 0, NULL, 0), +SND_SOC_DAPM_PGA("Right Line In", RT5610_PWR_MANAG_ADD3, 6, 0, NULL, 0), +SND_SOC_DAPM_PGA("Phone In PGA", RT5610_PWR_MANAG_ADD3, 5, 0, NULL, 0), +SND_SOC_DAPM_PGA("Phone In Mixer", RT5610_PWR_MANAG_ADD3, 4, 0, NULL, 0), +SND_SOC_DAPM_PGA("Mic 1 PGA", RT5610_PWR_MANAG_ADD3, 3, 0, NULL, 0), +SND_SOC_DAPM_PGA("Mic 2 PGA", RT5610_PWR_MANAG_ADD3, 2, 0, NULL, 0), +SND_SOC_DAPM_PGA("Mic 1 Pre Amp", RT5610_PWR_MANAG_ADD3, 1, 0, NULL, 0), +SND_SOC_DAPM_PGA("Mic 2 Pre Amp", RT5610_PWR_MANAG_ADD3, 0, 0, NULL, 0), +SND_SOC_DAPM_PGA("HP Amp", RT5610_PWR_MANAG_ADD1, 14, 0, NULL, 0), +SND_SOC_DAPM_PGA("SPKL Amp", RT5610_PWR_MANAG_ADD3, 13, 0, NULL, 0), +SND_SOC_DAPM_PGA("SPKR Amp", RT5610_PWR_MANAG_ADD3, 12, 0, NULL, 0), +SND_SOC_DAPM_MICBIAS("Mic Bias1", RT5610_PWR_MANAG_ADD1, 3, 0), +SND_SOC_DAPM_MICBIAS("Mic Bias2", RT5610_PWR_MANAG_ADD1, 2, 0), +SND_SOC_DAPM_OUTPUT("MONO"), +SND_SOC_DAPM_OUTPUT("HPL"), +SND_SOC_DAPM_OUTPUT("HPR"), +SND_SOC_DAPM_OUTPUT("SPKL"), +SND_SOC_DAPM_OUTPUT("SPKR"), +SND_SOC_DAPM_INPUT("LINEL"), +SND_SOC_DAPM_INPUT("LINER"), +SND_SOC_DAPM_INPUT("PHONEIN"), +SND_SOC_DAPM_INPUT("MIC1"), +SND_SOC_DAPM_INPUT("MIC2"), +SND_SOC_DAPM_INPUT("PCMIN"), +SND_SOC_DAPM_VMID("VMID"), +}; + +static const struct snd_soc_dapm_route audio_map[] = { + /* left HP mixer */ + {"Left HP Mixer" , "LineIn Playback Switch" , "Left Line In"}, + {"Left HP Mixer" , "PhoneIn Playback Switch" , "Phone In PGA"}, + {"Left HP Mixer" , "Mic1 Playback Switch" , "Mic 1 PGA"}, + {"Left HP Mixer" , "Mic2 Playback Switch" , "Mic 2 PGA"}, + {"Left HP Mixer" , "PCM Playback Switch" , "Left DAC"}, + {"Left HP Mixer" , "Voice Playback Switch" , "Voice DAC"}, + {"Left HP Mixer" , "RecordL Playback Switch" , "Left Record Mixer"}, + + /* right HP mixer */ + {"Right HP Mixer" , "LineIn Playback Switch" , "Right Line In"}, + {"Right HP Mixer" , "PhoneIn Playback Switch" , "Phone In PGA"}, + {"Right HP Mixer" , "Mic1 Playback Switch" , "Mic 1 PGA"}, + {"Right HP Mixer" , "Mic2 Playback Switch" , "Mic 2 PGA"}, + {"Right HP Mixer" , "PCM Playback Switch" , "Right DAC"}, + {"Right HP Mixer" , "Voice Playback Switch" , "Voice DAC"}, + {"Right HP Mixer" , "RecordR Playback Switch" , "Right Record Mixer"}, + + /* virtual mixer - mixes left & right channels for spk and mono */ + {"IIS Mixer" , NULL , "Left DAC"}, + {"IIS Mixer" , NULL , "Right DAC"}, + {"Line Mixer" , NULL , "Right Line In"}, + {"Line Mixer" , NULL , "Left Line In"}, + {"HP Mixer" , NULL , "Left HP Mixer"}, + {"HP Mixer" , NULL , "Right HP Mixer"}, + + /* speaker mixer */ + {"Speaker Mixer" , "LineIn Playback Switch" , "Line Mixer"}, + {"Speaker Mixer" , "PhoneIn Playback Switch" , "Phone In PGA"}, + {"Speaker Mixer" , "Mic1 Playback Switch" , "Mic 1 PGA"}, + {"Speaker Mixer" , "Mic2 Playback Switch" , "Mic 2 PGA"}, + {"Speaker Mixer" , "PCM Playback Switch" , "IIS Mixer"}, + {"Speaker Mixer" , "Voice Playback Switch" , "Voice DAC"}, + + /* mono mixer */ + {"Mono Mixer" , "LineIn Playback Switch" , "Line Mixer"}, + //{"Mono Mixer", "PhoneIn Playback Switch","Phone In PGA"}, + {"Mono Mixer" , "Mic1 Playback Switch" , "Mic 1 PGA"}, + {"Mono Mixer" , "Mic2 Playback Switch" , "Mic 2 PGA"}, + {"Mono Mixer" , "PCM Playback Switch" , "IIS Mixer"}, + {"Mono Mixer" , "Voice Playback Switch" , "Voice DAC"}, + {"Mono Mixer" , "RecordL Playback Switch" , "Left Record Mixer"}, + {"Mono Mixer" , "RecordR Playback Switch" , "Right Record Mixer"}, + + /*Left record mixer */ + {"Left Record Mixer" , "Mic1 Capture Switch" , "Mic 1 Pre Amp"}, + {"Left Record Mixer" , "Mic2 Capture Switch" , "Mic 2 Pre Amp"}, + {"Left Record Mixer" , "LineInL Capture Switch" , "LINEL"}, + {"Left Record Mixer" , "Phone Capture Switch" , "Phone In Mixer"}, + {"Left Record Mixer" , "HPMixerL Capture Switch" , "Left HP Mixer"}, + {"Left Record Mixer" , "SPKMixer Capture Switch" , "Speaker Mixer"}, + {"Left Record Mixer" , "MonoMixer Capture Switch" , "Mono Mixer"}, + + /*Right record mixer */ + {"Right Record Mixer" , "Mic1 Capture Switch" , "Mic 1 Pre Amp"}, + {"Right Record Mixer" , "Mic2 Capture Switch" , "Mic 2 Pre Amp"}, + {"Right Record Mixer" , "LineInR Capture Switch" , "LINER"}, + {"Right Record Mixer" , "Phone Capture Switch" , "Phone In Mixer"}, + {"Right Record Mixer" , "HPMixerR Capture Switch" , "Right HP Mixer"}, + {"Right Record Mixer" , "SPKMixer Capture Switch" , "Speaker Mixer"}, + {"Right Record Mixer" , "MonoMixer Capture Switch" , "Mono Mixer"}, + + /* headphone left mux */ + {"Left Headphone Out Mux" , "HPL mixer" , "Left HP Mixer"}, + + /* headphone right mux */ + {"Right Headphone Out Mux", "HPR mixer", "Right HP Mixer"}, + + /* speaker left mux */ + {"Left Speaker Out Mux", "HPL mixer", "Left HP Mixer"}, + {"Left Speaker Out Mux", "SPK mixer", "Speaker Mixer"}, + {"Left Speaker Out Mux", "Mono Mixer", "Mono Mixer"}, + + /* speaker right mux */ + {"Right Speaker Out Mux", "HPR mixer", "Right HP Mixer"}, + {"Right Speaker Out Mux", "SPK mixer", "Speaker Mixer"}, + {"Right Speaker Out Mux", "Mono Mixer", "Mono Mixer"}, + + /* mono mux */ + {"Mono Out Mux", "HP mixer", "HP Mixer"}, + {"Mono Out Mux", "SPK mixer", "Speaker Mixer"}, + {"Mono Out Mux", "Mono Mixer", "Mono Mixer"}, + + /* output pga */ + {"HPL", NULL, "HP Amp"}, + {"HP Amp", NULL, "Left Headphone"}, + {"Left Headphone", NULL, "Left Headphone Out Mux"}, + {"HPR", NULL, "HP Amp"}, + {"HP Amp", NULL, "Right Headphone"}, + {"Right Headphone", NULL, "Right Headphone Out Mux"}, + {"SPKL", NULL, "SPKL Amp"}, + {"SPKL Amp", NULL, "Left Speaker"}, + {"Left Speaker", NULL, "Left Speaker Out Mux"}, + {"SPKR", NULL, "SPKR Amp"}, + {"SPKR Amp", NULL, "Right Speaker"}, + {"Right Speaker", NULL, "Right Speaker Out Mux"}, + {"MONO", NULL, "Mono Out"}, + {"Mono Out", NULL, "Mono Out Mux"}, + + /* input pga */ + {"Left Line In", NULL, "LINEL"}, + {"Right Line In", NULL, "LINER"}, + {"Phone In PGA", NULL, "Phone In Mixer"}, + {"Phone In Mixer", NULL, "PHONEIN"}, + {"Mic 1 Pre Amp", NULL, "MIC1"}, + {"Mic 2 Pre Amp", NULL, "MIC2"}, + {"Mic 1 PGA", NULL, "Mic 1 Pre Amp"}, + {"Mic 2 PGA", NULL, "Mic 2 Pre Amp"}, + + /* left ADC */ + {"Left ADC", NULL, "Left Record Mixer"}, + + /* right ADC */ + {"Right ADC", NULL, "Right Record Mixer"}, + +}; + +static int rt5610_add_widgets(struct snd_soc_codec *codec) +{ + snd_soc_dapm_new_controls(codec, rt5610_dapm_widgets, + ARRAY_SIZE(rt5610_dapm_widgets)); + snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); + snd_soc_dapm_new_widgets(codec); +} + +#else +static int rt5610_pcm_hw_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *codec_dai) +{ + struct snd_soc_codec *codec = codec_dai->codec; + int stream = substream->stream; + dbg(""); + + switch (stream) + { + case SNDRV_PCM_STREAM_PLAYBACK: + rt5610_write_mask(codec, 0x3c, 0x0330, 0x0330); + rt5610_write_mask(codec, 0x3e, 0x3f00, 0x3f00); + rt5610_write_mask(codec, 0x3a, 0x4000, 0x4000); + rt5610_write_mask(codec, 0x02, 0x0000, 0x8080); + rt5610_write_mask(codec, 0x04, 0x0000, 0x8080); + break; + case SNDRV_PCM_STREAM_CAPTURE: + rt5610_write_mask(codec, 0x3a, 0x0008, 0x0008); + rt5610_write_mask(codec, 0x3c, 0x00c3, 0x00c3); + rt5610_write_mask(codec, 0x3e, 0x0002, 0x0002); + break; + } + + return 0; +} + +static int rt5610_vpcm_hw_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *codec_dai) +{ + struct snd_soc_codec *codec = codec_dai->codec; + int stream = substream->stream; + dbg(""); + + switch (stream) + { + case SNDRV_PCM_STREAM_PLAYBACK: + rt5610_write_mask(codec, 0x3c, 0x0430, 0x0430); + rt5610_write_mask(codec, 0x3e, 0x3f00, 0x3f00); + rt5610_write_mask(codec, 0x3a, 0x4000, 0x4000); + rt5610_write_mask(codec, 0x02, 0x0000, 0x8080); + rt5610_write_mask(codec, 0x04, 0x0000, 0x8080); + break; + case SNDRV_PCM_STREAM_CAPTURE: + rt5610_write_mask(codec, 0x3a, 0x0008, 0x0008); + rt5610_write_mask(codec, 0x3c, 0x0041, 0x0041); + rt5610_write_mask(codec, 0x3e, 0x3f00, 0x3f00); + break; + } + + return 0; +} +#endif +/* PLL divisors */ +struct _pll_div { + u32 pll_in; + u32 pll_out; + u16 regvalue; +}; + +static const struct _pll_div codec_pll_div[] = { + + { 2048000, 8192000, 0x0ea0}, + { 3686400, 8192000, 0x4e27}, + { 12000000, 8192000, 0x456b}, + { 13000000, 8192000, 0x495f}, + { 13100000, 8192000, 0x0320}, + { 2048000, 11289600, 0xf637}, + { 3686400, 11289600, 0x2f22}, + { 12000000, 11289600, 0x3e2f}, + { 13000000, 11289600, 0x4d5b}, + { 13100000, 11289600, 0x363b}, + { 2048000, 16384000, 0x1ea0}, + { 3686400, 16384000, 0x9e27}, + { 12000000, 16384000, 0x452b}, + { 13000000, 16384000, 0x542f}, + { 13100000, 16384000, 0x03a0}, + { 2048000, 16934400, 0xe625}, + { 3686400, 16934400, 0x9126}, + { 12000000, 16934400, 0x4d2c}, + { 13000000, 16934400, 0x742f}, + { 13100000, 16934400, 0x3c27}, + { 2048000, 22579200, 0x2aa0}, + { 3686400, 22579200, 0x2f20}, + { 12000000, 22579200, 0x7e2f}, + { 13000000, 22579200, 0x742f}, + { 13100000, 22579200, 0x3c27}, + { 2048000, 24576000, 0x2ea0}, + { 3686400, 24576000, 0xee27}, + { 12000000, 24576000, 0x2915}, + { 13000000, 24576000, 0x772e}, + { 13100000, 24576000, 0x0d20}, +}; + + +static int rt5610_set_pll(struct snd_soc_codec *codec, + int pll_id, unsigned int freq_in, unsigned int freq_out) +{ + int ret = -EINVAL; + int i; + + if (pll_id != RT5610_PLL_FR_MCLK) + return -EINVAL; + + //rt5610_write_mask(codec,RT5610_PWR_MANAG_ADD2, 0x0000,0x1000); //disable PLL power + + if (!freq_in || !freq_out) { + + return 0; + } + + for (i = 0; i < ARRAY_SIZE(codec_pll_div); i++) { + + if (codec_pll_div[i].pll_in == freq_in && codec_pll_div[i].pll_out == freq_out) + { + + rt5610_write_mask(codec, RT5610_GEN_CTRL_REG2, 0x0000, 0x4000); + rt5610_write(codec,RT5610_PLL_CTRL,codec_pll_div[i].regvalue);//set PLL parameter + rt5610_write_mask(codec,RT5610_PWR_MANAG_ADD2, 0x1000,0x1000); //enable PLL power + ret = 0; + } + } + return ret; +} +static int rt5610_set_dai_pll(struct snd_soc_dai *codec_dai, + int pll_id, unsigned int freq_in, unsigned int freq_out) +{ + int ret = -EINVAL; + struct snd_soc_codec *codec = codec_dai->codec; + struct rt5610_priv *rt5610 = codec->private_data; + dbg(""); + + ret = rt5610_set_pll(codec, pll_id, freq_in, freq_out); + if (ret < 0) { + err( "pll unmatched\n"); + return ret; + } + + rt5610_write_mask(codec,RT5610_GEN_CTRL_REG1,0x8000,0x8000);//Codec sys-clock from PLL + + rt5610->pll_id = pll_id; + rt5610->pll_in = freq_in; + rt5610->pll_out = freq_out; + + /* wait 10ms AC97 link frames for the link to stabilise */ + schedule_timeout_interruptible(msecs_to_jiffies(10)); + + return ret; +} + +static int rt5610_vpcm_set_dai_pll(struct snd_soc_dai *codec_dai, + int pll_id, unsigned int freq_in, unsigned int freq_out) +{ + + int ret = -EINVAL; + struct snd_soc_codec *codec = codec_dai->codec; + struct rt5610_priv *rt5610 = codec->private_data; + dbg(""); + + ret = rt5610_set_pll(codec, pll_id, freq_in, freq_out); + if (ret < 0){ + err("pll unmatched\n"); + return ret; + } + + rt5610_write_mask(codec, RT5610_VOICE_DAC_PCMCLK_CTRL1, 0x8000, 0xc000); //voice sysclk from pll + rt5610->pll_id = pll_id; + rt5610->pll_in = freq_in; + rt5610->pll_out = freq_out; + return ret; +} + + +struct _coeff_div { + u32 mclk; + u32 rate; + u16 fs; + u16 regvalue1; + u16 regvalue2; +}; + + + +static const struct _coeff_div coeff_div_vpcm[] = { + /*8k*/ + {24576000, 8000, 384*8, 0x2153, 0x4013}, + /*16k*/ + {24576000, 16000, 384*4, 0x2123, 0x4013}, +}; + + +static int get_coeff_vpcm(int mclk, int rate) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(coeff_div_vpcm); i++) { + if ((coeff_div_vpcm[i].rate == rate) && (coeff_div_vpcm[i].mclk == mclk)) + return i; + } + return -EINVAL; +} + + + +static int rt5610_vpcm_set_dai_sysclk(struct snd_soc_dai *codec_dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct rt5610_priv *rt5610 = codec->private_data; + dbg(""); + + rt5610->vpcm_sysclk= freq; + return 0; +} + + +static int rt5610_vpcm_set_dai_fmt(struct snd_soc_dai *codec_dai, + unsigned int fmt) +{ + struct snd_soc_codec *codec = codec_dai->codec; + u16 iface = 0; + + iface |= 0x8000; /*vopcm interace*/ + dbg(""); + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) + { + case SND_SOC_DAIFMT_CBM_CFM: + break; + case SND_SOC_DAIFMT_CBS_CFS: + iface |= 0x4000; + break; + default: + return -EINVAL; + + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) + { + case SND_SOC_DAIFMT_I2S: + break; + case SND_SOC_DAIFMT_RIGHT_J: + iface |= 0x0001; + break; + case SND_SOC_DAIFMT_LEFT_J: + iface |= 0x0002; + break; + case SND_SOC_DAIFMT_DSP_A: + iface |= 0x0003; + break; + case SND_SOC_DAIFMT_DSP_B: + iface |= 0x0043; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_IB_NF: + iface |= 0x0800; + break; + default: + return -EINVAL; + } + + rt5610_write(codec, RT5610_EXTEND_SDP_CTRL, iface); + return 0; +} + +static int rt5610_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *codec_dai) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct rt5610_priv *rt5610 = codec->private_data; + struct snd_soc_dapm_widget *w; + int stream = substream->stream; + + dbg(""); + if (stream == SNDRV_PCM_STREAM_CAPTURE) { + list_for_each_entry(w, &codec->dapm_widgets, list) + { + if (!w->sname) + continue; + if (!strcmp(w->name, "Right ADC")) + strcpy(w->sname, "Right HiFi Capture"); + } + rt5610_write_mask(codec, 0x36, 0x0000, 0x0100); + } + + rt5610_write_mask(codec, 0x3a, 0x0001, 0x0001); /*power on dac ref*/ + + return 0; +} + + +static int rt5610_vpcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *codec_dai) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct rt5610_priv *rt5610 = codec->private_data; + struct snd_soc_dapm_widget *w; + int stream = substream->stream; + u16 iface = rt5610_read(codec, RT5610_EXTEND_SDP_CTRL) & 0xfff3; + int coeff = get_coeff_vpcm(rt5610->vpcm_sysclk, params_rate(params)); + + dbg(""); + + if (stream == SNDRV_PCM_STREAM_CAPTURE) { + list_for_each_entry(w, &codec->dapm_widgets, list) + { + if (!w->sname) + continue; + if (!strcmp(w->name, "Right ADC")) + strcpy(w->sname, "Right Voice Capture"); + } + rt5610_write_mask(codec, 0x36, 0x0100, 0x0100); + } + + iface |= 0x8000; + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + iface |= 0x0000; + break; + case SNDRV_PCM_FORMAT_S20_3LE: + iface |= 0x0004; + break; + case SNDRV_PCM_FORMAT_S24_LE: + iface |= 0x0008; + break; + case SNDRV_PCM_FORMAT_S32_LE: + iface |= 0x000c; + break; + } + + rt5610_write(codec, RT5610_EXTEND_SDP_CTRL, iface); + rt5610_write_mask(codec, 0x3a, 0x0801, 0x0801); /*power on i2s and dac ref*/ + if (coeff >=0) + { + rt5610_write_mask(codec, RT5610_VOICE_DAC_PCMCLK_CTRL1, coeff_div_vpcm[coeff].regvalue1, 0x3fff); + rt5610_write(codec, RT5610_VOICE_DAC_PCMCLK_CTRL2, coeff_div_vpcm[coeff].regvalue2); + } + else + { + err("cant find matched sysclk and rate config\n"); + return -EINVAL; + } + return 0; +} + +static int rt5610_pcm_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *codec_dai) +{ + struct snd_soc_codec *codec = codec_dai->codec; + dbg(""); + + #if !USE_DAPM_CONTROL + rt5610_write_mask(codec, 0x02, 0x8080, 0x8080); + rt5610_write_mask(codec, 0x04, 0x8080, 0x8080); + rt5610_write_mask(codec, 0x08, 0x0080, 0x0080); + rt5610_write(codec, 0x3a, 0x0002); + rt5610_write(codec, 0x3c, 0x2000); + rt5610_write(codec, 0x3e, 0x0000); + #endif + + return 0; +} + +static int rt5610_vpcm_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *codec_dai) +{ + struct snd_soc_codec *codec = codec_dai->codec; + dbg(""); + + rt5610_write(codec, 0x2e, 0x0000); +#if !USE_DAPM_CONTROL + rt5610_write_mask(codec, 0x02, 0x8080, 0x8080); + rt5610_write_mask(codec, 0x04, 0x8080, 0x8080); + rt5610_write_mask(codec, 0x08, 0x0080, 0x0080); + rt5610_write(codec, 0x3a, 0x0002); + rt5610_write(codec, 0x3c, 0x2000); + rt5610_write(codec, 0x3e, 0x0000); +#endif + return 0; +} +#if !USE_DAPM_CONTROL +static int rt5610_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + switch (level) { + case SND_SOC_BIAS_ON: + rt5610_write_mask(codec, 0x50, GPIO_3, GPIO_3); //enable sticky + rt5610_write_mask(codec, 0x52, GPIO_3, GPIO_3); //set as wake up + case SND_SOC_BIAS_PREPARE: + break; + case SND_SOC_BIAS_STANDBY: + case SND_SOC_BIAS_OFF: + rt5610_write_mask(codec, 0x02, 0x8080, 0x8080); + rt5610_write_mask(codec, 0x04, 0x8080, 0x8080); + rt5610_write_mask(codec, 0x08, 0x0080, 0x0080); + rt5610_write(codec, 0x3a, 0x0002); + rt5610_write(codec, 0x3c, 0x2000); + rt5610_write(codec, 0x3e, 0x0000); + break; + } + codec->bias_level = level; + return 0; +} +#else +static int rt5610_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + switch (level) { + case SND_SOC_BIAS_ON: + case SND_SOC_BIAS_PREPARE: + break; + case SND_SOC_BIAS_STANDBY: + case SND_SOC_BIAS_OFF: + rt5610_write_mask(codec, 0x3a, 0x0000, 0x0801); + rt5610_write_mask(codec,RT5610_PWR_MANAG_ADD2, 0x0000,0x1000); //disable PLL power + break; + } + codec->bias_level = level; + return 0; +} +#endif + + +#define RT5610_HIFI_RATES SNDRV_PCM_RATE_48000 +#define RT5610_VOICE_RATES (SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_8000) + + +#define RT5610_HIFI_FORMATS (SNDRV_PCM_FMTBIT_S16_LE) +#define RT5610_VOICE_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ + SNDRV_PCM_FMTBIT_S24_LE) + +static struct snd_soc_dai_ops rt5610_hifi_ops = { + .hw_params = rt5610_pcm_hw_params, + .set_pll = rt5610_set_dai_pll, + .shutdown = rt5610_pcm_shutdown, +#if !USE_DAPM_CONTROL + .prepare = rt5610_pcm_hw_prepare, +#endif +}; + +static struct snd_soc_dai_ops rt5610_pcm_ops = { + .hw_params = rt5610_vpcm_hw_params, + .set_fmt = rt5610_vpcm_set_dai_fmt, + .set_sysclk = rt5610_vpcm_set_dai_sysclk, + .set_pll = rt5610_vpcm_set_dai_pll, + .shutdown = rt5610_vpcm_shutdown, +#if !USE_DAPM_CONTROL + .prepare = rt5610_vpcm_hw_prepare, +#endif +}; +struct snd_soc_dai rt5610_dai[2] = { + + { + .name = "RT5610 HiFi", + .playback = { + .stream_name = "HiFi Playback", + .channels_min = 1, + .channels_max = 2, + .rates = RT5610_HIFI_RATES, + .formats = RT5610_HIFI_FORMATS,}, + .capture = { + .stream_name = "HiFi Capture", + .channels_min = 1, + .channels_max = 2, + .rates = RT5610_HIFI_RATES, + .formats = RT5610_HIFI_FORMATS,}, + .ops = &rt5610_hifi_ops, + }, + + { + .name = "RT5610 Voice", + .playback = { + .stream_name = "Voice Playback", + .channels_min = 1, + .channels_max =2, + .rates = RT5610_VOICE_RATES, + .formats = RT5610_VOICE_FORMATS + }, + .capture = { + .stream_name = "Voice Capture", + .channels_min = 1, + .channels_max = 2, + .rates = RT5610_VOICE_RATES, + .formats = RT5610_VOICE_FORMATS, + }, + .ops = &rt5610_pcm_ops, + }, +}; + + +EXPORT_SYMBOL_GPL(rt5610_dai); + +//Power On SPK Amplifeir, this is just for Avenger-Dove-RT5630 Amplifier control. +//The Apm enable pin is connected to ALC5610-GPIO1 because of no enough DOVE GPIO numbers can be used. +//Remove the code if the board is not Avenger-Dove +int spk_amplifier_enable(bool enable) +{ + dbg("enable=%d\n",enable); + + rt5610_write_mask(codec, 0x4c, 0x0000, 0x0002); //Config GPIO1 as output + + if (enable && !hs_det) + rt5610_write_mask(codec, 0x5c, 0x0002, 0x0002); //ON + else + rt5610_write_mask(codec, 0x5c, 0x0000, 0x0002); //OFF + spk_enable=enable; + return 0; + +} +EXPORT_SYMBOL_GPL(spk_amplifier_enable); + +static int rt5610_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->card->codec; + + rt5610_codec_resumed=0; + + /* we only need to suspend if we are a valid card */ + if(!codec->card) + return 0; + + rt5610_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + return 0; +} +static int rt5610_resume(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->card->codec; + struct rt5610_priv *rt5610 = codec->private_data; + int ret, i; + u16 *cache = codec->reg_cache; + + rt5610_reset(codec, 0); + ret = rt5610_reset(codec, 1); + if (ret < 0) { + err("could not reset AC97 codec\n"); + return ret; + } + + rt5610_write(codec, RT5610_PD_CTRL_STAT, 0); + rt5610_set_bias_level(codec, SND_SOC_BIAS_STANDBY);\ + + /* do we need to re-start the PLL ? */ + if (rt5610->pll_out) + rt5610_set_pll(codec, rt5610->pll_id, rt5610->pll_in, rt5610->pll_out); + + /*only synchronise the codec if warm reset failed*/ + if (ret == 0) { + for (i = 2; i < ARRAY_SIZE(rt5610_reg) << 1; i += 2) { + if (i > 0x66) + break; + soc_ac97_ops.write(codec->ac97, i, cache[i >> 1]); + } + } + + if (codec->suspend_bias_level == SND_SOC_BIAS_ON) + rt5610_set_bias_level(codec, SND_SOC_BIAS_ON); + rt5610_codec_resumed=1; + return ret; + +} + + +/* + * initialise the RT5610 driver + * register the mixer and dsp interfaces with the kernel + */ +static void rt5610_hsdet_irq_worker(struct work_struct *work) +{ + + u16 status, pol; + dbg("rt5610_hsdet_irq_worker\n"); + + status=rt5610_read(codec, 0x54); + pol=rt5610_read(codec, 0x4e); + + dbg("GPIO3(pol,status)=%x,%x\n",(pol & GPIO_3)>>3,(status & GPIO_3)>>3); + + if (!(GPIO_3 & status)) + { + dbg("AC97 codec IRQ: Not Headset, quit."); + enable_irq(hs_irq); + + return ; + } + + if (GPIO_3 & pol) //current state: phone jack-in + { + dbg("phone jack-in\n"); + hs_det=1; + rt5610_write_mask(codec, 0x4e, 0, GPIO_3); //Low active, to detect phone jack-in + if (spk_enable) + rt5610_write_mask(codec, 0x5c, 0, 0x0002); //SPK CLASS D AMP OFF + + } + else //current state: phone jack-out + { + dbg("phone jack-out\n"); + hs_det=0; + rt5610_write_mask(codec, 0x4e, GPIO_3, GPIO_3); //High active, , to detect phone jack-out + if (spk_enable) + rt5610_write_mask(codec, 0x5c, 0x0002, 0x0002); //SPK CLASS D AMP ON + } + rt5610_write_mask(codec, 0x54, 0, GPIO_2|GPIO_3); //clear status + + enable_irq(hs_irq); + + +} + +static irqreturn_t rt5610_hsdet_int(int irq, void *dev_id) +{ + dbg("enter rt5610_hsdet_int handle.\n"); + + if (!work_pending(&hsdet_event_work)) { + disable_irq_nosync(hs_irq); + queue_work(hsdet_workq, &hsdet_event_work); + } + return IRQ_HANDLED; +} + +static int rt5610_probe(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + int ret; + + codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); + if (codec == NULL) + return -ENOMEM; + mutex_init(&codec->mutex); + socdev->card->codec = codec; + codec->reg_cache = kmemdup(rt5610_reg, sizeof(rt5610_reg), GFP_KERNEL); + if (codec->reg_cache == NULL) { + ret = -ENOMEM; + goto cache_err; + } + codec->reg_cache_size = sizeof(rt5610_reg); + codec->reg_cache_step = 2; + + codec->private_data = kzalloc(sizeof(struct rt5610_priv), GFP_KERNEL); + if (codec->private_data == NULL) { + ret = -ENOMEM; + goto priv_err; + } + + codec->name = "RT5610"; + codec->owner = THIS_MODULE; + codec->dai = rt5610_dai; + codec->num_dai = ARRAY_SIZE(rt5610_dai); + codec->read = rt5610_read; + codec->write = rt5610_write; + codec->set_bias_level = rt5610_set_bias_level; + INIT_LIST_HEAD(&codec->dapm_widgets); + INIT_LIST_HEAD(&codec->dapm_paths); + + ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0); + if (ret < 0) + goto codec_err; + + ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); + if (ret < 0) + goto pcm_err; + +#ifndef TOUCHSCREEN_RT5611 + // Suppose ALC5611 has been RESET in TSC Driver Init + // It does not RESET again. + rt5610_reset(codec, 0); + ret = rt5610_reset(codec, 1); + if (ret < 0) { + err("FAIL to reset rt5610\n"); + goto reset_err; + } +#endif + + rt5610_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + rt5610_write(codec, 0x26, 0x0000); + rt5610_write(codec, 0x3a, 0x0002); //main bias + rt5610_write(codec, 0x3c, 0x2000); //vref + rt5610_reg_init(codec); + + rt5610_add_controls(codec); + #if USE_DAPM_CONTROL + rt5610_add_widgets(codec); + #endif + ret = snd_soc_init_card(socdev); + if (ret < 0) + goto reset_err; +//HSDET INT{ + rt5610_write_mask(codec, 0x54, 0, GPIO_3); //clear status + rt5610_write_mask(codec, 0x4e, GPIO_3, GPIO_3); //High active, for headset_det + rt5610_write_mask(codec, 0x4c, GPIO_3, GPIO_3); // GPIO3 as input + rt5610_write_mask(codec, 0x50, GPIO_3, GPIO_3); //enable sticky + + hsdet_workq = create_singlethread_workqueue("rt5610_snd"); + if (hsdet_workq == NULL) { + err("Failed to create workqueue\n"); + return -1; + } + INIT_WORK(&hsdet_event_work, rt5610_hsdet_irq_worker); + + hs_irq=platform_get_irq(pdev,0); + dbg(KERN_ERR "rt5610 irq=0x%x\n",hs_irq); + if (request_irq(hs_irq, rt5610_hsdet_int, IRQF_SHARED, + "rt5610_hsdet", socdev)) { + err("Failed to register rt5610_headset_det interrupt"); + return -1; + } +//}HSDET INT + dbg("rt5610: initial ok\n"); + return 0; + +reset_err: + snd_soc_free_pcms(socdev); + +pcm_err: + snd_soc_free_ac97_codec(codec); + +codec_err: + kfree(codec->private_data); + +priv_err: + kfree(codec->reg_cache); + +cache_err: + kfree(socdev->card->codec); + socdev->card->codec = NULL; + return ret; +} + +static int rt5610_remove(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->card->codec; + + if (codec == NULL) + return 0; + + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); + snd_soc_free_ac97_codec(codec); + kfree(codec->private_data); + kfree(codec->reg_cache); + kfree(codec); + return 0; +} + +struct snd_soc_codec_device soc_codec_dev_rt5610 = { + .probe = rt5610_probe, + .remove = rt5610_remove, + .suspend = rt5610_suspend, + .resume = rt5610_resume, +}; + +EXPORT_SYMBOL_GPL(soc_codec_dev_rt5610); + +static int __devinit rt5610_dev_probe(struct platform_device *pdev) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(rt5610_dai); i++) + rt5610_dai[i].dev = &pdev->dev; + + return snd_soc_register_dais(rt5610_dai, ARRAY_SIZE(rt5610_dai)); +} + +static int __devexit rt5610_dev_remove(struct platform_device *pdev) +{ + snd_soc_unregister_dais(rt5610_dai, ARRAY_SIZE(rt5610_dai)); + + return 0; +} + +static struct platform_driver rt5610_driver = { + .probe = rt5610_dev_probe, + .remove = __devexit_p(rt5610_dev_remove), + .driver = { + .name = "rt5610-codec", + .owner = THIS_MODULE, + }, +}; + +static int __init rt5610_modinit(void) +{ + return platform_driver_register(&rt5610_driver); +} + +static void __exit rt5610_exit(void) +{ + platform_driver_unregister(&rt5610_driver); +} + +module_init(rt5610_modinit); +module_exit(rt5610_exit); +MODULE_LICENSE("GPL"); + --- linux-mvl-dove-2.6.32.orig/sound/soc/codecs/wm_hubs.c +++ linux-mvl-dove-2.6.32/sound/soc/codecs/wm_hubs.c @@ -593,12 +593,12 @@ { "SPKL", "Input Switch", "MIXINL" }, { "SPKL", "IN1LP Switch", "IN1LP" }, - { "SPKL", "Output Switch", "Left Output Mixer" }, + { "SPKL", "Output Switch", "Left Output PGA" }, { "SPKL", NULL, "TOCLK" }, { "SPKR", "Input Switch", "MIXINR" }, { "SPKR", "IN1RP Switch", "IN1RP" }, - { "SPKR", "Output Switch", "Right Output Mixer" }, + { "SPKR", "Output Switch", "Right Output PGA" }, { "SPKR", NULL, "TOCLK" }, { "SPKL Boost", "Direct Voice Switch", "Direct Voice" }, @@ -620,8 +620,8 @@ { "SPKOUTRP", NULL, "SPKR Driver" }, { "SPKOUTRN", NULL, "SPKR Driver" }, - { "Left Headphone Mux", "Mixer", "Left Output Mixer" }, - { "Right Headphone Mux", "Mixer", "Right Output Mixer" }, + { "Left Headphone Mux", "Mixer", "Left Output PGA" }, + { "Right Headphone Mux", "Mixer", "Right Output PGA" }, { "Headphone PGA", NULL, "Left Headphone Mux" }, { "Headphone PGA", NULL, "Right Headphone Mux" }, @@ -639,17 +639,17 @@ static const struct snd_soc_dapm_route lineout1_diff_routes[] = { { "LINEOUT1 Mixer", "IN1L Switch", "IN1L PGA" }, { "LINEOUT1 Mixer", "IN1R Switch", "IN1R PGA" }, - { "LINEOUT1 Mixer", "Output Switch", "Left Output Mixer" }, + { "LINEOUT1 Mixer", "Output Switch", "Left Output PGA" }, { "LINEOUT1N Driver", NULL, "LINEOUT1 Mixer" }, { "LINEOUT1P Driver", NULL, "LINEOUT1 Mixer" }, }; static const struct snd_soc_dapm_route lineout1_se_routes[] = { - { "LINEOUT1N Mixer", "Left Output Switch", "Left Output Mixer" }, - { "LINEOUT1N Mixer", "Right Output Switch", "Left Output Mixer" }, + { "LINEOUT1N Mixer", "Left Output Switch", "Left Output PGA" }, + { "LINEOUT1N Mixer", "Right Output Switch", "Right Output PGA" }, - { "LINEOUT1P Mixer", "Left Output Switch", "Left Output Mixer" }, + { "LINEOUT1P Mixer", "Left Output Switch", "Left Output PGA" }, { "LINEOUT1N Driver", NULL, "LINEOUT1N Mixer" }, { "LINEOUT1P Driver", NULL, "LINEOUT1P Mixer" }, @@ -658,17 +658,17 @@ static const struct snd_soc_dapm_route lineout2_diff_routes[] = { { "LINEOUT2 Mixer", "IN2L Switch", "IN2L PGA" }, { "LINEOUT2 Mixer", "IN2R Switch", "IN2R PGA" }, - { "LINEOUT2 Mixer", "Output Switch", "Right Output Mixer" }, + { "LINEOUT2 Mixer", "Output Switch", "Right Output PGA" }, { "LINEOUT2N Driver", NULL, "LINEOUT2 Mixer" }, { "LINEOUT2P Driver", NULL, "LINEOUT2 Mixer" }, }; static const struct snd_soc_dapm_route lineout2_se_routes[] = { - { "LINEOUT2N Mixer", "Left Output Switch", "Left Output Mixer" }, - { "LINEOUT2N Mixer", "Right Output Switch", "Left Output Mixer" }, + { "LINEOUT2N Mixer", "Left Output Switch", "Left Output PGA" }, + { "LINEOUT2N Mixer", "Right Output Switch", "Right Output PGA" }, - { "LINEOUT2P Mixer", "Right Output Switch", "Right Output Mixer" }, + { "LINEOUT2P Mixer", "Right Output Switch", "Right Output PGA" }, { "LINEOUT2N Driver", NULL, "LINEOUT2N Mixer" }, { "LINEOUT2P Driver", NULL, "LINEOUT2P Mixer" }, @@ -686,17 +686,21 @@ snd_soc_update_bits(codec, WM8993_RIGHT_LINE_INPUT_3_4_VOLUME, WM8993_IN2_VU, WM8993_IN2_VU); + snd_soc_update_bits(codec, WM8993_SPEAKER_VOLUME_LEFT, + WM8993_SPKOUT_VU, WM8993_SPKOUT_VU); snd_soc_update_bits(codec, WM8993_SPEAKER_VOLUME_RIGHT, WM8993_SPKOUT_VU, WM8993_SPKOUT_VU); snd_soc_update_bits(codec, WM8993_LEFT_OUTPUT_VOLUME, - WM8993_HPOUT1L_ZC, WM8993_HPOUT1L_ZC); + WM8993_HPOUT1_VU | WM8993_HPOUT1L_ZC, + WM8993_HPOUT1_VU | WM8993_HPOUT1L_ZC); snd_soc_update_bits(codec, WM8993_RIGHT_OUTPUT_VOLUME, WM8993_HPOUT1_VU | WM8993_HPOUT1R_ZC, WM8993_HPOUT1_VU | WM8993_HPOUT1R_ZC); snd_soc_update_bits(codec, WM8993_LEFT_OPGA_VOLUME, - WM8993_MIXOUTL_ZC, WM8993_MIXOUTL_ZC); + WM8993_MIXOUTL_ZC | WM8993_MIXOUT_VU, + WM8993_MIXOUTL_ZC | WM8993_MIXOUT_VU); snd_soc_update_bits(codec, WM8993_RIGHT_OPGA_VOLUME, WM8993_MIXOUTR_ZC | WM8993_MIXOUT_VU, WM8993_MIXOUTR_ZC | WM8993_MIXOUT_VU); --- linux-mvl-dove-2.6.32.orig/sound/soc/codecs/rt5623.c +++ linux-mvl-dove-2.6.32/sound/soc/codecs/rt5623.c @@ -0,0 +1,1582 @@ +/* + * rt5623.c -- RT5623 ALSA Soc Audio driver + * + * Copyright 2008 Realtek Microelectronics + * + * Author: flove Ethan + * + * Based on WM8753.c + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rt5623.h" + +#define AUDIO_NAME "rt5623" +#define RT5623_VERSION "0.01" + + +/* + * Debug + */ +#ifdef CONFIG_SND_DEBUG +#define s3cdbg(x...) printk(x) +#else +#define s3cdbg(x...) +#endif + +#define RT5623_DEBUG 0 + +#ifdef RT5623_DEBUG +#define dbg(format, arg...) \ + printk(KERN_DEBUG AUDIO_NAME ": " format "\n" , ## arg) +#else +#define dbg(format, arg...) do {} while (0) +#endif +#define err(format, arg...) \ + printk(KERN_ERR AUDIO_NAME ": " format "\n" , ## arg) +#define info(format, arg...) \ + printk(KERN_INFO AUDIO_NAME ": " format "\n" , ## arg) +#define warn(format, arg...) \ + printk(KERN_WARNING AUDIO_NAME ": " format "\n" , ## arg) + +static int caps_charge = 2000; +module_param(caps_charge, int, 0); +MODULE_PARM_DESC(caps_charge, "RT5623 cap charge time (msecs)"); + + + +/* codec private data */ +struct rt5623_priv { + unsigned int sysclk; +}; + + +static struct snd_soc_device *rt5623_socdev; + + +/* + * rt5623 register cache + * We can't read the RT5623 register space when we + * are using 2 wire for device control, so we cache them instead. + */ +static const u16 rt5623_reg[0x7E/2]; + + +/* virtual HP mixers regs */ +#define HPL_MIXER 0x80 +#define HPR_MIXER 0x82 + +static u16 reg80=0,reg82=0; + +static u16 Set_Codec_Reg_Init[][2]={ + {RT5623_AUDIO_INTERFACE ,0x8000},// 0x34 set I2S codec to slave mode + {RT5623_STEREO_DAC_VOL ,0x0808},// 0x0c default stereo DAC volume to 0db + {RT5623_OUTPUT_MIXER_CTRL,0x1740},// 0x1c default output mixer control +// {RT5623_ADC_REC_MIXER ,0x3f3f},// 0x14 set record source is Mic1 by default + {RT5623_ADC_REC_MIXER ,0x5f5f},// 0x14 set record source is Mic2 by default + {RT5623_MIC_CTRL ,0x0500},// 0x22 set Mic1,Mic2 boost 20db + {RT5623_SPK_OUT_VOL ,0x8080},// 0x02 default speaker volume to 0db + {RT5623_HP_OUT_VOL ,0x8080},// 0x04 default HP volume to 0db + {RT5623_ADC_REC_GAIN ,0xf891},// record gain 9 db +}; + +#define SET_CODEC_REG_INIT_NUM ARRAY_SIZE(Set_Codec_Reg_Init) + +/* + * read rt5623 register cache + */ +static inline unsigned int rt5623_read_reg_cache(struct snd_soc_codec *codec, + unsigned int reg) +{ + u16 *cache = codec->reg_cache; + if (reg < 1 || reg > (ARRAY_SIZE(rt5623_reg) + 1)) + return -1; + return cache[reg/2]; +} + +/* + * write rt5623 register cache + */ +static inline void rt5623_write_reg_cache(struct snd_soc_codec *codec, + unsigned int reg, unsigned int value) +{ + u16 *cache = codec->reg_cache; + if (reg < 0 || reg > 0x7e) + return; + cache[reg/2] = value; +} + + +static int rt5623_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + u8 data[3]; + + if(reg>0x7E) + { + if(reg==HPL_MIXER) + reg80=value; + else if(reg==HPR_MIXER) + reg82=value; + else + return -EIO; + + return 0; + } + +// printk("rt5623 write reg=%x,value=%x\n",reg,value); + data[0] = reg; + data[1] = (0xFF00 & value) >> 8; + data[2] = 0x00FF & value; + + if (codec->hw_write(codec->control_data, data, 3) == 3) + { + rt5623_write_reg_cache (codec, reg, value); +// printk("rt5623 write OK\n"); + return 0; + } + else + { +// printk("rt5623 write faile\n"); + return -EIO; + } +} + +static unsigned int rt5623_read(struct snd_soc_codec *codec, unsigned int reg) +{ + u8 data[2]={0}; + unsigned int value=0x0; + + if(reg>0x7E) + { + if(reg==HPL_MIXER) + return reg80; + else if(reg==HPR_MIXER) + return reg82; + else + return -EIO; + + return -EIO; + } + + data[0] = reg; + if(codec->hw_write(codec->control_data, data, 1) ==1) + { + i2c_master_recv(codec->control_data, data, 2); + value = (data[0]<<8) | data[1]; +// printk("rt5623 read reg%x=%x\n",reg,value); + + return value; + } + else + { +// printk("rt5623 read faile\n"); + return -EIO; + } + +} + +static int rt5623_write_mask(struct snd_soc_codec *codec, unsigned int reg,unsigned int value,unsigned int mask) +{ + + unsigned char RetVal=0; + unsigned int CodecData; + + if(!mask) + return 0; + + if(mask!=0xffff) + { + CodecData=rt5623_read(codec,reg); + CodecData&=~mask; + CodecData|=(value&mask); + RetVal=rt5623_write(codec,reg,CodecData); + } + else + { + RetVal=rt5623_write(codec,reg,value); + } + + return RetVal; +} + +#if 0 +//***************************************************************************** +// +//function AudioOutEnable:Mute/Unmute audio out channel +// WavOutPath:output channel +// Mute :Mute/Unmute output channel +// +//***************************************************************************** +static int rt5623_AudioOutEnable(struct snd_soc_codec *codec,unsigned short int WavOutPath,int Mute) +{ + int RetVal=0; + + + if(Mute) + { + switch(WavOutPath) + { + case RT_WAVOUT_ALL_ON: + + RetVal=rt5623_write_mask(codec,RT5623_SPK_OUT_VOL,RT_L_MUTE|RT_R_MUTE,RT_L_MUTE|RT_R_MUTE); //Mute Speaker right/left channel + RetVal=rt5623_write_mask(codec,RT5623_HP_OUT_VOL,RT_L_MUTE|RT_R_MUTE,RT_L_MUTE|RT_R_MUTE); //Mute headphone right/left channel + RetVal=rt5623_write_mask(codec,RT5623_MONO_AUX_OUT_VOL,RT_L_MUTE|RT_R_MUTE,RT_L_MUTE|RT_R_MUTE); //Mute Aux/Mono right/left channel + RetVal=rt5623_write_mask(codec,RT5623_STEREO_DAC_VOL,RT_M_HP_MIXER|RT_M_SPK_MIXER|RT_M_MONO_MIXER + ,RT_M_HP_MIXER|RT_M_SPK_MIXER|RT_M_MONO_MIXER); //Mute DAC to HP,Speaker,Mono Mixer + + break; + + case RT_WAVOUT_HP: + + RetVal=rt5623_write_mask(codec,RT5623_HP_OUT_VOL,RT_L_MUTE|RT_R_MUTE,RT_L_MUTE|RT_R_MUTE); //Mute headphone right/left channel + + break; + + case RT_WAVOUT_SPK: + + RetVal=rt5623_write_mask(codec,RT5623_SPK_OUT_VOL,RT_L_MUTE|RT_R_MUTE,RT_L_MUTE|RT_R_MUTE); //Mute Speaker right/left channel + + break; + + case RT_WAVOUT_AUXOUT: + + RetVal=rt5623_write_mask(codec,RT5623_MONO_AUX_OUT_VOL,RT_L_MUTE|RT_R_MUTE,RT_L_MUTE|RT_R_MUTE); //Mute AuxOut right/left channel + + break; + + case RT_WAVOUT_MONO: + + RetVal=rt5623_write_mask(codec,RT5623_MONO_AUX_OUT_VOL,RT_L_MUTE,RT_L_MUTE); //Mute MonoOut channel + + break; + + case RT_WAVOUT_DAC: + + RetVal=rt5623_write_mask(codec,RT5623_STEREO_DAC_VOL,RT_M_HP_MIXER|RT_M_SPK_MIXER|RT_M_MONO_MIXER + ,RT_M_HP_MIXER|RT_M_SPK_MIXER|RT_M_MONO_MIXER); //Mute DAC to HP,Speaker,Mono Mixer + break; + + default: + + return 0; + + } + } + else + { + switch(WavOutPath) + { + + case RT_WAVOUT_ALL_ON: + + RetVal=rt5623_write_mask(codec,RT5623_SPK_OUT_VOL ,0,RT_L_MUTE|RT_R_MUTE); //Mute Speaker right/left channel + RetVal=rt5623_write_mask(codec,RT5623_HP_OUT_VOL ,0,RT_L_MUTE|RT_R_MUTE); //Mute headphone right/left channel + RetVal=rt5623_write_mask(codec,RT5623_MONO_AUX_OUT_VOL,0,RT_L_MUTE|RT_R_MUTE); //Mute Aux/Mono right/left channel + RetVal=rt5623_write_mask(codec,RT5623_STEREO_DAC_VOL ,0,RT_M_HP_MIXER|RT_M_SPK_MIXER|RT_M_MONO_MIXER); //Mute DAC to HP,Speaker,Mono Mixer + + break; + + case RT_WAVOUT_HP: + + RetVal=rt5623_write_mask(codec,RT5623_HP_OUT_VOL,0,RT_L_MUTE|RT_R_MUTE); //UnMute headphone right/left channel + + break; + + case RT_WAVOUT_SPK: + + RetVal=rt5623_write_mask(codec,RT5623_SPK_OUT_VOL,0,RT_L_MUTE|RT_R_MUTE); //unMute Speaker right/left channel + + break; + + case RT_WAVOUT_AUXOUT: + + RetVal=rt5623_write_mask(codec,RT5623_MONO_AUX_OUT_VOL,0,RT_L_MUTE|RT_R_MUTE);//unMute AuxOut right/left channel + + break; + + case RT_WAVOUT_MONO: + + RetVal=rt5623_write_mask(codec,RT5623_MONO_AUX_OUT_VOL,0,RT_L_MUTE); //unMute MonoOut channel + + break; + + case RT_WAVOUT_DAC: + + RetVal=rt5623_write_mask(codec,RT5623_STEREO_DAC_VOL,0,RT_M_HP_MIXER|RT_M_SPK_MIXER|RT_M_MONO_MIXER); //unMute DAC to HP,Speaker,Mono Mixer + + default: + return 0; + } + + } + + return RetVal; +} +#endif +//***************************************************************************** +// +//function:Enable/Disable ADC input source control +// +//***************************************************************************** +static int Enable_ADC_Input_Source(struct snd_soc_codec *codec,unsigned short int ADC_Input_Sour,int Enable) +{ + int bRetVal=0; + + if(Enable) + { + //Enable ADC source + bRetVal=rt5623_write_mask(codec,RT5623_ADC_REC_MIXER,0,ADC_Input_Sour); + } + else + { + //Disable ADC source + bRetVal=rt5623_write_mask(codec,RT5623_ADC_REC_MIXER,ADC_Input_Sour,ADC_Input_Sour); + } + + return bRetVal; +} + + +#define rt5623_reset(c) rt5623_write(c, 0x0, 0) +/* + * RT5623 Controls + */ + +static const char *rt5623_spk_n_sour_sel[] = {"RN", "RP","LN","Vmid"}; +static const char *rt5623_spkout_input_sel[] = {"Vmid", "HP mixer","Speaker Mixer","Mono Mixer"}; +static const char *rt5623_hpl_out_input_sel[] = {"Vmid", "HP Left mixer"}; +static const char *rt5623_hpr_out_input_sel[] = {"Vmid", "HP Right mixer"}; +static const char *rt5623_mono_aux_out_input_sel[] = {"Vmid", "HP mixer","Speaker Mixer","Mono Mixer"}; +static const char *rt5623_mic_Boost_ctrl_sel[] = {"Bypass", "+20DB","+30DB","+40DB"}; + +static const struct soc_enum rt5623_enum[] = { +SOC_ENUM_SINGLE(RT5623_OUTPUT_MIXER_CTRL, 14, 4, rt5623_spk_n_sour_sel),// 0 +SOC_ENUM_SINGLE(RT5623_OUTPUT_MIXER_CTRL, 10, 4, rt5623_spkout_input_sel),// 1 +SOC_ENUM_SINGLE(RT5623_OUTPUT_MIXER_CTRL, 9, 2, rt5623_hpl_out_input_sel),// 2 +SOC_ENUM_SINGLE(RT5623_OUTPUT_MIXER_CTRL, 8, 2, rt5623_hpr_out_input_sel),// 3 +SOC_ENUM_SINGLE(RT5623_OUTPUT_MIXER_CTRL, 6, 4, rt5623_mono_aux_out_input_sel),// 4 +SOC_ENUM_SINGLE(RT5623_MIC_CTRL, 10, 4, rt5623_mic_Boost_ctrl_sel),// 5 +SOC_ENUM_SINGLE(RT5623_MIC_CTRL, 8, 4, rt5623_mic_Boost_ctrl_sel),// 6 +}; + +static const struct snd_kcontrol_new rt5623_snd_controls[] = { +SOC_DOUBLE("Speaker Playback Volume", RT5623_SPK_OUT_VOL, 8, 0, 31, 1), +SOC_DOUBLE("Speaker Playback Switch", RT5623_SPK_OUT_VOL, 15, 7, 1, 1), +SOC_DOUBLE("Headphone Playback Volume", RT5623_HP_OUT_VOL, 8, 0, 31, 1), +SOC_DOUBLE("Headphone Playback Switch", RT5623_HP_OUT_VOL,15, 7, 1, 1), +//SOC_DOUBLE("Auxout Playback Volume", RT5623_MONO_AUX_OUT_VOL,8, 0, 31, 1), +//SOC_DOUBLE("Auxout Playback Switch", RT5623_MONO_AUX_OUT_VOL,15, 7, 1, 1), +SOC_DOUBLE("PCM Playback Volume", RT5623_STEREO_DAC_VOL, 8, 0, 31, 1), +SOC_DOUBLE("PCM Playback Switch", RT5623_STEREO_DAC_VOL,15, 7, 1, 1), +//SOC_DOUBLE("LineIn Capture Volume", RT5623_LINE_IN_VOL, 8, 0, 31, 1), +//SOC_DOUBLE("AuxIn Capture Volume", RT5623_AUXIN_VOL, 8, 0, 31, 1), +//SOC_SINGLE("Mic1 Capture Volume", RT5623_MIC_VOL, 8, 31, 1), +//SOC_SINGLE("Mic2 Capture Volume", RT5623_MIC_VOL, 0, 31, 1), +SOC_DOUBLE("Rec Capture Volume", RT5623_ADC_REC_GAIN, 7, 0, 31, 0), +//SOC_ENUM("Mic 1 Boost", rt5623_enum[5]), +SOC_ENUM("Mic 2 Boost", rt5623_enum[6]), + +}; + + +/* add non dapm controls */ +static int rt5623_add_controls(struct snd_soc_codec *codec) +{ + int err, i; + + for (i = 0; i < ARRAY_SIZE(rt5623_snd_controls); i++) { + err = snd_ctl_add(codec->card, + snd_soc_cnew(&rt5623_snd_controls[i],codec, NULL)); + if (err < 0) + return err; + } + return 0; +} + +/* + * _DAPM_ Controls + */ + +/* We have to create a fake left and right HP mixers because + * the codec only has a single control that is shared by both channels. + * This makes it impossible to determine the audio path using the current + * register map, thus we add a new (virtual) register to help determine the + * audio route within the device. + */ +static int mixer_event (struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + u16 l=0, r=0, lineIn,mic1,mic2, auxin,pcm; + struct snd_soc_device *socdev = rt5623_socdev; + struct snd_soc_codec *codec = socdev->card->codec; + + l = rt5623_read(codec, HPL_MIXER); + r = rt5623_read(codec, HPR_MIXER); + lineIn = rt5623_read(codec, RT5623_LINE_IN_VOL); + mic1 = rt5623_read(codec, RT5623_MIC_ROUTING_CTRL); + mic2 = rt5623_read(codec, RT5623_MIC_ROUTING_CTRL); + auxin = rt5623_read(codec,RT5623_AUXIN_VOL); + pcm = rt5623_read(codec, RT5623_STEREO_DAC_VOL); + + if (event & SND_SOC_DAPM_PRE_REG) + return 0; + + if (l & 0x1 || r & 0x1) + rt5623_write(codec, RT5623_STEREO_DAC_VOL, pcm & 0x7fff); + else + rt5623_write(codec, RT5623_STEREO_DAC_VOL, pcm | 0x8000); + + if (l & 0x2 || r & 0x2) + rt5623_write(codec, RT5623_MIC_ROUTING_CTRL, mic2 & 0xf7ff); + else + rt5623_write(codec, RT5623_MIC_ROUTING_CTRL, mic2 | 0x0800); + + if (l & 0x4 || r & 0x4) + rt5623_write(codec, RT5623_MIC_ROUTING_CTRL, mic1 & 0x7fff); + else + rt5623_write(codec, RT5623_MIC_ROUTING_CTRL, mic1 | 0x8000); + + if (l & 0x8 || r & 0x8) + rt5623_write(codec, RT5623_AUXIN_VOL, auxin & 0x7fff); + else + rt5623_write(codec, RT5623_AUXIN_VOL, auxin | 0x8000); + + if (l & 0x10 || r & 0x10) + rt5623_write(codec, RT5623_LINE_IN_VOL, lineIn & 0x7fff); + else + rt5623_write(codec, RT5623_LINE_IN_VOL, lineIn | 0x8000); + + return 0; +} + +/* Left Headphone Mixers */ +static const struct snd_kcontrol_new rt5623_hpl_mixer_controls[] = { +SOC_DAPM_SINGLE("LineIn Playback Switch", HPL_MIXER, 4, 1, 0), +SOC_DAPM_SINGLE("AUXIN Playback Switch", HPL_MIXER, 3, 1, 0), +SOC_DAPM_SINGLE("Mic1 Playback Switch", HPL_MIXER, 2, 1, 0), +SOC_DAPM_SINGLE("Mic2 Playback Switch", HPL_MIXER, 1, 1, 0), +SOC_DAPM_SINGLE("PCM Playback Switch", HPL_MIXER, 0, 1, 0), +SOC_DAPM_SINGLE("RecordL Playback Switch", RT5623_ADC_REC_GAIN, 15, 1,1), +}; + + +/* Right Headphone Mixers */ +static const struct snd_kcontrol_new rt5623_hpr_mixer_controls[] = { +SOC_DAPM_SINGLE("LineIn Playback Switch", HPR_MIXER, 5, 1, 0), +SOC_DAPM_SINGLE("AUXIN Playback Switch", HPR_MIXER, 4, 1, 0), +SOC_DAPM_SINGLE("Mic1 Playback Switch", HPR_MIXER, 3, 1, 0), +SOC_DAPM_SINGLE("Mic2 Playback Switch", HPR_MIXER, 2, 1, 0), +SOC_DAPM_SINGLE("PCM Playback Switch", HPR_MIXER, 1, 1, 0), +SOC_DAPM_SINGLE("RecordR Playback Switch", RT5623_ADC_REC_GAIN, 14, 1,1), +}; + +//Left Record Mixer +static const struct snd_kcontrol_new rt5623_captureL_mixer_controls[] = { +SOC_DAPM_SINGLE("Mic1 Capture Switch", RT5623_ADC_REC_MIXER, 14, 1, 1), +SOC_DAPM_SINGLE("Mic2 Capture Switch", RT5623_ADC_REC_MIXER, 13, 1, 1), +SOC_DAPM_SINGLE("LineInL Capture Switch",RT5623_ADC_REC_MIXER,12, 1, 1), +SOC_DAPM_SINGLE("AuxInL Capture Switch", RT5623_ADC_REC_MIXER, 11, 1, 1), +SOC_DAPM_SINGLE("HPMixerL Capture Switch", RT5623_ADC_REC_MIXER,10, 1, 1), +SOC_DAPM_SINGLE("SPKMixer Capture Switch",RT5623_ADC_REC_MIXER,9, 1, 1), +SOC_DAPM_SINGLE("MonoMixer Capture Switch",RT5623_ADC_REC_MIXER,8, 1, 1), +}; + +//Right Record Mixer +static const struct snd_kcontrol_new rt5623_captureR_mixer_controls[] = { +SOC_DAPM_SINGLE("Mic1 Capture Switch", RT5623_ADC_REC_MIXER, 6, 1, 1), +SOC_DAPM_SINGLE("Mic2 Capture Switch", RT5623_ADC_REC_MIXER, 5, 1, 1), +SOC_DAPM_SINGLE("LineInR Capture Switch",RT5623_ADC_REC_MIXER,4, 1, 1), +SOC_DAPM_SINGLE("AuxInLR Capture Switch", RT5623_ADC_REC_MIXER, 3, 1, 1), +SOC_DAPM_SINGLE("HPMixerR Capture Switch", RT5623_ADC_REC_MIXER,2, 1, 1), +SOC_DAPM_SINGLE("SPKMixer Capture Switch",RT5623_ADC_REC_MIXER,1, 1, 1), +SOC_DAPM_SINGLE("MonoMixer Capture Switch",RT5623_ADC_REC_MIXER,0, 1, 1), +}; + + +/* Speaker Mixer */ +static const struct snd_kcontrol_new rt5623_speaker_mixer_controls[] = { +SOC_DAPM_SINGLE("LineIn Playback Switch", RT5623_LINE_IN_VOL, 14, 1, 1), +SOC_DAPM_SINGLE("AuxIn Playback Switch", RT5623_AUXIN_VOL, 14, 1, 1), +SOC_DAPM_SINGLE("Mic1 Playback Switch", RT5623_MIC_ROUTING_CTRL, 14, 1, 1), +SOC_DAPM_SINGLE("Mic2 Playback Switch", RT5623_MIC_ROUTING_CTRL, 6, 1, 1), +SOC_DAPM_SINGLE("PCM Playback Switch", RT5623_STEREO_DAC_VOL, 14, 1, 1), +}; + + +/* Mono Mixer */ +static const struct snd_kcontrol_new rt5623_mono_mixer_controls[] = { +SOC_DAPM_SINGLE("LineIn Playback Switch", RT5623_LINE_IN_VOL, 13, 1, 1), +SOC_DAPM_SINGLE("AuxIn Playback Switch", RT5623_AUXIN_VOL, 13, 1, 1), +SOC_DAPM_SINGLE("Mic1 Playback Switch", RT5623_MIC_ROUTING_CTRL, 13, 1, 1), +SOC_DAPM_SINGLE("Mic2 Playback Switch", RT5623_MIC_ROUTING_CTRL, 5, 1, 1), +SOC_DAPM_SINGLE("PCM Playback Switch", RT5623_STEREO_DAC_VOL, 13, 1, 1), +SOC_DAPM_SINGLE("RecordL Playback Switch", RT5623_ADC_REC_GAIN, 13, 1,1), +SOC_DAPM_SINGLE("RecordR Playback Switch", RT5623_ADC_REC_GAIN, 12, 1,1), +}; + +/* auxout output mux */ +static const struct snd_kcontrol_new rt5623_auxout_mux_controls = +SOC_DAPM_ENUM("Route", rt5623_enum[4]); + + +/* speaker output mux */ +static const struct snd_kcontrol_new rt5623_spkout_mux_controls = +SOC_DAPM_ENUM("Route", rt5623_enum[1]); + + +/* headphone left output mux */ +static const struct snd_kcontrol_new rt5623_hpl_out_mux_controls = +SOC_DAPM_ENUM("Route", rt5623_enum[2]); + + +/* headphone right output mux */ +static const struct snd_kcontrol_new rt5623_hpr_out_mux_controls = +SOC_DAPM_ENUM("Route", rt5623_enum[3]); + + +static const struct snd_soc_dapm_widget rt5623_dapm_widgets[] = { +SND_SOC_DAPM_MUX("Aux Out Mux", SND_SOC_NOPM, 0, 0, + &rt5623_auxout_mux_controls), +SND_SOC_DAPM_MUX("Speaker Out Mux", SND_SOC_NOPM, 0, 0, + &rt5623_spkout_mux_controls), +SND_SOC_DAPM_MUX("Left Headphone Out Mux", SND_SOC_NOPM, 0, 0, + &rt5623_hpl_out_mux_controls), +SND_SOC_DAPM_MUX("Right Headphone Out Mux", SND_SOC_NOPM, 0, 0, + &rt5623_hpr_out_mux_controls), +SND_SOC_DAPM_MIXER_E("Left HP Mixer",RT5623_PWR_MANAG_ADD2, 5, 0, + &rt5623_hpl_mixer_controls[0], ARRAY_SIZE(rt5623_hpl_mixer_controls), + mixer_event, SND_SOC_DAPM_POST_REG), +SND_SOC_DAPM_MIXER_E("Right HP Mixer",RT5623_PWR_MANAG_ADD2, 4, 0, + &rt5623_hpr_mixer_controls[0], ARRAY_SIZE(rt5623_hpr_mixer_controls), + mixer_event, SND_SOC_DAPM_POST_REG), +SND_SOC_DAPM_MIXER("Mono Mixer", RT5623_PWR_MANAG_ADD2, 2, 0, + &rt5623_mono_mixer_controls[0], ARRAY_SIZE(rt5623_mono_mixer_controls)), +SND_SOC_DAPM_MIXER("Speaker Mixer", RT5623_PWR_MANAG_ADD2,3,0, + &rt5623_speaker_mixer_controls[0], + ARRAY_SIZE(rt5623_speaker_mixer_controls)), +SND_SOC_DAPM_MIXER("Left Record Mixer", RT5623_PWR_MANAG_ADD2,1,0, + &rt5623_captureL_mixer_controls[0], + ARRAY_SIZE(rt5623_captureL_mixer_controls)), +SND_SOC_DAPM_MIXER("Right Record Mixer", RT5623_PWR_MANAG_ADD2,0,0, + &rt5623_captureR_mixer_controls[0], + ARRAY_SIZE(rt5623_captureR_mixer_controls)), +SND_SOC_DAPM_DAC("Left DAC", "Left HiFi Playback", RT5623_PWR_MANAG_ADD2,9, 0), +SND_SOC_DAPM_DAC("Right DAC", "Right HiFi Playback", RT5623_PWR_MANAG_ADD2, 8, 0), +SND_SOC_DAPM_MIXER("IIS Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), +SND_SOC_DAPM_MIXER("HP Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), +SND_SOC_DAPM_MIXER("AuxIn Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), +SND_SOC_DAPM_MIXER("Line Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), +SND_SOC_DAPM_ADC("Left ADC", "Left HiFi Capture", RT5623_PWR_MANAG_ADD2, 7, 0), +SND_SOC_DAPM_ADC("Right ADC", "Right HiFi Capture", RT5623_PWR_MANAG_ADD2, 6, 0), +SND_SOC_DAPM_PGA("Left Headphone", RT5623_PWR_MANAG_ADD3, 10, 0, NULL, 0), +SND_SOC_DAPM_PGA("Right Headphone", RT5623_PWR_MANAG_ADD3, 9, 0, NULL, 0), +SND_SOC_DAPM_PGA("Speaker Out", RT5623_PWR_MANAG_ADD3, 12, 0, NULL, 0), +SND_SOC_DAPM_PGA("Left Aux Out", RT5623_PWR_MANAG_ADD3, 14, 0, NULL, 0), +SND_SOC_DAPM_PGA("Right Aux Out", RT5623_PWR_MANAG_ADD3, 13, 0, NULL, 0), +SND_SOC_DAPM_PGA("Left Line In", RT5623_PWR_MANAG_ADD3, 7, 0, NULL, 0), +SND_SOC_DAPM_PGA("Right Line In", RT5623_PWR_MANAG_ADD3, 6, 0, NULL, 0), +SND_SOC_DAPM_PGA("Left Aux In",RT5623_PWR_MANAG_ADD3, 5, 0, NULL, 0), +SND_SOC_DAPM_PGA("Right Aux In",RT5623_PWR_MANAG_ADD3, 4, 0, NULL, 0), +SND_SOC_DAPM_PGA("Mic 1 PGA", RT5623_PWR_MANAG_ADD3, 3, 0, NULL, 0), +SND_SOC_DAPM_PGA("Mic 2 PGA", RT5623_PWR_MANAG_ADD3, 2, 0, NULL, 0), +SND_SOC_DAPM_PGA("Mic 1 Pre Amp", RT5623_PWR_MANAG_ADD3, 1, 0, NULL, 0), +SND_SOC_DAPM_PGA("Mic 2 Pre Amp", RT5623_PWR_MANAG_ADD3, 0, 0, NULL, 0), +SND_SOC_DAPM_MICBIAS("Mic Bias1", RT5623_PWR_MANAG_ADD1, 11, 0), +SND_SOC_DAPM_OUTPUT("AUXOUT"), +SND_SOC_DAPM_OUTPUT("HPL"), +SND_SOC_DAPM_OUTPUT("HPR"), +SND_SOC_DAPM_OUTPUT("SPKOUT"), +SND_SOC_DAPM_INPUT("LINEL"), +SND_SOC_DAPM_INPUT("LINER"), +SND_SOC_DAPM_INPUT("AUXINL"), +SND_SOC_DAPM_INPUT("AUXINR"), +SND_SOC_DAPM_INPUT("MIC1"), +SND_SOC_DAPM_INPUT("MIC2"), +SND_SOC_DAPM_VMID("VMID"), +}; + + +static const struct snd_soc_dapm_route intercon[] = { + /* left HP mixer */ + {"Left HP Mixer", "LineIn Playback Switch", "LINEL"}, + {"Left HP Mixer", "AuxIn Playback Switch","AUXIN"}, + {"Left HP Mixer", "Mic1 Playback Switch","MIC1"}, + {"Left HP Mixer", "Mic2 Playback Switch","MIC2"}, + {"Left HP Mixer", "PCM Playback Switch","Left DAC"}, + {"Left HP Mixer", "RecordL Playback Switch","Left Record Mixer"}, + + /* right HP mixer */ + {"Right HP Mixer", "LineIn Playback Switch", "LINER"}, + {"Right HP Mixer", "AuxIn Playback Switch","AUXIN"}, + {"Right HP Mixer", "Mic1 Playback Switch","MIC1"}, + {"Right HP Mixer", "Mic2 Playback Switch","MIC2"}, + {"Right HP Mixer", "PCM Playback Switch","Right DAC"}, + {"Right HP Mixer", "RecordR Playback Switch","Right Record Mixer"}, + + /* virtual mixer - mixes left & right channels for spk and mono */ + {"IIS Mixer", NULL, "Left DAC"}, + {"IIS Mixer", NULL, "Right DAC"}, + {"Line Mixer", NULL, "Right Line In"}, + {"Line Mixer", NULL, "Left Line In"}, + {"HP Mixer", NULL, "Left HP Mixer"}, + {"HP Mixer", NULL, "Right HP Mixer"}, + {"AuxIn Mixer",NULL,"Left Aux In"}, + {"AuxIn Mixer",NULL,"Right Aux In"}, + {"AuxOut Mixer",NULL,"Left Aux Out"}, + {"AuxOut Mixer",NULL,"Right Aux Out"}, + + /* speaker mixer */ + {"Speaker Mixer", "LineIn Playback Switch","Line Mixer"}, + {"Speaker Mixer", "AuxIn Playback Switch","AuxIn Mixer"}, + {"Speaker Mixer", "Mic1 Playback Switch","MIC1"}, + {"Speaker Mixer", "Mic2 Playback Switch","MIC2"}, + {"Speaker Mixer", "PCM Playback Switch","IIS Mixer"}, + + /* mono mixer */ + {"Mono Mixer", "LineIn Playback Switch","Line Mixer"}, + {"Mono Mixer", "AuxIn Playback Switch","AuxIn Mixer"}, + {"Mono Mixer", "Mic1 Playback Switch","MIC1"}, + {"Mono Mixer", "Mic2 Playback Switch","MIC2"}, + {"Mono Mixer", "PCM Playback Switch","IIS Mixer"}, + {"Mono Mixer", "RecordL Playback Switch","Left Record Mixer"}, + {"Mono Mixer", "RecordR Playback Switch","Right Record Mixer"}, + + /*Left record mixer */ + {"Left Record Mixer", "Mic1 Capture Switch","Mic 1 Pre Amp"}, + {"Left Record Mixer", "Mic2 Capture Switch","Mic 2 Pre Amp"}, + {"Left Record Mixer", "LineInL Capture Switch","LINEL"}, + {"Left Record Mixer", "Phone Capture Switch","PHONEIN"}, + {"Left Record Mixer", "HPMixerL Capture Switch","Left HP Mixer"}, + {"Left Record Mixer", "SPKMixer Capture Switch","Speaker Mixer"}, + {"Left Record Mixer", "MonoMixer Capture Switch","Mono Mixer"}, + + /*Right record mixer */ + {"Right Record Mixer", "Mic1 Capture Switch","Mic 1 Pre Amp"}, + {"Right Record Mixer", "Mic2 Capture Switch","Mic 2 Pre Amp"}, + {"Right Record Mixer", "LineInR Capture Switch","LINER"}, + {"Right Record Mixer", "Phone Capture Switch","PHONEIN"}, + {"Right Record Mixer", "HPMixerR Capture Switch","Right HP Mixer"}, + {"Right Record Mixer", "SPKMixer Capture Switch","Speaker Mixer"}, + {"Right Record Mixer", "MonoMixer Capture Switch","Mono Mixer"}, + + /* headphone left mux */ + {"Left Headphone Out Mux", "HP Left mixer", "Left HP Mixer"}, + + /* headphone right mux */ + {"Right Headphone Out Mux", "HP Right mixer", "Right HP Mixer"}, + + /* speaker out mux */ + {"Speaker Out Mux", "HP mixer", "HP Mixer"}, + {"Speaker Out Mux", "Speaker Mixer", "Speaker Mixer"}, + {"Speaker Out Mux", "Mono Mixer", "Mono Mixer"}, + + /* Aux Out mux */ + {"Aux Out Mux", "HP mixer", "HP Mixer"}, + {"Aux Out Mux", "Speaker Mixer", "Speaker Mixer"}, + {"Aux Out Mux", "Mono Mixer", "Mono Mixer"}, + + /* output pga */ + {"HPL", NULL, "Left Headphone"}, + {"Left Headphone", NULL, "Left Headphone Out Mux"}, + {"HPR", NULL, "Right Headphone"}, + {"Right Headphone", NULL, "Right Headphone Out Mux"}, + {"SPKOUT", NULL, "Speaker Out"}, + {"Speaker Out", NULL, "Speaker Out Mux"}, + {"AUXOUT", NULL, "AuxOut Mixer"}, + {"Left Aux Out", NULL, "Aux Out Mux"}, + {"Right Aux Out", NULL, "Aux Out Mux"}, + + /* input pga */ + {"Left Line In", NULL, "LINEL"}, + {"Right Line In", NULL, "LINER"}, + {"Left Aux In", NULL, "AUXINL"}, + {"Right Aux In", NULL, "AUXINR"}, + {"Mic 1 Pre Amp", NULL, "MIC1"}, + {"Mic 2 Pre Amp", NULL, "MIC2"}, + {"Mic 1 PGA", NULL, "Mic 1 Pre Amp"}, + {"Mic 2 PGA", NULL, "Mic 2 Pre Amp"}, + + /* left ADC */ + {"Left ADC", NULL, "Left Record Mixer"}, + + /* right ADC */ + {"Right ADC", NULL, "Right Record Mixer"}, + + /* terminator */ + {NULL, NULL, NULL}, +}; + + +static int rt5623_add_widgets(struct snd_soc_codec *codec) +{ + int i; + +// snd_soc_dapm_new_controls(codec, rt5623_dapm_widgets, ARRAY_SIZE(rt5623_dapm_widgets)); + + /* set up audio path interconnects */ +// snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon)); + + snd_soc_dapm_new_widgets(codec); + return 0; +} + + +#if 0 +/* PLL divisors */ +struct _pll_div { + u32 pll_in; + u32 pll_out; + u16 regvalue; +}; + +static const struct _pll_div codec_master_pll_div[] = { + + { 2048000, 8192000, 0x0ea0}, + { 3686400, 8192000, 0x4e27}, + { 12000000, 8192000, 0x456b}, + { 13000000, 8192000, 0x495f}, + { 13100000, 8192000, 0x0320}, + { 2048000, 11289600, 0xf637}, + { 3686400, 11289600, 0x2f22}, + { 12000000, 11289600, 0x3e2f}, + { 13000000, 11289600, 0x4d5b}, + { 13100000, 11289600, 0x363b}, + { 2048000, 16384000, 0x1ea0}, + { 3686400, 16384000, 0x9e27}, + { 12000000, 16384000, 0x452b}, + { 13000000, 16384000, 0x542f}, + { 13100000, 16384000, 0x03a0}, + { 2048000, 16934400, 0xe625}, + { 3686400, 16934400, 0x9126}, + { 12000000, 16934400, 0x4d2c}, + { 13000000, 16934400, 0x742f}, + { 13100000, 16934400, 0x3c27}, + { 2048000, 22579200, 0x2aa0}, + { 3686400, 22579200, 0x2f20}, + { 12000000, 22579200, 0x7e2f}, + { 13000000, 22579200, 0x742f}, + { 13100000, 22579200, 0x3c27}, + { 2048000, 24576000, 0x2ea0}, + { 3686400, 24576000, 0xee27}, + { 12000000, 24576000, 0x2915}, + { 13000000, 24576000, 0x772e}, + { 13100000, 24576000, 0x0d20}, +}; + +static const struct _pll_div codec_slave_pll_div[] = { + + { 1024000, 16384000, 0x3ea0}, + { 1411200, 22579200, 0x3ea0}, + { 1536000, 24576000, 0x3ea0}, + { 2048000, 16384000, 0x1ea0}, + { 2822400, 22579200, 0x1ea0}, + { 3072000, 24576000, 0x1ea0}, + +}; + + +static int rt5623_set_dai_pll(struct snd_soc_dai *codec_dai, + int pll_id, unsigned int freq_in, unsigned int freq_out) +{ + int i; + struct snd_soc_codec *codec = codec_dai->codec; + + if (pll_id < RT5623_PLL_FR_MCLK || pll_id > RT5623_PLL_FR_BCK) + return -ENODEV; + + rt5623_write_mask(codec,RT5623_PWR_MANAG_ADD2, 0x0000,0x1000); //disable PLL power + + if (!freq_in || !freq_out) { + + return 0; + } + + if (pll_id == RT5623_PLL_FR_MCLK) { //codec is master mode + + for (i = 0; i < ARRAY_SIZE(codec_master_pll_div); i++) { + + if (codec_master_pll_div[i].pll_in == freq_in && codec_master_pll_div[i].pll_out == freq_out) + { + rt5623_write(codec,RT5623_GLOBAL_CLK_CTRL_REG,0x0000);//PLL source from MCLK + + rt5623_write(codec,RT5623_PLL_CTRL,codec_master_pll_div[i].regvalue);//set PLL parameter + + rt5623_write_mask(codec,RT5623_PWR_MANAG_ADD2, 0x1000,0x1000); //enable PLL power + + rt5623_write(codec,RT5623_GLOBAL_CLK_CTRL_REG,0x8000);//Codec sys-clock from PLL + + break; + } + } + + } else { //codec is slave mode + + for (i = 0; i < ARRAY_SIZE(codec_slave_pll_div); i++) { + + if (codec_slave_pll_div[i].pll_in == freq_in && codec_slave_pll_div[i].pll_out == freq_out) + { + rt5623_write(codec,RT5623_GLOBAL_CLK_CTRL_REG,0x4000);//PLL source from Bitclk + + rt5623_write(codec,RT5623_PLL_CTRL,codec_master_pll_div[i].regvalue);//set PLL parameter + + rt5623_write_mask(codec,RT5623_PWR_MANAG_ADD2, 0x1000,0x1000); //enable PLL power + + rt5623_write(codec,RT5623_GLOBAL_CLK_CTRL_REG,0xc000);//Codec sys-clock from PLL + break; + } + } + } + + return 0; +} + +struct _coeff_div { + u32 mclk; + u32 rate; + u16 fs; + u16 regvalue; +}; + + +/* codec hifi mclk (after PLL) clock divider coefficients */ +static const struct _coeff_div coeff_div[] = { + /* 8k */ + { 8192000, 8000, 256*4, 0x2a69}, + {12288000, 8000, 384*4, 0x2c6b}, + + /* 11.025k */ + {11289600, 11025, 256*4, 0x2a69}, + {16934400, 11025, 384*4, 0x2c6b}, + + /* 16k */ + {16384000, 16000, 256*4, 0x2a69}, + {24576000, 16000, 384*4, 0x2c6b}, + + /* 22.05k */ + {11289600, 22050, 256*2, 0x1a69}, + {16934400, 22050, 384*2, 0x1c6b}, + + /* 32k */ + {16384000, 32000, 256*2, 0x1a69}, + {24576000, 32000, 384*2, 0x1c6b}, + + /* 44.1k */ + {22579200, 44100, 256*2, 0x1a69}, + + /* 48k */ + {24576000, 48000, 256*2, 0x1a69}, + +}; + +static int get_coeff(int mclk, int rate) +{ + int i; + +// printk("get_coeff mclk=%d,rate=%d\n",mclk,rate); + + for (i = 0; i < ARRAY_SIZE(coeff_div); i++) { + if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk) + return i; + } + return -EINVAL; +} +#endif + +/* + * Clock after PLL and dividers + */ +static int rt5623_set_dai_sysclk(struct snd_soc_dai *codec_dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct rt5623_priv *rt5623 = codec->private_data; + + switch (freq) { + case 8192000: + case 11289600: + case 12288000: + case 16384000: + case 16934400: + case 18432000: + case 22579200: + case 24576000: + rt5623->sysclk = freq; + return 0; + } + return -EINVAL; +} + + +static int rt5623_set_dai_fmt(struct snd_soc_dai *codec_dai, + unsigned int fmt) +{ + struct snd_soc_codec *codec = codec_dai->codec; + u16 iface = 0; + + /* set master/slave audio interface */ + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + iface = 0x0000; + break; + case SND_SOC_DAIFMT_CBS_CFS: + iface = 0x8000; + break; + default: + return -EINVAL; + } + + /* interface format */ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + iface |= 0x0000; + break; + case SND_SOC_DAIFMT_RIGHT_J: + iface |= 0x0001; + break; + case SND_SOC_DAIFMT_LEFT_J: + iface |= 0x0002; + break; + case SND_SOC_DAIFMT_DSP_A: + iface |= 0x0003; + break; + case SND_SOC_DAIFMT_DSP_B: + iface |= 0x4003; + break; + default: + return -EINVAL; + } + + /* clock inversion */ + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_IB_IF: + iface |= 0x0080; + break; + case SND_SOC_DAIFMT_IB_NF: + iface |= 0x0080; + break; + case SND_SOC_DAIFMT_NB_IF: + break; + default: + return -EINVAL; + } + + rt5623_write_mask(codec,RT5623_AUDIO_INTERFACE, iface,0x4803); + return 0; +} + + + +static int rt5623_pcm_hw_params(struct snd_pcm_substream *substream,struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_codec *codec = socdev->card->codec; +// struct rt5623_priv *rt5623 = codec->private_data; + u16 iface=rt5623_read(codec,RT5623_AUDIO_INTERFACE)&0xfff3; +// int coeff = get_coeff(rt5623->sysclk, params_rate(params)); + +// printk("rt5623_pcm_hw_params\n"); + + /* bit size */ + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: +// printk("S16_LE\n"); + break; + case SNDRV_PCM_FORMAT_S20_3LE: +// printk("S20_3LE\n"); + iface |= 0x0004; + break; + case SNDRV_PCM_FORMAT_S24_LE: +// printk("S24_LE\n"); + iface |= 0x0008; + break; + case SNDRV_PCM_FORMAT_S32_LE: +// printk("S32_LE\n"); + iface |= 0x000c; + break; + } + + /* set iface & srate */ + rt5623_write(codec, RT5623_AUDIO_INTERFACE, iface); +// if (coeff >= 0) +// rt5623_write(codec, RT5623_STEREO_AD_DA_CLK_CTRL,coeff_div[coeff].regvalue); + + return 0; +} + +static int rt5623_pcm_hw_trigger(struct snd_pcm_substream *substream,int cmd, + struct snd_soc_dai *dai) +{ +// struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_codec *codec = socdev->card->codec; + int ret = 0; + struct rt5623_setup_data *setup = socdev->codec_data; + +// printk("%s\n",__func__); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + if(substream->stream==SNDRV_PCM_STREAM_PLAYBACK) + { +// rt5623_ChangeCodecPowerStatus(codec,POWER_STATE_D1_PLAYBACK); +// rt5623_AudioOutEnable(codec,RT_WAVOUT_SPK,0); +// rt5623_AudioOutEnable(codec,RT_WAVOUT_HP,0); + } + else + { + if(setup->mic2_input) + {//mic2 input + Enable_ADC_Input_Source(codec,RT_WAVIN_L_LINE_IN|RT_WAVIN_R_LINE_IN,0); + Enable_ADC_Input_Source(codec,RT_WAVIN_L_MIC2|RT_WAVIN_R_MIC2,1); + } + else + { //line in + Enable_ADC_Input_Source(codec,RT_WAVIN_L_MIC2|RT_WAVIN_R_MIC2,0); + Enable_ADC_Input_Source(codec,RT_WAVIN_L_LINE_IN|RT_WAVIN_R_LINE_IN,1); + } + } + break; + + case SNDRV_PCM_TRIGGER_STOP: +// printk("%s : stop\n",__func__); + break; + + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + + break; + + case SNDRV_PCM_TRIGGER_RESUME: + + break; + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + + break; + + default: + ret = -EINVAL; + } + + return ret; +} + + + +static int rt5623_mute(struct snd_soc_dai *dai, int mute) +{ + struct snd_soc_codec *codec = dai->codec; + u16 mute_reg = rt5623_read(codec, RT5623_MISC_CTRL) & 0xfff3; + + + if (mute) + { +// printk("rt5623 mute\n"); + rt5623_write(codec, RT5623_MISC_CTRL, mute_reg | 0xc); + } + else + { +// printk("rt5623 unmute\n"); + rt5623_write(codec, RT5623_MISC_CTRL, mute_reg); + + } + return 0; +} + + +///////////////////////////////////////////////////////////////////////////////////////////// +// RT5623 DPAM for KW / Dove Avenger +///////////////////////////////////////////////////////////////////////////////////////////// + +#define RT5623_ADD1_POWER_D0 \ + PWR_MAIN_I2S_EN | PWR_ZC_DET_PD_EN | PWR_MIC1_BIAS_EN | PWR_SHORT_CURR_DET_EN | \ + PWR_SOFTGEN_EN | PWR_DEPOP_BUF_HP | PWR_HP_OUT_AMP | PWR_HP_OUT_ENH_AMP + +#define RT5623_ADD1_POWER_D0_PLAYBACK \ + PWR_MAIN_I2S_EN | PWR_ZC_DET_PD_EN | \ + PWR_SOFTGEN_EN | PWR_DEPOP_BUF_HP | PWR_HP_OUT_AMP | PWR_HP_OUT_ENH_AMP + +#define RT5623_ADD1_POWER_D0_CAPTURE \ + PWR_MAIN_I2S_EN | PWR_ZC_DET_PD_EN | PWR_MIC1_BIAS_EN | PWR_SHORT_CURR_DET_EN | \ + PWR_SOFTGEN_EN + +#define RT5623_ADD2_POWER_D0 \ + PWR_LINEOUT | PWR_VREF | PWR_DAC_REF_CIR | PWR_L_DAC_CLK | PWR_R_DAC_CLK | \ + PWR_L_ADC_CLK_GAIN | PWR_R_ADC_CLK_GAIN | PWR_L_HP_MIXER | PWR_R_HP_MIXER | \ + PWR_L_ADC_REC_MIXER | PWR_R_ADC_REC_MIXER + +#define RT5623_ADD2_POWER_D0_PLAYBACK \ + PWR_LINEOUT | PWR_VREF | PWR_DAC_REF_CIR | PWR_L_DAC_CLK | PWR_R_DAC_CLK | \ + PWR_L_HP_MIXER | PWR_R_HP_MIXER + +#define RT5623_ADD2_POWER_D0_CAPTURE \ + PWR_VREF | \ + PWR_L_ADC_CLK_GAIN | PWR_R_ADC_CLK_GAIN | \ + PWR_L_ADC_REC_MIXER | PWR_R_ADC_REC_MIXER + +#define RT5623_ADD3_POWER_D0 \ + PWR_MAIN_BIAS | PWR_SPK_OUT | PWR_HP_L_OUT_VOL | PWR_HP_R_OUT_VOL | \ + PWR_LINEIN_L_VOL | PWR_LINEIN_R_VOL | PWR_MIC2_BOOST_MIXER + +#define RT5623_ADD3_POWER_D0_PLAYBACK \ + PWR_MAIN_BIAS | PWR_SPK_OUT | PWR_HP_L_OUT_VOL | PWR_HP_R_OUT_VOL +#define RT5623_ADD3_POWER_D0_CAPTURE \ + PWR_MAIN_BIAS | PWR_LINEIN_L_VOL | PWR_LINEIN_R_VOL | PWR_MIC2_BOOST_MIXER + +#define RT5623_ADD1_POWER_D3HOT PWR_MIC1_BIAS_EN +#define RT5623_ADD2_POWER_D3HOT PWR_VREF +#define RT5623_ADD3_POWER_D3HOT PWR_MAIN_BIAS + + +#define RT5623_ADD1_POWER_D3COLD 0 +#define RT5623_ADD2_POWER_D3COLD 0 +#define RT5623_ADD3_POWER_D3COLD 0 + + + +static void enable_power_depop(struct snd_soc_codec *codec) +{ + + //Power On Main Bias +// rt5623_write_mask(codec, RT5623_PWR_MANAG_ADD3, PWR_MAIN_BIAS, PWR_MAIN_BIAS); + + //HP L/R MUTE + rt5623_write_mask(codec,RT5623_HP_OUT_VOL,RT_L_MUTE|RT_R_MUTE,RT_L_MUTE|RT_R_MUTE); + //SPK L/R MUTE + rt5623_write_mask(codec,RT5623_SPK_OUT_VOL,RT_L_MUTE|RT_R_MUTE,RT_L_MUTE|RT_R_MUTE); + + //Power On Softgen + rt5623_write_mask(codec, RT5623_PWR_MANAG_ADD1, PWR_SOFTGEN_EN, PWR_SOFTGEN_EN); + + //Power On Vref +// rt5623_write_mask(codec, RT5623_PWR_MANAG_ADD2, PWR_VREF, PWR_VREF); + + //Power On HP L/R vol + rt5623_write(codec, RT5623_PWR_MANAG_ADD3, RT5623_ADD3_POWER_D0); + + //enable HP Depop2 + rt5623_write_mask(codec,RT5623_MISC_CTRL,HP_DEPOP_MODE2_EN,HP_DEPOP_MODE2_EN); + + msleep(500); + +// rt5623_write_mask(codec, RT5623_PWR_MANAG_ADD1, PWR_HP_OUT_AMP | PWR_HP_OUT_ENH_AMP , PWR_HP_OUT_AMP | PWR_HP_OUT_ENH_AMP); + + + rt5623_write(codec, RT5623_PWR_MANAG_ADD2, RT5623_ADD2_POWER_D0); + rt5623_write(codec, RT5623_PWR_MANAG_ADD1, RT5623_ADD1_POWER_D0); + + //disable HP Depop2 + rt5623_write_mask(codec,RT5623_MISC_CTRL,0,HP_DEPOP_MODE2_EN); + + //HP L/R UNMUTE + rt5623_write_mask(codec,RT5623_HP_OUT_VOL,0,RT_L_MUTE|RT_R_MUTE); + //SPEAKER UNMUTE + rt5623_write_mask(codec,RT5623_SPK_OUT_VOL,0,RT_L_MUTE|RT_R_MUTE); + +} + + + +static int rt5623_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + switch (level) { + case SND_SOC_BIAS_ON: + /* vref/mid, osc on, dac unmute */ + enable_power_depop(codec); + break; + case SND_SOC_BIAS_PREPARE: + break; + case SND_SOC_BIAS_STANDBY: + /* everything off except vref/vmid, */ + rt5623_write(codec, RT5623_PWR_MANAG_ADD2, RT5623_ADD2_POWER_D3HOT); + rt5623_write(codec, RT5623_PWR_MANAG_ADD3, RT5623_ADD3_POWER_D3HOT); + rt5623_write(codec, RT5623_PWR_MANAG_ADD1, RT5623_ADD1_POWER_D3HOT); + break; + case SND_SOC_BIAS_OFF: + /* everything off, dac mute, inactive */ + rt5623_write(codec, RT5623_PWR_MANAG_ADD2, RT5623_ADD2_POWER_D3COLD); + rt5623_write(codec, RT5623_PWR_MANAG_ADD3, RT5623_ADD3_POWER_D3COLD); + rt5623_write(codec, RT5623_PWR_MANAG_ADD1, RT5623_ADD1_POWER_D3COLD); + break; + } + codec->bias_level = level; + return 0; +} + + +#define RT5623_RATES SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 + + +#define RT5623_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) + + +static struct snd_soc_dai_ops rt5623_dai_ops = { + .hw_params = rt5623_pcm_hw_params, + .trigger = rt5623_pcm_hw_trigger, + .digital_mute = rt5623_mute, + .set_fmt = rt5623_set_dai_fmt, + .set_sysclk = rt5623_set_dai_sysclk, +// .set_pll = rt5623_set_dai_pll, +}; + +struct snd_soc_dai rt5623_dai = { + .name = "RT5623", + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 2, + .rate_min = 44100, + .rate_max = 96000, + .rates = RT5623_RATES, + .formats = RT5623_FORMATS,}, + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 2, + .rate_min = 44100, + .rate_max = 96000, + .rates = RT5623_RATES, + .formats = RT5623_FORMATS,}, + + .ops = &rt5623_dai_ops, +}; +EXPORT_SYMBOL_GPL(rt5623_dai); + + +static void rt5623_work(struct work_struct *work) +{ + struct snd_soc_codec *codec = + container_of(work, struct snd_soc_codec, delayed_work.work); + rt5623_set_bias_level(codec, codec->bias_level); +} + +static int rt5623_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->card->codec; + + /* we only need to suspend if we are a valid card */ + if(!codec->card) + return 0; + + rt5623_set_bias_level(codec, SND_SOC_BIAS_OFF); + + return 0; +} + +static int rt5623_resume(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->card->codec; + int i; + u8 data[3]; + u16 *cache = codec->reg_cache; + + /* we only need to resume if we are a valid card */ + if(!codec->card) + return 0; + + /* Sync reg_cache with the hardware */ + + for (i = 0; i < ARRAY_SIZE(rt5623_reg); i++) { + if (i == RT5623_RESET) + continue; + data[0] =i*2; + data[1] = (0xFF00 & cache[i]) >> 8; + data[2] = 0x00FF & cache[i]; + codec->hw_write(codec->control_data, data, 3); + } + + rt5623_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + + /* charge rt5623 caps */ + if(codec->suspend_bias_level == SND_SOC_BIAS_ON) { + rt5623_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + codec->bias_level = SND_SOC_BIAS_ON; + schedule_delayed_work(&codec->delayed_work, + msecs_to_jiffies(caps_charge)); + + } + + return 0; +} + +/* + * initialise the RT5623 driver + * register the mixer and dsp interfaces with the kernel + */ +static int rt5623_init(struct snd_soc_device *socdev) +{ + struct snd_soc_codec *codec = socdev->card->codec; + int ret = 0,i=0; + + codec->name = "RT5623"; + codec->owner = THIS_MODULE; + codec->read = rt5623_read; + codec->write = rt5623_write; + codec->set_bias_level = rt5623_set_bias_level; + codec->dai = &rt5623_dai; + codec->num_dai = 1; + codec->reg_cache_size = sizeof(rt5623_reg); + codec->reg_cache = kmemdup(rt5623_reg, sizeof(rt5623_reg), GFP_KERNEL); + + if (codec->reg_cache == NULL) + return -ENOMEM; + + rt5623_reset(codec); + + rt5623_dai.dev = codec->dev; + + /* register pcms */ + ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); + if (ret < 0) { + printk(KERN_ERR "rt5623: failed to create pcms\n"); + goto pcm_err; + } + + rt5623_write(codec, RT5623_PWR_MANAG_ADD3, 0x8000);//enable Main bias + rt5623_write(codec, RT5623_PWR_MANAG_ADD2, 0x2000);//enable Vref + + /* power on device */ + rt5623_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + + schedule_delayed_work(&codec->delayed_work, + msecs_to_jiffies(caps_charge)); + + + //initize codec register + for(i=0;ireg_cache); + return ret; +} + + +/* If the i2c layer weren't so broken, we could pass this kind of data + around */ + + +#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE) + +/* + * RT5623 2 wire address is determined by A1 pin + * state during powerup. + * low = 0x1a + * high = 0x1b + */ +static const struct i2c_device_id rt5623_i2c_table[] = { + {"rt5623", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, rt5623_i2c_table); + + +static struct i2c_driver rt5623_i2c_driver; + +static int rt5623_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + struct snd_soc_device *socdev = rt5623_socdev; + struct rt5623_setup_data *setup = socdev->codec_data; + struct snd_soc_codec *codec = socdev->card->codec; + struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent); + int ret; + + if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_EMUL)) + return -EIO; + + i2c_set_clientdata(client, codec); + codec->control_data = client; + codec->dev = &client->dev; + + ret = rt5623_init(socdev); + + if (ret < 0) { + err("failed to initialise RT5623\n"); + goto err; + } + + return ret; + +err: + kfree(codec->private_data); + kfree(codec); + return ret; +} + +static int rt5623_i2c_remove(struct i2c_client *client) +{ + struct snd_soc_codec *codec = i2c_get_clientdata(client); + kfree(codec->reg_cache); + kfree(client); + return 0; +} + + +/* i2c codec control layer */ +static struct i2c_driver rt5623_i2c_driver = { + .driver = { + .name = "rt5623", + .owner = THIS_MODULE, + }, + .probe = rt5623_i2c_probe, + .remove = rt5623_i2c_remove, + .id_table = rt5623_i2c_table, +}; + + +#endif + +static int rt5623_probe(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct rt5623_setup_data *setup; + struct snd_soc_codec *codec; + struct rt5623_priv *rt5623; + int ret = 0; + + info("RT5623 Audio Codec %s",RT5623_VERSION); + + setup = socdev->codec_data; + codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); + if (codec == NULL) + return -ENOMEM; + + rt5623 = kzalloc(sizeof(struct rt5623_priv), GFP_KERNEL); + if (rt5623 == NULL) { + kfree(codec); + return -ENOMEM; + } + + codec->private_data = rt5623; + socdev->card->codec = codec; + mutex_init(&codec->mutex); + INIT_LIST_HEAD(&codec->dapm_widgets); + INIT_LIST_HEAD(&codec->dapm_paths); + rt5623_socdev = socdev; + INIT_DELAYED_WORK(&codec->delayed_work, rt5623_work); + +#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE) + + codec->hw_write = (hw_write_t)i2c_master_send; + + ret = i2c_add_driver(&rt5623_i2c_driver); + if (ret != 0) + printk(KERN_ERR "can't add i2c rt5623 driver"); +#else + /* Add other interfaces here */ +#endif + return ret; +} + +/* + * This function forces any delayed work to be queued and run. + */ +static int run_delayed_work(struct delayed_work *dwork) +{ + int ret; + + /* cancel any work waiting to be queued. */ + ret = cancel_delayed_work(dwork); + + /* if there was any work waiting then we run it now and + * wait for it's completion */ + if (ret) { + schedule_delayed_work(dwork, 0); + flush_scheduled_work(); + } + return ret; +} + +/* power down chip */ +static int rt5623_remove(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->card->codec; + + if (codec->control_data) + rt5623_set_bias_level(codec, SND_SOC_BIAS_OFF); + run_delayed_work(&codec->delayed_work); + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); +#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE) + i2c_del_driver(&rt5623_i2c_driver); +#endif + kfree(codec->private_data); + kfree(codec); + + return 0; +} + +struct snd_soc_codec_device soc_codec_dev_rt5623 = { + .probe = rt5623_probe, + .remove = rt5623_remove, + .suspend = rt5623_suspend, + .resume = rt5623_resume, +}; + +EXPORT_SYMBOL_GPL(soc_codec_dev_rt5623); + +static int __init rt5623_modinit(void) +{ + return snd_soc_register_dai(&rt5623_dai); +} +module_init(rt5623_modinit); + +static void __exit rt5623_modexit(void) +{ + snd_soc_unregister_dai(&rt5623_dai); +} +module_exit(rt5623_modexit); + +MODULE_DESCRIPTION("ASoC RT5623 driver"); +MODULE_AUTHOR("flove , Ethan"); +MODULE_LICENSE("GPL"); + --- linux-mvl-dove-2.6.32.orig/sound/soc/codecs/wm8510.c +++ linux-mvl-dove-2.6.32/sound/soc/codecs/wm8510.c @@ -425,23 +425,23 @@ /* filter coefficient */ switch (params_rate(params)) { - case SNDRV_PCM_RATE_8000: + case 8000: adn |= 0x5 << 1; break; - case SNDRV_PCM_RATE_11025: + case 11025: adn |= 0x4 << 1; break; - case SNDRV_PCM_RATE_16000: + case 16000: adn |= 0x3 << 1; break; - case SNDRV_PCM_RATE_22050: + case 22050: adn |= 0x2 << 1; break; - case SNDRV_PCM_RATE_32000: + case 32000: adn |= 0x1 << 1; break; - case SNDRV_PCM_RATE_44100: - case SNDRV_PCM_RATE_48000: + case 44100: + case 48000: break; } --- linux-mvl-dove-2.6.32.orig/sound/soc/codecs/rt655.h +++ linux-mvl-dove-2.6.32/sound/soc/codecs/rt655.h @@ -0,0 +1,46 @@ +#ifndef __RT_655_H_ +#define __RT_655_H_ + +//flove122309_S +#define RT655_RESET 0X00 //RESET +#define RT655_MASTER_VOL 0X02 //MASTER VOLUME +#define RT655_MONO_OUT_VOL 0X06 //MONO OUT VOLUME +#define RT655_PCBEEP_VOL 0X0A //PC BEEP VOLUME +#define RT655_PHONE_VOL 0X0C //PHONE VOLUME +#define RT655_MIC_VOL 0X0E //MIC VOLUME +#define RT655_LINEIN_VOL 0X10 //LINE IN VOLUME +#define RT655_CD_VOL 0X12 //CD VOLUME +#define RT655_AUX_VOL 0X16 //AUX VOLUME +#define RT655_FRONT_DAC_VOL 0X18 //PCM OUT VOLUME +#define RT655_REC_SEL 0X1A //RECORD SELECT +#define RT655_REC_GAIN 0X1C //RECORD GAIN +#define RT655_GEN_PUR 0X20 //GENERAL PURPOSE REGISTER +#define RT655_AUDIO_PAGING 0X24 //AUDIO INTERRUPT AND PAGING MECHANISM +#define RT655_PWR_CTRL 0X26 //POWERDOWN CONTROL/STAUTS +#define RT655_EXT_ID 0X28 //EXTENDED AUDIO ID +#define RT655_EXT_STAUS 0X2A //EXTENDED AUDIO STATUS AND CONTROL REGISTER +#define RT655_PCM_FR_SR 0X2C //PCM FRONT/CENTER OUTPUT SAMPLE RATE +#define RT655_PCM_SUR_SR 0X2E //PCM SURROUND OUTPUT SAMPLE RATE +#define RT655_PCM_LFE_SR 0X30 //PCM LFE OUTPUT SAMPLE RATE +#define RT655_PCM_IN_SR 0X32 //ADC PCM INPUT SAMPLE RATE +#define RT655_CEN_LFE_VOL 0X36 //LFE/CENTER MASTER VOLUME +#define RT655_SUR_VOL 0X38 //SURROUND MASTER VOLUME +#define RT655_SPDIF_CTRL 0X3A //SPDIF OUTPUT CHANNEL STATUS AND CONTROL +#define RT655_SPDIF_IN_STATUS_1 0X60 //SPDIF INPUT CHANNEL STATUS 1 +#define RT655_SPDIF_IN_STATUS_2 0X62 //SPDIF INPUT CHANNEL STATUS 2 +#define RT655_SUR_DAC_VOL 0X64 //SURROUND DAC VOLUME +#define RT655_CEN_LFE_DAC_VOL 0X66 //RESET CODEC TO DEFAULT +#define RT655_SENSE_SEN_CTRL 0X68 //SENSE SENSITIVITY CONTROL +#define RT655_MULT_CHAN_CTRL 0X6A //MULTI CHANNEL CONTROL +#define RT655_PRODUCT_NUM 0X6E //PRODUCT NUMBER +#define RT655_GPIO_INT_CTRL_STATUS 0X78 //GPIO(JD) INTERRUPT CONTROL & STATUS +#define RT655_EXT_CTRL 0X7A //EXTEND CONTROL +#define RT655_VEDNOR_ID 0X7C //RESET CODEC TO DEFAULT +#define RT655_VENDOR_ID2 0X7E //RESET CODEC TO DEFAULT +//flove122309_E + +extern int rt655_reset(struct snd_soc_codec *codec, int try_warm); + +extern struct snd_soc_codec_device soc_codec_dev_rt655; +extern struct snd_soc_dai rt655_dai; +#endif --- linux-mvl-dove-2.6.32.orig/sound/soc/codecs/Kconfig +++ linux-mvl-dove-2.6.32/sound/soc/codecs/Kconfig @@ -111,6 +111,12 @@ config SND_SOC_CX20442 tristate +# Cirrus Logic CS42L51 Codec +config SND_SOC_CS42L51 + tristate + depends on SND_SOC + + config SND_SOC_L3 tristate @@ -220,3 +226,24 @@ # Amp config SND_SOC_MAX9877 tristate + +# Realtek RT5623 Codec +config SND_SOC_RT5623 + tristate + depends on SND_SOC + +# Realtek RT5610 Codec +config SND_SOC_RT5610 + tristate + depends on SND_SOC + +# Realtek RT5630 Codec +config SND_SOC_RT5630 + tristate + depends on SND_SOC + +# Realtek RT655 Codec +config SND_SOC_RT655 + tristate + depends on SND_SOC + --- linux-mvl-dove-2.6.32.orig/sound/soc/codecs/cs42l51.c +++ linux-mvl-dove-2.6.32/sound/soc/codecs/cs42l51.c @@ -0,0 +1,632 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cs42l51.h" + +#define AUDIO_NAME "cs42l51" + +#define CS42L51_CACHE_SIZE (CS42L51_REG_MAX+1) + + +/* +#define CS42L51_DEBUG(format, args...) \ + printk(KERN_DEBUG "%s(%d): "format"\n", __FUNCTION__, __LINE__, ##args) +*/ + +#define CS42L51_DEBUG(format, args...) + +/* codec private data */ +struct cs42l51_priv { + unsigned int sysclk; + struct snd_soc_codec *codec; +}; + +static unsigned int cs42l51_read_reg_cache(struct snd_soc_codec *codec, + unsigned int reg) +{ + u8 *cache = codec->reg_cache; + if (reg > CS42L51_REG_MAX) + return -1; + return cache[reg]; +} + +static void cs42l51_write_reg_cache(struct snd_soc_codec *codec, + u8 reg, u8 value) +{ + u8 *cache = codec->reg_cache; + if (reg > CS42L51_REG_MAX) + return; + cache[reg] = value; +} + +static int cs42l51_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + u8 data[2]; + + reg &= 0x7f; + data[0] = reg & 0xff; + data[1] = value & 0xff; + + cs42l51_write_reg_cache(codec, data[0], data[1]); + if (codec->hw_write(codec->control_data, data, 2) == 2) + return 0; + else + return -EIO; +} + +static unsigned int cs42l51_read(struct snd_soc_codec *codec, unsigned int reg) +{ + return cs42l51_read_reg_cache(codec, reg); +} + +static unsigned int cs42l51_read_no_cache(struct snd_soc_codec *codec, + unsigned int reg) +{ + struct i2c_msg msg[2]; + u8 data[2]; + struct i2c_client *i2c_client = codec->control_data; + int ret; + + i2c_client = (struct i2c_client *)codec->control_data; + + data[0] = reg & 0xff; + msg[0].addr = i2c_client->addr; + msg[0].flags = 0; + msg[0].buf = &data[0]; + msg[0].len = 1; + + msg[1].addr = i2c_client->addr; + msg[1].flags = I2C_M_RD; + msg[1].buf = &data[1]; + msg[1].len = 1; + + ret = i2c_transfer(i2c_client->adapter, &msg[0], 2); + return (ret == 2) ? data[1] : -EIO; +} + +static void cs42l51_fill_cache(struct snd_soc_codec *codec) +{ + u8 *cache = codec->reg_cache; + unsigned int reg; + + for (reg = 1; reg <= CS42L51_REG_MAX; reg++) + cache[reg] = cs42l51_read_no_cache(codec, reg); + +} + + +static void cs42l51_sync_cache(struct snd_soc_codec *codec) +{ + u8 *cache = codec->reg_cache; + unsigned int reg; + + for (reg = 1; reg <= CS42L51_REG_MAX; reg++) + cs42l51_write(codec, reg, cache[reg]); +} + + +static void cs42l51_set_bits(struct snd_soc_codec *codec, u32 addr, + u32 start_bit, u32 end_bit, u32 value) +{ + u32 mask; + u32 new_value; + u32 old_value; + + old_value = cs42l51_read(codec, addr); + mask = ((1 << (end_bit + 1 - start_bit)) - 1) << start_bit; + new_value = old_value & (~mask); + new_value |= (mask & (value << start_bit)); + cs42l51_write(codec, addr, new_value); +} + +static u8 cs42l51_volume_mapping[] = { + 0x19, 0xB2, 0xB7, 0xBD, 0xC3, 0xC9, 0xCF, 0xD5, + 0xD8, 0xE1, 0xE7, 0xED, 0xF3, 0xF9, 0xFF, 0x00, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18 +}; + +#define CS42L51_NUM_VOLUME_STEPS ARRAY_SIZE(cs42l51_volume_mapping) + +static u8 cs42l51_reg2vol(u8 reg) +{ + u8 i; + + for (i = 0; i < CS42L51_NUM_VOLUME_STEPS; i++) { + if (reg == cs42l51_volume_mapping[i]) + return i; + if ((cs42l51_volume_mapping[i] > + cs42l51_volume_mapping[CS42L51_NUM_VOLUME_STEPS - 1]) + && (reg > cs42l51_volume_mapping[i]) + && (reg < cs42l51_volume_mapping[i + 1])) + return i; + + } + return 0; +} + +static u8 cs42l51_vol2reg(u8 vol) +{ + if (vol >= CS42L51_NUM_VOLUME_STEPS) + vol = CS42L51_NUM_VOLUME_STEPS - 1; + return cs42l51_volume_mapping[vol]; +} + +static int cs42l51_vol_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 2; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 39; + + return 0; +} + +static int cs42l51_vol_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + u8 reg; + u8 vol; + + reg = snd_soc_read(codec, CS42L51_REG_VOL_OUTA_CTRL); + vol = cs42l51_reg2vol(reg); + ucontrol->value.integer.value[0] = vol; + + reg = snd_soc_read(codec, CS42L51_REG_VOL_OUTB_CTRL); + vol = cs42l51_reg2vol(reg); + ucontrol->value.integer.value[1] = vol; + return 0; +} + +static int cs42l51_vol_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + u8 reg; + u8 vol; + + vol = (u8) ucontrol->value.integer.value[0]; + reg = cs42l51_vol2reg(vol); + snd_soc_update_bits(codec, CS42L51_REG_VOL_OUTA_CTRL, 0xFF, reg); + + vol = (u8) ucontrol->value.integer.value[1]; + reg = cs42l51_vol2reg(vol); + snd_soc_update_bits(codec, CS42L51_REG_VOL_OUTB_CTRL, 0xFF, reg); + + return 0; +} + +static struct snd_kcontrol_new cs42l51_snd_controls[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Playback DAC Volume", + .info = cs42l51_vol_info, + .get = cs42l51_vol_get, + .put = cs42l51_vol_set}, +}; + +/* add non dapm controls */ +static int cs42l51_add_controls(struct snd_soc_codec *codec) +{ + int err, i; + + CS42L51_DEBUG(""); + + for (i = 0; i < ARRAY_SIZE(cs42l51_snd_controls); i++) { + err = snd_ctl_add(codec->card, + snd_soc_cnew(&cs42l51_snd_controls[i], codec, + NULL)); + + if (err < 0) + return err; + } + return 0; +} + +static int cs42l51_startup(struct snd_pcm_substream *stream, + struct snd_soc_dai *dai) +{ + CS42L51_DEBUG(""); + return 0; +} + +static void cs42l51_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + CS42L51_DEBUG(""); +} + +static int cs42l51_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params, + struct snd_soc_dai *dai) +{ + CS42L51_DEBUG(""); + return 0; +} + +static int cs42l51_hw_free(struct snd_pcm_substream *stream, + struct snd_soc_dai *dai) +{ + CS42L51_DEBUG(""); + return 0; +} + +static int cs42l51_prepare(struct snd_pcm_substream *stream, + struct snd_soc_dai *dai) +{ + CS42L51_DEBUG(""); + return 0; +} + +static int cs42l51_trigger(struct snd_pcm_substream *stream, int cmd, + struct snd_soc_dai *dai) +{ + CS42L51_DEBUG(""); + return 0; +} + +static int cs42l51_mute(struct snd_soc_dai *dai, int mute) +{ + struct snd_soc_codec *codec = dai->codec; + + CS42L51_DEBUG("mute=%d", mute); + + if (mute) + cs42l51_set_bits(codec, CS42L51_REG_DAC_OUTPUT_CTRL, 0, 1, 3); + else + cs42l51_set_bits(codec, CS42L51_REG_DAC_OUTPUT_CTRL, 0, 1, 0); + + return 0; +} + +static int cs42l51_set_dai_sysclk(struct snd_soc_dai *codec_dai, + int clk_id, unsigned int freq, int dir) +{ + CS42L51_DEBUG("clk_id=%d freq=%u dir=%d", clk_id, freq, dir); + return 0; +} + +static int cs42l51_set_dai_fmt(struct snd_soc_dai *dai, + unsigned int fmt) +{ + struct snd_soc_codec *codec = dai->codec; + + CS42L51_DEBUG("fmt=%u", fmt); + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_LEFT_J: + cs42l51_set_bits(codec, CS42L51_REG_IF_CNTRL, 3, 5, 0); + break; + case SND_SOC_DAIFMT_I2S: + cs42l51_set_bits(codec, CS42L51_REG_IF_CNTRL, 3, 5, 1); + break; + case SND_SOC_DAIFMT_RIGHT_J: + cs42l51_set_bits(codec, CS42L51_REG_IF_CNTRL, 3, 5, 2); + break; + default: + return -EINVAL; + } + return 0; +} + + +static int cs42l51_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + CS42L51_DEBUG("bias level transition: %d -> %d", + codec->bias_level, level); + switch (level) { + case SND_SOC_BIAS_ON: + case SND_SOC_BIAS_PREPARE: + cs42l51_set_bits(codec, CS42L51_REG_POWER_CNTRL, 0, 0, 0); + break; + case SND_SOC_BIAS_STANDBY: + case SND_SOC_BIAS_OFF: + cs42l51_set_bits(codec, CS42L51_REG_POWER_CNTRL, 0, 0, 1); + break; + } + codec->bias_level = level; + return 0; +} + +static struct snd_soc_dai_ops cs42l51_dai_ops = { + .startup = cs42l51_startup, + .shutdown = cs42l51_shutdown, + .hw_params = cs42l51_hw_params, + .hw_free = cs42l51_hw_free, + .prepare = cs42l51_prepare, + .trigger = cs42l51_trigger, + .digital_mute = cs42l51_mute, + .set_sysclk = cs42l51_set_dai_sysclk, + .set_fmt = cs42l51_set_dai_fmt, +}; + + +struct snd_soc_dai cs42l51_dai = { + .name = "CS42L51", + .playback = { + .stream_name = "Playback", + .rate_min = 44100, + .rate_max = 96000, + .channels_min = 1, + .channels_max = 2, + .rates = (SNDRV_PCM_RATE_44100 | + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000), + .formats = (SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE), + }, + .capture = { + .stream_name = "Capture", + .rate_min = 44100, + .rate_max = 96000, + .channels_min = 1, + .channels_max = 2, + .rates = (SNDRV_PCM_RATE_44100 | + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000), + .formats = (SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE), + }, + /* pcm operations */ + .ops = &cs42l51_dai_ops, +}; +EXPORT_SYMBOL_GPL(cs42l51_dai); + +static int cs42l51_init(struct snd_soc_device *socdev) +{ + struct snd_soc_codec *codec = socdev->card->codec; + u8 reg; + int ret; + + CS42L51_DEBUG(""); + + codec->owner = THIS_MODULE; + codec->name = "CS42L51"; + codec->dai = &cs42l51_dai; + codec->set_bias_level = cs42l51_set_bias_level; + codec->num_dai = 1; + codec->reg_cache_size = CS42L51_CACHE_SIZE; + codec->reg_cache = kzalloc(codec->reg_cache_size, GFP_KERNEL); + if (!codec->reg_cache) + return -ENOMEM; + + cs42l51_fill_cache(codec); + + ret = -ENODEV; + + reg = cs42l51_read(codec, CS42L51_REG_ID); + printk(KERN_INFO "cs42l51: chipid/revision = %x\n", reg); + + /* Set the digital Interface format to I2S-up-to-24-bit */ + cs42l51_set_bits(codec, CS42L51_REG_IF_CNTRL, 3, 5, 1); + + /* Set the ADC Mode */ + cs42l51_set_bits(codec, CS42L51_REG_IF_CNTRL, 2, 2, 1); + + /* init the chip */ + /* use signal processor */ + cs42l51_write(codec, CS42L51_REG_DAC_CTRL, 0x40); + /* Unmute PCM-A & PCM-B and set default */ + cs42l51_write(codec, CS42L51_REG_PCMA_MIXER_VOL_CNTRL, 0x10); + cs42l51_write(codec, CS42L51_REG_PCMB_MIXER_VOL_CNTRL, 0x10); + /* default for AOUTx */ + cs42l51_write(codec, CS42L51_REG_VOL_OUTA_CTRL, cs42l51_vol2reg(4)); + cs42l51_write(codec, CS42L51_REG_VOL_OUTB_CTRL, cs42l51_vol2reg(4)); + /* swap channels */ + cs42l51_write(codec, CS42L51_REG_CHANNEL_MIXER, 0xff); + + cs42l51_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + + /* register pcms */ + ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); + if (ret < 0) { + pr_err("failed to create pcms"); + goto pcm_err; + } + cs42l51_add_controls(codec); + + + ret = snd_soc_init_card(socdev); + if (ret < 0) { + pr_err("failed to register card\n"); + goto card_err; + } + return 0; + +card_err: + snd_soc_free_pcms(socdev); + +pcm_err: + kfree(codec->reg_cache); + return ret; +} + +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) + +static const struct i2c_device_id cs42l51_i2c_table[] = { + {"cs42l51", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, cs42l51_i2c_table); + +static struct i2c_driver cs42l51_i2c_driver; +static struct snd_soc_device *cs42l51_socdev; + +static int cs42l51_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct snd_soc_device *socdev = cs42l51_socdev; + struct snd_soc_codec *codec = socdev->card->codec; + struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent); + int ret; + + CS42L51_DEBUG(""); + + if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_EMUL)) + return -EIO; + + i2c_set_clientdata(client, codec); + codec->control_data = client; + + codec->read = cs42l51_read; + codec->write = cs42l51_write; + + ret = cs42l51_init(socdev); + if (ret < 0) + goto err; + + return ret; + +err: + kfree(codec); + return ret; +} + +static int cs42l51_i2c_remove(struct i2c_client *client) +{ + return 0; +} + +static struct i2c_driver cs42l51_i2c_driver = { + .driver = { + .name = "cs42l51", + .owner = THIS_MODULE, + }, + .probe = cs42l51_i2c_probe, + .remove = cs42l51_i2c_remove, + .id_table = cs42l51_i2c_table, +}; + +#endif + +static int cs42l51_probe(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec; + struct cs42l51_priv *cs; + struct cs42l51_setup_data *setup; + int ret; + + CS42L51_DEBUG(""); + + ret = -ENOMEM; + setup = socdev->codec_data; + codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); + if (codec == NULL) + goto out; + + cs = kzalloc(sizeof(struct cs42l51_priv), GFP_KERNEL); + if (cs == NULL) { + kfree(codec); + goto out; + } + ret = 0; + + cs->codec = codec; + codec->private_data = cs; + socdev->card->codec = codec; + mutex_init(&codec->mutex); + INIT_LIST_HEAD(&codec->dapm_widgets); + INIT_LIST_HEAD(&codec->dapm_paths); + + cs42l51_socdev = socdev; +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) + if (setup && setup->i2c_address) { + codec->hw_write = (hw_write_t) i2c_master_send; + ret = i2c_add_driver(&cs42l51_i2c_driver); + if (ret) + printk(KERN_ERR "can't add i2c driver\n"); + } +#endif + +out: + return ret; +} + +/* power down chip */ +static int cs42l51_remove(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->card->codec; + + CS42L51_DEBUG(""); + + snd_soc_free_pcms(socdev); +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) + i2c_del_driver(&cs42l51_i2c_driver); +#endif + kfree(codec->private_data); + kfree(codec); + + return 0; +} + +static int cs42l51_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->card->codec; + + CS42L51_DEBUG("event=%d", state.event); + + cs42l51_set_bias_level(codec, SND_SOC_BIAS_OFF); + + return 0; +} + +static int cs42l51_resume(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->card->codec; + + CS42L51_DEBUG(""); + + cs42l51_sync_cache(codec); + cs42l51_set_bias_level(codec, codec->suspend_bias_level); + + return 0; +} + +struct snd_soc_codec_device soc_codec_dev_cs42l51 = { + .probe = cs42l51_probe, + .remove = cs42l51_remove, + .suspend = cs42l51_suspend, + .resume = cs42l51_resume, +}; +EXPORT_SYMBOL_GPL(soc_codec_dev_cs42l51); + +static int __init cs42l51_modinit(void) +{ + CS42L51_DEBUG(""); + return snd_soc_register_dai(&cs42l51_dai); +} +module_init(cs42l51_modinit); + +static void __exit cs42l51_modexit(void) +{ + CS42L51_DEBUG(""); + snd_soc_unregister_dai(&cs42l51_dai); +} +module_exit(cs42l51_modexit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("ASoC CS42l51 codec driver"); +MODULE_AUTHOR("Yuval Elmaliah "); --- linux-mvl-dove-2.6.32.orig/sound/soc/codecs/rt5630.c +++ linux-mvl-dove-2.6.32/sound/soc/codecs/rt5630.c @@ -0,0 +1,2458 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rt5630.h" + +#define RT5630_VERSION "0.04" + +/* +#define RT5630_DEBUG(format, args...) \ + printk(KERN_DEBUG "%s(%d): "format"\n", __FUNCTION__, __LINE__, ##args) +*/ + +#define RT5630_DEBUG(format, args...) +#if CONFIG_SND_DOVE_SOC_AC97_AVD1 +extern int spk_amplifier_enable(bool enable); +#endif +struct rt5630_priv { + unsigned int stereo_sysclk; + unsigned int voice_sysclk; +}; + +struct rt5630_init_reg { + char name[26]; + u16 reg_value; + u8 reg_index; +}; + +static struct rt5630_init_reg rt5630_init_list[] = { + {"HP Output Volume", 0x9090, RT5630_HP_OUT_VOL}, + {"SPK Output Volume", 0x8080, RT5630_SPK_OUT_VOL}, + {"DAC Mic Route", 0xee03, RT5630_DAC_AND_MIC_CTRL}, + {"Output Mixer Control", 0x0748, RT5630_OUTPUT_MIXER_CTRL}, + {"Mic Control", 0x0500, RT5630_MIC_CTRL}, + {"Voice DAC Volume", 0x6020, RT5630_VOICE_DAC_OUT_VOL}, + {"ADC Rec Mixer", 0x5f5f, RT5630_ADC_REC_MIXER}, //mic 2 On, others Mute in ADC_REC_MIXER + {"General Control", 0x0c0a, RT5630_GEN_CTRL_REG1}, + {"PCM Capture Volume",0xdfdf, RT5630_ADC_REC_GAIN}, +}; + +#define RT5630_INIT_REG_NUM ARRAY_SIZE(rt5630_init_list) + +/* + * bit[0] for linein playback switch + * bit[1] phone + * bit[2] mic1 + * bit[3] mic2 + * bit[4] vopcm + * + */ + #define HPL_MIXER 0x80 +#define HPR_MIXER 0x82 +static unsigned int reg80 = 0, reg82 = 0; + +/* + * bit[0][1] use for aec control + * bit[4] for SPKL pga + * bit[5] for SPKR pga + * bit[6] for hpl pga + * bit[7] for hpr pga + * bit[8-9] for misc dsp func + * bit[10-11] for ve mode + */ + /* + * bit[14] ve switch + * bit[15] aec switch + */ + #define VIRTUAL_REG_FOR_MISC_FUNC 0x84 +static unsigned int reg84 = 0; + + +static const u16 rt5630_reg[] = { + 0x59b4, 0x8080, 0x8080, 0x8080, /*reg00-reg06*/ + 0xc800, 0xe808, 0x1010, 0x0808, /*reg08-reg0e*/ + 0xe0ef, 0xcbcb, 0x7f7f, 0x0000, /*reg10-reg16*/ + 0xe010, 0x0000, 0x8008, 0x2007, /*reg18-reg1e*/ + 0x0000, 0x0000, 0x00c0, 0xef00, /*reg20-reg26*/ + 0x0000, 0x0000, 0x0000, 0x0000, /*reg28-reg2e*/ + 0x0000, 0x0000, 0x0000, 0x0000, /*reg30-reg36*/ + 0x0000, 0x0000, 0x0000, 0x0000, /*reg38-reg3e*/ + 0x0c0a, 0x0000, 0x0000, 0x0000, /*reg40-reg46*/ + 0x0029, 0x0000, 0xbe3e, 0x3e3e, /*reg48-reg4e*/ + 0x0000, 0x0000, 0x803a, 0x0000, /*reg50-reg56*/ + 0x0000, 0x0009, 0x0000, 0x3000, /*reg58-reg5e*/ + 0x3075, 0x1010, 0x3110, 0x0000, /*reg60-reg66*/ + 0x0553, 0x0000, 0x0000, 0x0000, /*reg68-reg6e*/ + 0x0000, 0x0000, 0x0000, 0x0000, /*reg70-reg76*/ + 0x0000, 0x0000, 0x0000, 0x0000, /*reg76-reg7e*/ +}; + + +Voice_DSP_Reg VODSP_AEC_Init_Value[]= +{ + {0x232C, 0x0025}, + {0x2308, 0x007f}, + {0x237f, 0x0046}, + {0x23f8, 0x4002}, + {0x231a, 0x0000}, + {0x2301, 0x0002}, + {0x2328, 0x0001}, + {0x231b, 0x0001}, + {0x2304, 0x00fc}, + {0x2305, 0x0800}, + {0x2306, 0x4000}, + {0x230b, 0x0003}, + {0x230d, 0x0800}, + {0x230e, 0x0100}, + {0x2314, 0xc000}, + {0x22cf, 0x0000}, + {0x22c0, 0x8800}, + {0x22c1, 0x1650}, + {0x22c2, 0x18e0}, + {0x22c3, 0x0a50}, + {0x22c4, 0x05e0}, + {0x2311, 0x0101}, + {0x2312, 0x4081}, + {0x2315, 0x9318}, + {0x2316, 0x0011}, + {0x2317, 0x1000}, + {0x2318, 0x1800}, + {0x2319, 0x1800}, + {0x231c, 0x1800}, + {0x231d, 0x0400}, + {0x2326, 0x1600}, + {0x2335, 0x0004}, + {0x2336, 0x0001}, + {0x233a, 0x0180}, + {0x233b, 0x0100}, + {0x233e, 0x0002}, + {0x233f, 0xfffe}, + {0x2344, 0x4000}, + {0x2351, 0x1c40}, + {0x2352, 0x2000}, + {0x2353, 0x6000}, + {0x235c, 0x0800}, + {0x2366, 0x0900}, + {0x2367, 0x19A0}, + {0x236F, 0x4000}, + {0x2370, 0x7100}, + {0x2375, 0x0004}, + {0x2376, 0x0820}, + {0x2377, 0x1018}, + {0x2379, 0x2000}, + {0x237A, 0x2000}, + {0x237b, 0x2000}, + {0x237d, 0x2000}, + {0x238b, 0x2000}, + {0x238c, 0x0400}, + {0x238d, 0x2000}, + {0x238e, 0x3000}, + {0x2391, 0x0008}, + {0x2392, 0x0200}, + {0x2399, 0x0009}, + {0x23A8, 0x0040}, + {0x23AB, 0x02C0}, + {0x23B0, 0x3000}, + {0x23B1, 0x1980}, + {0x23B2, 0x1980}, + {0x23B4, 0x4000}, + {0x23B5, 0x1000}, + {0x23B6, 0x6800}, + {0x23B7, 0x2900}, + {0x23Bb, 0x0010}, + {0x23Bc, 0x0060}, + {0x23Bd, 0x0900}, + {0x23Be, 0x1500}, + {0x23Bf, 0x0800}, + {0x23c0, 0x4200}, + {0x23cd, 0x0400}, + {0x23ce, 0x1800}, + {0x23cf, 0x1a00}, + {0x23d0, 0x2000}, + {0x23d1, 0x2b00}, + {0x23d2, 0x000e}, + {0x23d3, 0x0009}, + {0x23d4, 0x0080}, + {0x23d5, 0x0024}, + {0x23dd, 0xfff5}, + {0x23df, 0x0200}, + {0x23f0, 0x0200}, + {0x23fc, 0x0009}, + {0x23fb, 0x0560}, + {0x22f0, 0x0c00}, + {0x22f6, 0x00a0}, + {0x11de, 0x0001}, + {0x23b9, 0x000d}, + {0x23a0, 0x6000}, + {0x23a1, 0x0050}, + {0x23a2, 0x0060}, + {0x23a3, 0x0070}, + {0x239b, 0x0070}, + {0x239d, 0x003f}, + {0x239e, 0x0038}, + {0x239f, 0x0030}, + + {0x230C, 0x0000}, //to enable VODSP AEC function +}; + + +#define SET_VODSP_REG_AEC_INIT_NUM ARRAY_SIZE(VODSP_AEC_Init_Value) + +Voice_DSP_Reg VODSP_VE_Init_Value[]= +{ + {0x232C, 0x0025}, + {0x230B, 0x0003}, + {0x2308, 0x007F}, + {0x23F8, 0x4002}, + {0x231a, 0x0000}, + {0x23FF, 0x8002}, + {0x2301, 0x0002}, + {0x231b, 0x0001}, + + {0x2305, 0x0200}, + {0x2306, 0x4000}, + {0x230B, 0x8003}, + {0x230D, 0x0100}, + {0x230E, 0x0100}, + + {0x2312, 0x00B1}, + {0x2315, 0x002d}, + {0x2316, 0x007e}, + {0x2317, 0x1200}, + {0x2318, 0x0C00}, + {0x2319, 0x0e40}, + {0x231c, 0x3000}, + + {0x236B, 0x1000}, + {0x236d, 0x474b}, + {0x236f, 0x4000}, + {0x2370, 0x7100}, + {0x23ab, 0x02c0}, + {0x23B1, 0x2b00}, + {0x23B2, 0x2900}, + {0x23B6, 0x7800}, + {0x23Bb, 0x0300}, + {0x23Bc, 0x0100}, + {0x23Bd, 0x0d00}, + {0x23Be, 0x1000}, + {0x23fb, 0x0e00}, + + {0x23B9, 0x000d}, + {0x23a0, 0x6000}, + {0x23a1, 0x0050}, + {0x23a2, 0x0060}, + {0x23a3, 0x0070}, + + {0x239b, 0x0070}, + {0x239d, 0x003f}, + {0x2393, 0x0038}, + {0x239f, 0x0030}, + {0x230C, 0x0000}, //to enable VODSP VE function +}; + +#define SET_VODSP_VE_REG_INIT_NUM (sizeof(VODSP_VE_Init_Value)/sizeof(Voice_DSP_Reg)) + + +struct Voice_DSP_Function +{ + int feature; + Voice_DSP_Reg *reg_setting; + int regsize; +}; + +static int dsp_init_state; + +static struct Voice_DSP_Function voice_dsp_function_table[] = +{ + {VODSP_AEC_FUNC, VODSP_AEC_Init_Value, SET_VODSP_REG_AEC_INIT_NUM}, + {VODSP_VE_FUNC, VODSP_VE_Init_Value, SET_VODSP_VE_REG_INIT_NUM}, + {VODSP_ALL_FUNC, NULL, 0}, +}; + + + +static struct snd_soc_device *rt5630_socdev; + +static inline unsigned int rt5630_read_reg_cache(struct snd_soc_codec *codec, + unsigned int reg) +{ + u16 *cache = codec->reg_cache; + + if (reg > 0x7e) + return -1; + return cache[reg / 2]; +} + + +static unsigned int rt5630_read_hw_reg(struct snd_soc_codec *codec, unsigned int reg) +{ + u8 data[2] = {0}; + unsigned int value = 0x0; + + data[0] = reg; + if (codec->hw_write(codec->control_data, data, 1) == 1) + { + i2c_master_recv(codec->control_data, data, 2); + value = (data[0] << 8) | data[1]; +// RT5630_DEBUG("%s read reg%x = %x\n", reg, value); + return value; + } + else + { + RT5630_DEBUG("%s failed\n"); + return -EIO; + } +} + + +static unsigned int rt5630_read(struct snd_soc_codec *codec, unsigned int reg) +{ + if ((reg == 0x80) + || (reg == 0x82) + || (reg == 0x84)) + return (reg == 0x80) ? reg80 : ((reg == 0x82) ? reg82 : reg84); + + + + return rt5630_read_hw_reg(codec, reg); +} + + +static inline void rt5630_write_reg_cache(struct snd_soc_codec *codec, + unsigned int reg, unsigned int value) +{ + u16 *cache = codec->reg_cache; + if (reg > 0x7E) + return; + cache[reg / 2] = value; +} + +static int rt5630_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + u8 data[3]; + unsigned int *regvalue = NULL; + + data[0] = reg; + data[1] = (value & 0xff00) >> 8; + data[2] = value & 0x00ff; + + + if ((reg == 0x80) + || (reg == 0x82) + || (reg == 0x84)) + { + regvalue = ((reg == 0x80) ? ®80 : ((reg == 0x82) ? ®82 : ®84)); + *regvalue = value; + RT5630_DEBUG("rt5630_write ok, reg = %x, value = %x\n", reg, value); + return 0; + } + rt5630_write_reg_cache(codec, reg, value); + if (codec->hw_write(codec->control_data, data, 3) == 3) + { + RT5630_DEBUG("rt5630_write ok, reg = %x, value = %x\n", reg, value); + return 0; + } + else + { + printk(KERN_ERR "rt5630_write fail\n"); + return -EIO; + } +} + + +#define rt5630_write_mask(c, reg, value, mask) snd_soc_update_bits(c, reg, mask, value) + +#define rt5630_reset(c) rt5630_write(c, RT5630_RESET, 0) + +static int rt5630_reg_init(struct snd_soc_codec *codec) +{ + int i; + + for (i = 0; i < RT5630_INIT_REG_NUM; i++) + rt5630_write(codec, rt5630_init_list[i].reg_index, rt5630_init_list[i].reg_value); + + return 0; +} + + +/*read/write dsp reg*/ +static int rt5630_wait_vodsp_i2c_done(struct snd_soc_codec *codec) +{ + unsigned int checkcount = 0, vodsp_data; + + vodsp_data = rt5630_read(codec, RT5630_VODSP_REG_CMD); + while(vodsp_data & VODSP_BUSY) + { + if(checkcount > 10) + return -EBUSY; + vodsp_data = rt5630_read(codec, RT5630_VODSP_REG_CMD); + checkcount ++; + } + return 0; +} + + +static int rt5630_write_vodsp_reg(struct snd_soc_codec *codec, unsigned int vodspreg, unsigned int value) +{ + int ret = 0; + + if(ret = rt5630_wait_vodsp_i2c_done(codec)) + return ret; + + rt5630_write(codec, RT5630_VODSP_REG_ADDR, vodspreg); + rt5630_write(codec, RT5630_VODSP_REG_DATA, value); + rt5630_write(codec, RT5630_VODSP_REG_CMD, VODSP_WRITE_ENABLE | VODSP_CMD_MW); + + return ret; + +} + +static int rt5630_read_vodsp_reg(struct snd_soc_codec *codec, unsigned int vodspreg) +{ + int ret = 0; + unsigned int nDataH, nDataL; + + if(ret = rt5630_wait_vodsp_i2c_done(codec)) + return ret; + + rt5630_write(codec, RT5630_VODSP_REG_ADDR, vodspreg); + rt5630_write(codec, RT5630_VODSP_REG_CMD, VODSP_READ_ENABLE | VODSP_CMD_MR); + + if (ret = rt5630_wait_vodsp_i2c_done(codec)) + return ret; + rt5630_write(codec, RT5630_VODSP_REG_ADDR, 0x26); + rt5630_write(codec, RT5630_VODSP_REG_CMD, VODSP_READ_ENABLE | VODSP_CMD_RR); + + if(ret = rt5630_wait_vodsp_i2c_done(codec)) + return ret; + nDataH = rt5630_read(codec, RT5630_VODSP_REG_DATA); + rt5630_write(codec, RT5630_VODSP_REG_ADDR, 0x25); + rt5630_write(codec, RT5630_VODSP_REG_CMD, VODSP_READ_ENABLE | VODSP_CMD_RR); + + if(ret = rt5630_wait_vodsp_i2c_done(codec)) + return ret; + nDataL = rt5630_read(codec, RT5630_VODSP_REG_DATA); + return ((nDataH & 0xff) << 8) |(nDataL & 0xff); +} + +static unsigned int rt5630_read_index(struct snd_soc_codec *codec, unsigned int reg) +{ + unsigned int val; + + rt5630_write(codec, 0x6a, reg); + val = rt5630_read(codec, 0x6c); + return val; +} + + +static const char *rt5630_spk_out_sel[] = {"Class AB", "Class D"}; /*1*/ +static const char *rt5630_spk_l_source_sel[] = {"LPRN", "LPRP", "LPLN", "MM"}; /*2*/ +static const char *rt5630_spkmux_source_sel[] = {"VMID", "HP Mixer", + "SPK Mixer", "Mono Mixer"}; /*3*/ +static const char *rt5630_hplmux_source_sel[] = {"VMID","HPL Mixer"}; /*4*/ +static const char *rt5630_hprmux_source_sel[] = {"VMID","HPR Mixer"}; /*5*/ +static const char *rt5630_auxmux_source_sel[] = {"VMID", "HP Mixer", + "SPK Mixer", "Mono Mixer"}; /*6*/ +static const char *rt5630_spkamp_ratio_sel[] = {"2.25 Vdd", "2.00 Vdd", + "1.75 Vdd", "1.50 Vdd", "1.25 Vdd", "1.00 Vdd"}; /*7*/ +static const char *rt5630_mic1_boost_sel[] = {"Bypass", "+20db", "+30db", "+40db"}; /*8*/ +static const char *rt5630_mic2_boost_sel[] = {"Bypass", "+20db", "+30db", "+40db"}; /*9*/ +static const char *rt5630_dmic_boost_sel[] = {"Bypass", "+6db", "+12db", "+18db", + "+24db", "+30db", "+36db", "+42db"}; /*10*/ + + +static const struct soc_enum rt5630_enum[] = { + +SOC_ENUM_SINGLE(RT5630_OUTPUT_MIXER_CTRL, 13, 2, rt5630_spk_out_sel), /*1*/ +SOC_ENUM_SINGLE(RT5630_OUTPUT_MIXER_CTRL, 14, 4, rt5630_spk_l_source_sel), /*2*/ +SOC_ENUM_SINGLE(RT5630_OUTPUT_MIXER_CTRL, 10, 4, rt5630_spkmux_source_sel),/*3*/ +SOC_ENUM_SINGLE(RT5630_OUTPUT_MIXER_CTRL, 9, 2, rt5630_hplmux_source_sel), /*4*/ +SOC_ENUM_SINGLE(RT5630_OUTPUT_MIXER_CTRL, 8, 2, rt5630_hprmux_source_sel),/*5*/ +SOC_ENUM_SINGLE(RT5630_OUTPUT_MIXER_CTRL, 6, 4, rt5630_auxmux_source_sel),/*6*/ +SOC_ENUM_SINGLE(RT5630_GEN_CTRL_REG1, 1, 6, rt5630_spkamp_ratio_sel), /*7*/ +SOC_ENUM_SINGLE(RT5630_MIC_CTRL, 10, 4, rt5630_mic1_boost_sel), /*8*/ +SOC_ENUM_SINGLE(RT5630_MIC_CTRL, 8, 4, rt5630_mic2_boost_sel), /*9*/ +SOC_ENUM_SINGLE(RT5630_DMIC_CTRL, 0, 8, rt5630_dmic_boost_sel), /*10*/ +}; + + +static int init_vodsp_update(struct snd_soc_codec *codec, struct Voice_DSP_Function *dsp_func) +{ + int i; + int ret; + unsigned int reg; + int timeout = 10; + + RT5630_DEBUG("dsp_init_state=%d\n",dsp_init_state); + + if (dsp_func->feature == dsp_init_state) + { + RT5630_DEBUG("init_vodsp_update: dsp_init_state no change, return\n"); + return 0; + } + switch(dsp_init_state) + { +//init_dsp: + case VODSP_NULL: + /*enable LDO power and set output voltage to 1.2V*/ + rt5630_write_mask(codec, RT5630_LDO_CTRL,LDO_ENABLE|LDO_OUT_VOL_CTRL_1_20V,LDO_ENABLE|LDO_OUT_VOL_CTRL_MASK); + mdelay(20); + default: + rt5630_write_mask(codec, RT5630_VODSP_CTL,VODSP_NO_PD_MODE_ENA, VODSP_NO_PD_MODE_ENA); + mdelay(20); + rt5630_write_mask(codec, RT5630_PWR_MANAG_ADD3,PWR_VODSP_INTERFACE|PWR_I2C_FOR_VODSP,PWR_VODSP_INTERFACE|PWR_I2C_FOR_VODSP); + mdelay(1); + rt5630_write_mask(codec, RT5630_VODSP_CTL,0,VODSP_NO_RST_MODE_ENA); /*Reset VODSP*/ + mdelay(1); + rt5630_write_mask(codec, RT5630_VODSP_CTL,VODSP_NO_RST_MODE_ENA,VODSP_NO_RST_MODE_ENA); /*set VODSP to non-reset status*/ + mdelay(20); + + dsp_init_state = dsp_func->feature; + RT5630_DEBUG("dsp_init_state change to %d\n",dsp_init_state); + + for (i = 0; i < dsp_func->regsize; i ++) { + ret = rt5630_write_vodsp_reg(codec, dsp_func->reg_setting[i].VoiceDSPIndex, dsp_func->reg_setting[i].VoiceDSPValue); + if (ret < 0) + return ret; + } + schedule_timeout_uninterruptible(msecs_to_jiffies(100)); + reg = rt5630_read_vodsp_reg(codec, 0x230c); + while(timeout && (reg !=0x5a5a)) { + rt5630_write_vodsp_reg(codec, 0x230c, 0x0000); + schedule_timeout_uninterruptible(msecs_to_jiffies(10)); + timeout --; + reg = rt5630_read_vodsp_reg(codec, 0x230c); + + } + if (!timeout) { + RT5630_DEBUG("warning: dsp dump not ok!\n"); + rt5630_write_mask(codec, RT5630_LDO_CTRL,0,LDO_ENABLE|LDO_OUT_VOL_CTRL_MASK); + mdelay(20); +// goto init_dsp; + } + else + RT5630_DEBUG("dsp succesful to start\n"); + + break; + } + + + //set VODSP to pown down mode + rt5630_write_mask(codec, RT5630_VODSP_CTL,0,VODSP_NO_PD_MODE_ENA); + rt5630_write_mask(codec, RT5630_PWR_MANAG_ADD3,0,PWR_VODSP_INTERFACE|PWR_I2C_FOR_VODSP); //disable txdc/txdp/rxdp + return 0; +} + +static int set_vodsp_aec_path(struct snd_soc_codec *codec, unsigned int mode) +{ + RT5630_DEBUG("mode=%d\n",mode); + + switch(mode) + { + /*Far End signal is from Voice interface and Near End signal is from MIC1/MIC2)*/ + case PCM_IN_PCM_OUT: + + /* 1.Far End setting(Far end device PCM out-->VODAC PCM IN--->VODSP_RXDP )*/ + + /***************************************************************************** + * a.Enable RxDP power and select RxDP source from "Voice to Stereo Digital path" + * b.Voice PCM out from VoDSP TxDP(VODSP TXDP--->VODAC PCM out-->Far End devie PCM out) + ******************************************************************************/ + rt5630_write_mask(codec, RT5630_VODSP_PDM_CTL,VODSP_RXDP_PWR|VODSP_RXDP_S_SEL_VOICE|VOICE_PCM_S_SEL_AEC_TXDP + ,VODSP_RXDP_PWR|VODSP_RXDP_S_SEL_MASK|VOICE_PCM_S_SEL_MASK); + /* 2.Near end setting*/ + /*********************************************************************************** + * a.ADCR function select PDM Slave interface(Mic-->ADCR-->PDM interface) + * b.Voice DAC Source Select VODSP_TxDC + ************************************************************************************/ + rt5630_write_mask(codec, RT5630_DAC_ADC_VODAC_FUN_SEL,ADCR_FUNC_SEL_PDM|VODAC_SOUR_SEL_VODSP_TXDC + ,ADCR_FUNC_SEL_MASK|VODAC_SOUR_SEL_MASK); + + /*3.setting VODSP LRCK to 8k*/ + rt5630_write_mask(codec, RT5630_VODSP_CTL,VODSP_LRCK_SEL_8K,VODSP_LRCK_SEL_MASK); + + break; + + /*Far End signal is from Analog input and Near End signal is from MIC1/MIC2)*/ + case ANALOG_IN_ANALOG_OUT: + /* 1.Far End setting(Far end device-->Analog in-->ADC_L-->VODSP_RXDP) */ + /************************************************************************ + * a.Enable RxDP power and select RxDP source from ADC_L + ************************************************************************/ + rt5630_write_mask(codec, RT5630_VODSP_PDM_CTL,VODSP_RXDP_PWR|VODSP_RXDP_S_SEL_ADCL, + VODSP_RXDP_PWR|VODSP_RXDP_S_SEL_MASK); + + /*2.Near end setting*/ + /************************************************************************* + *a.VoDSP TxDP--->VODAC--->analog out-->to Far end analog input + *b.ADCR function select PDM Slave interface(Mic-->ADCR-->PDM interface) + *************************************************************************/ + rt5630_write_mask(codec, RT5630_DAC_ADC_VODAC_FUN_SEL,ADCR_FUNC_SEL_PDM|VODAC_SOUR_SEL_VODSP_TXDP + ,ADCR_FUNC_SEL_MASK|VODAC_SOUR_SEL_MASK); + /*3.setting VODSP LRCK to 16k*/ + rt5630_write_mask(codec, RT5630_VODSP_CTL,VODSP_LRCK_SEL_16K,VODSP_LRCK_SEL_MASK); + + break; + + /*Far End signal is from Playback and Near End signal is from MIC1/MIC2)*/ + case DAC_IN_ADC_OUT: + /*********************************************************************** + * 1.Far End setting(Playback-->SRC1-->VODSP_RXDP) + * a.enable SRC1 and VoDSP_RXDP source select SRC1 + * 2.Near End setting(VoDSP_TXDP-->SRC2-->Stereo Record) + * a.enable SRC2 and select Record source from SRC2 + **********************************************************************/ + /* + rt5630_write_mask(codec, RT5630_VODSP_PDM_CTL,VODSP_SRC1_PWR|VODSP_SRC2_PWR|VODSP_RXDP_PWR|VODSP_RXDP_S_SEL_SRC1|REC_S_SEL_SRC2, + VODSP_SRC1_PWR|VODSP_SRC2_PWR|VODSP_RXDP_PWR|VODSP_RXDP_S_SEL_MASK|REC_S_SEL_MASK); + */ + rt5630_write(codec, 0x1a, 0xa820); + rt5630_write(codec, 0x2e, 0x3030); + break; + + case VODSP_AEC_DISABLE: + default: + + /*set stereo DAC&Voice DAC&Stereo ADC function select to default*/ + rt5630_write(codec, RT5630_DAC_ADC_VODAC_FUN_SEL,0); + + /*set VODSP&PDM Control to default*/ + rt5630_write(codec, RT5630_VODSP_PDM_CTL,0); + + break; + } + + return 0; +} + + + +int enable_vodsp_aec_func(struct snd_soc_codec *codec, unsigned int VodspAEC_En, unsigned int AEC_mode) +{ + int ret = 0; + unsigned int reg; + RT5630_DEBUG("VodspAEC_En=%d\n",VodspAEC_En); + + if (VodspAEC_En != 0) + { + //select input/output of VODSP AEC + set_vodsp_aec_path(codec, AEC_mode); + //enable power of VODSP I2C interface & VODSP interface + rt5630_write_mask(codec, RT5630_PWR_MANAG_ADD3,PWR_VODSP_INTERFACE|PWR_I2C_FOR_VODSP,PWR_VODSP_INTERFACE|PWR_I2C_FOR_VODSP); + //enable power of VODSP I2S interface + rt5630_write_mask(codec, RT5630_PWR_MANAG_ADD1,PWR_I2S_INTERFACE,PWR_I2S_INTERFACE); + //set VODSP to active + rt5630_write_mask(codec, RT5630_VODSP_CTL,VODSP_NO_PD_MODE_ENA,VODSP_NO_PD_MODE_ENA); + mdelay(50); + reg = rt5630_read_vodsp_reg(codec, 0x230c); + RT5630_DEBUG("dsp reg 0x230c is 0x%x\n", reg); + } + else + { + //set VODSP AEC to power down mode + rt5630_write_mask(codec, RT5630_VODSP_CTL,0,VODSP_NO_PD_MODE_ENA); + //disable power of VODSP I2C interface & VODSP interface + rt5630_write_mask(codec, RT5630_PWR_MANAG_ADD3,0,PWR_VODSP_INTERFACE|PWR_I2C_FOR_VODSP); + //disable VODSP AEC path + set_vodsp_aec_path(codec, VODSP_AEC_DISABLE); + } + + return ret; +} + +EXPORT_SYMBOL_GPL(enable_vodsp_aec_func); + + + +static int set_vodsp_ve_path(struct snd_soc_codec *codec, int VE_mode) +{ +RT5630_DEBUG("VE_mode=%d",VE_mode); + switch (VE_mode) + { + case TXDP_TO_I2S: + rt5630_write_mask(codec, 0x1a, 0x2020, 0x2030); /*I2S source from TXDP*/ + break; + case TXDP_TO_PCM: + rt5630_write_mask(codec, 0x1a, 0x0080, 0x0080); /*vodac source from TXDP*/ + break; + case VE_DISABLE: + rt5630_write_mask(codec, 0x1a, 0x0000, 0x20b0); + break; + default: + return -EINVAL; + } + return 0; +} + + +int enable_vodsp_ve_func(struct snd_soc_codec *codec, int vodsp_ve_en, int VE_mode) +{ + int ret = 0; + unsigned int reg; + RT5630_DEBUG("vodsp_ve_en=%d\n",vodsp_ve_en); + + if(vodsp_ve_en != 0) + { + set_vodsp_ve_path(codec, VE_mode); + //enable power of VODSP I2C interface & VODSP interface + rt5630_write_mask(codec, RT5630_PWR_MANAG_ADD3,PWR_VODSP_INTERFACE|PWR_I2C_FOR_VODSP,PWR_VODSP_INTERFACE|PWR_I2C_FOR_VODSP); + //enable power of VODSP I2S interface + rt5630_write_mask(codec, RT5630_PWR_MANAG_ADD1,PWR_I2S_INTERFACE,PWR_I2S_INTERFACE); + //set VODSP to active + rt5630_write_mask(codec, RT5630_VODSP_CTL,VODSP_NO_PD_MODE_ENA,VODSP_NO_PD_MODE_ENA); + msleep(50); + reg = rt5630_read_vodsp_reg(codec, 0x230c); + RT5630_DEBUG("dsp reg 0x230c is 0x%x\n", reg); + + } + else + { + //set VODSP to power down mode + rt5630_write_mask(codec, RT5630_VODSP_CTL,0,VODSP_NO_PD_MODE_ENA); + //disable power of VODSP I2C interface & VODSP interface + rt5630_write_mask(codec, RT5630_PWR_MANAG_ADD3,0,PWR_VODSP_INTERFACE|PWR_I2C_FOR_VODSP); + set_vodsp_ve_path(codec, VE_DISABLE); + } + + return ret; +} +EXPORT_SYMBOL_GPL(enable_vodsp_ve_func); + + +static int realtek_aec_mode_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + int mode = codec->read(codec, VIRTUAL_REG_FOR_MISC_FUNC) & 0x8000; + RT5630_DEBUG("realtek_aec_mode_get:mode=%x \n", mode); + + if (mode) + ucontrol->value.integer.value[0] = 1; + else + ucontrol->value.integer.value[0] = 0; + + return 0; +} + + +static int realtek_aec_mode_set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + int mode = codec->read(codec, VIRTUAL_REG_FOR_MISC_FUNC); + + RT5630_DEBUG("realtek_aec_mode_set:mode=%x, uctrl=%d\n", mode,ucontrol->value.integer.value[0]); + + init_vodsp_update(codec, &voice_dsp_function_table[0]); + +// if (((mode & 0x8000) >> 15) == ucontrol->value.integer.value[0]) +// return 0; + + mode &= ~(0x8000); + mode |= (ucontrol->value.integer.value[0] << 15); + codec->write(codec, VIRTUAL_REG_FOR_MISC_FUNC, mode); + enable_vodsp_aec_func(codec, ucontrol->value.integer.value[0], DAC_IN_ADC_OUT); + RT5630_DEBUG("realtek_aec_mode_set:mode change to %x \n", mode); + + return 0; +} + +static int realtek_ve_mode_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + int mode = codec->read(codec, VIRTUAL_REG_FOR_MISC_FUNC) & 0x4000; + RT5630_DEBUG("realtek_ve_mode_get:mode=%x \n", mode); + + if (mode) + ucontrol->value.integer.value[0] = 1; + else + ucontrol->value.integer.value[0] = 0; + + return 0; +} + +static int realtek_ve_mode_set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + int mode = codec->read(codec, VIRTUAL_REG_FOR_MISC_FUNC); + RT5630_DEBUG("realtek_ve_mode_set:mode=%x, uctrl=%d\n", mode,ucontrol->value.integer.value[0]); + + init_vodsp_update(codec, &voice_dsp_function_table[1]); + +// if (((mode & 0x4000) >> 14) == ucontrol->value.integer.value[0]) +// return 0; + + mode &= ~(0x4000); + mode |= (ucontrol->value.integer.value[0] << 14); + codec->write(codec, VIRTUAL_REG_FOR_MISC_FUNC, mode); + enable_vodsp_ve_func(codec, ucontrol->value.integer.value[0], TXDP_TO_I2S); + RT5630_DEBUG("realtek_ve_mode_set:mode change to %x \n", mode); + + return 0; +} +static const struct snd_kcontrol_new rt5630_snd_controls[] = { +//SOC_ENUM("SPK Amp Type", rt5630_enum[0]), +//SOC_ENUM("Left SPK Source", rt5630_enum[1]), +//SOC_ENUM("SPK Amp Ratio", rt5630_enum[6]), +//SOC_ENUM("Mic1 Boost", rt5630_enum[7]), +//SOC_ENUM("Mic2 Boost", rt5630_enum[8]), +//SOC_ENUM("Dmic Boost", rt5630_enum[9]), +//SOC_DOUBLE("LineIn Playback Volume", RT5630_LINE_IN_VOL, 8, 0, 31, 1), +//SOC_SINGLE("Phone Playback Volume", RT5630_PHONEIN_VOL, 8, 31, 1), +//SOC_SINGLE("Mic1 Playback Volume", RT5630_MIC_VOL, 8, 31, 1), +SOC_SINGLE("EAR MIC Playback Volume", RT5630_MIC_VOL, 0, 31, 1), +SOC_DOUBLE("PCM Capture Volume", RT5630_ADC_REC_GAIN, 8, 0, 31, 0), +SOC_DOUBLE("SPKOUT Playback Volume", RT5630_SPK_OUT_VOL, 8, 0, 31, 1), +SOC_DOUBLE("SPKOUT Playback Switch", RT5630_SPK_OUT_VOL, 15, 7, 1, 1), +SOC_DOUBLE("HPOUT Playback Volume", RT5630_HP_OUT_VOL, 8, 0, 31, 1), +SOC_DOUBLE("HPOUT Playback Switch", RT5630_HP_OUT_VOL, 15, 7, 1, 1), +//SOC_DOUBLE("AUXOUT Playback Volume", RT5630_AUX_OUT_VOL, 8, 0, 31, 1), +//SOC_DOUBLE("AUXOUT Playback Switch", RT5630_AUX_OUT_VOL, 15, 7, 1, 1), +//SOC_SINGLE_EXT("AEC Switch", VIRTUAL_REG_FOR_MISC_FUNC, 15, 1, 0, realtek_aec_mode_get, realtek_aec_mode_set), +SOC_SINGLE_EXT("DIG MIC Switch", VIRTUAL_REG_FOR_MISC_FUNC, 14, 1, 0, realtek_ve_mode_get,realtek_ve_mode_set), +}; + +static int rt5630_add_controls(struct snd_soc_codec *codec) +{ + int err, i; + + for (i = 0; i < ARRAY_SIZE(rt5630_snd_controls); i++){ + err = snd_ctl_add(codec->card, + snd_soc_cnew(&rt5630_snd_controls[i], + codec, NULL)); + if (err < 0) + return err; + } + return 0; +} + +static void hp_depop_mode2(struct snd_soc_codec *codec) +{ + RT5630_DEBUG(""); + + rt5630_write_mask(codec, RT5630_PWR_MANAG_ADD1, PWR_MAIN_BIAS, PWR_MAIN_BIAS); + rt5630_write_mask(codec, RT5630_PWR_MANAG_ADD2, PWR_MIXER_VREF, PWR_MIXER_VREF); + rt5630_write_mask(codec, RT5630_PWR_MANAG_ADD1, PWR_SOFTGEN_EN, PWR_SOFTGEN_EN); + rt5630_write_mask(codec, RT5630_PWR_MANAG_ADD3, PWR_HP_R_OUT_VOL|PWR_HP_L_OUT_VOL, + PWR_HP_R_OUT_VOL|PWR_HP_L_OUT_VOL); + rt5630_write_mask(codec, RT5630_MISC_CTRL, HP_DEPOP_MODE2_EN, HP_DEPOP_MODE2_EN); + schedule_timeout_uninterruptible(msecs_to_jiffies(300)); + rt5630_write_mask(codec, RT5630_MISC_CTRL, 0, HP_DEPOP_MODE2_EN); + rt5630_write_mask(codec, RT5630_PWR_MANAG_ADD1, PWR_HP_OUT_AMP, + PWR_HP_OUT_AMP); +} + +#if USE_DAPM_CTRL +/* + * _DAPM_ Controls + */ + /*Left ADC Rec mixer*/ +static const struct snd_kcontrol_new rt5630_left_adc_rec_mixer_controls[] = { +SOC_DAPM_SINGLE("Mic1 Capture Switch", RT5630_ADC_REC_MIXER, 14, 1, 1), +SOC_DAPM_SINGLE("Mic2 Capture Switch", RT5630_ADC_REC_MIXER, 13, 1, 1), +SOC_DAPM_SINGLE("LineIn Capture Switch", RT5630_ADC_REC_MIXER, 12, 1, 1), +SOC_DAPM_SINGLE("Phone Capture Switch", RT5630_ADC_REC_MIXER, 11, 1, 1), +SOC_DAPM_SINGLE("HP Mixer Capture Switch", RT5630_ADC_REC_MIXER, 10, 1, 1), +SOC_DAPM_SINGLE("MoNo Mixer Capture Switch", RT5630_ADC_REC_MIXER, 8, 1, 1), +SOC_DAPM_SINGLE("SPK Mixer Capture Switch", RT5630_ADC_REC_MIXER, 9, 1, 1), + +}; + +/*Left ADC Rec mixer*/ +static const struct snd_kcontrol_new rt5630_right_adc_rec_mixer_controls[] = { +SOC_DAPM_SINGLE("Mic1 Capture Switch", RT5630_ADC_REC_MIXER, 6, 1, 1), +SOC_DAPM_SINGLE("Mic2 Capture Switch", RT5630_ADC_REC_MIXER, 5, 1, 1), +SOC_DAPM_SINGLE("LineIn Capture Switch", RT5630_ADC_REC_MIXER, 4, 1, 1), +SOC_DAPM_SINGLE("Phone Capture Switch", RT5630_ADC_REC_MIXER, 3, 1, 1), +SOC_DAPM_SINGLE("HP Mixer Capture Switch", RT5630_ADC_REC_MIXER, 2, 1, 1), +SOC_DAPM_SINGLE("MoNo Mixer Capture Switch", RT5630_ADC_REC_MIXER, 0, 1, 1), +SOC_DAPM_SINGLE("SPK Mixer Capture Switch", RT5630_ADC_REC_MIXER, 1, 1, 1), +}; + +static const struct snd_kcontrol_new rt5630_left_hp_mixer_controls[] = { +SOC_DAPM_SINGLE("ADC Playback Switch", RT5630_ADC_REC_GAIN, 15, 1, 1), +SOC_DAPM_SINGLE("LineIn Playback Switch", HPL_MIXER, 0, 1, 0), +SOC_DAPM_SINGLE("Phone Playback Switch", HPL_MIXER, 1, 1, 0), +SOC_DAPM_SINGLE("Mic1 Playback Switch", HPL_MIXER, 2, 1, 0), +SOC_DAPM_SINGLE("Mic2 Playback Switch", HPL_MIXER, 3, 1, 0), +SOC_DAPM_SINGLE("HIFI DAC Playback Switch", RT5630_DAC_AND_MIC_CTRL, 3, 1, 1), +SOC_DAPM_SINGLE("Voice DAC Playback Switch", HPL_MIXER, 4, 1, 0), +}; + +static const struct snd_kcontrol_new rt5630_right_hp_mixer_controls[] = { +SOC_DAPM_SINGLE("ADC Playback Switch", RT5630_ADC_REC_GAIN, 7, 1, 1), +SOC_DAPM_SINGLE("LineIn Playback Switch", HPR_MIXER, 0, 1, 0), +SOC_DAPM_SINGLE("Phone Playback Switch", HPR_MIXER, 1, 1, 0), +SOC_DAPM_SINGLE("Mic1 Playback Switch", HPR_MIXER, 2, 1, 0), +SOC_DAPM_SINGLE("Mic2 Playback Switch", HPR_MIXER, 3, 1, 0), +SOC_DAPM_SINGLE("HIFI DAC Playback Switch", RT5630_DAC_AND_MIC_CTRL, 2, 1, 1), +SOC_DAPM_SINGLE("Voice DAC Playback Switch", HPR_MIXER, 4, 1, 0), +}; + +static const struct snd_kcontrol_new rt5630_mono_mixer_controls[] = { +SOC_DAPM_SINGLE("ADCL Playback Switch", RT5630_ADC_REC_GAIN, 14, 1, 1), +SOC_DAPM_SINGLE("ADCR Playback Switch", RT5630_ADC_REC_GAIN, 6, 1, 1), +SOC_DAPM_SINGLE("Line Mixer Playback Switch", RT5630_LINE_IN_VOL, 13, 1, 1), +SOC_DAPM_SINGLE("Mic1 Playback Switch", RT5630_DAC_AND_MIC_CTRL, 13, 1, 1), +SOC_DAPM_SINGLE("Mic2 Playback Switch", RT5630_DAC_AND_MIC_CTRL, 9, 1, 1), +SOC_DAPM_SINGLE("DAC Mixer Playback Switch", RT5630_DAC_AND_MIC_CTRL, 0, 1, 1), +SOC_DAPM_SINGLE("Voice DAC Playback Switch", RT5630_VOICE_DAC_OUT_VOL, 13, 1, 1), +}; + +static const struct snd_kcontrol_new rt5630_spk_mixer_controls[] = { +SOC_DAPM_SINGLE("Line Mixer Playback Switch", RT5630_LINE_IN_VOL, 14, 1, 1), +SOC_DAPM_SINGLE("Phone Playback Switch", RT5630_PHONEIN_VOL, 14, 1, 1), +SOC_DAPM_SINGLE("Mic1 Playback Switch", RT5630_DAC_AND_MIC_CTRL, 14, 1, 1), +SOC_DAPM_SINGLE("Mic2 Playback Switch", RT5630_DAC_AND_MIC_CTRL, 10, 1, 1), +SOC_DAPM_SINGLE("DAC Mixer Playback Switch", RT5630_DAC_AND_MIC_CTRL, 1, 1, 1), +SOC_DAPM_SINGLE("Voice DAC Playback Switch", RT5630_VOICE_DAC_OUT_VOL, 14, 1, 1), +}; + +static int mixer_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *k, int event) +{ + struct snd_soc_codec *codec = w->codec; + unsigned int l, r; + + RT5630_DEBUG(""); + + l= rt5630_read(codec, HPL_MIXER); + r = rt5630_read(codec, HPR_MIXER); + + if ((l & 0x1) || (r & 0x1)) + rt5630_write_mask(codec, 0x0a, 0x0000, 0x8000); + else + rt5630_write_mask(codec, 0x0a, 0x8000, 0x8000); + + if ((l & 0x2) || (r & 0x2)) + rt5630_write_mask(codec, 0x08, 0x0000, 0x8000); + else + rt5630_write_mask(codec, 0x08, 0x8000, 0x8000); + + if ((l & 0x4) || (r & 0x4)) + rt5630_write_mask(codec, 0x10, 0x0000, 0x8000); + else + rt5630_write_mask(codec, 0x10, 0x8000, 0x8000); + + if ((l & 0x8) || (r & 0x8)) + rt5630_write_mask(codec, 0x10, 0x0000, 0x0800); + else + rt5630_write_mask(codec, 0x10, 0x0800, 0x0800); + + if ((l & 0x10) || (r & 0x10)) + rt5630_write_mask(codec, 0x18, 0x0000, 0x8000); + else + rt5630_write_mask(codec, 0x18, 0x8000, 0x8000); + + return 0; +} + + +/* + * bit[0][1] use for aec control + * bit[2][3] for ADCR func + * bit[4] for SPKL pga + * bit[5] for SPKR pga + * bit[6] for hpl pga + * bit[7] for hpr pga + */ +static int spk_pga_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *k, int event) + { + struct snd_soc_codec *codec = w->codec; + int reg; + + reg = rt5630_read(codec, VIRTUAL_REG_FOR_MISC_FUNC) & (0x3 << 4); + if ((reg >> 4) != 0x3 && reg != 0) + return 0; + RT5630_DEBUG("event=%d\n",event); + + + switch (event) + { + case SND_SOC_DAPM_POST_PMU: + RT5630_DEBUG("after virtual spk power up!\n"); + rt5630_write_mask(codec, 0x3e, 0x3000, 0x3000); + rt5630_write_mask(codec, 0x02, 0x0000, 0x8080); + rt5630_write_mask(codec, 0x3a, 0x0400, 0x0400); //power on spk amp +#if CONFIG_SND_DOVE_SOC_AC97_AVD1 + spk_amplifier_enable(1); //enable spk amp +#endif + + break; + case SND_SOC_DAPM_POST_PMD: + RT5630_DEBUG("aftet virtual spk power down!\n"); + rt5630_write_mask(codec, 0x3a, 0x0000, 0x0400);//power off spk amp + rt5630_write_mask(codec, 0x02, 0x8080, 0x8080); + rt5630_write_mask(codec, 0x3e, 0x0000, 0x3000); +#if CONFIG_SND_DOVE_SOC_AC97_AVD1 + spk_amplifier_enable(0); //disable spk amp +#endif + + break; + default: + return 0; + } + return 0; +} + + + + + +static int hp_pga_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *k, int event) +{ + struct snd_soc_codec *codec = w->codec; + int reg; + + reg = rt5630_read(codec, VIRTUAL_REG_FOR_MISC_FUNC) & (0x3 << 6); + if ((reg >> 6) != 0x3 && reg != 0) + return 0; + RT5630_DEBUG("event=%d\n",event); + + switch (event) + { + case SND_SOC_DAPM_POST_PMD: + RT5630_DEBUG("aftet virtual hp power down!\n"); + rt5630_write_mask(codec, 0x04, 0x8080, 0x8080); + rt5630_write_mask(codec, 0x3e, 0x0000, 0x0600); + rt5630_write_mask(codec, 0x3a, 0x0000, 0x0030); + break; + case SND_SOC_DAPM_POST_PMU: + RT5630_DEBUG("after virtual hp power up!\n"); + hp_depop_mode2(codec); + rt5630_write_mask(codec ,0x04, 0x0000, 0x8080); + break; + default: + return 0; + } + return 0; +} + + + +static int aux_pga_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *k, int event) +{ + return 0; +} + +/*SPKOUT Mux*/ +static const struct snd_kcontrol_new rt5630_spkout_mux_out_controls = +SOC_DAPM_ENUM("Route", rt5630_enum[2]); + +/*HPLOUT MUX*/ +static const struct snd_kcontrol_new rt5630_hplout_mux_out_controls = +SOC_DAPM_ENUM("Route", rt5630_enum[3]); + +/*HPROUT MUX*/ +static const struct snd_kcontrol_new rt5630_hprout_mux_out_controls = +SOC_DAPM_ENUM("Route", rt5630_enum[4]); +/*AUXOUT MUX*/ +static const struct snd_kcontrol_new rt5630_auxout_mux_out_controls = +SOC_DAPM_ENUM("Route", rt5630_enum[5]); + +static const struct snd_soc_dapm_widget rt5630_dapm_widgets[] = { +SND_SOC_DAPM_INPUT("Left LineIn"), +SND_SOC_DAPM_INPUT("Right LineIn"), +SND_SOC_DAPM_INPUT("Phone"), +SND_SOC_DAPM_INPUT("Mic1"), +SND_SOC_DAPM_INPUT("Mic2"), + +SND_SOC_DAPM_PGA("Mic1 Boost", RT5630_PWR_MANAG_ADD3, 1, 0, NULL, 0), +SND_SOC_DAPM_PGA("Mic2 Boost", RT5630_PWR_MANAG_ADD3, 0, 0, NULL, 0), + +SND_SOC_DAPM_DAC("Left DAC", "Left HiFi Playback DAC", RT5630_PWR_MANAG_ADD2, 9, 0), +SND_SOC_DAPM_DAC("Right DAC", "Right HiFi Playback DAC", RT5630_PWR_MANAG_ADD2, 8, 0), +SND_SOC_DAPM_DAC("Voice DAC", "Voice Playback DAC", RT5630_PWR_MANAG_ADD2, 10, 0), + +SND_SOC_DAPM_PGA("Left LineIn PGA", RT5630_PWR_MANAG_ADD3, 7, 0, NULL, 0), +SND_SOC_DAPM_PGA("Right LineIn PGA", RT5630_PWR_MANAG_ADD3, 6, 0, NULL, 0), +SND_SOC_DAPM_PGA("Phone PGA", RT5630_PWR_MANAG_ADD3, 5, 0, NULL, 0), +SND_SOC_DAPM_PGA("Mic1 PGA", RT5630_PWR_MANAG_ADD3, 3, 0, NULL, 0), +SND_SOC_DAPM_PGA("Mic2 PGA", RT5630_PWR_MANAG_ADD3, 2, 0, NULL, 0), + +SND_SOC_DAPM_MIXER("Left Rec Mixer", RT5630_PWR_MANAG_ADD2, 1, 0, + &rt5630_left_adc_rec_mixer_controls[0], ARRAY_SIZE(rt5630_left_adc_rec_mixer_controls)), +SND_SOC_DAPM_MIXER("Right Rec Mixer", RT5630_PWR_MANAG_ADD2, 0, 0, + &rt5630_right_adc_rec_mixer_controls[0], ARRAY_SIZE(rt5630_right_adc_rec_mixer_controls)), +SND_SOC_DAPM_MIXER_E("Left HP Mixer", RT5630_PWR_MANAG_ADD2, 5, 0, + &rt5630_left_hp_mixer_controls[0], ARRAY_SIZE(rt5630_left_hp_mixer_controls), + mixer_event, SND_SOC_DAPM_POST_REG), +SND_SOC_DAPM_MIXER_E("Right HP Mixer", RT5630_PWR_MANAG_ADD2, 4, 0, + &rt5630_right_hp_mixer_controls[0], ARRAY_SIZE(rt5630_right_hp_mixer_controls), + mixer_event, SND_SOC_DAPM_POST_REG), +SND_SOC_DAPM_MIXER("MoNo Mixer", RT5630_PWR_MANAG_ADD2, 2, 0, + &rt5630_mono_mixer_controls[0], ARRAY_SIZE(rt5630_mono_mixer_controls)), +SND_SOC_DAPM_MIXER("SPK Mixer", RT5630_PWR_MANAG_ADD2, 3, 0, + &rt5630_spk_mixer_controls[0], ARRAY_SIZE(rt5630_spk_mixer_controls)), + +/*hpl mixer --> hp mixer-->spkout mux, hpr mixer-->hp mixer -->spkout mux + hpl mixer-->hp mixer-->Auxout Mux, hpr muxer-->hp mixer-->auxout mux*/ +SND_SOC_DAPM_MIXER("HP Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), +SND_SOC_DAPM_MIXER("DAC Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), +SND_SOC_DAPM_MIXER("Line Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), + +SND_SOC_DAPM_MUX("SPKOUT Mux", SND_SOC_NOPM, 0, 0, &rt5630_spkout_mux_out_controls), +SND_SOC_DAPM_MUX("HPLOUT Mux", SND_SOC_NOPM, 0, 0, &rt5630_hplout_mux_out_controls), +SND_SOC_DAPM_MUX("HPROUT Mux", SND_SOC_NOPM, 0, 0, &rt5630_hprout_mux_out_controls), +SND_SOC_DAPM_MUX("AUXOUT Mux", SND_SOC_NOPM, 0, 0, &rt5630_auxout_mux_out_controls), + +SND_SOC_DAPM_PGA_E("SPKL Out PGA", VIRTUAL_REG_FOR_MISC_FUNC, 4, 0, NULL, 0, + spk_pga_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), +SND_SOC_DAPM_PGA_E("SPKR Out PGA", VIRTUAL_REG_FOR_MISC_FUNC, 5, 0, NULL, 0, + spk_pga_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), +SND_SOC_DAPM_PGA_E("HPL Out PGA",VIRTUAL_REG_FOR_MISC_FUNC, 6, 0, NULL, 0, + hp_pga_event, SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU), +SND_SOC_DAPM_PGA_E("HPR Out PGA",VIRTUAL_REG_FOR_MISC_FUNC, 7, 0, NULL, 0, + hp_pga_event, SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU), +SND_SOC_DAPM_PGA_E("AUX Out PGA",RT5630_PWR_MANAG_ADD3, 14, 0, NULL, 0, + aux_pga_event, SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + + +SND_SOC_DAPM_ADC("Left ADC", "Left ADC HiFi Capture", RT5630_PWR_MANAG_ADD2, 7, 0), +SND_SOC_DAPM_ADC("Right ADC", "Right ADC HiFi Capture", RT5630_PWR_MANAG_ADD2, 6, 0), +SND_SOC_DAPM_OUTPUT("SPKL"), +SND_SOC_DAPM_OUTPUT("SPKR"), +SND_SOC_DAPM_OUTPUT("HPL"), +SND_SOC_DAPM_OUTPUT("HPR"), +SND_SOC_DAPM_OUTPUT("AUX"), +SND_SOC_DAPM_MICBIAS("Mic1 Bias", RT5630_PWR_MANAG_ADD1, 3, 0), +SND_SOC_DAPM_MICBIAS("Mic2 Bias", RT5630_PWR_MANAG_ADD1, 2, 0), +}; + +static const struct snd_soc_dapm_route audio_map[] = { + /*Input PGA*/ + + {"Left LineIn PGA", NULL, "Left LineIn"}, + {"Right LineIn PGA", NULL, "Right LineIn"}, + {"Phone PGA", NULL, "Phone"}, + {"Mic1 Boost", NULL, "Mic1"}, + {"Mic2 Boost", NULL, "Mic2"}, + {"Mic1 PGA", NULL, "Mic1 Boost"}, + {"Mic2 PGA", NULL, "Mic2 Boost"}, + + /*Left ADC mixer*/ + {"Left Rec Mixer", "LineIn Capture Switch", "Left LineIn"}, + {"Left Rec Mixer", "Phone Capture Switch", "Phone"}, + {"Left Rec Mixer", "Mic1 Capture Switch", "Mic1"}, + {"Left Rec Mixer", "Mic2 Capture Switch", "Mic2"}, + {"Left Rec Mixer", "HP Mixer Capture Switch", "Left HP Mixer"}, + {"Left Rec Mixer", "SPK Mixer Capture Switch", "SPK Mixer"}, + {"Left Rec Mixer", "MoNo Mixer Capture Switch", "MoNo Mixer"}, + + /*Right ADC Mixer*/ + {"Right Rec Mixer", "LineIn Capture Switch", "Right LineIn"}, + {"Right Rec Mixer", "Phone Capture Switch", "Phone"}, + {"Right Rec Mixer", "Mic1 Capture Switch", "Mic1"}, + {"Right Rec Mixer", "Mic2 Capture Switch", "Mic2"}, + {"Right Rec Mixer", "HP Mixer Capture Switch", "Right HP Mixer"}, + {"Right Rec Mixer", "SPK Mixer Capture Switch", "SPK Mixer"}, + {"Right Rec Mixer", "MoNo Mixer Capture Switch", "MoNo Mixer"}, + + /*HPL mixer*/ + {"Left HP Mixer", "ADC Playback Switch", "Left Rec Mixer"}, + {"Left HP Mixer", "LineIn Playback Switch", "Left LineIn PGA"}, + {"Left HP Mixer", "Phone Playback Switch", "Phone PGA"}, + {"Left HP Mixer", "Mic1 Playback Switch", "Mic1 PGA"}, + {"Left HP Mixer", "Mic2 Playback Switch", "Mic2 PGA"}, + {"Left HP Mixer", "HIFI DAC Playback Switch", "Left DAC"}, + {"Left HP Mixer", "Voice DAC Playback Switch", "Voice DAC"}, + + /*HPR mixer*/ + {"Right HP Mixer", "ADC Playback Switch", "Right Rec Mixer"}, + {"Right HP Mixer", "LineIn Playback Switch", "Right LineIn PGA"}, + {"Right HP Mixer", "HIFI DAC Playback Switch", "Right DAC"}, + {"Right HP Mixer", "Phone Playback Switch", "Phone PGA"}, + {"Right HP Mixer", "Mic1 Playback Switch", "Mic1 PGA"}, + {"Right HP Mixer", "Mic2 Playback Switch", "Mic2 PGA"}, + {"Right HP Mixer", "Voice DAC Playback Switch", "Voice DAC"}, + + /*DAC Mixer*/ + {"DAC Mixer", NULL, "Left DAC"}, + {"DAC Mixer", NULL, "Right DAC"}, + + /*line mixer*/ + {"Line Mixer", NULL, "Left LineIn PGA"}, + {"Line Mixer", NULL, "Right LineIn PGA"}, + + /*spk mixer*/ + {"SPK Mixer", "Line Mixer Playback Switch", "Line Mixer"}, + {"SPK Mixer", "Phone Playback Switch", "Phone PGA"}, + {"SPK Mixer", "Mic1 Playback Switch", "Mic1 PGA"}, + {"SPK Mixer", "Mic2 Playback Switch", "Mic2 PGA"}, + {"SPK Mixer", "DAC Mixer Playback Switch", "DAC Mixer"}, + {"SPK Mixer", "Voice DAC Playback Switch", "Voice DAC"}, + + /*mono mixer*/ + {"MoNo Mixer", "Line Mixer Playback Switch", "Line Mixer"}, + {"MoNo Mixer", "ADCL Playback Switch","Left Rec Mixer"}, + {"MoNo Mixer", "ADCR Playback Switch","Right Rec Mixer"}, + {"MoNo Mixer", "Mic1 Playback Switch", "Mic1 PGA"}, + {"MoNo Mixer", "Mic2 Playback Switch", "Mic2 PGA"}, + {"MoNo Mixer", "DAC Mixer Playback Switch", "DAC Mixer"}, + {"MoNo Mixer", "Voice DAC Playback Switch", "Voice DAC"}, + + /*hp mixer*/ + {"HP Mixer", NULL, "Left HP Mixer"}, + {"HP Mixer", NULL, "Right HP Mixer"}, + + /*spkout mux*/ + {"SPKOUT Mux", "HP Mixer", "HP Mixer"}, + {"SPKOUT Mux", "SPK Mixer", "SPK Mixer"}, + {"SPKOUT Mux", "Mono Mixer", "MoNo Mixer"}, + + /*hpl out mux*/ + {"HPLOUT Mux", "HPL Mixer", "Left HP Mixer"}, + + /*hpr out mux*/ + {"HPROUT Mux", "HPR Mixer", "Right HP Mixer"}, + + /*aux out mux*/ + {"AUXOUT Mux", "HP Mixer", "HP Mixer"}, + {"AUXOUT Mux", "SPK Mixer", "SPK Mixer"}, + {"SPKOUT Mux", "Mono Mixer", "MoNo Mixer"}, + + /*spkl out pga*/ + {"SPKL Out PGA", NULL, "SPKOUT Mux"}, + + + /*spkr out pga*/ + {"SPKR Out PGA", NULL, "SPKOUT Mux"}, + + /*hpl out pga*/ + {"HPL Out PGA", NULL, "HPLOUT Mux"}, + + /*hpr out pga*/ + {"HPR Out PGA", NULL, "HPROUT Mux"}, + + /*aux out pga*/ + {"AUX Out PGA", NULL, "AUXOUT Mux"}, + + /*left adc*/ + {"Left ADC", NULL, "Left Rec Mixer"}, + + /*right adc*/ + {"Right ADC", NULL, "Right Rec Mixer"}, + + /*output*/ + {"SPKL", NULL, "SPKL Out PGA"}, + {"SPKR", NULL, "SPKR Out PGA"}, + {"HPL", NULL, "HPL Out PGA"}, + {"HPR", NULL, "HPR Out PGA"}, + {"AUX", NULL, "AUX Out PGA"}, +}; + + +static int rt5630_add_widgets(struct snd_soc_codec *codec) +{ + snd_soc_dapm_new_controls(codec, rt5630_dapm_widgets, + ARRAY_SIZE(rt5630_dapm_widgets)); + snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); + snd_soc_dapm_new_widgets(codec); +} + +#endif +#if !USE_DAPM_CTRL + +static enum OUTPUT_DEVICE_MASK +{ + SPK_OUTPUT_MASK = 1, + HP_OUTPUT_MASK, +}; + + + +static int rt5630_set_path_from_dac_to_output(struct snd_soc_codec *codec, int enable, int sink) +{ + RT5630_DEBUG("sink=%d, enable=%d\n",sink,enable); + + switch (sink) + { + case SPK_OUTPUT_MASK: + if (enable) + { + rt5630_write_mask(codec, 0x10, 0x000c, 0x000c); /*unmute dac-->hpmixer*/ + rt5630_write_mask(codec, 0x1c, 0x0400, 0x0400); /*choose mux to hpmixer-->spk */ + rt5630_write_mask(codec, 0x3c, 0x0300, 0x0300); /*power up dac lr */ + rt5630_write_mask(codec, 0x3c, 0x0030, 0x0030); /*power up hp mixer lr*/ + rt5630_write_mask(codec, 0x3c, 0x3000, 0x3000); /*power up spk lr*/ + + } + else + rt5630_write_mask(codec, 0x02, 0x8080, 0x8080); /*mute spk*/ + break; + case HP_OUTPUT_MASK: + if (enable) + { + rt5630_write_mask(codec, 0x10, 0x000c, 0x000c); /*unmute dac-->hpmixer*/ + rt5630_write_mask(codec, 0x1c, 0x0300, 0x0300); /*hpmixer to hp out*/ + rt5630_write_mask(codec, 0x3c, 0x0300, 0x0300); /*power up dac lr */ + rt5630_write_mask(codec, 0x3c, 0x0030, 0x0030); /*power up hp mixer lr*/ + hp_depop_mode2(codec); + } + else + { + rt5630_write_mask(codec, 0x3a, 0x0000, 0x0300); /*power off hp amp*/ + rt5630_write_mask(codec, 0x04, 0x8080, 0x8080); + } + break; + default: + return 0; + } + return 0; +} + + +#endif + +#if !USE_DAPM_CTRL + +static int rt5630_pcm_hw_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *codec_dai) +{ + struct snd_soc_codec *codec = codec_dai->codec; + int stream = substream->stream; + u16 reg=0; + RT5630_DEBUG("stream=%d\n",stream); + + switch (stream) + { + case SNDRV_PCM_STREAM_PLAYBACK: + + reg=rt5630_read(codec, 0x02); + if (!(reg & 0x8080)) + { + //power on SPK + rt5630_write_mask(codec, 0x3c, 0x2300, 0x2300); /*power hp mixerlr, daclr*/ + + rt5630_write_mask(codec, 0x3e, 0x3000, 0x3000); /*power spklr volume*/ + rt5630_write_mask(codec, 0x02, 0x0000, 0x8080); /*unmute spk*/ + rt5630_write_mask(codec, 0x3a, 0x0400, 0x0400); /*power on classabd amp*/ +#if CONFIG_SND_DOVE_SOC_AC97_AVD1 + spk_amplifier_enable(1); +#endif + } + + reg=rt5630_read(codec, 0x04); + if (!(reg & 0x8080)) + { + //power on hp + rt5630_write_mask(codec, 0x3c, 0x2300, 0x2300); /*power hp mixerlr, daclr*/ + hp_depop_mode2(codec); + + rt5630_write_mask(codec, 0x04, 0x0000, 0x8080); /*unmute hp*/ + } + + + break; + case SNDRV_PCM_STREAM_CAPTURE: + + rt5630_write_mask(codec, 0x3e, 0x0005, 0x0005); /*power on mic2 boost*/ + rt5630_write_mask(codec, 0x3a, 0x0004, 0x0004); /*mic bias2*/ + rt5630_write_mask(codec, 0x3c, 0x00c3, 0x00c3); /*power adc lr and rec mixer lr*/ + break; + default: + return 0; + } + return 0; +} + +static int rt5630_vopcm_hw_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *codec_dai) +{ + struct snd_soc_codec *codec = codec_dai->codec; + int stream = substream->stream; + RT5630_DEBUG("stream=%d\n",stream); + switch (stream) + { + case SNDRV_PCM_STREAM_PLAYBACK: + rt5630_write_mask(codec, 0x3c, 0x0430, 0x0430); + hp_depop_mode2(codec); + rt5630_write_mask(codec, 0x3e, 0x3000, 0x3000); + rt5630_write_mask(codec, 0x04, 0x0000, 0x8080); + rt5630_write_mask(codec, 0x02, 0x0000, 0x8080); + rt5630_write_mask(codec, 0x3a, 0x0400, 0x0400); + break; + case SNDRV_PCM_STREAM_CAPTURE: + rt5630_write_mask(codec, 0x3e, 0x0002, 0x0002); + rt5630_write_mask(codec, 0x3a, 0x0008, 0x0008); /*mic bias*/ + rt5630_write_mask(codec, 0x3c, 0x0041, 0x0041); + } + return 0; +} + +#endif + +struct _pll_div{ + u32 pll_in; + u32 pll_out; + u16 regvalue; +}; + + +/************************************************************** + * note: + * our codec support you to select different source as pll input, but if you + * use both of the I2S audio interface and pcm interface instantially. + * The two DAI must have the same pll setting params, so you have to offer + * the same pll input, and set our codec's sysclk the same one, we suggest + * 24576000. + **************************************************************/ +static const struct _pll_div codec_master_pll1_div[] = { + + { 2048000, 24576000, 0x2ea0}, + { 3686400, 24576000, 0xee27}, + { 11289600, 22579200, 0x06a0}, + { 12000000, 24576000, 0x2915}, + { 12288000, 24576000, 0x06a0}, + { 13000000, 24576000, 0x772e}, + { 13100000, 24576000, 0x0d20}, +}; + +static const struct _pll_div codec_bclk_pll1_div[] = { + + { 1536000, 24576000, 0x3ea0}, + { 3072000, 24576000, 0x1ea0}, +}; + +static const struct _pll_div codec_vbclk_pll1_div[] = { + + { 1536000, 24576000, 0x3ea0}, + { 3072000, 24576000, 0x1ea0}, +}; + + +struct _coeff_div_stereo { + unsigned int mclk; + unsigned int rate; + unsigned int reg60; + unsigned int reg62; +}; + +struct _coeff_div_voice { + unsigned int mclk; + unsigned int rate; + unsigned int reg64; +}; + +static const struct _coeff_div_stereo coeff_div_stereo[] = { + /*bclk is config to 32fs, if codec is choose to be slave mode , input bclk should be 32*fs */ + {22579200, 44100, 0x3174, 0x1010}, + {24576000, 48000, 0x3174, 0x1010}, + {12288000, 48000, 0x1174, 0x0000}, + {18432000, 48000, 0x2174, 0x1111}, + {36864000, 48000, 0x2274, 0x2020}, + {49152000, 48000, 0xf074, 0x3030}, + {0, 0, 0, 0}, +}; + +static const struct _coeff_div_voice coeff_div_voice[] = { + /*bclk is config to 32fs, if codec is choose to be slave mode , input bclk should be 32*fs */ + {24576000, 16000, 0x2622}, + {24576000, 8000, 0x2824}, + {0, 0, 0}, +}; + +static int get_coeff(unsigned int mclk, unsigned int rate, int mode) +{ + int i; + + RT5630_DEBUG("get_coeff mclk = %d, rate = %d\n", mclk, rate); + if (!mode){ + for (i = 0; i < ARRAY_SIZE(coeff_div_stereo); i++) { + if ((coeff_div_stereo[i].rate == rate) && (coeff_div_stereo[i].mclk == mclk)) + return i; + } + } + else { + for (i = 0; i< ARRAY_SIZE(coeff_div_voice); i++) { + if ((coeff_div_voice[i].rate == rate) && (coeff_div_voice[i].mclk == mclk)) + return i; + } + } + + return -EINVAL; + printk(KERN_ERR "can't find a matched mclk and rate in %s\n", + (mode ? "coeff_div_voice[]" : "coeff_div_audio[]")); +} + +int rt5630_codec_set_pll1(struct snd_soc_codec *codec, int pll_id, + unsigned int freq_in, unsigned int freq_out) +{ + int i; + int ret = -EINVAL; + + RT5630_DEBUG("pll_id = %d, freq_in = %d, freq_out = %d\n", pll_id, freq_in, freq_out); + + if (pll_id < RT5630_PLL1_FROM_MCLK || pll_id > RT5630_PLL1_FROM_VBCLK) + return -EINVAL; + + if (!freq_in || !freq_out) + return 0; + + if (RT5630_PLL1_FROM_MCLK == pll_id) + { + for (i = 0; i < ARRAY_SIZE(codec_master_pll1_div); i ++) + { + if ((freq_in == codec_master_pll1_div[i].pll_in) && (freq_out == codec_master_pll1_div[i].pll_out)) + { + rt5630_write(codec, RT5630_GEN_CTRL_REG2, 0x0000); /*PLL source from MCLK*/ + rt5630_write(codec, RT5630_PLL_CTRL, codec_master_pll1_div[i].regvalue); /*set pll code*/ + rt5630_write_mask(codec, RT5630_PWR_MANAG_ADD2, 0x8000, 0x8000); /*enable pll1 power*/ + ret = 0; + } + } + } + else if (RT5630_PLL1_FROM_BCLK == pll_id) + { + for (i = 0; i < ARRAY_SIZE(codec_bclk_pll1_div); i ++) + { + if ((freq_in == codec_bclk_pll1_div[i].pll_in) && (freq_out == codec_bclk_pll1_div[i].pll_out)) + { + rt5630_write(codec, RT5630_GEN_CTRL_REG2, 0x2000); /*PLL source from BCLK*/ + rt5630_write(codec, RT5630_PLL_CTRL, codec_bclk_pll1_div[i].regvalue); /*set pll1 code*/ + rt5630_write_mask(codec, RT5630_PWR_MANAG_ADD2, 0x8000, 0x8000); /*enable pll1 power*/ + ret = 0; + } + } + } + else if (RT5630_PLL1_FROM_VBCLK == pll_id) + { + for (i = 0; i < ARRAY_SIZE(codec_vbclk_pll1_div); i ++) + { + if ((freq_in == codec_vbclk_pll1_div[i].pll_in) && (freq_out == codec_vbclk_pll1_div[i].pll_out)) + { + rt5630_write(codec, RT5630_GEN_CTRL_REG2, 0x2000); /*PLL source from BCLK*/ + rt5630_write(codec, RT5630_PLL_CTRL, codec_vbclk_pll1_div[i].regvalue); /*set pll1 code*/ + rt5630_write_mask(codec, RT5630_PWR_MANAG_ADD2, 0x8000, 0x8000); /*enable pll1 power*/ + ret = 0; + } + } + } + + rt5630_write_mask(codec, RT5630_GEN_CTRL_REG1, 0x8000, 0x8000); + return ret; +} + +EXPORT_SYMBOL_GPL(rt5630_codec_set_pll1); + +static int rt5630_codec_set_pll2(struct snd_soc_codec *codec, int times) +{ + int iface = 0; + RT5630_DEBUG(""); + + rt5630_write_mask(codec, 0x3c, 0x4000, 0x4000); //power on pll2 + + switch (times) + { + case 8: + break; + case 16: + iface |= 0x0001; + break; + default: + return -EINVAL; + } + iface |= 0x8000; + rt5630_write(codec, 0x46, iface); + + return 0; + +} + +static int rt5630_codec_set_dai_pll(struct snd_soc_dai *codec_dai, + int pll_id, unsigned int freq_in, unsigned int freq_out) +{ + struct snd_soc_codec *codec = codec_dai->codec; + int times; + RT5630_DEBUG(""); + times = freq_out / freq_in; + + if (pll_id < RT5630_PLL2_FROM_VBCLK) + return rt5630_codec_set_pll1(codec, pll_id, freq_in, freq_out); + else + return rt5630_codec_set_pll2(codec, times); +} + + +static int rt5630_hifi_codec_set_dai_sysclk(struct snd_soc_dai *codec_dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct rt5630_priv * rt5630 = codec->private_data; + RT5630_DEBUG("freq=%d\n",freq); + + if ((freq >= (256 * 8000)) && (freq <= (512 * 48000))) { + rt5630->stereo_sysclk = freq; + return 0; + } + + printk(KERN_ERR "unsupported sysclk freq %u for audio i2s\n", freq); + return -EINVAL; +} + +static int rt5630_voice_codec_set_dai_sysclk(struct snd_soc_dai *codec_dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct rt5630_priv * rt5630 = codec->private_data; + + RT5630_DEBUG(""); + if ((freq >= (256 * 8000)) && (freq <= (512 * 48000))) { + rt5630->voice_sysclk = freq; + return 0; + } + + printk(KERN_ERR "unsupported sysclk freq %u for voice pcm\n", freq); + return -EINVAL; +} + + +static int rt5630_hifi_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_codec *codec = socdev->card->codec; + struct rt5630_priv *rt5630 = codec->private_data; + struct snd_soc_dapm_widget *w; + int stream = substream->stream; + unsigned int iface = rt5630_read(codec, RT5630_MAIN_SDP_CTRL) & 0xfff3; + int rate = params_rate(params); + int coeff = get_coeff(rt5630->stereo_sysclk, rate, 0); + + RT5630_DEBUG("stream=%d\n",stream); + + if (stream == SNDRV_PCM_STREAM_CAPTURE) { + list_for_each_entry(w, &codec->dapm_widgets, list) + { + if (!w->sname) + continue; + if (!strcmp(w->name, "Right ADC")) + strcpy(w->sname, "Right ADC HiFi Capture"); + } + } + + switch (params_format(params)) + { + case SNDRV_PCM_FORMAT_S16_LE: + break; + case SNDRV_PCM_FORMAT_S20_3LE: + iface |= 0x0004; + case SNDRV_PCM_FORMAT_S24_LE: + iface |= 0x0008; + case SNDRV_PCM_FORMAT_S8: + iface |= 0x000c; + } + rt5630_write(codec, RT5630_MAIN_SDP_CTRL, iface); + rt5630_write_mask(codec, 0x3a, 0x0801, 0x0801); /*power i2s and dac ref*/ + if (coeff >= 0) { + rt5630_write(codec, RT5630_STEREO_DAC_CLK_CTRL1, coeff_div_stereo[coeff].reg60); + rt5630_write(codec, RT5630_STEREO_DAC_CLK_CTRL2, coeff_div_stereo[coeff].reg62); + } + else + return coeff; + + return 0; +} + +static int rt5630_voice_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_codec *codec = socdev->card->codec; + struct rt5630_priv *rt5630 = codec->private_data; + unsigned int iface = rt5630_read(codec, RT5630_EXTEND_SDP_CTRL) & 0xfff3; + struct snd_soc_dapm_widget *w; + int stream = substream->stream; + int rate = params_rate(params); + int coeff = get_coeff(rt5630->voice_sysclk, rate, 1); + + RT5630_DEBUG("stream=%d\n",stream); + + + if (stream == SNDRV_PCM_STREAM_CAPTURE) { + list_for_each_entry(w, &codec->dapm_widgets, list) + { + if (!w->sname) + continue; + if (!strcmp(w->name, "Right ADC")) + strcpy(w->sname, "Right ADC Voice Capture"); + } + rt5630_write_mask(codec, 0x2e, 0x0010, 0x0030); /*set adcr to be voice adc*/ + } + switch (params_format(params)) + { + case SNDRV_PCM_FORMAT_S16_LE: + break; + case SNDRV_PCM_FORMAT_S20_3LE: + iface |= 0x0004; + case SNDRV_PCM_FORMAT_S24_LE: + iface |= 0x0008; + case SNDRV_PCM_FORMAT_S8: + iface |= 0x000c; + } + rt5630_write_mask(codec, 0x3a, 0x0801, 0x0801); /*power i2s and dac ref*/ + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) + rt5630_write_mask(codec, RT5630_DAC_ADC_VODAC_FUN_SEL, 0x0001, 0x0030); /*set adcr to be stereo adcr func*/ + + if (coeff >= 0) + rt5630_write(codec, RT5630_VOICE_DAC_PCMCLK_CTRL1, coeff_div_voice[coeff].reg64); + else + return coeff; + return 0; +} + + +static int rt5630_hifi_codec_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct rt5630_priv *rt5630 = codec->private_data; + u16 iface = 0; + + RT5630_DEBUG("fmt=%x\n",fmt); + + /*set master/slave interface*/ + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) + { + case SND_SOC_DAIFMT_CBM_CFM: + iface = 0x0000; + break; + case SND_SOC_DAIFMT_CBS_CFS: + iface = 0x8000; + break; + default: + return -EINVAL; + } + + /*interface format*/ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) + { + case SND_SOC_DAIFMT_I2S: + iface |= 0x0000; + break; + case SND_SOC_DAIFMT_LEFT_J: + iface |= 0x0001; + break; + case SND_SOC_DAIFMT_DSP_A: + iface |= 0x0002; + break; + case SND_SOC_DAIFMT_DSP_B: + iface |= 0x0003; + break; + default: + return -EINVAL; + } + + /*clock inversion*/ + switch (fmt & SND_SOC_DAIFMT_INV_MASK) + { + case SND_SOC_DAIFMT_NB_NF: + iface |= 0x0000; + break; + case SND_SOC_DAIFMT_IB_NF: + iface |= 0x0080; + break; + default: + return -EINVAL; + } + + rt5630_write(codec, RT5630_MAIN_SDP_CTRL, iface); + return 0; +} + +static int rt5630_voice_codec_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct rt5630_priv *rt5630 = codec->private_data; + int iface; + + RT5630_DEBUG("fmt=%x\n",fmt); + /*set slave/master mode*/ + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) + { + case SND_SOC_DAIFMT_CBM_CFM: + iface = 0x0000; + break; + case SND_SOC_DAIFMT_CBS_CFS: + iface = 0x4000; + break; + default: + return -EINVAL; + } + + switch(fmt & SND_SOC_DAIFMT_FORMAT_MASK) + { + case SND_SOC_DAIFMT_I2S: + iface |= 0x0000; + break; + case SND_SOC_DAIFMT_LEFT_J: + iface |= 0x0001; + break; + case SND_SOC_DAIFMT_DSP_A: + iface |= 0x0002; + break; + case SND_SOC_DAIFMT_DSP_B: + iface |= 0x0003; + break; + default: + return -EINVAL; + } + + /*clock inversion*/ + switch (fmt & SND_SOC_DAIFMT_INV_MASK) + { + case SND_SOC_DAIFMT_NB_NF: + iface |= 0x0000; + break; + case SND_SOC_DAIFMT_IB_NF: + iface |= 0x0080; + break; + default: + return -EINVAL; + } + + iface |= 0x8000; /*enable vopcm*/ + rt5630_write(codec, RT5630_EXTEND_SDP_CTRL, iface); + + return 0; +} + + +static int rt5630_hifi_codec_mute(struct snd_soc_dai *dai, int mute) +{ + struct snd_soc_codec *codec = dai->codec; + RT5630_DEBUG("mute=%d\n",mute); + + if (mute) + rt5630_write_mask(codec, RT5630_STEREO_DAC_VOL, 0x8080, 0x8080); + else + rt5630_write_mask(codec, RT5630_STEREO_DAC_VOL, 0x0000, 0x8080); + + return 0; +} + +static int rt5630_voice_codec_mute(struct snd_soc_dai *dai, int mute) +{ + struct snd_soc_codec *codec = dai->codec; + RT5630_DEBUG("mute=%d\n",mute); + + if (mute) + rt5630_write_mask(codec, RT5630_VOICE_DAC_OUT_VOL, 0x1000, 0x1000); + else + rt5630_write_mask(codec, RT5630_VOICE_DAC_OUT_VOL, 0x0000, 0x1000); + return 0; +} + + +#if USE_DAPM_CTRL + +static int rt5630_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + RT5630_DEBUG("level=%d\n",level); + + switch(level) { + case SND_SOC_BIAS_ON: + case SND_SOC_BIAS_PREPARE: + break; + case SND_SOC_BIAS_STANDBY: + rt5630_write(codec, 0x3e, 0x0000); + rt5630_write(codec, 0x3a, 0x0002); + rt5630_write(codec, 0x3c, 0x2000); + break; + case SND_SOC_BIAS_OFF: + rt5630_write_mask(codec, 0x3a, 0x0000, 0x0300); + rt5630_write_mask(codec, 0x02, 0x8080, 0x8080); + rt5630_write_mask(codec, 0x04, 0x8080, 0x8080); + rt5630_write(codec, 0x3e, 0x0000); + rt5630_write(codec, 0x3a, 0x0000); + rt5630_write(codec, 0x3c, 0x0000); + break; + } + codec->bias_level = level; + return 0; +} + +#else + +static int rt5630_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + + switch(level) { + case SND_SOC_BIAS_ON: + case SND_SOC_BIAS_PREPARE: + break; + case SND_SOC_BIAS_STANDBY: + break; + case SND_SOC_BIAS_OFF: + rt5630_write_mask(codec, 0x3a, 0x0000, 0x0300); + rt5630_write_mask(codec, 0x02, 0x8080, 0x8080); + rt5630_write_mask(codec, 0x04, 0x8080, 0x8080); + rt5630_write(codec, 0x3e, 0x0000); + rt5630_write(codec, 0x3a, 0x0000); + rt5630_write(codec, 0x3c, 0x0000); + + break; + + } + + codec->bias_level = level; + return 0; +} + +#endif + + +static int rt5630_hifi_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *codec_dai) +{ + struct snd_soc_codec *codec = codec_dai->codec; + int stream = substream->stream; + RT5630_DEBUG("stream=%d\n",stream); + switch (stream) + { + case SNDRV_PCM_STREAM_PLAYBACK: + +// rt5630_write_mask(codec, 0x04, 0x8080, 0x8080); /*mute hp*/ +// rt5630_write_mask(codec, 0x02, 0x8080, 0x8080); /*mute spk*/ +// rt5630_write_mask(codec, 0x3a, 0x0000, 0xcf01); /*power off DAC path and I2S classabd amp*/ + rt5630_write_mask(codec, 0x3a, 0x0000, 0x4f01); /*power off DAC path*/ + rt5630_write_mask(codec, 0x3c, 0x0000, 0x0330); /*power off hp mixerlr and daclr*/ + rt5630_write_mask(codec, 0x3e, 0x0000, 0x3c00); /*power spklr volume*/ +#if CONFIG_SND_DOVE_SOC_AC97_AVD1 + spk_amplifier_enable(0); +#endif + break; + + case SNDRV_PCM_STREAM_CAPTURE: + + rt5630_write_mask(codec, 0x3e, 0x0000, 0x0005); /*power mic1 boost*/ + rt5630_write_mask(codec, 0x3a, 0x0000, 0x0004); /*mic bias*/ + rt5630_write_mask(codec, 0x3c, 0x0000, 0x00c3); /*power adc lr and rec mixer lr*/ + + break; + + default: + return 0; + } + + + return 0; +} + + +#define RT5630_STEREO_RATES (SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_44100) +#define RT5626_VOICE_RATES (SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_8000) + +#define RT5630_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S20_3LE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S8) + + +struct snd_soc_dai_ops rt5630_hifi_ops = { + .hw_params = rt5630_hifi_pcm_hw_params, + .set_fmt = rt5630_hifi_codec_set_dai_fmt, + .set_sysclk = rt5630_hifi_codec_set_dai_sysclk, + .set_pll = rt5630_codec_set_dai_pll, + #if !USE_DAPM_CTRL + .prepare = rt5630_pcm_hw_prepare, + #endif + .shutdown = rt5630_hifi_shutdown, +}; + +struct snd_soc_dai_ops rt5630_voice_ops = { + .hw_params = rt5630_voice_pcm_hw_params, + .set_fmt = rt5630_voice_codec_set_dai_fmt, + .set_sysclk = rt5630_voice_codec_set_dai_sysclk, + .set_pll = rt5630_codec_set_dai_pll, + #if !USE_DAPM_CTRL + .prepare = rt5630_vopcm_hw_prepare, + #endif + +}; + +struct snd_soc_dai rt5630_dai[] = { + /*hifi codec dai*/ + { + .name = "RT5630 HiFi", + .id = 1, + .playback = { + .stream_name = "HiFi Playback", + .channels_min = 1, + .channels_max = 2, + .rates = RT5630_STEREO_RATES, + .formats = RT5630_FORMATS, + }, + .capture = { + .stream_name = "HiFi Capture", + .channels_min = 1, + .channels_max = 2, + .rates = RT5630_STEREO_RATES, + .formats = RT5630_FORMATS, + }, + .ops = &rt5630_hifi_ops, + }, + + /*voice codec dai*/ + { + .name = "RT5630 Voice", + .id = 1, + .playback = { + .stream_name = "Voice Playback", + .channels_min = 1, + .channels_max =1, + .rates = RT5626_VOICE_RATES, + .formats = RT5630_FORMATS, + }, + .capture = { + .stream_name = "Voice Capture", + .channels_min = 1, + .channels_max = 1, + .rates = RT5626_VOICE_RATES, + .formats = RT5630_FORMATS, + }, + .ops = &rt5630_voice_ops, + }, +}; + +EXPORT_SYMBOL_GPL(rt5630_dai); + + +static void rt5630_work(struct work_struct *work) +{ + struct snd_soc_codec *codec = + container_of(work, struct snd_soc_codec, delayed_work.work); + rt5630_set_bias_level(codec, codec->bias_level); +} + + + +static int rt5630_init(struct snd_soc_device *socdev) +{ + struct snd_soc_codec *codec = socdev->card->codec; + int reg, ret = 0; + + codec->name = "RT5630"; + codec->owner = THIS_MODULE; + codec->read = rt5630_read; + codec->write = rt5630_write; + codec->set_bias_level = rt5630_set_bias_level; + codec->dai= rt5630_dai; + codec->num_dai = 2; + codec->reg_cache_step=2; + codec->reg_cache_size = sizeof(rt5630_reg); + + codec->reg_cache = kmemdup(rt5630_reg, sizeof(rt5630_reg), GFP_KERNEL); + if (codec->reg_cache == NULL) + return -ENOMEM; + + rt5630_reset(codec); + + ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); + if (ret < 0 ) + { + printk(KERN_ERR "rt5630: failed to create pcms\n"); + goto pcm_err; + } + + rt5630_write(codec, RT5630_PD_CTRL_STAT, 0); + rt5630_write(codec, RT5630_PWR_MANAG_ADD1, PWR_MAIN_BIAS); + rt5630_write(codec, RT5630_PWR_MANAG_ADD2, PWR_MIXER_VREF); + + schedule_delayed_work(&codec->delayed_work, msecs_to_jiffies(1000)); + rt5630_reg_init(codec); + rt5630_set_bias_level(codec, SND_SOC_BIAS_PREPARE); + codec->bias_level = SND_SOC_BIAS_STANDBY; + + rt5630_add_controls(codec); +#if USE_DAPM_CTRL + rt5630_add_widgets(codec); +#endif + ret = snd_soc_init_card(socdev); + if (ret < 0) + { + printk(KERN_ERR "rt5630: failed to register card\n"); + goto card_err; + } + RT5630_DEBUG("rt5630: initial ok\n"); + return ret; + + card_err: + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); + + pcm_err: + kfree(codec->reg_cache); + return ret; + + +} + + +static int rt5630_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) +{ + struct snd_soc_device *socdev = rt5630_socdev; + struct snd_soc_codec *codec = socdev->card->codec; + int ret; + + i2c_set_clientdata(i2c, codec); + codec->control_data = i2c; + + ret = rt5630_init(socdev); + if (ret < 0) + pr_err("failed to initialise rt5630\n"); + + return ret; +} + +static int rt5630_i2c_remove(struct i2c_client *client) +{ + struct snd_soc_codec *codec = i2c_get_clientdata(client); + kfree(codec->reg_cache); + return 0; +} + +static const struct i2c_device_id rt5630_i2c_id[] = { + {"rt5630", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, rt5630_i2c_id); +static struct i2c_driver rt5630_i2c_driver = { + .driver = { + .name = "RT5630 I2C Codec", + .owner = THIS_MODULE, + }, + .probe = rt5630_i2c_probe, + .remove = rt5630_i2c_remove, + .id_table = rt5630_i2c_id, +}; + + +static int rt5630_add_i2c_device(struct platform_device *pdev, + const struct rt5630_setup_data *setup) +{ + struct i2c_board_info info; + struct i2c_adapter *adapter; + struct i2c_client *client; + int ret; + + ret = i2c_add_driver(&rt5630_i2c_driver); + if (ret != 0) { + dev_err(&pdev->dev, "can't add i2c driver\n"); + return ret; + } +#if 0 + memset(&info, 0, sizeof(struct i2c_board_info)); + info.addr = setup->i2c_address; + strlcpy(info.type, "rt5630", I2C_NAME_SIZE); + + adapter = i2c_get_adapter(setup->i2c_bus); + if (!adapter) { + dev_err(&pdev->dev, "can't get i2c adapter %d\n", + setup->i2c_bus); + goto err_driver; + } + + client = i2c_new_device(adapter, &info); + i2c_put_adapter(adapter); + if (!client) { + dev_err(&pdev->dev, "can't add i2c device at 0x%x\n", + (unsigned int)info.addr); + goto err_driver; + } +#endif + return 0; + +err_driver: + i2c_del_driver(&rt5630_i2c_driver); + return -ENODEV; +} + + +static ssize_t rt5630_dsp_reg_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct snd_soc_device *socdev = dev_get_drvdata(dev); + struct snd_soc_codec *codec = socdev->card->codec; + int count = 0; + int dsp_value; + int i; + Voice_DSP_Reg *vodsp_reg; + int dsp_num; + + if (dsp_init_state == VODSP_AEC_FUNC) { + dsp_num = SET_VODSP_REG_AEC_INIT_NUM; + vodsp_reg = VODSP_AEC_Init_Value; + } else if (dsp_init_state == VODSP_VE_FUNC) { + dsp_num = SET_VODSP_VE_REG_INIT_NUM; + vodsp_reg = VODSP_VE_Init_Value; + } else + return -ENOSYS; + + count += sprintf(buf, "%s dsp registers\n", codec ->name); + for (i = 0; i < dsp_num; i ++) { + count += sprintf(buf + count, "0x%4x:", vodsp_reg[i].VoiceDSPIndex); + if (count > PAGE_SIZE - 1) + break; + dsp_value = rt5630_read_vodsp_reg(codec, vodsp_reg[i].VoiceDSPIndex); + count += snprintf(buf + count, PAGE_SIZE - count, "0x%4x", dsp_value); + + if (count >= PAGE_SIZE - 1) + break; + + count += snprintf(buf + count, PAGE_SIZE - count, "\n"); + if (count >= PAGE_SIZE - 1) + break; + } + + if (count >= PAGE_SIZE) + count = PAGE_SIZE - 1; + + + return count; + +} + +static DEVICE_ATTR(dsp_reg, 0444, rt5630_dsp_reg_show, NULL); + +static ssize_t rt5630_index_reg_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct snd_soc_device *socdev = dev_get_drvdata(dev); + struct snd_soc_codec *codec = socdev->card->codec; + int count = 0; + int value; + int i; + + count += sprintf(buf, "%s index register\n", codec->name); + + for (i = 0; i < 60; i++) { + count += sprintf(buf + count, "index-%2x", i); + if (count >= PAGE_SIZE - 1) + break; + value = rt5630_read_index(codec, i); + count += snprintf(buf + count, PAGE_SIZE - count, "0x%4x", value); + + if (count >= PAGE_SIZE - 1) + break; + + count += snprintf(buf + count, PAGE_SIZE - count, "\n"); + if (count >= PAGE_SIZE - 1) + break; + } + + if (count >= PAGE_SIZE) + count = PAGE_SIZE - 1; + + return count; + +} + +static DEVICE_ATTR(index_reg, 0444, rt5630_index_reg_show, NULL); + + +static int rt5630_probe(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct rt5630_setup_data *setup = socdev->codec_data; + struct snd_soc_codec *codec; + struct rt5630_priv *rt5630; + int ret; + codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); + if (codec == NULL) + return -ENOMEM; + + rt5630 = kzalloc(sizeof(struct rt5630_priv), GFP_KERNEL); + if (rt5630 == NULL) { + kfree(codec); + return -ENOMEM; + } + + codec->private_data = rt5630; + socdev->card->codec = codec; + mutex_init(&codec->mutex); + INIT_LIST_HEAD(&codec->dapm_widgets); + INIT_LIST_HEAD(&codec->dapm_paths); + rt5630_socdev = socdev; + INIT_DELAYED_WORK(&codec->delayed_work, rt5630_work); + ret = device_create_file(&pdev->dev, &dev_attr_dsp_reg); + if (ret < 0) + printk(KERN_WARNING "asoc: failed to add dsp_reg sysfs files\n"); + ret = device_create_file(&pdev->dev, &dev_attr_index_reg); + if (ret < 0) + printk(KERN_WARNING "asoc: failed to add index_reg sysfs files\n"); + ret = -ENODEV; + if (setup->i2c_address) { + codec->hw_write = (hw_write_t)i2c_master_send; + ret = rt5630_add_i2c_device(pdev, setup); + } + + if (ret != 0) { + kfree(codec->private_data); + kfree(codec); + socdev->card->codec = NULL; + } + return ret; +} + +static int run_delayed_work(struct delayed_work *dwork) +{ + int ret; + + /* cancel any work waiting to be queued. */ + ret = cancel_delayed_work(dwork); + + /* if there was any work waiting then we run it now and + * wait for it's completion */ + if (ret) { + schedule_delayed_work(dwork, 0); + flush_scheduled_work(); + } + return ret; +} + + +static int rt5630_remove(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->card->codec; + + if (codec->control_data) + rt5630_set_bias_level(codec, SND_SOC_BIAS_OFF); + run_delayed_work(&codec->delayed_work); + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); + device_remove_file(&pdev->dev, &dev_attr_dsp_reg); + device_remove_file(&pdev->dev, &dev_attr_index_reg); + i2c_unregister_device(codec->control_data); + i2c_del_driver(&rt5630_i2c_driver); + kfree(codec->private_data); + kfree(codec); + + return 0; +} + +static int rt5630_suspend_reg[] = {0x3a, 0x3c, 0x3e}; +static int rt5630_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->card->codec; + int i; + u8 data[3]; + RT5630_DEBUG(""); + + rt5630_set_bias_level(codec, SND_SOC_BIAS_OFF); + for (i = 0; i < ARRAY_SIZE(rt5630_suspend_reg); i ++) { + data[0] = rt5630_suspend_reg[i]; + data[1] = 0x00; + data[2] = 0x00; + codec->hw_write(codec->control_data, data, 3); + } + dsp_init_state=VODSP_NULL; + + + return 0; +} + +static int rt5630_resume(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->card->codec; + int i; + u8 data[3]; + u16 *cache = codec->reg_cache; + RT5630_DEBUG(""); + rt5630_write_mask(codec, 0x3a, 0x0802, 0x0802); + rt5630_write_mask(codec, 0x3c, 0xa000, 0xa000); + schedule_timeout_uninterruptible(msecs_to_jiffies(1000)); + /* Sync reg_cache with the hardware */ + for (i = 0; i < ARRAY_SIZE(rt5630_reg); i++) { + if (i == RT5630_RESET) + continue; + data[0] = i << 1; + data[1] = (0xff00 & cache[i]) >> 8; + data[2] = (0x00ff & cache[i]); + codec->hw_write(codec->control_data, data, 3); + RT5630_DEBUG("recover codec register[0x%x] from cache\n", i<<1); + } + + rt5630_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + + /* charge rt5630 caps */ + if (codec->suspend_bias_level == SND_SOC_BIAS_ON) { + rt5630_set_bias_level(codec, SND_SOC_BIAS_PREPARE); + codec->bias_level = SND_SOC_BIAS_ON; + schedule_delayed_work(&codec->delayed_work, + msecs_to_jiffies(1000)); + } + + return 0; +} + + +struct snd_soc_codec_device soc_codec_dev_rt5630 = { + .probe = rt5630_probe, + .remove = rt5630_remove, + .suspend = rt5630_suspend, + .resume = rt5630_resume, +}; + +EXPORT_SYMBOL_GPL(soc_codec_dev_rt5630); + +static int __devinit rt5630_dev_probe(struct platform_device *pdev) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(rt5630_dai); i++) + rt5630_dai[i].dev = &pdev->dev; + + return snd_soc_register_dais(rt5630_dai, ARRAY_SIZE(rt5630_dai)); +} + +static int __devexit rt5630_dev_remove(struct platform_device *pdev) +{ + snd_soc_unregister_dais(rt5630_dai, ARRAY_SIZE(rt5630_dai)); + + return 0; +} + +static struct platform_driver rt5630_driver = { + .probe = rt5630_dev_probe, + .remove = __devexit_p(rt5630_dev_remove), + .driver = { + .name = "rt5630-codec", + .owner = THIS_MODULE, + }, +}; + +static int __init rt5630_modinit(void) +{ + return platform_driver_register(&rt5630_driver); +} + +static void __exit rt5630_exit(void) +{ + platform_driver_unregister(&rt5630_driver); +} + +module_init(rt5630_modinit); +module_exit(rt5630_exit); +MODULE_LICENSE("GPL"); + --- linux-mvl-dove-2.6.32.orig/sound/soc/codecs/wm8974.c +++ linux-mvl-dove-2.6.32/sound/soc/codecs/wm8974.c @@ -47,7 +47,7 @@ }; #define WM8974_POWER1_BIASEN 0x08 -#define WM8974_POWER1_BUFIOEN 0x10 +#define WM8974_POWER1_BUFIOEN 0x04 struct wm8974_priv { struct snd_soc_codec codec; @@ -480,23 +480,23 @@ /* filter coefficient */ switch (params_rate(params)) { - case SNDRV_PCM_RATE_8000: + case 8000: adn |= 0x5 << 1; break; - case SNDRV_PCM_RATE_11025: + case 11025: adn |= 0x4 << 1; break; - case SNDRV_PCM_RATE_16000: + case 16000: adn |= 0x3 << 1; break; - case SNDRV_PCM_RATE_22050: + case 22050: adn |= 0x2 << 1; break; - case SNDRV_PCM_RATE_32000: + case 32000: adn |= 0x1 << 1; break; - case SNDRV_PCM_RATE_44100: - case SNDRV_PCM_RATE_48000: + case 44100: + case 48000: break; } --- linux-mvl-dove-2.6.32.orig/sound/soc/codecs/wm8940.c +++ linux-mvl-dove-2.6.32/sound/soc/codecs/wm8940.c @@ -379,23 +379,23 @@ iface |= (1 << 9); switch (params_rate(params)) { - case SNDRV_PCM_RATE_8000: + case 8000: addcntrl |= (0x5 << 1); break; - case SNDRV_PCM_RATE_11025: + case 11025: addcntrl |= (0x4 << 1); break; - case SNDRV_PCM_RATE_16000: + case 16000: addcntrl |= (0x3 << 1); break; - case SNDRV_PCM_RATE_22050: + case 22050: addcntrl |= (0x2 << 1); break; - case SNDRV_PCM_RATE_32000: + case 32000: addcntrl |= (0x1 << 1); break; - case SNDRV_PCM_RATE_44100: - case SNDRV_PCM_RATE_48000: + case 44100: + case 48000: break; } ret = snd_soc_write(codec, WM8940_ADDCNTRL, addcntrl); --- linux-mvl-dove-2.6.32.orig/sound/soc/codecs/rt5630.h +++ linux-mvl-dove-2.6.32/sound/soc/codecs/rt5630.h @@ -0,0 +1,715 @@ +#ifndef _RT5630_H +#define _RT5630_H +#define RT5630_RESET 0X00 //RESET CODEC TO DEFAULT +#define RT5630_SPK_OUT_VOL 0X02 //SPEAKER OUT VOLUME +#define RT5630_HP_OUT_VOL 0X04 //HEADPHONE OUTPUT VOLUME +#define RT5630_AUX_OUT_VOL 0X06 //AUXOUT VOLUME +#define RT5630_PHONEIN_VOL 0X08 //PHONE INPUT VOLUME +#define RT5630_LINE_IN_VOL 0X0A //LINE IN VOLUME +#define RT5630_STEREO_DAC_VOL 0X0C //STEREO DAC VOLUME +#define RT5630_MIC_VOL 0X0E //MICROPHONE VOLUME +#define RT5630_DAC_AND_MIC_CTRL 0X10 //STEREO DAC AND MIC ROUTING CONTROL +#define RT5630_ADC_REC_GAIN 0X12 //ADC RECORD GAIN +#define RT5630_ADC_REC_MIXER 0X14 //ADC RECORD MIXER CONTROL +#define RT5630_VOICE_DAC_OUT_VOL 0X18 //VOICE DAC OUTPUT VOLUME +#define RT5630_VODSP_PDM_CTL 0X1A //VODSP & PDM CONTROL +#define RT5630_OUTPUT_MIXER_CTRL 0X1C //OUTPUT MIXER CONTROL +#define RT5630_VODSP_CTL 0X1E //VODSP CONTROL +#define RT5630_MIC_CTRL 0X22 //MICROPHONE CONTROL +#define RT5630_DMIC_CTRL 0x24 +#define RT5630_PD_CTRL_STAT 0X26 //POWER DOWN CONTROL/STATUS +#define RT5630_DAC_ADC_VODAC_FUN_SEL 0X2E //STEREO DAC,VOICE DAC,STEREO ADC FUNCTION SELECT +#define RT5630_MAIN_SDP_CTRL 0X34 //MAIN SERIAL DATA PORT CONTROL(STEREO I2S) +#define RT5630_EXTEND_SDP_CTRL 0X36 //EXTEND SERIAL DATA PORT CONTROL(VOICE I2S/PCM) +#define RT5630_PWR_MANAG_ADD1 0X3A //POWER MANAGMENT ADDITION 1 +#define RT5630_PWR_MANAG_ADD2 0X3C //POWER MANAGMENT ADDITION 2 +#define RT5630_PWR_MANAG_ADD3 0X3E //POWER MANAGMENT ADDITION 3 +#define RT5630_GEN_CTRL_REG1 0X40 //GENERAL PURPOSE CONTROL REGISTER 1 +#define RT5630_GEN_CTRL_REG2 0X42 //GENERAL PURPOSE CONTROL REGISTER 2 +#define RT5630_PLL_CTRL 0X44 //PLL1 CONTROL +#define RT5630_PLL2_CTRL 0X46 //PLL2 CONTROL +#define RT5630_LDO_CTRL 0X48 //LDO CONTROL +#define RT5630_GPIO_PIN_CONFIG 0X4C //GPIO PIN CONFIGURATION +#define RT5630_GPIO_PIN_POLARITY 0X4E //GPIO PIN POLARITY +#define RT5630_GPIO_PIN_STICKY 0X50 //GPIO PIN STICKY +#define RT5630_GPIO_PIN_WAKEUP 0X52 //GPIO PIN WAKE UP +#define RT5630_GPIO_PIN_STATUS 0X54 //GPIO PIN STATUS +#define RT5630_GPIO_PIN_SHARING 0X56 //GPIO PIN SHARING +#define RT5630_OVER_TEMP_CURR_STATUS 0X58 //OVER TEMPERATURE AND CURRENT STATUS +#define RT5630_SOFT_VOL_CTRL 0X5A //SOFT VOLUME CONTROL SETTING +#define RT5630_GPIO_OUT_CTRL 0X5C //GPIO OUTPUT PIN CONTRL +#define RT5630_MISC_CTRL 0X5E //MISC CONTROL +#define RT5630_STEREO_DAC_CLK_CTRL1 0X60 //STEREO DAC CLOCK CONTROL 1 +#define RT5630_STEREO_DAC_CLK_CTRL2 0X62 //STEREO DAC CLOCK CONTROL 2 +#define RT5630_VOICE_DAC_PCMCLK_CTRL1 0X64 //VOICE/PCM DAC CLOCK CONTROL 1 +#define RT5630_PSEDUEO_SPATIAL_CTRL 0X68 //PSEDUEO STEREO /SPATIAL EFFECT BLOCK CONTROL +#define RT5630_PRIV_ADDR 0X6A //PRIVATE ADDRESS +#define RT5630_PRIV_DATA 0X6C //PRIVATE DATA +#define RT5630_EQ_CTRL_ADC_HPF 0X6E //EQ CONTROL AND STATUS /ADC HPF CONTROL +#define RT5630_VODSP_REG_ADDR 0x70 //VODSP REGISTER ADDRESS +#define RT5630_VODSP_REG_DATA 0x72 //VODSP REGISTER DATA +#define RT5630_VODSP_REG_CMD 0x74 //VODSP REGISTER COMMAND + + +/************************************************************************************************** + *Bit define of Codec Register + *************************************************************************************************/ +//global definition +#define RT_L_MUTE (0x1<<15) //Mute Left Control +#define RT_L_ZC (0x1<<14) //Mute Left Zero-Cross Detector Control +#define RT_R_MUTE (0x1<<7) //Mute Right Control +#define RT_R_ZC (0x1<<6) //Mute Right Zero-Cross Detector Control +#define RT_M_HP_MIXER (0x1<<15) //Mute source to HP Mixer +#define RT_M_SPK_MIXER (0x1<<14) //Mute source to Speaker Mixer +#define RT_M_MONO_MIXER (0x1<<13) //Mute source to Mono Mixer + +//Phone Input Volume(0x08) +#define M_PHONEIN_TO_HP_MIXER (0x1<<15) //Mute Phone In volume to HP mixer +#define M_PHONEIN_TO_SPK_MIXER (0x1<<14) //Mute Phone In volume to speaker mixer + + +//Mic Routing Control(0x10) +#define M_MIC1_TO_HP_MIXER (0x1<<15) //Mute MIC1 to HP mixer +#define M_MIC1_TO_SPK_MIXER (0x1<<14) //Mute MiC1 to SPK mixer +#define M_MIC1_TO_MONO_MIXER (0x1<<13) //Mute MIC1 to MONO mixer +#define M_MIC2_TO_HP_MIXER (0x1<<11) //Mute MIC2 to HP mixer +#define M_MIC2_TO_SPK_MIXER (0x1<<10) //Mute MiC2 to SPK mixer +#define M_MIC2_TO_MONO_MIXER (0x1<<9) //Mute MIC2 to MONO mixer +#define M_DAC_TO_HPL_MIXER (0x1<<3) //Mute DAC to HP left mixer +#define M_DAC_TO_HPR_MIXER (0x1<<2) //Mute DAC to HP right mixer +#define M_DAC_TO_SPK_MIXER (0x1<<1) //Mute DAC to SPK mixer +#define M_DAC_TO_MONO_MIXER (0x1<<0) //Mute DAC to MONO mixer + + + +//ADC Record Gain(0x12) +#define M_ADC_L_TO_HP_MIXER (0x1<<15) //Mute left of ADC to HP Mixer +#define M_ADC_L_TO_MONO_MIXER (0x1<<14) //Mute left of ADC to MONO Mixer +#define ADC_L_ZC_DET (0x1<<13) //ADC Zero-Cross Detector Control +#define ADC_L_GAIN_MASK (0x1f<<8) //ADC Record Gain Left channel Mask +#define M_ADC_R_TO_HP_MIXER (0x1<<7) //Mute right of ADC to HP Mixer +#define M_ADC_R_TO_MONO_MIXER (0x1<<6) //Mute right of ADC to MONO Mixer +#define ADC_R_ZC_DET (0x1<<5) //ADC Zero-Cross Detector Control +#define ADC_R_GAIN_MASK (0x1f<<0) //ADC Record Gain Right channel Mask + +//Voice DAC Output Volume(0x18) +#define M_V_DAC_TO_HP_MIXER (0x1<<15) +#define M_V_DAC_TO_SPK_MIXER (0x1<<14) +#define M_V_DAC_TO_MONO_MIXER (0x1<<13) + + +//AEC & PDM Control(0x1A) +#define VODSP_SRC1_PWR (0x1<<15) //Enable SRC1 Power +#define VODSP_SRC2_PWR (0x1<<13) //Enable SRC2 Power + +#define VODSP_SRC2_S_SEL_MASK (0x1<<12) +#define VODSP_SRC2_S_SEL_TXDP (0x0<<12) //SRC2 source select AEC_TXDP +#define VODSP_SRC2_S_SEL_TXDC (0x1<<12) //SRC2 source select AEC_TXDC + +#define VODSP_RXDP_PWR (0x1<<11) //Enable AEC RXDP Power + +#define VODSP_RXDP_S_SEL_MASK (0x3<<9) +#define VODSP_RXDP_S_SEL_SRC1 (0x0<<9) //AEC RxDP source select SRC1 Output +#define VODSP_RXDP_S_SEL_ADCL (0x1<<9) //AEC RxDP source select ADC Left to AEC Digital Path +#define VODSP_RXDP_S_SEL_VOICE (0x2<<9) //AEC RxDP source select Voice to Stereo Digital Path +#define VODSP_RXDP_S_SEL_ADCR (0x3<<9) //AEC RxDP source select ADC Right to AEC Digital Path + +#define VODSP_RXDC_PWR (0x1<<8) //Enable AEC RXDC Power + +#define VOICE_PCM_S_SEL_MASK (0x1<<7) +#define VOICE_PCM_S_SEL_ADC_R (0x0<<7) //VSADC PCM interface source select ADC R +#define VOICE_PCM_S_SEL_AEC_TXDP (0x1<<7) //VSADC PCM interface source select AEC_TXDP + +#define REC_S_SEL_MASK (0x3<<4) +#define REC_S_SEL_ADC (0x0<<4) //Main Stereo Record I2S source select ADC L/R +#define REC_S_SEL_VOICE (0x1<<4) //Main Stereo Record I2S source select Voice to Stereo Digital Path +#define REC_S_SEL_SRC2 (0x2<<4) //Main Stereo Record I2S source select SRC2 + + +//Output Mixer Control(0x1C) +#define SPKOUT_N_SOUR_MASK (0x3<<14) +#define SPKOUT_N_SOUR_LN (0x2<<14) +#define SPKOUT_N_SOUR_RP (0x1<<14) +#define SPKOUT_N_SOUR_RN (0x0<<14) + +#define SPKOUT_SEL_CLASS_D (0x1<<13) +#define SPKOUT_SEL_CLASS_AB (0x0<<13) + +#define SPK_CLASS_AB_S_AMP (0x0<<12) +#define SPK_CALSS_AB_W_AMP (0x1<<12) + +#define SPKOUT_INPUT_SEL_MASK (0x3<<10) +#define SPKOUT_INPUT_SEL_MONOMIXER (0x3<<10) +#define SPKOUT_INPUT_SEL_SPKMIXER (0x2<<10) +#define SPKOUT_INPUT_SEL_HPMIXER (0x1<<10) +#define SPKOUT_INPUT_SEL_VMID (0x0<<10) + +#define HPL_INPUT_SEL_HPLMIXER (0x1<<9) +#define HPR_INPUT_SEL_HPRMIXER (0x1<<8) + +#define AUXOUT_INPUT_SEL_MASK (0x3<<6) +#define AUXOUT_INPUT_SEL_MONOMIXER (0x3<<6) +#define AUXOUT_INPUT_SEL_SPKMIXER (0x2<<6) +#define AUXOUT_INPUT_SEL_HPMIXER (0x1<<6) +#define AUXOUT_INPUT_SEL_VMID (0x0<<6) + + +//Voice DSP Control(0x1E) +#define VODSP_SYSCLK_S_SEL_MASK (0x1<<15) +#define VODSP_SYSCLK_S_SEL_M_CLK (0x0<<15) +#define VODSP_SYSCLK_S_SEL_V_CLK (0x1<<15) + +#define VODSP_LRCK_SEL_MASK (0x1<<13) +#define VODSP_LRCK_SEL_8K (0x0<<13) +#define VODSP_LRCK_SEL_16K (0x1<<13) + +#define VODSP_TEST_MODE_ENA (0x1<<3) +#define VODSP_NO_BP_MODE_ENA (0x1<<2) +#define VODSP_NO_PD_MODE_ENA (0x1<<1) +#define VODSP_NO_RST_MODE_ENA (0x1<<0) + + + + +//Micphone Control define(0x22) +#define MIC1 1 +#define MIC2 2 +#define MIC_BIAS_90_PRECNET_AVDD 1 +#define MIC_BIAS_75_PRECNET_AVDD 2 + +#define MIC1_BOOST_CONTROL_MASK (0x3<<10) +#define MIC1_BOOST_CONTROL_BYPASS (0x0<<10) +#define MIC1_BOOST_CONTROL_20DB (0x1<<10) +#define MIC1_BOOST_CONTROL_30DB (0x2<<10) +#define MIC1_BOOST_CONTROL_40DB (0x3<<10) + +#define MIC2_BOOST_CONTROL_MASK (0x3<<8) +#define MIC2_BOOST_CONTROL_BYPASS (0x0<<8) +#define MIC2_BOOST_CONTROL_20DB (0x1<<8) +#define MIC2_BOOST_CONTROL_30DB (0x2<<8) +#define MIC2_BOOST_CONTROL_40DB (0x3<<8) + +#define MIC1_BIAS_VOLT_CTRL_MASK (0x1<<5) +#define MIC1_BIAS_VOLT_CTRL_90P (0x0<<5) +#define MIC1_BIAS_VOLT_CTRL_75P (0x1<<5) + +#define MIC2_BIAS_VOLT_CTRL_MASK (0x1<<4) +#define MIC2_BIAS_VOLT_CTRL_90P (0x0<<4) +#define MIC2_BIAS_VOLT_CTRL_75P (0x1<<4) + +//PowerDown control of register(0x26) +//power management bits +#define RT_PWR_PR7 (0x1<<15) //write this bit to power down the Speaker Amplifier +#define RT_PWR_PR6 (0x1<<14) //write this bit to power down the Headphone Out and MonoOut +#define RT_PWR_PR5 (0x1<<13) //write this bit to power down the internal clock(without PLL) +#define RT_PWR_PR3 (0x1<<11) //write this bit to power down the mixer(vref/vrefout out off) +#define RT_PWR_PR2 (0x1<<10) //write this bit to power down the mixer(vref/vrefout still on) +#define RT_PWR_PR1 (0x1<<9) //write this bit to power down the dac +#define RT_PWR_PR0 (0x1<<8) //write this bit to power down the adc +#define RT_PWR_REF (0x1<<3) //read only +#define RT_PWR_ANL (0x1<<2) //read only +#define RT_PWR_DAC (0x1<<1) //read only +#define RT_PWR_ADC (0x1) //read only + + +//Stereo DAC/Voice DAC/Stereo ADC function(0x2E) +#define DAC_FUNC_SEL_MASK (0x3<<12) +#define DAC_FUNC_SEL_DAC (0x0<<12) +#define DAC_FUNC_SEL_SRC2 (0x1<<12) +#define DAC_FUNC_SEL_VODSP_TXDP (0x2<<12) +#define DAC_FUNC_SEL_VODSP_TXDC (0x3<<12) + +#define VODAC_SOUR_SEL_MASK (0x7<<8) +#define VODAC_SOUR_SEL_VOICE (0x0<<8) +#define VODAC_SOUR_SEL_SRC2 (0x1<<8) +#define VODAC_SOUR_SEL_VODSP_TXDP (0x2<<8) +#define VODAC_SOUR_SEL_VODSP_TXDC (0x3<<8) + +#define ADCR_FUNC_SEL_MASK (0x3<<4) +#define ADCR_FUNC_SEL_ADC (0x0<<4) +#define ADCR_FUNC_SEL_VOADC (0x1<<4) +#define ADCR_FUNC_SEL_VODSP (0x2<<4) +#define ADCR_FUNC_SEL_PDM (0x3<<4) + +#define ADCL_FUNC_SEL_MASK (0x3<<0) +#define ADCL_FUNC_SEL_ADC (0x0<<0) +#define ADCL_FUNC_SEL_VODSP (0x1<<0) + +//Main Serial Data Port Control(0x34) +#define MAIN_I2S_MODE_SEL (0x1<<15) //0:Master mode 1:Slave mode +#define MAIN_I2S_SADLRCK_CTRL (0x1<<14) //0:Disable,ADC and DAC use the same fs,1:Enable + +#define MAIN_I2S_PCM_MODE (0x1<<6) //0:Normal SADLRCK/SDALRCK,1:Invert SADLRCK/SDALRCK +//Data Length Slection +#define MAIN_I2S_DL_MASK (0x3<<2) //main i2s Data Length mask +#define MAIN_I2S_DL_16 (0x0<<2) //16 bits +#define MAIN_I2S_DL_20 (0x1<<2) //20 bits +#define MAIN_I2S_DL_24 (0x2<<2) //24 bits +#define MAIN_I2S_DL_32 (0x3<<2) //8 bits + +//PCM Data Format Selection +#define MAIN_I2S_DF_MASK (0x3) //main i2s Data Format mask +#define MAIN_I2S_DF_I2S (0x0) //I2S FORMAT +#define MAIN_I2S_DF_LEFT (0x1) //LEFT JUSTIFIED format +#define MAIN_I2S_DF_PCM_A (0x2) //PCM Mode A +#define MAIN_I2S_DF_PCM_B (0x3) //PCM Mode B + +//Extend Serial Data Port Control(0x36) +#define EXT_I2S_FUNC_ENABLE (0x1<<15) //Enable PCM interface on GPIO 1,3,4,5 0:GPIO function,1:Voice PCM interface +#define EXT_I2S_MODE_SEL (0x1<<14) //0:Master ,1:Slave +#define EXT_I2S_AUTO_CLK_CTRL (0x1<<13) //0:Disable,1:Enable +#define EXT_I2S_BCLK_POLARITY (0x1<<7) //0:Normal 1:Invert +#define EXT_I2S_PCM_MODE (0x1<<6) //0:Normal VSLRCK,1:Invert VSLRCK +//Data Length Slection +#define EXT_I2S_DL_MASK (0x3<<2) //Extend i2s Data Length mask +#define EXT_I2S_DL_32 (0x3<<2) //8 bits +#define EXT_I2S_DL_24 (0x2<<2) //24 bits +#define EXT_I2S_DL_20 (0x1<<2) //20 bits +#define EXT_I2S_DL_16 (0x0<<2) //16 bits + +//Voice Data Format +#define EXT_I2S_DF_MASK (0x3) //Extend i2s Data Format mask +#define EXT_I2S_DF_I2S (0x0) //I2S FORMAT +#define EXT_I2S_DF_LEFT (0x1) //LEFT JUSTIFIED format +#define EXT_I2S_DF_PCM_A (0x2) //PCM Mode A +#define EXT_I2S_DF_PCM_B (0x3) //PCM Mode B + +//Power managment addition 1 (0x3A),0:Disable,1:Enable +#define PWR_DAC_DF2SE_L (0x1<<15) +#define PWR_DAC_DF2SE_R (0x1<<14) +#define PWR_ZC_DET_PD (0x1<<13) +#define PWR_I2S_INTERFACE (0x1<<11) +#define PWR_AMP_POWER (0x1<<10) +#define PWR_HP_OUT_AMP (0x1<<9) +#define PWR_HP_OUT_ENH_AMP (0x1<<8) +#define PWR_VOICE_DF2SE (0x1<<7) +#define PWR_SOFTGEN_EN (0x1<<6) +#define PWR_MIC_BIAS1_DET (0x1<<5) +#define PWR_MIC_BIAS2_DET (0x1<<4) +#define PWR_MIC_BIAS1 (0x1<<3) +#define PWR_MIC_BIAS2 (0x1<<2) +#define PWR_MAIN_BIAS (0x1<<1) +#define PWR_DAC_REF (0x1) + + +//Power managment addition 2(0x3C),0:Disable,1:Enable +#define PWR_PLL1 (0x1<<15) +#define PWR_PLL2 (0x1<<14) +#define PWR_MIXER_VREF (0x1<<13) +#define PWR_TEMP_SENSOR (0x1<<12) +#define PWR_AUX_ADC (0x1<<11) +#define PWR_VOICE_CLOCK (0x1<<10) +#define PWR_L_DAC_CLK (0x1<<9) +#define PWR_R_DAC_CLK (0x1<<8) +#define PWR_L_ADC_CLK (0x1<<7) +#define PWR_R_ADC_CLK (0x1<<6) +#define PWR_L_HP_MIXER (0x1<<5) +#define PWR_R_HP_MIXER (0x1<<4) +#define PWR_SPK_MIXER (0x1<<3) +#define PWR_MONO_MIXER (0x1<<2) +#define PWR_L_ADC_REC_MIXER (0x1<<1) +#define PWR_R_ADC_REC_MIXER (0x1) + + +//Power managment addition 3(0x3E),0:Disable,1:Enable +#define PWR_OSC_EN (0x1<<15) +#define PWR_AUXOUT_VOL (0x1<<14) +#define PWR_SPK_OUT (0x1<<13) +#define PWR_SPK_OUT_N (0x1<<12) +#define PWR_HP_L_OUT_VOL (0x1<<11) +#define PWR_HP_R_OUT_VOL (0x1<<10) +#define PWR_VODSP_INTERFACE (0x1<<9) +#define PWR_I2C_FOR_VODSP (0x1<<8) +#define PWR_LINE_IN_L (0x1<<7) +#define PWR_LINE_IN_R (0x1<<6) +#define PWR_PHONE_VOL (0x1<<5) +#define PWR_PHONE_ADMIXER (0x1<<4) +#define PWR_MIC1_VOL_CTRL (0x1<<3) +#define PWR_MIC2_VOL_CTRL (0x1<<2) +#define PWR_MIC1_BOOST (0x1<<1) +#define PWR_MIC2_BOOST (0x1) + +//General Purpose Control Register 1(0x40) +#define GP_CLK_FROM_PLL (0x1<<15) +#define GP_CLK_FROM_MCLK (0x0<<15) + +#define GP_DAC_HI_PA_ENA (0x1<<10) //Enable DAC High Pass Filter + +#define GP_EXTCLK_S_SEL_PLL2 (0x1<<6) +#define GP_EXTCLK_S_SEL_PLL1 (0x0<<6) + +#define GP_EXTCLK_DIR_SEL_OUTPUT (0x1<<5) +#define GP_EXTCLK_DIR_SEL_INTPUT (0x0<<5) + +#define GP_VOSYS_S_SEL_PLL2 (0x0<<4) +#define GP_VOSYS_S_SEL_EXTCLK (0x1<<4) + +#define GP_SPK_AMP_CTRL_MASK (0x7<<1) +#define GP_SPK_AMP_CTRL_RATIO_225 (0x0<<1) //2.25 Vdd +#define GP_SPK_AMP_CTRL_RATIO_200 (0x1<<1) //2.00 Vdd +#define GP_SPK_AMP_CTRL_RATIO_175 (0x2<<1) //1.75 Vdd +#define GP_SPK_AMP_CTRL_RATIO_150 (0x3<<1) //1.50 Vdd +#define GP_SPK_AMP_CTRL_RATIO_125 (0x4<<1) //1.25 Vdd +#define GP_SPK_AMP_CTRL_RATIO_100 (0x5<<1) //1.00 Vdd + +//General Purpose Control Register 2(0x42) +#define GP2_PLL1_SOUR_SEL_MASK (0x3<<12) +#define GP2_PLL1_SOUR_SEL_MCLK (0x0<<12) +#define GP2_PLL1_SOUR_SEL_BCLK (0x2<<12) +#define GP2_PLL1_SOUR_SEL_VBCLK (0x3<<12) + +//PLL Control(0x44) +#define PLL_M_CODE_MASK 0xF //PLL M code mask +#define PLL_K_CODE_MASK (0x7<<4) //PLL K code mask +#define PLL_BYPASS_N (0x1<<7) //bypass PLL N code +#define PLL_N_CODE_MASK (0xFF<<8) //PLL N code mask + +#define PLL_CTRL_M_VAL(m) ((m)&0xf) +#define PLL_CTRL_K_VAL(k) (((k)&0x7)<<4) +#define PLL_CTRL_N_VAL(n) (((n)&0xff)<<8) + +//PLL2 CONTROL +#define PLL2_ENA (0x1<<15) +#define PLL_2_RATIO_8X (0x0) +#define PLL_2_RATIO_16X (0x1) + +//LDO Control(0x48) +#define LDO_ENABLE (0x1<<15) + +#define LDO_OUT_VOL_CTRL_MASK (0xf<<0) +#define LDO_OUT_VOL_CTRL_1_55V (0xf<<0) +#define LDO_OUT_VOL_CTRL_1_50V (0xe<<0) +#define LDO_OUT_VOL_CTRL_1_45V (0xd<<0) +#define LDO_OUT_VOL_CTRL_1_40V (0xc<<0) +#define LDO_OUT_VOL_CTRL_1_35V (0xb<<0) +#define LDO_OUT_VOL_CTRL_1_30V (0xa<<0) +#define LDO_OUT_VOL_CTRL_1_25V (0x9<<0) +#define LDO_OUT_VOL_CTRL_1_20V (0x8<<0) +#define LDO_OUT_VOL_CTRL_1_15V (0x7<<0) +#define LDO_OUT_VOL_CTRL_1_05V (0x6<<0) +#define LDO_OUT_VOL_CTRL_1_00V (0x5<<0) +#define LDO_OUT_VOL_CTRL_0_95V (0x4<<0) +#define LDO_OUT_VOL_CTRL_0_90V (0x3<<0) +#define LDO_OUT_VOL_CTRL_0_85V (0x2<<0) +#define LDO_OUT_VOL_CTRL_0_80V (0x1<<0) +#define LDO_OUT_VOL_CTRL_0_75V (0x0<<0) + + + +//GPIO Pin Configuration(0x4C) +#define GPIO_1 (0x1<<1) +#define GPIO_2 (0x1<<2) +#define GPIO_3 (0x1<<3) +#define GPIO_4 (0x1<<4) +#define GPIO_5 (0x1<<5) + + +////INTERRUPT CONTROL(0x5E) +#define DISABLE_FAST_VREG (0x1<<15) + +#define AVC_TARTGET_SEL_MASK (0x3<<12) +#define AVC_TARTGET_SEL_NONE (0x0<<12) +#define AVC_TARTGET_SEL_R (0x1<<12) +#define AVC_TARTGET_SEL_L (0x2<<12) +#define AVC_TARTGET_SEL_BOTH (0x3<<12) + +#define HP_DEPOP_MODE2_EN (0x1<<8) +#define HP_DEPOP_MODE1_EN (0x1<<9) +#define HP_L_M_UM_DEPOP_EN (0x1<<7) +#define HP_R_M_UM_DEPOP_EN (0x1<<6) +#define M_UM_DEPOP_EN (0x1<<5) + +//Stereo DAC Clock Control 1(0x60) +#define STEREO_BCLK_DIV1_MASK (0xF<<12) +#define STEREO_BCLK_DIV1_1 (0x0<<12) +#define STEREO_BCLK_DIV1_2 (0x1<<12) +#define STEREO_BCLK_DIV1_3 (0x2<<12) +#define STEREO_BCLK_DIV1_4 (0x3<<12) +#define STEREO_BCLK_DIV1_5 (0x4<<12) +#define STEREO_BCLK_DIV1_6 (0x5<<12) +#define STEREO_BCLK_DIV1_7 (0x6<<12) +#define STEREO_BCLK_DIV1_8 (0x7<<12) +#define STEREO_BCLK_DIV1_9 (0x8<<12) +#define STEREO_BCLK_DIV1_10 (0x9<<12) +#define STEREO_BCLK_DIV1_11 (0xA<<12) +#define STEREO_BCLK_DIV1_12 (0xB<<12) +#define STEREO_BCLK_DIV1_13 (0xC<<12) +#define STEREO_BCLK_DIV1_14 (0xD<<12) +#define STEREO_BCLK_DIV1_15 (0xE<<12) +#define STEREO_BCLK_DIV1_16 (0xF<<12) + +#define STEREO_BCLK_DIV2_MASK (0x7<<8) +#define STEREO_BCLK_DIV2_2 (0x0<<8) +#define STEREO_BCLK_DIV2_4 (0x1<<8) +#define STEREO_BCLK_DIV2_8 (0x2<<8) +#define STEREO_BCLK_DIV2_16 (0x3<<8) +#define STEREO_BCLK_DIV2_32 (0x4<<8) + +#define STEREO_AD_LRCK_DIV1_MASK (0xF<<4) +#define STEREO_AD_LRCK_DIV1_1 (0x0<<4) +#define STEREO_AD_LRCK_DIV1_2 (0x1<<4) +#define STEREO_AD_LRCK_DIV1_3 (0x2<<4) +#define STEREO_AD_LRCK_DIV1_4 (0x3<<4) +#define STEREO_AD_LRCK_DIV1_5 (0x4<<4) +#define STEREO_AD_LRCK_DIV1_6 (0x5<<4) +#define STEREO_AD_LRCK_DIV1_7 (0x6<<4) +#define STEREO_AD_LRCK_DIV1_8 (0x7<<4) +#define STEREO_AD_LRCK_DIV1_9 (0x8<<4) +#define STEREO_AD_LRCK_DIV1_10 (0x9<<4) +#define STEREO_AD_LRCK_DIV1_11 (0xA<<4) +#define STEREO_AD_LRCK_DIV1_12 (0xB<<4) +#define STEREO_AD_LRCK_DIV1_13 (0xC<<4) +#define STEREO_AD_LRCK_DIV1_14 (0xD<<4) +#define STEREO_AD_LRCK_DIV1_15 (0xE<<4) +#define STEREO_AD_LRCK_DIV1_16 (0xF<<4) + +#define STEREO_AD_LRCK_DIV2_MASK (0x7<<1) +#define STEREO_AD_LRCK_DIV2_2 (0x0<<1) +#define STEREO_AD_LRCK_DIV2_4 (0x1<<1) +#define STEREO_AD_LRCK_DIV2_8 (0x2<<1) +#define STEREO_AD_LRCK_DIV2_16 (0x3<<1) +#define STEREO_AD_LRCK_DIV2_32 (0x4<<1) + +#define STEREO_DA_LRCK_DIV_MASK (1) +#define STEREO_DA_LRCK_DIV_32 (0) +#define STEREO_DA_LRCK_DIV_64 (1) + +//Stereo DAC Clock Control 2(0x62) +#define STEREO_DA_FILTER_DIV1_MASK (0xF<<12) +#define STEREO_DA_FILTER_DIV1_1 (0x0<<12) +#define STEREO_DA_FILTER_DIV1_2 (0x1<<12) +#define STEREO_DA_FILTER_DIV1_3 (0x2<<12) +#define STEREO_DA_FILTER_DIV1_4 (0x3<<12) +#define STEREO_DA_FILTER_DIV1_5 (0x4<<12) +#define STEREO_DA_FILTER_DIV1_6 (0x5<<12) +#define STEREO_DA_FILTER_DIV1_7 (0x6<<12) +#define STEREO_DA_FILTER_DIV1_8 (0x7<<12) +#define STEREO_DA_FILTER_DIV1_9 (0x8<<12) +#define STEREO_DA_FILTER_DIV1_10 (0x9<<12) +#define STEREO_DA_FILTER_DIV1_11 (0xA<<12) +#define STEREO_DA_FILTER_DIV1_12 (0xB<<12) +#define STEREO_DA_FILTER_DIV1_13 (0xC<<12) +#define STEREO_DA_FILTER_DIV1_14 (0xD<<12) +#define STEREO_DA_FILTER_DIV1_15 (0xE<<12) +#define STEREO_DA_FILTER_DIV1_16 (0xF<<12) + +#define STEREO_DA_FILTER_DIV2_MASK (0x7<<9) +#define STEREO_DA_FILTER_DIV2_2 (0x0<<9) +#define STEREO_DA_FILTER_DIV2_4 (0x1<<9) +#define STEREO_DA_FILTER_DIV2_8 (0x2<<9) +#define STEREO_DA_FILTER_DIV2_16 (0x3<<9) +#define STEREO_DA_FILTER_DIV2_32 (0x4<<9) + +#define STEREO_AD_FILTER_DIV1_MASK (0xF<<4) +#define STEREO_AD_FILTER_DIV1_1 (0x0<<4) +#define STEREO_AD_FILTER_DIV1_2 (0x1<<4) +#define STEREO_AD_FILTER_DIV1_3 (0x2<<4) +#define STEREO_AD_FILTER_DIV1_4 (0x3<<4) +#define STEREO_AD_FILTER_DIV1_5 (0x4<<4) +#define STEREO_AD_FILTER_DIV1_6 (0x5<<4) +#define STEREO_AD_FILTER_DIV1_7 (0x6<<4) +#define STEREO_AD_FILTER_DIV1_8 (0x7<<4) +#define STEREO_AD_FILTER_DIV1_9 (0x8<<4) +#define STEREO_AD_FILTER_DIV1_10 (0x9<<4) +#define STEREO_AD_FILTER_DIV1_11 (0xA<<4) +#define STEREO_AD_FILTER_DIV1_12 (0xB<<4) +#define STEREO_AD_FILTER_DIV1_13 (0xC<<4) +#define STEREO_AD_FILTER_DIV1_14 (0xD<<4) +#define STEREO_AD_FILTER_DIV1_15 (0xE<<4) +#define STEREO_AD_FILTER_DIV1_16 (0xF<<4) + +#define STEREO_AD_FILTER_DIV2_MASK (0x7<<1) +#define STEREO_AD_FILTER_DIV2_1 (0x0<<1) +#define STEREO_AD_FILTER_DIV2_2 (0x1<<1) +#define STEREO_AD_FILTER_DIV2_4 (0x2<<1) +#define STEREO_AD_FILTER_DIV2_8 (0x3<<1) +#define STEREO_AD_FILTER_DIV2_16 (0x4<<1) +#define STEREO_AD_FILTER_DIV2_32 (0x5<<1) + + +//Voice DAC PCM Clock Control 1(0x64) +#define VOICE_BCLK_DIV1_MASK (0xF<<12) +#define VOICE_BCLK_DIV1_1 (0x0<<12) +#define VOICE_BCLK_DIV1_2 (0x1<<12) +#define VOICE_BCLK_DIV1_3 (0x2<<12) +#define VOICE_BCLK_DIV1_4 (0x3<<12) +#define VOICE_BCLK_DIV1_5 (0x4<<12) +#define VOICE_BCLK_DIV1_6 (0x5<<12) +#define VOICE_BCLK_DIV1_7 (0x6<<12) +#define VOICE_BCLK_DIV1_8 (0x7<<12) +#define VOICE_BCLK_DIV1_9 (0x8<<12) +#define VOICE_BCLK_DIV1_10 (0x9<<12) +#define VOICE_BCLK_DIV1_11 (0xA<<12) +#define VOICE_BCLK_DIV1_12 (0xB<<12) +#define VOICE_BCLK_DIV1_13 (0xC<<12) +#define VOICE_BCLK_DIV1_14 (0xD<<12) +#define VOICE_BCLK_DIV1_15 (0xE<<12) +#define VOICE_BCLK_DIV1_16 (0xF<<12) + +#define VOICE_BCLK_DIV2_MASK (0x7<<8) +#define VOICE_BCLK_DIV2_2 (0x0<<8) +#define VOICE_BCLK_DIV2_4 (0x1<<8) +#define VOICE_BCLK_DIV2_8 (0x2<<8) +#define VOICE_BCLK_DIV2_16 (0x3<<8) +#define VOICE_BCLK_DIV2_32 (0x4<<8) + +#define VOICE_AD_LRCK_DIV1_MASK (0xF<<4) +#define VOICE_AD_LRCK_DIV1_1 (0x0<<4) +#define VOICE_AD_LRCK_DIV1_2 (0x1<<4) +#define VOICE_AD_LRCK_DIV1_3 (0x2<<4) +#define VOICE_AD_LRCK_DIV1_4 (0x3<<4) +#define VOICE_AD_LRCK_DIV1_5 (0x4<<4) +#define VOICE_AD_LRCK_DIV1_6 (0x5<<4) +#define VOICE_AD_LRCK_DIV1_7 (0x6<<4) +#define VOICE_AD_LRCK_DIV1_8 (0x7<<4) +#define VOICE_AD_LRCK_DIV1_9 (0x8<<4) +#define VOICE_AD_LRCK_DIV1_10 (0x9<<4) +#define VOICE_AD_LRCK_DIV1_11 (0xA<<4) +#define VOICE_AD_LRCK_DIV1_12 (0xB<<4) +#define VOICE_AD_LRCK_DIV1_13 (0xC<<4) +#define VOICE_AD_LRCK_DIV1_14 (0xD<<4) +#define VOICE_AD_LRCK_DIV1_15 (0xE<<4) +#define VOICE_AD_LRCK_DIV1_16 (0xF<<4) + +#define VOICE_AD_LRCK_DIV2_MASK (0x7<<1) +#define VOICE_AD_LRCK_DIV2_2 (0x0<<1) +#define VOICE_AD_LRCK_DIV2_4 (0x1<<1) +#define VOICE_AD_LRCK_DIV2_8 (0x2<<1) +#define VOICE_AD_LRCK_DIV2_16 (0x3<<1) +#define VOICE_AD_LRCK_DIV2_32 (0x4<<1) + +#define VOICE_DA_LRCK_DIV_MASK (1) +#define VOICE_DA_LRCK_DIV_32 (0) +#define VOICE_DA_LRCK_DIV_64 (1) + + +//Psedueo Stereo & Spatial Effect Block Control(0x68) +#define SPATIAL_CTRL_EN (0x1<<15) +#define ALL_PASS_FILTER_EN (0x1<<14) +#define PSEUDO_STEREO_EN (0x1<<13) +#define STEREO_EXPENSION_EN (0x1<<12) + +#define SPATIAL_3D_GAIN1_MASK (0x3<<10) +#define SPATIAL_3D_GAIN1_1_0 (0x0<<10) +#define SPATIAL_3D_GAIN1_1_5 (0x1<<10) +#define SPATIAL_3D_GAIN1_2_0 (0x2<<10) + +#define SPATIAL_3D_RATIO1_MASK (0x3<<8) +#define SPATIAL_3D_RATIO1_0_0 (0x0<<8) +#define SPATIAL_3D_RATIO1_0_66 (0x1<<8) +#define SPATIAL_3D_RATIO1_1_0 (0x2<<8) + +#define SPATIAL_3D_GAIN2_MASK (0x3<<6) +#define SPATIAL_3D_GAIN2_1_0 (0x0<<6) +#define SPATIAL_3D_GAIN2_1_5 (0x1<<6) +#define SPATIAL_3D_GAIN2_2_0 (0x2<<6) + +#define SPATIAL_3D_RATIO2_MASK (0x3<<4) +#define SPATIAL_3D_RATIO2_0_0 (0x0<<4) +#define SPATIAL_3D_RATIO2_0_66 (0x1<<4) +#define SPATIAL_3D_RATIO2_1_0 (0x2<<4) + +#define APF_MASK (0x3) +#define APF_FOR_48K (0x3) +#define APF_FOR_44_1K (0x2) +#define APF_FOR_32K (0x1) + +//EQ Control and Status /ADC HPF Control(0x6E) +#define EN_HW_EQ_BLK (0x1<<15) //HW EQ block control + +#define EQ_SOUR_SEL_DAC (0x0<<14) +#define EQ_SOUR_SEL_ADC (0x1<<14) + +#define EQ_CHANGE_EN (0x1<<7) //EQ parameter update control +#define EN_HW_EQ_HPF (0x1<<4) //EQ High Pass Filter Control +#define EN_HW_EQ_BP3 (0x1<<3) //EQ Band-3 Control +#define EN_HW_EQ_BP2 (0x1<<2) //EQ Band-2 Control +#define EN_HW_EQ_BP1 (0x1<<1) //EQ Band-1 Control +#define EN_HW_EQ_LPF (0x1<<0) //EQ Low Pass Filter Control + + +//AEC register command(0x74) + +#define VODSP_BUSY (0x1<<15) //VODSP I2C busy flag + +#define VODSP_S_FROM_VODSP_RD (0x0<<14) +#define VODSP_S_FROM_MX72 (0x1<<14) + +#define VODSP_CLK_SEL_MASK (0x3<<12) //VODSP CLK select Mask +#define VODSP_CLK_SEL_12_288M (0x0<<12) //VODSP CLK select 12.288Mhz +#define VODSP_CLK_SEL_6_144M (0x1<<12) //VODSP CLK select 6.144Mhz +#define VODSP_CLK_SEL_3_072M (0x2<<12) //VODSP CLK select 3.072Mhz +#define VODSP_CLK_SEL_2_048M (0x3<<12) //VODSP CLK select 2.0488Mhz + +#define VODSP_READ_ENABLE (0x1<<9) //VODSP Read Enable +#define VODSP_WRITE_ENABLE (0x1<<8) //VODSP Write Enable + +#define VODSP_CMD_MASK (0xFF<<0) +#define VODSP_CMD_MW (0x3B<<0) //Memory Write +#define VODSP_CMD_MR (0x37<<0) //Memory Read +#define VODSP_CMD_RR (0x60<<0) //Register Read +#define VODSP_CMD_RW (0x68<<0) //Register Write + + +/************************************************************************************************* + *Index register of codec + *************************************************************************************************/ +/*Index(0x20) for Auto Volume Control*/ +#define AVC_CH_SEL_MASK (0x1<<7) +#define AVC_CH_SEL_L_CH (0x0<<7) +#define AVC_CH_SEL_R_CH (0x1<<7) +#define ENABLE_AVC_GAIN_CTRL (0x1<<15) + +enum VODSP_FUNC +{ + VODSP_NULL = 0, + VODSP_AEC_FUNC, + VODSP_VE_FUNC, + VODSP_ALL_FUNC, +}; + +enum pll_sel +{ + RT5630_PLL1_FROM_MCLK = 0, + RT5630_PLL1_FROM_BCLK, + RT5630_PLL1_FROM_VBCLK, + RT5630_PLL2_FROM_VBCLK +}; + +enum AEC_MODE +{ + PCM_IN_PCM_OUT = 0, + ANALOG_IN_ANALOG_OUT, + DAC_IN_ADC_OUT, + VODSP_AEC_DISABLE +}; + +enum VE_MODE +{ + TXDP_TO_I2S = 0, + TXDP_TO_PCM, + VE_DISABLE, +}; + +struct rt5630_setup_data { + int i2c_bus; + int i2c_address; +}; + +typedef struct +{ + unsigned short int VoiceDSPIndex; + unsigned short int VoiceDSPValue; + +}Voice_DSP_Reg; + +#define USE_DAPM_CTRL 0 + + +extern struct snd_soc_dai rt5630_dai[2]; +extern struct snd_soc_codec_device soc_codec_dev_rt5630; +extern int rt5630_codec_set_pll1(struct snd_soc_codec * codec, int pll_id, unsigned int freq_in, unsigned int freq_out); +extern int enable_vodsp_aec_func(struct snd_soc_codec * codec, unsigned int VodspAEC_En, unsigned int AEC_mode); +extern int enable_vodsp_ve_func(struct snd_soc_codec * codec, int vodsp_ve_en, int VE_mode); + +#endif --- linux-mvl-dove-2.6.32.orig/sound/soc/codecs/wm8990.c +++ linux-mvl-dove-2.6.32/sound/soc/codecs/wm8990.c @@ -110,21 +110,21 @@ #define wm8990_reset(c) snd_soc_write(c, WM8990_RESET, 0) -static const DECLARE_TLV_DB_LINEAR(rec_mix_tlv, -1500, 600); +static const DECLARE_TLV_DB_SCALE(rec_mix_tlv, -1500, 600, 0); -static const DECLARE_TLV_DB_LINEAR(in_pga_tlv, -1650, 3000); +static const DECLARE_TLV_DB_SCALE(in_pga_tlv, -1650, 3000, 0); -static const DECLARE_TLV_DB_LINEAR(out_mix_tlv, 0, -2100); +static const DECLARE_TLV_DB_SCALE(out_mix_tlv, 0, -2100, 0); -static const DECLARE_TLV_DB_LINEAR(out_pga_tlv, -7300, 600); +static const DECLARE_TLV_DB_SCALE(out_pga_tlv, -7300, 600, 0); -static const DECLARE_TLV_DB_LINEAR(out_omix_tlv, -600, 0); +static const DECLARE_TLV_DB_SCALE(out_omix_tlv, -600, 0, 0); -static const DECLARE_TLV_DB_LINEAR(out_dac_tlv, -7163, 0); +static const DECLARE_TLV_DB_SCALE(out_dac_tlv, -7163, 0, 0); -static const DECLARE_TLV_DB_LINEAR(in_adc_tlv, -7163, 1763); +static const DECLARE_TLV_DB_SCALE(in_adc_tlv, -7163, 1763, 0); -static const DECLARE_TLV_DB_LINEAR(out_sidetone_tlv, -3600, 0); +static const DECLARE_TLV_DB_SCALE(out_sidetone_tlv, -3600, 0, 0); static int wm899x_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -450,7 +450,7 @@ /* INMIX dB values */ static const unsigned int in_mix_tlv[] = { TLV_DB_RANGE_HEAD(1), - 0, 7, TLV_DB_LINEAR_ITEM(-1200, 600), + 0, 7, TLV_DB_SCALE_ITEM(-1200, 600, 0), }; /* Left In PGA Connections */ @@ -1185,7 +1185,7 @@ WM8990_VMIDTOG); /* Delay to allow output caps to discharge */ - msleep(msecs_to_jiffies(300)); + msleep(300); /* Disable VMIDTOG */ snd_soc_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST | @@ -1197,17 +1197,17 @@ /* Enable outputs */ snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1b00); - msleep(msecs_to_jiffies(50)); + msleep(50); /* Enable VMID at 2x50k */ snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f02); - msleep(msecs_to_jiffies(100)); + msleep(100); /* Enable VREF */ snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f03); - msleep(msecs_to_jiffies(600)); + msleep(600); /* Enable BUFIOEN */ snd_soc_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST | @@ -1252,7 +1252,7 @@ /* Disable VMID */ snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f01); - msleep(msecs_to_jiffies(300)); + msleep(300); /* Enable all output discharge bits */ snd_soc_write(codec, WM8990_ANTIPOP1, WM8990_DIS_LLINE | --- linux-mvl-dove-2.6.32.orig/sound/soc/codecs/Makefile +++ linux-mvl-dove-2.6.32/sound/soc/codecs/Makefile @@ -8,6 +8,7 @@ snd-soc-ak4642-objs := ak4642.o snd-soc-cs4270-objs := cs4270.o snd-soc-cx20442-objs := cx20442.o +snd-soc-cs42l51-objs := cs42l51.o snd-soc-l3-objs := l3.o snd-soc-pcm3008-objs := pcm3008.o snd-soc-spdif-objs := spdif_transciever.o @@ -47,6 +48,10 @@ # Amp snd-soc-max9877-objs := max9877.o +snd-soc-rt5623-objs := rt5623.o +snd-soc-rt5610-objs := rt5610.o +snd-soc-rt5630-objs := rt5630.o +snd-soc-rt655-objs := rt655.o obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o obj-$(CONFIG_SND_SOC_AD1836) += snd-soc-ad1836.o @@ -58,6 +63,7 @@ obj-$(CONFIG_SND_SOC_AK4642) += snd-soc-ak4642.o obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o +obj-$(CONFIG_SND_SOC_CS42L51) += snd-soc-cs42l51.o obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif.o @@ -97,3 +103,7 @@ # Amp obj-$(CONFIG_SND_SOC_MAX9877) += snd-soc-max9877.o +obj-$(CONFIG_SND_SOC_RT5623) += snd-soc-rt5623.o +obj-$(CONFIG_SND_SOC_RT5610) += snd-soc-rt5610.o +obj-$(CONFIG_SND_SOC_RT5630) += snd-soc-rt5630.o +obj-$(CONFIG_SND_SOC_RT655) += snd-soc-rt655.o --- linux-mvl-dove-2.6.32.orig/sound/soc/codecs/wm8400.c +++ linux-mvl-dove-2.6.32/sound/soc/codecs/wm8400.c @@ -106,21 +106,21 @@ wm8400_reset_codec_reg_cache(wm8400->wm8400); } -static const DECLARE_TLV_DB_LINEAR(rec_mix_tlv, -1500, 600); +static const DECLARE_TLV_DB_SCALE(rec_mix_tlv, -1500, 600, 0); -static const DECLARE_TLV_DB_LINEAR(in_pga_tlv, -1650, 3000); +static const DECLARE_TLV_DB_SCALE(in_pga_tlv, -1650, 3000, 0); -static const DECLARE_TLV_DB_LINEAR(out_mix_tlv, -2100, 0); +static const DECLARE_TLV_DB_SCALE(out_mix_tlv, -2100, 0, 0); -static const DECLARE_TLV_DB_LINEAR(out_pga_tlv, -7300, 600); +static const DECLARE_TLV_DB_SCALE(out_pga_tlv, -7300, 600, 0); -static const DECLARE_TLV_DB_LINEAR(out_omix_tlv, -600, 0); +static const DECLARE_TLV_DB_SCALE(out_omix_tlv, -600, 0, 0); -static const DECLARE_TLV_DB_LINEAR(out_dac_tlv, -7163, 0); +static const DECLARE_TLV_DB_SCALE(out_dac_tlv, -7163, 0, 0); -static const DECLARE_TLV_DB_LINEAR(in_adc_tlv, -7163, 1763); +static const DECLARE_TLV_DB_SCALE(in_adc_tlv, -7163, 1763, 0); -static const DECLARE_TLV_DB_LINEAR(out_sidetone_tlv, -3600, 0); +static const DECLARE_TLV_DB_SCALE(out_sidetone_tlv, -3600, 0, 0); static int wm8400_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -439,7 +439,7 @@ /* INMIX dB values */ static const unsigned int in_mix_tlv[] = { TLV_DB_RANGE_HEAD(1), - 0,7, TLV_DB_LINEAR_ITEM(-1200, 600), + 0,7, TLV_DB_SCALE_ITEM(-1200, 600, 0), }; /* Left In PGA Connections */ --- linux-mvl-dove-2.6.32.orig/sound/soc/codecs/rt5623.h +++ linux-mvl-dove-2.6.32/sound/soc/codecs/rt5623.h @@ -0,0 +1,489 @@ +/* + * rt5623.h -- audio driver for RT5623 + * + * Copyright 2008 Realtek Microelectronics + * + * Author: flove + * + * Based on WM8753.h + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#ifndef _RT5623_H +#define _RT5623_H + + +#define RT5623_RESET 0X00 //RESET CODEC TO DEFAULT +#define RT5623_SPK_OUT_VOL 0X02 //SPEAKER OUT VOLUME +#define RT5623_HP_OUT_VOL 0X04 //HEADPHONE OUTPUT VOLUME +#define RT5623_MONO_AUX_OUT_VOL 0X06 //MONO OUTPUT/AUXOUT VOLUME +#define RT5623_AUXIN_VOL 0X08 //AUXIN VOLUME +#define RT5623_LINE_IN_VOL 0X0A //LINE IN VOLUME +#define RT5623_STEREO_DAC_VOL 0X0C //STEREO DAC VOLUME +#define RT5623_MIC_VOL 0X0E //MICROPHONE VOLUME +#define RT5623_MIC_ROUTING_CTRL 0X10 //MIC ROUTING CONTROL +#define RT5623_ADC_REC_GAIN 0X12 //ADC RECORD GAIN +#define RT5623_ADC_REC_MIXER 0X14 //ADC RECORD MIXER CONTROL +#define RT5623_SOFT_VOL_CTRL_TIME 0X16 //SOFT VOLUME CONTROL TIME +#define RT5623_OUTPUT_MIXER_CTRL 0X1C //OUTPUT MIXER CONTROL +#define RT5623_MIC_CTRL 0X22 //MICROPHONE CONTROL +#define RT5623_AUDIO_INTERFACE 0X34 //AUDIO INTERFACE +#define RT5623_STEREO_AD_DA_CLK_CTRL 0X36 //STEREO AD/DA CLOCK CONTROL +#define RT5623_COMPANDING_CTRL 0X38 //COMPANDING CONTROL +#define RT5623_PWR_MANAG_ADD1 0X3A //POWER MANAGMENT ADDITION 1 +#define RT5623_PWR_MANAG_ADD2 0X3C //POWER MANAGMENT ADDITION 2 +#define RT5623_PWR_MANAG_ADD3 0X3E //POWER MANAGMENT ADDITION 3 +#define RT5623_ADD_CTRL_REG 0X40 //ADDITIONAL CONTROL REGISTER +#define RT5623_GLOBAL_CLK_CTRL_REG 0X42 //GLOBAL CLOCK CONTROL REGISTER +#define RT5623_PLL_CTRL 0X44 //PLL CONTROL +#define RT5623_GPIO_OUTPUT_PIN_CTRL 0X4A //GPIO OUTPUT PIN CONTROL +#define RT5623_GPIO_PIN_CONFIG 0X4C //GPIO PIN CONFIGURATION +#define RT5623_GPIO_PIN_POLARITY 0X4E //GPIO PIN POLARITY/TYPE +#define RT5623_GPIO_PIN_STICKY 0X50 //GPIO PIN STICKY +#define RT5623_GPIO_PIN_WAKEUP 0X52 //GPIO PIN WAKE UP +#define RT5623_GPIO_PIN_STATUS 0X54 //GPIO PIN STATUS +#define RT5623_GPIO_PIN_SHARING 0X56 //GPIO PIN SHARING +#define RT5623_OVER_TEMP_CURR_STATUS 0X58 //OVER TEMPERATURE AND CURRENT STATUS +#define RT5623_JACK_DET_CTRL 0X5A //JACK DETECT CONTROL REGISTER +#define RT5623_MISC_CTRL 0X5E //MISC CONTROL +#define RT5623_PSEDUEO_SPATIAL_CTRL 0X60 //PSEDUEO STEREO & SPATIAL EFFECT BLOCK CONTROL +#define RT5623_EQ_CTRL 0X62 //EQ CONTROL +#define RT5623_EQ_MODE_ENABLE 0X66 //EQ MODE CHANGE ENABLE +#define RT5623_AVC_CTRL 0X68 //AVC CONTROL +#define RT5623_HID_CTRL_INDEX 0X6A //HIDDEN CONTROL INDEX PORT +#define RT5623_HID_CTRL_DATA 0X6C //HIDDEN CONTROL DATA PORT +#define RT5623_VENDOR_ID1 0x7C //VENDOR ID1 +#define RT5623_VENDOR_ID2 0x7E //VENDOR ID2 + + +//global definition +#define RT_L_MUTE (0x1<<15) //MUTE LEFT CONTROL BIT +#define RT_L_ZC (0x1<<14) //LEFT ZERO CROSS CONTROL BIT +#define RT_L_SM (0x1<<13) //LEFT SOFTMUTE CONTROL BIT +#define RT_R_MUTE (0x1<<7) //MUTE RIGHT CONTROL BIT +#define RT_R_ZC (0x1<<6) //RIGHT ZERO CROSS CONTROL BIT +#define RT_R_SM (0x1<<5) //RIGHT SOFTMUTE CONTROL BIT +#define RT_M_HP_MIXER (0x1<<15) //Mute source to HP Mixer +#define RT_M_SPK_MIXER (0x1<<14) //Mute source to Speaker Mixer +#define RT_M_MONO_MIXER (0x1<<13) //Mute source to Mono Mixer +#define SPK_CLASS_AB 0 +#define SPK_CLASS_D 1 + +//Mic Routing Control(0x10) +#define M_MIC1_TO_HP_MIXER (0x1<<15) //Mute MIC1 to HP mixer +#define M_MIC1_TO_SPK_MIXER (0x1<<14) //Mute MiC1 to SPK mixer +#define M_MIC1_TO_MONO_MIXER (0x1<<13) //Mute MIC1 to MONO mixer +#define MIC1_DIFF_INPUT_CTRL (0x1<<12) //MIC1 different input control +#define M_MIC2_TO_HP_MIXER (0x1<<7) //Mute MIC2 to HP mixer +#define M_MIC2_TO_SPK_MIXER (0x1<<6) //Mute MiC2 to SPK mixer +#define M_MIC2_TO_MONO_MIXER (0x1<<5) //Mute MIC2 to MONO mixer +#define MIC2_DIFF_INPUT_CTRL (0x1<<4) //MIC2 different input control + +//ADC Record Gain(0x12) +#define M_ADC_L_TO_HP_MIXER (0x1<<15) //Mute left of ADC to HP Mixer +#define M_ADC_R_TO_HP_MIXER (0x1<<14) //Mute right of ADC to HP Mixer +#define M_ADC_L_TO_MONO_MIXER (0x1<<13) //Mute left of ADC to MONO Mixer +#define M_ADC_R_TO_MONO_MIXER (0x1<<12) //Mute right of ADC to MONO Mixer +#define ADC_L_GAIN_MASK (0x1f<<7) //ADC Record Gain Left channel Mask +#define ADC_L_ZC_DET (0x1<<6) //ADC Zero-Cross Detector Control +#define ADC_R_ZC_DET (0x1<<5) //ADC Zero-Cross Detector Control +#define ADC_R_GAIN_MASK (0x1f<<0) //ADC Record Gain Right channel Mask + +//ADC Input Mixer Control(0x14) +#define M_MIC1_TO_ADC_L_MIXER (0x1<<14) //Mute mic1 to left channel of ADC mixer +#define M_MIC2_TO_ADC_L_MIXER (0x1<<13) //Mute mic2 to left channel of ADC mixer +#define M_LINEIN_L_TO_ADC_L_MIXER (0x1<<12) //Mute line In left channel to left channel of ADC mixer +#define M_AUXIN_L_TO_ADC_L_MIXER (0x1<<11) //Mute aux In left channel to left channel of ADC mixer +#define M_HPMIXER_L_TO_ADC_L_MIXER (0x1<<10) //Mute HP mixer left channel to left channel of ADC mixer +#define M_SPKMIXER_L_TO_ADC_L_MIXER (0x1<<9) //Mute SPK mixer left channel to left channel of ADC mixer +#define M_MONOMIXER_L_TO_ADC_L_MIXER (0x1<<8) //Mute MONO mixer left channel to left channel of ADC mixer +#define M_MIC1_TO_ADC_R_MIXER (0x1<<6) //Mute mic1 to right channel of ADC mixer +#define M_MIC2_TO_ADC_R_MIXER (0x1<<5) //Mute mic2 to right channel of ADC mixer +#define M_LINEIN_R_TO_ADC_R_MIXER (0x1<<4) //Mute lineIn right channel to right channel of ADC mixer +#define M_AUXIN_R_TO_ADC_R_MIXER (0x1<<3) //Mute aux In right channel to right channel of ADC mixer +#define M_HPMIXER_R_TO_ADC_R_MIXER (0x1<<2) //Mute HP mixer right channel to right channel of ADC mixer +#define M_SPKMIXER_R_TO_ADC_R_MIXER (0x1<<1) //Mute SPK mixer right channel to right channel of ADC mixer +#define M_MONOMIXER_R_TO_ADC_R_MIXER (0x1<<0) //Mute MONO mixer right channel to right channel of ADC mixer + +//Output Mixer Control(0x1C) +#define SPKOUT_N_SOUR_MASK (0x3<<14) +#define SPKOUT_N_SOUR_LN (0x2<<14) +#define SPKOUT_N_SOUR_RP (0x1<<14) +#define SPKOUT_N_SOUR_RN (0x0<<14) +#define SPK_OUTPUT_CLASS_AB (0x0<<13) +#define SPK_OUTPUT_CLASS_D (0x1<<13) +#define SPK_CLASS_AB_S_AMP (0x0<<12) +#define SPK_CALSS_AB_W_AMP (0x1<<12) +#define SPKOUT_INPUT_SEL_MASK (0x3<<10) +#define SPKOUT_INPUT_SEL_MONOMIXER (0x3<<10) +#define SPKOUT_INPUT_SEL_SPKMIXER (0x2<<10) +#define SPKOUT_INPUT_SEL_HPMIXER (0x1<<10) +#define SPKOUT_INPUT_SEL_VMID (0x0<<10) +#define HPL_INPUT_SEL_HPLMIXER (0x1<<9) +#define HPR_INPUT_SEL_HPRMIXER (0x1<<8) +#define MONO_AUX_INPUT_SEL_MASK (0x3<<6) +#define MONO_AUX_INPUT_SEL_MONO (0x3<<6) +#define MONO_AUX_INPUT_SEL_SPK (0x2<<6) +#define MONO_AUX_INPUT_SEL_HP (0x1<<6) +#define MONO_AUX_INPUT_SEL_VMID (0x0<<6) + +//Micphone Control define(0x22) +#define MIC1 1 +#define MIC2 2 +#define MIC_BIAS_90_PRECNET_AVDD 1 +#define MIC_BIAS_75_PRECNET_AVDD 2 + +#define MIC1_BOOST_CTRL_MASK (0x3<<10) +#define MIC1_BOOST_CTRL_BYPASS (0x0<<10) +#define MIC1_BOOST_CTRL_20DB (0x1<<10) +#define MIC1_BOOST_CTRL_30DB (0x2<<10) +#define MIC1_BOOST_CTRL_40DB (0x3<<10) + +#define MIC2_BOOST_CTRL_MASK (0x3<<8) +#define MIC2_BOOST_CTRL_BYPASS (0x0<<8) +#define MIC2_BOOST_CTRL_20DB (0x1<<8) +#define MIC2_BOOST_CTRL_30DB (0x2<<8) +#define MIC2_BOOST_CTRL_40DB (0x3<<8) + +#define MICBIAS_VOLT_CTRL_MASK (0x1<<5) +#define MICBIAS_VOLT_CTRL_90P (0x0<<5) +#define MICBIAS_VOLT_CTRL_75P (0x1<<5) + +#define MICBIAS_SHORT_CURR_DET_MASK (0x3) +#define MICBIAS_SHORT_CURR_DET_600UA (0x0) +#define MICBIAS_SHORT_CURR_DET_1200UA (0x1) +#define MICBIAS_SHORT_CURR_DET_1800UA (0x2) + +//Audio Interface(0x34) +#define SDP_MASTER_MODE (0x0<<15) //Main I2S interface select Master mode +#define SDP_SLAVE_MODE (0x1<<15) //Main I2S interface select Slave mode +#define I2S_PCM_MODE (0x1<<14) //PCM 0:mode A ,1:mode B +#define MAIN_I2S_BCLK_POL_CTRL (0x1<<7) //0:Normal 1:Invert +#define ADC_DATA_L_R_SWAP (0x1<<5) //0:ADC data appear at left phase of LRCK + //1:ADC data appear at right phase of LRCK +#define DAC_DATA_L_R_SWAP (0x1<<4) //0:DAC data appear at left phase of LRCK + //1:DAC data appear at right phase of LRCK +//Data Length Slection +#define I2S_DL_MASK (0x3<<2) //main i2s Data Length mask +#define I2S_DL_16 (0x0<<2) //16 bits +#define I2S_DL_20 (0x1<<2) //20 bits +#define I2S_DL_24 (0x2<<2) //24 bits +#define I2S_DL_32 (0x3<<2) //32 bits + +//PCM Data Format Selection +#define I2S_DF_MASK (0x3) //main i2s Data Format mask +#define I2S_DF_I2S (0x0) //I2S FORMAT +#define I2S_DF_RIGHT (0x1) //RIGHT JUSTIFIED format +#define I2S_DF_LEFT (0x2) //LEFT JUSTIFIED format +#define I2S_DF_PCM (0x3) //PCM format + +//Stereo AD/DA Clock Control(0x36h) +#define I2S_PRE_DIV_MASK (0x7<<12) +#define I2S_PRE_DIV_1 (0x0<<12) //DIV 1 +#define I2S_PRE_DIV_2 (0x1<<12) //DIV 2 +#define I2S_PRE_DIV_4 (0x2<<12) //DIV 4 +#define I2S_PRE_DIV_8 (0x3<<12) //DIV 8 +#define I2S_PRE_DIV_16 (0x4<<12) //DIV 16 +#define I2S_PRE_DIV_32 (0x5<<12) //DIV 32 + +#define I2S_SCLK_DIV_MASK (0x7<<9) +#define I2S_SCLK_DIV_1 (0x0<<9) //DIV 1 +#define I2S_SCLK_DIV_2 (0x1<<9) //DIV 2 +#define I2S_SCLK_DIV_3 (0x2<<9) //DIV 3 +#define I2S_SCLK_DIV_4 (0x3<<9) //DIV 4 +#define I2S_SCLK_DIV_6 (0x4<<9) //DIV 6 +#define I2S_SCLK_DIV_8 (0x5<<9) //DIV 8 +#define I2S_SCLK_DIV_12 (0x6<<9) //DIV 12 +#define I2S_SCLK_DIV_16 (0x7<<9) //DIV 16 + +#define I2S_WCLK_DIV_PRE_MASK (0xF<<5) +#define I2S_WCLK_PRE_DIV_1 (0x0<<5) //DIV 1 +#define I2S_WCLK_PRE_DIV_2 (0x1<<5) //DIV 2 +#define I2S_WCLK_PRE_DIV_3 (0x2<<5) //DIV 3 +#define I2S_WCLK_PRE_DIV_4 (0x3<<5) //DIV 4 +#define I2S_WCLK_PRE_DIV_5 (0x4<<5) //DIV 5 +#define I2S_WCLK_PRE_DIV_6 (0x5<<5) //DIV 6 +#define I2S_WCLK_PRE_DIV_7 (0x6<<5) //DIV 7 +#define I2S_WCLK_PRE_DIV_8 (0x7<<5) //DIV 8 +//........................ + +#define I2S_WCLK_DIV_MASK (0x7<<2) +#define I2S_WCLK_DIV_2 (0x0<<2) //DIV 2 +#define I2S_WCLK_DIV_4 (0x1<<2) //DIV 4 +#define I2S_WCLK_DIV_8 (0x2<<2) //DIV 8 +#define I2S_WCLK_DIV_16 (0x3<<2) //DIV 16 +#define I2S_WCLK_DIV_32 (0x4<<2) //DIV 32 + +#define ADDA_FILTER_CLK_SEL_256FS (0<<1) //256FS +#define ADDA_FILTER_CLK_SEL_384FS (1<<1) //384FS + +#define ADDA_OSR_SEL_64FS (0) //64FS +#define ADDA_OSR_SEL_128FS (1) //128FS + +//Power managment addition 1 (0x3A),0:Disable,1:Enable +#define PWR_MAIN_I2S_EN (0x1<<15) +#define PWR_ZC_DET_PD_EN (0x1<<14) +#define PWR_MIC1_BIAS_EN (0x1<<11) +#define PWR_SHORT_CURR_DET_EN (0x1<<10) +#define PWR_SOFTGEN_EN (0x1<<8) +#define PWR_DEPOP_BUF_HP (0x1<<6) +#define PWR_HP_OUT_AMP (0x1<<5) +#define PWR_HP_OUT_ENH_AMP (0x1<<4) +#define PWR_DEPOP_BUF_AUX (0x1<<2) +#define PWR_AUX_OUT_AMP (0x1<<1) +#define PWR_AUX_OUT_ENH_AMP (0x1) + + +//Power managment addition 2(0x3C),0:Disable,1:Enable +#define PWR_LINEOUT (0x1<<15) +#define PWR_VREF (0x1<<13) +#define PWR_PLL (0x1<<12) +#define PWR_DAC_REF_CIR (0x1<<10) +#define PWR_L_DAC_CLK (0x1<<9) +#define PWR_R_DAC_CLK (0x1<<8) +#define PWR_L_ADC_CLK_GAIN (0x1<<7) +#define PWR_R_ADC_CLK_GAIN (0x1<<6) +#define PWR_L_HP_MIXER (0x1<<5) +#define PWR_R_HP_MIXER (0x1<<4) +#define PWR_SPK_MIXER (0x1<<3) +#define PWR_MONO_MIXER (0x1<<2) +#define PWR_L_ADC_REC_MIXER (0x1<<1) +#define PWR_R_ADC_REC_MIXER (0x1) + +//Power managment addition 3(0x3E),0:Disable,1:Enable +#define PWR_MAIN_BIAS (0x1<<15) +#define PWR_AUXOUT_L_VOL_AMP (0x1<<14) +#define PWR_AUXOUT_R_VOL_AMP (0x1<<13) +#define PWR_SPK_OUT (0x1<<12) +#define PWR_HP_L_OUT_VOL (0x1<<10) +#define PWR_HP_R_OUT_VOL (0x1<<9) +#define PWR_LINEIN_L_VOL (0x1<<7) +#define PWR_LINEIN_R_VOL (0x1<<6) +#define PWR_AUXIN_L_VOL (0x1<<5) +#define PWR_AUXIN_R_VOL (0x1<<4) +#define PWR_MIC1_FUN_CTRL (0x1<<3) +#define PWR_MIC2_FUN_CTRL (0x1<<2) +#define PWR_MIC1_BOOST_MIXER (0x1<<1) +#define PWR_MIC2_BOOST_MIXER (0x1) + + +//Additional Control Register(0x40) +#define AUXOUT_SEL_DIFF (0x1<<15) //Differential Mode +#define AUXOUT_SEL_SE (0x1<<15) //Single-End Mode + +#define STEREO_DAC_HI_PASS_FILTER_EN (0x1<<9) //Stereo DAC high pass filter enable +#define STEREO_ADC_HI_PASS_FILTER_EN (0x1<<8) //Stereo ADC high pass filter enable + +#define DIG_VOL_BOOST_MASK (0x3<<4) //Digital volume Boost mask +#define DIG_VOL_BOOST_0DB (0x0<<4) //Digital volume Boost 0DB +#define DIG_VOL_BOOST_6DB (0x1<<4) //Digital volume Boost 6DB +#define DIG_VOL_BOOST_12DB (0x2<<4) //Digital volume Boost 12DB +#define DIG_VOL_BOOST_18DB (0x3<<4) //Digital volume Boost 18DB + + +//Global Clock Control Register(0x42) +#define SYSCLK_SOUR_SEL_MASK (0x1<<15) +#define SYSCLK_SOUR_SEL_MCLK (0x0<<15) //system Clock source from MCLK +#define SYSCLK_SOUR_SEL_PLL (0x1<<15) //system Clock source from PLL +#define PLLCLK_SOUR_SEL_MCLK (0x0<<14) //PLL clock source from MCLK +#define PLLCLK_SOUR_SEL_BITCLK (0x1<<14) //PLL clock source from BITCLK + +#define PLLCLK_DIV_RATIO_MASK (0x3<<1) +#define PLLCLK_DIV_RATIO_DIV1 (0x0<<1) //DIV 1 +#define PLLCLK_DIV_RATIO_DIV2 (0x1<<1) //DIV 2 +#define PLLCLK_DIV_RATIO_DIV4 (0x2<<1) //DIV 4 +#define PLLCLK_DIV_RATIO_DIV8 (0x3<<1) //DIV 8 + +#define PLLCLK_PRE_DIV1 (0x0) //DIV 1 +#define PLLCLK_PRE_DIV2 (0x1) //DIV 2 + +//PLL Control(0x44) + +#define PLL_CTRL_M_VAL(m) ((m)&0xf) +#define PLL_CTRL_K_VAL(k) (((k)&0x7)<<4) +#define PLL_CTRL_N_VAL(n) (((n)&0xff)<<8) + +//GPIO Pin Configuration(0x4C) +#define GPIO_PIN_MASK (0x1<<1) +#define GPIO_PIN_SET_INPUT (0x1<<1) +#define GPIO_PIN_SET_OUTPUT (0x0<<1) + +//Pin Sharing(0x56) +#define LINEIN_L_PIN_SHARING (0x1<<15) +#define LINEIN_L_PIN_AS_LINEIN_L (0x0<<15) +#define LINEIN_L_PIN_AS_JD1 (0x1<<15) + +#define LINEIN_R_PIN_SHARING (0x1<<14) +#define LINEIN_R_PIN_AS_LINEIN_R (0x0<<14) +#define LINEIN_R_PIN_AS_JD2 (0x1<<14) + +#define GPIO_PIN_SHARING (0x3) +#define GPIO_PIN_AS_GPIO (0x0) +#define GPIO_PIN_AS_IRQOUT (0x1) +#define GPIO_PIN_AS_PLLOUT (0x3) + +//Jack Detect Control Register(0x5A) +#define JACK_DETECT_MASK (0x3<<14) +#define JACK_DETECT_USE_JD2 (0x3<<14) +#define JACK_DETECT_USE_JD1 (0x2<<14) +#define JACK_DETECT_USE_GPIO (0x1<<14) +#define JACK_DETECT_OFF (0x0<<14) + +#define SPK_EN_IN_HI (0x1<<11) +#define AUX_R_EN_IN_HI (0x1<<10) +#define AUX_L_EN_IN_HI (0x1<<9) +#define HP_EN_IN_HI (0x1<<8) +#define SPK_EN_IN_LO (0x1<<7) +#define AUX_R_EN_IN_LO (0x1<<6) +#define AUX_L_EN_IN_LO (0x1<<5) +#define HP_EN_IN_LO (0x1<<4) + +////MISC CONTROL(0x5E) +#define DISABLE_FAST_VREG (0x1<<15) +#define SPK_CLASS_AB_OC_PD (0x1<<13) +#define SPK_CLASS_AB_OC_DET (0x1<<12) +#define HP_DEPOP_MODE3_EN (0x1<<10) +#define HP_DEPOP_MODE2_EN (0x1<<9) +#define HP_DEPOP_MODE1_EN (0x1<<8) +#define AUXOUT_DEPOP_MODE3_EN (0x1<<6) +#define AUXOUT_DEPOP_MODE2_EN (0x1<<5) +#define AUXOUT_DEPOP_MODE1_EN (0x1<<4) +#define M_DAC_L_INPUT (0x1<<3) +#define M_DAC_R_INPUT (0x1<<2) +#define IRQOUT_INV_CTRL (0x1<<0) + +//Psedueo Stereo & Spatial Effect Block Control(0x60) +#define SPATIAL_CTRL_EN (0x1<<15) +#define ALL_PASS_FILTER_EN (0x1<<14) +#define PSEUDO_STEREO_EN (0x1<<13) +#define STEREO_EXPENSION_EN (0x1<<12) + +#define GAIN_3D_PARA_L_MASK (0x7<<9) +#define GAIN_3D_PARA_L_1_00 (0x0<<9) +#define GAIN_3D_PARA_L_1_25 (0x1<<9) +#define GAIN_3D_PARA_L_1_50 (0x2<<9) +#define GAIN_3D_PARA_L_1_75 (0x3<<9) +#define GAIN_3D_PARA_L_2_00 (0x4<<9) + +#define GAIN_3D_PARA_R_MASK (0x7<<6) +#define GAIN_3D_PARA_R_1_00 (0x0<<6) +#define GAIN_3D_PARA_R_1_25 (0x1<<6) +#define GAIN_3D_PARA_R_1_50 (0x2<<6) +#define GAIN_3D_PARA_R_1_75 (0x3<<6) +#define GAIN_3D_PARA_R_2_00 (0x4<<6) + +#define RATIO_3D_L_MASK (0x3<<4) +#define RATIO_3D_L_0_0 (0x0<<4) +#define RATIO_3D_L_0_66 (0x1<<4) +#define RATIO_3D_L_1_0 (0x2<<4) + +#define RATIO_3D_R_MASK (0x3<<2) +#define RATIO_3D_R_0_0 (0x0<<2) +#define RATIO_3D_R_0_66 (0x1<<2) +#define RATIO_3D_R_1_0 (0x2<<2) + +#define APF_MASK (0x3) +#define APF_FOR_48K (0x3) +#define APF_FOR_44_1K (0x2) +#define APF_FOR_32K (0x1) + +//EQ CONTROL(0x62) + +#define EN_HW_EQ_BLK (0x1<<15) //HW EQ block control +#define EN_HW_EQ_HPF_MODE (0x1<<14) //High Frequency shelving filter mode +#define EN_HW_EQ_SOUR (0x1<<11) //0:DAC PATH,1:ADC PATH +#define EN_HW_EQ_HPF (0x1<<4) //EQ High Pass Filter Control +#define EN_HW_EQ_BP3 (0x1<<3) //EQ Band-3 Control +#define EN_HW_EQ_BP2 (0x1<<2) //EQ Band-2 Control +#define EN_HW_EQ_BP1 (0x1<<1) //EQ Band-1 Control +#define EN_HW_EQ_LPF (0x1<<0) //EQ Low Pass Filter Control + +//EQ Mode Change Enable(0x66) +#define EQ_HPF_CHANGE_EN (0x1<<4) //EQ High Pass Filter Mode Change Enable +#define EQ_BP3_CHANGE_EN (0x1<<3) //EQ Band-3 Pass Filter Mode Change Enable +#define EQ_BP2_CHANGE_EN (0x1<<2) //EQ Band-2 Pass Filter Mode Change Enable +#define EQ_BP1_CHANGE_EN (0x1<<1) //EQ Band-1 Pass Filter Mode Change Enable +#define EQ_LPF_CHANGE_EN (0x1<<0) //EQ Low Pass Filter Mode Change Enable + + +//AVC Control(0x68) +#define AVC_ENABLE (0x1<<15) +#define AVC_TARTGET_SEL_MASK (0x1<<14) +#define AVC_TARTGET_SEL_R (0x1<<14) +#define AVC_TARTGET_SEL_L (0x0<<14) + + +struct rt5623_setup_data { + unsigned short i2c_address; + int mic2_input; +}; + + +#define RT5623_PLL_FR_MCLK 0 +#define RT5623_PLL_FR_BCK 1 + +//WaveOut channel for realtek codec +enum +{ + RT_WAVOUT_SPK =(0x1<<0), + RT_WAVOUT_SPK_R =(0x1<<1), + RT_WAVOUT_SPK_L =(0x1<<2), + RT_WAVOUT_HP =(0x1<<3), + RT_WAVOUT_HP_R =(0x1<<4), + RT_WAVOUT_HP_L =(0x1<<5), + RT_WAVOUT_MONO =(0x1<<6), + RT_WAVOUT_AUXOUT =(0x1<<7), + RT_WAVOUT_AUXOUT_R =(0x1<<8), + RT_WAVOUT_AUXOUT_L =(0x1<<9), + RT_WAVOUT_LINEOUT =(0x1<<10), + RT_WAVOUT_LINEOUT_R =(0x1<<11), + RT_WAVOUT_LINEOUT_L =(0x1<<12), + RT_WAVOUT_DAC =(0x1<<13), + RT_WAVOUT_ALL_ON =(0x1<<14), +}; + +//WaveIn channel for realtek codec +enum +{ + RT_WAVIN_R_MONO_MIXER =(0x1<<0), + RT_WAVIN_R_SPK_MIXER =(0x1<<1), + RT_WAVIN_R_HP_MIXER =(0x1<<2), + RT_WAVIN_R_PHONE =(0x1<<3), + RT_WAVIN_R_AUXIN =(0x1<<3), + RT_WAVIN_R_LINE_IN =(0x1<<4), + RT_WAVIN_R_MIC2 =(0x1<<5), + RT_WAVIN_R_MIC1 =(0x1<<6), + + RT_WAVIN_L_MONO_MIXER =(0x1<<8), + RT_WAVIN_L_SPK_MIXER =(0x1<<9), + RT_WAVIN_L_HP_MIXER =(0x1<<10), + RT_WAVIN_L_PHONE =(0x1<<11), + RT_WAVIN_L_AUXIN =(0x1<<11), + RT_WAVIN_L_LINE_IN =(0x1<<12), + RT_WAVIN_L_MIC2 =(0x1<<13), + RT_WAVIN_L_MIC1 =(0x1<<14), +}; + +enum +{ + POWER_STATE_D0=0, + POWER_STATE_D1, + POWER_STATE_D1_PLAYBACK, + POWER_STATE_D1_RECORD, + POWER_STATE_D2, + POWER_STATE_D2_PLAYBACK, + POWER_STATE_D2_RECORD, + POWER_STATE_D3, + POWER_STATE_D4 + +}; + + +extern struct snd_soc_dai rt5623_dai; +extern struct snd_soc_codec_device soc_codec_dev_rt5623; + +#endif --- linux-mvl-dove-2.6.32.orig/sound/soc/codecs/wm8350.c +++ linux-mvl-dove-2.6.32/sound/soc/codecs/wm8350.c @@ -423,8 +423,8 @@ SOC_ENUM_SINGLE(WM8350_INPUT_MIXER_VOLUME, 15, 2, wm8350_lr), }; -static DECLARE_TLV_DB_LINEAR(pre_amp_tlv, -1200, 3525); -static DECLARE_TLV_DB_LINEAR(out_pga_tlv, -5700, 600); +static DECLARE_TLV_DB_SCALE(pre_amp_tlv, -1200, 3525, 0); +static DECLARE_TLV_DB_SCALE(out_pga_tlv, -5700, 600, 0); static DECLARE_TLV_DB_SCALE(dac_pcm_tlv, -7163, 36, 1); static DECLARE_TLV_DB_SCALE(adc_pcm_tlv, -12700, 50, 1); static DECLARE_TLV_DB_SCALE(out_mix_tlv, -1500, 300, 1); @@ -925,7 +925,7 @@ iface |= 0x3 << 8; break; case SND_SOC_DAIFMT_DSP_B: - iface |= 0x3 << 8; /* lg not sure which mode */ + iface |= 0x3 << 8 | WM8350_AIF_LRCLK_INV; break; default: return -EINVAL; --- linux-mvl-dove-2.6.32.orig/sound/soc/codecs/wm9712.c +++ linux-mvl-dove-2.6.32/sound/soc/codecs/wm9712.c @@ -464,7 +464,8 @@ { u16 *cache = codec->reg_cache; - soc_ac97_ops.write(codec->ac97, reg, val); + if (reg < 0x7c) + soc_ac97_ops.write(codec->ac97, reg, val); reg = reg >> 1; if (reg < (ARRAY_SIZE(wm9712_reg))) cache[reg] = val; --- linux-mvl-dove-2.6.32.orig/sound/soc/codecs/wm8903.c +++ linux-mvl-dove-2.6.32/sound/soc/codecs/wm8903.c @@ -1506,7 +1506,7 @@ struct i2c_client *i2c = codec->control_data; int i; u16 *reg_cache = codec->reg_cache; - u16 *tmp_cache = kmemdup(codec->reg_cache, sizeof(wm8903_reg_defaults), + u16 *tmp_cache = kmemdup(reg_cache, sizeof(wm8903_reg_defaults), GFP_KERNEL); /* Bring the codec back up to standby first to minimise pop/clicks */ @@ -1518,6 +1518,7 @@ for (i = 2; i < ARRAY_SIZE(wm8903_reg_defaults); i++) if (tmp_cache[i] != reg_cache[i]) snd_soc_write(codec, i, tmp_cache[i]); + kfree(tmp_cache); } else { dev_err(&i2c->dev, "Failed to allocate temporary cache\n"); } --- linux-mvl-dove-2.6.32.orig/sound/soc/codecs/rt655.c +++ linux-mvl-dove-2.6.32/sound/soc/codecs/rt655.c @@ -0,0 +1,497 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "rt655.h" + +#define RT655_VERSION "0.2" +//#define RT655_DEBUG 1 +#if defined(RT655_DEBUG) +#define DBG(format, arg...) \ + printk(KERN_DEBUG format "\n", ## arg) +#else +#define DBG(format, arg...) do {} while(0) +#endif + +#define rt655_write_mask(c, reg, value, mask) snd_soc_update_bits(c, reg, mask, value) +static const u16 rt655_reg[] = { + 0x0000, 0x8000, 0x0000, 0x8000,//0 + 0x0000, 0x8000, 0x8008, 0x8008, + 0x8808, 0x8808, 0x0000, 0x8808,//1 + 0x8808, 0x0000, 0x8000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x000f,//2 + 0x09c4, 0x05f0, 0xbb80, 0xbb80, + 0xbb80, 0xbb80, 0x0000, 0x8080,//3 + 0x8080, 0x2000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000,//4 + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000,//5 + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0808, 0x0808,//6 + 0x0AEA, 0x0040, 0x0000, 0x0004, + 0x0000, 0x0000, 0x0000, 0x0000,//7 + 0x0000, 0x60a2, 0x414c, 0x4760, +}; +static unsigned int rt655_read(struct snd_soc_codec *codec, + unsigned int reg); +static int rt655_write(struct snd_soc_codec *codec, + unsigned int reg, unsigned int val); +static int rt655_write_page(struct snd_soc_codec *codec, + unsigned int reg, unsigned int val, int page_id); +static int rt655_read_page(struct snd_soc_codec *codec, + unsigned int reg, int page_id); +static int rt655_write_page_mask(struct snd_soc_codec *codec, + unsigned int reg, unsigned int val, unsigned int mask, int page_id); +int rt655_reset(struct snd_soc_codec *codec, int try_warm); + + +static int rt655_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai); +static int rt655_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *codec_dai); +static int rt655_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai); + +static int rt655_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level); +static int rt655_soc_probe(struct platform_device *pdev); +static int rt655_soc_remove(struct platform_device *pdev); +static int rt655_soc_suspend(struct platform_device *pdev); +static int rt655_soc_resume(struct platform_device *pdev); + +static int rt655_channels = 6; + + +u16 Set_Codec_Reg_Init[][2]={ + {RT655_REC_SEL ,0x0101}, //default reocrd source from Mic + {RT655_FRONT_DAC_VOL ,0x0808}, //set Front DAC to 0DB and unmute + {RT655_SUR_DAC_VOL ,0x0808}, //set Surround DAC to 0DB and unmute + {RT655_CEN_LFE_DAC_VOL ,0x0808}, //set Center/LFE DAC to 0DB and unmute + {RT655_MASTER_VOL ,0x8000}, //front channel mute by default + {RT655_SUR_VOL ,0x8080}, //surround channel mute by default + {RT655_CEN_LFE_VOL ,0x8080}, //Cent/LFE channel mute by default +}; + + +static int rt655_init_reg(struct snd_soc_codec *codec) +{ + int i; + + DBG("enter %s", __func__); + for(i=0;iac97, reg); +} + +static int rt655_write(struct snd_soc_codec *codec, + unsigned int reg, unsigned int val) +{ + u16 *cache = codec->reg_cache; + + soc_ac97_ops.write(codec->ac97, reg, val); + reg = reg >> 1; + if (reg < (ARRAY_SIZE(rt655_reg))) + cache[reg] = val; + + return 0; +} + +static int rt655_read_page(struct snd_soc_codec *codec, + unsigned int reg, int page_id) +{ + rt655_write_mask(codec, 0x24, page_id, 0x000f); + return rt655_read(codec, reg); +} + +static int rt655_write_page(struct snd_soc_codec *codec, + unsigned int reg, unsigned int val, int page_id) +{ + rt655_write_mask(codec, 0x24, page_id, 0x000f); + return rt655_write(codec, reg, val); +} + +static int rt655_write_page_mask(struct snd_soc_codec *codec, + unsigned int reg, unsigned int val, unsigned int mask, int page_id) +{ + int change; + unsigned int old, new; + + old = rt655_read_page(codec, reg, page_id); + new = (old & ~mask) | val; + change = old != new; + if (change) + rt655_write_page(codec, reg, val, page_id); + + return change; +} + + +int rt655_reset(struct snd_soc_codec *codec, int try_warm) +{ + + DBG("enter %s", __func__); + if (try_warm && soc_ac97_ops.warm_reset) { + soc_ac97_ops.warm_reset(codec->ac97); + if (codec->read(codec,0x7c) == 0x414c) + return 1; + } + + soc_ac97_ops.reset(codec->ac97); + if (codec->read(codec, 0x7c) != 0x414c) + return -EIO; + return 0; +} + +EXPORT_SYMBOL_GPL(rt655_reset); + +struct snd_soc_codec_device soc_codec_dev_rt655 = { + .probe = rt655_soc_probe, + .remove = rt655_soc_remove, + .suspend = rt655_soc_suspend, + .resume = rt655_soc_resume, +}; +EXPORT_SYMBOL_GPL(soc_codec_dev_rt655); + + +#define RT655_HIFI_FORMAT SNDRV_PCM_FMTBIT_S16_LE +//ALC655 only support 48k +#define RT655_HIFI_RATES SNDRV_PCM_RATE_48000 + +static struct snd_soc_dai_ops rt655_dai_ops = { + .prepare = rt655_prepare, + .hw_params = rt655_hw_params, + .shutdown = rt655_shutdown, +}; +struct snd_soc_dai rt655_dai = { + .name = "RT655", + .playback = { + .stream_name = "Hifi Playback", + .channels_min = 1, + .channels_max = 6, + .rates= RT655_HIFI_RATES, + .formats = RT655_HIFI_FORMAT, + }, + .capture = { + .stream_name = "Hifi Capture", + .channels_min = 1, + .channels_max = 2, + .rates = RT655_HIFI_RATES, + .formats = RT655_HIFI_FORMAT, + }, + .ops = &rt655_dai_ops, +}; +EXPORT_SYMBOL_GPL(rt655_dai); +static const char *rt655_record_source[] = {"Mic", "CD", "Mute", "AUX", + "Line", "Stereo Mixer", "Mono Mixer","Phone"}; +static const struct soc_enum rt655_record_enum = SOC_ENUM_DOUBLE(RT655_REC_SEL, 8, 0, 8, rt655_record_source); +static const struct snd_kcontrol_new rt655_snd_ac97_controls[] = { +SOC_DOUBLE("Front Playback Switch", RT655_MASTER_VOL, 15, 7, 1, 1), +SOC_DOUBLE("Front Playback Volume", RT655_MASTER_VOL, 8, 0, 31, 1), +SOC_DOUBLE("SURR Playback Volume", RT655_SUR_VOL, 8, 0, 31, 1), +SOC_DOUBLE("SURR Playback Switch", RT655_SUR_VOL, 15, 7, 1, 1), +SOC_DOUBLE("CEN_LFE Playback Volume", RT655_CEN_LFE_VOL, 8, 0, 31, 1), +SOC_DOUBLE("CEN_LFE Playback Switch", RT655_CEN_LFE_VOL, 15, 7, 1, 1), +SOC_DOUBLE("Front DAC Playback Volume", RT655_FRONT_DAC_VOL, 8, 0, 31, 1), +SOC_DOUBLE("Front DAC Playback Switch", RT655_FRONT_DAC_VOL, 15, 7, 1, 1), +SOC_DOUBLE("SURR DAC Playback Volume", RT655_SUR_DAC_VOL, 8, 0, 31, 1), +SOC_DOUBLE("SURR DAC Playback Switch", RT655_SUR_DAC_VOL, 15, 7, 1, 1), +SOC_DOUBLE("CEN_LFE DAC Playback Volume", RT655_CEN_LFE_DAC_VOL, 8, 0, 31, 1), +SOC_DOUBLE("CEN_LFE DAC Playback Switch", RT655_CEN_LFE_DAC_VOL, 15, 7, 1, 1), +SOC_SINGLE("Mono Playback Switch", RT655_MONO_OUT_VOL, 15, 1, 1), +SOC_SINGLE("Mono Playback Volume", RT655_MONO_OUT_VOL, 0, 31, 1), +SOC_SINGLE("PC BEEP Playback Volume", RT655_PCBEEP_VOL, 1, 15, 1), +SOC_SINGLE("PC BEEP Playback Switch", RT655_PCBEEP_VOL, 15, 1, 1), +SOC_SINGLE("Phone Capture Volume", RT655_PHONE_VOL, 0, 31, 1), +SOC_SINGLE("Phone Capture Switch", RT655_PHONE_VOL, 15, 1, 1), +SOC_SINGLE("Mic Capture Volume", RT655_MIC_VOL, 0, 31, 1), +SOC_SINGLE("Mic Capture Switch", RT655_MIC_VOL, 15, 1, 1), +SOC_DOUBLE("Line Capture Switch", RT655_LINEIN_VOL, 15, 7, 1, 1), +SOC_DOUBLE("Line Capture Volume", RT655_LINEIN_VOL, 8, 0, 31, 1), +SOC_DOUBLE("CD Capture Switch", RT655_CD_VOL, 15, 7, 1, 1), +SOC_DOUBLE("CD Capture Volume", RT655_CD_VOL, 8, 0, 31, 1), +SOC_DOUBLE("AUX Capture Switch", RT655_AUX_VOL, 15, 7, 1, 1), +SOC_DOUBLE("AUX Capture Volume", RT655_AUX_VOL, 8, 0, 31, 1), +SOC_SINGLE("Record Gain Capture Switch", RT655_REC_GAIN, 15, 1, 1), +SOC_DOUBLE("Record Gain Capture Volume", RT655_REC_GAIN, 8, 0, 15, 0), +SOC_ENUM("Record Capture Switch", rt655_record_enum), +}; +static int rt655_soc_probe(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->card->codec; + int ret; + + printk(KERN_INFO "rt655 soc codec, version is %s\n", RT655_VERSION); + socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); + if (socdev->card->codec == NULL) + return -ENOMEM; + codec = socdev->card->codec; + mutex_init(&codec->mutex); + + codec->reg_cache = kmemdup(rt655_reg, sizeof(rt655_reg), GFP_KERNEL); + if (codec->reg_cache == NULL) { + ret = -ENOMEM; + goto cache_err; + } + codec->reg_cache_size = ARRAY_SIZE(rt655_reg) * 2; + codec->reg_cache_step = 2; +/* + codec->private_data = kzalloc(sizeof(struct rt655_priv), GFP_KERNEL); + if (codec->private_data == NULL) { + ret = -ENOMEM; + goto priv_err; + } +*/ + codec->name = "rt655"; + codec->owner = THIS_MODULE; + codec->dai = &rt655_dai; + codec->num_dai = 1; + codec->read = rt655_read; + codec->write = rt655_write; + codec->set_bias_level = rt655_set_bias_level; + INIT_LIST_HEAD(&codec->dapm_widgets); + INIT_LIST_HEAD(&codec->dapm_paths); + + ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0); + if (ret < 0) { + printk(KERN_ERR "rt655: failed to register ac97 codec\n"); + goto codec_err; + } + + ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); + if (ret < 0) + goto pcm_err; + + ret = rt655_reset(codec, 0); + if (ret < 0) { + printk(KERN_ERR "FAIL to reset rt655\n"); + goto reset_err; + } + + rt655_write(codec, 0x26, 0x0000); + rt655_init_reg(codec); //initize some register + rt655_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + + snd_soc_add_controls(codec, rt655_snd_ac97_controls, + ARRAY_SIZE(rt655_snd_ac97_controls)); + ret = snd_soc_init_card(socdev); + if (ret < 0) { + printk(KERN_ERR "rt655: failed to register card\n"); + goto reset_err; + } + return 0; +reset_err: + snd_soc_free_pcms(socdev); + +pcm_err: + snd_soc_free_ac97_codec(codec); + +codec_err: + kfree(codec->reg_cache); + +cache_err: + kfree(socdev->card->codec); + socdev->card->codec = NULL; + return ret; +} + +static int rt655_soc_remove(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->card->codec; + + DBG("enter %s", __func__); + if (codec == NULL) + return 0; + + snd_soc_dapm_free(socdev); + snd_soc_free_pcms(socdev); + snd_soc_free_ac97_codec(codec); + kfree(codec->reg_cache); + kfree(codec); + return 0; +} + +static int rt655_soc_suspend(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->card->codec; + + DBG("enter %s", __func__); + rt655_set_bias_level(codec, SND_SOC_BIAS_OFF); + return 0; +} + +static int rt655_soc_resume(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->card->codec; + int i, ret; + u16 *cache = codec->reg_cache; + + DBG("enter %s", __func__); + ret = rt655_reset(codec, 1); + if (ret < 0) { + printk(KERN_ERR "could not reset AC97 codec\n"); + return ret; + } + + rt655_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + + if (ret == 0) { + /* Sync reg_cache with the hardware after cold reset */ + for (i = 2; i < ARRAY_SIZE(rt655_reg) << 1; i += 2) { + if (i == 0x26) + continue; + soc_ac97_ops.write(codec->ac97, i, cache[i>>1]); + } + } + + if (codec->suspend_bias_level == SND_SOC_BIAS_ON) + rt655_set_bias_level(codec, SND_SOC_BIAS_ON); + + return ret; +} + +static int rt655_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; +#if 0 + switch (params_channels(params)) { + case 2: + + rt655_channels=2; + rt655_write_mask(codec,RT655_MULT_CHAN_CTRL,0x0000,0x0030); + + break; + + case 4: + + rt655_channels=4; + rt655_write_mask(codec,RT655_MULT_CHAN_CTRL,0x0010,0x0030); + + break; + + case 6: + + rt655_channels=6; + rt655_write_mask(codec,RT655_MULT_CHAN_CTRL,0x0030,0x0030); + + break; + + } +#else + rt655_channels=6; + rt655_write_mask(codec,RT655_MULT_CHAN_CTRL,0x0030,0x0030); + +#endif + return 0; +} + + +static int rt655_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + int stream; + + DBG("enter %s", __func__); + + stream = substream->stream; + switch(stream) { + case SNDRV_PCM_STREAM_PLAYBACK: + + switch (rt655_channels) { + case 2: + + rt655_write_mask(codec, RT655_SUR_VOL , 0x8080, 0x8080); + rt655_write_mask(codec, RT655_CEN_LFE_VOL, 0x8080, 0x8080); + rt655_write_mask(codec, RT655_MASTER_VOL , 0x0000, 0x8000); + + break; + + case 4: + + rt655_write_mask(codec, RT655_CEN_LFE_VOL, 0x8080, 0x8080); + rt655_write_mask(codec, RT655_SUR_VOL , 0x0000, 0x8080); + rt655_write_mask(codec, RT655_MASTER_VOL , 0x0000, 0x8000); + + break; + + case 6: + + rt655_write_mask(codec, RT655_SUR_VOL , 0x0000, 0x8080); + rt655_write_mask(codec, RT655_CEN_LFE_VOL, 0x0000, 0x8080); + rt655_write_mask(codec, RT655_MASTER_VOL , 0x0000, 0x8000); + + break; + } + + break; + + case SNDRV_PCM_STREAM_CAPTURE: + + break; + } + return 0; +} +static int rt655_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *codec_dai) +{ + struct snd_soc_codec *codec = codec_dai->codec; + int stream; + + DBG("enter %s", __func__); + + stream = substream->stream; + switch(stream) { + case SNDRV_PCM_STREAM_PLAYBACK: + //mute all output + rt655_write_mask(codec, RT655_SUR_VOL , 0x8080, 0x8080); + rt655_write_mask(codec, RT655_CEN_LFE_VOL, 0x8080, 0x8080); + rt655_write_mask(codec, RT655_MASTER_VOL , 0x8000, 0x8000); + break; + case SNDRV_PCM_STREAM_CAPTURE: + break; + + } + return 0; +} + +static int rt655_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + DBG("enter %s", __func__); + + switch (level) { + case SND_SOC_BIAS_ON: + case SND_SOC_BIAS_PREPARE: + break; + case SND_SOC_BIAS_STANDBY: + rt655_write(codec, 0x26, 0x0000); + break; + case SND_SOC_BIAS_OFF: + rt655_write(codec, 0x26, 0xffff); + break; + } + return 0; +} +MODULE_DESCRIPTION("ASoC RT655 driver"); +MODULE_AUTHOR("rory_yin@realsil.com.cn"); +MODULE_LICENSE("GPL"); --- linux-mvl-dove-2.6.32.orig/sound/soc/codecs/wm8776.c +++ linux-mvl-dove-2.6.32/sound/soc/codecs/wm8776.c @@ -93,7 +93,6 @@ static const struct snd_soc_dapm_widget wm8776_dapm_widgets[] = { SND_SOC_DAPM_INPUT("AUX"), -SND_SOC_DAPM_INPUT("AUX"), SND_SOC_DAPM_INPUT("AIN1"), SND_SOC_DAPM_INPUT("AIN2"), @@ -178,13 +177,6 @@ case SND_SOC_DAIFMT_LEFT_J: iface |= 0x0001; break; - /* FIXME: CHECK A/B */ - case SND_SOC_DAIFMT_DSP_A: - iface |= 0x0003; - break; - case SND_SOC_DAIFMT_DSP_B: - iface |= 0x0007; - break; default: return -EINVAL; } --- linux-mvl-dove-2.6.32.orig/sound/soc/codecs/rt5610.h +++ linux-mvl-dove-2.6.32/sound/soc/codecs/rt5610.h @@ -0,0 +1,414 @@ +#ifndef _RT5610_H +#define _RT5610_H + + +//Index of Codec Register definition +#define RT5610_RESET 0X00 //RESET CODEC TO DEFAULT +#define RT5610_SPK_OUT_VOL 0X02 //SPEAKER OUT VOLUME +#define RT5610_HP_OUT_VOL 0X04 //HEADPHONE OUTPUT VOLUME +#define RT5610_PHONEIN_MONO_OUT_VOL 0X08 //PHONE INPUT/MONO OUTPUT VOLUME +#define RT5610_LINE_IN_VOL 0X0A //LINE IN VOLUME +#define RT5610_STEREO_DAC_VOL 0X0C //STEREO DAC VOLUME +#define RT5610_MIC_VOL 0X0E //MICROPHONE VOLUME +#define RT5610_MIC_ROUTING_CTRL 0X10 //MIC ROUTING CONTROL +#define RT5610_ADC_REC_GAIN 0X12 //ADC RECORD GAIN +#define RT5610_ADC_REC_MIXER 0X14 //ADC RECORD MIXER CONTROL +#define RT5610_VOICE_DAC_OUT_VOL 0X18 //VOICE DAC OUTPUT VOLUME +#define RT5610_OUTPUT_MIXER_CTRL 0X1C //OUTPUT MIXER CONTROL +#define RT5610_MIC_CTRL 0X22 //MICROPHONE CONTROL +#define RT5610_PD_CTRL_STAT 0X26 //POWER DOWN CONTROL/STATUS +#define RT5610_TONE_CTRL 0x2a //tone control +#define RT5610_DAC_DPE_RATE 0x2c //ac97's dac/dpe rate +#define RT5610_ADC_RATE 0x32 //ac97's adc rate +//#define RT5610_MAIN_SDP_CTRL 0X34 //MAIN SERIAL DATA PORT CONTROL(STEREO I2S) + +#define RT5610_EXTEND_SDP_CTRL 0X36 //EXTEND SERIAL DATA PORT CONTROL(VOICE I2S/PCM) +#define RT5610_PWR_MANAG_ADD1 0X3A //POWER MANAGMENT ADDITION 1 +#define RT5610_PWR_MANAG_ADD2 0X3C //POWER MANAGMENT ADDITION 2 +#define RT5610_PWR_MANAG_ADD3 0X3E //POWER MANAGMENT ADDITION 3 +#define RT5610_GEN_CTRL_REG1 0X40 //GENERAL PURPOSE CONTROL REGISTER 1 +#define RT5610_GEN_CTRL_REG2 0X42 //GENERAL PURPOSE CONTROL REGISTER 2 +#define RT5610_PLL_CTRL 0X44 //PLL CONTROL +#define RT5610_GPIO_PIN_CONFIG 0X4C //GPIO PIN CONFIGURATION +#define RT5610_GPIO_PIN_POLARITY 0X4E //GPIO PIN POLARITY +#define RT5610_GPIO_PIN_STICKY 0X50 //GPIO PIN STICKY +#define RT5610_GPIO_PIN_WAKEUP 0X52 //GPIO PIN WAKE UP +#define RT5610_GPIO_PIN_STATUS 0X54 //GPIO PIN STATUS +#define RT5610_GPIO_PIN_SHARING 0X56 //GPIO PIN SHARING +#define RT5610_OVER_TEMP_CURR_STATUS 0X58 //OVER TEMPERATURE AND CURRENT STATUS +#define RT5610_GPIO_OUT_CTRL 0X5C //GPIO OUTPUT PIN CONTRL +#define RT5610_MISC_CTRL 0X5E //MISC CONTROL +//#define RT5610_STEREO_DAC_CLK_CTRL1 0X60 //STEREO DAC CLOCK CONTROL 1 +//#define RT5610_STEREO_DAC_CLK_CTRL2 0X62 //STEREO DAC CLOCK CONTROL 2 +#define RT5610_VOICE_DAC_PCMCLK_CTRL1 0X64 //VOICE/PCM DAC CLOCK CONTROL 1 +#define RT5610_VOICE_DAC_PCMCLK_CTRL2 0X66 //VOICE/PCM DAC CLOCK CONTROL 2 +#define RT5610_PSEDUEO_SPATIAL_CTRL 0X68 //PSEDUEO STEREO /SPATIAL EFFECT BLOCK CONTROL +#define RT5610_INDEX_ADDRESS 0X6A //INDEX ADDRESS +#define RT5610_INDEX_DATA 0X6C //INDEX DATA +#define RT5610_EQ_STATUS 0X6E //EQ STATUS +#define RT5610_TOUCH_PANEL_STATUS 0x78 //touche panel indiction +#define RT5610_VENDOR_ID1 0x7C //VENDOR ID1 +#define RT5610_VENDOR_ID2 0x7E //VENDOR ID2 + + +//************************************************************************************************* +//Bit define of Codec Register +//************************************************************************************************* +//global definition +#define RT_L_MUTE (0x1<<15) //Mute Left Control +#define RT_L_ZC (0x1<<14) //Mute Left Zero-Cross Detector Control +#define RT_R_MUTE (0x1<<7) //Mute Right Control +#define RT_R_ZC (0x1<<6) //Mute Right Zero-Cross Detector Control +#define RT_M_HP_MIXER (0x1<<15) //Mute source to HP Mixer +#define RT_M_SPK_MIXER (0x1<<14) //Mute source to Speaker Mixer +#define RT_M_MONO_MIXER (0x1<<13) //Mute source to Mono Mixer + +//Phone Input/MONO Output Volume(0x08) +#define M_PHONEIN_TO_HP_MIXER (0x1<<15) //Mute Phone In volume to HP mixer +#define M_PHONEIN_TO_SPK_MIXER (0x1<<14) //Mute Phone In volume to speaker mixer +#define M_MONO_OUT_VOL (0x1<<7) //Mute Mono output volume + + +//Mic Routing Control(0x10) +#define M_MIC1_TO_HP_MIXER (0x1<<15) //Mute MIC1 to HP mixer +#define M_MIC1_TO_SPK_MIXER (0x1<<14) //Mute MiC1 to SPK mixer +#define M_MIC1_TO_MONO_MIXER (0x1<<13) //Mute MIC1 to MONO mixer +#define MIC1_DIFF_INPUT_CTRL (0x1<<12) //MIC1 different input control +#define M_MIC2_TO_HP_MIXER (0x1<<7) //Mute MIC2 to HP mixer +#define M_MIC2_TO_SPK_MIXER (0x1<<6) //Mute MiC2 to SPK mixer +#define M_MIC2_TO_MONO_MIXER (0x1<<5) //Mute MIC2 to MONO mixer +#define MIC2_DIFF_INPUT_CTRL (0x1<<4) //MIC2 different input control + +//ADC Record Gain(0x12) +#define M_ADC_L_TO_HP_MIXER (0x1<<15) //Mute left of ADC to HP Mixer +#define M_ADC_R_TO_HP_MIXER (0x1<<14) //Mute right of ADC to HP Mixer +#define M_ADC_L_TO_MONO_MIXER (0x1<<13) //Mute left of ADC to MONO Mixer +#define M_ADC_R_TO_MONO_MIXER (0x1<<12) //Mute right of ADC to MONO Mixer +#define ADC_L_GAIN_MASK (0x1f<<7) //ADC Record Gain Left channel Mask +#define ADC_L_ZC_DET (0x1<<6) //ADC Zero-Cross Detector Control +#define ADC_R_ZC_DET (0x1<<5) //ADC Zero-Cross Detector Control +#define ADC_R_GAIN_MASK (0x1f<<0) //ADC Record Gain Right channel Mask + +//Voice DAC Output Volume(0x18) +#define M_V_DAC_TO_HP_MIXER (0x1<<15) +#define M_V_DAC_TO_SPK_MIXER (0x1<<14) +#define M_V_DAC_TO_MONO_MIXER (0x1<<13) + +//Output Mixer Control(0x1C) +#define SPKL_INPUT_SEL_MASK (0x3<<14) +#define SPKL_INPUT_SEL_MONO (0x3<<14) +#define SPKL_INPUT_SEL_SPK (0x2<<14) +#define SPKL_INPUT_SEL_HPL (0x1<<14) +#define SPKL_INPUT_SEL_VMID (0x0<<14) + +#define SPK_OUT_SEL_CLASS_D (0x1<<13) +#define SPK_OUT_SEL_CLASS_AB (0x0<<13) + +#define SPKR_INPUT_SEL_MASK (0x3<<11) +#define SPKR_INPUT_SEL_MONO_MIXER (0x3<<11) +#define SPKR_INPUT_SEL_SPK_MIXER (0x2<<11) +#define SPKR_INPUT_SEL_HPR_MIXER (0x1<<11) +#define SPKR_INPUT_SEL_VMID (0x0<<11) + +#define HPL_INPUT_SEL_HPL_MIXER (0x1<<9) +#define HPR_INPUT_SEL_HPR_MIXER (0x1<<8) + +#define MONO_INPUT_SEL_MASK (0x3<<6) +#define MONO_INPUT_SEL_MONO_MIXER (0x3<<6) +#define MONO_INPUT_SEL_SPK_MIXER (0x2<<6) +#define MONO_INPUT_SEL_HP_MIXER (0x1<<6) +#define MONO_INPUT_SEL_VMID (0x0<<6) + +//Micphone Control define(0x22) +#define MIC1 1 +#define MIC2 2 +#define MIC_BIAS_90_PRECNET_AVDD 1 +#define MIC_BIAS_75_PRECNET_AVDD 2 + +#define MIC1_BOOST_CONTROL_MASK (0x3<<10) +#define MIC1_BOOST_CONTROL_BYPASS (0x0<<10) +#define MIC1_BOOST_CONTROL_20DB (0x1<<10) +#define MIC1_BOOST_CONTROL_30DB (0x2<<10) +#define MIC1_BOOST_CONTROL_40DB (0x3<<10) + +#define MIC2_BOOST_CONTROL_MASK (0x3<<8) +#define MIC2_BOOST_CONTROL_BYPASS (0x0<<8) +#define MIC2_BOOST_CONTROL_20DB (0x1<<8) +#define MIC2_BOOST_CONTROL_30DB (0x2<<8) +#define MIC2_BOOST_CONTROL_40DB (0x3<<8) + +#define MIC1_BIAS_VOLT_CTRL_MASK (0x1<<5) +#define MIC1_BIAS_VOLT_CTRL_90P (0x0<<5) +#define MIC1_BIAS_VOLT_CTRL_75P (0x1<<5) + +#define MIC2_BIAS_VOLT_CTRL_MASK (0x1<<4) +#define MIC2_BIAS_VOLT_CTRL_90P (0x0<<4) +#define MIC2_BIAS_VOLT_CTRL_75P (0x1<<4) + +//PowerDown control of register(0x26) +//power management bits +#define RT_PWR_PR7 (0x1<<15) //write this bit to power down the Speaker Amplifier +#define RT_PWR_PR6 (0x1<<14) //write this bit to power down the Headphone Out and MonoOut +#define RT_PWR_PR5 (0x1<<13) //write this bit to power down the internal clock(without PLL) +#define RT_PWR_PR3 (0x1<<11) //write this bit to power down the mixer(vref/vrefout out off) +#define RT_PWR_PR2 (0x1<<10) //write this bit to power down the mixer(vref/vrefout still on) +#define RT_PWR_PR1 (0x1<<9) //write this bit to power down the dac +#define RT_PWR_PR0 (0x1<<8) //write this bit to power down the adc +#define RT_PWR_REF (0x1<<3) //read only +#define RT_PWR_ANL (0x1<<2) //read only +#define RT_PWR_DAC (0x1<<1) //read only +#define RT_PWR_ADC (0x1) //read only + + + + +//Extend Serial Data Port Control(0x36) +#define EXT_I2S_FUNC_ENABLE (0x1<<15) //Enable PCM interface on GPIO 1,3,4,5 0:GPIO function,1:Voice PCM interface +#define EXT_I2S_MODE_SEL (0x1<<14) //0:Master ,1:Slave +#define EXT_I2S_VOICE_ADC_EN (0x1<<8) //ADC_L=Stereo, ADC_R=Voice +#define EXT_I2S_BCLK_POLARITY (0x1<<7) //0:Normal 1:Invert +#define EXT_I2S_PCM_MODE (0x1<<6) //PCM 0:mode A ,1:mode B + //Non PCM 0:Normal SADLRCK/SDALRCK,1:Invert SADLRCK/SDALRCK +//Data Length Slection +#define EXT_I2S_DL_MASK (0x3<<2) //Extend i2s Data Length mask +#define EXT_I2S_DL_32 (0x3<<2) //32 bits +#define EXT_I2S_DL_24 (0x2<<2) //24 bits +#define EXT_I2S_DL_20 (0x1<<2) //20 bits +#define EXT_I2S_DL_16 (0x0<<2) //16 bits + +//Voice Data Format +#define EXT_I2S_DF_MASK (0x3) //Extend i2s Data Format mask +#define EXT_I2S_DF_I2S (0x0) //I2S FORMAT +#define EXT_I2S_DF_RIGHT (0x1) //RIGHT JUSTIFIED format +#define EXT_I2S_DF_LEFT (0x2) //LEFT JUSTIFIED format +#define EXT_I2S_DF_PCM (0x3) //PCM format + +//Power managment addition 1 (0x3A),0:Disable,1:Enable +#define PWR_HI_R_LOAD_MONO (0x1<<15) +#define PWR_HI_R_LOAD_HP (0x1<<14) +#define PWR_ZC_DET_PD (0x1<<13) +#define PWR_MAIN_I2S (0x1<<11) +#define PWR_MIC_BIAS1_DET (0x1<<5) +#define PWR_MIC_BIAS2_DET (0x1<<4) +#define PWR_MIC_BIAS1 (0x1<<3) +#define PWR_MIC_BIAS2 (0x1<<2) +#define PWR_MAIN_BIAS (0x1<<1) +#define PWR_DAC_REF (0x1) + + +//Power managment addition 2(0x3C),0:Disable,1:Enable +#define EN_THREMAL_SHUTDOWN (0x1<<15) +#define PWR_CLASS_AB (0x1<<14) +#define PWR_MIXER_VREF (0x1<<13) +#define PWR_PLL (0x1<<12) +#define PWR_VOICE_CLOCK (0x1<<10) +#define PWR_L_DAC_CLK (0x1<<9) +#define PWR_R_DAC_CLK (0x1<<8) +#define PWR_L_ADC_CLK_GAIN (0x1<<7) +#define PWR_R_ADC_CLK_GAIN (0x1<<6) +#define PWR_L_HP_MIXER (0x1<<5) +#define PWR_R_HP_MIXER (0x1<<4) +#define PWR_SPK_MIXER (0x1<<3) +#define PWR_MONO_MIXER (0x1<<2) +#define PWR_L_ADC_REC_MIXER (0x1<<1) +#define PWR_R_ADC_REC_MIXER (0x1) + + +//Power managment addition 3(0x3E),0:Disable,1:Enable +#define PWR_MONO_VOL (0x1<<14) +#define PWR_SPK_LN_OUT (0x1<<13) +#define PWR_SPK_RN_OUT (0x1<<12) +#define PWR_HP_L_OUT (0x1<<11) +#define PWR_HP_R_OUT (0x1<<10) +#define PWR_SPK_L_OUT (0x1<<9) +#define PWR_SPK_R_OUT (0x1<<8) +#define PWR_LINE_IN_L (0x1<<7) +#define PWR_LINE_IN_R (0x1<<6) +#define PWR_PHONE_MIXER (0x1<<5) +#define PWR_PHONE_VOL (0x1<<4) +#define PWR_MIC1_VOL_CTRL (0x1<<3) +#define PWR_MIC2_VOL_CTRL (0x1<<2) +#define PWR_MIC1_BOOST (0x1<<1) +#define PWR_MIC2_BOOST (0x1) + +//General Purpose Control Register 1(0x40) +#define GP_CLK_FROM_PLL (0x1<<15) //Clock source from PLL output +#define GP_CLK_FROM_MCLK (0x0<<15) //Clock source from MCLK output + +#define GP_HP_AMP_CTRL_MASK (0x3<<8) +#define GP_HP_AMP_CTRL_RATIO_100 (0x0<<8) //1.00 Vdd +#define GP_HP_AMP_CTRL_RATIO_125 (0x1<<8) //1.25 Vdd +#define GP_HP_AMP_CTRL_RATIO_150 (0x2<<8) //1.50 Vdd + +#define GP_SPK_D_AMP_CTRL_MASK (0x3<<6) +#define GP_SPK_D_AMP_CTRL_RATIO_175 (0x0<<6) //1.75 Vdd +#define GP_SPK_D_AMP_CTRL_RATIO_150 (0x1<<6) //1.50 Vdd +#define GP_SPK_D_AMP_CTRL_RATIO_125 (0x2<<6) //1.25 Vdd +#define GP_SPK_D_AMP_CTRL_RATIO_100 (0x3<<6) //1.00 Vdd + +#define GP_SPK_AB_AMP_CTRL_MASK (0x7<<3) +#define GP_SPK_AB_AMP_CTRL_RATIO_225 (0x0<<3) //2.25 Vdd +#define GP_SPK_AB_AMP_CTRL_RATIO_200 (0x1<<3) //2.00 Vdd +#define GP_SPK_AB_AMP_CTRL_RATIO_175 (0x2<<3) //1.75 Vdd +#define GP_SPK_AB_AMP_CTRL_RATIO_150 (0x3<<3) //1.50 Vdd +#define GP_SPK_AB_AMP_CTRL_RATIO_125 (0x4<<3) //1.25 Vdd +#define GP_SPK_AB_AMP_CTRL_RATIO_100 (0x5<<3) //1.00 Vdd + +//General Purpose Control Register 2(0x42) +#define GP2_VOICE_TO_DIG_PATH_EN (0x1<<15) +#define GP2_CLASS_AB_SEL_DIFF (0x0<<13) //Differential Mode of Class AB +#define GP2_CLASS_D_SEL_SINGLE (0x1<<13) //Single End mode of Class AB +#define GP2_PLL_PRE_DIV_1 (0x0<<0) //PLL pre-Divider 1 +#define GP2_PLL_PRE_DIV_2 (0x1<<0) //PLL pre-Divider 2 + +//PLL Control(0x44) +#define PLL_M_CODE_MASK 0xF //PLL M code mask +#define PLL_K_CODE_MASK (0x7<<4) //PLL K code mask +#define PLL_BYPASS_N (0x1<<7) //bypass PLL N code +#define PLL_N_CODE_MASK (0xFF<<8) //PLL N code mask + +#define PLL_CTRL_M_VAL(m) ((m)&0xf) +#define PLL_CTRL_K_VAL(k) (((k)&0x7)<<4) +#define PLL_CTRL_N_VAL(n) (((n)&0xff)<<8) + + +//GPIO Pin Configuration(0x4C) +#define GPIO_1 (0x1<<1) +#define GPIO_2 (0x1<<2) +#define GPIO_3 (0x1<<3) +#define GPIO_4 (0x1<<4) +#define GPIO_5 (0x1<<5) + + +////INTERRUPT CONTROL(0x5E) +#define DISABLE_FAST_VREG (0x1<<15) + +#define AVC_TARTGET_SEL_MASK (0x3<<12) +#define AVC_TARTGET_SEL_NONE (0x0<<12) +#define AVC_TARTGET_SEL_R (0x1<<12) +#define AVC_TARTGET_SEL_L (0x2<<12) +#define AVC_TARTGET_SEL_BOTH (0x3<<12) + + + + +//Voice DAC PCM Clock Control 1(0x64) +#define VOICE_MCLK_SEL_MASK (0x1<<15) +#define VOICE_MCLK_SEL_MCLK_INPUT (0x0<<15) +#define VOICE_MCLK_SEL_PLL_OUTPUT (0x1<<15) + +#define VOICE_SYSCLK_SEL_MASK (0x1<<14) +#define VOICE_SYSCLK_SEL_MCLK (0x0<<14) +#define VOICE_SYSCLK_SEL_EXTCLK (0x1<<14) + +#define VOICE_WCLK_DIV_MASK (0x1<<13) +#define VOICE_WCLK_DIV_32 (0x0<<13) +#define VOICE_WCLK_DIV_64 (0x1<<13) + +#define VOICE_EXTCLK_OUT_DIV_MASK (0x7<<8) +#define VOICE_EXTCLK_OUT_DIV_1 (0x0<<8) +#define VOICE_EXTCLK_OUT_DIV_2 (0x1<<8) +#define VOICE_EXTCLK_OUT_DIV_4 (0x2<<8) +#define VOICE_EXTCLK_OUT_DIV_8 (0x3<<8) +#define VOICE_EXTCLK_OUT_DIV_16 (0x4<<8) + +#define VOICE_SCLK_DIV1_MASK (0xF<<4) +#define VOICE_SCLK_DIV1_1 (0x0<<4) +#define VOICE_SCLK_DIV1_2 (0x1<<4) +#define VOICE_SCLK_DIV1_3 (0x2<<4) +#define VOICE_SCLK_DIV1_4 (0x3<<4) +#define VOICE_SCLK_DIV1_5 (0x4<<4) +#define VOICE_SCLK_DIV1_6 (0x5<<4) +#define VOICE_SCLK_DIV1_7 (0x6<<4) +#define VOICE_SCLK_DIV1_8 (0x7<<4) +#define VOICE_SCLK_DIV1_9 (0x8<<4) +#define VOICE_SCLK_DIV1_10 (0x9<<4) +#define VOICE_SCLK_DIV1_11 (0xA<<4) +#define VOICE_SCLK_DIV1_12 (0xB<<4) +#define VOICE_SCLK_DIV1_13 (0xC<<4) +#define VOICE_SCLK_DIV1_14 (0xD<<4) +#define VOICE_SCLK_DIV1_15 (0xE<<4) +#define VOICE_SCLK_DIV1_16 (0xF<<4) + +#define VOICE_SCLK_DIV2_MASK (0x7) +#define VOICE_SCLK_DIV2_2 (0x0) +#define VOICE_SCLK_DIV2_4 (0x1) +#define VOICE_SCLK_DIV2_8 (0x2) +#define VOICE_SCLK_DIV2_16 (0x3) +#define VOICE_SCLK_DIV2_32 (0x4) + +//Voice DAC PCM Clock Control 2(0x66) +#define VOICE_CLK_FILTER_SLAVE_DIV_MASK (0x1<<15) +#define VOICE_CLK_FILTER_SLAVE_DIV_1 (0x0<<15) +#define VOICE_CLK_FILTER_SLAVE_DIV_2 (0x1<<15) + +#define VOICE_FILTER_CLK_F_MASK (0x1<<14) +#define VOICE_FILTER_CLK_F_MCLK (0x0<<14) +#define VOICE_FILTER_CLK_F_VBCLK (0X1<<14) + +#define VOICE_AD_DA_FILTER_SEL_MASK (0x1<<13) +#define VOICE_AD_DA_FILTER_SEL_128X (0x0<<13) +#define VOICE_AD_DA_FILTER_SEL_64X (0x1<<13) + +#define VOICE_CLK_FILTER_DIV1_MASK (0xF<<4) +#define VOICE_CLK_FILTER_DIV1_1 (0x0<<4) +#define VOICE_CLK_FILTER_DIV1_2 (0x1<<4) +#define VOICE_CLK_FILTER_DIV1_3 (0x2<<4) +#define VOICE_CLK_FILTER_DIV1_4 (0x3<<4) +#define VOICE_CLK_FILTER_DIV1_5 (0x4<<4) +#define VOICE_CLK_FILTER_DIV1_6 (0x5<<4) +#define VOICE_CLK_FILTER_DIV1_7 (0x6<<4) +#define VOICE_CLK_FILTER_DIV1_8 (0x7<<4) +#define VOICE_CLK_FILTER_DIV1_9 (0x8<<4) +#define VOICE_CLK_FILTER_DIV1_10 (0x9<<4) +#define VOICE_CLK_FILTER_DIV1_11 (0xA<<4) +#define VOICE_CLK_FILTER_DIV1_12 (0xB<<4) +#define VOICE_CLK_FILTER_DIV1_13 (0xC<<4) +#define VOICE_CLK_FILTER_DIV1_14 (0xD<<4) +#define VOICE_CLK_FILTER_DIV1_15 (0xE<<4) +#define VOICE_CLK_FILTER_DIV1_16 (0xF<<4) + +#define VOICE_CLK_FILTER_DIV2_MASK (0x7) +#define VOICE_CLK_FILTER_DIV2_2 (0x0) +#define VOICE_CLK_FILTER_DIV2_4 (0x1) +#define VOICE_CLK_FILTER_DIV2_8 (0x2) +#define VOICE_CLK_FILTER_DIV2_16 (0x3) +#define VOICE_CLK_FILTER_DIV2_32 (0x4) + + +//Psedueo Stereo & Spatial Effect Block Control(0x68) +#define SPATIAL_CTRL_EN (0x1<<15) +#define ALL_PASS_FILTER_EN (0x1<<14) +#define PSEUDO_STEREO_EN (0x1<<13) +#define STEREO_EXPENSION_EN (0x1<<12) + +#define SPATIAL_GAIN_MASK (0x3<<6) +#define SPATIAL_GAIN_1_0 (0x0<<6) +#define SPATIAL_GAIN_1_5 (0x1<<6) +#define SPATIAL_GAIN_2_0 (0x2<<6) + +#define SPATIAL_RATIO_MASK (0x3<<4) +#define SPATIAL_RATIO_0_0 (0x0<<4) +#define SPATIAL_RATIO_0_66 (0x1<<4) +#define SPATIAL_RATIO_1_0 (0x2<<4) + +#define APF_MASK (0x3) +#define APF_FOR_48K (0x3) +#define APF_FOR_44_1K (0x2) +#define APF_FOR_32K (0x1) + + + +struct rt5610_setup_data { + unsigned short i2c_address; + unsigned short i2c_bus; +}; + + +#define RT5610_PLL_FR_MCLK 0 + + +extern struct snd_soc_dai rt5610_dai[2]; +extern struct snd_soc_codec_device soc_codec_dev_rt5610; +extern int rt5610_reset(struct snd_soc_codec *codec, int try_warm); +#endif --- linux-mvl-dove-2.6.32.orig/sound/soc/codecs/wm8580.c +++ linux-mvl-dove-2.6.32/sound/soc/codecs/wm8580.c @@ -268,9 +268,9 @@ SOC_DOUBLE("DAC3 Invert Switch", WM8580_DAC_CONTROL4, 4, 5, 1, 0), SOC_SINGLE("DAC ZC Switch", WM8580_DAC_CONTROL5, 5, 1, 0), -SOC_SINGLE("DAC1 Switch", WM8580_DAC_CONTROL5, 0, 1, 0), -SOC_SINGLE("DAC2 Switch", WM8580_DAC_CONTROL5, 1, 1, 0), -SOC_SINGLE("DAC3 Switch", WM8580_DAC_CONTROL5, 2, 1, 0), +SOC_SINGLE("DAC1 Switch", WM8580_DAC_CONTROL5, 0, 1, 1), +SOC_SINGLE("DAC2 Switch", WM8580_DAC_CONTROL5, 1, 1, 1), +SOC_SINGLE("DAC3 Switch", WM8580_DAC_CONTROL5, 2, 1, 1), SOC_DOUBLE("ADC Mute Switch", WM8580_ADC_CONTROL1, 0, 1, 1, 0), SOC_SINGLE("ADC High-Pass Filter Switch", WM8580_ADC_CONTROL1, 4, 1, 0), --- linux-mvl-dove-2.6.32.orig/sound/soc/codecs/ad1980.c +++ linux-mvl-dove-2.6.32/sound/soc/codecs/ad1980.c @@ -24,6 +24,9 @@ #include "ad1980.h" +#define CODEC_TYPE_AD1888 1 +#define CODEC_TYPE_AD1980 2 + static unsigned int ac97_read(struct snd_soc_codec *codec, unsigned int reg); static int ac97_write(struct snd_soc_codec *codec, @@ -82,8 +85,12 @@ SOC_SINGLE("Stereo Mic Switch", AC97_AD_MISC, 6, 1, 0), SOC_DOUBLE("Line HP Swap Switch", AC97_AD_MISC, 10, 5, 1, 0), -SOC_DOUBLE("Surround Playback Volume", AC97_SURROUND_MASTER, 8, 0, 31, 1), -SOC_DOUBLE("Surround Playback Switch", AC97_SURROUND_MASTER, 15, 7, 1, 1), +SOC_SINGLE("Stereo Spread Switch", AC97_AD_MISC, 7, 1, 0), + +SOC_DOUBLE("Surround/Headphone Playback Volume", AC97_SURROUND_MASTER, + 8, 0, 31, 1), +SOC_DOUBLE("Surround/Headphone Playback Switch", AC97_SURROUND_MASTER, + 15, 7, 1, 1), SOC_DOUBLE("Center/LFE Playback Volume", AC97_CENTER_LFE_MASTER, 8, 0, 31, 1), SOC_DOUBLE("Center/LFE Playback Switch", AC97_CENTER_LFE_MASTER, 15, 7, 1, 1), @@ -128,7 +135,8 @@ return 0; } - +static struct snd_soc_dai_ops ad1980_dai_ops = { +}; struct snd_soc_dai ad1980_dai = { .name = "AC97", .ac97_control = 1, @@ -144,10 +152,11 @@ .channels_max = 2, .rates = SNDRV_PCM_RATE_48000, .formats = SND_SOC_STD_AC97_FMTS, }, + .ops = &ad1980_dai_ops, }; EXPORT_SYMBOL_GPL(ad1980_dai); -static int ad1980_reset(struct snd_soc_codec *codec, int try_warm) +static int ad1980_reset(struct snd_soc_codec *codec, int try_warm, int type) { u16 retry_cnt = 0; @@ -162,7 +171,10 @@ /* Set bit 16slot in register 74h, then every slot will has only 16 * bits. This command is sent out in 20bit mode, in which case the * first nibble of data is eaten by the addr. (Tag is always 16 bit)*/ - ac97_write(codec, AC97_AD_SERIAL_CFG, 0x9900); + if (type == CODEC_TYPE_AD1888) + ac97_write(codec, AC97_AD_SERIAL_CFG, 0x1000); + else + ac97_write(codec, AC97_AD_SERIAL_CFG, 0x9900); if (ac97_read(codec, AC97_RESET) != 0x0090) goto err; @@ -176,7 +188,30 @@ return -EIO; } -static int ad1980_soc_probe(struct platform_device *pdev) +static int ad1980_soc_suspend(struct platform_device *pdev, + pm_message_t state) +{ + return 0; +} + +static int ad1980_soc_resume(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->card->codec; + u16 *cache = codec->reg_cache; + int ret, i; + + ret = ad1980_reset(codec, 0, CODEC_TYPE_AD1888); + if (ret < 0) + printk(KERN_ERR "Failed to reset AD1980: AC97 link error\n"); + + for (i = 2; i < ARRAY_SIZE(ad1980_reg) << 1; i += 2) + soc_ac97_ops.write(codec->ac97, i, cache[i >> 1]); + + return 0; +} + +static int internal_soc_probe(struct platform_device *pdev, int type) { struct snd_soc_device *socdev = platform_get_drvdata(pdev); struct snd_soc_codec *codec; @@ -223,7 +258,7 @@ goto pcm_err; - ret = ad1980_reset(codec, 0); + ret = ad1980_reset(codec, 0, type); if (ret < 0) { printk(KERN_ERR "Failed to reset AD1980: AC97 link error\n"); goto reset_err; @@ -235,7 +270,7 @@ vendor_id2 = ac97_read(codec, AC97_VENDOR_ID2); - if (vendor_id2 != 0x5370) { + if ((vendor_id2 != 0x5370) && (vendor_id2 != 0x5368)) { if (vendor_id2 != 0x5374) goto reset_err; else @@ -280,6 +315,16 @@ return ret; } +static int ad1980_soc_probe(struct platform_device *pdev) +{ + return internal_soc_probe(pdev, CODEC_TYPE_AD1980); +} + +static int ad1888_soc_probe(struct platform_device *pdev) +{ + return internal_soc_probe(pdev, CODEC_TYPE_AD1888); +} + static int ad1980_soc_remove(struct platform_device *pdev) { struct snd_soc_device *socdev = platform_get_drvdata(pdev); @@ -302,6 +347,15 @@ }; EXPORT_SYMBOL_GPL(soc_codec_dev_ad1980); +struct snd_soc_codec_device soc_codec_dev_ad1888 = { + .probe = ad1888_soc_probe, + .remove = ad1980_soc_remove, + .suspend = ad1980_soc_suspend, + .resume = ad1980_soc_resume, +}; +EXPORT_SYMBOL_GPL(soc_codec_dev_ad1888); + + MODULE_DESCRIPTION("ASoC ad1980 driver"); MODULE_AUTHOR("Roy Huang, Cliff Cai"); MODULE_LICENSE("GPL"); --- linux-mvl-dove-2.6.32.orig/sound/soc/codecs/ak4104.c +++ linux-mvl-dove-2.6.32/sound/soc/codecs/ak4104.c @@ -90,12 +90,10 @@ if (reg >= codec->reg_cache_size) return -EINVAL; - reg &= AK4104_REG_MASK; - reg |= AK4104_WRITE; - /* only write to the hardware if value has changed */ if (cache[reg] != value) { - u8 tmp[2] = { reg, value }; + u8 tmp[2] = { (reg & AK4104_REG_MASK) | AK4104_WRITE, value }; + if (spi_write(spi, tmp, sizeof(tmp))) { dev_err(&spi->dev, "SPI write failed\n"); return -EIO; --- linux-mvl-dove-2.6.32.orig/sound/soc/blackfin/bf5xx-ac97.c +++ linux-mvl-dove-2.6.32/sound/soc/blackfin/bf5xx-ac97.c @@ -260,9 +260,9 @@ pr_debug("%s : sport %d\n", __func__, dai->id); if (!dai->active) return 0; - if (dai->capture.active) + if (dai->capture_active) sport_rx_stop(sport); - if (dai->playback.active) + if (dai->playback_active) sport_tx_stop(sport); return 0; } --- linux-mvl-dove-2.6.32.orig/sound/soc/blackfin/bf5xx-i2s-pcm.c +++ linux-mvl-dove-2.6.32/sound/soc/blackfin/bf5xx-i2s-pcm.c @@ -139,11 +139,20 @@ pr_debug("%s enter\n", __func__); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { diff = sport_curr_offset_tx(sport); - frames = bytes_to_frames(substream->runtime, diff); } else { diff = sport_curr_offset_rx(sport); - frames = bytes_to_frames(substream->runtime, diff); } + + /* + * TX at least can report one frame beyond the end of the + * buffer if we hit the wraparound case - clamp to within the + * buffer as the ALSA APIs require. + */ + if (diff == snd_pcm_lib_buffer_bytes(substream)) + diff = 0; + + frames = bytes_to_frames(substream->runtime, diff); + return frames; } --- linux-mvl-dove-2.6.32.orig/sound/soc/pxa/Kconfig +++ linux-mvl-dove-2.6.32/sound/soc/pxa/Kconfig @@ -18,6 +18,10 @@ select SND_PXA2XX_LIB_AC97 select SND_SOC_AC97_BUS +config SND_PXA2XX_SOC_AC97_SURROUND + tristate + select SND_PXA2XX_SOC_AC97 + config SND_PXA2XX_SOC_I2S tristate --- linux-mvl-dove-2.6.32.orig/sound/soc/pxa/pxa2xx-ac97.h +++ linux-mvl-dove-2.6.32/sound/soc/pxa/pxa2xx-ac97.h @@ -14,7 +14,11 @@ #define PXA2XX_DAI_AC97_AUX 1 #define PXA2XX_DAI_AC97_MIC 2 +#define PXA3XX_DAI_AC97_SURROUND 0 +#define PXA3XX_DAI_AC97_LFE 1 + extern struct snd_soc_dai pxa_ac97_dai[3]; +extern struct snd_soc_dai pxa_ac97_surround_dai[2]; /* platform data */ extern struct snd_ac97_bus_ops pxa2xx_ac97_ops; --- linux-mvl-dove-2.6.32.orig/sound/soc/pxa/Makefile +++ linux-mvl-dove-2.6.32/sound/soc/pxa/Makefile @@ -1,11 +1,13 @@ # PXA Platform Support snd-soc-pxa2xx-objs := pxa2xx-pcm.o snd-soc-pxa2xx-ac97-objs := pxa2xx-ac97.o +snd-soc-pxa2xx-ac97-surround-objs := pxa3xx-ac97-surround.o snd-soc-pxa2xx-i2s-objs := pxa2xx-i2s.o snd-soc-pxa-ssp-objs := pxa-ssp.o obj-$(CONFIG_SND_PXA2XX_SOC) += snd-soc-pxa2xx.o obj-$(CONFIG_SND_PXA2XX_SOC_AC97) += snd-soc-pxa2xx-ac97.o +obj-$(CONFIG_SND_PXA2XX_SOC_AC97_SURROUND) += snd-soc-pxa2xx-ac97-surround.o obj-$(CONFIG_SND_PXA2XX_SOC_I2S) += snd-soc-pxa2xx-i2s.o obj-$(CONFIG_SND_PXA_SOC_SSP) += snd-soc-pxa-ssp.o --- linux-mvl-dove-2.6.32.orig/sound/soc/pxa/pxa2xx-ac97.c +++ linux-mvl-dove-2.6.32/sound/soc/pxa/pxa2xx-ac97.c @@ -20,8 +20,12 @@ #include #include +#include #include +#ifndef CONFIG_ARCH_DOVE #include +#endif + #include #include "pxa2xx-pcm.h" @@ -193,7 +197,7 @@ .playback = { .stream_name = "AC97 Playback", .channels_min = 2, - .channels_max = 2, + .channels_max = 6, .rates = PXA2XX_AC97_RATES, .formats = SNDRV_PCM_FMTBIT_S16_LE,}, .capture = { --- linux-mvl-dove-2.6.32.orig/sound/soc/pxa/pxa3xx-ac97-surround.c +++ linux-mvl-dove-2.6.32/sound/soc/pxa/pxa3xx-ac97-surround.c @@ -0,0 +1,154 @@ +/* + * linux/sound/pxa3xx-ac97-Surround.c -- AC97 surround support for the + * Marvell PXA3xx chip. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include "pxa2xx-pcm.h" +#include "pxa2xx-ac97.h" +#include + +static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_surround_out = { + .name = "AC97 PCM Surround out", + .dev_addr = __PREG(PCSDR), + .drcmr = &DRCMR95, + .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | + DCMD_BURST32 | DCMD_WIDTH4, +}; + + +static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_lfe_out = { + .name = "AC97 PCM LFE out", + .dev_addr = __PREG(PCCLDR), + .drcmr = &DRCMR96, + .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | + DCMD_BURST32 | DCMD_WIDTH4, +}; + +static int pxa3xx_ac97_surround_probe(struct platform_device *pdev, + struct snd_soc_dai *dai) +{ + return 0; +} + +static void pxa3xx_ac97_surround_remove(struct platform_device *pdev, + struct snd_soc_dai *dai) +{ +} + +static int pxa2xx_ac97_hw_surround_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + cpu_dai->dma_data = &pxa2xx_ac97_pcm_surround_out; + + return 0; +} + +static int pxa2xx_ac97_hw_lfe_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + cpu_dai->dma_data = &pxa2xx_ac97_pcm_lfe_out; + + return 0; +} + +#define PXA2XX_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ + SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \ + SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) + +static struct snd_soc_dai_ops pxa2xx_ac97_surround_ops = { + .hw_params = pxa2xx_ac97_hw_surround_params, +}; + +static struct snd_soc_dai_ops pxa2xx_ac97_lfe_ops = { + .hw_params = pxa2xx_ac97_hw_lfe_params, +}; + +/* + * There is only 1 physical AC97 interface for pxa2xx, but it + * has extra fifo's that can be used for aux DACs and ADCs. + */ +struct snd_soc_dai pxa_ac97_surround_dai[] = { +{ + .name = "pxa2xx-surround-ac97", + .id = 0, + .ac97_control = 1, + .probe = pxa3xx_ac97_surround_probe, + .remove = pxa3xx_ac97_surround_remove, + .playback = { + .stream_name = "AC97 Surround Playback", + .channels_min = 2, + .channels_max = 2, + .rates = PXA2XX_AC97_RATES, + .formats = SNDRV_PCM_FMTBIT_S16_LE,}, + .ops = &pxa2xx_ac97_surround_ops, +}, +{ + .name = "pxa2xx-lfe-ac97", + .id = 1, + .ac97_control = 1, + .playback = { + .stream_name = "AC97 LFE Playback", + .channels_min = 2, + .channels_max = 2, + .rates = PXA2XX_AC97_RATES, + .formats = SNDRV_PCM_FMTBIT_S16_LE,}, + .ops = &pxa2xx_ac97_lfe_ops, +}, +}; +EXPORT_SYMBOL_GPL(pxa_ac97_surround_dai); + +static int __init pxa_ac97_surround_init(void) +{ + if (machine_is_dove_rd_avng()) + return -ENODEV; + return snd_soc_register_dais(pxa_ac97_surround_dai, + ARRAY_SIZE(pxa_ac97_surround_dai)); +} +module_init(pxa_ac97_surround_init); + +static void __exit pxa_ac97_surround_exit(void) +{ + snd_soc_unregister_dais(pxa_ac97_surround_dai, + ARRAY_SIZE(pxa_ac97_surround_dai)); +} +module_exit(pxa_ac97_surround_exit); + + +MODULE_AUTHOR("Shadi Ammouri"); +MODULE_DESCRIPTION("AC97 surround driver for the Intel PXA3xx chip"); +MODULE_LICENSE("GPL"); + --- linux-mvl-dove-2.6.32.orig/sound/core/rawmidi.c +++ linux-mvl-dove-2.6.32/sound/core/rawmidi.c @@ -530,13 +530,15 @@ { struct snd_rawmidi_file *rfile; struct snd_rawmidi *rmidi; + struct module *module; rfile = file->private_data; rmidi = rfile->rmidi; rawmidi_release_priv(rfile); kfree(rfile); + module = rmidi->card->module; snd_card_file_remove(rmidi->card, file); - module_put(rmidi->card->module); + module_put(module); return 0; } --- linux-mvl-dove-2.6.32.orig/sound/core/init.c +++ linux-mvl-dove-2.6.32/sound/core/init.c @@ -848,6 +848,7 @@ return -ENOMEM; mfile->file = file; mfile->disconnected_f_op = NULL; + INIT_LIST_HEAD(&mfile->shutdown_list); spin_lock(&card->files_lock); if (card->shutdown) { spin_unlock(&card->files_lock); @@ -883,6 +884,9 @@ list_for_each_entry(mfile, &card->files_list, list) { if (mfile->file == file) { list_del(&mfile->list); + spin_lock(&shutdown_lock); + list_del(&mfile->shutdown_list); + spin_unlock(&shutdown_lock); if (mfile->disconnected_f_op) fops_put(mfile->disconnected_f_op); found = mfile; --- linux-mvl-dove-2.6.32.orig/sound/core/control.c +++ linux-mvl-dove-2.6.32/sound/core/control.c @@ -31,6 +31,7 @@ /* max number of user-defined controls */ #define MAX_USER_CONTROLS 32 +#define MAX_CONTROL_COUNT 1028 struct snd_kctl_ioctl { struct list_head list; /* list of all ioctls */ @@ -190,6 +191,10 @@ if (snd_BUG_ON(!control || !control->count)) return NULL; + + if (control->count > MAX_CONTROL_COUNT) + return NULL; + kctl = kzalloc(sizeof(*kctl) + sizeof(struct snd_kcontrol_volatile) * control->count, GFP_KERNEL); if (kctl == NULL) { snd_printk(KERN_ERR "Cannot allocate control instance\n"); --- linux-mvl-dove-2.6.32.orig/sound/core/hrtimer.c +++ linux-mvl-dove-2.6.32/sound/core/hrtimer.c @@ -37,14 +37,23 @@ struct snd_hrtimer { struct snd_timer *timer; struct hrtimer hrt; + atomic_t running; }; static enum hrtimer_restart snd_hrtimer_callback(struct hrtimer *hrt) { struct snd_hrtimer *stime = container_of(hrt, struct snd_hrtimer, hrt); struct snd_timer *t = stime->timer; - hrtimer_forward_now(hrt, ns_to_ktime(t->sticks * resolution)); - snd_timer_interrupt(stime->timer, t->sticks); + unsigned long oruns; + + if (!atomic_read(&stime->running)) + return HRTIMER_NORESTART; + + oruns = hrtimer_forward_now(hrt, ns_to_ktime(t->sticks * resolution)); + snd_timer_interrupt(stime->timer, t->sticks * oruns); + + if (!atomic_read(&stime->running)) + return HRTIMER_NORESTART; return HRTIMER_RESTART; } @@ -58,6 +67,7 @@ hrtimer_init(&stime->hrt, CLOCK_MONOTONIC, HRTIMER_MODE_REL); stime->timer = t; stime->hrt.function = snd_hrtimer_callback; + atomic_set(&stime->running, 0); t->private_data = stime; return 0; } @@ -78,16 +88,18 @@ { struct snd_hrtimer *stime = t->private_data; + atomic_set(&stime->running, 0); + hrtimer_cancel(&stime->hrt); hrtimer_start(&stime->hrt, ns_to_ktime(t->sticks * resolution), HRTIMER_MODE_REL); + atomic_set(&stime->running, 1); return 0; } static int snd_hrtimer_stop(struct snd_timer *t) { struct snd_hrtimer *stime = t->private_data; - - hrtimer_cancel(&stime->hrt); + atomic_set(&stime->running, 0); return 0; } --- linux-mvl-dove-2.6.32.orig/sound/core/pcm_compat.c +++ linux-mvl-dove-2.6.32/sound/core/pcm_compat.c @@ -341,7 +341,7 @@ kfree(bufs); return -EFAULT; } - bufs[ch] = compat_ptr(ptr); + bufs[i] = compat_ptr(ptr); bufptr++; } if (dir == SNDRV_PCM_STREAM_PLAYBACK) --- linux-mvl-dove-2.6.32.orig/sound/core/pcm_native.c +++ linux-mvl-dove-2.6.32/sound/core/pcm_native.c @@ -314,10 +314,10 @@ if (!params->info) params->info = hw->info & ~SNDRV_PCM_INFO_FIFO_IN_FRAMES; if (!params->fifo_size) { - if (snd_mask_min(¶ms->masks[SNDRV_PCM_HW_PARAM_FORMAT]) == - snd_mask_max(¶ms->masks[SNDRV_PCM_HW_PARAM_FORMAT]) && - snd_mask_min(¶ms->masks[SNDRV_PCM_HW_PARAM_CHANNELS]) == - snd_mask_max(¶ms->masks[SNDRV_PCM_HW_PARAM_CHANNELS])) { + m = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); + i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); + if (snd_mask_min(m) == snd_mask_max(m) && + snd_interval_min(i) == snd_interval_max(i)) { changed = substream->ops->ioctl(substream, SNDRV_PCM_IOCTL1_FIFO_SIZE, params); if (changed < 0) @@ -972,6 +972,10 @@ { if (substream->runtime->trigger_master != substream) return 0; + /* some drivers might use hw_ptr to recover from the pause - + update the hw_ptr now */ + if (push) + snd_pcm_update_hw_ptr(substream); /* The jiffies check in snd_pcm_update_hw_ptr*() is done by * a delta betwen the current jiffies, this gives a large enough * delta, effectively to skip the check once. --- linux-mvl-dove-2.6.32.orig/sound/core/seq/oss/seq_oss_init.c +++ linux-mvl-dove-2.6.32/sound/core/seq/oss/seq_oss_init.c @@ -280,13 +280,10 @@ return 0; _error: - snd_seq_oss_writeq_delete(dp->writeq); - snd_seq_oss_readq_delete(dp->readq); snd_seq_oss_synth_cleanup(dp); snd_seq_oss_midi_cleanup(dp); - delete_port(dp); delete_seq_queue(dp->queue); - kfree(dp); + delete_port(dp); return rc; } @@ -349,8 +346,10 @@ static int delete_port(struct seq_oss_devinfo *dp) { - if (dp->port < 0) + if (dp->port < 0) { + kfree(dp); return 0; + } debug_printk(("delete_port %i\n", dp->port)); return snd_seq_event_port_detach(dp->cseq, dp->port); --- linux-mvl-dove-2.6.32.orig/sound/oss/sb_mixer.c +++ linux-mvl-dove-2.6.32/sound/oss/sb_mixer.c @@ -230,7 +230,7 @@ return 1; } -static void change_bits(sb_devc * devc, unsigned char *regval, int dev, int chn, int newval) +static void __change_bits(sb_devc * devc, unsigned char *regval, int dev, int chn, int newval) { unsigned char mask; int shift; @@ -282,7 +282,7 @@ return -EINVAL; val = sb_getmixer(devc, regoffs); - change_bits(devc, &val, dev, LEFT_CHN, left); + __change_bits(devc, &val, dev, LEFT_CHN, left); if ((*devc->iomap)[dev][RIGHT_CHN].regno != regoffs) /* * Change register @@ -302,7 +302,7 @@ * Read the new one */ } - change_bits(devc, &val, dev, RIGHT_CHN, right); + __change_bits(devc, &val, dev, RIGHT_CHN, right); sb_setmixer(devc, regoffs, val); --- linux-mvl-dove-2.6.32.orig/sound/oss/sequencer.c +++ linux-mvl-dove-2.6.32/sound/oss/sequencer.c @@ -241,7 +241,7 @@ return -ENXIO; fmt = (*(short *) &event_rec[0]) & 0xffff; - err = synth_devs[dev]->load_patch(dev, fmt, buf, p + 4, c, 0); + err = synth_devs[dev]->load_patch(dev, fmt, buf + p, c, 0); if (err < 0) return err; --- linux-mvl-dove-2.6.32.orig/sound/oss/midi_synth.h +++ linux-mvl-dove-2.6.32/sound/oss/midi_synth.h @@ -8,7 +8,7 @@ void midi_synth_close (int dev); void midi_synth_hw_control (int dev, unsigned char *event); int midi_synth_load_patch (int dev, int format, const char __user * addr, - int offs, int count, int pmgr_flag); + int count, int pmgr_flag); void midi_synth_panning (int dev, int channel, int pressure); void midi_synth_aftertouch (int dev, int channel, int pressure); void midi_synth_controller (int dev, int channel, int ctrl_num, int value); --- linux-mvl-dove-2.6.32.orig/sound/oss/ad1848.c +++ linux-mvl-dove-2.6.32/sound/oss/ad1848.c @@ -457,7 +457,7 @@ return mask; } -static void change_bits(ad1848_info * devc, unsigned char *regval, +static void __change_bits(ad1848_info * devc, unsigned char *regval, unsigned char *muteval, int dev, int chn, int newval) { unsigned char mask; @@ -515,10 +515,10 @@ if (muteregoffs != regoffs) { muteval = ad_read(devc, muteregoffs); - change_bits(devc, &val, &muteval, dev, channel, value); + __change_bits(devc, &val, &muteval, dev, channel, value); } else - change_bits(devc, &val, &val, dev, channel, value); + __change_bits(devc, &val, &val, dev, channel, value); spin_lock_irqsave(&devc->lock,flags); ad_write(devc, regoffs, val); --- linux-mvl-dove-2.6.32.orig/sound/oss/dev_table.h +++ linux-mvl-dove-2.6.32/sound/oss/dev_table.h @@ -271,7 +271,7 @@ void (*reset) (int dev); void (*hw_control) (int dev, unsigned char *event); int (*load_patch) (int dev, int format, const char __user *addr, - int offs, int count, int pmgr_flag); + int count, int pmgr_flag); void (*aftertouch) (int dev, int voice, int pressure); void (*controller) (int dev, int voice, int ctrl_num, int value); void (*panning) (int dev, int voice, int value); --- linux-mvl-dove-2.6.32.orig/sound/oss/soundcard.c +++ linux-mvl-dove-2.6.32/sound/oss/soundcard.c @@ -87,7 +87,7 @@ int i, n; for (i = 0; i < num_mixer_volumes; i++) { - if (strcmp(name, mixer_vols[i].name) == 0) { + if (strncmp(name, mixer_vols[i].name, 32) == 0) { if (present) mixer_vols[i].num = i; return mixer_vols[i].levels; @@ -99,7 +99,7 @@ } n = num_mixer_volumes++; - strcpy(mixer_vols[n].name, name); + strncpy(mixer_vols[n].name, name, 32); if (present) mixer_vols[n].num = n; --- linux-mvl-dove-2.6.32.orig/sound/oss/opl3.c +++ linux-mvl-dove-2.6.32/sound/oss/opl3.c @@ -819,7 +819,7 @@ } static int opl3_load_patch(int dev, int format, const char __user *addr, - int offs, int count, int pmgr_flag) + int count, int pmgr_flag) { struct sbi_instrument ins; @@ -829,11 +829,7 @@ return -EINVAL; } - /* - * What the fuck is going on here? We leave junk in the beginning - * of ins and then check the field pretty close to that beginning? - */ - if(copy_from_user(&((char *) &ins)[offs], addr + offs, sizeof(ins) - offs)) + if (copy_from_user(&ins, addr, sizeof(ins))) return -EFAULT; if (ins.channel < 0 || ins.channel >= SBFM_MAXINSTR) @@ -848,6 +844,10 @@ static void opl3_panning(int dev, int voice, int value) { + + if (voice < 0 || voice >= devc->nr_voice) + return; + devc->voc[voice].panning = value; } @@ -1065,8 +1065,15 @@ static void opl3_setup_voice(int dev, int voice, int chn) { - struct channel_info *info = - &synth_devs[dev]->chn_info[chn]; + struct channel_info *info; + + if (voice < 0 || voice >= devc->nr_voice) + return; + + if (chn < 0 || chn > 15) + return; + + info = &synth_devs[dev]->chn_info[chn]; opl3_set_instr(dev, voice, info->pgm_num); --- linux-mvl-dove-2.6.32.orig/sound/oss/midi_synth.c +++ linux-mvl-dove-2.6.32/sound/oss/midi_synth.c @@ -476,7 +476,7 @@ int midi_synth_load_patch(int dev, int format, const char __user *addr, - int offs, int count, int pmgr_flag) + int count, int pmgr_flag) { int orig_dev = synth_devs[dev]->midi_dev; @@ -491,39 +491,37 @@ if (!prefix_cmd(orig_dev, 0xf0)) return 0; + /* Invalid patch format */ if (format != SYSEX_PATCH) - { -/* printk("MIDI Error: Invalid patch format (key) 0x%x\n", format);*/ return -EINVAL; - } + + /* Patch header too short */ if (count < hdr_size) - { -/* printk("MIDI Error: Patch header too short\n");*/ return -EINVAL; - } + count -= hdr_size; /* - * Copy the header from user space but ignore the first bytes which have - * been transferred already. + * Copy the header from user space */ - if(copy_from_user(&((char *) &sysex)[offs], &(addr)[offs], hdr_size - offs)) + if (copy_from_user(&sysex, addr, hdr_size)) return -EFAULT; - - if (count < sysex.len) - { -/* printk(KERN_WARNING "MIDI Warning: Sysex record too short (%d<%d)\n", count, (int) sysex.len);*/ + + /* Sysex record too short */ + if ((unsigned)count < (unsigned)sysex.len) sysex.len = count; - } - left = sysex.len; - src_offs = 0; + + left = sysex.len; + src_offs = 0; for (i = 0; i < left && !signal_pending(current); i++) { unsigned char data; - get_user(*(unsigned char *) &data, (unsigned char __user *) &((addr)[hdr_size + i])); + if (get_user(data, + (unsigned char __user *)(addr + hdr_size + i))) + return -EFAULT; eox_seen = (i > 0 && data & 0x80); /* End of sysex */ --- linux-mvl-dove-2.6.32.orig/sound/ppc/tumbler.c +++ linux-mvl-dove-2.6.32/sound/ppc/tumbler.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -46,6 +47,8 @@ #define DBG(fmt...) #endif +#define IS_G4DA (machine_is_compatible("PowerMac3,4")) + /* i2c address for tumbler */ #define TAS_I2C_ADDR 0x34 @@ -1134,7 +1137,8 @@ gp->inactive_val = (*base) ? 0x4 : 0x5; } else { const u32 *prop = NULL; - gp->active_state = 0; + gp->active_state = IS_G4DA + && !strncmp(device, "keywest-gpio1", 13); gp->active_val = 0x4; gp->inactive_val = 0x5; /* Here are some crude hacks to extract the GPIO polarity and @@ -1312,6 +1316,9 @@ if (irq <= NO_IRQ) irq = tumbler_find_device("line-output-detect", NULL, &mix->line_detect, 1); + if (IS_G4DA && irq <= NO_IRQ) + irq = tumbler_find_device("keywest-gpio16", + NULL, &mix->line_detect, 1); mix->lineout_irq = irq; tumbler_reset_audio(chip); --- linux-mvl-dove-2.6.32.orig/sound/usb/usbaudio.c +++ linux-mvl-dove-2.6.32/sound/usb/usbaudio.c @@ -752,7 +752,7 @@ return 0; /* already large enough */ vfree(runtime->dma_area); } - runtime->dma_area = vmalloc(size); + runtime->dma_area = vmalloc_user(size); if (!runtime->dma_area) return -ENOMEM; runtime->dma_bytes = size; @@ -1936,7 +1936,7 @@ struct snd_usb_stream *as = snd_pcm_substream_chip(substream); struct snd_usb_substream *subs = &as->substream[direction]; - if (subs->interface >= 0) { + if (!as->chip->shutdown && subs->interface >= 0) { usb_set_interface(subs->dev, subs->interface, 0); subs->interface = -1; } @@ -3326,6 +3326,32 @@ } /* + * This call will put the synth in "USB send" mode, i.e it will send MIDI + * messages through USB (this is disabled at startup). The synth will + * acknowledge by sending a sysex on endpoint 0x85 and by displaying a USB + * sign on its LCD. Values here are chosen based on sniffing USB traffic + * under Windows. + */ +static int snd_usb_accessmusic_boot_quirk(struct usb_device *dev) +{ + int err, actual_length; + + /* "midi send" enable */ + static const u8 seq[] = { 0x4e, 0x73, 0x52, 0x01 }; + + void *buf = kmemdup(seq, ARRAY_SIZE(seq), GFP_KERNEL); + if (!buf) + return -ENOMEM; + err = usb_interrupt_msg(dev, usb_sndintpipe(dev, 0x05), buf, + ARRAY_SIZE(seq), &actual_length, 1000); + kfree(buf); + if (err < 0) + return err; + + return 0; +} + +/* * Setup quirks */ #define AUDIOPHILE_SET 0x01 /* if set, parse device_setup */ @@ -3616,6 +3642,12 @@ goto __err_val; } + /* Access Music VirusTI Desktop */ + if (id == USB_ID(0x133e, 0x0815)) { + if (snd_usb_accessmusic_boot_quirk(dev) < 0) + goto __err_val; + } + /* * found a config. now register to ALSA */ --- linux-mvl-dove-2.6.32.orig/sound/usb/usbmidi.c +++ linux-mvl-dove-2.6.32/sound/usb/usbmidi.c @@ -931,6 +931,8 @@ DEFINE_WAIT(wait); long timeout = msecs_to_jiffies(50); + if (ep->umidi->disconnected) + return; /* * The substream buffer is empty, but some data might still be in the * currently active URBs, so we have to wait for those to complete. @@ -1075,14 +1077,21 @@ * Frees an output endpoint. * May be called when ep hasn't been initialized completely. */ -static void snd_usbmidi_out_endpoint_delete(struct snd_usb_midi_out_endpoint* ep) +static void snd_usbmidi_out_endpoint_clear(struct snd_usb_midi_out_endpoint *ep) { unsigned int i; for (i = 0; i < OUTPUT_URBS; ++i) - if (ep->urbs[i].urb) + if (ep->urbs[i].urb) { free_urb_and_buffer(ep->umidi, ep->urbs[i].urb, ep->max_transfer); + ep->urbs[i].urb = NULL; + } +} + +static void snd_usbmidi_out_endpoint_delete(struct snd_usb_midi_out_endpoint *ep) +{ + snd_usbmidi_out_endpoint_clear(ep); kfree(ep); } @@ -1201,15 +1210,18 @@ usb_kill_urb(ep->out->urbs[j].urb); if (umidi->usb_protocol_ops->finish_out_endpoint) umidi->usb_protocol_ops->finish_out_endpoint(ep->out); + ep->out->active_urbs = 0; + if (ep->out->drain_urbs) { + ep->out->drain_urbs = 0; + wake_up(&ep->out->drain_wait); + } } if (ep->in) for (j = 0; j < INPUT_URBS; ++j) usb_kill_urb(ep->in->urbs[j]); /* free endpoints here; later call can result in Oops */ - if (ep->out) { - snd_usbmidi_out_endpoint_delete(ep->out); - ep->out = NULL; - } + if (ep->out) + snd_usbmidi_out_endpoint_clear(ep->out); if (ep->in) { snd_usbmidi_in_endpoint_delete(ep->in); ep->in = NULL; @@ -1360,6 +1372,12 @@ EXTERNAL_PORT(0x086a, 0x0001, 8, "%s Broadcast"), EXTERNAL_PORT(0x086a, 0x0002, 8, "%s Broadcast"), EXTERNAL_PORT(0x086a, 0x0003, 4, "%s Broadcast"), + /* Access Music Virus TI */ + EXTERNAL_PORT(0x133e, 0x0815, 0, "%s MIDI"), + PORT_INFO(0x133e, 0x0815, 1, "%s Synth", 0, + SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC | + SNDRV_SEQ_PORT_TYPE_HARDWARE | + SNDRV_SEQ_PORT_TYPE_SYNTHESIZER), }; static struct port_info *find_port_info(struct snd_usb_midi* umidi, int number) --- linux-mvl-dove-2.6.32.orig/sound/usb/usbquirks.h +++ linux-mvl-dove-2.6.32/sound/usb/usbquirks.h @@ -2050,6 +2050,33 @@ } }, +/* Access Music devices */ +{ + /* VirusTI Desktop */ + USB_DEVICE_VENDOR_SPEC(0x133e, 0x0815), + .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = &(const struct snd_usb_audio_quirk[]) { + { + .ifnum = 3, + .type = QUIRK_MIDI_FIXED_ENDPOINT, + .data = &(const struct snd_usb_midi_endpoint_info) { + .out_cables = 0x0003, + .in_cables = 0x0003 + } + }, + { + .ifnum = 4, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = -1 + } + } + } +}, + /* */ { /* aka. Serato Scratch Live DJ Box */ --- linux-mvl-dove-2.6.32.orig/sound/usb/usx2y/us122l.c +++ linux-mvl-dove-2.6.32/sound/usb/usx2y/us122l.c @@ -234,29 +234,26 @@ struct file *file, poll_table *wait) { struct us122l *us122l = hw->private_data; - struct usb_stream *s = us122l->sk.s; unsigned *polled; unsigned int mask; poll_wait(file, &us122l->sk.sleep, wait); - switch (s->state) { - case usb_stream_ready: - if (us122l->first == file) - polled = &s->periods_polled; - else - polled = &us122l->second_periods_polled; - if (*polled != s->periods_done) { - *polled = s->periods_done; - mask = POLLIN | POLLOUT | POLLWRNORM; - break; + mask = POLLIN | POLLOUT | POLLWRNORM | POLLERR; + if (mutex_trylock(&us122l->mutex)) { + struct usb_stream *s = us122l->sk.s; + if (s && s->state == usb_stream_ready) { + if (us122l->first == file) + polled = &s->periods_polled; + else + polled = &us122l->second_periods_polled; + if (*polled != s->periods_done) { + *polled = s->periods_done; + mask = POLLIN | POLLOUT | POLLWRNORM; + } else + mask = 0; } - /* Fall through */ - mask = 0; - break; - default: - mask = POLLIN | POLLOUT | POLLWRNORM | POLLERR; - break; + mutex_unlock(&us122l->mutex); } return mask; } @@ -342,6 +339,7 @@ { struct usb_stream_config *cfg; struct us122l *us122l = hw->private_data; + struct usb_stream *s; unsigned min_period_frames; int err = 0; bool high_speed; @@ -387,18 +385,18 @@ snd_power_wait(hw->card, SNDRV_CTL_POWER_D0); mutex_lock(&us122l->mutex); + s = us122l->sk.s; if (!us122l->master) us122l->master = file; else if (us122l->master != file) { - if (memcmp(cfg, &us122l->sk.s->cfg, sizeof(*cfg))) { + if (!s || memcmp(cfg, &s->cfg, sizeof(*cfg))) { err = -EIO; goto unlock; } us122l->slave = file; } - if (!us122l->sk.s || - memcmp(cfg, &us122l->sk.s->cfg, sizeof(*cfg)) || - us122l->sk.s->state == usb_stream_xrun) { + if (!s || memcmp(cfg, &s->cfg, sizeof(*cfg)) || + s->state == usb_stream_xrun) { us122l_stop(us122l); if (!us122l_start(us122l, cfg->sample_rate, cfg->period_frames)) err = -EIO; @@ -409,6 +407,7 @@ mutex_unlock(&us122l->mutex); free: kfree(cfg); + wake_up_all(&us122l->sk.sleep); return err; } --- linux-mvl-dove-2.6.32.orig/sound/usb/caiaq/midi.c +++ linux-mvl-dove-2.6.32/sound/usb/caiaq/midi.c @@ -135,7 +135,7 @@ if (ret < 0) return ret; - strcpy(rmidi->name, device->product_name); + strlcpy(rmidi->name, device->product_name, sizeof(rmidi->name)); rmidi->info_flags = SNDRV_RAWMIDI_INFO_DUPLEX; rmidi->private_data = device; --- linux-mvl-dove-2.6.32.orig/sound/usb/caiaq/audio.c +++ linux-mvl-dove-2.6.32/sound/usb/caiaq/audio.c @@ -639,7 +639,7 @@ } dev->pcm->private_data = dev; - strcpy(dev->pcm->name, dev->product_name); + strlcpy(dev->pcm->name, dev->product_name, sizeof(dev->pcm->name)); memset(dev->sub_playback, 0, sizeof(dev->sub_playback)); memset(dev->sub_capture, 0, sizeof(dev->sub_capture)); --- linux-mvl-dove-2.6.32.orig/include/Kbuild +++ linux-mvl-dove-2.6.32/include/Kbuild @@ -9,4 +9,3 @@ header-y += video/ header-y += drm/ header-y += xen/ -header-y += scsi/ --- linux-mvl-dove-2.6.32.orig/include/mtd/mtd-abi.h +++ linux-mvl-dove-2.6.32/include/mtd/mtd-abi.h @@ -134,7 +134,7 @@ */ struct nand_ecclayout { __u32 eccbytes; - __u32 eccpos[64]; + __u32 eccpos[128]; __u32 oobavail; struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES]; }; --- linux-mvl-dove-2.6.32.orig/include/sound/soc-dapm.h +++ linux-mvl-dove-2.6.32/include/sound/soc-dapm.h @@ -46,25 +46,25 @@ /* platform domain */ #define SND_SOC_DAPM_INPUT(wname) \ { .id = snd_soc_dapm_input, .name = wname, .kcontrols = NULL, \ - .num_kcontrols = 0} + .num_kcontrols = 0, .reg = SND_SOC_NOPM } #define SND_SOC_DAPM_OUTPUT(wname) \ { .id = snd_soc_dapm_output, .name = wname, .kcontrols = NULL, \ - .num_kcontrols = 0} + .num_kcontrols = 0, .reg = SND_SOC_NOPM } #define SND_SOC_DAPM_MIC(wname, wevent) \ { .id = snd_soc_dapm_mic, .name = wname, .kcontrols = NULL, \ - .num_kcontrols = 0, .event = wevent, \ + .num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \ .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD} #define SND_SOC_DAPM_HP(wname, wevent) \ { .id = snd_soc_dapm_hp, .name = wname, .kcontrols = NULL, \ - .num_kcontrols = 0, .event = wevent, \ + .num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \ .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD} #define SND_SOC_DAPM_SPK(wname, wevent) \ { .id = snd_soc_dapm_spk, .name = wname, .kcontrols = NULL, \ - .num_kcontrols = 0, .event = wevent, \ + .num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \ .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD} #define SND_SOC_DAPM_LINE(wname, wevent) \ { .id = snd_soc_dapm_line, .name = wname, .kcontrols = NULL, \ - .num_kcontrols = 0, .event = wevent, \ + .num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \ .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD} /* path domain */ @@ -129,11 +129,11 @@ /* events that are pre and post DAPM */ #define SND_SOC_DAPM_PRE(wname, wevent) \ { .id = snd_soc_dapm_pre, .name = wname, .kcontrols = NULL, \ - .num_kcontrols = 0, .event = wevent, \ + .num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \ .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD} #define SND_SOC_DAPM_POST(wname, wevent) \ { .id = snd_soc_dapm_post, .name = wname, .kcontrols = NULL, \ - .num_kcontrols = 0, .event = wevent, \ + .num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \ .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD} /* stream domain */ --- linux-mvl-dove-2.6.32.orig/include/sound/soc.h +++ linux-mvl-dove-2.6.32/include/sound/soc.h @@ -519,6 +519,7 @@ struct snd_soc_pcm_runtime { struct snd_soc_dai_link *dai; struct snd_soc_device *socdev; + struct snd_pcm_ops pcm_ops; }; /* mixer control */ --- linux-mvl-dove-2.6.32.orig/include/sound/emu10k1.h +++ linux-mvl-dove-2.6.32/include/sound/emu10k1.h @@ -1707,6 +1707,7 @@ unsigned int card_type; /* EMU10K1_CARD_* */ unsigned int ecard_ctrl; /* ecard control bits */ unsigned long dma_mask; /* PCI DMA mask */ + unsigned int delay_pcm_irq; /* in samples */ int max_cache_pages; /* max memory size / PAGE_SIZE */ struct snd_dma_buffer silent_page; /* silent page */ struct snd_dma_buffer ptb_pages; /* page table pages */ --- linux-mvl-dove-2.6.32.orig/include/video/kg2.h +++ linux-mvl-dove-2.6.32/include/video/kg2.h @@ -0,0 +1,56 @@ +/* + * kg2.h - Linux Driver for Marvell 88DE2750 Digital Video Format Converter + */ + +#ifndef __KG2_H__ +#define __KG2_H__ + +// Copied from "88DE2750/sdk/2750_core/private/88DE2750/avc/cmdapp/inc/avc27xx_cmd.h" + + +//AVC_CMD_SIGNAL_POLARITY is used in the AVC_CMD_TIMING_PARAM structure +typedef enum tagAVC_CMD_SIGNAL_POLARITY +{ + AVC_CMD_POLARITY_NO_INVERT = 0, + AVC_CMD_POLARITY_INVERT + +}AVC_CMD_SIGNAL_POLARITY; + +//AVC_CMD_ASPECT_RATIO is used in the AVC_CMD_TIMING_PARAM structure +typedef enum tagAVC_CMD_ASPECT_RATIO +{ + AVC_CMD_ASP_RATIO_4_3 = 0, + AVC_CMD_ASP_RATIO_16_9 + +}AVC_CMD_ASPECT_RATIO; + +//AVC_CMD_TIMING_PARAM to be used when the SUBCMD is AVC_SUBCMD_INPUT_RES_MANUAL_SEL only (Common for Input/Output) +typedef struct tagAVC_CMD_PARAM_TIMING +{ + unsigned short HTotal; + unsigned short HActive; + unsigned short HFrontPorch; + unsigned char HSyncWidth; + AVC_CMD_SIGNAL_POLARITY HPolarity; + + unsigned short VTotal; + unsigned short VActive; + unsigned short VFrontPorch; + unsigned char VSyncWidth; + AVC_CMD_SIGNAL_POLARITY VPolarity; + + AVC_CMD_ASPECT_RATIO AspRatio; + unsigned char IsProgressive; + + unsigned short RefRate; + +}AVC_CMD_TIMING_PARAM, *PAVC_CMD_TIMING_PARAM; + +// Copied from "88DE2750/sdk/2750_core/private/88DE2750/avc/cmdapp/inc/avc27xx_cmd.h" - + +int kg2_run_script(const unsigned char * array, int count); +int kg2_i2c_write(unsigned char baseaddr, unsigned char subaddr, const unsigned char * data, unsigned short dataLen); +int kg2_initialize(void); +int kg2_set_input_timing(AVC_CMD_TIMING_PARAM * timing); +int kg2_set_output_timing(AVC_CMD_TIMING_PARAM * timing); + +#endif --- linux-mvl-dove-2.6.32.orig/include/video/dovefbreg.h +++ linux-mvl-dove-2.6.32/include/video/dovefbreg.h @@ -0,0 +1,639 @@ +/* + * linux/include/video/dovefbreg.h -- Marvell frame buffer for DOVE + * + * + * Copyright (C) Marvell Semiconductor Company. All rights reserved. + * + * Written by Green Wan + * + * Adapted from: linux/drivers/video/skeletonfb.c + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + * + */ +#ifndef _DOVEFB_REG_H_ +#define _DOVEFB_REG_H_ + +/* ------------< LCD register >------------ */ +/* Video Frame 0&1 start address registers */ +#define LCD_SPU_ADV_REG 0x0084 + +/* Video Frame 0&1 start address registers */ +#define LCD_SPU_DMA_START_ADDR_Y0 0x00C0 +#define LCD_SPU_DMA_START_ADDR_U0 0x00C4 +#define LCD_SPU_DMA_START_ADDR_V0 0x00C8 +#define LCD_CFG_DMA_START_ADDR_0 0x00CC /* Cmd address */ +#define LCD_SPU_DMA_START_ADDR_Y1 0x00D0 +#define LCD_SPU_DMA_START_ADDR_U1 0x00D4 +#define LCD_SPU_DMA_START_ADDR_V1 0x00D8 +#define LCD_CFG_DMA_START_ADDR_1 0x00DC /* Cmd address */ + +/* YC & UV Pitch */ +#define LCD_SPU_DMA_PITCH_YC 0x00E0 +#define SPU_DMA_PITCH_C(c) (c<<16) +#define SPU_DMA_PITCH_Y(y) (y) +#define LCD_SPU_DMA_PITCH_UV 0x00E4 +#define SPU_DMA_PITCH_V(v) (v<<16) +#define SPU_DMA_PITCH_U(u) (u) + +/* Video Starting Point on Screen Register */ +#define LCD_SPUT_DMA_OVSA_HPXL_VLN 0x00E8 +#define CFG_DMA_OVSA_VLN(y) (y<<16) /* 0~0xfff */ +#define CFG_DMA_OVSA_HPXL(x) (x) /* 0~0xfff */ + +/* Video Size Register */ +#define LCD_SPU_DMA_HPXL_VLN 0x00EC +#define CFG_DMA_VLN(y) (y<<16) +#define CFG_DMA_HPXL(x) (x) + +/* Video Size After zooming Register */ +#define LCD_SPU_DZM_HPXL_VLN 0x00F0 +#define CFG_DZM_VLN(y) (y<<16) +#define CFG_DZM_HPXL(x) (x) + +/* Graphic Frame 0&1 Starting Address Register */ +#define LCD_CFG_GRA_START_ADDR0 0x00F4 +#define LCD_CFG_GRA_START_ADDR1 0x00F8 + +/* Graphic Frame Pitch */ +#define LCD_CFG_GRA_PITCH 0x00FC + +/* Graphic Starting Point on Screen Register */ +#define LCD_SPU_GRA_OVSA_HPXL_VLN 0x0100 +#define CFG_GRA_OVSA_VLN(y) (y<<16) +#define CFG_GRA_OVSA_HPXL(x) (x) + +/* Graphic Size Register */ +#define LCD_SPU_GRA_HPXL_VLN 0x0104 +#define CFG_GRA_VLN(y) (y<<16) +#define CFG_GRA_HPXL(x) (x) + +/* Graphic Size after Zooming Register */ +#define LCD_SPU_GZM_HPXL_VLN 0x0108 +#define CFG_GZM_VLN(y) (y<<16) +#define CFG_GZM_HPXL(x) (x) + +/* HW Cursor Starting Point on Screen Register */ +#define LCD_SPU_HWC_OVSA_HPXL_VLN 0x010C +#define CFG_HWC_OVSA_VLN(y) (y<<16) +#define CFG_HWC_OVSA_HPXL(x) (x) + +/* HW Cursor Size */ +#define LCD_SPU_HWC_HPXL_VLN 0x0110 +#define CFG_HWC_VLN(y) (y<<16) +#define CFG_HWC_HPXL(x) (x) + +/* Total Screen Size Register */ +#define LCD_SPUT_V_H_TOTAL 0x0114 +#define CFG_V_TOTAL(y) ((y)<<16) +#define CFG_H_TOTAL(x) (x) + +/* Total Screen Active Size Register */ +#define LCD_SPU_V_H_ACTIVE 0x0118 +#define CFG_V_ACTIVE(y) ((y)<<16) +#define CFG_H_ACTIVE(x) (x) + +/* Screen H&V Porch Register */ +#define LCD_SPU_H_PORCH 0x011C +#define CFG_H_BACK_PORCH(b) (b<<16) +#define CFG_H_FRONT_PORCH(f) (f) +#define LCD_SPU_V_PORCH 0x0120 +#define CFG_V_BACK_PORCH(b) (b<<16) +#define CFG_V_FRONT_PORCH(f) (f) + +/* Screen Blank Color Register */ +#define LCD_SPU_BLANKCOLOR 0x0124 +#define CFG_BLANKCOLOR_MASK 0x00FFFFFF +#define CFG_BLANKCOLOR_R_MASK 0x000000FF +#define CFG_BLANKCOLOR_G_MASK 0x0000FF00 +#define CFG_BLANKCOLOR_B_MASK 0x00FF0000 + +/* HW Cursor Color 1&2 Register */ +#define LCD_SPU_ALPHA_COLOR1 0x0128 +#define CFG_HWC_COLOR1 0x00FFFFFF +#define CFG_HWC_COLOR1_R(red) (red<<16) +#define CFG_HWC_COLOR1_G(green) (green<<8) +#define CFG_HWC_COLOR1_B(blue) (blue) +#define CFG_HWC_COLOR1_R_MASK 0x000000FF +#define CFG_HWC_COLOR1_G_MASK 0x0000FF00 +#define CFG_HWC_COLOR1_B_MASK 0x00FF0000 +#define LCD_SPU_ALPHA_COLOR2 0x012C +#define CFG_HWC_COLOR2 0x00FFFFFF +#define CFG_HWC_COLOR2_R_MASK 0x000000FF +#define CFG_HWC_COLOR2_G_MASK 0x0000FF00 +#define CFG_HWC_COLOR2_B_MASK 0x00FF0000 + +/* Video YUV Color Key Control */ +#define LCD_SPU_COLORKEY_Y 0x0130 +#define CFG_CKEY_Y2(y2) ((y2)<<24) +#define CFG_CKEY_Y2_MASK 0xFF000000 +#define CFG_CKEY_Y1(y1) ((y1)<<16) +#define CFG_CKEY_Y1_MASK 0x00FF0000 +#define CFG_CKEY_Y(y) ((y)<<8) +#define CFG_CKEY_Y_MASK 0x0000FF00 +#define CFG_ALPHA_Y(y) (y) +#define CFG_ALPHA_Y_MASK 0x000000FF +#define LCD_SPU_COLORKEY_U 0x0134 +#define CFG_CKEY_U2(u2) ((u2)<<24) +#define CFG_CKEY_U2_MASK 0xFF000000 +#define CFG_CKEY_U1(u1) ((u1)<<16) +#define CFG_CKEY_U1_MASK 0x00FF0000 +#define CFG_CKEY_U(u) ((u)<<8) +#define CFG_CKEY_U_MASK 0x0000FF00 +#define CFG_ALPHA_U(u) (u) +#define CFG_ALPHA_U_MASK 0x000000FF +#define LCD_SPU_COLORKEY_V 0x0138 +#define CFG_CKEY_V2(v2) ((v2)<<24) +#define CFG_CKEY_V2_MASK 0xFF000000 +#define CFG_CKEY_V1(v1) ((v1)<<16) +#define CFG_CKEY_V1_MASK 0x00FF0000 +#define CFG_CKEY_V(v) ((v)<<8) +#define CFG_CKEY_V_MASK 0x0000FF00 +#define CFG_ALPHA_V(v) (v) +#define CFG_ALPHA_V_MASK 0x000000FF + +/* LCD General Configuration Register */ +#define LCD_CFG_RDREG4F 0x013C + +/* SPI Read Data Register */ +#define LCD_SPU_SPI_RXDATA 0x0140 + +/* Smart Panel Read Data Register */ +#define LCD_SPU_ISA_RSDATA 0x0144 +#define ISA_RXDATA_16BIT_1_DATA_MASK 0x000000FF +#define ISA_RXDATA_16BIT_2_DATA_MASK 0x0000FF00 +#define ISA_RXDATA_16BIT_3_DATA_MASK 0x00FF0000 +#define ISA_RXDATA_16BIT_4_DATA_MASK 0xFF000000 +#define ISA_RXDATA_32BIT_1_DATA_MASK 0x00FFFFFF + +/* HWC SRAM Read Data Register */ +#define LCD_SPU_HWC_RDDAT 0x0158 + +/* Gamma Table SRAM Read Data Register */ +#define LCD_SPU_GAMMA_RDDAT 0x015c +#define CFG_GAMMA_RDDAT_MASK 0x000000FF + +/* Palette Table SRAM Read Data Register */ +#define LCD_SPU_PALETTE_RDDAT 0x0160 +#define CFG_PALETTE_RDDAT_MASK 0x00FFFFFF + +/* I/O Pads Input Read Only Register */ +#define LCD_SPU_IOPAD_IN 0x0178 +#define CFG_IOPAD_IN_MASK 0x0FFFFFFF + +/* Reserved Read Only Registers */ +#define LCD_CFG_RDREG5F 0x017C +#define IRE_FRAME_CNT_MASK 0x000000C0 +#define IPE_FRAME_CNT_MASK 0x00000030 +#define GRA_FRAME_CNT_MASK 0x0000000C /* Graphic */ +#define DMA_FRAME_CNT_MASK 0x00000003 /* Video */ + +/* SPI Control Register. */ +#define LCD_SPU_SPI_CTRL 0x0180 +#define CFG_SCLKCNT(div) (div<<24) /* 0xFF~0x2 */ +#define CFG_SCLKCNT_MASK 0xFF000000 +#define CFG_RXBITS(rx) (rx<<16) /* 0x1F~0x1 */ +#define CFG_RXBITS_MASK 0x00FF0000 +#define CFG_TXBITS(tx) (tx<<8) /* 0x1F~0x1 */ +#define CFG_TXBITS_MASK 0x0000FF00 +#define CFG_CLKINV(clk) (clk<<7) +#define CFG_CLKINV_MASK 0x00000080 +#define CFG_KEEPXFER(transfer) (transfer<<6) +#define CFG_KEEPXFER_MASK 0x00000040 +#define CFG_RXBITSTO0(rx) (rx<<5) +#define CFG_RXBITSTO0_MASK 0x00000020 +#define CFG_TXBITSTO0(tx) (tx<<4) +#define CFG_TXBITSTO0_MASK 0x00000010 +#define CFG_SPI_ENA(spi) (spi<<3) +#define CFG_SPI_ENA_MASK 0x00000008 +#define CFG_SPI_SEL(spi) (spi<<2) +#define CFG_SPI_SEL_MASK 0x00000004 +#define CFG_SPI_3W4WB(wire) (wire<<1) +#define CFG_SPI_3W4WB_MASK 0x00000002 +#define CFG_SPI_START(start) (start) +#define CFG_SPI_START_MASK 0x00000001 + +/* SPI Tx Data Register */ +#define LCD_SPU_SPI_TXDATA 0x0184 + +/* + 1. Smart Pannel 8-bit Bus Control Register. + 2. AHB Slave Path Data Port Register +*/ +#define LCD_SPU_SMPN_CTRL 0x0188 + +/* DMA Control 0 Register */ +#define LCD_SPU_DMA_CTRL0 0x0190 +#define CFG_NOBLENDING(nb) (nb<<31) +#define CFG_NOBLENDING_MASK 0x80000000 +#define CFG_GAMMA_ENA(gn) (gn<<30) +#define CFG_GAMMA_ENA_MASK 0x40000000 +#define CFG_CBSH_ENA(cn) (cn<<29) +#define CFG_CBSH_ENA_MASK 0x20000000 +#define CFG_PALETTE_ENA(pn) (pn<<28) +#define CFG_PALETTE_ENA_MASK 0x10000000 +#define CFG_ARBFAST_ENA(an) (an<<27) +#define CFG_ARBFAST_ENA_MASK 0x08000000 +#define CFG_HWC_1BITMOD(mode) (mode<<26) +#define CFG_HWC_1BITMOD_MASK 0x04000000 +#define CFG_HWC_1BITENA(mn) (mn<<25) +#define CFG_HWC_1BITENA_MASK 0x02000000 +#define CFG_HWC_ENA(cn) (cn<<24) +#define CFG_HWC_ENA_MASK 0x01000000 +#define CFG_DMAFORMAT(dmaformat) (dmaformat<<20) +#define CFG_DMAFORMAT_MASK 0x00F00000 +#define CFG_GRAFORMAT(graformat) (graformat<<16) +#define CFG_GRAFORMAT_MASK 0x000F0000 +/* for graphic part */ +#define CFG_GRA_FTOGGLE(toggle) (toggle<<15) +#define CFG_GRA_FTOGGLE_MASK 0x00008000 +#define CFG_GRA_HSMOOTH(smooth) (smooth<<14) +#define CFG_GRA_HSMOOTH_MASK 0x00004000 +#define CFG_GRA_TSTMODE(test) (test<<13) +#define CFG_GRA_TSTMODE_MASK 0x00002000 +#define CFG_GRA_SWAPRB(swap) (swap<<12) +#define CFG_GRA_SWAPRB_MASK 0x00001000 +#define CFG_GRA_SWAPUV(swap) (swap<<11) +#define CFG_GRA_SWAPUV_MASK 0x00000800 +#define CFG_GRA_SWAPYU(swap) (swap<<10) +#define CFG_GRA_SWAPYU_MASK 0x00000400 +#define CFG_YUV2RGB_GRA(cvrt) (cvrt<<9) +#define CFG_YUV2RGB_GRA_MASK 0x00000200 +#define CFG_GRA_ENA(gra) (gra<<8) +#define CFG_GRA_ENA_MASK 0x00000100 +/* for video part */ +#define CFG_DMA_FTOGGLE(toggle) (toggle<<7) +#define CFG_DMA_FTOGGLE_MASK 0x00000080 +#define CFG_DMA_HSMOOTH(smooth) (smooth<<6) +#define CFG_DMA_HSMOOTH_MASK 0x00000040 +#define CFG_DMA_TSTMODE(test) (test<<5) +#define CFG_DMA_TSTMODE_MASK 0x00000020 +#define CFG_DMA_SWAPRB(swap) (swap<<4) +#define CFG_DMA_SWAPRB_MASK 0x00000010 +#define CFG_DMA_SWAPUV(swap) (swap<<3) +#define CFG_DMA_SWAPUV_MASK 0x00000008 +#define CFG_DMA_SWAPYU(swap) (swap<<2) +#define CFG_DMA_SWAPYU_MASK 0x00000004 +#define CFG_DMA_SWAP_MASK 0x0000001C +#define CFG_YUV2RGB_DMA(cvrt) (cvrt<<1) +#define CFG_YUV2RGB_DMA_MASK 0x00000002 +#define CFG_DMA_ENA(video) (video) +#define CFG_DMA_ENA_MASK 0x00000001 + +/* DMA Control 1 Register */ +#define LCD_SPU_DMA_CTRL1 0x0194 +#define CFG_FRAME_TRIG(trig) (trig<<31) +#define CFG_FRAME_TRIG_MASK 0x80000000 +#define CFG_VSYNC_TRIG(trig) (trig<<28) +#define CFG_VSYNC_TRIG_MASK 0x70000000 +#define CFG_VSYNC_INV(inv) (inv<<27) +#define CFG_VSYNC_INV_MASK 0x08000000 +#define CFG_COLOR_KEY_MODE(cmode) (cmode<<24) +#define CFG_COLOR_KEY_MASK 0x07000000 +#define CFG_CARRY(carry) (carry<<23) +#define CFG_CARRY_MASK 0x00800000 +#define CFG_LNBUF_ENA(lnbuf) (lnbuf<<22) +#define CFG_LNBUF_ENA_MASK 0x00400000 +#define CFG_GATED_ENA(gated) (gated<<21) +#define CFG_GATED_ENA_MASK 0x00200000 +#define CFG_PWRDN_ENA(power) (power<<20) +#define CFG_PWRDN_ENA_MASK 0x00100000 +#define CFG_DSCALE(dscale) (dscale<<18) +#define CFG_DSCALE_MASK 0x000C0000 +#define CFG_ALPHA_MODE(amode) (amode<<16) +#define CFG_ALPHA_MODE_MASK 0x00030000 +#define CFG_ALPHA(alpha) (alpha<<8) +#define CFG_ALPHA_MASK 0x0000FF00 +#define CFG_PXLCMD(pxlcmd) (pxlcmd) +#define CFG_PXLCMD_MASK 0x000000FF + +/* SRAM Control Register */ +#define LCD_SPU_SRAM_CTRL 0x0198 +#define CFG_SRAM_INIT_WR_RD(mode) (mode<<14) +#define CFG_SRAM_INIT_WR_RD_MASK 0x0000C000 +#define CFG_SRAM_ADDR_LCDID(id) (id<<8) +#define CFG_SRAM_ADDR_LCDID_MASK 0x00000F00 +#define CFG_SRAM_ADDR(addr) (addr) +#define CFG_SRAM_ADDR_MASK 0x000000FF + +/* SRAM Write Data Register */ +#define LCD_SPU_SRAM_WRDAT 0x019C + +/* SRAM RTC/WTC Control Register */ +#define LCD_SPU_SRAM_PARA0 0x01A0 + +/* SRAM Power Down Control Register */ +#define LCD_SPU_SRAM_PARA1 0x01A4 +#define CFG_CSB_256x32(hwc) (hwc<<15) /* HWC */ +#define CFG_CSB_256x32_MASK 0x00008000 +#define CFG_CSB_256x24(palette) (palette<<14) /* Palette */ +#define CFG_CSB_256x24_MASK 0x00004000 +#define CFG_CSB_256x8(gamma) (gamma<<13) /* Gamma */ +#define CFG_CSB_256x8_MASK 0x00002000 +#define CFG_PDWN256x32(pdwn) (pdwn<<7) /* HWC */ +#define CFG_PDWN256x32_MASK 0x00000080 +#define CFG_PDWN256x24(pdwn) (pdwn<<6) /* Palette */ +#define CFG_PDWN256x24_MASK 0x00000040 +#define CFG_PDWN256x8(pdwn) (pdwn<<5) /* Gamma */ +#define CFG_PDWN256x8_MASK 0x00000020 +#define CFG_PDWN32x32(pdwn) (pdwn<<3) +#define CFG_PDWN32x32_MASK 0x00000008 +#define CFG_PDWN16x66(pdwn) (pdwn<<2) +#define CFG_PDWN16x66_MASK 0x00000004 +#define CFG_PDWN32x66(pdwn) (pdwn<<1) +#define CFG_PDWN32x66_MASK 0x00000002 +#define CFG_PDWN64x66(pdwn) (pdwn) +#define CFG_PDWN64x66_MASK 0x00000001 + +/* Smart or Dumb Panel Clock Divider */ +#define LCD_CFG_SCLK_DIV 0x01A8 +#define SCLK_SOURCE_SELECT(src) (src<<31) +#define SCLK_SOURCE_SELECT_MASK 0x80000000 +#define CLK_FRACDIV(frac) (frac<<16) +#define CLK_FRACDIV_MASK 0x0FFF0000 +#define CLK_INT_DIV(div) (div) +#define CLK_INT_DIV_MASK 0x0000FFFF + +/* Video Contrast Register */ +#define LCD_SPU_CONTRAST 0x01AC +#define CFG_BRIGHTNESS(bright) (bright<<16) +#define CFG_BRIGHTNESS_MASK 0xFFFF0000 +#define CFG_CONTRAST(contrast) (contrast) +#define CFG_CONTRAST_MASK 0x0000FFFF + +/* Video Saturation Register */ +#define LCD_SPU_SATURATION 0x01B0 +#define CFG_C_MULTS(mult) (mult<<16) +#define CFG_C_MULTS_MASK 0xFFFF0000 +#define CFG_SATURATION(sat) (sat) +#define CFG_SATURATION_MASK 0x0000FFFF + +/* Video Hue Adjust Register */ +#define LCD_SPU_CBSH_HUE 0x01B4 +#define CFG_SIN0(sin0) (sin0<<16) +#define CFG_SIN0_MASK 0xFFFF0000 +#define CFG_COS0(con0) (con0) +#define CFG_COS0_MASK 0x0000FFFF + +/* Dump LCD Panel Control Register */ +#define LCD_SPU_DUMB_CTRL 0x01B8 +#define CFG_DUMBMODE(mode) (mode<<28) +#define CFG_DUMBMODE_MASK 0xF0000000 +#define CFG_LCDGPIO_O(data) (data<<20) +#define CFG_LCDGPIO_O_MASK 0x0FF00000 +#define CFG_LCDGPIO_ENA(gpio) (gpio<<12) +#define CFG_LCDGPIO_ENA_MASK 0x000FF000 +#define CFG_BIAS_OUT(bias) (bias<<8) +#define CFG_BIAS_OUT_MASK 0x00000100 +#define CFG_REVERSE_RGB(rRGB) (rRGB<<7) +#define CFG_REVERSE_RGB_MASK 0x00000080 +#define CFG_INV_COMPBLANK(blank) (blank<<6) +#define CFG_INV_COMPBLANK_MASK 0x00000040 +#define CFG_INV_COMPSYNC(sync) (sync<<5) +#define CFG_INV_COMPSYNC_MASK 0x00000020 +#define CFG_INV_HENA(hena) (hena<<4) +#define CFG_INV_HENA_MASK 0x00000010 +#define CFG_INV_VSYNC(vsync) (vsync<<3) +#define CFG_INV_VSYNC_MASK 0x00000008 +#define CFG_INV_HSYNC(hsync) (hsync<<2) +#define CFG_INV_HSYNC_MASK 0x00000004 +#define CFG_INV_PCLK(pclk) (pclk<<1) +#define CFG_INV_PCLK_MASK 0x00000002 +#define CFG_DUMB_ENA(dumb) (dumb) +#define CFG_DUMB_ENA_MASK 0x00000001 + +/* LCD I/O Pads Control Register */ +#define SPU_IOPAD_CONTROL 0x01BC +#define CFG_GRA_VM_ENA(vm) (vm<<15) /* gfx */ +#define CFG_GRA_VM_ENA_MASK 0x00008000 +#define CFG_DMA_VM_ENA(vm) (vm<<13) /* video */ +#define CFG_DMA_VM_ENA_MASK 0x00002000 +#define CFG_CMD_VM_ENA(vm) (vm<<13) +#define CFG_CMD_VM_ENA_MASK 0x00000800 +#define CFG_CSC(csc) (csc<<8) /* csc */ +#define CFG_CSC_MASK 0x00000300 +#define CFG_AXICTRL(axi) (axi<<4) +#define CFG_AXICTRL_MASK 0x000000F0 +#define CFG_IOPADMODE(iopad) (iopad) +#define CFG_IOPADMODE_MASK 0x0000000F + +/* LCD Interrupt Control Register */ +#define SPU_IRQ_ENA 0x01C0 +#define DMA_FRAME_IRQ0_ENA(irq) (irq<<31) +#define DMA_FRAME_IRQ0_ENA_MASK 0x80000000 +#define DMA_FRAME_IRQ1_ENA(irq) (irq<<30) +#define DMA_FRAME_IRQ1_ENA_MASK 0x40000000 +#define DMA_FF_UNDERFLOW_ENA(ff) (ff<<29) +#define DMA_FF_UNDERFLOW_ENA_MASK 0x20000000 +#define GRA_FRAME_IRQ0_ENA(irq) (irq<<27) +#define GRA_FRAME_IRQ0_ENA_MASK 0x08000000 +#define GRA_FRAME_IRQ1_ENA(irq) (irq<<26) +#define GRA_FRAME_IRQ1_ENA_MASK 0x04000000 +#define GRA_FF_UNDERFLOW_ENA(ff) (ff<<25) +#define GRA_FF_UNDERFLOW_ENA_MASK 0x02000000 +#define VSYNC_IRQ_ENA(vsync_irq) (vsync_irq<<23) +#define VSYNC_IRQ_ENA_MASK 0x00800000 +#define DUMB_FRAMEDONE_ENA(fdone) (fdone<<22) +#define DUMB_FRAMEDONE_ENA_MASK 0x00400000 +#define TWC_FRAMEDONE_ENA(fdone) (fdone<<21) +#define TWC_FRAMEDONE_ENA_MASK 0x00200000 +#define HWC_FRAMEDONE_ENA(fdone) (fdone<<20) +#define HWC_FRAMEDONE_ENA_MASK 0x00100000 +#define SLV_IRQ_ENA(irq) (irq<<19) +#define SLV_IRQ_ENA_MASK 0x00080000 +#define SPI_IRQ_ENA(irq) (irq<<18) +#define SPI_IRQ_ENA_MASK 0x00040000 +#define PWRDN_IRQ_ENA(irq) (irq<<17) +#define PWRDN_IRQ_ENA_MASK 0x00020000 +#define ERR_IRQ_ENA(irq) (irq<<16) +#define ERR_IRQ_ENA_MASK 0x00010000 +#define CLEAN_SPU_IRQ_ISR(irq) (irq) +#define CLEAN_SPU_IRQ_ISR_MASK 0x0000FFFF + +/* LCD Interrupt Status Register */ +#define SPU_IRQ_ISR 0x01C4 +#define DMA_FRAME_IRQ0(irq) (irq<<31) +#define DMA_FRAME_IRQ0_MASK 0x80000000 +#define DMA_FRAME_IRQ1(irq) (irq<<30) +#define DMA_FRAME_IRQ1_MASK 0x40000000 +#define DMA_FF_UNDERFLOW(ff) (ff<<29) +#define DMA_FF_UNDERFLOW_MASK 0x20000000 +#define GRA_FRAME_IRQ0(irq) (irq<<27) +#define GRA_FRAME_IRQ0_MASK 0x08000000 +#define GRA_FRAME_IRQ1(irq) (irq<<26) +#define GRA_FRAME_IRQ1_MASK 0x04000000 +#define GRA_FF_UNDERFLOW(ff) (ff<<25) +#define GRA_FF_UNDERFLOW_MASK 0x02000000 +#define VSYNC_IRQ(vsync_irq) (vsync_irq<<23) +#define VSYNC_IRQ_MASK 0x00800000 +#define DUMB_FRAMEDONE(fdone) (fdone<<22) +#define DUMB_FRAMEDONE_MASK 0x00400000 +#define TWC_FRAMEDONE(fdone) (fdone<<21) +#define TWC_FRAMEDONE_MASK 0x00200000 +#define HWC_FRAMEDONE(fdone) (fdone<<20) +#define HWC_FRAMEDONE_MASK 0x00100000 +#define SLV_IRQ(irq) (irq<<19) +#define SLV_IRQ_MASK 0x00080000 +#define SPI_IRQ(irq) (irq<<18) +#define SPI_IRQ_MASK 0x00040000 +#define PWRDN_IRQ(irq) (irq<<17) +#define PWRDN_IRQ_MASK 0x00020000 +#define ERR_IRQ(irq) (irq<<16) +#define ERR_IRQ_MASK 0x00010000 +/* read-only */ +#define DMA_FRAME_IRQ0_LEVEL_MASK 0x00008000 +#define DMA_FRAME_IRQ1_LEVEL_MASK 0x00004000 +#define DMA_FRAME_CNT_ISR_MASK 0x00003000 +#define GRA_FRAME_IRQ0_LEVEL_MASK 0x00000800 +#define GRA_FRAME_IRQ1_LEVEL_MASK 0x00000400 +#define GRA_FRAME_CNT_ISR_MASK 0x00000300 +#define VSYNC_IRQ_LEVEL_MASK 0x00000080 +#define DUMB_FRAMEDONE_LEVEL_MASK 0x00000040 +#define TWC_FRAMEDONE_LEVEL_MASK 0x00000020 +#define HWC_FRAMEDONE_LEVEL_MASK 0x00000010 +#define SLV_FF_EMPTY_MASK 0x00000008 +#define DMA_FF_ALLEMPTY_MASK 0x00000004 +#define GRA_FF_ALLEMPTY_MASK 0x00000002 +#define PWRDN_IRQ_LEVEL_MASK 0x00000001 + +/* + * interrupt definition. + */ +#define DOVEFB_VSYNC_INT_MASK (VSYNC_IRQ_ENA_MASK) +#define DOVEFB_VID_INT_MASK (DMA_FRAME_IRQ0_ENA_MASK |\ + DMA_FRAME_IRQ1_ENA_MASK) +#define DOVEFB_GFX_INT_MASK (GRA_FRAME_IRQ0_ENA_MASK |\ + GRA_FRAME_IRQ1_ENA_MASK) + +/* + * defined Video Memory Color format for DMA control 0 register + * DMA0 bit[23:20] + */ +#define VMODE_RGB565 0x0 +#define VMODE_RGB1555 0x1 +#define VMODE_RGB888PACKED 0x2 +#define VMODE_RGB888UNPACKED 0x3 +#define VMODE_RGBA888 0x4 +#define VMODE_YUV422PACKED 0x5 +#define VMODE_YUV422PLANAR 0x6 +#define VMODE_YUV420PLANAR 0x7 +#define VMODE_SMPNCMD 0x8 +#define VMODE_PALETTE4BIT 0x9 +#define VMODE_PALETTE8BIT 0xa +#define VMODE_RESERVED 0xb + +/* + * defined Graphic Memory Color format for DMA control 0 register + * DMA0 bit[19:16] + */ +#define GMODE_RGB565 0x0 +#define GMODE_RGB1555 0x1 +#define GMODE_RGB888PACKED 0x2 +#define GMODE_RGB888UNPACKED 0x3 +#define GMODE_RGBA888 0x4 +#define GMODE_YUV422PACKED 0x5 +#define GMODE_YUV422PLANAR 0x6 +#define GMODE_YUV420PLANAR 0x7 +#define GMODE_SMPNCMD 0x8 +#define GMODE_PALETTE4BIT 0x9 +#define GMODE_PALETTE8BIT 0xa +#define GMODE_RESERVED 0xb + +/* + * define for DMA control 1 register + */ +#define DMA1_FRAME_TRIG 31 /* bit location */ +#define DMA1_VSYNC_MODE 28 +#define DMA1_VSYNC_INV 27 +#define DMA1_CKEY 24 +#define DMA1_CARRY 23 +#define DMA1_LNBUF_ENA 22 +#define DMA1_GATED_ENA 21 +#define DMA1_PWRDN_ENA 20 +#define DMA1_DSCALE 18 +#define DMA1_ALPHA_MODE 16 +#define DMA1_ALPHA 08 +#define DMA1_PXLCMD 00 + +/* + * defined for Configure Dumb Mode + * DUMB LCD Panel bit[31:28] + */ +#define DUMB16_RGB565_0 0x0 +#define DUMB16_RGB565_1 0x1 +#define DUMB18_RGB666_0 0x2 +#define DUMB18_RGB666_1 0x3 +#define DUMB12_RGB444_0 0x4 +#define DUMB12_RGB444_1 0x5 +#define DUMB24_RGB888_0 0x6 +#define DUMB_BLANK 0x7 + +/* + * defined for Configure I/O Pin Allocation Mode + * LCD LCD I/O Pads control register bit[3:0] + */ +#define IOPAD_DUMB24 0x0 +#define IOPAD_DUMB18SPI 0x1 +#define IOPAD_DUMB18GPIO 0x2 +#define IOPAD_DUMB16SPI 0x3 +#define IOPAD_DUMB16GPIO 0x4 +#define IOPAD_DUMB12 0x5 +#define IOPAD_SMART18SPI 0x6 +#define IOPAD_SMART16SPI 0x7 +#define IOPAD_SMART8BOTH 0x8 + +/* + * defined Dumb Panel Clock Divider register + * SCLK_Source bit[31] + */ +#define AXI_BUS_SEL 0x80000000 /* 0: PLL clock select*/ +#define CCD_CLK_SEL 0x40000000 +#define DCON_CLK_SEL 0x20000000 +#define ENA_CLK_INT_DIV CONFIG_FB_DOVE_CLCD_SCLK_DIV +#define IDLE_CLK_INT_DIV 0x1 /* idle Integer Divider */ +#define DIS_CLK_INT_DIV 0x0 /* Disable Integer Divider */ + +/* SRAM ID */ +#define SRAMID_gamma_yr 0x0 +#define SRAMID_gamma_ug 0x1 +#define SRAMID_gamma_vb 0x2 +#define SRAMID_palette 0x3 +#define SRAMID_hwc 0xf + +/* SRAM INIT Read/Write */ +#define SRAMID_INIT_READ 0x0 +#define SRAMID_INIT_WRITE 0x2 +#define SRAMID_INIT_DEFAULT 0x3 + +/* + * defined VSYNC selection mode for DMA control 1 register + * DMA1 bit[30:28] + */ +#define VMODE_SMPN 0x0 +#define VMODE_SMPNIRQ 0x1 +#define VMODE_DUMB 0x2 +#define VMODE_IPE 0x3 +#define VMODE_IRE 0x4 + +/* + * defined Configure Alpha and Alpha mode for DMA control 1 register + * DMA1 bit[15:08](alpha) / bit[17:16](alpha mode) + */ +/* ALPHA mode */ +#define MODE_ALPHA_DMA 0x0 +#define MODE_ALPHA_GRA 0x1 +#define MODE_ALPHA_CFG 0x2 + +/* alpha value */ +#define ALPHA_NOGRAPHIC 0xFF /* all video, no graphic */ +#define ALPHA_NOVIDEO 0x00 /* all graphic, no video */ +#define ALPHA_GRAPHnVIDEO 0x0F /* Selects graphic & video */ + +/* + * defined Pixel Command for DMA control 1 register + * DMA1 bit[07:00] + */ +#define PIXEL_CMD 0x81 +#endif --- linux-mvl-dove-2.6.32.orig/include/video/dovefb.h +++ linux-mvl-dove-2.6.32/include/video/dovefb.h @@ -0,0 +1,491 @@ +/* + * linux/include/video/dovefb.h -- Marvell frame buffer for DOVE + * + * + * Copyright (C) Marvell Semiconductor Company. All rights reserved. + * + * Written by Green Wan + * + * Adapted from: linux/drivers/video/skeletonfb.c + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + * + */ +#ifndef _DOVEFB_H_ +#define _DOVEFB_H_ + +/* ---------------------------------------------- */ +/* Header Files */ +/* ---------------------------------------------- */ +#include + +/* ---------------------------------------------- */ +/* IOCTL Definition */ +/* ---------------------------------------------- */ +#define DOVEFB_IOC_MAGIC 'm' +#define DOVEFB_IOCTL_CONFIG_CURSOR _IO(DOVEFB_IOC_MAGIC, 0) +#define DOVEFB_IOCTL_DUMP_REGS _IO(DOVEFB_IOC_MAGIC, 1) +#define DOVEFB_IOCTL_CLEAR_IRQ _IO(DOVEFB_IOC_MAGIC, 2) + +/* + * There are many video mode supported. + */ +#define DOVEFB_IOCTL_SET_VIDEO_MODE _IO(DOVEFB_IOC_MAGIC, 3) +#define DOVEFB_IOCTL_GET_VIDEO_MODE _IO(DOVEFB_IOC_MAGIC, 4) +/* Request a new video buffer from driver. User program needs to free + * this memory. + */ +#define DOVEFB_IOCTL_CREATE_VID_BUFFER _IO(DOVEFB_IOC_MAGIC, 5) + +/* Configure viewport in driver. */ +#define DOVEFB_IOCTL_SET_VIEWPORT_INFO _IO(DOVEFB_IOC_MAGIC, 6) +#define DOVEFB_IOCTL_GET_VIEWPORT_INFO _IO(DOVEFB_IOC_MAGIC, 7) + +/* Flip the video buffer from user mode. Vide buffer can be separated into: + * a. Current-used buffer - user program put any data into it. It will be + * displayed immediately. + * b. Requested from driver but not current-used - user programe can put any + * data into it. It will be displayed after calling + * DOVEFB_IOCTL_FLIP_VID_BUFFER. + * User program should free this memory when they don't use it any more. + * c. User program alloated - user program can allocated a contiguos DMA + * buffer to store its video data. And flip it to driver. Notices that + * this momory should be free by user programs. Driver won't take care of + * this. + */ +#define DOVEFB_IOCTL_FLIP_VID_BUFFER _IO(DOVEFB_IOC_MAGIC, 8) + +/* Get the current buffer information. User program could use it to display + * anything directly. If developer wants to allocate multiple video layers, + * try to use DOVEFB_IOCTL_CREATE_VID_BUFFER to request a brand new video + * buffer. + */ +#define DOVEFB_IOCTL_GET_BUFF_ADDR _IO(DOVEFB_IOC_MAGIC, 9) + +/* Get/Set offset position of screen */ +#define DOVEFB_IOCTL_SET_VID_OFFSET _IO(DOVEFB_IOC_MAGIC, 10) +#define DOVEFB_IOCTL_GET_VID_OFFSET _IO(DOVEFB_IOC_MAGIC, 11) + +/* Turn on the memory toggle function to improve the frame rate while playing + * movie. + */ +#define DOVEFB_IOCTL_SET_MEMORY_TOGGLE _IO(DOVEFB_IOC_MAGIC, 12) + +/* Turn on the memory toggle function to improve the frame rate while playing + * movie. + */ +#define DOVEFB_IOCTL_SET_COLORKEYnALPHA _IO(DOVEFB_IOC_MAGIC, 13) +#define DOVEFB_IOCTL_GET_COLORKEYnALPHA _IO(DOVEFB_IOC_MAGIC, 14) +#define DOVEFB_IOCTL_SWITCH_GRA_OVLY _IO(DOVEFB_IOC_MAGIC, 15) +#define DOVEFB_IOCTL_SWITCH_VID_OVLY _IO(DOVEFB_IOC_MAGIC, 16) + +/* For Vmeta integration */ +#define DOVEFB_IOCTL_GET_FREELIST _IO(DOVEFB_IOC_MAGIC, 17) + +/* Wait for vsync happen. */ +#define DOVEFB_IOCTL_WAIT_VSYNC _IO(DOVEFB_IOC_MAGIC, 18) + +/* for xv+vmeta/sw decoder w/o memory move. */ +#define DOVEFB_IOCTL_GET_FBPA _IO(DOVEFB_IOC_MAGIC, 19) +#define DOVEFB_IOCTL_GET_FBID _IO(DOVEFB_IOC_MAGIC, 20) +#define DOVEFB_IOCTL_SET_SRC_MODE _IO(DOVEFB_IOC_MAGIC, 21) +#define DOVEFB_IOCTL_GET_SRC_MODE _IO(DOVEFB_IOC_MAGIC, 22) + +/* Dynamic get EDID data */ +#define DOVEFB_IOCTL_GET_EDID_INFO _IO(DOVEFB_IOC_MAGIC, 23) +#define DOVEFB_IOCTL_GET_EDID_DATA _IO(DOVEFB_IOC_MAGIC, 24) +#define DOVEFB_IOCTL_SET_EDID_INTERVAL _IO(DOVEFB_IOC_MAGIC, 25) + +/* clear framebuffer: Makes resolution or color space changes look nicer */ +#define FBIO_CLEAR_FRAMEBUFFER _IO(FB_IOC_MAGIC, 19) + +/* Global alpha blend controls - Maintaining compatibility with existing + user programs. */ +#define FBIOPUT_VIDEO_ALPHABLEND 0xeb +#define FBIOPUT_GLOBAL_ALPHABLEND 0xe1 +#define FBIOPUT_GRAPHIC_ALPHABLEND 0xe2 + +/* color swapping */ +#define FBIOPUT_SWAP_GRAPHIC_RED_BLUE 0xe3 +#define FBIOPUT_SWAP_GRAPHIC_U_V 0xe4 +#define FBIOPUT_SWAP_GRAPHIC_Y_UV 0xe5 +#define FBIOPUT_SWAP_VIDEO_RED_BLUE 0xe6 +#define FBIOPUT_SWAP_VIDEO_U_V 0xe7 +#define FBIOPUT_SWAP_VIDEO_Y_UV 0xe8 + +/* colorkey compatibility */ +#define FBIOGET_CHROMAKEYS 0xe9 +#define FBIOPUT_CHROMAKEYS 0xea + +#define DOVEFB_VMODE_RGB565 0x100 +#define DOVEFB_VMODE_BGR565 0x101 +#define DOVEFB_VMODE_RGB1555 0x102 +#define DOVEFB_VMODE_BGR1555 0x103 +#define DOVEFB_VMODE_RGB888PACK 0x104 +#define DOVEFB_VMODE_BGR888PACK 0x105 +#define DOVEFB_VMODE_RGB888UNPACK 0x106 +#define DOVEFB_VMODE_BGR888UNPACK 0x107 +#define DOVEFB_VMODE_RGBA888 0x108 +#define DOVEFB_VMODE_BGRA888 0x109 + +#define DOVEFB_VMODE_YUV422PACKED 0x0 +#define DOVEFB_VMODE_YUV422PACKED_SWAPUV 0x1 +#define DOVEFB_VMODE_YUV422PACKED_SWAPYUorV 0x2 +#define DOVEFB_VMODE_YUV422PLANAR 0x3 +#define DOVEFB_VMODE_YUV422PLANAR_SWAPUV 0x4 +#define DOVEFB_VMODE_YUV422PLANAR_SWAPYUorV 0x5 +#define DOVEFB_VMODE_YUV420PLANAR 0x6 +#define DOVEFB_VMODE_YUV420PLANAR_SWAPUV 0x7 +#define DOVEFB_VMODE_YUV420PLANAR_SWAPYUorV 0x8 + +#define DOVEFB_HWCMODE_1BITMODE 0x0 +#define DOVEFB_HWCMODE_2BITMODE 0x1 + +#define DOVEFB_DISABLE_COLORKEY_MODE 0x0 +#define DOVEFB_ENABLE_Y_COLORKEY_MODE 0x1 +#define DOVEFB_ENABLE_U_COLORKEY_MODE 0x2 +#define DOVEFB_ENABLE_V_COLORKEY_MODE 0x4 +#define DOVEFB_ENABLE_RGB_COLORKEY_MODE 0x3 +#define DOVEFB_ENABLE_R_COLORKEY_MODE 0x5 +#define DOVEFB_ENABLE_G_COLORKEY_MODE 0x6 +#define DOVEFB_ENABLE_B_COLORKEY_MODE 0x7 + +#define DOVEFB_VID_PATH_ALPHA 0x0 +#define DOVEFB_GRA_PATH_ALPHA 0x1 +#define DOVEFB_CONFIG_ALPHA 0x2 + +#define DOVEFB_SYNC_COLORKEY_TO_CHROMA 1 +#define DOVEFB_SYNC_CHROMA_TO_COLORKEY 2 + +/* Compatible to pxa168. */ +#define FB_IOCTL_SET_COLORKEYnALPHA _IO(FB_IOC_MAGIC, 13) +#define FB_IOCTL_GET_COLORKEYnALPHA _IO(FB_IOC_MAGIC, 14) +#define FB_VID_PATH_ALPHA 0x0 +#define FB_GRA_PATH_ALPHA 0x1 +#define FB_CONFIG_ALPHA 0x2 + +#define FB_SYNC_COLORKEY_TO_CHROMA 1 +#define FB_SYNC_CHROMA_TO_COLORKEY 2 + +#define DOVEFB_FB_NUM 2 + +/* ---------------------------------------------- */ +/* Data Structure */ +/* ---------------------------------------------- */ +struct _sEdidInfo { + int connect; /* is monitor connected */ + int change; /* is edid data changed */ + int extension; /* the number of extension edid block */ + int interval; /* the interval to check edid */ +}; +/* + * The follow structures are used to pass data from + * user space into the kernel for the creation of + * overlay surfaces and setting the video mode. + */ + +#define DOVEFBVideoMode signed int + +struct _sViewPortInfo { + unsigned short srcWidth; /* video source size */ + unsigned short srcHeight; + unsigned short zoomXSize; /* size after zooming */ + unsigned short zoomYSize; + unsigned short ycPitch; + unsigned short uvPitch; +}; + +struct _sViewPortOffset { + unsigned short xOffset; /* position on screen */ + unsigned short yOffset; +}; + +struct _sVideoBufferAddr { + unsigned char frameID; /* which frame wants */ + unsigned char *startAddr; /* new buffer (PA) */ + unsigned char *inputData; /* input buf address (VA) */ + unsigned int length; /* input data's length */ +}; + +struct dovefb_chroma { + u_char mode; + u_char y_alpha; + u_char y; + u_char y1; + u_char y2; + u_char u_alpha; + u_char u; + u_char u1; + u_char u2; + u_char v_alpha; + u_char v; + u_char v1; + u_char v2; +}; + +struct _sColorKeyNAlpha { + unsigned int mode; + unsigned int alphapath; + unsigned int config; + unsigned int Y_ColorAlpha; + unsigned int U_ColorAlpha; + unsigned int V_ColorAlpha; +}; + +struct _sOvlySurface { + DOVEFBVideoMode videoMode; + struct _sViewPortInfo viewPortInfo; + struct _sViewPortOffset viewPortOffset; + struct _sVideoBufferAddr videoBufferAddr; +}; + +struct _sCursorConfig { + unsigned char enable; /* enable cursor or not */ + unsigned char mode; /* 1bit or 2bit mode */ + unsigned int color1; /* foreground color */ + unsigned int color2; /* background color */ + unsigned short xoffset; + unsigned short yoffset; + unsigned short width; + unsigned short height; + unsigned char *pBuffer; /* cursor data */ +}; + +#define SHM_NORMAL 0x01 +#define SHM_VMETA 0x02 +#define SHM_SOFTWARE_MAP 0x04 + +struct shm_private_info { + unsigned int method; + unsigned int fbid; + unsigned int format; + unsigned int width; + unsigned int height; + unsigned long fb_pa; +}; + +/* MAX bytes per yuv pixel. */ +#define MAX_YUV_PIXEL 2 + +/* Dumb interface */ +#define DOVEFB_PINS_DUMB_24 0 +#define DOVEFB_PINS_DUMB_18_SPI 1 +#define DOVEFB_PINS_DUMB_18_GPIO 2 +#define DOVEFB_PINS_DUMB_16_SPI 3 +#define DOVEFB_PINS_DUMB_16_GPIO 4 +#define DOVEFB_PINS_DUMB_12_SPI_GPIO 5 +#define DOVEFB_PINS_SMART_18_SPI 6 +#define DOVEFB_PINS_SMART_16_SPI 7 +#define DOVEFB_PINS_SMART_8_SPI_GPIO 8 + +/* Dumb interface pin allocation */ +#define DOVEFB_DUMB_PANEL_RGB565 0 +#define DOVEFB_DUMB_PANEL_RGB565_UPPER 1 +#define DOVEFB_DUMB_PANEL_RGB666 2 +#define DOVEFB_DUMB_PANEL_RGB666_UPPER 3 +#define DOVEFB_DUMB_PANEL_RGB444 4 +#define DOVEFB_DUMB_PANEL_RGB444_UPPER 5 +#define DOVEFB_DUMB_PANEL_RGB888 6 + +/* Max fb buffer. 1048x2048-32bits */ +#define DEFAULT_FB_SIZE (1024 * 2048 * 4) + +/* + * Buffer pixel format + * bit0 is for rb swap. + * bit12 is for Y UorV swap + */ +#define PIX_FMT_RGB565 0 +#define PIX_FMT_BGR565 1 +#define PIX_FMT_RGB1555 2 +#define PIX_FMT_BGR1555 3 +#define PIX_FMT_RGB888PACK 4 +#define PIX_FMT_BGR888PACK 5 +#define PIX_FMT_RGB888UNPACK 6 +#define PIX_FMT_BGR888UNPACK 7 +#define PIX_FMT_RGBA888 8 +#define PIX_FMT_BGRA888 9 +#define PIX_FMT_YUV422PACK 10 +#define PIX_FMT_YVU422PACK 11 +#define PIX_FMT_YUV422PLANAR 12 +#define PIX_FMT_YVU422PLANAR 13 +#define PIX_FMT_YUV420PLANAR 14 +#define PIX_FMT_YVU420PLANAR 15 +#define PIX_FMT_PSEUDOCOLOR 20 +#define PIX_FMT_UYVY422PACK (0x1000|PIX_FMT_YUV422PACK) + +#ifdef __KERNEL__ +#include + +enum dovefb_type { + DOVEFB_GFX_PLANE, + DOVEFB_OVLY_PLANE +}; + +#define MRVL_AXI_CLK 0 +#define MRVL_EXT_CLK0 1 +#define MRVL_PLL_CLK 2 +#define MRVL_EXT_CLK1 3 + +struct dovefb_layer_info { + struct device *dev; + enum dovefb_type type; + struct dovefb_info *info; + struct fb_info *fb_info; + + void *reg_base; + + unsigned long new_addr; + dma_addr_t fb_start_dma; + void *fb_start; + int fb_size; + atomic_t w_intr; + wait_queue_head_t w_intr_wq; + struct mutex access_ok; + struct _sOvlySurface surface; + struct _sColorKeyNAlpha ckey_alpha; + + unsigned char *hwc_buf; + unsigned int pseudo_palette[16]; + struct tasklet_struct tasklet; + char *mode_option; + + int ddc_polling_disable; + struct timer_list get_edid_timer; + unsigned char* raw_edid; + struct _sEdidInfo edid_info; + struct work_struct work_queue; + + int pix_fmt; + unsigned is_blanked:1; + unsigned cursor_enabled:1; + unsigned cursor_cfg:1; + unsigned active:1; + unsigned enabled:1; + unsigned checkbuf_timer_exist:1; + + /* + * 0: DMA mem is from DMA region. + * 1: DMA mem is from normal region. + */ + unsigned mem_status:1; + + /* + * current frame id for mapping to user. + */ + int cur_fbid; + int src_mode; + + unsigned int reserved; +}; + +/* + * Dove LCD controller private state. + */ +struct dovefb_info { + struct device *dev; + int id; + + void *reg_base; + struct dovefb_layer_info *gfx_plane; + struct dovefb_layer_info *vid_plane; + + struct fb_videomode dft_vmode; + struct fb_videomode out_vmode; + int fixed_output; + + char *mode_option; + struct clk *clk; + int clk_src; + int io_pin_allocation; + + int pix_fmt; + unsigned edid:1; + unsigned panel_rbswap:1; + unsigned edid_en:1; + + /* Hardware cursor related registers */ + unsigned int LCD_SPU_HWC_HPXL_VLN_saved_value; + unsigned int LCD_SPU_ALPHA_COLOR1_saved_value; + unsigned int LCD_SPU_ALPHA_COLOR2_saved_value; + + /* Colorkey related registers */ + unsigned int LCD_SPU_COLORKEY_Y_saved_value; + unsigned int LCD_SPU_COLORKEY_U_saved_value; + unsigned int LCD_SPU_COLORKEY_V_saved_value; + unsigned int LCD_SPU_DMA_CTRL1_saved_value; + unsigned int LCD_SPU_ADV_REG_saved_value; +}; + +/* + * Dove fb machine information + */ +struct dovefb_mach_info { + char id_gfx[16]; + char id_ovly[16]; + int clk_src; + int accurate_clk; + char *clk_name; + int num_modes; + struct fb_videomode *modes; + + /* + * Pix_fmt + */ + unsigned pix_fmt; + + /* + * I/O pin allocation. + */ + unsigned io_pin_allocation:4; + /* + * auto poll EDID data periodically + */ + unsigned ddc_polling_disable:1; + + /* + * I2C bus and address to read DDC data through. -1 not available + */ + int ddc_i2c_adapter; + int ddc_i2c_address; + + + /* + * Dumb panel -- assignment of R/G/B component info to the 24 + * available external data lanes. + */ + unsigned panel_rgb_type:4; + unsigned panel_rgb_reverse_lanes:1; + + /* + * Dumb panel -- GPIO output data. + */ + unsigned gpio_output_mask:8; + unsigned gpio_output_data:8; + + /* + * Dumb panel -- configurable output signal polarity. + */ + unsigned invert_composite_blank:1; + unsigned invert_pix_val_ena:1; + unsigned invert_pixclock:1; + unsigned invert_vsync:1; + unsigned invert_hsync:1; + unsigned panel_rbswap:1; + unsigned active:1; + unsigned enable_lcd0:1; +}; + +struct dovebl_platform_data; + +int clcd_platform_init(struct dovefb_mach_info *lcd0_dmi_data, + struct dovefb_mach_info *lcd0_vid_dmi_data, + struct dovefb_mach_info *lcd1_dmi_data, + struct dovefb_mach_info *lcd1_vid_dmi_data, + struct dovebl_platform_data *backlight_data); + + +#endif /* _KERNEL_ */ +#endif /* _DOVEFB_H_ */ --- linux-mvl-dove-2.6.32.orig/include/video/dovefb_display.h +++ linux-mvl-dove-2.6.32/include/video/dovefb_display.h @@ -0,0 +1,67 @@ +/* + * linux/include/video/dovefb_display.h -- Marvell display configuration driver + * + * Copyright (C) Marvell Semiconductor Company. All rights reserved. + * + * Written by Green Wan + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + */ +#ifndef _DOVEDISPLAY_H_ +#define _DOVEDISPLAY_H_ + +#include +#include