diff options
Diffstat (limited to 'sound')
216 files changed, 6494 insertions, 5306 deletions
diff --git a/sound/aoa/soundbus/i2sbus/core.c b/sound/aoa/soundbus/i2sbus/core.c index 467836057ee5..a80d5ea87ccd 100644 --- a/sound/aoa/soundbus/i2sbus/core.c +++ b/sound/aoa/soundbus/i2sbus/core.c @@ -47,15 +47,11 @@ static int alloc_dbdma_descriptor_ring(struct i2sbus_dev *i2sdev, /* We use the PCI APIs for now until the generic one gets fixed * enough or until we get some macio-specific versions */ - r->space = dma_alloc_coherent( - &macio_get_pci_dev(i2sdev->macio)->dev, - r->size, - &r->bus_addr, - GFP_KERNEL); + r->space = dma_zalloc_coherent(&macio_get_pci_dev(i2sdev->macio)->dev, + r->size, &r->bus_addr, GFP_KERNEL); + if (!r->space) + return -ENOMEM; - if (!r->space) return -ENOMEM; - - memset(r->space, 0, r->size); r->cmds = (void*)DBDMA_ALIGN(r->space); r->bus_cmd_start = r->bus_addr + (dma_addr_t)((char*)r->cmds - (char*)r->space); diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c index 7403f348ed14..89028fab64fd 100644 --- a/sound/core/compress_offload.c +++ b/sound/core/compress_offload.c @@ -491,7 +491,7 @@ static int snd_compress_check_input(struct snd_compr_params *params) { /* first let's check the buffer parameter's */ if (params->buffer.fragment_size == 0 || - params->buffer.fragments > SIZE_MAX / params->buffer.fragment_size) + params->buffer.fragments > INT_MAX / params->buffer.fragment_size) return -EINVAL; /* now codec parameters */ diff --git a/sound/core/info.c b/sound/core/info.c index 051d55b05521..9f404e965ea2 100644 --- a/sound/core/info.c +++ b/sound/core/info.c @@ -684,7 +684,7 @@ int snd_info_card_free(struct snd_card *card) * snd_info_get_line - read one line from the procfs buffer * @buffer: the procfs buffer * @line: the buffer to store - * @len: the max. buffer size - 1 + * @len: the max. buffer size * * Reads one line from the buffer and stores the string. * @@ -704,7 +704,7 @@ int snd_info_get_line(struct snd_info_buffer *buffer, char *line, int len) buffer->stop = 1; if (c == '\n') break; - if (len) { + if (len > 1) { len--; *line++ = c; } diff --git a/sound/core/pcm_compat.c b/sound/core/pcm_compat.c index af49721ba0e3..102e8fd1d450 100644 --- a/sound/core/pcm_compat.c +++ b/sound/core/pcm_compat.c @@ -101,7 +101,9 @@ struct snd_pcm_sw_params32 { u32 silence_threshold; u32 silence_size; u32 boundary; - unsigned char reserved[64]; + u32 proto; + u32 tstamp_type; + unsigned char reserved[56]; }; /* recalcuate the boundary within 32bit */ @@ -133,7 +135,9 @@ static int snd_pcm_ioctl_sw_params_compat(struct snd_pcm_substream *substream, get_user(params.start_threshold, &src->start_threshold) || get_user(params.stop_threshold, &src->stop_threshold) || get_user(params.silence_threshold, &src->silence_threshold) || - get_user(params.silence_size, &src->silence_size)) + get_user(params.silence_size, &src->silence_size) || + get_user(params.tstamp_type, &src->tstamp_type) || + get_user(params.proto, &src->proto)) return -EFAULT; /* * Check silent_size parameter. Since we have 64bit boundary, diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 9acc77eae487..0032278567ad 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -1782,14 +1782,16 @@ static int snd_pcm_lib_ioctl_fifo_size(struct snd_pcm_substream *substream, { struct snd_pcm_hw_params *params = arg; snd_pcm_format_t format; - int channels, width; + int channels; + ssize_t frame_size; params->fifo_size = substream->runtime->hw.fifo_size; if (!(substream->runtime->hw.info & SNDRV_PCM_INFO_FIFO_IN_FRAMES)) { format = params_format(params); channels = params_channels(params); - width = snd_pcm_format_physical_width(format); - params->fifo_size /= width * channels; + frame_size = snd_pcm_format_size(format, channels); + if (frame_size > 0) + params->fifo_size /= (unsigned)frame_size; } return 0; } diff --git a/sound/core/pcm_misc.c b/sound/core/pcm_misc.c index 4560ca0e5651..2c6fd80e0bd1 100644 --- a/sound/core/pcm_misc.c +++ b/sound/core/pcm_misc.c @@ -142,11 +142,11 @@ static struct pcm_format_data pcm_formats[(INT)SNDRV_PCM_FORMAT_LAST+1] = { }, [SNDRV_PCM_FORMAT_DSD_U8] = { .width = 8, .phys = 8, .le = 1, .signd = 0, - .silence = {}, + .silence = { 0x69 }, }, [SNDRV_PCM_FORMAT_DSD_U16_LE] = { .width = 16, .phys = 16, .le = 1, .signd = 0, - .silence = {}, + .silence = { 0x69, 0x69 }, }, /* FIXME: the following three formats are not defined properly yet */ [SNDRV_PCM_FORMAT_MPEG] = { diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index b653ab001fba..8cd2f930ad0b 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -543,6 +543,9 @@ static int snd_pcm_sw_params(struct snd_pcm_substream *substream, if (params->tstamp_mode > SNDRV_PCM_TSTAMP_LAST) return -EINVAL; + if (params->proto >= SNDRV_PROTOCOL_VERSION(2, 0, 12) && + params->tstamp_type > SNDRV_PCM_TSTAMP_TYPE_LAST) + return -EINVAL; if (params->avail_min == 0) return -EINVAL; if (params->silence_size >= runtime->boundary) { @@ -557,6 +560,8 @@ static int snd_pcm_sw_params(struct snd_pcm_substream *substream, err = 0; snd_pcm_stream_lock_irq(substream); runtime->tstamp_mode = params->tstamp_mode; + if (params->proto >= SNDRV_PROTOCOL_VERSION(2, 0, 12)) + runtime->tstamp_type = params->tstamp_type; runtime->period_step = params->period_step; runtime->control->avail_min = params->avail_min; runtime->start_threshold = params->start_threshold; @@ -2540,9 +2545,7 @@ static int snd_pcm_tstamp(struct snd_pcm_substream *substream, int __user *_arg) return -EFAULT; if (arg < 0 || arg > SNDRV_PCM_TSTAMP_TYPE_LAST) return -EINVAL; - runtime->tstamp_type = SNDRV_PCM_TSTAMP_TYPE_GETTIMEOFDAY; - if (arg == SNDRV_PCM_TSTAMP_TYPE_MONOTONIC) - runtime->tstamp_type = SNDRV_PCM_TSTAMP_TYPE_MONOTONIC; + runtime->tstamp_type = arg; return 0; } diff --git a/sound/core/seq/seq_memory.c b/sound/core/seq/seq_memory.c index 1e206de0c2dd..ba8e4a64e13e 100644 --- a/sound/core/seq/seq_memory.c +++ b/sound/core/seq/seq_memory.c @@ -101,9 +101,9 @@ int snd_seq_dump_var_event(const struct snd_seq_event *event, len -= size; } return 0; - } if (! (event->data.ext.len & SNDRV_SEQ_EXT_CHAINED)) { - return func(private_data, event->data.ext.ptr, len); } + if (!(event->data.ext.len & SNDRV_SEQ_EXT_CHAINED)) + return func(private_data, event->data.ext.ptr, len); cell = (struct snd_seq_event_cell *)event->data.ext.ptr; for (; len > 0 && cell; cell = cell->next) { diff --git a/sound/firewire/Kconfig b/sound/firewire/Kconfig index 775ef2efc296..46dff64908c8 100644 --- a/sound/firewire/Kconfig +++ b/sound/firewire/Kconfig @@ -83,8 +83,8 @@ config SND_BEBOB * Edirol FA-66/FA-101 * PreSonus FIREBOX/FIREPOD/FP10/Inspire1394 * BridgeCo RDAudio1/Audio5 - * Mackie Onyx 1220/1620/1640 (Firewire I/O Card) - * Mackie d.2 (Firewire Option) + * Mackie Onyx 1220/1620/1640 (FireWire I/O Card) + * Mackie d.2 (FireWire Option) * Stanton FinalScratch 2 (ScratchAmp) * Tascam IF-FW/DM * Behringer XENIX UFX 1204/1604 @@ -92,7 +92,7 @@ config SND_BEBOB * Apogee Rosetta 200/400 (X-FireWire card) * Apogee DA/AD/DD-16X (X-FireWire card) * Apogee Ensemble - * ESI Quotafire610 + * ESI QuataFire 610 * AcousticReality eARMasterOne * CME MatrixKFW * Phonic Helix Board 12 MkII/18 MkII/24 MkII @@ -101,13 +101,13 @@ config SND_BEBOB * ICON FireXon * PrismSound Orpheus/ADA-8XR * TerraTec PHASE 24 FW/PHASE X24 FW/PHASE 88 Rack FW - * Terratec EWS MIC2/EWS MIC4 - * Terratec Aureon 7.1 Firewire + * TerraTec EWS MIC2/EWS MIC8 + * TerraTec Aureon 7.1 FireWire * Yamaha GO44/GO46 * Focusrite Saffire/Saffire LE/SaffirePro10 IO/SaffirePro26 IO - * M-Audio Firewire410/AudioPhile/Solo + * M-Audio FireWire410/AudioPhile/Solo * M-Audio Ozonic/NRV10/ProfireLightBridge - * M-Audio Firewire 1814/ProjectMix IO + * M-Audio FireWire 1814/ProjectMix IO To compile this driver as a module, choose M here: the module will be called snd-bebob. diff --git a/sound/firewire/amdtp.c b/sound/firewire/amdtp.c index f96bf4c7c232..95fc2eaf11dc 100644 --- a/sound/firewire/amdtp.c +++ b/sound/firewire/amdtp.c @@ -507,7 +507,16 @@ static void amdtp_pull_midi(struct amdtp_stream *s, static void update_pcm_pointers(struct amdtp_stream *s, struct snd_pcm_substream *pcm, unsigned int frames) -{ unsigned int ptr; +{ + unsigned int ptr; + + /* + * In IEC 61883-6, one data block represents one event. In ALSA, one + * event equals to one PCM frame. But Dice has a quirk to transfer + * two PCM frames in one data block. + */ + if (s->double_pcm_frames) + frames *= 2; ptr = s->pcm_buffer_pointer + frames; if (ptr >= pcm->runtime->buffer_size) diff --git a/sound/firewire/amdtp.h b/sound/firewire/amdtp.h index d8ee7b0e9386..4823c08196ac 100644 --- a/sound/firewire/amdtp.h +++ b/sound/firewire/amdtp.h @@ -125,6 +125,7 @@ struct amdtp_stream { unsigned int pcm_buffer_pointer; unsigned int pcm_period_pointer; bool pointer_flush; + bool double_pcm_frames; struct snd_rawmidi_substream *midi[AMDTP_MAX_CHANNELS_FOR_MIDI * 8]; diff --git a/sound/firewire/dice.c b/sound/firewire/dice.c index a9a30c0161f1..e3a04d69c853 100644 --- a/sound/firewire/dice.c +++ b/sound/firewire/dice.c @@ -567,10 +567,14 @@ static int dice_hw_params(struct snd_pcm_substream *substream, return err; /* - * At rates above 96 kHz, pretend that the stream runs at half the - * actual sample rate with twice the number of channels; two samples - * of a channel are stored consecutively in the packet. Requires - * blocking mode and PCM buffer size should be aligned to SYT_INTERVAL. + * At 176.4/192.0 kHz, Dice has a quirk to transfer two PCM frames in + * one data block of AMDTP packet. Thus sampling transfer frequency is + * a half of PCM sampling frequency, i.e. PCM frames at 192.0 kHz are + * transferred on AMDTP packets at 96 kHz. Two successive samples of a + * channel are stored consecutively in the packet. This quirk is called + * as 'Dual Wire'. + * For this quirk, blocking mode is required and PCM buffer size should + * be aligned to SYT_INTERVAL. */ channels = params_channels(hw_params); if (rate_index > 4) { @@ -579,18 +583,25 @@ static int dice_hw_params(struct snd_pcm_substream *substream, return err; } - for (i = 0; i < channels; i++) { - dice->stream.pcm_positions[i * 2] = i; - dice->stream.pcm_positions[i * 2 + 1] = i + channels; - } - rate /= 2; channels *= 2; + dice->stream.double_pcm_frames = true; + } else { + dice->stream.double_pcm_frames = false; } mode = rate_index_to_mode(rate_index); amdtp_stream_set_parameters(&dice->stream, rate, channels, dice->rx_midi_ports[mode]); + if (rate_index > 4) { + channels /= 2; + + for (i = 0; i < channels; i++) { + dice->stream.pcm_positions[i] = i * 2; + dice->stream.pcm_positions[i + channels] = i * 2 + 1; + } + } + amdtp_stream_set_pcm_format(&dice->stream, params_format(hw_params)); diff --git a/sound/firewire/fireworks/fireworks_proc.c b/sound/firewire/fireworks/fireworks_proc.c index f29d4aaf56a1..0639dcb13f7d 100644 --- a/sound/firewire/fireworks/fireworks_proc.c +++ b/sound/firewire/fireworks/fireworks_proc.c @@ -64,7 +64,7 @@ proc_read_hwinfo(struct snd_info_entry *entry, struct snd_info_buffer *buffer) hwinfo->phys_in_grp_count); for (i = 0; i < hwinfo->phys_in_grp_count; i++) { snd_iprintf(buffer, - "phys in grp[0x%d]: type 0x%d, count 0x%d\n", + "phys in grp[%d]: type 0x%X, count 0x%X\n", i, hwinfo->phys_out_grps[i].type, hwinfo->phys_out_grps[i].count); } @@ -73,7 +73,7 @@ proc_read_hwinfo(struct snd_info_entry *entry, struct snd_info_buffer *buffer) hwinfo->phys_out_grp_count); for (i = 0; i < hwinfo->phys_out_grp_count; i++) { snd_iprintf(buffer, - "phys out grps[0x%d]: type 0x%d, count 0x%d\n", + "phys out grps[%d]: type 0x%X, count 0x%X\n", i, hwinfo->phys_out_grps[i].type, hwinfo->phys_out_grps[i].count); } diff --git a/sound/oss/kahlua.c b/sound/oss/kahlua.c index 12be1fb512dd..c4b0434c7604 100644 --- a/sound/oss/kahlua.c +++ b/sound/oss/kahlua.c @@ -197,7 +197,7 @@ MODULE_LICENSE("GPL"); * 5530 only. The 5510/5520 decode is different. */ -static DEFINE_PCI_DEVICE_TABLE(id_tbl) = { +static const struct pci_device_id id_tbl[] = { { PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5530_AUDIO), 0 }, { } }; diff --git a/sound/oss/mpu401.c b/sound/oss/mpu401.c index 3bbc3ec5be82..862735005b43 100644 --- a/sound/oss/mpu401.c +++ b/sound/oss/mpu401.c @@ -316,6 +316,7 @@ static int mpu_input_scanner(struct mpu_config *devc, unsigned char midic) case 0xf6: /* printk( "tune_request\n"); */ devc->m_state = ST_INIT; + break; /* * Real time messages @@ -972,7 +973,6 @@ int attach_mpu401(struct address_info *hw_config, struct module *owner) devc->m_busy = 0; devc->m_state = ST_INIT; devc->shared_irq = hw_config->always_detect; - devc->irq = hw_config->irq; spin_lock_init(&devc->lock); if (devc->irq < 0) diff --git a/sound/oss/opl3.c b/sound/oss/opl3.c index 4709e592e2cc..607cee4d545e 100644 --- a/sound/oss/opl3.c +++ b/sound/oss/opl3.c @@ -52,7 +52,7 @@ struct voice_info int panning; /* 0xffff means not set */ }; -typedef struct opl_devinfo +struct opl_devinfo { int base; int left_io, right_io; @@ -73,7 +73,7 @@ typedef struct opl_devinfo unsigned char cmask; int is_opl4; -} opl_devinfo; +}; static struct opl_devinfo *devc = NULL; diff --git a/sound/oss/pss.c b/sound/oss/pss.c index 145e36b2cfd0..ca0d6e9f49f5 100644 --- a/sound/oss/pss.c +++ b/sound/oss/pss.c @@ -123,25 +123,25 @@ static bool pss_mixer; #endif -typedef struct pss_mixerdata { +struct pss_mixerdata { unsigned int volume_l; unsigned int volume_r; unsigned int bass; unsigned int treble; unsigned int synth; -} pss_mixerdata; +}; -typedef struct pss_confdata { +struct pss_confdata { int base; int irq; int dma; int *osp; - pss_mixerdata mixer; + struct pss_mixerdata mixer; int ad_mixer_dev; -} pss_confdata; +}; -static pss_confdata pss_data; -static pss_confdata *devc = &pss_data; +static struct pss_confdata pss_data; +static struct pss_confdata *devc = &pss_data; static DEFINE_SPINLOCK(lock); static int pss_initialized; @@ -150,7 +150,7 @@ static int pss_cdrom_port = -1; /* Parameter for the PSS cdrom port */ static bool pss_enable_joystick; /* Parameter for enabling the joystick */ static coproc_operations pss_coproc_operations; -static void pss_write(pss_confdata *devc, int data) +static void pss_write(struct pss_confdata *devc, int data) { unsigned long i, limit; @@ -206,7 +206,7 @@ static int __init probe_pss(struct address_info *hw_config) return 1; } -static int set_irq(pss_confdata * devc, int dev, int irq) +static int set_irq(struct pss_confdata *devc, int dev, int irq) { static unsigned short irq_bits[16] = { @@ -232,7 +232,7 @@ static int set_irq(pss_confdata * devc, int dev, int irq) return 1; } -static void set_io_base(pss_confdata * devc, int dev, int base) +static void set_io_base(struct pss_confdata *devc, int dev, int base) { unsigned short tmp = inw(REG(dev)) & 0x003f; unsigned short bits = (base & 0x0ffc) << 4; @@ -240,7 +240,7 @@ static void set_io_base(pss_confdata * devc, int dev, int base) outw(bits | tmp, REG(dev)); } -static int set_dma(pss_confdata * devc, int dev, int dma) +static int set_dma(struct pss_confdata *devc, int dev, int dma) { static unsigned short dma_bits[8] = { @@ -264,7 +264,7 @@ static int set_dma(pss_confdata * devc, int dev, int dma) return 1; } -static int pss_reset_dsp(pss_confdata * devc) +static int pss_reset_dsp(struct pss_confdata *devc) { unsigned long i, limit = jiffies + HZ/10; @@ -275,7 +275,7 @@ static int pss_reset_dsp(pss_confdata * devc) return 1; } -static int pss_put_dspword(pss_confdata * devc, unsigned short word) +static int pss_put_dspword(struct pss_confdata *devc, unsigned short word) { int i, val; @@ -291,7 +291,7 @@ static int pss_put_dspword(pss_confdata * devc, unsigned short word) return 0; } -static int pss_get_dspword(pss_confdata * devc, unsigned short *word) +static int pss_get_dspword(struct pss_confdata *devc, unsigned short *word) { int i, val; @@ -307,7 +307,8 @@ static int pss_get_dspword(pss_confdata * devc, unsigned short *word) return 0; } -static int pss_download_boot(pss_confdata * devc, unsigned char *block, int size, int flags) +static int pss_download_boot(struct pss_confdata *devc, unsigned char *block, + int size, int flags) { int i, val, count; unsigned long limit; @@ -397,7 +398,7 @@ static int pss_download_boot(pss_confdata * devc, unsigned char *block, int size } /* Mixer */ -static void set_master_volume(pss_confdata *devc, int left, int right) +static void set_master_volume(struct pss_confdata *devc, int left, int right) { static unsigned char log_scale[101] = { 0xdb, 0xe0, 0xe3, 0xe5, 0xe7, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xed, 0xee, @@ -416,7 +417,7 @@ static void set_master_volume(pss_confdata *devc, int left, int right) pss_write(devc, log_scale[right] | 0x0100); } -static void set_synth_volume(pss_confdata *devc, int volume) +static void set_synth_volume(struct pss_confdata *devc, int volume) { int vol = ((0x8000*volume)/100L); pss_write(devc, 0x0080); @@ -425,21 +426,21 @@ static void set_synth_volume(pss_confdata *devc, int volume) pss_write(devc, vol); } -static void set_bass(pss_confdata *devc, int level) +static void set_bass(struct pss_confdata *devc, int level) { int vol = (int)(((0xfd - 0xf0) * level)/100L) + 0xf0; pss_write(devc, 0x0010); pss_write(devc, vol | 0x0200); }; -static void set_treble(pss_confdata *devc, int level) +static void set_treble(struct pss_confdata *devc, int level) { int vol = (((0xfd - 0xf0) * level)/100L) + 0xf0; pss_write(devc, 0x0010); pss_write(devc, vol | 0x0300); }; -static void pss_mixer_reset(pss_confdata *devc) +static void pss_mixer_reset(struct pss_confdata *devc) { set_master_volume(devc, 33, 33); set_bass(devc, 50); @@ -499,7 +500,8 @@ static int ret_vol_stereo(int left, int right) return ((right << 8) | left); } -static int call_ad_mixer(pss_confdata *devc,unsigned int cmd, void __user *arg) +static int call_ad_mixer(struct pss_confdata *devc, unsigned int cmd, + void __user *arg) { if (devc->ad_mixer_dev != NO_WSS_MIXER) return mixer_devs[devc->ad_mixer_dev]->ioctl(devc->ad_mixer_dev, cmd, arg); @@ -509,7 +511,7 @@ static int call_ad_mixer(pss_confdata *devc,unsigned int cmd, void __user *arg) static int pss_mixer_ioctl (int dev, unsigned int cmd, void __user *arg) { - pss_confdata *devc = mixer_devs[dev]->devc; + struct pss_confdata *devc = mixer_devs[dev]->devc; int cmdf = cmd & 0xff; if ((cmdf != SOUND_MIXER_VOLUME) && (cmdf != SOUND_MIXER_BASS) && diff --git a/sound/oss/uart401.c b/sound/oss/uart401.c index 62b8869f5a4c..279bc565ac7e 100644 --- a/sound/oss/uart401.c +++ b/sound/oss/uart401.c @@ -30,7 +30,7 @@ #include "mpu401.h" -typedef struct uart401_devc +struct uart401_devc { int base; int irq; @@ -41,14 +41,13 @@ typedef struct uart401_devc int my_dev; int share_irq; spinlock_t lock; -} -uart401_devc; +}; #define DATAPORT (devc->base) #define COMDPORT (devc->base+1) #define STATPORT (devc->base+1) -static int uart401_status(uart401_devc * devc) +static int uart401_status(struct uart401_devc *devc) { return inb(STATPORT); } @@ -56,17 +55,17 @@ static int uart401_status(uart401_devc * devc) #define input_avail(devc) (!(uart401_status(devc)&INPUT_AVAIL)) #define output_ready(devc) (!(uart401_status(devc)&OUTPUT_READY)) -static void uart401_cmd(uart401_devc * devc, unsigned char cmd) +static void uart401_cmd(struct uart401_devc *devc, unsigned char cmd) { outb((cmd), COMDPORT); } -static int uart401_read(uart401_devc * devc) +static int uart401_read(struct uart401_devc *devc) { return inb(DATAPORT); } -static void uart401_write(uart401_devc * devc, unsigned char byte) +static void uart401_write(struct uart401_devc *devc, unsigned char byte) { outb((byte), DATAPORT); } @@ -77,10 +76,10 @@ static void uart401_write(uart401_devc * devc, unsigned char byte) #define MPU_RESET 0xFF #define UART_MODE_ON 0x3F -static int reset_uart401(uart401_devc * devc); -static void enter_uart_mode(uart401_devc * devc); +static int reset_uart401(struct uart401_devc *devc); +static void enter_uart_mode(struct uart401_devc *devc); -static void uart401_input_loop(uart401_devc * devc) +static void uart401_input_loop(struct uart401_devc *devc) { int work_limit=30000; @@ -99,7 +98,7 @@ static void uart401_input_loop(uart401_devc * devc) irqreturn_t uart401intr(int irq, void *dev_id) { - uart401_devc *devc = dev_id; + struct uart401_devc *devc = dev_id; if (devc == NULL) { @@ -118,7 +117,8 @@ uart401_open(int dev, int mode, void (*output) (int dev) ) { - uart401_devc *devc = (uart401_devc *) midi_devs[dev]->devc; + struct uart401_devc *devc = (struct uart401_devc *) + midi_devs[dev]->devc; if (devc->opened) return -EBUSY; @@ -138,7 +138,8 @@ uart401_open(int dev, int mode, static void uart401_close(int dev) { - uart401_devc *devc = (uart401_devc *) midi_devs[dev]->devc; + struct uart401_devc *devc = (struct uart401_devc *) + midi_devs[dev]->devc; reset_uart401(devc); devc->opened = 0; @@ -148,7 +149,8 @@ static int uart401_out(int dev, unsigned char midi_byte) { int timeout; unsigned long flags; - uart401_devc *devc = (uart401_devc *) midi_devs[dev]->devc; + struct uart401_devc *devc = (struct uart401_devc *) + midi_devs[dev]->devc; if (devc->disabled) return 1; @@ -219,7 +221,7 @@ static const struct midi_operations uart401_operations = .buffer_status = uart401_buffer_status, }; -static void enter_uart_mode(uart401_devc * devc) +static void enter_uart_mode(struct uart401_devc *devc) { int ok, timeout; unsigned long flags; @@ -241,7 +243,7 @@ static void enter_uart_mode(uart401_devc * devc) spin_unlock_irqrestore(&devc->lock,flags); } -static int reset_uart401(uart401_devc * devc) +static int reset_uart401(struct uart401_devc *devc) { int ok, timeout, n; @@ -285,7 +287,7 @@ static int reset_uart401(uart401_devc * devc) int probe_uart401(struct address_info *hw_config, struct module *owner) { - uart401_devc *devc; + struct uart401_devc *devc; char *name = "MPU-401 (UART) MIDI"; int ok = 0; unsigned long flags; @@ -300,7 +302,7 @@ int probe_uart401(struct address_info *hw_config, struct module *owner) return 0; } - devc = kmalloc(sizeof(uart401_devc), GFP_KERNEL); + devc = kmalloc(sizeof(struct uart401_devc), GFP_KERNEL); if (!devc) { printk(KERN_WARNING "uart401: Can't allocate memory\n"); goto cleanup_region; @@ -392,7 +394,7 @@ cleanup_region: void unload_uart401(struct address_info *hw_config) { - uart401_devc *devc; + struct uart401_devc *devc; int n=hw_config->slots[4]; /* Not set up */ diff --git a/sound/oss/waveartist.c b/sound/oss/waveartist.c index 672af8b56542..b36ea47527e8 100644 --- a/sound/oss/waveartist.c +++ b/sound/oss/waveartist.c @@ -92,7 +92,7 @@ static unsigned short levels[SOUND_MIXER_NRDEVICES] = { 0x0000 /* Monitor */ }; -typedef struct { +struct wavnc_info { struct address_info hw; /* hardware */ char *chip_name; @@ -119,7 +119,7 @@ typedef struct { unsigned int line_mute_state :1;/* set by ioctl or autoselect */ unsigned int use_slider :1;/* use slider setting for o/p vol */ #endif -} wavnc_info; +}; /* * This is the implementation specific mixer information. @@ -129,29 +129,30 @@ struct waveartist_mixer_info { unsigned int recording_devs; /* Recordable devies */ unsigned int stereo_devs; /* Stereo devices */ - unsigned int (*select_input)(wavnc_info *, unsigned int, + unsigned int (*select_input)(struct wavnc_info *, unsigned int, unsigned char *, unsigned char *); - int (*decode_mixer)(wavnc_info *, int, + int (*decode_mixer)(struct wavnc_info *, int, unsigned char, unsigned char); - int (*get_mixer)(wavnc_info *, int); + int (*get_mixer)(struct wavnc_info *, int); }; -typedef struct wavnc_port_info { +struct wavnc_port_info { int open_mode; int speed; int channels; int audio_format; -} wavnc_port_info; +}; static int nr_waveartist_devs; -static wavnc_info adev_info[MAX_AUDIO_DEV]; +static struct wavnc_info adev_info[MAX_AUDIO_DEV]; static DEFINE_SPINLOCK(waveartist_lock); #ifndef CONFIG_ARCH_NETWINDER #define machine_is_netwinder() 0 #else static struct timer_list vnc_timer; -static void vnc_configure_mixer(wavnc_info *devc, unsigned int input_mask); +static void vnc_configure_mixer(struct wavnc_info *devc, + unsigned int input_mask); static int vnc_private_ioctl(int dev, unsigned int cmd, int __user *arg); static void vnc_slider_tick(unsigned long data); #endif @@ -169,7 +170,7 @@ waveartist_set_ctlr(struct address_info *hw, unsigned char clear, unsigned char /* Toggle IRQ acknowledge line */ static inline void -waveartist_iack(wavnc_info *devc) +waveartist_iack(struct wavnc_info *devc) { unsigned int ctlr_port = devc->hw.io_base + CTLR; int old_ctlr; @@ -188,7 +189,7 @@ waveartist_sleep(int timeout_ms) } static int -waveartist_reset(wavnc_info *devc) +waveartist_reset(struct wavnc_info *devc) { struct address_info *hw = &devc->hw; unsigned int timeout, res = -1; @@ -223,7 +224,7 @@ waveartist_reset(wavnc_info *devc) * and can send or receive multiple words. */ static int -waveartist_cmd(wavnc_info *devc, +waveartist_cmd(struct wavnc_info *devc, int nr_cmd, unsigned int *cmd, int nr_resp, unsigned int *resp) { @@ -299,7 +300,7 @@ waveartist_cmd(wavnc_info *devc, * Send one command word */ static inline int -waveartist_cmd1(wavnc_info *devc, unsigned int cmd) +waveartist_cmd1(struct wavnc_info *devc, unsigned int cmd) { return waveartist_cmd(devc, 1, &cmd, 0, NULL); } @@ -308,7 +309,7 @@ waveartist_cmd1(wavnc_info *devc, unsigned int cmd) * Send one command, receive one word */ static inline unsigned int -waveartist_cmd1_r(wavnc_info *devc, unsigned int cmd) +waveartist_cmd1_r(struct wavnc_info *devc, unsigned int cmd) { unsigned int ret; @@ -322,7 +323,7 @@ waveartist_cmd1_r(wavnc_info *devc, unsigned int cmd) * word (and throw it away) */ static inline int -waveartist_cmd2(wavnc_info *devc, unsigned int cmd, unsigned int arg) +waveartist_cmd2(struct wavnc_info *devc, unsigned int cmd, unsigned int arg) { unsigned int vals[2]; @@ -336,7 +337,7 @@ waveartist_cmd2(wavnc_info *devc, unsigned int cmd, unsigned int arg) * Send a triple command */ static inline int -waveartist_cmd3(wavnc_info *devc, unsigned int cmd, +waveartist_cmd3(struct wavnc_info *devc, unsigned int cmd, unsigned int arg1, unsigned int arg2) { unsigned int vals[3]; @@ -349,7 +350,7 @@ waveartist_cmd3(wavnc_info *devc, unsigned int cmd, } static int -waveartist_getrev(wavnc_info *devc, char *rev) +waveartist_getrev(struct wavnc_info *devc, char *rev) { unsigned int temp[2]; unsigned int cmd = WACMD_GETREV; @@ -371,15 +372,15 @@ static void waveartist_trigger(int dev, int state); static int waveartist_open(int dev, int mode) { - wavnc_info *devc; - wavnc_port_info *portc; + struct wavnc_info *devc; + struct wavnc_port_info *portc; unsigned long flags; if (dev < 0 || dev >= num_audiodevs) return -ENXIO; - devc = (wavnc_info *) audio_devs[dev]->devc; - portc = (wavnc_port_info *) audio_devs[dev]->portc; + devc = (struct wavnc_info *) audio_devs[dev]->devc; + portc = (struct wavnc_port_info *) audio_devs[dev]->portc; spin_lock_irqsave(&waveartist_lock, flags); if (portc->open_mode || (devc->open_mode & mode)) { @@ -404,8 +405,10 @@ waveartist_open(int dev, int mode) static void waveartist_close(int dev) { - wavnc_info *devc = (wavnc_info *) audio_devs[dev]->devc; - wavnc_port_info *portc = (wavnc_port_info *) audio_devs[dev]->portc; + struct wavnc_info *devc = (struct wavnc_info *) + audio_devs[dev]->devc; + struct wavnc_port_info *portc = (struct wavnc_port_info *) + audio_devs[dev]->portc; unsigned long flags; spin_lock_irqsave(&waveartist_lock, flags); @@ -422,8 +425,10 @@ waveartist_close(int dev) static void waveartist_output_block(int dev, unsigned long buf, int __count, int intrflag) { - wavnc_port_info *portc = (wavnc_port_info *) audio_devs[dev]->portc; - wavnc_info *devc = (wavnc_info *) audio_devs[dev]->devc; + struct wavnc_port_info *portc = (struct wavnc_port_info *) + audio_devs[dev]->portc; + struct wavnc_info *devc = (struct wavnc_info *) + audio_devs[dev]->devc; unsigned long flags; unsigned int count = __count; @@ -467,8 +472,10 @@ waveartist_output_block(int dev, unsigned long buf, int __count, int intrflag) static void waveartist_start_input(int dev, unsigned long buf, int __count, int intrflag) { - wavnc_port_info *portc = (wavnc_port_info *) audio_devs[dev]->portc; - wavnc_info *devc = (wavnc_info *) audio_devs[dev]->devc; + struct wavnc_port_info *portc = (struct wavnc_port_info *) + audio_devs[dev]->portc; + struct wavnc_info *devc = (struct wavnc_info *) + audio_devs[dev]->devc; unsigned long flags; unsigned int count = __count; @@ -514,7 +521,7 @@ waveartist_ioctl(int dev, unsigned int cmd, void __user * arg) } static unsigned int -waveartist_get_speed(wavnc_port_info *portc) +waveartist_get_speed(struct wavnc_port_info *portc) { unsigned int speed; @@ -542,7 +549,7 @@ waveartist_get_speed(wavnc_port_info *portc) } static unsigned int -waveartist_get_bits(wavnc_port_info *portc) +waveartist_get_bits(struct wavnc_port_info *portc) { unsigned int bits; @@ -560,8 +567,10 @@ static int waveartist_prepare_for_input(int dev, int bsize, int bcount) { unsigned long flags; - wavnc_info *devc = (wavnc_info *) audio_devs[dev]->devc; - wavnc_port_info *portc = (wavnc_port_info *) audio_devs[dev]->portc; + struct wavnc_info *devc = (struct wavnc_info *) + audio_devs[dev]->devc; + struct wavnc_port_info *portc = (struct wavnc_port_info *) + audio_devs[dev]->portc; unsigned int speed, bits; if (devc->audio_mode) @@ -615,8 +624,10 @@ static int waveartist_prepare_for_output(int dev, int bsize, int bcount) { unsigned long flags; - wavnc_info *devc = (wavnc_info *) audio_devs[dev]->devc; - wavnc_port_info *portc = (wavnc_port_info *) audio_devs[dev]->portc; + struct wavnc_info *devc = (struct wavnc_info *) + audio_devs[dev]->devc; + struct wavnc_port_info *portc = (struct wavnc_port_info *) + audio_devs[dev]->portc; unsigned int speed, bits; /* @@ -660,8 +671,9 @@ waveartist_prepare_for_output(int dev, int bsize, int bcount) static void waveartist_halt(int dev) { - wavnc_port_info *portc = (wavnc_port_info *) audio_devs[dev]->portc; - wavnc_info *devc; + struct wavnc_port_info *portc = (struct wavnc_port_info *) + audio_devs[dev]->portc; + struct wavnc_info *devc; if (portc->open_mode & OPEN_WRITE) waveartist_halt_output(dev); @@ -669,14 +681,15 @@ waveartist_halt(int dev) if (portc->open_mode & OPEN_READ) waveartist_halt_input(dev); - devc = (wavnc_info *) audio_devs[dev]->devc; + devc = (struct wavnc_info *) audio_devs[dev]->devc; devc->audio_mode = 0; } static void waveartist_halt_input(int dev) { - wavnc_info *devc = (wavnc_info *) audio_devs[dev]->devc; + struct wavnc_info *devc = (struct wavnc_info *) + audio_devs[dev]->devc; unsigned long flags; spin_lock_irqsave(&waveartist_lock, flags); @@ -703,7 +716,8 @@ waveartist_halt_input(int dev) static void waveartist_halt_output(int dev) { - wavnc_info *devc = (wavnc_info *) audio_devs[dev]->devc; + struct wavnc_info *devc = (struct wavnc_info *) + audio_devs[dev]->devc; unsigned long flags; spin_lock_irqsave(&waveartist_lock, flags); @@ -727,8 +741,10 @@ waveartist_halt_output(int dev) static void waveartist_trigger(int dev, int state) { - wavnc_info *devc = (wavnc_info *) audio_devs[dev]->devc; - wavnc_port_info *portc = (wavnc_port_info *) audio_devs[dev]->portc; + struct wavnc_info *devc = (struct wavnc_info *) + audio_devs[dev]->devc; + struct wavnc_port_info *portc = (struct wavnc_port_info *) + audio_devs[dev]->portc; unsigned long flags; if (debug_flg & DEBUG_TRIGGER) { @@ -764,7 +780,8 @@ waveartist_trigger(int dev, int state) static int waveartist_set_speed(int dev, int arg) { - wavnc_port_info *portc = (wavnc_port_info *) audio_devs[dev]->portc; + struct wavnc_port_info *portc = (struct wavnc_port_info *) + audio_devs[dev]->portc; if (arg <= 0) return portc->speed; @@ -782,7 +799,8 @@ waveartist_set_speed(int dev, int arg) static short waveartist_set_channels(int dev, short arg) { - wavnc_port_info *portc = (wavnc_port_info *) audio_devs[dev]->portc; + struct wavnc_port_info *portc = (struct wavnc_port_info *) + audio_devs[dev]->portc; if (arg != 1 && arg != 2) return portc->channels; @@ -794,7 +812,8 @@ waveartist_set_channels(int dev, short arg) static unsigned int waveartist_set_bits(int dev, unsigned int arg) { - wavnc_port_info *portc = (wavnc_port_info *) audio_devs[dev]->portc; + struct wavnc_port_info *portc = (struct wavnc_port_info *) + audio_devs[dev]->portc; if (arg == 0) return portc->audio_format; @@ -829,7 +848,7 @@ static struct audio_driver waveartist_audio_driver = { static irqreturn_t waveartist_intr(int irq, void *dev_id) { - wavnc_info *devc = dev_id; + struct wavnc_info *devc = dev_id; int irqstatus, status; spin_lock(&waveartist_lock); @@ -912,7 +931,7 @@ static const struct mix_ent mix_devs[SOUND_MIXER_NRDEVICES] = { }; static void -waveartist_mixer_update(wavnc_info *devc, int whichDev) +waveartist_mixer_update(struct wavnc_info *devc, int whichDev) { unsigned int lev_left, lev_right; @@ -973,7 +992,8 @@ waveartist_mixer_update(wavnc_info *devc, int whichDev) * relevant *_select_input function has done that for us. */ static void -waveartist_set_adc_mux(wavnc_info *devc, char left_dev, char right_dev) +waveartist_set_adc_mux(struct wavnc_info *devc, char left_dev, + char right_dev) { unsigned int reg_08, reg_09; @@ -996,7 +1016,7 @@ waveartist_set_adc_mux(wavnc_info *devc, char left_dev, char right_dev) * SOUND_MASK_MIC Mic Microphone */ static unsigned int -waveartist_select_input(wavnc_info *devc, unsigned int recmask, +waveartist_select_input(struct wavnc_info *devc, unsigned int recmask, unsigned char *dev_l, unsigned char *dev_r) { unsigned int recdev = ADC_MUX_NONE; @@ -1024,7 +1044,8 @@ waveartist_select_input(wavnc_info *devc, unsigned int recmask, } static int -waveartist_decode_mixer(wavnc_info *devc, int dev, unsigned char lev_l, +waveartist_decode_mixer(struct wavnc_info *devc, int dev, + unsigned char lev_l, unsigned char lev_r) { switch (dev) { @@ -1050,7 +1071,7 @@ waveartist_decode_mixer(wavnc_info *devc, int dev, unsigned char lev_l, return dev; } -static int waveartist_get_mixer(wavnc_info *devc, int dev) +static int waveartist_get_mixer(struct wavnc_info *devc, int dev) { return devc->levels[dev]; } @@ -1068,7 +1089,7 @@ static const struct waveartist_mixer_info waveartist_mixer = { }; static void -waveartist_set_recmask(wavnc_info *devc, unsigned int recmask) +waveartist_set_recmask(struct wavnc_info *devc, unsigned int recmask) { unsigned char dev_l, dev_r; @@ -1092,7 +1113,7 @@ waveartist_set_recmask(wavnc_info *devc, unsigned int recmask) } static int -waveartist_set_mixer(wavnc_info *devc, int dev, unsigned int level) +waveartist_set_mixer(struct wavnc_info *devc, int dev, unsigned int level) { unsigned int lev_left = level & 0x00ff; unsigned int lev_right = (level & 0xff00) >> 8; @@ -1120,7 +1141,7 @@ waveartist_set_mixer(wavnc_info *devc, int dev, unsigned int level) static int waveartist_mixer_ioctl(int dev, unsigned int cmd, void __user * arg) { - wavnc_info *devc = (wavnc_info *)audio_devs[dev]->devc; + struct wavnc_info *devc = (struct wavnc_info *)audio_devs[dev]->devc; int ret = 0, val, nr; /* @@ -1204,7 +1225,7 @@ static struct mixer_operations waveartist_mixer_operations = }; static void -waveartist_mixer_reset(wavnc_info *devc) +waveartist_mixer_reset(struct wavnc_info *devc) { int i; @@ -1241,9 +1262,9 @@ waveartist_mixer_reset(wavnc_info *devc) waveartist_mixer_update(devc, i); } -static int __init waveartist_init(wavnc_info *devc) +static int __init waveartist_init(struct wavnc_info *devc) { - wavnc_port_info *portc; + struct wavnc_port_info *portc; char rev[3], dev_name[64]; int my_dev; @@ -1261,7 +1282,7 @@ static int __init waveartist_init(wavnc_info *devc) conf_printf2(dev_name, devc->hw.io_base, devc->hw.irq, devc->hw.dma, devc->hw.dma2); - portc = kzalloc(sizeof(wavnc_port_info), GFP_KERNEL); + portc = kzalloc(sizeof(struct wavnc_port_info), GFP_KERNEL); if (portc == NULL) goto nomem; @@ -1330,7 +1351,7 @@ nomem: static int __init probe_waveartist(struct address_info *hw_config) { - wavnc_info *devc = &adev_info[nr_waveartist_devs]; + struct wavnc_info *devc = &adev_info[nr_waveartist_devs]; if (nr_waveartist_devs >= MAX_AUDIO_DEV) { printk(KERN_WARNING "waveartist: too many audio devices\n"); @@ -1367,7 +1388,7 @@ static int __init probe_waveartist(struct address_info *hw_config) static void __init attach_waveartist(struct address_info *hw, const struct waveartist_mixer_info *mix) { - wavnc_info *devc = &adev_info[nr_waveartist_devs]; + struct wavnc_info *devc = &adev_info[nr_waveartist_devs]; /* * NOTE! If irq < 0, there is another driver which has allocated the @@ -1410,7 +1431,7 @@ attach_waveartist(struct address_info *hw, const struct waveartist_mixer_info *m static void __exit unload_waveartist(struct address_info *hw) { - wavnc_info *devc = NULL; + struct wavnc_info *devc = NULL; int i; for (i = 0; i < nr_waveartist_devs; i++) @@ -1478,7 +1499,7 @@ static void __exit unload_waveartist(struct address_info *hw) #define VNC_DISABLE_AUTOSWITCH 0x80 static inline void -vnc_mute_spkr(wavnc_info *devc) +vnc_mute_spkr(struct wavnc_info *devc) { unsigned long flags; @@ -1488,7 +1509,7 @@ vnc_mute_spkr(wavnc_info *devc) } static void -vnc_mute_lout(wavnc_info *devc) +vnc_mute_lout(struct wavnc_info *devc) { unsigned int left, right; @@ -1507,7 +1528,7 @@ vnc_mute_lout(wavnc_info *devc) } static int -vnc_volume_slider(wavnc_info *devc) +vnc_volume_slider(struct wavnc_info *devc) { static signed int old_slider_volume; unsigned long flags; @@ -1567,7 +1588,7 @@ vnc_volume_slider(wavnc_info *devc) * SOUND_MASK_MIC Right Mic Builtin microphone */ static unsigned int -netwinder_select_input(wavnc_info *devc, unsigned int recmask, +netwinder_select_input(struct wavnc_info *devc, unsigned int recmask, unsigned char *dev_l, unsigned char *dev_r) { unsigned int recdev_l = ADC_MUX_NONE, recdev_r = ADC_MUX_NONE; @@ -1604,7 +1625,7 @@ netwinder_select_input(wavnc_info *devc, unsigned int recmask, } static int -netwinder_decode_mixer(wavnc_info *devc, int dev, unsigned char lev_l, +netwinder_decode_mixer(struct wavnc_info *devc, int dev, unsigned char lev_l, unsigned char lev_r) { switch (dev) { @@ -1643,7 +1664,7 @@ netwinder_decode_mixer(wavnc_info *devc, int dev, unsigned char lev_l, return dev; } -static int netwinder_get_mixer(wavnc_info *devc, int dev) +static int netwinder_get_mixer(struct wavnc_info *devc, int dev) { int levels; @@ -1703,7 +1724,7 @@ static const struct waveartist_mixer_info netwinder_mixer = { }; static void -vnc_configure_mixer(wavnc_info *devc, unsigned int recmask) +vnc_configure_mixer(struct wavnc_info *devc, unsigned int recmask) { if (!devc->no_autoselect) { if (devc->handset_detect) { @@ -1729,7 +1750,7 @@ vnc_configure_mixer(wavnc_info *devc, unsigned int recmask) } static int -vnc_slider(wavnc_info *devc) +vnc_slider(struct wavnc_info *devc) { signed int slider_volume; unsigned int temp, old_hs, old_td; @@ -1795,7 +1816,7 @@ vnc_slider_tick(unsigned long data) static int vnc_private_ioctl(int dev, unsigned int cmd, int __user * arg) { - wavnc_info *devc = (wavnc_info *)audio_devs[dev]->devc; + struct wavnc_info *devc = (struct wavnc_info *)audio_devs[dev]->devc; int val; switch (cmd) { diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index 3a3a3a71088b..50dd0086cfb1 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig @@ -858,8 +858,8 @@ config SND_VIRTUOSO select SND_JACK if INPUT=y || INPUT=SND help Say Y here to include support for sound cards based on the - Asus AV66/AV100/AV200 chips, i.e., Xonar D1, DX, D2, D2X, DS, - Essence ST (Deluxe), and Essence STX. + Asus AV66/AV100/AV200 chips, i.e., Xonar D1, DX, D2, D2X, DS, DSX, + Essence ST (Deluxe), and Essence STX (II). Support for the HDAV1.3 (Deluxe) and HDAV1.3 Slim is experimental; for the Xense, missing. diff --git a/sound/pci/ad1889.c b/sound/pci/ad1889.c index 488f966adde3..7bfdf9c51416 100644 --- a/sound/pci/ad1889.c +++ b/sound/pci/ad1889.c @@ -1045,7 +1045,7 @@ snd_ad1889_remove(struct pci_dev *pci) snd_card_free(pci_get_drvdata(pci)); } -static DEFINE_PCI_DEVICE_TABLE(snd_ad1889_ids) = { +static const struct pci_device_id snd_ad1889_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_ANALOG_DEVICES, PCI_DEVICE_ID_AD1889JS) }, { 0, }, }; diff --git a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c index feb29c24cab1..af89e42b2160 100644 --- a/sound/pci/ali5451/ali5451.c +++ b/sound/pci/ali5451/ali5451.c @@ -263,7 +263,7 @@ struct snd_ali { #endif }; -static DEFINE_PCI_DEVICE_TABLE(snd_ali_ids) = { +static const struct pci_device_id snd_ali_ids[] = { {PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M5451), 0, 0, 0}, {0, } }; diff --git a/sound/pci/als300.c b/sound/pci/als300.c index cc9a15a1304b..7bb6ac565107 100644 --- a/sound/pci/als300.c +++ b/sound/pci/als300.c @@ -141,7 +141,7 @@ struct snd_als300_substream_data { int block_counter_register; }; -static DEFINE_PCI_DEVICE_TABLE(snd_als300_ids) = { +static const struct pci_device_id snd_als300_ids[] = { { 0x4005, 0x0300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_ALS300 }, { 0x4005, 0x0308, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_ALS300_PLUS }, { 0, } diff --git a/sound/pci/als4000.c b/sound/pci/als4000.c index b751c381d25e..d3e6424ee656 100644 --- a/sound/pci/als4000.c +++ b/sound/pci/als4000.c @@ -116,7 +116,7 @@ struct snd_card_als4000 { #endif }; -static DEFINE_PCI_DEVICE_TABLE(snd_als4000_ids) = { +static const struct pci_device_id snd_als4000_ids[] = { { 0x4005, 0x4000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* ALS4000 */ { 0, } }; diff --git a/sound/pci/asihpi/asihpi.c b/sound/pci/asihpi/asihpi.c index 901c9490398a..5017176bfaa1 100644 --- a/sound/pci/asihpi/asihpi.c +++ b/sound/pci/asihpi/asihpi.c @@ -2955,7 +2955,7 @@ static void snd_asihpi_remove(struct pci_dev *pci_dev) asihpi_adapter_remove(pci_dev); } -static DEFINE_PCI_DEVICE_TABLE(asihpi_pci_tbl) = { +static const struct pci_device_id asihpi_pci_tbl[] = { {HPI_PCI_VENDOR_ID_TI, HPI_PCI_DEV_ID_DSP6205, HPI_PCI_VENDOR_ID_AUDIOSCIENCE, PCI_ANY_ID, 0, 0, (kernel_ulong_t)HPI_6205}, diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c index ae07b4926dc2..7895c5d300c7 100644 --- a/sound/pci/atiixp.c +++ b/sound/pci/atiixp.c @@ -286,7 +286,7 @@ struct atiixp { /* */ -static DEFINE_PCI_DEVICE_TABLE(snd_atiixp_ids) = { +static const struct pci_device_id snd_atiixp_ids[] = { { PCI_VDEVICE(ATI, 0x4341), 0 }, /* SB200 */ { PCI_VDEVICE(ATI, 0x4361), 0 }, /* SB300 */ { PCI_VDEVICE(ATI, 0x4370), 0 }, /* SB400 */ diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c index b9dc96c5d21e..3c3241309a30 100644 --- a/sound/pci/atiixp_modem.c +++ b/sound/pci/atiixp_modem.c @@ -261,7 +261,7 @@ struct atiixp_modem { /* */ -static DEFINE_PCI_DEVICE_TABLE(snd_atiixp_ids) = { +static const struct pci_device_id snd_atiixp_ids[] = { { PCI_VDEVICE(ATI, 0x434d), 0 }, /* SB200 */ { PCI_VDEVICE(ATI, 0x4378), 0 }, /* SB400 */ { 0, } diff --git a/sound/pci/au88x0/au8810.c b/sound/pci/au88x0/au8810.c index aa51cc7771dd..1b2e34069eb3 100644 --- a/sound/pci/au88x0/au8810.c +++ b/sound/pci/au88x0/au8810.c @@ -1,6 +1,6 @@ #include "au8810.h" #include "au88x0.h" -static DEFINE_PCI_DEVICE_TABLE(snd_vortex_ids) = { +static const struct pci_device_id snd_vortex_ids[] = { {PCI_VDEVICE(AUREAL, PCI_DEVICE_ID_AUREAL_ADVANTAGE), 1,}, {0,} }; diff --git a/sound/pci/au88x0/au8820.c b/sound/pci/au88x0/au8820.c index 2f321e7306cd..74c53fa5f06b 100644 --- a/sound/pci/au88x0/au8820.c +++ b/sound/pci/au88x0/au8820.c @@ -1,6 +1,6 @@ #include "au8820.h" #include "au88x0.h" -static DEFINE_PCI_DEVICE_TABLE(snd_vortex_ids) = { +static const struct pci_device_id snd_vortex_ids[] = { {PCI_VDEVICE(AUREAL, PCI_DEVICE_ID_AUREAL_VORTEX_1), 0,}, {0,} }; diff --git a/sound/pci/au88x0/au8830.c b/sound/pci/au88x0/au8830.c index 279b78f06d22..56f675aad3ad 100644 --- a/sound/pci/au88x0/au8830.c +++ b/sound/pci/au88x0/au8830.c @@ -1,6 +1,6 @@ #include "au8830.h" #include "au88x0.h" -static DEFINE_PCI_DEVICE_TABLE(snd_vortex_ids) = { +static const struct pci_device_id snd_vortex_ids[] = { {PCI_VDEVICE(AUREAL, PCI_DEVICE_ID_AUREAL_VORTEX_2), 0,}, {0,} }; diff --git a/sound/pci/aw2/aw2-alsa.c b/sound/pci/aw2/aw2-alsa.c index 120d0d320a60..3878cf5de9a4 100644 --- a/sound/pci/aw2/aw2-alsa.c +++ b/sound/pci/aw2/aw2-alsa.c @@ -160,7 +160,7 @@ MODULE_PARM_DESC(id, "ID string for the Audiowerk2 soundcard."); module_param_array(enable, bool, NULL, 0444); MODULE_PARM_DESC(enable, "Enable Audiowerk2 soundcard."); -static DEFINE_PCI_DEVICE_TABLE(snd_aw2_ids) = { +static const struct pci_device_id snd_aw2_ids[] = { {PCI_VENDOR_ID_PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7146, 0, 0, 0, 0, 0}, {0} diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c index c9216c0a9c8b..5a69e26cb2fb 100644 --- a/sound/pci/azt3328.c +++ b/sound/pci/azt3328.c @@ -321,7 +321,7 @@ struct snd_azf3328 { #endif }; -static DEFINE_PCI_DEVICE_TABLE(snd_azf3328_ids) = { +static const struct pci_device_id snd_azf3328_ids[] = { { 0x122D, 0x50DC, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* PCI168/3328 */ { 0x122D, 0x80DA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* 3328 */ { 0, } diff --git a/sound/pci/bt87x.c b/sound/pci/bt87x.c index 70951fd9b354..058b9973c09c 100644 --- a/sound/pci/bt87x.c +++ b/sound/pci/bt87x.c @@ -796,7 +796,7 @@ fail: .driver_data = SND_BT87X_BOARD_ ## id } /* driver_data is the card id for that device */ -static DEFINE_PCI_DEVICE_TABLE(snd_bt87x_ids) = { +static const struct pci_device_id snd_bt87x_ids[] = { /* Hauppauge WinTV series */ BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x0070, 0x13eb, GENERIC), /* Hauppauge WinTV series */ @@ -966,7 +966,7 @@ static void snd_bt87x_remove(struct pci_dev *pci) /* default entries for all Bt87x cards - it's not exported */ /* driver_data is set to 0 to call detection */ -static DEFINE_PCI_DEVICE_TABLE(snd_bt87x_default_ids) = { +static const struct pci_device_id snd_bt87x_default_ids[] = { BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, PCI_ANY_ID, PCI_ANY_ID, UNKNOWN), BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_879, PCI_ANY_ID, PCI_ANY_ID, UNKNOWN), { } diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index f94cc6e97d4a..96af33965b51 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c @@ -1968,7 +1968,7 @@ static SIMPLE_DEV_PM_OPS(snd_ca0106_pm, snd_ca0106_suspend, snd_ca0106_resume); #endif // PCI IDs -static DEFINE_PCI_DEVICE_TABLE(snd_ca0106_ids) = { +static const struct pci_device_id snd_ca0106_ids[] = { { PCI_VDEVICE(CREATIVE, 0x0007), 0 }, /* Audigy LS or Live 24bit */ { 0, } }; diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c index 12c318e175f4..85ed40339db9 100644 --- a/sound/pci/cmipci.c +++ b/sound/pci/cmipci.c @@ -2803,7 +2803,7 @@ static inline void snd_cmipci_proc_init(struct cmipci *cm) {} #endif -static DEFINE_PCI_DEVICE_TABLE(snd_cmipci_ids) = { +static const struct pci_device_id snd_cmipci_ids[] = { {PCI_VDEVICE(CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8338A), 0}, {PCI_VDEVICE(CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8338B), 0}, {PCI_VDEVICE(CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8738), 0}, @@ -3026,7 +3026,7 @@ static int snd_cmipci_create(struct snd_card *card, struct pci_dev *pci, int integrated_midi = 0; char modelstr[16]; int pcm_index, pcm_spdif_index; - static DEFINE_PCI_DEVICE_TABLE(intel_82437vx) = { + static const struct pci_device_id intel_82437vx[] = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437VX) }, { }, }; diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c index 43d1f912c641..4c49b5c8a7b3 100644 --- a/sound/pci/cs4281.c +++ b/sound/pci/cs4281.c @@ -494,7 +494,7 @@ struct cs4281 { static irqreturn_t snd_cs4281_interrupt(int irq, void *dev_id); -static DEFINE_PCI_DEVICE_TABLE(snd_cs4281_ids) = { +static const struct pci_device_id snd_cs4281_ids[] = { { PCI_VDEVICE(CIRRUS, 0x6005), 0, }, /* CS4281 */ { 0, } }; diff --git a/sound/pci/cs46xx/cs46xx.c b/sound/pci/cs46xx/cs46xx.c index af0eacbc8bd2..6a6858c07826 100644 --- a/sound/pci/cs46xx/cs46xx.c +++ b/sound/pci/cs46xx/cs46xx.c @@ -64,7 +64,7 @@ MODULE_PARM_DESC(thinkpad, "Force to enable Thinkpad's CLKRUN control."); module_param_array(mmap_valid, bool, NULL, 0444); MODULE_PARM_DESC(mmap_valid, "Support OSS mmap."); -static DEFINE_PCI_DEVICE_TABLE(snd_cs46xx_ids) = { +static const struct pci_device_id snd_cs46xx_ids[] = { { PCI_VDEVICE(CIRRUS, 0x6001), 0, }, /* CS4280 */ { PCI_VDEVICE(CIRRUS, 0x6003), 0, }, /* CS4612 */ { PCI_VDEVICE(CIRRUS, 0x6004), 0, }, /* CS4615 */ diff --git a/sound/pci/cs5530.c b/sound/pci/cs5530.c index b4e0ff6a99a3..b1025507a467 100644 --- a/sound/pci/cs5530.c +++ b/sound/pci/cs5530.c @@ -66,7 +66,7 @@ struct snd_cs5530 { unsigned long pci_base; }; -static DEFINE_PCI_DEVICE_TABLE(snd_cs5530_ids) = { +static const struct pci_device_id snd_cs5530_ids[] = { {PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_AUDIO, PCI_ANY_ID, PCI_ANY_ID, 0, 0}, {0,} diff --git a/sound/pci/cs5535audio/cs5535audio.c b/sound/pci/cs5535audio/cs5535audio.c index edcbbda5c488..16288e4d338a 100644 --- a/sound/pci/cs5535audio/cs5535audio.c +++ b/sound/pci/cs5535audio/cs5535audio.c @@ -66,7 +66,7 @@ MODULE_PARM_DESC(id, "ID string for " DRIVER_NAME); module_param_array(enable, bool, NULL, 0444); MODULE_PARM_DESC(enable, "Enable " DRIVER_NAME); -static DEFINE_PCI_DEVICE_TABLE(snd_cs5535audio_ids) = { +static const struct pci_device_id snd_cs5535audio_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_AUDIO) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_AUDIO) }, {} diff --git a/sound/pci/ctxfi/ct20k1reg.h b/sound/pci/ctxfi/ct20k1reg.h index f2e34e3f27ee..5851249f11d9 100644 --- a/sound/pci/ctxfi/ct20k1reg.h +++ b/sound/pci/ctxfi/ct20k1reg.h @@ -7,7 +7,7 @@ */ #ifndef CT20K1REG_H -#define CT20k1REG_H +#define CT20K1REG_H /* 20k1 registers */ #define DSPXRAM_START 0x000000 @@ -632,5 +632,3 @@ #define I2SD_R 0x19L #endif /* CT20K1REG_H */ - - diff --git a/sound/pci/ctxfi/xfi.c b/sound/pci/ctxfi/xfi.c index 98426d09c8bd..8f8b566a1b35 100644 --- a/sound/pci/ctxfi/xfi.c +++ b/sound/pci/ctxfi/xfi.c @@ -44,7 +44,7 @@ MODULE_PARM_DESC(enable, "Enable Creative X-Fi driver"); module_param_array(subsystem, int, NULL, 0444); MODULE_PARM_DESC(subsystem, "Override subsystem ID for Creative X-Fi driver"); -static DEFINE_PCI_DEVICE_TABLE(ct_pci_dev_ids) = { +static const struct pci_device_id ct_pci_dev_ids[] = { /* only X-Fi is supported, so... */ { PCI_DEVICE(PCI_VENDOR_ID_CREATIVE, PCI_DEVICE_ID_CREATIVE_20K1), .driver_data = ATC20K1, diff --git a/sound/pci/echoaudio/darla20.c b/sound/pci/echoaudio/darla20.c index d47e72ae2ab3..4632946205a8 100644 --- a/sound/pci/echoaudio/darla20.c +++ b/sound/pci/echoaudio/darla20.c @@ -63,7 +63,7 @@ static const struct firmware card_fw[] = { {0, "darla20_dsp.fw"} }; -static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = { +static const struct pci_device_id snd_echo_ids[] = { {0x1057, 0x1801, 0xECC0, 0x0010, 0, 0, 0}, /* DSP 56301 Darla20 rev.0 */ {0,} }; diff --git a/sound/pci/echoaudio/darla24.c b/sound/pci/echoaudio/darla24.c index 413acf702e3b..f81c839cc887 100644 --- a/sound/pci/echoaudio/darla24.c +++ b/sound/pci/echoaudio/darla24.c @@ -67,7 +67,7 @@ static const struct firmware card_fw[] = { {0, "darla24_dsp.fw"} }; -static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = { +static const struct pci_device_id snd_echo_ids[] = { {0x1057, 0x1801, 0xECC0, 0x0040, 0, 0, 0}, /* DSP 56301 Darla24 rev.0 */ {0x1057, 0x1801, 0xECC0, 0x0041, 0, 0, 0}, /* DSP 56301 Darla24 rev.1 */ {0,} diff --git a/sound/pci/echoaudio/echo3g.c b/sound/pci/echoaudio/echo3g.c index 1ec4edca060d..3a5346c33d76 100644 --- a/sound/pci/echoaudio/echo3g.c +++ b/sound/pci/echoaudio/echo3g.c @@ -81,7 +81,7 @@ static const struct firmware card_fw[] = { {0, "3g_asic.fw"} }; -static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = { +static const struct pci_device_id snd_echo_ids[] = { {0x1057, 0x3410, 0xECC0, 0x0100, 0, 0, 0}, /* Echo 3G */ {0,} }; diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c index 9f10c9e0df5e..631aaa4046ad 100644 --- a/sound/pci/echoaudio/echoaudio.c +++ b/sound/pci/echoaudio/echoaudio.c @@ -1754,9 +1754,6 @@ static struct snd_kcontrol_new snd_echo_vumeters_switch = { static int snd_echo_vumeters_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - struct echoaudio *chip; - - chip = snd_kcontrol_chip(kcontrol); uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = 96; uinfo->value.integer.min = ECHOGAIN_MINOUT; @@ -1798,9 +1795,6 @@ static struct snd_kcontrol_new snd_echo_vumeters = { static int snd_echo_channels_info_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - struct echoaudio *chip; - - chip = snd_kcontrol_chip(kcontrol); uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = 6; uinfo->value.integer.min = 0; diff --git a/sound/pci/echoaudio/gina20.c b/sound/pci/echoaudio/gina20.c index 039125b7e475..9cb81c500824 100644 --- a/sound/pci/echoaudio/gina20.c +++ b/sound/pci/echoaudio/gina20.c @@ -67,7 +67,7 @@ static const struct firmware card_fw[] = { {0, "gina20_dsp.fw"} }; -static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = { +static const struct pci_device_id snd_echo_ids[] = { {0x1057, 0x1801, 0xECC0, 0x0020, 0, 0, 0}, /* DSP 56301 Gina20 rev.0 */ {0,} }; diff --git a/sound/pci/echoaudio/gina24.c b/sound/pci/echoaudio/gina24.c index 5e966f6ffaa3..35d3e6eac990 100644 --- a/sound/pci/echoaudio/gina24.c +++ b/sound/pci/echoaudio/gina24.c @@ -85,7 +85,7 @@ static const struct firmware card_fw[] = { {0, "gina24_361_asic.fw"} }; -static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = { +static const struct pci_device_id snd_echo_ids[] = { {0x1057, 0x1801, 0xECC0, 0x0050, 0, 0, 0}, /* DSP 56301 Gina24 rev.0 */ {0x1057, 0x1801, 0xECC0, 0x0051, 0, 0, 0}, /* DSP 56301 Gina24 rev.1 */ {0x1057, 0x3410, 0xECC0, 0x0050, 0, 0, 0}, /* DSP 56361 Gina24 rev.0 */ diff --git a/sound/pci/echoaudio/indigo.c b/sound/pci/echoaudio/indigo.c index c166b7eea268..8d91842d1268 100644 --- a/sound/pci/echoaudio/indigo.c +++ b/sound/pci/echoaudio/indigo.c @@ -68,7 +68,7 @@ static const struct firmware card_fw[] = { {0, "indigo_dsp.fw"} }; -static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = { +static const struct pci_device_id snd_echo_ids[] = { {0x1057, 0x3410, 0xECC0, 0x0090, 0, 0, 0}, /* Indigo */ {0,} }; diff --git a/sound/pci/echoaudio/indigodj.c b/sound/pci/echoaudio/indigodj.c index a3ef3b992f40..289cb969f5b9 100644 --- a/sound/pci/echoaudio/indigodj.c +++ b/sound/pci/echoaudio/indigodj.c @@ -68,7 +68,7 @@ static const struct firmware card_fw[] = { {0, "indigo_dj_dsp.fw"} }; -static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = { +static const struct pci_device_id snd_echo_ids[] = { {0x1057, 0x3410, 0xECC0, 0x00B0, 0, 0, 0}, /* Indigo DJ*/ {0,} }; diff --git a/sound/pci/echoaudio/indigodjx.c b/sound/pci/echoaudio/indigodjx.c index f516444fc02d..201688ee50fa 100644 --- a/sound/pci/echoaudio/indigodjx.c +++ b/sound/pci/echoaudio/indigodjx.c @@ -68,7 +68,7 @@ static const struct firmware card_fw[] = { {0, "indigo_djx_dsp.fw"} }; -static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = { +static const struct pci_device_id snd_echo_ids[] = { {0x1057, 0x3410, 0xECC0, 0x00E0, 0, 0, 0}, /* Indigo DJx*/ {0,} }; diff --git a/sound/pci/echoaudio/indigoio.c b/sound/pci/echoaudio/indigoio.c index c22c82fd1f99..405a3f2e496f 100644 --- a/sound/pci/echoaudio/indigoio.c +++ b/sound/pci/echoaudio/indigoio.c @@ -69,7 +69,7 @@ static const struct firmware card_fw[] = { {0, "indigo_io_dsp.fw"} }; -static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = { +static const struct pci_device_id snd_echo_ids[] = { {0x1057, 0x3410, 0xECC0, 0x00A0, 0, 0, 0}, /* Indigo IO*/ {0,} }; diff --git a/sound/pci/echoaudio/indigoiox.c b/sound/pci/echoaudio/indigoiox.c index 86cf2d071758..e145b688148a 100644 --- a/sound/pci/echoaudio/indigoiox.c +++ b/sound/pci/echoaudio/indigoiox.c @@ -69,7 +69,7 @@ static const struct firmware card_fw[] = { {0, "indigo_iox_dsp.fw"} }; -static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = { +static const struct pci_device_id snd_echo_ids[] = { {0x1057, 0x3410, 0xECC0, 0x00D0, 0, 0, 0}, /* Indigo IOx */ {0,} }; diff --git a/sound/pci/echoaudio/layla20.c b/sound/pci/echoaudio/layla20.c index 6a027f3931cc..b392dd776b71 100644 --- a/sound/pci/echoaudio/layla20.c +++ b/sound/pci/echoaudio/layla20.c @@ -76,7 +76,7 @@ static const struct firmware card_fw[] = { {0, "layla20_asic.fw"} }; -static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = { +static const struct pci_device_id snd_echo_ids[] = { {0x1057, 0x1801, 0xECC0, 0x0030, 0, 0, 0}, /* DSP 56301 Layla20 rev.0 */ {0x1057, 0x1801, 0xECC0, 0x0031, 0, 0, 0}, /* DSP 56301 Layla20 rev.1 */ {0,} diff --git a/sound/pci/echoaudio/layla24.c b/sound/pci/echoaudio/layla24.c index 96a5991aca8f..bc7f730b0ec6 100644 --- a/sound/pci/echoaudio/layla24.c +++ b/sound/pci/echoaudio/layla24.c @@ -87,7 +87,7 @@ static const struct firmware card_fw[] = { {0, "layla24_2S_asic.fw"} }; -static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = { +static const struct pci_device_id snd_echo_ids[] = { {0x1057, 0x3410, 0xECC0, 0x0060, 0, 0, 0}, /* DSP 56361 Layla24 rev.0 */ {0,} }; diff --git a/sound/pci/echoaudio/mia.c b/sound/pci/echoaudio/mia.c index b8ce27e67e3a..27a9a6e5db2d 100644 --- a/sound/pci/echoaudio/mia.c +++ b/sound/pci/echoaudio/mia.c @@ -77,7 +77,7 @@ static const struct firmware card_fw[] = { {0, "mia_dsp.fw"} }; -static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = { +static const struct pci_device_id snd_echo_ids[] = { {0x1057, 0x3410, 0xECC0, 0x0080, 0, 0, 0}, /* DSP 56361 Mia rev.0 */ {0x1057, 0x3410, 0xECC0, 0x0081, 0, 0, 0}, /* DSP 56361 Mia rev.1 */ {0,} diff --git a/sound/pci/echoaudio/mona.c b/sound/pci/echoaudio/mona.c index 1283bfb26b2e..3d13875c303d 100644 --- a/sound/pci/echoaudio/mona.c +++ b/sound/pci/echoaudio/mona.c @@ -92,7 +92,7 @@ static const struct firmware card_fw[] = { {0, "mona_2_asic.fw"} }; -static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = { +static const struct pci_device_id snd_echo_ids[] = { {0x1057, 0x1801, 0xECC0, 0x0070, 0, 0, 0}, /* DSP 56301 Mona rev.0 */ {0x1057, 0x1801, 0xECC0, 0x0071, 0, 0, 0}, /* DSP 56301 Mona rev.1 */ {0x1057, 0x1801, 0xECC0, 0x0072, 0, 0, 0}, /* DSP 56301 Mona rev.2 */ diff --git a/sound/pci/emu10k1/emu10k1.c b/sound/pci/emu10k1/emu10k1.c index ad9d9f8b48ed..4c171636efcd 100644 --- a/sound/pci/emu10k1/emu10k1.c +++ b/sound/pci/emu10k1/emu10k1.c @@ -79,7 +79,7 @@ MODULE_PARM_DESC(delay_pcm_irq, "Delay PCM interrupt by specified number of samp /* * Class 0401: 1102:0008 (rev 00) Subsystem: 1102:1001 -> Audigy2 Value Model:SB0400 */ -static DEFINE_PCI_DEVICE_TABLE(snd_emu10k1_ids) = { +static const struct pci_device_id snd_emu10k1_ids[] = { { PCI_VDEVICE(CREATIVE, 0x0002), 0 }, /* EMU10K1 */ { PCI_VDEVICE(CREATIVE, 0x0004), 1 }, /* Audigy */ { PCI_VDEVICE(CREATIVE, 0x0008), 1 }, /* Audigy 2 Value SB0400 */ diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c index efe017526977..e223de1408c0 100644 --- a/sound/pci/emu10k1/emu10k1x.c +++ b/sound/pci/emu10k1/emu10k1x.c @@ -1634,7 +1634,7 @@ static void snd_emu10k1x_remove(struct pci_dev *pci) } // PCI IDs -static DEFINE_PCI_DEVICE_TABLE(snd_emu10k1x_ids) = { +static const struct pci_device_id snd_emu10k1x_ids[] = { { PCI_VDEVICE(CREATIVE, 0x0006), 0 }, /* Dell OEM version (EMU10K1) */ { 0, } }; diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c index 29cd339ffc37..d94cb3ca7a64 100644 --- a/sound/pci/ens1370.c +++ b/sound/pci/ens1370.c @@ -446,7 +446,7 @@ struct ensoniq { static irqreturn_t snd_audiopci_interrupt(int irq, void *dev_id); -static DEFINE_PCI_DEVICE_TABLE(snd_audiopci_ids) = { +static const struct pci_device_id snd_audiopci_ids[] = { #ifdef CHIP1370 { PCI_VDEVICE(ENSONIQ, 0x5000), 0, }, /* ES1370 */ #endif diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c index 34d95bf916b5..639962443ccc 100644 --- a/sound/pci/es1938.c +++ b/sound/pci/es1938.c @@ -243,7 +243,7 @@ struct es1938 { static irqreturn_t snd_es1938_interrupt(int irq, void *dev_id); -static DEFINE_PCI_DEVICE_TABLE(snd_es1938_ids) = { +static const struct pci_device_id snd_es1938_ids[] = { { PCI_VDEVICE(ESS, 0x1969), 0, }, /* Solo-1 */ { 0, } }; diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c index 5bb1cf603301..a9956a7c5677 100644 --- a/sound/pci/es1968.c +++ b/sound/pci/es1968.c @@ -570,7 +570,7 @@ struct es1968 { static irqreturn_t snd_es1968_interrupt(int irq, void *dev_id); -static DEFINE_PCI_DEVICE_TABLE(snd_es1968_ids) = { +static const struct pci_device_id snd_es1968_ids[] = { /* Maestro 1 */ { 0x1285, 0x0100, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, TYPE_MAESTRO }, /* Maestro 2 */ diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c index 529f5f4f4c9c..c5038303a126 100644 --- a/sound/pci/fm801.c +++ b/sound/pci/fm801.c @@ -218,7 +218,7 @@ struct fm801 { #endif }; -static DEFINE_PCI_DEVICE_TABLE(snd_fm801_ids) = { +static const struct pci_device_id snd_fm801_ids[] = { { 0x1319, 0x0801, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0, }, /* FM801 */ { 0x5213, 0x0510, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0, }, /* Gallant Odyssey Sound 4 */ { 0, } diff --git a/sound/pci/hda/ca0132_regs.h b/sound/pci/hda/ca0132_regs.h index 07e760937d3c..8371274aa811 100644 --- a/sound/pci/hda/ca0132_regs.h +++ b/sound/pci/hda/ca0132_regs.h @@ -20,7 +20,7 @@ */ #ifndef __CA0132_REGS_H -#define __CA0312_REGS_H +#define __CA0132_REGS_H #define DSP_CHIP_OFFSET 0x100000 #define DSP_DBGCNTL_MODULE_OFFSET 0xE30 diff --git a/sound/pci/hda/dell_wmi_helper.c b/sound/pci/hda/dell_wmi_helper.c new file mode 100644 index 000000000000..9c22f95838ef --- /dev/null +++ b/sound/pci/hda/dell_wmi_helper.c @@ -0,0 +1,76 @@ +/* Helper functions for Dell Mic Mute LED control; + * to be included from codec driver + */ + +#if IS_ENABLED(CONFIG_LEDS_DELL_NETBOOKS) +#include <linux/dell-led.h> + +static int dell_led_value; +static int (*dell_led_set_func)(int, int); +static void (*dell_old_cap_hook)(struct hda_codec *, + struct snd_kcontrol *, + struct snd_ctl_elem_value *); + +static void update_dell_wmi_micmute_led(struct hda_codec *codec, + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + if (dell_old_cap_hook) + dell_old_cap_hook(codec, kcontrol, ucontrol); + + if (!ucontrol || !dell_led_set_func) + return; + if (strcmp("Capture Switch", ucontrol->id.name) == 0 && ucontrol->id.index == 0) { + /* TODO: How do I verify if it's a mono or stereo here? */ + int val = (ucontrol->value.integer.value[0] || ucontrol->value.integer.value[1]) ? 0 : 1; + if (val == dell_led_value) + return; + dell_led_value = val; + if (dell_led_set_func) + dell_led_set_func(DELL_LED_MICMUTE, dell_led_value); + } +} + + +static void alc_fixup_dell_wmi(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct alc_spec *spec = codec->spec; + bool removefunc = false; + + if (action == HDA_FIXUP_ACT_PROBE) { + if (!dell_led_set_func) + dell_led_set_func = symbol_request(dell_app_wmi_led_set); + if (!dell_led_set_func) { + codec_warn(codec, "Failed to find dell wmi symbol dell_app_wmi_led_set\n"); + return; + } + + removefunc = true; + if (dell_led_set_func(DELL_LED_MICMUTE, false) >= 0) { + dell_led_value = 0; + if (spec->gen.num_adc_nids > 1) + codec_dbg(codec, "Skipping micmute LED control due to several ADCs"); + else { + dell_old_cap_hook = spec->gen.cap_sync_hook; + spec->gen.cap_sync_hook = update_dell_wmi_micmute_led; + removefunc = false; + } + } + + } + + if (dell_led_set_func && (action == HDA_FIXUP_ACT_FREE || removefunc)) { + symbol_put(dell_app_wmi_led_set); + dell_led_set_func = NULL; + dell_old_cap_hook = NULL; + } +} + +#else /* CONFIG_LEDS_DELL_NETBOOKS */ +static void alc_fixup_dell_wmi(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ +} + +#endif /* CONFIG_LEDS_DELL_NETBOOKS */ diff --git a/sound/pci/hda/hda_auto_parser.c b/sound/pci/hda/hda_auto_parser.c index dabe41975a9d..51dea49aadd4 100644 --- a/sound/pci/hda/hda_auto_parser.c +++ b/sound/pci/hda/hda_auto_parser.c @@ -17,8 +17,6 @@ #include "hda_local.h" #include "hda_auto_parser.h" -#define SFX "hda_codec: " - /* * Helper for automatic pin configuration */ @@ -856,7 +854,7 @@ void snd_hda_pick_pin_fixup(struct hda_codec *codec, { const struct snd_hda_pin_quirk *pq; - if (codec->fixup_forced) + if (codec->fixup_id != HDA_FIXUP_ID_NOT_SET) return; for (pq = pin_quirk; pq->subvendor; pq++) { @@ -882,14 +880,17 @@ void snd_hda_pick_fixup(struct hda_codec *codec, const struct hda_fixup *fixlist) { const struct snd_pci_quirk *q; - int id = -1; + int id = HDA_FIXUP_ID_NOT_SET; const char *name = NULL; + if (codec->fixup_id != HDA_FIXUP_ID_NOT_SET) + return; + /* when model=nofixup is given, don't pick up any fixups */ if (codec->modelname && !strcmp(codec->modelname, "nofixup")) { codec->fixup_list = NULL; - codec->fixup_id = -1; - codec->fixup_forced = 1; + codec->fixup_name = NULL; + codec->fixup_id = HDA_FIXUP_ID_NO_FIXUP; return; } @@ -899,13 +900,12 @@ void snd_hda_pick_fixup(struct hda_codec *codec, codec->fixup_id = models->id; codec->fixup_name = models->name; codec->fixup_list = fixlist; - codec->fixup_forced = 1; return; } models++; } } - if (id < 0 && quirk) { + if (quirk) { q = snd_pci_quirk_lookup(codec->bus->pci, quirk); if (q) { id = q->value; @@ -929,7 +929,6 @@ void snd_hda_pick_fixup(struct hda_codec *codec, } } - codec->fixup_forced = 0; codec->fixup_id = id; if (id >= 0) { codec->fixup_list = fixlist; diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 4c20277a6835..ec6a7d0d1886 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1476,6 +1476,7 @@ int snd_hda_codec_new(struct hda_bus *bus, INIT_DELAYED_WORK(&codec->jackpoll_work, hda_jackpoll_work); codec->depop_delay = -1; + codec->fixup_id = HDA_FIXUP_ID_NOT_SET; #ifdef CONFIG_PM spin_lock_init(&codec->power_lock); @@ -2727,7 +2728,7 @@ int snd_hda_codec_reset(struct hda_codec *codec) return 0; } -typedef int (*map_slave_func_t)(void *, struct snd_kcontrol *); +typedef int (*map_slave_func_t)(struct hda_codec *, void *, struct snd_kcontrol *); /* apply the function to all matching slave ctls in the mixer list */ static int map_slaves(struct hda_codec *codec, const char * const *slaves, @@ -2751,7 +2752,7 @@ static int map_slaves(struct hda_codec *codec, const char * const *slaves, name = tmpname; } if (!strcmp(sctl->id.name, name)) { - err = func(data, sctl); + err = func(codec, data, sctl); if (err) return err; break; @@ -2761,13 +2762,15 @@ static int map_slaves(struct hda_codec *codec, const char * const *slaves, return 0; } -static int check_slave_present(void *data, struct snd_kcontrol *sctl) +static int check_slave_present(struct hda_codec *codec, + void *data, struct snd_kcontrol *sctl) { return 1; } /* guess the value corresponding to 0dB */ -static int get_kctl_0dB_offset(struct snd_kcontrol *kctl, int *step_to_check) +static int get_kctl_0dB_offset(struct hda_codec *codec, + struct snd_kcontrol *kctl, int *step_to_check) { int _tlv[4]; const int *tlv = NULL; @@ -2788,7 +2791,7 @@ static int get_kctl_0dB_offset(struct snd_kcontrol *kctl, int *step_to_check) if (!step) return -1; if (*step_to_check && *step_to_check != step) { - snd_printk(KERN_ERR "hda_codec: Mismatching dB step for vmaster slave (%d!=%d)\n", + codec_err(codec, "Mismatching dB step for vmaster slave (%d!=%d)\n", - *step_to_check, step); return -1; } @@ -2813,20 +2816,28 @@ static int put_kctl_with_value(struct snd_kcontrol *kctl, int val) } /* initialize the slave volume with 0dB */ -static int init_slave_0dB(void *data, struct snd_kcontrol *slave) +static int init_slave_0dB(struct hda_codec *codec, + void *data, struct snd_kcontrol *slave) { - int offset = get_kctl_0dB_offset(slave, data); + int offset = get_kctl_0dB_offset(codec, slave, data); if (offset > 0) put_kctl_with_value(slave, offset); return 0; } /* unmute the slave */ -static int init_slave_unmute(void *data, struct snd_kcontrol *slave) +static int init_slave_unmute(struct hda_codec *codec, + void *data, struct snd_kcontrol *slave) { return put_kctl_with_value(slave, 1); } +static int add_slave(struct hda_codec *codec, + void *data, struct snd_kcontrol *slave) +{ + return snd_ctl_add_slave(data, slave); +} + /** * snd_hda_add_vmaster - create a virtual master control and add slaves * @codec: HD-audio codec @@ -2869,8 +2880,7 @@ int __snd_hda_add_vmaster(struct hda_codec *codec, char *name, if (err < 0) return err; - err = map_slaves(codec, slaves, suffix, - (map_slave_func_t)snd_ctl_add_slave, kctl); + err = map_slaves(codec, slaves, suffix, add_slave, kctl); if (err < 0) return err; @@ -4280,6 +4290,7 @@ static struct hda_rate_tbl rate_bits[] = { /** * snd_hda_calc_stream_format - calculate format bitset + * @codec: HD-audio codec * @rate: the sample rate * @channels: the number of channels * @format: the PCM format (SNDRV_PCM_FORMAT_XXX) @@ -4289,7 +4300,8 @@ static struct hda_rate_tbl rate_bits[] = { * * Return zero if invalid. */ -unsigned int snd_hda_calc_stream_format(unsigned int rate, +unsigned int snd_hda_calc_stream_format(struct hda_codec *codec, + unsigned int rate, unsigned int channels, unsigned int format, unsigned int maxbps, @@ -4304,12 +4316,12 @@ unsigned int snd_hda_calc_stream_format(unsigned int rate, break; } if (!rate_bits[i].hz) { - snd_printdd("invalid rate %d\n", rate); + codec_dbg(codec, "invalid rate %d\n", rate); return 0; } if (channels == 0 || channels > 8) { - snd_printdd("invalid channels %d\n", channels); + codec_dbg(codec, "invalid channels %d\n", channels); return 0; } val |= channels - 1; @@ -4332,7 +4344,7 @@ unsigned int snd_hda_calc_stream_format(unsigned int rate, val |= AC_FMT_BITS_20; break; default: - snd_printdd("invalid format width %d\n", + codec_dbg(codec, "invalid format width %d\n", snd_pcm_format_width(format)); return 0; } @@ -5670,12 +5682,13 @@ EXPORT_SYMBOL_GPL(_snd_hda_set_pin_ctl); * suffix is appended to the label. This label index number is stored * to type_idx when non-NULL pointer is given. */ -int snd_hda_add_imux_item(struct hda_input_mux *imux, const char *label, +int snd_hda_add_imux_item(struct hda_codec *codec, + struct hda_input_mux *imux, const char *label, int index, int *type_idx) { int i, label_idx = 0; if (imux->num_items >= HDA_MAX_NUM_INPUTS) { - snd_printd(KERN_ERR "hda_codec: Too many imux items!\n"); + codec_err(codec, "hda_codec: Too many imux items!\n"); return -EINVAL; } for (i = 0; i < imux->num_items; i++) { diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 5825aa17d8e3..bbc5a1392c75 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -402,7 +402,6 @@ struct hda_codec { /* fix-up list */ int fixup_id; - unsigned int fixup_forced:1; /* fixup explicitly set by user */ const struct hda_fixup *fixup_list; const char *fixup_name; @@ -538,7 +537,8 @@ void __snd_hda_codec_cleanup_stream(struct hda_codec *codec, hda_nid_t nid, int do_now); #define snd_hda_codec_cleanup_stream(codec, nid) \ __snd_hda_codec_cleanup_stream(codec, nid, 0) -unsigned int snd_hda_calc_stream_format(unsigned int rate, +unsigned int snd_hda_calc_stream_format(struct hda_codec *codec, + unsigned int rate, unsigned int channels, unsigned int format, unsigned int maxbps, diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c index 6df04d91c93c..8337645aa7a5 100644 --- a/sound/pci/hda/hda_controller.c +++ b/sound/pci/hda/hda_controller.c @@ -27,6 +27,7 @@ #include <linux/module.h> #include <linux/pm_runtime.h> #include <linux/slab.h> +#include <linux/reboot.h> #include <sound/core.h> #include <sound/initval.h> #include "hda_priv.h" @@ -152,11 +153,11 @@ static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev) upper_32_bits(azx_dev->bdl.addr)); /* enable the position buffer */ - if (chip->position_fix[0] != POS_FIX_LPIB || - chip->position_fix[1] != POS_FIX_LPIB) { - if (!(azx_readl(chip, DPLBASE) & ICH6_DPLBASE_ENABLE)) + if (chip->get_position[0] != azx_get_pos_lpib || + chip->get_position[1] != azx_get_pos_lpib) { + if (!(azx_readl(chip, DPLBASE) & AZX_DPLBASE_ENABLE)) azx_writel(chip, DPLBASE, - (u32)chip->posbuf.addr | ICH6_DPLBASE_ENABLE); + (u32)chip->posbuf.addr | AZX_DPLBASE_ENABLE); } /* set the interrupt enable bits in the descriptor control register */ @@ -482,7 +483,8 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream) } azx_stream_reset(chip, azx_dev); - format_val = snd_hda_calc_stream_format(runtime->rate, + format_val = snd_hda_calc_stream_format(apcm->codec, + runtime->rate, runtime->channels, runtime->format, hinfo->maxbps, @@ -673,125 +675,40 @@ static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) return 0; } -/* get the current DMA position with correction on VIA chips */ -static unsigned int azx_via_get_position(struct azx *chip, - struct azx_dev *azx_dev) +unsigned int azx_get_pos_lpib(struct azx *chip, struct azx_dev *azx_dev) { - unsigned int link_pos, mini_pos, bound_pos; - unsigned int mod_link_pos, mod_dma_pos, mod_mini_pos; - unsigned int fifo_size; - - link_pos = azx_sd_readl(chip, azx_dev, SD_LPIB); - if (azx_dev->substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - /* Playback, no problem using link position */ - return link_pos; - } - - /* Capture */ - /* For new chipset, - * use mod to get the DMA position just like old chipset - */ - mod_dma_pos = le32_to_cpu(*azx_dev->posbuf); - mod_dma_pos %= azx_dev->period_bytes; - - /* azx_dev->fifo_size can't get FIFO size of in stream. - * Get from base address + offset. - */ - fifo_size = readw(chip->remap_addr + VIA_IN_STREAM0_FIFO_SIZE_OFFSET); - - if (azx_dev->insufficient) { - /* Link position never gather than FIFO size */ - if (link_pos <= fifo_size) - return 0; - - azx_dev->insufficient = 0; - } - - if (link_pos <= fifo_size) - mini_pos = azx_dev->bufsize + link_pos - fifo_size; - else - mini_pos = link_pos - fifo_size; - - /* Find nearest previous boudary */ - mod_mini_pos = mini_pos % azx_dev->period_bytes; - mod_link_pos = link_pos % azx_dev->period_bytes; - if (mod_link_pos >= fifo_size) - bound_pos = link_pos - mod_link_pos; - else if (mod_dma_pos >= mod_mini_pos) - bound_pos = mini_pos - mod_mini_pos; - else { - bound_pos = mini_pos - mod_mini_pos + azx_dev->period_bytes; - if (bound_pos >= azx_dev->bufsize) - bound_pos = 0; - } + return azx_sd_readl(chip, azx_dev, SD_LPIB); +} +EXPORT_SYMBOL_GPL(azx_get_pos_lpib); - /* Calculate real DMA position we want */ - return bound_pos + mod_dma_pos; +unsigned int azx_get_pos_posbuf(struct azx *chip, struct azx_dev *azx_dev) +{ + return le32_to_cpu(*azx_dev->posbuf); } +EXPORT_SYMBOL_GPL(azx_get_pos_posbuf); unsigned int azx_get_position(struct azx *chip, - struct azx_dev *azx_dev, - bool with_check) + struct azx_dev *azx_dev) { struct snd_pcm_substream *substream = azx_dev->substream; - struct azx_pcm *apcm = snd_pcm_substream_chip(substream); unsigned int pos; int stream = substream->stream; - struct hda_pcm_stream *hinfo = apcm->hinfo[stream]; int delay = 0; - switch (chip->position_fix[stream]) { - case POS_FIX_LPIB: - /* read LPIB */ - pos = azx_sd_readl(chip, azx_dev, SD_LPIB); - break; - case POS_FIX_VIACOMBO: - pos = azx_via_get_position(chip, azx_dev); - break; - default: - /* use the position buffer */ - pos = le32_to_cpu(*azx_dev->posbuf); - if (with_check && chip->position_fix[stream] == POS_FIX_AUTO) { - if (!pos || pos == (u32)-1) { - dev_info(chip->card->dev, - "Invalid position buffer, using LPIB read method instead.\n"); - chip->position_fix[stream] = POS_FIX_LPIB; - pos = azx_sd_readl(chip, azx_dev, SD_LPIB); - } else - chip->position_fix[stream] = POS_FIX_POSBUF; - } - break; - } + if (chip->get_position[stream]) + pos = chip->get_position[stream](chip, azx_dev); + else /* use the position buffer as default */ + pos = azx_get_pos_posbuf(chip, azx_dev); if (pos >= azx_dev->bufsize) pos = 0; - /* calculate runtime delay from LPIB */ - if (substream->runtime && - chip->position_fix[stream] == POS_FIX_POSBUF && - (chip->driver_caps & AZX_DCAPS_COUNT_LPIB_DELAY)) { - unsigned int lpib_pos = azx_sd_readl(chip, azx_dev, SD_LPIB); - if (stream == SNDRV_PCM_STREAM_PLAYBACK) - delay = pos - lpib_pos; - else - delay = lpib_pos - pos; - if (delay < 0) { - if (delay >= azx_dev->delay_negative_threshold) - delay = 0; - else - delay += azx_dev->bufsize; - } - if (delay >= azx_dev->period_bytes) { - dev_info(chip->card->dev, - "Unstable LPIB (%d >= %d); disabling LPIB delay counting\n", - delay, azx_dev->period_bytes); - delay = 0; - chip->driver_caps &= ~AZX_DCAPS_COUNT_LPIB_DELAY; - } - delay = bytes_to_frames(substream->runtime, delay); - } - if (substream->runtime) { + struct azx_pcm *apcm = snd_pcm_substream_chip(substream); + struct hda_pcm_stream *hinfo = apcm->hinfo[stream]; + + if (chip->get_delay[stream]) + delay += chip->get_delay[stream](chip, azx_dev, pos); if (hinfo->ops.get_delay) delay += hinfo->ops.get_delay(hinfo, apcm->codec, substream); @@ -809,7 +726,7 @@ static snd_pcm_uframes_t azx_pcm_pointer(struct snd_pcm_substream *substream) struct azx *chip = apcm->chip; struct azx_dev *azx_dev = get_azx_dev(substream); return bytes_to_frames(substream->runtime, - azx_get_position(chip, azx_dev, false)); + azx_get_position(chip, azx_dev)); } static int azx_get_wallclock_tstamp(struct snd_pcm_substream *substream, @@ -1059,10 +976,10 @@ static void azx_init_cmd_io(struct azx *chip) azx_writew(chip, CORBWP, 0); /* reset the corb hw read pointer */ - azx_writew(chip, CORBRP, ICH6_CORBRP_RST); + azx_writew(chip, CORBRP, AZX_CORBRP_RST); if (!(chip->driver_caps & AZX_DCAPS_CORBRP_SELF_CLEAR)) { for (timeout = 1000; timeout > 0; timeout--) { - if ((azx_readw(chip, CORBRP) & ICH6_CORBRP_RST) == ICH6_CORBRP_RST) + if ((azx_readw(chip, CORBRP) & AZX_CORBRP_RST) == AZX_CORBRP_RST) break; udelay(1); } @@ -1082,7 +999,7 @@ static void azx_init_cmd_io(struct azx *chip) } /* enable corb dma */ - azx_writeb(chip, CORBCTL, ICH6_CORBCTL_RUN); + azx_writeb(chip, CORBCTL, AZX_CORBCTL_RUN); /* RIRB set up */ chip->rirb.addr = chip->rb.addr + 2048; @@ -1095,14 +1012,14 @@ static void azx_init_cmd_io(struct azx *chip) /* set the rirb size to 256 entries (ULI requires explicitly) */ azx_writeb(chip, RIRBSIZE, 0x02); /* reset the rirb hw write pointer */ - azx_writew(chip, RIRBWP, ICH6_RIRBWP_RST); + azx_writew(chip, RIRBWP, AZX_RIRBWP_RST); /* set N=1, get RIRB response interrupt for new entry */ if (chip->driver_caps & AZX_DCAPS_CTX_WORKAROUND) azx_writew(chip, RINTCNT, 0xc0); else azx_writew(chip, RINTCNT, 1); /* enable rirb dma and response irq */ - azx_writeb(chip, RIRBCTL, ICH6_RBCTL_DMA_EN | ICH6_RBCTL_IRQ_EN); + azx_writeb(chip, RIRBCTL, AZX_RBCTL_DMA_EN | AZX_RBCTL_IRQ_EN); spin_unlock_irq(&chip->reg_lock); } EXPORT_SYMBOL_GPL(azx_init_cmd_io); @@ -1146,7 +1063,7 @@ static int azx_corb_send_cmd(struct hda_bus *bus, u32 val) return -EIO; } wp++; - wp %= ICH6_MAX_CORB_ENTRIES; + wp %= AZX_MAX_CORB_ENTRIES; rp = azx_readw(chip, CORBRP); if (wp == rp) { @@ -1164,7 +1081,7 @@ static int azx_corb_send_cmd(struct hda_bus *bus, u32 val) return 0; } -#define ICH6_RIRB_EX_UNSOL_EV (1<<4) +#define AZX_RIRB_EX_UNSOL_EV (1<<4) /* retrieve RIRB entry - called from interrupt handler */ static void azx_update_rirb(struct azx *chip) @@ -1185,7 +1102,7 @@ static void azx_update_rirb(struct azx *chip) while (chip->rirb.rp != wp) { chip->rirb.rp++; - chip->rirb.rp %= ICH6_MAX_RIRB_ENTRIES; + chip->rirb.rp %= AZX_MAX_RIRB_ENTRIES; rp = chip->rirb.rp << 1; /* an RIRB entry is 8-bytes */ res_ex = le32_to_cpu(chip->rirb.buf[rp + 1]); @@ -1196,8 +1113,7 @@ static void azx_update_rirb(struct azx *chip) res, res_ex, chip->rirb.rp, wp); snd_BUG(); - } - else if (res_ex & ICH6_RIRB_EX_UNSOL_EV) + } else if (res_ex & AZX_RIRB_EX_UNSOL_EV) snd_hda_queue_unsol_event(chip->bus, res, res_ex); else if (chip->rirb.cmds[addr]) { chip->rirb.res[addr] = res; @@ -1305,7 +1221,7 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus, /* release CORB/RIRB */ azx_free_cmd_io(chip); /* disable unsolicited responses */ - azx_writel(chip, GCTL, azx_readl(chip, GCTL) & ~ICH6_GCTL_UNSOL); + azx_writel(chip, GCTL, azx_readl(chip, GCTL) & ~AZX_GCTL_UNSOL); return -1; } @@ -1326,7 +1242,7 @@ static int azx_single_wait_for_response(struct azx *chip, unsigned int addr) while (timeout--) { /* check IRV busy bit */ - if (azx_readw(chip, IRS) & ICH6_IRS_VALID) { + if (azx_readw(chip, IRS) & AZX_IRS_VALID) { /* reuse rirb.res as the response return value */ chip->rirb.res[addr] = azx_readl(chip, IR); return 0; @@ -1350,13 +1266,13 @@ static int azx_single_send_cmd(struct hda_bus *bus, u32 val) bus->rirb_error = 0; while (timeout--) { /* check ICB busy bit */ - if (!((azx_readw(chip, IRS) & ICH6_IRS_BUSY))) { + if (!((azx_readw(chip, IRS) & AZX_IRS_BUSY))) { /* Clear IRV valid bit */ azx_writew(chip, IRS, azx_readw(chip, IRS) | - ICH6_IRS_VALID); + AZX_IRS_VALID); azx_writel(chip, IC, val); azx_writew(chip, IRS, azx_readw(chip, IRS) | - ICH6_IRS_BUSY); + AZX_IRS_BUSY); return azx_single_wait_for_response(chip, addr); } udelay(1); @@ -1585,10 +1501,10 @@ void azx_enter_link_reset(struct azx *chip) unsigned long timeout; /* reset controller */ - azx_writel(chip, GCTL, azx_readl(chip, GCTL) & ~ICH6_GCTL_RESET); + azx_writel(chip, GCTL, azx_readl(chip, GCTL) & ~AZX_GCTL_RESET); timeout = jiffies + msecs_to_jiffies(100); - while ((azx_readb(chip, GCTL) & ICH6_GCTL_RESET) && + while ((azx_readb(chip, GCTL) & AZX_GCTL_RESET) && time_before(jiffies, timeout)) usleep_range(500, 1000); } @@ -1599,7 +1515,7 @@ static void azx_exit_link_reset(struct azx *chip) { unsigned long timeout; - azx_writeb(chip, GCTL, azx_readb(chip, GCTL) | ICH6_GCTL_RESET); + azx_writeb(chip, GCTL, azx_readb(chip, GCTL) | AZX_GCTL_RESET); timeout = jiffies + msecs_to_jiffies(100); while (!azx_readb(chip, GCTL) && @@ -1640,7 +1556,7 @@ static int azx_reset(struct azx *chip, bool full_reset) /* Accept unsolicited responses */ if (!chip->single_cmd) azx_writel(chip, GCTL, azx_readl(chip, GCTL) | - ICH6_GCTL_UNSOL); + AZX_GCTL_UNSOL); /* detect codecs */ if (!chip->codec_mask) { @@ -1657,7 +1573,7 @@ static void azx_int_enable(struct azx *chip) { /* enable controller CIE and GIE */ azx_writel(chip, INTCTL, azx_readl(chip, INTCTL) | - ICH6_INT_CTRL_EN | ICH6_INT_GLOBAL_EN); + AZX_INT_CTRL_EN | AZX_INT_GLOBAL_EN); } /* disable interrupts */ @@ -1678,7 +1594,7 @@ static void azx_int_disable(struct azx *chip) /* disable controller CIE and GIE */ azx_writel(chip, INTCTL, azx_readl(chip, INTCTL) & - ~(ICH6_INT_CTRL_EN | ICH6_INT_GLOBAL_EN)); + ~(AZX_INT_CTRL_EN | AZX_INT_GLOBAL_EN)); } /* clear interrupts */ @@ -1699,7 +1615,7 @@ static void azx_int_clear(struct azx *chip) azx_writeb(chip, RIRBSTS, RIRB_INT_MASK); /* clear int status */ - azx_writel(chip, INTSTS, ICH6_INT_CTRL_EN | ICH6_INT_ALL_STREAM); + azx_writel(chip, INTSTS, AZX_INT_CTRL_EN | AZX_INT_ALL_STREAM); } /* @@ -2031,5 +1947,30 @@ int azx_init_stream(struct azx *chip) } EXPORT_SYMBOL_GPL(azx_init_stream); +/* + * reboot notifier for hang-up problem at power-down + */ +static int azx_halt(struct notifier_block *nb, unsigned long event, void *buf) +{ + struct azx *chip = container_of(nb, struct azx, reboot_notifier); + snd_hda_bus_reboot_notify(chip->bus); + azx_stop_chip(chip); + return NOTIFY_OK; +} + +void azx_notifier_register(struct azx *chip) +{ + chip->reboot_notifier.notifier_call = azx_halt; + register_reboot_notifier(&chip->reboot_notifier); +} +EXPORT_SYMBOL_GPL(azx_notifier_register); + +void azx_notifier_unregister(struct azx *chip) +{ + if (chip->reboot_notifier.notifier_call) + unregister_reboot_notifier(&chip->reboot_notifier); +} +EXPORT_SYMBOL_GPL(azx_notifier_unregister); + MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Common HDA driver funcitons"); diff --git a/sound/pci/hda/hda_controller.h b/sound/pci/hda/hda_controller.h index baf0e77330af..c90d10fd4d8f 100644 --- a/sound/pci/hda/hda_controller.h +++ b/sound/pci/hda/hda_controller.h @@ -25,9 +25,9 @@ static inline struct azx_dev *get_azx_dev(struct snd_pcm_substream *substream) { return substream->runtime->private_data; } -unsigned int azx_get_position(struct azx *chip, - struct azx_dev *azx_dev, - bool with_check); +unsigned int azx_get_position(struct azx *chip, struct azx_dev *azx_dev); +unsigned int azx_get_pos_lpib(struct azx *chip, struct azx_dev *azx_dev); +unsigned int azx_get_pos_posbuf(struct azx *chip, struct azx_dev *azx_dev); /* Stream control. */ void azx_stream_stop(struct azx *chip, struct azx_dev *azx_dev); @@ -50,4 +50,7 @@ int azx_codec_configure(struct azx *chip); int azx_mixer_create(struct azx *chip); int azx_init_stream(struct azx *chip); +void azx_notifier_register(struct azx *chip); +void azx_notifier_unregister(struct azx *chip); + #endif /* __SOUND_HDA_CONTROLLER_H */ diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index 46690a7f48f6..e1cd34d9011d 100644 --- a/sound/pci/hda/hda_eld.c +++ b/sound/pci/hda/hda_eld.c @@ -167,7 +167,8 @@ static unsigned int hdmi_get_eld_data(struct hda_codec *codec, hda_nid_t nid, (buf[byte] >> (lowbit)) & ((1 << (bits)) - 1); \ }) -static void hdmi_update_short_audio_desc(struct cea_sad *a, +static void hdmi_update_short_audio_desc(struct hda_codec *codec, + struct cea_sad *a, const unsigned char *buf) { int i; @@ -188,8 +189,7 @@ static void hdmi_update_short_audio_desc(struct cea_sad *a, a->format = GRAB_BITS(buf, 0, 3, 4); switch (a->format) { case AUDIO_CODING_TYPE_REF_STREAM_HEADER: - snd_printd(KERN_INFO - "HDMI: audio coding type 0 not expected\n"); + codec_info(codec, "HDMI: audio coding type 0 not expected\n"); break; case AUDIO_CODING_TYPE_LPCM: @@ -233,9 +233,9 @@ static void hdmi_update_short_audio_desc(struct cea_sad *a, a->format = GRAB_BITS(buf, 2, 3, 5); if (a->format == AUDIO_CODING_XTYPE_HE_REF_CT || a->format >= AUDIO_CODING_XTYPE_FIRST_RESERVED) { - snd_printd(KERN_INFO - "HDMI: audio coding xtype %d not expected\n", - a->format); + codec_info(codec, + "HDMI: audio coding xtype %d not expected\n", + a->format); a->format = 0; } else a->format += AUDIO_CODING_TYPE_HE_AAC - @@ -247,7 +247,7 @@ static void hdmi_update_short_audio_desc(struct cea_sad *a, /* * Be careful, ELD buf could be totally rubbish! */ -int snd_hdmi_parse_eld(struct parsed_hdmi_eld *e, +int snd_hdmi_parse_eld(struct hda_codec *codec, struct parsed_hdmi_eld *e, const unsigned char *buf, int size) { int mnl; @@ -256,8 +256,7 @@ int snd_hdmi_parse_eld(struct parsed_hdmi_eld *e, e->eld_ver = GRAB_BITS(buf, 0, 3, 5); if (e->eld_ver != ELD_VER_CEA_861D && e->eld_ver != ELD_VER_PARTIAL) { - snd_printd(KERN_INFO "HDMI: Unknown ELD version %d\n", - e->eld_ver); + codec_info(codec, "HDMI: Unknown ELD version %d\n", e->eld_ver); goto out_fail; } @@ -280,20 +279,20 @@ int snd_hdmi_parse_eld(struct parsed_hdmi_eld *e, e->product_id = get_unaligned_le16(buf + 18); if (mnl > ELD_MAX_MNL) { - snd_printd(KERN_INFO "HDMI: MNL is reserved value %d\n", mnl); + codec_info(codec, "HDMI: MNL is reserved value %d\n", mnl); goto out_fail; } else if (ELD_FIXED_BYTES + mnl > size) { - snd_printd(KERN_INFO "HDMI: out of range MNL %d\n", mnl); + codec_info(codec, "HDMI: out of range MNL %d\n", mnl); goto out_fail; } else strlcpy(e->monitor_name, buf + ELD_FIXED_BYTES, mnl + 1); for (i = 0; i < e->sad_count; i++) { if (ELD_FIXED_BYTES + mnl + 3 * (i + 1) > size) { - snd_printd(KERN_INFO "HDMI: out of range SAD %d\n", i); + codec_info(codec, "HDMI: out of range SAD %d\n", i); goto out_fail; } - hdmi_update_short_audio_desc(e->sad + i, + hdmi_update_short_audio_desc(codec, e->sad + i, buf + ELD_FIXED_BYTES + mnl + 3 * i); } @@ -394,7 +393,8 @@ static void hdmi_print_pcm_rates(int pcm, char *buf, int buflen) #define SND_PRINT_RATES_ADVISED_BUFSIZE 80 -static void hdmi_show_short_audio_desc(struct cea_sad *a) +static void hdmi_show_short_audio_desc(struct hda_codec *codec, + struct cea_sad *a) { char buf[SND_PRINT_RATES_ADVISED_BUFSIZE]; char buf2[8 + SND_PRINT_BITS_ADVISED_BUFSIZE] = ", bits ="; @@ -412,12 +412,10 @@ static void hdmi_show_short_audio_desc(struct cea_sad *a) else buf2[0] = '\0'; - _snd_printd(SND_PR_VERBOSE, "HDMI: supports coding type %s:" - " channels = %d, rates =%s%s\n", - cea_audio_coding_type_names[a->format], - a->channels, - buf, - buf2); + codec_dbg(codec, + "HDMI: supports coding type %s: channels = %d, rates =%s%s\n", + cea_audio_coding_type_names[a->format], + a->channels, buf, buf2); } void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen) @@ -432,22 +430,22 @@ void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen) buf[j] = '\0'; /* necessary when j == 0 */ } -void snd_hdmi_show_eld(struct parsed_hdmi_eld *e) +void snd_hdmi_show_eld(struct hda_codec *codec, struct parsed_hdmi_eld *e) { int i; - _snd_printd(SND_PR_VERBOSE, "HDMI: detected monitor %s at connection type %s\n", + codec_dbg(codec, "HDMI: detected monitor %s at connection type %s\n", e->monitor_name, eld_connection_type_names[e->conn_type]); if (e->spk_alloc) { char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE]; snd_print_channel_allocation(e->spk_alloc, buf, sizeof(buf)); - _snd_printd(SND_PR_VERBOSE, "HDMI: available speakers:%s\n", buf); + codec_dbg(codec, "HDMI: available speakers:%s\n", buf); } for (i = 0; i < e->sad_count; i++) - hdmi_show_short_audio_desc(e->sad + i); + hdmi_show_short_audio_desc(codec, e->sad + i); } #ifdef CONFIG_PROC_FS diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index 589e47c5aeb3..b956449ddada 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -350,16 +350,16 @@ static void print_nid_path(struct hda_codec *codec, const char *pfx, struct nid_path *path) { char buf[40]; + char *pos = buf; int i; + *pos = 0; + for (i = 0; i < path->depth; i++) + pos += scnprintf(pos, sizeof(buf) - (pos - buf), "%s%02x", + pos != buf ? ":" : "", + path->path[i]); - buf[0] = 0; - for (i = 0; i < path->depth; i++) { - char tmp[4]; - sprintf(tmp, ":%02x", path->path[i]); - strlcat(buf, tmp, sizeof(buf)); - } - codec_dbg(codec, "%s path: depth=%d %s\n", pfx, path->depth, buf); + codec_dbg(codec, "%s path: depth=%d '%s'\n", pfx, path->depth, buf); } /* called recursively */ @@ -1700,9 +1700,11 @@ static int fill_and_eval_dacs(struct hda_codec *codec, #define DEBUG_BADNESS #ifdef DEBUG_BADNESS -#define debug_badness(fmt, args...) codec_dbg(codec, fmt, ##args) +#define debug_badness(fmt, ...) \ + codec_dbg(codec, fmt, ##__VA_ARGS__) #else -#define debug_badness(...) +#define debug_badness(fmt, ...) \ + do { if (0) codec_dbg(codec, fmt, ##__VA_ARGS__); } while (0) #endif #ifdef DEBUG_BADNESS @@ -3054,7 +3056,7 @@ static int parse_capture_source(struct hda_codec *codec, hda_nid_t pin, if (spec->hp_mic_pin == pin) spec->hp_mic_mux_idx = imux->num_items; spec->imux_pins[imux->num_items] = pin; - snd_hda_add_imux_item(imux, label, cfg_idx, NULL); + snd_hda_add_imux_item(codec, imux, label, cfg_idx, NULL); imux_added = true; if (spec->dyn_adc_switch) spec->dyn_adc_idx[imux_idx] = c; diff --git a/sound/pci/hda/hda_i915.c b/sound/pci/hda/hda_i915.c index 8b4940ba33d6..d4d0375ac181 100644 --- a/sound/pci/hda/hda_i915.c +++ b/sound/pci/hda/hda_i915.c @@ -28,8 +28,8 @@ * Clock) to 24MHz BCLK: BCLK = CDCLK * M / N * The values will be lost when the display power well is disabled. */ -#define ICH6_REG_EM4 0x100c -#define ICH6_REG_EM5 0x1010 +#define AZX_REG_EM4 0x100c +#define AZX_REG_EM5 0x1010 static int (*get_power)(void); static int (*put_power)(void); diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 83cd19017cf3..aa302fb03fc5 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -44,7 +44,6 @@ #include <linux/slab.h> #include <linux/pci.h> #include <linux/mutex.h> -#include <linux/reboot.h> #include <linux/io.h> #include <linux/pm_runtime.h> #include <linux/clocksource.h> @@ -66,6 +65,52 @@ #include "hda_priv.h" #include "hda_i915.h" +/* position fix mode */ +enum { + POS_FIX_AUTO, + POS_FIX_LPIB, + POS_FIX_POSBUF, + POS_FIX_VIACOMBO, + POS_FIX_COMBO, +}; + +/* Defines for ATI HD Audio support in SB450 south bridge */ +#define ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR 0x42 +#define ATI_SB450_HDAUDIO_ENABLE_SNOOP 0x02 + +/* Defines for Nvidia HDA support */ +#define NVIDIA_HDA_TRANSREG_ADDR 0x4e +#define NVIDIA_HDA_ENABLE_COHBITS 0x0f +#define NVIDIA_HDA_ISTRM_COH 0x4d +#define NVIDIA_HDA_OSTRM_COH 0x4c +#define NVIDIA_HDA_ENABLE_COHBIT 0x01 + +/* Defines for Intel SCH HDA snoop control */ +#define INTEL_SCH_HDA_DEVC 0x78 +#define INTEL_SCH_HDA_DEVC_NOSNOOP (0x1<<11) + +/* Define IN stream 0 FIFO size offset in VIA controller */ +#define VIA_IN_STREAM0_FIFO_SIZE_OFFSET 0x90 +/* Define VIA HD Audio Device ID*/ +#define VIA_HDAC_DEVICE_ID 0x3288 + +/* max number of SDs */ +/* ICH, ATI and VIA have 4 playback and 4 capture */ +#define ICH6_NUM_CAPTURE 4 +#define ICH6_NUM_PLAYBACK 4 + +/* ULI has 6 playback and 5 capture */ +#define ULI_NUM_CAPTURE 5 +#define ULI_NUM_PLAYBACK 6 + +/* ATI HDMI may have up to 8 playbacks and 0 capture */ +#define ATIHDMI_NUM_CAPTURE 0 +#define ATIHDMI_NUM_PLAYBACK 8 + +/* TERA has 4 playback and 3 capture */ +#define TERA_NUM_CAPTURE 3 +#define TERA_NUM_PLAYBACK 4 + static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; @@ -220,6 +265,7 @@ enum { AZX_DRIVER_TERA, AZX_DRIVER_CTX, AZX_DRIVER_CTHDA, + AZX_DRIVER_CMEDIA, AZX_DRIVER_GENERIC, AZX_NUM_DRIVERS, /* keep this as last entry */ }; @@ -285,13 +331,34 @@ static char *driver_short_names[] = { [AZX_DRIVER_TERA] = "HDA Teradici", [AZX_DRIVER_CTX] = "HDA Creative", [AZX_DRIVER_CTHDA] = "HDA Creative", + [AZX_DRIVER_CMEDIA] = "HDA C-Media", [AZX_DRIVER_GENERIC] = "HD-Audio Generic", }; struct hda_intel { struct azx chip; -}; + /* for pending irqs */ + struct work_struct irq_pending_work; + + /* sync probing */ + struct completion probe_wait; + struct work_struct probe_work; + + /* card list (for power_save trigger) */ + struct list_head list; + + /* extra flags */ + unsigned int irq_pending_warned:1; + + /* VGA-switcheroo setup */ + unsigned int use_vga_switcheroo:1; + unsigned int vga_switcheroo_registered:1; + unsigned int init_failed:1; /* delayed init failed */ + + /* secondary power domain for hdmi audio under vga device */ + struct dev_pm_domain hdmi_pm_domain; +}; #ifdef CONFIG_X86 static void __mark_pages_wc(struct azx *chip, struct snd_dma_buffer *dmab, bool on) @@ -373,7 +440,7 @@ static void azx_init_pci(struct azx *chip) */ if (!(chip->driver_caps & AZX_DCAPS_NO_TCSEL)) { dev_dbg(chip->card->dev, "Clearing TCSEL\n"); - update_pci_byte(chip->pci, ICH6_PCIREG_TCSEL, 0x07, 0); + update_pci_byte(chip->pci, AZX_PCIREG_TCSEL, 0x07, 0); } /* For ATI SB450/600/700/800/900 and AMD Hudson azalia HD audio, @@ -421,11 +488,44 @@ static void azx_init_pci(struct azx *chip) } } +/* calculate runtime delay from LPIB */ +static int azx_get_delay_from_lpib(struct azx *chip, struct azx_dev *azx_dev, + unsigned int pos) +{ + struct snd_pcm_substream *substream = azx_dev->substream; + int stream = substream->stream; + unsigned int lpib_pos = azx_get_pos_lpib(chip, azx_dev); + int delay; + + if (stream == SNDRV_PCM_STREAM_PLAYBACK) + delay = pos - lpib_pos; + else + delay = lpib_pos - pos; + if (delay < 0) { + if (delay >= azx_dev->delay_negative_threshold) + delay = 0; + else + delay += azx_dev->bufsize; + } + + if (delay >= azx_dev->period_bytes) { + dev_info(chip->card->dev, + "Unstable LPIB (%d >= %d); disabling LPIB delay counting\n", + delay, azx_dev->period_bytes); + delay = 0; + chip->driver_caps &= ~AZX_DCAPS_COUNT_LPIB_DELAY; + chip->get_delay[stream] = NULL; + } + + return bytes_to_frames(substream->runtime, delay); +} + static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev); /* called from IRQ */ static int azx_position_check(struct azx *chip, struct azx_dev *azx_dev) { + struct hda_intel *hda = container_of(chip, struct hda_intel, chip); int ok; ok = azx_position_ok(chip, azx_dev); @@ -435,7 +535,7 @@ static int azx_position_check(struct azx *chip, struct azx_dev *azx_dev) } else if (ok == 0 && chip->bus && chip->bus->workq) { /* bogus IRQ, process it later */ azx_dev->irq_pending = 1; - queue_work(chip->bus->workq, &chip->irq_pending_work); + queue_work(chip->bus->workq, &hda->irq_pending_work); } return 0; } @@ -451,6 +551,8 @@ static int azx_position_check(struct azx *chip, struct azx_dev *azx_dev) */ static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev) { + struct snd_pcm_substream *substream = azx_dev->substream; + int stream = substream->stream; u32 wallclk; unsigned int pos; @@ -458,7 +560,25 @@ static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev) if (wallclk < (azx_dev->period_wallclk * 2) / 3) return -1; /* bogus (too early) interrupt */ - pos = azx_get_position(chip, azx_dev, true); + if (chip->get_position[stream]) + pos = chip->get_position[stream](chip, azx_dev); + else { /* use the position buffer as default */ + pos = azx_get_pos_posbuf(chip, azx_dev); + if (!pos || pos == (u32)-1) { + dev_info(chip->card->dev, + "Invalid position buffer, using LPIB read method instead.\n"); + chip->get_position[stream] = azx_get_pos_lpib; + pos = azx_get_pos_lpib(chip, azx_dev); + chip->get_delay[stream] = NULL; + } else { + chip->get_position[stream] = azx_get_pos_posbuf; + if (chip->driver_caps & AZX_DCAPS_COUNT_LPIB_DELAY) + chip->get_delay[stream] = azx_get_delay_from_lpib; + } + } + + if (pos >= azx_dev->bufsize) + pos = 0; if (WARN_ONCE(!azx_dev->period_bytes, "hda-intel: zero azx_dev->period_bytes")) @@ -476,14 +596,15 @@ static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev) */ static void azx_irq_pending_work(struct work_struct *work) { - struct azx *chip = container_of(work, struct azx, irq_pending_work); + struct hda_intel *hda = container_of(work, struct hda_intel, irq_pending_work); + struct azx *chip = &hda->chip; int i, pending, ok; - if (!chip->irq_pending_warned) { + if (!hda->irq_pending_warned) { dev_info(chip->card->dev, "IRQ timing workaround is activated for card #%d. Suggest a bigger bdl_pos_adj.\n", chip->card->number); - chip->irq_pending_warned = 1; + hda->irq_pending_warned = 1; } for (;;) { @@ -541,27 +662,86 @@ static int azx_acquire_irq(struct azx *chip, int do_disconnect) return 0; } +/* get the current DMA position with correction on VIA chips */ +static unsigned int azx_via_get_position(struct azx *chip, + struct azx_dev *azx_dev) +{ + unsigned int link_pos, mini_pos, bound_pos; + unsigned int mod_link_pos, mod_dma_pos, mod_mini_pos; + unsigned int fifo_size; + + link_pos = azx_sd_readl(chip, azx_dev, SD_LPIB); + if (azx_dev->substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + /* Playback, no problem using link position */ + return link_pos; + } + + /* Capture */ + /* For new chipset, + * use mod to get the DMA position just like old chipset + */ + mod_dma_pos = le32_to_cpu(*azx_dev->posbuf); + mod_dma_pos %= azx_dev->period_bytes; + + /* azx_dev->fifo_size can't get FIFO size of in stream. + * Get from base address + offset. + */ + fifo_size = readw(chip->remap_addr + VIA_IN_STREAM0_FIFO_SIZE_OFFSET); + + if (azx_dev->insufficient) { + /* Link position never gather than FIFO size */ + if (link_pos <= fifo_size) + return 0; + + azx_dev->insufficient = 0; + } + + if (link_pos <= fifo_size) + mini_pos = azx_dev->bufsize + link_pos - fifo_size; + else + mini_pos = link_pos - fifo_size; + + /* Find nearest previous boudary */ + mod_mini_pos = mini_pos % azx_dev->period_bytes; + mod_link_pos = link_pos % azx_dev->period_bytes; + if (mod_link_pos >= fifo_size) + bound_pos = link_pos - mod_link_pos; + else if (mod_dma_pos >= mod_mini_pos) + bound_pos = mini_pos - mod_mini_pos; + else { + bound_pos = mini_pos - mod_mini_pos + azx_dev->period_bytes; + if (bound_pos >= azx_dev->bufsize) + bound_pos = 0; + } + + /* Calculate real DMA position we want */ + return bound_pos + mod_dma_pos; +} + #ifdef CONFIG_PM static DEFINE_MUTEX(card_list_lock); static LIST_HEAD(card_list); static void azx_add_card_list(struct azx *chip) { + struct hda_intel *hda = container_of(chip, struct hda_intel, chip); mutex_lock(&card_list_lock); - list_add(&chip->list, &card_list); + list_add(&hda->list, &card_list); mutex_unlock(&card_list_lock); } static void azx_del_card_list(struct azx *chip) { + struct hda_intel *hda = container_of(chip, struct hda_intel, chip); mutex_lock(&card_list_lock); - list_del_init(&chip->list); + list_del_init(&hda->list); mutex_unlock(&card_list_lock); } /* trigger power-save check at writing parameter */ static int param_set_xint(const char *val, const struct kernel_param *kp) { + struct hda_intel *hda; struct azx *chip; struct hda_codec *c; int prev = power_save; @@ -571,7 +751,8 @@ static int param_set_xint(const char *val, const struct kernel_param *kp) return ret; mutex_lock(&card_list_lock); - list_for_each_entry(chip, &card_list, list) { + list_for_each_entry(hda, &card_list, list) { + chip = &hda->chip; if (!chip->bus || chip->disabled) continue; list_for_each_entry(c, &chip->bus->codec_list, list) @@ -593,10 +774,16 @@ static int azx_suspend(struct device *dev) { struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); - struct azx *chip = card->private_data; + struct azx *chip; + struct hda_intel *hda; struct azx_pcm *p; - if (chip->disabled || chip->init_failed) + if (!card) + return 0; + + chip = card->private_data; + hda = container_of(chip, struct hda_intel, chip); + if (chip->disabled || hda->init_failed) return 0; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); @@ -626,9 +813,15 @@ static int azx_resume(struct device *dev) { struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); - struct azx *chip = card->private_data; + struct azx *chip; + struct hda_intel *hda; - if (chip->disabled || chip->init_failed) + if (!card) + return 0; + + chip = card->private_data; + hda = container_of(chip, struct hda_intel, chip); + if (chip->disabled || hda->init_failed) return 0; if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { @@ -663,9 +856,15 @@ static int azx_resume(struct device *dev) static int azx_runtime_suspend(struct device *dev) { struct snd_card *card = dev_get_drvdata(dev); - struct azx *chip = card->private_data; + struct azx *chip; + struct hda_intel *hda; + + if (!card) + return 0; - if (chip->disabled || chip->init_failed) + chip = card->private_data; + hda = container_of(chip, struct hda_intel, chip); + if (chip->disabled || hda->init_failed) return 0; if (!(chip->driver_caps & AZX_DCAPS_PM_RUNTIME)) @@ -687,12 +886,18 @@ static int azx_runtime_suspend(struct device *dev) static int azx_runtime_resume(struct device *dev) { struct snd_card *card = dev_get_drvdata(dev); - struct azx *chip = card->private_data; + struct azx *chip; + struct hda_intel *hda; struct hda_bus *bus; struct hda_codec *codec; int status; - if (chip->disabled || chip->init_failed) + if (!card) + return 0; + + chip = card->private_data; + hda = container_of(chip, struct hda_intel, chip); + if (chip->disabled || hda->init_failed) return 0; if (!(chip->driver_caps & AZX_DCAPS_PM_RUNTIME)) @@ -727,9 +932,15 @@ static int azx_runtime_resume(struct device *dev) static int azx_runtime_idle(struct device *dev) { struct snd_card *card = dev_get_drvdata(dev); - struct azx *chip = card->private_data; + struct azx *chip; + struct hda_intel *hda; + + if (!card) + return 0; - if (chip->disabled || chip->init_failed) + chip = card->private_data; + hda = container_of(chip, struct hda_intel, chip); + if (chip->disabled || hda->init_failed) return 0; if (!power_save_controller || @@ -753,29 +964,6 @@ static const struct dev_pm_ops azx_pm = { #endif /* CONFIG_PM */ -/* - * reboot notifier for hang-up problem at power-down - */ -static int azx_halt(struct notifier_block *nb, unsigned long event, void *buf) -{ - struct azx *chip = container_of(nb, struct azx, reboot_notifier); - snd_hda_bus_reboot_notify(chip->bus); - azx_stop_chip(chip); - return NOTIFY_OK; -} - -static void azx_notifier_register(struct azx *chip) -{ - chip->reboot_notifier.notifier_call = azx_halt; - register_reboot_notifier(&chip->reboot_notifier); -} - -static void azx_notifier_unregister(struct azx *chip) -{ - if (chip->reboot_notifier.notifier_call) - unregister_reboot_notifier(&chip->reboot_notifier); -} - static int azx_probe_continue(struct azx *chip); #ifdef SUPPORT_VGA_SWITCHEROO @@ -786,10 +974,11 @@ static void azx_vs_set_state(struct pci_dev *pci, { struct snd_card *card = pci_get_drvdata(pci); struct azx *chip = card->private_data; + struct hda_intel *hda = container_of(chip, struct hda_intel, chip); bool disabled; - wait_for_completion(&chip->probe_wait); - if (chip->init_failed) + wait_for_completion(&hda->probe_wait); + if (hda->init_failed) return; disabled = (state == VGA_SWITCHEROO_OFF); @@ -803,7 +992,7 @@ static void azx_vs_set_state(struct pci_dev *pci, "Start delayed initialization\n"); if (azx_probe_continue(chip) < 0) { dev_err(chip->card->dev, "initialization error\n"); - chip->init_failed = true; + hda->init_failed = true; } } } else { @@ -833,9 +1022,10 @@ static bool azx_vs_can_switch(struct pci_dev *pci) { struct snd_card *card = pci_get_drvdata(pci); struct azx *chip = card->private_data; + struct hda_intel *hda = container_of(chip, struct hda_intel, chip); - wait_for_completion(&chip->probe_wait); - if (chip->init_failed) + wait_for_completion(&hda->probe_wait); + if (hda->init_failed) return false; if (chip->disabled || !chip->bus) return true; @@ -847,11 +1037,12 @@ static bool azx_vs_can_switch(struct pci_dev *pci) static void init_vga_switcheroo(struct azx *chip) { + struct hda_intel *hda = container_of(chip, struct hda_intel, chip); struct pci_dev *p = get_bound_vga(chip->pci); if (p) { dev_info(chip->card->dev, "Handle VGA-switcheroo audio client\n"); - chip->use_vga_switcheroo = 1; + hda->use_vga_switcheroo = 1; pci_dev_put(p); } } @@ -863,9 +1054,10 @@ static const struct vga_switcheroo_client_ops azx_vs_ops = { static int register_vga_switcheroo(struct azx *chip) { + struct hda_intel *hda = container_of(chip, struct hda_intel, chip); int err; - if (!chip->use_vga_switcheroo) + if (!hda->use_vga_switcheroo) return 0; /* FIXME: currently only handling DIS controller * is there any machine with two switchable HDMI audio controllers? @@ -875,11 +1067,11 @@ static int register_vga_switcheroo(struct azx *chip) chip->bus != NULL); if (err < 0) return err; - chip->vga_switcheroo_registered = 1; + hda->vga_switcheroo_registered = 1; /* register as an optimus hdmi audio power domain */ vga_switcheroo_init_domain_pm_optimus_hdmi_audio(chip->card->dev, - &chip->hdmi_pm_domain); + &hda->hdmi_pm_domain); return 0; } #else @@ -895,7 +1087,6 @@ static int azx_free(struct azx *chip) { struct pci_dev *pci = chip->pci; struct hda_intel *hda = container_of(chip, struct hda_intel, chip); - int i; if ((chip->driver_caps & AZX_DCAPS_PM_RUNTIME) @@ -906,13 +1097,13 @@ static int azx_free(struct azx *chip) azx_notifier_unregister(chip); - chip->init_failed = 1; /* to be sure */ - complete_all(&chip->probe_wait); + hda->init_failed = 1; /* to be sure */ + complete_all(&hda->probe_wait); - if (use_vga_switcheroo(chip)) { + if (use_vga_switcheroo(hda)) { if (chip->disabled && chip->bus) snd_hda_unlock_devices(chip->bus); - if (chip->vga_switcheroo_registered) + if (hda->vga_switcheroo_registered) vga_switcheroo_unregister_client(chip->pci); } @@ -1048,6 +1239,30 @@ static int check_position_fix(struct azx *chip, int fix) return POS_FIX_AUTO; } +static void assign_position_fix(struct azx *chip, int fix) +{ + static azx_get_pos_callback_t callbacks[] = { + [POS_FIX_AUTO] = NULL, + [POS_FIX_LPIB] = azx_get_pos_lpib, + [POS_FIX_POSBUF] = azx_get_pos_posbuf, + [POS_FIX_VIACOMBO] = azx_via_get_position, + [POS_FIX_COMBO] = azx_get_pos_lpib, + }; + + chip->get_position[0] = chip->get_position[1] = callbacks[fix]; + + /* combo mode uses LPIB only for playback */ + if (fix == POS_FIX_COMBO) + chip->get_position[1] = NULL; + + if (fix == POS_FIX_POSBUF && + (chip->driver_caps & AZX_DCAPS_COUNT_LPIB_DELAY)) { + chip->get_delay[0] = chip->get_delay[1] = + azx_get_delay_from_lpib; + } + +} + /* * black-lists for probe_mask */ @@ -1160,6 +1375,7 @@ static void azx_check_snoop_available(struct azx *chip) snoop = false; break; case AZX_DRIVER_CTHDA: + case AZX_DRIVER_CMEDIA: snoop = false; break; } @@ -1173,7 +1389,8 @@ static void azx_check_snoop_available(struct azx *chip) static void azx_probe_work(struct work_struct *work) { - azx_probe_continue(container_of(work, struct azx, probe_work)); + struct hda_intel *hda = container_of(work, struct hda_intel, probe_work); + azx_probe_continue(&hda->chip); } /* @@ -1216,19 +1433,13 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci, check_msi(chip); chip->dev_index = dev; chip->jackpoll_ms = jackpoll_ms; - INIT_WORK(&chip->irq_pending_work, azx_irq_pending_work); INIT_LIST_HEAD(&chip->pcm_list); - INIT_LIST_HEAD(&chip->list); + INIT_WORK(&hda->irq_pending_work, azx_irq_pending_work); + INIT_LIST_HEAD(&hda->list); init_vga_switcheroo(chip); - init_completion(&chip->probe_wait); - - chip->position_fix[0] = chip->position_fix[1] = - check_position_fix(chip, position_fix[dev]); - /* combo mode uses LPIB for playback */ - if (chip->position_fix[0] == POS_FIX_COMBO) { - chip->position_fix[0] = POS_FIX_LPIB; - chip->position_fix[1] = POS_FIX_AUTO; - } + init_completion(&hda->probe_wait); + + assign_position_fix(chip, check_position_fix(chip, position_fix[dev])); check_probe_mask(chip, dev); @@ -1257,7 +1468,7 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci, } /* continue probing in work context as may trigger request module */ - INIT_WORK(&chip->probe_work, azx_probe_work); + INIT_WORK(&hda->probe_work, azx_probe_work); *rchip = chip; @@ -1315,7 +1526,7 @@ static int azx_first_init(struct azx *chip) NULL); if (p_smbus) { if (p_smbus->revision < 0x30) - gcap &= ~ICH6_GCAP_64OK; + gcap &= ~AZX_GCAP_64OK; pci_dev_put(p_smbus); } } @@ -1323,7 +1534,7 @@ static int azx_first_init(struct azx *chip) /* disable 64bit DMA address on some devices */ if (chip->driver_caps & AZX_DCAPS_NO_64BIT) { dev_dbg(card->dev, "Disabling 64bit DMA\n"); - gcap &= ~ICH6_GCAP_64OK; + gcap &= ~AZX_GCAP_64OK; } /* disable buffer size rounding to 128-byte multiples if supported */ @@ -1339,7 +1550,7 @@ static int azx_first_init(struct azx *chip) } /* allow 64bit DMA address if supported by H/W */ - if ((gcap & ICH6_GCAP_64OK) && !pci_set_dma_mask(pci, DMA_BIT_MASK(64))) + if ((gcap & AZX_GCAP_64OK) && !pci_set_dma_mask(pci, DMA_BIT_MASK(64))) pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(64)); else { pci_set_dma_mask(pci, DMA_BIT_MASK(32)); @@ -1583,6 +1794,7 @@ static int azx_probe(struct pci_dev *pci, { static int dev; struct snd_card *card; + struct hda_intel *hda; struct azx *chip; bool schedule_probe; int err; @@ -1606,6 +1818,7 @@ static int azx_probe(struct pci_dev *pci, if (err < 0) goto out_free; card->private_data = chip; + hda = container_of(chip, struct hda_intel, chip); pci_set_drvdata(pci, card); @@ -1642,11 +1855,11 @@ static int azx_probe(struct pci_dev *pci, #endif if (schedule_probe) - schedule_work(&chip->probe_work); + schedule_work(&hda->probe_work); dev++; if (chip->disabled) - complete_all(&chip->probe_wait); + complete_all(&hda->probe_wait); return 0; out_free: @@ -1662,6 +1875,7 @@ static unsigned int azx_max_codecs[AZX_NUM_DRIVERS] = { static int azx_probe_continue(struct azx *chip) { + struct hda_intel *hda = container_of(chip, struct hda_intel, chip); struct pci_dev *pci = chip->pci; int dev = chip->dev_index; int err; @@ -1735,13 +1949,13 @@ static int azx_probe_continue(struct azx *chip) power_down_all_codecs(chip); azx_notifier_register(chip); azx_add_card_list(chip); - if ((chip->driver_caps & AZX_DCAPS_PM_RUNTIME) || chip->use_vga_switcheroo) + if ((chip->driver_caps & AZX_DCAPS_PM_RUNTIME) || hda->use_vga_switcheroo) pm_runtime_put_noidle(&pci->dev); out_free: if (err < 0) - chip->init_failed = 1; - complete_all(&chip->probe_wait); + hda->init_failed = 1; + complete_all(&hda->probe_wait); return err; } @@ -1806,6 +2020,9 @@ static const struct pci_device_id azx_ids[] = { /* BayTrail */ { PCI_DEVICE(0x8086, 0x0f04), .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH_NOPM }, + /* Braswell */ + { PCI_DEVICE(0x8086, 0x2284), + .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, /* ICH */ { PCI_DEVICE(0x8086, 0x2668), .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC | @@ -1940,6 +2157,10 @@ static const struct pci_device_id azx_ids[] = { .driver_data = AZX_DRIVER_CTX | AZX_DCAPS_CTX_WORKAROUND | AZX_DCAPS_RIRB_PRE_DELAY | AZX_DCAPS_POSFIX_LPIB }, #endif + /* CM8888 */ + { PCI_DEVICE(0x13f6, 0x5011), + .driver_data = AZX_DRIVER_CMEDIA | + AZX_DCAPS_NO_MSI | AZX_DCAPS_POSFIX_LPIB }, /* Vortex86MX */ { PCI_DEVICE(0x17f3, 0x3010), .driver_data = AZX_DRIVER_GENERIC }, /* VMware HDAudio */ diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 4e2d4863daa1..364bb413e02a 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -268,7 +268,8 @@ int snd_hda_input_mux_put(struct hda_codec *codec, const struct hda_input_mux *imux, struct snd_ctl_elem_value *ucontrol, hda_nid_t nid, unsigned int *cur_val); -int snd_hda_add_imux_item(struct hda_input_mux *imux, const char *label, +int snd_hda_add_imux_item(struct hda_codec *codec, + struct hda_input_mux *imux, const char *label, int index, int *type_index_ret); /* @@ -437,6 +438,8 @@ struct snd_hda_pin_quirk { #endif +#define HDA_FIXUP_ID_NOT_SET -1 +#define HDA_FIXUP_ID_NO_FIXUP -2 /* fixup types */ enum { @@ -773,9 +776,9 @@ struct hdmi_eld { int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid); int snd_hdmi_get_eld(struct hda_codec *codec, hda_nid_t nid, unsigned char *buf, int *eld_size); -int snd_hdmi_parse_eld(struct parsed_hdmi_eld *e, +int snd_hdmi_parse_eld(struct hda_codec *codec, struct parsed_hdmi_eld *e, const unsigned char *buf, int size); -void snd_hdmi_show_eld(struct parsed_hdmi_eld *e); +void snd_hdmi_show_eld(struct hda_codec *codec, struct parsed_hdmi_eld *e); void snd_hdmi_eld_update_pcm_info(struct parsed_hdmi_eld *e, struct hda_pcm_stream *hinfo); diff --git a/sound/pci/hda/hda_priv.h b/sound/pci/hda/hda_priv.h index e9d1a5762a55..949cd437eeb2 100644 --- a/sound/pci/hda/hda_priv.h +++ b/sound/pci/hda/hda_priv.h @@ -22,107 +22,87 @@ /* * registers */ -#define ICH6_REG_GCAP 0x00 -#define ICH6_GCAP_64OK (1 << 0) /* 64bit address support */ -#define ICH6_GCAP_NSDO (3 << 1) /* # of serial data out signals */ -#define ICH6_GCAP_BSS (31 << 3) /* # of bidirectional streams */ -#define ICH6_GCAP_ISS (15 << 8) /* # of input streams */ -#define ICH6_GCAP_OSS (15 << 12) /* # of output streams */ -#define ICH6_REG_VMIN 0x02 -#define ICH6_REG_VMAJ 0x03 -#define ICH6_REG_OUTPAY 0x04 -#define ICH6_REG_INPAY 0x06 -#define ICH6_REG_GCTL 0x08 -#define ICH6_GCTL_RESET (1 << 0) /* controller reset */ -#define ICH6_GCTL_FCNTRL (1 << 1) /* flush control */ -#define ICH6_GCTL_UNSOL (1 << 8) /* accept unsol. response enable */ -#define ICH6_REG_WAKEEN 0x0c -#define ICH6_REG_STATESTS 0x0e -#define ICH6_REG_GSTS 0x10 -#define ICH6_GSTS_FSTS (1 << 1) /* flush status */ -#define ICH6_REG_INTCTL 0x20 -#define ICH6_REG_INTSTS 0x24 -#define ICH6_REG_WALLCLK 0x30 /* 24Mhz source */ -#define ICH6_REG_OLD_SSYNC 0x34 /* SSYNC for old ICH */ -#define ICH6_REG_SSYNC 0x38 -#define ICH6_REG_CORBLBASE 0x40 -#define ICH6_REG_CORBUBASE 0x44 -#define ICH6_REG_CORBWP 0x48 -#define ICH6_REG_CORBRP 0x4a -#define ICH6_CORBRP_RST (1 << 15) /* read pointer reset */ -#define ICH6_REG_CORBCTL 0x4c -#define ICH6_CORBCTL_RUN (1 << 1) /* enable DMA */ -#define ICH6_CORBCTL_CMEIE (1 << 0) /* enable memory error irq */ -#define ICH6_REG_CORBSTS 0x4d -#define ICH6_CORBSTS_CMEI (1 << 0) /* memory error indication */ -#define ICH6_REG_CORBSIZE 0x4e - -#define ICH6_REG_RIRBLBASE 0x50 -#define ICH6_REG_RIRBUBASE 0x54 -#define ICH6_REG_RIRBWP 0x58 -#define ICH6_RIRBWP_RST (1 << 15) /* write pointer reset */ -#define ICH6_REG_RINTCNT 0x5a -#define ICH6_REG_RIRBCTL 0x5c -#define ICH6_RBCTL_IRQ_EN (1 << 0) /* enable IRQ */ -#define ICH6_RBCTL_DMA_EN (1 << 1) /* enable DMA */ -#define ICH6_RBCTL_OVERRUN_EN (1 << 2) /* enable overrun irq */ -#define ICH6_REG_RIRBSTS 0x5d -#define ICH6_RBSTS_IRQ (1 << 0) /* response irq */ -#define ICH6_RBSTS_OVERRUN (1 << 2) /* overrun irq */ -#define ICH6_REG_RIRBSIZE 0x5e - -#define ICH6_REG_IC 0x60 -#define ICH6_REG_IR 0x64 -#define ICH6_REG_IRS 0x68 -#define ICH6_IRS_VALID (1<<1) -#define ICH6_IRS_BUSY (1<<0) - -#define ICH6_REG_DPLBASE 0x70 -#define ICH6_REG_DPUBASE 0x74 -#define ICH6_DPLBASE_ENABLE 0x1 /* Enable position buffer */ +#define AZX_REG_GCAP 0x00 +#define AZX_GCAP_64OK (1 << 0) /* 64bit address support */ +#define AZX_GCAP_NSDO (3 << 1) /* # of serial data out signals */ +#define AZX_GCAP_BSS (31 << 3) /* # of bidirectional streams */ +#define AZX_GCAP_ISS (15 << 8) /* # of input streams */ +#define AZX_GCAP_OSS (15 << 12) /* # of output streams */ +#define AZX_REG_VMIN 0x02 +#define AZX_REG_VMAJ 0x03 +#define AZX_REG_OUTPAY 0x04 +#define AZX_REG_INPAY 0x06 +#define AZX_REG_GCTL 0x08 +#define AZX_GCTL_RESET (1 << 0) /* controller reset */ +#define AZX_GCTL_FCNTRL (1 << 1) /* flush control */ +#define AZX_GCTL_UNSOL (1 << 8) /* accept unsol. response enable */ +#define AZX_REG_WAKEEN 0x0c +#define AZX_REG_STATESTS 0x0e +#define AZX_REG_GSTS 0x10 +#define AZX_GSTS_FSTS (1 << 1) /* flush status */ +#define AZX_REG_INTCTL 0x20 +#define AZX_REG_INTSTS 0x24 +#define AZX_REG_WALLCLK 0x30 /* 24Mhz source */ +#define AZX_REG_OLD_SSYNC 0x34 /* SSYNC for old ICH */ +#define AZX_REG_SSYNC 0x38 +#define AZX_REG_CORBLBASE 0x40 +#define AZX_REG_CORBUBASE 0x44 +#define AZX_REG_CORBWP 0x48 +#define AZX_REG_CORBRP 0x4a +#define AZX_CORBRP_RST (1 << 15) /* read pointer reset */ +#define AZX_REG_CORBCTL 0x4c +#define AZX_CORBCTL_RUN (1 << 1) /* enable DMA */ +#define AZX_CORBCTL_CMEIE (1 << 0) /* enable memory error irq */ +#define AZX_REG_CORBSTS 0x4d +#define AZX_CORBSTS_CMEI (1 << 0) /* memory error indication */ +#define AZX_REG_CORBSIZE 0x4e + +#define AZX_REG_RIRBLBASE 0x50 +#define AZX_REG_RIRBUBASE 0x54 +#define AZX_REG_RIRBWP 0x58 +#define AZX_RIRBWP_RST (1 << 15) /* write pointer reset */ +#define AZX_REG_RINTCNT 0x5a +#define AZX_REG_RIRBCTL 0x5c +#define AZX_RBCTL_IRQ_EN (1 << 0) /* enable IRQ */ +#define AZX_RBCTL_DMA_EN (1 << 1) /* enable DMA */ +#define AZX_RBCTL_OVERRUN_EN (1 << 2) /* enable overrun irq */ +#define AZX_REG_RIRBSTS 0x5d +#define AZX_RBSTS_IRQ (1 << 0) /* response irq */ +#define AZX_RBSTS_OVERRUN (1 << 2) /* overrun irq */ +#define AZX_REG_RIRBSIZE 0x5e + +#define AZX_REG_IC 0x60 +#define AZX_REG_IR 0x64 +#define AZX_REG_IRS 0x68 +#define AZX_IRS_VALID (1<<1) +#define AZX_IRS_BUSY (1<<0) + +#define AZX_REG_DPLBASE 0x70 +#define AZX_REG_DPUBASE 0x74 +#define AZX_DPLBASE_ENABLE 0x1 /* Enable position buffer */ /* SD offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; /* stream register offsets from stream base */ -#define ICH6_REG_SD_CTL 0x00 -#define ICH6_REG_SD_STS 0x03 -#define ICH6_REG_SD_LPIB 0x04 -#define ICH6_REG_SD_CBL 0x08 -#define ICH6_REG_SD_LVI 0x0c -#define ICH6_REG_SD_FIFOW 0x0e -#define ICH6_REG_SD_FIFOSIZE 0x10 -#define ICH6_REG_SD_FORMAT 0x12 -#define ICH6_REG_SD_BDLPL 0x18 -#define ICH6_REG_SD_BDLPU 0x1c +#define AZX_REG_SD_CTL 0x00 +#define AZX_REG_SD_STS 0x03 +#define AZX_REG_SD_LPIB 0x04 +#define AZX_REG_SD_CBL 0x08 +#define AZX_REG_SD_LVI 0x0c +#define AZX_REG_SD_FIFOW 0x0e +#define AZX_REG_SD_FIFOSIZE 0x10 +#define AZX_REG_SD_FORMAT 0x12 +#define AZX_REG_SD_BDLPL 0x18 +#define AZX_REG_SD_BDLPU 0x1c /* PCI space */ -#define ICH6_PCIREG_TCSEL 0x44 +#define AZX_PCIREG_TCSEL 0x44 /* * other constants */ -/* max number of SDs */ -/* ICH, ATI and VIA have 4 playback and 4 capture */ -#define ICH6_NUM_CAPTURE 4 -#define ICH6_NUM_PLAYBACK 4 - -/* ULI has 6 playback and 5 capture */ -#define ULI_NUM_CAPTURE 5 -#define ULI_NUM_PLAYBACK 6 - -/* ATI HDMI may have up to 8 playbacks and 0 capture */ -#define ATIHDMI_NUM_CAPTURE 0 -#define ATIHDMI_NUM_PLAYBACK 8 - -/* TERA has 4 playback and 3 capture */ -#define TERA_NUM_CAPTURE 3 -#define TERA_NUM_PLAYBACK 4 - -/* this number is statically defined for simplicity */ -#define MAX_AZX_DEV 16 - /* max number of fragments - we may use more if allocating more pages for BDL */ #define BDL_SIZE 4096 #define AZX_MAX_BDL_ENTRIES (BDL_SIZE / 16) @@ -160,13 +140,13 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; #define SD_STS_FIFO_READY 0x20 /* FIFO ready */ /* INTCTL and INTSTS */ -#define ICH6_INT_ALL_STREAM 0xff /* all stream interrupts */ -#define ICH6_INT_CTRL_EN 0x40000000 /* controller interrupt enable bit */ -#define ICH6_INT_GLOBAL_EN 0x80000000 /* global interrupt enable bit */ +#define AZX_INT_ALL_STREAM 0xff /* all stream interrupts */ +#define AZX_INT_CTRL_EN 0x40000000 /* controller interrupt enable bit */ +#define AZX_INT_GLOBAL_EN 0x80000000 /* global interrupt enable bit */ /* below are so far hardcoded - should read registers in future */ -#define ICH6_MAX_CORB_ENTRIES 256 -#define ICH6_MAX_RIRB_ENTRIES 256 +#define AZX_MAX_CORB_ENTRIES 256 +#define AZX_MAX_RIRB_ENTRIES 256 /* driver quirks (capabilities) */ /* bits 0-7 are used for indicating driver type */ @@ -192,35 +172,6 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; #define AZX_DCAPS_I915_POWERWELL (1 << 27) /* HSW i915 powerwell support */ #define AZX_DCAPS_CORBRP_SELF_CLEAR (1 << 28) /* CORBRP clears itself after reset */ -/* position fix mode */ -enum { - POS_FIX_AUTO, - POS_FIX_LPIB, - POS_FIX_POSBUF, - POS_FIX_VIACOMBO, - POS_FIX_COMBO, -}; - -/* Defines for ATI HD Audio support in SB450 south bridge */ -#define ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR 0x42 -#define ATI_SB450_HDAUDIO_ENABLE_SNOOP 0x02 - -/* Defines for Nvidia HDA support */ -#define NVIDIA_HDA_TRANSREG_ADDR 0x4e -#define NVIDIA_HDA_ENABLE_COHBITS 0x0f -#define NVIDIA_HDA_ISTRM_COH 0x4d -#define NVIDIA_HDA_OSTRM_COH 0x4c -#define NVIDIA_HDA_ENABLE_COHBIT 0x01 - -/* Defines for Intel SCH HDA snoop control */ -#define INTEL_SCH_HDA_DEVC 0x78 -#define INTEL_SCH_HDA_DEVC_NOSNOOP (0x1<<11) - -/* Define IN stream 0 FIFO size offset in VIA controller */ -#define VIA_IN_STREAM0_FIFO_SIZE_OFFSET 0x90 -/* Define VIA HD Audio Device ID*/ -#define VIA_HDAC_DEVICE_ID 0x3288 - /* HD Audio class code */ #define PCI_CLASS_MULTIMEDIA_HD_AUDIO 0x0403 @@ -325,6 +276,9 @@ struct azx_pcm { struct list_head list; }; +typedef unsigned int (*azx_get_pos_callback_t)(struct azx *, struct azx_dev *); +typedef int (*azx_get_delay_callback_t)(struct azx *, struct azx_dev *, unsigned int pos); + struct azx { struct snd_card *card; struct pci_dev *pci; @@ -343,6 +297,10 @@ struct azx { /* Register interaction. */ const struct hda_controller_ops *ops; + /* position adjustment callbacks */ + azx_get_pos_callback_t get_position[2]; + azx_get_delay_callback_t get_delay[2]; + /* pci resources */ unsigned long addr; void __iomem *remap_addr; @@ -351,7 +309,6 @@ struct azx { /* locks */ spinlock_t reg_lock; struct mutex open_mutex; /* Prevents concurrent open/close operations */ - struct completion probe_wait; /* streams (x num_streams) */ struct azx_dev *azx_dev; @@ -378,7 +335,6 @@ struct azx { #endif /* flags */ - int position_fix[2]; /* for both playback/capture streams */ const int *bdl_pos_adj; int poll_count; unsigned int running:1; @@ -386,46 +342,23 @@ struct azx { unsigned int single_cmd:1; unsigned int polling_mode:1; unsigned int msi:1; - unsigned int irq_pending_warned:1; unsigned int probing:1; /* codec probing phase */ unsigned int snoop:1; unsigned int align_buffer_size:1; unsigned int region_requested:1; - - /* VGA-switcheroo setup */ - unsigned int use_vga_switcheroo:1; - unsigned int vga_switcheroo_registered:1; - unsigned int init_failed:1; /* delayed init failed */ unsigned int disabled:1; /* disabled by VGA-switcher */ /* for debugging */ unsigned int last_cmd[AZX_MAX_CODECS]; - /* for pending irqs */ - struct work_struct irq_pending_work; - - struct work_struct probe_work; - /* reboot notifier (for mysterious hangup problem at power-down) */ struct notifier_block reboot_notifier; - /* card list (for power_save trigger) */ - struct list_head list; - #ifdef CONFIG_SND_HDA_DSP_LOADER struct azx_dev saved_azx_dev; #endif - - /* secondary power domain for hdmi audio under vga device */ - struct dev_pm_domain hdmi_pm_domain; }; -#ifdef CONFIG_SND_VERBOSE_PRINTK -#define SFX /* nop */ -#else -#define SFX "hda-intel " -#endif - #ifdef CONFIG_X86 #define azx_snoop(chip) ((chip)->snoop) #else @@ -437,29 +370,29 @@ struct azx { */ #define azx_writel(chip, reg, value) \ - ((chip)->ops->reg_writel(value, (chip)->remap_addr + ICH6_REG_##reg)) + ((chip)->ops->reg_writel(value, (chip)->remap_addr + AZX_REG_##reg)) #define azx_readl(chip, reg) \ - ((chip)->ops->reg_readl((chip)->remap_addr + ICH6_REG_##reg)) + ((chip)->ops->reg_readl((chip)->remap_addr + AZX_REG_##reg)) #define azx_writew(chip, reg, value) \ - ((chip)->ops->reg_writew(value, (chip)->remap_addr + ICH6_REG_##reg)) + ((chip)->ops->reg_writew(value, (chip)->remap_addr + AZX_REG_##reg)) #define azx_readw(chip, reg) \ - ((chip)->ops->reg_readw((chip)->remap_addr + ICH6_REG_##reg)) + ((chip)->ops->reg_readw((chip)->remap_addr + AZX_REG_##reg)) #define azx_writeb(chip, reg, value) \ - ((chip)->ops->reg_writeb(value, (chip)->remap_addr + ICH6_REG_##reg)) + ((chip)->ops->reg_writeb(value, (chip)->remap_addr + AZX_REG_##reg)) #define azx_readb(chip, reg) \ - ((chip)->ops->reg_readb((chip)->remap_addr + ICH6_REG_##reg)) + ((chip)->ops->reg_readb((chip)->remap_addr + AZX_REG_##reg)) #define azx_sd_writel(chip, dev, reg, value) \ - ((chip)->ops->reg_writel(value, (dev)->sd_addr + ICH6_REG_##reg)) + ((chip)->ops->reg_writel(value, (dev)->sd_addr + AZX_REG_##reg)) #define azx_sd_readl(chip, dev, reg) \ - ((chip)->ops->reg_readl((dev)->sd_addr + ICH6_REG_##reg)) + ((chip)->ops->reg_readl((dev)->sd_addr + AZX_REG_##reg)) #define azx_sd_writew(chip, dev, reg, value) \ - ((chip)->ops->reg_writew(value, (dev)->sd_addr + ICH6_REG_##reg)) + ((chip)->ops->reg_writew(value, (dev)->sd_addr + AZX_REG_##reg)) #define azx_sd_readw(chip, dev, reg) \ - ((chip)->ops->reg_readw((dev)->sd_addr + ICH6_REG_##reg)) + ((chip)->ops->reg_readw((dev)->sd_addr + AZX_REG_##reg)) #define azx_sd_writeb(chip, dev, reg, value) \ - ((chip)->ops->reg_writeb(value, (dev)->sd_addr + ICH6_REG_##reg)) + ((chip)->ops->reg_writeb(value, (dev)->sd_addr + AZX_REG_##reg)) #define azx_sd_readb(chip, dev, reg) \ - ((chip)->ops->reg_readb((dev)->sd_addr + ICH6_REG_##reg)) + ((chip)->ops->reg_readb((dev)->sd_addr + AZX_REG_##reg)) #endif /* __SOUND_HDA_PRIV_H */ diff --git a/sound/pci/hda/hda_tegra.c b/sound/pci/hda/hda_tegra.c index 358414da6418..227990bc02e3 100644 --- a/sound/pci/hda/hda_tegra.c +++ b/sound/pci/hda/hda_tegra.c @@ -29,7 +29,6 @@ #include <linux/moduleparam.h> #include <linux/mutex.h> #include <linux/of_device.h> -#include <linux/reboot.h> #include <linux/slab.h> #include <linux/time.h> @@ -272,13 +271,9 @@ static int hda_tegra_resume(struct device *dev) struct snd_card *card = dev_get_drvdata(dev); struct azx *chip = card->private_data; struct hda_tegra *hda = container_of(chip, struct hda_tegra, chip); - int status; hda_tegra_enable_clocks(hda); - /* Read STATESTS before controller reset */ - status = azx_readw(chip, STATESTS); - hda_tegra_init(hda); azx_init_chip(chip, 1); @@ -295,30 +290,6 @@ static const struct dev_pm_ops hda_tegra_pm = { }; /* - * reboot notifier for hang-up problem at power-down - */ -static int hda_tegra_halt(struct notifier_block *nb, unsigned long event, - void *buf) -{ - struct azx *chip = container_of(nb, struct azx, reboot_notifier); - snd_hda_bus_reboot_notify(chip->bus); - azx_stop_chip(chip); - return NOTIFY_OK; -} - -static void hda_tegra_notifier_register(struct azx *chip) -{ - chip->reboot_notifier.notifier_call = hda_tegra_halt; - register_reboot_notifier(&chip->reboot_notifier); -} - -static void hda_tegra_notifier_unregister(struct azx *chip) -{ - if (chip->reboot_notifier.notifier_call) - unregister_reboot_notifier(&chip->reboot_notifier); -} - -/* * destructor */ static int hda_tegra_dev_free(struct snd_device *device) @@ -326,7 +297,7 @@ static int hda_tegra_dev_free(struct snd_device *device) int i; struct azx *chip = device->device_data; - hda_tegra_notifier_unregister(chip); + azx_notifier_unregister(chip); if (chip->initialized) { for (i = 0; i < chip->num_streams; i++) @@ -478,10 +449,7 @@ static int hda_tegra_create(struct snd_card *card, chip->driver_type = driver_caps & 0xff; chip->dev_index = 0; INIT_LIST_HEAD(&chip->pcm_list); - INIT_LIST_HEAD(&chip->list); - chip->position_fix[0] = POS_FIX_AUTO; - chip->position_fix[1] = POS_FIX_AUTO; chip->codec_probe_mask = -1; chip->single_cmd = false; @@ -559,7 +527,7 @@ static int hda_tegra_probe(struct platform_device *pdev) chip->running = 1; power_down_all_codecs(chip); - hda_tegra_notifier_register(chip); + azx_notifier_register(chip); return 0; diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 092f2bd030bd..5d8455e2dacd 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -2046,14 +2046,14 @@ enum dma_state { DMA_STATE_RUN = 1 }; -static int dma_convert_to_hda_format( +static int dma_convert_to_hda_format(struct hda_codec *codec, unsigned int sample_rate, unsigned short channels, unsigned short *hda_format) { unsigned int format_val; - format_val = snd_hda_calc_stream_format( + format_val = snd_hda_calc_stream_format(codec, sample_rate, channels, SNDRV_PCM_FORMAT_S32_LE, @@ -2452,7 +2452,7 @@ static int dspxfr_image(struct hda_codec *codec, } dma_engine->codec = codec; - dma_convert_to_hda_format(sample_rate, channels, &hda_format); + dma_convert_to_hda_format(codec, sample_rate, channels, &hda_format); dma_engine->m_converter_format = hda_format; dma_engine->buf_size = (ovly ? DSP_DMA_WRITE_BUFLEN_OVLY : DSP_DMA_WRITE_BUFLEN_INIT) * 2; @@ -4376,6 +4376,9 @@ static void ca0132_download_dsp(struct hda_codec *codec) return; /* NOP */ #endif + if (spec->dsp_state == DSP_DOWNLOAD_FAILED) + return; /* don't retry failures */ + chipio_enable_clocks(codec); spec->dsp_state = DSP_DOWNLOADING; if (!ca0132_download_dsp_images(codec)) @@ -4552,7 +4555,8 @@ static int ca0132_init(struct hda_codec *codec) struct auto_pin_cfg *cfg = &spec->autocfg; int i; - spec->dsp_state = DSP_DOWNLOAD_INIT; + if (spec->dsp_state != DSP_DOWNLOAD_FAILED) + spec->dsp_state = DSP_DOWNLOAD_INIT; spec->curr_chip_addx = INVALID_CHIP_ADDRESS; snd_hda_power_up(codec); @@ -4663,6 +4667,7 @@ static int patch_ca0132(struct hda_codec *codec) codec->spec = spec; spec->codec = codec; + spec->dsp_state = DSP_DOWNLOAD_INIT; spec->num_mixers = 1; spec->mixers[0] = ca0132_mixer; diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index 387f0b551889..3db724eaa53c 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -657,8 +657,10 @@ static void cs4208_fixup_mac(struct hda_codec *codec, { if (action != HDA_FIXUP_ACT_PRE_PROBE) return; + + codec->fixup_id = HDA_FIXUP_ID_NOT_SET; snd_hda_pick_fixup(codec, NULL, cs4208_mac_fixup_tbl, cs4208_fixups); - if (codec->fixup_id < 0 || codec->fixup_id == CS4208_MAC_AUTO) + if (codec->fixup_id == HDA_FIXUP_ID_NOT_SET) codec->fixup_id = CS4208_GPIO0; /* default fixup */ snd_hda_apply_fixup(codec, action); } diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c index 061ea5965dd5..c895a8f21192 100644 --- a/sound/pci/hda/patch_cmedia.c +++ b/sound/pci/hda/patch_cmedia.c @@ -31,549 +31,10 @@ #include "hda_jack.h" #include "hda_generic.h" -#undef ENABLE_CMI_STATIC_QUIRKS - -#ifdef ENABLE_CMI_STATIC_QUIRKS -#define NUM_PINS 11 - - -/* board config type */ -enum { - CMI_MINIMAL, /* back 3-jack */ - CMI_MIN_FP, /* back 3-jack + front-panel 2-jack */ - CMI_FULL, /* back 6-jack + front-panel 2-jack */ - CMI_FULL_DIG, /* back 6-jack + front-panel 2-jack + digital I/O */ - CMI_ALLOUT, /* back 5-jack + front-panel 2-jack + digital out */ - CMI_AUTO, /* let driver guess it */ - CMI_MODELS -}; -#endif /* ENABLE_CMI_STATIC_QUIRKS */ - struct cmi_spec { struct hda_gen_spec gen; - -#ifdef ENABLE_CMI_STATIC_QUIRKS - /* below are only for static models */ - - int board_config; - unsigned int no_line_in: 1; /* no line-in (5-jack) */ - unsigned int front_panel: 1; /* has front-panel 2-jack */ - - /* playback */ - struct hda_multi_out multiout; - hda_nid_t dac_nids[AUTO_CFG_MAX_OUTS]; /* NID for each DAC */ - int num_dacs; - - /* capture */ - const hda_nid_t *adc_nids; - hda_nid_t dig_in_nid; - - /* capture source */ - const struct hda_input_mux *input_mux; - unsigned int cur_mux[2]; - - /* channel mode */ - int num_channel_modes; - const struct hda_channel_mode *channel_modes; - - struct hda_pcm pcm_rec[2]; /* PCM information */ - - /* pin default configuration */ - hda_nid_t pin_nid[NUM_PINS]; - unsigned int def_conf[NUM_PINS]; - unsigned int pin_def_confs; - - /* multichannel pins */ - struct hda_verb multi_init[9]; /* 2 verbs for each pin + terminator */ -#endif /* ENABLE_CMI_STATIC_QUIRKS */ -}; - -#ifdef ENABLE_CMI_STATIC_QUIRKS -/* - * input MUX - */ -static int cmi_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct cmi_spec *spec = codec->spec; - return snd_hda_input_mux_info(spec->input_mux, uinfo); -} - -static int cmi_mux_enum_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct cmi_spec *spec = codec->spec; - unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - - ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx]; - return 0; -} - -static int cmi_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct cmi_spec *spec = codec->spec; - unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - - return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, - spec->adc_nids[adc_idx], &spec->cur_mux[adc_idx]); -} - -/* - * shared line-in, mic for surrounds - */ - -/* 3-stack / 2 channel */ -static const struct hda_verb cmi9880_ch2_init[] = { - /* set line-in PIN for input */ - { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, - /* set mic PIN for input, also enable vref */ - { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - /* route front PCM (DAC1) to HP */ - { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, - {} -}; - -/* 3-stack / 6 channel */ -static const struct hda_verb cmi9880_ch6_init[] = { - /* set line-in PIN for output */ - { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - /* set mic PIN for output */ - { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - /* route front PCM (DAC1) to HP */ - { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, - {} -}; - -/* 3-stack+front / 8 channel */ -static const struct hda_verb cmi9880_ch8_init[] = { - /* set line-in PIN for output */ - { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - /* set mic PIN for output */ - { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - /* route rear-surround PCM (DAC4) to HP */ - { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x03 }, - {} -}; - -static const struct hda_channel_mode cmi9880_channel_modes[3] = { - { 2, cmi9880_ch2_init }, - { 6, cmi9880_ch6_init }, - { 8, cmi9880_ch8_init }, }; -static int cmi_ch_mode_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct cmi_spec *spec = codec->spec; - return snd_hda_ch_mode_info(codec, uinfo, spec->channel_modes, - spec->num_channel_modes); -} - -static int cmi_ch_mode_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct cmi_spec *spec = codec->spec; - return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_modes, - spec->num_channel_modes, spec->multiout.max_channels); -} - -static int cmi_ch_mode_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct cmi_spec *spec = codec->spec; - return snd_hda_ch_mode_put(codec, ucontrol, spec->channel_modes, - spec->num_channel_modes, &spec->multiout.max_channels); -} - -/* - */ -static const struct snd_kcontrol_new cmi9880_basic_mixer[] = { - /* CMI9880 has no playback volumes! */ - HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT), /* front */ - HDA_CODEC_MUTE("Surround Playback Switch", 0x04, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Side Playback Switch", 0x06, 0x0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 2, - .info = cmi_mux_enum_info, - .get = cmi_mux_enum_get, - .put = cmi_mux_enum_put, - }, - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Beep Playback Volume", 0x23, 0, HDA_OUTPUT), - HDA_CODEC_MUTE("Beep Playback Switch", 0x23, 0, HDA_OUTPUT), - { } /* end */ -}; - -/* - * shared I/O pins - */ -static const struct snd_kcontrol_new cmi9880_ch_mode_mixer[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = cmi_ch_mode_info, - .get = cmi_ch_mode_get, - .put = cmi_ch_mode_put, - }, - { } /* end */ -}; - -/* AUD-in selections: - * 0x0b 0x0c 0x0d 0x0e 0x0f 0x10 0x11 0x1f 0x20 - */ -static const struct hda_input_mux cmi9880_basic_mux = { - .num_items = 4, - .items = { - { "Front Mic", 0x5 }, - { "Rear Mic", 0x2 }, - { "Line", 0x1 }, - { "CD", 0x7 }, - } -}; - -static const struct hda_input_mux cmi9880_no_line_mux = { - .num_items = 3, - .items = { - { "Front Mic", 0x5 }, - { "Rear Mic", 0x2 }, - { "CD", 0x7 }, - } -}; - -/* front, rear, clfe, rear_surr */ -static const hda_nid_t cmi9880_dac_nids[4] = { - 0x03, 0x04, 0x05, 0x06 -}; -/* ADC0, ADC1 */ -static const hda_nid_t cmi9880_adc_nids[2] = { - 0x08, 0x09 -}; - -#define CMI_DIG_OUT_NID 0x07 -#define CMI_DIG_IN_NID 0x0a - -/* - */ -static const struct hda_verb cmi9880_basic_init[] = { - /* port-D for line out (rear panel) */ - { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, - /* port-E for HP out (front panel) */ - { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, - /* route front PCM to HP */ - { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, - /* port-A for surround (rear panel) */ - { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, - /* port-G for CLFE (rear panel) */ - { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, - { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x02 }, - /* port-H for side (rear panel) */ - { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, - { 0x20, AC_VERB_SET_CONNECT_SEL, 0x01 }, - /* port-C for line-in (rear panel) */ - { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, - /* port-B for mic-in (rear panel) with vref */ - { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - /* port-F for mic-in (front panel) with vref */ - { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - /* CD-in */ - { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, - /* route front mic to ADC1/2 */ - { 0x08, AC_VERB_SET_CONNECT_SEL, 0x05 }, - { 0x09, AC_VERB_SET_CONNECT_SEL, 0x05 }, - {} /* terminator */ -}; - -static const struct hda_verb cmi9880_allout_init[] = { - /* port-D for line out (rear panel) */ - { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, - /* port-E for HP out (front panel) */ - { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, - /* route front PCM to HP */ - { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, - /* port-A for side (rear panel) */ - { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, - /* port-G for CLFE (rear panel) */ - { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, - { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x02 }, - /* port-H for side (rear panel) */ - { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, - { 0x20, AC_VERB_SET_CONNECT_SEL, 0x01 }, - /* port-C for surround (rear panel) */ - { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, - /* port-B for mic-in (rear panel) with vref */ - { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - /* port-F for mic-in (front panel) with vref */ - { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - /* CD-in */ - { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, - /* route front mic to ADC1/2 */ - { 0x08, AC_VERB_SET_CONNECT_SEL, 0x05 }, - { 0x09, AC_VERB_SET_CONNECT_SEL, 0x05 }, - {} /* terminator */ -}; - -/* - */ -static int cmi9880_build_controls(struct hda_codec *codec) -{ - struct cmi_spec *spec = codec->spec; - struct snd_kcontrol *kctl; - int i, err; - - err = snd_hda_add_new_ctls(codec, cmi9880_basic_mixer); - if (err < 0) - return err; - if (spec->channel_modes) { - err = snd_hda_add_new_ctls(codec, cmi9880_ch_mode_mixer); - if (err < 0) - return err; - } - if (spec->multiout.dig_out_nid) { - err = snd_hda_create_spdif_out_ctls(codec, - spec->multiout.dig_out_nid, - spec->multiout.dig_out_nid); - if (err < 0) - return err; - err = snd_hda_create_spdif_share_sw(codec, - &spec->multiout); - if (err < 0) - return err; - spec->multiout.share_spdif = 1; - } - if (spec->dig_in_nid) { - err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid); - if (err < 0) - return err; - } - - /* assign Capture Source enums to NID */ - kctl = snd_hda_find_mixer_ctl(codec, "Capture Source"); - for (i = 0; kctl && i < kctl->count; i++) { - err = snd_hda_add_nid(codec, kctl, i, spec->adc_nids[i]); - if (err < 0) - return err; - } - return 0; -} - -static int cmi9880_init(struct hda_codec *codec) -{ - struct cmi_spec *spec = codec->spec; - if (spec->board_config == CMI_ALLOUT) - snd_hda_sequence_write(codec, cmi9880_allout_init); - else - snd_hda_sequence_write(codec, cmi9880_basic_init); - if (spec->board_config == CMI_AUTO) - snd_hda_sequence_write(codec, spec->multi_init); - return 0; -} - -/* - * Analog playback callbacks - */ -static int cmi9880_playback_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct cmi_spec *spec = codec->spec; - return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream, - hinfo); -} - -static int cmi9880_playback_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct cmi_spec *spec = codec->spec; - return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag, - format, substream); -} - -static int cmi9880_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct cmi_spec *spec = codec->spec; - return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); -} - -/* - * Digital out - */ -static int cmi9880_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct cmi_spec *spec = codec->spec; - return snd_hda_multi_out_dig_open(codec, &spec->multiout); -} - -static int cmi9880_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct cmi_spec *spec = codec->spec; - return snd_hda_multi_out_dig_close(codec, &spec->multiout); -} - -static int cmi9880_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct cmi_spec *spec = codec->spec; - return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag, - format, substream); -} - -/* - * Analog capture - */ -static int cmi9880_capture_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct cmi_spec *spec = codec->spec; - - snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], - stream_tag, 0, format); - return 0; -} - -static int cmi9880_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct cmi_spec *spec = codec->spec; - - snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]); - return 0; -} - - -/* - */ -static const struct hda_pcm_stream cmi9880_pcm_analog_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 8, - .nid = 0x03, /* NID to query formats and rates */ - .ops = { - .open = cmi9880_playback_pcm_open, - .prepare = cmi9880_playback_pcm_prepare, - .cleanup = cmi9880_playback_pcm_cleanup - }, -}; - -static const struct hda_pcm_stream cmi9880_pcm_analog_capture = { - .substreams = 2, - .channels_min = 2, - .channels_max = 2, - .nid = 0x08, /* NID to query formats and rates */ - .ops = { - .prepare = cmi9880_capture_pcm_prepare, - .cleanup = cmi9880_capture_pcm_cleanup - }, -}; - -static const struct hda_pcm_stream cmi9880_pcm_digital_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - /* NID is set in cmi9880_build_pcms */ - .ops = { - .open = cmi9880_dig_playback_pcm_open, - .close = cmi9880_dig_playback_pcm_close, - .prepare = cmi9880_dig_playback_pcm_prepare - }, -}; - -static const struct hda_pcm_stream cmi9880_pcm_digital_capture = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - /* NID is set in cmi9880_build_pcms */ -}; - -static int cmi9880_build_pcms(struct hda_codec *codec) -{ - struct cmi_spec *spec = codec->spec; - struct hda_pcm *info = spec->pcm_rec; - - codec->num_pcms = 1; - codec->pcm_info = info; - - info->name = "CMI9880"; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = cmi9880_pcm_analog_playback; - info->stream[SNDRV_PCM_STREAM_CAPTURE] = cmi9880_pcm_analog_capture; - - if (spec->multiout.dig_out_nid || spec->dig_in_nid) { - codec->num_pcms++; - info++; - info->name = "CMI9880 Digital"; - info->pcm_type = HDA_PCM_TYPE_SPDIF; - if (spec->multiout.dig_out_nid) { - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = cmi9880_pcm_digital_playback; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid; - } - if (spec->dig_in_nid) { - info->stream[SNDRV_PCM_STREAM_CAPTURE] = cmi9880_pcm_digital_capture; - info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid; - } - } - - return 0; -} - -static void cmi9880_free(struct hda_codec *codec) -{ - kfree(codec->spec); -} - -/* - */ - -static const char * const cmi9880_models[CMI_MODELS] = { - [CMI_MINIMAL] = "minimal", - [CMI_MIN_FP] = "min_fp", - [CMI_FULL] = "full", - [CMI_FULL_DIG] = "full_dig", - [CMI_ALLOUT] = "allout", - [CMI_AUTO] = "auto", -}; - -static const struct snd_pci_quirk cmi9880_cfg_tbl[] = { - SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", CMI_FULL_DIG), - SND_PCI_QUIRK(0x1854, 0x002b, "LG LS75", CMI_MINIMAL), - SND_PCI_QUIRK(0x1854, 0x0032, "LG", CMI_FULL_DIG), - {} /* terminator */ -}; - -static const struct hda_codec_ops cmi9880_patch_ops = { - .build_controls = cmi9880_build_controls, - .build_pcms = cmi9880_build_pcms, - .init = cmi9880_init, - .free = cmi9880_free, -}; -#endif /* ENABLE_CMI_STATIC_QUIRKS */ - /* * stuff for auto-parser */ @@ -585,12 +46,18 @@ static const struct hda_codec_ops cmi_auto_patch_ops = { .unsol_event = snd_hda_jack_unsol_event, }; -static int cmi_parse_auto_config(struct hda_codec *codec) +static int patch_cmi9880(struct hda_codec *codec) { - struct cmi_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->gen.autocfg; + struct cmi_spec *spec; + struct auto_pin_cfg *cfg; int err; + spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (spec == NULL) + return -ENOMEM; + + codec->spec = spec; + cfg = &spec->gen.autocfg; snd_hda_gen_spec_init(&spec->gen); err = snd_hda_parse_pin_defcfg(codec, cfg, NULL, 0); @@ -608,88 +75,62 @@ static int cmi_parse_auto_config(struct hda_codec *codec) return err; } - -static int patch_cmi9880(struct hda_codec *codec) +static int patch_cmi8888(struct hda_codec *codec) { struct cmi_spec *spec; + struct auto_pin_cfg *cfg; + int err; spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) + if (!spec) return -ENOMEM; codec->spec = spec; -#ifdef ENABLE_CMI_STATIC_QUIRKS - spec->board_config = snd_hda_check_board_config(codec, CMI_MODELS, - cmi9880_models, - cmi9880_cfg_tbl); - if (spec->board_config < 0) { - codec_dbg(codec, "%s: BIOS auto-probing.\n", - codec->chip_name); - spec->board_config = CMI_AUTO; /* try everything */ - } + cfg = &spec->gen.autocfg; + snd_hda_gen_spec_init(&spec->gen); - if (spec->board_config == CMI_AUTO) - return cmi_parse_auto_config(codec); + /* mask NID 0x10 from the playback volume selection; + * it's a headphone boost volume handled manually below + */ + spec->gen.out_vol_mask = (1ULL << 0x10); - /* copy default DAC NIDs */ - memcpy(spec->dac_nids, cmi9880_dac_nids, sizeof(spec->dac_nids)); - spec->num_dacs = 4; + err = snd_hda_parse_pin_defcfg(codec, cfg, NULL, 0); + if (err < 0) + goto error; + err = snd_hda_gen_parse_auto_config(codec, cfg); + if (err < 0) + goto error; - switch (spec->board_config) { - case CMI_MINIMAL: - case CMI_MIN_FP: - spec->channel_modes = cmi9880_channel_modes; - if (spec->board_config == CMI_MINIMAL) - spec->num_channel_modes = 2; - else { - spec->front_panel = 1; - spec->num_channel_modes = 3; - } - spec->multiout.max_channels = cmi9880_channel_modes[0].channels; - spec->input_mux = &cmi9880_basic_mux; - break; - case CMI_FULL: - case CMI_FULL_DIG: - spec->front_panel = 1; - spec->multiout.max_channels = 8; - spec->input_mux = &cmi9880_basic_mux; - if (spec->board_config == CMI_FULL_DIG) { - spec->multiout.dig_out_nid = CMI_DIG_OUT_NID; - spec->dig_in_nid = CMI_DIG_IN_NID; + if (get_defcfg_device(snd_hda_codec_get_pincfg(codec, 0x10)) == + AC_JACK_HP_OUT) { + static const struct snd_kcontrol_new amp_kctl = + HDA_CODEC_VOLUME("Headphone Amp Playback Volume", + 0x10, 0, HDA_OUTPUT); + if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &_kctl)) { + err = -ENOMEM; + goto error; } - break; - case CMI_ALLOUT: - default: - spec->front_panel = 1; - spec->multiout.max_channels = 8; - spec->no_line_in = 1; - spec->input_mux = &cmi9880_no_line_mux; - spec->multiout.dig_out_nid = CMI_DIG_OUT_NID; - break; } - spec->multiout.num_dacs = spec->num_dacs; - spec->multiout.dac_nids = spec->dac_nids; - - spec->adc_nids = cmi9880_adc_nids; - - codec->patch_ops = cmi9880_patch_ops; - + codec->patch_ops = cmi_auto_patch_ops; return 0; -#else - return cmi_parse_auto_config(codec); -#endif + + error: + snd_hda_gen_free(codec); + return err; } /* * patch entries */ static const struct hda_codec_preset snd_hda_preset_cmedia[] = { + { .id = 0x13f68888, .name = "CMI8888", .patch = patch_cmi8888 }, { .id = 0x13f69880, .name = "CMI9880", .patch = patch_cmi9880 }, { .id = 0x434d4980, .name = "CMI9880", .patch = patch_cmi9880 }, {} /* terminator */ }; +MODULE_ALIAS("snd-hda-codec-id:13f68888"); MODULE_ALIAS("snd-hda-codec-id:13f69880"); MODULE_ALIAS("snd-hda-codec-id:434d4980"); diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 1dc7e974f3b1..47ccb8f44adb 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -26,6 +26,7 @@ #include <linux/module.h> #include <sound/core.h> #include <sound/jack.h> +#include <sound/tlv.h> #include "hda_codec.h" #include "hda_local.h" @@ -34,27 +35,6 @@ #include "hda_jack.h" #include "hda_generic.h" -#undef ENABLE_CXT_STATIC_QUIRKS - -#define CXT_PIN_DIR_IN 0x00 -#define CXT_PIN_DIR_OUT 0x01 -#define CXT_PIN_DIR_INOUT 0x02 -#define CXT_PIN_DIR_IN_NOMICBIAS 0x03 -#define CXT_PIN_DIR_INOUT_NOMICBIAS 0x04 - -#define CONEXANT_HP_EVENT 0x37 -#define CONEXANT_MIC_EVENT 0x38 -#define CONEXANT_LINE_EVENT 0x39 - -/* Conexant 5051 specific */ - -#define CXT5051_SPDIF_OUT 0x12 -#define CXT5051_PORTB_EVENT 0x38 -#define CXT5051_PORTC_EVENT 0x39 - -#define AUTO_MIC_PORTB (1 << 1) -#define AUTO_MIC_PORTC (1 << 2) - struct conexant_spec { struct hda_gen_spec gen; @@ -72,64 +52,6 @@ struct conexant_spec { bool dc_enable; unsigned int dc_input_bias; /* offset into olpc_xo_dc_bias */ struct nid_path *dc_mode_path; - -#ifdef ENABLE_CXT_STATIC_QUIRKS - const struct snd_kcontrol_new *mixers[5]; - int num_mixers; - hda_nid_t vmaster_nid; - - const struct hda_verb *init_verbs[5]; /* initialization verbs - * don't forget NULL - * termination! - */ - unsigned int num_init_verbs; - - /* playback */ - struct hda_multi_out multiout; /* playback set-up - * max_channels, dacs must be set - * dig_out_nid and hp_nid are optional - */ - unsigned int cur_eapd; - unsigned int hp_present; - unsigned int line_present; - unsigned int auto_mic; - - /* capture */ - unsigned int num_adc_nids; - const hda_nid_t *adc_nids; - hda_nid_t dig_in_nid; /* digital-in NID; optional */ - - unsigned int cur_adc_idx; - hda_nid_t cur_adc; - unsigned int cur_adc_stream_tag; - unsigned int cur_adc_format; - - const struct hda_pcm_stream *capture_stream; - - /* capture source */ - const struct hda_input_mux *input_mux; - const hda_nid_t *capsrc_nids; - unsigned int cur_mux[3]; - - /* channel model */ - const struct hda_channel_mode *channel_mode; - int num_channel_mode; - - /* PCM information */ - struct hda_pcm pcm_rec[2]; /* used in build_pcms() */ - - unsigned int spdif_route; - - unsigned int port_d_mode; - unsigned int dell_automute:1; - unsigned int dell_vostro:1; - unsigned int ideapad:1; - unsigned int thinkpad:1; - unsigned int hp_laptop:1; - unsigned int asus:1; - - unsigned int mic_boost; /* offset into cxt5066_analog_mic_boost */ -#endif /* ENABLE_CXT_STATIC_QUIRKS */ }; @@ -173,2533 +95,6 @@ static int add_beep_ctls(struct hda_codec *codec) #define add_beep_ctls(codec) 0 #endif - -#ifdef ENABLE_CXT_STATIC_QUIRKS -static int conexant_playback_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct conexant_spec *spec = codec->spec; - return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream, - hinfo); -} - -static int conexant_playback_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct conexant_spec *spec = codec->spec; - return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, - stream_tag, - format, substream); -} - -static int conexant_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct conexant_spec *spec = codec->spec; - return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); -} - -/* - * Digital out - */ -static int conexant_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct conexant_spec *spec = codec->spec; - return snd_hda_multi_out_dig_open(codec, &spec->multiout); -} - -static int conexant_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct conexant_spec *spec = codec->spec; - return snd_hda_multi_out_dig_close(codec, &spec->multiout); -} - -static int conexant_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct conexant_spec *spec = codec->spec; - return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, - stream_tag, - format, substream); -} - -/* - * Analog capture - */ -static int conexant_capture_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct conexant_spec *spec = codec->spec; - snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], - stream_tag, 0, format); - return 0; -} - -static int conexant_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct conexant_spec *spec = codec->spec; - snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]); - return 0; -} - - - -static const struct hda_pcm_stream conexant_pcm_analog_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - .nid = 0, /* fill later */ - .ops = { - .open = conexant_playback_pcm_open, - .prepare = conexant_playback_pcm_prepare, - .cleanup = conexant_playback_pcm_cleanup - }, -}; - -static const struct hda_pcm_stream conexant_pcm_analog_capture = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - .nid = 0, /* fill later */ - .ops = { - .prepare = conexant_capture_pcm_prepare, - .cleanup = conexant_capture_pcm_cleanup - }, -}; - - -static const struct hda_pcm_stream conexant_pcm_digital_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - .nid = 0, /* fill later */ - .ops = { - .open = conexant_dig_playback_pcm_open, - .close = conexant_dig_playback_pcm_close, - .prepare = conexant_dig_playback_pcm_prepare - }, -}; - -static const struct hda_pcm_stream conexant_pcm_digital_capture = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - /* NID is set in alc_build_pcms */ -}; - -static int cx5051_capture_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct conexant_spec *spec = codec->spec; - spec->cur_adc = spec->adc_nids[spec->cur_adc_idx]; - spec->cur_adc_stream_tag = stream_tag; - spec->cur_adc_format = format; - snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format); - return 0; -} - -static int cx5051_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct conexant_spec *spec = codec->spec; - snd_hda_codec_cleanup_stream(codec, spec->cur_adc); - spec->cur_adc = 0; - return 0; -} - -static const struct hda_pcm_stream cx5051_pcm_analog_capture = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - .nid = 0, /* fill later */ - .ops = { - .prepare = cx5051_capture_pcm_prepare, - .cleanup = cx5051_capture_pcm_cleanup - }, -}; - -static int conexant_build_pcms(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - struct hda_pcm *info = spec->pcm_rec; - - codec->num_pcms = 1; - codec->pcm_info = info; - - info->name = "CONEXANT Analog"; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = conexant_pcm_analog_playback; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = - spec->multiout.max_channels; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = - spec->multiout.dac_nids[0]; - if (spec->capture_stream) - info->stream[SNDRV_PCM_STREAM_CAPTURE] = *spec->capture_stream; - else { - if (codec->vendor_id == 0x14f15051) - info->stream[SNDRV_PCM_STREAM_CAPTURE] = - cx5051_pcm_analog_capture; - else { - info->stream[SNDRV_PCM_STREAM_CAPTURE] = - conexant_pcm_analog_capture; - info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = - spec->num_adc_nids; - } - } - info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; - - if (spec->multiout.dig_out_nid) { - info++; - codec->num_pcms++; - info->name = "Conexant Digital"; - info->pcm_type = HDA_PCM_TYPE_SPDIF; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = - conexant_pcm_digital_playback; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = - spec->multiout.dig_out_nid; - if (spec->dig_in_nid) { - info->stream[SNDRV_PCM_STREAM_CAPTURE] = - conexant_pcm_digital_capture; - info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = - spec->dig_in_nid; - } - } - - return 0; -} - -static int conexant_mux_enum_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct conexant_spec *spec = codec->spec; - - return snd_hda_input_mux_info(spec->input_mux, uinfo); -} - -static int conexant_mux_enum_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct conexant_spec *spec = codec->spec; - unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - - ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx]; - return 0; -} - -static int conexant_mux_enum_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct conexant_spec *spec = codec->spec; - unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - - return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, - spec->capsrc_nids[adc_idx], - &spec->cur_mux[adc_idx]); -} - -static void conexant_set_power(struct hda_codec *codec, hda_nid_t fg, - unsigned int power_state) -{ - if (power_state == AC_PWRST_D3) - msleep(100); - snd_hda_codec_read(codec, fg, 0, AC_VERB_SET_POWER_STATE, - power_state); - /* partial workaround for "azx_get_response timeout" */ - if (power_state == AC_PWRST_D0) - msleep(10); - snd_hda_codec_set_power_to_all(codec, fg, power_state); -} - -static int conexant_init(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - int i; - - for (i = 0; i < spec->num_init_verbs; i++) - snd_hda_sequence_write(codec, spec->init_verbs[i]); - return 0; -} - -static void conexant_free(struct hda_codec *codec) -{ - kfree(codec->spec); -} - -static const struct snd_kcontrol_new cxt_capture_mixers[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .info = conexant_mux_enum_info, - .get = conexant_mux_enum_get, - .put = conexant_mux_enum_put - }, - {} -}; - -static const char * const slave_pfxs[] = { - "Headphone", "Speaker", "Bass Speaker", "Front", "Surround", "CLFE", - NULL -}; - -static int conexant_build_controls(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - unsigned int i; - int err; - - for (i = 0; i < spec->num_mixers; i++) { - err = snd_hda_add_new_ctls(codec, spec->mixers[i]); - if (err < 0) - return err; - } - if (spec->multiout.dig_out_nid) { - err = snd_hda_create_spdif_out_ctls(codec, - spec->multiout.dig_out_nid, - spec->multiout.dig_out_nid); - if (err < 0) - return err; - err = snd_hda_create_spdif_share_sw(codec, - &spec->multiout); - if (err < 0) - return err; - spec->multiout.share_spdif = 1; - } - if (spec->dig_in_nid) { - err = snd_hda_create_spdif_in_ctls(codec,spec->dig_in_nid); - if (err < 0) - return err; - } - - /* if we have no master control, let's create it */ - if (spec->vmaster_nid && - !snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) { - unsigned int vmaster_tlv[4]; - snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid, - HDA_OUTPUT, vmaster_tlv); - err = snd_hda_add_vmaster(codec, "Master Playback Volume", - vmaster_tlv, slave_pfxs, - "Playback Volume"); - if (err < 0) - return err; - } - if (spec->vmaster_nid && - !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) { - err = snd_hda_add_vmaster(codec, "Master Playback Switch", - NULL, slave_pfxs, - "Playback Switch"); - if (err < 0) - return err; - } - - if (spec->input_mux) { - err = snd_hda_add_new_ctls(codec, cxt_capture_mixers); - if (err < 0) - return err; - } - - err = add_beep_ctls(codec); - if (err < 0) - return err; - - return 0; -} - -static const struct hda_codec_ops conexant_patch_ops = { - .build_controls = conexant_build_controls, - .build_pcms = conexant_build_pcms, - .init = conexant_init, - .free = conexant_free, - .set_power_state = conexant_set_power, -}; - -static int patch_conexant_auto(struct hda_codec *codec); -/* - * EAPD control - * the private value = nid | (invert << 8) - */ - -#define cxt_eapd_info snd_ctl_boolean_mono_info - -static int cxt_eapd_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct conexant_spec *spec = codec->spec; - int invert = (kcontrol->private_value >> 8) & 1; - if (invert) - ucontrol->value.integer.value[0] = !spec->cur_eapd; - else - ucontrol->value.integer.value[0] = spec->cur_eapd; - return 0; - -} - -static int cxt_eapd_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct conexant_spec *spec = codec->spec; - int invert = (kcontrol->private_value >> 8) & 1; - hda_nid_t nid = kcontrol->private_value & 0xff; - unsigned int eapd; - - eapd = !!ucontrol->value.integer.value[0]; - if (invert) - eapd = !eapd; - if (eapd == spec->cur_eapd) - return 0; - - spec->cur_eapd = eapd; - snd_hda_codec_write_cache(codec, nid, - 0, AC_VERB_SET_EAPD_BTLENABLE, - eapd ? 0x02 : 0x00); - return 1; -} - -/* controls for test mode */ -#ifdef CONFIG_SND_DEBUG - -#define CXT_EAPD_SWITCH(xname, nid, mask) \ - { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ - .info = cxt_eapd_info, \ - .get = cxt_eapd_get, \ - .put = cxt_eapd_put, \ - .private_value = nid | (mask<<16) } - - - -static int conexant_ch_mode_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct conexant_spec *spec = codec->spec; - return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode, - spec->num_channel_mode); -} - -static int conexant_ch_mode_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct conexant_spec *spec = codec->spec; - return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode, - spec->num_channel_mode, - spec->multiout.max_channels); -} - -static int conexant_ch_mode_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct conexant_spec *spec = codec->spec; - int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode, - spec->num_channel_mode, - &spec->multiout.max_channels); - return err; -} - -#define CXT_PIN_MODE(xname, nid, dir) \ - { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ - .info = conexant_ch_mode_info, \ - .get = conexant_ch_mode_get, \ - .put = conexant_ch_mode_put, \ - .private_value = nid | (dir<<16) } - -#endif /* CONFIG_SND_DEBUG */ - -/* Conexant 5045 specific */ - -static const hda_nid_t cxt5045_dac_nids[1] = { 0x19 }; -static const hda_nid_t cxt5045_adc_nids[1] = { 0x1a }; -static const hda_nid_t cxt5045_capsrc_nids[1] = { 0x1a }; -#define CXT5045_SPDIF_OUT 0x18 - -static const struct hda_channel_mode cxt5045_modes[1] = { - { 2, NULL }, -}; - -static const struct hda_input_mux cxt5045_capture_source = { - .num_items = 2, - .items = { - { "Internal Mic", 0x1 }, - { "Mic", 0x2 }, - } -}; - -static const struct hda_input_mux cxt5045_capture_source_benq = { - .num_items = 4, - .items = { - { "Internal Mic", 0x1 }, - { "Mic", 0x2 }, - { "Line", 0x3 }, - { "Mixer", 0x0 }, - } -}; - -/* turn on/off EAPD (+ mute HP) as a master switch */ -static int cxt5045_hp_master_sw_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct conexant_spec *spec = codec->spec; - unsigned int bits; - - if (!cxt_eapd_put(kcontrol, ucontrol)) - return 0; - - /* toggle internal speakers mute depending of presence of - * the headphone jack - */ - bits = (!spec->hp_present && spec->cur_eapd) ? 0 : HDA_AMP_MUTE; - snd_hda_codec_amp_stereo(codec, 0x10, HDA_OUTPUT, 0, - HDA_AMP_MUTE, bits); - - bits = spec->cur_eapd ? 0 : HDA_AMP_MUTE; - snd_hda_codec_amp_stereo(codec, 0x11, HDA_OUTPUT, 0, - HDA_AMP_MUTE, bits); - return 1; -} - -/* bind volumes of both NID 0x10 and 0x11 */ -static const struct hda_bind_ctls cxt5045_hp_bind_master_vol = { - .ops = &snd_hda_bind_vol, - .values = { - HDA_COMPOSE_AMP_VAL(0x10, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x11, 3, 0, HDA_OUTPUT), - 0 - }, -}; - -/* toggle input of built-in and mic jack appropriately */ -static void cxt5045_hp_automic(struct hda_codec *codec) -{ - static const struct hda_verb mic_jack_on[] = { - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - {} - }; - static const struct hda_verb mic_jack_off[] = { - {0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - {} - }; - unsigned int present; - - present = snd_hda_jack_detect(codec, 0x12); - if (present) - snd_hda_sequence_write(codec, mic_jack_on); - else - snd_hda_sequence_write(codec, mic_jack_off); -} - - -/* mute internal speaker if HP is plugged */ -static void cxt5045_hp_automute(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - unsigned int bits; - - spec->hp_present = snd_hda_jack_detect(codec, 0x11); - - bits = (spec->hp_present || !spec->cur_eapd) ? HDA_AMP_MUTE : 0; - snd_hda_codec_amp_stereo(codec, 0x10, HDA_OUTPUT, 0, - HDA_AMP_MUTE, bits); -} - -/* unsolicited event for HP jack sensing */ -static void cxt5045_hp_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - res >>= 26; - switch (res) { - case CONEXANT_HP_EVENT: - cxt5045_hp_automute(codec); - break; - case CONEXANT_MIC_EVENT: - cxt5045_hp_automic(codec); - break; - - } -} - -static const struct snd_kcontrol_new cxt5045_mixers[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x1a, 0x00, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x1a, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("PCM Playback Volume", 0x17, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("PCM Playback Switch", 0x17, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x17, 0x2, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x17, 0x2, HDA_INPUT), - HDA_BIND_VOL("Master Playback Volume", &cxt5045_hp_bind_master_vol), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .info = cxt_eapd_info, - .get = cxt_eapd_get, - .put = cxt5045_hp_master_sw_put, - .private_value = 0x10, - }, - - {} -}; - -static const struct snd_kcontrol_new cxt5045_benq_mixers[] = { - HDA_CODEC_VOLUME("Line Playback Volume", 0x17, 0x3, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x17, 0x3, HDA_INPUT), - - {} -}; - -static const struct hda_verb cxt5045_init_verbs[] = { - /* Line in, Mic */ - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 }, - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 }, - /* HP, Amp */ - {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x10, AC_VERB_SET_CONNECT_SEL, 0x1}, - {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x11, AC_VERB_SET_CONNECT_SEL, 0x1}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - /* Record selector: Internal mic */ - {0x1a, AC_VERB_SET_CONNECT_SEL,0x1}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, - AC_AMP_SET_INPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x17}, - /* SPDIF route: PCM */ - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - { 0x13, AC_VERB_SET_CONNECT_SEL, 0x0 }, - /* EAPD */ - {0x10, AC_VERB_SET_EAPD_BTLENABLE, 0x2 }, /* default on */ - { } /* end */ -}; - -static const struct hda_verb cxt5045_benq_init_verbs[] = { - /* Internal Mic, Mic */ - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 }, - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 }, - /* Line In,HP, Amp */ - {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x10, AC_VERB_SET_CONNECT_SEL, 0x1}, - {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x11, AC_VERB_SET_CONNECT_SEL, 0x1}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - /* Record selector: Internal mic */ - {0x1a, AC_VERB_SET_CONNECT_SEL, 0x1}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, - AC_AMP_SET_INPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x17}, - /* SPDIF route: PCM */ - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x13, AC_VERB_SET_CONNECT_SEL, 0x0}, - /* EAPD */ - {0x10, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ - { } /* end */ -}; - -static const struct hda_verb cxt5045_hp_sense_init_verbs[] = { - /* pin sensing on HP jack */ - {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, - { } /* end */ -}; - -static const struct hda_verb cxt5045_mic_sense_init_verbs[] = { - /* pin sensing on HP jack */ - {0x12, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT}, - { } /* end */ -}; - -#ifdef CONFIG_SND_DEBUG -/* Test configuration for debugging, modelled after the ALC260 test - * configuration. - */ -static const struct hda_input_mux cxt5045_test_capture_source = { - .num_items = 5, - .items = { - { "MIXER", 0x0 }, - { "MIC1 pin", 0x1 }, - { "LINE1 pin", 0x2 }, - { "HP-OUT pin", 0x3 }, - { "CD pin", 0x4 }, - }, -}; - -static const struct snd_kcontrol_new cxt5045_test_mixer[] = { - - /* Output controls */ - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x10, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Speaker Playback Switch", 0x10, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("HP-OUT Playback Volume", 0x11, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("HP-OUT Playback Switch", 0x11, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("LINE1 Playback Volume", 0x12, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("LINE1 Playback Switch", 0x12, 0x0, HDA_OUTPUT), - - /* Modes for retasking pin widgets */ - CXT_PIN_MODE("HP-OUT pin mode", 0x11, CXT_PIN_DIR_INOUT), - CXT_PIN_MODE("LINE1 pin mode", 0x12, CXT_PIN_DIR_INOUT), - - /* EAPD Switch Control */ - CXT_EAPD_SWITCH("External Amplifier", 0x10, 0x0), - - /* Loopback mixer controls */ - - HDA_CODEC_VOLUME("PCM Volume", 0x17, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("PCM Switch", 0x17, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("MIC1 pin Volume", 0x17, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("MIC1 pin Switch", 0x17, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("LINE1 pin Volume", 0x17, 0x2, HDA_INPUT), - HDA_CODEC_MUTE("LINE1 pin Switch", 0x17, 0x2, HDA_INPUT), - HDA_CODEC_VOLUME("HP-OUT pin Volume", 0x17, 0x3, HDA_INPUT), - HDA_CODEC_MUTE("HP-OUT pin Switch", 0x17, 0x3, HDA_INPUT), - HDA_CODEC_VOLUME("CD pin Volume", 0x17, 0x4, HDA_INPUT), - HDA_CODEC_MUTE("CD pin Switch", 0x17, 0x4, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Input Source", - .info = conexant_mux_enum_info, - .get = conexant_mux_enum_get, - .put = conexant_mux_enum_put, - }, - /* Audio input controls */ - HDA_CODEC_VOLUME("Capture Volume", 0x1a, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x1a, 0x0, HDA_INPUT), - { } /* end */ -}; - -static const struct hda_verb cxt5045_test_init_verbs[] = { - /* Set connections */ - { 0x10, AC_VERB_SET_CONNECT_SEL, 0x0 }, - { 0x11, AC_VERB_SET_CONNECT_SEL, 0x0 }, - { 0x12, AC_VERB_SET_CONNECT_SEL, 0x0 }, - /* Enable retasking pins as output, initially without power amp */ - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - - /* Disable digital (SPDIF) pins initially, but users can enable - * them via a mixer switch. In the case of SPDIF-out, this initverb - * payload also sets the generation to 0, output to be in "consumer" - * PCM format, copyright asserted, no pre-emphasis and no validity - * control. - */ - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x18, AC_VERB_SET_DIGI_CONVERT_1, 0}, - - /* Unmute retasking pin widget output buffers since the default - * state appears to be output. As the pin mode is changed by the - * user the pin mode control will take care of enabling the pin's - * input/output buffers as needed. - */ - {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* Mute capture amp left and right */ - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - - /* Set ADC connection select to match default mixer setting (mic1 - * pin) - */ - {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, - {0x17, AC_VERB_SET_CONNECT_SEL, 0x01}, - - /* Mute all inputs to mixer widget (even unconnected ones) */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* Mixer */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* Mic1 pin */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* Line pin */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* HP pin */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */ - - { } -}; -#endif - - -/* initialize jack-sensing, too */ -static int cxt5045_init(struct hda_codec *codec) -{ - conexant_init(codec); - cxt5045_hp_automute(codec); - return 0; -} - - -enum { - CXT5045_LAPTOP_HPSENSE, - CXT5045_LAPTOP_MICSENSE, - CXT5045_LAPTOP_HPMICSENSE, - CXT5045_BENQ, -#ifdef CONFIG_SND_DEBUG - CXT5045_TEST, -#endif - CXT5045_AUTO, - CXT5045_MODELS -}; - -static const char * const cxt5045_models[CXT5045_MODELS] = { - [CXT5045_LAPTOP_HPSENSE] = "laptop-hpsense", - [CXT5045_LAPTOP_MICSENSE] = "laptop-micsense", - [CXT5045_LAPTOP_HPMICSENSE] = "laptop-hpmicsense", - [CXT5045_BENQ] = "benq", -#ifdef CONFIG_SND_DEBUG - [CXT5045_TEST] = "test", -#endif - [CXT5045_AUTO] = "auto", -}; - -static const struct snd_pci_quirk cxt5045_cfg_tbl[] = { - SND_PCI_QUIRK(0x152d, 0x0753, "Benq R55E", CXT5045_BENQ), - SND_PCI_QUIRK(0x1734, 0x10ad, "Fujitsu Si1520", CXT5045_LAPTOP_MICSENSE), - SND_PCI_QUIRK(0x1734, 0x10cb, "Fujitsu Si3515", CXT5045_LAPTOP_HPMICSENSE), - SND_PCI_QUIRK(0x1734, 0x110e, "Fujitsu V5505", - CXT5045_LAPTOP_HPMICSENSE), - SND_PCI_QUIRK(0x1509, 0x1e40, "FIC", CXT5045_LAPTOP_HPMICSENSE), - SND_PCI_QUIRK(0x1509, 0x2f05, "FIC", CXT5045_LAPTOP_HPMICSENSE), - SND_PCI_QUIRK(0x1509, 0x2f06, "FIC", CXT5045_LAPTOP_HPMICSENSE), - SND_PCI_QUIRK_MASK(0x1631, 0xff00, 0xc100, "Packard Bell", - CXT5045_LAPTOP_HPMICSENSE), - SND_PCI_QUIRK(0x8086, 0x2111, "Conexant Reference board", CXT5045_LAPTOP_HPSENSE), - {} -}; - -static int patch_cxt5045(struct hda_codec *codec) -{ - struct conexant_spec *spec; - int board_config; - - board_config = snd_hda_check_board_config(codec, CXT5045_MODELS, - cxt5045_models, - cxt5045_cfg_tbl); - if (board_config < 0) - board_config = CXT5045_AUTO; /* model=auto as default */ - if (board_config == CXT5045_AUTO) - return patch_conexant_auto(codec); - - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (!spec) - return -ENOMEM; - codec->spec = spec; - codec->single_adc_amp = 1; - - spec->multiout.max_channels = 2; - spec->multiout.num_dacs = ARRAY_SIZE(cxt5045_dac_nids); - spec->multiout.dac_nids = cxt5045_dac_nids; - spec->multiout.dig_out_nid = CXT5045_SPDIF_OUT; - spec->num_adc_nids = 1; - spec->adc_nids = cxt5045_adc_nids; - spec->capsrc_nids = cxt5045_capsrc_nids; - spec->input_mux = &cxt5045_capture_source; - spec->num_mixers = 1; - spec->mixers[0] = cxt5045_mixers; - spec->num_init_verbs = 1; - spec->init_verbs[0] = cxt5045_init_verbs; - spec->spdif_route = 0; - spec->num_channel_mode = ARRAY_SIZE(cxt5045_modes); - spec->channel_mode = cxt5045_modes; - - set_beep_amp(spec, 0x16, 0, 1); - - codec->patch_ops = conexant_patch_ops; - - switch (board_config) { - case CXT5045_LAPTOP_HPSENSE: - codec->patch_ops.unsol_event = cxt5045_hp_unsol_event; - spec->input_mux = &cxt5045_capture_source; - spec->num_init_verbs = 2; - spec->init_verbs[1] = cxt5045_hp_sense_init_verbs; - spec->mixers[0] = cxt5045_mixers; - codec->patch_ops.init = cxt5045_init; - break; - case CXT5045_LAPTOP_MICSENSE: - codec->patch_ops.unsol_event = cxt5045_hp_unsol_event; - spec->input_mux = &cxt5045_capture_source; - spec->num_init_verbs = 2; - spec->init_verbs[1] = cxt5045_mic_sense_init_verbs; - spec->mixers[0] = cxt5045_mixers; - codec->patch_ops.init = cxt5045_init; - break; - default: - case CXT5045_LAPTOP_HPMICSENSE: - codec->patch_ops.unsol_event = cxt5045_hp_unsol_event; - spec->input_mux = &cxt5045_capture_source; - spec->num_init_verbs = 3; - spec->init_verbs[1] = cxt5045_hp_sense_init_verbs; - spec->init_verbs[2] = cxt5045_mic_sense_init_verbs; - spec->mixers[0] = cxt5045_mixers; - codec->patch_ops.init = cxt5045_init; - break; - case CXT5045_BENQ: - codec->patch_ops.unsol_event = cxt5045_hp_unsol_event; - spec->input_mux = &cxt5045_capture_source_benq; - spec->num_init_verbs = 1; - spec->init_verbs[0] = cxt5045_benq_init_verbs; - spec->mixers[0] = cxt5045_mixers; - spec->mixers[1] = cxt5045_benq_mixers; - spec->num_mixers = 2; - codec->patch_ops.init = cxt5045_init; - break; -#ifdef CONFIG_SND_DEBUG - case CXT5045_TEST: - spec->input_mux = &cxt5045_test_capture_source; - spec->mixers[0] = cxt5045_test_mixer; - spec->init_verbs[0] = cxt5045_test_init_verbs; - break; - -#endif - } - - switch (codec->subsystem_id >> 16) { - case 0x103c: - 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) | - (0x14 << AC_AMPCAP_NUM_STEPS_SHIFT) | - (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) | - (1 << AC_AMPCAP_MUTE_SHIFT)); - break; - } - - if (spec->beep_amp) - snd_hda_attach_beep_device(codec, get_amp_nid_(spec->beep_amp)); - - return 0; -} - - -/* Conexant 5047 specific */ -#define CXT5047_SPDIF_OUT 0x11 - -static const hda_nid_t cxt5047_dac_nids[1] = { 0x10 }; /* 0x1c */ -static const hda_nid_t cxt5047_adc_nids[1] = { 0x12 }; -static const hda_nid_t cxt5047_capsrc_nids[1] = { 0x1a }; - -static const struct hda_channel_mode cxt5047_modes[1] = { - { 2, NULL }, -}; - -static const struct hda_input_mux cxt5047_toshiba_capture_source = { - .num_items = 2, - .items = { - { "ExtMic", 0x2 }, - { "Line-In", 0x1 }, - } -}; - -/* turn on/off EAPD (+ mute HP) as a master switch */ -static int cxt5047_hp_master_sw_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct conexant_spec *spec = codec->spec; - unsigned int bits; - - if (!cxt_eapd_put(kcontrol, ucontrol)) - return 0; - - /* toggle internal speakers mute depending of presence of - * the headphone jack - */ - bits = (!spec->hp_present && spec->cur_eapd) ? 0 : HDA_AMP_MUTE; - /* NOTE: Conexat codec needs the index for *OUTPUT* amp of - * pin widgets unlike other codecs. In this case, we need to - * set index 0x01 for the volume from the mixer amp 0x19. - */ - snd_hda_codec_amp_stereo(codec, 0x1d, HDA_OUTPUT, 0x01, - HDA_AMP_MUTE, bits); - bits = spec->cur_eapd ? 0 : HDA_AMP_MUTE; - snd_hda_codec_amp_stereo(codec, 0x13, HDA_OUTPUT, 0, - HDA_AMP_MUTE, bits); - return 1; -} - -/* mute internal speaker if HP is plugged */ -static void cxt5047_hp_automute(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - unsigned int bits; - - spec->hp_present = snd_hda_jack_detect(codec, 0x13); - - bits = (spec->hp_present || !spec->cur_eapd) ? HDA_AMP_MUTE : 0; - /* See the note in cxt5047_hp_master_sw_put */ - snd_hda_codec_amp_stereo(codec, 0x1d, HDA_OUTPUT, 0x01, - HDA_AMP_MUTE, bits); -} - -/* toggle input of built-in and mic jack appropriately */ -static void cxt5047_hp_automic(struct hda_codec *codec) -{ - static const struct hda_verb mic_jack_on[] = { - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {} - }; - static const struct hda_verb mic_jack_off[] = { - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {} - }; - unsigned int present; - - present = snd_hda_jack_detect(codec, 0x15); - if (present) - snd_hda_sequence_write(codec, mic_jack_on); - else - snd_hda_sequence_write(codec, mic_jack_off); -} - -/* unsolicited event for HP jack sensing */ -static void cxt5047_hp_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - switch (res >> 26) { - case CONEXANT_HP_EVENT: - cxt5047_hp_automute(codec); - break; - case CONEXANT_MIC_EVENT: - cxt5047_hp_automic(codec); - break; - } -} - -static const struct snd_kcontrol_new cxt5047_base_mixers[] = { - HDA_CODEC_VOLUME("Mic Playback Volume", 0x19, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x19, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x1a, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x03, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x12, 0x03, HDA_INPUT), - HDA_CODEC_VOLUME("PCM Volume", 0x10, 0x00, HDA_OUTPUT), - HDA_CODEC_MUTE("PCM Switch", 0x10, 0x00, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .info = cxt_eapd_info, - .get = cxt_eapd_get, - .put = cxt5047_hp_master_sw_put, - .private_value = 0x13, - }, - - {} -}; - -static const struct snd_kcontrol_new cxt5047_hp_spk_mixers[] = { - /* See the note in cxt5047_hp_master_sw_put */ - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x1d, 0x01, HDA_OUTPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x13, 0x00, HDA_OUTPUT), - {} -}; - -static const struct snd_kcontrol_new cxt5047_hp_only_mixers[] = { - HDA_CODEC_VOLUME("Master Playback Volume", 0x13, 0x00, HDA_OUTPUT), - { } /* end */ -}; - -static const struct hda_verb cxt5047_init_verbs[] = { - /* Line in, Mic, Built-in Mic */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_50 }, - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_50 }, - /* HP, Speaker */ - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, - {0x13, AC_VERB_SET_CONNECT_SEL, 0x0}, /* mixer(0x19) */ - {0x1d, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mixer(0x19) */ - /* Record selector: Mic */ - {0x12, AC_VERB_SET_CONNECT_SEL,0x03}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, - AC_AMP_SET_INPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x17}, - {0x1A, AC_VERB_SET_CONNECT_SEL,0x02}, - {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, - AC_AMP_SET_OUTPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x00}, - {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, - AC_AMP_SET_OUTPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x03}, - /* SPDIF route: PCM */ - { 0x18, AC_VERB_SET_CONNECT_SEL, 0x0 }, - /* Enable unsolicited events */ - {0x13, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT}, - { } /* end */ -}; - -/* configuration for Toshiba Laptops */ -static const struct hda_verb cxt5047_toshiba_init_verbs[] = { - {0x13, AC_VERB_SET_EAPD_BTLENABLE, 0x0}, /* default off */ - {} -}; - -/* Test configuration for debugging, modelled after the ALC260 test - * configuration. - */ -#ifdef CONFIG_SND_DEBUG -static const struct hda_input_mux cxt5047_test_capture_source = { - .num_items = 4, - .items = { - { "LINE1 pin", 0x0 }, - { "MIC1 pin", 0x1 }, - { "MIC2 pin", 0x2 }, - { "CD pin", 0x3 }, - }, -}; - -static const struct snd_kcontrol_new cxt5047_test_mixer[] = { - - /* Output only controls */ - HDA_CODEC_VOLUME("OutAmp-1 Volume", 0x10, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("OutAmp-1 Switch", 0x10,0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("OutAmp-2 Volume", 0x1c, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("OutAmp-2 Switch", 0x1c, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x1d, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Speaker Playback Switch", 0x1d, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("HeadPhone Playback Volume", 0x13, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("HeadPhone Playback Switch", 0x13, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Line1-Out Playback Volume", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Line1-Out Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Line2-Out Playback Volume", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Line2-Out Playback Switch", 0x15, 0x0, HDA_OUTPUT), - - /* Modes for retasking pin widgets */ - CXT_PIN_MODE("LINE1 pin mode", 0x14, CXT_PIN_DIR_INOUT), - CXT_PIN_MODE("MIC1 pin mode", 0x15, CXT_PIN_DIR_INOUT), - - /* EAPD Switch Control */ - CXT_EAPD_SWITCH("External Amplifier", 0x13, 0x0), - - /* Loopback mixer controls */ - HDA_CODEC_VOLUME("MIC1 Playback Volume", 0x12, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("MIC1 Playback Switch", 0x12, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("MIC2 Playback Volume", 0x12, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("MIC2 Playback Switch", 0x12, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("LINE Playback Volume", 0x12, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("LINE Playback Switch", 0x12, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x12, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x12, 0x04, HDA_INPUT), - - HDA_CODEC_VOLUME("Capture-1 Volume", 0x19, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture-1 Switch", 0x19, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Capture-2 Volume", 0x19, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Capture-2 Switch", 0x19, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Capture-3 Volume", 0x19, 0x2, HDA_INPUT), - HDA_CODEC_MUTE("Capture-3 Switch", 0x19, 0x2, HDA_INPUT), - HDA_CODEC_VOLUME("Capture-4 Volume", 0x19, 0x3, HDA_INPUT), - HDA_CODEC_MUTE("Capture-4 Switch", 0x19, 0x3, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Input Source", - .info = conexant_mux_enum_info, - .get = conexant_mux_enum_get, - .put = conexant_mux_enum_put, - }, - HDA_CODEC_VOLUME("Mic Boost Volume", 0x1a, 0x0, HDA_OUTPUT), - - { } /* end */ -}; - -static const struct hda_verb cxt5047_test_init_verbs[] = { - /* Enable retasking pins as output, initially without power amp */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - - /* Disable digital (SPDIF) pins initially, but users can enable - * them via a mixer switch. In the case of SPDIF-out, this initverb - * payload also sets the generation to 0, output to be in "consumer" - * PCM format, copyright asserted, no pre-emphasis and no validity - * control. - */ - {0x18, AC_VERB_SET_DIGI_CONVERT_1, 0}, - - /* Ensure mic1, mic2, line1 pin widgets take input from the - * OUT1 sum bus when acting as an output. - */ - {0x1a, AC_VERB_SET_CONNECT_SEL, 0}, - {0x1b, AC_VERB_SET_CONNECT_SEL, 0}, - - /* Start with output sum widgets muted and their output gains at min */ - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - - /* Unmute retasking pin widget output buffers since the default - * state appears to be output. As the pin mode is changed by the - * user the pin mode control will take care of enabling the pin's - * input/output buffers as needed. - */ - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* Mute capture amp left and right */ - {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - - /* Set ADC connection select to match default mixer setting (mic1 - * pin) - */ - {0x12, AC_VERB_SET_CONNECT_SEL, 0x00}, - - /* Mute all inputs to mixer widget (even unconnected ones) */ - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */ - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */ - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */ - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */ - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */ - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */ - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */ - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */ - - { } -}; -#endif - - -/* initialize jack-sensing, too */ -static int cxt5047_hp_init(struct hda_codec *codec) -{ - conexant_init(codec); - cxt5047_hp_automute(codec); - return 0; -} - - -enum { - CXT5047_LAPTOP, /* Laptops w/o EAPD support */ - CXT5047_LAPTOP_HP, /* Some HP laptops */ - CXT5047_LAPTOP_EAPD, /* Laptops with EAPD support */ -#ifdef CONFIG_SND_DEBUG - CXT5047_TEST, -#endif - CXT5047_AUTO, - CXT5047_MODELS -}; - -static const char * const cxt5047_models[CXT5047_MODELS] = { - [CXT5047_LAPTOP] = "laptop", - [CXT5047_LAPTOP_HP] = "laptop-hp", - [CXT5047_LAPTOP_EAPD] = "laptop-eapd", -#ifdef CONFIG_SND_DEBUG - [CXT5047_TEST] = "test", -#endif - [CXT5047_AUTO] = "auto", -}; - -static const struct snd_pci_quirk cxt5047_cfg_tbl[] = { - SND_PCI_QUIRK(0x103c, 0x30a5, "HP DV5200T/DV8000T", CXT5047_LAPTOP_HP), - SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3000, "HP DV Series", - CXT5047_LAPTOP), - SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba P100", CXT5047_LAPTOP_EAPD), - {} -}; - -static int patch_cxt5047(struct hda_codec *codec) -{ - struct conexant_spec *spec; - int board_config; - - board_config = snd_hda_check_board_config(codec, CXT5047_MODELS, - cxt5047_models, - cxt5047_cfg_tbl); - if (board_config < 0) - board_config = CXT5047_AUTO; /* model=auto as default */ - if (board_config == CXT5047_AUTO) - return patch_conexant_auto(codec); - - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (!spec) - return -ENOMEM; - codec->spec = spec; - codec->pin_amp_workaround = 1; - - spec->multiout.max_channels = 2; - spec->multiout.num_dacs = ARRAY_SIZE(cxt5047_dac_nids); - spec->multiout.dac_nids = cxt5047_dac_nids; - spec->multiout.dig_out_nid = CXT5047_SPDIF_OUT; - spec->num_adc_nids = 1; - spec->adc_nids = cxt5047_adc_nids; - spec->capsrc_nids = cxt5047_capsrc_nids; - spec->num_mixers = 1; - spec->mixers[0] = cxt5047_base_mixers; - spec->num_init_verbs = 1; - spec->init_verbs[0] = cxt5047_init_verbs; - spec->spdif_route = 0; - spec->num_channel_mode = ARRAY_SIZE(cxt5047_modes), - spec->channel_mode = cxt5047_modes, - - codec->patch_ops = conexant_patch_ops; - - switch (board_config) { - case CXT5047_LAPTOP: - spec->num_mixers = 2; - spec->mixers[1] = cxt5047_hp_spk_mixers; - codec->patch_ops.unsol_event = cxt5047_hp_unsol_event; - break; - case CXT5047_LAPTOP_HP: - spec->num_mixers = 2; - spec->mixers[1] = cxt5047_hp_only_mixers; - codec->patch_ops.unsol_event = cxt5047_hp_unsol_event; - codec->patch_ops.init = cxt5047_hp_init; - break; - case CXT5047_LAPTOP_EAPD: - spec->input_mux = &cxt5047_toshiba_capture_source; - spec->num_mixers = 2; - spec->mixers[1] = cxt5047_hp_spk_mixers; - spec->num_init_verbs = 2; - spec->init_verbs[1] = cxt5047_toshiba_init_verbs; - codec->patch_ops.unsol_event = cxt5047_hp_unsol_event; - break; -#ifdef CONFIG_SND_DEBUG - case CXT5047_TEST: - spec->input_mux = &cxt5047_test_capture_source; - spec->mixers[0] = cxt5047_test_mixer; - spec->init_verbs[0] = cxt5047_test_init_verbs; - codec->patch_ops.unsol_event = cxt5047_hp_unsol_event; -#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; -} - -/* Conexant 5051 specific */ -static const hda_nid_t cxt5051_dac_nids[1] = { 0x10 }; -static const hda_nid_t cxt5051_adc_nids[2] = { 0x14, 0x15 }; - -static const struct hda_channel_mode cxt5051_modes[1] = { - { 2, NULL }, -}; - -static void cxt5051_update_speaker(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - unsigned int pinctl; - /* headphone pin */ - pinctl = (spec->hp_present && spec->cur_eapd) ? PIN_HP : 0; - snd_hda_set_pin_ctl(codec, 0x16, pinctl); - /* speaker pin */ - pinctl = (!spec->hp_present && spec->cur_eapd) ? PIN_OUT : 0; - snd_hda_set_pin_ctl(codec, 0x1a, pinctl); - /* on ideapad there is an additional speaker (subwoofer) to mute */ - if (spec->ideapad) - snd_hda_set_pin_ctl(codec, 0x1b, pinctl); -} - -/* turn on/off EAPD (+ mute HP) as a master switch */ -static int cxt5051_hp_master_sw_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - - if (!cxt_eapd_put(kcontrol, ucontrol)) - return 0; - cxt5051_update_speaker(codec); - return 1; -} - -/* toggle input of built-in and mic jack appropriately */ -static void cxt5051_portb_automic(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - unsigned int present; - - if (!(spec->auto_mic & AUTO_MIC_PORTB)) - return; - present = snd_hda_jack_detect(codec, 0x17); - snd_hda_codec_write(codec, 0x14, 0, - AC_VERB_SET_CONNECT_SEL, - present ? 0x01 : 0x00); -} - -/* switch the current ADC according to the jack state */ -static void cxt5051_portc_automic(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - unsigned int present; - hda_nid_t new_adc; - - if (!(spec->auto_mic & AUTO_MIC_PORTC)) - return; - present = snd_hda_jack_detect(codec, 0x18); - if (present) - spec->cur_adc_idx = 1; - else - spec->cur_adc_idx = 0; - new_adc = spec->adc_nids[spec->cur_adc_idx]; - if (spec->cur_adc && spec->cur_adc != new_adc) { - /* stream is running, let's swap the current ADC */ - __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1); - spec->cur_adc = new_adc; - snd_hda_codec_setup_stream(codec, new_adc, - spec->cur_adc_stream_tag, 0, - spec->cur_adc_format); - } -} - -/* mute internal speaker if HP is plugged */ -static void cxt5051_hp_automute(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - - spec->hp_present = snd_hda_jack_detect(codec, 0x16); - cxt5051_update_speaker(codec); -} - -/* unsolicited event for HP jack sensing */ -static void cxt5051_hp_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - switch (res >> 26) { - case CONEXANT_HP_EVENT: - cxt5051_hp_automute(codec); - break; - case CXT5051_PORTB_EVENT: - cxt5051_portb_automic(codec); - break; - case CXT5051_PORTC_EVENT: - cxt5051_portc_automic(codec); - break; - } -} - -static const struct snd_kcontrol_new cxt5051_playback_mixers[] = { - HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .info = cxt_eapd_info, - .get = cxt_eapd_get, - .put = cxt5051_hp_master_sw_put, - .private_value = 0x1a, - }, - {} -}; - -static const struct snd_kcontrol_new cxt5051_capture_mixers[] = { - HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Volume", 0x14, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Mic Switch", 0x14, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("Dock Mic Volume", 0x15, 0x00, HDA_INPUT), - HDA_CODEC_MUTE("Dock Mic Switch", 0x15, 0x00, HDA_INPUT), - {} -}; - -static const struct snd_kcontrol_new cxt5051_hp_mixers[] = { - HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Volume", 0x15, 0x00, HDA_INPUT), - HDA_CODEC_MUTE("Mic Switch", 0x15, 0x00, HDA_INPUT), - {} -}; - -static const struct snd_kcontrol_new cxt5051_hp_dv6736_mixers[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x00, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x14, 0x00, HDA_INPUT), - {} -}; - -static const struct snd_kcontrol_new cxt5051_f700_mixers[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x14, 0x01, HDA_INPUT), - {} -}; - -static const struct snd_kcontrol_new cxt5051_toshiba_mixers[] = { - HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Volume", 0x14, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Mic Switch", 0x14, 0x01, HDA_INPUT), - {} -}; - -static const struct hda_verb cxt5051_init_verbs[] = { - /* Line in, Mic */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, - /* SPK */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* HP, Amp */ - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* DAC1 */ - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Record selector: Internal mic */ - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44}, - /* SPDIF route: PCM */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x1c, AC_VERB_SET_CONNECT_SEL, 0x0}, - /* EAPD */ - {0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ - {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT}, - { } /* end */ -}; - -static const struct hda_verb cxt5051_hp_dv6736_init_verbs[] = { - /* Line in, Mic */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0}, - {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0}, - /* SPK */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* HP, Amp */ - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* DAC1 */ - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Record selector: Internal mic */ - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44}, - {0x14, AC_VERB_SET_CONNECT_SEL, 0x1}, - /* SPDIF route: PCM */ - {0x1c, AC_VERB_SET_CONNECT_SEL, 0x0}, - /* EAPD */ - {0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ - {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT}, - { } /* end */ -}; - -static const struct hda_verb cxt5051_f700_init_verbs[] = { - /* Line in, Mic */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0}, - {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0}, - /* SPK */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* HP, Amp */ - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* DAC1 */ - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Record selector: Internal mic */ - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44}, - {0x14, AC_VERB_SET_CONNECT_SEL, 0x1}, - /* SPDIF route: PCM */ - {0x1c, AC_VERB_SET_CONNECT_SEL, 0x0}, - /* EAPD */ - {0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ - {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT}, - { } /* end */ -}; - -static void cxt5051_init_mic_port(struct hda_codec *codec, hda_nid_t nid, - unsigned int event) -{ - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_UNSOLICITED_ENABLE, - AC_USRSP_EN | event); -} - -static const struct hda_verb cxt5051_ideapad_init_verbs[] = { - /* Subwoofer */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, - { } /* end */ -}; - -/* initialize jack-sensing, too */ -static int cxt5051_init(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - - conexant_init(codec); - - if (spec->auto_mic & AUTO_MIC_PORTB) - cxt5051_init_mic_port(codec, 0x17, CXT5051_PORTB_EVENT); - if (spec->auto_mic & AUTO_MIC_PORTC) - cxt5051_init_mic_port(codec, 0x18, CXT5051_PORTC_EVENT); - - if (codec->patch_ops.unsol_event) { - cxt5051_hp_automute(codec); - cxt5051_portb_automic(codec); - cxt5051_portc_automic(codec); - } - return 0; -} - - -enum { - CXT5051_LAPTOP, /* Laptops w/ EAPD support */ - CXT5051_HP, /* no docking */ - CXT5051_HP_DV6736, /* HP without mic switch */ - CXT5051_F700, /* HP Compaq Presario F700 */ - CXT5051_TOSHIBA, /* Toshiba M300 & co */ - CXT5051_IDEAPAD, /* Lenovo IdeaPad Y430 */ - CXT5051_AUTO, /* auto-parser */ - CXT5051_MODELS -}; - -static const char *const cxt5051_models[CXT5051_MODELS] = { - [CXT5051_LAPTOP] = "laptop", - [CXT5051_HP] = "hp", - [CXT5051_HP_DV6736] = "hp-dv6736", - [CXT5051_F700] = "hp-700", - [CXT5051_TOSHIBA] = "toshiba", - [CXT5051_IDEAPAD] = "ideapad", - [CXT5051_AUTO] = "auto", -}; - -static const struct snd_pci_quirk cxt5051_cfg_tbl[] = { - SND_PCI_QUIRK(0x103c, 0x30cf, "HP DV6736", CXT5051_HP_DV6736), - SND_PCI_QUIRK(0x103c, 0x360b, "Compaq Presario CQ60", CXT5051_HP), - SND_PCI_QUIRK(0x103c, 0x30ea, "Compaq Presario F700", CXT5051_F700), - SND_PCI_QUIRK(0x1179, 0xff50, "Toshiba M30x", CXT5051_TOSHIBA), - SND_PCI_QUIRK(0x14f1, 0x0101, "Conexant Reference board", - CXT5051_LAPTOP), - SND_PCI_QUIRK(0x14f1, 0x5051, "HP Spartan 1.1", CXT5051_HP), - SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo IdeaPad", CXT5051_IDEAPAD), - {} -}; - -static int patch_cxt5051(struct hda_codec *codec) -{ - struct conexant_spec *spec; - int board_config; - - board_config = snd_hda_check_board_config(codec, CXT5051_MODELS, - cxt5051_models, - cxt5051_cfg_tbl); - if (board_config < 0) - board_config = CXT5051_AUTO; /* model=auto as default */ - if (board_config == CXT5051_AUTO) - return patch_conexant_auto(codec); - - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (!spec) - return -ENOMEM; - codec->spec = spec; - codec->pin_amp_workaround = 1; - - codec->patch_ops = conexant_patch_ops; - codec->patch_ops.init = cxt5051_init; - - spec->multiout.max_channels = 2; - spec->multiout.num_dacs = ARRAY_SIZE(cxt5051_dac_nids); - spec->multiout.dac_nids = cxt5051_dac_nids; - spec->multiout.dig_out_nid = CXT5051_SPDIF_OUT; - spec->num_adc_nids = 1; /* not 2; via auto-mic switch */ - spec->adc_nids = cxt5051_adc_nids; - spec->num_mixers = 2; - spec->mixers[0] = cxt5051_capture_mixers; - spec->mixers[1] = cxt5051_playback_mixers; - spec->num_init_verbs = 1; - spec->init_verbs[0] = cxt5051_init_verbs; - spec->spdif_route = 0; - spec->num_channel_mode = ARRAY_SIZE(cxt5051_modes); - spec->channel_mode = cxt5051_modes; - spec->cur_adc = 0; - spec->cur_adc_idx = 0; - - set_beep_amp(spec, 0x13, 0, HDA_OUTPUT); - - codec->patch_ops.unsol_event = cxt5051_hp_unsol_event; - - spec->auto_mic = AUTO_MIC_PORTB | AUTO_MIC_PORTC; - switch (board_config) { - case CXT5051_HP: - spec->mixers[0] = cxt5051_hp_mixers; - break; - case CXT5051_HP_DV6736: - spec->init_verbs[0] = cxt5051_hp_dv6736_init_verbs; - spec->mixers[0] = cxt5051_hp_dv6736_mixers; - spec->auto_mic = 0; - break; - case CXT5051_F700: - spec->init_verbs[0] = cxt5051_f700_init_verbs; - spec->mixers[0] = cxt5051_f700_mixers; - spec->auto_mic = 0; - break; - case CXT5051_TOSHIBA: - spec->mixers[0] = cxt5051_toshiba_mixers; - spec->auto_mic = AUTO_MIC_PORTB; - break; - case CXT5051_IDEAPAD: - spec->init_verbs[spec->num_init_verbs++] = - cxt5051_ideapad_init_verbs; - spec->ideapad = 1; - break; - } - - if (spec->beep_amp) - snd_hda_attach_beep_device(codec, get_amp_nid_(spec->beep_amp)); - - return 0; -} - -/* Conexant 5066 specific */ - -static const hda_nid_t cxt5066_dac_nids[1] = { 0x10 }; -static const hda_nid_t cxt5066_adc_nids[3] = { 0x14, 0x15, 0x16 }; -static const hda_nid_t cxt5066_capsrc_nids[1] = { 0x17 }; -static const hda_nid_t cxt5066_digout_pin_nids[2] = { 0x20, 0x22 }; - -static const struct hda_channel_mode cxt5066_modes[1] = { - { 2, NULL }, -}; - -#define HP_PRESENT_PORT_A (1 << 0) -#define HP_PRESENT_PORT_D (1 << 1) -#define hp_port_a_present(spec) ((spec)->hp_present & HP_PRESENT_PORT_A) -#define hp_port_d_present(spec) ((spec)->hp_present & HP_PRESENT_PORT_D) - -static void cxt5066_update_speaker(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - unsigned int pinctl; - - codec_dbg(codec, - "CXT5066: update speaker, hp_present=%d, cur_eapd=%d\n", - spec->hp_present, spec->cur_eapd); - - /* Port A (HP) */ - pinctl = (hp_port_a_present(spec) && spec->cur_eapd) ? PIN_HP : 0; - snd_hda_set_pin_ctl(codec, 0x19, pinctl); - - /* Port D (HP/LO) */ - pinctl = spec->cur_eapd ? spec->port_d_mode : 0; - if (spec->dell_automute || spec->thinkpad) { - /* Mute if Port A is connected */ - if (hp_port_a_present(spec)) - pinctl = 0; - } else { - /* Thinkpad/Dell doesn't give pin-D status */ - if (!hp_port_d_present(spec)) - pinctl = 0; - } - snd_hda_set_pin_ctl(codec, 0x1c, pinctl); - - /* CLASS_D AMP */ - pinctl = (!spec->hp_present && spec->cur_eapd) ? PIN_OUT : 0; - snd_hda_set_pin_ctl(codec, 0x1f, pinctl); -} - -/* turn on/off EAPD (+ mute HP) as a master switch */ -static int cxt5066_hp_master_sw_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - - if (!cxt_eapd_put(kcontrol, ucontrol)) - return 0; - - cxt5066_update_speaker(codec); - return 1; -} - -/* toggle input of built-in digital mic and mic jack appropriately */ -static void cxt5066_vostro_automic(struct hda_codec *codec) -{ - unsigned int present; - - struct hda_verb ext_mic_present[] = { - /* enable external mic, port B */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - - /* switch to external mic input */ - {0x17, AC_VERB_SET_CONNECT_SEL, 0}, - {0x14, AC_VERB_SET_CONNECT_SEL, 0}, - - /* disable internal digital mic */ - {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {} - }; - static const struct hda_verb ext_mic_absent[] = { - /* enable internal mic, port C */ - {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - - /* switch to internal mic input */ - {0x14, AC_VERB_SET_CONNECT_SEL, 2}, - - /* disable external mic, port B */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {} - }; - - present = snd_hda_jack_detect(codec, 0x1a); - if (present) { - codec_dbg(codec, "CXT5066: external microphone detected\n"); - snd_hda_sequence_write(codec, ext_mic_present); - } else { - codec_dbg(codec, "CXT5066: external microphone absent\n"); - snd_hda_sequence_write(codec, ext_mic_absent); - } -} - -/* toggle input of built-in digital mic and mic jack appropriately */ -static void cxt5066_ideapad_automic(struct hda_codec *codec) -{ - unsigned int present; - - struct hda_verb ext_mic_present[] = { - {0x14, AC_VERB_SET_CONNECT_SEL, 0}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {} - }; - static const struct hda_verb ext_mic_absent[] = { - {0x14, AC_VERB_SET_CONNECT_SEL, 2}, - {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {} - }; - - present = snd_hda_jack_detect(codec, 0x1b); - if (present) { - codec_dbg(codec, "CXT5066: external microphone detected\n"); - snd_hda_sequence_write(codec, ext_mic_present); - } else { - codec_dbg(codec, "CXT5066: external microphone absent\n"); - snd_hda_sequence_write(codec, ext_mic_absent); - } -} - - -/* toggle input of built-in digital mic and mic jack appropriately */ -static void cxt5066_asus_automic(struct hda_codec *codec) -{ - unsigned int present; - - present = snd_hda_jack_detect(codec, 0x1b); - codec_dbg(codec, "CXT5066: external microphone present=%d\n", present); - snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_CONNECT_SEL, - present ? 1 : 0); -} - - -/* toggle input of built-in digital mic and mic jack appropriately */ -static void cxt5066_hp_laptop_automic(struct hda_codec *codec) -{ - unsigned int present; - - present = snd_hda_jack_detect(codec, 0x1b); - codec_dbg(codec, "CXT5066: external microphone present=%d\n", present); - snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_CONNECT_SEL, - present ? 1 : 3); -} - - -/* toggle input of built-in digital mic and mic jack appropriately - order is: external mic -> dock mic -> interal mic */ -static void cxt5066_thinkpad_automic(struct hda_codec *codec) -{ - unsigned int ext_present, dock_present; - - static const struct hda_verb ext_mic_present[] = { - {0x14, AC_VERB_SET_CONNECT_SEL, 0}, - {0x17, AC_VERB_SET_CONNECT_SEL, 1}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {} - }; - static const struct hda_verb dock_mic_present[] = { - {0x14, AC_VERB_SET_CONNECT_SEL, 0}, - {0x17, AC_VERB_SET_CONNECT_SEL, 0}, - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {} - }; - static const struct hda_verb ext_mic_absent[] = { - {0x14, AC_VERB_SET_CONNECT_SEL, 2}, - {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {} - }; - - ext_present = snd_hda_jack_detect(codec, 0x1b); - dock_present = snd_hda_jack_detect(codec, 0x1a); - if (ext_present) { - codec_dbg(codec, "CXT5066: external microphone detected\n"); - snd_hda_sequence_write(codec, ext_mic_present); - } else if (dock_present) { - codec_dbg(codec, "CXT5066: dock microphone detected\n"); - snd_hda_sequence_write(codec, dock_mic_present); - } else { - codec_dbg(codec, "CXT5066: external microphone absent\n"); - snd_hda_sequence_write(codec, ext_mic_absent); - } -} - -/* mute internal speaker if HP is plugged */ -static void cxt5066_hp_automute(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - unsigned int portA, portD; - - /* Port A */ - portA = snd_hda_jack_detect(codec, 0x19); - - /* Port D */ - portD = snd_hda_jack_detect(codec, 0x1c); - - spec->hp_present = portA ? HP_PRESENT_PORT_A : 0; - spec->hp_present |= portD ? HP_PRESENT_PORT_D : 0; - codec_dbg(codec, "CXT5066: hp automute portA=%x portD=%x present=%d\n", - portA, portD, spec->hp_present); - cxt5066_update_speaker(codec); -} - -/* Dispatch the right mic autoswitch function */ -static void cxt5066_automic(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - - if (spec->dell_vostro) - cxt5066_vostro_automic(codec); - else if (spec->ideapad) - cxt5066_ideapad_automic(codec); - else if (spec->thinkpad) - cxt5066_thinkpad_automic(codec); - else if (spec->hp_laptop) - cxt5066_hp_laptop_automic(codec); - else if (spec->asus) - cxt5066_asus_automic(codec); -} - -/* unsolicited event for jack sensing */ -static void cxt5066_unsol_event(struct hda_codec *codec, unsigned int res) -{ - codec_dbg(codec, "CXT5066: unsol event %x (%x)\n", res, res >> 26); - switch (res >> 26) { - case CONEXANT_HP_EVENT: - cxt5066_hp_automute(codec); - break; - case CONEXANT_MIC_EVENT: - cxt5066_automic(codec); - break; - } -} - - -static const struct hda_input_mux cxt5066_analog_mic_boost = { - .num_items = 5, - .items = { - { "0dB", 0 }, - { "10dB", 1 }, - { "20dB", 2 }, - { "30dB", 3 }, - { "40dB", 4 }, - }, -}; - -static void cxt5066_set_mic_boost(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - snd_hda_codec_write_cache(codec, 0x17, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | AC_AMP_SET_OUTPUT | - cxt5066_analog_mic_boost.items[spec->mic_boost].index); - if (spec->ideapad || spec->thinkpad) { - /* adjust the internal mic as well...it is not through 0x17 */ - snd_hda_codec_write_cache(codec, 0x23, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | AC_AMP_SET_INPUT | - cxt5066_analog_mic_boost. - items[spec->mic_boost].index); - } -} - -static int cxt5066_mic_boost_mux_enum_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - return snd_hda_input_mux_info(&cxt5066_analog_mic_boost, uinfo); -} - -static int cxt5066_mic_boost_mux_enum_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct conexant_spec *spec = codec->spec; - ucontrol->value.enumerated.item[0] = spec->mic_boost; - return 0; -} - -static int cxt5066_mic_boost_mux_enum_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct conexant_spec *spec = codec->spec; - const struct hda_input_mux *imux = &cxt5066_analog_mic_boost; - unsigned int idx; - idx = ucontrol->value.enumerated.item[0]; - if (idx >= imux->num_items) - idx = imux->num_items - 1; - - spec->mic_boost = idx; - cxt5066_set_mic_boost(codec); - return 1; -} - -static void conexant_check_dig_outs(struct hda_codec *codec, - const hda_nid_t *dig_pins, - int num_pins) -{ - struct conexant_spec *spec = codec->spec; - hda_nid_t *nid_loc = &spec->multiout.dig_out_nid; - int i; - - for (i = 0; i < num_pins; i++, dig_pins++) { - unsigned int cfg = snd_hda_codec_get_pincfg(codec, *dig_pins); - if (get_defcfg_connect(cfg) == AC_JACK_PORT_NONE) - continue; - if (snd_hda_get_connections(codec, *dig_pins, nid_loc, 1) != 1) - continue; - } -} - -static const struct hda_input_mux cxt5066_capture_source = { - .num_items = 4, - .items = { - { "Mic B", 0 }, - { "Mic C", 1 }, - { "Mic E", 2 }, - { "Mic F", 3 }, - }, -}; - -static const struct hda_bind_ctls cxt5066_bind_capture_vol_others = { - .ops = &snd_hda_bind_vol, - .values = { - HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_INPUT), - HDA_COMPOSE_AMP_VAL(0x14, 3, 2, HDA_INPUT), - 0 - }, -}; - -static const struct hda_bind_ctls cxt5066_bind_capture_sw_others = { - .ops = &snd_hda_bind_sw, - .values = { - HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_INPUT), - HDA_COMPOSE_AMP_VAL(0x14, 3, 2, HDA_INPUT), - 0 - }, -}; - -static const struct snd_kcontrol_new cxt5066_mixer_master[] = { - HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT), - {} -}; - -static const struct snd_kcontrol_new cxt5066_mixers[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .info = cxt_eapd_info, - .get = cxt_eapd_get, - .put = cxt5066_hp_master_sw_put, - .private_value = 0x1d, - }, - - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Analog Mic Boost Capture Enum", - .info = cxt5066_mic_boost_mux_enum_info, - .get = cxt5066_mic_boost_mux_enum_get, - .put = cxt5066_mic_boost_mux_enum_put, - }, - - HDA_BIND_VOL("Capture Volume", &cxt5066_bind_capture_vol_others), - HDA_BIND_SW("Capture Switch", &cxt5066_bind_capture_sw_others), - {} -}; - -static const struct snd_kcontrol_new cxt5066_vostro_mixers[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Internal Mic Boost Capture Enum", - .info = cxt5066_mic_boost_mux_enum_info, - .get = cxt5066_mic_boost_mux_enum_get, - .put = cxt5066_mic_boost_mux_enum_put, - .private_value = 0x23 | 0x100, - }, - {} -}; - -static const struct hda_verb cxt5066_init_verbs[] = { - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port B */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port C */ - {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port F */ - {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port E */ - - /* Speakers */ - {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x1f, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ - - /* HP, Amp */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ - - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x1c, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ - - /* DAC1 */ - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* Node 14 connections: 0x17 0x18 0x23 0x24 0x27 */ - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x50}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2) | 0x50}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - - /* no digital microphone support yet */ - {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - - /* Audio input selector */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x3}, - - /* SPDIF route: PCM */ - {0x20, AC_VERB_SET_CONNECT_SEL, 0x0}, - {0x22, AC_VERB_SET_CONNECT_SEL, 0x0}, - - {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - - /* EAPD */ - {0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ - - /* not handling these yet */ - {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, 0}, - {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, 0}, - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, 0}, - {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, 0}, - {0x1d, AC_VERB_SET_UNSOLICITED_ENABLE, 0}, - {0x1e, AC_VERB_SET_UNSOLICITED_ENABLE, 0}, - {0x20, AC_VERB_SET_UNSOLICITED_ENABLE, 0}, - {0x22, AC_VERB_SET_UNSOLICITED_ENABLE, 0}, - { } /* end */ -}; - -static const struct hda_verb cxt5066_init_verbs_vostro[] = { - /* Port A: headphones */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ - - /* Port B: external microphone */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - - /* Port C: unused */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - - /* Port D: unused */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - - /* Port E: unused, but has primary EAPD */ - {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ - - /* Port F: unused */ - {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - - /* Port G: internal speakers */ - {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x1f, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ - - /* DAC1 */ - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* DAC2: unused */ - {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - - /* Digital microphone port */ - {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - - /* Audio input selectors */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x3}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - - /* Disable SPDIF */ - {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - - /* enable unsolicited events for Port A and B */ - {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, - {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT}, - { } /* end */ -}; - -static const struct hda_verb cxt5066_init_verbs_ideapad[] = { - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port B */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port C */ - {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port F */ - {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port E */ - - /* Speakers */ - {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x1f, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ - - /* HP, Amp */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ - - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x1c, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ - - /* DAC1 */ - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* Node 14 connections: 0x17 0x18 0x23 0x24 0x27 */ - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x50}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2) | 0x50}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - {0x14, AC_VERB_SET_CONNECT_SEL, 2}, /* default to internal mic */ - - /* Audio input selector */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x2}, - {0x17, AC_VERB_SET_CONNECT_SEL, 1}, /* route ext mic */ - - /* SPDIF route: PCM */ - {0x20, AC_VERB_SET_CONNECT_SEL, 0x0}, - {0x22, AC_VERB_SET_CONNECT_SEL, 0x0}, - - {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - - /* internal microphone */ - {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* enable internal mic */ - - /* EAPD */ - {0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ - - {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT}, - { } /* end */ -}; - -static const struct hda_verb cxt5066_init_verbs_thinkpad[] = { - {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port F */ - {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port E */ - - /* Port G: internal speakers */ - {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x1f, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ - - /* Port A: HP, Amp */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ - - /* Port B: Mic Dock */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - - /* Port C: Mic */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - - /* Port D: HP Dock, Amp */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x1c, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ - - /* DAC1 */ - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* Node 14 connections: 0x17 0x18 0x23 0x24 0x27 */ - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x50}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2) | 0x50}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - {0x14, AC_VERB_SET_CONNECT_SEL, 2}, /* default to internal mic */ - - /* Audio input selector */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x2}, - {0x17, AC_VERB_SET_CONNECT_SEL, 1}, /* route ext mic */ - - /* SPDIF route: PCM */ - {0x20, AC_VERB_SET_CONNECT_SEL, 0x0}, - {0x22, AC_VERB_SET_CONNECT_SEL, 0x0}, - - {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - - /* internal microphone */ - {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* enable internal mic */ - - /* EAPD */ - {0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ - - /* enable unsolicited events for Port A, B, C and D */ - {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, - {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, - {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT}, - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT}, - { } /* end */ -}; - -static const struct hda_verb cxt5066_init_verbs_portd_lo[] = { - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - { } /* end */ -}; - - -static const struct hda_verb cxt5066_init_verbs_hp_laptop[] = { - {0x14, AC_VERB_SET_CONNECT_SEL, 0x0}, - {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT}, - { } /* end */ -}; - -/* initialize jack-sensing, too */ -static int cxt5066_init(struct hda_codec *codec) -{ - codec_dbg(codec, "CXT5066: init\n"); - conexant_init(codec); - if (codec->patch_ops.unsol_event) { - cxt5066_hp_automute(codec); - cxt5066_automic(codec); - } - cxt5066_set_mic_boost(codec); - return 0; -} - -enum { - CXT5066_LAPTOP, /* Laptops w/ EAPD support */ - CXT5066_DELL_LAPTOP, /* Dell Laptop */ - CXT5066_DELL_VOSTRO, /* Dell Vostro 1015i */ - CXT5066_IDEAPAD, /* Lenovo IdeaPad U150 */ - CXT5066_THINKPAD, /* Lenovo ThinkPad T410s, others? */ - CXT5066_ASUS, /* Asus K52JU, Lenovo G560 - Int mic at 0x1a and Ext mic at 0x1b */ - CXT5066_HP_LAPTOP, /* HP Laptop */ - CXT5066_AUTO, /* BIOS auto-parser */ - CXT5066_MODELS -}; - -static const char * const cxt5066_models[CXT5066_MODELS] = { - [CXT5066_LAPTOP] = "laptop", - [CXT5066_DELL_LAPTOP] = "dell-laptop", - [CXT5066_DELL_VOSTRO] = "dell-vostro", - [CXT5066_IDEAPAD] = "ideapad", - [CXT5066_THINKPAD] = "thinkpad", - [CXT5066_ASUS] = "asus", - [CXT5066_HP_LAPTOP] = "hp-laptop", - [CXT5066_AUTO] = "auto", -}; - -static const struct snd_pci_quirk cxt5066_cfg_tbl[] = { - SND_PCI_QUIRK_MASK(0x1025, 0xff00, 0x0400, "Acer", CXT5066_IDEAPAD), - SND_PCI_QUIRK(0x1028, 0x02d8, "Dell Vostro", CXT5066_DELL_VOSTRO), - SND_PCI_QUIRK(0x1028, 0x02f5, "Dell Vostro 320", CXT5066_IDEAPAD), - SND_PCI_QUIRK(0x1028, 0x0401, "Dell Vostro 1014", CXT5066_DELL_VOSTRO), - SND_PCI_QUIRK(0x1028, 0x0408, "Dell Inspiron One 19T", CXT5066_IDEAPAD), - SND_PCI_QUIRK(0x1028, 0x050f, "Dell Inspiron", CXT5066_IDEAPAD), - SND_PCI_QUIRK(0x103c, 0x360b, "HP G60", CXT5066_HP_LAPTOP), - SND_PCI_QUIRK(0x1043, 0x13f3, "Asus A52J", CXT5066_ASUS), - SND_PCI_QUIRK(0x1043, 0x1643, "Asus K52JU", CXT5066_ASUS), - SND_PCI_QUIRK(0x1043, 0x1993, "Asus U50F", CXT5066_ASUS), - SND_PCI_QUIRK(0x1179, 0xff1e, "Toshiba Satellite C650D", CXT5066_IDEAPAD), - SND_PCI_QUIRK(0x14f1, 0x0101, "Conexant Reference board", - CXT5066_LAPTOP), - SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400s", CXT5066_THINKPAD), - SND_PCI_QUIRK(0x17aa, 0x21c5, "Thinkpad Edge 13", CXT5066_THINKPAD), - SND_PCI_QUIRK(0x17aa, 0x21c6, "Thinkpad Edge 13", CXT5066_ASUS), - SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo U350", CXT5066_ASUS), - SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo G560", CXT5066_ASUS), - {} -}; - -static int patch_cxt5066(struct hda_codec *codec) -{ - struct conexant_spec *spec; - int board_config; - - board_config = snd_hda_check_board_config(codec, CXT5066_MODELS, - cxt5066_models, cxt5066_cfg_tbl); - if (board_config < 0) - board_config = CXT5066_AUTO; /* model=auto as default */ - if (board_config == CXT5066_AUTO) - return patch_conexant_auto(codec); - - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (!spec) - return -ENOMEM; - codec->spec = spec; - - codec->patch_ops = conexant_patch_ops; - codec->patch_ops.init = conexant_init; - - spec->dell_automute = 0; - spec->multiout.max_channels = 2; - spec->multiout.num_dacs = ARRAY_SIZE(cxt5066_dac_nids); - spec->multiout.dac_nids = cxt5066_dac_nids; - conexant_check_dig_outs(codec, cxt5066_digout_pin_nids, - ARRAY_SIZE(cxt5066_digout_pin_nids)); - spec->num_adc_nids = 1; - spec->adc_nids = cxt5066_adc_nids; - spec->capsrc_nids = cxt5066_capsrc_nids; - spec->input_mux = &cxt5066_capture_source; - - spec->port_d_mode = PIN_HP; - - spec->num_init_verbs = 1; - spec->init_verbs[0] = cxt5066_init_verbs; - spec->num_channel_mode = ARRAY_SIZE(cxt5066_modes); - spec->channel_mode = cxt5066_modes; - spec->cur_adc = 0; - spec->cur_adc_idx = 0; - - set_beep_amp(spec, 0x13, 0, HDA_OUTPUT); - - switch (board_config) { - default: - case CXT5066_LAPTOP: - spec->mixers[spec->num_mixers++] = cxt5066_mixer_master; - spec->mixers[spec->num_mixers++] = cxt5066_mixers; - break; - case CXT5066_DELL_LAPTOP: - spec->mixers[spec->num_mixers++] = cxt5066_mixer_master; - spec->mixers[spec->num_mixers++] = cxt5066_mixers; - - spec->port_d_mode = PIN_OUT; - spec->init_verbs[spec->num_init_verbs] = cxt5066_init_verbs_portd_lo; - spec->num_init_verbs++; - spec->dell_automute = 1; - break; - case CXT5066_ASUS: - case CXT5066_HP_LAPTOP: - codec->patch_ops.init = cxt5066_init; - codec->patch_ops.unsol_event = cxt5066_unsol_event; - spec->init_verbs[spec->num_init_verbs] = - cxt5066_init_verbs_hp_laptop; - spec->num_init_verbs++; - spec->hp_laptop = board_config == CXT5066_HP_LAPTOP; - spec->asus = board_config == CXT5066_ASUS; - spec->mixers[spec->num_mixers++] = cxt5066_mixer_master; - spec->mixers[spec->num_mixers++] = cxt5066_mixers; - /* no S/PDIF out */ - if (board_config == CXT5066_HP_LAPTOP) - spec->multiout.dig_out_nid = 0; - /* input source automatically selected */ - spec->input_mux = NULL; - spec->port_d_mode = 0; - spec->mic_boost = 3; /* default 30dB gain */ - break; - - case CXT5066_DELL_VOSTRO: - codec->patch_ops.init = cxt5066_init; - codec->patch_ops.unsol_event = cxt5066_unsol_event; - spec->init_verbs[0] = cxt5066_init_verbs_vostro; - spec->mixers[spec->num_mixers++] = cxt5066_mixer_master; - spec->mixers[spec->num_mixers++] = cxt5066_mixers; - spec->mixers[spec->num_mixers++] = cxt5066_vostro_mixers; - spec->port_d_mode = 0; - spec->dell_vostro = 1; - spec->mic_boost = 3; /* default 30dB gain */ - - /* no S/PDIF out */ - spec->multiout.dig_out_nid = 0; - - /* input source automatically selected */ - spec->input_mux = NULL; - break; - case CXT5066_IDEAPAD: - codec->patch_ops.init = cxt5066_init; - codec->patch_ops.unsol_event = cxt5066_unsol_event; - spec->mixers[spec->num_mixers++] = cxt5066_mixer_master; - spec->mixers[spec->num_mixers++] = cxt5066_mixers; - spec->init_verbs[0] = cxt5066_init_verbs_ideapad; - spec->port_d_mode = 0; - spec->ideapad = 1; - spec->mic_boost = 2; /* default 20dB gain */ - - /* no S/PDIF out */ - spec->multiout.dig_out_nid = 0; - - /* input source automatically selected */ - spec->input_mux = NULL; - break; - case CXT5066_THINKPAD: - codec->patch_ops.init = cxt5066_init; - codec->patch_ops.unsol_event = cxt5066_unsol_event; - spec->mixers[spec->num_mixers++] = cxt5066_mixer_master; - spec->mixers[spec->num_mixers++] = cxt5066_mixers; - spec->init_verbs[0] = cxt5066_init_verbs_thinkpad; - spec->thinkpad = 1; - spec->port_d_mode = PIN_OUT; - spec->mic_boost = 2; /* default 20dB gain */ - - /* no S/PDIF out */ - spec->multiout.dig_out_nid = 0; - - /* input source automatically selected */ - spec->input_mux = NULL; - break; - } - - if (spec->beep_amp) - snd_hda_attach_beep_device(codec, get_amp_nid_(spec->beep_amp)); - - return 0; -} - -#endif /* ENABLE_CXT_STATIC_QUIRKS */ - - /* * Automatic parser for CX20641 & co */ @@ -2822,6 +217,7 @@ enum { CXT_FIXUP_HEADPHONE_MIC_PIN, CXT_FIXUP_HEADPHONE_MIC, CXT_FIXUP_GPIO1, + CXT_FIXUP_ASPIRE_DMIC, CXT_FIXUP_THINKPAD_ACPI, CXT_FIXUP_OLPC_XO, CXT_FIXUP_CAP_MIX_AMP, @@ -3269,6 +665,12 @@ static const struct hda_fixup cxt_fixups[] = { { } }, }, + [CXT_FIXUP_ASPIRE_DMIC] = { + .type = HDA_FIXUP_FUNC, + .v.func = cxt_fixup_stereo_dmic, + .chained = true, + .chain_id = CXT_FIXUP_GPIO1, + }, [CXT_FIXUP_THINKPAD_ACPI] = { .type = HDA_FIXUP_FUNC, .v.func = hda_fixup_thinkpad_acpi, @@ -3349,7 +751,7 @@ static const struct hda_model_fixup cxt5051_fixup_models[] = { static const struct snd_pci_quirk cxt5066_fixups[] = { SND_PCI_QUIRK(0x1025, 0x0543, "Acer Aspire One 522", CXT_FIXUP_STEREO_DMIC), - SND_PCI_QUIRK(0x1025, 0x054c, "Acer Aspire 3830TG", CXT_FIXUP_GPIO1), + SND_PCI_QUIRK(0x1025, 0x054c, "Acer Aspire 3830TG", CXT_FIXUP_ASPIRE_DMIC), SND_PCI_QUIRK(0x1043, 0x138d, "Asus", CXT_FIXUP_HEADPHONE_MIC_PIN), SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT_FIXUP_OLPC_XO), SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400", CXT_PINCFG_LENOVO_TP410), @@ -3375,6 +777,7 @@ static const struct hda_model_fixup cxt5066_fixup_models[] = { { .id = CXT_PINCFG_LENOVO_TP410, .name = "tp410" }, { .id = CXT_FIXUP_THINKPAD_ACPI, .name = "thinkpad" }, { .id = CXT_PINCFG_LEMOTE_A1004, .name = "lemote-a1004" }, + { .id = CXT_PINCFG_LEMOTE_A1205, .name = "lemote-a1205" }, { .id = CXT_FIXUP_OLPC_XO, .name = "olpc-xo" }, {} }; @@ -3465,6 +868,11 @@ static int patch_conexant_auto(struct hda_codec *codec) if (err < 0) goto error; + if (codec->vendor_id == 0x14f15051) { + /* minimum value is actually mute */ + spec->gen.vmaster_tlv[3] |= TLV_DB_SCALE_MUTE; + } + codec->patch_ops = cx_auto_patch_ops; /* Some laptops with Conexant chips show stalls in S3 resume, @@ -3487,35 +895,28 @@ static int patch_conexant_auto(struct hda_codec *codec) return err; } -#ifndef ENABLE_CXT_STATIC_QUIRKS -#define patch_cxt5045 patch_conexant_auto -#define patch_cxt5047 patch_conexant_auto -#define patch_cxt5051 patch_conexant_auto -#define patch_cxt5066 patch_conexant_auto -#endif - /* */ static const struct hda_codec_preset snd_hda_preset_conexant[] = { { .id = 0x14f15045, .name = "CX20549 (Venice)", - .patch = patch_cxt5045 }, + .patch = patch_conexant_auto }, { .id = 0x14f15047, .name = "CX20551 (Waikiki)", - .patch = patch_cxt5047 }, + .patch = patch_conexant_auto }, { .id = 0x14f15051, .name = "CX20561 (Hermosa)", - .patch = patch_cxt5051 }, + .patch = patch_conexant_auto }, { .id = 0x14f15066, .name = "CX20582 (Pebble)", - .patch = patch_cxt5066 }, + .patch = patch_conexant_auto }, { .id = 0x14f15067, .name = "CX20583 (Pebble HSF)", - .patch = patch_cxt5066 }, + .patch = patch_conexant_auto }, { .id = 0x14f15068, .name = "CX20584", - .patch = patch_cxt5066 }, + .patch = patch_conexant_auto }, { .id = 0x14f15069, .name = "CX20585", - .patch = patch_cxt5066 }, + .patch = patch_conexant_auto }, { .id = 0x14f1506c, .name = "CX20588", - .patch = patch_cxt5066 }, + .patch = patch_conexant_auto }, { .id = 0x14f1506e, .name = "CX20590", - .patch = patch_cxt5066 }, + .patch = patch_conexant_auto }, { .id = 0x14f15097, .name = "CX20631", .patch = patch_conexant_auto }, { .id = 0x14f15098, .name = "CX20632", diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index ba4ca52072ff..99d7d7fecaad 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -50,6 +50,8 @@ MODULE_PARM_DESC(static_hdmi_pcm, "Don't restrict PCM parameters per ELD info"); #define is_haswell_plus(codec) (is_haswell(codec) || is_broadwell(codec)) #define is_valleyview(codec) ((codec)->vendor_id == 0x80862882) +#define is_cherryview(codec) ((codec)->vendor_id == 0x80862883) +#define is_valleyview_plus(codec) (is_valleyview(codec) || is_cherryview(codec)) struct hdmi_spec_per_cvt { hda_nid_t cvt_nid; @@ -648,7 +650,8 @@ static int get_channel_allocation_order(int ca) * * TODO: it could select the wrong CA from multiple candidates. */ -static int hdmi_channel_allocation(struct hdmi_eld *eld, int channels) +static int hdmi_channel_allocation(struct hda_codec *codec, + struct hdmi_eld *eld, int channels) { int i; int ca = 0; @@ -694,7 +697,7 @@ static int hdmi_channel_allocation(struct hdmi_eld *eld, int channels) } snd_print_channel_allocation(eld->info.spk_alloc, buf, sizeof(buf)); - snd_printdd("HDMI: select CA 0x%x for %d-channel allocation: %s\n", + codec_dbg(codec, "HDMI: select CA 0x%x for %d-channel allocation: %s\n", ca, channels, buf); return ca; @@ -1131,7 +1134,7 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, if (!non_pcm && per_pin->chmap_set) ca = hdmi_manual_channel_allocation(channels, per_pin->chmap); else - ca = hdmi_channel_allocation(eld, channels); + ca = hdmi_channel_allocation(codec, eld, channels); if (ca < 0) ca = 0; @@ -1458,7 +1461,7 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo, mux_idx); /* configure unused pins to choose other converters */ - if (is_haswell_plus(codec) || is_valleyview(codec)) + if (is_haswell_plus(codec) || is_valleyview_plus(codec)) intel_not_share_assigned_cvt(codec, per_pin->pin_nid, mux_idx); snd_hda_spdif_ctls_assign(codec, pin_idx, per_cvt->cvt_nid); @@ -1557,13 +1560,13 @@ static bool hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll) eld->eld_valid = false; else { memset(&eld->info, 0, sizeof(struct parsed_hdmi_eld)); - if (snd_hdmi_parse_eld(&eld->info, eld->eld_buffer, + if (snd_hdmi_parse_eld(codec, &eld->info, eld->eld_buffer, eld->eld_size) < 0) eld->eld_valid = false; } if (eld->eld_valid) { - snd_hdmi_show_eld(&eld->info); + snd_hdmi_show_eld(codec, &eld->info); update_eld = true; } else if (repoll) { @@ -1597,7 +1600,8 @@ static bool hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll) * and this can make HW reset converter selection on a pin. */ if (eld->eld_valid && !old_eld_valid && per_pin->setup) { - if (is_haswell_plus(codec) || is_valleyview(codec)) { + if (is_haswell_plus(codec) || + is_valleyview_plus(codec)) { intel_verify_pin_cvt_connect(codec, per_pin); intel_not_share_assigned_cvt(codec, pin_nid, per_pin->mux_idx); @@ -1778,7 +1782,7 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, bool non_pcm; int pinctl; - if (is_haswell_plus(codec) || is_valleyview(codec)) { + if (is_haswell_plus(codec) || is_valleyview_plus(codec)) { /* Verify pin:cvt selections to avoid silent audio after S3. * After S3, the audio driver restores pin:cvt selections * but this can happen before gfx is ready and such selection @@ -2329,9 +2333,8 @@ static int patch_generic_hdmi(struct hda_codec *codec) intel_haswell_fixup_enable_dp12(codec); } - if (is_haswell(codec) || is_valleyview(codec)) { + if (is_haswell_plus(codec) || is_valleyview_plus(codec)) codec->depop_delay = 0; - } if (hdmi_parse_codec(codec) < 0) { codec->spec = NULL; @@ -3355,6 +3358,7 @@ static const struct hda_codec_preset snd_hda_preset_hdmi[] = { { .id = 0x80862808, .name = "Broadwell HDMI", .patch = patch_generic_hdmi }, { .id = 0x80862880, .name = "CedarTrail HDMI", .patch = patch_generic_hdmi }, { .id = 0x80862882, .name = "Valleyview2 HDMI", .patch = patch_generic_hdmi }, +{ .id = 0x80862883, .name = "Braswell HDMI", .patch = patch_generic_hdmi }, { .id = 0x808629fb, .name = "Crestline HDMI", .patch = patch_generic_hdmi }, {} /* terminator */ }; @@ -3414,6 +3418,7 @@ MODULE_ALIAS("snd-hda-codec-id:80862807"); MODULE_ALIAS("snd-hda-codec-id:80862808"); MODULE_ALIAS("snd-hda-codec-id:80862880"); MODULE_ALIAS("snd-hda-codec-id:80862882"); +MODULE_ALIAS("snd-hda-codec-id:80862883"); MODULE_ALIAS("snd-hda-codec-id:808629fb"); MODULE_LICENSE("GPL"); diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index b60824e90408..1ba22fb527c2 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -101,6 +101,7 @@ struct alc_spec { /* mute LED for HP laptops, see alc269_fixup_mic_mute_hook() */ int mute_led_polarity; hda_nid_t mute_led_nid; + hda_nid_t cap_mute_led_nid; unsigned int gpio_led; /* used for alc269_fixup_hp_gpio_led() */ @@ -180,6 +181,8 @@ static void alc_fix_pll(struct hda_codec *codec) spec->pll_coef_idx); val = snd_hda_codec_read(codec, spec->pll_nid, 0, AC_VERB_GET_PROC_COEF, 0); + if (val == -1) + return; snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX, spec->pll_coef_idx); snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_PROC_COEF, @@ -325,6 +328,7 @@ static void alc_auto_init_amp(struct hda_codec *codec, int type) case 0x10ec0885: case 0x10ec0887: /*case 0x10ec0889:*/ /* this causes an SPDIF problem */ + case 0x10ec0900: alc889_coef_init(codec); break; case 0x10ec0888: @@ -2347,6 +2351,7 @@ static int patch_alc882(struct hda_codec *codec) switch (codec->vendor_id) { case 0x10ec0882: case 0x10ec0885: + case 0x10ec0900: break; default: /* ALC883 and variants */ @@ -2781,9 +2786,32 @@ static int alc269_parse_auto_config(struct hda_codec *codec) return alc_parse_auto_config(codec, alc269_ignore, ssids); } +static int find_ext_mic_pin(struct hda_codec *codec); + +static void alc286_shutup(struct hda_codec *codec) +{ + int i; + int mic_pin = find_ext_mic_pin(codec); + /* don't shut up pins when unloading the driver; otherwise it breaks + * the default pin setup at the next load of the driver + */ + if (codec->bus->shutdown) + return; + for (i = 0; i < codec->init_pins.used; i++) { + struct hda_pincfg *pin = snd_array_elem(&codec->init_pins, i); + /* use read here for syncing after issuing each verb */ + if (pin->nid != mic_pin) + snd_hda_codec_read(codec, pin->nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, 0); + } + codec->pins_shutup = 1; +} + static void alc269vb_toggle_power_output(struct hda_codec *codec, int power_up) { int val = alc_read_coef_idx(codec, 0x04); + if (val == -1) + return; if (power_up) val |= 1 << 11; else @@ -3242,6 +3270,15 @@ static int alc269_resume(struct hda_codec *codec) snd_hda_codec_resume_cache(codec); alc_inv_dmic_sync(codec, true); hda_call_check_power_status(codec, 0x01); + + /* on some machine, the BIOS will clear the codec gpio data when enter + * suspend, and won't restore the data after resume, so we restore it + * in the driver. + */ + if (spec->gpio_led) + snd_hda_codec_write(codec, codec->afg, 0, AC_VERB_SET_GPIO_DATA, + spec->gpio_led); + if (spec->has_alc5505_dsp) alc5505_dsp_resume(codec); @@ -3402,7 +3439,8 @@ static unsigned int led_power_filter(struct hda_codec *codec, { struct alc_spec *spec = codec->spec; - if (power_state != AC_PWRST_D3 || nid != spec->mute_led_nid) + if (power_state != AC_PWRST_D3 || nid == 0 || + (nid != spec->mute_led_nid && nid != spec->cap_mute_led_nid)) return power_state; /* Set pin ctl again, it might have just been set to 0 */ @@ -3520,6 +3558,68 @@ static void alc269_fixup_hp_gpio_led(struct hda_codec *codec, } } +/* turn on/off mic-mute LED per capture hook */ +static void alc269_fixup_hp_cap_mic_mute_hook(struct hda_codec *codec, + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct alc_spec *spec = codec->spec; + unsigned int pinval, enable, disable; + + pinval = snd_hda_codec_get_pin_target(codec, spec->cap_mute_led_nid); + pinval &= ~AC_PINCTL_VREFEN; + enable = pinval | AC_PINCTL_VREF_80; + disable = pinval | AC_PINCTL_VREF_HIZ; + + if (!ucontrol) + return; + + if (ucontrol->value.integer.value[0] || + ucontrol->value.integer.value[1]) + pinval = disable; + else + pinval = enable; + + if (spec->cap_mute_led_nid) + snd_hda_set_pin_ctl_cache(codec, spec->cap_mute_led_nid, pinval); +} + +static void alc269_fixup_hp_gpio_mic1_led(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct alc_spec *spec = codec->spec; + static const struct hda_verb gpio_init[] = { + { 0x01, AC_VERB_SET_GPIO_MASK, 0x08 }, + { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x08 }, + {} + }; + + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + spec->gen.vmaster_mute.hook = alc269_fixup_hp_gpio_mute_hook; + spec->gen.cap_sync_hook = alc269_fixup_hp_cap_mic_mute_hook; + spec->gpio_led = 0; + spec->cap_mute_led_nid = 0x18; + snd_hda_add_verbs(codec, gpio_init); + codec->power_filter = led_power_filter; + } +} + +static void alc269_fixup_hp_line1_mic1_led(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct alc_spec *spec = codec->spec; + + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + spec->gen.vmaster_mute.hook = alc269_fixup_mic_mute_hook; + spec->gen.cap_sync_hook = alc269_fixup_hp_cap_mic_mute_hook; + spec->mute_led_polarity = 0; + spec->mute_led_nid = 0x1a; + spec->cap_mute_led_nid = 0x18; + spec->gen.vmaster_mute_enum = 1; + codec->power_filter = led_power_filter; + } +} + static void alc_headset_mode_unplugged(struct hda_codec *codec) { int val; @@ -4008,7 +4108,7 @@ static unsigned int alc_power_filter_xps13(struct hda_codec *codec, /* Avoid pop noises when headphones are plugged in */ if (spec->gen.hp_jack_present) - if (nid == codec->afg || nid == 0x02) + if (nid == codec->afg || nid == 0x02 || nid == 0x15) return AC_PWRST_D0; return power_state; } @@ -4018,8 +4118,19 @@ static void alc_fixup_dell_xps13(struct hda_codec *codec, { if (action == HDA_FIXUP_ACT_PROBE) { struct alc_spec *spec = codec->spec; + struct hda_input_mux *imux = &spec->gen.input_mux; + int i; + spec->shutup = alc_no_shutup; codec->power_filter = alc_power_filter_xps13; + + /* Make the internal mic the default input source. */ + for (i = 0; i < imux->num_items; i++) { + if (spec->gen.imux_pins[i] == 0x12) { + spec->gen.cur_mux[0] = i; + break; + } + } } } @@ -4231,6 +4342,9 @@ static void alc290_fixup_mono_speakers(struct hda_codec *codec, /* for hda_fixup_thinkpad_acpi() */ #include "thinkpad_helper.c" +/* for dell wmi mic mute led */ +#include "dell_wmi_helper.c" + enum { ALC269_FIXUP_SONY_VAIO, ALC275_FIXUP_SONY_VAIO_GPIO2, @@ -4255,6 +4369,8 @@ enum { ALC269_FIXUP_HP_MUTE_LED_MIC1, ALC269_FIXUP_HP_MUTE_LED_MIC2, ALC269_FIXUP_HP_GPIO_LED, + ALC269_FIXUP_HP_GPIO_MIC1_LED, + ALC269_FIXUP_HP_LINE1_MIC1_LED, ALC269_FIXUP_INV_DMIC, ALC269_FIXUP_LENOVO_DOCK, ALC269_FIXUP_NO_SHUTUP, @@ -4292,6 +4408,9 @@ enum { ALC255_FIXUP_HEADSET_MODE_NO_HP_MIC, ALC293_FIXUP_DELL1_MIC_NO_PRESENCE, ALC292_FIXUP_TPT440_DOCK, + ALC283_FIXUP_BXBT2807_MIC, + ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED, + ALC282_FIXUP_ASPIRE_V5_PINS, }; static const struct hda_fixup alc269_fixups[] = { @@ -4447,6 +4566,14 @@ static const struct hda_fixup alc269_fixups[] = { .type = HDA_FIXUP_FUNC, .v.func = alc269_fixup_hp_gpio_led, }, + [ALC269_FIXUP_HP_GPIO_MIC1_LED] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc269_fixup_hp_gpio_mic1_led, + }, + [ALC269_FIXUP_HP_LINE1_MIC1_LED] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc269_fixup_hp_line1_mic1_led, + }, [ALC269_FIXUP_INV_DMIC] = { .type = HDA_FIXUP_FUNC, .v.func = alc_fixup_inv_dmic_0x12, @@ -4718,6 +4845,36 @@ static const struct hda_fixup alc269_fixups[] = { .chained = true, .chain_id = ALC269_FIXUP_LIMIT_INT_MIC_BOOST }, + [ALC283_FIXUP_BXBT2807_MIC] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x19, 0x04a110f0 }, + { }, + }, + }, + [ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_dell_wmi, + .chained_before = true, + .chain_id = ALC255_FIXUP_DELL1_MIC_NO_PRESENCE + }, + [ALC282_FIXUP_ASPIRE_V5_PINS] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x12, 0x90a60130 }, + { 0x14, 0x90170110 }, + { 0x17, 0x40000008 }, + { 0x18, 0x411111f0 }, + { 0x19, 0x411111f0 }, + { 0x1a, 0x411111f0 }, + { 0x1b, 0x411111f0 }, + { 0x1d, 0x40f89b2d }, + { 0x1e, 0x411111f0 }, + { 0x21, 0x0321101f }, + { }, + }, + }, + }; static const struct snd_pci_quirk alc269_fixup_tbl[] = { @@ -4727,8 +4884,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1025, 0x047c, "Acer AC700", ALC269_FIXUP_ACER_AC700), SND_PCI_QUIRK(0x1025, 0x0740, "Acer AO725", ALC271_FIXUP_HP_GATE_MIC_JACK), SND_PCI_QUIRK(0x1025, 0x0742, "Acer AO756", ALC271_FIXUP_HP_GATE_MIC_JACK), - SND_PCI_QUIRK_VENDOR(0x1025, "Acer Aspire", ALC271_FIXUP_DMIC), SND_PCI_QUIRK(0x1025, 0x0775, "Acer Aspire E1-572", ALC271_FIXUP_HP_GATE_MIC_JACK_E1_572), + SND_PCI_QUIRK(0x1025, 0x079b, "Acer Aspire V5-573G", ALC282_FIXUP_ASPIRE_V5_PINS), SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z), SND_PCI_QUIRK(0x1028, 0x05bd, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x05be, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE), @@ -4761,10 +4918,12 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1028, 0x0606, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x0608, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x0609, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x0610, "Dell", ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED), SND_PCI_QUIRK(0x1028, 0x0613, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x0614, "Dell Inspiron 3135", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x0615, "Dell Vostro 5470", ALC290_FIXUP_SUBWOOFER_HSJACK), SND_PCI_QUIRK(0x1028, 0x0616, "Dell Vostro 5470", ALC290_FIXUP_SUBWOOFER_HSJACK), + SND_PCI_QUIRK(0x1028, 0x061f, "Dell", ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED), SND_PCI_QUIRK(0x1028, 0x0638, "Dell Inspiron 5439", ALC290_FIXUP_MONO_SPEAKERS_HSJACK), SND_PCI_QUIRK(0x1028, 0x063f, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x064a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), @@ -4782,6 +4941,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x1983, "HP Pavilion", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x218b, "HP", ALC269_FIXUP_LIMIT_INT_MIC_BOOST_MUTE_LED), /* ALC282 */ + SND_PCI_QUIRK(0x103c, 0x21f8, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x21f9, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x220d, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x220e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x220f, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), @@ -4790,6 +4951,20 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x2212, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2213, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2214, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x2234, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2235, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2236, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2237, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2238, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2239, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2246, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2247, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2248, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2249, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x224a, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x224b, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x224c, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x224d, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED), SND_PCI_QUIRK(0x103c, 0x2266, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2267, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2268, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), @@ -4814,13 +4989,43 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x22ce, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x22cf, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x22d0, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x22da, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x22db, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x22dc, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x22fb, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x8004, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), /* ALC290 */ + SND_PCI_QUIRK(0x103c, 0x221b, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x221c, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x221d, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2220, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2221, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2222, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2223, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2224, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2225, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2246, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2247, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2248, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2249, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2253, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2254, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2255, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2256, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2257, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2258, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2259, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x225a, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), SND_PCI_QUIRK(0x103c, 0x2260, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2261, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2262, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2263, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2264, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2265, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x2272, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2273, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2277, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2278, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), SND_PCI_QUIRK(0x103c, 0x227d, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x227e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x227f, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), @@ -4843,7 +5048,6 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x2335, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2336, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2337, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), - SND_PCI_QUIRK_VENDOR(0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED), SND_PCI_QUIRK(0x1043, 0x103f, "ASUS TX300", ALC282_FIXUP_ASUS_TX300), SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), SND_PCI_QUIRK(0x1043, 0x115d, "Asus 1015E", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), @@ -4864,9 +5068,9 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x104d, 0x907b, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ), SND_PCI_QUIRK(0x104d, 0x9084, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ), SND_PCI_QUIRK(0x104d, 0x9099, "Sony VAIO S13", ALC275_FIXUP_SONY_DISABLE_AAMIX), - SND_PCI_QUIRK_VENDOR(0x104d, "Sony VAIO", ALC269_FIXUP_SONY_VAIO), SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook", ALC269_FIXUP_LIFEBOOK), SND_PCI_QUIRK(0x10cf, 0x1845, "Lifebook U904", ALC269_FIXUP_LIFEBOOK_EXTMIC), + SND_PCI_QUIRK(0x1458, 0xfa53, "Gigabyte BXBT-2807", ALC283_FIXUP_BXBT2807_MIC), SND_PCI_QUIRK(0x17aa, 0x20f2, "Thinkpad SL410/510", ALC269_FIXUP_SKU_IGNORE), SND_PCI_QUIRK(0x17aa, 0x215e, "Thinkpad L512", ALC269_FIXUP_SKU_IGNORE), SND_PCI_QUIRK(0x17aa, 0x21b8, "Thinkpad Edge 14", ALC269_FIXUP_SKU_IGNORE), @@ -4891,7 +5095,6 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x5109, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_PCM_44K), SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD), - SND_PCI_QUIRK_VENDOR(0x17aa, "Thinkpad", ALC269_FIXUP_THINKPAD_ACPI), SND_PCI_QUIRK(0x1b7d, 0xa831, "Ordissimo EVE2 ", ALC269VB_FIXUP_ORDISSIMO_EVE2), /* Also known as Malata PC-B1303 */ #if 0 @@ -4945,6 +5148,14 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { {} }; +static const struct snd_pci_quirk alc269_fixup_vendor_tbl[] = { + SND_PCI_QUIRK_VENDOR(0x1025, "Acer Aspire", ALC271_FIXUP_DMIC), + SND_PCI_QUIRK_VENDOR(0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED), + SND_PCI_QUIRK_VENDOR(0x104d, "Sony VAIO", ALC269_FIXUP_SONY_VAIO), + SND_PCI_QUIRK_VENDOR(0x17aa, "Thinkpad", ALC269_FIXUP_THINKPAD_ACPI), + {} +}; + static const struct hda_model_fixup alc269_fixup_models[] = { {.id = ALC269_FIXUP_AMIC, .name = "laptop-amic"}, {.id = ALC269_FIXUP_DMIC, .name = "laptop-dmic"}, @@ -5040,6 +5251,17 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { {0x1d, 0x40700001}, {0x1e, 0x411111f0}, {0x21, 0x02211040}), + SND_HDA_PIN_QUIRK(0x10ec0282, 0x103c, "HP 15 Touchsmart", ALC269_FIXUP_HP_MUTE_LED_MIC1, + {0x12, 0x99a30130}, + {0x14, 0x90170110}, + {0x17, 0x40000000}, + {0x18, 0x411111f0}, + {0x19, 0x03a11020}, + {0x1a, 0x411111f0}, + {0x1b, 0x411111f0}, + {0x1d, 0x40f41905}, + {0x1e, 0x411111f0}, + {0x21, 0x0321101f}), SND_HDA_PIN_QUIRK(0x10ec0283, 0x1028, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE, {0x12, 0x90a60130}, {0x14, 0x90170110}, @@ -5122,27 +5344,30 @@ static void alc269_fill_coef(struct hda_codec *codec) if ((alc_get_coef0(codec) & 0x00ff) == 0x017) { val = alc_read_coef_idx(codec, 0x04); /* Power up output pin */ - alc_write_coef_idx(codec, 0x04, val | (1<<11)); + if (val != -1) + alc_write_coef_idx(codec, 0x04, val | (1<<11)); } if ((alc_get_coef0(codec) & 0x00ff) == 0x018) { val = alc_read_coef_idx(codec, 0xd); - if ((val & 0x0c00) >> 10 != 0x1) { + if (val != -1 && (val & 0x0c00) >> 10 != 0x1) { /* Capless ramp up clock control */ alc_write_coef_idx(codec, 0xd, val | (1<<10)); } val = alc_read_coef_idx(codec, 0x17); - if ((val & 0x01c0) >> 6 != 0x4) { + if (val != -1 && (val & 0x01c0) >> 6 != 0x4) { /* Class D power on reset */ alc_write_coef_idx(codec, 0x17, val | (1<<7)); } } val = alc_read_coef_idx(codec, 0xd); /* Class D */ - alc_write_coef_idx(codec, 0xd, val | (1<<14)); + if (val != -1) + alc_write_coef_idx(codec, 0xd, val | (1<<14)); val = alc_read_coef_idx(codec, 0x4); /* HP */ - alc_write_coef_idx(codec, 0x4, val | (1<<11)); + if (val != -1) + alc_write_coef_idx(codec, 0x4, val | (1<<11)); } /* @@ -5162,6 +5387,8 @@ static int patch_alc269(struct hda_codec *codec) snd_hda_pick_fixup(codec, alc269_fixup_models, alc269_fixup_tbl, alc269_fixups); snd_hda_pick_pin_fixup(codec, alc269_pin_fixup_tbl, alc269_fixups); + snd_hda_pick_fixup(codec, NULL, alc269_fixup_vendor_tbl, + alc269_fixups); snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); alc_auto_parse_customize_define(codec); @@ -5225,6 +5452,7 @@ static int patch_alc269(struct hda_codec *codec) case 0x10ec0286: case 0x10ec0288: spec->codec_variant = ALC269_TYPE_ALC286; + spec->shutup = alc286_shutup; break; case 0x10ec0255: spec->codec_variant = ALC269_TYPE_ALC255; @@ -5858,6 +6086,7 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = { SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE), SND_PCI_QUIRK(0x1028, 0x05d8, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x05db, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x05fe, "Dell XPS 15", ALC668_FIXUP_DELL_XPS13), SND_PCI_QUIRK(0x1028, 0x060a, "Dell XPS 13", ALC668_FIXUP_DELL_XPS13), SND_PCI_QUIRK(0x1028, 0x0625, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x0626, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 3744ea4e843d..98cd1908c039 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -84,6 +84,7 @@ enum { STAC_DELL_EQ, STAC_ALIENWARE_M17X, STAC_92HD89XX_HP_FRONT_JACK, + STAC_92HD89XX_HP_Z1_G2_RIGHT_MIC_JACK, STAC_92HD73XX_MODELS }; @@ -103,6 +104,7 @@ enum { STAC_92HD83XXX_HP, STAC_HP_ENVY_BASS, STAC_HP_BNB13_EQ, + STAC_HP_ENVY_TS_BASS, STAC_92HD83XXX_MODELS }; @@ -564,8 +566,8 @@ static void stac_init_power_map(struct hda_codec *codec) if (snd_hda_jack_tbl_get(codec, nid)) continue; if (def_conf == AC_JACK_PORT_COMPLEX && - !(spec->vref_mute_led_nid == nid || - is_jack_detectable(codec, nid))) { + spec->vref_mute_led_nid != nid && + is_jack_detectable(codec, nid)) { snd_hda_jack_detect_enable_callback(codec, nid, STAC_PWR_EVENT, jack_update_power); @@ -1017,7 +1019,7 @@ static int stac_create_spdif_mux_ctls(struct hda_codec *codec) for (i = 0; i < num_cons; i++) { if (snd_BUG_ON(!labels[i])) return -EINVAL; - snd_hda_add_imux_item(&spec->spdif_mux, labels[i], i, NULL); + snd_hda_add_imux_item(codec, &spec->spdif_mux, labels[i], i, NULL); } kctl = snd_hda_gen_add_kctl(&spec->gen, NULL, &stac_smux_mixer); @@ -1809,6 +1811,11 @@ static const struct hda_pintbl stac92hd89xx_hp_front_jack_pin_configs[] = { {} }; +static const struct hda_pintbl stac92hd89xx_hp_z1_g2_right_mic_jack_pin_configs[] = { + { 0x0e, 0x400000f0 }, + {} +}; + static void stac92hd73xx_fixup_ref(struct hda_codec *codec, const struct hda_fixup *fix, int action) { @@ -1931,6 +1938,10 @@ static const struct hda_fixup stac92hd73xx_fixups[] = { [STAC_92HD89XX_HP_FRONT_JACK] = { .type = HDA_FIXUP_PINS, .v.pins = stac92hd89xx_hp_front_jack_pin_configs, + }, + [STAC_92HD89XX_HP_Z1_G2_RIGHT_MIC_JACK] = { + .type = HDA_FIXUP_PINS, + .v.pins = stac92hd89xx_hp_z1_g2_right_mic_jack_pin_configs, } }; @@ -1991,6 +2002,8 @@ static const struct snd_pci_quirk stac92hd73xx_fixup_tbl[] = { "Alienware M17x", STAC_ALIENWARE_M17X), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0490, "Alienware M17x R3", STAC_DELL_EQ), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1927, + "HP Z1 G2", STAC_92HD89XX_HP_Z1_G2_RIGHT_MIC_JACK), SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2b17, "unknown HP", STAC_92HD89XX_HP_FRONT_JACK), {} /* terminator */ @@ -2668,6 +2681,13 @@ static const struct hda_fixup stac92hd83xxx_fixups[] = { .chained = true, .chain_id = STAC_92HD83XXX_HP_MIC_LED, }, + [STAC_HP_ENVY_TS_BASS] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x10, 0x92170111 }, + {} + }, + }, }; static const struct hda_model_fixup stac92hd83xxx_models[] = { @@ -2684,6 +2704,7 @@ static const struct hda_model_fixup stac92hd83xxx_models[] = { { .id = STAC_92HD83XXX_HEADSET_JACK, .name = "headset-jack" }, { .id = STAC_HP_ENVY_BASS, .name = "hp-envy-bass" }, { .id = STAC_HP_BNB13_EQ, .name = "hp-bnb13-eq" }, + { .id = STAC_HP_ENVY_TS_BASS, .name = "hp-envy-ts-bass" }, {} }; @@ -2739,6 +2760,8 @@ static const struct snd_pci_quirk stac92hd83xxx_fixup_tbl[] = { "HP bNB13", STAC_HP_BNB13_EQ), SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x190A, "HP bNB13", STAC_HP_BNB13_EQ), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x190e, + "HP ENVY TS", STAC_HP_ENVY_TS_BASS), SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1940, "HP bNB13", STAC_HP_BNB13_EQ), SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1941, @@ -3438,9 +3461,11 @@ static void stac922x_fixup_intel_mac_auto(struct hda_codec *codec, { if (action != HDA_FIXUP_ACT_PRE_PROBE) return; + + codec->fixup_id = HDA_FIXUP_ID_NOT_SET; snd_hda_pick_fixup(codec, NULL, stac922x_intel_mac_fixup_tbl, stac922x_fixups); - if (codec->fixup_id != STAC_INTEL_MAC_AUTO) + if (codec->fixup_id != HDA_FIXUP_ID_NOT_SET) snd_hda_apply_fixup(codec, action); } @@ -4251,11 +4276,18 @@ static int stac_parse_auto_config(struct hda_codec *codec) return err; } - stac_init_power_map(codec); - return 0; } +static int stac_build_controls(struct hda_codec *codec) +{ + int err = snd_hda_gen_build_controls(codec); + + if (err < 0) + return err; + stac_init_power_map(codec); + return 0; +} static int stac_init(struct hda_codec *codec) { @@ -4367,7 +4399,7 @@ static int stac_suspend(struct hda_codec *codec) #endif /* CONFIG_PM */ static const struct hda_codec_ops stac_patch_ops = { - .build_controls = snd_hda_gen_build_controls, + .build_controls = stac_build_controls, .build_pcms = snd_hda_gen_build_pcms, .init = stac_init, .free = stac_free, diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c index d9b9e4595f17..87f7fc41d4f2 100644 --- a/sound/pci/ice1712/ice1712.c +++ b/sound/pci/ice1712/ice1712.c @@ -105,7 +105,7 @@ module_param_array(dxr_enable, int, NULL, 0444); MODULE_PARM_DESC(dxr_enable, "Enable DXR support for Terratec DMX6FIRE."); -static DEFINE_PCI_DEVICE_TABLE(snd_ice1712_ids) = { +static const struct pci_device_id snd_ice1712_ids[] = { { PCI_VDEVICE(ICE, PCI_DEVICE_ID_ICE_1712), 0 }, /* ICE1712 */ { 0, } }; diff --git a/sound/pci/ice1712/ice1712.h b/sound/pci/ice1712/ice1712.h index b209fc30b334..58f8f2ae758d 100644 --- a/sound/pci/ice1712/ice1712.h +++ b/sound/pci/ice1712/ice1712.h @@ -41,14 +41,17 @@ #define ICEREG(ice, x) ((ice)->port + ICE1712_REG_##x) #define ICE1712_REG_CONTROL 0x00 /* byte */ -#define ICE1712_RESET 0x80 /* reset whole chip */ -#define ICE1712_SERR_LEVEL 0x04 /* SERR# level otherwise edge */ +#define ICE1712_RESET 0x80 /* soft reset whole chip */ +#define ICE1712_SERR_ASSERT_DS_DMA 0x40 /* disabled SERR# assertion for the DS DMA Ch-C irq otherwise enabled */ +#define ICE1712_DOS_VOL 0x10 /* DOS WT/FM volume control */ +#define ICE1712_SERR_LEVEL 0x08 /* SERR# level otherwise edge */ +#define ICE1712_SERR_ASSERT_SB 0x02 /* disabled SERR# assertion for SB irq otherwise enabled */ #define ICE1712_NATIVE 0x01 /* native mode otherwise SB */ #define ICE1712_REG_IRQMASK 0x01 /* byte */ -#define ICE1712_IRQ_MPU1 0x80 -#define ICE1712_IRQ_TIMER 0x40 -#define ICE1712_IRQ_MPU2 0x20 -#define ICE1712_IRQ_PROPCM 0x10 +#define ICE1712_IRQ_MPU1 0x80 /* MIDI irq mask */ +#define ICE1712_IRQ_TIMER 0x40 /* Timer mask */ +#define ICE1712_IRQ_MPU2 0x20 /* Secondary MIDI irq mask */ +#define ICE1712_IRQ_PROPCM 0x10 /* professional multi-track */ #define ICE1712_IRQ_FM 0x08 /* FM/MIDI - legacy */ #define ICE1712_IRQ_PBKDS 0x04 /* playback DS channels */ #define ICE1712_IRQ_CONCAP 0x02 /* consumer capture */ diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c index 5e7948f3efe9..08cb08ac85e6 100644 --- a/sound/pci/ice1712/ice1724.c +++ b/sound/pci/ice1712/ice1724.c @@ -94,7 +94,7 @@ MODULE_PARM_DESC(model, "Use the given board model."); /* Both VT1720 and VT1724 have the same PCI IDs */ -static DEFINE_PCI_DEVICE_TABLE(snd_vt1724_ids) = { +static const struct pci_device_id snd_vt1724_ids[] = { { PCI_VDEVICE(ICE, PCI_DEVICE_ID_VT1724), 0 }, { 0, } }; diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index c91860e0a28d..4a28252a42b9 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c @@ -430,7 +430,7 @@ struct intel8x0 { u32 int_sta_mask; /* interrupt status mask */ }; -static DEFINE_PCI_DEVICE_TABLE(snd_intel8x0_ids) = { +static const struct pci_device_id snd_intel8x0_ids[] = { { PCI_VDEVICE(INTEL, 0x2415), DEVICE_INTEL }, /* 82801AA */ { PCI_VDEVICE(INTEL, 0x2425), DEVICE_INTEL }, /* 82901AB */ { PCI_VDEVICE(INTEL, 0x2445), DEVICE_INTEL }, /* 82801BA */ diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c index b54d3e93cab1..6b40235be13c 100644 --- a/sound/pci/intel8x0m.c +++ b/sound/pci/intel8x0m.c @@ -219,7 +219,7 @@ struct intel8x0m { unsigned int pcm_pos_shift; }; -static DEFINE_PCI_DEVICE_TABLE(snd_intel8x0m_ids) = { +static const struct pci_device_id snd_intel8x0m_ids[] = { { PCI_VDEVICE(INTEL, 0x2416), DEVICE_INTEL }, /* 82801AA */ { PCI_VDEVICE(INTEL, 0x2426), DEVICE_INTEL }, /* 82901AB */ { PCI_VDEVICE(INTEL, 0x2446), DEVICE_INTEL }, /* 82801BA */ diff --git a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c index 8f36d77f01e5..9fe549b2efdf 100644 --- a/sound/pci/korg1212/korg1212.c +++ b/sound/pci/korg1212/korg1212.c @@ -418,7 +418,7 @@ module_param_array(enable, bool, NULL, 0444); MODULE_PARM_DESC(enable, "Enable Korg 1212 soundcard."); MODULE_AUTHOR("Haroldo Gamal <gamal@alternex.com.br>"); -static DEFINE_PCI_DEVICE_TABLE(snd_korg1212_ids) = { +static const struct pci_device_id snd_korg1212_ids[] = { { .vendor = 0x10b5, .device = 0x906d, diff --git a/sound/pci/lola/lola.c b/sound/pci/lola/lola.c index 68824cdd137d..a75c8dc66dec 100644 --- a/sound/pci/lola/lola.c +++ b/sound/pci/lola/lola.c @@ -760,7 +760,7 @@ static void lola_remove(struct pci_dev *pci) } /* PCI IDs */ -static DEFINE_PCI_DEVICE_TABLE(lola_ids) = { +static const struct pci_device_id lola_ids[] = { { PCI_VDEVICE(DIGIGRAM, 0x0001) }, { 0, } }; diff --git a/sound/pci/lx6464es/lx6464es.c b/sound/pci/lx6464es/lx6464es.c index 27f60ce8a55c..a671f0865f71 100644 --- a/sound/pci/lx6464es/lx6464es.c +++ b/sound/pci/lx6464es/lx6464es.c @@ -56,7 +56,7 @@ static const char card_name[] = "LX6464ES"; #define PCI_DEVICE_ID_PLX_LX6464ES PCI_DEVICE_ID_PLX_9056 -static DEFINE_PCI_DEVICE_TABLE(snd_lx6464es_ids) = { +static const struct pci_device_id snd_lx6464es_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_LX6464ES), .subvendor = PCI_VENDOR_ID_DIGIGRAM, .subdevice = PCI_SUBDEVICE_ID_DIGIGRAM_LX6464ES_SERIAL_SUBSYSTEM diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c index 0d3ea3e79952..98823d11d485 100644 --- a/sound/pci/maestro3.c +++ b/sound/pci/maestro3.c @@ -800,7 +800,7 @@ struct snd_m3 { /* * pci ids */ -static DEFINE_PCI_DEVICE_TABLE(snd_m3_ids) = { +static const struct pci_device_id snd_m3_ids[] = { {PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_ALLEGRO_1, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0}, {PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_ALLEGRO, PCI_ANY_ID, PCI_ANY_ID, diff --git a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c index a93e7af51eed..75fc342cff2a 100644 --- a/sound/pci/mixart/mixart.c +++ b/sound/pci/mixart/mixart.c @@ -61,7 +61,7 @@ MODULE_PARM_DESC(enable, "Enable Digigram " CARD_NAME " soundcard."); /* */ -static DEFINE_PCI_DEVICE_TABLE(snd_mixart_ids) = { +static const struct pci_device_id snd_mixart_ids[] = { { PCI_VDEVICE(MOTOROLA, 0x0003), 0, }, /* MC8240 */ { 0, } }; diff --git a/sound/pci/mixart/mixart_core.c b/sound/pci/mixart/mixart_core.c index 71f4bdcc4055..84f67450924e 100644 --- a/sound/pci/mixart/mixart_core.c +++ b/sound/pci/mixart/mixart_core.c @@ -151,13 +151,11 @@ static int send_msg( struct mixart_mgr *mgr, { u32 headptr, tailptr; u32 msg_frame_address; - int err, i; + int i; if (snd_BUG_ON(msg->size % 4)) return -EINVAL; - err = 0; - /* get message frame address */ tailptr = readl_be(MIXART_MEM(mgr, MSG_INBOUND_FREE_TAIL)); headptr = readl_be(MIXART_MEM(mgr, MSG_INBOUND_FREE_HEAD)); diff --git a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c index ddc60215cc10..4e41a4e29a1e 100644 --- a/sound/pci/nm256/nm256.c +++ b/sound/pci/nm256/nm256.c @@ -262,7 +262,7 @@ struct nm256 { /* * PCI ids */ -static DEFINE_PCI_DEVICE_TABLE(snd_nm256_ids) = { +static const struct pci_device_id snd_nm256_ids[] = { {PCI_VDEVICE(NEOMAGIC, PCI_DEVICE_ID_NEOMAGIC_NM256AV_AUDIO), 0}, {PCI_VDEVICE(NEOMAGIC, PCI_DEVICE_ID_NEOMAGIC_NM256ZX_AUDIO), 0}, {PCI_VDEVICE(NEOMAGIC, PCI_DEVICE_ID_NEOMAGIC_NM256XL_PLUS_AUDIO), 0}, diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c index ada6c256378e..74afb6b75976 100644 --- a/sound/pci/oxygen/oxygen.c +++ b/sound/pci/oxygen/oxygen.c @@ -97,7 +97,7 @@ enum { MODEL_XONAR_DGX, }; -static DEFINE_PCI_DEVICE_TABLE(oxygen_ids) = { +static const struct pci_device_id oxygen_ids[] = { /* C-Media's reference design */ { OXYGEN_PCI_SUBID(0x10b0, 0x0216), .driver_data = MODEL_CMEDIA_REF }, { OXYGEN_PCI_SUBID(0x10b0, 0x0217), .driver_data = MODEL_CMEDIA_REF }, diff --git a/sound/pci/oxygen/virtuoso.c b/sound/pci/oxygen/virtuoso.c index 64b9fda5f04a..7b317a28a19c 100644 --- a/sound/pci/oxygen/virtuoso.c +++ b/sound/pci/oxygen/virtuoso.c @@ -41,7 +41,7 @@ MODULE_PARM_DESC(id, "ID string"); module_param_array(enable, bool, NULL, 0444); MODULE_PARM_DESC(enable, "enable card"); -static DEFINE_PCI_DEVICE_TABLE(xonar_ids) = { +static const struct pci_device_id xonar_ids[] = { { OXYGEN_PCI_SUBID(0x1043, 0x8269) }, { OXYGEN_PCI_SUBID(0x1043, 0x8275) }, { OXYGEN_PCI_SUBID(0x1043, 0x82b7) }, @@ -53,6 +53,7 @@ static DEFINE_PCI_DEVICE_TABLE(xonar_ids) = { { OXYGEN_PCI_SUBID(0x1043, 0x835e) }, { OXYGEN_PCI_SUBID(0x1043, 0x838e) }, { OXYGEN_PCI_SUBID(0x1043, 0x8522) }, + { OXYGEN_PCI_SUBID(0x1043, 0x85f4) }, { OXYGEN_PCI_SUBID_BROKEN_EEPROM }, { } }; diff --git a/sound/pci/oxygen/xonar_pcm179x.c b/sound/pci/oxygen/xonar_pcm179x.c index c8c7f2c9b355..e02605931669 100644 --- a/sound/pci/oxygen/xonar_pcm179x.c +++ b/sound/pci/oxygen/xonar_pcm179x.c @@ -100,8 +100,8 @@ */ /* - * Xonar Essence ST (Deluxe)/STX - * ----------------------------- + * Xonar Essence ST (Deluxe)/STX (II) + * ---------------------------------- * * CMI8788: * @@ -1138,6 +1138,14 @@ int get_xonar_pcm179x_model(struct oxygen *chip, chip->model.resume = xonar_stx_resume; chip->model.set_dac_params = set_pcm1796_params; break; + case 0x85f4: + chip->model = model_xonar_st; + /* TODO: daughterboard support */ + chip->model.shortname = "Xonar STX II"; + chip->model.init = xonar_stx_init; + chip->model.resume = xonar_stx_resume; + chip->model.set_dac_params = set_pcm1796_params; + break; default: return -EINVAL; } diff --git a/sound/pci/pcxhr/pcxhr.c b/sound/pci/pcxhr/pcxhr.c index 8d09444ff88b..68a37a7906c1 100644 --- a/sound/pci/pcxhr/pcxhr.c +++ b/sound/pci/pcxhr/pcxhr.c @@ -102,7 +102,7 @@ enum { PCI_ID_LAST }; -static DEFINE_PCI_DEVICE_TABLE(pcxhr_ids) = { +static const struct pci_device_id pcxhr_ids[] = { { 0x10b5, 0x9656, 0x1369, 0xb001, 0, 0, PCI_ID_VX882HR, }, { 0x10b5, 0x9656, 0x1369, 0xb101, 0, 0, PCI_ID_PCX882HR, }, { 0x10b5, 0x9656, 0x1369, 0xb201, 0, 0, PCI_ID_VX881HR, }, diff --git a/sound/pci/riptide/riptide.c b/sound/pci/riptide/riptide.c index b4a8278241b1..6abc2ac8fffb 100644 --- a/sound/pci/riptide/riptide.c +++ b/sound/pci/riptide/riptide.c @@ -508,7 +508,7 @@ static int riptide_reset(struct cmdif *cif, struct snd_riptide *chip); /* */ -static DEFINE_PCI_DEVICE_TABLE(snd_riptide_ids) = { +static const struct pci_device_id snd_riptide_ids[] = { { PCI_DEVICE(0x127a, 0x4310) }, { PCI_DEVICE(0x127a, 0x4320) }, { PCI_DEVICE(0x127a, 0x4330) }, @@ -517,7 +517,7 @@ static DEFINE_PCI_DEVICE_TABLE(snd_riptide_ids) = { }; #ifdef SUPPORT_JOYSTICK -static DEFINE_PCI_DEVICE_TABLE(snd_riptide_joystick_ids) = { +static const struct pci_device_id snd_riptide_joystick_ids[] = { { PCI_DEVICE(0x127a, 0x4312) }, { PCI_DEVICE(0x127a, 0x4322) }, { PCI_DEVICE(0x127a, 0x4332) }, @@ -941,7 +941,7 @@ setmixer(struct cmdif *cif, short num, unsigned short rval, unsigned short lval) union cmdret rptr = CMDRET_ZERO; int i = 0; - snd_printdd("sent mixer %d: 0x%d 0x%d\n", num, rval, lval); + snd_printdd("sent mixer %d: 0x%x 0x%x\n", num, rval, lval); do { SEND_SDGV(cif, num, num, rval, lval); SEND_RDGV(cif, num, num, &rptr); @@ -1080,7 +1080,7 @@ getmixer(struct cmdif *cif, short num, unsigned short *rval, return -EIO; *rval = rptr.retwords[0]; *lval = rptr.retwords[1]; - snd_printdd("got mixer %d: 0x%d 0x%d\n", num, *rval, *lval); + snd_printdd("got mixer %d: 0x%x 0x%x\n", num, *rval, *lval); return 0; } diff --git a/sound/pci/rme32.c b/sound/pci/rme32.c index cc2f0c1b6484..4afd3cab775b 100644 --- a/sound/pci/rme32.c +++ b/sound/pci/rme32.c @@ -226,7 +226,7 @@ struct rme32 { struct snd_kcontrol *spdif_ctl; }; -static DEFINE_PCI_DEVICE_TABLE(snd_rme32_ids) = { +static const struct pci_device_id snd_rme32_ids[] = { {PCI_VDEVICE(XILINX_RME, PCI_DEVICE_ID_RME_DIGI32), 0,}, {PCI_VDEVICE(XILINX_RME, PCI_DEVICE_ID_RME_DIGI32_8), 0,}, {PCI_VDEVICE(XILINX_RME, PCI_DEVICE_ID_RME_DIGI32_PRO), 0,}, diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c index 76169929770d..5a395c87c6fc 100644 --- a/sound/pci/rme96.c +++ b/sound/pci/rme96.c @@ -263,7 +263,7 @@ struct rme96 { struct snd_kcontrol *spdif_ctl; }; -static DEFINE_PCI_DEVICE_TABLE(snd_rme96_ids) = { +static const struct pci_device_id snd_rme96_ids[] = { { PCI_VDEVICE(XILINX, PCI_DEVICE_ID_RME_DIGI96), 0, }, { PCI_VDEVICE(XILINX, PCI_DEVICE_ID_RME_DIGI96_8), 0, }, { PCI_VDEVICE(XILINX, PCI_DEVICE_ID_RME_DIGI96_8_PRO), 0, }, diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c index 4c6f5d1c9882..7646ba1664eb 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/sound/pci/rme9652/hdsp.c @@ -597,7 +597,7 @@ static void snd_hammerfall_free_buffer(struct snd_dma_buffer *dmab, struct pci_d } -static DEFINE_PCI_DEVICE_TABLE(snd_hdsp_ids) = { +static const struct pci_device_id snd_hdsp_ids[] = { { .vendor = PCI_VENDOR_ID_XILINX, .device = PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP, diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index cb82b593473a..52d86af3ef2d 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -1077,7 +1077,7 @@ struct hdspm { }; -static DEFINE_PCI_DEVICE_TABLE(snd_hdspm_ids) = { +static const struct pci_device_id snd_hdspm_ids[] = { { .vendor = PCI_VENDOR_ID_XILINX, .device = PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP_MADI, diff --git a/sound/pci/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c index 1d9be90f7748..fa9a2a8dce5a 100644 --- a/sound/pci/rme9652/rme9652.c +++ b/sound/pci/rme9652/rme9652.c @@ -307,7 +307,7 @@ static void snd_hammerfall_free_buffer(struct snd_dma_buffer *dmab, struct pci_d } -static DEFINE_PCI_DEVICE_TABLE(snd_rme9652_ids) = { +static const struct pci_device_id snd_rme9652_ids[] = { { .vendor = 0x10ee, .device = 0x3fc4, diff --git a/sound/pci/sis7019.c b/sound/pci/sis7019.c index 6b26b93e001d..7f6a0a0d115a 100644 --- a/sound/pci/sis7019.c +++ b/sound/pci/sis7019.c @@ -52,7 +52,7 @@ MODULE_PARM_DESC(enable, "Enable SiS7019 Audio Accelerator."); module_param(codecs, int, 0444); MODULE_PARM_DESC(codecs, "Set bit to indicate that codec number is expected to be present (default 1)"); -static DEFINE_PCI_DEVICE_TABLE(snd_sis7019_ids) = { +static const struct pci_device_id snd_sis7019_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_SI, 0x7019) }, { 0, } }; diff --git a/sound/pci/sonicvibes.c b/sound/pci/sonicvibes.c index 2044dc742071..5b0d317cc9a6 100644 --- a/sound/pci/sonicvibes.c +++ b/sound/pci/sonicvibes.c @@ -242,7 +242,7 @@ struct sonicvibes { #endif }; -static DEFINE_PCI_DEVICE_TABLE(snd_sonic_ids) = { +static const struct pci_device_id snd_sonic_ids[] = { { PCI_VDEVICE(S3, 0xca00), 0, }, { 0, } }; diff --git a/sound/pci/trident/trident.c b/sound/pci/trident/trident.c index d852458caf38..a54cd6879b31 100644 --- a/sound/pci/trident/trident.c +++ b/sound/pci/trident/trident.c @@ -62,7 +62,7 @@ MODULE_PARM_DESC(pcm_channels, "Number of hardware channels assigned for PCM."); module_param_array(wavetable_size, int, NULL, 0444); MODULE_PARM_DESC(wavetable_size, "Maximum memory size in kB for wavetable synth."); -static DEFINE_PCI_DEVICE_TABLE(snd_trident_ids) = { +static const struct pci_device_id snd_trident_ids[] = { {PCI_DEVICE(PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_TRIDENT_4DWAVE_DX), PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0}, {PCI_DEVICE(PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_TRIDENT_4DWAVE_NX), diff --git a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c index 1272c18a2544..da875dced2ef 100644 --- a/sound/pci/trident/trident_main.c +++ b/sound/pci/trident/trident_main.c @@ -3880,14 +3880,12 @@ void snd_trident_free_voice(struct snd_trident * trident, struct snd_trident_voi { unsigned long flags; void (*private_free)(struct snd_trident_voice *); - void *private_data; if (voice == NULL || !voice->use) return; snd_trident_clear_voices(trident, voice->number, voice->number); spin_lock_irqsave(&trident->voice_alloc, flags); private_free = voice->private_free; - private_data = voice->private_data; voice->private_free = NULL; voice->private_data = NULL; if (voice->pcm) diff --git a/sound/pci/trident/trident_memory.c b/sound/pci/trident/trident_memory.c index 3102a579660b..04c474658e3c 100644 --- a/sound/pci/trident/trident_memory.c +++ b/sound/pci/trident/trident_memory.c @@ -139,12 +139,11 @@ static inline void *offset_ptr(struct snd_trident *trident, int offset) static struct snd_util_memblk * search_empty(struct snd_util_memhdr *hdr, int size) { - struct snd_util_memblk *blk, *prev; + struct snd_util_memblk *blk; int page, psize; struct list_head *p; psize = get_aligned_page(size + ALIGN_PAGE_SIZE -1); - prev = NULL; page = 0; list_for_each(p, &hdr->block) { blk = list_entry(p, struct snd_util_memblk, list); diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index 95b98f537b67..ecedf4dbfa2a 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c @@ -404,7 +404,7 @@ struct via82xx { #endif }; -static DEFINE_PCI_DEVICE_TABLE(snd_via82xx_ids) = { +static const struct pci_device_id snd_via82xx_ids[] = { /* 0x1106, 0x3058 */ { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_82C686_5), TYPE_CARD_VIA686, }, /* 686A */ /* 0x1106, 0x3059 */ diff --git a/sound/pci/via82xx_modem.c b/sound/pci/via82xx_modem.c index 46a0526b1d79..fd46ffe12e4f 100644 --- a/sound/pci/via82xx_modem.c +++ b/sound/pci/via82xx_modem.c @@ -260,7 +260,7 @@ struct via82xx_modem { struct snd_info_entry *proc_entry; }; -static DEFINE_PCI_DEVICE_TABLE(snd_via82xx_modem_ids) = { +static const struct pci_device_id snd_via82xx_modem_ids[] = { { PCI_VDEVICE(VIA, 0x3068), TYPE_CARD_VIA82XX_MODEM, }, { 0, } }; diff --git a/sound/pci/vx222/vx222.c b/sound/pci/vx222/vx222.c index ff9074d22607..3dc4732142ee 100644 --- a/sound/pci/vx222/vx222.c +++ b/sound/pci/vx222/vx222.c @@ -60,7 +60,7 @@ enum { VX_PCI_VX222_NEW }; -static DEFINE_PCI_DEVICE_TABLE(snd_vx222_ids) = { +static const struct pci_device_id snd_vx222_ids[] = { { 0x10b5, 0x9050, 0x1369, PCI_ANY_ID, 0, 0, VX_PCI_VX222_OLD, }, /* PLX */ { 0x10b5, 0x9030, 0x1369, PCI_ANY_ID, 0, 0, VX_PCI_VX222_NEW, }, /* PLX */ { 0, } diff --git a/sound/pci/ymfpci/ymfpci.c b/sound/pci/ymfpci/ymfpci.c index 82eed164b275..47a192369e8f 100644 --- a/sound/pci/ymfpci/ymfpci.c +++ b/sound/pci/ymfpci/ymfpci.c @@ -66,7 +66,7 @@ MODULE_PARM_DESC(joystick_port, "Joystick port address"); module_param_array(rear_switch, bool, NULL, 0444); MODULE_PARM_DESC(rear_switch, "Enable shared rear/line-in switch"); -static DEFINE_PCI_DEVICE_TABLE(snd_ymfpci_ids) = { +static const struct pci_device_id snd_ymfpci_ids[] = { { PCI_VDEVICE(YAMAHA, 0x0004), 0, }, /* YMF724 */ { PCI_VDEVICE(YAMAHA, 0x000d), 0, }, /* YMF724F */ { PCI_VDEVICE(YAMAHA, 0x000a), 0, }, /* YMF740 */ diff --git a/sound/ppc/pmac.c b/sound/ppc/pmac.c index 7a43c0c38316..8a431bcb056c 100644 --- a/sound/ppc/pmac.c +++ b/sound/ppc/pmac.c @@ -992,9 +992,9 @@ static int snd_pmac_detect(struct snd_pmac *chip) return -ENODEV; if (!sound) { - sound = of_find_node_by_name(NULL, "sound"); - while (sound && sound->parent != chip->node) - sound = of_find_node_by_name(sound, "sound"); + for_each_node_by_name(sound, "sound") + if (sound->parent == chip->node) + break; } if (! sound) { of_node_put(chip->node); diff --git a/sound/soc/au1x/psc-ac97.c b/sound/soc/au1x/psc-ac97.c index 986dcec79fa0..84f31e1f9d24 100644 --- a/sound/soc/au1x/psc-ac97.c +++ b/sound/soc/au1x/psc-ac97.c @@ -79,28 +79,28 @@ static unsigned short au1xpsc_ac97_read(struct snd_ac97 *ac97, unsigned short retry, tmo; unsigned long data; - au_writel(PSC_AC97EVNT_CD, AC97_EVNT(pscdata)); - au_sync(); + __raw_writel(PSC_AC97EVNT_CD, AC97_EVNT(pscdata)); + wmb(); /* drain writebuffer */ retry = AC97_RW_RETRIES; do { mutex_lock(&pscdata->lock); - au_writel(PSC_AC97CDC_RD | PSC_AC97CDC_INDX(reg), + __raw_writel(PSC_AC97CDC_RD | PSC_AC97CDC_INDX(reg), AC97_CDC(pscdata)); - au_sync(); + wmb(); /* drain writebuffer */ tmo = 20; do { udelay(21); - if (au_readl(AC97_EVNT(pscdata)) & PSC_AC97EVNT_CD) + if (__raw_readl(AC97_EVNT(pscdata)) & PSC_AC97EVNT_CD) break; } while (--tmo); - data = au_readl(AC97_CDC(pscdata)); + data = __raw_readl(AC97_CDC(pscdata)); - au_writel(PSC_AC97EVNT_CD, AC97_EVNT(pscdata)); - au_sync(); + __raw_writel(PSC_AC97EVNT_CD, AC97_EVNT(pscdata)); + wmb(); /* drain writebuffer */ mutex_unlock(&pscdata->lock); @@ -119,26 +119,26 @@ static void au1xpsc_ac97_write(struct snd_ac97 *ac97, unsigned short reg, struct au1xpsc_audio_data *pscdata = ac97_to_pscdata(ac97); unsigned int tmo, retry; - au_writel(PSC_AC97EVNT_CD, AC97_EVNT(pscdata)); - au_sync(); + __raw_writel(PSC_AC97EVNT_CD, AC97_EVNT(pscdata)); + wmb(); /* drain writebuffer */ retry = AC97_RW_RETRIES; do { mutex_lock(&pscdata->lock); - au_writel(PSC_AC97CDC_INDX(reg) | (val & 0xffff), + __raw_writel(PSC_AC97CDC_INDX(reg) | (val & 0xffff), AC97_CDC(pscdata)); - au_sync(); + wmb(); /* drain writebuffer */ tmo = 20; do { udelay(21); - if (au_readl(AC97_EVNT(pscdata)) & PSC_AC97EVNT_CD) + if (__raw_readl(AC97_EVNT(pscdata)) & PSC_AC97EVNT_CD) break; } while (--tmo); - au_writel(PSC_AC97EVNT_CD, AC97_EVNT(pscdata)); - au_sync(); + __raw_writel(PSC_AC97EVNT_CD, AC97_EVNT(pscdata)); + wmb(); /* drain writebuffer */ mutex_unlock(&pscdata->lock); } while (--retry && !tmo); @@ -149,11 +149,11 @@ static void au1xpsc_ac97_warm_reset(struct snd_ac97 *ac97) { struct au1xpsc_audio_data *pscdata = ac97_to_pscdata(ac97); - au_writel(PSC_AC97RST_SNC, AC97_RST(pscdata)); - au_sync(); + __raw_writel(PSC_AC97RST_SNC, AC97_RST(pscdata)); + wmb(); /* drain writebuffer */ msleep(10); - au_writel(0, AC97_RST(pscdata)); - au_sync(); + __raw_writel(0, AC97_RST(pscdata)); + wmb(); /* drain writebuffer */ } static void au1xpsc_ac97_cold_reset(struct snd_ac97 *ac97) @@ -162,25 +162,25 @@ static void au1xpsc_ac97_cold_reset(struct snd_ac97 *ac97) int i; /* disable PSC during cold reset */ - au_writel(0, AC97_CFG(au1xpsc_ac97_workdata)); - au_sync(); - au_writel(PSC_CTRL_DISABLE, PSC_CTRL(pscdata)); - au_sync(); + __raw_writel(0, AC97_CFG(au1xpsc_ac97_workdata)); + wmb(); /* drain writebuffer */ + __raw_writel(PSC_CTRL_DISABLE, PSC_CTRL(pscdata)); + wmb(); /* drain writebuffer */ /* issue cold reset */ - au_writel(PSC_AC97RST_RST, AC97_RST(pscdata)); - au_sync(); + __raw_writel(PSC_AC97RST_RST, AC97_RST(pscdata)); + wmb(); /* drain writebuffer */ msleep(500); - au_writel(0, AC97_RST(pscdata)); - au_sync(); + __raw_writel(0, AC97_RST(pscdata)); + wmb(); /* drain writebuffer */ /* enable PSC */ - au_writel(PSC_CTRL_ENABLE, PSC_CTRL(pscdata)); - au_sync(); + __raw_writel(PSC_CTRL_ENABLE, PSC_CTRL(pscdata)); + wmb(); /* drain writebuffer */ /* wait for PSC to indicate it's ready */ i = 1000; - while (!((au_readl(AC97_STAT(pscdata)) & PSC_AC97STAT_SR)) && (--i)) + while (!((__raw_readl(AC97_STAT(pscdata)) & PSC_AC97STAT_SR)) && (--i)) msleep(1); if (i == 0) { @@ -189,12 +189,12 @@ static void au1xpsc_ac97_cold_reset(struct snd_ac97 *ac97) } /* enable the ac97 function */ - au_writel(pscdata->cfg | PSC_AC97CFG_DE_ENABLE, AC97_CFG(pscdata)); - au_sync(); + __raw_writel(pscdata->cfg | PSC_AC97CFG_DE_ENABLE, AC97_CFG(pscdata)); + wmb(); /* drain writebuffer */ /* wait for AC97 core to become ready */ i = 1000; - while (!((au_readl(AC97_STAT(pscdata)) & PSC_AC97STAT_DR)) && (--i)) + while (!((__raw_readl(AC97_STAT(pscdata)) & PSC_AC97STAT_DR)) && (--i)) msleep(1); if (i == 0) printk(KERN_ERR "au1xpsc-ac97: AC97 ctrl not ready\n"); @@ -218,8 +218,8 @@ static int au1xpsc_ac97_hw_params(struct snd_pcm_substream *substream, chans = params_channels(params); - r = ro = au_readl(AC97_CFG(pscdata)); - stat = au_readl(AC97_STAT(pscdata)); + r = ro = __raw_readl(AC97_CFG(pscdata)); + stat = __raw_readl(AC97_STAT(pscdata)); /* already active? */ if (stat & (PSC_AC97STAT_TB | PSC_AC97STAT_RB)) { @@ -252,28 +252,28 @@ static int au1xpsc_ac97_hw_params(struct snd_pcm_substream *substream, mutex_lock(&pscdata->lock); /* disable AC97 device controller first... */ - au_writel(r & ~PSC_AC97CFG_DE_ENABLE, AC97_CFG(pscdata)); - au_sync(); + __raw_writel(r & ~PSC_AC97CFG_DE_ENABLE, AC97_CFG(pscdata)); + wmb(); /* drain writebuffer */ /* ...wait for it... */ t = 100; - while ((au_readl(AC97_STAT(pscdata)) & PSC_AC97STAT_DR) && --t) + while ((__raw_readl(AC97_STAT(pscdata)) & PSC_AC97STAT_DR) && --t) msleep(1); if (!t) printk(KERN_ERR "PSC-AC97: can't disable!\n"); /* ...write config... */ - au_writel(r, AC97_CFG(pscdata)); - au_sync(); + __raw_writel(r, AC97_CFG(pscdata)); + wmb(); /* drain writebuffer */ /* ...enable the AC97 controller again... */ - au_writel(r | PSC_AC97CFG_DE_ENABLE, AC97_CFG(pscdata)); - au_sync(); + __raw_writel(r | PSC_AC97CFG_DE_ENABLE, AC97_CFG(pscdata)); + wmb(); /* drain writebuffer */ /* ...and wait for ready bit */ t = 100; - while ((!(au_readl(AC97_STAT(pscdata)) & PSC_AC97STAT_DR)) && --t) + while ((!(__raw_readl(AC97_STAT(pscdata)) & PSC_AC97STAT_DR)) && --t) msleep(1); if (!t) @@ -300,21 +300,21 @@ static int au1xpsc_ac97_trigger(struct snd_pcm_substream *substream, switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: - au_writel(AC97PCR_CLRFIFO(stype), AC97_PCR(pscdata)); - au_sync(); - au_writel(AC97PCR_START(stype), AC97_PCR(pscdata)); - au_sync(); + __raw_writel(AC97PCR_CLRFIFO(stype), AC97_PCR(pscdata)); + wmb(); /* drain writebuffer */ + __raw_writel(AC97PCR_START(stype), AC97_PCR(pscdata)); + wmb(); /* drain writebuffer */ break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: - au_writel(AC97PCR_STOP(stype), AC97_PCR(pscdata)); - au_sync(); + __raw_writel(AC97PCR_STOP(stype), AC97_PCR(pscdata)); + wmb(); /* drain writebuffer */ - while (au_readl(AC97_STAT(pscdata)) & AC97STAT_BUSY(stype)) + while (__raw_readl(AC97_STAT(pscdata)) & AC97STAT_BUSY(stype)) asm volatile ("nop"); - au_writel(AC97PCR_CLRFIFO(stype), AC97_PCR(pscdata)); - au_sync(); + __raw_writel(AC97PCR_CLRFIFO(stype), AC97_PCR(pscdata)); + wmb(); /* drain writebuffer */ break; default: @@ -398,13 +398,13 @@ static int au1xpsc_ac97_drvprobe(struct platform_device *pdev) PSC_AC97CFG_DE_ENABLE; /* preserve PSC clock source set up by platform */ - sel = au_readl(PSC_SEL(wd)) & PSC_SEL_CLK_MASK; - au_writel(PSC_CTRL_DISABLE, PSC_CTRL(wd)); - au_sync(); - au_writel(0, PSC_SEL(wd)); - au_sync(); - au_writel(PSC_SEL_PS_AC97MODE | sel, PSC_SEL(wd)); - au_sync(); + sel = __raw_readl(PSC_SEL(wd)) & PSC_SEL_CLK_MASK; + __raw_writel(PSC_CTRL_DISABLE, PSC_CTRL(wd)); + wmb(); /* drain writebuffer */ + __raw_writel(0, PSC_SEL(wd)); + wmb(); /* drain writebuffer */ + __raw_writel(PSC_SEL_PS_AC97MODE | sel, PSC_SEL(wd)); + wmb(); /* drain writebuffer */ /* name the DAI like this device instance ("au1xpsc-ac97.PSCINDEX") */ memcpy(&wd->dai_drv, &au1xpsc_ac97_dai_template, @@ -433,10 +433,10 @@ static int au1xpsc_ac97_drvremove(struct platform_device *pdev) snd_soc_unregister_component(&pdev->dev); /* disable PSC completely */ - au_writel(0, AC97_CFG(wd)); - au_sync(); - au_writel(PSC_CTRL_DISABLE, PSC_CTRL(wd)); - au_sync(); + __raw_writel(0, AC97_CFG(wd)); + wmb(); /* drain writebuffer */ + __raw_writel(PSC_CTRL_DISABLE, PSC_CTRL(wd)); + wmb(); /* drain writebuffer */ au1xpsc_ac97_workdata = NULL; /* MDEV */ @@ -449,12 +449,12 @@ static int au1xpsc_ac97_drvsuspend(struct device *dev) struct au1xpsc_audio_data *wd = dev_get_drvdata(dev); /* save interesting registers and disable PSC */ - wd->pm[0] = au_readl(PSC_SEL(wd)); + wd->pm[0] = __raw_readl(PSC_SEL(wd)); - au_writel(0, AC97_CFG(wd)); - au_sync(); - au_writel(PSC_CTRL_DISABLE, PSC_CTRL(wd)); - au_sync(); + __raw_writel(0, AC97_CFG(wd)); + wmb(); /* drain writebuffer */ + __raw_writel(PSC_CTRL_DISABLE, PSC_CTRL(wd)); + wmb(); /* drain writebuffer */ return 0; } @@ -464,8 +464,8 @@ static int au1xpsc_ac97_drvresume(struct device *dev) struct au1xpsc_audio_data *wd = dev_get_drvdata(dev); /* restore PSC clock config */ - au_writel(wd->pm[0] | PSC_SEL_PS_AC97MODE, PSC_SEL(wd)); - au_sync(); + __raw_writel(wd->pm[0] | PSC_SEL_PS_AC97MODE, PSC_SEL(wd)); + wmb(); /* drain writebuffer */ /* after this point the ac97 core will cold-reset the codec. * During cold-reset the PSC is reinitialized and the last diff --git a/sound/soc/au1x/psc-i2s.c b/sound/soc/au1x/psc-i2s.c index fe923a7bdc39..814beffc56f2 100644 --- a/sound/soc/au1x/psc-i2s.c +++ b/sound/soc/au1x/psc-i2s.c @@ -120,10 +120,10 @@ static int au1xpsc_i2s_hw_params(struct snd_pcm_substream *substream, unsigned long stat; /* check if the PSC is already streaming data */ - stat = au_readl(I2S_STAT(pscdata)); + stat = __raw_readl(I2S_STAT(pscdata)); if (stat & (PSC_I2SSTAT_TB | PSC_I2SSTAT_RB)) { /* reject parameters not currently set up in hardware */ - cfgbits = au_readl(I2S_CFG(pscdata)); + cfgbits = __raw_readl(I2S_CFG(pscdata)); if ((PSC_I2SCFG_GET_LEN(cfgbits) != params->msbits) || (params_rate(params) != pscdata->rate)) return -EINVAL; @@ -149,33 +149,33 @@ static int au1xpsc_i2s_configure(struct au1xpsc_audio_data *pscdata) unsigned long tmo; /* bring PSC out of sleep, and configure I2S unit */ - au_writel(PSC_CTRL_ENABLE, PSC_CTRL(pscdata)); - au_sync(); + __raw_writel(PSC_CTRL_ENABLE, PSC_CTRL(pscdata)); + wmb(); /* drain writebuffer */ tmo = 1000000; - while (!(au_readl(I2S_STAT(pscdata)) & PSC_I2SSTAT_SR) && tmo) + while (!(__raw_readl(I2S_STAT(pscdata)) & PSC_I2SSTAT_SR) && tmo) tmo--; if (!tmo) goto psc_err; - au_writel(0, I2S_CFG(pscdata)); - au_sync(); - au_writel(pscdata->cfg | PSC_I2SCFG_DE_ENABLE, I2S_CFG(pscdata)); - au_sync(); + __raw_writel(0, I2S_CFG(pscdata)); + wmb(); /* drain writebuffer */ + __raw_writel(pscdata->cfg | PSC_I2SCFG_DE_ENABLE, I2S_CFG(pscdata)); + wmb(); /* drain writebuffer */ /* wait for I2S controller to become ready */ tmo = 1000000; - while (!(au_readl(I2S_STAT(pscdata)) & PSC_I2SSTAT_DR) && tmo) + while (!(__raw_readl(I2S_STAT(pscdata)) & PSC_I2SSTAT_DR) && tmo) tmo--; if (tmo) return 0; psc_err: - au_writel(0, I2S_CFG(pscdata)); - au_writel(PSC_CTRL_SUSPEND, PSC_CTRL(pscdata)); - au_sync(); + __raw_writel(0, I2S_CFG(pscdata)); + __raw_writel(PSC_CTRL_SUSPEND, PSC_CTRL(pscdata)); + wmb(); /* drain writebuffer */ return -ETIMEDOUT; } @@ -187,26 +187,26 @@ static int au1xpsc_i2s_start(struct au1xpsc_audio_data *pscdata, int stype) ret = 0; /* if both TX and RX are idle, configure the PSC */ - stat = au_readl(I2S_STAT(pscdata)); + stat = __raw_readl(I2S_STAT(pscdata)); if (!(stat & (PSC_I2SSTAT_TB | PSC_I2SSTAT_RB))) { ret = au1xpsc_i2s_configure(pscdata); if (ret) goto out; } - au_writel(I2SPCR_CLRFIFO(stype), I2S_PCR(pscdata)); - au_sync(); - au_writel(I2SPCR_START(stype), I2S_PCR(pscdata)); - au_sync(); + __raw_writel(I2SPCR_CLRFIFO(stype), I2S_PCR(pscdata)); + wmb(); /* drain writebuffer */ + __raw_writel(I2SPCR_START(stype), I2S_PCR(pscdata)); + wmb(); /* drain writebuffer */ /* wait for start confirmation */ tmo = 1000000; - while (!(au_readl(I2S_STAT(pscdata)) & I2SSTAT_BUSY(stype)) && tmo) + while (!(__raw_readl(I2S_STAT(pscdata)) & I2SSTAT_BUSY(stype)) && tmo) tmo--; if (!tmo) { - au_writel(I2SPCR_STOP(stype), I2S_PCR(pscdata)); - au_sync(); + __raw_writel(I2SPCR_STOP(stype), I2S_PCR(pscdata)); + wmb(); /* drain writebuffer */ ret = -ETIMEDOUT; } out: @@ -217,21 +217,21 @@ static int au1xpsc_i2s_stop(struct au1xpsc_audio_data *pscdata, int stype) { unsigned long tmo, stat; - au_writel(I2SPCR_STOP(stype), I2S_PCR(pscdata)); - au_sync(); + __raw_writel(I2SPCR_STOP(stype), I2S_PCR(pscdata)); + wmb(); /* drain writebuffer */ /* wait for stop confirmation */ tmo = 1000000; - while ((au_readl(I2S_STAT(pscdata)) & I2SSTAT_BUSY(stype)) && tmo) + while ((__raw_readl(I2S_STAT(pscdata)) & I2SSTAT_BUSY(stype)) && tmo) tmo--; /* if both TX and RX are idle, disable PSC */ - stat = au_readl(I2S_STAT(pscdata)); + stat = __raw_readl(I2S_STAT(pscdata)); if (!(stat & (PSC_I2SSTAT_TB | PSC_I2SSTAT_RB))) { - au_writel(0, I2S_CFG(pscdata)); - au_sync(); - au_writel(PSC_CTRL_SUSPEND, PSC_CTRL(pscdata)); - au_sync(); + __raw_writel(0, I2S_CFG(pscdata)); + wmb(); /* drain writebuffer */ + __raw_writel(PSC_CTRL_SUSPEND, PSC_CTRL(pscdata)); + wmb(); /* drain writebuffer */ } return 0; } @@ -332,12 +332,12 @@ static int au1xpsc_i2s_drvprobe(struct platform_device *pdev) /* preserve PSC clock source set up by platform (dev.platform_data * is already occupied by soc layer) */ - sel = au_readl(PSC_SEL(wd)) & PSC_SEL_CLK_MASK; - au_writel(PSC_CTRL_DISABLE, PSC_CTRL(wd)); - au_sync(); - au_writel(PSC_SEL_PS_I2SMODE | sel, PSC_SEL(wd)); - au_writel(0, I2S_CFG(wd)); - au_sync(); + sel = __raw_readl(PSC_SEL(wd)) & PSC_SEL_CLK_MASK; + __raw_writel(PSC_CTRL_DISABLE, PSC_CTRL(wd)); + wmb(); /* drain writebuffer */ + __raw_writel(PSC_SEL_PS_I2SMODE | sel, PSC_SEL(wd)); + __raw_writel(0, I2S_CFG(wd)); + wmb(); /* drain writebuffer */ /* preconfigure: set max rx/tx fifo depths */ wd->cfg |= PSC_I2SCFG_RT_FIFO8 | PSC_I2SCFG_TT_FIFO8; @@ -364,10 +364,10 @@ static int au1xpsc_i2s_drvremove(struct platform_device *pdev) snd_soc_unregister_component(&pdev->dev); - au_writel(0, I2S_CFG(wd)); - au_sync(); - au_writel(PSC_CTRL_DISABLE, PSC_CTRL(wd)); - au_sync(); + __raw_writel(0, I2S_CFG(wd)); + wmb(); /* drain writebuffer */ + __raw_writel(PSC_CTRL_DISABLE, PSC_CTRL(wd)); + wmb(); /* drain writebuffer */ return 0; } @@ -378,12 +378,12 @@ static int au1xpsc_i2s_drvsuspend(struct device *dev) struct au1xpsc_audio_data *wd = dev_get_drvdata(dev); /* save interesting register and disable PSC */ - wd->pm[0] = au_readl(PSC_SEL(wd)); + wd->pm[0] = __raw_readl(PSC_SEL(wd)); - au_writel(0, I2S_CFG(wd)); - au_sync(); - au_writel(PSC_CTRL_DISABLE, PSC_CTRL(wd)); - au_sync(); + __raw_writel(0, I2S_CFG(wd)); + wmb(); /* drain writebuffer */ + __raw_writel(PSC_CTRL_DISABLE, PSC_CTRL(wd)); + wmb(); /* drain writebuffer */ return 0; } @@ -393,12 +393,12 @@ static int au1xpsc_i2s_drvresume(struct device *dev) struct au1xpsc_audio_data *wd = dev_get_drvdata(dev); /* select I2S mode and PSC clock */ - au_writel(PSC_CTRL_DISABLE, PSC_CTRL(wd)); - au_sync(); - au_writel(0, PSC_SEL(wd)); - au_sync(); - au_writel(wd->pm[0], PSC_SEL(wd)); - au_sync(); + __raw_writel(PSC_CTRL_DISABLE, PSC_CTRL(wd)); + wmb(); /* drain writebuffer */ + __raw_writel(0, PSC_SEL(wd)); + wmb(); /* drain writebuffer */ + __raw_writel(wd->pm[0], PSC_SEL(wd)); + wmb(); /* drain writebuffer */ return 0; } diff --git a/sound/soc/au1x/psc.h b/sound/soc/au1x/psc.h index b16b2e02e0c9..74dffeb641fa 100644 --- a/sound/soc/au1x/psc.h +++ b/sound/soc/au1x/psc.h @@ -27,16 +27,16 @@ struct au1xpsc_audio_data { }; /* easy access macros */ -#define PSC_CTRL(x) ((unsigned long)((x)->mmio) + PSC_CTRL_OFFSET) -#define PSC_SEL(x) ((unsigned long)((x)->mmio) + PSC_SEL_OFFSET) -#define I2S_STAT(x) ((unsigned long)((x)->mmio) + PSC_I2SSTAT_OFFSET) -#define I2S_CFG(x) ((unsigned long)((x)->mmio) + PSC_I2SCFG_OFFSET) -#define I2S_PCR(x) ((unsigned long)((x)->mmio) + PSC_I2SPCR_OFFSET) -#define AC97_CFG(x) ((unsigned long)((x)->mmio) + PSC_AC97CFG_OFFSET) -#define AC97_CDC(x) ((unsigned long)((x)->mmio) + PSC_AC97CDC_OFFSET) -#define AC97_EVNT(x) ((unsigned long)((x)->mmio) + PSC_AC97EVNT_OFFSET) -#define AC97_PCR(x) ((unsigned long)((x)->mmio) + PSC_AC97PCR_OFFSET) -#define AC97_RST(x) ((unsigned long)((x)->mmio) + PSC_AC97RST_OFFSET) -#define AC97_STAT(x) ((unsigned long)((x)->mmio) + PSC_AC97STAT_OFFSET) +#define PSC_CTRL(x) ((x)->mmio + PSC_CTRL_OFFSET) +#define PSC_SEL(x) ((x)->mmio + PSC_SEL_OFFSET) +#define I2S_STAT(x) ((x)->mmio + PSC_I2SSTAT_OFFSET) +#define I2S_CFG(x) ((x)->mmio + PSC_I2SCFG_OFFSET) +#define I2S_PCR(x) ((x)->mmio + PSC_I2SPCR_OFFSET) +#define AC97_CFG(x) ((x)->mmio + PSC_AC97CFG_OFFSET) +#define AC97_CDC(x) ((x)->mmio + PSC_AC97CDC_OFFSET) +#define AC97_EVNT(x) ((x)->mmio + PSC_AC97EVNT_OFFSET) +#define AC97_PCR(x) ((x)->mmio + PSC_AC97PCR_OFFSET) +#define AC97_RST(x) ((x)->mmio + PSC_AC97RST_OFFSET) +#define AC97_STAT(x) ((x)->mmio + PSC_AC97STAT_OFFSET) #endif diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 8838838e25ed..7678122f8fe0 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -43,6 +43,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_ALC5623 if I2C select SND_SOC_ALC5632 if I2C select SND_SOC_CQ0093VC if MFD_DAVINCI_VOICECODEC + select SND_SOC_CS35L32 if I2C select SND_SOC_CS42L51_I2C if I2C select SND_SOC_CS42L52 if I2C && INPUT select SND_SOC_CS42L56 if I2C && INPUT @@ -56,7 +57,10 @@ config SND_SOC_ALL_CODECS select SND_SOC_DA7213 if I2C select SND_SOC_DA732X if I2C select SND_SOC_DA9055 if I2C + select SND_SOC_DMIC select SND_SOC_BT_SCO + select SND_SOC_ES8328_SPI if SPI_MASTER + select SND_SOC_ES8328_I2C if I2C select SND_SOC_ISABELLE if I2C select SND_SOC_JZ4740_CODEC select SND_SOC_LM4857 if I2C @@ -323,6 +327,10 @@ config SND_SOC_ALC5632 config SND_SOC_CQ0093VC tristate +config SND_SOC_CS35L32 + tristate "Cirrus Logic CS35L32 CODEC" + depends on I2C + config SND_SOC_CS42L51 tristate @@ -405,6 +413,17 @@ config SND_SOC_DMIC config SND_SOC_HDMI_CODEC tristate "HDMI stub CODEC" +config SND_SOC_ES8328 + tristate "Everest Semi ES8328 CODEC" + +config SND_SOC_ES8328_I2C + tristate + select SND_SOC_ES8328 + +config SND_SOC_ES8328_SPI + tristate + select SND_SOC_ES8328 + config SND_SOC_ISABELLE tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 20afe0f0c5be..afba944657bc 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -32,6 +32,7 @@ snd-soc-ak4671-objs := ak4671.o snd-soc-ak5386-objs := ak5386.o snd-soc-arizona-objs := arizona.o snd-soc-cq93vc-objs := cq93vc.o +snd-soc-cs35l32-objs := cs35l32.o snd-soc-cs42l51-objs := cs42l51.o snd-soc-cs42l51-i2c-objs := cs42l51-i2c.o snd-soc-cs42l52-objs := cs42l52.o @@ -49,6 +50,9 @@ snd-soc-da732x-objs := da732x.o snd-soc-da9055-objs := da9055.o snd-soc-bt-sco-objs := bt-sco.o snd-soc-dmic-objs := dmic.o +snd-soc-es8328-objs := es8328.o +snd-soc-es8328-i2c-objs := es8328-i2c.o +snd-soc-es8328-spi-objs := es8328-spi.o snd-soc-isabelle-objs := isabelle.o snd-soc-jz4740-codec-objs := jz4740.o snd-soc-l3-objs := l3.o @@ -203,6 +207,7 @@ obj-$(CONFIG_SND_SOC_ALC5623) += snd-soc-alc5623.o obj-$(CONFIG_SND_SOC_ALC5632) += snd-soc-alc5632.o obj-$(CONFIG_SND_SOC_ARIZONA) += snd-soc-arizona.o obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.o +obj-$(CONFIG_SND_SOC_CS35L32) += snd-soc-cs35l32.o obj-$(CONFIG_SND_SOC_CS42L51) += snd-soc-cs42l51.o obj-$(CONFIG_SND_SOC_CS42L51_I2C) += snd-soc-cs42l51-i2c.o obj-$(CONFIG_SND_SOC_CS42L52) += snd-soc-cs42l52.o @@ -220,6 +225,9 @@ obj-$(CONFIG_SND_SOC_DA732X) += snd-soc-da732x.o obj-$(CONFIG_SND_SOC_DA9055) += snd-soc-da9055.o obj-$(CONFIG_SND_SOC_BT_SCO) += snd-soc-bt-sco.o obj-$(CONFIG_SND_SOC_DMIC) += snd-soc-dmic.o +obj-$(CONFIG_SND_SOC_ES8328) += snd-soc-es8328.o +obj-$(CONFIG_SND_SOC_ES8328_I2C)+= snd-soc-es8328-i2c.o +obj-$(CONFIG_SND_SOC_ES8328_SPI)+= snd-soc-es8328-spi.o obj-$(CONFIG_SND_SOC_ISABELLE) += snd-soc-isabelle.o obj-$(CONFIG_SND_SOC_JZ4740_CODEC) += snd-soc-jz4740-codec.o obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c index 1fb4402bf72d..fd43827bb856 100644 --- a/sound/soc/codecs/ab8500-codec.c +++ b/sound/soc/codecs/ab8500-codec.c @@ -56,8 +56,7 @@ #define GPIO31_DIR_OUTPUT 0x40 /* Macrocell register definitions */ -#define AB8500_CTRL3_REG 0x0200 -#define AB8500_GPIO_DIR4_REG 0x1013 +#define AB8500_GPIO_DIR4_REG 0x13 /* Bank AB8500_MISC */ /* Nr of FIR/IIR-coeff banks in ANC-block */ #define AB8500_NR_OF_ANC_COEFF_BANKS 2 @@ -126,6 +125,8 @@ struct ab8500_codec_drvdata_dbg { /* Private data for AB8500 device-driver */ struct ab8500_codec_drvdata { + struct regmap *regmap; + /* Sidetone */ long *sid_fir_values; enum sid_state sid_status; @@ -166,49 +167,35 @@ static inline const char *amic_type_str(enum amic_type type) */ /* Read a register from the audio-bank of AB8500 */ -static unsigned int ab8500_codec_read_reg(struct snd_soc_codec *codec, - unsigned int reg) +static int ab8500_codec_read_reg(void *context, unsigned int reg, + unsigned int *value) { + struct device *dev = context; int status; - unsigned int value = 0; u8 value8; - status = abx500_get_register_interruptible(codec->dev, AB8500_AUDIO, - reg, &value8); - if (status < 0) { - dev_err(codec->dev, - "%s: ERROR: Register (0x%02x:0x%02x) read failed (%d).\n", - __func__, (u8)AB8500_AUDIO, (u8)reg, status); - } else { - dev_dbg(codec->dev, - "%s: Read 0x%02x from register 0x%02x:0x%02x\n", - __func__, value8, (u8)AB8500_AUDIO, (u8)reg); - value = (unsigned int)value8; - } + status = abx500_get_register_interruptible(dev, AB8500_AUDIO, + reg, &value8); + *value = (unsigned int)value8; - return value; + return status; } /* Write to a register in the audio-bank of AB8500 */ -static int ab8500_codec_write_reg(struct snd_soc_codec *codec, - unsigned int reg, unsigned int value) +static int ab8500_codec_write_reg(void *context, unsigned int reg, + unsigned int value) { - int status; - - status = abx500_set_register_interruptible(codec->dev, AB8500_AUDIO, - reg, value); - if (status < 0) - dev_err(codec->dev, - "%s: ERROR: Register (%02x:%02x) write failed (%d).\n", - __func__, (u8)AB8500_AUDIO, (u8)reg, status); - else - dev_dbg(codec->dev, - "%s: Wrote 0x%02x into register %02x:%02x\n", - __func__, (u8)value, (u8)AB8500_AUDIO, (u8)reg); + struct device *dev = context; - return status; + return abx500_set_register_interruptible(dev, AB8500_AUDIO, + reg, value); } +static const struct regmap_config ab8500_codec_regmap = { + .reg_read = ab8500_codec_read_reg, + .reg_write = ab8500_codec_write_reg, +}; + /* * Controls - DAPM */ @@ -1968,16 +1955,16 @@ static int ab8500_audio_setup_mics(struct snd_soc_codec *codec, dev_dbg(codec->dev, "%s: Enter.\n", __func__); /* Set DMic-clocks to outputs */ - status = abx500_get_register_interruptible(codec->dev, (u8)AB8500_MISC, - (u8)AB8500_GPIO_DIR4_REG, + status = abx500_get_register_interruptible(codec->dev, AB8500_MISC, + AB8500_GPIO_DIR4_REG, &value8); if (status < 0) return status; value = value8 | GPIO27_DIR_OUTPUT | GPIO29_DIR_OUTPUT | GPIO31_DIR_OUTPUT; status = abx500_set_register_interruptible(codec->dev, - (u8)AB8500_MISC, - (u8)AB8500_GPIO_DIR4_REG, + AB8500_MISC, + AB8500_GPIO_DIR4_REG, value); if (status < 0) return status; @@ -2565,9 +2552,6 @@ static int ab8500_codec_probe(struct snd_soc_codec *codec) static struct snd_soc_codec_driver ab8500_codec_driver = { .probe = ab8500_codec_probe, - .read = ab8500_codec_read_reg, - .write = ab8500_codec_write_reg, - .reg_word_size = sizeof(u8), .controls = ab8500_ctrls, .num_controls = ARRAY_SIZE(ab8500_ctrls), .dapm_widgets = ab8500_dapm_widgets, @@ -2592,6 +2576,15 @@ static int ab8500_codec_driver_probe(struct platform_device *pdev) drvdata->anc_status = ANC_UNCONFIGURED; dev_set_drvdata(&pdev->dev, drvdata); + drvdata->regmap = devm_regmap_init(&pdev->dev, NULL, &pdev->dev, + &ab8500_codec_regmap); + if (IS_ERR(drvdata->regmap)) { + status = PTR_ERR(drvdata->regmap); + dev_err(&pdev->dev, "%s: Failed to allocate regmap: %d\n", + __func__, status); + return status; + } + dev_dbg(&pdev->dev, "%s: Register codec.\n", __func__); status = snd_soc_register_codec(&pdev->dev, &ab8500_codec_driver, ab8500_codec_dai, diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c index e889e1b84192..bd9b1839c8b0 100644 --- a/sound/soc/codecs/ac97.c +++ b/sound/soc/codecs/ac97.c @@ -69,19 +69,6 @@ static struct snd_soc_dai_driver ac97_dai = { .ops = &ac97_dai_ops, }; -static unsigned int ac97_read(struct snd_soc_codec *codec, - unsigned int reg) -{ - return soc_ac97_ops->read(codec->ac97, reg); -} - -static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int val) -{ - soc_ac97_ops->write(codec->ac97, reg, val); - return 0; -} - static int ac97_soc_probe(struct snd_soc_codec *codec) { struct snd_ac97_bus *ac97_bus; @@ -122,8 +109,6 @@ static int ac97_soc_resume(struct snd_soc_codec *codec) #endif static struct snd_soc_codec_driver soc_codec_dev_ac97 = { - .write = ac97_write, - .read = ac97_read, .probe = ac97_soc_probe, .suspend = ac97_soc_suspend, .resume = ac97_soc_resume, diff --git a/sound/soc/codecs/adau1373.c b/sound/soc/codecs/adau1373.c index 1ff7d4d027e9..7c784ad3e8b2 100644 --- a/sound/soc/codecs/adau1373.c +++ b/sound/soc/codecs/adau1373.c @@ -1448,29 +1448,10 @@ static int adau1373_set_bias_level(struct snd_soc_codec *codec, return 0; } -static int adau1373_remove(struct snd_soc_codec *codec) -{ - adau1373_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - -static int adau1373_suspend(struct snd_soc_codec *codec) -{ - struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec); - int ret; - - ret = adau1373_set_bias_level(codec, SND_SOC_BIAS_OFF); - regcache_cache_only(adau1373->regmap, true); - - return ret; -} - static int adau1373_resume(struct snd_soc_codec *codec) { struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec); - regcache_cache_only(adau1373->regmap, false); - adau1373_set_bias_level(codec, SND_SOC_BIAS_STANDBY); regcache_sync(adau1373->regmap); return 0; @@ -1501,8 +1482,6 @@ static const struct regmap_config adau1373_regmap_config = { static struct snd_soc_codec_driver adau1373_codec_driver = { .probe = adau1373_probe, - .remove = adau1373_remove, - .suspend = adau1373_suspend, .resume = adau1373_resume, .set_bias_level = adau1373_set_bias_level, .idle_bias_off = true, diff --git a/sound/soc/codecs/adau1761.c b/sound/soc/codecs/adau1761.c index 848cab839553..5518ebd6947c 100644 --- a/sound/soc/codecs/adau1761.c +++ b/sound/soc/codecs/adau1761.c @@ -714,9 +714,9 @@ static int adau1761_codec_probe(struct snd_soc_codec *codec) static const struct snd_soc_codec_driver adau1761_codec_driver = { .probe = adau1761_codec_probe, - .suspend = adau17x1_suspend, .resume = adau17x1_resume, .set_bias_level = adau1761_set_bias_level, + .suspend_bias_off = true, .controls = adau1761_controls, .num_controls = ARRAY_SIZE(adau1761_controls), diff --git a/sound/soc/codecs/adau1781.c b/sound/soc/codecs/adau1781.c index 045a61413840..e9fc00fb13dd 100644 --- a/sound/soc/codecs/adau1781.c +++ b/sound/soc/codecs/adau1781.c @@ -446,9 +446,9 @@ static int adau1781_codec_probe(struct snd_soc_codec *codec) static const struct snd_soc_codec_driver adau1781_codec_driver = { .probe = adau1781_codec_probe, - .suspend = adau17x1_suspend, .resume = adau17x1_resume, .set_bias_level = adau1781_set_bias_level, + .suspend_bias_off = true, .controls = adau1781_controls, .num_controls = ARRAY_SIZE(adau1781_controls), diff --git a/sound/soc/codecs/adau17x1.c b/sound/soc/codecs/adau17x1.c index 0b659704e60c..3e16c1c64115 100644 --- a/sound/soc/codecs/adau17x1.c +++ b/sound/soc/codecs/adau17x1.c @@ -815,13 +815,6 @@ int adau17x1_add_routes(struct snd_soc_codec *codec) } EXPORT_SYMBOL_GPL(adau17x1_add_routes); -int adau17x1_suspend(struct snd_soc_codec *codec) -{ - codec->driver->set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} -EXPORT_SYMBOL_GPL(adau17x1_suspend); - int adau17x1_resume(struct snd_soc_codec *codec) { struct adau *adau = snd_soc_codec_get_drvdata(codec); @@ -829,7 +822,6 @@ int adau17x1_resume(struct snd_soc_codec *codec) if (adau->switch_mode) adau->switch_mode(codec->dev); - codec->driver->set_bias_level(codec, SND_SOC_BIAS_STANDBY); regcache_sync(adau->regmap); return 0; diff --git a/sound/soc/codecs/adau17x1.h b/sound/soc/codecs/adau17x1.h index 3ffabaf4c7a8..e4a557fd7155 100644 --- a/sound/soc/codecs/adau17x1.h +++ b/sound/soc/codecs/adau17x1.h @@ -52,7 +52,6 @@ int adau17x1_set_micbias_voltage(struct snd_soc_codec *codec, enum adau17x1_micbias_voltage micbias); bool adau17x1_readable_register(struct device *dev, unsigned int reg); bool adau17x1_volatile_register(struct device *dev, unsigned int reg); -int adau17x1_suspend(struct snd_soc_codec *codec); int adau17x1_resume(struct snd_soc_codec *codec); extern const struct snd_soc_dai_ops adau17x1_dai_ops; diff --git a/sound/soc/codecs/adav80x.c b/sound/soc/codecs/adav80x.c index c43b93fdf0df..ce3cdca9fc62 100644 --- a/sound/soc/codecs/adav80x.c +++ b/sound/soc/codecs/adav80x.c @@ -812,42 +812,23 @@ static int adav80x_probe(struct snd_soc_codec *codec) /* Disable DAC zero flag */ regmap_write(adav80x->regmap, ADAV80X_DAC_CTRL3, 0x6); - return adav80x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); -} - -static int adav80x_suspend(struct snd_soc_codec *codec) -{ - struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); - int ret; - - ret = adav80x_set_bias_level(codec, SND_SOC_BIAS_OFF); - regcache_cache_only(adav80x->regmap, true); - - return ret; + return 0; } static int adav80x_resume(struct snd_soc_codec *codec) { struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); - regcache_cache_only(adav80x->regmap, false); - adav80x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); regcache_sync(adav80x->regmap); return 0; } -static int adav80x_remove(struct snd_soc_codec *codec) -{ - return adav80x_set_bias_level(codec, SND_SOC_BIAS_OFF); -} - static struct snd_soc_codec_driver adav80x_codec_driver = { .probe = adav80x_probe, - .remove = adav80x_remove, - .suspend = adav80x_suspend, .resume = adav80x_resume, .set_bias_level = adav80x_set_bias_level, + .suspend_bias_off = true, .set_pll = adav80x_set_pll, .set_sysclk = adav80x_set_sysclk, diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 2f2e91ac690f..2c71f16bd661 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -107,7 +107,7 @@ static int arizona_spk_ev(struct snd_soc_dapm_widget *w, break; case SND_SOC_DAPM_POST_PMU: val = snd_soc_read(codec, ARIZONA_INTERRUPT_RAW_STATUS_3); - if (val & ARIZONA_SPK_SHUTDOWN_STS) { + if (val & ARIZONA_SPK_OVERHEAT_STS) { dev_crit(arizona->dev, "Speaker not enabled due to temperature\n"); return -EBUSY; @@ -159,7 +159,7 @@ static irqreturn_t arizona_thermal_warn(int irq, void *data) if (ret != 0) { dev_err(arizona->dev, "Failed to read thermal status: %d\n", ret); - } else if (val & ARIZONA_SPK_SHUTDOWN_WARN_STS) { + } else if (val & ARIZONA_SPK_OVERHEAT_WARN_STS) { dev_crit(arizona->dev, "Thermal warning\n"); } @@ -177,7 +177,7 @@ static irqreturn_t arizona_thermal_shutdown(int irq, void *data) if (ret != 0) { dev_err(arizona->dev, "Failed to read thermal status: %d\n", ret); - } else if (val & ARIZONA_SPK_SHUTDOWN_STS) { + } else if (val & ARIZONA_SPK_OVERHEAT_STS) { dev_crit(arizona->dev, "Thermal shutdown\n"); ret = regmap_update_bits(arizona->regmap, ARIZONA_OUTPUT_ENABLES_1, @@ -223,7 +223,7 @@ int arizona_init_spk(struct snd_soc_codec *codec) break; } - ret = arizona_request_irq(arizona, ARIZONA_IRQ_SPK_SHUTDOWN_WARN, + ret = arizona_request_irq(arizona, ARIZONA_IRQ_SPK_OVERHEAT_WARN, "Thermal warning", arizona_thermal_warn, arizona); if (ret != 0) @@ -231,7 +231,7 @@ int arizona_init_spk(struct snd_soc_codec *codec) "Failed to get thermal warning IRQ: %d\n", ret); - ret = arizona_request_irq(arizona, ARIZONA_IRQ_SPK_SHUTDOWN, + ret = arizona_request_irq(arizona, ARIZONA_IRQ_SPK_OVERHEAT, "Thermal shutdown", arizona_thermal_shutdown, arizona); if (ret != 0) @@ -1278,6 +1278,8 @@ static int arizona_hw_params(struct snd_pcm_substream *substream, else rates = &arizona_48k_bclk_rates[0]; + wl = snd_pcm_format_width(params_format(params)); + if (tdm_slots) { arizona_aif_dbg(dai, "Configuring for %d %d bit TDM slots\n", tdm_slots, tdm_width); @@ -1285,6 +1287,7 @@ static int arizona_hw_params(struct snd_pcm_substream *substream, channels = tdm_slots; } else { bclk_target = snd_soc_params_to_bclk(params); + tdm_width = wl; } if (chan_limit && chan_limit < channels) { @@ -1319,8 +1322,7 @@ static int arizona_hw_params(struct snd_pcm_substream *substream, arizona_aif_dbg(dai, "BCLK %dHz LRCLK %dHz\n", rates[bclk], rates[bclk] / lrclk); - wl = snd_pcm_format_width(params_format(params)); - frame = wl << ARIZONA_AIF1TX_WL_SHIFT | wl; + frame = wl << ARIZONA_AIF1TX_WL_SHIFT | tdm_width; reconfig = arizona_aif_cfg_changed(codec, base, bclk, lrclk, frame); diff --git a/sound/soc/codecs/cs35l32.c b/sound/soc/codecs/cs35l32.c new file mode 100644 index 000000000000..c125925da92e --- /dev/null +++ b/sound/soc/codecs/cs35l32.c @@ -0,0 +1,631 @@ +/* + * cs35l32.c -- CS35L32 ALSA SoC audio driver + * + * Copyright 2014 CirrusLogic, Inc. + * + * Author: Brian Austin <brian.austin@cirrus.com> + * + * 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 <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/version.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/gpio.h> +#include <linux/regmap.h> +#include <linux/slab.h> +#include <linux/platform_device.h> +#include <linux/regulator/consumer.h> +#include <linux/gpio/consumer.h> +#include <linux/of_device.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/soc-dapm.h> +#include <sound/initval.h> +#include <sound/tlv.h> +#include <dt-bindings/sound/cs35l32.h> + +#include "cs35l32.h" + +#define CS35L32_NUM_SUPPLIES 2 +static const char *const cs35l32_supply_names[CS35L32_NUM_SUPPLIES] = { + "VA", + "VP", +}; + +struct cs35l32_private { + struct regmap *regmap; + struct snd_soc_codec *codec; + struct regulator_bulk_data supplies[CS35L32_NUM_SUPPLIES]; + struct cs35l32_platform_data pdata; + struct gpio_desc *reset_gpio; +}; + +static const struct reg_default cs35l32_reg_defaults[] = { + + { 0x06, 0x04 }, /* Power Ctl 1 */ + { 0x07, 0xE8 }, /* Power Ctl 2 */ + { 0x08, 0x40 }, /* Clock Ctl */ + { 0x09, 0x20 }, /* Low Battery Threshold */ + { 0x0A, 0x00 }, /* Voltage Monitor [RO] */ + { 0x0B, 0x40 }, /* Conv Peak Curr Protection CTL */ + { 0x0C, 0x07 }, /* IMON Scaling */ + { 0x0D, 0x03 }, /* Audio/LED Pwr Manager */ + { 0x0F, 0x20 }, /* Serial Port Control */ + { 0x10, 0x14 }, /* Class D Amp CTL */ + { 0x11, 0x00 }, /* Protection Release CTL */ + { 0x12, 0xFF }, /* Interrupt Mask 1 */ + { 0x13, 0xFF }, /* Interrupt Mask 2 */ + { 0x14, 0xFF }, /* Interrupt Mask 3 */ + { 0x19, 0x00 }, /* LED Flash Mode Current */ + { 0x1A, 0x00 }, /* LED Movie Mode Current */ + { 0x1B, 0x20 }, /* LED Flash Timer */ + { 0x1C, 0x00 }, /* LED Flash Inhibit Current */ +}; + +static bool cs35l32_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CS35L32_DEVID_AB: + case CS35L32_DEVID_CD: + case CS35L32_DEVID_E: + case CS35L32_FAB_ID: + case CS35L32_REV_ID: + case CS35L32_PWRCTL1: + case CS35L32_PWRCTL2: + case CS35L32_CLK_CTL: + case CS35L32_BATT_THRESHOLD: + case CS35L32_VMON: + case CS35L32_BST_CPCP_CTL: + case CS35L32_IMON_SCALING: + case CS35L32_AUDIO_LED_MNGR: + case CS35L32_ADSP_CTL: + case CS35L32_CLASSD_CTL: + case CS35L32_PROTECT_CTL: + case CS35L32_INT_MASK_1: + case CS35L32_INT_MASK_2: + case CS35L32_INT_MASK_3: + case CS35L32_INT_STATUS_1: + case CS35L32_INT_STATUS_2: + case CS35L32_INT_STATUS_3: + case CS35L32_LED_STATUS: + case CS35L32_FLASH_MODE: + case CS35L32_MOVIE_MODE: + case CS35L32_FLASH_TIMER: + case CS35L32_FLASH_INHIBIT: + return true; + default: + return false; + } +} + +static bool cs35l32_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CS35L32_DEVID_AB: + case CS35L32_DEVID_CD: + case CS35L32_DEVID_E: + case CS35L32_FAB_ID: + case CS35L32_REV_ID: + case CS35L32_INT_STATUS_1: + case CS35L32_INT_STATUS_2: + case CS35L32_INT_STATUS_3: + case CS35L32_LED_STATUS: + return true; + default: + return false; + } +} + +static bool cs35l32_precious_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CS35L32_INT_STATUS_1: + case CS35L32_INT_STATUS_2: + case CS35L32_INT_STATUS_3: + case CS35L32_LED_STATUS: + return true; + default: + return false; + } +} + +static DECLARE_TLV_DB_SCALE(classd_ctl_tlv, 900, 300, 0); + +static const struct snd_kcontrol_new imon_ctl = + SOC_DAPM_SINGLE("Switch", CS35L32_PWRCTL2, 6, 1, 1); + +static const struct snd_kcontrol_new vmon_ctl = + SOC_DAPM_SINGLE("Switch", CS35L32_PWRCTL2, 7, 1, 1); + +static const struct snd_kcontrol_new vpmon_ctl = + SOC_DAPM_SINGLE("Switch", CS35L32_PWRCTL2, 5, 1, 1); + +static const struct snd_kcontrol_new cs35l32_snd_controls[] = { + SOC_SINGLE_TLV("Speaker Volume", CS35L32_CLASSD_CTL, + 3, 0x04, 1, classd_ctl_tlv), + SOC_SINGLE("Zero Cross Switch", CS35L32_CLASSD_CTL, 2, 1, 0), + SOC_SINGLE("Gain Manager Switch", CS35L32_AUDIO_LED_MNGR, 3, 1, 0), +}; + +static const struct snd_soc_dapm_widget cs35l32_dapm_widgets[] = { + + SND_SOC_DAPM_SUPPLY("BOOST", CS35L32_PWRCTL1, 2, 1, NULL, 0), + SND_SOC_DAPM_OUT_DRV("Speaker", CS35L32_PWRCTL1, 7, 1, NULL, 0), + + SND_SOC_DAPM_AIF_OUT("SDOUT", NULL, 0, CS35L32_PWRCTL2, 3, 1), + + SND_SOC_DAPM_INPUT("VP"), + SND_SOC_DAPM_INPUT("ISENSE"), + SND_SOC_DAPM_INPUT("VSENSE"), + + SND_SOC_DAPM_SWITCH("VMON ADC", CS35L32_PWRCTL2, 7, 1, &vmon_ctl), + SND_SOC_DAPM_SWITCH("IMON ADC", CS35L32_PWRCTL2, 6, 1, &imon_ctl), + SND_SOC_DAPM_SWITCH("VPMON ADC", CS35L32_PWRCTL2, 5, 1, &vpmon_ctl), +}; + +static const struct snd_soc_dapm_route cs35l32_audio_map[] = { + + {"Speaker", NULL, "BOOST"}, + + {"VMON ADC", NULL, "VSENSE"}, + {"IMON ADC", NULL, "ISENSE"}, + {"VPMON ADC", NULL, "VP"}, + + {"SDOUT", "Switch", "VMON ADC"}, + {"SDOUT", "Switch", "IMON ADC"}, + {"SDOUT", "Switch", "VPMON ADC"}, + + {"Capture", NULL, "SDOUT"}, +}; + +static int cs35l32_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) +{ + struct snd_soc_codec *codec = codec_dai->codec; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + snd_soc_update_bits(codec, CS35L32_ADSP_CTL, + CS35L32_ADSP_MASTER_MASK, + CS35L32_ADSP_MASTER_MASK); + break; + case SND_SOC_DAIFMT_CBS_CFS: + snd_soc_update_bits(codec, CS35L32_ADSP_CTL, + CS35L32_ADSP_MASTER_MASK, 0); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int cs35l32_set_tristate(struct snd_soc_dai *dai, int tristate) +{ + struct snd_soc_codec *codec = dai->codec; + + return snd_soc_update_bits(codec, CS35L32_PWRCTL2, + CS35L32_SDOUT_3ST, tristate << 3); +} + +static const struct snd_soc_dai_ops cs35l32_ops = { + .set_fmt = cs35l32_set_dai_fmt, + .set_tristate = cs35l32_set_tristate, +}; + +static struct snd_soc_dai_driver cs35l32_dai[] = { + { + .name = "cs35l32-monitor", + .id = 0, + .capture = { + .stream_name = "Capture", + .channels_min = 2, + .channels_max = 2, + .rates = CS35L32_RATES, + .formats = CS35L32_FORMATS, + }, + .ops = &cs35l32_ops, + .symmetric_rates = 1, + } +}; + +static int cs35l32_codec_set_sysclk(struct snd_soc_codec *codec, + int clk_id, int source, unsigned int freq, int dir) +{ + unsigned int val; + + switch (freq) { + case 6000000: + val = CS35L32_MCLK_RATIO; + break; + case 12000000: + val = CS35L32_MCLK_DIV2_MASK | CS35L32_MCLK_RATIO; + break; + case 6144000: + val = 0; + break; + case 12288000: + val = CS35L32_MCLK_DIV2_MASK; + break; + default: + return -EINVAL; + } + + return snd_soc_update_bits(codec, CS35L32_CLK_CTL, + CS35L32_MCLK_DIV2_MASK | CS35L32_MCLK_RATIO_MASK, val); +} + +static struct snd_soc_codec_driver soc_codec_dev_cs35l32 = { + .set_sysclk = cs35l32_codec_set_sysclk, + + .dapm_widgets = cs35l32_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(cs35l32_dapm_widgets), + .dapm_routes = cs35l32_audio_map, + .num_dapm_routes = ARRAY_SIZE(cs35l32_audio_map), + + .controls = cs35l32_snd_controls, + .num_controls = ARRAY_SIZE(cs35l32_snd_controls), +}; + +/* Current and threshold powerup sequence Pg37 in datasheet */ +static const struct reg_default cs35l32_monitor_patch[] = { + + { 0x00, 0x99 }, + { 0x48, 0x17 }, + { 0x49, 0x56 }, + { 0x43, 0x01 }, + { 0x3B, 0x62 }, + { 0x3C, 0x80 }, + { 0x00, 0x00 }, +}; + +static struct regmap_config cs35l32_regmap = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = CS35L32_MAX_REGISTER, + .reg_defaults = cs35l32_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(cs35l32_reg_defaults), + .volatile_reg = cs35l32_volatile_register, + .readable_reg = cs35l32_readable_register, + .precious_reg = cs35l32_precious_register, + .cache_type = REGCACHE_RBTREE, +}; + +static int cs35l32_handle_of_data(struct i2c_client *i2c_client, + struct cs35l32_platform_data *pdata) +{ + struct device_node *np = i2c_client->dev.of_node; + unsigned int val; + + if (of_property_read_u32(np, "cirrus,sdout-share", &val) >= 0) + pdata->sdout_share = val; + + of_property_read_u32(np, "cirrus,boost-manager", &val); + switch (val) { + case CS35L32_BOOST_MGR_AUTO: + case CS35L32_BOOST_MGR_AUTO_AUDIO: + case CS35L32_BOOST_MGR_BYPASS: + case CS35L32_BOOST_MGR_FIXED: + pdata->boost_mng = val; + break; + default: + dev_err(&i2c_client->dev, + "Wrong cirrus,boost-manager DT value %d\n", val); + pdata->boost_mng = CS35L32_BOOST_MGR_BYPASS; + } + + of_property_read_u32(np, "cirrus,sdout-datacfg", &val); + switch (val) { + case CS35L32_DATA_CFG_LR_VP: + case CS35L32_DATA_CFG_LR_STAT: + case CS35L32_DATA_CFG_LR: + case CS35L32_DATA_CFG_LR_VPSTAT: + pdata->sdout_datacfg = val; + break; + default: + dev_err(&i2c_client->dev, + "Wrong cirrus,sdout-datacfg DT value %d\n", val); + pdata->sdout_datacfg = CS35L32_DATA_CFG_LR; + } + + of_property_read_u32(np, "cirrus,battery-threshold", &val); + switch (val) { + case CS35L32_BATT_THRESH_3_1V: + case CS35L32_BATT_THRESH_3_2V: + case CS35L32_BATT_THRESH_3_3V: + case CS35L32_BATT_THRESH_3_4V: + pdata->batt_thresh = val; + break; + default: + dev_err(&i2c_client->dev, + "Wrong cirrus,battery-threshold DT value %d\n", val); + pdata->batt_thresh = CS35L32_BATT_THRESH_3_3V; + } + + of_property_read_u32(np, "cirrus,battery-recovery", &val); + switch (val) { + case CS35L32_BATT_RECOV_3_1V: + case CS35L32_BATT_RECOV_3_2V: + case CS35L32_BATT_RECOV_3_3V: + case CS35L32_BATT_RECOV_3_4V: + case CS35L32_BATT_RECOV_3_5V: + case CS35L32_BATT_RECOV_3_6V: + pdata->batt_recov = val; + break; + default: + dev_err(&i2c_client->dev, + "Wrong cirrus,battery-recovery DT value %d\n", val); + pdata->batt_recov = CS35L32_BATT_RECOV_3_4V; + } + + return 0; +} + +static int cs35l32_i2c_probe(struct i2c_client *i2c_client, + const struct i2c_device_id *id) +{ + struct cs35l32_private *cs35l32; + struct cs35l32_platform_data *pdata = + dev_get_platdata(&i2c_client->dev); + int ret, i; + unsigned int devid = 0; + unsigned int reg; + + + cs35l32 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs35l32_private), + GFP_KERNEL); + if (!cs35l32) { + dev_err(&i2c_client->dev, "could not allocate codec\n"); + return -ENOMEM; + } + + i2c_set_clientdata(i2c_client, cs35l32); + + cs35l32->regmap = devm_regmap_init_i2c(i2c_client, &cs35l32_regmap); + if (IS_ERR(cs35l32->regmap)) { + ret = PTR_ERR(cs35l32->regmap); + dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret); + return ret; + } + + if (pdata) { + cs35l32->pdata = *pdata; + } else { + pdata = devm_kzalloc(&i2c_client->dev, + sizeof(struct cs35l32_platform_data), + GFP_KERNEL); + if (!pdata) { + dev_err(&i2c_client->dev, "could not allocate pdata\n"); + return -ENOMEM; + } + if (i2c_client->dev.of_node) { + ret = cs35l32_handle_of_data(i2c_client, + &cs35l32->pdata); + if (ret != 0) + return ret; + } + } + + for (i = 0; i < ARRAY_SIZE(cs35l32->supplies); i++) + cs35l32->supplies[i].supply = cs35l32_supply_names[i]; + + ret = devm_regulator_bulk_get(&i2c_client->dev, + ARRAY_SIZE(cs35l32->supplies), + cs35l32->supplies); + if (ret != 0) { + dev_err(&i2c_client->dev, + "Failed to request supplies: %d\n", ret); + return ret; + } + + ret = regulator_bulk_enable(ARRAY_SIZE(cs35l32->supplies), + cs35l32->supplies); + if (ret != 0) { + dev_err(&i2c_client->dev, + "Failed to enable supplies: %d\n", ret); + return ret; + } + + /* Reset the Device */ + cs35l32->reset_gpio = devm_gpiod_get(&i2c_client->dev, + "reset-gpios"); + if (IS_ERR(cs35l32->reset_gpio)) { + ret = PTR_ERR(cs35l32->reset_gpio); + if (ret != -ENOENT && ret != -ENOSYS) + return ret; + + cs35l32->reset_gpio = NULL; + } else { + ret = gpiod_direction_output(cs35l32->reset_gpio, 0); + if (ret) + return ret; + gpiod_set_value_cansleep(cs35l32->reset_gpio, 1); + } + + /* initialize codec */ + ret = regmap_read(cs35l32->regmap, CS35L32_DEVID_AB, ®); + devid = (reg & 0xFF) << 12; + + ret = regmap_read(cs35l32->regmap, CS35L32_DEVID_CD, ®); + devid |= (reg & 0xFF) << 4; + + ret = regmap_read(cs35l32->regmap, CS35L32_DEVID_E, ®); + devid |= (reg & 0xF0) >> 4; + + if (devid != CS35L32_CHIP_ID) { + ret = -ENODEV; + dev_err(&i2c_client->dev, + "CS35L32 Device ID (%X). Expected %X\n", + devid, CS35L32_CHIP_ID); + return ret; + } + + ret = regmap_read(cs35l32->regmap, CS35L32_REV_ID, ®); + if (ret < 0) { + dev_err(&i2c_client->dev, "Get Revision ID failed\n"); + return ret; + } + + ret = regmap_register_patch(cs35l32->regmap, cs35l32_monitor_patch, + ARRAY_SIZE(cs35l32_monitor_patch)); + if (ret < 0) { + dev_err(&i2c_client->dev, "Failed to apply errata patch\n"); + return ret; + } + + dev_info(&i2c_client->dev, + "Cirrus Logic CS35L32, Revision: %02X\n", reg & 0xFF); + + /* Setup VBOOST Management */ + if (cs35l32->pdata.boost_mng) + regmap_update_bits(cs35l32->regmap, CS35L32_AUDIO_LED_MNGR, + CS35L32_BOOST_MASK, + cs35l32->pdata.boost_mng); + + /* Setup ADSP Format Config */ + if (cs35l32->pdata.sdout_share) + regmap_update_bits(cs35l32->regmap, CS35L32_ADSP_CTL, + CS35L32_ADSP_SHARE_MASK, + cs35l32->pdata.sdout_share << 3); + + /* Setup ADSP Data Configuration */ + if (cs35l32->pdata.sdout_datacfg) + regmap_update_bits(cs35l32->regmap, CS35L32_ADSP_CTL, + CS35L32_ADSP_DATACFG_MASK, + cs35l32->pdata.sdout_datacfg << 4); + + /* Setup Low Battery Recovery */ + if (cs35l32->pdata.batt_recov) + regmap_update_bits(cs35l32->regmap, CS35L32_BATT_THRESHOLD, + CS35L32_BATT_REC_MASK, + cs35l32->pdata.batt_recov << 1); + + /* Setup Low Battery Threshold */ + if (cs35l32->pdata.batt_thresh) + regmap_update_bits(cs35l32->regmap, CS35L32_BATT_THRESHOLD, + CS35L32_BATT_THRESH_MASK, + cs35l32->pdata.batt_thresh << 4); + + /* Power down the AMP */ + regmap_update_bits(cs35l32->regmap, CS35L32_PWRCTL1, CS35L32_PDN_AMP, + CS35L32_PDN_AMP); + + /* Clear MCLK Error Bit since we don't have the clock yet */ + ret = regmap_read(cs35l32->regmap, CS35L32_INT_STATUS_1, ®); + + ret = snd_soc_register_codec(&i2c_client->dev, + &soc_codec_dev_cs35l32, cs35l32_dai, + ARRAY_SIZE(cs35l32_dai)); + if (ret < 0) + goto err_disable; + + return 0; + +err_disable: + regulator_bulk_disable(ARRAY_SIZE(cs35l32->supplies), + cs35l32->supplies); + return ret; +} + +static int cs35l32_i2c_remove(struct i2c_client *i2c_client) +{ + struct cs35l32_private *cs35l32 = i2c_get_clientdata(i2c_client); + + snd_soc_unregister_codec(&i2c_client->dev); + + /* Hold down reset */ + if (cs35l32->reset_gpio) + gpiod_set_value_cansleep(cs35l32->reset_gpio, 0); + + return 0; +} + +#ifdef CONFIG_PM_RUNTIME +static int cs35l32_runtime_suspend(struct device *dev) +{ + struct cs35l32_private *cs35l32 = dev_get_drvdata(dev); + + regcache_cache_only(cs35l32->regmap, true); + regcache_mark_dirty(cs35l32->regmap); + + /* Hold down reset */ + if (cs35l32->reset_gpio) + gpiod_set_value_cansleep(cs35l32->reset_gpio, 0); + + /* remove power */ + regulator_bulk_disable(ARRAY_SIZE(cs35l32->supplies), + cs35l32->supplies); + + return 0; +} + +static int cs35l32_runtime_resume(struct device *dev) +{ + struct cs35l32_private *cs35l32 = dev_get_drvdata(dev); + int ret; + + /* Enable power */ + ret = regulator_bulk_enable(ARRAY_SIZE(cs35l32->supplies), + cs35l32->supplies); + if (ret != 0) { + dev_err(dev, "Failed to enable supplies: %d\n", + ret); + return ret; + } + + if (cs35l32->reset_gpio) + gpiod_set_value_cansleep(cs35l32->reset_gpio, 1); + + regcache_cache_only(cs35l32->regmap, false); + regcache_sync(cs35l32->regmap); + + return 0; +} +#endif + +static const struct dev_pm_ops cs35l32_runtime_pm = { + SET_RUNTIME_PM_OPS(cs35l32_runtime_suspend, cs35l32_runtime_resume, + NULL) +}; + +static const struct of_device_id cs35l32_of_match[] = { + { .compatible = "cirrus,cs35l32", }, + {}, +}; +MODULE_DEVICE_TABLE(of, cs35l32_of_match); + + +static const struct i2c_device_id cs35l32_id[] = { + {"cs35l32", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, cs35l32_id); + +static struct i2c_driver cs35l32_i2c_driver = { + .driver = { + .name = "cs35l32", + .owner = THIS_MODULE, + .pm = &cs35l32_runtime_pm, + .of_match_table = cs35l32_of_match, + }, + .id_table = cs35l32_id, + .probe = cs35l32_i2c_probe, + .remove = cs35l32_i2c_remove, +}; + +module_i2c_driver(cs35l32_i2c_driver); + +MODULE_DESCRIPTION("ASoC CS35L32 driver"); +MODULE_AUTHOR("Brian Austin, Cirrus Logic Inc, <brian.austin@cirrus.com>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/cs35l32.h b/sound/soc/codecs/cs35l32.h new file mode 100644 index 000000000000..31ab804a22bc --- /dev/null +++ b/sound/soc/codecs/cs35l32.h @@ -0,0 +1,93 @@ +/* + * cs35l32.h -- CS35L32 ALSA SoC audio driver + * + * Copyright 2014 CirrusLogic, Inc. + * + * Author: Brian Austin <brian.austin@cirrus.com> + * + * 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 __CS35L32_H__ +#define __CS35L32_H__ + +struct cs35l32_platform_data { + /* Low Battery Threshold */ + unsigned int batt_thresh; + /* Low Battery Recovery */ + unsigned int batt_recov; + /* LED Current Management*/ + unsigned int led_mng; + /* Audio Gain w/ LED */ + unsigned int audiogain_mng; + /* Boost Management */ + unsigned int boost_mng; + /* Data CFG for DUAL device */ + unsigned int sdout_datacfg; + /* SDOUT Sharing */ + unsigned int sdout_share; +}; + +#define CS35L32_CHIP_ID 0x00035A32 +#define CS35L32_DEVID_AB 0x01 /* Device ID A & B [RO] */ +#define CS35L32_DEVID_CD 0x02 /* Device ID C & D [RO] */ +#define CS35L32_DEVID_E 0x03 /* Device ID E [RO] */ +#define CS35L32_FAB_ID 0x04 /* Fab ID [RO] */ +#define CS35L32_REV_ID 0x05 /* Revision ID [RO] */ +#define CS35L32_PWRCTL1 0x06 /* Power Ctl 1 */ +#define CS35L32_PWRCTL2 0x07 /* Power Ctl 2 */ +#define CS35L32_CLK_CTL 0x08 /* Clock Ctl */ +#define CS35L32_BATT_THRESHOLD 0x09 /* Low Battery Threshold */ +#define CS35L32_VMON 0x0A /* Voltage Monitor [RO] */ +#define CS35L32_BST_CPCP_CTL 0x0B /* Conv Peak Curr Protection CTL */ +#define CS35L32_IMON_SCALING 0x0C /* IMON Scaling */ +#define CS35L32_AUDIO_LED_MNGR 0x0D /* Audio/LED Pwr Manager */ +#define CS35L32_ADSP_CTL 0x0F /* Serial Port Control */ +#define CS35L32_CLASSD_CTL 0x10 /* Class D Amp CTL */ +#define CS35L32_PROTECT_CTL 0x11 /* Protection Release CTL */ +#define CS35L32_INT_MASK_1 0x12 /* Interrupt Mask 1 */ +#define CS35L32_INT_MASK_2 0x13 /* Interrupt Mask 2 */ +#define CS35L32_INT_MASK_3 0x14 /* Interrupt Mask 3 */ +#define CS35L32_INT_STATUS_1 0x15 /* Interrupt Status 1 [RO] */ +#define CS35L32_INT_STATUS_2 0x16 /* Interrupt Status 2 [RO] */ +#define CS35L32_INT_STATUS_3 0x17 /* Interrupt Status 3 [RO] */ +#define CS35L32_LED_STATUS 0x18 /* LED Lighting Status [RO] */ +#define CS35L32_FLASH_MODE 0x19 /* LED Flash Mode Current */ +#define CS35L32_MOVIE_MODE 0x1A /* LED Movie Mode Current */ +#define CS35L32_FLASH_TIMER 0x1B /* LED Flash Timer */ +#define CS35L32_FLASH_INHIBIT 0x1C /* LED Flash Inhibit Current */ +#define CS35L32_MAX_REGISTER 0x1C + +#define CS35L32_MCLK_DIV2 0x01 +#define CS35L32_MCLK_RATIO 0x01 +#define CS35L32_MCLKDIS 0x80 +#define CS35L32_PDN_ALL 0x01 +#define CS35L32_PDN_AMP 0x80 +#define CS35L32_PDN_BOOST 0x04 +#define CS35L32_PDN_IMON 0x40 +#define CS35L32_PDN_VMON 0x80 +#define CS35L32_PDN_VPMON 0x20 +#define CS35L32_PDN_ADSP 0x08 + +#define CS35L32_MCLK_DIV2_MASK 0x40 +#define CS35L32_MCLK_RATIO_MASK 0x01 +#define CS35L32_MCLK_MASK 0x41 +#define CS35L32_ADSP_MASTER_MASK 0x40 +#define CS35L32_BOOST_MASK 0x03 +#define CS35L32_GAIN_MGR_MASK 0x08 +#define CS35L32_ADSP_SHARE_MASK 0x08 +#define CS35L32_ADSP_DATACFG_MASK 0x30 +#define CS35L32_SDOUT_3ST 0x80 +#define CS35L32_BATT_REC_MASK 0x0E +#define CS35L32_BATT_THRESH_MASK 0x30 + +#define CS35L32_RATES (SNDRV_PCM_RATE_48000) +#define CS35L32_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE) + + +#endif diff --git a/sound/soc/codecs/cs4265.c b/sound/soc/codecs/cs4265.c index a20b30ca52c0..4fdd47d700e3 100644 --- a/sound/soc/codecs/cs4265.c +++ b/sound/soc/codecs/cs4265.c @@ -77,6 +77,7 @@ static bool cs4265_readable_register(struct device *dev, unsigned int reg) case CS4265_INT_MASK: case CS4265_STATUS_MODE_MSB: case CS4265_STATUS_MODE_LSB: + case CS4265_CHIP_ID: return true; default: return false; @@ -282,10 +283,10 @@ static const struct cs4265_clk_para clk_map_table[] = { /*64k*/ {8192000, 64000, 1, 0}, - {1228800, 64000, 1, 1}, - {1693440, 64000, 1, 2}, - {2457600, 64000, 1, 3}, - {3276800, 64000, 1, 4}, + {12288000, 64000, 1, 1}, + {16934400, 64000, 1, 2}, + {24576000, 64000, 1, 3}, + {32768000, 64000, 1, 4}, /* 88.2k */ {11289600, 88200, 1, 0}, @@ -435,10 +436,10 @@ static int cs4265_pcm_hw_params(struct snd_pcm_substream *substream, index = cs4265_get_clk_index(cs4265->sysclk, params_rate(params)); if (index >= 0) { snd_soc_update_bits(codec, CS4265_ADC_CTL, - CS4265_ADC_FM, clk_map_table[index].fm_mode); + CS4265_ADC_FM, clk_map_table[index].fm_mode << 6); snd_soc_update_bits(codec, CS4265_MCLK_FREQ, CS4265_MCLK_FREQ_MASK, - clk_map_table[index].mclkdiv); + clk_map_table[index].mclkdiv << 4); } else { dev_err(codec->dev, "can't get correct mclk\n"); @@ -458,12 +459,12 @@ static int cs4265_pcm_hw_params(struct snd_pcm_substream *substream, if (params_width(params) == 16) { snd_soc_update_bits(codec, CS4265_DAC_CTL, CS4265_DAC_CTL_DIF, (1 << 5)); - snd_soc_update_bits(codec, CS4265_ADC_CTL, + snd_soc_update_bits(codec, CS4265_SPDIF_CTL2, CS4265_SPDIF_CTL2_DIF, (1 << 7)); } else { snd_soc_update_bits(codec, CS4265_DAC_CTL, CS4265_DAC_CTL_DIF, (3 << 5)); - snd_soc_update_bits(codec, CS4265_ADC_CTL, + snd_soc_update_bits(codec, CS4265_SPDIF_CTL2, CS4265_SPDIF_CTL2_DIF, (1 << 7)); } break; @@ -472,7 +473,7 @@ static int cs4265_pcm_hw_params(struct snd_pcm_substream *substream, CS4265_DAC_CTL_DIF, 0); snd_soc_update_bits(codec, CS4265_ADC_CTL, CS4265_ADC_DIF, 0); - snd_soc_update_bits(codec, CS4265_ADC_CTL, + snd_soc_update_bits(codec, CS4265_SPDIF_CTL2, CS4265_SPDIF_CTL2_DIF, (1 << 6)); break; diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c index 969167d8b71e..da4f758cd12a 100644 --- a/sound/soc/codecs/cs42l52.c +++ b/sound/soc/codecs/cs42l52.c @@ -176,9 +176,9 @@ static bool cs42l52_volatile_register(struct device *dev, unsigned int reg) case CS42L52_BATT_LEVEL: case CS42L52_SPK_STATUS: case CS42L52_CHARGE_PUMP: - return 1; + return true; default: - return 0; + return false; } } diff --git a/sound/soc/codecs/cs42l56.c b/sound/soc/codecs/cs42l56.c index c766a5a9ce80..bb74dd17fa26 100644 --- a/sound/soc/codecs/cs42l56.c +++ b/sound/soc/codecs/cs42l56.c @@ -171,9 +171,9 @@ static bool cs42l56_volatile_register(struct device *dev, unsigned int reg) { switch (reg) { case CS42L56_INT_STATUS: - return 1; + return true; default: - return 0; + return false; } } @@ -1175,11 +1175,8 @@ static int cs42l56_probe(struct snd_soc_codec *codec) static int cs42l56_remove(struct snd_soc_codec *codec) { - struct cs42l56_private *cs42l56 = snd_soc_codec_get_drvdata(codec); - cs42l56_free_beep(codec); cs42l56_set_bias_level(codec, SND_SOC_BIAS_OFF); - regulator_bulk_free(ARRAY_SIZE(cs42l56->supplies), cs42l56->supplies); return 0; } diff --git a/sound/soc/codecs/da732x.c b/sound/soc/codecs/da732x.c index 2fae31cb0067..fa15fa1c0516 100644 --- a/sound/soc/codecs/da732x.c +++ b/sound/soc/codecs/da732x.c @@ -217,7 +217,7 @@ static void da732x_set_charge_pump(struct snd_soc_codec *codec, int state) snd_soc_write(codec, DA732X_REG_CP_CTRL1, DA723X_CP_DIS); break; default: - pr_err(KERN_ERR "Wrong charge pump state\n"); + pr_err("Wrong charge pump state\n"); break; } } diff --git a/sound/soc/codecs/da732x.h b/sound/soc/codecs/da732x.h index 1dceafeec415..f586cbd30b77 100644 --- a/sound/soc/codecs/da732x.h +++ b/sound/soc/codecs/da732x.h @@ -11,7 +11,7 @@ */ #ifndef __DA732X_H_ -#define __DA732X_H +#define __DA732X_H_ #include <sound/soc.h> diff --git a/sound/soc/codecs/es8328-i2c.c b/sound/soc/codecs/es8328-i2c.c new file mode 100644 index 000000000000..aae410d122ee --- /dev/null +++ b/sound/soc/codecs/es8328-i2c.c @@ -0,0 +1,60 @@ +/* + * es8328-i2c.c -- ES8328 ALSA SoC I2C Audio driver + * + * Copyright 2014 Sutajio Ko-Usagi PTE LTD + * + * Author: Sean Cross <xobs@kosagi.com> + * + * 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 <linux/module.h> +#include <linux/i2c.h> +#include <linux/regmap.h> + +#include <sound/soc.h> + +#include "es8328.h" + +static const struct i2c_device_id es8328_id[] = { + { "everest,es8328", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, es8328_id); + +static const struct of_device_id es8328_of_match[] = { + { .compatible = "everest,es8328", }, + { } +}; +MODULE_DEVICE_TABLE(of, es8328_of_match); + +static int es8328_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + return es8328_probe(&i2c->dev, + devm_regmap_init_i2c(i2c, &es8328_regmap_config)); +} + +static int es8328_i2c_remove(struct i2c_client *i2c) +{ + snd_soc_unregister_codec(&i2c->dev); + return 0; +} + +static struct i2c_driver es8328_i2c_driver = { + .driver = { + .name = "es8328", + .of_match_table = es8328_of_match, + }, + .probe = es8328_i2c_probe, + .remove = es8328_i2c_remove, + .id_table = es8328_id, +}; + +module_i2c_driver(es8328_i2c_driver); + +MODULE_DESCRIPTION("ASoC ES8328 audio CODEC I2C driver"); +MODULE_AUTHOR("Sean Cross <xobs@kosagi.com>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/es8328-spi.c b/sound/soc/codecs/es8328-spi.c new file mode 100644 index 000000000000..8fbd935e1c76 --- /dev/null +++ b/sound/soc/codecs/es8328-spi.c @@ -0,0 +1,49 @@ +/* + * es8328.c -- ES8328 ALSA SoC SPI Audio driver + * + * Copyright 2014 Sutajio Ko-Usagi PTE LTD + * + * Author: Sean Cross <xobs@kosagi.com> + * + * 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 <linux/module.h> +#include <linux/regmap.h> +#include <linux/spi/spi.h> +#include <sound/soc.h> +#include "es8328.h" + +static const struct of_device_id es8328_of_match[] = { + { .compatible = "everest,es8328", }, + { } +}; +MODULE_DEVICE_TABLE(of, es8328_of_match); + +static int es8328_spi_probe(struct spi_device *spi) +{ + return es8328_probe(&spi->dev, + devm_regmap_init_spi(spi, &es8328_regmap_config)); +} + +static int es8328_spi_remove(struct spi_device *spi) +{ + snd_soc_unregister_codec(&spi->dev); + return 0; +} + +static struct spi_driver es8328_spi_driver = { + .driver = { + .name = "es8328", + .of_match_table = es8328_of_match, + }, + .probe = es8328_spi_probe, + .remove = es8328_spi_remove, +}; + +module_spi_driver(es8328_spi_driver); +MODULE_DESCRIPTION("ASoC ES8328 audio CODEC SPI driver"); +MODULE_AUTHOR("Sean Cross <xobs@kosagi.com>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/es8328.c b/sound/soc/codecs/es8328.c new file mode 100644 index 000000000000..f27325155ace --- /dev/null +++ b/sound/soc/codecs/es8328.c @@ -0,0 +1,756 @@ +/* + * es8328.c -- ES8328 ALSA SoC Audio driver + * + * Copyright 2014 Sutajio Ko-Usagi PTE LTD + * + * Author: Sean Cross <xobs@kosagi.com> + * + * 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 <linux/clk.h> +#include <linux/delay.h> +#include <linux/of_device.h> +#include <linux/module.h> +#include <linux/pm.h> +#include <linux/regmap.h> +#include <linux/slab.h> +#include <linux/regulator/consumer.h> +#include <sound/core.h> +#include <sound/initval.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/tlv.h> +#include "es8328.h" + +#define ES8328_SYSCLK_RATE_1X 11289600 +#define ES8328_SYSCLK_RATE_2X 22579200 + +/* Run the codec at 22.5792 or 11.2896 MHz to support these rates */ +static struct { + int rate; + u8 ratio; +} mclk_ratios[] = { + { 8000, 9 }, + {11025, 7 }, + {22050, 4 }, + {44100, 2 }, +}; + +/* regulator supplies for sgtl5000, VDDD is an optional external supply */ +enum sgtl5000_regulator_supplies { + DVDD, + AVDD, + PVDD, + HPVDD, + ES8328_SUPPLY_NUM +}; + +/* vddd is optional supply */ +static const char * const supply_names[ES8328_SUPPLY_NUM] = { + "DVDD", + "AVDD", + "PVDD", + "HPVDD", +}; + +#define ES8328_RATES (SNDRV_PCM_RATE_44100 | \ + SNDRV_PCM_RATE_22050 | \ + SNDRV_PCM_RATE_11025) +#define ES8328_FORMATS (SNDRV_PCM_FMTBIT_S16_LE) + +struct es8328_priv { + struct regmap *regmap; + struct clk *clk; + int playback_fs; + bool deemph; + struct regulator_bulk_data supplies[ES8328_SUPPLY_NUM]; +}; + +/* + * ES8328 Controls + */ + +static const char * const adcpol_txt[] = {"Normal", "L Invert", "R Invert", + "L + R Invert"}; +static SOC_ENUM_SINGLE_DECL(adcpol, + ES8328_ADCCONTROL6, 6, adcpol_txt); + +static const DECLARE_TLV_DB_SCALE(play_tlv, -3000, 100, 0); +static const DECLARE_TLV_DB_SCALE(dac_adc_tlv, -9600, 50, 0); +static const DECLARE_TLV_DB_SCALE(pga_tlv, 0, 300, 0); +static const DECLARE_TLV_DB_SCALE(bypass_tlv, -1500, 300, 0); +static const DECLARE_TLV_DB_SCALE(mic_tlv, 0, 300, 0); + +static const int deemph_settings[] = { 0, 32000, 44100, 48000 }; + +static int es8328_set_deemph(struct snd_soc_codec *codec) +{ + struct es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec); + int val, i, best; + + /* + * If we're using deemphasis select the nearest available sample + * rate. + */ + if (es8328->deemph) { + best = 1; + for (i = 2; i < ARRAY_SIZE(deemph_settings); i++) { + if (abs(deemph_settings[i] - es8328->playback_fs) < + abs(deemph_settings[best] - es8328->playback_fs)) + best = i; + } + + val = best << 1; + } else { + val = 0; + } + + dev_dbg(codec->dev, "Set deemphasis %d\n", val); + + return snd_soc_update_bits(codec, ES8328_DACCONTROL6, 0x6, val); +} + +static int es8328_get_deemph(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec); + + ucontrol->value.enumerated.item[0] = es8328->deemph; + return 0; +} + +static int es8328_put_deemph(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec); + int deemph = ucontrol->value.enumerated.item[0]; + int ret; + + if (deemph > 1) + return -EINVAL; + + ret = es8328_set_deemph(codec); + if (ret < 0) + return ret; + + es8328->deemph = deemph; + + return 0; +} + + + +static const struct snd_kcontrol_new es8328_snd_controls[] = { + SOC_DOUBLE_R_TLV("Capture Digital Volume", + ES8328_ADCCONTROL8, ES8328_ADCCONTROL9, + 0, 0xc0, 1, dac_adc_tlv), + SOC_SINGLE("Capture ZC Switch", ES8328_ADCCONTROL7, 6, 1, 0), + + SOC_SINGLE_BOOL_EXT("DAC Deemphasis Switch", 0, + es8328_get_deemph, es8328_put_deemph), + + SOC_ENUM("Capture Polarity", adcpol), + + SOC_SINGLE_TLV("Left Mixer Left Bypass Volume", + ES8328_DACCONTROL17, 3, 7, 1, bypass_tlv), + SOC_SINGLE_TLV("Left Mixer Right Bypass Volume", + ES8328_DACCONTROL19, 3, 7, 1, bypass_tlv), + SOC_SINGLE_TLV("Right Mixer Left Bypass Volume", + ES8328_DACCONTROL18, 3, 7, 1, bypass_tlv), + SOC_SINGLE_TLV("Right Mixer Right Bypass Volume", + ES8328_DACCONTROL20, 3, 7, 1, bypass_tlv), + + SOC_DOUBLE_R_TLV("PCM Volume", + ES8328_LDACVOL, ES8328_RDACVOL, + 0, ES8328_DACVOL_MAX, 1, dac_adc_tlv), + + SOC_DOUBLE_R_TLV("Output 1 Playback Volume", + ES8328_LOUT1VOL, ES8328_ROUT1VOL, + 0, ES8328_OUT1VOL_MAX, 0, play_tlv), + + SOC_DOUBLE_R_TLV("Output 2 Playback Volume", + ES8328_LOUT2VOL, ES8328_ROUT2VOL, + 0, ES8328_OUT2VOL_MAX, 0, play_tlv), + + SOC_DOUBLE_TLV("Mic PGA Volume", ES8328_ADCCONTROL1, + 4, 0, 8, 0, mic_tlv), +}; + +/* + * DAPM Controls + */ + +static const char * const es8328_line_texts[] = { + "Line 1", "Line 2", "PGA", "Differential"}; + +static const struct soc_enum es8328_lline_enum = + SOC_ENUM_SINGLE(ES8328_DACCONTROL16, 3, + ARRAY_SIZE(es8328_line_texts), + es8328_line_texts); +static const struct snd_kcontrol_new es8328_left_line_controls = + SOC_DAPM_ENUM("Route", es8328_lline_enum); + +static const struct soc_enum es8328_rline_enum = + SOC_ENUM_SINGLE(ES8328_DACCONTROL16, 0, + ARRAY_SIZE(es8328_line_texts), + es8328_line_texts); +static const struct snd_kcontrol_new es8328_right_line_controls = + SOC_DAPM_ENUM("Route", es8328_lline_enum); + +/* Left Mixer */ +static const struct snd_kcontrol_new es8328_left_mixer_controls[] = { + SOC_DAPM_SINGLE("Playback Switch", ES8328_DACCONTROL17, 8, 1, 0), + SOC_DAPM_SINGLE("Left Bypass Switch", ES8328_DACCONTROL17, 7, 1, 0), + SOC_DAPM_SINGLE("Right Playback Switch", ES8328_DACCONTROL18, 8, 1, 0), + SOC_DAPM_SINGLE("Right Bypass Switch", ES8328_DACCONTROL18, 7, 1, 0), +}; + +/* Right Mixer */ +static const struct snd_kcontrol_new es8328_right_mixer_controls[] = { + SOC_DAPM_SINGLE("Left Playback Switch", ES8328_DACCONTROL19, 8, 1, 0), + SOC_DAPM_SINGLE("Left Bypass Switch", ES8328_DACCONTROL19, 7, 1, 0), + SOC_DAPM_SINGLE("Playback Switch", ES8328_DACCONTROL20, 8, 1, 0), + SOC_DAPM_SINGLE("Right Bypass Switch", ES8328_DACCONTROL20, 7, 1, 0), +}; + +static const char * const es8328_pga_sel[] = { + "Line 1", "Line 2", "Line 3", "Differential"}; + +/* Left PGA Mux */ +static const struct soc_enum es8328_lpga_enum = + SOC_ENUM_SINGLE(ES8328_ADCCONTROL2, 6, + ARRAY_SIZE(es8328_pga_sel), + es8328_pga_sel); +static const struct snd_kcontrol_new es8328_left_pga_controls = + SOC_DAPM_ENUM("Route", es8328_lpga_enum); + +/* Right PGA Mux */ +static const struct soc_enum es8328_rpga_enum = + SOC_ENUM_SINGLE(ES8328_ADCCONTROL2, 4, + ARRAY_SIZE(es8328_pga_sel), + es8328_pga_sel); +static const struct snd_kcontrol_new es8328_right_pga_controls = + SOC_DAPM_ENUM("Route", es8328_rpga_enum); + +/* Differential Mux */ +static const char * const es8328_diff_sel[] = {"Line 1", "Line 2"}; +static SOC_ENUM_SINGLE_DECL(diffmux, + ES8328_ADCCONTROL3, 7, es8328_diff_sel); +static const struct snd_kcontrol_new es8328_diffmux_controls = + SOC_DAPM_ENUM("Route", diffmux); + +/* Mono ADC Mux */ +static const char * const es8328_mono_mux[] = {"Stereo", "Mono (Left)", + "Mono (Right)", "Digital Mono"}; +static SOC_ENUM_SINGLE_DECL(monomux, + ES8328_ADCCONTROL3, 3, es8328_mono_mux); +static const struct snd_kcontrol_new es8328_monomux_controls = + SOC_DAPM_ENUM("Route", monomux); + +static const struct snd_soc_dapm_widget es8328_dapm_widgets[] = { + SND_SOC_DAPM_MUX("Differential Mux", SND_SOC_NOPM, 0, 0, + &es8328_diffmux_controls), + SND_SOC_DAPM_MUX("Left ADC Mux", SND_SOC_NOPM, 0, 0, + &es8328_monomux_controls), + SND_SOC_DAPM_MUX("Right ADC Mux", SND_SOC_NOPM, 0, 0, + &es8328_monomux_controls), + + SND_SOC_DAPM_MUX("Left PGA Mux", ES8328_ADCPOWER, + ES8328_ADCPOWER_AINL_OFF, 1, + &es8328_left_pga_controls), + SND_SOC_DAPM_MUX("Right PGA Mux", ES8328_ADCPOWER, + ES8328_ADCPOWER_AINR_OFF, 1, + &es8328_right_pga_controls), + + SND_SOC_DAPM_MUX("Left Line Mux", SND_SOC_NOPM, 0, 0, + &es8328_left_line_controls), + SND_SOC_DAPM_MUX("Right Line Mux", SND_SOC_NOPM, 0, 0, + &es8328_right_line_controls), + + SND_SOC_DAPM_ADC("Right ADC", "Right Capture", ES8328_ADCPOWER, + ES8328_ADCPOWER_ADCR_OFF, 1), + SND_SOC_DAPM_ADC("Left ADC", "Left Capture", ES8328_ADCPOWER, + ES8328_ADCPOWER_ADCL_OFF, 1), + + SND_SOC_DAPM_SUPPLY("Mic Bias", ES8328_ADCPOWER, + ES8328_ADCPOWER_MIC_BIAS_OFF, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY("Mic Bias Gen", ES8328_ADCPOWER, + ES8328_ADCPOWER_ADC_BIAS_GEN_OFF, 1, NULL, 0), + + SND_SOC_DAPM_SUPPLY("DAC STM", ES8328_CHIPPOWER, + ES8328_CHIPPOWER_DACSTM_RESET, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY("ADC STM", ES8328_CHIPPOWER, + ES8328_CHIPPOWER_ADCSTM_RESET, 1, NULL, 0), + + SND_SOC_DAPM_SUPPLY("DAC DIG", ES8328_CHIPPOWER, + ES8328_CHIPPOWER_DACDIG_OFF, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY("ADC DIG", ES8328_CHIPPOWER, + ES8328_CHIPPOWER_ADCDIG_OFF, 1, NULL, 0), + + SND_SOC_DAPM_SUPPLY("DAC DLL", ES8328_CHIPPOWER, + ES8328_CHIPPOWER_DACDLL_OFF, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY("ADC DLL", ES8328_CHIPPOWER, + ES8328_CHIPPOWER_ADCDLL_OFF, 1, NULL, 0), + + SND_SOC_DAPM_SUPPLY("ADC Vref", ES8328_CHIPPOWER, + ES8328_CHIPPOWER_ADCVREF_OFF, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY("DAC Vref", ES8328_CHIPPOWER, + ES8328_CHIPPOWER_DACVREF_OFF, 1, NULL, 0), + + SND_SOC_DAPM_DAC("Right DAC", "Right Playback", ES8328_DACPOWER, + ES8328_DACPOWER_RDAC_OFF, 1), + SND_SOC_DAPM_DAC("Left DAC", "Left Playback", ES8328_DACPOWER, + ES8328_DACPOWER_LDAC_OFF, 1), + + SND_SOC_DAPM_MIXER("Left Mixer", SND_SOC_NOPM, 0, 0, + &es8328_left_mixer_controls[0], + ARRAY_SIZE(es8328_left_mixer_controls)), + SND_SOC_DAPM_MIXER("Right Mixer", SND_SOC_NOPM, 0, 0, + &es8328_right_mixer_controls[0], + ARRAY_SIZE(es8328_right_mixer_controls)), + + SND_SOC_DAPM_PGA("Right Out 2", ES8328_DACPOWER, + ES8328_DACPOWER_ROUT2_ON, 0, NULL, 0), + SND_SOC_DAPM_PGA("Left Out 2", ES8328_DACPOWER, + ES8328_DACPOWER_LOUT2_ON, 0, NULL, 0), + SND_SOC_DAPM_PGA("Right Out 1", ES8328_DACPOWER, + ES8328_DACPOWER_ROUT1_ON, 0, NULL, 0), + SND_SOC_DAPM_PGA("Left Out 1", ES8328_DACPOWER, + ES8328_DACPOWER_LOUT1_ON, 0, NULL, 0), + + SND_SOC_DAPM_OUTPUT("LOUT1"), + SND_SOC_DAPM_OUTPUT("ROUT1"), + SND_SOC_DAPM_OUTPUT("LOUT2"), + SND_SOC_DAPM_OUTPUT("ROUT2"), + + SND_SOC_DAPM_INPUT("LINPUT1"), + SND_SOC_DAPM_INPUT("LINPUT2"), + SND_SOC_DAPM_INPUT("RINPUT1"), + SND_SOC_DAPM_INPUT("RINPUT2"), +}; + +static const struct snd_soc_dapm_route es8328_dapm_routes[] = { + + { "Left Line Mux", "Line 1", "LINPUT1" }, + { "Left Line Mux", "Line 2", "LINPUT2" }, + { "Left Line Mux", "PGA", "Left PGA Mux" }, + { "Left Line Mux", "Differential", "Differential Mux" }, + + { "Right Line Mux", "Line 1", "RINPUT1" }, + { "Right Line Mux", "Line 2", "RINPUT2" }, + { "Right Line Mux", "PGA", "Right PGA Mux" }, + { "Right Line Mux", "Differential", "Differential Mux" }, + + { "Left PGA Mux", "Line 1", "LINPUT1" }, + { "Left PGA Mux", "Line 2", "LINPUT2" }, + { "Left PGA Mux", "Differential", "Differential Mux" }, + + { "Right PGA Mux", "Line 1", "RINPUT1" }, + { "Right PGA Mux", "Line 2", "RINPUT2" }, + { "Right PGA Mux", "Differential", "Differential Mux" }, + + { "Differential Mux", "Line 1", "LINPUT1" }, + { "Differential Mux", "Line 1", "RINPUT1" }, + { "Differential Mux", "Line 2", "LINPUT2" }, + { "Differential Mux", "Line 2", "RINPUT2" }, + + { "Left ADC Mux", "Stereo", "Left PGA Mux" }, + { "Left ADC Mux", "Mono (Left)", "Left PGA Mux" }, + { "Left ADC Mux", "Digital Mono", "Left PGA Mux" }, + + { "Right ADC Mux", "Stereo", "Right PGA Mux" }, + { "Right ADC Mux", "Mono (Right)", "Right PGA Mux" }, + { "Right ADC Mux", "Digital Mono", "Right PGA Mux" }, + + { "Left ADC", NULL, "Left ADC Mux" }, + { "Right ADC", NULL, "Right ADC Mux" }, + + { "ADC DIG", NULL, "ADC STM" }, + { "ADC DIG", NULL, "ADC Vref" }, + { "ADC DIG", NULL, "ADC DLL" }, + + { "Left ADC", NULL, "ADC DIG" }, + { "Right ADC", NULL, "ADC DIG" }, + + { "Mic Bias", NULL, "Mic Bias Gen" }, + + { "Left Line Mux", "Line 1", "LINPUT1" }, + { "Left Line Mux", "Line 2", "LINPUT2" }, + { "Left Line Mux", "PGA", "Left PGA Mux" }, + { "Left Line Mux", "Differential", "Differential Mux" }, + + { "Right Line Mux", "Line 1", "RINPUT1" }, + { "Right Line Mux", "Line 2", "RINPUT2" }, + { "Right Line Mux", "PGA", "Right PGA Mux" }, + { "Right Line Mux", "Differential", "Differential Mux" }, + + { "Left Out 1", NULL, "Left DAC" }, + { "Right Out 1", NULL, "Right DAC" }, + { "Left Out 2", NULL, "Left DAC" }, + { "Right Out 2", NULL, "Right DAC" }, + + { "Left Mixer", "Playback Switch", "Left DAC" }, + { "Left Mixer", "Left Bypass Switch", "Left Line Mux" }, + { "Left Mixer", "Right Playback Switch", "Right DAC" }, + { "Left Mixer", "Right Bypass Switch", "Right Line Mux" }, + + { "Right Mixer", "Left Playback Switch", "Left DAC" }, + { "Right Mixer", "Left Bypass Switch", "Left Line Mux" }, + { "Right Mixer", "Playback Switch", "Right DAC" }, + { "Right Mixer", "Right Bypass Switch", "Right Line Mux" }, + + { "DAC DIG", NULL, "DAC STM" }, + { "DAC DIG", NULL, "DAC Vref" }, + { "DAC DIG", NULL, "DAC DLL" }, + + { "Left DAC", NULL, "DAC DIG" }, + { "Right DAC", NULL, "DAC DIG" }, + + { "Left Out 1", NULL, "Left Mixer" }, + { "LOUT1", NULL, "Left Out 1" }, + { "Right Out 1", NULL, "Right Mixer" }, + { "ROUT1", NULL, "Right Out 1" }, + + { "Left Out 2", NULL, "Left Mixer" }, + { "LOUT2", NULL, "Left Out 2" }, + { "Right Out 2", NULL, "Right Mixer" }, + { "ROUT2", NULL, "Right Out 2" }, +}; + +static int es8328_mute(struct snd_soc_dai *dai, int mute) +{ + return snd_soc_update_bits(dai->codec, ES8328_DACCONTROL3, + ES8328_DACCONTROL3_DACMUTE, + mute ? ES8328_DACCONTROL3_DACMUTE : 0); +} + +static int es8328_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; + struct es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec); + int clk_rate; + int i; + int reg; + u8 ratio; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + reg = ES8328_DACCONTROL2; + else + reg = ES8328_ADCCONTROL5; + + clk_rate = clk_get_rate(es8328->clk); + + if ((clk_rate != ES8328_SYSCLK_RATE_1X) && + (clk_rate != ES8328_SYSCLK_RATE_2X)) { + dev_err(codec->dev, + "%s: clock is running at %d Hz, not %d or %d Hz\n", + __func__, clk_rate, + ES8328_SYSCLK_RATE_1X, ES8328_SYSCLK_RATE_2X); + return -EINVAL; + } + + /* find master mode MCLK to sampling frequency ratio */ + ratio = mclk_ratios[0].rate; + for (i = 1; i < ARRAY_SIZE(mclk_ratios); i++) + if (params_rate(params) <= mclk_ratios[i].rate) + ratio = mclk_ratios[i].ratio; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + es8328->playback_fs = params_rate(params); + es8328_set_deemph(codec); + } + + return snd_soc_update_bits(codec, reg, ES8328_RATEMASK, ratio); +} + +static int es8328_set_dai_fmt(struct snd_soc_dai *codec_dai, + unsigned int fmt) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec); + int clk_rate; + u8 mode = ES8328_DACCONTROL1_DACWL_16; + + /* set master/slave audio interface */ + if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBM_CFM) + return -EINVAL; + + /* interface format */ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + mode |= ES8328_DACCONTROL1_DACFORMAT_I2S; + break; + case SND_SOC_DAIFMT_RIGHT_J: + mode |= ES8328_DACCONTROL1_DACFORMAT_RJUST; + break; + case SND_SOC_DAIFMT_LEFT_J: + mode |= ES8328_DACCONTROL1_DACFORMAT_LJUST; + break; + default: + return -EINVAL; + } + + /* clock inversion */ + if ((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_NB_NF) + return -EINVAL; + + snd_soc_write(codec, ES8328_DACCONTROL1, mode); + snd_soc_write(codec, ES8328_ADCCONTROL4, mode); + + /* Master serial port mode, with BCLK generated automatically */ + clk_rate = clk_get_rate(es8328->clk); + if (clk_rate == ES8328_SYSCLK_RATE_1X) + snd_soc_write(codec, ES8328_MASTERMODE, + ES8328_MASTERMODE_MSC); + else + snd_soc_write(codec, ES8328_MASTERMODE, + ES8328_MASTERMODE_MCLKDIV2 | + ES8328_MASTERMODE_MSC); + + return 0; +} + +static int es8328_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + switch (level) { + case SND_SOC_BIAS_ON: + break; + + case SND_SOC_BIAS_PREPARE: + /* VREF, VMID=2x50k, digital enabled */ + snd_soc_write(codec, ES8328_CHIPPOWER, 0); + snd_soc_update_bits(codec, ES8328_CONTROL1, + ES8328_CONTROL1_VMIDSEL_MASK | + ES8328_CONTROL1_ENREF, + ES8328_CONTROL1_VMIDSEL_50k | + ES8328_CONTROL1_ENREF); + break; + + case SND_SOC_BIAS_STANDBY: + if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { + snd_soc_update_bits(codec, ES8328_CONTROL1, + ES8328_CONTROL1_VMIDSEL_MASK | + ES8328_CONTROL1_ENREF, + ES8328_CONTROL1_VMIDSEL_5k | + ES8328_CONTROL1_ENREF); + + /* Charge caps */ + msleep(100); + } + + snd_soc_write(codec, ES8328_CONTROL2, + ES8328_CONTROL2_OVERCURRENT_ON | + ES8328_CONTROL2_THERMAL_SHUTDOWN_ON); + + /* VREF, VMID=2*500k, digital stopped */ + snd_soc_update_bits(codec, ES8328_CONTROL1, + ES8328_CONTROL1_VMIDSEL_MASK | + ES8328_CONTROL1_ENREF, + ES8328_CONTROL1_VMIDSEL_500k | + ES8328_CONTROL1_ENREF); + break; + + case SND_SOC_BIAS_OFF: + snd_soc_update_bits(codec, ES8328_CONTROL1, + ES8328_CONTROL1_VMIDSEL_MASK | + ES8328_CONTROL1_ENREF, + 0); + break; + } + codec->dapm.bias_level = level; + return 0; +} + +static const struct snd_soc_dai_ops es8328_dai_ops = { + .hw_params = es8328_hw_params, + .digital_mute = es8328_mute, + .set_fmt = es8328_set_dai_fmt, +}; + +static struct snd_soc_dai_driver es8328_dai = { + .name = "es8328-hifi-analog", + .playback = { + .stream_name = "Playback", + .channels_min = 2, + .channels_max = 2, + .rates = ES8328_RATES, + .formats = ES8328_FORMATS, + }, + .capture = { + .stream_name = "Capture", + .channels_min = 2, + .channels_max = 2, + .rates = ES8328_RATES, + .formats = ES8328_FORMATS, + }, + .ops = &es8328_dai_ops, +}; + +static int es8328_suspend(struct snd_soc_codec *codec) +{ + struct es8328_priv *es8328; + int ret; + + es8328 = snd_soc_codec_get_drvdata(codec); + + clk_disable_unprepare(es8328->clk); + + ret = regulator_bulk_disable(ARRAY_SIZE(es8328->supplies), + es8328->supplies); + if (ret) { + dev_err(codec->dev, "unable to disable regulators\n"); + return ret; + } + return 0; +} + +static int es8328_resume(struct snd_soc_codec *codec) +{ + struct regmap *regmap = dev_get_regmap(codec->dev, NULL); + struct es8328_priv *es8328; + int ret; + + es8328 = snd_soc_codec_get_drvdata(codec); + + ret = clk_prepare_enable(es8328->clk); + if (ret) { + dev_err(codec->dev, "unable to enable clock\n"); + return ret; + } + + ret = regulator_bulk_enable(ARRAY_SIZE(es8328->supplies), + es8328->supplies); + if (ret) { + dev_err(codec->dev, "unable to enable regulators\n"); + return ret; + } + + regcache_mark_dirty(regmap); + ret = regcache_sync(regmap); + if (ret) { + dev_err(codec->dev, "unable to sync regcache\n"); + return ret; + } + + return 0; +} + +static int es8328_codec_probe(struct snd_soc_codec *codec) +{ + struct es8328_priv *es8328; + int ret; + + es8328 = snd_soc_codec_get_drvdata(codec); + + ret = regulator_bulk_enable(ARRAY_SIZE(es8328->supplies), + es8328->supplies); + if (ret) { + dev_err(codec->dev, "unable to enable regulators\n"); + return ret; + } + + /* Setup clocks */ + es8328->clk = devm_clk_get(codec->dev, NULL); + if (IS_ERR(es8328->clk)) { + dev_err(codec->dev, "codec clock missing or invalid\n"); + ret = PTR_ERR(es8328->clk); + goto clk_fail; + } + + ret = clk_prepare_enable(es8328->clk); + if (ret) { + dev_err(codec->dev, "unable to prepare codec clk\n"); + goto clk_fail; + } + + return 0; + +clk_fail: + regulator_bulk_disable(ARRAY_SIZE(es8328->supplies), + es8328->supplies); + return ret; +} + +static int es8328_remove(struct snd_soc_codec *codec) +{ + struct es8328_priv *es8328; + + es8328 = snd_soc_codec_get_drvdata(codec); + + if (es8328->clk) + clk_disable_unprepare(es8328->clk); + + regulator_bulk_disable(ARRAY_SIZE(es8328->supplies), + es8328->supplies); + + return 0; +} + +const struct regmap_config es8328_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = ES8328_REG_MAX, + .cache_type = REGCACHE_RBTREE, +}; +EXPORT_SYMBOL_GPL(es8328_regmap_config); + +static struct snd_soc_codec_driver es8328_codec_driver = { + .probe = es8328_codec_probe, + .suspend = es8328_suspend, + .resume = es8328_resume, + .remove = es8328_remove, + .set_bias_level = es8328_set_bias_level, + .suspend_bias_off = true, + + .controls = es8328_snd_controls, + .num_controls = ARRAY_SIZE(es8328_snd_controls), + .dapm_widgets = es8328_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(es8328_dapm_widgets), + .dapm_routes = es8328_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(es8328_dapm_routes), +}; + +int es8328_probe(struct device *dev, struct regmap *regmap) +{ + struct es8328_priv *es8328; + int ret; + int i; + + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + es8328 = devm_kzalloc(dev, sizeof(*es8328), GFP_KERNEL); + if (es8328 == NULL) + return -ENOMEM; + + es8328->regmap = regmap; + + for (i = 0; i < ARRAY_SIZE(es8328->supplies); i++) + es8328->supplies[i].supply = supply_names[i]; + + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(es8328->supplies), + es8328->supplies); + if (ret) { + dev_err(dev, "unable to get regulators\n"); + return ret; + } + + dev_set_drvdata(dev, es8328); + + return snd_soc_register_codec(dev, + &es8328_codec_driver, &es8328_dai, 1); +} +EXPORT_SYMBOL_GPL(es8328_probe); + +MODULE_DESCRIPTION("ASoC ES8328 driver"); +MODULE_AUTHOR("Sean Cross <xobs@kosagi.com>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/es8328.h b/sound/soc/codecs/es8328.h new file mode 100644 index 000000000000..cb36afe10c0e --- /dev/null +++ b/sound/soc/codecs/es8328.h @@ -0,0 +1,314 @@ +/* + * es8328.h -- ES8328 ALSA SoC Audio driver + */ + +#ifndef _ES8328_H +#define _ES8328_H + +#include <linux/regmap.h> + +struct device; + +extern const struct regmap_config es8328_regmap_config; +int es8328_probe(struct device *dev, struct regmap *regmap); + +#define ES8328_DACLVOL 46 +#define ES8328_DACRVOL 47 +#define ES8328_DACCTL 28 +#define ES8328_RATEMASK (0x1f << 0) + +#define ES8328_CONTROL1 0x00 +#define ES8328_CONTROL1_VMIDSEL_OFF (0 << 0) +#define ES8328_CONTROL1_VMIDSEL_50k (1 << 0) +#define ES8328_CONTROL1_VMIDSEL_500k (2 << 0) +#define ES8328_CONTROL1_VMIDSEL_5k (3 << 0) +#define ES8328_CONTROL1_VMIDSEL_MASK (7 << 0) +#define ES8328_CONTROL1_ENREF (1 << 2) +#define ES8328_CONTROL1_SEQEN (1 << 3) +#define ES8328_CONTROL1_SAMEFS (1 << 4) +#define ES8328_CONTROL1_DACMCLK_ADC (0 << 5) +#define ES8328_CONTROL1_DACMCLK_DAC (1 << 5) +#define ES8328_CONTROL1_LRCM (1 << 6) +#define ES8328_CONTROL1_SCP_RESET (1 << 7) + +#define ES8328_CONTROL2 0x01 +#define ES8328_CONTROL2_VREF_BUF_OFF (1 << 0) +#define ES8328_CONTROL2_VREF_LOWPOWER (1 << 1) +#define ES8328_CONTROL2_IBIASGEN_OFF (1 << 2) +#define ES8328_CONTROL2_ANALOG_OFF (1 << 3) +#define ES8328_CONTROL2_VREF_BUF_LOWPOWER (1 << 4) +#define ES8328_CONTROL2_VCM_MOD_LOWPOWER (1 << 5) +#define ES8328_CONTROL2_OVERCURRENT_ON (1 << 6) +#define ES8328_CONTROL2_THERMAL_SHUTDOWN_ON (1 << 7) + +#define ES8328_CHIPPOWER 0x02 +#define ES8328_CHIPPOWER_DACVREF_OFF 0 +#define ES8328_CHIPPOWER_ADCVREF_OFF 1 +#define ES8328_CHIPPOWER_DACDLL_OFF 2 +#define ES8328_CHIPPOWER_ADCDLL_OFF 3 +#define ES8328_CHIPPOWER_DACSTM_RESET 4 +#define ES8328_CHIPPOWER_ADCSTM_RESET 5 +#define ES8328_CHIPPOWER_DACDIG_OFF 6 +#define ES8328_CHIPPOWER_ADCDIG_OFF 7 + +#define ES8328_ADCPOWER 0x03 +#define ES8328_ADCPOWER_INT1_LOWPOWER 0 +#define ES8328_ADCPOWER_FLASH_ADC_LOWPOWER 1 +#define ES8328_ADCPOWER_ADC_BIAS_GEN_OFF 2 +#define ES8328_ADCPOWER_MIC_BIAS_OFF 3 +#define ES8328_ADCPOWER_ADCR_OFF 4 +#define ES8328_ADCPOWER_ADCL_OFF 5 +#define ES8328_ADCPOWER_AINR_OFF 6 +#define ES8328_ADCPOWER_AINL_OFF 7 + +#define ES8328_DACPOWER 0x04 +#define ES8328_DACPOWER_OUT3_ON 0 +#define ES8328_DACPOWER_MONO_ON 1 +#define ES8328_DACPOWER_ROUT2_ON 2 +#define ES8328_DACPOWER_LOUT2_ON 3 +#define ES8328_DACPOWER_ROUT1_ON 4 +#define ES8328_DACPOWER_LOUT1_ON 5 +#define ES8328_DACPOWER_RDAC_OFF 6 +#define ES8328_DACPOWER_LDAC_OFF 7 + +#define ES8328_CHIPLOPOW1 0x05 +#define ES8328_CHIPLOPOW2 0x06 +#define ES8328_ANAVOLMANAG 0x07 + +#define ES8328_MASTERMODE 0x08 +#define ES8328_MASTERMODE_BCLKDIV (0 << 0) +#define ES8328_MASTERMODE_BCLK_INV (1 << 5) +#define ES8328_MASTERMODE_MCLKDIV2 (1 << 6) +#define ES8328_MASTERMODE_MSC (1 << 7) + +#define ES8328_ADCCONTROL1 0x09 +#define ES8328_ADCCONTROL2 0x0a +#define ES8328_ADCCONTROL3 0x0b +#define ES8328_ADCCONTROL4 0x0c +#define ES8328_ADCCONTROL5 0x0d +#define ES8328_ADCCONTROL5_RATEMASK (0x1f << 0) + +#define ES8328_ADCCONTROL6 0x0e + +#define ES8328_ADCCONTROL7 0x0f +#define ES8328_ADCCONTROL7_ADC_MUTE (1 << 2) +#define ES8328_ADCCONTROL7_ADC_LER (1 << 3) +#define ES8328_ADCCONTROL7_ADC_ZERO_CROSS (1 << 4) +#define ES8328_ADCCONTROL7_ADC_SOFT_RAMP (1 << 5) +#define ES8328_ADCCONTROL7_ADC_RAMP_RATE_4 (0 << 6) +#define ES8328_ADCCONTROL7_ADC_RAMP_RATE_8 (1 << 6) +#define ES8328_ADCCONTROL7_ADC_RAMP_RATE_16 (2 << 6) +#define ES8328_ADCCONTROL7_ADC_RAMP_RATE_32 (3 << 6) + +#define ES8328_ADCCONTROL8 0x10 +#define ES8328_ADCCONTROL9 0x11 +#define ES8328_ADCCONTROL10 0x12 +#define ES8328_ADCCONTROL11 0x13 +#define ES8328_ADCCONTROL12 0x14 +#define ES8328_ADCCONTROL13 0x15 +#define ES8328_ADCCONTROL14 0x16 + +#define ES8328_DACCONTROL1 0x17 +#define ES8328_DACCONTROL1_DACFORMAT_I2S (0 << 1) +#define ES8328_DACCONTROL1_DACFORMAT_LJUST (1 << 1) +#define ES8328_DACCONTROL1_DACFORMAT_RJUST (2 << 1) +#define ES8328_DACCONTROL1_DACFORMAT_PCM (3 << 1) +#define ES8328_DACCONTROL1_DACWL_24 (0 << 3) +#define ES8328_DACCONTROL1_DACWL_20 (1 << 3) +#define ES8328_DACCONTROL1_DACWL_18 (2 << 3) +#define ES8328_DACCONTROL1_DACWL_16 (3 << 3) +#define ES8328_DACCONTROL1_DACWL_32 (4 << 3) +#define ES8328_DACCONTROL1_DACLRP_I2S_POL_NORMAL (0 << 6) +#define ES8328_DACCONTROL1_DACLRP_I2S_POL_INV (1 << 6) +#define ES8328_DACCONTROL1_DACLRP_PCM_MSB_CLK2 (0 << 6) +#define ES8328_DACCONTROL1_DACLRP_PCM_MSB_CLK1 (1 << 6) +#define ES8328_DACCONTROL1_LRSWAP (1 << 7) + +#define ES8328_DACCONTROL2 0x18 +#define ES8328_DACCONTROL2_RATEMASK (0x1f << 0) +#define ES8328_DACCONTROL2_DOUBLESPEED (1 << 5) + +#define ES8328_DACCONTROL3 0x19 +#define ES8328_DACCONTROL3_AUTOMUTE (1 << 2) +#define ES8328_DACCONTROL3_DACMUTE (1 << 2) +#define ES8328_DACCONTROL3_LEFTGAINVOL (1 << 3) +#define ES8328_DACCONTROL3_DACZEROCROSS (1 << 4) +#define ES8328_DACCONTROL3_DACSOFTRAMP (1 << 5) +#define ES8328_DACCONTROL3_DACRAMPRATE (3 << 6) + +#define ES8328_LDACVOL 0x1a +#define ES8328_LDACVOL_MASK (0 << 0) +#define ES8328_LDACVOL_MAX (0xc0) + +#define ES8328_RDACVOL 0x1b +#define ES8328_RDACVOL_MASK (0 << 0) +#define ES8328_RDACVOL_MAX (0xc0) + +#define ES8328_DACVOL_MAX (0xc0) + +#define ES8328_DACCONTROL4 0x1a +#define ES8328_DACCONTROL5 0x1b + +#define ES8328_DACCONTROL6 0x1c +#define ES8328_DACCONTROL6_CLICKFREE (1 << 3) +#define ES8328_DACCONTROL6_DAC_INVR (1 << 4) +#define ES8328_DACCONTROL6_DAC_INVL (1 << 5) +#define ES8328_DACCONTROL6_DEEMPH_OFF (0 << 6) +#define ES8328_DACCONTROL6_DEEMPH_32k (1 << 6) +#define ES8328_DACCONTROL6_DEEMPH_44_1k (2 << 6) +#define ES8328_DACCONTROL6_DEEMPH_48k (3 << 6) + +#define ES8328_DACCONTROL7 0x1d +#define ES8328_DACCONTROL7_VPP_SCALE_3p5 (0 << 0) +#define ES8328_DACCONTROL7_VPP_SCALE_4p0 (1 << 0) +#define ES8328_DACCONTROL7_VPP_SCALE_3p0 (2 << 0) +#define ES8328_DACCONTROL7_VPP_SCALE_2p5 (3 << 0) +#define ES8328_DACCONTROL7_SHELVING_STRENGTH (1 << 2) /* In eights */ +#define ES8328_DACCONTROL7_MONO (1 << 5) +#define ES8328_DACCONTROL7_ZEROR (1 << 6) +#define ES8328_DACCONTROL7_ZEROL (1 << 7) + +/* Shelving filter */ +#define ES8328_DACCONTROL8 0x1e +#define ES8328_DACCONTROL9 0x1f +#define ES8328_DACCONTROL10 0x20 +#define ES8328_DACCONTROL11 0x21 +#define ES8328_DACCONTROL12 0x22 +#define ES8328_DACCONTROL13 0x23 +#define ES8328_DACCONTROL14 0x24 +#define ES8328_DACCONTROL15 0x25 + +#define ES8328_DACCONTROL16 0x26 +#define ES8328_DACCONTROL16_RMIXSEL_RIN1 (0 << 0) +#define ES8328_DACCONTROL16_RMIXSEL_RIN2 (1 << 0) +#define ES8328_DACCONTROL16_RMIXSEL_RIN3 (2 << 0) +#define ES8328_DACCONTROL16_RMIXSEL_RADC (3 << 0) +#define ES8328_DACCONTROL16_LMIXSEL_LIN1 (0 << 3) +#define ES8328_DACCONTROL16_LMIXSEL_LIN2 (1 << 3) +#define ES8328_DACCONTROL16_LMIXSEL_LIN3 (2 << 3) +#define ES8328_DACCONTROL16_LMIXSEL_LADC (3 << 3) + +#define ES8328_DACCONTROL17 0x27 +#define ES8328_DACCONTROL17_LI2LOVOL (7 << 3) +#define ES8328_DACCONTROL17_LI2LO (1 << 6) +#define ES8328_DACCONTROL17_LD2LO (1 << 7) + +#define ES8328_DACCONTROL18 0x28 +#define ES8328_DACCONTROL18_RI2LOVOL (7 << 3) +#define ES8328_DACCONTROL18_RI2LO (1 << 6) +#define ES8328_DACCONTROL18_RD2LO (1 << 7) + +#define ES8328_DACCONTROL19 0x29 +#define ES8328_DACCONTROL19_LI2ROVOL (7 << 3) +#define ES8328_DACCONTROL19_LI2RO (1 << 6) +#define ES8328_DACCONTROL19_LD2RO (1 << 7) + +#define ES8328_DACCONTROL20 0x2a +#define ES8328_DACCONTROL20_RI2ROVOL (7 << 3) +#define ES8328_DACCONTROL20_RI2RO (1 << 6) +#define ES8328_DACCONTROL20_RD2RO (1 << 7) + +#define ES8328_DACCONTROL21 0x2b +#define ES8328_DACCONTROL21_LI2MOVOL (7 << 3) +#define ES8328_DACCONTROL21_LI2MO (1 << 6) +#define ES8328_DACCONTROL21_LD2MO (1 << 7) + +#define ES8328_DACCONTROL22 0x2c +#define ES8328_DACCONTROL22_RI2MOVOL (7 << 3) +#define ES8328_DACCONTROL22_RI2MO (1 << 6) +#define ES8328_DACCONTROL22_RD2MO (1 << 7) + +#define ES8328_DACCONTROL23 0x2d +#define ES8328_DACCONTROL23_MOUTINV (1 << 1) +#define ES8328_DACCONTROL23_HPSWPOL (1 << 2) +#define ES8328_DACCONTROL23_HPSWEN (1 << 3) +#define ES8328_DACCONTROL23_VROI_1p5k (0 << 4) +#define ES8328_DACCONTROL23_VROI_40k (1 << 4) +#define ES8328_DACCONTROL23_OUT3_VREF (0 << 5) +#define ES8328_DACCONTROL23_OUT3_ROUT1 (1 << 5) +#define ES8328_DACCONTROL23_OUT3_MONOOUT (2 << 5) +#define ES8328_DACCONTROL23_OUT3_RIGHT_MIXER (3 << 5) +#define ES8328_DACCONTROL23_ROUT2INV (1 << 7) + +/* LOUT1 Amplifier */ +#define ES8328_LOUT1VOL 0x2e +#define ES8328_LOUT1VOL_MASK (0 << 5) +#define ES8328_LOUT1VOL_MAX (0x24) + +/* ROUT1 Amplifier */ +#define ES8328_ROUT1VOL 0x2f +#define ES8328_ROUT1VOL_MASK (0 << 5) +#define ES8328_ROUT1VOL_MAX (0x24) + +#define ES8328_OUT1VOL_MAX (0x24) + +/* LOUT2 Amplifier */ +#define ES8328_LOUT2VOL 0x30 +#define ES8328_LOUT2VOL_MASK (0 << 5) +#define ES8328_LOUT2VOL_MAX (0x24) + +/* ROUT2 Amplifier */ +#define ES8328_ROUT2VOL 0x31 +#define ES8328_ROUT2VOL_MASK (0 << 5) +#define ES8328_ROUT2VOL_MAX (0x24) + +#define ES8328_OUT2VOL_MAX (0x24) + +/* Mono Out Amplifier */ +#define ES8328_MONOOUTVOL 0x32 +#define ES8328_MONOOUTVOL_MASK (0 << 5) +#define ES8328_MONOOUTVOL_MAX (0x24) + +#define ES8328_DACCONTROL29 0x33 +#define ES8328_DACCONTROL30 0x34 + +#define ES8328_SYSCLK 0 + +#define ES8328_REG_MAX 0x35 + +#define ES8328_PLL1 0 +#define ES8328_PLL2 1 + +/* clock inputs */ +#define ES8328_MCLK 0 +#define ES8328_PCMCLK 1 + +/* clock divider id's */ +#define ES8328_PCMDIV 0 +#define ES8328_BCLKDIV 1 +#define ES8328_VXCLKDIV 2 + +/* PCM clock dividers */ +#define ES8328_PCM_DIV_1 (0 << 6) +#define ES8328_PCM_DIV_3 (2 << 6) +#define ES8328_PCM_DIV_5_5 (3 << 6) +#define ES8328_PCM_DIV_2 (4 << 6) +#define ES8328_PCM_DIV_4 (5 << 6) +#define ES8328_PCM_DIV_6 (6 << 6) +#define ES8328_PCM_DIV_8 (7 << 6) + +/* BCLK clock dividers */ +#define ES8328_BCLK_DIV_1 (0 << 7) +#define ES8328_BCLK_DIV_2 (1 << 7) +#define ES8328_BCLK_DIV_4 (2 << 7) +#define ES8328_BCLK_DIV_8 (3 << 7) + +/* VXCLK clock dividers */ +#define ES8328_VXCLK_DIV_1 (0 << 6) +#define ES8328_VXCLK_DIV_2 (1 << 6) +#define ES8328_VXCLK_DIV_4 (2 << 6) +#define ES8328_VXCLK_DIV_8 (3 << 6) +#define ES8328_VXCLK_DIV_16 (4 << 6) + +#define ES8328_DAI_HIFI 0 +#define ES8328_DAI_VOICE 1 + +#define ES8328_1536FS 1536 +#define ES8328_1024FS 1024 +#define ES8328_768FS 768 +#define ES8328_512FS 512 +#define ES8328_384FS 384 +#define ES8328_256FS 256 +#define ES8328_128FS 128 + +#endif diff --git a/sound/soc/codecs/lm49453.c b/sound/soc/codecs/lm49453.c index 275b3f72f3f4..c1ae5764983f 100644 --- a/sound/soc/codecs/lm49453.c +++ b/sound/soc/codecs/lm49453.c @@ -1395,18 +1395,6 @@ static struct snd_soc_dai_driver lm49453_dai[] = { }, }; -static int lm49453_suspend(struct snd_soc_codec *codec) -{ - lm49453_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - -static int lm49453_resume(struct snd_soc_codec *codec) -{ - lm49453_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - return 0; -} - /* power down chip */ static int lm49453_remove(struct snd_soc_codec *codec) { @@ -1416,8 +1404,6 @@ static int lm49453_remove(struct snd_soc_codec *codec) static struct snd_soc_codec_driver soc_codec_dev_lm49453 = { .remove = lm49453_remove, - .suspend = lm49453_suspend, - .resume = lm49453_resume, .set_bias_level = lm49453_set_bias_level, .controls = lm49453_snd_controls, .num_controls = ARRAY_SIZE(lm49453_snd_controls), diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c index 4a063fa88526..7e111865946a 100644 --- a/sound/soc/codecs/max98090.c +++ b/sound/soc/codecs/max98090.c @@ -1311,8 +1311,6 @@ static const struct snd_soc_dapm_route max98090_dapm_routes[] = { {"MIC1 Input", NULL, "MIC1"}, {"MIC2 Input", NULL, "MIC2"}, - {"DMICL", NULL, "DMICL_ENA"}, - {"DMICR", NULL, "DMICR_ENA"}, {"DMICL", NULL, "AHPF"}, {"DMICR", NULL, "AHPF"}, @@ -1370,6 +1368,8 @@ static const struct snd_soc_dapm_route max98090_dapm_routes[] = { {"DMIC Mux", "ADC", "ADCR"}, {"DMIC Mux", "DMIC", "DMICL"}, {"DMIC Mux", "DMIC", "DMICR"}, + {"DMIC Mux", "DMIC", "DMICL_ENA"}, + {"DMIC Mux", "DMIC", "DMICR_ENA"}, {"LBENL Mux", "Normal", "DMIC Mux"}, {"LBENL Mux", "Loopback", "LTENL Mux"}, @@ -1972,6 +1972,102 @@ static int max98090_dai_digital_mute(struct snd_soc_dai *codec_dai, int mute) return 0; } +static int max98090_dai_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + if (!max98090->master && dai->active == 1) + queue_delayed_work(system_power_efficient_wq, + &max98090->pll_det_enable_work, + msecs_to_jiffies(10)); + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + if (!max98090->master && dai->active == 1) + schedule_work(&max98090->pll_det_disable_work); + break; + default: + break; + } + + return 0; +} + +static void max98090_pll_det_enable_work(struct work_struct *work) +{ + struct max98090_priv *max98090 = + container_of(work, struct max98090_priv, + pll_det_enable_work.work); + struct snd_soc_codec *codec = max98090->codec; + unsigned int status, mask; + + /* + * Clear status register in order to clear possibly already occurred + * PLL unlock. If PLL hasn't still locked, the status will be set + * again and PLL unlock interrupt will occur. + * Note this will clear all status bits + */ + regmap_read(max98090->regmap, M98090_REG_DEVICE_STATUS, &status); + + /* + * Queue jack work in case jack state has just changed but handler + * hasn't run yet + */ + regmap_read(max98090->regmap, M98090_REG_INTERRUPT_S, &mask); + status &= mask; + if (status & M98090_JDET_MASK) + queue_delayed_work(system_power_efficient_wq, + &max98090->jack_work, + msecs_to_jiffies(100)); + + /* Enable PLL unlock interrupt */ + snd_soc_update_bits(codec, M98090_REG_INTERRUPT_S, + M98090_IULK_MASK, + 1 << M98090_IULK_SHIFT); +} + +static void max98090_pll_det_disable_work(struct work_struct *work) +{ + struct max98090_priv *max98090 = + container_of(work, struct max98090_priv, pll_det_disable_work); + struct snd_soc_codec *codec = max98090->codec; + + cancel_delayed_work_sync(&max98090->pll_det_enable_work); + + /* Disable PLL unlock interrupt */ + snd_soc_update_bits(codec, M98090_REG_INTERRUPT_S, + M98090_IULK_MASK, 0); +} + +static void max98090_pll_work(struct work_struct *work) +{ + struct max98090_priv *max98090 = + container_of(work, struct max98090_priv, pll_work); + struct snd_soc_codec *codec = max98090->codec; + + if (!snd_soc_codec_is_active(codec)) + return; + + dev_info(codec->dev, "PLL unlocked\n"); + + /* Toggle shutdown OFF then ON */ + snd_soc_update_bits(codec, M98090_REG_DEVICE_SHUTDOWN, + M98090_SHDNN_MASK, 0); + msleep(10); + snd_soc_update_bits(codec, M98090_REG_DEVICE_SHUTDOWN, + M98090_SHDNN_MASK, M98090_SHDNN_MASK); + + /* Give PLL time to lock */ + msleep(10); +} + static void max98090_jack_work(struct work_struct *work) { struct max98090_priv *max98090 = container_of(work, @@ -2103,8 +2199,10 @@ static irqreturn_t max98090_interrupt(int irq, void *data) if (active & M98090_SLD_MASK) dev_dbg(codec->dev, "M98090_SLD_MASK\n"); - if (active & M98090_ULK_MASK) - dev_err(codec->dev, "M98090_ULK_MASK\n"); + if (active & M98090_ULK_MASK) { + dev_dbg(codec->dev, "M98090_ULK_MASK\n"); + schedule_work(&max98090->pll_work); + } if (active & M98090_JDET_MASK) { dev_dbg(codec->dev, "M98090_JDET_MASK\n"); @@ -2177,6 +2275,7 @@ static struct snd_soc_dai_ops max98090_dai_ops = { .set_tdm_slot = max98090_set_tdm_slot, .hw_params = max98090_dai_hw_params, .digital_mute = max98090_dai_digital_mute, + .trigger = max98090_dai_trigger, }; static struct snd_soc_dai_driver max98090_dai[] = { @@ -2258,6 +2357,11 @@ static int max98090_probe(struct snd_soc_codec *codec) max98090->jack_state = M98090_JACK_STATE_NO_HEADSET; INIT_DELAYED_WORK(&max98090->jack_work, max98090_jack_work); + INIT_DELAYED_WORK(&max98090->pll_det_enable_work, + max98090_pll_det_enable_work); + INIT_WORK(&max98090->pll_det_disable_work, + max98090_pll_det_disable_work); + INIT_WORK(&max98090->pll_work, max98090_pll_work); /* Enable jack detection */ snd_soc_write(codec, M98090_REG_JACK_DETECT, @@ -2310,6 +2414,9 @@ static int max98090_remove(struct snd_soc_codec *codec) struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec); cancel_delayed_work_sync(&max98090->jack_work); + cancel_delayed_work_sync(&max98090->pll_det_enable_work); + cancel_work_sync(&max98090->pll_det_disable_work); + cancel_work_sync(&max98090->pll_work); return 0; } diff --git a/sound/soc/codecs/max98090.h b/sound/soc/codecs/max98090.h index cf1b6062ba8c..14427a566f41 100644 --- a/sound/soc/codecs/max98090.h +++ b/sound/soc/codecs/max98090.h @@ -1532,6 +1532,9 @@ struct max98090_priv { int irq; int jack_state; struct delayed_work jack_work; + struct delayed_work pll_det_enable_work; + struct work_struct pll_det_disable_work; + struct work_struct pll_work; struct snd_soc_jack *jack; unsigned int dai_fmt; int tdm_slots; diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c index 163ec3855fd4..0c8aefab404c 100644 --- a/sound/soc/codecs/pcm512x.c +++ b/sound/soc/codecs/pcm512x.c @@ -259,13 +259,13 @@ static const struct soc_enum pcm512x_veds = pcm512x_ramp_step_text); static const struct snd_kcontrol_new pcm512x_controls[] = { -SOC_DOUBLE_R_TLV("Playback Digital Volume", PCM512x_DIGITAL_VOLUME_2, +SOC_DOUBLE_R_TLV("Digital Playback Volume", PCM512x_DIGITAL_VOLUME_2, PCM512x_DIGITAL_VOLUME_3, 0, 255, 1, digital_tlv), SOC_DOUBLE_TLV("Playback Volume", PCM512x_ANALOG_GAIN_CTRL, PCM512x_LAGN_SHIFT, PCM512x_RAGN_SHIFT, 1, 1, analog_tlv), SOC_DOUBLE_TLV("Playback Boost Volume", PCM512x_ANALOG_GAIN_BOOST, PCM512x_AGBL_SHIFT, PCM512x_AGBR_SHIFT, 1, 0, boost_tlv), -SOC_DOUBLE("Playback Digital Switch", PCM512x_MUTE, PCM512x_RQML_SHIFT, +SOC_DOUBLE("Digital Playback Switch", PCM512x_MUTE, PCM512x_RQML_SHIFT, PCM512x_RQMR_SHIFT, 1, 1), SOC_SINGLE("Deemphasis Switch", PCM512x_DSP, PCM512x_DEMP_SHIFT, 1, 1), diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c index e4f6102efc1a..b86b426f159d 100644 --- a/sound/soc/codecs/rt286.c +++ b/sound/soc/codecs/rt286.c @@ -51,7 +51,7 @@ static struct reg_default rt286_index_def[] = { { 0x04, 0xaf01 }, { 0x08, 0x000d }, { 0x09, 0xd810 }, - { 0x0a, 0x0060 }, + { 0x0a, 0x0120 }, { 0x0b, 0x0000 }, { 0x0d, 0x2800 }, { 0x0f, 0x0000 }, @@ -60,7 +60,7 @@ static struct reg_default rt286_index_def[] = { { 0x33, 0x0208 }, { 0x49, 0x0004 }, { 0x4f, 0x50e9 }, - { 0x50, 0x2c00 }, + { 0x50, 0x2000 }, { 0x63, 0x2902 }, { 0x67, 0x1111 }, { 0x68, 0x1016 }, @@ -104,7 +104,6 @@ static const struct reg_default rt286_reg[] = { { 0x02170700, 0x00000000 }, { 0x02270100, 0x00000000 }, { 0x02370100, 0x00000000 }, - { 0x02040000, 0x00004002 }, { 0x01870700, 0x00000020 }, { 0x00830000, 0x000000c3 }, { 0x00930000, 0x000000c3 }, @@ -192,7 +191,6 @@ static int rt286_hw_write(void *context, unsigned int reg, unsigned int value) /*handle index registers*/ if (reg <= 0xff) { rt286_hw_write(client, RT286_COEF_INDEX, reg); - reg = RT286_PROC_COEF; for (i = 0; i < INDEX_CACHE_SIZE; i++) { if (reg == rt286->index_cache[i].reg) { rt286->index_cache[i].def = value; @@ -200,6 +198,7 @@ static int rt286_hw_write(void *context, unsigned int reg, unsigned int value) } } + reg = RT286_PROC_COEF; } data[0] = (reg >> 24) & 0xff; diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index 6bc6efdec550..c3f2decd643c 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -1906,6 +1906,32 @@ static int rt5640_set_bias_level(struct snd_soc_codec *codec, return 0; } +int rt5640_dmic_enable(struct snd_soc_codec *codec, + bool dmic1_data_pin, bool dmic2_data_pin) +{ + struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec); + + regmap_update_bits(rt5640->regmap, RT5640_GPIO_CTRL1, + RT5640_GP2_PIN_MASK, RT5640_GP2_PIN_DMIC1_SCL); + + if (dmic1_data_pin) { + regmap_update_bits(rt5640->regmap, RT5640_DMIC, + RT5640_DMIC_1_DP_MASK, RT5640_DMIC_1_DP_GPIO3); + regmap_update_bits(rt5640->regmap, RT5640_GPIO_CTRL1, + RT5640_GP3_PIN_MASK, RT5640_GP3_PIN_DMIC1_SDA); + } + + if (dmic2_data_pin) { + regmap_update_bits(rt5640->regmap, RT5640_DMIC, + RT5640_DMIC_2_DP_MASK, RT5640_DMIC_2_DP_GPIO4); + regmap_update_bits(rt5640->regmap, RT5640_GPIO_CTRL1, + RT5640_GP4_PIN_MASK, RT5640_GP4_PIN_DMIC2_SDA); + } + + return 0; +} +EXPORT_SYMBOL_GPL(rt5640_dmic_enable); + static int rt5640_probe(struct snd_soc_codec *codec) { struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec); @@ -1945,6 +1971,10 @@ static int rt5640_probe(struct snd_soc_codec *codec) return -ENODEV; } + if (rt5640->pdata.dmic_en) + rt5640_dmic_enable(codec, rt5640->pdata.dmic1_data_pin, + rt5640->pdata.dmic2_data_pin); + return 0; } @@ -2059,6 +2089,7 @@ static struct snd_soc_codec_driver soc_codec_dev_rt5640 = { static const struct regmap_config rt5640_regmap = { .reg_bits = 8, .val_bits = 16, + .use_single_rw = true, .max_register = RT5640_VENDOR_ID2 + 1 + (ARRAY_SIZE(rt5640_ranges) * RT5640_PR_SPACING), @@ -2194,25 +2225,6 @@ static int rt5640_i2c_probe(struct i2c_client *i2c, regmap_update_bits(rt5640->regmap, RT5640_IN3_IN4, RT5640_IN_DF2, RT5640_IN_DF2); - if (rt5640->pdata.dmic_en) { - regmap_update_bits(rt5640->regmap, RT5640_GPIO_CTRL1, - RT5640_GP2_PIN_MASK, RT5640_GP2_PIN_DMIC1_SCL); - - if (rt5640->pdata.dmic1_data_pin) { - regmap_update_bits(rt5640->regmap, RT5640_DMIC, - RT5640_DMIC_1_DP_MASK, RT5640_DMIC_1_DP_GPIO3); - regmap_update_bits(rt5640->regmap, RT5640_GPIO_CTRL1, - RT5640_GP3_PIN_MASK, RT5640_GP3_PIN_DMIC1_SDA); - } - - if (rt5640->pdata.dmic2_data_pin) { - regmap_update_bits(rt5640->regmap, RT5640_DMIC, - RT5640_DMIC_2_DP_MASK, RT5640_DMIC_2_DP_GPIO4); - regmap_update_bits(rt5640->regmap, RT5640_GPIO_CTRL1, - RT5640_GP4_PIN_MASK, RT5640_GP4_PIN_DMIC2_SDA); - } - } - rt5640->hp_mute = 1; return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5640, diff --git a/sound/soc/codecs/rt5640.h b/sound/soc/codecs/rt5640.h index 58ebe96b86da..3deb8babeabb 100644 --- a/sound/soc/codecs/rt5640.h +++ b/sound/soc/codecs/rt5640.h @@ -2097,4 +2097,7 @@ struct rt5640_priv { bool hp_mute; }; +int rt5640_dmic_enable(struct snd_soc_codec *codec, + bool dmic1_data_pin, bool dmic2_data_pin); + #endif diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 67f14556462f..dc978ad59fc7 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -19,6 +19,7 @@ #include <linux/i2c.h> #include <linux/platform_device.h> #include <linux/spi/spi.h> +#include <linux/gpio.h> #include <sound/core.h> #include <sound/pcm.h> #include <sound/pcm_params.h> @@ -1700,14 +1701,19 @@ static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = { SND_SOC_DAPM_INPUT("Haptic Generator"), - SND_SOC_DAPM_PGA("DMIC1", RT5677_DMIC_CTRL1, RT5677_DMIC_1_EN_SFT, 0, - NULL, 0), - SND_SOC_DAPM_PGA("DMIC2", RT5677_DMIC_CTRL1, RT5677_DMIC_2_EN_SFT, 0, - NULL, 0), - SND_SOC_DAPM_PGA("DMIC3", RT5677_DMIC_CTRL1, RT5677_DMIC_3_EN_SFT, 0, - NULL, 0), - SND_SOC_DAPM_PGA("DMIC4", RT5677_DMIC_CTRL2, RT5677_DMIC_4_EN_SFT, 0, - NULL, 0), + SND_SOC_DAPM_PGA("DMIC1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("DMIC2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("DMIC3", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("DMIC4", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_SUPPLY("DMIC1 power", RT5677_DMIC_CTRL1, + RT5677_DMIC_1_EN_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("DMIC2 power", RT5677_DMIC_CTRL1, + RT5677_DMIC_2_EN_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("DMIC3 power", RT5677_DMIC_CTRL1, + RT5677_DMIC_3_EN_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("DMIC4 power", RT5677_DMIC_CTRL2, + RT5677_DMIC_4_EN_SFT, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("DMIC CLK", SND_SOC_NOPM, 0, 0, set_dmic_clk, SND_SOC_DAPM_PRE_PMU), @@ -2130,15 +2136,22 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = { { "DMIC L4", NULL, "DMIC CLK" }, { "DMIC R4", NULL, "DMIC CLK" }, + { "DMIC L1", NULL, "DMIC1 power" }, + { "DMIC R1", NULL, "DMIC1 power" }, + { "DMIC L3", NULL, "DMIC3 power" }, + { "DMIC R3", NULL, "DMIC3 power" }, + { "DMIC L4", NULL, "DMIC4 power" }, + { "DMIC R4", NULL, "DMIC4 power" }, + { "BST1", NULL, "IN1P" }, { "BST1", NULL, "IN1N" }, { "BST2", NULL, "IN2P" }, { "BST2", NULL, "IN2N" }, - { "IN1P", NULL, "micbias1" }, - { "IN1N", NULL, "micbias1" }, - { "IN2P", NULL, "micbias1" }, - { "IN2N", NULL, "micbias1" }, + { "IN1P", NULL, "MICBIAS1" }, + { "IN1N", NULL, "MICBIAS1" }, + { "IN2P", NULL, "MICBIAS1" }, + { "IN2N", NULL, "MICBIAS1" }, { "ADC 1", NULL, "BST1" }, { "ADC 1", NULL, "ADC 1 power" }, @@ -2793,6 +2806,16 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = { { "PDM2R", NULL, "PDM2 R Mux" }, }; +static const struct snd_soc_dapm_route rt5677_dmic2_clk_1[] = { + { "DMIC L2", NULL, "DMIC1 power" }, + { "DMIC R2", NULL, "DMIC1 power" }, +}; + +static const struct snd_soc_dapm_route rt5677_dmic2_clk_2[] = { + { "DMIC L2", NULL, "DMIC2 power" }, + { "DMIC R2", NULL, "DMIC2 power" }, +}; + static int rt5677_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { @@ -3138,12 +3161,148 @@ static int rt5677_set_bias_level(struct snd_soc_codec *codec, return 0; } +#ifdef CONFIG_GPIOLIB +static inline struct rt5677_priv *gpio_to_rt5677(struct gpio_chip *chip) +{ + return container_of(chip, struct rt5677_priv, gpio_chip); +} + +static void rt5677_gpio_set(struct gpio_chip *chip, unsigned offset, int value) +{ + struct rt5677_priv *rt5677 = gpio_to_rt5677(chip); + + switch (offset) { + case RT5677_GPIO1 ... RT5677_GPIO5: + regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL2, + 0x1 << (offset * 3 + 1), !!value << (offset * 3 + 1)); + break; + + case RT5677_GPIO6: + regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL3, + RT5677_GPIO6_OUT_MASK, !!value << RT5677_GPIO6_OUT_SFT); + break; + + default: + break; + } +} + +static int rt5677_gpio_direction_out(struct gpio_chip *chip, + unsigned offset, int value) +{ + struct rt5677_priv *rt5677 = gpio_to_rt5677(chip); + + switch (offset) { + case RT5677_GPIO1 ... RT5677_GPIO5: + regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL2, + 0x3 << (offset * 3 + 1), + (0x2 | !!value) << (offset * 3 + 1)); + break; + + case RT5677_GPIO6: + regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL3, + RT5677_GPIO6_DIR_MASK | RT5677_GPIO6_OUT_MASK, + RT5677_GPIO6_DIR_OUT | !!value << RT5677_GPIO6_OUT_SFT); + break; + + default: + break; + } + + return 0; +} + +static int rt5677_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + struct rt5677_priv *rt5677 = gpio_to_rt5677(chip); + int value, ret; + + ret = regmap_read(rt5677->regmap, RT5677_GPIO_ST, &value); + if (ret < 0) + return ret; + + return (value & (0x1 << offset)) >> offset; +} + +static int rt5677_gpio_direction_in(struct gpio_chip *chip, unsigned offset) +{ + struct rt5677_priv *rt5677 = gpio_to_rt5677(chip); + + switch (offset) { + case RT5677_GPIO1 ... RT5677_GPIO5: + regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL2, + 0x1 << (offset * 3 + 2), 0x0); + break; + + case RT5677_GPIO6: + regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL3, + RT5677_GPIO6_DIR_MASK, RT5677_GPIO6_DIR_IN); + break; + + default: + break; + } + + return 0; +} + +static struct gpio_chip rt5677_template_chip = { + .label = "rt5677", + .owner = THIS_MODULE, + .direction_output = rt5677_gpio_direction_out, + .set = rt5677_gpio_set, + .direction_input = rt5677_gpio_direction_in, + .get = rt5677_gpio_get, + .can_sleep = 1, +}; + +static void rt5677_init_gpio(struct i2c_client *i2c) +{ + struct rt5677_priv *rt5677 = i2c_get_clientdata(i2c); + int ret; + + rt5677->gpio_chip = rt5677_template_chip; + rt5677->gpio_chip.ngpio = RT5677_GPIO_NUM; + rt5677->gpio_chip.dev = &i2c->dev; + rt5677->gpio_chip.base = -1; + + ret = gpiochip_add(&rt5677->gpio_chip); + if (ret != 0) + dev_err(&i2c->dev, "Failed to add GPIOs: %d\n", ret); +} + +static void rt5677_free_gpio(struct i2c_client *i2c) +{ + struct rt5677_priv *rt5677 = i2c_get_clientdata(i2c); + + gpiochip_remove(&rt5677->gpio_chip); +} +#else +static void rt5677_init_gpio(struct i2c_client *i2c) +{ +} + +static void rt5677_free_gpio(struct i2c_client *i2c) +{ +} +#endif + static int rt5677_probe(struct snd_soc_codec *codec) { struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); rt5677->codec = codec; + if (rt5677->pdata.dmic2_clk_pin == RT5677_DMIC_CLK2) { + snd_soc_dapm_add_routes(&codec->dapm, + rt5677_dmic2_clk_2, + ARRAY_SIZE(rt5677_dmic2_clk_2)); + } else { /*use dmic1 clock by default*/ + snd_soc_dapm_add_routes(&codec->dapm, + rt5677_dmic2_clk_1, + ARRAY_SIZE(rt5677_dmic2_clk_1)); + } + rt5677_set_bias_level(codec, SND_SOC_BIAS_OFF); regmap_write(rt5677->regmap, RT5677_DIG_MISC, 0x0020); @@ -3381,6 +3540,17 @@ static int rt5677_i2c_probe(struct i2c_client *i2c, regmap_update_bits(rt5677->regmap, RT5677_IN1, RT5677_IN_DF2, RT5677_IN_DF2); + if (rt5677->pdata.dmic2_clk_pin == RT5677_DMIC_CLK2) { + regmap_update_bits(rt5677->regmap, RT5677_GEN_CTRL2, + RT5677_GPIO5_FUNC_MASK, + RT5677_GPIO5_FUNC_DMIC); + regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL2, + RT5677_GPIO5_DIR_MASK, + RT5677_GPIO5_DIR_OUT); + } + + rt5677_init_gpio(i2c); + return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5677, rt5677_dai, ARRAY_SIZE(rt5677_dai)); } @@ -3388,6 +3558,7 @@ static int rt5677_i2c_probe(struct i2c_client *i2c, static int rt5677_i2c_remove(struct i2c_client *i2c) { snd_soc_unregister_codec(&i2c->dev); + rt5677_free_gpio(i2c); return 0; } diff --git a/sound/soc/codecs/rt5677.h b/sound/soc/codecs/rt5677.h index 863393e62096..b61b72cfcbd7 100644 --- a/sound/soc/codecs/rt5677.h +++ b/sound/soc/codecs/rt5677.h @@ -1287,16 +1287,16 @@ #define RT5677_PLL1_PD_SFT 8 #define RT5677_PLL1_PD_1 (0x0 << 8) #define RT5677_PLL1_PD_2 (0x1 << 8) -#define RT5671_DAC_OSR_MASK (0x3 << 6) -#define RT5671_DAC_OSR_SFT 6 -#define RT5671_DAC_OSR_128 (0x0 << 6) -#define RT5671_DAC_OSR_64 (0x1 << 6) -#define RT5671_DAC_OSR_32 (0x2 << 6) -#define RT5671_ADC_OSR_MASK (0x3 << 4) -#define RT5671_ADC_OSR_SFT 4 -#define RT5671_ADC_OSR_128 (0x0 << 4) -#define RT5671_ADC_OSR_64 (0x1 << 4) -#define RT5671_ADC_OSR_32 (0x2 << 4) +#define RT5677_DAC_OSR_MASK (0x3 << 6) +#define RT5677_DAC_OSR_SFT 6 +#define RT5677_DAC_OSR_128 (0x0 << 6) +#define RT5677_DAC_OSR_64 (0x1 << 6) +#define RT5677_DAC_OSR_32 (0x2 << 6) +#define RT5677_ADC_OSR_MASK (0x3 << 4) +#define RT5677_ADC_OSR_SFT 4 +#define RT5677_ADC_OSR_128 (0x0 << 4) +#define RT5677_ADC_OSR_64 (0x1 << 4) +#define RT5677_ADC_OSR_32 (0x2 << 4) /* Global Clock Control 2 (0x81) */ #define RT5677_PLL2_PR_SRC_MASK (0x1 << 15) @@ -1312,18 +1312,18 @@ #define RT5677_PLL2_SRC_BCLK4 (0x4 << 12) #define RT5677_PLL2_SRC_RCCLK (0x5 << 12) #define RT5677_PLL2_SRC_SLIM (0x6 << 12) -#define RT5671_DSP_ASRC_O_SRC (0x3 << 10) -#define RT5671_DSP_ASRC_O_SRC_SFT 10 -#define RT5671_DSP_ASRC_O_MCLK (0x0 << 10) -#define RT5671_DSP_ASRC_O_PLL1 (0x1 << 10) -#define RT5671_DSP_ASRC_O_SLIM (0x2 << 10) -#define RT5671_DSP_ASRC_O_RCCLK (0x3 << 10) -#define RT5671_DSP_ASRC_I_SRC (0x3 << 8) -#define RT5671_DSP_ASRC_I_SRC_SFT 8 -#define RT5671_DSP_ASRC_I_MCLK (0x0 << 8) -#define RT5671_DSP_ASRC_I_PLL1 (0x1 << 8) -#define RT5671_DSP_ASRC_I_SLIM (0x2 << 8) -#define RT5671_DSP_ASRC_I_RCCLK (0x3 << 8) +#define RT5677_DSP_ASRC_O_SRC (0x3 << 10) +#define RT5677_DSP_ASRC_O_SRC_SFT 10 +#define RT5677_DSP_ASRC_O_MCLK (0x0 << 10) +#define RT5677_DSP_ASRC_O_PLL1 (0x1 << 10) +#define RT5677_DSP_ASRC_O_SLIM (0x2 << 10) +#define RT5677_DSP_ASRC_O_RCCLK (0x3 << 10) +#define RT5677_DSP_ASRC_I_SRC (0x3 << 8) +#define RT5677_DSP_ASRC_I_SRC_SFT 8 +#define RT5677_DSP_ASRC_I_MCLK (0x0 << 8) +#define RT5677_DSP_ASRC_I_PLL1 (0x1 << 8) +#define RT5677_DSP_ASRC_I_SLIM (0x2 << 8) +#define RT5677_DSP_ASRC_I_RCCLK (0x3 << 8) #define RT5677_DSP_CLK_SRC_MASK (0x1 << 7) #define RT5677_DSP_CLK_SRC_SFT 7 #define RT5677_DSP_CLK_SRC_PLL2 (0x0 << 7) @@ -1363,6 +1363,110 @@ #define RT5677_SEL_SRC_IB01 (0x1 << 0) #define RT5677_SEL_SRC_IB01_SFT 0 +/* GPIO status (0xbf) */ +#define RT5677_GPIO6_STATUS_MASK (0x1 << 5) +#define RT5677_GPIO6_STATUS_SFT 5 +#define RT5677_GPIO5_STATUS_MASK (0x1 << 4) +#define RT5677_GPIO5_STATUS_SFT 4 +#define RT5677_GPIO4_STATUS_MASK (0x1 << 3) +#define RT5677_GPIO4_STATUS_SFT 3 +#define RT5677_GPIO3_STATUS_MASK (0x1 << 2) +#define RT5677_GPIO3_STATUS_SFT 2 +#define RT5677_GPIO2_STATUS_MASK (0x1 << 1) +#define RT5677_GPIO2_STATUS_SFT 1 +#define RT5677_GPIO1_STATUS_MASK (0x1 << 0) +#define RT5677_GPIO1_STATUS_SFT 0 + +/* GPIO Control 1 (0xc0) */ +#define RT5677_GPIO1_PIN_MASK (0x1 << 15) +#define RT5677_GPIO1_PIN_SFT 15 +#define RT5677_GPIO1_PIN_GPIO1 (0x0 << 15) +#define RT5677_GPIO1_PIN_IRQ (0x1 << 15) +#define RT5677_IPTV_MODE_MASK (0x1 << 14) +#define RT5677_IPTV_MODE_SFT 14 +#define RT5677_IPTV_MODE_GPIO (0x0 << 14) +#define RT5677_IPTV_MODE_IPTV (0x1 << 14) +#define RT5677_FUNC_MODE_MASK (0x1 << 13) +#define RT5677_FUNC_MODE_SFT 13 +#define RT5677_FUNC_MODE_DMIC_GPIO (0x0 << 13) +#define RT5677_FUNC_MODE_JTAG (0x1 << 13) + +/* GPIO Control 2 (0xc1) */ +#define RT5677_GPIO5_DIR_MASK (0x1 << 14) +#define RT5677_GPIO5_DIR_SFT 14 +#define RT5677_GPIO5_DIR_IN (0x0 << 14) +#define RT5677_GPIO5_DIR_OUT (0x1 << 14) +#define RT5677_GPIO5_OUT_MASK (0x1 << 13) +#define RT5677_GPIO5_OUT_SFT 13 +#define RT5677_GPIO5_OUT_LO (0x0 << 13) +#define RT5677_GPIO5_OUT_HI (0x1 << 13) +#define RT5677_GPIO5_P_MASK (0x1 << 12) +#define RT5677_GPIO5_P_SFT 12 +#define RT5677_GPIO5_P_NOR (0x0 << 12) +#define RT5677_GPIO5_P_INV (0x1 << 12) +#define RT5677_GPIO4_DIR_MASK (0x1 << 11) +#define RT5677_GPIO4_DIR_SFT 11 +#define RT5677_GPIO4_DIR_IN (0x0 << 11) +#define RT5677_GPIO4_DIR_OUT (0x1 << 11) +#define RT5677_GPIO4_OUT_MASK (0x1 << 10) +#define RT5677_GPIO4_OUT_SFT 10 +#define RT5677_GPIO4_OUT_LO (0x0 << 10) +#define RT5677_GPIO4_OUT_HI (0x1 << 10) +#define RT5677_GPIO4_P_MASK (0x1 << 9) +#define RT5677_GPIO4_P_SFT 9 +#define RT5677_GPIO4_P_NOR (0x0 << 9) +#define RT5677_GPIO4_P_INV (0x1 << 9) +#define RT5677_GPIO3_DIR_MASK (0x1 << 8) +#define RT5677_GPIO3_DIR_SFT 8 +#define RT5677_GPIO3_DIR_IN (0x0 << 8) +#define RT5677_GPIO3_DIR_OUT (0x1 << 8) +#define RT5677_GPIO3_OUT_MASK (0x1 << 7) +#define RT5677_GPIO3_OUT_SFT 7 +#define RT5677_GPIO3_OUT_LO (0x0 << 7) +#define RT5677_GPIO3_OUT_HI (0x1 << 7) +#define RT5677_GPIO3_P_MASK (0x1 << 6) +#define RT5677_GPIO3_P_SFT 6 +#define RT5677_GPIO3_P_NOR (0x0 << 6) +#define RT5677_GPIO3_P_INV (0x1 << 6) +#define RT5677_GPIO2_DIR_MASK (0x1 << 5) +#define RT5677_GPIO2_DIR_SFT 5 +#define RT5677_GPIO2_DIR_IN (0x0 << 5) +#define RT5677_GPIO2_DIR_OUT (0x1 << 5) +#define RT5677_GPIO2_OUT_MASK (0x1 << 4) +#define RT5677_GPIO2_OUT_SFT 4 +#define RT5677_GPIO2_OUT_LO (0x0 << 4) +#define RT5677_GPIO2_OUT_HI (0x1 << 4) +#define RT5677_GPIO2_P_MASK (0x1 << 3) +#define RT5677_GPIO2_P_SFT 3 +#define RT5677_GPIO2_P_NOR (0x0 << 3) +#define RT5677_GPIO2_P_INV (0x1 << 3) +#define RT5677_GPIO1_DIR_MASK (0x1 << 2) +#define RT5677_GPIO1_DIR_SFT 2 +#define RT5677_GPIO1_DIR_IN (0x0 << 2) +#define RT5677_GPIO1_DIR_OUT (0x1 << 2) +#define RT5677_GPIO1_OUT_MASK (0x1 << 1) +#define RT5677_GPIO1_OUT_SFT 1 +#define RT5677_GPIO1_OUT_LO (0x0 << 1) +#define RT5677_GPIO1_OUT_HI (0x1 << 1) +#define RT5677_GPIO1_P_MASK (0x1 << 0) +#define RT5677_GPIO1_P_SFT 0 +#define RT5677_GPIO1_P_NOR (0x0 << 0) +#define RT5677_GPIO1_P_INV (0x1 << 0) + +/* GPIO Control 3 (0xc2) */ +#define RT5677_GPIO6_DIR_MASK (0x1 << 2) +#define RT5677_GPIO6_DIR_SFT 2 +#define RT5677_GPIO6_DIR_IN (0x0 << 2) +#define RT5677_GPIO6_DIR_OUT (0x1 << 2) +#define RT5677_GPIO6_OUT_MASK (0x1 << 1) +#define RT5677_GPIO6_OUT_SFT 1 +#define RT5677_GPIO6_OUT_LO (0x0 << 1) +#define RT5677_GPIO6_OUT_HI (0x1 << 1) +#define RT5677_GPIO6_P_MASK (0x1 << 0) +#define RT5677_GPIO6_P_SFT 0 +#define RT5677_GPIO6_P_NOR (0x0 << 0) +#define RT5677_GPIO6_P_INV (0x1 << 0) + /* Virtual DSP Mixer Control (0xf7 0xf8 0xf9) */ #define RT5677_DSP_IB_01_H (0x1 << 15) #define RT5677_DSP_IB_01_H_SFT 15 @@ -1393,6 +1497,11 @@ #define RT5677_DSP_IB_9_L (0x1 << 1) #define RT5677_DSP_IB_9_L_SFT 1 +/* General Control2 (0xfc)*/ +#define RT5677_GPIO5_FUNC_MASK (0x1 << 9) +#define RT5677_GPIO5_FUNC_GPIO (0x0 << 9) +#define RT5677_GPIO5_FUNC_DMIC (0x1 << 9) + /* System Clock Source */ enum { RT5677_SCLK_S_MCLK, @@ -1418,6 +1527,16 @@ enum { RT5677_AIFS, }; +enum { + RT5677_GPIO1, + RT5677_GPIO2, + RT5677_GPIO3, + RT5677_GPIO4, + RT5677_GPIO5, + RT5677_GPIO6, + RT5677_GPIO_NUM, +}; + struct rt5677_priv { struct snd_soc_codec *codec; struct rt5677_platform_data pdata; @@ -1431,6 +1550,9 @@ struct rt5677_priv { int pll_src; int pll_in; int pll_out; +#ifdef CONFIG_GPIOLIB + struct gpio_chip gpio_chip; +#endif }; #endif /* __RT5677_H__ */ diff --git a/sound/soc/codecs/ssm2518.c b/sound/soc/codecs/ssm2518.c index e8680bea5f86..67ea55adb307 100644 --- a/sound/soc/codecs/ssm2518.c +++ b/sound/soc/codecs/ssm2518.c @@ -646,17 +646,6 @@ static struct snd_soc_dai_driver ssm2518_dai = { .ops = &ssm2518_dai_ops, }; -static int ssm2518_probe(struct snd_soc_codec *codec) -{ - return ssm2518_set_bias_level(codec, SND_SOC_BIAS_OFF); -} - -static int ssm2518_remove(struct snd_soc_codec *codec) -{ - ssm2518_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - static int ssm2518_set_sysclk(struct snd_soc_codec *codec, int clk_id, int source, unsigned int freq, int dir) { @@ -727,8 +716,6 @@ static int ssm2518_set_sysclk(struct snd_soc_codec *codec, int clk_id, } static struct snd_soc_codec_driver ssm2518_codec_driver = { - .probe = ssm2518_probe, - .remove = ssm2518_remove, .set_bias_level = ssm2518_set_bias_level, .set_sysclk = ssm2518_set_sysclk, .idle_bias_off = true, diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c index 484b3bbe8624..527de0463548 100644 --- a/sound/soc/codecs/ssm2602.c +++ b/sound/soc/codecs/ssm2602.c @@ -502,18 +502,11 @@ static struct snd_soc_dai_driver ssm2602_dai = { .symmetric_samplebits = 1, }; -static int ssm2602_suspend(struct snd_soc_codec *codec) -{ - ssm2602_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - static int ssm2602_resume(struct snd_soc_codec *codec) { struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec); regcache_sync(ssm2602->regmap); - ssm2602_set_bias_level(codec, SND_SOC_BIAS_STANDBY); return 0; } @@ -586,27 +579,14 @@ static int ssm260x_codec_probe(struct snd_soc_codec *codec) break; } - if (ret) - return ret; - - ssm2602_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - - return 0; -} - -/* remove everything here */ -static int ssm2602_remove(struct snd_soc_codec *codec) -{ - ssm2602_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; + return ret; } static struct snd_soc_codec_driver soc_codec_dev_ssm2602 = { .probe = ssm260x_codec_probe, - .remove = ssm2602_remove, - .suspend = ssm2602_suspend, .resume = ssm2602_resume, .set_bias_level = ssm2602_set_bias_level, + .suspend_bias_off = true, .controls = ssm260x_snd_controls, .num_controls = ARRAY_SIZE(ssm260x_snd_controls), @@ -647,7 +627,7 @@ int ssm2602_probe(struct device *dev, enum ssm2602_type type, return -ENOMEM; dev_set_drvdata(dev, ssm2602); - ssm2602->type = SSM2602; + ssm2602->type = type; ssm2602->regmap = regmap; return snd_soc_register_codec(dev, &soc_codec_dev_ssm2602, diff --git a/sound/soc/codecs/sta529.c b/sound/soc/codecs/sta529.c index 9aa1323fb2ab..89c748dd3d6e 100644 --- a/sound/soc/codecs/sta529.c +++ b/sound/soc/codecs/sta529.c @@ -4,7 +4,7 @@ * sound/soc/codecs/sta529.c -- spear ALSA Soc codec driver * * Copyright (C) 2012 ST Microelectronics - * Rajeev Kumar <rajeev-dlh.kumar@st.com> + * Rajeev Kumar <rajeevkumar.linux@gmail.com> * * This file is licensed under the terms of the GNU General Public * License version 2. This program is licensed "as is" without any @@ -426,5 +426,5 @@ static struct i2c_driver sta529_i2c_driver = { module_i2c_driver(sta529_i2c_driver); MODULE_DESCRIPTION("ASoC STA529 codec driver"); -MODULE_AUTHOR("Rajeev Kumar <rajeev-dlh.kumar@st.com>"); +MODULE_AUTHOR("Rajeev Kumar <rajeevkumar.linux@gmail.com>"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index 0f64c7890eed..aea9e1ff9126 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c @@ -189,46 +189,57 @@ static const struct aic31xx_rate_divs aic31xx_divs[] = { /* mclk rate pll: p j d dosr ndac mdac aors nadc madc */ /* 8k rate */ {12000000, 8000, 1, 8, 1920, 128, 48, 2, 128, 48, 2}, + {12000000, 8000, 1, 8, 1920, 128, 32, 3, 128, 32, 3}, {24000000, 8000, 2, 8, 1920, 128, 48, 2, 128, 48, 2}, {25000000, 8000, 2, 7, 8643, 128, 48, 2, 128, 48, 2}, /* 11.025k rate */ {12000000, 11025, 1, 7, 5264, 128, 32, 2, 128, 32, 2}, + {12000000, 11025, 1, 8, 4672, 128, 24, 3, 128, 24, 3}, {24000000, 11025, 2, 7, 5264, 128, 32, 2, 128, 32, 2}, {25000000, 11025, 2, 7, 2253, 128, 32, 2, 128, 32, 2}, /* 16k rate */ {12000000, 16000, 1, 8, 1920, 128, 24, 2, 128, 24, 2}, + {12000000, 16000, 1, 8, 1920, 128, 16, 3, 128, 16, 3}, {24000000, 16000, 2, 8, 1920, 128, 24, 2, 128, 24, 2}, {25000000, 16000, 2, 7, 8643, 128, 24, 2, 128, 24, 2}, /* 22.05k rate */ {12000000, 22050, 1, 7, 5264, 128, 16, 2, 128, 16, 2}, + {12000000, 22050, 1, 8, 4672, 128, 12, 3, 128, 12, 3}, {24000000, 22050, 2, 7, 5264, 128, 16, 2, 128, 16, 2}, {25000000, 22050, 2, 7, 2253, 128, 16, 2, 128, 16, 2}, /* 32k rate */ {12000000, 32000, 1, 8, 1920, 128, 12, 2, 128, 12, 2}, + {12000000, 32000, 1, 8, 1920, 128, 8, 3, 128, 8, 3}, {24000000, 32000, 2, 8, 1920, 128, 12, 2, 128, 12, 2}, {25000000, 32000, 2, 7, 8643, 128, 12, 2, 128, 12, 2}, /* 44.1k rate */ {12000000, 44100, 1, 7, 5264, 128, 8, 2, 128, 8, 2}, + {12000000, 44100, 1, 8, 4672, 128, 6, 3, 128, 6, 3}, {24000000, 44100, 2, 7, 5264, 128, 8, 2, 128, 8, 2}, {25000000, 44100, 2, 7, 2253, 128, 8, 2, 128, 8, 2}, /* 48k rate */ {12000000, 48000, 1, 8, 1920, 128, 8, 2, 128, 8, 2}, + {12000000, 48000, 1, 7, 6800, 96, 5, 4, 96, 5, 4}, {24000000, 48000, 2, 8, 1920, 128, 8, 2, 128, 8, 2}, {25000000, 48000, 2, 7, 8643, 128, 8, 2, 128, 8, 2}, /* 88.2k rate */ {12000000, 88200, 1, 7, 5264, 64, 8, 2, 64, 8, 2}, + {12000000, 88200, 1, 8, 4672, 64, 6, 3, 64, 6, 3}, {24000000, 88200, 2, 7, 5264, 64, 8, 2, 64, 8, 2}, {25000000, 88200, 2, 7, 2253, 64, 8, 2, 64, 8, 2}, /* 96k rate */ {12000000, 96000, 1, 8, 1920, 64, 8, 2, 64, 8, 2}, + {12000000, 96000, 1, 7, 6800, 48, 5, 4, 48, 5, 4}, {24000000, 96000, 2, 8, 1920, 64, 8, 2, 64, 8, 2}, {25000000, 96000, 2, 7, 8643, 64, 8, 2, 64, 8, 2}, /* 176.4k rate */ {12000000, 176400, 1, 7, 5264, 32, 8, 2, 32, 8, 2}, + {12000000, 176400, 1, 8, 4672, 32, 6, 3, 32, 6, 3}, {24000000, 176400, 2, 7, 5264, 32, 8, 2, 32, 8, 2}, {25000000, 176400, 2, 7, 2253, 32, 8, 2, 32, 8, 2}, /* 192k rate */ {12000000, 192000, 1, 8, 1920, 32, 8, 2, 32, 8, 2}, + {12000000, 192000, 1, 7, 6800, 24, 5, 4, 24, 5, 4}, {24000000, 192000, 2, 8, 1920, 32, 8, 2, 32, 8, 2}, {25000000, 192000, 2, 7, 8643, 32, 8, 2, 32, 8, 2}, }; @@ -680,7 +691,9 @@ static int aic31xx_setup_pll(struct snd_soc_codec *codec, struct snd_pcm_hw_params *params) { struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec); + int bclk_score = snd_soc_params_to_frame_size(params); int bclk_n = 0; + int match = -1; int i; /* Use PLL as CODEC_CLKIN and DAC_CLK as BDIV_CLKIN */ @@ -691,15 +704,37 @@ static int aic31xx_setup_pll(struct snd_soc_codec *codec, for (i = 0; i < ARRAY_SIZE(aic31xx_divs); i++) { if (aic31xx_divs[i].rate == params_rate(params) && - aic31xx_divs[i].mclk == aic31xx->sysclk) - break; + aic31xx_divs[i].mclk == aic31xx->sysclk) { + int s = (aic31xx_divs[i].dosr * aic31xx_divs[i].mdac) % + snd_soc_params_to_frame_size(params); + int bn = (aic31xx_divs[i].dosr * aic31xx_divs[i].mdac) / + snd_soc_params_to_frame_size(params); + if (s < bclk_score && bn > 0) { + match = i; + bclk_n = bn; + bclk_score = s; + } + } } - if (i == ARRAY_SIZE(aic31xx_divs)) { - dev_err(codec->dev, "%s: Sampling rate %u not supported\n", + if (match == -1) { + dev_err(codec->dev, + "%s: Sample rate (%u) and format not supported\n", __func__, params_rate(params)); + /* See bellow for details how fix this. */ return -EINVAL; } + if (bclk_score != 0) { + dev_warn(codec->dev, "Can not produce exact bitclock"); + /* This is fine if using dsp format, but if using i2s + there may be trouble. To fix the issue edit the + aic31xx_divs table for your mclk and sample + rate. Details can be found from: + http://www.ti.com/lit/ds/symlink/tlv320aic3100.pdf + Section: 5.6 CLOCK Generation and PLL + */ + } + i = match; /* PLL configuration */ snd_soc_update_bits(codec, AIC31XX_PLLPR, AIC31XX_PLL_MASK, @@ -729,14 +764,6 @@ static int aic31xx_setup_pll(struct snd_soc_codec *codec, snd_soc_write(codec, AIC31XX_AOSR, aic31xx_divs[i].aosr); /* Bit clock divider configuration. */ - bclk_n = (aic31xx_divs[i].dosr * aic31xx_divs[i].mdac) - / snd_soc_params_to_frame_size(params); - if (bclk_n == 0) { - dev_err(codec->dev, "%s: Not enough BLCK bandwidth\n", - __func__); - return -EINVAL; - } - snd_soc_update_bits(codec, AIC31XX_BCLKN, AIC31XX_PLL_MASK, bclk_n); diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 64f179ee9834..f2c416d16b6c 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -1222,20 +1222,6 @@ static struct snd_soc_dai_driver aic3x_dai = { .symmetric_rates = 1, }; -static int aic3x_suspend(struct snd_soc_codec *codec) -{ - aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF); - - return 0; -} - -static int aic3x_resume(struct snd_soc_codec *codec) -{ - aic3x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - - return 0; -} - static void aic3x_mono_init(struct snd_soc_codec *codec) { /* DAC to Mono Line Out default volume and route to Output mixer */ @@ -1429,8 +1415,6 @@ static struct snd_soc_codec_driver soc_codec_dev_aic3x = { .idle_bias_off = true, .probe = aic3x_probe, .remove = aic3x_remove, - .suspend = aic3x_suspend, - .resume = aic3x_resume, .controls = aic3x_snd_controls, .num_controls = ARRAY_SIZE(aic3x_snd_controls), .dapm_widgets = aic3x_dapm_widgets, diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c index 7bb0d36d4c54..a01ad629ed61 100644 --- a/sound/soc/codecs/wm5100.c +++ b/sound/soc/codecs/wm5100.c @@ -2319,11 +2319,8 @@ static void wm5100_init_gpio(struct i2c_client *i2c) static void wm5100_free_gpio(struct i2c_client *i2c) { struct wm5100_priv *wm5100 = i2c_get_clientdata(i2c); - int ret; - ret = gpiochip_remove(&wm5100->gpio_chip); - if (ret != 0) - dev_err(&i2c->dev, "Failed to remove GPIOs: %d\n", ret); + gpiochip_remove(&wm5100->gpio_chip); } #else static void wm5100_init_gpio(struct i2c_client *i2c) diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c index 3dfdcc4197fa..628ec774cf22 100644 --- a/sound/soc/codecs/wm8350.c +++ b/sound/soc/codecs/wm8350.c @@ -212,7 +212,7 @@ static void wm8350_pga_work(struct work_struct *work) { struct snd_soc_dapm_context *dapm = container_of(work, struct snd_soc_dapm_context, delayed_work.work); - struct snd_soc_codec *codec = dapm->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm); struct wm8350_data *wm8350_data = snd_soc_codec_get_drvdata(codec); struct wm8350_output *out1 = &wm8350_data->out1, *out2 = &wm8350_data->out2; diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index e54e097f4fcb..21ca3a94fc96 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c @@ -1433,7 +1433,7 @@ static void wm8753_work(struct work_struct *work) struct snd_soc_dapm_context *dapm = container_of(work, struct snd_soc_dapm_context, delayed_work.work); - struct snd_soc_codec *codec = dapm->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm); wm8753_set_bias_level(codec, dapm->bias_level); } diff --git a/sound/soc/codecs/wm8804.c b/sound/soc/codecs/wm8804.c index 0ea01dfcb6e1..3addc5fe5cb2 100644 --- a/sound/soc/codecs/wm8804.c +++ b/sound/soc/codecs/wm8804.c @@ -518,23 +518,6 @@ static int wm8804_set_bias_level(struct snd_soc_codec *codec, return 0; } -#ifdef CONFIG_PM -static int wm8804_suspend(struct snd_soc_codec *codec) -{ - wm8804_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - -static int wm8804_resume(struct snd_soc_codec *codec) -{ - wm8804_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - return 0; -} -#else -#define wm8804_suspend NULL -#define wm8804_resume NULL -#endif - static int wm8804_remove(struct snd_soc_codec *codec) { struct wm8804_priv *wm8804; @@ -671,8 +654,6 @@ static struct snd_soc_dai_driver wm8804_dai = { static struct snd_soc_codec_driver soc_codec_dev_wm8804 = { .probe = wm8804_probe, .remove = wm8804_remove, - .suspend = wm8804_suspend, - .resume = wm8804_resume, .set_bias_level = wm8804_set_bias_level, .idle_bias_off = true, diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index aa0984864e76..c038b3e04398 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -1877,11 +1877,7 @@ static void wm8903_init_gpio(struct wm8903_priv *wm8903) static void wm8903_free_gpio(struct wm8903_priv *wm8903) { - int ret; - - ret = gpiochip_remove(&wm8903->gpio_chip); - if (ret != 0) - dev_err(wm8903->dev, "Failed to remove GPIOs: %d\n", ret); + gpiochip_remove(&wm8903->gpio_chip); } #else static void wm8903_init_gpio(struct wm8903_priv *wm8903) diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index 1098ae32f1f9..9077411e62ce 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -3398,11 +3398,8 @@ static void wm8962_init_gpio(struct snd_soc_codec *codec) static void wm8962_free_gpio(struct snd_soc_codec *codec) { struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); - int ret; - ret = gpiochip_remove(&wm8962->gpio_chip); - if (ret != 0) - dev_err(codec->dev, "Failed to remove GPIOs: %d\n", ret); + gpiochip_remove(&wm8962->gpio_chip); } #else static void wm8962_init_gpio(struct snd_soc_codec *codec) diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c index 0499cd4cfb71..39ddb9b8834c 100644 --- a/sound/soc/codecs/wm8971.c +++ b/sound/soc/codecs/wm8971.c @@ -615,7 +615,7 @@ static void wm8971_work(struct work_struct *work) struct snd_soc_dapm_context *dapm = container_of(work, struct snd_soc_dapm_context, delayed_work.work); - struct snd_soc_codec *codec = dapm->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm); wm8971_set_bias_level(codec, codec->dapm.bias_level); } diff --git a/sound/soc/codecs/wm8995.c b/sound/soc/codecs/wm8995.c index cae4ac5a5730..1288edeb8c7d 100644 --- a/sound/soc/codecs/wm8995.c +++ b/sound/soc/codecs/wm8995.c @@ -1998,23 +1998,6 @@ static int wm8995_set_bias_level(struct snd_soc_codec *codec, return 0; } -#ifdef CONFIG_PM -static int wm8995_suspend(struct snd_soc_codec *codec) -{ - wm8995_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - -static int wm8995_resume(struct snd_soc_codec *codec) -{ - wm8995_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - return 0; -} -#else -#define wm8995_suspend NULL -#define wm8995_resume NULL -#endif - static int wm8995_remove(struct snd_soc_codec *codec) { struct wm8995_priv *wm8995; @@ -2220,8 +2203,6 @@ static struct snd_soc_dai_driver wm8995_dai[] = { static struct snd_soc_codec_driver soc_codec_dev_wm8995 = { .probe = wm8995_probe, .remove = wm8995_remove, - .suspend = wm8995_suspend, - .resume = wm8995_resume, .set_bias_level = wm8995_set_bias_level, .idle_bias_off = true, }; diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c index f16ff4f56923..b1dcc11c1b23 100644 --- a/sound/soc/codecs/wm8996.c +++ b/sound/soc/codecs/wm8996.c @@ -2216,11 +2216,7 @@ static void wm8996_init_gpio(struct wm8996_priv *wm8996) static void wm8996_free_gpio(struct wm8996_priv *wm8996) { - int ret; - - ret = gpiochip_remove(&wm8996->gpio_chip); - if (ret != 0) - dev_err(wm8996->dev, "Failed to remove GPIOs: %d\n", ret); + gpiochip_remove(&wm8996->gpio_chip); } #else static void wm8996_init_gpio(struct wm8996_priv *wm8996) diff --git a/sound/soc/davinci/Kconfig b/sound/soc/davinci/Kconfig index d69510c53239..8e948c63f3d9 100644 --- a/sound/soc/davinci/Kconfig +++ b/sound/soc/davinci/Kconfig @@ -63,7 +63,8 @@ config SND_DM365_AIC3X_CODEC Say Y if you want to add support for AIC3101 audio codec config SND_DM365_VOICE_CODEC - bool "Voice Codec - CQ93VC" + tristate "Voice Codec - CQ93VC" + depends on SND_DAVINCI_SOC select MFD_DAVINCI_VOICECODEC select SND_DAVINCI_SOC_VCIF select SND_SOC_CQ0093VC diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index c28508da34cf..0eed9b1b24e1 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -42,14 +42,26 @@ #define MCASP_MAX_AFIFO_DEPTH 64 +static u32 context_regs[] = { + DAVINCI_MCASP_TXFMCTL_REG, + DAVINCI_MCASP_RXFMCTL_REG, + DAVINCI_MCASP_TXFMT_REG, + DAVINCI_MCASP_RXFMT_REG, + DAVINCI_MCASP_ACLKXCTL_REG, + DAVINCI_MCASP_ACLKRCTL_REG, + DAVINCI_MCASP_AHCLKXCTL_REG, + DAVINCI_MCASP_AHCLKRCTL_REG, + DAVINCI_MCASP_PDIR_REG, + DAVINCI_MCASP_RXMASK_REG, + DAVINCI_MCASP_TXMASK_REG, + DAVINCI_MCASP_RXTDM_REG, + DAVINCI_MCASP_TXTDM_REG, +}; + struct davinci_mcasp_context { - u32 txfmtctl; - u32 rxfmtctl; - u32 txfmt; - u32 rxfmt; - u32 aclkxctl; - u32 aclkrctl; - u32 pdir; + u32 config_regs[ARRAY_SIZE(context_regs)]; + u32 afifo_regs[2]; /* for read/write fifo control registers */ + u32 *xrsr_regs; /* for serializer configuration */ }; struct davinci_mcasp { @@ -403,7 +415,8 @@ out: return ret; } -static int davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div) +static int __davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id, + int div, bool explicit) { struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai); @@ -420,7 +433,8 @@ static int davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div ACLKXDIV(div - 1), ACLKXDIV_MASK); mcasp_mod_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRDIV(div - 1), ACLKRDIV_MASK); - mcasp->bclk_div = div; + if (explicit) + mcasp->bclk_div = div; break; case 2: /* BCLK/LRCLK ratio */ @@ -434,6 +448,12 @@ static int davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div return 0; } +static int davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id, + int div) +{ + return __davinci_mcasp_set_clkdiv(dai, div_id, div, 1); +} + static int davinci_mcasp_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int freq, int dir) { @@ -459,8 +479,17 @@ static int davinci_config_channel_size(struct davinci_mcasp *mcasp, { u32 fmt; u32 tx_rotate = (word_length / 4) & 0x7; - u32 rx_rotate = (32 - word_length) / 4; u32 mask = (1ULL << word_length) - 1; + /* + * For captured data we should not rotate, inversion and masking is + * enoguh to get the data to the right position: + * Format data from bus after reverse (XRBUF) + * S16_LE: |LSB|MSB|xxx|xxx| |xxx|xxx|MSB|LSB| + * S24_3LE: |LSB|DAT|MSB|xxx| |xxx|MSB|DAT|LSB| + * S24_LE: |LSB|DAT|MSB|xxx| |xxx|MSB|DAT|LSB| + * S32_LE: |LSB|DAT|DAT|MSB| |MSB|DAT|DAT|LSB| + */ + u32 rx_rotate = 0; /* * if s BCLK-to-LRCLK ratio has been configured via the set_clkdiv() @@ -738,7 +767,7 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, "Inaccurate BCLK: %u Hz / %u != %u Hz\n", mcasp->sysclk_freq, div, bclk_freq); } - davinci_mcasp_set_clkdiv(cpu_dai, 1, div); + __davinci_mcasp_set_clkdiv(cpu_dai, 1, div, 0); } ret = mcasp_common_hw_param(mcasp, substream->stream, @@ -857,14 +886,24 @@ static int davinci_mcasp_suspend(struct snd_soc_dai *dai) { struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai); struct davinci_mcasp_context *context = &mcasp->context; + u32 reg; + int i; - context->txfmtctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_TXFMCTL_REG); - context->rxfmtctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_RXFMCTL_REG); - context->txfmt = mcasp_get_reg(mcasp, DAVINCI_MCASP_TXFMT_REG); - context->rxfmt = mcasp_get_reg(mcasp, DAVINCI_MCASP_RXFMT_REG); - context->aclkxctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_ACLKXCTL_REG); - context->aclkrctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_ACLKRCTL_REG); - context->pdir = mcasp_get_reg(mcasp, DAVINCI_MCASP_PDIR_REG); + for (i = 0; i < ARRAY_SIZE(context_regs); i++) + context->config_regs[i] = mcasp_get_reg(mcasp, context_regs[i]); + + if (mcasp->txnumevt) { + reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET; + context->afifo_regs[0] = mcasp_get_reg(mcasp, reg); + } + if (mcasp->rxnumevt) { + reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET; + context->afifo_regs[1] = mcasp_get_reg(mcasp, reg); + } + + for (i = 0; i < mcasp->num_serializer; i++) + context->xrsr_regs[i] = mcasp_get_reg(mcasp, + DAVINCI_MCASP_XRSRCTL_REG(i)); return 0; } @@ -873,14 +912,24 @@ static int davinci_mcasp_resume(struct snd_soc_dai *dai) { struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai); struct davinci_mcasp_context *context = &mcasp->context; + u32 reg; + int i; + + for (i = 0; i < ARRAY_SIZE(context_regs); i++) + mcasp_set_reg(mcasp, context_regs[i], context->config_regs[i]); + + if (mcasp->txnumevt) { + reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET; + mcasp_set_reg(mcasp, reg, context->afifo_regs[0]); + } + if (mcasp->rxnumevt) { + reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET; + mcasp_set_reg(mcasp, reg, context->afifo_regs[1]); + } - mcasp_set_reg(mcasp, DAVINCI_MCASP_TXFMCTL_REG, context->txfmtctl); - mcasp_set_reg(mcasp, DAVINCI_MCASP_RXFMCTL_REG, context->rxfmtctl); - mcasp_set_reg(mcasp, DAVINCI_MCASP_TXFMT_REG, context->txfmt); - mcasp_set_reg(mcasp, DAVINCI_MCASP_RXFMT_REG, context->rxfmt); - mcasp_set_reg(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, context->aclkxctl); - mcasp_set_reg(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, context->aclkrctl); - mcasp_set_reg(mcasp, DAVINCI_MCASP_PDIR_REG, context->pdir); + for (i = 0; i < mcasp->num_serializer; i++) + mcasp_set_reg(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i), + context->xrsr_regs[i]); return 0; } @@ -1199,6 +1248,11 @@ static int davinci_mcasp_probe(struct platform_device *pdev) mcasp->op_mode = pdata->op_mode; mcasp->tdm_slots = pdata->tdm_slots; mcasp->num_serializer = pdata->num_serializer; +#ifdef CONFIG_PM_SLEEP + mcasp->context.xrsr_regs = devm_kzalloc(&pdev->dev, + sizeof(u32) * mcasp->num_serializer, + GFP_KERNEL); +#endif mcasp->serial_dir = pdata->serial_dir; mcasp->version = pdata->version; mcasp->txnumevt = pdata->txnumevt; diff --git a/sound/soc/davinci/edma-pcm.c b/sound/soc/davinci/edma-pcm.c index 605e643133db..59e588abe54b 100644 --- a/sound/soc/davinci/edma-pcm.c +++ b/sound/soc/davinci/edma-pcm.c @@ -25,6 +25,8 @@ #include <sound/dmaengine_pcm.h> #include <linux/edma.h> +#include "edma-pcm.h" + static const struct snd_pcm_hardware edma_pcm_hardware = { .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | diff --git a/sound/soc/dwc/designware_i2s.c b/sound/soc/dwc/designware_i2s.c index 25c31f1655f6..e961388e6e9c 100644 --- a/sound/soc/dwc/designware_i2s.c +++ b/sound/soc/dwc/designware_i2s.c @@ -4,7 +4,7 @@ * sound/soc/dwc/designware_i2s.c * * Copyright (C) 2010 ST Microelectronics - * Rajeev Kumar <rajeev-dlh.kumar@st.com> + * Rajeev Kumar <rajeevkumar.linux@gmail.com> * * This file is licensed under the terms of the GNU General Public * License version 2. This program is licensed "as is" without any @@ -455,7 +455,7 @@ static struct platform_driver dw_i2s_driver = { module_platform_driver(dw_i2s_driver); -MODULE_AUTHOR("Rajeev Kumar <rajeev-dlh.kumar@st.com>"); +MODULE_AUTHOR("Rajeev Kumar <rajeevkumar.linux@gmail.com>"); MODULE_DESCRIPTION("DESIGNWARE I2S SoC Interface"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:designware_i2s"); diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index f54a8fc99291..081e406b3713 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -49,7 +49,6 @@ config SND_SOC_FSL_ESAI tristate "Enhanced Serial Audio Interface (ESAI) module support" select REGMAP_MMIO select SND_SOC_IMX_PCM_DMA if SND_IMX_SOC != n - select SND_SOC_FSL_UTILS help Say Y if you want to add Enhanced Synchronous Audio Interface (ESAI) support for the Freescale CPUs. @@ -241,6 +240,18 @@ config SND_SOC_IMX_WM8962 Say Y if you want to add support for SoC audio on an i.MX board with a wm8962 codec. +config SND_SOC_IMX_ES8328 + tristate "SoC Audio support for i.MX boards with the ES8328 codec" + depends on OF && (I2C || SPI) + select SND_SOC_ES8328_I2C if I2C + select SND_SOC_ES8328_SPI if SPI_MASTER + select SND_SOC_IMX_PCM_DMA + select SND_SOC_IMX_AUDMUX + select SND_SOC_FSL_SSI + help + Say Y if you want to add support for the ES8328 audio codec connected + via SSI/I2S over either SPI or I2C. + config SND_SOC_IMX_SGTL5000 tristate "SoC Audio support for i.MX boards with sgtl5000" depends on OF && I2C @@ -269,6 +280,20 @@ config SND_SOC_IMX_MC13783 select SND_SOC_MC13783 select SND_SOC_IMX_PCM_DMA +config SND_SOC_FSL_ASOC_CARD + tristate "Generic ASoC Sound Card with ASRC support" + depends on OF && I2C + select SND_SOC_IMX_AUDMUX + select SND_SOC_IMX_PCM_DMA + select SND_SOC_FSL_ESAI + select SND_SOC_FSL_SAI + select SND_SOC_FSL_SSI + help + ALSA SoC Audio support with ASRC feature for Freescale SoCs that have + ESAI/SAI/SSI and connect with external CODECs such as WM8962, CS42888 + and SGTL5000. + Say Y if you want to add support for Freescale Generic ASoC Sound Card. + endif # SND_IMX_SOC endmenu diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile index 9ff59267eac9..d28dc25c9375 100644 --- a/sound/soc/fsl/Makefile +++ b/sound/soc/fsl/Makefile @@ -11,6 +11,7 @@ snd-soc-p1022-rdk-objs := p1022_rdk.o obj-$(CONFIG_SND_SOC_P1022_RDK) += snd-soc-p1022-rdk.o # Freescale SSI/DMA/SAI/SPDIF Support +snd-soc-fsl-asoc-card-objs := fsl-asoc-card.o snd-soc-fsl-asrc-objs := fsl_asrc.o fsl_asrc_dma.o snd-soc-fsl-sai-objs := fsl_sai.o snd-soc-fsl-ssi-y := fsl_ssi.o @@ -19,6 +20,7 @@ snd-soc-fsl-spdif-objs := fsl_spdif.o snd-soc-fsl-esai-objs := fsl_esai.o snd-soc-fsl-utils-objs := fsl_utils.o snd-soc-fsl-dma-objs := fsl_dma.o +obj-$(CONFIG_SND_SOC_FSL_ASOC_CARD) += snd-soc-fsl-asoc-card.o obj-$(CONFIG_SND_SOC_FSL_ASRC) += snd-soc-fsl-asrc.o obj-$(CONFIG_SND_SOC_FSL_SAI) += snd-soc-fsl-sai.o obj-$(CONFIG_SND_SOC_FSL_SSI) += snd-soc-fsl-ssi.o @@ -50,6 +52,7 @@ snd-soc-eukrea-tlv320-objs := eukrea-tlv320.o snd-soc-phycore-ac97-objs := phycore-ac97.o snd-soc-mx27vis-aic32x4-objs := mx27vis-aic32x4.o snd-soc-wm1133-ev1-objs := wm1133-ev1.o +snd-soc-imx-es8328-objs := imx-es8328.o snd-soc-imx-sgtl5000-objs := imx-sgtl5000.o snd-soc-imx-wm8962-objs := imx-wm8962.o snd-soc-imx-spdif-objs := imx-spdif.o @@ -59,6 +62,7 @@ obj-$(CONFIG_SND_SOC_EUKREA_TLV320) += snd-soc-eukrea-tlv320.o obj-$(CONFIG_SND_SOC_PHYCORE_AC97) += snd-soc-phycore-ac97.o obj-$(CONFIG_SND_SOC_MX27VIS_AIC32X4) += snd-soc-mx27vis-aic32x4.o obj-$(CONFIG_SND_MXC_SOC_WM1133_EV1) += snd-soc-wm1133-ev1.o +obj-$(CONFIG_SND_SOC_IMX_ES8328) += snd-soc-imx-es8328.o obj-$(CONFIG_SND_SOC_IMX_SGTL5000) += snd-soc-imx-sgtl5000.o obj-$(CONFIG_SND_SOC_IMX_WM8962) += snd-soc-imx-wm8962.o obj-$(CONFIG_SND_SOC_IMX_SPDIF) += snd-soc-imx-spdif.o diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c new file mode 100644 index 000000000000..007c772f3cef --- /dev/null +++ b/sound/soc/fsl/fsl-asoc-card.c @@ -0,0 +1,574 @@ +/* + * Freescale Generic ASoC Sound Card driver with ASRC + * + * Copyright (C) 2014 Freescale Semiconductor, Inc. + * + * Author: Nicolin Chen <nicoleotsuka@gmail.com> + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#include <linux/clk.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/of_platform.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> + +#include "fsl_esai.h" +#include "fsl_sai.h" +#include "imx-audmux.h" + +#include "../codecs/sgtl5000.h" +#include "../codecs/wm8962.h" + +#define RX 0 +#define TX 1 + +/* Default DAI format without Master and Slave flag */ +#define DAI_FMT_BASE (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF) + +/** + * CODEC private data + * + * @mclk_freq: Clock rate of MCLK + * @mclk_id: MCLK (or main clock) id for set_sysclk() + * @fll_id: FLL (or secordary clock) id for set_sysclk() + * @pll_id: PLL id for set_pll() + */ +struct codec_priv { + unsigned long mclk_freq; + u32 mclk_id; + u32 fll_id; + u32 pll_id; +}; + +/** + * CPU private data + * + * @sysclk_freq[2]: SYSCLK rates for set_sysclk() + * @sysclk_dir[2]: SYSCLK directions for set_sysclk() + * @sysclk_id[2]: SYSCLK ids for set_sysclk() + * + * Note: [1] for tx and [0] for rx + */ +struct cpu_priv { + unsigned long sysclk_freq[2]; + u32 sysclk_dir[2]; + u32 sysclk_id[2]; +}; + +/** + * Freescale Generic ASOC card private data + * + * @dai_link[3]: DAI link structure including normal one and DPCM link + * @pdev: platform device pointer + * @codec_priv: CODEC private data + * @cpu_priv: CPU private data + * @card: ASoC card structure + * @sample_rate: Current sample rate + * @sample_format: Current sample format + * @asrc_rate: ASRC sample rate used by Back-Ends + * @asrc_format: ASRC sample format used by Back-Ends + * @dai_fmt: DAI format between CPU and CODEC + * @name: Card name + */ + +struct fsl_asoc_card_priv { + struct snd_soc_dai_link dai_link[3]; + struct platform_device *pdev; + struct codec_priv codec_priv; + struct cpu_priv cpu_priv; + struct snd_soc_card card; + u32 sample_rate; + u32 sample_format; + u32 asrc_rate; + u32 asrc_format; + u32 dai_fmt; + char name[32]; +}; + +/** + * This dapm route map exsits for DPCM link only. + * The other routes shall go through Device Tree. + */ +static const struct snd_soc_dapm_route audio_map[] = { + {"CPU-Playback", NULL, "ASRC-Playback"}, + {"Playback", NULL, "CPU-Playback"}, + {"ASRC-Capture", NULL, "CPU-Capture"}, + {"CPU-Capture", NULL, "Capture"}, +}; + +/* Add all possible widgets into here without being redundant */ +static const struct snd_soc_dapm_widget fsl_asoc_card_dapm_widgets[] = { + SND_SOC_DAPM_LINE("Line Out Jack", NULL), + SND_SOC_DAPM_LINE("Line In Jack", NULL), + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_SPK("Ext Spk", NULL), + SND_SOC_DAPM_MIC("Mic Jack", NULL), + SND_SOC_DAPM_MIC("AMIC", NULL), + SND_SOC_DAPM_MIC("DMIC", NULL), +}; + +static int fsl_asoc_card_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card); + bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; + struct cpu_priv *cpu_priv = &priv->cpu_priv; + struct device *dev = rtd->card->dev; + int ret; + + priv->sample_rate = params_rate(params); + priv->sample_format = params_format(params); + + if (priv->card.set_bias_level) + return 0; + + /* Specific configurations of DAIs starts from here */ + ret = snd_soc_dai_set_sysclk(rtd->cpu_dai, cpu_priv->sysclk_id[tx], + cpu_priv->sysclk_freq[tx], + cpu_priv->sysclk_dir[tx]); + if (ret) { + dev_err(dev, "failed to set sysclk for cpu dai\n"); + return ret; + } + + return 0; +} + +static struct snd_soc_ops fsl_asoc_card_ops = { + .hw_params = fsl_asoc_card_hw_params, +}; + +static int be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card); + struct snd_interval *rate; + struct snd_mask *mask; + + rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); + rate->max = rate->min = priv->asrc_rate; + + mask = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); + snd_mask_none(mask); + snd_mask_set(mask, priv->asrc_format); + + return 0; +} + +static struct snd_soc_dai_link fsl_asoc_card_dai[] = { + /* Default ASoC DAI Link*/ + { + .name = "HiFi", + .stream_name = "HiFi", + .ops = &fsl_asoc_card_ops, + }, + /* DPCM Link between Front-End and Back-End (Optional) */ + { + .name = "HiFi-ASRC-FE", + .stream_name = "HiFi-ASRC-FE", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .dpcm_playback = 1, + .dpcm_capture = 1, + .dynamic = 1, + }, + { + .name = "HiFi-ASRC-BE", + .stream_name = "HiFi-ASRC-BE", + .platform_name = "snd-soc-dummy", + .be_hw_params_fixup = be_hw_params_fixup, + .ops = &fsl_asoc_card_ops, + .dpcm_playback = 1, + .dpcm_capture = 1, + .no_pcm = 1, + }, +}; + +static int fsl_asoc_card_set_bias_level(struct snd_soc_card *card, + struct snd_soc_dapm_context *dapm, + enum snd_soc_bias_level level) +{ + struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(card); + struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai; + struct codec_priv *codec_priv = &priv->codec_priv; + struct device *dev = card->dev; + unsigned int pll_out; + int ret; + + if (dapm->dev != codec_dai->dev) + return 0; + + switch (level) { + case SND_SOC_BIAS_PREPARE: + if (dapm->bias_level != SND_SOC_BIAS_STANDBY) + break; + + if (priv->sample_format == SNDRV_PCM_FORMAT_S24_LE) + pll_out = priv->sample_rate * 384; + else + pll_out = priv->sample_rate * 256; + + ret = snd_soc_dai_set_pll(codec_dai, codec_priv->pll_id, + codec_priv->mclk_id, + codec_priv->mclk_freq, pll_out); + if (ret) { + dev_err(dev, "failed to start FLL: %d\n", ret); + return ret; + } + + ret = snd_soc_dai_set_sysclk(codec_dai, codec_priv->fll_id, + pll_out, SND_SOC_CLOCK_IN); + if (ret) { + dev_err(dev, "failed to set SYSCLK: %d\n", ret); + return ret; + } + break; + + case SND_SOC_BIAS_STANDBY: + if (dapm->bias_level != SND_SOC_BIAS_PREPARE) + break; + + ret = snd_soc_dai_set_sysclk(codec_dai, codec_priv->mclk_id, + codec_priv->mclk_freq, + SND_SOC_CLOCK_IN); + if (ret) { + dev_err(dev, "failed to switch away from FLL: %d\n", ret); + return ret; + } + + ret = snd_soc_dai_set_pll(codec_dai, codec_priv->pll_id, 0, 0, 0); + if (ret) { + dev_err(dev, "failed to stop FLL: %d\n", ret); + return ret; + } + break; + + default: + break; + } + + return 0; +} + +static int fsl_asoc_card_audmux_init(struct device_node *np, + struct fsl_asoc_card_priv *priv) +{ + struct device *dev = &priv->pdev->dev; + u32 int_ptcr = 0, ext_ptcr = 0; + int int_port, ext_port; + int ret; + + ret = of_property_read_u32(np, "mux-int-port", &int_port); + if (ret) { + dev_err(dev, "mux-int-port missing or invalid\n"); + return ret; + } + ret = of_property_read_u32(np, "mux-ext-port", &ext_port); + if (ret) { + dev_err(dev, "mux-ext-port missing or invalid\n"); + return ret; + } + + /* + * The port numbering in the hardware manual starts at 1, while + * the AUDMUX API expects it starts at 0. + */ + int_port--; + ext_port--; + + /* + * Use asynchronous mode (6 wires) for all cases. + * If only 4 wires are needed, just set SSI into + * synchronous mode and enable 4 PADs in IOMUX. + */ + switch (priv->dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + int_ptcr = IMX_AUDMUX_V2_PTCR_RFSEL(8 | ext_port) | + IMX_AUDMUX_V2_PTCR_RCSEL(8 | ext_port) | + IMX_AUDMUX_V2_PTCR_TFSEL(ext_port) | + IMX_AUDMUX_V2_PTCR_TCSEL(ext_port) | + IMX_AUDMUX_V2_PTCR_RFSDIR | + IMX_AUDMUX_V2_PTCR_RCLKDIR | + IMX_AUDMUX_V2_PTCR_TFSDIR | + IMX_AUDMUX_V2_PTCR_TCLKDIR; + break; + case SND_SOC_DAIFMT_CBM_CFS: + int_ptcr = IMX_AUDMUX_V2_PTCR_RCSEL(8 | ext_port) | + IMX_AUDMUX_V2_PTCR_TCSEL(ext_port) | + IMX_AUDMUX_V2_PTCR_RCLKDIR | + IMX_AUDMUX_V2_PTCR_TCLKDIR; + ext_ptcr = IMX_AUDMUX_V2_PTCR_RFSEL(8 | int_port) | + IMX_AUDMUX_V2_PTCR_TFSEL(int_port) | + IMX_AUDMUX_V2_PTCR_RFSDIR | + IMX_AUDMUX_V2_PTCR_TFSDIR; + break; + case SND_SOC_DAIFMT_CBS_CFM: + int_ptcr = IMX_AUDMUX_V2_PTCR_RFSEL(8 | ext_port) | + IMX_AUDMUX_V2_PTCR_TFSEL(ext_port) | + IMX_AUDMUX_V2_PTCR_RFSDIR | + IMX_AUDMUX_V2_PTCR_TFSDIR; + ext_ptcr = IMX_AUDMUX_V2_PTCR_RCSEL(8 | int_port) | + IMX_AUDMUX_V2_PTCR_TCSEL(int_port) | + IMX_AUDMUX_V2_PTCR_RCLKDIR | + IMX_AUDMUX_V2_PTCR_TCLKDIR; + break; + case SND_SOC_DAIFMT_CBS_CFS: + ext_ptcr = IMX_AUDMUX_V2_PTCR_RFSEL(8 | int_port) | + IMX_AUDMUX_V2_PTCR_RCSEL(8 | int_port) | + IMX_AUDMUX_V2_PTCR_TFSEL(int_port) | + IMX_AUDMUX_V2_PTCR_TCSEL(int_port) | + IMX_AUDMUX_V2_PTCR_RFSDIR | + IMX_AUDMUX_V2_PTCR_RCLKDIR | + IMX_AUDMUX_V2_PTCR_TFSDIR | + IMX_AUDMUX_V2_PTCR_TCLKDIR; + break; + default: + return -EINVAL; + } + + /* Asynchronous mode can not be set along with RCLKDIR */ + ret = imx_audmux_v2_configure_port(int_port, 0, + IMX_AUDMUX_V2_PDCR_RXDSEL(ext_port)); + if (ret) { + dev_err(dev, "audmux internal port setup failed\n"); + return ret; + } + + ret = imx_audmux_v2_configure_port(int_port, int_ptcr, + IMX_AUDMUX_V2_PDCR_RXDSEL(ext_port)); + if (ret) { + dev_err(dev, "audmux internal port setup failed\n"); + return ret; + } + + ret = imx_audmux_v2_configure_port(ext_port, 0, + IMX_AUDMUX_V2_PDCR_RXDSEL(int_port)); + if (ret) { + dev_err(dev, "audmux external port setup failed\n"); + return ret; + } + + ret = imx_audmux_v2_configure_port(ext_port, ext_ptcr, + IMX_AUDMUX_V2_PDCR_RXDSEL(int_port)); + if (ret) { + dev_err(dev, "audmux external port setup failed\n"); + return ret; + } + + return 0; +} + +static int fsl_asoc_card_late_probe(struct snd_soc_card *card) +{ + struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(card); + struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai; + struct codec_priv *codec_priv = &priv->codec_priv; + struct device *dev = card->dev; + int ret; + + ret = snd_soc_dai_set_sysclk(codec_dai, codec_priv->mclk_id, + codec_priv->mclk_freq, SND_SOC_CLOCK_IN); + if (ret) { + dev_err(dev, "failed to set sysclk in %s\n", __func__); + return ret; + } + + return 0; +} + +static int fsl_asoc_card_probe(struct platform_device *pdev) +{ + struct device_node *cpu_np, *codec_np, *asrc_np; + struct device_node *np = pdev->dev.of_node; + struct platform_device *asrc_pdev = NULL; + struct platform_device *cpu_pdev; + struct fsl_asoc_card_priv *priv; + struct i2c_client *codec_dev; + struct clk *codec_clk; + u32 width; + int ret; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + cpu_np = of_parse_phandle(np, "audio-cpu", 0); + /* Give a chance to old DT binding */ + if (!cpu_np) + cpu_np = of_parse_phandle(np, "ssi-controller", 0); + codec_np = of_parse_phandle(np, "audio-codec", 0); + if (!cpu_np || !codec_np) { + dev_err(&pdev->dev, "phandle missing or invalid\n"); + ret = -EINVAL; + goto fail; + } + + cpu_pdev = of_find_device_by_node(cpu_np); + if (!cpu_pdev) { + dev_err(&pdev->dev, "failed to find CPU DAI device\n"); + ret = -EINVAL; + goto fail; + } + + codec_dev = of_find_i2c_device_by_node(codec_np); + if (!codec_dev) { + dev_err(&pdev->dev, "failed to find codec platform device\n"); + ret = -EINVAL; + goto fail; + } + + asrc_np = of_parse_phandle(np, "audio-asrc", 0); + if (asrc_np) + asrc_pdev = of_find_device_by_node(asrc_np); + + /* Get the MCLK rate only, and leave it controlled by CODEC drivers */ + codec_clk = clk_get(&codec_dev->dev, NULL); + if (!IS_ERR(codec_clk)) { + priv->codec_priv.mclk_freq = clk_get_rate(codec_clk); + clk_put(codec_clk); + } + + /* Default sample rate and format, will be updated in hw_params() */ + priv->sample_rate = 44100; + priv->sample_format = SNDRV_PCM_FORMAT_S16_LE; + + /* Assign a default DAI format, and allow each card to overwrite it */ + priv->dai_fmt = DAI_FMT_BASE; + + /* Diversify the card configurations */ + if (of_device_is_compatible(np, "fsl,imx-audio-cs42888")) { + priv->card.set_bias_level = NULL; + priv->cpu_priv.sysclk_freq[TX] = priv->codec_priv.mclk_freq; + priv->cpu_priv.sysclk_freq[RX] = priv->codec_priv.mclk_freq; + priv->cpu_priv.sysclk_dir[TX] = SND_SOC_CLOCK_OUT; + priv->cpu_priv.sysclk_dir[RX] = SND_SOC_CLOCK_OUT; + priv->dai_fmt |= SND_SOC_DAIFMT_CBS_CFS; + } else if (of_device_is_compatible(np, "fsl,imx-audio-sgtl5000")) { + priv->codec_priv.mclk_id = SGTL5000_SYSCLK; + priv->dai_fmt |= SND_SOC_DAIFMT_CBM_CFM; + } else if (of_device_is_compatible(np, "fsl,imx-audio-wm8962")) { + priv->card.set_bias_level = fsl_asoc_card_set_bias_level; + priv->codec_priv.mclk_id = WM8962_SYSCLK_MCLK; + priv->codec_priv.fll_id = WM8962_SYSCLK_FLL; + priv->codec_priv.pll_id = WM8962_FLL; + priv->dai_fmt |= SND_SOC_DAIFMT_CBM_CFM; + } else { + dev_err(&pdev->dev, "unknown Device Tree compatible\n"); + return -EINVAL; + } + + /* Common settings for corresponding Freescale CPU DAI driver */ + if (strstr(cpu_np->name, "ssi")) { + /* Only SSI needs to configure AUDMUX */ + ret = fsl_asoc_card_audmux_init(np, priv); + if (ret) { + dev_err(&pdev->dev, "failed to init audmux\n"); + goto asrc_fail; + } + } else if (strstr(cpu_np->name, "esai")) { + priv->cpu_priv.sysclk_id[1] = ESAI_HCKT_EXTAL; + priv->cpu_priv.sysclk_id[0] = ESAI_HCKR_EXTAL; + } else if (strstr(cpu_np->name, "sai")) { + priv->cpu_priv.sysclk_id[1] = FSL_SAI_CLK_MAST1; + priv->cpu_priv.sysclk_id[0] = FSL_SAI_CLK_MAST1; + } + + sprintf(priv->name, "%s-audio", codec_dev->name); + + /* Initialize sound card */ + priv->pdev = pdev; + priv->card.dev = &pdev->dev; + priv->card.name = priv->name; + priv->card.dai_link = priv->dai_link; + priv->card.dapm_routes = audio_map; + priv->card.late_probe = fsl_asoc_card_late_probe; + priv->card.num_dapm_routes = ARRAY_SIZE(audio_map); + priv->card.dapm_widgets = fsl_asoc_card_dapm_widgets; + priv->card.num_dapm_widgets = ARRAY_SIZE(fsl_asoc_card_dapm_widgets); + + memcpy(priv->dai_link, fsl_asoc_card_dai, + sizeof(struct snd_soc_dai_link) * ARRAY_SIZE(priv->dai_link)); + + /* Normal DAI Link */ + priv->dai_link[0].cpu_of_node = cpu_np; + priv->dai_link[0].codec_of_node = codec_np; + priv->dai_link[0].codec_dai_name = codec_dev->name; + priv->dai_link[0].platform_of_node = cpu_np; + priv->dai_link[0].dai_fmt = priv->dai_fmt; + priv->card.num_links = 1; + + if (asrc_pdev) { + /* DPCM DAI Links only if ASRC exsits */ + priv->dai_link[1].cpu_of_node = asrc_np; + priv->dai_link[1].platform_of_node = asrc_np; + priv->dai_link[2].codec_dai_name = codec_dev->name; + priv->dai_link[2].codec_of_node = codec_np; + priv->dai_link[2].cpu_of_node = cpu_np; + priv->dai_link[2].dai_fmt = priv->dai_fmt; + priv->card.num_links = 3; + + ret = of_property_read_u32(asrc_np, "fsl,asrc-rate", + &priv->asrc_rate); + if (ret) { + dev_err(&pdev->dev, "failed to get output rate\n"); + ret = -EINVAL; + goto asrc_fail; + } + + ret = of_property_read_u32(asrc_np, "fsl,asrc-width", &width); + if (ret) { + dev_err(&pdev->dev, "failed to get output rate\n"); + ret = -EINVAL; + goto asrc_fail; + } + + if (width == 24) + priv->asrc_format = SNDRV_PCM_FORMAT_S24_LE; + else + priv->asrc_format = SNDRV_PCM_FORMAT_S16_LE; + } + + /* Finish card registering */ + platform_set_drvdata(pdev, priv); + snd_soc_card_set_drvdata(&priv->card, priv); + + ret = devm_snd_soc_register_card(&pdev->dev, &priv->card); + if (ret) + dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret); + +asrc_fail: + of_node_put(asrc_np); +fail: + of_node_put(codec_np); + of_node_put(cpu_np); + + return ret; +} + +static const struct of_device_id fsl_asoc_card_dt_ids[] = { + { .compatible = "fsl,imx-audio-cs42888", }, + { .compatible = "fsl,imx-audio-sgtl5000", }, + { .compatible = "fsl,imx-audio-wm8962", }, + {} +}; + +static struct platform_driver fsl_asoc_card_driver = { + .probe = fsl_asoc_card_probe, + .driver = { + .name = "fsl-asoc-card", + .pm = &snd_soc_pm_ops, + .of_match_table = fsl_asoc_card_dt_ids, + }, +}; +module_platform_driver(fsl_asoc_card_driver); + +MODULE_DESCRIPTION("Freescale Generic ASoC Sound Card driver with ASRC"); +MODULE_AUTHOR("Nicolin Chen <nicoleotsuka@gmail.com>"); +MODULE_ALIAS("platform:fsl-asoc-card"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c index 822110420b71..3b145313f93e 100644 --- a/sound/soc/fsl/fsl_asrc.c +++ b/sound/soc/fsl/fsl_asrc.c @@ -684,7 +684,7 @@ static bool fsl_asrc_writeable_reg(struct device *dev, unsigned int reg) } } -static struct regmap_config fsl_asrc_regmap_config = { +static const struct regmap_config fsl_asrc_regmap_config = { .reg_bits = 32, .reg_stride = 4, .val_bits = 32, @@ -802,10 +802,6 @@ static int fsl_asrc_probe(struct platform_device *pdev) asrc_priv->paddr = res->start; - /* Register regmap and let it prepare core clock */ - if (of_property_read_bool(np, "big-endian")) - fsl_asrc_regmap_config.val_format_endian = REGMAP_ENDIAN_BIG; - asrc_priv->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "mem", regs, &fsl_asrc_regmap_config); if (IS_ERR(asrc_priv->regmap)) { diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c index 72d154e7dd03..8bcdfda09d7a 100644 --- a/sound/soc/fsl/fsl_esai.c +++ b/sound/soc/fsl/fsl_esai.c @@ -18,7 +18,6 @@ #include "fsl_esai.h" #include "imx-pcm.h" -#include "fsl_utils.h" #define FSL_ESAI_RATES SNDRV_PCM_RATE_8000_192000 #define FSL_ESAI_FORMATS (SNDRV_PCM_FMTBIT_S8 | \ @@ -38,6 +37,7 @@ * @fsysclk: system clock source to derive HCK, SCK and FS * @fifo_depth: depth of tx/rx FIFO * @slot_width: width of each DAI slot + * @slots: number of slots * @hck_rate: clock rate of desired HCKx clock * @sck_rate: clock rate of desired SCKx clock * @hck_dir: the direction of HCKx pads @@ -56,6 +56,7 @@ struct fsl_esai { struct clk *fsysclk; u32 fifo_depth; u32 slot_width; + u32 slots; u32 hck_rate[2]; u32 sck_rate[2]; bool hck_dir[2]; @@ -363,6 +364,7 @@ static int fsl_esai_set_dai_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask, ESAI_xSMB_xS_MASK, ESAI_xSMB_xS(rx_mask)); esai_priv->slot_width = slot_width; + esai_priv->slots = slots; return 0; } @@ -510,10 +512,11 @@ static int fsl_esai_hw_params(struct snd_pcm_substream *substream, bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; u32 width = snd_pcm_format_width(params_format(params)); u32 channels = params_channels(params); + u32 pins = DIV_ROUND_UP(channels, esai_priv->slots); u32 bclk, mask, val; int ret; - bclk = params_rate(params) * esai_priv->slot_width * 2; + bclk = params_rate(params) * esai_priv->slot_width * esai_priv->slots; ret = fsl_esai_set_bclk(dai, tx, bclk); if (ret) @@ -530,7 +533,7 @@ static int fsl_esai_hw_params(struct snd_pcm_substream *substream, mask = ESAI_xFCR_xFR_MASK | ESAI_xFCR_xWA_MASK | ESAI_xFCR_xFWM_MASK | (tx ? ESAI_xFCR_TE_MASK | ESAI_xFCR_TIEN : ESAI_xFCR_RE_MASK); val = ESAI_xFCR_xWA(width) | ESAI_xFCR_xFWM(esai_priv->fifo_depth) | - (tx ? ESAI_xFCR_TE(channels) | ESAI_xFCR_TIEN : ESAI_xFCR_RE(channels)); + (tx ? ESAI_xFCR_TE(pins) | ESAI_xFCR_TIEN : ESAI_xFCR_RE(pins)); regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx), mask, val); @@ -565,6 +568,7 @@ static int fsl_esai_trigger(struct snd_pcm_substream *substream, int cmd, struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai); bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; u8 i, channels = substream->runtime->channels; + u32 pins = DIV_ROUND_UP(channels, esai_priv->slots); switch (cmd) { case SNDRV_PCM_TRIGGER_START: @@ -579,7 +583,7 @@ static int fsl_esai_trigger(struct snd_pcm_substream *substream, int cmd, regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx), tx ? ESAI_xCR_TE_MASK : ESAI_xCR_RE_MASK, - tx ? ESAI_xCR_TE(channels) : ESAI_xCR_RE(channels)); + tx ? ESAI_xCR_TE(pins) : ESAI_xCR_RE(pins)); break; case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_STOP: @@ -607,7 +611,6 @@ static struct snd_soc_dai_ops fsl_esai_dai_ops = { .hw_params = fsl_esai_hw_params, .set_sysclk = fsl_esai_set_dai_sysclk, .set_fmt = fsl_esai_set_dai_fmt, - .xlate_tdm_slot_mask = fsl_asoc_xlate_tdm_slot_mask, .set_tdm_slot = fsl_esai_set_dai_tdm_slot, }; @@ -707,7 +710,7 @@ static bool fsl_esai_writeable_reg(struct device *dev, unsigned int reg) } } -static struct regmap_config fsl_esai_regmap_config = { +static const struct regmap_config fsl_esai_regmap_config = { .reg_bits = 32, .reg_stride = 4, .val_bits = 32, @@ -733,9 +736,6 @@ static int fsl_esai_probe(struct platform_device *pdev) esai_priv->pdev = pdev; strcpy(esai_priv->name, np->name); - if (of_property_read_bool(np, "big-endian")) - fsl_esai_regmap_config.val_format_endian = REGMAP_ENDIAN_BIG; - /* Get the addresses and IRQ */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); regs = devm_ioremap_resource(&pdev->dev, res); @@ -783,6 +783,9 @@ static int fsl_esai_probe(struct platform_device *pdev) /* Set a default slot size */ esai_priv->slot_width = 32; + /* Set a default slot number */ + esai_priv->slots = 2; + /* Set a default master/slave state */ esai_priv->slave_mode = true; diff --git a/sound/soc/fsl/fsl_esai.h b/sound/soc/fsl/fsl_esai.h index 75e14033e8d8..91a550f4a10d 100644 --- a/sound/soc/fsl/fsl_esai.h +++ b/sound/soc/fsl/fsl_esai.h @@ -130,8 +130,8 @@ #define ESAI_xFCR_RE_WIDTH 4 #define ESAI_xFCR_TE_MASK (((1 << ESAI_xFCR_TE_WIDTH) - 1) << ESAI_xFCR_xE_SHIFT) #define ESAI_xFCR_RE_MASK (((1 << ESAI_xFCR_RE_WIDTH) - 1) << ESAI_xFCR_xE_SHIFT) -#define ESAI_xFCR_TE(x) ((ESAI_xFCR_TE_MASK >> (ESAI_xFCR_TE_WIDTH - ((x + 1) >> 1))) & ESAI_xFCR_TE_MASK) -#define ESAI_xFCR_RE(x) ((ESAI_xFCR_RE_MASK >> (ESAI_xFCR_RE_WIDTH - ((x + 1) >> 1))) & ESAI_xFCR_RE_MASK) +#define ESAI_xFCR_TE(x) ((ESAI_xFCR_TE_MASK >> (ESAI_xFCR_TE_WIDTH - x)) & ESAI_xFCR_TE_MASK) +#define ESAI_xFCR_RE(x) ((ESAI_xFCR_RE_MASK >> (ESAI_xFCR_RE_WIDTH - x)) & ESAI_xFCR_RE_MASK) #define ESAI_xFCR_xFR_SHIFT 1 #define ESAI_xFCR_xFR_MASK (1 << ESAI_xFCR_xFR_SHIFT) #define ESAI_xFCR_xFR (1 << ESAI_xFCR_xFR_SHIFT) @@ -272,8 +272,8 @@ #define ESAI_xCR_RE_WIDTH 4 #define ESAI_xCR_TE_MASK (((1 << ESAI_xCR_TE_WIDTH) - 1) << ESAI_xCR_xE_SHIFT) #define ESAI_xCR_RE_MASK (((1 << ESAI_xCR_RE_WIDTH) - 1) << ESAI_xCR_xE_SHIFT) -#define ESAI_xCR_TE(x) ((ESAI_xCR_TE_MASK >> (ESAI_xCR_TE_WIDTH - ((x + 1) >> 1))) & ESAI_xCR_TE_MASK) -#define ESAI_xCR_RE(x) ((ESAI_xCR_RE_MASK >> (ESAI_xCR_RE_WIDTH - ((x + 1) >> 1))) & ESAI_xCR_RE_MASK) +#define ESAI_xCR_TE(x) ((ESAI_xCR_TE_MASK >> (ESAI_xCR_TE_WIDTH - x)) & ESAI_xCR_TE_MASK) +#define ESAI_xCR_RE(x) ((ESAI_xCR_RE_MASK >> (ESAI_xCR_RE_WIDTH - x)) & ESAI_xCR_RE_MASK) /* * Transmit Clock Control Register -- REG_ESAI_TCCR 0xD8 diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index faa049797897..7eeb1dd8ce27 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -175,7 +175,7 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai, bool tx = fsl_dir == FSL_FMT_TRANSMITTER; u32 val_cr2 = 0, val_cr4 = 0; - if (!sai->big_endian_data) + if (!sai->is_lsb_first) val_cr4 |= FSL_SAI_CR4_MF; /* DAI mode */ @@ -304,7 +304,7 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream, val_cr5 |= FSL_SAI_CR5_WNW(word_width); val_cr5 |= FSL_SAI_CR5_W0W(word_width); - if (sai->big_endian_data) + if (sai->is_lsb_first) val_cr5 |= FSL_SAI_CR5_FBT(0); else val_cr5 |= FSL_SAI_CR5_FBT(word_width - 1); @@ -330,13 +330,13 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd, u32 xcsr, count = 100; /* - * The transmitter bit clock and frame sync are to be - * used by both the transmitter and receiver. + * Asynchronous mode: Clear SYNC for both Tx and Rx. + * Rx sync with Tx clocks: Clear SYNC for Tx, set it for Rx. + * Tx sync with Rx clocks: Clear SYNC for Rx, set it for Tx. */ - regmap_update_bits(sai->regmap, FSL_SAI_TCR2, FSL_SAI_CR2_SYNC, - ~FSL_SAI_CR2_SYNC); + regmap_update_bits(sai->regmap, FSL_SAI_TCR2, FSL_SAI_CR2_SYNC, 0); regmap_update_bits(sai->regmap, FSL_SAI_RCR2, FSL_SAI_CR2_SYNC, - FSL_SAI_CR2_SYNC); + sai->synchronous[RX] ? FSL_SAI_CR2_SYNC : 0); /* * It is recommended that the transmitter is the last enabled @@ -437,8 +437,13 @@ static int fsl_sai_dai_probe(struct snd_soc_dai *cpu_dai) { struct fsl_sai *sai = dev_get_drvdata(cpu_dai->dev); - regmap_update_bits(sai->regmap, FSL_SAI_TCSR, 0xffffffff, 0x0); - regmap_update_bits(sai->regmap, FSL_SAI_RCSR, 0xffffffff, 0x0); + /* Software Reset for both Tx and Rx */ + regmap_write(sai->regmap, FSL_SAI_TCSR, FSL_SAI_CSR_SR); + regmap_write(sai->regmap, FSL_SAI_RCSR, FSL_SAI_CSR_SR); + /* Clear SR bit to finish the reset */ + regmap_write(sai->regmap, FSL_SAI_TCSR, 0); + regmap_write(sai->regmap, FSL_SAI_RCSR, 0); + regmap_update_bits(sai->regmap, FSL_SAI_TCR1, FSL_SAI_CR1_RFW_MASK, FSL_SAI_MAXBURST_TX * 2); regmap_update_bits(sai->regmap, FSL_SAI_RCR1, FSL_SAI_CR1_RFW_MASK, @@ -539,7 +544,7 @@ static bool fsl_sai_writeable_reg(struct device *dev, unsigned int reg) } } -static struct regmap_config fsl_sai_regmap_config = { +static const struct regmap_config fsl_sai_regmap_config = { .reg_bits = 32, .reg_stride = 4, .val_bits = 32, @@ -568,11 +573,7 @@ static int fsl_sai_probe(struct platform_device *pdev) if (of_device_is_compatible(pdev->dev.of_node, "fsl,imx6sx-sai")) sai->sai_on_imx = true; - sai->big_endian_regs = of_property_read_bool(np, "big-endian-regs"); - if (sai->big_endian_regs) - fsl_sai_regmap_config.val_format_endian = REGMAP_ENDIAN_BIG; - - sai->big_endian_data = of_property_read_bool(np, "big-endian-data"); + sai->is_lsb_first = of_property_read_bool(np, "lsb-first"); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); base = devm_ioremap_resource(&pdev->dev, res); @@ -621,6 +622,33 @@ static int fsl_sai_probe(struct platform_device *pdev) return ret; } + /* Sync Tx with Rx as default by following old DT binding */ + sai->synchronous[RX] = true; + sai->synchronous[TX] = false; + fsl_sai_dai.symmetric_rates = 1; + fsl_sai_dai.symmetric_channels = 1; + fsl_sai_dai.symmetric_samplebits = 1; + + if (of_find_property(np, "fsl,sai-synchronous-rx", NULL) && + of_find_property(np, "fsl,sai-asynchronous", NULL)) { + /* error out if both synchronous and asynchronous are present */ + dev_err(&pdev->dev, "invalid binding for synchronous mode\n"); + return -EINVAL; + } + + if (of_find_property(np, "fsl,sai-synchronous-rx", NULL)) { + /* Sync Rx with Tx */ + sai->synchronous[RX] = false; + sai->synchronous[TX] = true; + } else if (of_find_property(np, "fsl,sai-asynchronous", NULL)) { + /* Discard all settings for asynchronous mode */ + sai->synchronous[RX] = false; + sai->synchronous[TX] = false; + fsl_sai_dai.symmetric_rates = 0; + fsl_sai_dai.symmetric_channels = 0; + fsl_sai_dai.symmetric_samplebits = 0; + } + sai->dma_params_rx.addr = res->start + FSL_SAI_RDR; sai->dma_params_tx.addr = res->start + FSL_SAI_TDR; sai->dma_params_rx.maxburst = FSL_SAI_MAXBURST_RX; diff --git a/sound/soc/fsl/fsl_sai.h b/sound/soc/fsl/fsl_sai.h index 0e6c9f595d75..34667209b607 100644 --- a/sound/soc/fsl/fsl_sai.h +++ b/sound/soc/fsl/fsl_sai.h @@ -48,6 +48,7 @@ /* SAI Transmit/Recieve Control Register */ #define FSL_SAI_CSR_TERE BIT(31) #define FSL_SAI_CSR_FR BIT(25) +#define FSL_SAI_CSR_SR BIT(24) #define FSL_SAI_CSR_xF_SHIFT 16 #define FSL_SAI_CSR_xF_W_SHIFT 18 #define FSL_SAI_CSR_xF_MASK (0x1f << FSL_SAI_CSR_xF_SHIFT) @@ -131,13 +132,16 @@ struct fsl_sai { struct clk *bus_clk; struct clk *mclk_clk[FSL_SAI_MCLK_MAX]; - bool big_endian_regs; - bool big_endian_data; + bool is_lsb_first; bool is_dsp_mode; bool sai_on_imx; + bool synchronous[2]; struct snd_dmaengine_dai_dma_data dma_params_rx; struct snd_dmaengine_dai_dma_data dma_params_tx; }; +#define TX 1 +#define RX 0 + #endif /* __FSL_SAI_H */ diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index 70acfe4a9bd5..ae4e408810ec 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c @@ -1040,7 +1040,7 @@ static bool fsl_spdif_writeable_reg(struct device *dev, unsigned int reg) } } -static struct regmap_config fsl_spdif_regmap_config = { +static const struct regmap_config fsl_spdif_regmap_config = { .reg_bits = 32, .reg_stride = 4, .val_bits = 32, @@ -1184,9 +1184,6 @@ static int fsl_spdif_probe(struct platform_device *pdev) memcpy(&spdif_priv->cpu_dai_drv, &fsl_spdif_dai, sizeof(fsl_spdif_dai)); spdif_priv->cpu_dai_drv.name = spdif_priv->name; - if (of_property_read_bool(np, "big-endian")) - fsl_spdif_regmap_config.val_format_endian = REGMAP_ENDIAN_BIG; - /* Get the addresses and IRQ */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); regs = devm_ioremap_resource(&pdev->dev, res); diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index f19224ee5b03..e6955170dc42 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -786,8 +786,9 @@ static int fsl_ssi_hw_free(struct snd_pcm_substream *substream, return 0; } -static int _fsl_ssi_set_dai_fmt(struct fsl_ssi_private *ssi_private, - unsigned int fmt) +static int _fsl_ssi_set_dai_fmt(struct device *dev, + struct fsl_ssi_private *ssi_private, + unsigned int fmt) { struct regmap *regs = ssi_private->regs; u32 strcr = 0, stcr, srcr, scr, mask; @@ -796,7 +797,7 @@ static int _fsl_ssi_set_dai_fmt(struct fsl_ssi_private *ssi_private, ssi_private->dai_fmt = fmt; if (fsl_ssi_is_i2s_master(ssi_private) && IS_ERR(ssi_private->baudclk)) { - dev_err(&ssi_private->pdev->dev, "baudclk is missing which is necessary for master mode\n"); + dev_err(dev, "baudclk is missing which is necessary for master mode\n"); return -EINVAL; } @@ -957,7 +958,7 @@ static int fsl_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) { struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(cpu_dai); - return _fsl_ssi_set_dai_fmt(ssi_private, fmt); + return _fsl_ssi_set_dai_fmt(cpu_dai->dev, ssi_private, fmt); } /** @@ -1444,7 +1445,8 @@ static int fsl_ssi_probe(struct platform_device *pdev) done: if (ssi_private->dai_fmt) - _fsl_ssi_set_dai_fmt(ssi_private, ssi_private->dai_fmt); + _fsl_ssi_set_dai_fmt(&pdev->dev, ssi_private, + ssi_private->dai_fmt); return 0; diff --git a/sound/soc/fsl/imx-es8328.c b/sound/soc/fsl/imx-es8328.c new file mode 100644 index 000000000000..653e66d150c8 --- /dev/null +++ b/sound/soc/fsl/imx-es8328.c @@ -0,0 +1,232 @@ +/* + * Copyright 2012 Freescale Semiconductor, Inc. + * Copyright 2012 Linaro Ltd. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include <linux/gpio.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_platform.h> +#include <linux/i2c.h> +#include <linux/of_gpio.h> +#include <sound/soc.h> +#include <sound/jack.h> + +#include "imx-audmux.h" + +#define DAI_NAME_SIZE 32 +#define MUX_PORT_MAX 7 + +struct imx_es8328_data { + struct device *dev; + struct snd_soc_dai_link dai; + struct snd_soc_card card; + char codec_dai_name[DAI_NAME_SIZE]; + char platform_name[DAI_NAME_SIZE]; + int jack_gpio; +}; + +static struct snd_soc_jack_gpio headset_jack_gpios[] = { + { + .gpio = -1, + .name = "headset-gpio", + .report = SND_JACK_HEADSET, + .invert = 0, + .debounce_time = 200, + }, +}; + +static struct snd_soc_jack headset_jack; + +static int imx_es8328_dai_init(struct snd_soc_pcm_runtime *rtd) +{ + struct imx_es8328_data *data = container_of(rtd->card, + struct imx_es8328_data, card); + int ret = 0; + + /* Headphone jack detection */ + if (gpio_is_valid(data->jack_gpio)) { + ret = snd_soc_jack_new(rtd->codec, "Headphone", + SND_JACK_HEADPHONE | SND_JACK_BTN_0, + &headset_jack); + if (ret) + return ret; + + headset_jack_gpios[0].gpio = data->jack_gpio; + ret = snd_soc_jack_add_gpios(&headset_jack, + ARRAY_SIZE(headset_jack_gpios), + headset_jack_gpios); + } + + return ret; +} + +static const struct snd_soc_dapm_widget imx_es8328_dapm_widgets[] = { + SND_SOC_DAPM_MIC("Mic Jack", NULL), + SND_SOC_DAPM_HP("Headphone", NULL), + SND_SOC_DAPM_SPK("Speaker", NULL), + SND_SOC_DAPM_REGULATOR_SUPPLY("audio-amp", 1, 0), +}; + +static int imx_es8328_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct device_node *ssi_np, *codec_np; + struct platform_device *ssi_pdev; + struct imx_es8328_data *data; + u32 int_port, ext_port; + int ret; + struct device *dev = &pdev->dev; + + ret = of_property_read_u32(np, "mux-int-port", &int_port); + if (ret) { + dev_err(dev, "mux-int-port missing or invalid\n"); + goto fail; + } + if (int_port > MUX_PORT_MAX || int_port == 0) { + dev_err(dev, "mux-int-port: hardware only has %d mux ports\n", + MUX_PORT_MAX); + goto fail; + } + + ret = of_property_read_u32(np, "mux-ext-port", &ext_port); + if (ret) { + dev_err(dev, "mux-ext-port missing or invalid\n"); + goto fail; + } + if (ext_port > MUX_PORT_MAX || ext_port == 0) { + dev_err(dev, "mux-ext-port: hardware only has %d mux ports\n", + MUX_PORT_MAX); + goto fail; + } + + /* + * The port numbering in the hardware manual starts at 1, while + * the audmux API expects it starts at 0. + */ + int_port--; + ext_port--; + ret = imx_audmux_v2_configure_port(int_port, + IMX_AUDMUX_V2_PTCR_SYN | + IMX_AUDMUX_V2_PTCR_TFSEL(ext_port) | + IMX_AUDMUX_V2_PTCR_TCSEL(ext_port) | + IMX_AUDMUX_V2_PTCR_TFSDIR | + IMX_AUDMUX_V2_PTCR_TCLKDIR, + IMX_AUDMUX_V2_PDCR_RXDSEL(ext_port)); + if (ret) { + dev_err(dev, "audmux internal port setup failed\n"); + return ret; + } + ret = imx_audmux_v2_configure_port(ext_port, + IMX_AUDMUX_V2_PTCR_SYN, + IMX_AUDMUX_V2_PDCR_RXDSEL(int_port)); + if (ret) { + dev_err(dev, "audmux external port setup failed\n"); + return ret; + } + + ssi_np = of_parse_phandle(pdev->dev.of_node, "ssi-controller", 0); + codec_np = of_parse_phandle(pdev->dev.of_node, "audio-codec", 0); + if (!ssi_np || !codec_np) { + dev_err(dev, "phandle missing or invalid\n"); + ret = -EINVAL; + goto fail; + } + + ssi_pdev = of_find_device_by_node(ssi_np); + if (!ssi_pdev) { + dev_err(dev, "failed to find SSI platform device\n"); + ret = -EINVAL; + goto fail; + } + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) { + ret = -ENOMEM; + goto fail; + } + + data->dev = dev; + + data->jack_gpio = of_get_named_gpio(pdev->dev.of_node, "jack-gpio", 0); + + data->dai.name = "hifi"; + data->dai.stream_name = "hifi"; + data->dai.codec_dai_name = "es8328-hifi-analog"; + data->dai.codec_of_node = codec_np; + data->dai.cpu_of_node = ssi_np; + data->dai.platform_of_node = ssi_np; + data->dai.init = &imx_es8328_dai_init; + data->dai.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM; + + data->card.dev = dev; + data->card.dapm_widgets = imx_es8328_dapm_widgets; + data->card.num_dapm_widgets = ARRAY_SIZE(imx_es8328_dapm_widgets); + ret = snd_soc_of_parse_card_name(&data->card, "model"); + if (ret) { + dev_err(dev, "Unable to parse card name\n"); + goto fail; + } + ret = snd_soc_of_parse_audio_routing(&data->card, "audio-routing"); + if (ret) { + dev_err(dev, "Unable to parse routing: %d\n", ret); + goto fail; + } + data->card.num_links = 1; + data->card.owner = THIS_MODULE; + data->card.dai_link = &data->dai; + + ret = snd_soc_register_card(&data->card); + if (ret) { + dev_err(dev, "Unable to register: %d\n", ret); + goto fail; + } + + platform_set_drvdata(pdev, data); +fail: + of_node_put(ssi_np); + of_node_put(codec_np); + + return ret; +} + +static int imx_es8328_remove(struct platform_device *pdev) +{ + struct imx_es8328_data *data = platform_get_drvdata(pdev); + + snd_soc_jack_free_gpios(&headset_jack, ARRAY_SIZE(headset_jack_gpios), + headset_jack_gpios); + + snd_soc_unregister_card(&data->card); + + return 0; +} + +static const struct of_device_id imx_es8328_dt_ids[] = { + { .compatible = "fsl,imx-audio-es8328", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, imx_es8328_dt_ids); + +static struct platform_driver imx_es8328_driver = { + .driver = { + .name = "imx-es8328", + .of_match_table = imx_es8328_dt_ids, + }, + .probe = imx_es8328_probe, + .remove = imx_es8328_remove, +}; +module_platform_driver(imx_es8328_driver); + +MODULE_AUTHOR("Sean Cross <xobs@kosagi.com>"); +MODULE_DESCRIPTION("Kosagi i.MX6 ES8328 ASoC machine driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:imx-audio-es8328"); diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 159e517fa09a..cef7776b712c 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -481,12 +481,19 @@ static int asoc_simple_card_probe(struct platform_device *pdev) snd_soc_card_set_drvdata(&priv->snd_card, priv); ret = devm_snd_soc_register_card(&pdev->dev, &priv->snd_card); + if (ret >= 0) + return ret; err: asoc_simple_card_unref(pdev); return ret; } +static int asoc_simple_card_remove(struct platform_device *pdev) +{ + return asoc_simple_card_unref(pdev); +} + static const struct of_device_id asoc_simple_of_match[] = { { .compatible = "simple-audio-card", }, {}, @@ -500,6 +507,7 @@ static struct platform_driver asoc_simple_card = { .of_match_table = asoc_simple_of_match, }, .probe = asoc_simple_card_probe, + .remove = asoc_simple_card_remove, }; module_platform_driver(asoc_simple_card); diff --git a/sound/soc/intel/Makefile b/sound/soc/intel/Makefile index 7acbfc43a0c6..f841786dad15 100644 --- a/sound/soc/intel/Makefile +++ b/sound/soc/intel/Makefile @@ -2,7 +2,8 @@ snd-soc-sst-dsp-objs := sst-dsp.o sst-firmware.o snd-soc-sst-acpi-objs := sst-acpi.o -snd-soc-sst-mfld-platform-objs := sst-mfld-platform-pcm.o sst-mfld-platform-compress.o +snd-soc-sst-mfld-platform-objs := sst-mfld-platform-pcm.o \ + sst-mfld-platform-compress.o sst-atom-controls.o snd-soc-mfld-machine-objs := mfld_machine.o obj-$(CONFIG_SND_SST_MFLD_PLATFORM) += snd-soc-sst-mfld-platform.o diff --git a/sound/soc/intel/byt-max98090.c b/sound/soc/intel/byt-max98090.c index b8b8af571ef1..d52681e7225e 100644 --- a/sound/soc/intel/byt-max98090.c +++ b/sound/soc/intel/byt-max98090.c @@ -139,6 +139,7 @@ static struct snd_soc_card byt_max98090_card = { .num_dapm_routes = ARRAY_SIZE(byt_max98090_audio_map), .controls = byt_max98090_controls, .num_controls = ARRAY_SIZE(byt_max98090_controls), + .fully_routed = true, }; static int byt_max98090_probe(struct platform_device *pdev) diff --git a/sound/soc/intel/byt-rt5640.c b/sound/soc/intel/byt-rt5640.c index 234a58de3c53..e03abdf21c1b 100644 --- a/sound/soc/intel/byt-rt5640.c +++ b/sound/soc/intel/byt-rt5640.c @@ -17,6 +17,7 @@ #include <linux/platform_device.h> #include <linux/acpi.h> #include <linux/device.h> +#include <linux/dmi.h> #include <linux/slab.h> #include <sound/pcm.h> #include <sound/pcm_params.h> @@ -36,8 +37,6 @@ static const struct snd_soc_dapm_widget byt_rt5640_widgets[] = { static const struct snd_soc_dapm_route byt_rt5640_audio_map[] = { {"Headset Mic", NULL, "MICBIAS1"}, {"IN2P", NULL, "Headset Mic"}, - {"IN2N", NULL, "Headset Mic"}, - {"DMIC1", NULL, "Internal Mic"}, {"Headphone", NULL, "HPOL"}, {"Headphone", NULL, "HPOR"}, {"Speaker", NULL, "SPOLP"}, @@ -46,6 +45,31 @@ static const struct snd_soc_dapm_route byt_rt5640_audio_map[] = { {"Speaker", NULL, "SPORN"}, }; +static const struct snd_soc_dapm_route byt_rt5640_intmic_dmic1_map[] = { + {"DMIC1", NULL, "Internal Mic"}, +}; + +static const struct snd_soc_dapm_route byt_rt5640_intmic_dmic2_map[] = { + {"DMIC2", NULL, "Internal Mic"}, +}; + +static const struct snd_soc_dapm_route byt_rt5640_intmic_in1_map[] = { + {"Internal Mic", NULL, "MICBIAS1"}, + {"IN1P", NULL, "Internal Mic"}, +}; + +enum { + BYT_RT5640_DMIC1_MAP, + BYT_RT5640_DMIC2_MAP, + BYT_RT5640_IN1_MAP, +}; + +#define BYT_RT5640_MAP(quirk) ((quirk) & 0xff) +#define BYT_RT5640_DMIC_EN BIT(16) + +static unsigned long byt_rt5640_quirk = BYT_RT5640_DMIC1_MAP | + BYT_RT5640_DMIC_EN; + static const struct snd_kcontrol_new byt_rt5640_controls[] = { SOC_DAPM_PIN_SWITCH("Headphone"), SOC_DAPM_PIN_SWITCH("Headset Mic"), @@ -77,12 +101,41 @@ static int byt_rt5640_hw_params(struct snd_pcm_substream *substream, return 0; } +static int byt_rt5640_quirk_cb(const struct dmi_system_id *id) +{ + byt_rt5640_quirk = (unsigned long)id->driver_data; + return 1; +} + +static const struct dmi_system_id byt_rt5640_quirk_table[] = { + { + .callback = byt_rt5640_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "T100TA"), + }, + .driver_data = (unsigned long *)BYT_RT5640_IN1_MAP, + }, + { + .callback = byt_rt5640_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "DellInc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Venue 8 Pro 5830"), + }, + .driver_data = (unsigned long *)(BYT_RT5640_DMIC2_MAP | + BYT_RT5640_DMIC_EN), + }, + {} +}; + static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime) { int ret; struct snd_soc_codec *codec = runtime->codec; struct snd_soc_dapm_context *dapm = &codec->dapm; struct snd_soc_card *card = runtime->card; + const struct snd_soc_dapm_route *custom_map; + int num_routes; card->dapm.idle_bias_off = true; @@ -93,6 +146,31 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime) return ret; } + dmi_check_system(byt_rt5640_quirk_table); + switch (BYT_RT5640_MAP(byt_rt5640_quirk)) { + case BYT_RT5640_IN1_MAP: + custom_map = byt_rt5640_intmic_in1_map; + num_routes = ARRAY_SIZE(byt_rt5640_intmic_in1_map); + break; + case BYT_RT5640_DMIC2_MAP: + custom_map = byt_rt5640_intmic_dmic2_map; + num_routes = ARRAY_SIZE(byt_rt5640_intmic_dmic2_map); + break; + default: + custom_map = byt_rt5640_intmic_dmic1_map; + num_routes = ARRAY_SIZE(byt_rt5640_intmic_dmic1_map); + } + + ret = snd_soc_dapm_add_routes(dapm, custom_map, num_routes); + if (ret) + return ret; + + if (byt_rt5640_quirk & BYT_RT5640_DMIC_EN) { + ret = rt5640_dmic_enable(codec, 0, 0); + if (ret) + return ret; + } + snd_soc_dapm_ignore_suspend(dapm, "HPOL"); snd_soc_dapm_ignore_suspend(dapm, "HPOR"); @@ -131,6 +209,7 @@ static struct snd_soc_card byt_rt5640_card = { .num_dapm_widgets = ARRAY_SIZE(byt_rt5640_widgets), .dapm_routes = byt_rt5640_audio_map, .num_dapm_routes = ARRAY_SIZE(byt_rt5640_audio_map), + .fully_routed = true, }; static int byt_rt5640_probe(struct platform_device *pdev) diff --git a/sound/soc/intel/sst-acpi.c b/sound/soc/intel/sst-acpi.c index 42edc6f4fc4a..03d0a166b635 100644 --- a/sound/soc/intel/sst-acpi.c +++ b/sound/soc/intel/sst-acpi.c @@ -246,8 +246,8 @@ static struct sst_acpi_desc sst_acpi_broadwell_desc = { }; static struct sst_acpi_mach baytrail_machines[] = { - { "10EC5640", "byt-rt5640", "intel/fw_sst_0f28.bin-i2s_master" }, - { "193C9890", "byt-max98090", "intel/fw_sst_0f28.bin-i2s_master" }, + { "10EC5640", "byt-rt5640", "intel/fw_sst_0f28.bin-48kHz_i2s_master" }, + { "193C9890", "byt-max98090", "intel/fw_sst_0f28.bin-48kHz_i2s_master" }, {} }; diff --git a/sound/soc/intel/sst-atom-controls.c b/sound/soc/intel/sst-atom-controls.c new file mode 100644 index 000000000000..7104a34181a9 --- /dev/null +++ b/sound/soc/intel/sst-atom-controls.c @@ -0,0 +1,218 @@ +/* + * sst-atom-controls.c - Intel MID Platform driver DPCM ALSA controls for Mrfld + * + * Copyright (C) 2013-14 Intel Corp + * Author: Omair Mohammed Abdullah <omair.m.abdullah@intel.com> + * Vinod Koul <vinod.koul@intel.com> + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/slab.h> +#include <sound/soc.h> +#include <sound/tlv.h> +#include "sst-mfld-platform.h" +#include "sst-atom-controls.h" + +static int sst_fill_byte_control(struct sst_data *drv, + u8 ipc_msg, u8 block, + u8 task_id, u8 pipe_id, + u16 len, void *cmd_data) +{ + struct snd_sst_bytes_v2 *byte_data = drv->byte_stream; + + byte_data->type = SST_CMD_BYTES_SET; + byte_data->ipc_msg = ipc_msg; + byte_data->block = block; + byte_data->task_id = task_id; + byte_data->pipe_id = pipe_id; + + if (len > SST_MAX_BIN_BYTES - sizeof(*byte_data)) { + dev_err(&drv->pdev->dev, "command length too big (%u)", len); + return -EINVAL; + } + byte_data->len = len; + memcpy(byte_data->bytes, cmd_data, len); + print_hex_dump_bytes("writing to lpe: ", DUMP_PREFIX_OFFSET, + byte_data, len + sizeof(*byte_data)); + return 0; +} + +static int sst_fill_and_send_cmd_unlocked(struct sst_data *drv, + u8 ipc_msg, u8 block, u8 task_id, u8 pipe_id, + void *cmd_data, u16 len) +{ + int ret = 0; + + ret = sst_fill_byte_control(drv, ipc_msg, + block, task_id, pipe_id, len, cmd_data); + if (ret < 0) + return ret; + return sst->ops->send_byte_stream(sst->dev, drv->byte_stream); +} + +/** + * sst_fill_and_send_cmd - generate the IPC message and send it to the FW + * @ipc_msg: type of IPC (CMD, SET_PARAMS, GET_PARAMS) + * @cmd_data: the IPC payload + */ +static int sst_fill_and_send_cmd(struct sst_data *drv, + u8 ipc_msg, u8 block, u8 task_id, u8 pipe_id, + void *cmd_data, u16 len) +{ + int ret; + + mutex_lock(&drv->lock); + ret = sst_fill_and_send_cmd_unlocked(drv, ipc_msg, block, + task_id, pipe_id, cmd_data, len); + mutex_unlock(&drv->lock); + + return ret; +} + +static int sst_send_algo_cmd(struct sst_data *drv, + struct sst_algo_control *bc) +{ + int len, ret = 0; + struct sst_cmd_set_params *cmd; + + /*bc->max includes sizeof algos + length field*/ + len = sizeof(cmd->dst) + sizeof(cmd->command_id) + bc->max; + + cmd = kzalloc(len, GFP_KERNEL); + if (cmd == NULL) + return -ENOMEM; + + SST_FILL_DESTINATION(2, cmd->dst, bc->pipe_id, bc->module_id); + cmd->command_id = bc->cmd_id; + memcpy(cmd->params, bc->params, bc->max); + + ret = sst_fill_and_send_cmd_unlocked(drv, SST_IPC_IA_SET_PARAMS, + SST_FLAG_BLOCKED, bc->task_id, 0, cmd, len); + kfree(cmd); + return ret; +} + +static int sst_algo_bytes_ctl_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct sst_algo_control *bc = (void *)kcontrol->private_value; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; + uinfo->count = bc->max; + + return 0; +} + +static int sst_algo_control_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct sst_algo_control *bc = (void *)kcontrol->private_value; + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + + switch (bc->type) { + case SST_ALGO_PARAMS: + memcpy(ucontrol->value.bytes.data, bc->params, bc->max); + break; + default: + dev_err(component->dev, "Invalid Input- algo type:%d\n", + bc->type); + return -EINVAL; + + } + return 0; +} + +static int sst_algo_control_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int ret = 0; + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct sst_data *drv = snd_soc_component_get_drvdata(cmpnt); + struct sst_algo_control *bc = (void *)kcontrol->private_value; + + dev_dbg(cmpnt->dev, "control_name=%s\n", kcontrol->id.name); + mutex_lock(&drv->lock); + switch (bc->type) { + case SST_ALGO_PARAMS: + memcpy(bc->params, ucontrol->value.bytes.data, bc->max); + break; + default: + mutex_unlock(&drv->lock); + dev_err(cmpnt->dev, "Invalid Input- algo type:%d\n", + bc->type); + return -EINVAL; + } + /*if pipe is enabled, need to send the algo params from here*/ + if (bc->w && bc->w->power) + ret = sst_send_algo_cmd(drv, bc); + mutex_unlock(&drv->lock); + + return ret; +} + +static const struct snd_kcontrol_new sst_algo_controls[] = { + SST_ALGO_KCONTROL_BYTES("media_loop1_out", "fir", 272, SST_MODULE_ID_FIR_24, + SST_PATH_INDEX_MEDIA_LOOP1_OUT, 0, SST_TASK_SBA, SBA_VB_SET_FIR), + SST_ALGO_KCONTROL_BYTES("media_loop1_out", "iir", 300, SST_MODULE_ID_IIR_24, + SST_PATH_INDEX_MEDIA_LOOP1_OUT, 0, SST_TASK_SBA, SBA_VB_SET_IIR), + SST_ALGO_KCONTROL_BYTES("media_loop1_out", "mdrp", 286, SST_MODULE_ID_MDRP, + SST_PATH_INDEX_MEDIA_LOOP1_OUT, 0, SST_TASK_SBA, SBA_SET_MDRP), + SST_ALGO_KCONTROL_BYTES("media_loop2_out", "fir", 272, SST_MODULE_ID_FIR_24, + SST_PATH_INDEX_MEDIA_LOOP2_OUT, 0, SST_TASK_SBA, SBA_VB_SET_FIR), + SST_ALGO_KCONTROL_BYTES("media_loop2_out", "iir", 300, SST_MODULE_ID_IIR_24, + SST_PATH_INDEX_MEDIA_LOOP2_OUT, 0, SST_TASK_SBA, SBA_VB_SET_IIR), + SST_ALGO_KCONTROL_BYTES("media_loop2_out", "mdrp", 286, SST_MODULE_ID_MDRP, + SST_PATH_INDEX_MEDIA_LOOP2_OUT, 0, SST_TASK_SBA, SBA_SET_MDRP), + SST_ALGO_KCONTROL_BYTES("sprot_loop_out", "lpro", 192, SST_MODULE_ID_SPROT, + SST_PATH_INDEX_SPROT_LOOP_OUT, 0, SST_TASK_SBA, SBA_VB_LPRO), + SST_ALGO_KCONTROL_BYTES("codec_in0", "dcr", 52, SST_MODULE_ID_FILT_DCR, + SST_PATH_INDEX_CODEC_IN0, 0, SST_TASK_SBA, SBA_VB_SET_IIR), + SST_ALGO_KCONTROL_BYTES("codec_in1", "dcr", 52, SST_MODULE_ID_FILT_DCR, + SST_PATH_INDEX_CODEC_IN1, 0, SST_TASK_SBA, SBA_VB_SET_IIR), + +}; + +static int sst_algo_control_init(struct device *dev) +{ + int i = 0; + struct sst_algo_control *bc; + /*allocate space to cache the algo parameters in the driver*/ + for (i = 0; i < ARRAY_SIZE(sst_algo_controls); i++) { + bc = (struct sst_algo_control *)sst_algo_controls[i].private_value; + bc->params = devm_kzalloc(dev, bc->max, GFP_KERNEL); + if (bc->params == NULL) + return -ENOMEM; + } + return 0; +} + +int sst_dsp_init_v2_dpcm(struct snd_soc_platform *platform) +{ + int ret = 0; + struct sst_data *drv = snd_soc_platform_get_drvdata(platform); + + drv->byte_stream = devm_kzalloc(platform->dev, + SST_MAX_BIN_BYTES, GFP_KERNEL); + if (!drv->byte_stream) + return -ENOMEM; + + /*Initialize algo control params*/ + ret = sst_algo_control_init(platform->dev); + if (ret) + return ret; + ret = snd_soc_add_platform_controls(platform, sst_algo_controls, + ARRAY_SIZE(sst_algo_controls)); + return ret; +} diff --git a/sound/soc/intel/sst-atom-controls.h b/sound/soc/intel/sst-atom-controls.h index 14063ab8c7c5..a73e894b175c 100644 --- a/sound/soc/intel/sst-atom-controls.h +++ b/sound/soc/intel/sst-atom-controls.h @@ -1,4 +1,6 @@ /* + * sst-atom-controls.h - Intel MID Platform driver header file + * * Copyright (C) 2013-14 Intel Corp * Author: Ramesh Babu <ramesh.babu.koul@intel.com> * Omair M Abdullah <omair.m.abdullah@intel.com> @@ -18,13 +20,423 @@ * */ -#ifndef __SST_CONTROLS_V2_H__ -#define __SST_CONTROLS_V2_H__ +#ifndef __SST_ATOM_CONTROLS_H__ +#define __SST_ATOM_CONTROLS_H__ enum { MERR_DPCM_AUDIO = 0, MERR_DPCM_COMPR, }; +/* define a bit for each mixer input */ +#define SST_MIX_IP(x) (x) + +#define SST_IP_CODEC0 SST_MIX_IP(2) +#define SST_IP_CODEC1 SST_MIX_IP(3) +#define SST_IP_LOOP0 SST_MIX_IP(4) +#define SST_IP_LOOP1 SST_MIX_IP(5) +#define SST_IP_LOOP2 SST_MIX_IP(6) +#define SST_IP_PROBE SST_MIX_IP(7) +#define SST_IP_VOIP SST_MIX_IP(12) +#define SST_IP_PCM0 SST_MIX_IP(13) +#define SST_IP_PCM1 SST_MIX_IP(14) +#define SST_IP_MEDIA0 SST_MIX_IP(17) +#define SST_IP_MEDIA1 SST_MIX_IP(18) +#define SST_IP_MEDIA2 SST_MIX_IP(19) +#define SST_IP_MEDIA3 SST_MIX_IP(20) + +#define SST_IP_LAST SST_IP_MEDIA3 + +#define SST_SWM_INPUT_COUNT (SST_IP_LAST + 1) +#define SST_CMD_SWM_MAX_INPUTS 6 + +#define SST_PATH_ID_SHIFT 8 +#define SST_DEFAULT_LOCATION_ID 0xFFFF +#define SST_DEFAULT_CELL_NBR 0xFF +#define SST_DEFAULT_MODULE_ID 0xFFFF + +/* + * Audio DSP Path Ids. Specified by the audio DSP FW + */ +enum sst_path_index { + SST_PATH_INDEX_CODEC_OUT0 = (0x02 << SST_PATH_ID_SHIFT), + SST_PATH_INDEX_CODEC_OUT1 = (0x03 << SST_PATH_ID_SHIFT), + + SST_PATH_INDEX_SPROT_LOOP_OUT = (0x04 << SST_PATH_ID_SHIFT), + SST_PATH_INDEX_MEDIA_LOOP1_OUT = (0x05 << SST_PATH_ID_SHIFT), + SST_PATH_INDEX_MEDIA_LOOP2_OUT = (0x06 << SST_PATH_ID_SHIFT), + + SST_PATH_INDEX_VOIP_OUT = (0x0C << SST_PATH_ID_SHIFT), + SST_PATH_INDEX_PCM0_OUT = (0x0D << SST_PATH_ID_SHIFT), + SST_PATH_INDEX_PCM1_OUT = (0x0E << SST_PATH_ID_SHIFT), + SST_PATH_INDEX_PCM2_OUT = (0x0F << SST_PATH_ID_SHIFT), + + SST_PATH_INDEX_MEDIA0_OUT = (0x12 << SST_PATH_ID_SHIFT), + SST_PATH_INDEX_MEDIA1_OUT = (0x13 << SST_PATH_ID_SHIFT), + + + /* Start of input paths */ + SST_PATH_INDEX_CODEC_IN0 = (0x82 << SST_PATH_ID_SHIFT), + SST_PATH_INDEX_CODEC_IN1 = (0x83 << SST_PATH_ID_SHIFT), + + SST_PATH_INDEX_SPROT_LOOP_IN = (0x84 << SST_PATH_ID_SHIFT), + SST_PATH_INDEX_MEDIA_LOOP1_IN = (0x85 << SST_PATH_ID_SHIFT), + SST_PATH_INDEX_MEDIA_LOOP2_IN = (0x86 << SST_PATH_ID_SHIFT), + + SST_PATH_INDEX_VOIP_IN = (0x8C << SST_PATH_ID_SHIFT), + + SST_PATH_INDEX_PCM0_IN = (0x8D << SST_PATH_ID_SHIFT), + SST_PATH_INDEX_PCM1_IN = (0x8E << SST_PATH_ID_SHIFT), + + SST_PATH_INDEX_MEDIA0_IN = (0x8F << SST_PATH_ID_SHIFT), + SST_PATH_INDEX_MEDIA1_IN = (0x90 << SST_PATH_ID_SHIFT), + SST_PATH_INDEX_MEDIA2_IN = (0x91 << SST_PATH_ID_SHIFT), + + SST_PATH_INDEX_MEDIA3_IN = (0x9C << SST_PATH_ID_SHIFT), + + SST_PATH_INDEX_RESERVED = (0xFF << SST_PATH_ID_SHIFT), +}; + +/* + * path IDs + */ +enum sst_swm_inputs { + SST_SWM_IN_CODEC0 = (SST_PATH_INDEX_CODEC_IN0 | SST_DEFAULT_CELL_NBR), + SST_SWM_IN_CODEC1 = (SST_PATH_INDEX_CODEC_IN1 | SST_DEFAULT_CELL_NBR), + SST_SWM_IN_SPROT_LOOP = (SST_PATH_INDEX_SPROT_LOOP_IN | SST_DEFAULT_CELL_NBR), + SST_SWM_IN_MEDIA_LOOP1 = (SST_PATH_INDEX_MEDIA_LOOP1_IN | SST_DEFAULT_CELL_NBR), + SST_SWM_IN_MEDIA_LOOP2 = (SST_PATH_INDEX_MEDIA_LOOP2_IN | SST_DEFAULT_CELL_NBR), + SST_SWM_IN_VOIP = (SST_PATH_INDEX_VOIP_IN | SST_DEFAULT_CELL_NBR), + SST_SWM_IN_PCM0 = (SST_PATH_INDEX_PCM0_IN | SST_DEFAULT_CELL_NBR), + SST_SWM_IN_PCM1 = (SST_PATH_INDEX_PCM1_IN | SST_DEFAULT_CELL_NBR), + SST_SWM_IN_MEDIA0 = (SST_PATH_INDEX_MEDIA0_IN | SST_DEFAULT_CELL_NBR), /* Part of Media Mixer */ + SST_SWM_IN_MEDIA1 = (SST_PATH_INDEX_MEDIA1_IN | SST_DEFAULT_CELL_NBR), /* Part of Media Mixer */ + SST_SWM_IN_MEDIA2 = (SST_PATH_INDEX_MEDIA2_IN | SST_DEFAULT_CELL_NBR), /* Part of Media Mixer */ + SST_SWM_IN_MEDIA3 = (SST_PATH_INDEX_MEDIA3_IN | SST_DEFAULT_CELL_NBR), /* Part of Media Mixer */ + SST_SWM_IN_END = (SST_PATH_INDEX_RESERVED | SST_DEFAULT_CELL_NBR) +}; + +/* + * path IDs + */ +enum sst_swm_outputs { + SST_SWM_OUT_CODEC0 = (SST_PATH_INDEX_CODEC_OUT0 | SST_DEFAULT_CELL_NBR), + SST_SWM_OUT_CODEC1 = (SST_PATH_INDEX_CODEC_OUT1 | SST_DEFAULT_CELL_NBR), + SST_SWM_OUT_SPROT_LOOP = (SST_PATH_INDEX_SPROT_LOOP_OUT | SST_DEFAULT_CELL_NBR), + SST_SWM_OUT_MEDIA_LOOP1 = (SST_PATH_INDEX_MEDIA_LOOP1_OUT | SST_DEFAULT_CELL_NBR), + SST_SWM_OUT_MEDIA_LOOP2 = (SST_PATH_INDEX_MEDIA_LOOP2_OUT | SST_DEFAULT_CELL_NBR), + SST_SWM_OUT_VOIP = (SST_PATH_INDEX_VOIP_OUT | SST_DEFAULT_CELL_NBR), + SST_SWM_OUT_PCM0 = (SST_PATH_INDEX_PCM0_OUT | SST_DEFAULT_CELL_NBR), + SST_SWM_OUT_PCM1 = (SST_PATH_INDEX_PCM1_OUT | SST_DEFAULT_CELL_NBR), + SST_SWM_OUT_PCM2 = (SST_PATH_INDEX_PCM2_OUT | SST_DEFAULT_CELL_NBR), + SST_SWM_OUT_MEDIA0 = (SST_PATH_INDEX_MEDIA0_OUT | SST_DEFAULT_CELL_NBR), /* Part of Media Mixer */ + SST_SWM_OUT_MEDIA1 = (SST_PATH_INDEX_MEDIA1_OUT | SST_DEFAULT_CELL_NBR), /* Part of Media Mixer */ + SST_SWM_OUT_END = (SST_PATH_INDEX_RESERVED | SST_DEFAULT_CELL_NBR), +}; + +enum sst_ipc_msg { + SST_IPC_IA_CMD = 1, + SST_IPC_IA_SET_PARAMS, + SST_IPC_IA_GET_PARAMS, +}; + +enum sst_cmd_type { + SST_CMD_BYTES_SET = 1, + SST_CMD_BYTES_GET = 2, +}; + +enum sst_task { + SST_TASK_SBA = 1, + SST_TASK_MMX, +}; + +enum sst_type { + SST_TYPE_CMD = 1, + SST_TYPE_PARAMS, +}; + +enum sst_flag { + SST_FLAG_BLOCKED = 1, + SST_FLAG_NONBLOCK, +}; + +/* + * Enumeration for indexing the gain cells in VB_SET_GAIN DSP command + */ +enum sst_gain_index { + /* GAIN IDs for SB task start here */ + SST_GAIN_INDEX_CODEC_OUT0, + SST_GAIN_INDEX_CODEC_OUT1, + SST_GAIN_INDEX_CODEC_IN0, + SST_GAIN_INDEX_CODEC_IN1, + + SST_GAIN_INDEX_SPROT_LOOP_OUT, + SST_GAIN_INDEX_MEDIA_LOOP1_OUT, + SST_GAIN_INDEX_MEDIA_LOOP2_OUT, + + SST_GAIN_INDEX_PCM0_IN_LEFT, + SST_GAIN_INDEX_PCM0_IN_RIGHT, + + SST_GAIN_INDEX_PCM1_OUT_LEFT, + SST_GAIN_INDEX_PCM1_OUT_RIGHT, + SST_GAIN_INDEX_PCM1_IN_LEFT, + SST_GAIN_INDEX_PCM1_IN_RIGHT, + SST_GAIN_INDEX_PCM2_OUT_LEFT, + + SST_GAIN_INDEX_PCM2_OUT_RIGHT, + SST_GAIN_INDEX_VOIP_OUT, + SST_GAIN_INDEX_VOIP_IN, + + /* Gain IDs for MMX task start here */ + SST_GAIN_INDEX_MEDIA0_IN_LEFT, + SST_GAIN_INDEX_MEDIA0_IN_RIGHT, + SST_GAIN_INDEX_MEDIA1_IN_LEFT, + SST_GAIN_INDEX_MEDIA1_IN_RIGHT, + + SST_GAIN_INDEX_MEDIA2_IN_LEFT, + SST_GAIN_INDEX_MEDIA2_IN_RIGHT, + + SST_GAIN_INDEX_GAIN_END +}; + +/* + * Audio DSP module IDs specified by FW spec + * TODO: Update with all modules + */ +enum sst_module_id { + SST_MODULE_ID_PCM = 0x0001, + SST_MODULE_ID_MP3 = 0x0002, + SST_MODULE_ID_MP24 = 0x0003, + SST_MODULE_ID_AAC = 0x0004, + SST_MODULE_ID_AACP = 0x0005, + SST_MODULE_ID_EAACP = 0x0006, + SST_MODULE_ID_WMA9 = 0x0007, + SST_MODULE_ID_WMA10 = 0x0008, + SST_MODULE_ID_WMA10P = 0x0009, + SST_MODULE_ID_RA = 0x000A, + SST_MODULE_ID_DDAC3 = 0x000B, + SST_MODULE_ID_TRUE_HD = 0x000C, + SST_MODULE_ID_HD_PLUS = 0x000D, + + SST_MODULE_ID_SRC = 0x0064, + SST_MODULE_ID_DOWNMIX = 0x0066, + SST_MODULE_ID_GAIN_CELL = 0x0067, + SST_MODULE_ID_SPROT = 0x006D, + SST_MODULE_ID_BASS_BOOST = 0x006E, + SST_MODULE_ID_STEREO_WDNG = 0x006F, + SST_MODULE_ID_AV_REMOVAL = 0x0070, + SST_MODULE_ID_MIC_EQ = 0x0071, + SST_MODULE_ID_SPL = 0x0072, + SST_MODULE_ID_ALGO_VTSV = 0x0073, + SST_MODULE_ID_NR = 0x0076, + SST_MODULE_ID_BWX = 0x0077, + SST_MODULE_ID_DRP = 0x0078, + SST_MODULE_ID_MDRP = 0x0079, + + SST_MODULE_ID_ANA = 0x007A, + SST_MODULE_ID_AEC = 0x007B, + SST_MODULE_ID_NR_SNS = 0x007C, + SST_MODULE_ID_SER = 0x007D, + SST_MODULE_ID_AGC = 0x007E, + + SST_MODULE_ID_CNI = 0x007F, + SST_MODULE_ID_CONTEXT_ALGO_AWARE = 0x0080, + SST_MODULE_ID_FIR_24 = 0x0081, + SST_MODULE_ID_IIR_24 = 0x0082, + + SST_MODULE_ID_ASRC = 0x0083, + SST_MODULE_ID_TONE_GEN = 0x0084, + SST_MODULE_ID_BMF = 0x0086, + SST_MODULE_ID_EDL = 0x0087, + SST_MODULE_ID_GLC = 0x0088, + + SST_MODULE_ID_FIR_16 = 0x0089, + SST_MODULE_ID_IIR_16 = 0x008A, + SST_MODULE_ID_DNR = 0x008B, + + SST_MODULE_ID_VIRTUALIZER = 0x008C, + SST_MODULE_ID_VISUALIZATION = 0x008D, + SST_MODULE_ID_LOUDNESS_OPTIMIZER = 0x008E, + SST_MODULE_ID_REVERBERATION = 0x008F, + + SST_MODULE_ID_CNI_TX = 0x0090, + SST_MODULE_ID_REF_LINE = 0x0091, + SST_MODULE_ID_VOLUME = 0x0092, + SST_MODULE_ID_FILT_DCR = 0x0094, + SST_MODULE_ID_SLV = 0x009A, + SST_MODULE_ID_NLF = 0x009B, + SST_MODULE_ID_TNR = 0x009C, + SST_MODULE_ID_WNR = 0x009D, + + SST_MODULE_ID_LOG = 0xFF00, + + SST_MODULE_ID_TASK = 0xFFFF, +}; + +enum sst_cmd { + SBA_IDLE = 14, + SBA_VB_SET_SPEECH_PATH = 26, + MMX_SET_GAIN = 33, + SBA_VB_SET_GAIN = 33, + FBA_VB_RX_CNI = 35, + MMX_SET_GAIN_TIMECONST = 36, + SBA_VB_SET_TIMECONST = 36, + SBA_VB_START = 85, + SBA_SET_SWM = 114, + SBA_SET_MDRP = 116, + SBA_HW_SET_SSP = 117, + SBA_SET_MEDIA_LOOP_MAP = 118, + SBA_SET_MEDIA_PATH = 119, + MMX_SET_MEDIA_PATH = 119, + SBA_VB_LPRO = 126, + SBA_VB_SET_FIR = 128, + SBA_VB_SET_IIR = 129, + SBA_SET_SSP_SLOT_MAP = 130, +}; + +enum sst_dsp_switch { + SST_SWITCH_OFF = 0, + SST_SWITCH_ON = 3, +}; + +enum sst_path_switch { + SST_PATH_OFF = 0, + SST_PATH_ON = 1, +}; + +enum sst_swm_state { + SST_SWM_OFF = 0, + SST_SWM_ON = 3, +}; + +#define SST_FILL_LOCATION_IDS(dst, cell_idx, pipe_id) do { \ + dst.location_id.p.cell_nbr_idx = (cell_idx); \ + dst.location_id.p.path_id = (pipe_id); \ + } while (0) +#define SST_FILL_LOCATION_ID(dst, loc_id) (\ + dst.location_id.f = (loc_id)) +#define SST_FILL_MODULE_ID(dst, mod_id) (\ + dst.module_id = (mod_id)) + +#define SST_FILL_DESTINATION1(dst, id) do { \ + SST_FILL_LOCATION_ID(dst, (id) & 0xFFFF); \ + SST_FILL_MODULE_ID(dst, ((id) & 0xFFFF0000) >> 16); \ + } while (0) +#define SST_FILL_DESTINATION2(dst, loc_id, mod_id) do { \ + SST_FILL_LOCATION_ID(dst, loc_id); \ + SST_FILL_MODULE_ID(dst, mod_id); \ + } while (0) +#define SST_FILL_DESTINATION3(dst, cell_idx, path_id, mod_id) do { \ + SST_FILL_LOCATION_IDS(dst, cell_idx, path_id); \ + SST_FILL_MODULE_ID(dst, mod_id); \ + } while (0) + +#define SST_FILL_DESTINATION(level, dst, ...) \ + SST_FILL_DESTINATION##level(dst, __VA_ARGS__) +#define SST_FILL_DEFAULT_DESTINATION(dst) \ + SST_FILL_DESTINATION(2, dst, SST_DEFAULT_LOCATION_ID, SST_DEFAULT_MODULE_ID) + +struct sst_destination_id { + union sst_location_id { + struct { + u8 cell_nbr_idx; /* module index */ + u8 path_id; /* pipe_id */ + } __packed p; /* part */ + u16 f; /* full */ + } __packed location_id; + u16 module_id; +} __packed; +struct sst_dsp_header { + struct sst_destination_id dst; + u16 command_id; + u16 length; +} __packed; + +/* + * + * Common Commands + * + */ +struct sst_cmd_generic { + struct sst_dsp_header header; +} __packed; +struct sst_cmd_set_params { + struct sst_destination_id dst; + u16 command_id; + char params[0]; +} __packed; +#define SST_CONTROL_NAME(xpname, xmname, xinstance, xtype) \ + xpname " " xmname " " #xinstance " " xtype + +#define SST_COMBO_CONTROL_NAME(xpname, xmname, xinstance, xtype, xsubmodule) \ + xpname " " xmname " " #xinstance " " xtype " " xsubmodule +enum sst_algo_kcontrol_type { + SST_ALGO_PARAMS, + SST_ALGO_BYPASS, +}; + +struct sst_algo_control { + enum sst_algo_kcontrol_type type; + int max; + u16 module_id; + u16 pipe_id; + u16 task_id; + u16 cmd_id; + bool bypass; + unsigned char *params; + struct snd_soc_dapm_widget *w; +}; + +/* size of the control = size of params + size of length field */ +#define SST_ALGO_CTL_VALUE(xcount, xtype, xpipe, xmod, xtask, xcmd) \ + (struct sst_algo_control){ \ + .max = xcount + sizeof(u16), .type = xtype, .module_id = xmod, \ + .pipe_id = xpipe, .task_id = xtask, .cmd_id = xcmd, \ + } + +#define SST_ALGO_KCONTROL(xname, xcount, xmod, xpipe, \ + xtask, xcmd, xtype, xinfo, xget, xput) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .info = xinfo, .get = xget, .put = xput, \ + .private_value = (unsigned long)& \ + SST_ALGO_CTL_VALUE(xcount, xtype, xpipe, \ + xmod, xtask, xcmd), \ +} + +#define SST_ALGO_KCONTROL_BYTES(xpname, xmname, xcount, xmod, \ + xpipe, xinstance, xtask, xcmd) \ + SST_ALGO_KCONTROL(SST_CONTROL_NAME(xpname, xmname, xinstance, "params"), \ + xcount, xmod, xpipe, xtask, xcmd, SST_ALGO_PARAMS, \ + sst_algo_bytes_ctl_info, \ + sst_algo_control_get, sst_algo_control_set) + +#define SST_ALGO_KCONTROL_BOOL(xpname, xmname, xmod, xpipe, xinstance, xtask) \ + SST_ALGO_KCONTROL(SST_CONTROL_NAME(xpname, xmname, xinstance, "bypass"), \ + 0, xmod, xpipe, xtask, 0, SST_ALGO_BYPASS, \ + snd_soc_info_bool_ext, \ + sst_algo_control_get, sst_algo_control_set) + +#define SST_ALGO_BYPASS_PARAMS(xpname, xmname, xcount, xmod, xpipe, \ + xinstance, xtask, xcmd) \ + SST_ALGO_KCONTROL_BOOL(xpname, xmname, xmod, xpipe, xinstance, xtask), \ + SST_ALGO_KCONTROL_BYTES(xpname, xmname, xcount, xmod, xpipe, xinstance, xtask, xcmd) + +#define SST_COMBO_ALGO_KCONTROL_BYTES(xpname, xmname, xsubmod, xcount, xmod, \ + xpipe, xinstance, xtask, xcmd) \ + SST_ALGO_KCONTROL(SST_COMBO_CONTROL_NAME(xpname, xmname, xinstance, "params", \ + xsubmod), \ + xcount, xmod, xpipe, xtask, xcmd, SST_ALGO_PARAMS, \ + sst_algo_bytes_ctl_info, \ + sst_algo_control_get, sst_algo_control_set) + + +struct sst_enum { + bool tx; + unsigned short reg; + unsigned int max; + const char * const *texts; + struct snd_soc_dapm_widget *w; +}; #endif diff --git a/sound/soc/intel/sst-baytrail-ipc.c b/sound/soc/intel/sst-baytrail-ipc.c index 67673a2c0f41..b4ad98c43e5c 100644 --- a/sound/soc/intel/sst-baytrail-ipc.c +++ b/sound/soc/intel/sst-baytrail-ipc.c @@ -817,7 +817,7 @@ static struct sst_dsp_device byt_dev = { .ops = &sst_byt_ops, }; -int sst_byt_dsp_suspend_noirq(struct device *dev, struct sst_pdata *pdata) +int sst_byt_dsp_suspend_late(struct device *dev, struct sst_pdata *pdata) { struct sst_byt *byt = pdata->dsp; @@ -826,14 +826,6 @@ int sst_byt_dsp_suspend_noirq(struct device *dev, struct sst_pdata *pdata) sst_byt_drop_all(byt); dev_dbg(byt->dev, "dsp in reset\n"); - return 0; -} -EXPORT_SYMBOL_GPL(sst_byt_dsp_suspend_noirq); - -int sst_byt_dsp_suspend_late(struct device *dev, struct sst_pdata *pdata) -{ - struct sst_byt *byt = pdata->dsp; - dev_dbg(byt->dev, "free all blocks and unload fw\n"); sst_fw_unload(byt->fw); diff --git a/sound/soc/intel/sst-baytrail-ipc.h b/sound/soc/intel/sst-baytrail-ipc.h index 06a4d202689b..8faff6dcf25d 100644 --- a/sound/soc/intel/sst-baytrail-ipc.h +++ b/sound/soc/intel/sst-baytrail-ipc.h @@ -66,7 +66,6 @@ int sst_byt_get_dsp_position(struct sst_byt *byt, int sst_byt_dsp_init(struct device *dev, struct sst_pdata *pdata); void sst_byt_dsp_free(struct device *dev, struct sst_pdata *pdata); struct sst_dsp *sst_byt_get_dsp(struct sst_byt *byt); -int sst_byt_dsp_suspend_noirq(struct device *dev, struct sst_pdata *pdata); int sst_byt_dsp_suspend_late(struct device *dev, struct sst_pdata *pdata); int sst_byt_dsp_boot(struct device *dev, struct sst_pdata *pdata); int sst_byt_dsp_wait_for_ready(struct device *dev, struct sst_pdata *pdata); diff --git a/sound/soc/intel/sst-baytrail-pcm.c b/sound/soc/intel/sst-baytrail-pcm.c index 599401c0c655..eab1c7d85187 100644 --- a/sound/soc/intel/sst-baytrail-pcm.c +++ b/sound/soc/intel/sst-baytrail-pcm.c @@ -59,6 +59,9 @@ struct sst_byt_priv_data { /* DAI data */ struct sst_byt_pcm_data pcm[BYT_PCM_COUNT]; + + /* flag indicating is stream context restore needed after suspend */ + bool restore_stream; }; /* this may get called several times by oss emulation */ @@ -184,7 +187,10 @@ static int sst_byt_pcm_trigger(struct snd_pcm_substream *substream, int cmd) sst_byt_stream_start(byt, pcm_data->stream, 0); break; case SNDRV_PCM_TRIGGER_RESUME: - schedule_work(&pcm_data->work); + if (pdata->restore_stream == true) + schedule_work(&pcm_data->work); + else + sst_byt_stream_resume(byt, pcm_data->stream); break; case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: sst_byt_stream_resume(byt, pcm_data->stream); @@ -193,6 +199,7 @@ static int sst_byt_pcm_trigger(struct snd_pcm_substream *substream, int cmd) sst_byt_stream_stop(byt, pcm_data->stream); break; case SNDRV_PCM_TRIGGER_SUSPEND: + pdata->restore_stream = false; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: sst_byt_stream_pause(byt, pcm_data->stream); break; @@ -404,26 +411,10 @@ static const struct snd_soc_component_driver byt_dai_component = { }; #ifdef CONFIG_PM -static int sst_byt_pcm_dev_suspend_noirq(struct device *dev) -{ - struct sst_pdata *sst_pdata = dev_get_platdata(dev); - int ret; - - dev_dbg(dev, "suspending noirq\n"); - - /* at this point all streams will be stopped and context saved */ - ret = sst_byt_dsp_suspend_noirq(dev, sst_pdata); - if (ret < 0) { - dev_err(dev, "failed to suspend %d\n", ret); - return ret; - } - - return ret; -} - static int sst_byt_pcm_dev_suspend_late(struct device *dev) { struct sst_pdata *sst_pdata = dev_get_platdata(dev); + struct sst_byt_priv_data *priv_data = dev_get_drvdata(dev); int ret; dev_dbg(dev, "suspending late\n"); @@ -434,34 +425,30 @@ static int sst_byt_pcm_dev_suspend_late(struct device *dev) return ret; } + priv_data->restore_stream = true; + return ret; } static int sst_byt_pcm_dev_resume_early(struct device *dev) { struct sst_pdata *sst_pdata = dev_get_platdata(dev); + int ret; dev_dbg(dev, "resume early\n"); /* load fw and boot DSP */ - return sst_byt_dsp_boot(dev, sst_pdata); -} - -static int sst_byt_pcm_dev_resume(struct device *dev) -{ - struct sst_pdata *sst_pdata = dev_get_platdata(dev); - - dev_dbg(dev, "resume\n"); + ret = sst_byt_dsp_boot(dev, sst_pdata); + if (ret) + return ret; /* wait for FW to finish booting */ return sst_byt_dsp_wait_for_ready(dev, sst_pdata); } static const struct dev_pm_ops sst_byt_pm_ops = { - .suspend_noirq = sst_byt_pcm_dev_suspend_noirq, .suspend_late = sst_byt_pcm_dev_suspend_late, .resume_early = sst_byt_pcm_dev_resume_early, - .resume = sst_byt_pcm_dev_resume, }; #define SST_BYT_PM_OPS (&sst_byt_pm_ops) diff --git a/sound/soc/intel/sst-haswell-pcm.c b/sound/soc/intel/sst-haswell-pcm.c index 61bf6da4bb02..33fc5c3abf55 100644 --- a/sound/soc/intel/sst-haswell-pcm.c +++ b/sound/soc/intel/sst-haswell-pcm.c @@ -138,11 +138,10 @@ static inline unsigned int hsw_ipc_to_mixer(u32 value) static int hsw_stream_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol); + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct hsw_priv_data *pdata = snd_soc_component_get_drvdata(cmpnt); struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; - struct hsw_priv_data *pdata = - snd_soc_platform_get_drvdata(platform); struct hsw_pcm_data *pcm_data = &pdata->pcm[mc->reg]; struct sst_hsw *hsw = pdata->hsw; u32 volume; @@ -176,11 +175,10 @@ static int hsw_stream_volume_put(struct snd_kcontrol *kcontrol, static int hsw_stream_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol); + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct hsw_priv_data *pdata = snd_soc_component_get_drvdata(cmpnt); struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; - struct hsw_priv_data *pdata = - snd_soc_platform_get_drvdata(platform); struct hsw_pcm_data *pcm_data = &pdata->pcm[mc->reg]; struct sst_hsw *hsw = pdata->hsw; u32 volume; @@ -208,8 +206,8 @@ static int hsw_stream_volume_get(struct snd_kcontrol *kcontrol, static int hsw_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol); - struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform); + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct hsw_priv_data *pdata = snd_soc_component_get_drvdata(cmpnt); struct sst_hsw *hsw = pdata->hsw; u32 volume; @@ -233,8 +231,8 @@ static int hsw_volume_put(struct snd_kcontrol *kcontrol, static int hsw_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol); - struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform); + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct hsw_priv_data *pdata = snd_soc_component_get_drvdata(cmpnt); struct sst_hsw *hsw = pdata->hsw; unsigned int volume = 0; @@ -778,20 +776,11 @@ static const struct snd_soc_dapm_route graph[] = { static int hsw_pcm_probe(struct snd_soc_platform *platform) { + struct hsw_priv_data *priv_data = snd_soc_platform_get_drvdata(platform); struct sst_pdata *pdata = dev_get_platdata(platform->dev); - struct hsw_priv_data *priv_data; - struct device *dma_dev; + struct device *dma_dev = pdata->dma_dev; int i, ret = 0; - if (!pdata) - return -ENODEV; - - dma_dev = pdata->dma_dev; - - priv_data = devm_kzalloc(platform->dev, sizeof(*priv_data), GFP_KERNEL); - priv_data->hsw = pdata->dsp; - snd_soc_platform_set_drvdata(platform, priv_data); - /* allocate DSP buffer page tables */ for (i = 0; i < ARRAY_SIZE(hsw_dais); i++) { @@ -848,27 +837,38 @@ static struct snd_soc_platform_driver hsw_soc_platform = { .ops = &hsw_pcm_ops, .pcm_new = hsw_pcm_new, .pcm_free = hsw_pcm_free, - .controls = hsw_volume_controls, - .num_controls = ARRAY_SIZE(hsw_volume_controls), - .dapm_widgets = widgets, - .num_dapm_widgets = ARRAY_SIZE(widgets), - .dapm_routes = graph, - .num_dapm_routes = ARRAY_SIZE(graph), }; static const struct snd_soc_component_driver hsw_dai_component = { - .name = "haswell-dai", + .name = "haswell-dai", + .controls = hsw_volume_controls, + .num_controls = ARRAY_SIZE(hsw_volume_controls), + .dapm_widgets = widgets, + .num_dapm_widgets = ARRAY_SIZE(widgets), + .dapm_routes = graph, + .num_dapm_routes = ARRAY_SIZE(graph), }; static int hsw_pcm_dev_probe(struct platform_device *pdev) { struct sst_pdata *sst_pdata = dev_get_platdata(&pdev->dev); + struct hsw_priv_data *priv_data; int ret; + if (!sst_pdata) + return -EINVAL; + + priv_data = devm_kzalloc(&pdev->dev, sizeof(*priv_data), GFP_KERNEL); + if (!priv_data) + return -ENOMEM; + ret = sst_hsw_dsp_init(&pdev->dev, sst_pdata); if (ret < 0) return -ENODEV; + priv_data->hsw = sst_pdata->dsp; + platform_set_drvdata(pdev, priv_data); + ret = snd_soc_register_platform(&pdev->dev, &hsw_soc_platform); if (ret < 0) goto err_plat; diff --git a/sound/soc/intel/sst-mfld-platform-compress.c b/sound/soc/intel/sst-mfld-platform-compress.c index 29c059ca19e8..59467775c9b8 100644 --- a/sound/soc/intel/sst-mfld-platform-compress.c +++ b/sound/soc/intel/sst-mfld-platform-compress.c @@ -86,7 +86,7 @@ static int sst_platform_compr_free(struct snd_compr_stream *cstream) /*need to check*/ str_id = stream->id; if (str_id) - ret_val = stream->compr_ops->close(str_id); + ret_val = stream->compr_ops->close(sst->dev, str_id); module_put(sst->dev->driver->owner); kfree(stream); pr_debug("%s: %d\n", __func__, ret_val); @@ -158,7 +158,7 @@ static int sst_platform_compr_set_params(struct snd_compr_stream *cstream, cb.drain_cb_param = cstream; cb.drain_notify = sst_drain_notify; - retval = stream->compr_ops->open(&str_params, &cb); + retval = stream->compr_ops->open(sst->dev, &str_params, &cb); if (retval < 0) { pr_err("stream allocation failed %d\n", retval); return retval; @@ -170,10 +170,30 @@ static int sst_platform_compr_set_params(struct snd_compr_stream *cstream, static int sst_platform_compr_trigger(struct snd_compr_stream *cstream, int cmd) { - struct sst_runtime_stream *stream = - cstream->runtime->private_data; - - return stream->compr_ops->control(cmd, stream->id); + struct sst_runtime_stream *stream = cstream->runtime->private_data; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + if (stream->compr_ops->stream_start) + return stream->compr_ops->stream_start(sst->dev, stream->id); + case SNDRV_PCM_TRIGGER_STOP: + if (stream->compr_ops->stream_drop) + return stream->compr_ops->stream_drop(sst->dev, stream->id); + case SND_COMPR_TRIGGER_DRAIN: + if (stream->compr_ops->stream_drain) + return stream->compr_ops->stream_drain(sst->dev, stream->id); + case SND_COMPR_TRIGGER_PARTIAL_DRAIN: + if (stream->compr_ops->stream_partial_drain) + return stream->compr_ops->stream_partial_drain(sst->dev, stream->id); + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + if (stream->compr_ops->stream_pause) + return stream->compr_ops->stream_pause(sst->dev, stream->id); + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + if (stream->compr_ops->stream_pause_release) + return stream->compr_ops->stream_pause_release(sst->dev, stream->id); + default: + return -EINVAL; + } } static int sst_platform_compr_pointer(struct snd_compr_stream *cstream, @@ -182,7 +202,7 @@ static int sst_platform_compr_pointer(struct snd_compr_stream *cstream, struct sst_runtime_stream *stream; stream = cstream->runtime->private_data; - stream->compr_ops->tstamp(stream->id, tstamp); + stream->compr_ops->tstamp(sst->dev, stream->id, tstamp); tstamp->byte_offset = tstamp->copied_total % (u32)cstream->runtime->buffer_size; pr_debug("calc bytes offset/copied bytes as %d\n", tstamp->byte_offset); @@ -195,7 +215,7 @@ static int sst_platform_compr_ack(struct snd_compr_stream *cstream, struct sst_runtime_stream *stream; stream = cstream->runtime->private_data; - stream->compr_ops->ack(stream->id, (unsigned long)bytes); + stream->compr_ops->ack(sst->dev, stream->id, (unsigned long)bytes); stream->bytes_written += bytes; return 0; @@ -225,7 +245,7 @@ static int sst_platform_compr_set_metadata(struct snd_compr_stream *cstream, struct sst_runtime_stream *stream = cstream->runtime->private_data; - return stream->compr_ops->set_metadata(stream->id, metadata); + return stream->compr_ops->set_metadata(sst->dev, stream->id, metadata); } struct snd_compr_ops sst_platform_compr_ops = { diff --git a/sound/soc/intel/sst-mfld-platform-pcm.c b/sound/soc/intel/sst-mfld-platform-pcm.c index 706212a6a68c..aa9b600dfc9b 100644 --- a/sound/soc/intel/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/sst-mfld-platform-pcm.c @@ -43,12 +43,12 @@ int sst_register_dsp(struct sst_device *dev) return -ENODEV; mutex_lock(&sst_lock); if (sst) { - pr_err("we already have a device %s\n", sst->name); + dev_err(dev->dev, "we already have a device %s\n", sst->name); module_put(dev->dev->driver->owner); mutex_unlock(&sst_lock); return -EEXIST; } - pr_debug("registering device %s\n", dev->name); + dev_dbg(dev->dev, "registering device %s\n", dev->name); sst = dev; mutex_unlock(&sst_lock); return 0; @@ -70,7 +70,7 @@ int sst_unregister_dsp(struct sst_device *dev) } module_put(sst->dev->driver->owner); - pr_debug("unreg %s\n", sst->name); + dev_dbg(dev->dev, "unreg %s\n", sst->name); sst = NULL; mutex_unlock(&sst_lock); return 0; @@ -252,7 +252,7 @@ int sst_fill_stream_params(void *substream, } static int sst_platform_alloc_stream(struct snd_pcm_substream *substream, - struct snd_soc_platform *platform) + struct snd_soc_dai *dai) { struct sst_runtime_stream *stream = substream->runtime->private_data; @@ -260,7 +260,7 @@ static int sst_platform_alloc_stream(struct snd_pcm_substream *substream, struct snd_sst_params str_params = {0}; struct snd_sst_alloc_params_ext alloc_params = {0}; int ret_val = 0; - struct sst_data *ctx = snd_soc_platform_get_drvdata(platform); + struct sst_data *ctx = snd_soc_dai_get_drvdata(dai); /* set codec params and inform SST driver the same */ sst_fill_pcm_params(substream, ¶m); @@ -277,7 +277,7 @@ static int sst_platform_alloc_stream(struct snd_pcm_substream *substream, stream->stream_info.str_id = str_params.stream_id; - ret_val = stream->ops->open(&str_params); + ret_val = stream->ops->open(sst->dev, &str_params); if (ret_val <= 0) return ret_val; @@ -306,22 +306,31 @@ static int sst_platform_init_stream(struct snd_pcm_substream *substream) { struct sst_runtime_stream *stream = substream->runtime->private_data; + struct snd_soc_pcm_runtime *rtd = substream->private_data; int ret_val; - pr_debug("setting buffer ptr param\n"); + dev_dbg(rtd->dev, "setting buffer ptr param\n"); sst_set_stream_status(stream, SST_PLATFORM_INIT); stream->stream_info.period_elapsed = sst_period_elapsed; stream->stream_info.arg = substream; stream->stream_info.buffer_ptr = 0; stream->stream_info.sfreq = substream->runtime->rate; - ret_val = stream->ops->device_control( - SST_SND_STREAM_INIT, &stream->stream_info); + ret_val = stream->ops->stream_init(sst->dev, &stream->stream_info); if (ret_val) - pr_err("control_set ret error %d\n", ret_val); + dev_err(rtd->dev, "control_set ret error %d\n", ret_val); return ret_val; } -/* end -- helper functions */ + +static int power_up_sst(struct sst_runtime_stream *stream) +{ + return stream->ops->power(sst->dev, true); +} + +static void power_down_sst(struct sst_runtime_stream *stream) +{ + stream->ops->power(sst->dev, false); +} static int sst_media_open(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) @@ -339,7 +348,7 @@ static int sst_media_open(struct snd_pcm_substream *substream, mutex_lock(&sst_lock); if (!sst || !try_module_get(sst->dev->driver->owner)) { - pr_err("no device available to run\n"); + dev_err(dai->dev, "no device available to run\n"); ret_val = -ENODEV; goto out_ops; } @@ -352,6 +361,10 @@ static int sst_media_open(struct snd_pcm_substream *substream, /* allocate memory for SST API set */ runtime->private_data = stream; + ret_val = power_up_sst(stream); + if (ret_val < 0) + return ret_val; + /* Make sure, that the period size is always even */ snd_pcm_hw_constraint_step(substream->runtime, 0, SNDRV_PCM_HW_PARAM_PERIODS, 2); @@ -371,26 +384,29 @@ static void sst_media_close(struct snd_pcm_substream *substream, int ret_val = 0, str_id; stream = substream->runtime->private_data; + power_down_sst(stream); + str_id = stream->stream_info.str_id; if (str_id) - ret_val = stream->ops->close(str_id); + ret_val = stream->ops->close(sst->dev, str_id); module_put(sst->dev->driver->owner); kfree(stream); } -static inline unsigned int get_current_pipe_id(struct snd_soc_platform *platform, +static inline unsigned int get_current_pipe_id(struct snd_soc_dai *dai, struct snd_pcm_substream *substream) { - struct sst_data *sst = snd_soc_platform_get_drvdata(platform); + struct sst_data *sst = snd_soc_dai_get_drvdata(dai); struct sst_dev_stream_map *map = sst->pdata->pdev_strm_map; struct sst_runtime_stream *stream = substream->runtime->private_data; u32 str_id = stream->stream_info.str_id; unsigned int pipe_id; + pipe_id = map[str_id].device_id; - pr_debug("%s: got pipe_id = %#x for str_id = %d\n", - __func__, pipe_id, str_id); + dev_dbg(dai->dev, "got pipe_id = %#x for str_id = %d\n", + pipe_id, str_id); return pipe_id; } @@ -403,12 +419,11 @@ static int sst_media_prepare(struct snd_pcm_substream *substream, stream = substream->runtime->private_data; str_id = stream->stream_info.str_id; if (stream->stream_info.str_id) { - ret_val = stream->ops->device_control( - SST_SND_DROP, &str_id); + ret_val = stream->ops->stream_drop(sst->dev, str_id); return ret_val; } - ret_val = sst_platform_alloc_stream(substream, dai->platform); + ret_val = sst_platform_alloc_stream(substream, dai); if (ret_val <= 0) return ret_val; snprintf(substream->pcm->id, sizeof(substream->pcm->id), @@ -461,37 +476,40 @@ static int sst_platform_pcm_trigger(struct snd_pcm_substream *substream, { int ret_val = 0, str_id; struct sst_runtime_stream *stream; - int str_cmd, status; + int status; + struct snd_soc_pcm_runtime *rtd = substream->private_data; - pr_debug("sst_platform_pcm_trigger called\n"); + dev_dbg(rtd->dev, "sst_platform_pcm_trigger called\n"); + if (substream->pcm->internal) + return 0; stream = substream->runtime->private_data; str_id = stream->stream_info.str_id; switch (cmd) { case SNDRV_PCM_TRIGGER_START: - pr_debug("sst: Trigger Start\n"); - str_cmd = SST_SND_START; + dev_dbg(rtd->dev, "sst: Trigger Start\n"); status = SST_PLATFORM_RUNNING; stream->stream_info.arg = substream; + ret_val = stream->ops->stream_start(sst->dev, str_id); break; case SNDRV_PCM_TRIGGER_STOP: - pr_debug("sst: in stop\n"); - str_cmd = SST_SND_DROP; + dev_dbg(rtd->dev, "sst: in stop\n"); status = SST_PLATFORM_DROPPED; + ret_val = stream->ops->stream_drop(sst->dev, str_id); break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - pr_debug("sst: in pause\n"); - str_cmd = SST_SND_PAUSE; + dev_dbg(rtd->dev, "sst: in pause\n"); status = SST_PLATFORM_PAUSED; + ret_val = stream->ops->stream_pause(sst->dev, str_id); break; case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - pr_debug("sst: in pause release\n"); - str_cmd = SST_SND_RESUME; + dev_dbg(rtd->dev, "sst: in pause release\n"); status = SST_PLATFORM_RUNNING; + ret_val = stream->ops->stream_pause_release(sst->dev, str_id); break; default: return -EINVAL; } - ret_val = stream->ops->device_control(str_cmd, &str_id); + if (!ret_val) sst_set_stream_status(stream, status); @@ -505,16 +523,16 @@ static snd_pcm_uframes_t sst_platform_pcm_pointer struct sst_runtime_stream *stream; int ret_val, status; struct pcm_stream_info *str_info; + struct snd_soc_pcm_runtime *rtd = substream->private_data; stream = substream->runtime->private_data; status = sst_get_stream_status(stream); if (status == SST_PLATFORM_INIT) return 0; str_info = &stream->stream_info; - ret_val = stream->ops->device_control( - SST_SND_BUFFER_POINTER, str_info); + ret_val = stream->ops->stream_read_tstamp(sst->dev, str_info); if (ret_val) { - pr_err("sst: error code = %d\n", ret_val); + dev_err(rtd->dev, "sst: error code = %d\n", ret_val); return ret_val; } substream->runtime->delay = str_info->pcm_delay; @@ -530,7 +548,7 @@ static struct snd_pcm_ops sst_platform_ops = { static void sst_pcm_free(struct snd_pcm *pcm) { - pr_debug("sst_pcm_free called\n"); + dev_dbg(pcm->dev, "sst_pcm_free called\n"); snd_pcm_lib_preallocate_free_for_all(pcm); } @@ -547,14 +565,20 @@ static int sst_pcm_new(struct snd_soc_pcm_runtime *rtd) snd_dma_continuous_data(GFP_DMA), SST_MIN_BUFFER, SST_MAX_BUFFER); if (retval) { - pr_err("dma buffer allocationf fail\n"); + dev_err(rtd->dev, "dma buffer allocationf fail\n"); return retval; } } return retval; } -static struct snd_soc_platform_driver sst_soc_platform_drv = { +static int sst_soc_probe(struct snd_soc_platform *platform) +{ + return sst_dsp_init_v2_dpcm(platform); +} + +static struct snd_soc_platform_driver sst_soc_platform_drv = { + .probe = sst_soc_probe, .ops = &sst_platform_ops, .compr_ops = &sst_platform_compr_ops, .pcm_new = sst_pcm_new, @@ -574,13 +598,11 @@ static int sst_platform_probe(struct platform_device *pdev) drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL); if (drv == NULL) { - pr_err("kzalloc failed\n"); return -ENOMEM; } pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); if (pdata == NULL) { - pr_err("kzalloc failed for pdata\n"); return -ENOMEM; } @@ -592,14 +614,14 @@ static int sst_platform_probe(struct platform_device *pdev) ret = snd_soc_register_platform(&pdev->dev, &sst_soc_platform_drv); if (ret) { - pr_err("registering soc platform failed\n"); + dev_err(&pdev->dev, "registering soc platform failed\n"); return ret; } ret = snd_soc_register_component(&pdev->dev, &sst_component, sst_platform_dai, ARRAY_SIZE(sst_platform_dai)); if (ret) { - pr_err("registering cpu dais failed\n"); + dev_err(&pdev->dev, "registering cpu dais failed\n"); snd_soc_unregister_platform(&pdev->dev); } return ret; @@ -610,7 +632,7 @@ static int sst_platform_remove(struct platform_device *pdev) snd_soc_unregister_component(&pdev->dev); snd_soc_unregister_platform(&pdev->dev); - pr_debug("sst_platform_remove success\n"); + dev_dbg(&pdev->dev, "sst_platform_remove success\n"); return 0; } diff --git a/sound/soc/intel/sst-mfld-platform.h b/sound/soc/intel/sst-mfld-platform.h index 6c6a42c08e24..19f83ec51613 100644 --- a/sound/soc/intel/sst-mfld-platform.h +++ b/sound/soc/intel/sst-mfld-platform.h @@ -54,20 +54,6 @@ enum sst_drv_status { SST_PLATFORM_DROPPED, }; -enum sst_controls { - SST_SND_ALLOC = 0x00, - SST_SND_PAUSE = 0x01, - SST_SND_RESUME = 0x02, - SST_SND_DROP = 0x03, - SST_SND_FREE = 0x04, - SST_SND_BUFFER_POINTER = 0x05, - SST_SND_STREAM_INIT = 0x06, - SST_SND_START = 0x07, - SST_SET_BYTE_STREAM = 0x100A, - SST_GET_BYTE_STREAM = 0x100B, - SST_MAX_CONTROLS = SST_GET_BYTE_STREAM, -}; - enum sst_stream_ops { STREAM_OPS_PLAYBACK = 0, STREAM_OPS_CAPTURE, @@ -113,24 +99,37 @@ struct sst_compress_cb { struct compress_sst_ops { const char *name; - int (*open) (struct snd_sst_params *str_params, - struct sst_compress_cb *cb); - int (*control) (unsigned int cmd, unsigned int str_id); - int (*tstamp) (unsigned int str_id, struct snd_compr_tstamp *tstamp); - int (*ack) (unsigned int str_id, unsigned long bytes); - int (*close) (unsigned int str_id); - int (*get_caps) (struct snd_compr_caps *caps); - int (*get_codec_caps) (struct snd_compr_codec_caps *codec); - int (*set_metadata) (unsigned int str_id, + int (*open)(struct device *dev, + struct snd_sst_params *str_params, struct sst_compress_cb *cb); + int (*stream_start)(struct device *dev, unsigned int str_id); + int (*stream_drop)(struct device *dev, unsigned int str_id); + int (*stream_drain)(struct device *dev, unsigned int str_id); + int (*stream_partial_drain)(struct device *dev, unsigned int str_id); + int (*stream_pause)(struct device *dev, unsigned int str_id); + int (*stream_pause_release)(struct device *dev, unsigned int str_id); + + int (*tstamp)(struct device *dev, unsigned int str_id, + struct snd_compr_tstamp *tstamp); + int (*ack)(struct device *dev, unsigned int str_id, + unsigned long bytes); + int (*close)(struct device *dev, unsigned int str_id); + int (*get_caps)(struct snd_compr_caps *caps); + int (*get_codec_caps)(struct snd_compr_codec_caps *codec); + int (*set_metadata)(struct device *dev, unsigned int str_id, struct snd_compr_metadata *mdata); - }; struct sst_ops { - int (*open) (struct snd_sst_params *str_param); - int (*device_control) (int cmd, void *arg); - int (*set_generic_params)(enum sst_controls cmd, void *arg); - int (*close) (unsigned int str_id); + int (*open)(struct device *dev, struct snd_sst_params *str_param); + int (*stream_init)(struct device *dev, struct pcm_stream_info *str_info); + int (*stream_start)(struct device *dev, int str_id); + int (*stream_drop)(struct device *dev, int str_id); + int (*stream_pause)(struct device *dev, int str_id); + int (*stream_pause_release)(struct device *dev, int str_id); + int (*stream_read_tstamp)(struct device *dev, struct pcm_stream_info *str_info); + int (*send_byte_stream)(struct device *dev, struct snd_sst_bytes_v2 *bytes); + int (*close)(struct device *dev, unsigned int str_id); + int (*power)(struct device *dev, bool state); }; struct sst_runtime_stream { @@ -152,6 +151,8 @@ struct sst_device { }; struct sst_data; + +int sst_dsp_init_v2_dpcm(struct snd_soc_platform *platform); void sst_set_stream_status(struct sst_runtime_stream *stream, int state); int sst_fill_stream_params(void *substream, const struct sst_data *ctx, struct snd_sst_params *str_params, bool is_compress); @@ -166,6 +167,7 @@ struct sst_algo_int_control_v2 { struct sst_data { struct platform_device *pdev; struct sst_platform_data *pdata; + struct snd_sst_bytes_v2 *byte_stream; struct mutex lock; }; int sst_register_dsp(struct sst_device *sst); diff --git a/sound/soc/omap/omap-twl4030.c b/sound/soc/omap/omap-twl4030.c index f8a6adc2d81c..4336d1831485 100644 --- a/sound/soc/omap/omap-twl4030.c +++ b/sound/soc/omap/omap-twl4030.c @@ -260,7 +260,7 @@ static struct snd_soc_dai_link omap_twl4030_dai_links[] = { .stream_name = "TWL4030 Voice", .cpu_dai_name = "omap-mcbsp.3", .codec_dai_name = "twl4030-voice", - .platform_name = "omap-mcbsp.2", + .platform_name = "omap-mcbsp.3", .codec_name = "twl4030-codec", .dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF | SND_SOC_DAIFMT_CBM_CFM, diff --git a/sound/soc/omap/rx51.c b/sound/soc/omap/rx51.c index 943922c79f78..b10ae8074461 100644 --- a/sound/soc/omap/rx51.c +++ b/sound/soc/omap/rx51.c @@ -168,7 +168,7 @@ static int rx51_spk_event(struct snd_soc_dapm_widget *w, static int rx51_hp_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *k, int event) { - struct snd_soc_codec *codec = w->dapm->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); if (SND_SOC_DAPM_EVENT_ON(event)) tpa6130a2_stereo_enable(codec, 1); diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c index 0109f6c2334e..a8e097433074 100644 --- a/sound/soc/pxa/pxa-ssp.c +++ b/sound/soc/pxa/pxa-ssp.c @@ -765,9 +765,7 @@ static int pxa_ssp_remove(struct snd_soc_dai *dai) SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_64000 | \ SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) -#define PXA_SSP_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ - SNDRV_PCM_FMTBIT_S24_LE | \ - SNDRV_PCM_FMTBIT_S32_LE) +#define PXA_SSP_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE) static const struct snd_soc_dai_ops pxa_ssp_dai_ops = { .startup = pxa_ssp_startup, diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c index 8d8e4b59049f..fb9e05c9f471 100644 --- a/sound/soc/rockchip/rockchip_i2s.c +++ b/sound/soc/rockchip/rockchip_i2s.c @@ -165,13 +165,14 @@ static int rockchip_i2s_set_fmt(struct snd_soc_dai *cpu_dai, struct rk_i2s_dev *i2s = to_info(cpu_dai); unsigned int mask = 0, val = 0; - mask = I2S_CKR_MSS_SLAVE; + mask = I2S_CKR_MSS_MASK; switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBS_CFS: - val = I2S_CKR_MSS_SLAVE; + /* Set source clock in Master mode */ + val = I2S_CKR_MSS_MASTER; break; case SND_SOC_DAIFMT_CBM_CFM: - val = I2S_CKR_MSS_MASTER; + val = I2S_CKR_MSS_SLAVE; break; default: return -EINVAL; @@ -361,6 +362,8 @@ static bool rockchip_i2s_rd_reg(struct device *dev, unsigned int reg) case I2S_XFER: case I2S_CLR: case I2S_RXDR: + case I2S_FIFOLR: + case I2S_INTSR: return true; default: return false; @@ -370,8 +373,8 @@ static bool rockchip_i2s_rd_reg(struct device *dev, unsigned int reg) static bool rockchip_i2s_volatile_reg(struct device *dev, unsigned int reg) { switch (reg) { - case I2S_FIFOLR: case I2S_INTSR: + case I2S_CLR: return true; default: return false; @@ -381,8 +384,6 @@ static bool rockchip_i2s_volatile_reg(struct device *dev, unsigned int reg) static bool rockchip_i2s_precious_reg(struct device *dev, unsigned int reg) { switch (reg) { - case I2S_FIFOLR: - return true; default: return false; } diff --git a/sound/soc/samsung/goni_wm8994.c b/sound/soc/samsung/goni_wm8994.c index 9506d7617223..3b527dcfc0aa 100644 --- a/sound/soc/samsung/goni_wm8994.c +++ b/sound/soc/samsung/goni_wm8994.c @@ -16,7 +16,7 @@ #include <sound/jack.h> #include <asm/mach-types.h> -#include <mach/gpio.h> +#include <mach/gpio-samsung.h> #include "../codecs/wm8994.h" diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index 03eec22f0f46..9d513473b300 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -462,7 +462,7 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, if (dir == SND_SOC_CLOCK_IN) rfs = 0; - if ((rfs && other->rfs && (other->rfs != rfs)) || + if ((rfs && other && other->rfs && (other->rfs != rfs)) || (any_active(i2s) && (((dir == SND_SOC_CLOCK_IN) && !(mod & MOD_CDCLKCON)) || @@ -762,7 +762,8 @@ static void i2s_shutdown(struct snd_pcm_substream *substream, } else { u32 mod = readl(i2s->addr + I2SMOD); i2s->cdclk_out = !(mod & MOD_CDCLKCON); - other->cdclk_out = i2s->cdclk_out; + if (other) + other->cdclk_out = i2s->cdclk_out; } /* Reset any constraint on RFS and BFS */ i2s->rfs = 0; diff --git a/sound/soc/samsung/speyside.c b/sound/soc/samsung/speyside.c index 9902efcb8ea1..a05482651aae 100644 --- a/sound/soc/samsung/speyside.c +++ b/sound/soc/samsung/speyside.c @@ -228,10 +228,12 @@ static struct snd_soc_dai_link speyside_dai[] = { }, }; -static int speyside_wm9081_init(struct snd_soc_dapm_context *dapm) +static int speyside_wm9081_init(struct snd_soc_component *component) { + struct snd_soc_codec *codec = snd_soc_component_to_codec(component); + /* At any time the WM9081 is active it will have this clock */ - return snd_soc_codec_set_sysclk(dapm->codec, WM9081_SYSCLK_MCLK, 0, + return snd_soc_codec_set_sysclk(codec, WM9081_SYSCLK_MCLK, 0, MCLK_AUDIO_RATE, 0); } diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index 3fdf3be7b99a..f95e7ab135e8 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c @@ -247,7 +247,7 @@ rsnd_gen2_dma_addr(struct rsnd_priv *priv, }; /* it shouldn't happen */ - if (use_dvc & !use_src) + if (use_dvc && !use_src) dev_err(dev, "DVC is selected without SRC\n"); /* use SSIU or SSI ? */ diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index 27c06acce205..cecfab3cc948 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -101,10 +101,12 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream) fe->dpcm[stream].runtime = fe_substream->runtime; - if (dpcm_path_get(fe, stream, &list) <= 0) { + ret = dpcm_path_get(fe, stream, &list); + if (ret < 0) + goto fe_err; + else if (ret == 0) dev_dbg(fe->dev, "ASoC: %s no valid %s route\n", fe->dai_link->name, stream ? "capture" : "playback"); - } /* calculate valid and active FE <-> BE dpcms */ dpcm_process_paths(fe, stream, &list, 1); diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index d4bfd4a9076f..3d8cff629a18 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -270,79 +270,54 @@ static const struct file_operations codec_reg_fops = { .llseek = default_llseek, }; -static struct dentry *soc_debugfs_create_dir(struct dentry *parent, - const char *fmt, ...) +static void soc_init_component_debugfs(struct snd_soc_component *component) { - struct dentry *de; - va_list ap; - char *s; + if (component->debugfs_prefix) { + char *name; - va_start(ap, fmt); - s = kvasprintf(GFP_KERNEL, fmt, ap); - va_end(ap); + name = kasprintf(GFP_KERNEL, "%s:%s", + component->debugfs_prefix, component->name); + if (name) { + component->debugfs_root = debugfs_create_dir(name, + component->card->debugfs_card_root); + kfree(name); + } + } else { + component->debugfs_root = debugfs_create_dir(component->name, + component->card->debugfs_card_root); + } - if (!s) - return NULL; + if (!component->debugfs_root) { + dev_warn(component->dev, + "ASoC: Failed to create component debugfs directory\n"); + return; + } - de = debugfs_create_dir(s, parent); - kfree(s); + snd_soc_dapm_debugfs_init(snd_soc_component_get_dapm(component), + component->debugfs_root); - return de; + if (component->init_debugfs) + component->init_debugfs(component); } -static void soc_init_codec_debugfs(struct snd_soc_codec *codec) +static void soc_cleanup_component_debugfs(struct snd_soc_component *component) { - struct dentry *debugfs_card_root = codec->component.card->debugfs_card_root; + debugfs_remove_recursive(component->debugfs_root); +} - codec->debugfs_codec_root = soc_debugfs_create_dir(debugfs_card_root, - "codec:%s", - codec->component.name); - if (!codec->debugfs_codec_root) { - dev_warn(codec->dev, - "ASoC: Failed to create codec debugfs directory\n"); - return; - } +static void soc_init_codec_debugfs(struct snd_soc_component *component) +{ + struct snd_soc_codec *codec = snd_soc_component_to_codec(component); - debugfs_create_bool("cache_sync", 0444, codec->debugfs_codec_root, + debugfs_create_bool("cache_sync", 0444, codec->component.debugfs_root, &codec->cache_sync); - debugfs_create_bool("cache_only", 0444, codec->debugfs_codec_root, - &codec->cache_only); codec->debugfs_reg = debugfs_create_file("codec_reg", 0644, - codec->debugfs_codec_root, + codec->component.debugfs_root, codec, &codec_reg_fops); if (!codec->debugfs_reg) dev_warn(codec->dev, "ASoC: Failed to create codec register debugfs file\n"); - - snd_soc_dapm_debugfs_init(&codec->dapm, codec->debugfs_codec_root); -} - -static void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec) -{ - debugfs_remove_recursive(codec->debugfs_codec_root); -} - -static void soc_init_platform_debugfs(struct snd_soc_platform *platform) -{ - struct dentry *debugfs_card_root = platform->component.card->debugfs_card_root; - - platform->debugfs_platform_root = soc_debugfs_create_dir(debugfs_card_root, - "platform:%s", - platform->component.name); - if (!platform->debugfs_platform_root) { - dev_warn(platform->dev, - "ASoC: Failed to create platform debugfs directory\n"); - return; - } - - snd_soc_dapm_debugfs_init(&platform->component.dapm, - platform->debugfs_platform_root); -} - -static void soc_cleanup_platform_debugfs(struct snd_soc_platform *platform) -{ - debugfs_remove_recursive(platform->debugfs_platform_root); } static ssize_t codec_list_read_file(struct file *file, char __user *user_buf, @@ -474,19 +449,15 @@ static void soc_cleanup_card_debugfs(struct snd_soc_card *card) #else -static inline void soc_init_codec_debugfs(struct snd_soc_codec *codec) -{ -} - -static inline void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec) -{ -} +#define soc_init_codec_debugfs NULL -static inline void soc_init_platform_debugfs(struct snd_soc_platform *platform) +static inline void soc_init_component_debugfs( + struct snd_soc_component *component) { } -static inline void soc_cleanup_platform_debugfs(struct snd_soc_platform *platform) +static inline void soc_cleanup_component_debugfs( + struct snd_soc_component *component) { } @@ -579,10 +550,8 @@ int snd_soc_suspend(struct device *dev) struct snd_soc_codec *codec; int i, j; - /* If the initialization of this soc device failed, there is no codec - * associated with it. Just bail out in this case. - */ - if (list_empty(&card->codec_dev_list)) + /* If the card is not initialized yet there is nothing to do */ + if (!card->instantiated) return 0; /* Due to the resume being scheduled into a workqueue we could @@ -668,7 +637,7 @@ int snd_soc_suspend(struct device *dev) list_for_each_entry(codec, &card->codec_dev_list, card_list) { /* If there are paths active then the CODEC will be held with * bias _ON and should not be suspended. */ - if (!codec->suspended && codec->driver->suspend) { + if (!codec->suspended) { switch (codec->dapm.bias_level) { case SND_SOC_BIAS_STANDBY: /* @@ -682,8 +651,10 @@ int snd_soc_suspend(struct device *dev) "ASoC: idle_bias_off CODEC on over suspend\n"); break; } + case SND_SOC_BIAS_OFF: - codec->driver->suspend(codec); + if (codec->driver->suspend) + codec->driver->suspend(codec); codec->suspended = 1; codec->cache_sync = 1; if (codec->component.regmap) @@ -757,11 +728,12 @@ static void soc_resume_deferred(struct work_struct *work) * left with bias OFF or STANDBY and suspended so we must now * resume. Otherwise the suspend was suppressed. */ - if (codec->driver->resume && codec->suspended) { + if (codec->suspended) { switch (codec->dapm.bias_level) { case SND_SOC_BIAS_STANDBY: case SND_SOC_BIAS_OFF: - codec->driver->resume(codec); + if (codec->driver->resume) + codec->driver->resume(codec); codec->suspended = 0; break; default: @@ -835,10 +807,8 @@ int snd_soc_resume(struct device *dev) struct snd_soc_card *card = dev_get_drvdata(dev); int i, ac97_control = 0; - /* If the initialization of this soc device failed, there is no codec - * associated with it. Just bail out in this case. - */ - if (list_empty(&card->codec_dev_list)) + /* If the card is not initialized yet there is nothing to do */ + if (!card->instantiated) return 0; /* activate pins from sleep state */ @@ -887,35 +857,40 @@ EXPORT_SYMBOL_GPL(snd_soc_resume); static const struct snd_soc_dai_ops null_dai_ops = { }; -static struct snd_soc_codec *soc_find_codec( - const struct device_node *codec_of_node, - const char *codec_name) +static struct snd_soc_component *soc_find_component( + const struct device_node *of_node, const char *name) { - struct snd_soc_codec *codec; + struct snd_soc_component *component; - list_for_each_entry(codec, &codec_list, list) { - if (codec_of_node) { - if (codec->dev->of_node != codec_of_node) - continue; - } else { - if (strcmp(codec->component.name, codec_name)) - continue; + list_for_each_entry(component, &component_list, list) { + if (of_node) { + if (component->dev->of_node == of_node) + return component; + } else if (strcmp(component->name, name) == 0) { + return component; } - - return codec; } return NULL; } -static struct snd_soc_dai *soc_find_codec_dai(struct snd_soc_codec *codec, - const char *codec_dai_name) +static struct snd_soc_dai *snd_soc_find_dai( + const struct snd_soc_dai_link_component *dlc) { - struct snd_soc_dai *codec_dai; + struct snd_soc_component *component; + struct snd_soc_dai *dai; + + /* Find CPU DAI from registered DAIs*/ + list_for_each_entry(component, &component_list, list) { + if (dlc->of_node && component->dev->of_node != dlc->of_node) + continue; + if (dlc->name && strcmp(dev_name(component->dev), dlc->name)) + continue; + list_for_each_entry(dai, &component->dai_list, list) { + if (dlc->dai_name && strcmp(dai->name, dlc->dai_name)) + continue; - list_for_each_entry(codec_dai, &codec->component.dai_list, list) { - if (!strcmp(codec_dai->name, codec_dai_name)) { - return codec_dai; + return dai; } } @@ -926,33 +901,19 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num) { struct snd_soc_dai_link *dai_link = &card->dai_link[num]; struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; - struct snd_soc_component *component; struct snd_soc_dai_link_component *codecs = dai_link->codecs; + struct snd_soc_dai_link_component cpu_dai_component; struct snd_soc_dai **codec_dais = rtd->codec_dais; struct snd_soc_platform *platform; - struct snd_soc_dai *cpu_dai; const char *platform_name; int i; dev_dbg(card->dev, "ASoC: binding %s at idx %d\n", dai_link->name, num); - /* Find CPU DAI from registered DAIs*/ - list_for_each_entry(component, &component_list, list) { - if (dai_link->cpu_of_node && - component->dev->of_node != dai_link->cpu_of_node) - continue; - if (dai_link->cpu_name && - strcmp(dev_name(component->dev), dai_link->cpu_name)) - continue; - list_for_each_entry(cpu_dai, &component->dai_list, list) { - if (dai_link->cpu_dai_name && - strcmp(cpu_dai->name, dai_link->cpu_dai_name)) - continue; - - rtd->cpu_dai = cpu_dai; - } - } - + cpu_dai_component.name = dai_link->cpu_name; + cpu_dai_component.of_node = dai_link->cpu_of_node; + cpu_dai_component.dai_name = dai_link->cpu_dai_name; + rtd->cpu_dai = snd_soc_find_dai(&cpu_dai_component); if (!rtd->cpu_dai) { dev_err(card->dev, "ASoC: CPU DAI %s not registered\n", dai_link->cpu_dai_name); @@ -963,15 +924,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num) /* Find CODEC from registered CODECs */ for (i = 0; i < rtd->num_codecs; i++) { - struct snd_soc_codec *codec; - codec = soc_find_codec(codecs[i].of_node, codecs[i].name); - if (!codec) { - dev_err(card->dev, "ASoC: CODEC %s not registered\n", - codecs[i].name); - return -EPROBE_DEFER; - } - - codec_dais[i] = soc_find_codec_dai(codec, codecs[i].dai_name); + codec_dais[i] = snd_soc_find_dai(&codecs[i]); if (!codec_dais[i]) { dev_err(card->dev, "ASoC: CODEC DAI %s not registered\n", codecs[i].dai_name); @@ -1012,68 +965,46 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num) return 0; } -static int soc_remove_platform(struct snd_soc_platform *platform) +static void soc_remove_component(struct snd_soc_component *component) { - int ret; - - if (platform->driver->remove) { - ret = platform->driver->remove(platform); - if (ret < 0) - dev_err(platform->dev, "ASoC: failed to remove %d\n", - ret); - } - - /* Make sure all DAPM widgets are freed */ - snd_soc_dapm_free(&platform->component.dapm); - - soc_cleanup_platform_debugfs(platform); - platform->probed = 0; - module_put(platform->dev->driver->owner); - - return 0; -} + if (!component->probed) + return; -static void soc_remove_codec(struct snd_soc_codec *codec) -{ - int err; + /* This is a HACK and will be removed soon */ + if (component->codec) + list_del(&component->codec->card_list); - if (codec->driver->remove) { - err = codec->driver->remove(codec); - if (err < 0) - dev_err(codec->dev, "ASoC: failed to remove %d\n", err); - } + if (component->remove) + component->remove(component); - /* Make sure all DAPM widgets are freed */ - snd_soc_dapm_free(&codec->dapm); + snd_soc_dapm_free(snd_soc_component_get_dapm(component)); - soc_cleanup_codec_debugfs(codec); - codec->probed = 0; - list_del(&codec->card_list); - module_put(codec->dev->driver->owner); + soc_cleanup_component_debugfs(component); + component->probed = 0; + module_put(component->dev->driver->owner); } -static void soc_remove_codec_dai(struct snd_soc_dai *codec_dai, int order) +static void soc_remove_dai(struct snd_soc_dai *dai, int order) { int err; - if (codec_dai && codec_dai->probed && - codec_dai->driver->remove_order == order) { - if (codec_dai->driver->remove) { - err = codec_dai->driver->remove(codec_dai); + if (dai && dai->probed && + dai->driver->remove_order == order) { + if (dai->driver->remove) { + err = dai->driver->remove(dai); if (err < 0) - dev_err(codec_dai->dev, + dev_err(dai->dev, "ASoC: failed to remove %s: %d\n", - codec_dai->name, err); + dai->name, err); } - codec_dai->probed = 0; + dai->probed = 0; } } static void soc_remove_link_dais(struct snd_soc_card *card, int num, int order) { struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - int i, err; + int i; /* unregister the rtd device */ if (rtd->dev_registered) { @@ -1085,22 +1016,9 @@ static void soc_remove_link_dais(struct snd_soc_card *card, int num, int order) /* remove the CODEC DAI */ for (i = 0; i < rtd->num_codecs; i++) - soc_remove_codec_dai(rtd->codec_dais[i], order); + soc_remove_dai(rtd->codec_dais[i], order); - /* remove the cpu_dai */ - if (cpu_dai && cpu_dai->probed && - cpu_dai->driver->remove_order == order) { - if (cpu_dai->driver->remove) { - err = cpu_dai->driver->remove(cpu_dai); - if (err < 0) - dev_err(cpu_dai->dev, - "ASoC: failed to remove %s: %d\n", - cpu_dai->name, err); - } - cpu_dai->probed = 0; - if (!cpu_dai->codec) - module_put(cpu_dai->dev->driver->owner); - } + soc_remove_dai(rtd->cpu_dai, order); } static void soc_remove_link_components(struct snd_soc_card *card, int num, @@ -1109,29 +1027,24 @@ static void soc_remove_link_components(struct snd_soc_card *card, int num, struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct snd_soc_platform *platform = rtd->platform; - struct snd_soc_codec *codec; + struct snd_soc_component *component; int i; /* remove the platform */ - if (platform && platform->probed && - platform->driver->remove_order == order) { - soc_remove_platform(platform); - } + if (platform && platform->component.driver->remove_order == order) + soc_remove_component(&platform->component); /* remove the CODEC-side CODEC */ for (i = 0; i < rtd->num_codecs; i++) { - codec = rtd->codec_dais[i]->codec; - if (codec && codec->probed && - codec->driver->remove_order == order) - soc_remove_codec(codec); + component = rtd->codec_dais[i]->component; + if (component->driver->remove_order == order) + soc_remove_component(component); } /* remove any CPU-side CODEC */ if (cpu_dai) { - codec = cpu_dai->codec; - if (codec && codec->probed && - codec->driver->remove_order == order) - soc_remove_codec(codec); + if (cpu_dai->component->driver->remove_order == order) + soc_remove_component(cpu_dai->component); } } @@ -1173,137 +1086,78 @@ static void soc_set_name_prefix(struct snd_soc_card *card, } } -static int soc_probe_codec(struct snd_soc_card *card, - struct snd_soc_codec *codec) +static int soc_probe_component(struct snd_soc_card *card, + struct snd_soc_component *component) { - int ret = 0; - const struct snd_soc_codec_driver *driver = codec->driver; + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); struct snd_soc_dai *dai; + int ret; + + if (component->probed) + return 0; - codec->component.card = card; - codec->dapm.card = card; - soc_set_name_prefix(card, &codec->component); + component->card = card; + dapm->card = card; + soc_set_name_prefix(card, component); - if (!try_module_get(codec->dev->driver->owner)) + if (!try_module_get(component->dev->driver->owner)) return -ENODEV; - soc_init_codec_debugfs(codec); + soc_init_component_debugfs(component); - if (driver->dapm_widgets) { - ret = snd_soc_dapm_new_controls(&codec->dapm, - driver->dapm_widgets, - driver->num_dapm_widgets); + if (component->dapm_widgets) { + ret = snd_soc_dapm_new_controls(dapm, component->dapm_widgets, + component->num_dapm_widgets); if (ret != 0) { - dev_err(codec->dev, + dev_err(component->dev, "Failed to create new controls %d\n", ret); goto err_probe; } } - /* Create DAPM widgets for each DAI stream */ - list_for_each_entry(dai, &codec->component.dai_list, list) { - ret = snd_soc_dapm_new_dai_widgets(&codec->dapm, dai); - + list_for_each_entry(dai, &component->dai_list, list) { + ret = snd_soc_dapm_new_dai_widgets(dapm, dai); if (ret != 0) { - dev_err(codec->dev, + dev_err(component->dev, "Failed to create DAI widgets %d\n", ret); goto err_probe; } } - codec->dapm.idle_bias_off = driver->idle_bias_off; - - if (driver->probe) { - ret = driver->probe(codec); + if (component->probe) { + ret = component->probe(component); if (ret < 0) { - dev_err(codec->dev, - "ASoC: failed to probe CODEC %d\n", ret); + dev_err(component->dev, + "ASoC: failed to probe component %d\n", ret); goto err_probe; } - WARN(codec->dapm.idle_bias_off && - codec->dapm.bias_level != SND_SOC_BIAS_OFF, - "codec %s can not start from non-off bias with idle_bias_off==1\n", - codec->component.name); - } - - if (driver->controls) - snd_soc_add_codec_controls(codec, driver->controls, - driver->num_controls); - if (driver->dapm_routes) - snd_soc_dapm_add_routes(&codec->dapm, driver->dapm_routes, - driver->num_dapm_routes); - - /* mark codec as probed and add to card codec list */ - codec->probed = 1; - list_add(&codec->card_list, &card->codec_dev_list); - list_add(&codec->dapm.list, &card->dapm_list); - return 0; - -err_probe: - soc_cleanup_codec_debugfs(codec); - module_put(codec->dev->driver->owner); - - return ret; -} - -static int soc_probe_platform(struct snd_soc_card *card, - struct snd_soc_platform *platform) -{ - int ret = 0; - const struct snd_soc_platform_driver *driver = platform->driver; - struct snd_soc_component *component; - struct snd_soc_dai *dai; - - platform->component.card = card; - platform->component.dapm.card = card; - - if (!try_module_get(platform->dev->driver->owner)) - return -ENODEV; - - soc_init_platform_debugfs(platform); - - if (driver->dapm_widgets) - snd_soc_dapm_new_controls(&platform->component.dapm, - driver->dapm_widgets, driver->num_dapm_widgets); - - /* Create DAPM widgets for each DAI stream */ - list_for_each_entry(component, &component_list, list) { - if (component->dev != platform->dev) - continue; - list_for_each_entry(dai, &component->dai_list, list) - snd_soc_dapm_new_dai_widgets(&platform->component.dapm, - dai); + WARN(dapm->idle_bias_off && + dapm->bias_level != SND_SOC_BIAS_OFF, + "codec %s can not start from non-off bias with idle_bias_off==1\n", + component->name); } - platform->component.dapm.idle_bias_off = 1; - - if (driver->probe) { - ret = driver->probe(platform); - if (ret < 0) { - dev_err(platform->dev, - "ASoC: failed to probe platform %d\n", ret); - goto err_probe; - } - } + if (component->controls) + snd_soc_add_component_controls(component, component->controls, + component->num_controls); + if (component->dapm_routes) + snd_soc_dapm_add_routes(dapm, component->dapm_routes, + component->num_dapm_routes); - if (driver->controls) - snd_soc_add_platform_controls(platform, driver->controls, - driver->num_controls); - if (driver->dapm_routes) - snd_soc_dapm_add_routes(&platform->component.dapm, - driver->dapm_routes, driver->num_dapm_routes); + component->probed = 1; + list_add(&dapm->list, &card->dapm_list); - /* mark platform as probed and add to card platform list */ - platform->probed = 1; - list_add(&platform->component.dapm.list, &card->dapm_list); + /* This is a HACK and will be removed soon */ + if (component->codec) + list_add(&component->codec->card_list, &card->codec_dev_list); return 0; err_probe: - soc_cleanup_platform_debugfs(platform); - module_put(platform->dev->driver->owner); + soc_cleanup_component_debugfs(component); + module_put(component->dev->driver->owner); return ret; } @@ -1325,7 +1179,7 @@ static int soc_post_component_init(struct snd_soc_pcm_runtime *rtd, device_initialize(rtd->dev); rtd->dev->parent = rtd->card->dev; rtd->dev->release = rtd_release; - rtd->dev->init_name = name; + dev_set_name(rtd->dev, "%s", name); dev_set_drvdata(rtd->dev, rtd); mutex_init(&rtd->pcm_mutex); INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_PLAYBACK].be_clients); @@ -1342,17 +1196,21 @@ static int soc_post_component_init(struct snd_soc_pcm_runtime *rtd, } rtd->dev_registered = 1; - /* add DAPM sysfs entries for this codec */ - ret = snd_soc_dapm_sys_add(rtd->dev); - if (ret < 0) - dev_err(rtd->dev, - "ASoC: failed to add codec dapm sysfs entries: %d\n", ret); + if (rtd->codec) { + /* add DAPM sysfs entries for this codec */ + ret = snd_soc_dapm_sys_add(rtd->dev); + if (ret < 0) + dev_err(rtd->dev, + "ASoC: failed to add codec dapm sysfs entries: %d\n", + ret); - /* add codec sysfs entries */ - ret = device_create_file(rtd->dev, &dev_attr_codec_reg); - if (ret < 0) - dev_err(rtd->dev, - "ASoC: failed to add codec sysfs files: %d\n", ret); + /* add codec sysfs entries */ + ret = device_create_file(rtd->dev, &dev_attr_codec_reg); + if (ret < 0) + dev_err(rtd->dev, + "ASoC: failed to add codec sysfs files: %d\n", + ret); + } return 0; } @@ -1361,33 +1219,31 @@ static int soc_probe_link_components(struct snd_soc_card *card, int num, int order) { struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct snd_soc_platform *platform = rtd->platform; + struct snd_soc_component *component; int i, ret; /* probe the CPU-side component, if it is a CODEC */ - if (cpu_dai->codec && - !cpu_dai->codec->probed && - cpu_dai->codec->driver->probe_order == order) { - ret = soc_probe_codec(card, cpu_dai->codec); + component = rtd->cpu_dai->component; + if (component->driver->probe_order == order) { + ret = soc_probe_component(card, component); if (ret < 0) return ret; } /* probe the CODEC-side components */ for (i = 0; i < rtd->num_codecs; i++) { - if (!rtd->codec_dais[i]->codec->probed && - rtd->codec_dais[i]->codec->driver->probe_order == order) { - ret = soc_probe_codec(card, rtd->codec_dais[i]->codec); + component = rtd->codec_dais[i]->component; + if (component->driver->probe_order == order) { + ret = soc_probe_component(card, component); if (ret < 0) return ret; } } /* probe the platform */ - if (!platform->probed && - platform->driver->probe_order == order) { - ret = soc_probe_platform(card, platform); + if (platform->component.driver->probe_order == order) { + ret = soc_probe_component(card, &platform->component); if (ret < 0) return ret; } @@ -1482,18 +1338,12 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order) /* probe the cpu_dai */ if (!cpu_dai->probed && cpu_dai->driver->probe_order == order) { - if (!cpu_dai->codec) { - if (!try_module_get(cpu_dai->dev->driver->owner)) - return -ENODEV; - } - if (cpu_dai->driver->probe) { ret = cpu_dai->driver->probe(cpu_dai); if (ret < 0) { dev_err(cpu_dai->dev, "ASoC: failed to probe CPU DAI %s: %d\n", cpu_dai->name, ret); - module_put(cpu_dai->dev->driver->owner); return ret; } } @@ -1654,17 +1504,24 @@ static int soc_bind_aux_dev(struct snd_soc_card *card, int num) { struct snd_soc_pcm_runtime *rtd = &card->rtd_aux[num]; struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num]; - const char *codecname = aux_dev->codec_name; + const char *name = aux_dev->codec_name; - rtd->codec = soc_find_codec(aux_dev->codec_of_node, codecname); - if (!rtd->codec) { + rtd->component = soc_find_component(aux_dev->codec_of_node, name); + if (!rtd->component) { if (aux_dev->codec_of_node) - codecname = of_node_full_name(aux_dev->codec_of_node); + name = of_node_full_name(aux_dev->codec_of_node); - dev_err(card->dev, "ASoC: %s not registered\n", codecname); + dev_err(card->dev, "ASoC: %s not registered\n", name); return -EPROBE_DEFER; } + /* + * Some places still reference rtd->codec, so we have to keep that + * initialized if the component is a CODEC. Once all those references + * have been removed, this code can be removed as well. + */ + rtd->codec = rtd->component->codec; + return 0; } @@ -1674,18 +1531,13 @@ static int soc_probe_aux_dev(struct snd_soc_card *card, int num) struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num]; int ret; - if (rtd->codec->probed) { - dev_err(rtd->codec->dev, "ASoC: codec already probed\n"); - return -EBUSY; - } - - ret = soc_probe_codec(card, rtd->codec); + ret = soc_probe_component(card, rtd->component); if (ret < 0) return ret; /* do machine specific initialization */ if (aux_dev->init) { - ret = aux_dev->init(&rtd->codec->dapm); + ret = aux_dev->init(rtd->component); if (ret < 0) { dev_err(card->dev, "ASoC: failed to init %s: %d\n", aux_dev->name, ret); @@ -1699,7 +1551,7 @@ static int soc_probe_aux_dev(struct snd_soc_card *card, int num) static void soc_remove_aux_dev(struct snd_soc_card *card, int num) { struct snd_soc_pcm_runtime *rtd = &card->rtd_aux[num]; - struct snd_soc_codec *codec = rtd->codec; + struct snd_soc_component *component = rtd->component; /* unregister the rtd device */ if (rtd->dev_registered) { @@ -1708,8 +1560,8 @@ static void soc_remove_aux_dev(struct snd_soc_card *card, int num) rtd->dev_registered = 0; } - if (codec && codec->probed) - soc_remove_codec(codec); + if (component && component->probed) + soc_remove_component(component); } static int snd_soc_init_codec_cache(struct snd_soc_codec *codec) @@ -2107,19 +1959,14 @@ static struct platform_driver soc_driver = { int snd_soc_new_ac97_codec(struct snd_soc_codec *codec, struct snd_ac97_bus_ops *ops, int num) { - mutex_lock(&codec->mutex); - codec->ac97 = kzalloc(sizeof(struct snd_ac97), GFP_KERNEL); - if (codec->ac97 == NULL) { - mutex_unlock(&codec->mutex); + if (codec->ac97 == NULL) return -ENOMEM; - } codec->ac97->bus = kzalloc(sizeof(struct snd_ac97_bus), GFP_KERNEL); if (codec->ac97->bus == NULL) { kfree(codec->ac97); codec->ac97 = NULL; - mutex_unlock(&codec->mutex); return -ENOMEM; } @@ -2132,7 +1979,6 @@ int snd_soc_new_ac97_codec(struct snd_soc_codec *codec, */ codec->ac97_created = 1; - mutex_unlock(&codec->mutex); return 0; } EXPORT_SYMBOL_GPL(snd_soc_new_ac97_codec); @@ -2302,7 +2148,6 @@ EXPORT_SYMBOL_GPL(snd_soc_set_ac97_ops_of_reset); */ void snd_soc_free_ac97_codec(struct snd_soc_codec *codec) { - mutex_lock(&codec->mutex); #ifdef CONFIG_SND_SOC_AC97_BUS soc_unregister_ac97_codec(codec); #endif @@ -2310,7 +2155,6 @@ void snd_soc_free_ac97_codec(struct snd_soc_codec *codec) kfree(codec->ac97); codec->ac97 = NULL; codec->ac97_created = 0; - mutex_unlock(&codec->mutex); } EXPORT_SYMBOL_GPL(snd_soc_free_ac97_codec); @@ -3027,9 +2871,10 @@ int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol, unsigned int val, val_mask; int ret; - val = ((ucontrol->value.integer.value[0] + min) & mask); if (invert) - val = max - val; + val = (max - ucontrol->value.integer.value[0]) & mask; + else + val = ((ucontrol->value.integer.value[0] + min) & mask); val_mask = mask << shift; val = val << shift; @@ -3038,9 +2883,10 @@ int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol, return ret; if (snd_soc_volsw_is_stereo(mc)) { - val = ((ucontrol->value.integer.value[1] + min) & mask); if (invert) - val = max - val; + val = (max - ucontrol->value.integer.value[1]) & mask; + else + val = ((ucontrol->value.integer.value[1] + min) & mask); val_mask = mask << shift; val = val << shift; @@ -3085,8 +2931,9 @@ int snd_soc_get_volsw_range(struct snd_kcontrol *kcontrol, if (invert) ucontrol->value.integer.value[0] = max - ucontrol->value.integer.value[0]; - ucontrol->value.integer.value[0] = - ucontrol->value.integer.value[0] - min; + else + ucontrol->value.integer.value[0] = + ucontrol->value.integer.value[0] - min; if (snd_soc_volsw_is_stereo(mc)) { ret = snd_soc_component_read(component, rreg, &val); @@ -3097,8 +2944,9 @@ int snd_soc_get_volsw_range(struct snd_kcontrol *kcontrol, if (invert) ucontrol->value.integer.value[1] = max - ucontrol->value.integer.value[1]; - ucontrol->value.integer.value[1] = - ucontrol->value.integer.value[1] - min; + else + ucontrol->value.integer.value[1] = + ucontrol->value.integer.value[1] - min; } return 0; @@ -3203,7 +3051,7 @@ int snd_soc_bytes_put(struct snd_kcontrol *kcontrol, unsigned int val, mask; void *data; - if (!component->regmap) + if (!component->regmap || !params->num_regs) return -EINVAL; len = params->num_regs * component->val_bytes; @@ -3928,8 +3776,11 @@ EXPORT_SYMBOL_GPL(snd_soc_register_card); */ int snd_soc_unregister_card(struct snd_soc_card *card) { - if (card->instantiated) + if (card->instantiated) { + card->instantiated = false; + snd_soc_dapm_shutdown(card); soc_cleanup_card_resources(card); + } dev_dbg(card->dev, "ASoC: Unregistered card '%s'\n", card->name); return 0; @@ -4116,6 +3967,8 @@ static int snd_soc_component_initialize(struct snd_soc_component *component, component->dev = dev; component->driver = driver; + component->probe = component->driver->probe; + component->remove = component->driver->remove; if (!component->dapm_ptr) component->dapm_ptr = &component->dapm; @@ -4124,19 +3977,42 @@ static int snd_soc_component_initialize(struct snd_soc_component *component, dapm->dev = dev; dapm->component = component; dapm->bias_level = SND_SOC_BIAS_OFF; + dapm->idle_bias_off = true; if (driver->seq_notifier) dapm->seq_notifier = snd_soc_component_seq_notifier; if (driver->stream_event) dapm->stream_event = snd_soc_component_stream_event; + component->controls = driver->controls; + component->num_controls = driver->num_controls; + component->dapm_widgets = driver->dapm_widgets; + component->num_dapm_widgets = driver->num_dapm_widgets; + component->dapm_routes = driver->dapm_routes; + component->num_dapm_routes = driver->num_dapm_routes; + INIT_LIST_HEAD(&component->dai_list); mutex_init(&component->io_mutex); return 0; } +static void snd_soc_component_init_regmap(struct snd_soc_component *component) +{ + if (!component->regmap) + component->regmap = dev_get_regmap(component->dev, NULL); + if (component->regmap) { + int val_bytes = regmap_get_val_bytes(component->regmap); + /* Errors are legitimate for non-integer byte multiples */ + if (val_bytes > 0) + component->val_bytes = val_bytes; + } +} + static void snd_soc_component_add_unlocked(struct snd_soc_component *component) { + if (!component->write && !component->read) + snd_soc_component_init_regmap(component); + list_add(&component->list, &component_list); } @@ -4225,22 +4101,18 @@ found: } EXPORT_SYMBOL_GPL(snd_soc_unregister_component); -static int snd_soc_platform_drv_write(struct snd_soc_component *component, - unsigned int reg, unsigned int val) +static int snd_soc_platform_drv_probe(struct snd_soc_component *component) { struct snd_soc_platform *platform = snd_soc_component_to_platform(component); - return platform->driver->write(platform, reg, val); + return platform->driver->probe(platform); } -static int snd_soc_platform_drv_read(struct snd_soc_component *component, - unsigned int reg, unsigned int *val) +static void snd_soc_platform_drv_remove(struct snd_soc_component *component) { struct snd_soc_platform *platform = snd_soc_component_to_platform(component); - *val = platform->driver->read(platform, reg); - - return 0; + platform->driver->remove(platform); } /** @@ -4261,10 +4133,15 @@ int snd_soc_add_platform(struct device *dev, struct snd_soc_platform *platform, platform->dev = dev; platform->driver = platform_drv; - if (platform_drv->write) - platform->component.write = snd_soc_platform_drv_write; - if (platform_drv->read) - platform->component.read = snd_soc_platform_drv_read; + + if (platform_drv->probe) + platform->component.probe = snd_soc_platform_drv_probe; + if (platform_drv->remove) + platform->component.remove = snd_soc_platform_drv_remove; + +#ifdef CONFIG_DEBUG_FS + platform->component.debugfs_prefix = "platform"; +#endif mutex_lock(&client_mutex); snd_soc_component_add_unlocked(&platform->component); @@ -4386,6 +4263,20 @@ static void fixup_codec_formats(struct snd_soc_pcm_stream *stream) stream->formats |= codec_format_map[i]; } +static int snd_soc_codec_drv_probe(struct snd_soc_component *component) +{ + struct snd_soc_codec *codec = snd_soc_component_to_codec(component); + + return codec->driver->probe(codec); +} + +static void snd_soc_codec_drv_remove(struct snd_soc_component *component) +{ + struct snd_soc_codec *codec = snd_soc_component_to_codec(component); + + codec->driver->remove(codec); +} + static int snd_soc_codec_drv_write(struct snd_soc_component *component, unsigned int reg, unsigned int val) { @@ -4424,7 +4315,6 @@ int snd_soc_register_codec(struct device *dev, { struct snd_soc_codec *codec; struct snd_soc_dai *dai; - struct regmap *regmap; int ret, i; dev_dbg(dev, "codec register %s\n", dev_name(dev)); @@ -4434,18 +4324,37 @@ int snd_soc_register_codec(struct device *dev, return -ENOMEM; codec->component.dapm_ptr = &codec->dapm; + codec->component.codec = codec; ret = snd_soc_component_initialize(&codec->component, &codec_drv->component_driver, dev); if (ret) goto err_free; + if (codec_drv->controls) { + codec->component.controls = codec_drv->controls; + codec->component.num_controls = codec_drv->num_controls; + } + if (codec_drv->dapm_widgets) { + codec->component.dapm_widgets = codec_drv->dapm_widgets; + codec->component.num_dapm_widgets = codec_drv->num_dapm_widgets; + } + if (codec_drv->dapm_routes) { + codec->component.dapm_routes = codec_drv->dapm_routes; + codec->component.num_dapm_routes = codec_drv->num_dapm_routes; + } + + if (codec_drv->probe) + codec->component.probe = snd_soc_codec_drv_probe; + if (codec_drv->remove) + codec->component.remove = snd_soc_codec_drv_remove; if (codec_drv->write) codec->component.write = snd_soc_codec_drv_write; if (codec_drv->read) codec->component.read = snd_soc_codec_drv_read; codec->component.ignore_pmdown_time = codec_drv->ignore_pmdown_time; - codec->dapm.codec = codec; + codec->dapm.idle_bias_off = codec_drv->idle_bias_off; + codec->dapm.suspend_bias_off = codec_drv->suspend_bias_off; if (codec_drv->seq_notifier) codec->dapm.seq_notifier = codec_drv->seq_notifier; if (codec_drv->set_bias_level) @@ -4455,23 +4364,13 @@ int snd_soc_register_codec(struct device *dev, codec->component.val_bytes = codec_drv->reg_word_size; mutex_init(&codec->mutex); - if (!codec->component.write) { - if (codec_drv->get_regmap) - regmap = codec_drv->get_regmap(dev); - else - regmap = dev_get_regmap(dev, NULL); - - if (regmap) { - ret = snd_soc_component_init_io(&codec->component, - regmap); - if (ret) { - dev_err(codec->dev, - "Failed to set cache I/O:%d\n", - ret); - goto err_cleanup; - } - } - } +#ifdef CONFIG_DEBUG_FS + codec->component.init_debugfs = soc_init_codec_debugfs; + codec->component.debugfs_prefix = "codec"; +#endif + + if (codec_drv->get_regmap) + codec->component.regmap = codec_drv->get_regmap(dev); for (i = 0; i < num_dai; i++) { fixup_codec_formats(&dai_drv[i].playback); diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 8348352dc2c6..2c456a376ade 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -326,12 +326,13 @@ static struct list_head *dapm_kcontrol_get_path_list( list_for_each_entry(path, dapm_kcontrol_get_path_list(kcontrol), \ list_kcontrol) -static unsigned int dapm_kcontrol_get_value(const struct snd_kcontrol *kcontrol) +unsigned int dapm_kcontrol_get_value(const struct snd_kcontrol *kcontrol) { struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol); return data->value; } +EXPORT_SYMBOL_GPL(dapm_kcontrol_get_value); static bool dapm_kcontrol_set_value(const struct snd_kcontrol *kcontrol, unsigned int value) @@ -1683,6 +1684,22 @@ static void dapm_power_one_widget(struct snd_soc_dapm_widget *w, } } +static bool dapm_idle_bias_off(struct snd_soc_dapm_context *dapm) +{ + if (dapm->idle_bias_off) + return true; + + switch (snd_power_get_state(dapm->card->snd_card)) { + case SNDRV_CTL_POWER_D3hot: + case SNDRV_CTL_POWER_D3cold: + return dapm->suspend_bias_off; + default: + break; + } + + return false; +} + /* * Scan each dapm widget for complete audio path. * A complete path is a route that has valid endpoints i.e.:- @@ -1706,7 +1723,7 @@ static int dapm_power_widgets(struct snd_soc_card *card, int event) trace_snd_soc_dapm_start(card); list_for_each_entry(d, &card->dapm_list, list) { - if (d->idle_bias_off) + if (dapm_idle_bias_off(d)) d->target_bias_level = SND_SOC_BIAS_OFF; else d->target_bias_level = SND_SOC_BIAS_STANDBY; @@ -1772,7 +1789,7 @@ static int dapm_power_widgets(struct snd_soc_card *card, int event) if (d->target_bias_level > bias) bias = d->target_bias_level; list_for_each_entry(d, &card->dapm_list, list) - if (!d->idle_bias_off) + if (!dapm_idle_bias_off(d)) d->target_bias_level = bias; trace_snd_soc_dapm_walk_done(card); @@ -2860,12 +2877,14 @@ int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol, struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol); struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; unsigned int reg_val, val; - int ret = 0; - if (e->reg != SND_SOC_NOPM) - ret = soc_dapm_read(dapm, e->reg, ®_val); - else + if (e->reg != SND_SOC_NOPM) { + int ret = soc_dapm_read(dapm, e->reg, ®_val); + if (ret) + return ret; + } else { reg_val = dapm_kcontrol_get_value(kcontrol); + } val = (reg_val >> e->shift_l) & e->mask; ucontrol->value.enumerated.item[0] = snd_soc_enum_val_to_item(e, val); @@ -2875,7 +2894,7 @@ int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol, ucontrol->value.enumerated.item[1] = val; } - return ret; + return 0; } EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_double); @@ -3107,7 +3126,8 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, } w->dapm = dapm; - w->codec = dapm->codec; + if (dapm->component) + w->codec = dapm->component->codec; INIT_LIST_HEAD(&w->sources); INIT_LIST_HEAD(&w->sinks); INIT_LIST_HEAD(&w->list); diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c index 6307f85e871b..b329b84bc5af 100644 --- a/sound/soc/soc-generic-dmaengine-pcm.c +++ b/sound/soc/soc-generic-dmaengine-pcm.c @@ -336,10 +336,12 @@ static const struct snd_pcm_ops dmaengine_pcm_ops = { }; static const struct snd_soc_platform_driver dmaengine_pcm_platform = { + .component_driver = { + .probe_order = SND_SOC_COMP_ORDER_LATE, + }, .ops = &dmaengine_pcm_ops, .pcm_new = dmaengine_pcm_new, .pcm_free = dmaengine_pcm_free, - .probe_order = SND_SOC_COMP_ORDER_LATE, }; static const char * const dmaengine_pcm_dma_channel_names[] = { diff --git a/sound/soc/soc-io.c b/sound/soc/soc-io.c index 7767fbd73eb7..9b3939049cef 100644 --- a/sound/soc/soc-io.c +++ b/sound/soc/soc-io.c @@ -271,31 +271,3 @@ int snd_soc_platform_write(struct snd_soc_platform *platform, return snd_soc_component_write(&platform->component, reg, val); } EXPORT_SYMBOL_GPL(snd_soc_platform_write); - -/** - * snd_soc_component_init_io() - Initialize regmap IO - * - * @component: component to initialize - * @regmap: regmap instance to use for IO operations - * - * Return: 0 on success, a negative error code otherwise - */ -int snd_soc_component_init_io(struct snd_soc_component *component, - struct regmap *regmap) -{ - int ret; - - if (!regmap) - return -EINVAL; - - ret = regmap_get_val_bytes(regmap); - /* Errors are legitimate for non-integer byte - * multiples */ - if (ret > 0) - component->val_bytes = ret; - - component->regmap = regmap; - - return 0; -} -EXPORT_SYMBOL_GPL(snd_soc_component_init_io); diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 731fdb5b5f9b..642c86240752 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -2352,7 +2352,11 @@ static int dpcm_fe_dai_open(struct snd_pcm_substream *fe_substream) mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); fe->dpcm[stream].runtime = fe_substream->runtime; - if (dpcm_path_get(fe, stream, &list) <= 0) { + ret = dpcm_path_get(fe, stream, &list); + if (ret < 0) { + mutex_unlock(&fe->card->mutex); + return ret; + } else if (ret == 0) { dev_dbg(fe->dev, "ASoC: %s no valid %s route\n", fe->dai_link->name, stream ? "capture" : "playback"); } diff --git a/sound/soc/spear/spear_pcm.c b/sound/soc/spear/spear_pcm.c index 0e5a8f35d0ad..a7dc3c56f44d 100644 --- a/sound/soc/spear/spear_pcm.c +++ b/sound/soc/spear/spear_pcm.c @@ -4,7 +4,7 @@ * sound/soc/spear/spear_pcm.c * * Copyright (C) 2012 ST Microelectronics - * Rajeev Kumar<rajeev-dlh.kumar@st.com> + * Rajeev Kumar<rajeevkumar.linux@gmail.com> * * This file is licensed under the terms of the GNU General Public * License version 2. This program is licensed "as is" without any @@ -50,6 +50,6 @@ int devm_spear_pcm_platform_register(struct device *dev, } EXPORT_SYMBOL_GPL(devm_spear_pcm_platform_register); -MODULE_AUTHOR("Rajeev Kumar <rajeev-dlh.kumar@st.com>"); +MODULE_AUTHOR("Rajeev Kumar <rajeevkumar.linux@gmail.com>"); MODULE_DESCRIPTION("SPEAr PCM DMA module"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/tegra/tegra_asoc_utils.h b/sound/soc/tegra/tegra_asoc_utils.h index 9577121ce971..ca8037634100 100644 --- a/sound/soc/tegra/tegra_asoc_utils.h +++ b/sound/soc/tegra/tegra_asoc_utils.h @@ -21,7 +21,7 @@ */ #ifndef __TEGRA_ASOC_UTILS_H__ -#define __TEGRA_ASOC_UTILS_H_ +#define __TEGRA_ASOC_UTILS_H__ struct clk; struct device; diff --git a/sound/sparc/dbri.c b/sound/sparc/dbri.c index be1b1aa96b7e..b2c3d0d5dca3 100644 --- a/sound/sparc/dbri.c +++ b/sound/sparc/dbri.c @@ -2534,12 +2534,10 @@ static int snd_dbri_create(struct snd_card *card, dbri->op = op; dbri->irq = irq; - dbri->dma = dma_alloc_coherent(&op->dev, - sizeof(struct dbri_dma), - &dbri->dma_dvma, GFP_ATOMIC); + dbri->dma = dma_zalloc_coherent(&op->dev, sizeof(struct dbri_dma), + &dbri->dma_dvma, GFP_ATOMIC); if (!dbri->dma) return -ENOMEM; - memset((void *)dbri->dma, 0, sizeof(struct dbri_dma)); dprintk(D_GEN, "DMA Cmd Block 0x%p (0x%08x)\n", dbri->dma, dbri->dma_dvma); diff --git a/sound/usb/caiaq/control.c b/sound/usb/caiaq/control.c index f65fc0987cfb..b7a7c805d63f 100644 --- a/sound/usb/caiaq/control.c +++ b/sound/usb/caiaq/control.c @@ -100,15 +100,19 @@ static int control_put(struct snd_kcontrol *kcontrol, struct snd_usb_caiaqdev *cdev = caiaqdev(chip->card); int pos = kcontrol->private_value; int v = ucontrol->value.integer.value[0]; - unsigned char cmd = EP1_CMD_WRITE_IO; + unsigned char cmd; - if (cdev->chip.usb_id == - USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1)) - cmd = EP1_CMD_DIMM_LEDS; - - if (cdev->chip.usb_id == - USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_MASCHINECONTROLLER)) + switch (cdev->chip.usb_id) { + case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_MASCHINECONTROLLER): + case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1): + case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER2): + case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER): cmd = EP1_CMD_DIMM_LEDS; + break; + default: + cmd = EP1_CMD_WRITE_IO; + break; + } if (pos & CNT_INTVAL) { int i = pos & ~CNT_INTVAL; diff --git a/sound/usb/card.c b/sound/usb/card.c index a09e5f3519e3..7ecd0e8a5c51 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c @@ -680,6 +680,7 @@ static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message) struct snd_usb_audio *chip = usb_get_intfdata(intf); struct snd_usb_stream *as; struct usb_mixer_interface *mixer; + struct list_head *p; if (chip == (void *)-1L) return 0; @@ -692,6 +693,9 @@ static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message) as->substream[0].need_setup_ep = as->substream[1].need_setup_ep = true; } + list_for_each(p, &chip->midi_list) { + snd_usbmidi_suspend(p); + } } } else { /* @@ -713,6 +717,7 @@ static int __usb_audio_resume(struct usb_interface *intf, bool reset_resume) { struct snd_usb_audio *chip = usb_get_intfdata(intf); struct usb_mixer_interface *mixer; + struct list_head *p; int err = 0; if (chip == (void *)-1L) @@ -731,6 +736,10 @@ static int __usb_audio_resume(struct usb_interface *intf, bool reset_resume) goto err_out; } + list_for_each(p, &chip->midi_list) { + snd_usbmidi_resume(p); + } + if (!chip->autosuspended) snd_power_change_state(chip->card, SNDRV_CTL_POWER_D0); chip->autosuspended = 0; diff --git a/sound/usb/midi.c b/sound/usb/midi.c index 9da74d2e8eee..7b166c2be0f7 100644 --- a/sound/usb/midi.c +++ b/sound/usb/midi.c @@ -102,8 +102,8 @@ struct usb_protocol_ops { void (*input)(struct snd_usb_midi_in_endpoint*, uint8_t*, int); void (*output)(struct snd_usb_midi_out_endpoint *ep, struct urb *urb); void (*output_packet)(struct urb*, uint8_t, uint8_t, uint8_t, uint8_t); - void (*init_out_endpoint)(struct snd_usb_midi_out_endpoint*); - void (*finish_out_endpoint)(struct snd_usb_midi_out_endpoint*); + void (*init_out_endpoint)(struct snd_usb_midi_out_endpoint *); + void (*finish_out_endpoint)(struct snd_usb_midi_out_endpoint *); }; struct snd_usb_midi { @@ -112,7 +112,7 @@ struct snd_usb_midi { struct usb_interface *iface; const struct snd_usb_audio_quirk *quirk; struct snd_rawmidi *rmidi; - struct usb_protocol_ops* usb_protocol_ops; + struct usb_protocol_ops *usb_protocol_ops; struct list_head list; struct timer_list error_timer; spinlock_t disc_lock; @@ -134,7 +134,7 @@ struct snd_usb_midi { }; struct snd_usb_midi_out_endpoint { - struct snd_usb_midi* umidi; + struct snd_usb_midi *umidi; struct out_urb_context { struct urb *urb; struct snd_usb_midi_out_endpoint *ep; @@ -147,7 +147,7 @@ struct snd_usb_midi_out_endpoint { spinlock_t buffer_lock; struct usbmidi_out_port { - struct snd_usb_midi_out_endpoint* ep; + struct snd_usb_midi_out_endpoint *ep; struct snd_rawmidi_substream *substream; int active; uint8_t cable; /* cable number << 4 */ @@ -167,8 +167,8 @@ struct snd_usb_midi_out_endpoint { }; struct snd_usb_midi_in_endpoint { - struct snd_usb_midi* umidi; - struct urb* urbs[INPUT_URBS]; + struct snd_usb_midi *umidi; + struct urb *urbs[INPUT_URBS]; struct usbmidi_in_port { struct snd_rawmidi_substream *substream; u8 running_status_length; @@ -178,7 +178,7 @@ struct snd_usb_midi_in_endpoint { int current_port; }; -static void snd_usbmidi_do_output(struct snd_usb_midi_out_endpoint* ep); +static void snd_usbmidi_do_output(struct snd_usb_midi_out_endpoint *ep); static const uint8_t snd_usbmidi_cin_length[] = { 0, 0, 2, 3, 3, 1, 2, 3, 3, 3, 3, 3, 2, 2, 3, 1 @@ -187,7 +187,7 @@ static const uint8_t snd_usbmidi_cin_length[] = { /* * Submits the URB, with error handling. */ -static int snd_usbmidi_submit_urb(struct urb* urb, gfp_t flags) +static int snd_usbmidi_submit_urb(struct urb *urb, gfp_t flags) { int err = usb_submit_urb(urb, flags); if (err < 0 && err != -ENODEV) @@ -221,10 +221,10 @@ static int snd_usbmidi_urb_error(const struct urb *urb) /* * Receives a chunk of MIDI data. */ -static void snd_usbmidi_input_data(struct snd_usb_midi_in_endpoint* ep, int portidx, - uint8_t* data, int length) +static void snd_usbmidi_input_data(struct snd_usb_midi_in_endpoint *ep, + int portidx, uint8_t *data, int length) { - struct usbmidi_in_port* port = &ep->ports[portidx]; + struct usbmidi_in_port *port = &ep->ports[portidx]; if (!port->substream) { dev_dbg(&ep->umidi->dev->dev, "unexpected port %d!\n", portidx); @@ -250,9 +250,9 @@ static void dump_urb(const char *type, const u8 *data, int length) /* * Processes the data read from the device. */ -static void snd_usbmidi_in_urb_complete(struct urb* urb) +static void snd_usbmidi_in_urb_complete(struct urb *urb) { - struct snd_usb_midi_in_endpoint* ep = urb->context; + struct snd_usb_midi_in_endpoint *ep = urb->context; if (urb->status == 0) { dump_urb("received", urb->transfer_buffer, urb->actual_length); @@ -274,10 +274,10 @@ static void snd_usbmidi_in_urb_complete(struct urb* urb) snd_usbmidi_submit_urb(urb, GFP_ATOMIC); } -static void snd_usbmidi_out_urb_complete(struct urb* urb) +static void snd_usbmidi_out_urb_complete(struct urb *urb) { struct out_urb_context *context = urb->context; - struct snd_usb_midi_out_endpoint* ep = context->ep; + struct snd_usb_midi_out_endpoint *ep = context->ep; unsigned int urb_index; spin_lock(&ep->buffer_lock); @@ -304,10 +304,10 @@ static void snd_usbmidi_out_urb_complete(struct urb* urb) * This is called when some data should be transferred to the device * (from one or more substreams). */ -static void snd_usbmidi_do_output(struct snd_usb_midi_out_endpoint* ep) +static void snd_usbmidi_do_output(struct snd_usb_midi_out_endpoint *ep) { unsigned int urb_index; - struct urb* urb; + struct urb *urb; unsigned long flags; spin_lock_irqsave(&ep->buffer_lock, flags); @@ -343,7 +343,8 @@ static void snd_usbmidi_do_output(struct snd_usb_midi_out_endpoint* ep) static void snd_usbmidi_out_tasklet(unsigned long data) { - struct snd_usb_midi_out_endpoint* ep = (struct snd_usb_midi_out_endpoint *) data; + struct snd_usb_midi_out_endpoint *ep = + (struct snd_usb_midi_out_endpoint *) data; snd_usbmidi_do_output(ep); } @@ -375,7 +376,7 @@ static void snd_usbmidi_error_timer(unsigned long data) } /* helper function to send static data that may not DMA-able */ -static int send_bulk_static_data(struct snd_usb_midi_out_endpoint* ep, +static int send_bulk_static_data(struct snd_usb_midi_out_endpoint *ep, const void *data, int len) { int err = 0; @@ -396,8 +397,8 @@ static int send_bulk_static_data(struct snd_usb_midi_out_endpoint* ep, * fourth byte in each packet, and uses length instead of CIN. */ -static void snd_usbmidi_standard_input(struct snd_usb_midi_in_endpoint* ep, - uint8_t* buffer, int buffer_length) +static void snd_usbmidi_standard_input(struct snd_usb_midi_in_endpoint *ep, + uint8_t *buffer, int buffer_length) { int i; @@ -405,12 +406,13 @@ static void snd_usbmidi_standard_input(struct snd_usb_midi_in_endpoint* ep, if (buffer[i] != 0) { int cable = buffer[i] >> 4; int length = snd_usbmidi_cin_length[buffer[i] & 0x0f]; - snd_usbmidi_input_data(ep, cable, &buffer[i + 1], length); + snd_usbmidi_input_data(ep, cable, &buffer[i + 1], + length); } } -static void snd_usbmidi_midiman_input(struct snd_usb_midi_in_endpoint* ep, - uint8_t* buffer, int buffer_length) +static void snd_usbmidi_midiman_input(struct snd_usb_midi_in_endpoint *ep, + uint8_t *buffer, int buffer_length) { int i; @@ -427,8 +429,8 @@ static void snd_usbmidi_midiman_input(struct snd_usb_midi_in_endpoint* ep, * the data bytes but not the status byte and that is marked with CIN 4. */ static void snd_usbmidi_maudio_broken_running_status_input( - struct snd_usb_midi_in_endpoint* ep, - uint8_t* buffer, int buffer_length) + struct snd_usb_midi_in_endpoint *ep, + uint8_t *buffer, int buffer_length) { int i; @@ -458,7 +460,8 @@ static void snd_usbmidi_maudio_broken_running_status_input( * doesn't use this format.) */ port->running_status_length = 0; - snd_usbmidi_input_data(ep, cable, &buffer[i + 1], length); + snd_usbmidi_input_data(ep, cable, &buffer[i + 1], + length); } } @@ -479,11 +482,13 @@ static void snd_usbmidi_cme_input(struct snd_usb_midi_in_endpoint *ep, /* * Adds one USB MIDI packet to the output buffer. */ -static void snd_usbmidi_output_standard_packet(struct urb* urb, uint8_t p0, - uint8_t p1, uint8_t p2, uint8_t p3) +static void snd_usbmidi_output_standard_packet(struct urb *urb, uint8_t p0, + uint8_t p1, uint8_t p2, + uint8_t p3) { - uint8_t* buf = (uint8_t*)urb->transfer_buffer + urb->transfer_buffer_length; + uint8_t *buf = + (uint8_t *)urb->transfer_buffer + urb->transfer_buffer_length; buf[0] = p0; buf[1] = p1; buf[2] = p2; @@ -494,11 +499,13 @@ static void snd_usbmidi_output_standard_packet(struct urb* urb, uint8_t p0, /* * Adds one Midiman packet to the output buffer. */ -static void snd_usbmidi_output_midiman_packet(struct urb* urb, uint8_t p0, - uint8_t p1, uint8_t p2, uint8_t p3) +static void snd_usbmidi_output_midiman_packet(struct urb *urb, uint8_t p0, + uint8_t p1, uint8_t p2, + uint8_t p3) { - uint8_t* buf = (uint8_t*)urb->transfer_buffer + urb->transfer_buffer_length; + uint8_t *buf = + (uint8_t *)urb->transfer_buffer + urb->transfer_buffer_length; buf[0] = p1; buf[1] = p2; buf[2] = p3; @@ -509,8 +516,8 @@ static void snd_usbmidi_output_midiman_packet(struct urb* urb, uint8_t p0, /* * Converts MIDI commands to USB MIDI packets. */ -static void snd_usbmidi_transmit_byte(struct usbmidi_out_port* port, - uint8_t b, struct urb* urb) +static void snd_usbmidi_transmit_byte(struct usbmidi_out_port *port, + uint8_t b, struct urb *urb) { uint8_t p0 = port->cable; void (*output_packet)(struct urb*, uint8_t, uint8_t, uint8_t, uint8_t) = @@ -547,10 +554,12 @@ static void snd_usbmidi_transmit_byte(struct usbmidi_out_port* port, output_packet(urb, p0 | 0x05, 0xf7, 0, 0); break; case STATE_SYSEX_1: - output_packet(urb, p0 | 0x06, port->data[0], 0xf7, 0); + output_packet(urb, p0 | 0x06, port->data[0], + 0xf7, 0); break; case STATE_SYSEX_2: - output_packet(urb, p0 | 0x07, port->data[0], port->data[1], 0xf7); + output_packet(urb, p0 | 0x07, port->data[0], + port->data[1], 0xf7); break; } port->state = STATE_UNKNOWN; @@ -596,21 +605,22 @@ static void snd_usbmidi_transmit_byte(struct usbmidi_out_port* port, port->state = STATE_SYSEX_2; break; case STATE_SYSEX_2: - output_packet(urb, p0 | 0x04, port->data[0], port->data[1], b); + output_packet(urb, p0 | 0x04, port->data[0], + port->data[1], b); port->state = STATE_SYSEX_0; break; } } } -static void snd_usbmidi_standard_output(struct snd_usb_midi_out_endpoint* ep, +static void snd_usbmidi_standard_output(struct snd_usb_midi_out_endpoint *ep, struct urb *urb) { int p; /* FIXME: lower-numbered ports can starve higher-numbered ports */ for (p = 0; p < 0x10; ++p) { - struct usbmidi_out_port* port = &ep->ports[p]; + struct usbmidi_out_port *port = &ep->ports[p]; if (!port->active) continue; while (urb->transfer_buffer_length + 3 < ep->max_transfer) { @@ -753,18 +763,18 @@ static struct usb_protocol_ops snd_usbmidi_akai_ops = { * at the third byte. */ -static void snd_usbmidi_novation_input(struct snd_usb_midi_in_endpoint* ep, - uint8_t* buffer, int buffer_length) +static void snd_usbmidi_novation_input(struct snd_usb_midi_in_endpoint *ep, + uint8_t *buffer, int buffer_length) { if (buffer_length < 2 || !buffer[0] || buffer_length < buffer[0] + 1) return; snd_usbmidi_input_data(ep, 0, &buffer[2], buffer[0] - 1); } -static void snd_usbmidi_novation_output(struct snd_usb_midi_out_endpoint* ep, +static void snd_usbmidi_novation_output(struct snd_usb_midi_out_endpoint *ep, struct urb *urb) { - uint8_t* transfer_buffer; + uint8_t *transfer_buffer; int count; if (!ep->ports[0].active) @@ -791,13 +801,13 @@ static struct usb_protocol_ops snd_usbmidi_novation_ops = { * "raw" protocol: just move raw MIDI bytes from/to the endpoint */ -static void snd_usbmidi_raw_input(struct snd_usb_midi_in_endpoint* ep, - uint8_t* buffer, int buffer_length) +static void snd_usbmidi_raw_input(struct snd_usb_midi_in_endpoint *ep, + uint8_t *buffer, int buffer_length) { snd_usbmidi_input_data(ep, 0, buffer, buffer_length); } -static void snd_usbmidi_raw_output(struct snd_usb_midi_out_endpoint* ep, +static void snd_usbmidi_raw_output(struct snd_usb_midi_out_endpoint *ep, struct urb *urb) { int count; @@ -823,8 +833,8 @@ static struct usb_protocol_ops snd_usbmidi_raw_ops = { * FTDI protocol: raw MIDI bytes, but input packets have two modem status bytes. */ -static void snd_usbmidi_ftdi_input(struct snd_usb_midi_in_endpoint* ep, - uint8_t* buffer, int buffer_length) +static void snd_usbmidi_ftdi_input(struct snd_usb_midi_in_endpoint *ep, + uint8_t *buffer, int buffer_length) { if (buffer_length > 2) snd_usbmidi_input_data(ep, 0, buffer + 2, buffer_length - 2); @@ -883,7 +893,7 @@ static struct usb_protocol_ops snd_usbmidi_122l_ops = { * Emagic USB MIDI protocol: raw MIDI with "F5 xx" port switching. */ -static void snd_usbmidi_emagic_init_out(struct snd_usb_midi_out_endpoint* ep) +static void snd_usbmidi_emagic_init_out(struct snd_usb_midi_out_endpoint *ep) { static const u8 init_data[] = { /* initialization magic: "get version" */ @@ -900,7 +910,7 @@ static void snd_usbmidi_emagic_init_out(struct snd_usb_midi_out_endpoint* ep) send_bulk_static_data(ep, init_data, sizeof(init_data)); } -static void snd_usbmidi_emagic_finish_out(struct snd_usb_midi_out_endpoint* ep) +static void snd_usbmidi_emagic_finish_out(struct snd_usb_midi_out_endpoint *ep) { static const u8 finish_data[] = { /* switch to patch mode with last preset */ @@ -916,8 +926,8 @@ static void snd_usbmidi_emagic_finish_out(struct snd_usb_midi_out_endpoint* ep) send_bulk_static_data(ep, finish_data, sizeof(finish_data)); } -static void snd_usbmidi_emagic_input(struct snd_usb_midi_in_endpoint* ep, - uint8_t* buffer, int buffer_length) +static void snd_usbmidi_emagic_input(struct snd_usb_midi_in_endpoint *ep, + uint8_t *buffer, int buffer_length) { int i; @@ -960,18 +970,18 @@ static void snd_usbmidi_emagic_input(struct snd_usb_midi_in_endpoint* ep, } } -static void snd_usbmidi_emagic_output(struct snd_usb_midi_out_endpoint* ep, +static void snd_usbmidi_emagic_output(struct snd_usb_midi_out_endpoint *ep, struct urb *urb) { int port0 = ep->current_port; - uint8_t* buf = urb->transfer_buffer; + uint8_t *buf = urb->transfer_buffer; int buf_free = ep->max_transfer; int length, i; for (i = 0; i < 0x10; ++i) { /* round-robin, starting at the last current port */ int portnum = (port0 + i) & 15; - struct usbmidi_out_port* port = &ep->ports[portnum]; + struct usbmidi_out_port *port = &ep->ports[portnum]; if (!port->active) continue; @@ -1015,7 +1025,7 @@ static struct usb_protocol_ops snd_usbmidi_emagic_ops = { }; -static void update_roland_altsetting(struct snd_usb_midi* umidi) +static void update_roland_altsetting(struct snd_usb_midi *umidi) { struct usb_interface *intf; struct usb_host_interface *hostif; @@ -1037,7 +1047,7 @@ static void update_roland_altsetting(struct snd_usb_midi* umidi) static int substream_open(struct snd_rawmidi_substream *substream, int dir, int open) { - struct snd_usb_midi* umidi = substream->rmidi->private_data; + struct snd_usb_midi *umidi = substream->rmidi->private_data; struct snd_kcontrol *ctl; down_read(&umidi->disc_rwsem); @@ -1051,7 +1061,8 @@ static int substream_open(struct snd_rawmidi_substream *substream, int dir, if (!umidi->opened[0] && !umidi->opened[1]) { if (umidi->roland_load_ctl) { ctl = umidi->roland_load_ctl; - ctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE; + ctl->vd[0].access |= + SNDRV_CTL_ELEM_ACCESS_INACTIVE; snd_ctl_notify(umidi->card, SNDRV_CTL_EVENT_MASK_INFO, &ctl->id); update_roland_altsetting(umidi); @@ -1067,7 +1078,8 @@ static int substream_open(struct snd_rawmidi_substream *substream, int dir, if (!umidi->opened[0] && !umidi->opened[1]) { if (umidi->roland_load_ctl) { ctl = umidi->roland_load_ctl; - ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE; + ctl->vd[0].access &= + ~SNDRV_CTL_ELEM_ACCESS_INACTIVE; snd_ctl_notify(umidi->card, SNDRV_CTL_EVENT_MASK_INFO, &ctl->id); } @@ -1080,8 +1092,8 @@ static int substream_open(struct snd_rawmidi_substream *substream, int dir, static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream) { - struct snd_usb_midi* umidi = substream->rmidi->private_data; - struct usbmidi_out_port* port = NULL; + struct snd_usb_midi *umidi = substream->rmidi->private_data; + struct usbmidi_out_port *port = NULL; int i, j; for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) @@ -1106,9 +1118,11 @@ static int snd_usbmidi_output_close(struct snd_rawmidi_substream *substream) return substream_open(substream, 0, 0); } -static void snd_usbmidi_output_trigger(struct snd_rawmidi_substream *substream, int up) +static void snd_usbmidi_output_trigger(struct snd_rawmidi_substream *substream, + int up) { - struct usbmidi_out_port* port = (struct usbmidi_out_port*)substream->runtime->private_data; + struct usbmidi_out_port *port = + (struct usbmidi_out_port *)substream->runtime->private_data; port->active = up; if (up) { @@ -1125,7 +1139,7 @@ static void snd_usbmidi_output_trigger(struct snd_rawmidi_substream *substream, static void snd_usbmidi_output_drain(struct snd_rawmidi_substream *substream) { - struct usbmidi_out_port* port = substream->runtime->private_data; + struct usbmidi_out_port *port = substream->runtime->private_data; struct snd_usb_midi_out_endpoint *ep = port->ep; unsigned int drain_urbs; DEFINE_WAIT(wait); @@ -1164,9 +1178,10 @@ static int snd_usbmidi_input_close(struct snd_rawmidi_substream *substream) return substream_open(substream, 1, 0); } -static void snd_usbmidi_input_trigger(struct snd_rawmidi_substream *substream, int up) +static void snd_usbmidi_input_trigger(struct snd_rawmidi_substream *substream, + int up) { - struct snd_usb_midi* umidi = substream->rmidi->private_data; + struct snd_usb_midi *umidi = substream->rmidi->private_data; if (up) set_bit(substream->number, &umidi->input_triggered); @@ -1199,7 +1214,7 @@ static void free_urb_and_buffer(struct snd_usb_midi *umidi, struct urb *urb, * Frees an input endpoint. * May be called when ep hasn't been initialized completely. */ -static void snd_usbmidi_in_endpoint_delete(struct snd_usb_midi_in_endpoint* ep) +static void snd_usbmidi_in_endpoint_delete(struct snd_usb_midi_in_endpoint *ep) { unsigned int i; @@ -1213,12 +1228,12 @@ static void snd_usbmidi_in_endpoint_delete(struct snd_usb_midi_in_endpoint* ep) /* * Creates an input endpoint. */ -static int snd_usbmidi_in_endpoint_create(struct snd_usb_midi* umidi, - struct snd_usb_midi_endpoint_info* ep_info, - struct snd_usb_midi_endpoint* rep) +static int snd_usbmidi_in_endpoint_create(struct snd_usb_midi *umidi, + struct snd_usb_midi_endpoint_info *ep_info, + struct snd_usb_midi_endpoint *rep) { - struct snd_usb_midi_in_endpoint* ep; - void* buffer; + struct snd_usb_midi_in_endpoint *ep; + void *buffer; unsigned int pipe; int length; unsigned int i; @@ -1289,14 +1304,14 @@ static void snd_usbmidi_out_endpoint_delete(struct snd_usb_midi_out_endpoint *ep /* * Creates an output endpoint, and initializes output ports. */ -static int snd_usbmidi_out_endpoint_create(struct snd_usb_midi* umidi, - struct snd_usb_midi_endpoint_info* ep_info, - struct snd_usb_midi_endpoint* rep) +static int snd_usbmidi_out_endpoint_create(struct snd_usb_midi *umidi, + struct snd_usb_midi_endpoint_info *ep_info, + struct snd_usb_midi_endpoint *rep) { - struct snd_usb_midi_out_endpoint* ep; + struct snd_usb_midi_out_endpoint *ep; unsigned int i; unsigned int pipe; - void* buffer; + void *buffer; rep->out = NULL; ep = kzalloc(sizeof(*ep), GFP_KERNEL); @@ -1381,12 +1396,12 @@ static int snd_usbmidi_out_endpoint_create(struct snd_usb_midi* umidi, /* * Frees everything. */ -static void snd_usbmidi_free(struct snd_usb_midi* umidi) +static void snd_usbmidi_free(struct snd_usb_midi *umidi) { int i; for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) { - struct snd_usb_midi_endpoint* ep = &umidi->endpoints[i]; + struct snd_usb_midi_endpoint *ep = &umidi->endpoints[i]; if (ep->out) snd_usbmidi_out_endpoint_delete(ep->out); if (ep->in) @@ -1399,9 +1414,9 @@ static void snd_usbmidi_free(struct snd_usb_midi* umidi) /* * Unlinks all URBs (must be done before the usb_device is deleted). */ -void snd_usbmidi_disconnect(struct list_head* p) +void snd_usbmidi_disconnect(struct list_head *p) { - struct snd_usb_midi* umidi; + struct snd_usb_midi *umidi; unsigned int i, j; umidi = list_entry(p, struct snd_usb_midi, list); @@ -1417,7 +1432,7 @@ void snd_usbmidi_disconnect(struct list_head* p) up_write(&umidi->disc_rwsem); for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) { - struct snd_usb_midi_endpoint* ep = &umidi->endpoints[i]; + struct snd_usb_midi_endpoint *ep = &umidi->endpoints[i]; if (ep->out) tasklet_kill(&ep->out->tasklet); if (ep->out) { @@ -1448,16 +1463,18 @@ EXPORT_SYMBOL(snd_usbmidi_disconnect); static void snd_usbmidi_rawmidi_free(struct snd_rawmidi *rmidi) { - struct snd_usb_midi* umidi = rmidi->private_data; + struct snd_usb_midi *umidi = rmidi->private_data; snd_usbmidi_free(umidi); } -static struct snd_rawmidi_substream *snd_usbmidi_find_substream(struct snd_usb_midi* umidi, - int stream, int number) +static struct snd_rawmidi_substream *snd_usbmidi_find_substream(struct snd_usb_midi *umidi, + int stream, + int number) { struct snd_rawmidi_substream *substream; - list_for_each_entry(substream, &umidi->rmidi->streams[stream].substreams, list) { + list_for_each_entry(substream, &umidi->rmidi->streams[stream].substreams, + list) { if (substream->number == number) return substream; } @@ -1633,7 +1650,7 @@ static struct port_info { SNDRV_SEQ_PORT_TYPE_SYNTHESIZER), }; -static struct port_info *find_port_info(struct snd_usb_midi* umidi, int number) +static struct port_info *find_port_info(struct snd_usb_midi *umidi, int number) { int i; @@ -1659,16 +1676,18 @@ static void snd_usbmidi_get_port_info(struct snd_rawmidi *rmidi, int number, } } -static void snd_usbmidi_init_substream(struct snd_usb_midi* umidi, +static void snd_usbmidi_init_substream(struct snd_usb_midi *umidi, int stream, int number, - struct snd_rawmidi_substream ** rsubstream) + struct snd_rawmidi_substream **rsubstream) { struct port_info *port_info; const char *name_format; - struct snd_rawmidi_substream *substream = snd_usbmidi_find_substream(umidi, stream, number); + struct snd_rawmidi_substream *substream = + snd_usbmidi_find_substream(umidi, stream, number); if (!substream) { - dev_err(&umidi->dev->dev, "substream %d:%d not found\n", stream, number); + dev_err(&umidi->dev->dev, "substream %d:%d not found\n", stream, + number); return; } @@ -1684,21 +1703,23 @@ static void snd_usbmidi_init_substream(struct snd_usb_midi* umidi, /* * Creates the endpoints and their ports. */ -static int snd_usbmidi_create_endpoints(struct snd_usb_midi* umidi, - struct snd_usb_midi_endpoint_info* endpoints) +static int snd_usbmidi_create_endpoints(struct snd_usb_midi *umidi, + struct snd_usb_midi_endpoint_info *endpoints) { int i, j, err; int out_ports = 0, in_ports = 0; for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) { if (endpoints[i].out_cables) { - err = snd_usbmidi_out_endpoint_create(umidi, &endpoints[i], + err = snd_usbmidi_out_endpoint_create(umidi, + &endpoints[i], &umidi->endpoints[i]); if (err < 0) return err; } if (endpoints[i].in_cables) { - err = snd_usbmidi_in_endpoint_create(umidi, &endpoints[i], + err = snd_usbmidi_in_endpoint_create(umidi, + &endpoints[i], &umidi->endpoints[i]); if (err < 0) return err; @@ -1706,12 +1727,16 @@ static int snd_usbmidi_create_endpoints(struct snd_usb_midi* umidi, for (j = 0; j < 0x10; ++j) { if (endpoints[i].out_cables & (1 << j)) { - snd_usbmidi_init_substream(umidi, SNDRV_RAWMIDI_STREAM_OUTPUT, out_ports, + snd_usbmidi_init_substream(umidi, + SNDRV_RAWMIDI_STREAM_OUTPUT, + out_ports, &umidi->endpoints[i].out->ports[j].substream); ++out_ports; } if (endpoints[i].in_cables & (1 << j)) { - snd_usbmidi_init_substream(umidi, SNDRV_RAWMIDI_STREAM_INPUT, in_ports, + snd_usbmidi_init_substream(umidi, + SNDRV_RAWMIDI_STREAM_INPUT, + in_ports, &umidi->endpoints[i].in->ports[j].substream); ++in_ports; } @@ -1725,16 +1750,16 @@ static int snd_usbmidi_create_endpoints(struct snd_usb_midi* umidi, /* * Returns MIDIStreaming device capabilities. */ -static int snd_usbmidi_get_ms_info(struct snd_usb_midi* umidi, - struct snd_usb_midi_endpoint_info* endpoints) +static int snd_usbmidi_get_ms_info(struct snd_usb_midi *umidi, + struct snd_usb_midi_endpoint_info *endpoints) { - struct usb_interface* intf; + struct usb_interface *intf; struct usb_host_interface *hostif; - struct usb_interface_descriptor* intfd; - struct usb_ms_header_descriptor* ms_header; + struct usb_interface_descriptor *intfd; + struct usb_ms_header_descriptor *ms_header; struct usb_host_endpoint *hostep; - struct usb_endpoint_descriptor* ep; - struct usb_ms_endpoint_descriptor* ms_ep; + struct usb_endpoint_descriptor *ep; + struct usb_ms_endpoint_descriptor *ms_ep; int i, epidx; intf = umidi->iface; @@ -1742,7 +1767,7 @@ static int snd_usbmidi_get_ms_info(struct snd_usb_midi* umidi, return -ENXIO; hostif = &intf->altsetting[0]; intfd = get_iface_desc(hostif); - ms_header = (struct usb_ms_header_descriptor*)hostif->extra; + ms_header = (struct usb_ms_header_descriptor *)hostif->extra; if (hostif->extralen >= 7 && ms_header->bLength >= 7 && ms_header->bDescriptorType == USB_DT_CS_INTERFACE && @@ -1759,7 +1784,7 @@ static int snd_usbmidi_get_ms_info(struct snd_usb_midi* umidi, ep = get_ep_desc(hostep); if (!usb_endpoint_xfer_bulk(ep) && !usb_endpoint_xfer_int(ep)) continue; - ms_ep = (struct usb_ms_endpoint_descriptor*)hostep->extra; + ms_ep = (struct usb_ms_endpoint_descriptor *)hostep->extra; if (hostep->extralen < 4 || ms_ep->bLength < 4 || ms_ep->bDescriptorType != USB_DT_CS_ENDPOINT || @@ -1783,9 +1808,10 @@ static int snd_usbmidi_get_ms_info(struct snd_usb_midi* umidi, * ESI MIDI Mate that try to use them anyway. */ endpoints[epidx].out_interval = 1; - endpoints[epidx].out_cables = (1 << ms_ep->bNumEmbMIDIJack) - 1; + endpoints[epidx].out_cables = + (1 << ms_ep->bNumEmbMIDIJack) - 1; dev_dbg(&umidi->dev->dev, "EP %02X: %d jack(s)\n", - ep->bEndpointAddress, ms_ep->bNumEmbMIDIJack); + ep->bEndpointAddress, ms_ep->bNumEmbMIDIJack); } else { if (endpoints[epidx].in_ep) { if (++epidx >= MIDI_MAX_ENDPOINTS) { @@ -1799,9 +1825,10 @@ static int snd_usbmidi_get_ms_info(struct snd_usb_midi* umidi, endpoints[epidx].in_interval = ep->bInterval; else if (snd_usb_get_speed(umidi->dev) == USB_SPEED_LOW) endpoints[epidx].in_interval = 1; - endpoints[epidx].in_cables = (1 << ms_ep->bNumEmbMIDIJack) - 1; + endpoints[epidx].in_cables = + (1 << ms_ep->bNumEmbMIDIJack) - 1; dev_dbg(&umidi->dev->dev, "EP %02X: %d jack(s)\n", - ep->bEndpointAddress, ms_ep->bNumEmbMIDIJack); + ep->bEndpointAddress, ms_ep->bNumEmbMIDIJack); } } return 0; @@ -1825,7 +1852,7 @@ static int roland_load_get(struct snd_kcontrol *kcontrol, static int roland_load_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *value) { - struct snd_usb_midi* umidi = kcontrol->private_data; + struct snd_usb_midi *umidi = kcontrol->private_data; int changed; if (value->value.enumerated.item[0] > 1) @@ -1851,11 +1878,11 @@ static struct snd_kcontrol_new roland_load_ctl = { * On Roland devices, use the second alternate setting to be able to use * the interrupt input endpoint. */ -static void snd_usbmidi_switch_roland_altsetting(struct snd_usb_midi* umidi) +static void snd_usbmidi_switch_roland_altsetting(struct snd_usb_midi *umidi) { - struct usb_interface* intf; + struct usb_interface *intf; struct usb_host_interface *hostif; - struct usb_interface_descriptor* intfd; + struct usb_interface_descriptor *intfd; intf = umidi->iface; if (!intf || intf->num_altsetting != 2) @@ -1864,8 +1891,10 @@ static void snd_usbmidi_switch_roland_altsetting(struct snd_usb_midi* umidi) hostif = &intf->altsetting[1]; intfd = get_iface_desc(hostif); if (intfd->bNumEndpoints != 2 || - (get_endpoint(hostif, 0)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK || - (get_endpoint(hostif, 1)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT) + (get_endpoint(hostif, 0)->bmAttributes & + USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK || + (get_endpoint(hostif, 1)->bmAttributes & + USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT) return; dev_dbg(&umidi->dev->dev, "switching to altsetting %d with int ep\n", @@ -1881,14 +1910,14 @@ static void snd_usbmidi_switch_roland_altsetting(struct snd_usb_midi* umidi) /* * Try to find any usable endpoints in the interface. */ -static int snd_usbmidi_detect_endpoints(struct snd_usb_midi* umidi, - struct snd_usb_midi_endpoint_info* endpoint, +static int snd_usbmidi_detect_endpoints(struct snd_usb_midi *umidi, + struct snd_usb_midi_endpoint_info *endpoint, int max_endpoints) { - struct usb_interface* intf; + struct usb_interface *intf; struct usb_host_interface *hostif; - struct usb_interface_descriptor* intfd; - struct usb_endpoint_descriptor* epd; + struct usb_interface_descriptor *intfd; + struct usb_endpoint_descriptor *epd; int i, out_eps = 0, in_eps = 0; if (USB_ID_VENDOR(umidi->usb_id) == 0x0582) @@ -1929,8 +1958,8 @@ static int snd_usbmidi_detect_endpoints(struct snd_usb_midi* umidi, /* * Detects the endpoints for one-port-per-endpoint protocols. */ -static int snd_usbmidi_detect_per_port_endpoints(struct snd_usb_midi* umidi, - struct snd_usb_midi_endpoint_info* endpoints) +static int snd_usbmidi_detect_per_port_endpoints(struct snd_usb_midi *umidi, + struct snd_usb_midi_endpoint_info *endpoints) { int err, i; @@ -1947,13 +1976,13 @@ static int snd_usbmidi_detect_per_port_endpoints(struct snd_usb_midi* umidi, /* * Detects the endpoints and ports of Yamaha devices. */ -static int snd_usbmidi_detect_yamaha(struct snd_usb_midi* umidi, - struct snd_usb_midi_endpoint_info* endpoint) +static int snd_usbmidi_detect_yamaha(struct snd_usb_midi *umidi, + struct snd_usb_midi_endpoint_info *endpoint) { - struct usb_interface* intf; + struct usb_interface *intf; struct usb_host_interface *hostif; - struct usb_interface_descriptor* intfd; - uint8_t* cs_desc; + struct usb_interface_descriptor *intfd; + uint8_t *cs_desc; intf = umidi->iface; if (!intf) @@ -1972,9 +2001,11 @@ static int snd_usbmidi_detect_yamaha(struct snd_usb_midi* umidi, cs_desc += cs_desc[0]) { if (cs_desc[1] == USB_DT_CS_INTERFACE) { if (cs_desc[2] == UAC_MIDI_IN_JACK) - endpoint->in_cables = (endpoint->in_cables << 1) | 1; + endpoint->in_cables = + (endpoint->in_cables << 1) | 1; else if (cs_desc[2] == UAC_MIDI_OUT_JACK) - endpoint->out_cables = (endpoint->out_cables << 1) | 1; + endpoint->out_cables = + (endpoint->out_cables << 1) | 1; } } if (!endpoint->in_cables && !endpoint->out_cables) @@ -1986,12 +2017,12 @@ static int snd_usbmidi_detect_yamaha(struct snd_usb_midi* umidi, /* * Detects the endpoints and ports of Roland devices. */ -static int snd_usbmidi_detect_roland(struct snd_usb_midi* umidi, - struct snd_usb_midi_endpoint_info* endpoint) +static int snd_usbmidi_detect_roland(struct snd_usb_midi *umidi, + struct snd_usb_midi_endpoint_info *endpoint) { - struct usb_interface* intf; + struct usb_interface *intf; struct usb_host_interface *hostif; - u8* cs_desc; + u8 *cs_desc; intf = umidi->iface; if (!intf) @@ -2024,14 +2055,14 @@ static int snd_usbmidi_detect_roland(struct snd_usb_midi* umidi, /* * Creates the endpoints and their ports for Midiman devices. */ -static int snd_usbmidi_create_endpoints_midiman(struct snd_usb_midi* umidi, - struct snd_usb_midi_endpoint_info* endpoint) +static int snd_usbmidi_create_endpoints_midiman(struct snd_usb_midi *umidi, + struct snd_usb_midi_endpoint_info *endpoint) { struct snd_usb_midi_endpoint_info ep_info; - struct usb_interface* intf; + struct usb_interface *intf; struct usb_host_interface *hostif; - struct usb_interface_descriptor* intfd; - struct usb_endpoint_descriptor* epd; + struct usb_interface_descriptor *intfd; + struct usb_endpoint_descriptor *epd; int cable, err; intf = umidi->iface; @@ -2068,39 +2099,50 @@ static int snd_usbmidi_create_endpoints_midiman(struct snd_usb_midi* umidi, epd = get_endpoint(hostif, 4); if (!usb_endpoint_dir_out(epd) || !usb_endpoint_xfer_bulk(epd)) { - dev_dbg(&umidi->dev->dev, "endpoint[4] isn't bulk output\n"); + dev_dbg(&umidi->dev->dev, + "endpoint[4] isn't bulk output\n"); return -ENXIO; } } - ep_info.out_ep = get_endpoint(hostif, 2)->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; + ep_info.out_ep = get_endpoint(hostif, 2)->bEndpointAddress & + USB_ENDPOINT_NUMBER_MASK; ep_info.out_interval = 0; ep_info.out_cables = endpoint->out_cables & 0x5555; - err = snd_usbmidi_out_endpoint_create(umidi, &ep_info, &umidi->endpoints[0]); + err = snd_usbmidi_out_endpoint_create(umidi, &ep_info, + &umidi->endpoints[0]); if (err < 0) return err; - ep_info.in_ep = get_endpoint(hostif, 0)->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; + ep_info.in_ep = get_endpoint(hostif, 0)->bEndpointAddress & + USB_ENDPOINT_NUMBER_MASK; ep_info.in_interval = get_endpoint(hostif, 0)->bInterval; ep_info.in_cables = endpoint->in_cables; - err = snd_usbmidi_in_endpoint_create(umidi, &ep_info, &umidi->endpoints[0]); + err = snd_usbmidi_in_endpoint_create(umidi, &ep_info, + &umidi->endpoints[0]); if (err < 0) return err; if (endpoint->out_cables > 0x0001) { - ep_info.out_ep = get_endpoint(hostif, 4)->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; + ep_info.out_ep = get_endpoint(hostif, 4)->bEndpointAddress & + USB_ENDPOINT_NUMBER_MASK; ep_info.out_cables = endpoint->out_cables & 0xaaaa; - err = snd_usbmidi_out_endpoint_create(umidi, &ep_info, &umidi->endpoints[1]); + err = snd_usbmidi_out_endpoint_create(umidi, &ep_info, + &umidi->endpoints[1]); if (err < 0) return err; } for (cable = 0; cable < 0x10; ++cable) { if (endpoint->out_cables & (1 << cable)) - snd_usbmidi_init_substream(umidi, SNDRV_RAWMIDI_STREAM_OUTPUT, cable, + snd_usbmidi_init_substream(umidi, + SNDRV_RAWMIDI_STREAM_OUTPUT, + cable, &umidi->endpoints[cable & 1].out->ports[cable].substream); if (endpoint->in_cables & (1 << cable)) - snd_usbmidi_init_substream(umidi, SNDRV_RAWMIDI_STREAM_INPUT, cable, + snd_usbmidi_init_substream(umidi, + SNDRV_RAWMIDI_STREAM_INPUT, + cable, &umidi->endpoints[0].in->ports[cable].substream); } return 0; @@ -2110,7 +2152,7 @@ static struct snd_rawmidi_global_ops snd_usbmidi_ops = { .get_port_info = snd_usbmidi_get_port_info, }; -static int snd_usbmidi_create_rawmidi(struct snd_usb_midi* umidi, +static int snd_usbmidi_create_rawmidi(struct snd_usb_midi *umidi, int out_ports, int in_ports) { struct snd_rawmidi *rmidi; @@ -2128,8 +2170,10 @@ static int snd_usbmidi_create_rawmidi(struct snd_usb_midi* umidi, rmidi->ops = &snd_usbmidi_ops; rmidi->private_data = umidi; rmidi->private_free = snd_usbmidi_rawmidi_free; - snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_usbmidi_output_ops); - snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_usbmidi_input_ops); + snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, + &snd_usbmidi_output_ops); + snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, + &snd_usbmidi_input_ops); umidi->rmidi = rmidi; return 0; @@ -2138,16 +2182,16 @@ static int snd_usbmidi_create_rawmidi(struct snd_usb_midi* umidi, /* * Temporarily stop input. */ -void snd_usbmidi_input_stop(struct list_head* p) +void snd_usbmidi_input_stop(struct list_head *p) { - struct snd_usb_midi* umidi; + struct snd_usb_midi *umidi; unsigned int i, j; umidi = list_entry(p, struct snd_usb_midi, list); if (!umidi->input_running) return; for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) { - struct snd_usb_midi_endpoint* ep = &umidi->endpoints[i]; + struct snd_usb_midi_endpoint *ep = &umidi->endpoints[i]; if (ep->in) for (j = 0; j < INPUT_URBS; ++j) usb_kill_urb(ep->in->urbs[j]); @@ -2156,14 +2200,14 @@ void snd_usbmidi_input_stop(struct list_head* p) } EXPORT_SYMBOL(snd_usbmidi_input_stop); -static void snd_usbmidi_input_start_ep(struct snd_usb_midi_in_endpoint* ep) +static void snd_usbmidi_input_start_ep(struct snd_usb_midi_in_endpoint *ep) { unsigned int i; if (!ep) return; for (i = 0; i < INPUT_URBS; ++i) { - struct urb* urb = ep->urbs[i]; + struct urb *urb = ep->urbs[i]; urb->dev = ep->umidi->dev; snd_usbmidi_submit_urb(urb, GFP_KERNEL); } @@ -2172,9 +2216,9 @@ static void snd_usbmidi_input_start_ep(struct snd_usb_midi_in_endpoint* ep) /* * Resume input after a call to snd_usbmidi_input_stop(). */ -void snd_usbmidi_input_start(struct list_head* p) +void snd_usbmidi_input_start(struct list_head *p) { - struct snd_usb_midi* umidi; + struct snd_usb_midi *umidi; int i; umidi = list_entry(p, struct snd_usb_midi, list); @@ -2187,14 +2231,42 @@ void snd_usbmidi_input_start(struct list_head* p) EXPORT_SYMBOL(snd_usbmidi_input_start); /* + * Prepare for suspend. Typically called from the USB suspend callback. + */ +void snd_usbmidi_suspend(struct list_head *p) +{ + struct snd_usb_midi *umidi; + + umidi = list_entry(p, struct snd_usb_midi, list); + mutex_lock(&umidi->mutex); + snd_usbmidi_input_stop(p); + mutex_unlock(&umidi->mutex); +} +EXPORT_SYMBOL(snd_usbmidi_suspend); + +/* + * Resume. Typically called from the USB resume callback. + */ +void snd_usbmidi_resume(struct list_head *p) +{ + struct snd_usb_midi *umidi; + + umidi = list_entry(p, struct snd_usb_midi, list); + mutex_lock(&umidi->mutex); + snd_usbmidi_input_start(p); + mutex_unlock(&umidi->mutex); +} +EXPORT_SYMBOL(snd_usbmidi_resume); + +/* * Creates and registers everything needed for a MIDI streaming interface. */ int snd_usbmidi_create(struct snd_card *card, - struct usb_interface* iface, + struct usb_interface *iface, struct list_head *midi_list, - const struct snd_usb_audio_quirk* quirk) + const struct snd_usb_audio_quirk *quirk) { - struct snd_usb_midi* umidi; + struct snd_usb_midi *umidi; struct snd_usb_midi_endpoint_info endpoints[MIDI_MAX_ENDPOINTS]; int out_ports, in_ports; int i, err; @@ -2292,7 +2364,8 @@ int snd_usbmidi_create(struct snd_card *card, err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints); break; default: - dev_err(&umidi->dev->dev, "invalid quirk type %d\n", quirk->type); + dev_err(&umidi->dev->dev, "invalid quirk type %d\n", + quirk->type); err = -ENXIO; break; } diff --git a/sound/usb/midi.h b/sound/usb/midi.h index 2fca80b744c0..ad8a3211f8e7 100644 --- a/sound/usb/midi.h +++ b/sound/usb/midi.h @@ -43,8 +43,10 @@ int snd_usbmidi_create(struct snd_card *card, struct usb_interface *iface, struct list_head *midi_list, const struct snd_usb_audio_quirk *quirk); -void snd_usbmidi_input_stop(struct list_head* p); -void snd_usbmidi_input_start(struct list_head* p); +void snd_usbmidi_input_stop(struct list_head *p); +void snd_usbmidi_input_start(struct list_head *p); void snd_usbmidi_disconnect(struct list_head *p); +void snd_usbmidi_suspend(struct list_head *p); +void snd_usbmidi_resume(struct list_head *p); #endif /* __USBMIDI_H */ diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 0b728d886f0d..2e4a9dbc51fa 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -1340,12 +1340,11 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, */ if (range > 384) { usb_audio_warn(state->chip, - "Warning! Unlikely big volume range (=%u), " - "cval->res is probably wrong.", + "Warning! Unlikely big volume range (=%u), cval->res is probably wrong.", range); - usb_audio_warn(state->chip, "[%d] FU [%s] ch = %d, " - "val = %d/%d/%d", cval->id, - kctl->id.name, cval->channels, + usb_audio_warn(state->chip, + "[%d] FU [%s] ch = %d, val = %d/%d/%d", + cval->id, kctl->id.name, cval->channels, cval->min, cval->max, cval->res); } diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index f652b10ce905..223c47b33ba3 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -1581,6 +1581,35 @@ YAMAHA_DEVICE(0x7010, "UB99"), } }, { + /* BOSS ME-25 */ + USB_DEVICE(0x0582, 0x0113), + .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 = 0, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + }, + { + .ifnum = 1, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + }, + { + .ifnum = 2, + .type = QUIRK_MIDI_FIXED_ENDPOINT, + .data = & (const struct snd_usb_midi_endpoint_info) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } + }, + { + .ifnum = -1 + } + } + } +}, +{ /* only 44.1 kHz works at the moment */ USB_DEVICE(0x0582, 0x0120), .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index 7c57f2268dd7..19a921eb75f1 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -670,7 +670,7 @@ static int snd_usb_gamecon780_boot_quirk(struct usb_device *dev) /* set the initial volume and don't change; other values are either * too loud or silent due to firmware bug (bko#65251) */ - u8 buf[2] = { 0x74, 0xdc }; + u8 buf[2] = { 0x74, 0xe3 }; return snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, UAC_FU_VOLUME << 8, 9 << 8, buf, 2); |