Path: blob/master/sound/pci/ice1712/prodigy_hifi.c
10817 views
/*1* ALSA driver for ICEnsemble VT1724 (Envy24HT)2*3* Lowlevel functions for Audiotrak Prodigy 7.1 Hifi4* based on pontis.c5*6* Copyright (c) 2007 Julian Scheel <[email protected]>7* Copyright (c) 2007 allank8* Copyright (c) 2004 Takashi Iwai <[email protected]>9*10* This program is free software; you can redistribute it and/or modify11* it under the terms of the GNU General Public License as published by12* the Free Software Foundation; either version 2 of the License, or13* (at your option) any later version.14*15* This program is distributed in the hope that it will be useful,16* but WITHOUT ANY WARRANTY; without even the implied warranty of17* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the18* GNU General Public License for more details.19*20* You should have received a copy of the GNU General Public License21* along with this program; if not, write to the Free Software22* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA23*24*/252627#include <asm/io.h>28#include <linux/delay.h>29#include <linux/interrupt.h>30#include <linux/init.h>31#include <linux/slab.h>32#include <linux/mutex.h>3334#include <sound/core.h>35#include <sound/info.h>36#include <sound/tlv.h>3738#include "ice1712.h"39#include "envy24ht.h"40#include "prodigy_hifi.h"4142struct prodigy_hifi_spec {43unsigned short master[2];44unsigned short vol[8];45};4647/* I2C addresses */48#define WM_DEV 0x344950/* WM8776 registers */51#define WM_HP_ATTEN_L 0x00 /* headphone left attenuation */52#define WM_HP_ATTEN_R 0x01 /* headphone left attenuation */53#define WM_HP_MASTER 0x02 /* headphone master (both channels),54override LLR */55#define WM_DAC_ATTEN_L 0x03 /* digital left attenuation */56#define WM_DAC_ATTEN_R 0x0457#define WM_DAC_MASTER 0x0558#define WM_PHASE_SWAP 0x06 /* DAC phase swap */59#define WM_DAC_CTRL1 0x0760#define WM_DAC_MUTE 0x0861#define WM_DAC_CTRL2 0x0962#define WM_DAC_INT 0x0a63#define WM_ADC_INT 0x0b64#define WM_MASTER_CTRL 0x0c65#define WM_POWERDOWN 0x0d66#define WM_ADC_ATTEN_L 0x0e67#define WM_ADC_ATTEN_R 0x0f68#define WM_ALC_CTRL1 0x1069#define WM_ALC_CTRL2 0x1170#define WM_ALC_CTRL3 0x1271#define WM_NOISE_GATE 0x1372#define WM_LIMITER 0x1473#define WM_ADC_MUX 0x1574#define WM_OUT_MUX 0x1675#define WM_RESET 0x177677/* Analog Recording Source :- Mic, LineIn, CD/Video, */7879/* implement capture source select control for WM8776 */8081#define WM_AIN1 "AIN1"82#define WM_AIN2 "AIN2"83#define WM_AIN3 "AIN3"84#define WM_AIN4 "AIN4"85#define WM_AIN5 "AIN5"8687/* GPIO pins of envy24ht connected to wm8766 */88#define WM8766_SPI_CLK (1<<17) /* CLK, Pin97 on ICE1724 */89#define WM8766_SPI_MD (1<<16) /* DATA VT1724 -> WM8766, Pin96 */90#define WM8766_SPI_ML (1<<18) /* Latch, Pin98 */9192/* WM8766 registers */93#define WM8766_DAC_CTRL 0x02 /* DAC Control */94#define WM8766_INT_CTRL 0x03 /* Interface Control */95#define WM8766_DAC_CTRL2 0x0996#define WM8766_DAC_CTRL3 0x0a97#define WM8766_RESET 0x1f98#define WM8766_LDA1 0x0099#define WM8766_LDA2 0x04100#define WM8766_LDA3 0x06101#define WM8766_RDA1 0x01102#define WM8766_RDA2 0x05103#define WM8766_RDA3 0x07104#define WM8766_MUTE1 0x0C105#define WM8766_MUTE2 0x0F106107108/*109* Prodigy HD2110*/111#define AK4396_ADDR 0x00112#define AK4396_CSN (1 << 8) /* CSN->GPIO8, pin 75 */113#define AK4396_CCLK (1 << 9) /* CCLK->GPIO9, pin 76 */114#define AK4396_CDTI (1 << 10) /* CDTI->GPIO10, pin 77 */115116/* ak4396 registers */117#define AK4396_CTRL1 0x00118#define AK4396_CTRL2 0x01119#define AK4396_CTRL3 0x02120#define AK4396_LCH_ATT 0x03121#define AK4396_RCH_ATT 0x04122123124/*125* get the current register value of WM codec126*/127static unsigned short wm_get(struct snd_ice1712 *ice, int reg)128{129reg <<= 1;130return ((unsigned short)ice->akm[0].images[reg] << 8) |131ice->akm[0].images[reg + 1];132}133134/*135* set the register value of WM codec and remember it136*/137static void wm_put_nocache(struct snd_ice1712 *ice, int reg, unsigned short val)138{139unsigned short cval;140cval = (reg << 9) | val;141snd_vt1724_write_i2c(ice, WM_DEV, cval >> 8, cval & 0xff);142}143144static void wm_put(struct snd_ice1712 *ice, int reg, unsigned short val)145{146wm_put_nocache(ice, reg, val);147reg <<= 1;148ice->akm[0].images[reg] = val >> 8;149ice->akm[0].images[reg + 1] = val;150}151152/*153* write data in the SPI mode154*/155156static void set_gpio_bit(struct snd_ice1712 *ice, unsigned int bit, int val)157{158unsigned int tmp = snd_ice1712_gpio_read(ice);159if (val)160tmp |= bit;161else162tmp &= ~bit;163snd_ice1712_gpio_write(ice, tmp);164}165166/*167* SPI implementation for WM8766 codec - only writing supported, no readback168*/169170static void wm8766_spi_send_word(struct snd_ice1712 *ice, unsigned int data)171{172int i;173for (i = 0; i < 16; i++) {174set_gpio_bit(ice, WM8766_SPI_CLK, 0);175udelay(1);176set_gpio_bit(ice, WM8766_SPI_MD, data & 0x8000);177udelay(1);178set_gpio_bit(ice, WM8766_SPI_CLK, 1);179udelay(1);180data <<= 1;181}182}183184static void wm8766_spi_write(struct snd_ice1712 *ice, unsigned int reg,185unsigned int data)186{187unsigned int block;188189snd_ice1712_gpio_set_dir(ice, WM8766_SPI_MD|190WM8766_SPI_CLK|WM8766_SPI_ML);191snd_ice1712_gpio_set_mask(ice, ~(WM8766_SPI_MD|192WM8766_SPI_CLK|WM8766_SPI_ML));193/* latch must be low when writing */194set_gpio_bit(ice, WM8766_SPI_ML, 0);195block = (reg << 9) | (data & 0x1ff);196wm8766_spi_send_word(ice, block); /* REGISTER ADDRESS */197/* release latch */198set_gpio_bit(ice, WM8766_SPI_ML, 1);199udelay(1);200/* restore */201snd_ice1712_gpio_set_mask(ice, ice->gpio.write_mask);202snd_ice1712_gpio_set_dir(ice, ice->gpio.direction);203}204205206/*207* serial interface for ak4396 - only writing supported, no readback208*/209210static void ak4396_send_word(struct snd_ice1712 *ice, unsigned int data)211{212int i;213for (i = 0; i < 16; i++) {214set_gpio_bit(ice, AK4396_CCLK, 0);215udelay(1);216set_gpio_bit(ice, AK4396_CDTI, data & 0x8000);217udelay(1);218set_gpio_bit(ice, AK4396_CCLK, 1);219udelay(1);220data <<= 1;221}222}223224static void ak4396_write(struct snd_ice1712 *ice, unsigned int reg,225unsigned int data)226{227unsigned int block;228229snd_ice1712_gpio_set_dir(ice, AK4396_CSN|AK4396_CCLK|AK4396_CDTI);230snd_ice1712_gpio_set_mask(ice, ~(AK4396_CSN|AK4396_CCLK|AK4396_CDTI));231/* latch must be low when writing */232set_gpio_bit(ice, AK4396_CSN, 0);233block = ((AK4396_ADDR & 0x03) << 14) | (1 << 13) |234((reg & 0x1f) << 8) | (data & 0xff);235ak4396_send_word(ice, block); /* REGISTER ADDRESS */236/* release latch */237set_gpio_bit(ice, AK4396_CSN, 1);238udelay(1);239/* restore */240snd_ice1712_gpio_set_mask(ice, ice->gpio.write_mask);241snd_ice1712_gpio_set_dir(ice, ice->gpio.direction);242}243244245/*246* ak4396 mixers247*/248249250251/*252* DAC volume attenuation mixer control (-64dB to 0dB)253*/254255static int ak4396_dac_vol_info(struct snd_kcontrol *kcontrol,256struct snd_ctl_elem_info *uinfo)257{258uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;259uinfo->count = 2;260uinfo->value.integer.min = 0; /* mute */261uinfo->value.integer.max = 0xFF; /* linear */262return 0;263}264265static int ak4396_dac_vol_get(struct snd_kcontrol *kcontrol,266struct snd_ctl_elem_value *ucontrol)267{268struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);269struct prodigy_hifi_spec *spec = ice->spec;270int i;271272for (i = 0; i < 2; i++)273ucontrol->value.integer.value[i] = spec->vol[i];274275return 0;276}277278static int ak4396_dac_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)279{280struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);281struct prodigy_hifi_spec *spec = ice->spec;282int i;283int change = 0;284285mutex_lock(&ice->gpio_mutex);286for (i = 0; i < 2; i++) {287if (ucontrol->value.integer.value[i] != spec->vol[i]) {288spec->vol[i] = ucontrol->value.integer.value[i];289ak4396_write(ice, AK4396_LCH_ATT + i,290spec->vol[i] & 0xff);291change = 1;292}293}294mutex_unlock(&ice->gpio_mutex);295return change;296}297298static const DECLARE_TLV_DB_SCALE(db_scale_wm_dac, -12700, 100, 1);299300static struct snd_kcontrol_new prodigy_hd2_controls[] __devinitdata = {301{302.iface = SNDRV_CTL_ELEM_IFACE_MIXER,303.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |304SNDRV_CTL_ELEM_ACCESS_TLV_READ),305.name = "Front Playback Volume",306.info = ak4396_dac_vol_info,307.get = ak4396_dac_vol_get,308.put = ak4396_dac_vol_put,309.tlv = { .p = db_scale_wm_dac },310},311};312313314/* --------------- */315316/*317* Logarithmic volume values for WM87*6318* Computed as 20 * Log10(255 / x)319*/320static const unsigned char wm_vol[256] = {321127, 48, 42, 39, 36, 34, 33, 31, 30, 29, 28, 27, 27, 26, 25, 25, 24, 24, 23,32223, 22, 22, 21, 21, 21, 20, 20, 20, 19, 19, 19, 18, 18, 18, 18, 17, 17, 17,32317, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 13, 13, 13,32413, 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11,32511, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 8,3268, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6,3276, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,3285, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3,3293, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,3302, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,3311, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,3320, 0333};334335#define WM_VOL_MAX (sizeof(wm_vol) - 1)336#define WM_VOL_MUTE 0x8000337338339#define DAC_0dB 0xff340#define DAC_RES 128341#define DAC_MIN (DAC_0dB - DAC_RES)342343344static void wm_set_vol(struct snd_ice1712 *ice, unsigned int index,345unsigned short vol, unsigned short master)346{347unsigned char nvol;348349if ((master & WM_VOL_MUTE) || (vol & WM_VOL_MUTE))350nvol = 0;351else {352nvol = (((vol & ~WM_VOL_MUTE) * (master & ~WM_VOL_MUTE)) / 128)353& WM_VOL_MAX;354nvol = (nvol ? (nvol + DAC_MIN) : 0) & 0xff;355}356357wm_put(ice, index, nvol);358wm_put_nocache(ice, index, 0x100 | nvol);359}360361static void wm8766_set_vol(struct snd_ice1712 *ice, unsigned int index,362unsigned short vol, unsigned short master)363{364unsigned char nvol;365366if ((master & WM_VOL_MUTE) || (vol & WM_VOL_MUTE))367nvol = 0;368else {369nvol = (((vol & ~WM_VOL_MUTE) * (master & ~WM_VOL_MUTE)) / 128)370& WM_VOL_MAX;371nvol = (nvol ? (nvol + DAC_MIN) : 0) & 0xff;372}373374wm8766_spi_write(ice, index, (0x0100 | nvol));375}376377378/*379* DAC volume attenuation mixer control (-64dB to 0dB)380*/381382static int wm_dac_vol_info(struct snd_kcontrol *kcontrol,383struct snd_ctl_elem_info *uinfo)384{385uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;386uinfo->count = 2;387uinfo->value.integer.min = 0; /* mute */388uinfo->value.integer.max = DAC_RES; /* 0dB, 0.5dB step */389return 0;390}391392static int wm_dac_vol_get(struct snd_kcontrol *kcontrol,393struct snd_ctl_elem_value *ucontrol)394{395struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);396struct prodigy_hifi_spec *spec = ice->spec;397int i;398399for (i = 0; i < 2; i++)400ucontrol->value.integer.value[i] =401spec->vol[2 + i] & ~WM_VOL_MUTE;402return 0;403}404405static int wm_dac_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)406{407struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);408struct prodigy_hifi_spec *spec = ice->spec;409int i, idx, change = 0;410411mutex_lock(&ice->gpio_mutex);412for (i = 0; i < 2; i++) {413if (ucontrol->value.integer.value[i] != spec->vol[2 + i]) {414idx = WM_DAC_ATTEN_L + i;415spec->vol[2 + i] &= WM_VOL_MUTE;416spec->vol[2 + i] |= ucontrol->value.integer.value[i];417wm_set_vol(ice, idx, spec->vol[2 + i], spec->master[i]);418change = 1;419}420}421mutex_unlock(&ice->gpio_mutex);422return change;423}424425426/*427* WM8766 DAC volume attenuation mixer control428*/429static int wm8766_vol_info(struct snd_kcontrol *kcontrol,430struct snd_ctl_elem_info *uinfo)431{432int voices = kcontrol->private_value >> 8;433uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;434uinfo->count = voices;435uinfo->value.integer.min = 0; /* mute */436uinfo->value.integer.max = DAC_RES; /* 0dB */437return 0;438}439440static int wm8766_vol_get(struct snd_kcontrol *kcontrol,441struct snd_ctl_elem_value *ucontrol)442{443struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);444struct prodigy_hifi_spec *spec = ice->spec;445int i, ofs, voices;446447voices = kcontrol->private_value >> 8;448ofs = kcontrol->private_value & 0xff;449for (i = 0; i < voices; i++)450ucontrol->value.integer.value[i] = spec->vol[ofs + i];451return 0;452}453454static int wm8766_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)455{456struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);457struct prodigy_hifi_spec *spec = ice->spec;458int i, idx, ofs, voices;459int change = 0;460461voices = kcontrol->private_value >> 8;462ofs = kcontrol->private_value & 0xff;463mutex_lock(&ice->gpio_mutex);464for (i = 0; i < voices; i++) {465if (ucontrol->value.integer.value[i] != spec->vol[ofs + i]) {466idx = WM8766_LDA1 + ofs + i;467spec->vol[ofs + i] &= WM_VOL_MUTE;468spec->vol[ofs + i] |= ucontrol->value.integer.value[i];469wm8766_set_vol(ice, idx,470spec->vol[ofs + i], spec->master[i]);471change = 1;472}473}474mutex_unlock(&ice->gpio_mutex);475return change;476}477478/*479* Master volume attenuation mixer control / applied to WM8776+WM8766480*/481static int wm_master_vol_info(struct snd_kcontrol *kcontrol,482struct snd_ctl_elem_info *uinfo)483{484uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;485uinfo->count = 2;486uinfo->value.integer.min = 0;487uinfo->value.integer.max = DAC_RES;488return 0;489}490491static int wm_master_vol_get(struct snd_kcontrol *kcontrol,492struct snd_ctl_elem_value *ucontrol)493{494struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);495struct prodigy_hifi_spec *spec = ice->spec;496int i;497for (i = 0; i < 2; i++)498ucontrol->value.integer.value[i] = spec->master[i];499return 0;500}501502static int wm_master_vol_put(struct snd_kcontrol *kcontrol,503struct snd_ctl_elem_value *ucontrol)504{505struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);506struct prodigy_hifi_spec *spec = ice->spec;507int ch, change = 0;508509mutex_lock(&ice->gpio_mutex);510for (ch = 0; ch < 2; ch++) {511if (ucontrol->value.integer.value[ch] != spec->master[ch]) {512spec->master[ch] = ucontrol->value.integer.value[ch];513514/* Apply to front DAC */515wm_set_vol(ice, WM_DAC_ATTEN_L + ch,516spec->vol[2 + ch], spec->master[ch]);517518wm8766_set_vol(ice, WM8766_LDA1 + ch,519spec->vol[0 + ch], spec->master[ch]);520521wm8766_set_vol(ice, WM8766_LDA2 + ch,522spec->vol[4 + ch], spec->master[ch]);523524wm8766_set_vol(ice, WM8766_LDA3 + ch,525spec->vol[6 + ch], spec->master[ch]);526change = 1;527}528}529mutex_unlock(&ice->gpio_mutex);530return change;531}532533534/* KONSTI */535536static int wm_adc_mux_enum_info(struct snd_kcontrol *kcontrol,537struct snd_ctl_elem_info *uinfo)538{539static char* texts[32] = {540"NULL", WM_AIN1, WM_AIN2, WM_AIN1 "+" WM_AIN2,541WM_AIN3, WM_AIN1 "+" WM_AIN3, WM_AIN2 "+" WM_AIN3,542WM_AIN1 "+" WM_AIN2 "+" WM_AIN3,543WM_AIN4, WM_AIN1 "+" WM_AIN4, WM_AIN2 "+" WM_AIN4,544WM_AIN1 "+" WM_AIN2 "+" WM_AIN4,545WM_AIN3 "+" WM_AIN4, WM_AIN1 "+" WM_AIN3 "+" WM_AIN4,546WM_AIN2 "+" WM_AIN3 "+" WM_AIN4,547WM_AIN1 "+" WM_AIN2 "+" WM_AIN3 "+" WM_AIN4,548WM_AIN5, WM_AIN1 "+" WM_AIN5, WM_AIN2 "+" WM_AIN5,549WM_AIN1 "+" WM_AIN2 "+" WM_AIN5,550WM_AIN3 "+" WM_AIN5, WM_AIN1 "+" WM_AIN3 "+" WM_AIN5,551WM_AIN2 "+" WM_AIN3 "+" WM_AIN5,552WM_AIN1 "+" WM_AIN2 "+" WM_AIN3 "+" WM_AIN5,553WM_AIN4 "+" WM_AIN5, WM_AIN1 "+" WM_AIN4 "+" WM_AIN5,554WM_AIN2 "+" WM_AIN4 "+" WM_AIN5,555WM_AIN1 "+" WM_AIN2 "+" WM_AIN4 "+" WM_AIN5,556WM_AIN3 "+" WM_AIN4 "+" WM_AIN5,557WM_AIN1 "+" WM_AIN3 "+" WM_AIN4 "+" WM_AIN5,558WM_AIN2 "+" WM_AIN3 "+" WM_AIN4 "+" WM_AIN5,559WM_AIN1 "+" WM_AIN2 "+" WM_AIN3 "+" WM_AIN4 "+" WM_AIN5560};561562uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;563uinfo->count = 1;564uinfo->value.enumerated.items = 32;565if (uinfo->value.enumerated.item > 31)566uinfo->value.enumerated.item = 31;567strcpy(uinfo->value.enumerated.name,568texts[uinfo->value.enumerated.item]);569return 0;570}571572static int wm_adc_mux_enum_get(struct snd_kcontrol *kcontrol,573struct snd_ctl_elem_value *ucontrol)574{575struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);576577mutex_lock(&ice->gpio_mutex);578ucontrol->value.integer.value[0] = wm_get(ice, WM_ADC_MUX) & 0x1f;579mutex_unlock(&ice->gpio_mutex);580return 0;581}582583static int wm_adc_mux_enum_put(struct snd_kcontrol *kcontrol,584struct snd_ctl_elem_value *ucontrol)585{586struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);587unsigned short oval, nval;588int change = 0;589590mutex_lock(&ice->gpio_mutex);591oval = wm_get(ice, WM_ADC_MUX);592nval = (oval & 0xe0) | ucontrol->value.integer.value[0];593if (nval != oval) {594wm_put(ice, WM_ADC_MUX, nval);595change = 1;596}597mutex_unlock(&ice->gpio_mutex);598return change;599}600601/* KONSTI */602603/*604* ADC gain mixer control (-64dB to 0dB)605*/606607#define ADC_0dB 0xcf608#define ADC_RES 128609#define ADC_MIN (ADC_0dB - ADC_RES)610611static int wm_adc_vol_info(struct snd_kcontrol *kcontrol,612struct snd_ctl_elem_info *uinfo)613{614uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;615uinfo->count = 2;616uinfo->value.integer.min = 0; /* mute (-64dB) */617uinfo->value.integer.max = ADC_RES; /* 0dB, 0.5dB step */618return 0;619}620621static int wm_adc_vol_get(struct snd_kcontrol *kcontrol,622struct snd_ctl_elem_value *ucontrol)623{624struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);625unsigned short val;626int i;627628mutex_lock(&ice->gpio_mutex);629for (i = 0; i < 2; i++) {630val = wm_get(ice, WM_ADC_ATTEN_L + i) & 0xff;631val = val > ADC_MIN ? (val - ADC_MIN) : 0;632ucontrol->value.integer.value[i] = val;633}634mutex_unlock(&ice->gpio_mutex);635return 0;636}637638static int wm_adc_vol_put(struct snd_kcontrol *kcontrol,639struct snd_ctl_elem_value *ucontrol)640{641struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);642unsigned short ovol, nvol;643int i, idx, change = 0;644645mutex_lock(&ice->gpio_mutex);646for (i = 0; i < 2; i++) {647nvol = ucontrol->value.integer.value[i];648nvol = nvol ? (nvol + ADC_MIN) : 0;649idx = WM_ADC_ATTEN_L + i;650ovol = wm_get(ice, idx) & 0xff;651if (ovol != nvol) {652wm_put(ice, idx, nvol);653change = 1;654}655}656mutex_unlock(&ice->gpio_mutex);657return change;658}659660/*661* ADC input mux mixer control662*/663#define wm_adc_mux_info snd_ctl_boolean_mono_info664665static int wm_adc_mux_get(struct snd_kcontrol *kcontrol,666struct snd_ctl_elem_value *ucontrol)667{668struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);669int bit = kcontrol->private_value;670671mutex_lock(&ice->gpio_mutex);672ucontrol->value.integer.value[0] =673(wm_get(ice, WM_ADC_MUX) & (1 << bit)) ? 1 : 0;674mutex_unlock(&ice->gpio_mutex);675return 0;676}677678static int wm_adc_mux_put(struct snd_kcontrol *kcontrol,679struct snd_ctl_elem_value *ucontrol)680{681struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);682int bit = kcontrol->private_value;683unsigned short oval, nval;684int change;685686mutex_lock(&ice->gpio_mutex);687nval = oval = wm_get(ice, WM_ADC_MUX);688if (ucontrol->value.integer.value[0])689nval |= (1 << bit);690else691nval &= ~(1 << bit);692change = nval != oval;693if (change) {694wm_put(ice, WM_ADC_MUX, nval);695}696mutex_unlock(&ice->gpio_mutex);697return 0;698}699700/*701* Analog bypass (In -> Out)702*/703#define wm_bypass_info snd_ctl_boolean_mono_info704705static int wm_bypass_get(struct snd_kcontrol *kcontrol,706struct snd_ctl_elem_value *ucontrol)707{708struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);709710mutex_lock(&ice->gpio_mutex);711ucontrol->value.integer.value[0] =712(wm_get(ice, WM_OUT_MUX) & 0x04) ? 1 : 0;713mutex_unlock(&ice->gpio_mutex);714return 0;715}716717static int wm_bypass_put(struct snd_kcontrol *kcontrol,718struct snd_ctl_elem_value *ucontrol)719{720struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);721unsigned short val, oval;722int change = 0;723724mutex_lock(&ice->gpio_mutex);725val = oval = wm_get(ice, WM_OUT_MUX);726if (ucontrol->value.integer.value[0])727val |= 0x04;728else729val &= ~0x04;730if (val != oval) {731wm_put(ice, WM_OUT_MUX, val);732change = 1;733}734mutex_unlock(&ice->gpio_mutex);735return change;736}737738/*739* Left/Right swap740*/741#define wm_chswap_info snd_ctl_boolean_mono_info742743static int wm_chswap_get(struct snd_kcontrol *kcontrol,744struct snd_ctl_elem_value *ucontrol)745{746struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);747748mutex_lock(&ice->gpio_mutex);749ucontrol->value.integer.value[0] =750(wm_get(ice, WM_DAC_CTRL1) & 0xf0) != 0x90;751mutex_unlock(&ice->gpio_mutex);752return 0;753}754755static int wm_chswap_put(struct snd_kcontrol *kcontrol,756struct snd_ctl_elem_value *ucontrol)757{758struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);759unsigned short val, oval;760int change = 0;761762mutex_lock(&ice->gpio_mutex);763oval = wm_get(ice, WM_DAC_CTRL1);764val = oval & 0x0f;765if (ucontrol->value.integer.value[0])766val |= 0x60;767else768val |= 0x90;769if (val != oval) {770wm_put(ice, WM_DAC_CTRL1, val);771wm_put_nocache(ice, WM_DAC_CTRL1, val);772change = 1;773}774mutex_unlock(&ice->gpio_mutex);775return change;776}777778779/*780* mixers781*/782783static struct snd_kcontrol_new prodigy_hifi_controls[] __devinitdata = {784{785.iface = SNDRV_CTL_ELEM_IFACE_MIXER,786.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |787SNDRV_CTL_ELEM_ACCESS_TLV_READ),788.name = "Master Playback Volume",789.info = wm_master_vol_info,790.get = wm_master_vol_get,791.put = wm_master_vol_put,792.tlv = { .p = db_scale_wm_dac }793},794{795.iface = SNDRV_CTL_ELEM_IFACE_MIXER,796.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |797SNDRV_CTL_ELEM_ACCESS_TLV_READ),798.name = "Front Playback Volume",799.info = wm_dac_vol_info,800.get = wm_dac_vol_get,801.put = wm_dac_vol_put,802.tlv = { .p = db_scale_wm_dac },803},804{805.iface = SNDRV_CTL_ELEM_IFACE_MIXER,806.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |807SNDRV_CTL_ELEM_ACCESS_TLV_READ),808.name = "Rear Playback Volume",809.info = wm8766_vol_info,810.get = wm8766_vol_get,811.put = wm8766_vol_put,812.private_value = (2 << 8) | 0,813.tlv = { .p = db_scale_wm_dac },814},815{816.iface = SNDRV_CTL_ELEM_IFACE_MIXER,817.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |818SNDRV_CTL_ELEM_ACCESS_TLV_READ),819.name = "Center Playback Volume",820.info = wm8766_vol_info,821.get = wm8766_vol_get,822.put = wm8766_vol_put,823.private_value = (1 << 8) | 4,824.tlv = { .p = db_scale_wm_dac }825},826{827.iface = SNDRV_CTL_ELEM_IFACE_MIXER,828.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |829SNDRV_CTL_ELEM_ACCESS_TLV_READ),830.name = "LFE Playback Volume",831.info = wm8766_vol_info,832.get = wm8766_vol_get,833.put = wm8766_vol_put,834.private_value = (1 << 8) | 5,835.tlv = { .p = db_scale_wm_dac }836},837{838.iface = SNDRV_CTL_ELEM_IFACE_MIXER,839.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |840SNDRV_CTL_ELEM_ACCESS_TLV_READ),841.name = "Side Playback Volume",842.info = wm8766_vol_info,843.get = wm8766_vol_get,844.put = wm8766_vol_put,845.private_value = (2 << 8) | 6,846.tlv = { .p = db_scale_wm_dac },847},848{849.iface = SNDRV_CTL_ELEM_IFACE_MIXER,850.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |851SNDRV_CTL_ELEM_ACCESS_TLV_READ),852.name = "Capture Volume",853.info = wm_adc_vol_info,854.get = wm_adc_vol_get,855.put = wm_adc_vol_put,856.tlv = { .p = db_scale_wm_dac },857},858{859.iface = SNDRV_CTL_ELEM_IFACE_MIXER,860.name = "CD Capture Switch",861.info = wm_adc_mux_info,862.get = wm_adc_mux_get,863.put = wm_adc_mux_put,864.private_value = 0,865},866{867.iface = SNDRV_CTL_ELEM_IFACE_MIXER,868.name = "Line Capture Switch",869.info = wm_adc_mux_info,870.get = wm_adc_mux_get,871.put = wm_adc_mux_put,872.private_value = 1,873},874{875.iface = SNDRV_CTL_ELEM_IFACE_MIXER,876.name = "Analog Bypass Switch",877.info = wm_bypass_info,878.get = wm_bypass_get,879.put = wm_bypass_put,880},881{882.iface = SNDRV_CTL_ELEM_IFACE_MIXER,883.name = "Swap Output Channels",884.info = wm_chswap_info,885.get = wm_chswap_get,886.put = wm_chswap_put,887},888{889.iface = SNDRV_CTL_ELEM_IFACE_MIXER,890.name = "Analog Capture Source",891.info = wm_adc_mux_enum_info,892.get = wm_adc_mux_enum_get,893.put = wm_adc_mux_enum_put,894},895};896897/*898* WM codec registers899*/900static void wm_proc_regs_write(struct snd_info_entry *entry,901struct snd_info_buffer *buffer)902{903struct snd_ice1712 *ice = entry->private_data;904char line[64];905unsigned int reg, val;906mutex_lock(&ice->gpio_mutex);907while (!snd_info_get_line(buffer, line, sizeof(line))) {908if (sscanf(line, "%x %x", ®, &val) != 2)909continue;910if (reg <= 0x17 && val <= 0xffff)911wm_put(ice, reg, val);912}913mutex_unlock(&ice->gpio_mutex);914}915916static void wm_proc_regs_read(struct snd_info_entry *entry,917struct snd_info_buffer *buffer)918{919struct snd_ice1712 *ice = entry->private_data;920int reg, val;921922mutex_lock(&ice->gpio_mutex);923for (reg = 0; reg <= 0x17; reg++) {924val = wm_get(ice, reg);925snd_iprintf(buffer, "%02x = %04x\n", reg, val);926}927mutex_unlock(&ice->gpio_mutex);928}929930static void wm_proc_init(struct snd_ice1712 *ice)931{932struct snd_info_entry *entry;933if (!snd_card_proc_new(ice->card, "wm_codec", &entry)) {934snd_info_set_text_ops(entry, ice, wm_proc_regs_read);935entry->mode |= S_IWUSR;936entry->c.text.write = wm_proc_regs_write;937}938}939940static int __devinit prodigy_hifi_add_controls(struct snd_ice1712 *ice)941{942unsigned int i;943int err;944945for (i = 0; i < ARRAY_SIZE(prodigy_hifi_controls); i++) {946err = snd_ctl_add(ice->card,947snd_ctl_new1(&prodigy_hifi_controls[i], ice));948if (err < 0)949return err;950}951952wm_proc_init(ice);953954return 0;955}956957static int __devinit prodigy_hd2_add_controls(struct snd_ice1712 *ice)958{959unsigned int i;960int err;961962for (i = 0; i < ARRAY_SIZE(prodigy_hd2_controls); i++) {963err = snd_ctl_add(ice->card,964snd_ctl_new1(&prodigy_hd2_controls[i], ice));965if (err < 0)966return err;967}968969wm_proc_init(ice);970971return 0;972}973974975/*976* initialize the chip977*/978static int __devinit prodigy_hifi_init(struct snd_ice1712 *ice)979{980static unsigned short wm_inits[] = {981/* These come first to reduce init pop noise */982WM_ADC_MUX, 0x0003, /* ADC mute */983/* 0x00c0 replaced by 0x0003 */984985WM_DAC_MUTE, 0x0001, /* DAC softmute */986WM_DAC_CTRL1, 0x0000, /* DAC mute */987988WM_POWERDOWN, 0x0008, /* All power-up except HP */989WM_RESET, 0x0000, /* reset */990};991static unsigned short wm_inits2[] = {992WM_MASTER_CTRL, 0x0022, /* 256fs, slave mode */993WM_DAC_INT, 0x0022, /* I2S, normal polarity, 24bit */994WM_ADC_INT, 0x0022, /* I2S, normal polarity, 24bit */995WM_DAC_CTRL1, 0x0090, /* DAC L/R */996WM_OUT_MUX, 0x0001, /* OUT DAC */997WM_HP_ATTEN_L, 0x0179, /* HP 0dB */998WM_HP_ATTEN_R, 0x0179, /* HP 0dB */999WM_DAC_ATTEN_L, 0x0000, /* DAC 0dB */1000WM_DAC_ATTEN_L, 0x0100, /* DAC 0dB */1001WM_DAC_ATTEN_R, 0x0000, /* DAC 0dB */1002WM_DAC_ATTEN_R, 0x0100, /* DAC 0dB */1003WM_PHASE_SWAP, 0x0000, /* phase normal */1004#if 01005WM_DAC_MASTER, 0x0100, /* DAC master muted */1006#endif1007WM_DAC_CTRL2, 0x0000, /* no deemphasis, no ZFLG */1008WM_ADC_ATTEN_L, 0x0000, /* ADC muted */1009WM_ADC_ATTEN_R, 0x0000, /* ADC muted */1010#if 11011WM_ALC_CTRL1, 0x007b, /* */1012WM_ALC_CTRL2, 0x0000, /* */1013WM_ALC_CTRL3, 0x0000, /* */1014WM_NOISE_GATE, 0x0000, /* */1015#endif1016WM_DAC_MUTE, 0x0000, /* DAC unmute */1017WM_ADC_MUX, 0x0003, /* ADC unmute, both CD/Line On */1018};1019static unsigned short wm8766_inits[] = {1020WM8766_RESET, 0x0000,1021WM8766_DAC_CTRL, 0x0120,1022WM8766_INT_CTRL, 0x0022, /* I2S Normal Mode, 24 bit */1023WM8766_DAC_CTRL2, 0x0001,1024WM8766_DAC_CTRL3, 0x0080,1025WM8766_LDA1, 0x0100,1026WM8766_LDA2, 0x0100,1027WM8766_LDA3, 0x0100,1028WM8766_RDA1, 0x0100,1029WM8766_RDA2, 0x0100,1030WM8766_RDA3, 0x0100,1031WM8766_MUTE1, 0x0000,1032WM8766_MUTE2, 0x0000,1033};10341035struct prodigy_hifi_spec *spec;1036unsigned int i;10371038ice->vt1720 = 0;1039ice->vt1724 = 1;10401041ice->num_total_dacs = 8;1042ice->num_total_adcs = 1;10431044/* HACK - use this as the SPDIF source.1045* don't call snd_ice1712_gpio_get/put(), otherwise it's overwritten1046*/1047ice->gpio.saved[0] = 0;1048/* to remember the register values */10491050ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL);1051if (! ice->akm)1052return -ENOMEM;1053ice->akm_codecs = 1;10541055spec = kzalloc(sizeof(*spec), GFP_KERNEL);1056if (!spec)1057return -ENOMEM;1058ice->spec = spec;10591060/* initialize WM8776 codec */1061for (i = 0; i < ARRAY_SIZE(wm_inits); i += 2)1062wm_put(ice, wm_inits[i], wm_inits[i+1]);1063schedule_timeout_uninterruptible(1);1064for (i = 0; i < ARRAY_SIZE(wm_inits2); i += 2)1065wm_put(ice, wm_inits2[i], wm_inits2[i+1]);10661067/* initialize WM8766 codec */1068for (i = 0; i < ARRAY_SIZE(wm8766_inits); i += 2)1069wm8766_spi_write(ice, wm8766_inits[i], wm8766_inits[i+1]);107010711072return 0;1073}107410751076/*1077* initialize the chip1078*/1079static void ak4396_init(struct snd_ice1712 *ice)1080{1081static unsigned short ak4396_inits[] = {1082AK4396_CTRL1, 0x87, /* I2S Normal Mode, 24 bit */1083AK4396_CTRL2, 0x02,1084AK4396_CTRL3, 0x00,1085AK4396_LCH_ATT, 0x00,1086AK4396_RCH_ATT, 0x00,1087};10881089unsigned int i;10901091/* initialize ak4396 codec */1092/* reset codec */1093ak4396_write(ice, AK4396_CTRL1, 0x86);1094msleep(100);1095ak4396_write(ice, AK4396_CTRL1, 0x87);10961097for (i = 0; i < ARRAY_SIZE(ak4396_inits); i += 2)1098ak4396_write(ice, ak4396_inits[i], ak4396_inits[i+1]);1099}11001101#ifdef CONFIG_PM1102static int prodigy_hd2_resume(struct snd_ice1712 *ice)1103{1104/* initialize ak4396 codec and restore previous mixer volumes */1105struct prodigy_hifi_spec *spec = ice->spec;1106int i;1107mutex_lock(&ice->gpio_mutex);1108ak4396_init(ice);1109for (i = 0; i < 2; i++)1110ak4396_write(ice, AK4396_LCH_ATT + i, spec->vol[i] & 0xff);1111mutex_unlock(&ice->gpio_mutex);1112return 0;1113}1114#endif11151116static int __devinit prodigy_hd2_init(struct snd_ice1712 *ice)1117{1118struct prodigy_hifi_spec *spec;11191120ice->vt1720 = 0;1121ice->vt1724 = 1;11221123ice->num_total_dacs = 1;1124ice->num_total_adcs = 1;11251126/* HACK - use this as the SPDIF source.1127* don't call snd_ice1712_gpio_get/put(), otherwise it's overwritten1128*/1129ice->gpio.saved[0] = 0;1130/* to remember the register values */11311132ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL);1133if (! ice->akm)1134return -ENOMEM;1135ice->akm_codecs = 1;11361137spec = kzalloc(sizeof(*spec), GFP_KERNEL);1138if (!spec)1139return -ENOMEM;1140ice->spec = spec;11411142#ifdef CONFIG_PM1143ice->pm_resume = &prodigy_hd2_resume;1144ice->pm_suspend_enabled = 1;1145#endif11461147ak4396_init(ice);11481149return 0;1150}115111521153static unsigned char prodigy71hifi_eeprom[] __devinitdata = {11540x4b, /* SYSCONF: clock 512, spdif-in/ADC, 4DACs */11550x80, /* ACLINK: I2S */11560xfc, /* I2S: vol, 96k, 24bit, 192k */11570xc3, /* SPDIF: out-en, out-int, spdif-in */11580xff, /* GPIO_DIR */11590xff, /* GPIO_DIR1 */11600x5f, /* GPIO_DIR2 */11610x00, /* GPIO_MASK */11620x00, /* GPIO_MASK1 */11630x00, /* GPIO_MASK2 */11640x00, /* GPIO_STATE */11650x00, /* GPIO_STATE1 */11660x00, /* GPIO_STATE2 */1167};11681169static unsigned char prodigyhd2_eeprom[] __devinitdata = {11700x4b, /* SYSCONF: clock 512, spdif-in/ADC, 4DACs */11710x80, /* ACLINK: I2S */11720xfc, /* I2S: vol, 96k, 24bit, 192k */11730xc3, /* SPDIF: out-en, out-int, spdif-in */11740xff, /* GPIO_DIR */11750xff, /* GPIO_DIR1 */11760x5f, /* GPIO_DIR2 */11770x00, /* GPIO_MASK */11780x00, /* GPIO_MASK1 */11790x00, /* GPIO_MASK2 */11800x00, /* GPIO_STATE */11810x00, /* GPIO_STATE1 */11820x00, /* GPIO_STATE2 */1183};11841185static unsigned char fortissimo4_eeprom[] __devinitdata = {11860x43, /* SYSCONF: clock 512, ADC, 4DACs */11870x80, /* ACLINK: I2S */11880xfc, /* I2S: vol, 96k, 24bit, 192k */11890xc1, /* SPDIF: out-en, out-int */11900xff, /* GPIO_DIR */11910xff, /* GPIO_DIR1 */11920x5f, /* GPIO_DIR2 */11930x00, /* GPIO_MASK */11940x00, /* GPIO_MASK1 */11950x00, /* GPIO_MASK2 */11960x00, /* GPIO_STATE */11970x00, /* GPIO_STATE1 */11980x00, /* GPIO_STATE2 */1199};12001201/* entry point */1202struct snd_ice1712_card_info snd_vt1724_prodigy_hifi_cards[] __devinitdata = {1203{1204.subvendor = VT1724_SUBDEVICE_PRODIGY_HIFI,1205.name = "Audiotrak Prodigy 7.1 HiFi",1206.model = "prodigy71hifi",1207.chip_init = prodigy_hifi_init,1208.build_controls = prodigy_hifi_add_controls,1209.eeprom_size = sizeof(prodigy71hifi_eeprom),1210.eeprom_data = prodigy71hifi_eeprom,1211.driver = "Prodigy71HIFI",1212},1213{1214.subvendor = VT1724_SUBDEVICE_PRODIGY_HD2,1215.name = "Audiotrak Prodigy HD2",1216.model = "prodigyhd2",1217.chip_init = prodigy_hd2_init,1218.build_controls = prodigy_hd2_add_controls,1219.eeprom_size = sizeof(prodigyhd2_eeprom),1220.eeprom_data = prodigyhd2_eeprom,1221.driver = "Prodigy71HD2",1222},1223{1224.subvendor = VT1724_SUBDEVICE_FORTISSIMO4,1225.name = "Hercules Fortissimo IV",1226.model = "fortissimo4",1227.chip_init = prodigy_hifi_init,1228.build_controls = prodigy_hifi_add_controls,1229.eeprom_size = sizeof(fortissimo4_eeprom),1230.eeprom_data = fortissimo4_eeprom,1231.driver = "Fortissimo4",1232},1233{ } /* terminator */1234};1235123612371238