diff options
Diffstat (limited to 'sound')
556 files changed, 24180 insertions, 22541 deletions
diff --git a/sound/Kconfig b/sound/Kconfig index 261a03c8a209..c710ce2c5c37 100644 --- a/sound/Kconfig +++ b/sound/Kconfig @@ -52,9 +52,6 @@ config SOUND_OSS_CORE_PRECLAIM Disabling this allows alternative OSS implementations. - Please read Documentation/feature-removal-schedule.txt for - details. - If unsure, say Y. source "sound/oss/dmasound/Kconfig" diff --git a/sound/arm/aaci.c b/sound/arm/aaci.c index 5119fdabcb98..aa5d8034890b 100644 --- a/sound/arm/aaci.c +++ b/sound/arm/aaci.c @@ -786,7 +786,7 @@ static int aaci_resume(struct amba_device *dev) #endif -static struct ac97_pcm ac97_defs[] __devinitdata = { +static struct ac97_pcm ac97_defs[] = { [0] = { /* Front PCM */ .exclusive = 1, .r = { @@ -832,7 +832,7 @@ static struct snd_ac97_bus_ops aaci_bus_ops = { .read = aaci_ac97_read, }; -static int __devinit aaci_probe_ac97(struct aaci *aaci) +static int aaci_probe_ac97(struct aaci *aaci) { struct snd_ac97_template ac97_template; struct snd_ac97_bus *ac97_bus; @@ -893,7 +893,7 @@ static void aaci_free_card(struct snd_card *card) iounmap(aaci->base); } -static struct aaci * __devinit aaci_init_card(struct amba_device *dev) +static struct aaci *aaci_init_card(struct amba_device *dev) { struct aaci *aaci; struct snd_card *card; @@ -926,7 +926,7 @@ static struct aaci * __devinit aaci_init_card(struct amba_device *dev) return aaci; } -static int __devinit aaci_init_pcm(struct aaci *aaci) +static int aaci_init_pcm(struct aaci *aaci) { struct snd_pcm *pcm; int ret; @@ -948,7 +948,7 @@ static int __devinit aaci_init_pcm(struct aaci *aaci) return ret; } -static unsigned int __devinit aaci_size_fifo(struct aaci *aaci) +static unsigned int aaci_size_fifo(struct aaci *aaci) { struct aaci_runtime *aacirun = &aaci->playback; int i; @@ -984,8 +984,8 @@ static unsigned int __devinit aaci_size_fifo(struct aaci *aaci) return i; } -static int __devinit aaci_probe(struct amba_device *dev, - const struct amba_id *id) +static int aaci_probe(struct amba_device *dev, + const struct amba_id *id) { struct aaci *aaci; int ret, i; @@ -1072,7 +1072,7 @@ static int __devinit aaci_probe(struct amba_device *dev, return ret; } -static int __devexit aaci_remove(struct amba_device *dev) +static int aaci_remove(struct amba_device *dev) { struct snd_card *card = amba_get_drvdata(dev); @@ -1104,7 +1104,7 @@ static struct amba_driver aaci_driver = { .name = DRIVER_NAME, }, .probe = aaci_probe, - .remove = __devexit_p(aaci_remove), + .remove = aaci_remove, .suspend = aaci_suspend, .resume = aaci_resume, .id_table = aaci_ids, diff --git a/sound/arm/pxa2xx-ac97-lib.c b/sound/arm/pxa2xx-ac97-lib.c index 48d7c0aa5073..fff7753e35c1 100644 --- a/sound/arm/pxa2xx-ac97-lib.c +++ b/sound/arm/pxa2xx-ac97-lib.c @@ -18,6 +18,7 @@ #include <linux/delay.h> #include <linux/module.h> #include <linux/io.h> +#include <linux/gpio.h> #include <sound/ac97_codec.h> #include <sound/pxa2xx-lib.h> @@ -148,6 +149,8 @@ static inline void pxa_ac97_warm_pxa27x(void) static inline void pxa_ac97_cold_pxa27x(void) { + unsigned int timeout; + GCR &= GCR_COLD_RST; /* clear everything but nCRST */ GCR &= ~GCR_COLD_RST; /* then assert nCRST */ @@ -157,8 +160,10 @@ static inline void pxa_ac97_cold_pxa27x(void) clk_enable(ac97conf_clk); udelay(5); clk_disable(ac97conf_clk); - GCR = GCR_COLD_RST; - udelay(50); + GCR = GCR_COLD_RST | GCR_WARM_RST; + timeout = 100; /* wait for the codec-ready bit to be set */ + while (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR)) && timeout--) + mdelay(1); } #endif @@ -314,7 +319,7 @@ int pxa2xx_ac97_hw_resume(void) EXPORT_SYMBOL_GPL(pxa2xx_ac97_hw_resume); #endif -int __devinit pxa2xx_ac97_hw_probe(struct platform_device *dev) +int pxa2xx_ac97_hw_probe(struct platform_device *dev) { int ret; pxa2xx_audio_ops_t *pdata = dev->dev.platform_data; @@ -340,8 +345,21 @@ int __devinit pxa2xx_ac97_hw_probe(struct platform_device *dev) } if (cpu_is_pxa27x()) { - /* Use GPIO 113 as AC97 Reset on Bulverde */ + /* + * This gpio is needed for a work-around to a bug in the ac97 + * controller during warm reset. The direction and level is set + * here so that it is an output driven high when switching from + * AC97_nRESET alt function to generic gpio. + */ + ret = gpio_request_one(reset_gpio, GPIOF_OUT_INIT_HIGH, + "pxa27x ac97 reset"); + if (ret < 0) { + pr_err("%s: gpio_request_one() failed: %d\n", + __func__, ret); + goto err_conf; + } pxa27x_assert_ac97reset(reset_gpio, 0); + ac97conf_clk = clk_get(&dev->dev, "AC97CONFCLK"); if (IS_ERR(ac97conf_clk)) { ret = PTR_ERR(ac97conf_clk); @@ -384,6 +402,8 @@ EXPORT_SYMBOL_GPL(pxa2xx_ac97_hw_probe); void pxa2xx_ac97_hw_remove(struct platform_device *dev) { + if (cpu_is_pxa27x()) + gpio_free(reset_gpio); GCR |= GCR_ACLINK_OFF; free_irq(IRQ_AC97, NULL); if (ac97conf_clk) { diff --git a/sound/arm/pxa2xx-ac97.c b/sound/arm/pxa2xx-ac97.c index 4e1fda75c1c9..ec54be4efff0 100644 --- a/sound/arm/pxa2xx-ac97.c +++ b/sound/arm/pxa2xx-ac97.c @@ -163,7 +163,7 @@ static int pxa2xx_ac97_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(pxa2xx_ac97_pm_ops, pxa2xx_ac97_suspend, pxa2xx_ac97_resume); #endif -static int __devinit pxa2xx_ac97_probe(struct platform_device *dev) +static int pxa2xx_ac97_probe(struct platform_device *dev) { struct snd_card *card; struct snd_ac97_bus *ac97_bus; @@ -224,7 +224,7 @@ err_dev: return ret; } -static int __devexit pxa2xx_ac97_remove(struct platform_device *dev) +static int pxa2xx_ac97_remove(struct platform_device *dev) { struct snd_card *card = platform_get_drvdata(dev); @@ -239,7 +239,7 @@ static int __devexit pxa2xx_ac97_remove(struct platform_device *dev) static struct platform_driver pxa2xx_ac97_driver = { .probe = pxa2xx_ac97_probe, - .remove = __devexit_p(pxa2xx_ac97_remove), + .remove = pxa2xx_ac97_remove, .driver = { .name = "pxa2xx-ac97", .owner = THIS_MODULE, diff --git a/sound/atmel/abdac.c b/sound/atmel/abdac.c index 277ebce23a45..071ce1b5f2b4 100644 --- a/sound/atmel/abdac.c +++ b/sound/atmel/abdac.c @@ -309,7 +309,7 @@ static struct snd_pcm_ops atmel_abdac_ops = { .pointer = atmel_abdac_pointer, }; -static int __devinit atmel_abdac_pcm_new(struct atmel_abdac *dac) +static int atmel_abdac_pcm_new(struct atmel_abdac *dac) { struct snd_pcm_hardware hw = atmel_abdac_hw; struct snd_pcm *pcm; @@ -386,7 +386,7 @@ static int set_sample_rates(struct atmel_abdac *dac) return retval; } -static int __devinit atmel_abdac_probe(struct platform_device *pdev) +static int atmel_abdac_probe(struct platform_device *pdev) { struct snd_card *card; struct atmel_abdac *dac; @@ -567,7 +567,7 @@ static SIMPLE_DEV_PM_OPS(atmel_abdac_pm, atmel_abdac_suspend, atmel_abdac_resume #define ATMEL_ABDAC_PM_OPS NULL #endif -static int __devexit atmel_abdac_remove(struct platform_device *pdev) +static int atmel_abdac_remove(struct platform_device *pdev) { struct snd_card *card = platform_get_drvdata(pdev); struct atmel_abdac *dac = get_dac(card); @@ -589,7 +589,7 @@ static int __devexit atmel_abdac_remove(struct platform_device *pdev) } static struct platform_driver atmel_abdac_driver = { - .remove = __devexit_p(atmel_abdac_remove), + .remove = atmel_abdac_remove, .driver = { .name = "atmel_abdac", .owner = THIS_MODULE, diff --git a/sound/atmel/ac97c.c b/sound/atmel/ac97c.c index 9052aff37f64..79d6bda58753 100644 --- a/sound/atmel/ac97c.c +++ b/sound/atmel/ac97c.c @@ -728,7 +728,7 @@ static irqreturn_t atmel_ac97c_interrupt(int irq, void *dev) return retval; } -static struct ac97_pcm at91_ac97_pcm_defs[] __devinitdata = { +static struct ac97_pcm at91_ac97_pcm_defs[] = { /* Playback */ { .exclusive = 1, @@ -756,7 +756,7 @@ static struct ac97_pcm at91_ac97_pcm_defs[] __devinitdata = { }, }; -static int __devinit atmel_ac97c_pcm_new(struct atmel_ac97c *chip) +static int atmel_ac97c_pcm_new(struct atmel_ac97c *chip) { struct snd_pcm *pcm; struct snd_pcm_hardware hw = atmel_ac97c_hw; @@ -902,7 +902,7 @@ static void atmel_ac97c_reset(struct atmel_ac97c *chip) } } -static int __devinit atmel_ac97c_probe(struct platform_device *pdev) +static int atmel_ac97c_probe(struct platform_device *pdev) { struct snd_card *card; struct atmel_ac97c *chip; @@ -1168,7 +1168,7 @@ static SIMPLE_DEV_PM_OPS(atmel_ac97c_pm, atmel_ac97c_suspend, atmel_ac97c_resume #define ATMEL_AC97C_PM_OPS NULL #endif -static int __devexit atmel_ac97c_remove(struct platform_device *pdev) +static int atmel_ac97c_remove(struct platform_device *pdev) { struct snd_card *card = platform_get_drvdata(pdev); struct atmel_ac97c *chip = get_chip(card); @@ -1205,7 +1205,7 @@ static int __devexit atmel_ac97c_remove(struct platform_device *pdev) } static struct platform_driver atmel_ac97c_driver = { - .remove = __devexit_p(atmel_ac97c_remove), + .remove = atmel_ac97c_remove, .driver = { .name = "atmel_ac97c", .owner = THIS_MODULE, diff --git a/sound/core/oss/pcm_plugin.c b/sound/core/oss/pcm_plugin.c index 71cc3ddf5c15..727ac44d39f4 100644 --- a/sound/core/oss/pcm_plugin.c +++ b/sound/core/oss/pcm_plugin.c @@ -199,12 +199,13 @@ int snd_pcm_plugin_free(struct snd_pcm_plugin *plugin) snd_pcm_sframes_t snd_pcm_plug_client_size(struct snd_pcm_substream *plug, snd_pcm_uframes_t drv_frames) { struct snd_pcm_plugin *plugin, *plugin_prev, *plugin_next; - int stream = snd_pcm_plug_stream(plug); + int stream; if (snd_BUG_ON(!plug)) return -ENXIO; if (drv_frames == 0) return 0; + stream = snd_pcm_plug_stream(plug); if (stream == SNDRV_PCM_STREAM_PLAYBACK) { plugin = snd_pcm_plug_last(plug); while (plugin && drv_frames > 0) { @@ -230,13 +231,14 @@ snd_pcm_sframes_t snd_pcm_plug_slave_size(struct snd_pcm_substream *plug, snd_pc { struct snd_pcm_plugin *plugin, *plugin_prev, *plugin_next; snd_pcm_sframes_t frames; - int stream = snd_pcm_plug_stream(plug); + int stream; if (snd_BUG_ON(!plug)) return -ENXIO; if (clt_frames == 0) return 0; frames = clt_frames; + stream = snd_pcm_plug_stream(plug); if (stream == SNDRV_PCM_STREAM_PLAYBACK) { plugin = snd_pcm_plug_first(plug); while (plugin && frames > 0) { diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 030102caeee9..61798f85d030 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -981,8 +981,7 @@ void snd_pcm_detach_substream(struct snd_pcm_substream *substream) PAGE_ALIGN(sizeof(struct snd_pcm_mmap_control))); kfree(runtime->hw_constraints.rules); #ifdef CONFIG_SND_PCM_XRUN_DEBUG - if (runtime->hwptr_log) - kfree(runtime->hwptr_log); + kfree(runtime->hwptr_log); #endif kfree(runtime); substream->runtime = NULL; diff --git a/sound/core/pcm_compat.c b/sound/core/pcm_compat.c index 91cdf9435fec..af49721ba0e3 100644 --- a/sound/core/pcm_compat.c +++ b/sound/core/pcm_compat.c @@ -190,7 +190,9 @@ struct snd_pcm_status32 { u32 avail_max; u32 overrange; s32 suspended_state; - unsigned char reserved[60]; + u32 reserved_alignment; + struct compat_timespec audio_tstamp; + unsigned char reserved[56-sizeof(struct compat_timespec)]; } __attribute__((packed)); @@ -205,17 +207,16 @@ static int snd_pcm_status_user_compat(struct snd_pcm_substream *substream, return err; if (put_user(status.state, &src->state) || - put_user(status.trigger_tstamp.tv_sec, &src->trigger_tstamp.tv_sec) || - put_user(status.trigger_tstamp.tv_nsec, &src->trigger_tstamp.tv_nsec) || - put_user(status.tstamp.tv_sec, &src->tstamp.tv_sec) || - put_user(status.tstamp.tv_nsec, &src->tstamp.tv_nsec) || + compat_put_timespec(&status.trigger_tstamp, &src->trigger_tstamp) || + compat_put_timespec(&status.tstamp, &src->tstamp) || put_user(status.appl_ptr, &src->appl_ptr) || put_user(status.hw_ptr, &src->hw_ptr) || put_user(status.delay, &src->delay) || put_user(status.avail, &src->avail) || put_user(status.avail_max, &src->avail_max) || put_user(status.overrange, &src->overrange) || - put_user(status.suspended_state, &src->suspended_state)) + put_user(status.suspended_state, &src->suspended_state) || + compat_put_timespec(&status.audio_tstamp, &src->audio_tstamp)) return -EFAULT; return err; @@ -364,6 +365,7 @@ struct snd_pcm_mmap_status32 { u32 hw_ptr; struct compat_timespec tstamp; s32 suspended_state; + struct compat_timespec audio_tstamp; } __attribute__((packed)); struct snd_pcm_mmap_control32 { @@ -426,12 +428,14 @@ static int snd_pcm_ioctl_sync_ptr_compat(struct snd_pcm_substream *substream, sstatus.hw_ptr = status->hw_ptr % boundary; sstatus.tstamp = status->tstamp; sstatus.suspended_state = status->suspended_state; + sstatus.audio_tstamp = status->audio_tstamp; snd_pcm_stream_unlock_irq(substream); if (put_user(sstatus.state, &src->s.status.state) || put_user(sstatus.hw_ptr, &src->s.status.hw_ptr) || - put_user(sstatus.tstamp.tv_sec, &src->s.status.tstamp.tv_sec) || - put_user(sstatus.tstamp.tv_nsec, &src->s.status.tstamp.tv_nsec) || + compat_put_timespec(&sstatus.tstamp, &src->s.status.tstamp) || put_user(sstatus.suspended_state, &src->s.status.suspended_state) || + compat_put_timespec(&sstatus.audio_tstamp, + &src->s.status.audio_tstamp) || put_user(scontrol.appl_ptr, &src->c.control.appl_ptr) || put_user(scontrol.avail_min, &src->c.control.avail_min)) return -EFAULT; diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index f42c10a43315..c4840ff75d00 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -316,6 +316,8 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, unsigned long jdelta; unsigned long curr_jiffies; struct timespec curr_tstamp; + struct timespec audio_tstamp; + int crossed_boundary = 0; old_hw_ptr = runtime->status->hw_ptr; @@ -327,9 +329,14 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, */ pos = substream->ops->pointer(substream); curr_jiffies = jiffies; - if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) + if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) { snd_pcm_gettime(runtime, (struct timespec *)&curr_tstamp); + if ((runtime->hw.info & SNDRV_PCM_INFO_HAS_WALL_CLOCK) && + (substream->ops->wall_clock)) + substream->ops->wall_clock(substream, &audio_tstamp); + } + if (pos == SNDRV_PCM_POS_XRUN) { xrun(substream); return -EPIPE; @@ -360,8 +367,10 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, hdelta = curr_jiffies - runtime->hw_ptr_jiffies; if (hdelta > runtime->hw_ptr_buffer_jiffies/2) { hw_base += runtime->buffer_size; - if (hw_base >= runtime->boundary) + if (hw_base >= runtime->boundary) { hw_base = 0; + crossed_boundary++; + } new_hw_ptr = hw_base + pos; goto __delta; } @@ -371,8 +380,10 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, /* pointer crosses the end of the ring buffer */ if (new_hw_ptr < old_hw_ptr) { hw_base += runtime->buffer_size; - if (hw_base >= runtime->boundary) + if (hw_base >= runtime->boundary) { hw_base = 0; + crossed_boundary++; + } new_hw_ptr = hw_base + pos; } __delta: @@ -410,8 +421,10 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, while (hdelta > xrun_threshold) { delta += runtime->buffer_size; hw_base += runtime->buffer_size; - if (hw_base >= runtime->boundary) + if (hw_base >= runtime->boundary) { hw_base = 0; + crossed_boundary++; + } new_hw_ptr = hw_base + pos; hdelta -= runtime->hw_ptr_buffer_jiffies; } @@ -456,8 +469,10 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, /* the delta value is small or zero in most cases */ while (delta > 0) { new_hw_ptr += runtime->period_size; - if (new_hw_ptr >= runtime->boundary) + if (new_hw_ptr >= runtime->boundary) { new_hw_ptr -= runtime->boundary; + crossed_boundary--; + } delta--; } /* align hw_base to buffer_size */ @@ -507,9 +522,35 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, runtime->hw_ptr_base = hw_base; runtime->status->hw_ptr = new_hw_ptr; runtime->hw_ptr_jiffies = curr_jiffies; - if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) + if (crossed_boundary) { + snd_BUG_ON(crossed_boundary != 1); + runtime->hw_ptr_wrap += runtime->boundary; + } + if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) { runtime->status->tstamp = curr_tstamp; + if (!(runtime->hw.info & SNDRV_PCM_INFO_HAS_WALL_CLOCK)) { + /* + * no wall clock available, provide audio timestamp + * derived from pointer position+delay + */ + u64 audio_frames, audio_nsecs; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + audio_frames = runtime->hw_ptr_wrap + + runtime->status->hw_ptr + - runtime->delay; + else + audio_frames = runtime->hw_ptr_wrap + + runtime->status->hw_ptr + + runtime->delay; + audio_nsecs = div_u64(audio_frames * 1000000000LL, + runtime->rate); + audio_tstamp = ns_to_timespec(audio_nsecs); + } + runtime->status->audio_tstamp = audio_tstamp; + } + return snd_pcm_update_state(substream, runtime); } @@ -1661,8 +1702,10 @@ static int snd_pcm_lib_ioctl_reset(struct snd_pcm_substream *substream, if (snd_pcm_running(substream) && snd_pcm_update_hw_ptr(substream) >= 0) runtime->status->hw_ptr %= runtime->buffer_size; - else + else { runtime->status->hw_ptr = 0; + runtime->hw_ptr_wrap = 0; + } snd_pcm_stream_unlock_irqrestore(substream, flags); return 0; } diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index f9ddecf2f4cd..09b4286c65f9 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -602,6 +602,8 @@ int snd_pcm_status(struct snd_pcm_substream *substream, snd_pcm_update_hw_ptr(substream); if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) { status->tstamp = runtime->status->tstamp; + status->audio_tstamp = + runtime->status->audio_tstamp; goto _tstamp_end; } } @@ -1998,7 +2000,7 @@ int snd_pcm_hw_constraints_complete(struct snd_pcm_substream *substream) if (runtime->dma_bytes) { err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 0, runtime->dma_bytes); if (err < 0) - return -EINVAL; + return err; } if (!(hw->rates & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS))) { diff --git a/sound/core/seq/seq_device.c b/sound/core/seq/seq_device.c index 60e8fc1b3440..040c60e1da28 100644 --- a/sound/core/seq/seq_device.c +++ b/sound/core/seq/seq_device.c @@ -66,7 +66,7 @@ struct ops_list { /* operators */ struct snd_seq_dev_ops ops; - /* registred devices */ + /* registered devices */ struct list_head dev_list; /* list of devices */ int num_devices; /* number of associated devices */ int num_init_devices; /* number of initialized devices */ diff --git a/sound/drivers/Kconfig b/sound/drivers/Kconfig index fe5ae09ffccb..7d02c322ed93 100644 --- a/sound/drivers/Kconfig +++ b/sound/drivers/Kconfig @@ -14,6 +14,7 @@ config SND_OPL4_LIB config SND_VX_LIB tristate + select FW_LOADER select SND_HWDEP select SND_PCM @@ -35,7 +36,6 @@ config SND_PCSP tristate "PC-Speaker support (READ HELP!)" depends on PCSPKR_PLATFORM && X86 && HIGH_RES_TIMERS depends on INPUT - depends on EXPERIMENTAL select SND_PCM help If you don't have a sound card in your computer, you can include a diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c index 0fe6d64ff840..64d534710b51 100644 --- a/sound/drivers/aloop.c +++ b/sound/drivers/aloop.c @@ -120,7 +120,6 @@ struct loopback_pcm { unsigned int last_drift; unsigned long last_jiffies; struct timer_list timer; - spinlock_t timer_lock; }; static struct platform_device *devices[SNDRV_CARDS]; @@ -166,12 +165,12 @@ static inline unsigned int get_rate_shift(struct loopback_pcm *dpcm) return get_setup(dpcm)->rate_shift; } +/* call in cable->lock */ static void loopback_timer_start(struct loopback_pcm *dpcm) { unsigned long tick; unsigned int rate_shift = get_rate_shift(dpcm); - spin_lock(&dpcm->timer_lock); if (rate_shift != dpcm->pcm_rate_shift) { dpcm->pcm_rate_shift = rate_shift; dpcm->period_size_frac = frac_pos(dpcm, dpcm->pcm_period_size); @@ -184,15 +183,13 @@ static void loopback_timer_start(struct loopback_pcm *dpcm) tick = (tick + dpcm->pcm_bps - 1) / dpcm->pcm_bps; dpcm->timer.expires = jiffies + tick; add_timer(&dpcm->timer); - spin_unlock(&dpcm->timer_lock); } +/* call in cable->lock */ static inline void loopback_timer_stop(struct loopback_pcm *dpcm) { - spin_lock(&dpcm->timer_lock); del_timer(&dpcm->timer); dpcm->timer.expires = 0; - spin_unlock(&dpcm->timer_lock); } #define CABLE_VALID_PLAYBACK (1 << SNDRV_PCM_STREAM_PLAYBACK) @@ -274,8 +271,8 @@ static int loopback_trigger(struct snd_pcm_substream *substream, int cmd) spin_lock(&cable->lock); cable->running |= stream; cable->pause &= ~stream; - spin_unlock(&cable->lock); loopback_timer_start(dpcm); + spin_unlock(&cable->lock); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) loopback_active_notify(dpcm); break; @@ -283,23 +280,25 @@ static int loopback_trigger(struct snd_pcm_substream *substream, int cmd) spin_lock(&cable->lock); cable->running &= ~stream; cable->pause &= ~stream; - spin_unlock(&cable->lock); loopback_timer_stop(dpcm); + spin_unlock(&cable->lock); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) loopback_active_notify(dpcm); break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + case SNDRV_PCM_TRIGGER_SUSPEND: spin_lock(&cable->lock); cable->pause |= stream; - spin_unlock(&cable->lock); loopback_timer_stop(dpcm); + spin_unlock(&cable->lock); break; case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + case SNDRV_PCM_TRIGGER_RESUME: spin_lock(&cable->lock); dpcm->last_jiffies = jiffies; cable->pause &= ~stream; - spin_unlock(&cable->lock); loopback_timer_start(dpcm); + spin_unlock(&cable->lock); break; default: return -EINVAL; @@ -477,6 +476,7 @@ static inline void bytepos_finish(struct loopback_pcm *dpcm, dpcm->buf_pos %= dpcm->pcm_buffer_size; } +/* call in cable->lock */ static unsigned int loopback_pos_update(struct loopback_cable *cable) { struct loopback_pcm *dpcm_play = @@ -485,9 +485,7 @@ static unsigned int loopback_pos_update(struct loopback_cable *cable) cable->streams[SNDRV_PCM_STREAM_CAPTURE]; unsigned long delta_play = 0, delta_capt = 0; unsigned int running, count1, count2; - unsigned long flags; - spin_lock_irqsave(&cable->lock, flags); running = cable->running ^ cable->pause; if (running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) { delta_play = jiffies - dpcm_play->last_jiffies; @@ -529,38 +527,46 @@ static unsigned int loopback_pos_update(struct loopback_cable *cable) bytepos_finish(dpcm_play, count1); bytepos_finish(dpcm_capt, count1); unlock: - spin_unlock_irqrestore(&cable->lock, flags); return running; } static void loopback_timer_function(unsigned long data) { struct loopback_pcm *dpcm = (struct loopback_pcm *)data; - unsigned int running; + unsigned long flags; - running = loopback_pos_update(dpcm->cable); - if (running & (1 << dpcm->substream->stream)) { + spin_lock_irqsave(&dpcm->cable->lock, flags); + if (loopback_pos_update(dpcm->cable) & (1 << dpcm->substream->stream)) { loopback_timer_start(dpcm); if (dpcm->period_update_pending) { dpcm->period_update_pending = 0; + spin_unlock_irqrestore(&dpcm->cable->lock, flags); + /* need to unlock before calling below */ snd_pcm_period_elapsed(dpcm->substream); + return; } } + spin_unlock_irqrestore(&dpcm->cable->lock, flags); } static snd_pcm_uframes_t loopback_pointer(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct loopback_pcm *dpcm = runtime->private_data; + snd_pcm_uframes_t pos; + spin_lock(&dpcm->cable->lock); loopback_pos_update(dpcm->cable); - return bytes_to_frames(runtime, dpcm->buf_pos); + pos = dpcm->buf_pos; + spin_unlock(&dpcm->cable->lock); + return bytes_to_frames(runtime, pos); } static struct snd_pcm_hardware loopback_pcm_hardware = { .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE), + SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_RESUME), .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE | SNDRV_PCM_FMTBIT_FLOAT_LE | SNDRV_PCM_FMTBIT_FLOAT_BE), @@ -672,7 +678,6 @@ static int loopback_open(struct snd_pcm_substream *substream) dpcm->substream = substream; setup_timer(&dpcm->timer, loopback_timer_function, (unsigned long)dpcm); - spin_lock_init(&dpcm->timer_lock); cable = loopback->cables[substream->number][dev]; if (!cable) { @@ -772,8 +777,8 @@ static struct snd_pcm_ops loopback_capture_ops = { .mmap = snd_pcm_lib_mmap_vmalloc, }; -static int __devinit loopback_pcm_new(struct loopback *loopback, - int device, int substreams) +static int loopback_pcm_new(struct loopback *loopback, + int device, int substreams) { struct snd_pcm *pcm; int err; @@ -947,7 +952,7 @@ static int loopback_channels_get(struct snd_kcontrol *kcontrol, return 0; } -static struct snd_kcontrol_new loopback_controls[] __devinitdata = { +static struct snd_kcontrol_new loopback_controls[] = { { .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = "PCM Rate Shift 100000", @@ -996,7 +1001,7 @@ static struct snd_kcontrol_new loopback_controls[] __devinitdata = { } }; -static int __devinit loopback_mixer_new(struct loopback *loopback, int notify) +static int loopback_mixer_new(struct loopback *loopback, int notify) { struct snd_card *card = loopback->card; struct snd_pcm *pcm; @@ -1109,7 +1114,7 @@ static void print_cable_info(struct snd_info_entry *entry, mutex_unlock(&loopback->cable_lock); } -static int __devinit loopback_proc_new(struct loopback *loopback, int cidx) +static int loopback_proc_new(struct loopback *loopback, int cidx) { char name[32]; struct snd_info_entry *entry; @@ -1130,7 +1135,7 @@ static int __devinit loopback_proc_new(struct loopback *loopback, int cidx) #endif -static int __devinit loopback_probe(struct platform_device *devptr) +static int loopback_probe(struct platform_device *devptr) { struct snd_card *card; struct loopback *loopback; @@ -1175,7 +1180,7 @@ static int __devinit loopback_probe(struct platform_device *devptr) return err; } -static int __devexit loopback_remove(struct platform_device *devptr) +static int loopback_remove(struct platform_device *devptr) { snd_card_free(platform_get_drvdata(devptr)); platform_set_drvdata(devptr, NULL); @@ -1213,7 +1218,7 @@ static SIMPLE_DEV_PM_OPS(loopback_pm, loopback_suspend, loopback_resume); static struct platform_driver loopback_driver = { .probe = loopback_probe, - .remove = __devexit_p(loopback_remove), + .remove = loopback_remove, .driver = { .name = SND_LOOPBACK_DRIVER, .owner = THIS_MODULE, diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c index 54bb6644a598..fd798f753609 100644 --- a/sound/drivers/dummy.c +++ b/sound/drivers/dummy.c @@ -134,6 +134,9 @@ struct snd_dummy { spinlock_t mixer_lock; int mixer_volume[MIXER_ADDR_LAST+1][2]; int capture_source[MIXER_ADDR_LAST+1][2]; + int iobox; + struct snd_kcontrol *cd_volume_ctl; + struct snd_kcontrol *cd_switch_ctl; const struct dummy_timer_ops *timer_ops; }; @@ -685,8 +688,8 @@ static struct snd_pcm_ops dummy_pcm_ops_no_buf = { .page = dummy_pcm_page, }; -static int __devinit snd_card_dummy_pcm(struct snd_dummy *dummy, int device, - int substreams) +static int snd_card_dummy_pcm(struct snd_dummy *dummy, int device, + int substreams) { struct snd_pcm *pcm; struct snd_pcm_ops *ops; @@ -817,6 +820,57 @@ static int snd_dummy_capsrc_put(struct snd_kcontrol *kcontrol, struct snd_ctl_el return change; } +static int snd_dummy_iobox_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *info) +{ + const char *const names[] = { "None", "CD Player" }; + + return snd_ctl_enum_info(info, 1, 2, names); +} + +static int snd_dummy_iobox_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *value) +{ + struct snd_dummy *dummy = snd_kcontrol_chip(kcontrol); + + value->value.enumerated.item[0] = dummy->iobox; + return 0; +} + +static int snd_dummy_iobox_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *value) +{ + struct snd_dummy *dummy = snd_kcontrol_chip(kcontrol); + int changed; + + if (value->value.enumerated.item[0] > 1) + return -EINVAL; + + changed = value->value.enumerated.item[0] != dummy->iobox; + if (changed) { + dummy->iobox = value->value.enumerated.item[0]; + + if (dummy->iobox) { + dummy->cd_volume_ctl->vd[0].access &= + ~SNDRV_CTL_ELEM_ACCESS_INACTIVE; + dummy->cd_switch_ctl->vd[0].access &= + ~SNDRV_CTL_ELEM_ACCESS_INACTIVE; + } else { + dummy->cd_volume_ctl->vd[0].access |= + SNDRV_CTL_ELEM_ACCESS_INACTIVE; + dummy->cd_switch_ctl->vd[0].access |= + SNDRV_CTL_ELEM_ACCESS_INACTIVE; + } + + snd_ctl_notify(dummy->card, SNDRV_CTL_EVENT_MASK_INFO, + &dummy->cd_volume_ctl->id); + snd_ctl_notify(dummy->card, SNDRV_CTL_EVENT_MASK_INFO, + &dummy->cd_switch_ctl->id); + } + + return changed; +} + static struct snd_kcontrol_new snd_dummy_controls[] = { DUMMY_VOLUME("Master Volume", 0, MIXER_ADDR_MASTER), DUMMY_CAPSRC("Master Capture Switch", 0, MIXER_ADDR_MASTER), @@ -827,22 +881,37 @@ DUMMY_CAPSRC("Line Capture Switch", 0, MIXER_ADDR_LINE), DUMMY_VOLUME("Mic Volume", 0, MIXER_ADDR_MIC), DUMMY_CAPSRC("Mic Capture Switch", 0, MIXER_ADDR_MIC), DUMMY_VOLUME("CD Volume", 0, MIXER_ADDR_CD), -DUMMY_CAPSRC("CD Capture Switch", 0, MIXER_ADDR_CD) +DUMMY_CAPSRC("CD Capture Switch", 0, MIXER_ADDR_CD), +{ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "External I/O Box", + .info = snd_dummy_iobox_info, + .get = snd_dummy_iobox_get, + .put = snd_dummy_iobox_put, +}, }; -static int __devinit snd_card_dummy_new_mixer(struct snd_dummy *dummy) +static int snd_card_dummy_new_mixer(struct snd_dummy *dummy) { struct snd_card *card = dummy->card; + struct snd_kcontrol *kcontrol; unsigned int idx; int err; spin_lock_init(&dummy->mixer_lock); strcpy(card->mixername, "Dummy Mixer"); + dummy->iobox = 1; for (idx = 0; idx < ARRAY_SIZE(snd_dummy_controls); idx++) { - err = snd_ctl_add(card, snd_ctl_new1(&snd_dummy_controls[idx], dummy)); + kcontrol = snd_ctl_new1(&snd_dummy_controls[idx], dummy); + err = snd_ctl_add(card, kcontrol); if (err < 0) return err; + if (!strcmp(kcontrol->id.name, "CD Volume")) + dummy->cd_volume_ctl = kcontrol; + else if (!strcmp(kcontrol->id.name, "CD Capture Switch")) + dummy->cd_switch_ctl = kcontrol; + } return 0; } @@ -962,7 +1031,7 @@ static void dummy_proc_write(struct snd_info_entry *entry, } } -static void __devinit dummy_proc_init(struct snd_dummy *chip) +static void dummy_proc_init(struct snd_dummy *chip) { struct snd_info_entry *entry; @@ -977,7 +1046,7 @@ static void __devinit dummy_proc_init(struct snd_dummy *chip) #define dummy_proc_init(x) #endif /* CONFIG_SND_DEBUG && CONFIG_PROC_FS */ -static int __devinit snd_dummy_probe(struct platform_device *devptr) +static int snd_dummy_probe(struct platform_device *devptr) { struct snd_card *card; struct snd_dummy *dummy; @@ -1057,7 +1126,7 @@ static int __devinit snd_dummy_probe(struct platform_device *devptr) return err; } -static int __devexit snd_dummy_remove(struct platform_device *devptr) +static int snd_dummy_remove(struct platform_device *devptr) { snd_card_free(platform_get_drvdata(devptr)); platform_set_drvdata(devptr, NULL); @@ -1093,7 +1162,7 @@ static SIMPLE_DEV_PM_OPS(snd_dummy_pm, snd_dummy_suspend, snd_dummy_resume); static struct platform_driver snd_dummy_driver = { .probe = snd_dummy_probe, - .remove = __devexit_p(snd_dummy_remove), + .remove = snd_dummy_remove, .driver = { .name = SND_DUMMY_DRIVER, .owner = THIS_MODULE, diff --git a/sound/drivers/ml403-ac97cr.c b/sound/drivers/ml403-ac97cr.c index 6c83b1aed288..8125a7e95ee4 100644 --- a/sound/drivers/ml403-ac97cr.c +++ b/sound/drivers/ml403-ac97cr.c @@ -1063,7 +1063,7 @@ snd_ml403_ac97cr_codec_write(struct snd_ac97 *ac97, unsigned short reg, return; } -static int __devinit +static int snd_ml403_ac97cr_chip_init(struct snd_ml403_ac97cr *ml403_ac97cr) { unsigned long end_time; @@ -1108,7 +1108,7 @@ static int snd_ml403_ac97cr_dev_free(struct snd_device *snddev) return snd_ml403_ac97cr_free(ml403_ac97cr); } -static int __devinit +static int snd_ml403_ac97cr_create(struct snd_card *card, struct platform_device *pfdev, struct snd_ml403_ac97cr **rml403_ac97cr) { @@ -1204,7 +1204,7 @@ static void snd_ml403_ac97cr_mixer_free(struct snd_ac97 *ac97) PDEBUG(INIT_INFO, "mixer_free(): (done)\n"); } -static int __devinit +static int snd_ml403_ac97cr_mixer(struct snd_ml403_ac97cr *ml403_ac97cr) { struct snd_ac97_bus *bus; @@ -1237,7 +1237,7 @@ snd_ml403_ac97cr_mixer(struct snd_ml403_ac97cr *ml403_ac97cr) return err; } -static int __devinit +static int snd_ml403_ac97cr_pcm(struct snd_ml403_ac97cr *ml403_ac97cr, int device, struct snd_pcm **rpcm) { @@ -1268,7 +1268,7 @@ snd_ml403_ac97cr_pcm(struct snd_ml403_ac97cr *ml403_ac97cr, int device, return 0; } -static int __devinit snd_ml403_ac97cr_probe(struct platform_device *pfdev) +static int snd_ml403_ac97cr_probe(struct platform_device *pfdev) { struct snd_card *card; struct snd_ml403_ac97cr *ml403_ac97cr = NULL; diff --git a/sound/drivers/mpu401/mpu401.c b/sound/drivers/mpu401/mpu401.c index bc03a2046c9c..da1a29bfc85d 100644 --- a/sound/drivers/mpu401/mpu401.c +++ b/sound/drivers/mpu401/mpu401.c @@ -100,7 +100,7 @@ static int snd_mpu401_create(int dev, struct snd_card **rcard) return err; } -static int __devinit snd_mpu401_probe(struct platform_device *devptr) +static int snd_mpu401_probe(struct platform_device *devptr) { int dev = devptr->id; int err; @@ -126,7 +126,7 @@ static int __devinit snd_mpu401_probe(struct platform_device *devptr) return 0; } -static int __devexit snd_mpu401_remove(struct platform_device *devptr) +static int snd_mpu401_remove(struct platform_device *devptr) { snd_card_free(platform_get_drvdata(devptr)); platform_set_drvdata(devptr, NULL); @@ -137,7 +137,7 @@ static int __devexit snd_mpu401_remove(struct platform_device *devptr) static struct platform_driver snd_mpu401_driver = { .probe = snd_mpu401_probe, - .remove = __devexit_p(snd_mpu401_remove), + .remove = snd_mpu401_remove, .driver = { .name = SND_MPU401_DRIVER, .owner = THIS_MODULE, @@ -156,8 +156,8 @@ static struct pnp_device_id snd_mpu401_pnpids[] = { MODULE_DEVICE_TABLE(pnp, snd_mpu401_pnpids); -static int __devinit snd_mpu401_pnp(int dev, struct pnp_dev *device, - const struct pnp_device_id *id) +static int snd_mpu401_pnp(int dev, struct pnp_dev *device, + const struct pnp_device_id *id) { if (!pnp_port_valid(device, 0) || pnp_port_flags(device, 0) & IORESOURCE_DISABLED) { @@ -182,8 +182,8 @@ static int __devinit snd_mpu401_pnp(int dev, struct pnp_dev *device, return 0; } -static int __devinit snd_mpu401_pnp_probe(struct pnp_dev *pnp_dev, - const struct pnp_device_id *id) +static int snd_mpu401_pnp_probe(struct pnp_dev *pnp_dev, + const struct pnp_device_id *id) { static int dev; struct snd_card *card; @@ -211,7 +211,7 @@ static int __devinit snd_mpu401_pnp_probe(struct pnp_dev *pnp_dev, return -ENODEV; } -static void __devexit snd_mpu401_pnp_remove(struct pnp_dev *dev) +static void snd_mpu401_pnp_remove(struct pnp_dev *dev) { struct snd_card *card = (struct snd_card *) pnp_get_drvdata(dev); @@ -223,7 +223,7 @@ static struct pnp_driver snd_mpu401_pnp_driver = { .name = "mpu401", .id_table = snd_mpu401_pnpids, .probe = snd_mpu401_pnp_probe, - .remove = __devexit_p(snd_mpu401_pnp_remove), + .remove = snd_mpu401_pnp_remove, }; #else static struct pnp_driver snd_mpu401_pnp_driver; diff --git a/sound/drivers/mtpav.c b/sound/drivers/mtpav.c index cad73af3860c..9f1815b99a15 100644 --- a/sound/drivers/mtpav.c +++ b/sound/drivers/mtpav.c @@ -583,7 +583,7 @@ static irqreturn_t snd_mtpav_irqh(int irq, void *dev_id) /* * get ISA resources */ -static int __devinit snd_mtpav_get_ISA(struct mtpav * mcard) +static int snd_mtpav_get_ISA(struct mtpav *mcard) { if ((mcard->res_port = request_region(port, 3, "MotuMTPAV MIDI")) == NULL) { snd_printk(KERN_ERR "MTVAP port 0x%lx is busy\n", port); @@ -619,8 +619,8 @@ static struct snd_rawmidi_ops snd_mtpav_input = { * get RAWMIDI resources */ -static void __devinit snd_mtpav_set_name(struct mtpav *chip, - struct snd_rawmidi_substream *substream) +static void snd_mtpav_set_name(struct mtpav *chip, + struct snd_rawmidi_substream *substream) { if (substream->number >= 0 && substream->number < chip->num_ports) sprintf(substream->name, "MTP direct %d", (substream->number % chip->num_ports) + 1); @@ -634,7 +634,7 @@ static void __devinit snd_mtpav_set_name(struct mtpav *chip, strcpy(substream->name, "MTP broadcast"); } -static int __devinit snd_mtpav_get_RAWMIDI(struct mtpav *mcard) +static int snd_mtpav_get_RAWMIDI(struct mtpav *mcard) { int rval; struct snd_rawmidi *rawmidi; @@ -691,7 +691,7 @@ static void snd_mtpav_free(struct snd_card *card) /* */ -static int __devinit snd_mtpav_probe(struct platform_device *dev) +static int snd_mtpav_probe(struct platform_device *dev) { struct snd_card *card; int err; @@ -746,7 +746,7 @@ static int __devinit snd_mtpav_probe(struct platform_device *dev) return err; } -static int __devexit snd_mtpav_remove(struct platform_device *devptr) +static int snd_mtpav_remove(struct platform_device *devptr) { snd_card_free(platform_get_drvdata(devptr)); platform_set_drvdata(devptr, NULL); @@ -757,7 +757,7 @@ static int __devexit snd_mtpav_remove(struct platform_device *devptr) static struct platform_driver snd_mtpav_driver = { .probe = snd_mtpav_probe, - .remove = __devexit_p(snd_mtpav_remove), + .remove = snd_mtpav_remove, .driver = { .name = SND_MTPAV_DRIVER, .owner = THIS_MODULE, diff --git a/sound/drivers/mts64.c b/sound/drivers/mts64.c index 2d5514b0a290..4e0dd22ba08e 100644 --- a/sound/drivers/mts64.c +++ b/sound/drivers/mts64.c @@ -83,9 +83,9 @@ static int snd_mts64_free(struct mts64 *mts) return 0; } -static int __devinit snd_mts64_create(struct snd_card *card, - struct pardevice *pardev, - struct mts64 **rchip) +static int snd_mts64_create(struct snd_card *card, + struct pardevice *pardev, + struct mts64 **rchip) { struct mts64 *mts; @@ -214,7 +214,7 @@ static int mts64_device_ready(struct parport *p) * 0 init ok * -EIO failure */ -static int __devinit mts64_device_init(struct parport *p) +static int mts64_device_init(struct parport *p) { int i; @@ -290,7 +290,7 @@ static u8 mts64_map_midi_input(u8 c) * 0 device found * -ENODEV no device */ -static int __devinit mts64_probe(struct parport *p) +static int mts64_probe(struct parport *p) { u8 c; @@ -483,7 +483,7 @@ __out: return changed; } -static struct snd_kcontrol_new mts64_ctl_smpte_switch __devinitdata = { +static struct snd_kcontrol_new mts64_ctl_smpte_switch = { .iface = SNDRV_CTL_ELEM_IFACE_RAWMIDI, .name = "SMPTE Playback Switch", .index = 0, @@ -556,7 +556,7 @@ static int snd_mts64_ctl_smpte_time_put(struct snd_kcontrol *kctl, return changed; } -static struct snd_kcontrol_new mts64_ctl_smpte_time_hours __devinitdata = { +static struct snd_kcontrol_new mts64_ctl_smpte_time_hours = { .iface = SNDRV_CTL_ELEM_IFACE_RAWMIDI, .name = "SMPTE Time Hours", .index = 0, @@ -567,7 +567,7 @@ static struct snd_kcontrol_new mts64_ctl_smpte_time_hours __devinitdata = { .put = snd_mts64_ctl_smpte_time_put }; -static struct snd_kcontrol_new mts64_ctl_smpte_time_minutes __devinitdata = { +static struct snd_kcontrol_new mts64_ctl_smpte_time_minutes = { .iface = SNDRV_CTL_ELEM_IFACE_RAWMIDI, .name = "SMPTE Time Minutes", .index = 0, @@ -578,7 +578,7 @@ static struct snd_kcontrol_new mts64_ctl_smpte_time_minutes __devinitdata = { .put = snd_mts64_ctl_smpte_time_put }; -static struct snd_kcontrol_new mts64_ctl_smpte_time_seconds __devinitdata = { +static struct snd_kcontrol_new mts64_ctl_smpte_time_seconds = { .iface = SNDRV_CTL_ELEM_IFACE_RAWMIDI, .name = "SMPTE Time Seconds", .index = 0, @@ -589,7 +589,7 @@ static struct snd_kcontrol_new mts64_ctl_smpte_time_seconds __devinitdata = { .put = snd_mts64_ctl_smpte_time_put }; -static struct snd_kcontrol_new mts64_ctl_smpte_time_frames __devinitdata = { +static struct snd_kcontrol_new mts64_ctl_smpte_time_frames = { .iface = SNDRV_CTL_ELEM_IFACE_RAWMIDI, .name = "SMPTE Time Frames", .index = 0, @@ -651,7 +651,7 @@ static int snd_mts64_ctl_smpte_fps_put(struct snd_kcontrol *kctl, return changed; } -static struct snd_kcontrol_new mts64_ctl_smpte_fps __devinitdata = { +static struct snd_kcontrol_new mts64_ctl_smpte_fps = { .iface = SNDRV_CTL_ELEM_IFACE_RAWMIDI, .name = "SMPTE Fps", .index = 0, @@ -663,11 +663,11 @@ static struct snd_kcontrol_new mts64_ctl_smpte_fps __devinitdata = { }; -static int __devinit snd_mts64_ctl_create(struct snd_card *card, - struct mts64 *mts) +static int snd_mts64_ctl_create(struct snd_card *card, + struct mts64 *mts) { int err, i; - static struct snd_kcontrol_new *control[] __devinitdata = { + static struct snd_kcontrol_new *control[] = { &mts64_ctl_smpte_switch, &mts64_ctl_smpte_time_hours, &mts64_ctl_smpte_time_minutes, @@ -774,7 +774,7 @@ static struct snd_rawmidi_ops snd_mts64_rawmidi_input_ops = { }; /* Create and initialize the rawmidi component */ -static int __devinit snd_mts64_rawmidi_create(struct snd_card *card) +static int snd_mts64_rawmidi_create(struct snd_card *card) { struct mts64 *mts = card->private_data; struct snd_rawmidi *rmidi; @@ -860,7 +860,7 @@ __out: spin_unlock(&mts->lock); } -static int __devinit snd_mts64_probe_port(struct parport *p) +static int snd_mts64_probe_port(struct parport *p) { struct pardevice *pardev; int res; @@ -884,7 +884,7 @@ static int __devinit snd_mts64_probe_port(struct parport *p) return res; } -static void __devinit snd_mts64_attach(struct parport *p) +static void snd_mts64_attach(struct parport *p) { struct platform_device *device; @@ -940,7 +940,7 @@ static void snd_mts64_card_private_free(struct snd_card *card) snd_mts64_free(mts); } -static int __devinit snd_mts64_probe(struct platform_device *pdev) +static int snd_mts64_probe(struct platform_device *pdev) { struct pardevice *pardev; struct parport *p; @@ -1025,7 +1025,7 @@ __err: return err; } -static int __devexit snd_mts64_remove(struct platform_device *pdev) +static int snd_mts64_remove(struct platform_device *pdev) { struct snd_card *card = platform_get_drvdata(pdev); @@ -1038,7 +1038,7 @@ static int __devexit snd_mts64_remove(struct platform_device *pdev) static struct platform_driver snd_mts64_driver = { .probe = snd_mts64_probe, - .remove = __devexit_p(snd_mts64_remove), + .remove = snd_mts64_remove, .driver = { .name = PLATFORM_DRIVER, .owner = THIS_MODULE, diff --git a/sound/drivers/pcsp/pcsp.c b/sound/drivers/pcsp/pcsp.c index ef171295f6d4..7a5fdb9b0afc 100644 --- a/sound/drivers/pcsp/pcsp.c +++ b/sound/drivers/pcsp/pcsp.c @@ -39,7 +39,7 @@ MODULE_PARM_DESC(nopcm, "Disable PC-Speaker PCM sound. Only beeps remain."); struct snd_pcsp pcsp_chip; -static int __devinit snd_pcsp_create(struct snd_card *card) +static int snd_pcsp_create(struct snd_card *card) { static struct snd_device_ops ops = { }; struct timespec tp; @@ -93,7 +93,7 @@ static int __devinit snd_pcsp_create(struct snd_card *card) return 0; } -static int __devinit snd_card_pcsp_probe(int devnum, struct device *dev) +static int snd_card_pcsp_probe(int devnum, struct device *dev) { struct snd_card *card; int err; @@ -142,7 +142,7 @@ static int __devinit snd_card_pcsp_probe(int devnum, struct device *dev) return 0; } -static int __devinit alsa_card_pcsp_init(struct device *dev) +static int alsa_card_pcsp_init(struct device *dev) { int err; @@ -161,12 +161,12 @@ static int __devinit alsa_card_pcsp_init(struct device *dev) return 0; } -static void __devexit alsa_card_pcsp_exit(struct snd_pcsp *chip) +static void alsa_card_pcsp_exit(struct snd_pcsp *chip) { snd_card_free(chip->card); } -static int __devinit pcsp_probe(struct platform_device *dev) +static int pcsp_probe(struct platform_device *dev) { int err; @@ -184,7 +184,7 @@ static int __devinit pcsp_probe(struct platform_device *dev) return 0; } -static int __devexit pcsp_remove(struct platform_device *dev) +static int pcsp_remove(struct platform_device *dev) { struct snd_pcsp *chip = platform_get_drvdata(dev); alsa_card_pcsp_exit(chip); @@ -227,7 +227,7 @@ static struct platform_driver pcsp_platform_driver = { .pm = PCSP_PM_OPS, }, .probe = pcsp_probe, - .remove = __devexit_p(pcsp_remove), + .remove = pcsp_remove, .shutdown = pcsp_shutdown, }; diff --git a/sound/drivers/pcsp/pcsp_input.c b/sound/drivers/pcsp/pcsp_input.c index b5e2b54c2604..b874b0ad99cd 100644 --- a/sound/drivers/pcsp/pcsp_input.c +++ b/sound/drivers/pcsp/pcsp_input.c @@ -77,7 +77,7 @@ static int pcspkr_input_event(struct input_dev *dev, unsigned int type, return 0; } -int __devinit pcspkr_input_init(struct input_dev **rdev, struct device *dev) +int pcspkr_input_init(struct input_dev **rdev, struct device *dev) { int err; diff --git a/sound/drivers/pcsp/pcsp_input.h b/sound/drivers/pcsp/pcsp_input.h index e66738c78333..d692749b8c9b 100644 --- a/sound/drivers/pcsp/pcsp_input.h +++ b/sound/drivers/pcsp/pcsp_input.h @@ -7,7 +7,7 @@ #ifndef __PCSP_INPUT_H__ #define __PCSP_INPUT_H__ -int __devinit pcspkr_input_init(struct input_dev **rdev, struct device *dev); +int pcspkr_input_init(struct input_dev **rdev, struct device *dev); int pcspkr_input_remove(struct input_dev *dev); void pcspkr_stop_sound(void); diff --git a/sound/drivers/pcsp/pcsp_lib.c b/sound/drivers/pcsp/pcsp_lib.c index 434981dd4a61..29ebaa4ec0fd 100644 --- a/sound/drivers/pcsp/pcsp_lib.c +++ b/sound/drivers/pcsp/pcsp_lib.c @@ -334,7 +334,7 @@ static struct snd_pcm_ops snd_pcsp_playback_ops = { .pointer = snd_pcsp_playback_pointer, }; -int __devinit snd_pcsp_new_pcm(struct snd_pcsp *chip) +int snd_pcsp_new_pcm(struct snd_pcsp *chip) { int err; diff --git a/sound/drivers/pcsp/pcsp_mixer.c b/sound/drivers/pcsp/pcsp_mixer.c index 6f633f4f3b96..f1e1defc09b1 100644 --- a/sound/drivers/pcsp/pcsp_mixer.c +++ b/sound/drivers/pcsp/pcsp_mixer.c @@ -119,17 +119,17 @@ static int pcsp_pcspkr_put(struct snd_kcontrol *kcontrol, .put = pcsp_##ctl_type##_put, \ } -static struct snd_kcontrol_new __devinitdata snd_pcsp_controls_pcm[] = { +static struct snd_kcontrol_new snd_pcsp_controls_pcm[] = { PCSP_MIXER_CONTROL(enable, "Master Playback Switch"), PCSP_MIXER_CONTROL(treble, "BaseFRQ Playback Volume"), }; -static struct snd_kcontrol_new __devinitdata snd_pcsp_controls_spkr[] = { +static struct snd_kcontrol_new snd_pcsp_controls_spkr[] = { PCSP_MIXER_CONTROL(pcspkr, "Beep Playback Switch"), }; -static int __devinit snd_pcsp_ctls_add(struct snd_pcsp *chip, - struct snd_kcontrol_new *ctls, int num) +static int snd_pcsp_ctls_add(struct snd_pcsp *chip, + struct snd_kcontrol_new *ctls, int num) { int i, err; struct snd_card *card = chip->card; @@ -141,7 +141,7 @@ static int __devinit snd_pcsp_ctls_add(struct snd_pcsp *chip, return 0; } -int __devinit snd_pcsp_new_mixer(struct snd_pcsp *chip, int nopcm) +int snd_pcsp_new_mixer(struct snd_pcsp *chip, int nopcm) { int err; struct snd_card *card = chip->card; diff --git a/sound/drivers/portman2x4.c b/sound/drivers/portman2x4.c index 8364855ed14f..991018df7131 100644 --- a/sound/drivers/portman2x4.c +++ b/sound/drivers/portman2x4.c @@ -96,9 +96,9 @@ static int portman_free(struct portman *pm) return 0; } -static int __devinit portman_create(struct snd_card *card, - struct pardevice *pardev, - struct portman **rchip) +static int portman_create(struct snd_card *card, + struct pardevice *pardev, + struct portman **rchip) { struct portman *pm; @@ -561,7 +561,7 @@ static struct snd_rawmidi_ops snd_portman_midi_input = { }; /* Create and initialize the rawmidi component */ -static int __devinit snd_portman_rawmidi_create(struct snd_card *card) +static int snd_portman_rawmidi_create(struct snd_card *card) { struct portman *pm = card->private_data; struct snd_rawmidi *rmidi; @@ -648,7 +648,7 @@ static void snd_portman_interrupt(void *userdata) spin_unlock(&pm->reg_lock); } -static int __devinit snd_portman_probe_port(struct parport *p) +static int snd_portman_probe_port(struct parport *p) { struct pardevice *pardev; int res; @@ -672,7 +672,7 @@ static int __devinit snd_portman_probe_port(struct parport *p) return res ? -EIO : 0; } -static void __devinit snd_portman_attach(struct parport *p) +static void snd_portman_attach(struct parport *p) { struct platform_device *device; @@ -728,7 +728,7 @@ static void snd_portman_card_private_free(struct snd_card *card) portman_free(pm); } -static int __devinit snd_portman_probe(struct platform_device *pdev) +static int snd_portman_probe(struct platform_device *pdev) { struct pardevice *pardev; struct parport *p; @@ -814,7 +814,7 @@ __err: return err; } -static int __devexit snd_portman_remove(struct platform_device *pdev) +static int snd_portman_remove(struct platform_device *pdev) { struct snd_card *card = platform_get_drvdata(pdev); @@ -827,7 +827,7 @@ static int __devexit snd_portman_remove(struct platform_device *pdev) static struct platform_driver snd_portman_driver = { .probe = snd_portman_probe, - .remove = __devexit_p(snd_portman_remove), + .remove = snd_portman_remove, .driver = { .name = PLATFORM_DRIVER, .owner = THIS_MODULE, diff --git a/sound/drivers/serial-u16550.c b/sound/drivers/serial-u16550.c index 86700671d1ac..7425dd8c1f09 100644 --- a/sound/drivers/serial-u16550.c +++ b/sound/drivers/serial-u16550.c @@ -328,7 +328,7 @@ static void snd_uart16550_buffer_timer(unsigned long data) * return 0 if found * return negative error if not found */ -static int __devinit snd_uart16550_detect(struct snd_uart16550 *uart) +static int snd_uart16550_detect(struct snd_uart16550 *uart) { unsigned long io_base = uart->base; int ok; @@ -783,14 +783,14 @@ static int snd_uart16550_dev_free(struct snd_device *device) return snd_uart16550_free(uart); } -static int __devinit snd_uart16550_create(struct snd_card *card, - unsigned long iobase, - int irq, - unsigned int speed, - unsigned int base, - int adaptor, - int droponfull, - struct snd_uart16550 **ruart) +static int snd_uart16550_create(struct snd_card *card, + unsigned long iobase, + int irq, + unsigned int speed, + unsigned int base, + int adaptor, + int droponfull, + struct snd_uart16550 **ruart) { static struct snd_device_ops ops = { .dev_free = snd_uart16550_dev_free, @@ -863,7 +863,7 @@ static int __devinit snd_uart16550_create(struct snd_card *card, return 0; } -static void __devinit snd_uart16550_substreams(struct snd_rawmidi_str *stream) +static void snd_uart16550_substreams(struct snd_rawmidi_str *stream) { struct snd_rawmidi_substream *substream; @@ -872,9 +872,9 @@ static void __devinit snd_uart16550_substreams(struct snd_rawmidi_str *stream) } } -static int __devinit snd_uart16550_rmidi(struct snd_uart16550 *uart, int device, - int outs, int ins, - struct snd_rawmidi **rmidi) +static int snd_uart16550_rmidi(struct snd_uart16550 *uart, int device, + int outs, int ins, + struct snd_rawmidi **rmidi) { struct snd_rawmidi *rrawmidi; int err; @@ -899,7 +899,7 @@ static int __devinit snd_uart16550_rmidi(struct snd_uart16550 *uart, int device, return 0; } -static int __devinit snd_serial_probe(struct platform_device *devptr) +static int snd_serial_probe(struct platform_device *devptr) { struct snd_card *card; struct snd_uart16550 *uart; @@ -982,7 +982,7 @@ static int __devinit snd_serial_probe(struct platform_device *devptr) return err; } -static int __devexit snd_serial_remove(struct platform_device *devptr) +static int snd_serial_remove(struct platform_device *devptr) { snd_card_free(platform_get_drvdata(devptr)); platform_set_drvdata(devptr, NULL); @@ -993,7 +993,7 @@ static int __devexit snd_serial_remove(struct platform_device *devptr) static struct platform_driver snd_serial_driver = { .probe = snd_serial_probe, - .remove = __devexit_p( snd_serial_remove), + .remove = snd_serial_remove, .driver = { .name = SND_SERIAL_DRIVER, .owner = THIS_MODULE, diff --git a/sound/drivers/virmidi.c b/sound/drivers/virmidi.c index d7d514df9058..cc4be88d7318 100644 --- a/sound/drivers/virmidi.c +++ b/sound/drivers/virmidi.c @@ -83,7 +83,7 @@ struct snd_card_virmidi { static struct platform_device *devices[SNDRV_CARDS]; -static int __devinit snd_virmidi_probe(struct platform_device *devptr) +static int snd_virmidi_probe(struct platform_device *devptr) { struct snd_card *card; struct snd_card_virmidi *vmidi; @@ -129,7 +129,7 @@ static int __devinit snd_virmidi_probe(struct platform_device *devptr) return err; } -static int __devexit snd_virmidi_remove(struct platform_device *devptr) +static int snd_virmidi_remove(struct platform_device *devptr) { snd_card_free(platform_get_drvdata(devptr)); platform_set_drvdata(devptr, NULL); @@ -140,7 +140,7 @@ static int __devexit snd_virmidi_remove(struct platform_device *devptr) static struct platform_driver snd_virmidi_driver = { .probe = snd_virmidi_probe, - .remove = __devexit_p(snd_virmidi_remove), + .remove = snd_virmidi_remove, .driver = { .name = SND_VIRMIDI_DRIVER, .owner = THIS_MODULE, diff --git a/sound/drivers/vx/vx_core.c b/sound/drivers/vx/vx_core.c index de5055a3b0d0..c39961c11401 100644 --- a/sound/drivers/vx/vx_core.c +++ b/sound/drivers/vx/vx_core.c @@ -52,7 +52,6 @@ MODULE_LICENSE("GPL"); int snd_vx_check_reg_bit(struct vx_core *chip, int reg, int mask, int bit, int time) { unsigned long end_time = jiffies + (time * HZ + 999) / 1000; -#ifdef CONFIG_SND_DEBUG static char *reg_names[VX_REG_MAX] = { "ICR", "CVR", "ISR", "IVR", "RXH", "RXM", "RXL", "DMA", "CDSP", "RFREQ", "RUER/V2", "DATA", "MEMIRQ", @@ -60,7 +59,7 @@ int snd_vx_check_reg_bit(struct vx_core *chip, int reg, int mask, int bit, int t "MIC3", "INTCSR", "CNTRL", "GPIOC", "LOFREQ", "HIFREQ", "CSUER", "RUER" }; -#endif + do { if ((snd_vx_inb(chip, reg) & mask) == bit) return 0; diff --git a/sound/drivers/vx/vx_hwdep.c b/sound/drivers/vx/vx_hwdep.c index 4a1fae99ac55..3014b86362bd 100644 --- a/sound/drivers/vx/vx_hwdep.c +++ b/sound/drivers/vx/vx_hwdep.c @@ -29,8 +29,6 @@ #include <sound/hwdep.h> #include <sound/vx_core.h> -#ifdef SND_VX_FW_LOADER - MODULE_FIRMWARE("vx/bx_1_vxp.b56"); MODULE_FIRMWARE("vx/bx_1_vp4.b56"); MODULE_FIRMWARE("vx/x1_1_vx2.xlx"); @@ -119,142 +117,5 @@ void snd_vx_free_firmware(struct vx_core *chip) #endif } -#else /* old style firmware loading */ - -static int vx_hwdep_dsp_status(struct snd_hwdep *hw, - struct snd_hwdep_dsp_status *info) -{ - static char *type_ids[VX_TYPE_NUMS] = { - [VX_TYPE_BOARD] = "vxboard", - [VX_TYPE_V2] = "vx222", - [VX_TYPE_MIC] = "vx222", - [VX_TYPE_VXPOCKET] = "vxpocket", - [VX_TYPE_VXP440] = "vxp440", - }; - struct vx_core *vx = hw->private_data; - - if (snd_BUG_ON(!type_ids[vx->type])) - return -EINVAL; - strcpy(info->id, type_ids[vx->type]); - if (vx_is_pcmcia(vx)) - info->num_dsps = 4; - else - info->num_dsps = 3; - if (vx->chip_status & VX_STAT_CHIP_INIT) - info->chip_ready = 1; - info->version = VX_DRIVER_VERSION; - return 0; -} - -static void free_fw(const struct firmware *fw) -{ - if (fw) { - vfree(fw->data); - kfree(fw); - } -} - -static int vx_hwdep_dsp_load(struct snd_hwdep *hw, - struct snd_hwdep_dsp_image *dsp) -{ - struct vx_core *vx = hw->private_data; - int index, err; - struct firmware *fw; - - if (snd_BUG_ON(!vx->ops->load_dsp)) - return -ENXIO; - - fw = kmalloc(sizeof(*fw), GFP_KERNEL); - if (! fw) { - snd_printk(KERN_ERR "cannot allocate firmware\n"); - return -ENOMEM; - } - fw->size = dsp->length; - fw->data = vmalloc(fw->size); - if (! fw->data) { - snd_printk(KERN_ERR "cannot allocate firmware image (length=%d)\n", - (int)fw->size); - kfree(fw); - return -ENOMEM; - } - if (copy_from_user((void *)fw->data, dsp->image, dsp->length)) { - free_fw(fw); - return -EFAULT; - } - - index = dsp->index; - if (! vx_is_pcmcia(vx)) - index++; - err = vx->ops->load_dsp(vx, index, fw); - if (err < 0) { - free_fw(fw); - return err; - } -#ifdef CONFIG_PM - vx->firmware[index] = fw; -#else - free_fw(fw); -#endif - - if (index == 1) - vx->chip_status |= VX_STAT_XILINX_LOADED; - if (index < 3) - return 0; - - /* ok, we reached to the last one */ - /* create the devices if not built yet */ - if (! (vx->chip_status & VX_STAT_DEVICE_INIT)) { - if ((err = snd_vx_pcm_new(vx)) < 0) - return err; - - if ((err = snd_vx_mixer_new(vx)) < 0) - return err; - - if (vx->ops->add_controls) - if ((err = vx->ops->add_controls(vx)) < 0) - return err; - - if ((err = snd_card_register(vx->card)) < 0) - return err; - - vx->chip_status |= VX_STAT_DEVICE_INIT; - } - vx->chip_status |= VX_STAT_CHIP_INIT; - return 0; -} - - -/* exported */ -int snd_vx_setup_firmware(struct vx_core *chip) -{ - int err; - struct snd_hwdep *hw; - - if ((err = snd_hwdep_new(chip->card, SND_VX_HWDEP_ID, 0, &hw)) < 0) - return err; - - hw->iface = SNDRV_HWDEP_IFACE_VX; - hw->private_data = chip; - hw->ops.dsp_status = vx_hwdep_dsp_status; - hw->ops.dsp_load = vx_hwdep_dsp_load; - hw->exclusive = 1; - sprintf(hw->name, "VX Loader (%s)", chip->card->driver); - chip->hwdep = hw; - - return snd_card_register(chip->card); -} - -/* exported */ -void snd_vx_free_firmware(struct vx_core *chip) -{ -#ifdef CONFIG_PM - int i; - for (i = 0; i < 4; i++) - free_fw(chip->firmware[i]); -#endif -} - -#endif /* SND_VX_FW_LOADER */ - EXPORT_SYMBOL(snd_vx_setup_firmware); EXPORT_SYMBOL(snd_vx_free_firmware); diff --git a/sound/firewire/Kconfig b/sound/firewire/Kconfig index 26071489970b..ea063e1f8722 100644 --- a/sound/firewire/Kconfig +++ b/sound/firewire/Kconfig @@ -33,4 +33,17 @@ config SND_ISIGHT To compile this driver as a module, choose M here: the module will be called snd-isight. +config SND_SCS1X + tristate "Stanton Control System 1 MIDI" + select SND_PCM + select SND_RAWMIDI + select SND_FIREWIRE_LIB + help + Say Y here to include support for the MIDI ports of the Stanton + SCS.1d/SCS.1m DJ controllers. (SCS.1m audio is still handled + by FFADO.) + + To compile this driver as a module, choose M here: the module + will be called snd-scs1x. + endif # SND_FIREWIRE diff --git a/sound/firewire/Makefile b/sound/firewire/Makefile index d71ed8935f76..460179df5bb5 100644 --- a/sound/firewire/Makefile +++ b/sound/firewire/Makefile @@ -2,7 +2,9 @@ snd-firewire-lib-objs := lib.o iso-resources.o packets-buffer.o \ fcp.o cmp.o amdtp.o snd-firewire-speakers-objs := speakers.o snd-isight-objs := isight.o +snd-scs1x-objs := scs1x.o obj-$(CONFIG_SND_FIREWIRE_LIB) += snd-firewire-lib.o obj-$(CONFIG_SND_FIREWIRE_SPEAKERS) += snd-firewire-speakers.o obj-$(CONFIG_SND_ISIGHT) += snd-isight.o +obj-$(CONFIG_SND_SCS1X) += snd-scs1x.o diff --git a/sound/firewire/scs1x.c b/sound/firewire/scs1x.c new file mode 100644 index 000000000000..844a555c3b1e --- /dev/null +++ b/sound/firewire/scs1x.c @@ -0,0 +1,527 @@ +/* + * Stanton Control System 1 MIDI driver + * + * Copyright (c) Clemens Ladisch <clemens@ladisch.de> + * Licensed under the terms of the GNU General Public License, version 2. + */ + +#include <linux/device.h> +#include <linux/firewire.h> +#include <linux/firewire-constants.h> +#include <linux/interrupt.h> +#include <linux/module.h> +#include <linux/mod_devicetable.h> +#include <linux/slab.h> +#include <linux/string.h> +#include <linux/wait.h> +#include <sound/core.h> +#include <sound/initval.h> +#include <sound/rawmidi.h> +#include "lib.h" + +#define OUI_STANTON 0x001260 +#define MODEL_SCS_1M 0x001000 +#define MODEL_SCS_1D 0x002000 + +#define HSS1394_ADDRESS 0xc007dedadadaULL +#define HSS1394_MAX_PACKET_SIZE 64 + +#define HSS1394_TAG_USER_DATA 0x00 +#define HSS1394_TAG_CHANGE_ADDRESS 0xf1 + +struct scs { + struct snd_card *card; + struct fw_unit *unit; + struct fw_address_handler hss_handler; + struct fw_transaction transaction; + bool transaction_running; + bool output_idle; + u8 output_status; + u8 output_bytes; + bool output_escaped; + bool output_escape_high_nibble; + u8 input_escape_count; + struct snd_rawmidi_substream *output; + struct snd_rawmidi_substream *input; + struct tasklet_struct tasklet; + wait_queue_head_t idle_wait; + u8 *buffer; +}; + +static const u8 sysex_escape_prefix[] = { + 0xf0, /* SysEx begin */ + 0x00, 0x01, 0x60, /* Stanton DJ */ + 0x48, 0x53, 0x53, /* "HSS" */ +}; + +static int scs_output_open(struct snd_rawmidi_substream *stream) +{ + struct scs *scs = stream->rmidi->private_data; + + scs->output_status = 0; + scs->output_bytes = 1; + scs->output_escaped = false; + + return 0; +} + +static int scs_output_close(struct snd_rawmidi_substream *stream) +{ + return 0; +} + +static void scs_output_trigger(struct snd_rawmidi_substream *stream, int up) +{ + struct scs *scs = stream->rmidi->private_data; + + ACCESS_ONCE(scs->output) = up ? stream : NULL; + if (up) { + scs->output_idle = false; + tasklet_schedule(&scs->tasklet); + } +} + +static void scs_write_callback(struct fw_card *card, int rcode, + void *data, size_t length, void *callback_data) +{ + struct scs *scs = callback_data; + + if (rcode == RCODE_GENERATION) { + /* TODO: retry this packet */ + } + + scs->transaction_running = false; + tasklet_schedule(&scs->tasklet); +} + +static bool is_valid_running_status(u8 status) +{ + return status >= 0x80 && status <= 0xef; +} + +static bool is_one_byte_cmd(u8 status) +{ + return status == 0xf6 || + status >= 0xf8; +} + +static bool is_two_bytes_cmd(u8 status) +{ + return (status >= 0xc0 && status <= 0xdf) || + status == 0xf1 || + status == 0xf3; +} + +static bool is_three_bytes_cmd(u8 status) +{ + return (status >= 0x80 && status <= 0xbf) || + (status >= 0xe0 && status <= 0xef) || + status == 0xf2; +} + +static bool is_invalid_cmd(u8 status) +{ + return status == 0xf4 || + status == 0xf5 || + status == 0xf9 || + status == 0xfd; +} + +static void scs_output_tasklet(unsigned long data) +{ + struct scs *scs = (void *)data; + struct snd_rawmidi_substream *stream; + unsigned int i; + u8 byte; + struct fw_device *dev; + int generation; + + if (scs->transaction_running) + return; + + stream = ACCESS_ONCE(scs->output); + if (!stream) { + scs->output_idle = true; + wake_up(&scs->idle_wait); + return; + } + + i = scs->output_bytes; + for (;;) { + if (snd_rawmidi_transmit(stream, &byte, 1) != 1) { + scs->output_bytes = i; + scs->output_idle = true; + wake_up(&scs->idle_wait); + return; + } + /* + * Convert from real MIDI to what I think the device expects (no + * running status, one command per packet, unescaped SysExs). + */ + if (scs->output_escaped && byte < 0x80) { + if (scs->output_escape_high_nibble) { + if (i < HSS1394_MAX_PACKET_SIZE) { + scs->buffer[i] = byte << 4; + scs->output_escape_high_nibble = false; + } + } else { + scs->buffer[i++] |= byte & 0x0f; + scs->output_escape_high_nibble = true; + } + } else if (byte < 0x80) { + if (i == 1) { + if (!is_valid_running_status(scs->output_status)) + continue; + scs->buffer[0] = HSS1394_TAG_USER_DATA; + scs->buffer[i++] = scs->output_status; + } + scs->buffer[i++] = byte; + if ((i == 3 && is_two_bytes_cmd(scs->output_status)) || + (i == 4 && is_three_bytes_cmd(scs->output_status))) + break; + if (i == 1 + ARRAY_SIZE(sysex_escape_prefix) && + !memcmp(scs->buffer + 1, sysex_escape_prefix, + ARRAY_SIZE(sysex_escape_prefix))) { + scs->output_escaped = true; + scs->output_escape_high_nibble = true; + i = 0; + } + if (i >= HSS1394_MAX_PACKET_SIZE) + i = 1; + } else if (byte == 0xf7) { + if (scs->output_escaped) { + if (i >= 1 && scs->output_escape_high_nibble && + scs->buffer[0] != HSS1394_TAG_CHANGE_ADDRESS) + break; + } else { + if (i > 1 && scs->output_status == 0xf0) { + scs->buffer[i++] = 0xf7; + break; + } + } + i = 1; + scs->output_escaped = false; + } else if (!is_invalid_cmd(byte) && + byte < 0xf8) { + i = 1; + scs->buffer[0] = HSS1394_TAG_USER_DATA; + scs->buffer[i++] = byte; + scs->output_status = byte; + scs->output_escaped = false; + if (is_one_byte_cmd(byte)) + break; + } + } + scs->output_bytes = 1; + scs->output_escaped = false; + + scs->transaction_running = true; + dev = fw_parent_device(scs->unit); + generation = dev->generation; + smp_rmb(); /* node_id vs. generation */ + fw_send_request(dev->card, &scs->transaction, TCODE_WRITE_BLOCK_REQUEST, + dev->node_id, generation, dev->max_speed, + HSS1394_ADDRESS, scs->buffer, i, + scs_write_callback, scs); +} + +static void scs_output_drain(struct snd_rawmidi_substream *stream) +{ + struct scs *scs = stream->rmidi->private_data; + + wait_event(scs->idle_wait, scs->output_idle); +} + +static struct snd_rawmidi_ops output_ops = { + .open = scs_output_open, + .close = scs_output_close, + .trigger = scs_output_trigger, + .drain = scs_output_drain, +}; + +static int scs_input_open(struct snd_rawmidi_substream *stream) +{ + struct scs *scs = stream->rmidi->private_data; + + scs->input_escape_count = 0; + + return 0; +} + +static int scs_input_close(struct snd_rawmidi_substream *stream) +{ + return 0; +} + +static void scs_input_trigger(struct snd_rawmidi_substream *stream, int up) +{ + struct scs *scs = stream->rmidi->private_data; + + ACCESS_ONCE(scs->input) = up ? stream : NULL; +} + +static void scs_input_escaped_byte(struct snd_rawmidi_substream *stream, + u8 byte) +{ + u8 nibbles[2]; + + nibbles[0] = byte >> 4; + nibbles[1] = byte & 0x0f; + snd_rawmidi_receive(stream, nibbles, 2); +} + +static void scs_input_midi_byte(struct scs *scs, + struct snd_rawmidi_substream *stream, + u8 byte) +{ + if (scs->input_escape_count > 0) { + scs_input_escaped_byte(stream, byte); + scs->input_escape_count--; + if (scs->input_escape_count == 0) + snd_rawmidi_receive(stream, (const u8[]) { 0xf7 }, 1); + } else if (byte == 0xf9) { + snd_rawmidi_receive(stream, sysex_escape_prefix, + ARRAY_SIZE(sysex_escape_prefix)); + scs_input_escaped_byte(stream, 0x00); + scs_input_escaped_byte(stream, 0xf9); + scs->input_escape_count = 3; + } else { + snd_rawmidi_receive(stream, &byte, 1); + } +} + +static void scs_input_packet(struct scs *scs, + struct snd_rawmidi_substream *stream, + const u8 *data, unsigned int bytes) +{ + unsigned int i; + + if (data[0] == HSS1394_TAG_USER_DATA) { + for (i = 1; i < bytes; ++i) + scs_input_midi_byte(scs, stream, data[i]); + } else { + snd_rawmidi_receive(stream, sysex_escape_prefix, + ARRAY_SIZE(sysex_escape_prefix)); + for (i = 0; i < bytes; ++i) + scs_input_escaped_byte(stream, data[i]); + snd_rawmidi_receive(stream, (const u8[]) { 0xf7 }, 1); + } +} + +static struct snd_rawmidi_ops input_ops = { + .open = scs_input_open, + .close = scs_input_close, + .trigger = scs_input_trigger, +}; + +static int scs_create_midi(struct scs *scs) +{ + struct snd_rawmidi *rmidi; + int err; + + err = snd_rawmidi_new(scs->card, "SCS.1x", 0, 1, 1, &rmidi); + if (err < 0) + return err; + snprintf(rmidi->name, sizeof(rmidi->name), + "%s MIDI", scs->card->shortname); + rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT | + SNDRV_RAWMIDI_INFO_INPUT | + SNDRV_RAWMIDI_INFO_DUPLEX; + rmidi->private_data = scs; + snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &output_ops); + snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &input_ops); + + return 0; +} + +static void handle_hss(struct fw_card *card, struct fw_request *request, + int tcode, int destination, int source, int generation, + unsigned long long offset, void *data, size_t length, + void *callback_data) +{ + struct scs *scs = callback_data; + struct snd_rawmidi_substream *stream; + + if (offset != scs->hss_handler.offset) { + fw_send_response(card, request, RCODE_ADDRESS_ERROR); + return; + } + if (tcode != TCODE_WRITE_QUADLET_REQUEST && + tcode != TCODE_WRITE_BLOCK_REQUEST) { + fw_send_response(card, request, RCODE_TYPE_ERROR); + return; + } + + if (length >= 1) { + stream = ACCESS_ONCE(scs->input); + if (stream) + scs_input_packet(scs, stream, data, length); + } + + fw_send_response(card, request, RCODE_COMPLETE); +} + +static int scs_init_hss_address(struct scs *scs) +{ + __be64 data; + int err; + + data = cpu_to_be64(((u64)HSS1394_TAG_CHANGE_ADDRESS << 56) | + scs->hss_handler.offset); + err = snd_fw_transaction(scs->unit, TCODE_WRITE_BLOCK_REQUEST, + HSS1394_ADDRESS, &data, 8); + if (err < 0) + dev_err(&scs->unit->device, "HSS1394 communication failed\n"); + + return err; +} + +static void scs_card_free(struct snd_card *card) +{ + struct scs *scs = card->private_data; + + fw_core_remove_address_handler(&scs->hss_handler); + kfree(scs->buffer); +} + +static int scs_probe(struct device *unit_dev) +{ + struct fw_unit *unit = fw_unit(unit_dev); + struct fw_device *fw_dev = fw_parent_device(unit); + struct snd_card *card; + struct scs *scs; + int err; + + err = snd_card_create(-16, NULL, THIS_MODULE, sizeof(*scs), &card); + if (err < 0) + return err; + snd_card_set_dev(card, unit_dev); + + scs = card->private_data; + scs->card = card; + scs->unit = unit; + tasklet_init(&scs->tasklet, scs_output_tasklet, (unsigned long)scs); + init_waitqueue_head(&scs->idle_wait); + scs->output_idle = true; + + scs->buffer = kmalloc(HSS1394_MAX_PACKET_SIZE, GFP_KERNEL); + if (!scs->buffer) + goto err_card; + + scs->hss_handler.length = HSS1394_MAX_PACKET_SIZE; + scs->hss_handler.address_callback = handle_hss; + scs->hss_handler.callback_data = scs; + err = fw_core_add_address_handler(&scs->hss_handler, + &fw_high_memory_region); + if (err < 0) + goto err_buffer; + + card->private_free = scs_card_free; + + strcpy(card->driver, "SCS.1x"); + strcpy(card->shortname, "SCS.1x"); + fw_csr_string(unit->directory, CSR_MODEL, + card->shortname, sizeof(card->shortname)); + snprintf(card->longname, sizeof(card->longname), + "Stanton DJ %s (GUID %08x%08x) at %s, S%d", + card->shortname, fw_dev->config_rom[3], fw_dev->config_rom[4], + dev_name(&unit->device), 100 << fw_dev->max_speed); + strcpy(card->mixername, card->shortname); + + err = scs_init_hss_address(scs); + if (err < 0) + goto err_card; + + err = scs_create_midi(scs); + if (err < 0) + goto err_card; + + err = snd_card_register(card); + if (err < 0) + goto err_card; + + dev_set_drvdata(unit_dev, scs); + + return 0; + +err_buffer: + kfree(scs->buffer); +err_card: + snd_card_free(card); + return err; +} + +static int scs_remove(struct device *dev) +{ + struct scs *scs = dev_get_drvdata(dev); + + snd_card_disconnect(scs->card); + + ACCESS_ONCE(scs->output) = NULL; + ACCESS_ONCE(scs->input) = NULL; + + wait_event(scs->idle_wait, scs->output_idle); + + tasklet_kill(&scs->tasklet); + + snd_card_free_when_closed(scs->card); + + return 0; +} + +static void scs_update(struct fw_unit *unit) +{ + struct scs *scs = dev_get_drvdata(&unit->device); + __be64 data; + + data = cpu_to_be64(((u64)HSS1394_TAG_CHANGE_ADDRESS << 56) | + scs->hss_handler.offset); + snd_fw_transaction(scs->unit, TCODE_WRITE_BLOCK_REQUEST, + HSS1394_ADDRESS, &data, 8); +} + +static const struct ieee1394_device_id scs_id_table[] = { + { + .match_flags = IEEE1394_MATCH_VENDOR_ID | + IEEE1394_MATCH_MODEL_ID, + .vendor_id = OUI_STANTON, + .model_id = MODEL_SCS_1M, + }, + { + .match_flags = IEEE1394_MATCH_VENDOR_ID | + IEEE1394_MATCH_MODEL_ID, + .vendor_id = OUI_STANTON, + .model_id = MODEL_SCS_1D, + }, + {} +}; +MODULE_DEVICE_TABLE(ieee1394, scs_id_table); + +MODULE_DESCRIPTION("SCS.1x MIDI driver"); +MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); +MODULE_LICENSE("GPL v2"); + +static struct fw_driver scs_driver = { + .driver = { + .owner = THIS_MODULE, + .name = KBUILD_MODNAME, + .bus = &fw_bus_type, + .probe = scs_probe, + .remove = scs_remove, + }, + .update = scs_update, + .id_table = scs_id_table, +}; + +static int __init alsa_scs1x_init(void) +{ + return driver_register(&scs_driver.driver); +} + +static void __exit alsa_scs1x_exit(void) +{ + driver_unregister(&scs_driver.driver); +} + +module_init(alsa_scs1x_init); +module_exit(alsa_scs1x_exit); diff --git a/sound/firewire/speakers.c b/sound/firewire/speakers.c index 297244e658d9..d6846557f270 100644 --- a/sound/firewire/speakers.c +++ b/sound/firewire/speakers.c @@ -663,7 +663,7 @@ static void fwspk_card_free(struct snd_card *card) mutex_destroy(&fwspk->mutex); } -static const struct device_info *__devinit fwspk_detect(struct fw_device *dev) +static const struct device_info *fwspk_detect(struct fw_device *dev) { static const struct device_info griffin_firewave = { .driver_name = "FireWave", @@ -699,7 +699,7 @@ static const struct device_info *__devinit fwspk_detect(struct fw_device *dev) return NULL; } -static int __devinit fwspk_probe(struct device *unit_dev) +static int fwspk_probe(struct device *unit_dev) { struct fw_unit *unit = fw_unit(unit_dev); struct fw_device *fw_dev = fw_parent_device(unit); @@ -770,7 +770,7 @@ error: return err; } -static int __devexit fwspk_remove(struct device *dev) +static int fwspk_remove(struct device *dev) { struct fwspk *fwspk = dev_get_drvdata(dev); @@ -834,7 +834,7 @@ static struct fw_driver fwspk_driver = { .name = KBUILD_MODNAME, .bus = &fw_bus_type, .probe = fwspk_probe, - .remove = __devexit_p(fwspk_remove), + .remove = fwspk_remove, }, .update = fwspk_bus_reset, .id_table = fwspk_id_table, diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig index a38d9643e9d8..affa13480659 100644 --- a/sound/isa/Kconfig +++ b/sound/isa/Kconfig @@ -425,7 +425,7 @@ config SND_WAVEFRONT config SND_MSND_PINNACLE tristate "Turtle Beach MultiSound Pinnacle/Fiji driver" - depends on X86 && EXPERIMENTAL + depends on X86 select FW_LOADER select SND_MPU401_UART select SND_PCM @@ -438,7 +438,7 @@ config SND_MSND_PINNACLE config SND_MSND_CLASSIC tristate "Support for Turtle Beach MultiSound Classic, Tahiti, Monterey" - depends on X86 && EXPERIMENTAL + depends on X86 select FW_LOADER select SND_MPU401_UART select SND_PCM diff --git a/sound/isa/ad1816a/ad1816a.c b/sound/isa/ad1816a/ad1816a.c index 2c2f829c3fd7..26ce26a5884d 100644 --- a/sound/isa/ad1816a/ad1816a.c +++ b/sound/isa/ad1816a/ad1816a.c @@ -94,8 +94,8 @@ MODULE_DEVICE_TABLE(pnp_card, snd_ad1816a_pnpids); #define DRIVER_NAME "snd-card-ad1816a" -static int __devinit snd_card_ad1816a_pnp(int dev, struct pnp_card_link *card, - const struct pnp_card_device_id *id) +static int snd_card_ad1816a_pnp(int dev, struct pnp_card_link *card, + const struct pnp_card_device_id *id) { struct pnp_dev *pdev; int err; @@ -135,8 +135,8 @@ static int __devinit snd_card_ad1816a_pnp(int dev, struct pnp_card_link *card, return 0; } -static int __devinit snd_card_ad1816a_probe(int dev, struct pnp_card_link *pcard, - const struct pnp_card_device_id *pid) +static int snd_card_ad1816a_probe(int dev, struct pnp_card_link *pcard, + const struct pnp_card_device_id *pid) { int error; struct snd_card *card; @@ -217,10 +217,10 @@ static int __devinit snd_card_ad1816a_probe(int dev, struct pnp_card_link *pcard return 0; } -static unsigned int __devinitdata ad1816a_devices; +static unsigned int ad1816a_devices; -static int __devinit snd_ad1816a_pnp_detect(struct pnp_card_link *card, - const struct pnp_card_device_id *id) +static int snd_ad1816a_pnp_detect(struct pnp_card_link *card, + const struct pnp_card_device_id *id) { static int dev; int res; @@ -238,7 +238,7 @@ static int __devinit snd_ad1816a_pnp_detect(struct pnp_card_link *card, return -ENODEV; } -static void __devexit snd_ad1816a_pnp_remove(struct pnp_card_link * pcard) +static void snd_ad1816a_pnp_remove(struct pnp_card_link *pcard) { snd_card_free(pnp_get_card_drvdata(pcard)); pnp_set_card_drvdata(pcard, NULL); @@ -270,7 +270,7 @@ static struct pnp_card_driver ad1816a_pnpc_driver = { .name = "ad1816a", .id_table = snd_ad1816a_pnpids, .probe = snd_ad1816a_pnp_detect, - .remove = __devexit_p(snd_ad1816a_pnp_remove), + .remove = snd_ad1816a_pnp_remove, #ifdef CONFIG_PM .suspend = snd_ad1816a_pnp_suspend, .resume = snd_ad1816a_pnp_resume, diff --git a/sound/isa/ad1816a/ad1816a_lib.c b/sound/isa/ad1816a/ad1816a_lib.c index db64df6023e0..f0fd98e695e3 100644 --- a/sound/isa/ad1816a/ad1816a_lib.c +++ b/sound/isa/ad1816a/ad1816a_lib.c @@ -537,7 +537,7 @@ void snd_ad1816a_resume(struct snd_ad1816a *chip) } #endif -static int __devinit snd_ad1816a_probe(struct snd_ad1816a *chip) +static int snd_ad1816a_probe(struct snd_ad1816a *chip) { unsigned long flags; @@ -583,7 +583,7 @@ static int snd_ad1816a_dev_free(struct snd_device *device) return snd_ad1816a_free(chip); } -static const char __devinit *snd_ad1816a_chip_id(struct snd_ad1816a *chip) +static const char *snd_ad1816a_chip_id(struct snd_ad1816a *chip) { switch (chip->hardware) { case AD1816A_HW_AD1816A: return "AD1816A"; @@ -596,9 +596,9 @@ static const char __devinit *snd_ad1816a_chip_id(struct snd_ad1816a *chip) } } -int __devinit snd_ad1816a_create(struct snd_card *card, - unsigned long port, int irq, int dma1, int dma2, - struct snd_ad1816a *chip) +int snd_ad1816a_create(struct snd_card *card, + unsigned long port, int irq, int dma1, int dma2, + struct snd_ad1816a *chip) { static struct snd_device_ops ops = { .dev_free = snd_ad1816a_dev_free, @@ -675,7 +675,7 @@ static struct snd_pcm_ops snd_ad1816a_capture_ops = { .pointer = snd_ad1816a_capture_pointer, }; -int __devinit snd_ad1816a_pcm(struct snd_ad1816a *chip, int device, struct snd_pcm **rpcm) +int snd_ad1816a_pcm(struct snd_ad1816a *chip, int device, struct snd_pcm **rpcm) { int error; struct snd_pcm *pcm; @@ -702,7 +702,8 @@ int __devinit snd_ad1816a_pcm(struct snd_ad1816a *chip, int device, struct snd_p return 0; } -int __devinit snd_ad1816a_timer(struct snd_ad1816a *chip, int device, struct snd_timer **rtimer) +int snd_ad1816a_timer(struct snd_ad1816a *chip, int device, + struct snd_timer **rtimer) { struct snd_timer *timer; struct snd_timer_id tid; @@ -923,7 +924,7 @@ static const DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0); static const DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0); static const DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0); -static struct snd_kcontrol_new snd_ad1816a_controls[] __devinitdata = { +static struct snd_kcontrol_new snd_ad1816a_controls[] = { AD1816A_DOUBLE("Master Playback Switch", AD1816A_MASTER_ATT, 15, 7, 1, 1), AD1816A_DOUBLE_TLV("Master Playback Volume", AD1816A_MASTER_ATT, 8, 0, 31, 1, db_scale_5bit), @@ -969,7 +970,7 @@ AD1816A_SINGLE("3D Control - Switch", AD1816A_3D_PHAT_CTRL, 15, 1, 1), AD1816A_SINGLE("3D Control - Level", AD1816A_3D_PHAT_CTRL, 0, 15, 0), }; -int __devinit snd_ad1816a_mixer(struct snd_ad1816a *chip) +int snd_ad1816a_mixer(struct snd_ad1816a *chip) { struct snd_card *card; unsigned int idx; diff --git a/sound/isa/ad1848/ad1848.c b/sound/isa/ad1848/ad1848.c index 2af77faefbb1..c214ecf45400 100644 --- a/sound/isa/ad1848/ad1848.c +++ b/sound/isa/ad1848/ad1848.c @@ -64,7 +64,7 @@ MODULE_PARM_DESC(dma1, "DMA1 # for " CRD_NAME " driver."); module_param_array(thinkpad, bool, NULL, 0444); MODULE_PARM_DESC(thinkpad, "Enable only for the onboard CS4248 of IBM Thinkpad 360/750/755 series."); -static int __devinit snd_ad1848_match(struct device *dev, unsigned int n) +static int snd_ad1848_match(struct device *dev, unsigned int n) { if (!enable[n]) return 0; @@ -84,7 +84,7 @@ static int __devinit snd_ad1848_match(struct device *dev, unsigned int n) return 1; } -static int __devinit snd_ad1848_probe(struct device *dev, unsigned int n) +static int snd_ad1848_probe(struct device *dev, unsigned int n) { struct snd_card *card; struct snd_wss *chip; @@ -132,7 +132,7 @@ out: snd_card_free(card); return error; } -static int __devexit snd_ad1848_remove(struct device *dev, unsigned int n) +static int snd_ad1848_remove(struct device *dev, unsigned int n) { snd_card_free(dev_get_drvdata(dev)); dev_set_drvdata(dev, NULL); @@ -164,7 +164,7 @@ static int snd_ad1848_resume(struct device *dev, unsigned int n) static struct isa_driver snd_ad1848_driver = { .match = snd_ad1848_match, .probe = snd_ad1848_probe, - .remove = __devexit_p(snd_ad1848_remove), + .remove = snd_ad1848_remove, #ifdef CONFIG_PM .suspend = snd_ad1848_suspend, .resume = snd_ad1848_resume, diff --git a/sound/isa/adlib.c b/sound/isa/adlib.c index 4d50c69f3290..d26545543732 100644 --- a/sound/isa/adlib.c +++ b/sound/isa/adlib.c @@ -30,7 +30,7 @@ MODULE_PARM_DESC(enable, "Enable " CRD_NAME " soundcard."); module_param_array(port, long, NULL, 0444); MODULE_PARM_DESC(port, "Port # for " CRD_NAME " driver."); -static int __devinit snd_adlib_match(struct device *dev, unsigned int n) +static int snd_adlib_match(struct device *dev, unsigned int n) { if (!enable[n]) return 0; @@ -47,7 +47,7 @@ static void snd_adlib_free(struct snd_card *card) release_and_free_resource(card->private_data); } -static int __devinit snd_adlib_probe(struct device *dev, unsigned int n) +static int snd_adlib_probe(struct device *dev, unsigned int n) { struct snd_card *card; struct snd_opl3 *opl3; @@ -98,7 +98,7 @@ out: snd_card_free(card); return error; } -static int __devexit snd_adlib_remove(struct device *dev, unsigned int n) +static int snd_adlib_remove(struct device *dev, unsigned int n) { snd_card_free(dev_get_drvdata(dev)); dev_set_drvdata(dev, NULL); @@ -108,7 +108,7 @@ static int __devexit snd_adlib_remove(struct device *dev, unsigned int n) static struct isa_driver snd_adlib_driver = { .match = snd_adlib_match, .probe = snd_adlib_probe, - .remove = __devexit_p(snd_adlib_remove), + .remove = snd_adlib_remove, .driver = { .name = DEV_NAME diff --git a/sound/isa/als100.c b/sound/isa/als100.c index f7cdaf51512d..10f08a18fe3b 100644 --- a/sound/isa/als100.c +++ b/sound/isa/als100.c @@ -117,9 +117,9 @@ static struct pnp_card_device_id snd_als100_pnpids[] = { MODULE_DEVICE_TABLE(pnp_card, snd_als100_pnpids); -static int __devinit snd_card_als100_pnp(int dev, struct snd_card_als100 *acard, - struct pnp_card_link *card, - const struct pnp_card_device_id *id) +static int snd_card_als100_pnp(int dev, struct snd_card_als100 *acard, + struct pnp_card_link *card, + const struct pnp_card_device_id *id) { struct pnp_dev *pdev; int err; @@ -183,9 +183,9 @@ static int __devinit snd_card_als100_pnp(int dev, struct snd_card_als100 *acard, return 0; } -static int __devinit snd_card_als100_probe(int dev, - struct pnp_card_link *pcard, - const struct pnp_card_device_id *pid) +static int snd_card_als100_probe(int dev, + struct pnp_card_link *pcard, + const struct pnp_card_device_id *pid) { int error; struct snd_sb *chip; @@ -286,10 +286,10 @@ static int __devinit snd_card_als100_probe(int dev, return 0; } -static unsigned int __devinitdata als100_devices; +static unsigned int als100_devices; -static int __devinit snd_als100_pnp_detect(struct pnp_card_link *card, - const struct pnp_card_device_id *id) +static int snd_als100_pnp_detect(struct pnp_card_link *card, + const struct pnp_card_device_id *id) { static int dev; int res; @@ -307,7 +307,7 @@ static int __devinit snd_als100_pnp_detect(struct pnp_card_link *card, return -ENODEV; } -static void __devexit snd_als100_pnp_remove(struct pnp_card_link * pcard) +static void snd_als100_pnp_remove(struct pnp_card_link *pcard) { snd_card_free(pnp_get_card_drvdata(pcard)); pnp_set_card_drvdata(pcard, NULL); @@ -344,7 +344,7 @@ static struct pnp_card_driver als100_pnpc_driver = { .name = "als100", .id_table = snd_als100_pnpids, .probe = snd_als100_pnp_detect, - .remove = __devexit_p(snd_als100_pnp_remove), + .remove = snd_als100_pnp_remove, #ifdef CONFIG_PM .suspend = snd_als100_pnp_suspend, .resume = snd_als100_pnp_resume, diff --git a/sound/isa/azt2320.c b/sound/isa/azt2320.c index 6a2c78ef1d8f..db301ff94ec2 100644 --- a/sound/isa/azt2320.c +++ b/sound/isa/azt2320.c @@ -99,9 +99,9 @@ MODULE_DEVICE_TABLE(pnp_card, snd_azt2320_pnpids); #define DRIVER_NAME "snd-card-azt2320" -static int __devinit snd_card_azt2320_pnp(int dev, struct snd_card_azt2320 *acard, - struct pnp_card_link *card, - const struct pnp_card_device_id *id) +static int snd_card_azt2320_pnp(int dev, struct snd_card_azt2320 *acard, + struct pnp_card_link *card, + const struct pnp_card_device_id *id) { struct pnp_dev *pdev; int err; @@ -147,7 +147,7 @@ static int __devinit snd_card_azt2320_pnp(int dev, struct snd_card_azt2320 *acar } /* same of snd_sbdsp_command by Jaroslav Kysela */ -static int __devinit snd_card_azt2320_command(unsigned long port, unsigned char val) +static int snd_card_azt2320_command(unsigned long port, unsigned char val) { int i; unsigned long limit; @@ -161,7 +161,7 @@ static int __devinit snd_card_azt2320_command(unsigned long port, unsigned char return -EBUSY; } -static int __devinit snd_card_azt2320_enable_wss(unsigned long port) +static int snd_card_azt2320_enable_wss(unsigned long port) { int error; @@ -174,9 +174,9 @@ static int __devinit snd_card_azt2320_enable_wss(unsigned long port) return 0; } -static int __devinit snd_card_azt2320_probe(int dev, - struct pnp_card_link *pcard, - const struct pnp_card_device_id *pid) +static int snd_card_azt2320_probe(int dev, + struct pnp_card_link *pcard, + const struct pnp_card_device_id *pid) { int error; struct snd_card *card; @@ -264,10 +264,10 @@ static int __devinit snd_card_azt2320_probe(int dev, return 0; } -static unsigned int __devinitdata azt2320_devices; +static unsigned int azt2320_devices; -static int __devinit snd_azt2320_pnp_detect(struct pnp_card_link *card, - const struct pnp_card_device_id *id) +static int snd_azt2320_pnp_detect(struct pnp_card_link *card, + const struct pnp_card_device_id *id) { static int dev; int res; @@ -285,7 +285,7 @@ static int __devinit snd_azt2320_pnp_detect(struct pnp_card_link *card, return -ENODEV; } -static void __devexit snd_azt2320_pnp_remove(struct pnp_card_link * pcard) +static void snd_azt2320_pnp_remove(struct pnp_card_link *pcard) { snd_card_free(pnp_get_card_drvdata(pcard)); pnp_set_card_drvdata(pcard, NULL); @@ -320,7 +320,7 @@ static struct pnp_card_driver azt2320_pnpc_driver = { .name = "azt2320", .id_table = snd_azt2320_pnpids, .probe = snd_azt2320_pnp_detect, - .remove = __devexit_p(snd_azt2320_pnp_remove), + .remove = snd_azt2320_pnp_remove, #ifdef CONFIG_PM .suspend = snd_azt2320_pnp_suspend, .resume = snd_azt2320_pnp_resume, diff --git a/sound/isa/cmi8328.c b/sound/isa/cmi8328.c index bde60139bb95..a7369fe19a6f 100644 --- a/sound/isa/cmi8328.c +++ b/sound/isa/cmi8328.c @@ -140,7 +140,7 @@ static void snd_cmi8328_cfg_restore(u16 port, u8 cfg[]) snd_cmi8328_cfg_write(port, CFG3, cfg[2]); } -static int __devinit snd_cmi8328_mixer(struct snd_wss *chip) +static int snd_cmi8328_mixer(struct snd_wss *chip) { struct snd_card *card; struct snd_ctl_elem_id id1, id2; @@ -212,7 +212,7 @@ int array_find_l(long array[], long item) return -1; } -static int __devinit snd_cmi8328_probe(struct device *pdev, unsigned int ndev) +static int snd_cmi8328_probe(struct device *pdev, unsigned int ndev) { struct snd_card *card; struct snd_opl3 *opl3; @@ -401,7 +401,7 @@ error: return err; } -static int __devexit snd_cmi8328_remove(struct device *pdev, unsigned int dev) +static int snd_cmi8328_remove(struct device *pdev, unsigned int dev) { struct snd_card *card = dev_get_drvdata(pdev); struct snd_cmi8328 *cmi = card->private_data; @@ -459,7 +459,7 @@ static int snd_cmi8328_resume(struct device *pdev, unsigned int n) static struct isa_driver snd_cmi8328_driver = { .probe = snd_cmi8328_probe, - .remove = __devexit_p(snd_cmi8328_remove), + .remove = snd_cmi8328_remove, #ifdef CONFIG_PM .suspend = snd_cmi8328_suspend, .resume = snd_cmi8328_resume, diff --git a/sound/isa/cmi8330.c b/sound/isa/cmi8330.c index 7bd5e337ee93..c707c52268ab 100644 --- a/sound/isa/cmi8330.c +++ b/sound/isa/cmi8330.c @@ -193,7 +193,7 @@ MODULE_DEVICE_TABLE(pnp_card, snd_cmi8330_pnpids); #endif -static struct snd_kcontrol_new snd_cmi8330_controls[] __devinitdata = { +static struct snd_kcontrol_new snd_cmi8330_controls[] = { WSS_DOUBLE("Master Playback Volume", 0, CMI8330_MASTVOL, CMI8330_MASTVOL, 4, 0, 15, 0), WSS_SINGLE("Loud Playback Switch", 0, @@ -249,7 +249,7 @@ WSS_SINGLE(SNDRV_CTL_NAME_IEC958("Input ", PLAYBACK, SWITCH), 0, }; #ifdef ENABLE_SB_MIXER -static struct sbmix_elem cmi8330_sb_mixers[] __devinitdata = { +static struct sbmix_elem cmi8330_sb_mixers[] = { SB_DOUBLE("SB Master Playback Volume", SB_DSP4_MASTER_DEV, (SB_DSP4_MASTER_DEV + 1), 3, 3, 31), SB_DOUBLE("Tone Control - Bass", SB_DSP4_BASS_DEV, (SB_DSP4_BASS_DEV + 1), 4, 4, 15), SB_DOUBLE("Tone Control - Treble", SB_DSP4_TREBLE_DEV, (SB_DSP4_TREBLE_DEV + 1), 4, 4, 15), @@ -267,7 +267,7 @@ SB_DOUBLE("SB Playback Volume", SB_DSP4_OGAIN_DEV, (SB_DSP4_OGAIN_DEV + 1), 6, 6 SB_SINGLE("SB Mic Auto Gain", SB_DSP4_MIC_AGC, 0, 1), }; -static unsigned char cmi8330_sb_init_values[][2] __devinitdata = { +static unsigned char cmi8330_sb_init_values[][2] = { { SB_DSP4_MASTER_DEV + 0, 0 }, { SB_DSP4_MASTER_DEV + 1, 0 }, { SB_DSP4_PCM_DEV + 0, 0 }, @@ -281,7 +281,7 @@ static unsigned char cmi8330_sb_init_values[][2] __devinitdata = { }; -static int __devinit cmi8330_add_sb_mixers(struct snd_sb *chip) +static int cmi8330_add_sb_mixers(struct snd_sb *chip) { int idx, err; unsigned long flags; @@ -306,7 +306,7 @@ static int __devinit cmi8330_add_sb_mixers(struct snd_sb *chip) } #endif -static int __devinit snd_cmi8330_mixer(struct snd_card *card, struct snd_cmi8330 *acard) +static int snd_cmi8330_mixer(struct snd_card *card, struct snd_cmi8330 *acard) { unsigned int idx; int err; @@ -329,9 +329,9 @@ static int __devinit snd_cmi8330_mixer(struct snd_card *card, struct snd_cmi8330 } #ifdef CONFIG_PNP -static int __devinit snd_cmi8330_pnp(int dev, struct snd_cmi8330 *acard, - struct pnp_card_link *card, - const struct pnp_card_device_id *id) +static int snd_cmi8330_pnp(int dev, struct snd_cmi8330 *acard, + struct pnp_card_link *card, + const struct pnp_card_device_id *id) { struct pnp_dev *pdev; int err; @@ -437,7 +437,7 @@ static int snd_cmi8330_capture_open(struct snd_pcm_substream *substream) return chip->streams[SNDRV_PCM_STREAM_CAPTURE].open(substream); } -static int __devinit snd_cmi8330_pcm(struct snd_card *card, struct snd_cmi8330 *chip) +static int snd_cmi8330_pcm(struct snd_card *card, struct snd_cmi8330 *chip) { struct snd_pcm *pcm; const struct snd_pcm_ops *ops; @@ -532,7 +532,7 @@ static int snd_cmi8330_card_new(int dev, struct snd_card **cardp) return 0; } -static int __devinit snd_cmi8330_probe(struct snd_card *card, int dev) +static int snd_cmi8330_probe(struct snd_card *card, int dev) { struct snd_cmi8330 *acard; int i, err; @@ -613,8 +613,8 @@ static int __devinit snd_cmi8330_probe(struct snd_card *card, int dev) return snd_card_register(card); } -static int __devinit snd_cmi8330_isa_match(struct device *pdev, - unsigned int dev) +static int snd_cmi8330_isa_match(struct device *pdev, + unsigned int dev) { if (!enable[dev] || is_isapnp_selected(dev)) return 0; @@ -629,8 +629,8 @@ static int __devinit snd_cmi8330_isa_match(struct device *pdev, return 1; } -static int __devinit snd_cmi8330_isa_probe(struct device *pdev, - unsigned int dev) +static int snd_cmi8330_isa_probe(struct device *pdev, + unsigned int dev) { struct snd_card *card; int err; @@ -647,8 +647,8 @@ static int __devinit snd_cmi8330_isa_probe(struct device *pdev, return 0; } -static int __devexit snd_cmi8330_isa_remove(struct device *devptr, - unsigned int dev) +static int snd_cmi8330_isa_remove(struct device *devptr, + unsigned int dev) { snd_card_free(dev_get_drvdata(devptr)); dev_set_drvdata(devptr, NULL); @@ -673,7 +673,7 @@ static int snd_cmi8330_isa_resume(struct device *dev, unsigned int n) static struct isa_driver snd_cmi8330_driver = { .match = snd_cmi8330_isa_match, .probe = snd_cmi8330_isa_probe, - .remove = __devexit_p(snd_cmi8330_isa_remove), + .remove = snd_cmi8330_isa_remove, #ifdef CONFIG_PM .suspend = snd_cmi8330_isa_suspend, .resume = snd_cmi8330_isa_resume, @@ -685,8 +685,8 @@ static struct isa_driver snd_cmi8330_driver = { #ifdef CONFIG_PNP -static int __devinit snd_cmi8330_pnp_detect(struct pnp_card_link *pcard, - const struct pnp_card_device_id *pid) +static int snd_cmi8330_pnp_detect(struct pnp_card_link *pcard, + const struct pnp_card_device_id *pid) { static int dev; struct snd_card *card; @@ -717,7 +717,7 @@ static int __devinit snd_cmi8330_pnp_detect(struct pnp_card_link *pcard, return 0; } -static void __devexit snd_cmi8330_pnp_remove(struct pnp_card_link * pcard) +static void snd_cmi8330_pnp_remove(struct pnp_card_link *pcard) { snd_card_free(pnp_get_card_drvdata(pcard)); pnp_set_card_drvdata(pcard, NULL); @@ -740,7 +740,7 @@ static struct pnp_card_driver cmi8330_pnpc_driver = { .name = "cmi8330", .id_table = snd_cmi8330_pnpids, .probe = snd_cmi8330_pnp_detect, - .remove = __devexit_p(snd_cmi8330_pnp_remove), + .remove = snd_cmi8330_pnp_remove, #ifdef CONFIG_PM .suspend = snd_cmi8330_pnp_suspend, .resume = snd_cmi8330_pnp_resume, diff --git a/sound/isa/cs423x/cs4231.c b/sound/isa/cs423x/cs4231.c index 99dda45e82f5..aa7a5d86e480 100644 --- a/sound/isa/cs423x/cs4231.c +++ b/sound/isa/cs423x/cs4231.c @@ -68,7 +68,7 @@ MODULE_PARM_DESC(dma1, "DMA1 # for " CRD_NAME " driver."); module_param_array(dma2, int, NULL, 0444); MODULE_PARM_DESC(dma2, "DMA2 # for " CRD_NAME " driver."); -static int __devinit snd_cs4231_match(struct device *dev, unsigned int n) +static int snd_cs4231_match(struct device *dev, unsigned int n) { if (!enable[n]) return 0; @@ -88,7 +88,7 @@ static int __devinit snd_cs4231_match(struct device *dev, unsigned int n) return 1; } -static int __devinit snd_cs4231_probe(struct device *dev, unsigned int n) +static int snd_cs4231_probe(struct device *dev, unsigned int n) { struct snd_card *card; struct snd_wss *chip; @@ -148,7 +148,7 @@ out: snd_card_free(card); return error; } -static int __devexit snd_cs4231_remove(struct device *dev, unsigned int n) +static int snd_cs4231_remove(struct device *dev, unsigned int n) { snd_card_free(dev_get_drvdata(dev)); dev_set_drvdata(dev, NULL); @@ -180,7 +180,7 @@ static int snd_cs4231_resume(struct device *dev, unsigned int n) static struct isa_driver snd_cs4231_driver = { .match = snd_cs4231_match, .probe = snd_cs4231_probe, - .remove = __devexit_p(snd_cs4231_remove), + .remove = snd_cs4231_remove, #ifdef CONFIG_PM .suspend = snd_cs4231_suspend, .resume = snd_cs4231_resume, diff --git a/sound/isa/cs423x/cs4236.c b/sound/isa/cs423x/cs4236.c index 740c51a1ed7b..252e9fb37db3 100644 --- a/sound/isa/cs423x/cs4236.c +++ b/sound/isa/cs423x/cs4236.c @@ -251,7 +251,7 @@ static struct pnp_card_device_id snd_cs423x_pnpids[] = { MODULE_DEVICE_TABLE(pnp_card, snd_cs423x_pnpids); /* WSS initialization */ -static int __devinit snd_cs423x_pnp_init_wss(int dev, struct pnp_dev *pdev) +static int snd_cs423x_pnp_init_wss(int dev, struct pnp_dev *pdev) { if (pnp_activate_dev(pdev) < 0) { printk(KERN_ERR IDENT " WSS PnP configure failed for WSS (out of resources?)\n"); @@ -272,7 +272,7 @@ static int __devinit snd_cs423x_pnp_init_wss(int dev, struct pnp_dev *pdev) } /* CTRL initialization */ -static int __devinit snd_cs423x_pnp_init_ctrl(int dev, struct pnp_dev *pdev) +static int snd_cs423x_pnp_init_ctrl(int dev, struct pnp_dev *pdev) { if (pnp_activate_dev(pdev) < 0) { printk(KERN_ERR IDENT " CTRL PnP configure failed for WSS (out of resources?)\n"); @@ -284,7 +284,7 @@ static int __devinit snd_cs423x_pnp_init_ctrl(int dev, struct pnp_dev *pdev) } /* MPU initialization */ -static int __devinit snd_cs423x_pnp_init_mpu(int dev, struct pnp_dev *pdev) +static int snd_cs423x_pnp_init_mpu(int dev, struct pnp_dev *pdev) { if (pnp_activate_dev(pdev) < 0) { printk(KERN_ERR IDENT " MPU401 PnP configure failed for WSS (out of resources?)\n"); @@ -303,9 +303,9 @@ static int __devinit snd_cs423x_pnp_init_mpu(int dev, struct pnp_dev *pdev) return 0; } -static int __devinit snd_card_cs423x_pnp(int dev, struct snd_card_cs4236 *acard, - struct pnp_dev *pdev, - struct pnp_dev *cdev) +static int snd_card_cs423x_pnp(int dev, struct snd_card_cs4236 *acard, + struct pnp_dev *pdev, + struct pnp_dev *cdev) { acard->wss = pdev; if (snd_cs423x_pnp_init_wss(dev, acard->wss) < 0) @@ -317,9 +317,9 @@ static int __devinit snd_card_cs423x_pnp(int dev, struct snd_card_cs4236 *acard, return 0; } -static int __devinit snd_card_cs423x_pnpc(int dev, struct snd_card_cs4236 *acard, - struct pnp_card_link *card, - const struct pnp_card_device_id *id) +static int snd_card_cs423x_pnpc(int dev, struct snd_card_cs4236 *acard, + struct pnp_card_link *card, + const struct pnp_card_device_id *id) { acard->wss = pnp_request_card_device(card, id->devs[0].id, NULL); if (acard->wss == NULL) @@ -378,7 +378,7 @@ static int snd_cs423x_card_new(int dev, struct snd_card **cardp) return 0; } -static int __devinit snd_cs423x_probe(struct snd_card *card, int dev) +static int snd_cs423x_probe(struct snd_card *card, int dev) { struct snd_card_cs4236 *acard; struct snd_pcm *pcm; @@ -456,8 +456,8 @@ static int __devinit snd_cs423x_probe(struct snd_card *card, int dev) return snd_card_register(card); } -static int __devinit snd_cs423x_isa_match(struct device *pdev, - unsigned int dev) +static int snd_cs423x_isa_match(struct device *pdev, + unsigned int dev) { if (!enable[dev] || is_isapnp_selected(dev)) return 0; @@ -481,8 +481,8 @@ static int __devinit snd_cs423x_isa_match(struct device *pdev, return 1; } -static int __devinit snd_cs423x_isa_probe(struct device *pdev, - unsigned int dev) +static int snd_cs423x_isa_probe(struct device *pdev, + unsigned int dev) { struct snd_card *card; int err; @@ -500,8 +500,8 @@ static int __devinit snd_cs423x_isa_probe(struct device *pdev, return 0; } -static int __devexit snd_cs423x_isa_remove(struct device *pdev, - unsigned int dev) +static int snd_cs423x_isa_remove(struct device *pdev, + unsigned int dev) { snd_card_free(dev_get_drvdata(pdev)); dev_set_drvdata(pdev, NULL); @@ -540,7 +540,7 @@ static int snd_cs423x_isa_resume(struct device *dev, unsigned int n) static struct isa_driver cs423x_isa_driver = { .match = snd_cs423x_isa_match, .probe = snd_cs423x_isa_probe, - .remove = __devexit_p(snd_cs423x_isa_remove), + .remove = snd_cs423x_isa_remove, #ifdef CONFIG_PM .suspend = snd_cs423x_isa_suspend, .resume = snd_cs423x_isa_resume, @@ -552,8 +552,8 @@ static struct isa_driver cs423x_isa_driver = { #ifdef CONFIG_PNP -static int __devinit snd_cs423x_pnpbios_detect(struct pnp_dev *pdev, - const struct pnp_device_id *id) +static int snd_cs423x_pnpbios_detect(struct pnp_dev *pdev, + const struct pnp_device_id *id) { static int dev; int err; @@ -597,7 +597,7 @@ static int __devinit snd_cs423x_pnpbios_detect(struct pnp_dev *pdev, return 0; } -static void __devexit snd_cs423x_pnp_remove(struct pnp_dev *pdev) +static void snd_cs423x_pnp_remove(struct pnp_dev *pdev) { snd_card_free(pnp_get_drvdata(pdev)); pnp_set_drvdata(pdev, NULL); @@ -619,15 +619,15 @@ static struct pnp_driver cs423x_pnp_driver = { .name = "cs423x-pnpbios", .id_table = snd_cs423x_pnpbiosids, .probe = snd_cs423x_pnpbios_detect, - .remove = __devexit_p(snd_cs423x_pnp_remove), + .remove = snd_cs423x_pnp_remove, #ifdef CONFIG_PM .suspend = snd_cs423x_pnp_suspend, .resume = snd_cs423x_pnp_resume, #endif }; -static int __devinit snd_cs423x_pnpc_detect(struct pnp_card_link *pcard, - const struct pnp_card_device_id *pid) +static int snd_cs423x_pnpc_detect(struct pnp_card_link *pcard, + const struct pnp_card_device_id *pid) { static int dev; struct snd_card *card; @@ -659,7 +659,7 @@ static int __devinit snd_cs423x_pnpc_detect(struct pnp_card_link *pcard, return 0; } -static void __devexit snd_cs423x_pnpc_remove(struct pnp_card_link * pcard) +static void snd_cs423x_pnpc_remove(struct pnp_card_link *pcard) { snd_card_free(pnp_get_card_drvdata(pcard)); pnp_set_card_drvdata(pcard, NULL); @@ -682,7 +682,7 @@ static struct pnp_card_driver cs423x_pnpc_driver = { .name = CS423X_ISAPNP_DRIVER, .id_table = snd_cs423x_pnpids, .probe = snd_cs423x_pnpc_detect, - .remove = __devexit_p(snd_cs423x_pnpc_remove), + .remove = snd_cs423x_pnpc_remove, #ifdef CONFIG_PM .suspend = snd_cs423x_pnpc_suspend, .resume = snd_cs423x_pnpc_resume, diff --git a/sound/isa/es1688/es1688.c b/sound/isa/es1688/es1688.c index b036e60f62d1..102874a703d4 100644 --- a/sound/isa/es1688/es1688.c +++ b/sound/isa/es1688/es1688.c @@ -90,13 +90,13 @@ MODULE_PARM_DESC(dma8, "8-bit DMA # for " CRD_NAME " driver."); #define is_isapnp_selected(dev) 0 #endif -static int __devinit snd_es1688_match(struct device *dev, unsigned int n) +static int snd_es1688_match(struct device *dev, unsigned int n) { return enable[n] && !is_isapnp_selected(n); } -static int __devinit snd_es1688_legacy_create(struct snd_card *card, - struct device *dev, unsigned int n) +static int snd_es1688_legacy_create(struct snd_card *card, + struct device *dev, unsigned int n) { struct snd_es1688 *chip = card->private_data; static long possible_ports[] = {0x220, 0x240, 0x260}; @@ -134,7 +134,7 @@ static int __devinit snd_es1688_legacy_create(struct snd_card *card, return error; } -static int __devinit snd_es1688_probe(struct snd_card *card, unsigned int n) +static int snd_es1688_probe(struct snd_card *card, unsigned int n) { struct snd_es1688 *chip = card->private_data; struct snd_opl3 *opl3; @@ -182,7 +182,7 @@ static int __devinit snd_es1688_probe(struct snd_card *card, unsigned int n) return snd_card_register(card); } -static int __devinit snd_es1688_isa_probe(struct device *dev, unsigned int n) +static int snd_es1688_isa_probe(struct device *dev, unsigned int n) { struct snd_card *card; int error; @@ -210,7 +210,7 @@ out: return error; } -static int __devexit snd_es1688_isa_remove(struct device *dev, unsigned int n) +static int snd_es1688_isa_remove(struct device *dev, unsigned int n) { snd_card_free(dev_get_drvdata(dev)); dev_set_drvdata(dev, NULL); @@ -220,7 +220,7 @@ static int __devexit snd_es1688_isa_remove(struct device *dev, unsigned int n) static struct isa_driver snd_es1688_driver = { .match = snd_es1688_match, .probe = snd_es1688_isa_probe, - .remove = __devexit_p(snd_es1688_isa_remove), + .remove = snd_es1688_isa_remove, #if 0 /* FIXME */ .suspend = snd_es1688_suspend, .resume = snd_es1688_resume, @@ -233,9 +233,9 @@ static struct isa_driver snd_es1688_driver = { static int snd_es968_pnp_is_probed; #ifdef CONFIG_PNP -static int __devinit snd_card_es968_pnp(struct snd_card *card, unsigned int n, - struct pnp_card_link *pcard, - const struct pnp_card_device_id *pid) +static int snd_card_es968_pnp(struct snd_card *card, unsigned int n, + struct pnp_card_link *pcard, + const struct pnp_card_device_id *pid) { struct snd_es1688 *chip = card->private_data; struct pnp_dev *pdev; @@ -258,8 +258,8 @@ static int __devinit snd_card_es968_pnp(struct snd_card *card, unsigned int n, mpu_irq[n], dma8[n], ES1688_HW_AUTO); } -static int __devinit snd_es968_pnp_detect(struct pnp_card_link *pcard, - const struct pnp_card_device_id *pid) +static int snd_es968_pnp_detect(struct pnp_card_link *pcard, + const struct pnp_card_device_id *pid) { struct snd_card *card; static unsigned int dev; @@ -295,7 +295,7 @@ static int __devinit snd_es968_pnp_detect(struct pnp_card_link *pcard, return 0; } -static void __devexit snd_es968_pnp_remove(struct pnp_card_link * pcard) +static void snd_es968_pnp_remove(struct pnp_card_link *pcard) { snd_card_free(pnp_get_card_drvdata(pcard)); pnp_set_card_drvdata(pcard, NULL); @@ -338,7 +338,7 @@ static struct pnp_card_driver es968_pnpc_driver = { .name = DEV_NAME " PnP", .id_table = snd_es968_pnpids, .probe = snd_es968_pnp_detect, - .remove = __devexit_p(snd_es968_pnp_remove), + .remove = snd_es968_pnp_remove, #ifdef CONFIG_PM .suspend = snd_es968_pnp_suspend, .resume = snd_es968_pnp_resume, diff --git a/sound/isa/es18xx.c b/sound/isa/es18xx.c index c20baafd9b7c..24380efe31a1 100644 --- a/sound/isa/es18xx.c +++ b/sound/isa/es18xx.c @@ -348,7 +348,7 @@ static inline int snd_es18xx_mixer_writable(struct snd_es18xx *chip, unsigned ch } -static int __devinit snd_es18xx_reset(struct snd_es18xx *chip) +static int snd_es18xx_reset(struct snd_es18xx *chip) { int i; outb(0x03, chip->port + 0x06); @@ -1363,7 +1363,7 @@ static struct snd_kcontrol_new snd_es18xx_hw_volume_controls[] = { ES18XX_SINGLE("Hardware Master Volume Split", 0, 0x64, 7, 1, 0), }; -static int __devinit snd_es18xx_config_read(struct snd_es18xx *chip, unsigned char reg) +static int snd_es18xx_config_read(struct snd_es18xx *chip, unsigned char reg) { int data; @@ -1372,8 +1372,8 @@ static int __devinit snd_es18xx_config_read(struct snd_es18xx *chip, unsigned ch return data; } -static void __devinit snd_es18xx_config_write(struct snd_es18xx *chip, - unsigned char reg, unsigned char data) +static void snd_es18xx_config_write(struct snd_es18xx *chip, + unsigned char reg, unsigned char data) { /* No need for spinlocks, this function is used only in otherwise protected init code */ @@ -1384,9 +1384,9 @@ static void __devinit snd_es18xx_config_write(struct snd_es18xx *chip, #endif } -static int __devinit snd_es18xx_initialize(struct snd_es18xx *chip, - unsigned long mpu_port, - unsigned long fm_port) +static int snd_es18xx_initialize(struct snd_es18xx *chip, + unsigned long mpu_port, + unsigned long fm_port) { int mask = 0; @@ -1549,7 +1549,7 @@ static int __devinit snd_es18xx_initialize(struct snd_es18xx *chip, return 0; } -static int __devinit snd_es18xx_identify(struct snd_es18xx *chip) +static int snd_es18xx_identify(struct snd_es18xx *chip) { int hi,lo; @@ -1618,9 +1618,9 @@ static int __devinit snd_es18xx_identify(struct snd_es18xx *chip) return 0; } -static int __devinit snd_es18xx_probe(struct snd_es18xx *chip, - unsigned long mpu_port, - unsigned long fm_port) +static int snd_es18xx_probe(struct snd_es18xx *chip, + unsigned long mpu_port, + unsigned long fm_port) { if (snd_es18xx_identify(chip) < 0) { snd_printk(KERN_ERR PFX "[0x%lx] ESS chip not found\n", chip->port); @@ -1680,8 +1680,8 @@ static struct snd_pcm_ops snd_es18xx_capture_ops = { .pointer = snd_es18xx_capture_pointer, }; -static int __devinit snd_es18xx_pcm(struct snd_card *card, int device, - struct snd_pcm **rpcm) +static int snd_es18xx_pcm(struct snd_card *card, int device, + struct snd_pcm **rpcm) { struct snd_es18xx *chip = card->private_data; struct snd_pcm *pcm; @@ -1777,11 +1777,11 @@ static int snd_es18xx_dev_free(struct snd_device *device) return snd_es18xx_free(device->card); } -static int __devinit snd_es18xx_new_device(struct snd_card *card, - unsigned long port, - unsigned long mpu_port, - unsigned long fm_port, - int irq, int dma1, int dma2) +static int snd_es18xx_new_device(struct snd_card *card, + unsigned long port, + unsigned long mpu_port, + unsigned long fm_port, + int irq, int dma1, int dma2) { struct snd_es18xx *chip = card->private_data; static struct snd_device_ops ops = { @@ -1839,7 +1839,7 @@ static int __devinit snd_es18xx_new_device(struct snd_card *card, return 0; } -static int __devinit snd_es18xx_mixer(struct snd_card *card) +static int snd_es18xx_mixer(struct snd_card *card) { struct snd_es18xx *chip = card->private_data; int err; @@ -2016,7 +2016,7 @@ static struct pnp_device_id snd_audiodrive_pnpbiosids[] = { MODULE_DEVICE_TABLE(pnp, snd_audiodrive_pnpbiosids); /* PnP main device initialization */ -static int __devinit snd_audiodrive_pnp_init_main(int dev, struct pnp_dev *pdev) +static int snd_audiodrive_pnp_init_main(int dev, struct pnp_dev *pdev) { if (pnp_activate_dev(pdev) < 0) { snd_printk(KERN_ERR PFX "PnP configure failure (out of resources?)\n"); @@ -2043,8 +2043,8 @@ static int __devinit snd_audiodrive_pnp_init_main(int dev, struct pnp_dev *pdev) return 0; } -static int __devinit snd_audiodrive_pnp(int dev, struct snd_es18xx *chip, - struct pnp_dev *pdev) +static int snd_audiodrive_pnp(int dev, struct snd_es18xx *chip, + struct pnp_dev *pdev) { chip->dev = pdev; if (snd_audiodrive_pnp_init_main(dev, chip->dev) < 0) @@ -2073,9 +2073,9 @@ static struct pnp_card_device_id snd_audiodrive_pnpids[] = { MODULE_DEVICE_TABLE(pnp_card, snd_audiodrive_pnpids); -static int __devinit snd_audiodrive_pnpc(int dev, struct snd_es18xx *chip, - struct pnp_card_link *card, - const struct pnp_card_device_id *id) +static int snd_audiodrive_pnpc(int dev, struct snd_es18xx *chip, + struct pnp_card_link *card, + const struct pnp_card_device_id *id) { chip->dev = pnp_request_card_device(card, id->devs[0].id, NULL); if (chip->dev == NULL) @@ -2111,7 +2111,7 @@ static int snd_es18xx_card_new(int dev, struct snd_card **cardp) sizeof(struct snd_es18xx), cardp); } -static int __devinit snd_audiodrive_probe(struct snd_card *card, int dev) +static int snd_audiodrive_probe(struct snd_card *card, int dev) { struct snd_es18xx *chip = card->private_data; struct snd_opl3 *opl3; @@ -2169,12 +2169,12 @@ static int __devinit snd_audiodrive_probe(struct snd_card *card, int dev) return snd_card_register(card); } -static int __devinit snd_es18xx_isa_match(struct device *pdev, unsigned int dev) +static int snd_es18xx_isa_match(struct device *pdev, unsigned int dev) { return enable[dev] && !is_isapnp_selected(dev); } -static int __devinit snd_es18xx_isa_probe1(int dev, struct device *devptr) +static int snd_es18xx_isa_probe1(int dev, struct device *devptr) { struct snd_card *card; int err; @@ -2191,7 +2191,7 @@ static int __devinit snd_es18xx_isa_probe1(int dev, struct device *devptr) return 0; } -static int __devinit snd_es18xx_isa_probe(struct device *pdev, unsigned int dev) +static int snd_es18xx_isa_probe(struct device *pdev, unsigned int dev) { int err; static int possible_irqs[] = {5, 9, 10, 7, 11, 12, -1}; @@ -2231,8 +2231,8 @@ static int __devinit snd_es18xx_isa_probe(struct device *pdev, unsigned int dev) } } -static int __devexit snd_es18xx_isa_remove(struct device *devptr, - unsigned int dev) +static int snd_es18xx_isa_remove(struct device *devptr, + unsigned int dev) { snd_card_free(dev_get_drvdata(devptr)); dev_set_drvdata(devptr, NULL); @@ -2257,7 +2257,7 @@ static int snd_es18xx_isa_resume(struct device *dev, unsigned int n) static struct isa_driver snd_es18xx_isa_driver = { .match = snd_es18xx_isa_match, .probe = snd_es18xx_isa_probe, - .remove = __devexit_p(snd_es18xx_isa_remove), + .remove = snd_es18xx_isa_remove, #ifdef CONFIG_PM .suspend = snd_es18xx_isa_suspend, .resume = snd_es18xx_isa_resume, @@ -2269,8 +2269,8 @@ static struct isa_driver snd_es18xx_isa_driver = { #ifdef CONFIG_PNP -static int __devinit snd_audiodrive_pnp_detect(struct pnp_dev *pdev, - const struct pnp_device_id *id) +static int snd_audiodrive_pnp_detect(struct pnp_dev *pdev, + const struct pnp_device_id *id) { static int dev; int err; @@ -2302,7 +2302,7 @@ static int __devinit snd_audiodrive_pnp_detect(struct pnp_dev *pdev, return 0; } -static void __devexit snd_audiodrive_pnp_remove(struct pnp_dev * pdev) +static void snd_audiodrive_pnp_remove(struct pnp_dev *pdev) { snd_card_free(pnp_get_drvdata(pdev)); pnp_set_drvdata(pdev, NULL); @@ -2323,15 +2323,15 @@ static struct pnp_driver es18xx_pnp_driver = { .name = "es18xx-pnpbios", .id_table = snd_audiodrive_pnpbiosids, .probe = snd_audiodrive_pnp_detect, - .remove = __devexit_p(snd_audiodrive_pnp_remove), + .remove = snd_audiodrive_pnp_remove, #ifdef CONFIG_PM .suspend = snd_audiodrive_pnp_suspend, .resume = snd_audiodrive_pnp_resume, #endif }; -static int __devinit snd_audiodrive_pnpc_detect(struct pnp_card_link *pcard, - const struct pnp_card_device_id *pid) +static int snd_audiodrive_pnpc_detect(struct pnp_card_link *pcard, + const struct pnp_card_device_id *pid) { static int dev; struct snd_card *card; @@ -2363,7 +2363,7 @@ static int __devinit snd_audiodrive_pnpc_detect(struct pnp_card_link *pcard, return 0; } -static void __devexit snd_audiodrive_pnpc_remove(struct pnp_card_link * pcard) +static void snd_audiodrive_pnpc_remove(struct pnp_card_link *pcard) { snd_card_free(pnp_get_card_drvdata(pcard)); pnp_set_card_drvdata(pcard, NULL); @@ -2387,7 +2387,7 @@ static struct pnp_card_driver es18xx_pnpc_driver = { .name = "es18xx", .id_table = snd_audiodrive_pnpids, .probe = snd_audiodrive_pnpc_detect, - .remove = __devexit_p(snd_audiodrive_pnpc_remove), + .remove = snd_audiodrive_pnpc_remove, #ifdef CONFIG_PM .suspend = snd_audiodrive_pnpc_suspend, .resume = snd_audiodrive_pnpc_resume, diff --git a/sound/isa/galaxy/galaxy.c b/sound/isa/galaxy/galaxy.c index 55e20782858d..672184e3221a 100644 --- a/sound/isa/galaxy/galaxy.c +++ b/sound/isa/galaxy/galaxy.c @@ -84,7 +84,7 @@ MODULE_PARM_DESC(dma2, "Capture DMA # for " CRD_NAME " driver."); #define DSP_COMMAND_GET_VERSION 0xe1 -static int __devinit dsp_get_byte(void __iomem *port, u8 *val) +static int dsp_get_byte(void __iomem *port, u8 *val) { int loops = 1000; @@ -97,7 +97,7 @@ static int __devinit dsp_get_byte(void __iomem *port, u8 *val) return 0; } -static int __devinit dsp_reset(void __iomem *port) +static int dsp_reset(void __iomem *port) { u8 val; @@ -111,7 +111,7 @@ static int __devinit dsp_reset(void __iomem *port) return 0; } -static int __devinit dsp_command(void __iomem *port, u8 cmd) +static int dsp_command(void __iomem *port, u8 cmd) { int loops = 1000; @@ -124,7 +124,7 @@ static int __devinit dsp_command(void __iomem *port, u8 cmd) return 0; } -static int __devinit dsp_get_version(void __iomem *port, u8 *major, u8 *minor) +static int dsp_get_version(void __iomem *port, u8 *major, u8 *minor) { int err; @@ -161,7 +161,7 @@ static int __devinit dsp_get_version(void __iomem *port, u8 *major, u8 *minor) #define WSS_SIGNATURE 4 -static int __devinit wss_detect(void __iomem *wss_port) +static int wss_detect(void __iomem *wss_port) { if ((ioread8(wss_port + WSS_PORT_SIGNATURE) & 0x3f) != WSS_SIGNATURE) return -ENODEV; @@ -204,7 +204,7 @@ struct snd_galaxy { static u32 config[SNDRV_CARDS]; static u8 wss_config[SNDRV_CARDS]; -static int __devinit snd_galaxy_match(struct device *dev, unsigned int n) +static int snd_galaxy_match(struct device *dev, unsigned int n) { if (!enable[n]) return 0; @@ -379,7 +379,7 @@ fm: return 1; } -static int __devinit galaxy_init(struct snd_galaxy *galaxy, u8 *type) +static int galaxy_init(struct snd_galaxy *galaxy, u8 *type) { u8 major; u8 minor; @@ -411,7 +411,7 @@ static int __devinit galaxy_init(struct snd_galaxy *galaxy, u8 *type) return 0; } -static int __devinit galaxy_set_mode(struct snd_galaxy *galaxy, u8 mode) +static int galaxy_set_mode(struct snd_galaxy *galaxy, u8 mode) { int err; @@ -449,7 +449,7 @@ static void galaxy_set_config(struct snd_galaxy *galaxy, u32 config) msleep(10); } -static void __devinit galaxy_config(struct snd_galaxy *galaxy, u32 config) +static void galaxy_config(struct snd_galaxy *galaxy, u32 config) { int i; @@ -461,7 +461,7 @@ static void __devinit galaxy_config(struct snd_galaxy *galaxy, u32 config) galaxy_set_config(galaxy, config); } -static int __devinit galaxy_wss_config(struct snd_galaxy *galaxy, u8 wss_config) +static int galaxy_wss_config(struct snd_galaxy *galaxy, u8 wss_config) { int err; @@ -498,7 +498,7 @@ static void snd_galaxy_free(struct snd_card *card) } } -static int __devinit snd_galaxy_probe(struct device *dev, unsigned int n) +static int snd_galaxy_probe(struct device *dev, unsigned int n) { struct snd_galaxy *galaxy; struct snd_wss *chip; @@ -620,7 +620,7 @@ error: return err; } -static int __devexit snd_galaxy_remove(struct device *dev, unsigned int n) +static int snd_galaxy_remove(struct device *dev, unsigned int n) { snd_card_free(dev_get_drvdata(dev)); dev_set_drvdata(dev, NULL); @@ -630,7 +630,7 @@ static int __devexit snd_galaxy_remove(struct device *dev, unsigned int n) static struct isa_driver snd_galaxy_driver = { .match = snd_galaxy_match, .probe = snd_galaxy_probe, - .remove = __devexit_p(snd_galaxy_remove), + .remove = snd_galaxy_remove, .driver = { .name = DEV_NAME diff --git a/sound/isa/gus/gusclassic.c b/sound/isa/gus/gusclassic.c index bf6333671613..16bca4e96c08 100644 --- a/sound/isa/gus/gusclassic.c +++ b/sound/isa/gus/gusclassic.c @@ -73,13 +73,14 @@ MODULE_PARM_DESC(channels, "GF1 channels for " CRD_NAME " driver."); module_param_array(pcm_channels, int, NULL, 0444); MODULE_PARM_DESC(pcm_channels, "Reserved PCM channels for " CRD_NAME " driver."); -static int __devinit snd_gusclassic_match(struct device *dev, unsigned int n) +static int snd_gusclassic_match(struct device *dev, unsigned int n) { return enable[n]; } -static int __devinit snd_gusclassic_create(struct snd_card *card, - struct device *dev, unsigned int n, struct snd_gus_card **rgus) +static int snd_gusclassic_create(struct snd_card *card, + struct device *dev, unsigned int n, + struct snd_gus_card **rgus) { static long possible_ports[] = {0x220, 0x230, 0x240, 0x250, 0x260}; static int possible_irqs[] = {5, 11, 12, 9, 7, 15, 3, 4, -1}; @@ -123,7 +124,7 @@ static int __devinit snd_gusclassic_create(struct snd_card *card, return error; } -static int __devinit snd_gusclassic_detect(struct snd_gus_card *gus) +static int snd_gusclassic_detect(struct snd_gus_card *gus) { unsigned char d; @@ -142,7 +143,7 @@ static int __devinit snd_gusclassic_detect(struct snd_gus_card *gus) return 0; } -static int __devinit snd_gusclassic_probe(struct device *dev, unsigned int n) +static int snd_gusclassic_probe(struct device *dev, unsigned int n) { struct snd_card *card; struct snd_gus_card *gus; @@ -211,7 +212,7 @@ out: snd_card_free(card); return error; } -static int __devexit snd_gusclassic_remove(struct device *dev, unsigned int n) +static int snd_gusclassic_remove(struct device *dev, unsigned int n) { snd_card_free(dev_get_drvdata(dev)); dev_set_drvdata(dev, NULL); @@ -221,7 +222,7 @@ static int __devexit snd_gusclassic_remove(struct device *dev, unsigned int n) static struct isa_driver snd_gusclassic_driver = { .match = snd_gusclassic_match, .probe = snd_gusclassic_probe, - .remove = __devexit_p(snd_gusclassic_remove), + .remove = snd_gusclassic_remove, #if 0 /* FIXME */ .suspend = snd_gusclassic_suspend, .remove = snd_gusclassic_remove, diff --git a/sound/isa/gus/gusextreme.c b/sound/isa/gus/gusextreme.c index bc10cc26e5f9..0b9c2426b49f 100644 --- a/sound/isa/gus/gusextreme.c +++ b/sound/isa/gus/gusextreme.c @@ -89,13 +89,14 @@ MODULE_PARM_DESC(channels, "GF1 channels for " CRD_NAME " driver."); module_param_array(pcm_channels, int, NULL, 0444); MODULE_PARM_DESC(pcm_channels, "Reserved PCM channels for " CRD_NAME " driver."); -static int __devinit snd_gusextreme_match(struct device *dev, unsigned int n) +static int snd_gusextreme_match(struct device *dev, unsigned int n) { return enable[n]; } -static int __devinit snd_gusextreme_es1688_create(struct snd_card *card, - struct snd_es1688 *chip, struct device *dev, unsigned int n) +static int snd_gusextreme_es1688_create(struct snd_card *card, + struct snd_es1688 *chip, + struct device *dev, unsigned int n) { static long possible_ports[] = {0x220, 0x240, 0x260}; static int possible_irqs[] = {5, 9, 10, 7, -1}; @@ -132,8 +133,9 @@ static int __devinit snd_gusextreme_es1688_create(struct snd_card *card, return error; } -static int __devinit snd_gusextreme_gus_card_create(struct snd_card *card, - struct device *dev, unsigned int n, struct snd_gus_card **rgus) +static int snd_gusextreme_gus_card_create(struct snd_card *card, + struct device *dev, unsigned int n, + struct snd_gus_card **rgus) { static int possible_irqs[] = {11, 12, 15, 9, 5, 7, 3, -1}; static int possible_dmas[] = {5, 6, 7, 3, 1, -1}; @@ -156,8 +158,8 @@ static int __devinit snd_gusextreme_gus_card_create(struct snd_card *card, 0, channels[n], pcm_channels[n], 0, rgus); } -static int __devinit snd_gusextreme_detect(struct snd_gus_card *gus, - struct snd_es1688 *es1688) +static int snd_gusextreme_detect(struct snd_gus_card *gus, + struct snd_es1688 *es1688) { unsigned long flags; unsigned char d; @@ -206,7 +208,7 @@ static int __devinit snd_gusextreme_detect(struct snd_gus_card *gus, return 0; } -static int __devinit snd_gusextreme_mixer(struct snd_card *card) +static int snd_gusextreme_mixer(struct snd_card *card) { struct snd_ctl_elem_id id1, id2; int error; @@ -232,7 +234,7 @@ static int __devinit snd_gusextreme_mixer(struct snd_card *card) return 0; } -static int __devinit snd_gusextreme_probe(struct device *dev, unsigned int n) +static int snd_gusextreme_probe(struct device *dev, unsigned int n) { struct snd_card *card; struct snd_gus_card *gus; @@ -339,7 +341,7 @@ out: snd_card_free(card); return error; } -static int __devexit snd_gusextreme_remove(struct device *dev, unsigned int n) +static int snd_gusextreme_remove(struct device *dev, unsigned int n) { snd_card_free(dev_get_drvdata(dev)); dev_set_drvdata(dev, NULL); @@ -349,7 +351,7 @@ static int __devexit snd_gusextreme_remove(struct device *dev, unsigned int n) static struct isa_driver snd_gusextreme_driver = { .match = snd_gusextreme_match, .probe = snd_gusextreme_probe, - .remove = __devexit_p(snd_gusextreme_remove), + .remove = snd_gusextreme_remove, #if 0 /* FIXME */ .suspend = snd_gusextreme_suspend, .resume = snd_gusextreme_resume, diff --git a/sound/isa/gus/gusmax.c b/sound/isa/gus/gusmax.c index 41c3f448745f..c309a5d0e7e1 100644 --- a/sound/isa/gus/gusmax.c +++ b/sound/isa/gus/gusmax.c @@ -82,7 +82,7 @@ struct snd_gusmax { #define PFX "gusmax: " -static int __devinit snd_gusmax_detect(struct snd_gus_card * gus) +static int snd_gusmax_detect(struct snd_gus_card *gus) { unsigned char d; @@ -124,8 +124,8 @@ static irqreturn_t snd_gusmax_interrupt(int irq, void *dev_id) return IRQ_RETVAL(handled); } -static void __devinit snd_gusmax_init(int dev, struct snd_card *card, - struct snd_gus_card * gus) +static void snd_gusmax_init(int dev, struct snd_card *card, + struct snd_gus_card *gus) { gus->equal_irq = 1; gus->codec_flag = 1; @@ -140,7 +140,7 @@ static void __devinit snd_gusmax_init(int dev, struct snd_card *card, outb(gus->max_cntrl_val, GUSP(gus, MAXCNTRLPORT)); } -static int __devinit snd_gusmax_mixer(struct snd_wss *chip) +static int snd_gusmax_mixer(struct snd_wss *chip) { struct snd_card *card = chip->card; struct snd_ctl_elem_id id1, id2; @@ -199,12 +199,12 @@ static void snd_gusmax_free(struct snd_card *card) free_irq(maxcard->irq, (void *)maxcard); } -static int __devinit snd_gusmax_match(struct device *pdev, unsigned int dev) +static int snd_gusmax_match(struct device *pdev, unsigned int dev) { return enable[dev]; } -static int __devinit snd_gusmax_probe(struct device *pdev, unsigned int dev) +static int snd_gusmax_probe(struct device *pdev, unsigned int dev) { static int possible_irqs[] = {5, 11, 12, 9, 7, 15, 3, -1}; static int possible_dmas[] = {5, 6, 7, 1, 3, -1}; @@ -354,7 +354,7 @@ static int __devinit snd_gusmax_probe(struct device *pdev, unsigned int dev) return err; } -static int __devexit snd_gusmax_remove(struct device *devptr, unsigned int dev) +static int snd_gusmax_remove(struct device *devptr, unsigned int dev) { snd_card_free(dev_get_drvdata(devptr)); dev_set_drvdata(devptr, NULL); @@ -366,7 +366,7 @@ static int __devexit snd_gusmax_remove(struct device *devptr, unsigned int dev) static struct isa_driver snd_gusmax_driver = { .match = snd_gusmax_match, .probe = snd_gusmax_probe, - .remove = __devexit_p(snd_gusmax_remove), + .remove = snd_gusmax_remove, /* FIXME: suspend/resume */ .driver = { .name = DEV_NAME diff --git a/sound/isa/gus/interwave.c b/sound/isa/gus/interwave.c index 3fc8b66fd167..78bc5744e89a 100644 --- a/sound/isa/gus/interwave.c +++ b/sound/isa/gus/interwave.c @@ -207,9 +207,9 @@ static struct snd_i2c_bit_ops snd_interwave_i2c_bit_ops = { .getdata = snd_interwave_i2c_getdataline, }; -static int __devinit snd_interwave_detect_stb(struct snd_interwave *iwcard, - struct snd_gus_card * gus, int dev, - struct snd_i2c_bus **rbus) +static int snd_interwave_detect_stb(struct snd_interwave *iwcard, + struct snd_gus_card *gus, int dev, + struct snd_i2c_bus **rbus) { unsigned long port; struct snd_i2c_bus *bus; @@ -249,11 +249,11 @@ static int __devinit snd_interwave_detect_stb(struct snd_interwave *iwcard, } #endif -static int __devinit snd_interwave_detect(struct snd_interwave *iwcard, - struct snd_gus_card * gus, - int dev +static int snd_interwave_detect(struct snd_interwave *iwcard, + struct snd_gus_card *gus, + int dev #ifdef SNDRV_STB - , struct snd_i2c_bus **rbus + , struct snd_i2c_bus **rbus #endif ) { @@ -318,7 +318,7 @@ static irqreturn_t snd_interwave_interrupt(int irq, void *dev_id) return IRQ_RETVAL(handled); } -static void __devinit snd_interwave_reset(struct snd_gus_card * gus) +static void snd_interwave_reset(struct snd_gus_card *gus) { snd_gf1_write8(gus, SNDRV_GF1_GB_RESET, 0x00); udelay(160); @@ -326,7 +326,7 @@ static void __devinit snd_interwave_reset(struct snd_gus_card * gus) udelay(160); } -static void __devinit snd_interwave_bank_sizes(struct snd_gus_card * gus, int *sizes) +static void snd_interwave_bank_sizes(struct snd_gus_card *gus, int *sizes) { unsigned int idx; unsigned int local; @@ -377,7 +377,7 @@ struct rom_hdr { /* 511 */ unsigned char csum; }; -static void __devinit snd_interwave_detect_memory(struct snd_gus_card * gus) +static void snd_interwave_detect_memory(struct snd_gus_card *gus) { static unsigned int lmc[13] = { @@ -475,7 +475,7 @@ static void __devinit snd_interwave_detect_memory(struct snd_gus_card * gus) snd_interwave_reset(gus); } -static void __devinit snd_interwave_init(int dev, struct snd_gus_card * gus) +static void snd_interwave_init(int dev, struct snd_gus_card *gus) { unsigned long flags; @@ -508,7 +508,7 @@ WSS_DOUBLE("Mic Playback Volume", 0, CS4231_LEFT_MIC_INPUT, CS4231_RIGHT_MIC_INPUT, 0, 0, 31, 1) }; -static int __devinit snd_interwave_mixer(struct snd_wss *chip) +static int snd_interwave_mixer(struct snd_wss *chip) { struct snd_card *card = chip->card; struct snd_ctl_elem_id id1, id2; @@ -558,9 +558,9 @@ static int __devinit snd_interwave_mixer(struct snd_wss *chip) #ifdef CONFIG_PNP -static int __devinit snd_interwave_pnp(int dev, struct snd_interwave *iwcard, - struct pnp_card_link *card, - const struct pnp_card_device_id *id) +static int snd_interwave_pnp(int dev, struct snd_interwave *iwcard, + struct pnp_card_link *card, + const struct pnp_card_device_id *id) { struct pnp_dev *pdev; int err; @@ -644,7 +644,7 @@ static int snd_interwave_card_new(int dev, struct snd_card **cardp) return 0; } -static int __devinit snd_interwave_probe(struct snd_card *card, int dev) +static int snd_interwave_probe(struct snd_card *card, int dev) { int xirq, xdma1, xdma2; struct snd_interwave *iwcard = card->private_data; @@ -775,7 +775,7 @@ static int __devinit snd_interwave_probe(struct snd_card *card, int dev) return 0; } -static int __devinit snd_interwave_isa_probe1(int dev, struct device *devptr) +static int snd_interwave_isa_probe1(int dev, struct device *devptr) { struct snd_card *card; int err; @@ -793,8 +793,8 @@ static int __devinit snd_interwave_isa_probe1(int dev, struct device *devptr) return 0; } -static int __devinit snd_interwave_isa_match(struct device *pdev, - unsigned int dev) +static int snd_interwave_isa_match(struct device *pdev, + unsigned int dev) { if (!enable[dev]) return 0; @@ -805,8 +805,8 @@ static int __devinit snd_interwave_isa_match(struct device *pdev, return 1; } -static int __devinit snd_interwave_isa_probe(struct device *pdev, - unsigned int dev) +static int snd_interwave_isa_probe(struct device *pdev, + unsigned int dev) { int err; static int possible_irqs[] = {5, 11, 12, 9, 7, 15, 3, -1}; @@ -846,7 +846,7 @@ static int __devinit snd_interwave_isa_probe(struct device *pdev, } } -static int __devexit snd_interwave_isa_remove(struct device *devptr, unsigned int dev) +static int snd_interwave_isa_remove(struct device *devptr, unsigned int dev) { snd_card_free(dev_get_drvdata(devptr)); dev_set_drvdata(devptr, NULL); @@ -856,7 +856,7 @@ static int __devexit snd_interwave_isa_remove(struct device *devptr, unsigned in static struct isa_driver snd_interwave_driver = { .match = snd_interwave_isa_match, .probe = snd_interwave_isa_probe, - .remove = __devexit_p(snd_interwave_isa_remove), + .remove = snd_interwave_isa_remove, /* FIXME: suspend,resume */ .driver = { .name = INTERWAVE_DRIVER @@ -864,8 +864,8 @@ static struct isa_driver snd_interwave_driver = { }; #ifdef CONFIG_PNP -static int __devinit snd_interwave_pnp_detect(struct pnp_card_link *pcard, - const struct pnp_card_device_id *pid) +static int snd_interwave_pnp_detect(struct pnp_card_link *pcard, + const struct pnp_card_device_id *pid) { static int dev; struct snd_card *card; @@ -896,7 +896,7 @@ static int __devinit snd_interwave_pnp_detect(struct pnp_card_link *pcard, return 0; } -static void __devexit snd_interwave_pnp_remove(struct pnp_card_link * pcard) +static void snd_interwave_pnp_remove(struct pnp_card_link *pcard) { snd_card_free(pnp_get_card_drvdata(pcard)); pnp_set_card_drvdata(pcard, NULL); @@ -907,7 +907,7 @@ static struct pnp_card_driver interwave_pnpc_driver = { .name = INTERWAVE_PNP_DRIVER, .id_table = snd_interwave_pnpids, .probe = snd_interwave_pnp_detect, - .remove = __devexit_p(snd_interwave_pnp_remove), + .remove = snd_interwave_pnp_remove, /* FIXME: suspend,resume */ }; diff --git a/sound/isa/msnd/msnd.h b/sound/isa/msnd/msnd.h index a168ba3313ac..dbac3a42347b 100644 --- a/sound/isa/msnd/msnd.h +++ b/sound/isa/msnd/msnd.h @@ -303,6 +303,6 @@ int snd_msndmidi_new(struct snd_card *card, int device); void snd_msndmidi_input_read(void *mpu); void snd_msndmix_setup(struct snd_msnd *chip); -int __devinit snd_msndmix_new(struct snd_card *card); +int snd_msndmix_new(struct snd_card *card); int snd_msndmix_force_recsrc(struct snd_msnd *chip, int recsrc); #endif /* __MSND_H */ diff --git a/sound/isa/msnd/msnd_pinnacle.c b/sound/isa/msnd/msnd_pinnacle.c index 29cc8e162b02..ddabb406b14c 100644 --- a/sound/isa/msnd/msnd_pinnacle.c +++ b/sound/isa/msnd/msnd_pinnacle.c @@ -78,7 +78,7 @@ # define LOGNAME "snd_msnd_pinnacle" #endif -static void __devinit set_default_audio_parameters(struct snd_msnd *chip) +static void set_default_audio_parameters(struct snd_msnd *chip) { chip->play_sample_size = DEFSAMPLESIZE; chip->play_sample_rate = DEFSAMPLERATE; @@ -213,7 +213,7 @@ static int snd_msnd_reset_dsp(long io, unsigned char *info) return -EIO; } -static int __devinit snd_msnd_probe(struct snd_card *card) +static int snd_msnd_probe(struct snd_card *card) { struct snd_msnd *chip = card->private_data; unsigned char info; @@ -497,7 +497,7 @@ static int snd_msnd_send_dsp_cmd_chk(struct snd_msnd *chip, u8 cmd) return snd_msnd_send_dsp_cmd(chip, cmd); } -static int __devinit snd_msnd_calibrate_adc(struct snd_msnd *chip, u16 srate) +static int snd_msnd_calibrate_adc(struct snd_msnd *chip, u16 srate) { snd_printdd("snd_msnd_calibrate_adc(%i)\n", srate); writew(srate, chip->SMA + SMA_wCalFreqAtoD); @@ -535,7 +535,7 @@ static void snd_msnd_mpu401_close(struct snd_mpu401 *mpu) static long mpu_io[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; -static int __devinit snd_msnd_attach(struct snd_card *card) +static int snd_msnd_attach(struct snd_card *card) { struct snd_msnd *chip = card->private_data; int err; @@ -634,7 +634,7 @@ err_release_region: } -static void __devexit snd_msnd_unload(struct snd_card *card) +static void snd_msnd_unload(struct snd_card *card) { struct snd_msnd *chip = card->private_data; @@ -649,7 +649,7 @@ static void __devexit snd_msnd_unload(struct snd_card *card) /* Pinnacle/Fiji Logical Device Configuration */ -static int __devinit snd_msnd_write_cfg(int cfg, int reg, int value) +static int snd_msnd_write_cfg(int cfg, int reg, int value) { outb(reg, cfg); outb(value, cfg + 1); @@ -660,7 +660,7 @@ static int __devinit snd_msnd_write_cfg(int cfg, int reg, int value) return 0; } -static int __devinit snd_msnd_write_cfg_io0(int cfg, int num, u16 io) +static int snd_msnd_write_cfg_io0(int cfg, int num, u16 io) { if (snd_msnd_write_cfg(cfg, IREG_LOGDEVICE, num)) return -EIO; @@ -671,7 +671,7 @@ static int __devinit snd_msnd_write_cfg_io0(int cfg, int num, u16 io) return 0; } -static int __devinit snd_msnd_write_cfg_io1(int cfg, int num, u16 io) +static int snd_msnd_write_cfg_io1(int cfg, int num, u16 io) { if (snd_msnd_write_cfg(cfg, IREG_LOGDEVICE, num)) return -EIO; @@ -682,7 +682,7 @@ static int __devinit snd_msnd_write_cfg_io1(int cfg, int num, u16 io) return 0; } -static int __devinit snd_msnd_write_cfg_irq(int cfg, int num, u16 irq) +static int snd_msnd_write_cfg_irq(int cfg, int num, u16 irq) { if (snd_msnd_write_cfg(cfg, IREG_LOGDEVICE, num)) return -EIO; @@ -693,7 +693,7 @@ static int __devinit snd_msnd_write_cfg_irq(int cfg, int num, u16 irq) return 0; } -static int __devinit snd_msnd_write_cfg_mem(int cfg, int num, int mem) +static int snd_msnd_write_cfg_mem(int cfg, int num, int mem) { u16 wmem; @@ -711,7 +711,7 @@ static int __devinit snd_msnd_write_cfg_mem(int cfg, int num, int mem) return 0; } -static int __devinit snd_msnd_activate_logical(int cfg, int num) +static int snd_msnd_activate_logical(int cfg, int num) { if (snd_msnd_write_cfg(cfg, IREG_LOGDEVICE, num)) return -EIO; @@ -720,8 +720,8 @@ static int __devinit snd_msnd_activate_logical(int cfg, int num) return 0; } -static int __devinit snd_msnd_write_cfg_logical(int cfg, int num, u16 io0, - u16 io1, u16 irq, int mem) +static int snd_msnd_write_cfg_logical(int cfg, int num, u16 io0, + u16 io1, u16 irq, int mem) { if (snd_msnd_write_cfg(cfg, IREG_LOGDEVICE, num)) return -EIO; @@ -738,7 +738,7 @@ static int __devinit snd_msnd_write_cfg_logical(int cfg, int num, u16 io0, return 0; } -static int __devinit snd_msnd_pinnacle_cfg_reset(int cfg) +static int snd_msnd_pinnacle_cfg_reset(int cfg) { int i; @@ -818,7 +818,7 @@ module_param_array(joystick_io, long, NULL, S_IRUGO); #endif -static int __devinit snd_msnd_isa_match(struct device *pdev, unsigned int i) +static int snd_msnd_isa_match(struct device *pdev, unsigned int i) { if (io[i] == SNDRV_AUTO_PORT) return 0; @@ -888,7 +888,7 @@ static int __devinit snd_msnd_isa_match(struct device *pdev, unsigned int i) return 1; } -static int __devinit snd_msnd_isa_probe(struct device *pdev, unsigned int idx) +static int snd_msnd_isa_probe(struct device *pdev, unsigned int idx) { int err; struct snd_card *card; @@ -1061,7 +1061,7 @@ cfg_error: #endif } -static int __devexit snd_msnd_isa_remove(struct device *pdev, unsigned int dev) +static int snd_msnd_isa_remove(struct device *pdev, unsigned int dev) { snd_msnd_unload(dev_get_drvdata(pdev)); dev_set_drvdata(pdev, NULL); @@ -1073,7 +1073,7 @@ static int __devexit snd_msnd_isa_remove(struct device *pdev, unsigned int dev) static struct isa_driver snd_msnd_driver = { .match = snd_msnd_isa_match, .probe = snd_msnd_isa_probe, - .remove = __devexit_p(snd_msnd_isa_remove), + .remove = snd_msnd_isa_remove, /* FIXME: suspend, resume */ .driver = { .name = DEV_NAME @@ -1081,8 +1081,8 @@ static struct isa_driver snd_msnd_driver = { }; #ifdef CONFIG_PNP -static int __devinit snd_msnd_pnp_detect(struct pnp_card_link *pcard, - const struct pnp_card_device_id *pid) +static int snd_msnd_pnp_detect(struct pnp_card_link *pcard, + const struct pnp_card_device_id *pid) { static int idx; struct pnp_dev *pnp_dev; @@ -1185,7 +1185,7 @@ _release_card: return ret; } -static void __devexit snd_msnd_pnp_remove(struct pnp_card_link *pcard) +static void snd_msnd_pnp_remove(struct pnp_card_link *pcard) { snd_msnd_unload(pnp_get_card_drvdata(pcard)); pnp_set_card_drvdata(pcard, NULL); @@ -1207,7 +1207,7 @@ static struct pnp_card_driver msnd_pnpc_driver = { .name = "msnd_pinnacle", .id_table = msnd_pnpids, .probe = snd_msnd_pnp_detect, - .remove = __devexit_p(snd_msnd_pnp_remove), + .remove = snd_msnd_pnp_remove, }; #endif /* CONFIG_PNP */ diff --git a/sound/isa/msnd/msnd_pinnacle_mixer.c b/sound/isa/msnd/msnd_pinnacle_mixer.c index 1de59d441426..031dc69b7470 100644 --- a/sound/isa/msnd/msnd_pinnacle_mixer.c +++ b/sound/isa/msnd/msnd_pinnacle_mixer.c @@ -302,7 +302,7 @@ DUMMY_VOLUME("Monitor", 0, MSND_MIXER_IMIX), }; -int __devinit snd_msndmix_new(struct snd_card *card) +int snd_msndmix_new(struct snd_card *card) { struct snd_msnd *chip = card->private_data; unsigned int idx; diff --git a/sound/isa/opl3sa2.c b/sound/isa/opl3sa2.c index f6cc0b917ef0..075777a6cf0b 100644 --- a/sound/isa/opl3sa2.c +++ b/sound/isa/opl3sa2.c @@ -221,7 +221,7 @@ static void snd_opl3sa2_write(struct snd_opl3sa2 *chip, unsigned char reg, unsig spin_unlock_irqrestore(&chip->reg_lock, flags); } -static int __devinit snd_opl3sa2_detect(struct snd_card *card) +static int snd_opl3sa2_detect(struct snd_card *card) { struct snd_opl3sa2 *chip = card->private_data; unsigned long port; @@ -496,7 +496,7 @@ static void snd_opl3sa2_master_free(struct snd_kcontrol *kcontrol) chip->master_volume = NULL; } -static int __devinit snd_opl3sa2_mixer(struct snd_card *card) +static int snd_opl3sa2_mixer(struct snd_card *card) { struct snd_opl3sa2 *chip = card->private_data; struct snd_ctl_elem_id id1, id2; @@ -596,8 +596,8 @@ static int snd_opl3sa2_resume(struct snd_card *card) #endif /* CONFIG_PM */ #ifdef CONFIG_PNP -static int __devinit snd_opl3sa2_pnp(int dev, struct snd_opl3sa2 *chip, - struct pnp_dev *pdev) +static int snd_opl3sa2_pnp(int dev, struct snd_opl3sa2 *chip, + struct pnp_dev *pdev) { if (pnp_activate_dev(pdev) < 0) { snd_printk(KERN_ERR "PnP configure failure (out of resources?)\n"); @@ -647,7 +647,7 @@ static int snd_opl3sa2_card_new(int dev, struct snd_card **cardp) return 0; } -static int __devinit snd_opl3sa2_probe(struct snd_card *card, int dev) +static int snd_opl3sa2_probe(struct snd_card *card, int dev) { int xirq, xdma1, xdma2; struct snd_opl3sa2 *chip; @@ -721,8 +721,8 @@ static int __devinit snd_opl3sa2_probe(struct snd_card *card, int dev) } #ifdef CONFIG_PNP -static int __devinit snd_opl3sa2_pnp_detect(struct pnp_dev *pdev, - const struct pnp_device_id *id) +static int snd_opl3sa2_pnp_detect(struct pnp_dev *pdev, + const struct pnp_device_id *id) { static int dev; int err; @@ -754,7 +754,7 @@ static int __devinit snd_opl3sa2_pnp_detect(struct pnp_dev *pdev, return 0; } -static void __devexit snd_opl3sa2_pnp_remove(struct pnp_dev * pdev) +static void snd_opl3sa2_pnp_remove(struct pnp_dev *pdev) { snd_card_free(pnp_get_drvdata(pdev)); pnp_set_drvdata(pdev, NULL); @@ -775,15 +775,15 @@ static struct pnp_driver opl3sa2_pnp_driver = { .name = "snd-opl3sa2-pnpbios", .id_table = snd_opl3sa2_pnpbiosids, .probe = snd_opl3sa2_pnp_detect, - .remove = __devexit_p(snd_opl3sa2_pnp_remove), + .remove = snd_opl3sa2_pnp_remove, #ifdef CONFIG_PM .suspend = snd_opl3sa2_pnp_suspend, .resume = snd_opl3sa2_pnp_resume, #endif }; -static int __devinit snd_opl3sa2_pnp_cdetect(struct pnp_card_link *pcard, - const struct pnp_card_device_id *id) +static int snd_opl3sa2_pnp_cdetect(struct pnp_card_link *pcard, + const struct pnp_card_device_id *id) { static int dev; struct pnp_dev *pdev; @@ -820,7 +820,7 @@ static int __devinit snd_opl3sa2_pnp_cdetect(struct pnp_card_link *pcard, return 0; } -static void __devexit snd_opl3sa2_pnp_cremove(struct pnp_card_link * pcard) +static void snd_opl3sa2_pnp_cremove(struct pnp_card_link *pcard) { snd_card_free(pnp_get_card_drvdata(pcard)); pnp_set_card_drvdata(pcard, NULL); @@ -842,7 +842,7 @@ static struct pnp_card_driver opl3sa2_pnpc_driver = { .name = "snd-opl3sa2-cpnp", .id_table = snd_opl3sa2_pnpids, .probe = snd_opl3sa2_pnp_cdetect, - .remove = __devexit_p(snd_opl3sa2_pnp_cremove), + .remove = snd_opl3sa2_pnp_cremove, #ifdef CONFIG_PM .suspend = snd_opl3sa2_pnp_csuspend, .resume = snd_opl3sa2_pnp_cresume, @@ -850,8 +850,8 @@ static struct pnp_card_driver opl3sa2_pnpc_driver = { }; #endif /* CONFIG_PNP */ -static int __devinit snd_opl3sa2_isa_match(struct device *pdev, - unsigned int dev) +static int snd_opl3sa2_isa_match(struct device *pdev, + unsigned int dev) { if (!enable[dev]) return 0; @@ -878,8 +878,8 @@ static int __devinit snd_opl3sa2_isa_match(struct device *pdev, return 1; } -static int __devinit snd_opl3sa2_isa_probe(struct device *pdev, - unsigned int dev) +static int snd_opl3sa2_isa_probe(struct device *pdev, + unsigned int dev) { struct snd_card *card; int err; @@ -896,8 +896,8 @@ static int __devinit snd_opl3sa2_isa_probe(struct device *pdev, return 0; } -static int __devexit snd_opl3sa2_isa_remove(struct device *devptr, - unsigned int dev) +static int snd_opl3sa2_isa_remove(struct device *devptr, + unsigned int dev) { snd_card_free(dev_get_drvdata(devptr)); dev_set_drvdata(devptr, NULL); @@ -922,7 +922,7 @@ static int snd_opl3sa2_isa_resume(struct device *dev, unsigned int n) static struct isa_driver snd_opl3sa2_isa_driver = { .match = snd_opl3sa2_isa_match, .probe = snd_opl3sa2_isa_probe, - .remove = __devexit_p(snd_opl3sa2_isa_remove), + .remove = snd_opl3sa2_isa_remove, #ifdef CONFIG_PM .suspend = snd_opl3sa2_isa_suspend, .resume = snd_opl3sa2_isa_resume, diff --git a/sound/isa/opti9xx/miro.c b/sound/isa/opti9xx/miro.c index 4a7ff4e8985b..c3da1df9371d 100644 --- a/sound/isa/opti9xx/miro.c +++ b/sound/isa/opti9xx/miro.c @@ -587,7 +587,7 @@ static int snd_miro_put_double(struct snd_kcontrol *kcontrol, return change; } -static struct snd_kcontrol_new snd_miro_controls[] __devinitdata = { +static struct snd_kcontrol_new snd_miro_controls[] = { MIRO_DOUBLE("Master Playback Volume", 0, ACI_GET_MASTER, ACI_SET_MASTER), MIRO_DOUBLE("Mic Playback Volume", 1, ACI_GET_MIC, ACI_SET_MIC), MIRO_DOUBLE("Line Playback Volume", 1, ACI_GET_LINE, ACI_SET_LINE), @@ -599,7 +599,7 @@ MIRO_DOUBLE("Aux Playback Volume", 2, ACI_GET_LINE2, ACI_SET_LINE2), /* Equalizer with seven bands (only PCM20) from -12dB up to +12dB on each band */ -static struct snd_kcontrol_new snd_miro_eq_controls[] __devinitdata = { +static struct snd_kcontrol_new snd_miro_eq_controls[] = { MIRO_DOUBLE("Tone Control - 28 Hz", 0, ACI_GET_EQ1, ACI_SET_EQ1), MIRO_DOUBLE("Tone Control - 160 Hz", 0, ACI_GET_EQ2, ACI_SET_EQ2), MIRO_DOUBLE("Tone Control - 400 Hz", 0, ACI_GET_EQ3, ACI_SET_EQ3), @@ -609,15 +609,15 @@ MIRO_DOUBLE("Tone Control - 6.3 kHz", 0, ACI_GET_EQ6, ACI_SET_EQ6), MIRO_DOUBLE("Tone Control - 16 kHz", 0, ACI_GET_EQ7, ACI_SET_EQ7), }; -static struct snd_kcontrol_new snd_miro_radio_control[] __devinitdata = { +static struct snd_kcontrol_new snd_miro_radio_control[] = { MIRO_DOUBLE("Radio Playback Volume", 0, ACI_GET_LINE1, ACI_SET_LINE1), }; -static struct snd_kcontrol_new snd_miro_line_control[] __devinitdata = { +static struct snd_kcontrol_new snd_miro_line_control[] = { MIRO_DOUBLE("Line Playback Volume", 2, ACI_GET_LINE1, ACI_SET_LINE1), }; -static struct snd_kcontrol_new snd_miro_preamp_control[] __devinitdata = { +static struct snd_kcontrol_new snd_miro_preamp_control[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Mic Boost", @@ -627,7 +627,7 @@ static struct snd_kcontrol_new snd_miro_preamp_control[] __devinitdata = { .put = snd_miro_put_preamp, }}; -static struct snd_kcontrol_new snd_miro_amp_control[] __devinitdata = { +static struct snd_kcontrol_new snd_miro_amp_control[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Line Boost", @@ -637,7 +637,7 @@ static struct snd_kcontrol_new snd_miro_amp_control[] __devinitdata = { .put = snd_miro_put_amp, }}; -static struct snd_kcontrol_new snd_miro_capture_control[] __devinitdata = { +static struct snd_kcontrol_new snd_miro_capture_control[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "PCM Capture Switch", @@ -647,7 +647,7 @@ static struct snd_kcontrol_new snd_miro_capture_control[] __devinitdata = { .put = snd_miro_put_capture, }}; -static unsigned char aci_init_values[][2] __devinitdata = { +static unsigned char aci_init_values[][2] = { { ACI_SET_MUTE, 0x00 }, { ACI_SET_POWERAMP, 0x00 }, { ACI_SET_PREAMP, 0x00 }, @@ -670,7 +670,7 @@ static unsigned char aci_init_values[][2] __devinitdata = { { ACI_SET_MASTER + 1, 0x20 }, }; -static int __devinit snd_set_aci_init_values(struct snd_miro *miro) +static int snd_set_aci_init_values(struct snd_miro *miro) { int idx, error; struct snd_miro_aci *aci = miro->aci; @@ -713,8 +713,8 @@ static int __devinit snd_set_aci_init_values(struct snd_miro *miro) return 0; } -static int __devinit snd_miro_mixer(struct snd_card *card, - struct snd_miro *miro) +static int snd_miro_mixer(struct snd_card *card, + struct snd_miro *miro) { unsigned int idx; int err; @@ -771,8 +771,8 @@ static int __devinit snd_miro_mixer(struct snd_card *card, return 0; } -static int __devinit snd_miro_init(struct snd_miro *chip, - unsigned short hardware) +static int snd_miro_init(struct snd_miro *chip, + unsigned short hardware) { static int opti9xx_mc_size[] = {7, 7, 10, 10, 2, 2, 2}; @@ -989,8 +989,8 @@ static void snd_miro_proc_read(struct snd_info_entry * entry, snd_iprintf(buffer, " preamp : 0x%x\n", aci->aci_preamp); } -static void __devinit snd_miro_proc_init(struct snd_card *card, - struct snd_miro *miro) +static void snd_miro_proc_init(struct snd_card *card, + struct snd_miro *miro) { struct snd_info_entry *entry; @@ -1002,7 +1002,7 @@ static void __devinit snd_miro_proc_init(struct snd_card *card, * Init */ -static int __devinit snd_miro_configure(struct snd_miro *chip) +static int snd_miro_configure(struct snd_miro *chip) { unsigned char wss_base_bits; unsigned char irq_bits; @@ -1162,7 +1162,7 @@ __skip_mpu: return 0; } -static int __devinit snd_miro_opti_check(struct snd_miro *chip) +static int snd_miro_opti_check(struct snd_miro *chip) { unsigned char value; @@ -1182,8 +1182,8 @@ static int __devinit snd_miro_opti_check(struct snd_miro *chip) return -ENODEV; } -static int __devinit snd_card_miro_detect(struct snd_card *card, - struct snd_miro *chip) +static int snd_card_miro_detect(struct snd_card *card, + struct snd_miro *chip) { int i, err; @@ -1200,8 +1200,8 @@ static int __devinit snd_card_miro_detect(struct snd_card *card, return -ENODEV; } -static int __devinit snd_card_miro_aci_detect(struct snd_card *card, - struct snd_miro *miro) +static int snd_card_miro_aci_detect(struct snd_card *card, + struct snd_miro *miro) { unsigned char regval; int i; @@ -1265,7 +1265,7 @@ static void snd_card_miro_free(struct snd_card *card) release_and_free_resource(miro->res_mc_base); } -static int __devinit snd_miro_probe(struct snd_card *card) +static int snd_miro_probe(struct snd_card *card) { int error; struct snd_miro *miro = card->private_data; @@ -1386,7 +1386,7 @@ static int __devinit snd_miro_probe(struct snd_card *card) return snd_card_register(card); } -static int __devinit snd_miro_isa_match(struct device *devptr, unsigned int n) +static int snd_miro_isa_match(struct device *devptr, unsigned int n) { #ifdef CONFIG_PNP if (snd_miro_pnp_is_probed) @@ -1397,7 +1397,7 @@ static int __devinit snd_miro_isa_match(struct device *devptr, unsigned int n) return 1; } -static int __devinit snd_miro_isa_probe(struct device *devptr, unsigned int n) +static int snd_miro_isa_probe(struct device *devptr, unsigned int n) { static long possible_ports[] = {0x530, 0xe80, 0xf40, 0x604, -1}; static long possible_mpu_ports[] = {0x330, 0x300, 0x310, 0x320, -1}; @@ -1491,8 +1491,8 @@ static int __devinit snd_miro_isa_probe(struct device *devptr, unsigned int n) return 0; } -static int __devexit snd_miro_isa_remove(struct device *devptr, - unsigned int dev) +static int snd_miro_isa_remove(struct device *devptr, + unsigned int dev) { snd_card_free(dev_get_drvdata(devptr)); dev_set_drvdata(devptr, NULL); @@ -1504,7 +1504,7 @@ static int __devexit snd_miro_isa_remove(struct device *devptr, static struct isa_driver snd_miro_driver = { .match = snd_miro_isa_match, .probe = snd_miro_isa_probe, - .remove = __devexit_p(snd_miro_isa_remove), + .remove = snd_miro_isa_remove, /* FIXME: suspend/resume */ .driver = { .name = DEV_NAME @@ -1513,9 +1513,9 @@ static struct isa_driver snd_miro_driver = { #ifdef CONFIG_PNP -static int __devinit snd_card_miro_pnp(struct snd_miro *chip, - struct pnp_card_link *card, - const struct pnp_card_device_id *pid) +static int snd_card_miro_pnp(struct snd_miro *chip, + struct pnp_card_link *card, + const struct pnp_card_device_id *pid) { struct pnp_dev *pdev; int err; @@ -1574,8 +1574,8 @@ static int __devinit snd_card_miro_pnp(struct snd_miro *chip, return 0; } -static int __devinit snd_miro_pnp_probe(struct pnp_card_link *pcard, - const struct pnp_card_device_id *pid) +static int snd_miro_pnp_probe(struct pnp_card_link *pcard, + const struct pnp_card_device_id *pid) { struct snd_card *card; int err; @@ -1624,7 +1624,7 @@ static int __devinit snd_miro_pnp_probe(struct pnp_card_link *pcard, return 0; } -static void __devexit snd_miro_pnp_remove(struct pnp_card_link * pcard) +static void snd_miro_pnp_remove(struct pnp_card_link *pcard) { snd_card_free(pnp_get_card_drvdata(pcard)); pnp_set_card_drvdata(pcard, NULL); @@ -1636,7 +1636,7 @@ static struct pnp_card_driver miro_pnpc_driver = { .name = "miro", .id_table = snd_miro_pnpids, .probe = snd_miro_pnp_probe, - .remove = __devexit_p(snd_miro_pnp_remove), + .remove = snd_miro_pnp_remove, }; #endif diff --git a/sound/isa/opti9xx/opti92x-ad1848.c b/sound/isa/opti9xx/opti92x-ad1848.c index 2899c9fd1ceb..b41ed8661b23 100644 --- a/sound/isa/opti9xx/opti92x-ad1848.c +++ b/sound/isa/opti9xx/opti92x-ad1848.c @@ -186,8 +186,8 @@ static char * snd_opti9xx_names[] = { "82C930", "82C931", "82C933" }; -static int __devinit snd_opti9xx_init(struct snd_opti9xx *chip, - unsigned short hardware) +static int snd_opti9xx_init(struct snd_opti9xx *chip, + unsigned short hardware) { static int opti9xx_mc_size[] = {7, 7, 10, 10, 2, 2, 2}; @@ -593,7 +593,7 @@ WSS_DOUBLE_TLV("Aux Playback Volume", 0, db_scale_4bit_12db_max), }; -static int __devinit snd_opti93x_mixer(struct snd_wss *chip) +static int snd_opti93x_mixer(struct snd_wss *chip) { struct snd_card *card; unsigned int idx; @@ -666,7 +666,7 @@ static irqreturn_t snd_opti93x_interrupt(int irq, void *dev_id) #endif /* OPTi93X */ -static int __devinit snd_opti9xx_read_check(struct snd_opti9xx *chip) +static int snd_opti9xx_read_check(struct snd_opti9xx *chip) { unsigned char value; #ifdef OPTi93X @@ -707,8 +707,8 @@ static int __devinit snd_opti9xx_read_check(struct snd_opti9xx *chip) return -ENODEV; } -static int __devinit snd_card_opti9xx_detect(struct snd_card *card, - struct snd_opti9xx *chip) +static int snd_card_opti9xx_detect(struct snd_card *card, + struct snd_opti9xx *chip) { int i, err; @@ -732,9 +732,9 @@ static int __devinit snd_card_opti9xx_detect(struct snd_card *card, } #ifdef CONFIG_PNP -static int __devinit snd_card_opti9xx_pnp(struct snd_opti9xx *chip, - struct pnp_card_link *card, - const struct pnp_card_device_id *pid) +static int snd_card_opti9xx_pnp(struct snd_opti9xx *chip, + struct pnp_card_link *card, + const struct pnp_card_device_id *pid) { struct pnp_dev *pdev; int err; @@ -817,7 +817,7 @@ static void snd_card_opti9xx_free(struct snd_card *card) } } -static int __devinit snd_opti9xx_probe(struct snd_card *card) +static int snd_opti9xx_probe(struct snd_card *card) { static long possible_ports[] = {0x530, 0xe80, 0xf40, 0x604, -1}; int error; @@ -952,8 +952,8 @@ static int snd_opti9xx_card_new(struct snd_card **cardp) return 0; } -static int __devinit snd_opti9xx_isa_match(struct device *devptr, - unsigned int dev) +static int snd_opti9xx_isa_match(struct device *devptr, + unsigned int dev) { #ifdef CONFIG_PNP if (snd_opti9xx_pnp_is_probed) @@ -964,8 +964,8 @@ static int __devinit snd_opti9xx_isa_match(struct device *devptr, return 1; } -static int __devinit snd_opti9xx_isa_probe(struct device *devptr, - unsigned int dev) +static int snd_opti9xx_isa_probe(struct device *devptr, + unsigned int dev) { struct snd_card *card; int error; @@ -1031,8 +1031,8 @@ static int __devinit snd_opti9xx_isa_probe(struct device *devptr, return 0; } -static int __devexit snd_opti9xx_isa_remove(struct device *devptr, - unsigned int dev) +static int snd_opti9xx_isa_remove(struct device *devptr, + unsigned int dev) { snd_card_free(dev_get_drvdata(devptr)); dev_set_drvdata(devptr, NULL); @@ -1083,7 +1083,7 @@ static int snd_opti9xx_isa_resume(struct device *dev, unsigned int n) static struct isa_driver snd_opti9xx_driver = { .match = snd_opti9xx_isa_match, .probe = snd_opti9xx_isa_probe, - .remove = __devexit_p(snd_opti9xx_isa_remove), + .remove = snd_opti9xx_isa_remove, #ifdef CONFIG_PM .suspend = snd_opti9xx_isa_suspend, .resume = snd_opti9xx_isa_resume, @@ -1094,8 +1094,8 @@ static struct isa_driver snd_opti9xx_driver = { }; #ifdef CONFIG_PNP -static int __devinit snd_opti9xx_pnp_probe(struct pnp_card_link *pcard, - const struct pnp_card_device_id *pid) +static int snd_opti9xx_pnp_probe(struct pnp_card_link *pcard, + const struct pnp_card_device_id *pid) { struct snd_card *card; int error, hw; @@ -1146,7 +1146,7 @@ static int __devinit snd_opti9xx_pnp_probe(struct pnp_card_link *pcard, return 0; } -static void __devexit snd_opti9xx_pnp_remove(struct pnp_card_link * pcard) +static void snd_opti9xx_pnp_remove(struct pnp_card_link *pcard) { snd_card_free(pnp_get_card_drvdata(pcard)); pnp_set_card_drvdata(pcard, NULL); @@ -1171,7 +1171,7 @@ static struct pnp_card_driver opti9xx_pnpc_driver = { .name = "opti9xx", .id_table = snd_opti9xx_pnpids, .probe = snd_opti9xx_pnp_probe, - .remove = __devexit_p(snd_opti9xx_pnp_remove), + .remove = snd_opti9xx_pnp_remove, #ifdef CONFIG_PM .suspend = snd_opti9xx_pnp_suspend, .resume = snd_opti9xx_pnp_resume, diff --git a/sound/isa/sb/emu8000.c b/sound/isa/sb/emu8000.c index 2aae6a0efbcd..45fcdff611f9 100644 --- a/sound/isa/sb/emu8000.c +++ b/sound/isa/sb/emu8000.c @@ -131,7 +131,7 @@ snd_emu8000_dma_chan(struct snd_emu8000 *emu, int ch, int mode) /* */ -static void __devinit +static void snd_emu8000_read_wait(struct snd_emu8000 *emu) { while ((EMU8000_SMALR_READ(emu) & 0x80000000) != 0) { @@ -143,7 +143,7 @@ snd_emu8000_read_wait(struct snd_emu8000 *emu) /* */ -static void __devinit +static void snd_emu8000_write_wait(struct snd_emu8000 *emu) { while ((EMU8000_SMALW_READ(emu) & 0x80000000) != 0) { @@ -156,7 +156,7 @@ snd_emu8000_write_wait(struct snd_emu8000 *emu) /* * detect a card at the given port */ -static int __devinit +static int snd_emu8000_detect(struct snd_emu8000 *emu) { /* Initialise */ @@ -182,7 +182,7 @@ snd_emu8000_detect(struct snd_emu8000 *emu) /* * intiailize audio channels */ -static void __devinit +static void init_audio(struct snd_emu8000 *emu) { int ch; @@ -223,7 +223,7 @@ init_audio(struct snd_emu8000 *emu) /* * initialize DMA address */ -static void __devinit +static void init_dma(struct snd_emu8000 *emu) { EMU8000_SMALR_WRITE(emu, 0); @@ -235,7 +235,7 @@ init_dma(struct snd_emu8000 *emu) /* * initialization arrays; from ADIP */ -static unsigned short init1[128] /*__devinitdata*/ = { +static unsigned short init1[128] = { 0x03ff, 0x0030, 0x07ff, 0x0130, 0x0bff, 0x0230, 0x0fff, 0x0330, 0x13ff, 0x0430, 0x17ff, 0x0530, 0x1bff, 0x0630, 0x1fff, 0x0730, 0x23ff, 0x0830, 0x27ff, 0x0930, 0x2bff, 0x0a30, 0x2fff, 0x0b30, @@ -257,7 +257,7 @@ static unsigned short init1[128] /*__devinitdata*/ = { 0xf3ff, 0x0c30, 0xf7ff, 0x0d30, 0xfbff, 0x0e30, 0xffff, 0x0f30, }; -static unsigned short init2[128] /*__devinitdata*/ = { +static unsigned short init2[128] = { 0x03ff, 0x8030, 0x07ff, 0x8130, 0x0bff, 0x8230, 0x0fff, 0x8330, 0x13ff, 0x8430, 0x17ff, 0x8530, 0x1bff, 0x8630, 0x1fff, 0x8730, 0x23ff, 0x8830, 0x27ff, 0x8930, 0x2bff, 0x8a30, 0x2fff, 0x8b30, @@ -279,7 +279,7 @@ static unsigned short init2[128] /*__devinitdata*/ = { 0xf3ff, 0x8c30, 0xf7ff, 0x8d30, 0xfbff, 0x8e30, 0xffff, 0x8f30, }; -static unsigned short init3[128] /*__devinitdata*/ = { +static unsigned short init3[128] = { 0x0C10, 0x8470, 0x14FE, 0xB488, 0x167F, 0xA470, 0x18E7, 0x84B5, 0x1B6E, 0x842A, 0x1F1D, 0x852A, 0x0DA3, 0x8F7C, 0x167E, 0xF254, 0x0000, 0x842A, 0x0001, 0x852A, 0x18E6, 0x8BAA, 0x1B6D, 0xF234, @@ -301,7 +301,7 @@ static unsigned short init3[128] /*__devinitdata*/ = { 0x1342, 0xD36E, 0x3EC7, 0xB3FF, 0x0000, 0x8365, 0x1420, 0x9570, }; -static unsigned short init4[128] /*__devinitdata*/ = { +static unsigned short init4[128] = { 0x0C10, 0x8470, 0x14FE, 0xB488, 0x167F, 0xA470, 0x18E7, 0x84B5, 0x1B6E, 0x842A, 0x1F1D, 0x852A, 0x0DA3, 0x0F7C, 0x167E, 0x7254, 0x0000, 0x842A, 0x0001, 0x852A, 0x18E6, 0x0BAA, 0x1B6D, 0x7234, @@ -327,7 +327,7 @@ static unsigned short init4[128] /*__devinitdata*/ = { * Taken from the oss driver, not obvious from the doc how this * is meant to work */ -static void __devinit +static void send_array(struct snd_emu8000 *emu, unsigned short *data, int size) { int i; @@ -349,7 +349,7 @@ send_array(struct snd_emu8000 *emu, unsigned short *data, int size) * Send initialization arrays to start up, this just follows the * initialisation sequence in the adip. */ -static void __devinit +static void init_arrays(struct snd_emu8000 *emu) { send_array(emu, init1, ARRAY_SIZE(init1)/4); @@ -375,7 +375,7 @@ init_arrays(struct snd_emu8000 *emu) * seems that the only way to do this is to use the one channel and keep * reallocating between read and write. */ -static void __devinit +static void size_dram(struct snd_emu8000 *emu) { int i, size, detected_size; @@ -512,7 +512,7 @@ snd_emu8000_init_fm(struct snd_emu8000 *emu) /* * The main initialization routine. */ -static void __devinit +static void snd_emu8000_init_hw(struct snd_emu8000 *emu) { int i; @@ -1031,7 +1031,7 @@ static struct snd_kcontrol_new *mixer_defs[EMU8000_NUM_CONTROLS] = { /* * create and attach mixer elements for WaveTable treble/bass controls */ -static int __devinit +static int snd_emu8000_create_mixer(struct snd_card *card, struct snd_emu8000 *emu) { int i, err = 0; @@ -1082,7 +1082,7 @@ static int snd_emu8000_dev_free(struct snd_device *device) /* * initialize and register emu8000 synth device. */ -int __devinit +int snd_emu8000_new(struct snd_card *card, int index, long port, int seq_ports, struct snd_seq_device **awe_ret) { diff --git a/sound/isa/sb/jazz16.c b/sound/isa/sb/jazz16.c index 410758c68090..4961da4e627c 100644 --- a/sound/isa/sb/jazz16.c +++ b/sound/isa/sb/jazz16.c @@ -78,8 +78,8 @@ static irqreturn_t jazz16_interrupt(int irq, void *chip) return snd_sb8dsp_interrupt(chip); } -static int __devinit jazz16_configure_ports(unsigned long port, - unsigned long mpu_port, int idx) +static int jazz16_configure_ports(unsigned long port, + unsigned long mpu_port, int idx) { unsigned char val; @@ -99,8 +99,8 @@ static int __devinit jazz16_configure_ports(unsigned long port, return 0; } -static int __devinit jazz16_detect_board(unsigned long port, - unsigned long mpu_port) +static int jazz16_detect_board(unsigned long port, + unsigned long mpu_port) { int err; int val; @@ -156,7 +156,7 @@ err_unmap: return err; } -static int __devinit jazz16_configure_board(struct snd_sb *chip, int mpu_irq) +static int jazz16_configure_board(struct snd_sb *chip, int mpu_irq) { static unsigned char jazz_irq_bits[] = { 0, 0, 2, 3, 0, 1, 0, 4, 0, 2, 5, 0, 0, 0, 0, 6 }; @@ -183,7 +183,7 @@ static int __devinit jazz16_configure_board(struct snd_sb *chip, int mpu_irq) return 0; } -static int __devinit snd_jazz16_match(struct device *devptr, unsigned int dev) +static int snd_jazz16_match(struct device *devptr, unsigned int dev) { if (!enable[dev]) return 0; @@ -218,7 +218,7 @@ static int __devinit snd_jazz16_match(struct device *devptr, unsigned int dev) return 1; } -static int __devinit snd_jazz16_probe(struct device *devptr, unsigned int dev) +static int snd_jazz16_probe(struct device *devptr, unsigned int dev) { struct snd_card *card; struct snd_card_jazz16 *jazz16; @@ -341,7 +341,7 @@ err_free: return err; } -static int __devexit snd_jazz16_remove(struct device *devptr, unsigned int dev) +static int snd_jazz16_remove(struct device *devptr, unsigned int dev) { struct snd_card *card = dev_get_drvdata(devptr); @@ -380,7 +380,7 @@ static int snd_jazz16_resume(struct device *pdev, unsigned int n) static struct isa_driver snd_jazz16_driver = { .match = snd_jazz16_match, .probe = snd_jazz16_probe, - .remove = __devexit_p(snd_jazz16_remove), + .remove = snd_jazz16_remove, #ifdef CONFIG_PM .suspend = snd_jazz16_suspend, .resume = snd_jazz16_resume, diff --git a/sound/isa/sb/sb16.c b/sound/isa/sb/sb16.c index 39b8eca15213..50dbec454f98 100644 --- a/sound/isa/sb/sb16.c +++ b/sound/isa/sb/sb16.c @@ -250,9 +250,9 @@ MODULE_DEVICE_TABLE(pnp_card, snd_sb16_pnpids); #ifdef CONFIG_PNP -static int __devinit snd_card_sb16_pnp(int dev, struct snd_card_sb16 *acard, - struct pnp_card_link *card, - const struct pnp_card_device_id *id) +static int snd_card_sb16_pnp(int dev, struct snd_card_sb16 *acard, + struct pnp_card_link *card, + const struct pnp_card_device_id *id) { struct pnp_dev *pdev; int err; @@ -337,7 +337,7 @@ static int snd_sb16_card_new(int dev, struct snd_card **cardp) return 0; } -static int __devinit snd_sb16_probe(struct snd_card *card, int dev) +static int snd_sb16_probe(struct snd_card *card, int dev) { int xirq, xdma8, xdma16; struct snd_sb *chip; @@ -487,7 +487,7 @@ static int snd_sb16_resume(struct snd_card *card) } #endif -static int __devinit snd_sb16_isa_probe1(int dev, struct device *pdev) +static int snd_sb16_isa_probe1(int dev, struct device *pdev) { struct snd_card_sb16 *acard; struct snd_card *card; @@ -517,12 +517,12 @@ static int __devinit snd_sb16_isa_probe1(int dev, struct device *pdev) } -static int __devinit snd_sb16_isa_match(struct device *pdev, unsigned int dev) +static int snd_sb16_isa_match(struct device *pdev, unsigned int dev) { return enable[dev] && !is_isapnp_selected(dev); } -static int __devinit snd_sb16_isa_probe(struct device *pdev, unsigned int dev) +static int snd_sb16_isa_probe(struct device *pdev, unsigned int dev) { int err; static int possible_irqs[] = {5, 9, 10, 7, -1}; @@ -563,7 +563,7 @@ static int __devinit snd_sb16_isa_probe(struct device *pdev, unsigned int dev) } } -static int __devexit snd_sb16_isa_remove(struct device *pdev, unsigned int dev) +static int snd_sb16_isa_remove(struct device *pdev, unsigned int dev) { snd_card_free(dev_get_drvdata(pdev)); dev_set_drvdata(pdev, NULL); @@ -592,7 +592,7 @@ static int snd_sb16_isa_resume(struct device *dev, unsigned int n) static struct isa_driver snd_sb16_isa_driver = { .match = snd_sb16_isa_match, .probe = snd_sb16_isa_probe, - .remove = __devexit_p(snd_sb16_isa_remove), + .remove = snd_sb16_isa_remove, #ifdef CONFIG_PM .suspend = snd_sb16_isa_suspend, .resume = snd_sb16_isa_resume, @@ -604,8 +604,8 @@ static struct isa_driver snd_sb16_isa_driver = { #ifdef CONFIG_PNP -static int __devinit snd_sb16_pnp_detect(struct pnp_card_link *pcard, - const struct pnp_card_device_id *pid) +static int snd_sb16_pnp_detect(struct pnp_card_link *pcard, + const struct pnp_card_device_id *pid) { static int dev; struct snd_card *card; @@ -631,7 +631,7 @@ static int __devinit snd_sb16_pnp_detect(struct pnp_card_link *pcard, return -ENODEV; } -static void __devexit snd_sb16_pnp_remove(struct pnp_card_link * pcard) +static void snd_sb16_pnp_remove(struct pnp_card_link *pcard) { snd_card_free(pnp_get_card_drvdata(pcard)); pnp_set_card_drvdata(pcard, NULL); @@ -657,7 +657,7 @@ static struct pnp_card_driver sb16_pnpc_driver = { #endif .id_table = snd_sb16_pnpids, .probe = snd_sb16_pnp_detect, - .remove = __devexit_p(snd_sb16_pnp_remove), + .remove = snd_sb16_pnp_remove, #ifdef CONFIG_PM .suspend = snd_sb16_pnp_suspend, .resume = snd_sb16_pnp_resume, diff --git a/sound/isa/sb/sb8.c b/sound/isa/sb/sb8.c index ab5cebea52e1..237d964ff8a6 100644 --- a/sound/isa/sb/sb8.c +++ b/sound/isa/sb/sb8.c @@ -79,7 +79,7 @@ static void snd_sb8_free(struct snd_card *card) release_and_free_resource(acard->fm_res); } -static int __devinit snd_sb8_match(struct device *pdev, unsigned int dev) +static int snd_sb8_match(struct device *pdev, unsigned int dev) { if (!enable[dev]) return 0; @@ -94,7 +94,7 @@ static int __devinit snd_sb8_match(struct device *pdev, unsigned int dev) return 1; } -static int __devinit snd_sb8_probe(struct device *pdev, unsigned int dev) +static int snd_sb8_probe(struct device *pdev, unsigned int dev) { struct snd_sb *chip; struct snd_card *card; @@ -205,7 +205,7 @@ static int __devinit snd_sb8_probe(struct device *pdev, unsigned int dev) return err; } -static int __devexit snd_sb8_remove(struct device *pdev, unsigned int dev) +static int snd_sb8_remove(struct device *pdev, unsigned int dev) { snd_card_free(dev_get_drvdata(pdev)); dev_set_drvdata(pdev, NULL); @@ -244,7 +244,7 @@ static int snd_sb8_resume(struct device *dev, unsigned int n) static struct isa_driver snd_sb8_driver = { .match = snd_sb8_match, .probe = snd_sb8_probe, - .remove = __devexit_p(snd_sb8_remove), + .remove = snd_sb8_remove, #ifdef CONFIG_PM .suspend = snd_sb8_suspend, .resume = snd_sb8_resume, diff --git a/sound/isa/sc6000.c b/sound/isa/sc6000.c index d97d0f381817..5376ebff845e 100644 --- a/sound/isa/sc6000.c +++ b/sound/isa/sc6000.c @@ -121,7 +121,7 @@ MODULE_PARM_DESC(joystick, "Enable gameport."); /* * sc6000_irq_to_softcfg - Decode irq number into cfg code. */ -static __devinit unsigned char sc6000_irq_to_softcfg(int irq) +static unsigned char sc6000_irq_to_softcfg(int irq) { unsigned char val = 0; @@ -150,7 +150,7 @@ static __devinit unsigned char sc6000_irq_to_softcfg(int irq) /* * sc6000_dma_to_softcfg - Decode dma number into cfg code. */ -static __devinit unsigned char sc6000_dma_to_softcfg(int dma) +static unsigned char sc6000_dma_to_softcfg(int dma) { unsigned char val = 0; @@ -173,7 +173,7 @@ static __devinit unsigned char sc6000_dma_to_softcfg(int dma) /* * sc6000_mpu_irq_to_softcfg - Decode MPU-401 irq number into cfg code. */ -static __devinit unsigned char sc6000_mpu_irq_to_softcfg(int mpu_irq) +static unsigned char sc6000_mpu_irq_to_softcfg(int mpu_irq) { unsigned char val = 0; @@ -242,8 +242,8 @@ static int sc6000_write(char __iomem *vport, int cmd) return -EIO; } -static int __devinit sc6000_dsp_get_answer(char __iomem *vport, int command, - char *data, int data_len) +static int sc6000_dsp_get_answer(char __iomem *vport, int command, + char *data, int data_len) { int len = 0; @@ -269,7 +269,7 @@ static int __devinit sc6000_dsp_get_answer(char __iomem *vport, int command, return len ? len : -EIO; } -static int __devinit sc6000_dsp_reset(char __iomem *vport) +static int sc6000_dsp_reset(char __iomem *vport) { iowrite8(1, vport + DSP_RESET); udelay(10); @@ -281,7 +281,7 @@ static int __devinit sc6000_dsp_reset(char __iomem *vport) } /* detection and initialization */ -static int __devinit sc6000_hw_cfg_write(char __iomem *vport, const int *cfg) +static int sc6000_hw_cfg_write(char __iomem *vport, const int *cfg) { if (sc6000_write(vport, COMMAND_6C) < 0) { snd_printk(KERN_WARNING "CMD 0x%x: failed!\n", COMMAND_6C); @@ -345,8 +345,8 @@ static int sc6000_setup_board(char __iomem *vport, int config) return 0; } -static int __devinit sc6000_init_mss(char __iomem *vport, int config, - char __iomem *vmss_port, int mss_config) +static int sc6000_init_mss(char __iomem *vport, int config, + char __iomem *vmss_port, int mss_config) { if (sc6000_write(vport, DSP_INIT_MSS)) { snd_printk(KERN_ERR "sc6000_init_mss [0x%x]: failed!\n", @@ -364,9 +364,9 @@ static int __devinit sc6000_init_mss(char __iomem *vport, int config, return 0; } -static void __devinit sc6000_hw_cfg_encode(char __iomem *vport, int *cfg, - long xport, long xmpu, - long xmss_port, int joystick) +static void sc6000_hw_cfg_encode(char __iomem *vport, int *cfg, + long xport, long xmpu, + long xmss_port, int joystick) { cfg[0] = 0; cfg[1] = 0; @@ -386,8 +386,8 @@ static void __devinit sc6000_hw_cfg_encode(char __iomem *vport, int *cfg, snd_printd("hw cfg %x, %x\n", cfg[0], cfg[1]); } -static int __devinit sc6000_init_board(char __iomem *vport, - char __iomem *vmss_port, int dev) +static int sc6000_init_board(char __iomem *vport, + char __iomem *vmss_port, int dev) { char answer[15]; char version[2]; @@ -467,7 +467,7 @@ static int __devinit sc6000_init_board(char __iomem *vport, return 0; } -static int __devinit snd_sc6000_mixer(struct snd_wss *chip) +static int snd_sc6000_mixer(struct snd_wss *chip) { struct snd_card *card = chip->card; struct snd_ctl_elem_id id1, id2; @@ -502,7 +502,7 @@ static int __devinit snd_sc6000_mixer(struct snd_wss *chip) return 0; } -static int __devinit snd_sc6000_match(struct device *devptr, unsigned int dev) +static int snd_sc6000_match(struct device *devptr, unsigned int dev) { if (!enable[dev]) return 0; @@ -545,7 +545,7 @@ static int __devinit snd_sc6000_match(struct device *devptr, unsigned int dev) return 1; } -static int __devinit snd_sc6000_probe(struct device *devptr, unsigned int dev) +static int snd_sc6000_probe(struct device *devptr, unsigned int dev) { static int possible_irqs[] = { 5, 7, 9, 10, 11, -1 }; static int possible_dmas[] = { 1, 3, 0, -1 }; @@ -687,7 +687,7 @@ err_exit: return err; } -static int __devexit snd_sc6000_remove(struct device *devptr, unsigned int dev) +static int snd_sc6000_remove(struct device *devptr, unsigned int dev) { struct snd_card *card = dev_get_drvdata(devptr); char __iomem **vport = card->private_data; @@ -706,7 +706,7 @@ static int __devexit snd_sc6000_remove(struct device *devptr, unsigned int dev) static struct isa_driver snd_sc6000_driver = { .match = snd_sc6000_match, .probe = snd_sc6000_probe, - .remove = __devexit_p(snd_sc6000_remove), + .remove = snd_sc6000_remove, /* FIXME: suspend/resume */ .driver = { .name = DRV_NAME, diff --git a/sound/isa/sscape.c b/sound/isa/sscape.c index 8490f59709bb..42a009720b29 100644 --- a/sound/isa/sscape.c +++ b/sound/isa/sscape.c @@ -683,7 +683,7 @@ static struct snd_kcontrol_new midi_mixer_ctl = { * These IRQs are encoded as bit patterns so that they can be * written to the control registers. */ -static unsigned __devinit get_irq_config(int sscape_type, int irq) +static unsigned get_irq_config(int sscape_type, int irq) { static const int valid_irq[] = { 9, 5, 7, 10 }; static const int old_irq[] = { 9, 7, 5, 15 }; @@ -706,7 +706,7 @@ static unsigned __devinit get_irq_config(int sscape_type, int irq) * Perform certain arcane port-checks to see whether there * is a SoundScape board lurking behind the given ports. */ -static int __devinit detect_sscape(struct soundscape *s, long wss_io) +static int detect_sscape(struct soundscape *s, long wss_io) { unsigned long flags; unsigned d; @@ -817,8 +817,8 @@ static int mpu401_open(struct snd_mpu401 *mpu) /* * Initialse an MPU-401 subdevice for MIDI support on the SoundScape. */ -static int __devinit create_mpu401(struct snd_card *card, int devnum, - unsigned long port, int irq) +static int create_mpu401(struct snd_card *card, int devnum, + unsigned long port, int irq) { struct soundscape *sscape = get_card_soundscape(card); struct snd_rawmidi *rawmidi; @@ -845,8 +845,8 @@ static int __devinit create_mpu401(struct snd_card *card, int devnum, * try to support at least some of the extra bits by overriding * some of the CS4231 callback. */ -static int __devinit create_ad1845(struct snd_card *card, unsigned port, - int irq, int dma1, int dma2) +static int create_ad1845(struct snd_card *card, unsigned port, + int irq, int dma1, int dma2) { register struct soundscape *sscape = get_card_soundscape(card); struct snd_wss *chip; @@ -937,7 +937,7 @@ _error: * Create an ALSA soundcard entry for the SoundScape, using * the given list of port, IRQ and DMA resources. */ -static int __devinit create_sscape(int dev, struct snd_card *card) +static int create_sscape(int dev, struct snd_card *card) { struct soundscape *sscape = get_card_soundscape(card); unsigned dma_cfg; @@ -1143,7 +1143,7 @@ _release_region: } -static int __devinit snd_sscape_match(struct device *pdev, unsigned int i) +static int snd_sscape_match(struct device *pdev, unsigned int i) { /* * Make sure we were given ALL of the other parameters. @@ -1163,7 +1163,7 @@ static int __devinit snd_sscape_match(struct device *pdev, unsigned int i) return 1; } -static int __devinit snd_sscape_probe(struct device *pdev, unsigned int dev) +static int snd_sscape_probe(struct device *pdev, unsigned int dev) { struct snd_card *card; struct soundscape *sscape; @@ -1197,7 +1197,7 @@ _release_card: return ret; } -static int __devexit snd_sscape_remove(struct device *devptr, unsigned int dev) +static int snd_sscape_remove(struct device *devptr, unsigned int dev) { snd_card_free(dev_get_drvdata(devptr)); dev_set_drvdata(devptr, NULL); @@ -1209,7 +1209,7 @@ static int __devexit snd_sscape_remove(struct device *devptr, unsigned int dev) static struct isa_driver snd_sscape_driver = { .match = snd_sscape_match, .probe = snd_sscape_probe, - .remove = __devexit_p(snd_sscape_remove), + .remove = snd_sscape_remove, /* FIXME: suspend/resume */ .driver = { .name = DEV_NAME @@ -1217,7 +1217,7 @@ static struct isa_driver snd_sscape_driver = { }; #ifdef CONFIG_PNP -static inline int __devinit get_next_autoindex(int i) +static inline int get_next_autoindex(int i) { while (i < SNDRV_CARDS && port[i] != SNDRV_AUTO_PORT) ++i; @@ -1225,8 +1225,8 @@ static inline int __devinit get_next_autoindex(int i) } -static int __devinit sscape_pnp_detect(struct pnp_card_link *pcard, - const struct pnp_card_device_id *pid) +static int sscape_pnp_detect(struct pnp_card_link *pcard, + const struct pnp_card_device_id *pid) { static int idx = 0; struct pnp_dev *dev; @@ -1310,7 +1310,7 @@ _release_card: return ret; } -static void __devexit sscape_pnp_remove(struct pnp_card_link * pcard) +static void sscape_pnp_remove(struct pnp_card_link *pcard) { snd_card_free(pnp_get_card_drvdata(pcard)); pnp_set_card_drvdata(pcard, NULL); @@ -1321,7 +1321,7 @@ static struct pnp_card_driver sscape_pnpc_driver = { .name = "sscape", .id_table = sscape_pnpids, .probe = sscape_pnp_detect, - .remove = __devexit_p(sscape_pnp_remove), + .remove = sscape_pnp_remove, }; #endif /* CONFIG_PNP */ diff --git a/sound/isa/wavefront/wavefront.c b/sound/isa/wavefront/wavefront.c index e0a73271cb91..fe5dd982bd23 100644 --- a/sound/isa/wavefront/wavefront.c +++ b/sound/isa/wavefront/wavefront.c @@ -98,7 +98,7 @@ static struct pnp_card_device_id snd_wavefront_pnpids[] = { MODULE_DEVICE_TABLE(pnp_card, snd_wavefront_pnpids); -static int __devinit +static int snd_wavefront_pnp (int dev, snd_wavefront_card_t *acard, struct pnp_card_link *card, const struct pnp_card_device_id *id) { @@ -231,10 +231,9 @@ static irqreturn_t snd_wavefront_ics2115_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static struct snd_hwdep * __devinit -snd_wavefront_new_synth (struct snd_card *card, - int hw_dev, - snd_wavefront_card_t *acard) +static struct snd_hwdep *snd_wavefront_new_synth(struct snd_card *card, + int hw_dev, + snd_wavefront_card_t *acard) { struct snd_hwdep *wavefront_synth; @@ -257,11 +256,10 @@ snd_wavefront_new_synth (struct snd_card *card, return wavefront_synth; } -static struct snd_hwdep * __devinit -snd_wavefront_new_fx (struct snd_card *card, - int hw_dev, - snd_wavefront_card_t *acard, - unsigned long port) +static struct snd_hwdep *snd_wavefront_new_fx(struct snd_card *card, + int hw_dev, + snd_wavefront_card_t *acard, + unsigned long port) { struct snd_hwdep *fx_processor; @@ -284,12 +282,11 @@ snd_wavefront_new_fx (struct snd_card *card, static snd_wavefront_mpu_id internal_id = internal_mpu; static snd_wavefront_mpu_id external_id = external_mpu; -static struct snd_rawmidi *__devinit -snd_wavefront_new_midi (struct snd_card *card, - int midi_dev, - snd_wavefront_card_t *acard, - unsigned long port, - snd_wavefront_mpu_id mpu) +static struct snd_rawmidi *snd_wavefront_new_midi(struct snd_card *card, + int midi_dev, + snd_wavefront_card_t *acard, + unsigned long port, + snd_wavefront_mpu_id mpu) { struct snd_rawmidi *rmidi; @@ -361,7 +358,7 @@ static int snd_wavefront_card_new(int dev, struct snd_card **cardp) return 0; } -static int __devinit +static int snd_wavefront_probe (struct snd_card *card, int dev) { snd_wavefront_card_t *acard = card->private_data; @@ -541,8 +538,8 @@ snd_wavefront_probe (struct snd_card *card, int dev) return snd_card_register(card); } -static int __devinit snd_wavefront_isa_match(struct device *pdev, - unsigned int dev) +static int snd_wavefront_isa_match(struct device *pdev, + unsigned int dev) { if (!enable[dev]) return 0; @@ -561,8 +558,8 @@ static int __devinit snd_wavefront_isa_match(struct device *pdev, return 1; } -static int __devinit snd_wavefront_isa_probe(struct device *pdev, - unsigned int dev) +static int snd_wavefront_isa_probe(struct device *pdev, + unsigned int dev) { struct snd_card *card; int err; @@ -580,8 +577,8 @@ static int __devinit snd_wavefront_isa_probe(struct device *pdev, return 0; } -static int __devexit snd_wavefront_isa_remove(struct device *devptr, - unsigned int dev) +static int snd_wavefront_isa_remove(struct device *devptr, + unsigned int dev) { snd_card_free(dev_get_drvdata(devptr)); dev_set_drvdata(devptr, NULL); @@ -593,7 +590,7 @@ static int __devexit snd_wavefront_isa_remove(struct device *devptr, static struct isa_driver snd_wavefront_driver = { .match = snd_wavefront_isa_match, .probe = snd_wavefront_isa_probe, - .remove = __devexit_p(snd_wavefront_isa_remove), + .remove = snd_wavefront_isa_remove, /* FIXME: suspend, resume */ .driver = { .name = DEV_NAME @@ -602,8 +599,8 @@ static struct isa_driver snd_wavefront_driver = { #ifdef CONFIG_PNP -static int __devinit snd_wavefront_pnp_detect(struct pnp_card_link *pcard, - const struct pnp_card_device_id *pid) +static int snd_wavefront_pnp_detect(struct pnp_card_link *pcard, + const struct pnp_card_device_id *pid) { static int dev; struct snd_card *card; @@ -637,7 +634,7 @@ static int __devinit snd_wavefront_pnp_detect(struct pnp_card_link *pcard, return 0; } -static void __devexit snd_wavefront_pnp_remove(struct pnp_card_link * pcard) +static void snd_wavefront_pnp_remove(struct pnp_card_link *pcard) { snd_card_free(pnp_get_card_drvdata(pcard)); pnp_set_card_drvdata(pcard, NULL); @@ -648,7 +645,7 @@ static struct pnp_card_driver wavefront_pnpc_driver = { .name = "wavefront", .id_table = snd_wavefront_pnpids, .probe = snd_wavefront_pnp_detect, - .remove = __devexit_p(snd_wavefront_pnp_remove), + .remove = snd_wavefront_pnp_remove, /* FIXME: suspend,resume */ }; diff --git a/sound/isa/wavefront/wavefront_fx.c b/sound/isa/wavefront/wavefront_fx.c index e51e0906050b..b77883c7ee76 100644 --- a/sound/isa/wavefront/wavefront_fx.c +++ b/sound/isa/wavefront/wavefront_fx.c @@ -240,7 +240,7 @@ snd_wavefront_fx_ioctl (struct snd_hwdep *sdev, struct file *file, that outputs it. */ -int __devinit +int snd_wavefront_fx_start (snd_wavefront_t *dev) { unsigned int i; diff --git a/sound/isa/wavefront/wavefront_midi.c b/sound/isa/wavefront/wavefront_midi.c index 65329f3abc30..7dc991682297 100644 --- a/sound/isa/wavefront/wavefront_midi.c +++ b/sound/isa/wavefront/wavefront_midi.c @@ -481,7 +481,7 @@ snd_wavefront_midi_disable_virtual (snd_wavefront_card_t *card) spin_unlock_irqrestore (&card->wavefront.midi.virtual, flags); } -int __devinit +int snd_wavefront_midi_start (snd_wavefront_card_t *card) { diff --git a/sound/isa/wavefront/wavefront_synth.c b/sound/isa/wavefront/wavefront_synth.c index b1bf8d4e6494..a2f87f9488ee 100644 --- a/sound/isa/wavefront/wavefront_synth.c +++ b/sound/isa/wavefront/wavefront_synth.c @@ -1739,7 +1739,7 @@ snd_wavefront_internal_interrupt (snd_wavefront_card_t *card) 7 Unused */ -static int __devinit +static int snd_wavefront_interrupt_bits (int irq) { @@ -1767,7 +1767,7 @@ snd_wavefront_interrupt_bits (int irq) return bits; } -static void __devinit +static void wavefront_should_cause_interrupt (snd_wavefront_t *dev, int val, int port, unsigned long timeout) @@ -1786,7 +1786,7 @@ wavefront_should_cause_interrupt (snd_wavefront_t *dev, } } -static int __devinit +static int wavefront_reset_to_cleanliness (snd_wavefront_t *dev) { @@ -1937,7 +1937,7 @@ wavefront_reset_to_cleanliness (snd_wavefront_t *dev) return (1); } -static int __devinit +static int wavefront_download_firmware (snd_wavefront_t *dev, char *path) { @@ -2010,7 +2010,7 @@ wavefront_download_firmware (snd_wavefront_t *dev, char *path) } -static int __devinit +static int wavefront_do_reset (snd_wavefront_t *dev) { @@ -2099,7 +2099,7 @@ wavefront_do_reset (snd_wavefront_t *dev) return 1; } -int __devinit +int snd_wavefront_start (snd_wavefront_t *dev) { @@ -2141,7 +2141,7 @@ snd_wavefront_start (snd_wavefront_t *dev) return (0); } -int __devinit +int snd_wavefront_detect (snd_wavefront_card_t *card) { diff --git a/sound/mips/au1x00.c b/sound/mips/au1x00.c index 3f3ec0bec067..224f54be15a6 100644 --- a/sound/mips/au1x00.c +++ b/sound/mips/au1x00.c @@ -439,7 +439,7 @@ static struct snd_pcm_ops snd_card_au1000_capture_ops = { .pointer = snd_au1000_pointer, }; -static int __devinit +static int snd_au1000_pcm_new(struct snd_au1000 *au1000) { struct snd_pcm *pcm; @@ -552,7 +552,7 @@ get the interrupt driven case to work efficiently */ spin_unlock(&au1000->ac97_lock); } -static int __devinit +static int snd_au1000_ac97_new(struct snd_au1000 *au1000) { int err; diff --git a/sound/mips/hal2.c b/sound/mips/hal2.c index 5f88d1f09ffe..7420c59444ab 100644 --- a/sound/mips/hal2.c +++ b/sound/mips/hal2.c @@ -260,7 +260,7 @@ static int hal2_gain_put(struct snd_kcontrol *kcontrol, return old != new; } -static struct snd_kcontrol_new hal2_ctrl_headphone __devinitdata = { +static struct snd_kcontrol_new hal2_ctrl_headphone = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Headphone Playback Volume", .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, @@ -270,7 +270,7 @@ static struct snd_kcontrol_new hal2_ctrl_headphone __devinitdata = { .put = hal2_gain_put, }; -static struct snd_kcontrol_new hal2_ctrl_mic __devinitdata = { +static struct snd_kcontrol_new hal2_ctrl_mic = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Mic Capture Volume", .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, @@ -280,7 +280,7 @@ static struct snd_kcontrol_new hal2_ctrl_mic __devinitdata = { .put = hal2_gain_put, }; -static int __devinit hal2_mixer_create(struct snd_hal2 *hal2) +static int hal2_mixer_create(struct snd_hal2 *hal2) { int err; @@ -733,7 +733,7 @@ static struct snd_pcm_ops hal2_capture_ops = { .ack = hal2_capture_ack, }; -static int __devinit hal2_pcm_create(struct snd_hal2 *hal2) +static int hal2_pcm_create(struct snd_hal2 *hal2) { struct snd_pcm *pcm; int err; @@ -874,7 +874,7 @@ static int hal2_create(struct snd_card *card, struct snd_hal2 **rchip) return 0; } -static int __devinit hal2_probe(struct platform_device *pdev) +static int hal2_probe(struct platform_device *pdev) { struct snd_card *card; struct snd_hal2 *chip; @@ -917,7 +917,7 @@ static int __devinit hal2_probe(struct platform_device *pdev) return 0; } -static int __devexit hal2_remove(struct platform_device *pdev) +static int hal2_remove(struct platform_device *pdev) { struct snd_card *card = platform_get_drvdata(pdev); @@ -928,7 +928,7 @@ static int __devexit hal2_remove(struct platform_device *pdev) static struct platform_driver hal2_driver = { .probe = hal2_probe, - .remove = __devexit_p(hal2_remove), + .remove = hal2_remove, .driver = { .name = "sgihal2", .owner = THIS_MODULE, diff --git a/sound/mips/sgio2audio.c b/sound/mips/sgio2audio.c index ceaa593ea4ef..01a03efdc8b0 100644 --- a/sound/mips/sgio2audio.c +++ b/sound/mips/sgio2audio.c @@ -237,7 +237,7 @@ static int sgio2audio_source_put(struct snd_kcontrol *kcontrol, } /* dac1/pcm0 mixer control */ -static struct snd_kcontrol_new sgio2audio_ctrl_pcm0 __devinitdata = { +static struct snd_kcontrol_new sgio2audio_ctrl_pcm0 = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "PCM Playback Volume", .index = 0, @@ -249,7 +249,7 @@ static struct snd_kcontrol_new sgio2audio_ctrl_pcm0 __devinitdata = { }; /* dac2/pcm1 mixer control */ -static struct snd_kcontrol_new sgio2audio_ctrl_pcm1 __devinitdata = { +static struct snd_kcontrol_new sgio2audio_ctrl_pcm1 = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "PCM Playback Volume", .index = 1, @@ -261,7 +261,7 @@ static struct snd_kcontrol_new sgio2audio_ctrl_pcm1 __devinitdata = { }; /* record level mixer control */ -static struct snd_kcontrol_new sgio2audio_ctrl_reclevel __devinitdata = { +static struct snd_kcontrol_new sgio2audio_ctrl_reclevel = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Capture Volume", .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, @@ -272,7 +272,7 @@ static struct snd_kcontrol_new sgio2audio_ctrl_reclevel __devinitdata = { }; /* record level source control */ -static struct snd_kcontrol_new sgio2audio_ctrl_recsource __devinitdata = { +static struct snd_kcontrol_new sgio2audio_ctrl_recsource = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Capture Source", .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, @@ -282,7 +282,7 @@ static struct snd_kcontrol_new sgio2audio_ctrl_recsource __devinitdata = { }; /* line mixer control */ -static struct snd_kcontrol_new sgio2audio_ctrl_line __devinitdata = { +static struct snd_kcontrol_new sgio2audio_ctrl_line = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Line Playback Volume", .index = 0, @@ -294,7 +294,7 @@ static struct snd_kcontrol_new sgio2audio_ctrl_line __devinitdata = { }; /* cd mixer control */ -static struct snd_kcontrol_new sgio2audio_ctrl_cd __devinitdata = { +static struct snd_kcontrol_new sgio2audio_ctrl_cd = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Line Playback Volume", .index = 1, @@ -306,7 +306,7 @@ static struct snd_kcontrol_new sgio2audio_ctrl_cd __devinitdata = { }; /* mic mixer control */ -static struct snd_kcontrol_new sgio2audio_ctrl_mic __devinitdata = { +static struct snd_kcontrol_new sgio2audio_ctrl_mic = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Mic Playback Volume", .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, @@ -317,7 +317,7 @@ static struct snd_kcontrol_new sgio2audio_ctrl_mic __devinitdata = { }; -static int __devinit snd_sgio2audio_new_mixer(struct snd_sgio2audio *chip) +static int snd_sgio2audio_new_mixer(struct snd_sgio2audio *chip) { int err; @@ -726,7 +726,7 @@ static struct snd_pcm_ops snd_sgio2audio_capture_ops = { */ /* create a pcm device */ -static int __devinit snd_sgio2audio_new_pcm(struct snd_sgio2audio *chip) +static int snd_sgio2audio_new_pcm(struct snd_sgio2audio *chip) { struct snd_pcm *pcm; int err; @@ -834,8 +834,8 @@ static struct snd_device_ops ops = { .dev_free = snd_sgio2audio_dev_free, }; -static int __devinit snd_sgio2audio_create(struct snd_card *card, - struct snd_sgio2audio **rchip) +static int snd_sgio2audio_create(struct snd_card *card, + struct snd_sgio2audio **rchip) { struct snd_sgio2audio *chip; int i, err; @@ -914,7 +914,7 @@ static int __devinit snd_sgio2audio_create(struct snd_card *card, return 0; } -static int __devinit snd_sgio2audio_probe(struct platform_device *pdev) +static int snd_sgio2audio_probe(struct platform_device *pdev) { struct snd_card *card; struct snd_sgio2audio *chip; @@ -958,7 +958,7 @@ static int __devinit snd_sgio2audio_probe(struct platform_device *pdev) return 0; } -static int __devexit snd_sgio2audio_remove(struct platform_device *pdev) +static int snd_sgio2audio_remove(struct platform_device *pdev) { struct snd_card *card = platform_get_drvdata(pdev); @@ -969,7 +969,7 @@ static int __devexit snd_sgio2audio_remove(struct platform_device *pdev) static struct platform_driver sgio2audio_driver = { .probe = snd_sgio2audio_probe, - .remove = __devexit_p(snd_sgio2audio_remove), + .remove = snd_sgio2audio_remove, .driver = { .name = "sgio2audio", .owner = THIS_MODULE, diff --git a/sound/oss/ad1848.c b/sound/oss/ad1848.c index 98d23bdcaf21..4918b7145b73 100644 --- a/sound/oss/ad1848.c +++ b/sound/oss/ad1848.c @@ -2864,7 +2864,7 @@ static struct { {NULL} }; -static struct isapnp_device_id id_table[] __devinitdata = { +static struct isapnp_device_id id_table[] = { { ISAPNP_VENDOR('C','M','I'), ISAPNP_DEVICE(0x0001), ISAPNP_VENDOR('@','@','@'), ISAPNP_FUNCTION(0x0001), 0 }, { ISAPNP_ANY_ID, ISAPNP_ANY_ID, diff --git a/sound/oss/kahlua.c b/sound/oss/kahlua.c index 52d06a334e8f..2a44cc106459 100644 --- a/sound/oss/kahlua.c +++ b/sound/oss/kahlua.c @@ -43,7 +43,7 @@ * not real hardware. */ -static u8 __devinit mixer_read(unsigned long io, u8 reg) +static u8 mixer_read(unsigned long io, u8 reg) { outb(reg, io + 4); udelay(20); @@ -52,7 +52,7 @@ static u8 __devinit mixer_read(unsigned long io, u8 reg) return reg; } -static int __devinit probe_one(struct pci_dev *pdev, const struct pci_device_id *ent) +static int probe_one(struct pci_dev *pdev, const struct pci_device_id *ent) { struct address_info *hw_config; unsigned long base; @@ -183,7 +183,7 @@ err_out_free: return 1; } -static void __devexit remove_one(struct pci_dev *pdev) +static void remove_one(struct pci_dev *pdev) { struct address_info *hw_config = pci_get_drvdata(pdev); sb_dsp_unload(hw_config, 0); @@ -210,7 +210,7 @@ static struct pci_driver kahlua_driver = { .name = "kahlua", .id_table = id_tbl, .probe = probe_one, - .remove = __devexit_p(remove_one), + .remove = remove_one, }; @@ -220,7 +220,7 @@ static int __init kahlua_init_module(void) return pci_register_driver(&kahlua_driver); } -static void __devexit kahlua_cleanup_module(void) +static void kahlua_cleanup_module(void) { pci_unregister_driver(&kahlua_driver); } diff --git a/sound/oss/pas2_card.c b/sound/oss/pas2_card.c index dabf8a871dcc..7004e24d209f 100644 --- a/sound/oss/pas2_card.c +++ b/sound/oss/pas2_card.c @@ -333,6 +333,11 @@ static void __init attach_pas_card(struct address_info *hw_config) { char temp[100]; + if (pas_model < 0 || + pas_model >= ARRAY_SIZE(pas_model_names)) { + printk(KERN_ERR "pas2 unrecognized model.\n"); + return; + } sprintf(temp, "%s rev %d", pas_model_names[(int) pas_model], pas_read(0x2789)); diff --git a/sound/oss/sb_audio.c b/sound/oss/sb_audio.c index b2b3c014221a..048439a16000 100644 --- a/sound/oss/sb_audio.c +++ b/sound/oss/sb_audio.c @@ -442,7 +442,7 @@ static int sb201_audio_set_speed(int dev, int speed) { sb_devc *devc = audio_devs[dev]->devc; int tmp; - int s = speed * devc->channels; + int s; if (speed > 0) { @@ -452,6 +452,7 @@ static int sb201_audio_set_speed(int dev, int speed) speed = 44100; if (devc->opened & OPEN_READ && speed > 15000) speed = 15000; + s = speed * devc->channels; devc->tconst = (256 - ((1000000 + s / 2) / s)) & 0xff; tmp = 256 - devc->tconst; speed = ((1000000 + tmp / 2) / tmp) / devc->channels; diff --git a/sound/parisc/harmony.c b/sound/parisc/harmony.c index f47f9e226b08..0e66ba48d453 100644 --- a/sound/parisc/harmony.c +++ b/sound/parisc/harmony.c @@ -856,7 +856,7 @@ static struct snd_kcontrol_new snd_harmony_controls[] = { HARMONY_GAIN_HE_SHIFT, 1, 0), }; -static void __devinit +static void snd_harmony_mixer_reset(struct snd_harmony *h) { harmony_mute(h); @@ -865,7 +865,7 @@ snd_harmony_mixer_reset(struct snd_harmony *h) harmony_unmute(h); } -static int __devinit +static int snd_harmony_mixer_init(struct snd_harmony *h) { struct snd_card *card; @@ -915,7 +915,7 @@ snd_harmony_dev_free(struct snd_device *dev) return snd_harmony_free(h); } -static int __devinit +static int snd_harmony_create(struct snd_card *card, struct parisc_device *padev, struct snd_harmony **rchip) @@ -972,7 +972,7 @@ free_and_ret: return err; } -static int __devinit +static int snd_harmony_probe(struct parisc_device *padev) { int err; @@ -1012,7 +1012,7 @@ free_and_ret: return err; } -static int __devexit +static int snd_harmony_remove(struct parisc_device *padev) { snd_card_free(parisc_get_drvdata(padev)); @@ -1024,7 +1024,7 @@ static struct parisc_driver snd_harmony_driver = { .name = "harmony", .id_table = snd_harmony_devtable, .probe = snd_harmony_probe, - .remove = __devexit_p(snd_harmony_remove), + .remove = snd_harmony_remove, }; static int __init diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index f99fa2512286..947cfb4eb30c 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig @@ -572,6 +572,7 @@ source "sound/pci/hda/Kconfig" config SND_HDSP tristate "RME Hammerfall DSP Audio" + select FW_LOADER select SND_HWDEP select SND_RAWMIDI select SND_PCM @@ -630,7 +631,7 @@ config SND_ICE1724 AudioTrak Prodigy 192, 7.1 (HIFI/LT/XT), HD2; Hercules Fortissimo IV; ESI Juli@; Pontis MS300; EGO-SYS WaveTerminal 192M; Albatron K8X800 Pro II; Chaintech ZNF3-150/250, 9CJS, - AV-710; Shuttle SN25P. + AV-710; Shuttle SN25P; Philips PSC724 Ultimate Edge. To compile this driver as a module, choose M here: the module will be called snd-ice1724. @@ -707,6 +708,7 @@ config SND_MAESTRO3_INPUT config SND_MIXART tristate "Digigram miXart" + select FW_LOADER select SND_HWDEP select SND_PCM help @@ -727,6 +729,7 @@ config SND_NM256 config SND_PCXHR tristate "Digigram PCXHR" + select FW_LOADER select SND_PCM select SND_HWDEP help diff --git a/sound/pci/ad1889.c b/sound/pci/ad1889.c index e672ff4df2da..ad8a31173939 100644 --- a/sound/pci/ad1889.c +++ b/sound/pci/ad1889.c @@ -624,7 +624,7 @@ snd_ad1889_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static int __devinit +static int snd_ad1889_pcm_init(struct snd_ad1889 *chip, int device, struct snd_pcm **rpcm) { int err; @@ -747,7 +747,7 @@ snd_ad1889_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffe snd_iprintf(buffer, "Resampler samplerate: %u Hz\n", reg); } -static void __devinit +static void snd_ad1889_proc_init(struct snd_ad1889 *chip) { struct snd_info_entry *entry; @@ -767,7 +767,7 @@ static struct ac97_quirk ac97_quirks[] = { { } /* terminator */ }; -static void __devinit +static void snd_ad1889_ac97_xinit(struct snd_ad1889 *chip) { u16 reg; @@ -805,7 +805,7 @@ snd_ad1889_ac97_free(struct snd_ac97 *ac97) chip->ac97 = NULL; } -static int __devinit +static int snd_ad1889_ac97_init(struct snd_ad1889 *chip, const char *quirk_override) { int err; @@ -878,7 +878,7 @@ snd_ad1889_dev_free(struct snd_device *device) return snd_ad1889_free(chip); } -static int __devinit +static int snd_ad1889_init(struct snd_ad1889 *chip) { ad1889_writew(chip, AD_DS_CCS, AD_DS_CCS_CLKEN); /* turn on clock */ @@ -892,7 +892,7 @@ snd_ad1889_init(struct snd_ad1889 *chip) return 0; } -static int __devinit +static int snd_ad1889_create(struct snd_card *card, struct pci_dev *pci, struct snd_ad1889 **rchip) @@ -978,7 +978,7 @@ free_and_ret: return err; } -static int __devinit +static int snd_ad1889_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { @@ -1042,7 +1042,7 @@ free_and_ret: return err; } -static void __devexit +static void snd_ad1889_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); @@ -1059,7 +1059,7 @@ static struct pci_driver ad1889_pci_driver = { .name = KBUILD_MODNAME, .id_table = snd_ad1889_ids, .probe = snd_ad1889_probe, - .remove = __devexit_p(snd_ad1889_remove), + .remove = snd_ad1889_remove, }; module_pci_driver(ad1889_pci_driver); diff --git a/sound/pci/ak4531_codec.c b/sound/pci/ak4531_codec.c index cadf7b962e30..3bf0dc53360a 100644 --- a/sound/pci/ak4531_codec.c +++ b/sound/pci/ak4531_codec.c @@ -274,7 +274,7 @@ static const DECLARE_TLV_DB_SCALE(db_scale_master, -6200, 200, 0); static const DECLARE_TLV_DB_SCALE(db_scale_mono, -2800, 400, 0); static const DECLARE_TLV_DB_SCALE(db_scale_input, -5000, 200, 0); -static struct snd_kcontrol_new snd_ak4531_controls[] __devinitdata = { +static struct snd_kcontrol_new snd_ak4531_controls[] = { AK4531_DOUBLE_TLV("Master Playback Switch", 0, AK4531_LMASTER, AK4531_RMASTER, 7, 7, 1, 1, @@ -383,9 +383,9 @@ static u8 snd_ak4531_initial_map[0x19 + 1] = { 0x01 /* 19: Mic Amp Setup */ }; -int __devinit snd_ak4531_mixer(struct snd_card *card, - struct snd_ak4531 *_ak4531, - struct snd_ak4531 **rak4531) +int snd_ak4531_mixer(struct snd_card *card, + struct snd_ak4531 *_ak4531, + struct snd_ak4531 **rak4531) { unsigned int idx; int err; @@ -483,7 +483,7 @@ static void snd_ak4531_proc_read(struct snd_info_entry *entry, ak4531->regs[AK4531_MIC_GAIN] & 1 ? "+30dB" : "+0dB"); } -static void __devinit +static void snd_ak4531_proc_init(struct snd_card *card, struct snd_ak4531 *ak4531) { struct snd_info_entry *entry; diff --git a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c index c7e3c533316e..136a393b70ab 100644 --- a/sound/pci/ali5451/ali5451.c +++ b/sound/pci/ali5451/ali5451.c @@ -1678,8 +1678,8 @@ static void snd_ali_pcm_free(struct snd_pcm *pcm) } -static int __devinit snd_ali_pcm(struct snd_ali * codec, int device, - struct ali_pcm_description *desc) +static int snd_ali_pcm(struct snd_ali *codec, int device, + struct ali_pcm_description *desc) { struct snd_pcm *pcm; int err; @@ -1727,7 +1727,7 @@ static struct ali_pcm_description ali_pcms[] = { } }; -static int __devinit snd_ali_build_pcms(struct snd_ali *codec) +static int snd_ali_build_pcms(struct snd_ali *codec) { int i, err; for (i = 0; i < codec->num_of_codecs && i < ARRAY_SIZE(ali_pcms); i++) { @@ -1832,7 +1832,7 @@ static int snd_ali5451_spdif_put(struct snd_kcontrol *kcontrol, return change; } -static struct snd_kcontrol_new snd_ali5451_mixer_spdif[] __devinitdata = { +static struct snd_kcontrol_new snd_ali5451_mixer_spdif[] = { /* spdif aplayback switch */ /* FIXME: "IEC958 Playback Switch" may conflict with one on ac97_codec */ ALI5451_SPDIF(SNDRV_CTL_NAME_IEC958("Output ",NONE,SWITCH), 0, 0), @@ -1842,7 +1842,7 @@ static struct snd_kcontrol_new snd_ali5451_mixer_spdif[] __devinitdata = { ALI5451_SPDIF(SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH), 0, 2) }; -static int __devinit snd_ali_mixer(struct snd_ali * codec) +static int snd_ali_mixer(struct snd_ali *codec) { struct snd_ac97_template ac97; unsigned int idx; @@ -2079,14 +2079,14 @@ static void snd_ali_proc_read(struct snd_info_entry *entry, snd_iprintf(buf, "%02x: %08x\n", i, inl(ALI_REG(codec, i))); } -static void __devinit snd_ali_proc_init(struct snd_ali *codec) +static void snd_ali_proc_init(struct snd_ali *codec) { struct snd_info_entry *entry; if (!snd_card_proc_new(codec->card, "ali5451", &entry)) snd_info_set_text_ops(entry, codec, snd_ali_proc_read); } -static int __devinit snd_ali_resources(struct snd_ali *codec) +static int snd_ali_resources(struct snd_ali *codec) { int err; @@ -2112,11 +2112,11 @@ static int snd_ali_dev_free(struct snd_device *device) return 0; } -static int __devinit snd_ali_create(struct snd_card *card, - struct pci_dev *pci, - int pcm_streams, - int spdif_support, - struct snd_ali ** r_ali) +static int snd_ali_create(struct snd_card *card, + struct pci_dev *pci, + int pcm_streams, + int spdif_support, + struct snd_ali **r_ali) { struct snd_ali *codec; int i, err; @@ -2246,8 +2246,8 @@ static int __devinit snd_ali_create(struct snd_card *card, return 0; } -static int __devinit snd_ali_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int snd_ali_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { struct snd_card *card; struct snd_ali *codec; @@ -2295,7 +2295,7 @@ static int __devinit snd_ali_probe(struct pci_dev *pci, return err; } -static void __devexit snd_ali_remove(struct pci_dev *pci) +static void snd_ali_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); pci_set_drvdata(pci, NULL); @@ -2305,7 +2305,7 @@ static struct pci_driver ali5451_driver = { .name = KBUILD_MODNAME, .id_table = snd_ali_ids, .probe = snd_ali_probe, - .remove = __devexit_p(snd_ali_remove), + .remove = snd_ali_remove, .driver = { .pm = ALI_PM_OPS, }, diff --git a/sound/pci/als300.c b/sound/pci/als300.c index 5af3cb6b0c18..864c4310366b 100644 --- a/sound/pci/als300.c +++ b/sound/pci/als300.c @@ -278,7 +278,7 @@ static irqreturn_t snd_als300plus_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static void __devexit snd_als300_remove(struct pci_dev *pci) +static void snd_als300_remove(struct pci_dev *pci) { snd_als300_dbgcallenter(); snd_card_free(pci_get_drvdata(pci)); @@ -622,7 +622,7 @@ static struct snd_pcm_ops snd_als300_capture_ops = { .pointer = snd_als300_pointer, }; -static int __devinit snd_als300_new_pcm(struct snd_als300 *chip) +static int snd_als300_new_pcm(struct snd_als300 *chip) { struct snd_pcm *pcm; int err; @@ -683,9 +683,9 @@ static void snd_als300_init(struct snd_als300 *chip) snd_als300_dbgcallleave(); } -static int __devinit snd_als300_create(struct snd_card *card, - struct pci_dev *pci, int chip_type, - struct snd_als300 **rchip) +static int snd_als300_create(struct snd_card *card, + struct pci_dev *pci, int chip_type, + struct snd_als300 **rchip) { struct snd_als300 *chip; void *irq_handler; @@ -815,7 +815,7 @@ static SIMPLE_DEV_PM_OPS(snd_als300_pm, snd_als300_suspend, snd_als300_resume); #define SND_ALS300_PM_OPS NULL #endif -static int __devinit snd_als300_probe(struct pci_dev *pci, +static int snd_als300_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { static int dev; @@ -867,7 +867,7 @@ static struct pci_driver als300_driver = { .name = KBUILD_MODNAME, .id_table = snd_als300_ids, .probe = snd_als300_probe, - .remove = __devexit_p(snd_als300_remove), + .remove = snd_als300_remove, .driver = { .pm = SND_ALS300_PM_OPS, }, diff --git a/sound/pci/als4000.c b/sound/pci/als4000.c index feb2a1436830..61efda2a4d94 100644 --- a/sound/pci/als4000.c +++ b/sound/pci/als4000.c @@ -694,7 +694,7 @@ static struct snd_pcm_ops snd_als4000_capture_ops = { .pointer = snd_als4000_capture_pointer }; -static int __devinit snd_als4000_pcm(struct snd_sb *chip, int device) +static int snd_als4000_pcm(struct snd_sb *chip, int device) { struct snd_pcm *pcm; int err; @@ -770,7 +770,7 @@ static void snd_als4000_configure(struct snd_sb *chip) } #ifdef SUPPORT_JOYSTICK -static int __devinit snd_als4000_create_gameport(struct snd_card_als4000 *acard, int dev) +static int snd_als4000_create_gameport(struct snd_card_als4000 *acard, int dev) { struct gameport *gp; struct resource *r; @@ -847,8 +847,8 @@ static void snd_card_als4000_free( struct snd_card *card ) pci_disable_device(acard->pci); } -static int __devinit snd_card_als4000_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int snd_card_als4000_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { static int dev; struct snd_card *card; @@ -981,7 +981,7 @@ out: return err; } -static void __devexit snd_card_als4000_remove(struct pci_dev *pci) +static void snd_card_als4000_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); pci_set_drvdata(pci, NULL); @@ -1046,7 +1046,7 @@ static struct pci_driver als4000_driver = { .name = KBUILD_MODNAME, .id_table = snd_als4000_ids, .probe = snd_card_als4000_probe, - .remove = __devexit_p(snd_card_als4000_remove), + .remove = snd_card_als4000_remove, .driver = { .pm = SND_ALS4000_PM_OPS, }, diff --git a/sound/pci/asihpi/asihpi.c b/sound/pci/asihpi/asihpi.c index eedc017c1cd8..3536b076b529 100644 --- a/sound/pci/asihpi/asihpi.c +++ b/sound/pci/asihpi/asihpi.c @@ -1235,8 +1235,7 @@ static struct snd_pcm_ops snd_card_asihpi_capture_mmap_ops = { .pointer = snd_card_asihpi_capture_pointer, }; -static int __devinit snd_card_asihpi_pcm_new( - struct snd_card_asihpi *asihpi, int device) +static int snd_card_asihpi_pcm_new(struct snd_card_asihpi *asihpi, int device) { struct snd_pcm *pcm; int err; @@ -1497,8 +1496,8 @@ static int snd_asihpi_volume_mute_put(struct snd_kcontrol *kcontrol, return change; } -static int __devinit snd_asihpi_volume_add(struct snd_card_asihpi *asihpi, - struct hpi_control *hpi_ctl) +static int snd_asihpi_volume_add(struct snd_card_asihpi *asihpi, + struct hpi_control *hpi_ctl) { struct snd_card *card = asihpi->card; struct snd_kcontrol_new snd_control; @@ -1593,8 +1592,8 @@ static int snd_asihpi_level_put(struct snd_kcontrol *kcontrol, static const DECLARE_TLV_DB_SCALE(db_scale_level, -1000, 100, 0); -static int __devinit snd_asihpi_level_add(struct snd_card_asihpi *asihpi, - struct hpi_control *hpi_ctl) +static int snd_asihpi_level_add(struct snd_card_asihpi *asihpi, + struct hpi_control *hpi_ctl) { struct snd_card *card = asihpi->card; struct snd_kcontrol_new snd_control; @@ -1715,8 +1714,8 @@ static int snd_asihpi_aesebu_rxstatus_get(struct snd_kcontrol *kcontrol, return 0; } -static int __devinit snd_asihpi_aesebu_rx_add(struct snd_card_asihpi *asihpi, - struct hpi_control *hpi_ctl) +static int snd_asihpi_aesebu_rx_add(struct snd_card_asihpi *asihpi, + struct hpi_control *hpi_ctl) { struct snd_card *card = asihpi->card; struct snd_kcontrol_new snd_control; @@ -1753,8 +1752,8 @@ static int snd_asihpi_aesebu_tx_format_put(struct snd_kcontrol *kcontrol, } -static int __devinit snd_asihpi_aesebu_tx_add(struct snd_card_asihpi *asihpi, - struct hpi_control *hpi_ctl) +static int snd_asihpi_aesebu_tx_add(struct snd_card_asihpi *asihpi, + struct hpi_control *hpi_ctl) { struct snd_card *card = asihpi->card; struct snd_kcontrol_new snd_control; @@ -1996,8 +1995,8 @@ static int snd_asihpi_tuner_freq_put(struct snd_kcontrol *kcontrol, } /* Tuner control group initializer */ -static int __devinit snd_asihpi_tuner_add(struct snd_card_asihpi *asihpi, - struct hpi_control *hpi_ctl) +static int snd_asihpi_tuner_add(struct snd_card_asihpi *asihpi, + struct hpi_control *hpi_ctl) { struct snd_card *card = asihpi->card; struct snd_kcontrol_new snd_control; @@ -2100,8 +2099,8 @@ static int snd_asihpi_meter_get(struct snd_kcontrol *kcontrol, return 0; } -static int __devinit snd_asihpi_meter_add(struct snd_card_asihpi *asihpi, - struct hpi_control *hpi_ctl, int subidx) +static int snd_asihpi_meter_add(struct snd_card_asihpi *asihpi, + struct hpi_control *hpi_ctl, int subidx) { struct snd_card *card = asihpi->card; struct snd_kcontrol_new snd_control; @@ -2214,8 +2213,8 @@ static int snd_asihpi_mux_put(struct snd_kcontrol *kcontrol, } -static int __devinit snd_asihpi_mux_add(struct snd_card_asihpi *asihpi, - struct hpi_control *hpi_ctl) +static int snd_asihpi_mux_add(struct snd_card_asihpi *asihpi, + struct hpi_control *hpi_ctl) { struct snd_card *card = asihpi->card; struct snd_kcontrol_new snd_control; @@ -2303,8 +2302,8 @@ static int snd_asihpi_cmode_put(struct snd_kcontrol *kcontrol, } -static int __devinit snd_asihpi_cmode_add(struct snd_card_asihpi *asihpi, - struct hpi_control *hpi_ctl) +static int snd_asihpi_cmode_add(struct snd_card_asihpi *asihpi, + struct hpi_control *hpi_ctl) { struct snd_card *card = asihpi->card; struct snd_kcontrol_new snd_control; @@ -2471,8 +2470,8 @@ static int snd_asihpi_clkrate_get(struct snd_kcontrol *kcontrol, return 0; } -static int __devinit snd_asihpi_sampleclock_add(struct snd_card_asihpi *asihpi, - struct hpi_control *hpi_ctl) +static int snd_asihpi_sampleclock_add(struct snd_card_asihpi *asihpi, + struct hpi_control *hpi_ctl) { struct snd_card *card = asihpi->card; struct snd_kcontrol_new snd_control; @@ -2548,7 +2547,7 @@ static int __devinit snd_asihpi_sampleclock_add(struct snd_card_asihpi *asihpi, Mixer ------------------------------------------------------------*/ -static int __devinit snd_card_asihpi_mixer_new(struct snd_card_asihpi *asihpi) +static int snd_card_asihpi_mixer_new(struct snd_card_asihpi *asihpi) { struct snd_card *card = asihpi->card; unsigned int idx = 0; @@ -2722,7 +2721,7 @@ snd_asihpi_proc_read(struct snd_info_entry *entry, } } -static void __devinit snd_asihpi_proc_init(struct snd_card_asihpi *asihpi) +static void snd_asihpi_proc_init(struct snd_card_asihpi *asihpi) { struct snd_info_entry *entry; @@ -2764,8 +2763,8 @@ static int snd_asihpi_hpi_ioctl(struct snd_hwdep *hw, struct file *file, /* results in /dev/snd/hwC#D0 file for each card with index # also /proc/asound/hwdep will contain '#-00: asihpi (HPI) for each card' */ -static int __devinit snd_asihpi_hpi_new(struct snd_card_asihpi *asihpi, - int device, struct snd_hwdep **rhwdep) +static int snd_asihpi_hpi_new(struct snd_card_asihpi *asihpi, + int device, struct snd_hwdep **rhwdep) { struct snd_hwdep *hw; int err; @@ -2789,8 +2788,8 @@ static int __devinit snd_asihpi_hpi_new(struct snd_card_asihpi *asihpi, /*------------------------------------------------------------ CARD ------------------------------------------------------------*/ -static int __devinit snd_asihpi_probe(struct pci_dev *pci_dev, - const struct pci_device_id *pci_id) +static int snd_asihpi_probe(struct pci_dev *pci_dev, + const struct pci_device_id *pci_id) { int err; struct hpi_adapter *hpi; @@ -2944,7 +2943,7 @@ __nodev: } -static void __devexit snd_asihpi_remove(struct pci_dev *pci_dev) +static void snd_asihpi_remove(struct pci_dev *pci_dev) { struct hpi_adapter *hpi = pci_get_drvdata(pci_dev); snd_card_free(hpi->snd_card); @@ -2967,7 +2966,7 @@ static struct pci_driver driver = { .name = KBUILD_MODNAME, .id_table = asihpi_pci_tbl, .probe = snd_asihpi_probe, - .remove = __devexit_p(snd_asihpi_remove), + .remove = snd_asihpi_remove, #ifdef CONFIG_PM_SLEEP /* .suspend = snd_asihpi_suspend, .resume = snd_asihpi_resume, */ diff --git a/sound/pci/asihpi/hpidspcd.c b/sound/pci/asihpi/hpidspcd.c index 456a758f04f6..ac9163770013 100644 --- a/sound/pci/asihpi/hpidspcd.c +++ b/sound/pci/asihpi/hpidspcd.c @@ -49,14 +49,12 @@ short hpi_dsp_code_open(u32 adapter, void *os_data, struct dsp_code *dsp_code, err = request_firmware(&firmware, fw_name, &dev->dev); if (err || !firmware) { - dev_printk(KERN_ERR, &dev->dev, - "%d, request_firmware failed for %s\n", err, - fw_name); + dev_err(&dev->dev, "%d, request_firmware failed for %s\n", + err, fw_name); goto error1; } if (firmware->size < sizeof(header)) { - dev_printk(KERN_ERR, &dev->dev, "Header size too small %s\n", - fw_name); + dev_err(&dev->dev, "Header size too small %s\n", fw_name); goto error2; } memcpy(&header, firmware->data, sizeof(header)); @@ -64,7 +62,7 @@ short hpi_dsp_code_open(u32 adapter, void *os_data, struct dsp_code *dsp_code, if ((header.type != 0x45444F43) || /* "CODE" */ (header.adapter != adapter) || (header.size != firmware->size)) { - dev_printk(KERN_ERR, &dev->dev, + dev_err(&dev->dev, "Invalid firmware header size %d != file %zd\n", header.size, firmware->size); goto error2; @@ -72,17 +70,15 @@ short hpi_dsp_code_open(u32 adapter, void *os_data, struct dsp_code *dsp_code, if ((header.version >> 9) != (HPI_VER >> 9)) { /* Consider even and subsequent odd minor versions to be compatible */ - dev_printk(KERN_ERR, &dev->dev, - "Incompatible firmware version " - "DSP image %X != Driver %X\n", header.version, - HPI_VER); + dev_err(&dev->dev, "Incompatible firmware version DSP image %X != Driver %X\n", + header.version, HPI_VER); goto error2; } if (header.version != HPI_VER) { - dev_printk(KERN_INFO, &dev->dev, - "Firmware: release version mismatch DSP image %X != Driver %X\n", - header.version, HPI_VER); + dev_info(&dev->dev, + "Firmware: release version mismatch DSP image %X != Driver %X\n", + header.version, HPI_VER); } HPI_DEBUG_LOG(DEBUG, "dsp code %s opened\n", fw_name); diff --git a/sound/pci/asihpi/hpioctl.c b/sound/pci/asihpi/hpioctl.c index 609156205562..ef5019fe5193 100644 --- a/sound/pci/asihpi/hpioctl.c +++ b/sound/pci/asihpi/hpioctl.c @@ -307,8 +307,8 @@ out: return err; } -int __devinit asihpi_adapter_probe(struct pci_dev *pci_dev, - const struct pci_device_id *pci_id) +int asihpi_adapter_probe(struct pci_dev *pci_dev, + const struct pci_device_id *pci_id) { int idx, nm; int adapter_index; @@ -326,7 +326,7 @@ int __devinit asihpi_adapter_probe(struct pci_dev *pci_dev, pci_dev->subsystem_device, pci_dev->devfn); if (pci_enable_device(pci_dev) < 0) { - dev_printk(KERN_ERR, &pci_dev->dev, + dev_err(&pci_dev->dev, "pci_enable_device failed, disabling device\n"); return -EIO; } @@ -398,9 +398,8 @@ int __devinit asihpi_adapter_probe(struct pci_dev *pci_dev, mutex_init(&adapters[adapter_index].mutex); pci_set_drvdata(pci_dev, &adapters[adapter_index]); - dev_printk(KERN_INFO, &pci_dev->dev, - "probe succeeded for ASI%04X HPI index %d\n", - adapter.adapter->type, adapter_index); + dev_info(&pci_dev->dev, "probe succeeded for ASI%04X HPI index %d\n", + adapter.adapter->type, adapter_index); return 0; @@ -421,7 +420,7 @@ err: return -ENODEV; } -void __devexit asihpi_adapter_remove(struct pci_dev *pci_dev) +void asihpi_adapter_remove(struct pci_dev *pci_dev) { int idx; struct hpi_message hm; @@ -448,11 +447,11 @@ void __devexit asihpi_adapter_remove(struct pci_dev *pci_dev) pci_set_drvdata(pci_dev, NULL); if (1) - dev_printk(KERN_INFO, &pci_dev->dev, - "remove %04x:%04x,%04x:%04x,%04x," " HPI index %d.\n", - pci_dev->vendor, pci_dev->device, - pci_dev->subsystem_vendor, pci_dev->subsystem_device, - pci_dev->devfn, pa->adapter->index); + dev_info(&pci_dev->dev, + "remove %04x:%04x,%04x:%04x,%04x, HPI index %d\n", + pci_dev->vendor, pci_dev->device, + pci_dev->subsystem_vendor, pci_dev->subsystem_device, + pci_dev->devfn, pa->adapter->index); memset(pa, 0, sizeof(*pa)); } diff --git a/sound/pci/asihpi/hpioctl.h b/sound/pci/asihpi/hpioctl.h index 2614aff672e2..0d767e10ac48 100644 --- a/sound/pci/asihpi/hpioctl.h +++ b/sound/pci/asihpi/hpioctl.h @@ -19,9 +19,9 @@ Linux HPI ioctl, and shared module init functions *******************************************************************************/ -int __devinit asihpi_adapter_probe(struct pci_dev *pci_dev, - const struct pci_device_id *pci_id); -void __devexit asihpi_adapter_remove(struct pci_dev *pci_dev); +int asihpi_adapter_probe(struct pci_dev *pci_dev, + const struct pci_device_id *pci_id); +void asihpi_adapter_remove(struct pci_dev *pci_dev); void __init asihpi_init(void); void __exit asihpi_exit(void); diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c index 368df8b0853e..6e78c6789858 100644 --- a/sound/pci/atiixp.c +++ b/sound/pci/atiixp.c @@ -296,7 +296,7 @@ static DEFINE_PCI_DEVICE_TABLE(snd_atiixp_ids) = { MODULE_DEVICE_TABLE(pci, snd_atiixp_ids); -static struct snd_pci_quirk atiixp_quirks[] __devinitdata = { +static struct snd_pci_quirk atiixp_quirks[] = { SND_PCI_QUIRK(0x105b, 0x0c81, "Foxconn RC4107MA-RS2", 0), SND_PCI_QUIRK(0x15bd, 0x3100, "DFI RS482", 0), { } /* terminator */ @@ -561,21 +561,22 @@ static int snd_atiixp_aclink_down(struct atiixp *chip) ATI_REG_ISR_CODEC2_NOT_READY) #define CODEC_CHECK_BITS (ALL_CODEC_NOT_READY|ATI_REG_ISR_NEW_FRAME) -static int __devinit ac97_probing_bugs(struct pci_dev *pci) +static int ac97_probing_bugs(struct pci_dev *pci) { const struct snd_pci_quirk *q; q = snd_pci_quirk_lookup(pci, atiixp_quirks); if (q) { - snd_printdd(KERN_INFO "Atiixp quirk for %s. " - "Forcing codec %d\n", q->name, q->value); + snd_printdd(KERN_INFO + "Atiixp quirk for %s. Forcing codec %d\n", + snd_pci_quirk_name(q), q->value); return q->value; } /* this hardware doesn't need workarounds. Probe for codec */ return -1; } -static int __devinit snd_atiixp_codec_detect(struct atiixp *chip) +static int snd_atiixp_codec_detect(struct atiixp *chip) { int timeout; @@ -1183,7 +1184,7 @@ static struct snd_pcm_ops snd_atiixp_spdif_ops = { .pointer = snd_atiixp_pcm_pointer, }; -static struct ac97_pcm atiixp_pcm_defs[] __devinitdata = { +static struct ac97_pcm atiixp_pcm_defs[] = { /* front PCM */ { .exclusive = 1, @@ -1247,7 +1248,7 @@ static struct atiixp_dma_ops snd_atiixp_spdif_dma_ops = { }; -static int __devinit snd_atiixp_pcm_new(struct atiixp *chip) +static int snd_atiixp_pcm_new(struct atiixp *chip) { struct snd_pcm *pcm; struct snd_pcm_chmap *chmap; @@ -1390,7 +1391,7 @@ static irqreturn_t snd_atiixp_interrupt(int irq, void *dev_id) * ac97 mixer section */ -static struct ac97_quirk ac97_quirks[] __devinitdata = { +static struct ac97_quirk ac97_quirks[] = { { .subvendor = 0x103c, .subdevice = 0x006b, @@ -1412,8 +1413,8 @@ static struct ac97_quirk ac97_quirks[] __devinitdata = { { } /* terminator */ }; -static int __devinit snd_atiixp_mixer_new(struct atiixp *chip, int clock, - const char *quirk_override) +static int snd_atiixp_mixer_new(struct atiixp *chip, int clock, + const char *quirk_override) { struct snd_ac97_bus *pbus; struct snd_ac97_template ac97; @@ -1560,7 +1561,7 @@ static void snd_atiixp_proc_read(struct snd_info_entry *entry, snd_iprintf(buffer, "%02x: %08x\n", i, readl(chip->remap_addr + i)); } -static void __devinit snd_atiixp_proc_init(struct atiixp *chip) +static void snd_atiixp_proc_init(struct atiixp *chip) { struct snd_info_entry *entry; @@ -1602,9 +1603,9 @@ static int snd_atiixp_dev_free(struct snd_device *device) /* * constructor for chip instance */ -static int __devinit snd_atiixp_create(struct snd_card *card, - struct pci_dev *pci, - struct atiixp **r_chip) +static int snd_atiixp_create(struct snd_card *card, + struct pci_dev *pci, + struct atiixp **r_chip) { static struct snd_device_ops ops = { .dev_free = snd_atiixp_dev_free, @@ -1661,8 +1662,8 @@ static int __devinit snd_atiixp_create(struct snd_card *card, } -static int __devinit snd_atiixp_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int snd_atiixp_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { struct snd_card *card; struct atiixp *chip; @@ -1710,7 +1711,7 @@ static int __devinit snd_atiixp_probe(struct pci_dev *pci, return err; } -static void __devexit snd_atiixp_remove(struct pci_dev *pci) +static void snd_atiixp_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); pci_set_drvdata(pci, NULL); @@ -1720,7 +1721,7 @@ static struct pci_driver atiixp_driver = { .name = KBUILD_MODNAME, .id_table = snd_atiixp_ids, .probe = snd_atiixp_probe, - .remove = __devexit_p(snd_atiixp_remove), + .remove = snd_atiixp_remove, .driver = { .pm = SND_ATIIXP_PM_OPS, }, diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c index 6fc03d9f2cff..d0bec7ba3b0d 100644 --- a/sound/pci/atiixp_modem.c +++ b/sound/pci/atiixp_modem.c @@ -988,7 +988,7 @@ static struct atiixp_dma_ops snd_atiixp_capture_dma_ops = { .flush_dma = atiixp_in_flush_dma, }; -static int __devinit snd_atiixp_pcm_new(struct atiixp_modem *chip) +static int snd_atiixp_pcm_new(struct atiixp_modem *chip) { struct snd_pcm *pcm; int err; @@ -1061,7 +1061,7 @@ static irqreturn_t snd_atiixp_interrupt(int irq, void *dev_id) * ac97 mixer section */ -static int __devinit snd_atiixp_mixer_new(struct atiixp_modem *chip, int clock) +static int snd_atiixp_mixer_new(struct atiixp_modem *chip, int clock) { struct snd_ac97_bus *pbus; struct snd_ac97_template ac97; @@ -1186,7 +1186,7 @@ static void snd_atiixp_proc_read(struct snd_info_entry *entry, snd_iprintf(buffer, "%02x: %08x\n", i, readl(chip->remap_addr + i)); } -static void __devinit snd_atiixp_proc_init(struct atiixp_modem *chip) +static void snd_atiixp_proc_init(struct atiixp_modem *chip) { struct snd_info_entry *entry; @@ -1228,9 +1228,9 @@ static int snd_atiixp_dev_free(struct snd_device *device) /* * constructor for chip instance */ -static int __devinit snd_atiixp_create(struct snd_card *card, - struct pci_dev *pci, - struct atiixp_modem **r_chip) +static int snd_atiixp_create(struct snd_card *card, + struct pci_dev *pci, + struct atiixp_modem **r_chip) { static struct snd_device_ops ops = { .dev_free = snd_atiixp_dev_free, @@ -1287,8 +1287,8 @@ static int __devinit snd_atiixp_create(struct snd_card *card, } -static int __devinit snd_atiixp_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int snd_atiixp_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { struct snd_card *card; struct atiixp_modem *chip; @@ -1331,7 +1331,7 @@ static int __devinit snd_atiixp_probe(struct pci_dev *pci, return err; } -static void __devexit snd_atiixp_remove(struct pci_dev *pci) +static void snd_atiixp_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); pci_set_drvdata(pci, NULL); @@ -1341,7 +1341,7 @@ static struct pci_driver atiixp_modem_driver = { .name = KBUILD_MODNAME, .id_table = snd_atiixp_ids, .probe = snd_atiixp_probe, - .remove = __devexit_p(snd_atiixp_remove), + .remove = snd_atiixp_remove, .driver = { .pm = SND_ATIIXP_PM_OPS, }, diff --git a/sound/pci/au88x0/au88x0.c b/sound/pci/au88x0/au88x0.c index ffc376f9f4e4..b157e1fadd8f 100644 --- a/sound/pci/au88x0/au88x0.c +++ b/sound/pci/au88x0/au88x0.c @@ -78,7 +78,7 @@ static void vortex_fix_agp_bridge(struct pci_dev *via) } } -static void __devinit snd_vortex_workaround(struct pci_dev *vortex, int fix) +static void snd_vortex_workaround(struct pci_dev *vortex, int fix) { struct pci_dev *via = NULL; @@ -137,7 +137,7 @@ static int snd_vortex_dev_free(struct snd_device *device) // chip-specific constructor // (see "Management of Cards and Components") -static int __devinit +static int snd_vortex_create(struct snd_card *card, struct pci_dev *pci, vortex_t ** rchip) { vortex_t *chip; @@ -234,7 +234,7 @@ snd_vortex_create(struct snd_card *card, struct pci_dev *pci, vortex_t ** rchip) } // constructor -- see "Constructor" sub-section -static int __devinit +static int snd_vortex_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { static int dev; @@ -368,7 +368,7 @@ snd_vortex_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) } // destructor -- see "Destructor" sub-section -static void __devexit snd_vortex_remove(struct pci_dev *pci) +static void snd_vortex_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); pci_set_drvdata(pci, NULL); @@ -379,7 +379,7 @@ static struct pci_driver vortex_driver = { .name = KBUILD_MODNAME, .id_table = snd_vortex_ids, .probe = snd_vortex_probe, - .remove = __devexit_p(snd_vortex_remove), + .remove = snd_vortex_remove, }; module_pci_driver(vortex_driver); diff --git a/sound/pci/au88x0/au88x0_a3d.c b/sound/pci/au88x0/au88x0_a3d.c index 9ae8b3b17651..aad831acbb17 100644 --- a/sound/pci/au88x0/au88x0_a3d.c +++ b/sound/pci/au88x0/au88x0_a3d.c @@ -594,7 +594,7 @@ static int Vort3DRend_Initialize(vortex_t * v, unsigned short mode) static int vortex_a3d_register_controls(vortex_t * vortex); static void vortex_a3d_unregister_controls(vortex_t * vortex); /* A3D base support init/shudown */ -static void __devinit vortex_Vort3D_enable(vortex_t * v) +static void vortex_Vort3D_enable(vortex_t *v) { int i; @@ -845,7 +845,7 @@ snd_vortex_a3d_filter_put(struct snd_kcontrol *kcontrol, return changed; } -static struct snd_kcontrol_new vortex_a3d_kcontrol __devinitdata = { +static struct snd_kcontrol_new vortex_a3d_kcontrol = { .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = "Playback PCM advanced processing", .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, @@ -855,7 +855,7 @@ static struct snd_kcontrol_new vortex_a3d_kcontrol __devinitdata = { }; /* Control (un)registration. */ -static int __devinit vortex_a3d_register_controls(vortex_t * vortex) +static int vortex_a3d_register_controls(vortex_t *vortex) { struct snd_kcontrol *kcontrol; int err, i; diff --git a/sound/pci/au88x0/au88x0_core.c b/sound/pci/au88x0/au88x0_core.c index 525f881f0409..ae59dbaa53d9 100644 --- a/sound/pci/au88x0/au88x0_core.c +++ b/sound/pci/au88x0/au88x0_core.c @@ -2461,7 +2461,12 @@ static irqreturn_t vortex_interrupt(int irq, void *dev_id) #ifndef CHIP_AU8810 for (i = 0; i < NR_WT; i++) { if (vortex->dma_wt[i].fifo_status == FIFO_START) { - if (vortex_wtdma_bufshift(vortex, i)) ; + /* FIXME: we ignore the return value from + * vortex_wtdma_bufshift() below as the delta + * calculation seems not working for wavetable + * by some reason + */ + vortex_wtdma_bufshift(vortex, i); spin_unlock(&vortex->lock); snd_pcm_period_elapsed(vortex->dma_wt[i]. substream); @@ -2675,7 +2680,7 @@ static void vortex_spdif_init(vortex_t * vortex, int spdif_sr, int spdif_mode) /* Initialization */ -static int __devinit vortex_core_init(vortex_t * vortex) +static int vortex_core_init(vortex_t *vortex) { printk(KERN_INFO "Vortex: init.... "); diff --git a/sound/pci/au88x0/au88x0_eq.c b/sound/pci/au88x0/au88x0_eq.c index 278ed8189fca..e7220533ecfc 100644 --- a/sound/pci/au88x0/au88x0_eq.c +++ b/sound/pci/au88x0/au88x0_eq.c @@ -757,7 +757,7 @@ snd_vortex_eqtoggle_put(struct snd_kcontrol *kcontrol, return 1; /* Allways changes */ } -static struct snd_kcontrol_new vortex_eqtoggle_kcontrol __devinitdata = { +static struct snd_kcontrol_new vortex_eqtoggle_kcontrol = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "EQ Enable", .index = 0, @@ -815,7 +815,7 @@ snd_vortex_eq_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucon return changed; } -static struct snd_kcontrol_new vortex_eq_kcontrol __devinitdata = { +static struct snd_kcontrol_new vortex_eq_kcontrol = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = " .", .index = 0, @@ -854,7 +854,7 @@ snd_vortex_peaks_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *u return 0; } -static struct snd_kcontrol_new vortex_levels_kcontrol __devinitdata = { +static struct snd_kcontrol_new vortex_levels_kcontrol = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "EQ Peaks", .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, @@ -863,7 +863,7 @@ static struct snd_kcontrol_new vortex_levels_kcontrol __devinitdata = { }; /* EQ band gain labels. */ -static char *EqBandLabels[10] __devinitdata = { +static char *EqBandLabels[10] = { "EQ0 31Hz\0", "EQ1 63Hz\0", "EQ2 125Hz\0", @@ -877,7 +877,7 @@ static char *EqBandLabels[10] __devinitdata = { }; /* ALSA driver entry points. Init and exit. */ -static int __devinit vortex_eq_init(vortex_t * vortex) +static int vortex_eq_init(vortex_t *vortex) { struct snd_kcontrol *kcontrol; int err, i; diff --git a/sound/pci/au88x0/au88x0_game.c b/sound/pci/au88x0/au88x0_game.c index 30a456700d89..280f86de2230 100644 --- a/sound/pci/au88x0/au88x0_game.c +++ b/sound/pci/au88x0/au88x0_game.c @@ -92,7 +92,7 @@ static int vortex_game_open(struct gameport *gameport, int mode) return 0; } -static int __devinit vortex_gameport_register(vortex_t * vortex) +static int vortex_gameport_register(vortex_t *vortex) { struct gameport *gp; diff --git a/sound/pci/au88x0/au88x0_mixer.c b/sound/pci/au88x0/au88x0_mixer.c index fa13efbebdaf..a58298cfe7e0 100644 --- a/sound/pci/au88x0/au88x0_mixer.c +++ b/sound/pci/au88x0/au88x0_mixer.c @@ -19,7 +19,7 @@ static int remove_ctl(struct snd_card *card, const char *name) return snd_ctl_remove_id(card, &id); } -static int __devinit snd_vortex_mixer(vortex_t * vortex) +static int snd_vortex_mixer(vortex_t *vortex) { struct snd_ac97_bus *pbus; struct snd_ac97_template ac97; diff --git a/sound/pci/au88x0/au88x0_mpu401.c b/sound/pci/au88x0/au88x0_mpu401.c index e6c6a0febb75..29e5945eef60 100644 --- a/sound/pci/au88x0/au88x0_mpu401.c +++ b/sound/pci/au88x0/au88x0_mpu401.c @@ -41,7 +41,7 @@ #define MPU401_ENTER_UART 0x3f #define MPU401_ACK 0xfe -static int __devinit snd_vortex_midi(vortex_t * vortex) +static int snd_vortex_midi(vortex_t *vortex) { struct snd_rawmidi *rmidi; int temp, mode; diff --git a/sound/pci/au88x0/au88x0_pcm.c b/sound/pci/au88x0/au88x0_pcm.c index b2405020284c..a4184bb27761 100644 --- a/sound/pci/au88x0/au88x0_pcm.c +++ b/sound/pci/au88x0/au88x0_pcm.c @@ -516,7 +516,7 @@ static int snd_vortex_spdif_put(struct snd_kcontrol *kcontrol, struct snd_ctl_el } /* spdif controls */ -static struct snd_kcontrol_new snd_vortex_mixer_spdif[] __devinitdata = { +static struct snd_kcontrol_new snd_vortex_mixer_spdif[] = { { .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), @@ -598,7 +598,7 @@ static int snd_vortex_pcm_vol_put(struct snd_kcontrol *kcontrol, static const DECLARE_TLV_DB_MINMAX(vortex_pcm_vol_db_scale, -9600, 2400); -static struct snd_kcontrol_new snd_vortex_pcm_vol __devinitdata = { +static struct snd_kcontrol_new snd_vortex_pcm_vol = { .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = "PCM Playback Volume", .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | @@ -611,7 +611,7 @@ static struct snd_kcontrol_new snd_vortex_pcm_vol __devinitdata = { }; /* create a pcm device */ -static int __devinit snd_vortex_new_pcm(vortex_t *chip, int idx, int nr) +static int snd_vortex_new_pcm(vortex_t *chip, int idx, int nr) { struct snd_pcm *pcm; struct snd_kcontrol *kctl; diff --git a/sound/pci/au88x0/au88x0_synth.c b/sound/pci/au88x0/au88x0_synth.c index 2805e34bd41d..8bef47311e45 100644 --- a/sound/pci/au88x0/au88x0_synth.c +++ b/sound/pci/au88x0/au88x0_synth.c @@ -58,7 +58,7 @@ static void vortex_wt_setdsout(vortex_t * vortex, u32 wt, int en) if (en) temp |= (1 << (wt & 0x1f)); else - temp &= (1 << ~(wt & 0x1f)); + temp &= ~(1 << (wt & 0x1f)); hwwrite(vortex->mmio, WT_DSREG((wt >= 0x20) ? 1 : 0), temp); } diff --git a/sound/pci/aw2/aw2-alsa.c b/sound/pci/aw2/aw2-alsa.c index 0f804741825f..08e9a4702cbc 100644 --- a/sound/pci/aw2/aw2-alsa.c +++ b/sound/pci/aw2/aw2-alsa.c @@ -113,11 +113,11 @@ struct aw2 { * FUNCTION DECLARATIONS ********************************/ static int snd_aw2_dev_free(struct snd_device *device); -static int __devinit snd_aw2_create(struct snd_card *card, - struct pci_dev *pci, struct aw2 **rchip); -static int __devinit snd_aw2_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id); -static void __devexit snd_aw2_remove(struct pci_dev *pci); +static int snd_aw2_create(struct snd_card *card, + struct pci_dev *pci, struct aw2 **rchip); +static int snd_aw2_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id); +static void snd_aw2_remove(struct pci_dev *pci); static int snd_aw2_pcm_playback_open(struct snd_pcm_substream *substream); static int snd_aw2_pcm_playback_close(struct snd_pcm_substream *substream); static int snd_aw2_pcm_capture_open(struct snd_pcm_substream *substream); @@ -135,7 +135,7 @@ static snd_pcm_uframes_t snd_aw2_pcm_pointer_playback(struct snd_pcm_substream *substream); static snd_pcm_uframes_t snd_aw2_pcm_pointer_capture(struct snd_pcm_substream *substream); -static int __devinit snd_aw2_new_pcm(struct aw2 *chip); +static int snd_aw2_new_pcm(struct aw2 *chip); static int snd_aw2_control_switch_capture_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo); @@ -173,7 +173,7 @@ static struct pci_driver aw2_driver = { .name = KBUILD_MODNAME, .id_table = snd_aw2_ids, .probe = snd_aw2_probe, - .remove = __devexit_p(snd_aw2_remove), + .remove = snd_aw2_remove, }; module_pci_driver(aw2_driver); @@ -202,7 +202,7 @@ static struct snd_pcm_ops snd_aw2_capture_ops = { .pointer = snd_aw2_pcm_pointer_capture, }; -static struct snd_kcontrol_new aw2_control __devinitdata = { +static struct snd_kcontrol_new aw2_control = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "PCM Capture Route", .index = 0, @@ -242,8 +242,8 @@ static int snd_aw2_dev_free(struct snd_device *device) } /* chip-specific constructor */ -static int __devinit snd_aw2_create(struct snd_card *card, - struct pci_dev *pci, struct aw2 **rchip) +static int snd_aw2_create(struct snd_card *card, + struct pci_dev *pci, struct aw2 **rchip) { struct aw2 *chip; int err; @@ -332,8 +332,8 @@ static int __devinit snd_aw2_create(struct snd_card *card, } /* constructor */ -static int __devinit snd_aw2_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int snd_aw2_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { static int dev; struct snd_card *card; @@ -389,7 +389,7 @@ static int __devinit snd_aw2_probe(struct pci_dev *pci, } /* destructor */ -static void __devexit snd_aw2_remove(struct pci_dev *pci) +static void snd_aw2_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); pci_set_drvdata(pci, NULL); @@ -591,7 +591,7 @@ static snd_pcm_uframes_t snd_aw2_pcm_pointer_capture(struct snd_pcm_substream } /* create a pcm device */ -static int __devinit snd_aw2_new_pcm(struct aw2 *chip) +static int snd_aw2_new_pcm(struct aw2 *chip) { struct snd_pcm *pcm_playback_ana; struct snd_pcm *pcm_playback_num; diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c index c03b66b784a3..1204a0fa3368 100644 --- a/sound/pci/azt3328.c +++ b/sound/pci/azt3328.c @@ -817,7 +817,7 @@ snd_azf3328_mixer_ac97_write(struct snd_ac97 *ac97, snd_azf3328_mixer_ac97_map_unsupported(reg_ac97, "write"); } -static int __devinit +static int snd_azf3328_mixer_new(struct snd_azf3328 *chip) { struct snd_ac97_bus *bus; @@ -1171,7 +1171,7 @@ snd_azf3328_put_mixer_enum(struct snd_kcontrol *kcontrol, return (nreg != oreg); } -static struct snd_kcontrol_new snd_azf3328_mixer_controls[] __devinitdata = { +static struct snd_kcontrol_new snd_azf3328_mixer_controls[] = { AZF3328_MIXER_SWITCH("Master Playback Switch", IDX_MIXER_PLAY_MASTER, 15, 1), AZF3328_MIXER_VOL_STEREO("Master Playback Volume", IDX_MIXER_PLAY_MASTER, 0x1f, 1), AZF3328_MIXER_SWITCH("PCM Playback Switch", IDX_MIXER_WAVEOUT, 15, 1), @@ -1229,7 +1229,7 @@ static struct snd_kcontrol_new snd_azf3328_mixer_controls[] __devinitdata = { #endif }; -static u16 __devinitdata snd_azf3328_init_values[][2] = { +static u16 snd_azf3328_init_values[][2] = { { IDX_MIXER_PLAY_MASTER, MIXER_MUTE_MASK|0x1f1f }, { IDX_MIXER_MODEMOUT, MIXER_MUTE_MASK|0x1f1f }, { IDX_MIXER_BASSTREBLE, 0x0000 }, @@ -1245,7 +1245,7 @@ static u16 __devinitdata snd_azf3328_init_values[][2] = { { IDX_MIXER_REC_VOLUME, MIXER_MUTE_MASK|0x0707 }, }; -static int __devinit +static int snd_azf3328_mixer_new(struct snd_azf3328 *chip) { struct snd_card *card; @@ -1899,7 +1899,7 @@ snd_azf3328_gameport_cooked_read(struct gameport *gameport, return 0; } -static int __devinit +static int snd_azf3328_gameport(struct snd_azf3328 *chip, int dev) { struct gameport *gp; @@ -2212,7 +2212,7 @@ static struct snd_pcm_ops snd_azf3328_i2s_out_ops = { .pointer = snd_azf3328_pcm_pointer }; -static int __devinit +static int snd_azf3328_pcm(struct snd_azf3328 *chip) { enum { AZF_PCMDEV_STD, AZF_PCMDEV_I2S_OUT, NUM_AZF_PCMDEVS }; /* pcm devices */ @@ -2344,7 +2344,7 @@ static struct snd_timer_hardware snd_azf3328_timer_hw = { .precise_resolution = snd_azf3328_timer_precise_resolution, }; -static int __devinit +static int snd_azf3328_timer(struct snd_azf3328 *chip, int device) { struct snd_timer *timer = NULL; @@ -2489,7 +2489,7 @@ snd_azf3328_debug_show_ports(const struct snd_azf3328 *chip) #endif /* DEBUG_MISC */ } -static int __devinit +static int snd_azf3328_create(struct snd_card *card, struct pci_dev *pci, unsigned long device_type, @@ -2615,7 +2615,7 @@ out: return err; } -static int __devinit +static int snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { static int dev; @@ -2720,7 +2720,7 @@ out: return err; } -static void __devexit +static void snd_azf3328_remove(struct pci_dev *pci) { snd_azf3328_dbgcallenter(); @@ -2872,7 +2872,7 @@ static struct pci_driver azf3328_driver = { .name = KBUILD_MODNAME, .id_table = snd_azf3328_ids, .probe = snd_azf3328_probe, - .remove = __devexit_p(snd_azf3328_remove), + .remove = snd_azf3328_remove, .driver = { .pm = SND_AZF3328_PM_OPS, }, diff --git a/sound/pci/bt87x.c b/sound/pci/bt87x.c index b6a95eeca095..cdd100dae855 100644 --- a/sound/pci/bt87x.c +++ b/sound/pci/bt87x.c @@ -164,7 +164,7 @@ struct snd_bt87x_board { unsigned no_digital:1; /* No digital input */ }; -static __devinitdata struct snd_bt87x_board snd_bt87x_boards[] = { +static struct snd_bt87x_board snd_bt87x_boards[] = { [SND_BT87X_BOARD_UNKNOWN] = { .dig_rate = 32000, /* just a guess */ }, @@ -696,7 +696,7 @@ static int snd_bt87x_dev_free(struct snd_device *device) return snd_bt87x_free(chip); } -static int __devinit snd_bt87x_pcm(struct snd_bt87x *chip, int device, char *name) +static int snd_bt87x_pcm(struct snd_bt87x *chip, int device, char *name) { int err; struct snd_pcm *pcm; @@ -714,9 +714,9 @@ static int __devinit snd_bt87x_pcm(struct snd_bt87x *chip, int device, char *nam ALIGN(255 * 4092, 1024)); } -static int __devinit snd_bt87x_create(struct snd_card *card, - struct pci_dev *pci, - struct snd_bt87x **rchip) +static int snd_bt87x_create(struct snd_card *card, + struct pci_dev *pci, + struct snd_bt87x **rchip) { struct snd_bt87x *chip; int err; @@ -822,7 +822,7 @@ MODULE_DEVICE_TABLE(pci, snd_bt87x_ids); * (DVB cards use the audio function to transfer MPEG data) */ static struct { unsigned short subvendor, subdevice; -} blacklist[] __devinitdata = { +} blacklist[] = { {0x0071, 0x0101}, /* Nebula Electronics DigiTV */ {0x11bd, 0x001c}, /* Pinnacle PCTV Sat */ {0x11bd, 0x0026}, /* Pinnacle PCTV SAT CI */ @@ -837,7 +837,7 @@ static struct { }; /* return the id of the card, or a negative value if it's blacklisted */ -static int __devinit snd_bt87x_detect_card(struct pci_dev *pci) +static int snd_bt87x_detect_card(struct pci_dev *pci) { int i; const struct pci_device_id *supported; @@ -862,8 +862,8 @@ static int __devinit snd_bt87x_detect_card(struct pci_dev *pci) return SND_BT87X_BOARD_UNKNOWN; } -static int __devinit snd_bt87x_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int snd_bt87x_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { static int dev; struct snd_card *card; @@ -948,7 +948,7 @@ _error: return err; } -static void __devexit snd_bt87x_remove(struct pci_dev *pci) +static void snd_bt87x_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); pci_set_drvdata(pci, NULL); @@ -966,7 +966,7 @@ static struct pci_driver bt87x_driver = { .name = KBUILD_MODNAME, .id_table = snd_bt87x_ids, .probe = snd_bt87x_probe, - .remove = __devexit_p(snd_bt87x_remove), + .remove = snd_bt87x_remove, }; module_pci_driver(bt87x_driver); diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index 65c55910566b..1610a5705970 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c @@ -1352,7 +1352,7 @@ static const struct snd_pcm_chmap_elem side_map[] = { { } }; -static int __devinit snd_ca0106_pcm(struct snd_ca0106 *emu, int device) +static int snd_ca0106_pcm(struct snd_ca0106 *emu, int device) { struct snd_pcm *pcm; struct snd_pcm_substream *substream; @@ -1650,7 +1650,7 @@ static void ca0106_stop_chip(struct snd_ca0106 *chip) */ } -static int __devinit snd_ca0106_create(int dev, struct snd_card *card, +static int snd_ca0106_create(int dev, struct snd_card *card, struct pci_dev *pci, struct snd_ca0106 **rchip) { @@ -1777,7 +1777,7 @@ static int ca0106_dev_id_port(void *dev_id) return ((struct snd_ca0106 *)dev_id)->port; } -static int __devinit snd_ca0106_midi(struct snd_ca0106 *chip, unsigned int channel) +static int snd_ca0106_midi(struct snd_ca0106 *chip, unsigned int channel) { struct snd_ca_midi *midi; char *name; @@ -1828,7 +1828,7 @@ static int __devinit snd_ca0106_midi(struct snd_ca0106 *chip, unsigned int chann } -static int __devinit snd_ca0106_probe(struct pci_dev *pci, +static int snd_ca0106_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { static int dev; @@ -1893,7 +1893,7 @@ static int __devinit snd_ca0106_probe(struct pci_dev *pci, return err; } -static void __devexit snd_ca0106_remove(struct pci_dev *pci) +static void snd_ca0106_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); pci_set_drvdata(pci, NULL); @@ -1971,7 +1971,7 @@ static struct pci_driver ca0106_driver = { .name = KBUILD_MODNAME, .id_table = snd_ca0106_ids, .probe = snd_ca0106_probe, - .remove = __devexit_p(snd_ca0106_remove), + .remove = snd_ca0106_remove, .driver = { .pm = SND_CA0106_PM_OPS, }, diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c index 68eacf7002d6..27de0de90018 100644 --- a/sound/pci/ca0106/ca0106_mixer.c +++ b/sound/pci/ca0106/ca0106_mixer.c @@ -325,7 +325,7 @@ static int snd_ca0106_capture_mic_line_in_put(struct snd_kcontrol *kcontrol, return change; } -static struct snd_kcontrol_new snd_ca0106_capture_mic_line_in __devinitdata = +static struct snd_kcontrol_new snd_ca0106_capture_mic_line_in = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Shared Mic/Line in Capture Switch", @@ -334,7 +334,7 @@ static struct snd_kcontrol_new snd_ca0106_capture_mic_line_in __devinitdata = .put = snd_ca0106_capture_mic_line_in_put }; -static struct snd_kcontrol_new snd_ca0106_capture_line_in_side_out __devinitdata = +static struct snd_kcontrol_new snd_ca0106_capture_line_in_side_out = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Shared Line in/Side out Capture Switch", @@ -588,7 +588,7 @@ static int spi_mute_put(struct snd_kcontrol *kcontrol, .private_value = ((chid) << 8) | (reg) \ } -static struct snd_kcontrol_new snd_ca0106_volume_ctls[] __devinitdata = { +static struct snd_kcontrol_new snd_ca0106_volume_ctls[] = { CA_VOLUME("Analog Front Playback Volume", CONTROL_FRONT_CHANNEL, PLAYBACK_VOLUME2), CA_VOLUME("Analog Rear Playback Volume", @@ -669,7 +669,7 @@ static struct snd_kcontrol_new snd_ca0106_volume_ctls[] __devinitdata = { .private_value = chid \ } -static struct snd_kcontrol_new snd_ca0106_volume_i2c_adc_ctls[] __devinitdata = { +static struct snd_kcontrol_new snd_ca0106_volume_i2c_adc_ctls[] = { I2C_VOLUME("Phone Capture Volume", 0), I2C_VOLUME("Mic Capture Volume", 1), I2C_VOLUME("Line in Capture Volume", 2), @@ -691,7 +691,7 @@ static const int spi_dmute_bit[] = { SPI_DMUTE4_BIT, }; -static struct snd_kcontrol_new __devinit +static struct snd_kcontrol_new snd_ca0106_volume_spi_dac_ctl(struct snd_ca0106_details *details, int channel_id) { @@ -735,7 +735,7 @@ snd_ca0106_volume_spi_dac_ctl(struct snd_ca0106_details *details, return spi_switch; } -static int __devinit remove_ctl(struct snd_card *card, const char *name) +static int remove_ctl(struct snd_card *card, const char *name) { struct snd_ctl_elem_id id; memset(&id, 0, sizeof(id)); @@ -744,7 +744,7 @@ static int __devinit remove_ctl(struct snd_card *card, const char *name) return snd_ctl_remove_id(card, &id); } -static struct snd_kcontrol __devinit *ctl_find(struct snd_card *card, const char *name) +static struct snd_kcontrol *ctl_find(struct snd_card *card, const char *name) { struct snd_ctl_elem_id sid; memset(&sid, 0, sizeof(sid)); @@ -754,7 +754,7 @@ static struct snd_kcontrol __devinit *ctl_find(struct snd_card *card, const char return snd_ctl_find_id(card, &sid); } -static int __devinit rename_ctl(struct snd_card *card, const char *src, const char *dst) +static int rename_ctl(struct snd_card *card, const char *src, const char *dst) { struct snd_kcontrol *kctl = ctl_find(card, src); if (kctl) { @@ -774,10 +774,10 @@ static int __devinit rename_ctl(struct snd_card *card, const char *src, const ch } \ } while (0) -static __devinitdata +static DECLARE_TLV_DB_SCALE(snd_ca0106_master_db_scale, -6375, 25, 1); -static char *slave_vols[] __devinitdata = { +static char *slave_vols[] = { "Analog Front Playback Volume", "Analog Rear Playback Volume", "Analog Center/LFE Playback Volume", @@ -790,7 +790,7 @@ static char *slave_vols[] __devinitdata = { NULL }; -static char *slave_sws[] __devinitdata = { +static char *slave_sws[] = { "Analog Front Playback Switch", "Analog Rear Playback Switch", "Analog Center/LFE Playback Switch", @@ -799,7 +799,7 @@ static char *slave_sws[] __devinitdata = { NULL }; -static void __devinit add_slaves(struct snd_card *card, +static void add_slaves(struct snd_card *card, struct snd_kcontrol *master, char **list) { for (; *list; list++) { @@ -809,7 +809,7 @@ static void __devinit add_slaves(struct snd_card *card, } } -int __devinit snd_ca0106_mixer(struct snd_ca0106 *emu) +int snd_ca0106_mixer(struct snd_ca0106 *emu) { int err; struct snd_card *card = emu->card; diff --git a/sound/pci/ca0106/ca0106_proc.c b/sound/pci/ca0106/ca0106_proc.c index c694464b1168..4f9c2821bb31 100644 --- a/sound/pci/ca0106/ca0106_proc.c +++ b/sound/pci/ca0106/ca0106_proc.c @@ -424,7 +424,7 @@ static void snd_ca0106_proc_i2c_write(struct snd_info_entry *entry, } } -int __devinit snd_ca0106_proc_init(struct snd_ca0106 * emu) +int snd_ca0106_proc_init(struct snd_ca0106 *emu) { struct snd_info_entry *entry; diff --git a/sound/pci/ca0106/ca_midi.c b/sound/pci/ca0106/ca_midi.c index c7885117da33..8bbdf265d11d 100644 --- a/sound/pci/ca0106/ca_midi.c +++ b/sound/pci/ca0106/ca_midi.c @@ -286,7 +286,7 @@ static void ca_rmidi_free(struct snd_rawmidi *rmidi) ca_midi_free(rmidi->private_data); } -int __devinit ca_midi_init(void *dev_id, struct snd_ca_midi *midi, int device, char *name) +int ca_midi_init(void *dev_id, struct snd_ca_midi *midi, int device, char *name) { struct snd_rawmidi *rmidi; int err; diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c index 22122ff26e34..c617435db6e6 100644 --- a/sound/pci/cmipci.c +++ b/sound/pci/cmipci.c @@ -1045,7 +1045,7 @@ static int snd_cmipci_spdif_default_put(struct snd_kcontrol *kcontrol, return change; } -static struct snd_kcontrol_new snd_cmipci_spdif_default __devinitdata = +static struct snd_kcontrol_new snd_cmipci_spdif_default = { .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), @@ -1072,7 +1072,7 @@ static int snd_cmipci_spdif_mask_get(struct snd_kcontrol *kcontrol, return 0; } -static struct snd_kcontrol_new snd_cmipci_spdif_mask __devinitdata = +static struct snd_kcontrol_new snd_cmipci_spdif_mask = { .access = SNDRV_CTL_ELEM_ACCESS_READ, .iface = SNDRV_CTL_ELEM_IFACE_PCM, @@ -1119,7 +1119,7 @@ static int snd_cmipci_spdif_stream_put(struct snd_kcontrol *kcontrol, return change; } -static struct snd_kcontrol_new snd_cmipci_spdif_stream __devinitdata = +static struct snd_kcontrol_new snd_cmipci_spdif_stream = { .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, .iface = SNDRV_CTL_ELEM_IFACE_PCM, @@ -1897,7 +1897,7 @@ static struct snd_pcm_ops snd_cmipci_capture_spdif_ops = { /* */ -static int __devinit snd_cmipci_pcm_new(struct cmipci *cm, int device) +static int snd_cmipci_pcm_new(struct cmipci *cm, int device) { struct snd_pcm *pcm; int err; @@ -1920,7 +1920,7 @@ static int __devinit snd_cmipci_pcm_new(struct cmipci *cm, int device) return 0; } -static int __devinit snd_cmipci_pcm2_new(struct cmipci *cm, int device) +static int snd_cmipci_pcm2_new(struct cmipci *cm, int device) { struct snd_pcm *pcm; int err; @@ -1942,7 +1942,7 @@ static int __devinit snd_cmipci_pcm2_new(struct cmipci *cm, int device) return 0; } -static int __devinit snd_cmipci_pcm_spdif_new(struct cmipci *cm, int device) +static int snd_cmipci_pcm_spdif_new(struct cmipci *cm, int device) { struct snd_pcm *pcm; int err; @@ -2290,7 +2290,7 @@ static int snd_cmipci_put_native_mixer_sensitive(struct snd_kcontrol *kcontrol, } -static struct snd_kcontrol_new snd_cmipci_mixers[] __devinitdata = { +static struct snd_kcontrol_new snd_cmipci_mixers[] = { CMIPCI_SB_VOL_STEREO("Master Playback Volume", SB_DSP4_MASTER_DEV, 3, 31), CMIPCI_MIXER_SW_MONO("3D Control - Switch", CM_REG_MIXER1, CM_X3DEN_SHIFT, 0), CMIPCI_SB_VOL_STEREO("PCM Playback Volume", SB_DSP4_PCM_DEV, 3, 31), @@ -2601,7 +2601,7 @@ static int snd_cmipci_mic_in_mode_put(struct snd_kcontrol *kcontrol, } /* both for CM8338/8738 */ -static struct snd_kcontrol_new snd_cmipci_mixer_switches[] __devinitdata = { +static struct snd_kcontrol_new snd_cmipci_mixer_switches[] = { DEFINE_MIXER_SWITCH("Four Channel Mode", fourch), { .name = "Line-In Mode", @@ -2613,11 +2613,11 @@ static struct snd_kcontrol_new snd_cmipci_mixer_switches[] __devinitdata = { }; /* for non-multichannel chips */ -static struct snd_kcontrol_new snd_cmipci_nomulti_switch __devinitdata = +static struct snd_kcontrol_new snd_cmipci_nomulti_switch = DEFINE_MIXER_SWITCH("Exchange DAC", exchange_dac); /* only for CM8738 */ -static struct snd_kcontrol_new snd_cmipci_8738_mixer_switches[] __devinitdata = { +static struct snd_kcontrol_new snd_cmipci_8738_mixer_switches[] = { #if 0 /* controlled in pcm device */ DEFINE_MIXER_SWITCH("IEC958 In Record", spdif_in), DEFINE_MIXER_SWITCH("IEC958 Out", spdif_out), @@ -2639,14 +2639,14 @@ static struct snd_kcontrol_new snd_cmipci_8738_mixer_switches[] __devinitdata = }; /* only for model 033/037 */ -static struct snd_kcontrol_new snd_cmipci_old_mixer_switches[] __devinitdata = { +static struct snd_kcontrol_new snd_cmipci_old_mixer_switches[] = { DEFINE_MIXER_SWITCH("IEC958 Mix Analog", spdif_dac_out), DEFINE_MIXER_SWITCH("IEC958 In Phase Inverse", spdi_phase), DEFINE_MIXER_SWITCH("IEC958 In Select", spdif_in_sel1), }; /* only for model 039 or later */ -static struct snd_kcontrol_new snd_cmipci_extra_mixer_switches[] __devinitdata = { +static struct snd_kcontrol_new snd_cmipci_extra_mixer_switches[] = { DEFINE_MIXER_SWITCH("IEC958 In Select", spdif_in_sel2), DEFINE_MIXER_SWITCH("IEC958 In Phase Inverse", spdi_phase2), { @@ -2659,11 +2659,11 @@ static struct snd_kcontrol_new snd_cmipci_extra_mixer_switches[] __devinitdata = }; /* card control switches */ -static struct snd_kcontrol_new snd_cmipci_modem_switch __devinitdata = +static struct snd_kcontrol_new snd_cmipci_modem_switch = DEFINE_CARD_SWITCH("Modem", modem); -static int __devinit snd_cmipci_mixer_new(struct cmipci *cm, int pcm_spdif_device) +static int snd_cmipci_mixer_new(struct cmipci *cm, int pcm_spdif_device) { struct snd_card *card; struct snd_kcontrol_new *sw; @@ -2791,7 +2791,7 @@ static void snd_cmipci_proc_read(struct snd_info_entry *entry, snd_iprintf(buffer, "\n"); } -static void __devinit snd_cmipci_proc_init(struct cmipci *cm) +static void snd_cmipci_proc_init(struct cmipci *cm) { struct snd_info_entry *entry; @@ -2817,7 +2817,7 @@ static DEFINE_PCI_DEVICE_TABLE(snd_cmipci_ids) = { * check chip version and capabilities * driver name is modified according to the chip model */ -static void __devinit query_chip(struct cmipci *cm) +static void query_chip(struct cmipci *cm) { unsigned int detect; @@ -2866,7 +2866,7 @@ static void __devinit query_chip(struct cmipci *cm) } #ifdef SUPPORT_JOYSTICK -static int __devinit snd_cmipci_create_gameport(struct cmipci *cm, int dev) +static int snd_cmipci_create_gameport(struct cmipci *cm, int dev) { static int ports[] = { 0x201, 0x200, 0 }; /* FIXME: majority is 0x201? */ struct gameport *gp; @@ -2959,7 +2959,7 @@ static int snd_cmipci_dev_free(struct snd_device *device) return snd_cmipci_free(cm); } -static int __devinit snd_cmipci_create_fm(struct cmipci *cm, long fm_port) +static int snd_cmipci_create_fm(struct cmipci *cm, long fm_port) { long iosynth; unsigned int val; @@ -3012,8 +3012,8 @@ static int __devinit snd_cmipci_create_fm(struct cmipci *cm, long fm_port) return 0; } -static int __devinit snd_cmipci_create(struct snd_card *card, struct pci_dev *pci, - int dev, struct cmipci **rcmipci) +static int snd_cmipci_create(struct snd_card *card, struct pci_dev *pci, + int dev, struct cmipci **rcmipci) { struct cmipci *cm; int err; @@ -3265,8 +3265,8 @@ static int __devinit snd_cmipci_create(struct snd_card *card, struct pci_dev *pc MODULE_DEVICE_TABLE(pci, snd_cmipci_ids); -static int __devinit snd_cmipci_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int snd_cmipci_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { static int dev; struct snd_card *card; @@ -3314,7 +3314,7 @@ static int __devinit snd_cmipci_probe(struct pci_dev *pci, } -static void __devexit snd_cmipci_remove(struct pci_dev *pci) +static void snd_cmipci_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); pci_set_drvdata(pci, NULL); @@ -3415,7 +3415,7 @@ static struct pci_driver cmipci_driver = { .name = KBUILD_MODNAME, .id_table = snd_cmipci_ids, .probe = snd_cmipci_probe, - .remove = __devexit_p(snd_cmipci_remove), + .remove = snd_cmipci_remove, .driver = { .pm = SND_CMIPCI_PM_OPS, }, diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c index 8e86ec0031fc..6a8695069941 100644 --- a/sound/pci/cs4281.c +++ b/sound/pci/cs4281.c @@ -969,8 +969,8 @@ static struct snd_pcm_ops snd_cs4281_capture_ops = { .pointer = snd_cs4281_pointer, }; -static int __devinit snd_cs4281_pcm(struct cs4281 * chip, int device, - struct snd_pcm ** rpcm) +static int snd_cs4281_pcm(struct cs4281 *chip, int device, + struct snd_pcm **rpcm) { struct snd_pcm *pcm; int err; @@ -1093,7 +1093,7 @@ static void snd_cs4281_mixer_free_ac97(struct snd_ac97 *ac97) chip->ac97 = NULL; } -static int __devinit snd_cs4281_mixer(struct cs4281 * chip) +static int snd_cs4281_mixer(struct cs4281 *chip) { struct snd_card *card = chip->card; struct snd_ac97_template ac97; @@ -1171,7 +1171,7 @@ static struct snd_info_entry_ops snd_cs4281_proc_ops_BA1 = { .read = snd_cs4281_BA1_read, }; -static void __devinit snd_cs4281_proc_init(struct cs4281 * chip) +static void snd_cs4281_proc_init(struct cs4281 *chip) { struct snd_info_entry *entry; @@ -1259,7 +1259,7 @@ static int snd_cs4281_gameport_open(struct gameport *gameport, int mode) return 0; } -static int __devinit snd_cs4281_create_gameport(struct cs4281 *chip) +static int snd_cs4281_create_gameport(struct cs4281 *chip) { struct gameport *gp; @@ -1335,10 +1335,10 @@ static int snd_cs4281_dev_free(struct snd_device *device) static int snd_cs4281_chip_init(struct cs4281 *chip); /* defined below */ -static int __devinit snd_cs4281_create(struct snd_card *card, - struct pci_dev *pci, - struct cs4281 ** rchip, - int dual_codec) +static int snd_cs4281_create(struct snd_card *card, + struct pci_dev *pci, + struct cs4281 **rchip, + int dual_codec) { struct cs4281 *chip; unsigned int tmp; @@ -1779,8 +1779,8 @@ static struct snd_rawmidi_ops snd_cs4281_midi_input = .trigger = snd_cs4281_midi_input_trigger, }; -static int __devinit snd_cs4281_midi(struct cs4281 * chip, int device, - struct snd_rawmidi **rrawmidi) +static int snd_cs4281_midi(struct cs4281 *chip, int device, + struct snd_rawmidi **rrawmidi) { struct snd_rawmidi *rmidi; int err; @@ -1901,8 +1901,8 @@ static void snd_cs4281_opl3_command(struct snd_opl3 *opl3, unsigned short cmd, spin_unlock_irqrestore(&opl3->reg_lock, flags); } -static int __devinit snd_cs4281_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int snd_cs4281_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { static int dev; struct snd_card *card; @@ -1968,7 +1968,7 @@ static int __devinit snd_cs4281_probe(struct pci_dev *pci, return 0; } -static void __devexit snd_cs4281_remove(struct pci_dev *pci) +static void snd_cs4281_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); pci_set_drvdata(pci, NULL); @@ -2095,7 +2095,7 @@ static struct pci_driver cs4281_driver = { .name = KBUILD_MODNAME, .id_table = snd_cs4281_ids, .probe = snd_cs4281_probe, - .remove = __devexit_p(snd_cs4281_remove), + .remove = snd_cs4281_remove, .driver = { .pm = CS4281_PM_OPS, }, diff --git a/sound/pci/cs46xx/cs46xx.c b/sound/pci/cs46xx/cs46xx.c index 575bed0836ff..6b0d8b50a305 100644 --- a/sound/pci/cs46xx/cs46xx.c +++ b/sound/pci/cs46xx/cs46xx.c @@ -73,8 +73,8 @@ static DEFINE_PCI_DEVICE_TABLE(snd_cs46xx_ids) = { MODULE_DEVICE_TABLE(pci, snd_cs46xx_ids); -static int __devinit snd_card_cs46xx_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int snd_card_cs46xx_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { static int dev; struct snd_card *card; @@ -155,7 +155,7 @@ static int __devinit snd_card_cs46xx_probe(struct pci_dev *pci, return 0; } -static void __devexit snd_card_cs46xx_remove(struct pci_dev *pci) +static void snd_card_cs46xx_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); pci_set_drvdata(pci, NULL); @@ -165,7 +165,7 @@ static struct pci_driver cs46xx_driver = { .name = KBUILD_MODNAME, .id_table = snd_cs46xx_ids, .probe = snd_card_cs46xx_probe, - .remove = __devexit_p(snd_card_cs46xx_remove), + .remove = snd_card_cs46xx_remove, #ifdef CONFIG_PM_SLEEP .driver = { .pm = &snd_cs46xx_pm, diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c index a2bb8c91ebe6..1b66efd9b728 100644 --- a/sound/pci/cs46xx/cs46xx_lib.c +++ b/sound/pci/cs46xx/cs46xx_lib.c @@ -1590,7 +1590,7 @@ static struct snd_pcm_ops snd_cs46xx_capture_indirect_ops = { #define MAX_PLAYBACK_CHANNELS 1 #endif -int __devinit snd_cs46xx_pcm(struct snd_cs46xx *chip, int device, struct snd_pcm ** rpcm) +int snd_cs46xx_pcm(struct snd_cs46xx *chip, int device, struct snd_pcm **rpcm) { struct snd_pcm *pcm; int err; @@ -1621,7 +1621,8 @@ int __devinit snd_cs46xx_pcm(struct snd_cs46xx *chip, int device, struct snd_pcm #ifdef CONFIG_SND_CS46XX_NEW_DSP -int __devinit snd_cs46xx_pcm_rear(struct snd_cs46xx *chip, int device, struct snd_pcm ** rpcm) +int snd_cs46xx_pcm_rear(struct snd_cs46xx *chip, int device, + struct snd_pcm **rpcm) { struct snd_pcm *pcm; int err; @@ -1650,7 +1651,8 @@ int __devinit snd_cs46xx_pcm_rear(struct snd_cs46xx *chip, int device, struct sn return 0; } -int __devinit snd_cs46xx_pcm_center_lfe(struct snd_cs46xx *chip, int device, struct snd_pcm ** rpcm) +int snd_cs46xx_pcm_center_lfe(struct snd_cs46xx *chip, int device, + struct snd_pcm **rpcm) { struct snd_pcm *pcm; int err; @@ -1679,7 +1681,8 @@ int __devinit snd_cs46xx_pcm_center_lfe(struct snd_cs46xx *chip, int device, str return 0; } -int __devinit snd_cs46xx_pcm_iec958(struct snd_cs46xx *chip, int device, struct snd_pcm ** rpcm) +int snd_cs46xx_pcm_iec958(struct snd_cs46xx *chip, int device, + struct snd_pcm **rpcm) { struct snd_pcm *pcm; int err; @@ -2092,7 +2095,7 @@ static int snd_cs46xx_spdif_stream_put(struct snd_kcontrol *kcontrol, #endif /* CONFIG_SND_CS46XX_NEW_DSP */ -static struct snd_kcontrol_new snd_cs46xx_controls[] __devinitdata = { +static struct snd_kcontrol_new snd_cs46xx_controls[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "DAC Volume", @@ -2278,7 +2281,7 @@ static void snd_cs46xx_codec_reset (struct snd_ac97 * ac97) } #endif -static int __devinit cs46xx_detect_codec(struct snd_cs46xx *chip, int codec) +static int cs46xx_detect_codec(struct snd_cs46xx *chip, int codec) { int idx, err; struct snd_ac97_template ac97; @@ -2311,7 +2314,7 @@ static int __devinit cs46xx_detect_codec(struct snd_cs46xx *chip, int codec) return -ENXIO; } -int __devinit snd_cs46xx_mixer(struct snd_cs46xx *chip, int spdif_device) +int snd_cs46xx_mixer(struct snd_cs46xx *chip, int spdif_device) { struct snd_card *card = chip->card; struct snd_ctl_elem_id id; @@ -2531,7 +2534,7 @@ static struct snd_rawmidi_ops snd_cs46xx_midi_input = .trigger = snd_cs46xx_midi_input_trigger, }; -int __devinit snd_cs46xx_midi(struct snd_cs46xx *chip, int device, struct snd_rawmidi **rrawmidi) +int snd_cs46xx_midi(struct snd_cs46xx *chip, int device, struct snd_rawmidi **rrawmidi) { struct snd_rawmidi *rmidi; int err; @@ -2613,7 +2616,7 @@ static int snd_cs46xx_gameport_open(struct gameport *gameport, int mode) return 0; } -int __devinit snd_cs46xx_gameport(struct snd_cs46xx *chip) +int snd_cs46xx_gameport(struct snd_cs46xx *chip) { struct gameport *gp; @@ -2649,7 +2652,7 @@ static inline void snd_cs46xx_remove_gameport(struct snd_cs46xx *chip) } } #else -int __devinit snd_cs46xx_gameport(struct snd_cs46xx *chip) { return -ENOSYS; } +int snd_cs46xx_gameport(struct snd_cs46xx *chip) { return -ENOSYS; } static inline void snd_cs46xx_remove_gameport(struct snd_cs46xx *chip) { } #endif /* CONFIG_GAMEPORT */ @@ -2674,7 +2677,7 @@ static struct snd_info_entry_ops snd_cs46xx_proc_io_ops = { .read = snd_cs46xx_io_read, }; -static int __devinit snd_cs46xx_proc_init(struct snd_card *card, struct snd_cs46xx *chip) +static int snd_cs46xx_proc_init(struct snd_card *card, struct snd_cs46xx *chip) { struct snd_info_entry *entry; int idx; @@ -3061,7 +3064,7 @@ static void cs46xx_enable_stream_irqs(struct snd_cs46xx *chip) snd_cs46xx_poke(chip, BA1_CIE, tmp); /* capture interrupt enable */ } -int __devinit snd_cs46xx_start_dsp(struct snd_cs46xx *chip) +int snd_cs46xx_start_dsp(struct snd_cs46xx *chip) { unsigned int tmp; /* @@ -3477,7 +3480,7 @@ struct cs_card_type void (*mixer_init)(struct snd_cs46xx *); }; -static struct cs_card_type __devinitdata cards[] = { +static struct cs_card_type cards[] = { { .vendor = 0x1489, .id = 0x7001, @@ -3717,10 +3720,10 @@ SIMPLE_DEV_PM_OPS(snd_cs46xx_pm, snd_cs46xx_suspend, snd_cs46xx_resume); /* */ -int __devinit snd_cs46xx_create(struct snd_card *card, - struct pci_dev * pci, +int snd_cs46xx_create(struct snd_card *card, + struct pci_dev *pci, int external_amp, int thinkpad, - struct snd_cs46xx ** rchip) + struct snd_cs46xx **rchip) { struct snd_cs46xx *chip; int err, idx; diff --git a/sound/pci/cs5530.c b/sound/pci/cs5530.c index d1cca2831575..dace827b45d1 100644 --- a/sound/pci/cs5530.c +++ b/sound/pci/cs5530.c @@ -88,13 +88,13 @@ static int snd_cs5530_dev_free(struct snd_device *device) return snd_cs5530_free(chip); } -static void __devexit snd_cs5530_remove(struct pci_dev *pci) +static void snd_cs5530_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); pci_set_drvdata(pci, NULL); } -static u8 __devinit snd_cs5530_mixer_read(unsigned long io, u8 reg) +static u8 snd_cs5530_mixer_read(unsigned long io, u8 reg) { outb(reg, io + 4); udelay(20); @@ -103,9 +103,9 @@ static u8 __devinit snd_cs5530_mixer_read(unsigned long io, u8 reg) return reg; } -static int __devinit snd_cs5530_create(struct snd_card *card, - struct pci_dev *pci, - struct snd_cs5530 **rchip) +static int snd_cs5530_create(struct snd_card *card, + struct pci_dev *pci, + struct snd_cs5530 **rchip) { struct snd_cs5530 *chip; unsigned long sb_base; @@ -250,8 +250,8 @@ static int __devinit snd_cs5530_create(struct snd_card *card, return 0; } -static int __devinit snd_cs5530_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int snd_cs5530_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { static int dev; struct snd_card *card; @@ -294,7 +294,7 @@ static struct pci_driver cs5530_driver = { .name = KBUILD_MODNAME, .id_table = snd_cs5530_ids, .probe = snd_cs5530_probe, - .remove = __devexit_p(snd_cs5530_remove), + .remove = snd_cs5530_remove, }; module_pci_driver(cs5530_driver); diff --git a/sound/pci/cs5535audio/cs5535audio.c b/sound/pci/cs5535audio/cs5535audio.c index 4915efa551fc..7e4b13e2d12a 100644 --- a/sound/pci/cs5535audio/cs5535audio.c +++ b/sound/pci/cs5535audio/cs5535audio.c @@ -43,7 +43,7 @@ static char *ac97_quirk; module_param(ac97_quirk, charp, 0444); MODULE_PARM_DESC(ac97_quirk, "AC'97 board specific workarounds."); -static struct ac97_quirk ac97_quirks[] __devinitdata = { +static struct ac97_quirk ac97_quirks[] = { #if 0 /* Not yet confirmed if all 5536 boards are HP only */ { .subvendor = PCI_VENDOR_ID_AMD, @@ -144,7 +144,7 @@ static unsigned short snd_cs5535audio_ac97_codec_read(struct snd_ac97 *ac97, return snd_cs5535audio_codec_read(cs5535au, reg); } -static int __devinit snd_cs5535audio_mixer(struct cs5535audio *cs5535au) +static int snd_cs5535audio_mixer(struct cs5535audio *cs5535au) { struct snd_card *card = cs5535au->card; struct snd_ac97_bus *pbus; @@ -270,9 +270,9 @@ static int snd_cs5535audio_dev_free(struct snd_device *device) return snd_cs5535audio_free(cs5535au); } -static int __devinit snd_cs5535audio_create(struct snd_card *card, - struct pci_dev *pci, - struct cs5535audio **rcs5535au) +static int snd_cs5535audio_create(struct snd_card *card, + struct pci_dev *pci, + struct cs5535audio **rcs5535au) { struct cs5535audio *cs5535au; @@ -338,8 +338,8 @@ pcifail: return err; } -static int __devinit snd_cs5535audio_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int snd_cs5535audio_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { static int dev; struct snd_card *card; @@ -387,7 +387,7 @@ probefail_out: return err; } -static void __devexit snd_cs5535audio_remove(struct pci_dev *pci) +static void snd_cs5535audio_remove(struct pci_dev *pci) { olpc_quirks_cleanup(); snd_card_free(pci_get_drvdata(pci)); @@ -398,7 +398,7 @@ static struct pci_driver cs5535audio_driver = { .name = KBUILD_MODNAME, .id_table = snd_cs5535audio_ids, .probe = snd_cs5535audio_probe, - .remove = __devexit_p(snd_cs5535audio_remove), + .remove = snd_cs5535audio_remove, #ifdef CONFIG_PM_SLEEP .driver = { .pm = &snd_cs5535audio_pm, diff --git a/sound/pci/cs5535audio/cs5535audio.h b/sound/pci/cs5535audio/cs5535audio.h index bb3cc641130c..0579daa62215 100644 --- a/sound/pci/cs5535audio/cs5535audio.h +++ b/sound/pci/cs5535audio/cs5535audio.h @@ -97,10 +97,10 @@ struct cs5535audio { extern const struct dev_pm_ops snd_cs5535audio_pm; #ifdef CONFIG_OLPC -void __devinit olpc_prequirks(struct snd_card *card, - struct snd_ac97_template *ac97); -int __devinit olpc_quirks(struct snd_card *card, struct snd_ac97 *ac97); -void __devexit olpc_quirks_cleanup(void); +void olpc_prequirks(struct snd_card *card, + struct snd_ac97_template *ac97); +int olpc_quirks(struct snd_card *card, struct snd_ac97 *ac97); +void olpc_quirks_cleanup(void); void olpc_analog_input(struct snd_ac97 *ac97, int on); void olpc_mic_bias(struct snd_ac97 *ac97, int on); @@ -133,7 +133,7 @@ static inline void olpc_capture_open(struct snd_ac97 *ac97) { } static inline void olpc_capture_close(struct snd_ac97 *ac97) { } #endif -int __devinit snd_cs5535audio_pcm(struct cs5535audio *cs5535audio); +int snd_cs5535audio_pcm(struct cs5535audio *cs5535audio); #endif /* __SOUND_CS5535AUDIO_H */ diff --git a/sound/pci/cs5535audio/cs5535audio_olpc.c b/sound/pci/cs5535audio/cs5535audio_olpc.c index 50da49be9ae5..da1cb9c4c76c 100644 --- a/sound/pci/cs5535audio/cs5535audio_olpc.c +++ b/sound/pci/cs5535audio/cs5535audio_olpc.c @@ -114,7 +114,7 @@ static int olpc_mic_put(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *v) return 1; } -static struct snd_kcontrol_new olpc_cs5535audio_ctls[] __devinitdata = { +static struct snd_kcontrol_new olpc_cs5535audio_ctls[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "DC Mode Enable", @@ -133,8 +133,8 @@ static struct snd_kcontrol_new olpc_cs5535audio_ctls[] __devinitdata = { }, }; -void __devinit olpc_prequirks(struct snd_card *card, - struct snd_ac97_template *ac97) +void olpc_prequirks(struct snd_card *card, + struct snd_ac97_template *ac97) { if (!machine_is_olpc()) return; @@ -144,7 +144,7 @@ void __devinit olpc_prequirks(struct snd_card *card, ac97->scaps |= AC97_SCAP_INV_EAPD; } -int __devinit olpc_quirks(struct snd_card *card, struct snd_ac97 *ac97) +int olpc_quirks(struct snd_card *card, struct snd_ac97 *ac97) { struct snd_ctl_elem_id elem; int i, err; @@ -185,7 +185,7 @@ int __devinit olpc_quirks(struct snd_card *card, struct snd_ac97 *ac97) return 0; } -void __devexit olpc_quirks_cleanup(void) +void olpc_quirks_cleanup(void) { gpio_free(OLPC_GPIO_MIC_AC); } diff --git a/sound/pci/cs5535audio/cs5535audio_pcm.c b/sound/pci/cs5535audio/cs5535audio_pcm.c index dbf94b189e75..9ab01a7047cf 100644 --- a/sound/pci/cs5535audio/cs5535audio_pcm.c +++ b/sound/pci/cs5535audio/cs5535audio_pcm.c @@ -422,7 +422,7 @@ static struct cs5535audio_dma_ops snd_cs5535audio_capture_dma_ops = { .read_dma_pntr = cs5535audio_capture_read_dma_pntr, }; -int __devinit snd_cs5535audio_pcm(struct cs5535audio *cs5535au) +int snd_cs5535audio_pcm(struct cs5535audio *cs5535au) { struct snd_pcm *pcm; int err; diff --git a/sound/pci/ctxfi/ctatc.c b/sound/pci/ctxfi/ctatc.c index a2f997a9977a..b5fa583a239a 100644 --- a/sound/pci/ctxfi/ctatc.c +++ b/sound/pci/ctxfi/ctatc.c @@ -38,7 +38,7 @@ | (0x10 << 16) \ | ((IEC958_AES3_CON_FS_48000) << 24)) -static struct snd_pci_quirk __devinitdata subsys_20k1_list[] = { +static struct snd_pci_quirk subsys_20k1_list[] = { SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, 0x0022, "SB055x", CTSB055X), SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, 0x002f, "SB055x", CTSB055X), SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, 0x0029, "SB073x", CTSB073X), @@ -48,7 +48,7 @@ static struct snd_pci_quirk __devinitdata subsys_20k1_list[] = { { } /* terminator */ }; -static struct snd_pci_quirk __devinitdata subsys_20k2_list[] = { +static struct snd_pci_quirk subsys_20k2_list[] = { SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB0760, "SB0760", CTSB0760), SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB1270, @@ -1249,7 +1249,7 @@ static int atc_dev_free(struct snd_device *dev) return ct_atc_destroy(atc); } -static int __devinit atc_identify_card(struct ct_atc *atc, unsigned int ssid) +static int atc_identify_card(struct ct_atc *atc, unsigned int ssid) { const struct snd_pci_quirk *p; const struct snd_pci_quirk *list; @@ -1296,7 +1296,7 @@ static int __devinit atc_identify_card(struct ct_atc *atc, unsigned int ssid) return 0; } -int __devinit ct_atc_create_alsa_devs(struct ct_atc *atc) +int ct_atc_create_alsa_devs(struct ct_atc *atc) { enum CTALSADEVS i; int err; @@ -1319,7 +1319,7 @@ int __devinit ct_atc_create_alsa_devs(struct ct_atc *atc) return 0; } -static int __devinit atc_create_hw_devs(struct ct_atc *atc) +static int atc_create_hw_devs(struct ct_atc *atc) { struct hw *hw; struct card_conf info = {0}; @@ -1614,7 +1614,7 @@ static int atc_resume(struct ct_atc *atc) } #endif -static struct ct_atc atc_preset __devinitdata = { +static struct ct_atc atc_preset = { .map_audio_buffer = ct_map_audio_buffer, .unmap_audio_buffer = ct_unmap_audio_buffer, .pcm_playback_prepare = atc_pcm_playback_prepare, @@ -1665,10 +1665,10 @@ static struct ct_atc atc_preset __devinitdata = { * Returns 0 if succeeds, or negative error code if fails. */ -int __devinit ct_atc_create(struct snd_card *card, struct pci_dev *pci, - unsigned int rsr, unsigned int msr, - int chip_type, unsigned int ssid, - struct ct_atc **ratc) +int ct_atc_create(struct snd_card *card, struct pci_dev *pci, + unsigned int rsr, unsigned int msr, + int chip_type, unsigned int ssid, + struct ct_atc **ratc) { struct ct_atc *atc; static struct snd_device_ops ops = { diff --git a/sound/pci/ctxfi/ctatc.h b/sound/pci/ctxfi/ctatc.h index 69b51f9d345e..5f11ca22fcde 100644 --- a/sound/pci/ctxfi/ctatc.h +++ b/sound/pci/ctxfi/ctatc.h @@ -152,9 +152,9 @@ struct ct_atc { }; -int __devinit ct_atc_create(struct snd_card *card, struct pci_dev *pci, - unsigned int rsr, unsigned int msr, int chip_type, - unsigned int subsysid, struct ct_atc **ratc); -int __devinit ct_atc_create_alsa_devs(struct ct_atc *atc); +int ct_atc_create(struct snd_card *card, struct pci_dev *pci, + unsigned int rsr, unsigned int msr, int chip_type, + unsigned int subsysid, struct ct_atc **ratc); +int ct_atc_create_alsa_devs(struct ct_atc *atc); #endif /* CTATC_H */ diff --git a/sound/pci/ctxfi/cthardware.c b/sound/pci/ctxfi/cthardware.c index 8e64f4862e85..110b8ace6d8a 100644 --- a/sound/pci/ctxfi/cthardware.c +++ b/sound/pci/ctxfi/cthardware.c @@ -20,8 +20,8 @@ #include "cthw20k2.h" #include <linux/bug.h> -int __devinit create_hw_obj(struct pci_dev *pci, enum CHIPTYP chip_type, - enum CTCARDS model, struct hw **rhw) +int create_hw_obj(struct pci_dev *pci, enum CHIPTYP chip_type, + enum CTCARDS model, struct hw **rhw) { int err; diff --git a/sound/pci/ctxfi/cthw20k1.c b/sound/pci/ctxfi/cthw20k1.c index 4507f7088b24..6ac40beb49da 100644 --- a/sound/pci/ctxfi/cthw20k1.c +++ b/sound/pci/ctxfi/cthw20k1.c @@ -2171,7 +2171,7 @@ static void hw_write_pci(struct hw *hw, u32 reg, u32 data) &container_of(hw, struct hw20k1, hw)->reg_pci_lock, flags); } -static struct hw ct20k1_preset __devinitdata = { +static struct hw ct20k1_preset = { .irq = -1, .card_init = hw_card_init, @@ -2275,7 +2275,7 @@ static struct hw ct20k1_preset __devinitdata = { .get_wc = get_wc, }; -int __devinit create_20k1_hw_obj(struct hw **rhw) +int create_20k1_hw_obj(struct hw **rhw) { struct hw20k1 *hw20k1; diff --git a/sound/pci/ctxfi/cthw20k2.c b/sound/pci/ctxfi/cthw20k2.c index b9c9349058bc..b1438861d38a 100644 --- a/sound/pci/ctxfi/cthw20k2.c +++ b/sound/pci/ctxfi/cthw20k2.c @@ -2237,7 +2237,7 @@ static void hw_write_20kx(struct hw *hw, u32 reg, u32 data) writel(data, (void *)(hw->mem_base + reg)); } -static struct hw ct20k2_preset __devinitdata = { +static struct hw ct20k2_preset = { .irq = -1, .card_init = hw_card_init, @@ -2345,7 +2345,7 @@ static struct hw ct20k2_preset __devinitdata = { .get_wc = get_wc, }; -int __devinit create_20k2_hw_obj(struct hw **rhw) +int create_20k2_hw_obj(struct hw **rhw) { struct hw20k2 *hw20k2; diff --git a/sound/pci/ctxfi/xfi.c b/sound/pci/ctxfi/xfi.c index 07c07d752fd8..d01ffcb2b2f5 100644 --- a/sound/pci/ctxfi/xfi.c +++ b/sound/pci/ctxfi/xfi.c @@ -56,7 +56,7 @@ static DEFINE_PCI_DEVICE_TABLE(ct_pci_dev_ids) = { }; MODULE_DEVICE_TABLE(pci, ct_pci_dev_ids); -static int __devinit +static int ct_card_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { static int dev; @@ -119,7 +119,7 @@ error: return err; } -static void __devexit ct_card_remove(struct pci_dev *pci) +static void ct_card_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); pci_set_drvdata(pci, NULL); @@ -152,7 +152,7 @@ static struct pci_driver ct_driver = { .name = KBUILD_MODNAME, .id_table = ct_pci_dev_ids, .probe = ct_card_probe, - .remove = __devexit_p(ct_card_remove), + .remove = ct_card_remove, .driver = { .pm = CT_CARD_PM_OPS, }, diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c index abb0b86c41c9..760cbff53210 100644 --- a/sound/pci/echoaudio/echoaudio.c +++ b/sound/pci/echoaudio/echoaudio.c @@ -907,7 +907,7 @@ static int snd_echo_preallocate_pages(struct snd_pcm *pcm, struct device *dev) /*<--snd_echo_probe() */ -static int __devinit snd_echo_new_pcm(struct echoaudio *chip) +static int snd_echo_new_pcm(struct echoaudio *chip) { struct snd_pcm *pcm; int err; @@ -1050,7 +1050,7 @@ static int snd_echo_output_gain_put(struct snd_kcontrol *kcontrol, #ifdef ECHOCARD_HAS_LINE_OUT_GAIN /* On the Mia this one controls the line-out volume */ -static struct snd_kcontrol_new snd_echo_line_output_gain __devinitdata = { +static struct snd_kcontrol_new snd_echo_line_output_gain = { .name = "Line Playback Volume", .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | @@ -1061,7 +1061,7 @@ static struct snd_kcontrol_new snd_echo_line_output_gain __devinitdata = { .tlv = {.p = db_scale_output_gain}, }; #else -static struct snd_kcontrol_new snd_echo_pcm_output_gain __devinitdata = { +static struct snd_kcontrol_new snd_echo_pcm_output_gain = { .name = "PCM Playback Volume", .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, @@ -1131,7 +1131,7 @@ static int snd_echo_input_gain_put(struct snd_kcontrol *kcontrol, static const DECLARE_TLV_DB_SCALE(db_scale_input_gain, -2500, 50, 0); -static struct snd_kcontrol_new snd_echo_line_input_gain __devinitdata = { +static struct snd_kcontrol_new snd_echo_line_input_gain = { .name = "Line Capture Volume", .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, @@ -1195,7 +1195,7 @@ static int snd_echo_output_nominal_put(struct snd_kcontrol *kcontrol, return changed; } -static struct snd_kcontrol_new snd_echo_output_nominal_level __devinitdata = { +static struct snd_kcontrol_new snd_echo_output_nominal_level = { .name = "Line Playback Switch (-10dBV)", .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .info = snd_echo_output_nominal_info, @@ -1261,7 +1261,7 @@ static int snd_echo_input_nominal_put(struct snd_kcontrol *kcontrol, return changed; } -static struct snd_kcontrol_new snd_echo_intput_nominal_level __devinitdata = { +static struct snd_kcontrol_new snd_echo_intput_nominal_level = { .name = "Line Capture Switch (-10dBV)", .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .info = snd_echo_input_nominal_info, @@ -1327,7 +1327,7 @@ static int snd_echo_mixer_put(struct snd_kcontrol *kcontrol, return changed; } -static struct snd_kcontrol_new snd_echo_monitor_mixer __devinitdata = { +static struct snd_kcontrol_new snd_echo_monitor_mixer = { .name = "Monitor Mixer Volume", .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, @@ -1395,7 +1395,7 @@ static int snd_echo_vmixer_put(struct snd_kcontrol *kcontrol, return changed; } -static struct snd_kcontrol_new snd_echo_vmixer __devinitdata = { +static struct snd_kcontrol_new snd_echo_vmixer = { .name = "VMixer Volume", .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, @@ -1490,7 +1490,7 @@ static int snd_echo_digital_mode_put(struct snd_kcontrol *kcontrol, return changed; } -static struct snd_kcontrol_new snd_echo_digital_mode_switch __devinitdata = { +static struct snd_kcontrol_new snd_echo_digital_mode_switch = { .name = "Digital mode Switch", .iface = SNDRV_CTL_ELEM_IFACE_CARD, .info = snd_echo_digital_mode_info, @@ -1547,7 +1547,7 @@ static int snd_echo_spdif_mode_put(struct snd_kcontrol *kcontrol, return 0; } -static struct snd_kcontrol_new snd_echo_spdif_mode_switch __devinitdata = { +static struct snd_kcontrol_new snd_echo_spdif_mode_switch = { .name = "S/PDIF mode Switch", .iface = SNDRV_CTL_ELEM_IFACE_CARD, .info = snd_echo_spdif_mode_info, @@ -1626,7 +1626,7 @@ static int snd_echo_clock_source_put(struct snd_kcontrol *kcontrol, return changed; } -static struct snd_kcontrol_new snd_echo_clock_source_switch __devinitdata = { +static struct snd_kcontrol_new snd_echo_clock_source_switch = { .name = "Sample Clock Source", .iface = SNDRV_CTL_ELEM_IFACE_PCM, .info = snd_echo_clock_source_info, @@ -1669,7 +1669,7 @@ static int snd_echo_phantom_power_put(struct snd_kcontrol *kcontrol, return changed; } -static struct snd_kcontrol_new snd_echo_phantom_power_switch __devinitdata = { +static struct snd_kcontrol_new snd_echo_phantom_power_switch = { .name = "Phantom power Switch", .iface = SNDRV_CTL_ELEM_IFACE_CARD, .info = snd_echo_phantom_power_info, @@ -1712,7 +1712,7 @@ static int snd_echo_automute_put(struct snd_kcontrol *kcontrol, return changed; } -static struct snd_kcontrol_new snd_echo_automute_switch __devinitdata = { +static struct snd_kcontrol_new snd_echo_automute_switch = { .name = "Digital Capture Switch (automute)", .iface = SNDRV_CTL_ELEM_IFACE_CARD, .info = snd_echo_automute_info, @@ -1739,7 +1739,7 @@ static int snd_echo_vumeters_switch_put(struct snd_kcontrol *kcontrol, return 1; } -static struct snd_kcontrol_new snd_echo_vumeters_switch __devinitdata = { +static struct snd_kcontrol_new snd_echo_vumeters_switch = { .name = "VU-meters Switch", .iface = SNDRV_CTL_ELEM_IFACE_CARD, .access = SNDRV_CTL_ELEM_ACCESS_WRITE, @@ -1780,7 +1780,7 @@ static int snd_echo_vumeters_get(struct snd_kcontrol *kcontrol, return 0; } -static struct snd_kcontrol_new snd_echo_vumeters __devinitdata = { +static struct snd_kcontrol_new snd_echo_vumeters = { .name = "VU-meters", .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .access = SNDRV_CTL_ELEM_ACCESS_READ | @@ -1836,7 +1836,7 @@ static int snd_echo_channels_info_get(struct snd_kcontrol *kcontrol, return 0; } -static struct snd_kcontrol_new snd_echo_channels_info __devinitdata = { +static struct snd_kcontrol_new snd_echo_channels_info = { .name = "Channels info", .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, @@ -1940,9 +1940,9 @@ static int snd_echo_dev_free(struct snd_device *device) /* <--snd_echo_probe() */ -static __devinit int snd_echo_create(struct snd_card *card, - struct pci_dev *pci, - struct echoaudio **rchip) +static int snd_echo_create(struct snd_card *card, + struct pci_dev *pci, + struct echoaudio **rchip) { struct echoaudio *chip; int err; @@ -2040,8 +2040,8 @@ static __devinit int snd_echo_create(struct snd_card *card, /* constructor */ -static int __devinit snd_echo_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int snd_echo_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { static int dev; struct snd_card *card; @@ -2316,7 +2316,7 @@ static SIMPLE_DEV_PM_OPS(snd_echo_pm, snd_echo_suspend, snd_echo_resume); #endif /* CONFIG_PM_SLEEP */ -static void __devexit snd_echo_remove(struct pci_dev *pci) +static void snd_echo_remove(struct pci_dev *pci) { struct echoaudio *chip; @@ -2337,7 +2337,7 @@ static struct pci_driver echo_driver = { .name = KBUILD_MODNAME, .id_table = snd_echo_ids, .probe = snd_echo_probe, - .remove = __devexit_p(snd_echo_remove), + .remove = snd_echo_remove, .driver = { .pm = SND_ECHO_PM_OPS, }, diff --git a/sound/pci/echoaudio/echoaudio.h b/sound/pci/echoaudio/echoaudio.h index e158369f5faa..b86b88da81cd 100644 --- a/sound/pci/echoaudio/echoaudio.h +++ b/sound/pci/echoaudio/echoaudio.h @@ -475,8 +475,8 @@ static int enable_midi_input(struct echoaudio *chip, char enable); static void snd_echo_midi_output_trigger( struct snd_rawmidi_substream *substream, int up); static int midi_service_irq(struct echoaudio *chip); -static int __devinit snd_echo_midi_create(struct snd_card *card, - struct echoaudio *chip); +static int snd_echo_midi_create(struct snd_card *card, + struct echoaudio *chip); #endif diff --git a/sound/pci/echoaudio/midi.c b/sound/pci/echoaudio/midi.c index a953d142cb4b..abfd51c2530e 100644 --- a/sound/pci/echoaudio/midi.c +++ b/sound/pci/echoaudio/midi.c @@ -307,8 +307,8 @@ static struct snd_rawmidi_ops snd_echo_midi_output = { /* <--snd_echo_probe() */ -static int __devinit snd_echo_midi_create(struct snd_card *card, - struct echoaudio *chip) +static int snd_echo_midi_create(struct snd_card *card, + struct echoaudio *chip) { int err; diff --git a/sound/pci/emu10k1/emu10k1.c b/sound/pci/emu10k1/emu10k1.c index b7c1875ba90e..8c5010f7889c 100644 --- a/sound/pci/emu10k1/emu10k1.c +++ b/sound/pci/emu10k1/emu10k1.c @@ -99,8 +99,8 @@ static DEFINE_PCI_DEVICE_TABLE(snd_emu10k1_ids) = { MODULE_DEVICE_TABLE(pci, snd_emu10k1_ids); -static int __devinit snd_card_emu10k1_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int snd_card_emu10k1_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { static int dev; struct snd_card *card; @@ -199,7 +199,7 @@ static int __devinit snd_card_emu10k1_probe(struct pci_dev *pci, return err; } -static void __devexit snd_card_emu10k1_remove(struct pci_dev *pci) +static void snd_card_emu10k1_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); pci_set_drvdata(pci, NULL); @@ -215,6 +215,8 @@ static int snd_emu10k1_suspend(struct device *dev) snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); + emu->suspend = 1; + snd_pcm_suspend_all(emu->pcm); snd_pcm_suspend_all(emu->pcm_mic); snd_pcm_suspend_all(emu->pcm_efx); @@ -260,6 +262,8 @@ static int snd_emu10k1_resume(struct device *dev) if (emu->card_capabilities->ca0151_chip) snd_p16v_resume(emu); + emu->suspend = 0; + snd_power_change_state(card, SNDRV_CTL_POWER_D0); return 0; } @@ -274,7 +278,7 @@ static struct pci_driver emu10k1_driver = { .name = KBUILD_MODNAME, .id_table = snd_emu10k1_ids, .probe = snd_card_emu10k1_probe, - .remove = __devexit_p(snd_card_emu10k1_remove), + .remove = snd_card_emu10k1_remove, .driver = { .pm = SND_EMU10K1_PM_OPS, }, diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index c21adb6ef1d5..a7c296a36a17 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -657,22 +657,17 @@ static int snd_emu10k1_cardbus_init(struct snd_emu10k1 *emu) return 0; } -static int snd_emu1010_load_firmware(struct snd_emu10k1 *emu, const char *filename) +static int snd_emu1010_load_firmware(struct snd_emu10k1 *emu) { - int err; int n, i; int reg; int value; unsigned int write_post; unsigned long flags; - const struct firmware *fw_entry; + const struct firmware *fw_entry = emu->firmware; - err = request_firmware(&fw_entry, filename, &emu->pci->dev); - if (err != 0) { - snd_printk(KERN_ERR "firmware: %s not found. Err = %d\n", filename, err); - return err; - } - snd_printk(KERN_INFO "firmware size = 0x%zx\n", fw_entry->size); + if (!fw_entry) + return -EIO; /* The FPGA is a Xilinx Spartan IIE XC2S50E */ /* GPIO7 -> FPGA PGMN @@ -705,7 +700,6 @@ static int snd_emu1010_load_firmware(struct snd_emu10k1 *emu, const char *filena write_post = inl(emu->port + A_IOCFG); spin_unlock_irqrestore(&emu->emu_lock, flags); - release_firmware(fw_entry); return 0; } @@ -720,6 +714,10 @@ static int emu1010_firmware_thread(void *data) msleep_interruptible(1000); if (kthread_should_stop()) break; +#ifdef CONFIG_PM_SLEEP + if (emu->suspend) + continue; +#endif snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &tmp); /* IRQ Status */ snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, ®); /* OPTIONS: Which cards are attached to the EMU */ if (reg & EMU_HANA_OPTION_DOCK_OFFLINE) { @@ -727,22 +725,9 @@ static int emu1010_firmware_thread(void *data) /* Return to Audio Dock programming mode */ snd_printk(KERN_INFO "emu1010: Loading Audio Dock Firmware\n"); snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, EMU_HANA_FPGA_CONFIG_AUDIODOCK); - if (emu->card_capabilities->emu_model == - EMU_MODEL_EMU1010) { - err = snd_emu1010_load_firmware(emu, DOCK_FILENAME); - if (err != 0) - continue; - } else if (emu->card_capabilities->emu_model == - EMU_MODEL_EMU1010B) { - err = snd_emu1010_load_firmware(emu, MICRO_DOCK_FILENAME); - if (err != 0) - continue; - } else if (emu->card_capabilities->emu_model == - EMU_MODEL_EMU1616) { - err = snd_emu1010_load_firmware(emu, MICRO_DOCK_FILENAME); - if (err != 0) - continue; - } + err = snd_emu1010_load_firmware(emu); + if (err != 0) + continue; snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, 0); snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, ®); @@ -807,7 +792,6 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu) unsigned int i; u32 tmp, tmp2, reg; int err; - const char *filename = NULL; snd_printk(KERN_INFO "emu1010: Special config.\n"); /* AC97 2.1, Any 16Meg of 4Gig address, Auto-Mute, EMU32 Slave, @@ -849,31 +833,33 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu) return -ENODEV; } snd_printk(KERN_INFO "emu1010: EMU_HANA_ID = 0x%x\n", reg); - switch (emu->card_capabilities->emu_model) { - case EMU_MODEL_EMU1010: - filename = HANA_FILENAME; - break; - case EMU_MODEL_EMU1010B: - filename = EMU1010B_FILENAME; - break; - case EMU_MODEL_EMU1616: - filename = EMU1010_NOTEBOOK_FILENAME; - break; - case EMU_MODEL_EMU0404: - filename = EMU0404_FILENAME; - break; - default: - filename = NULL; - return -ENODEV; - break; - } - snd_printk(KERN_INFO "emu1010: filename %s testing\n", filename); - err = snd_emu1010_load_firmware(emu, filename); - if (err != 0) { - snd_printk( - KERN_INFO "emu1010: Loading Firmware file %s failed\n", - filename); - return err; + + if (!emu->firmware) { + const char *filename; + switch (emu->card_capabilities->emu_model) { + case EMU_MODEL_EMU1010: + filename = HANA_FILENAME; + break; + case EMU_MODEL_EMU1010B: + filename = EMU1010B_FILENAME; + break; + case EMU_MODEL_EMU1616: + filename = EMU1010_NOTEBOOK_FILENAME; + break; + case EMU_MODEL_EMU0404: + filename = EMU0404_FILENAME; + break; + default: + return -ENODEV; + } + + err = request_firmware(&emu->firmware, filename, &emu->pci->dev); + if (err != 0) { + snd_printk(KERN_ERR "emu1010: firmware: %s not found. Err = %d\n", filename, err); + return err; + } + snd_printk(KERN_INFO "emu1010: firmware file = %s, size = 0x%zx\n", + filename, emu->firmware->size); } /* ID, should read & 0x7f = 0x55 when FPGA programmed. */ @@ -1259,6 +1245,8 @@ static int snd_emu10k1_free(struct snd_emu10k1 *emu) } if (emu->emu1010.firmware_thread) kthread_stop(emu->emu1010.firmware_thread); + if (emu->firmware) + release_firmware(emu->firmware); if (emu->irq >= 0) free_irq(emu->irq, emu); /* remove reserved page */ @@ -1738,7 +1726,7 @@ static struct snd_emu_chip_details emu_chip_details[] = { { } /* terminator */ }; -int __devinit snd_emu10k1_create(struct snd_card *card, +int snd_emu10k1_create(struct snd_card *card, struct pci_dev *pci, unsigned short extin_mask, unsigned short extout_mask, @@ -2025,7 +2013,7 @@ static unsigned char saved_regs_audigy[] = { 0xff /* end */ }; -static int __devinit alloc_pm_buffer(struct snd_emu10k1 *emu) +static int alloc_pm_buffer(struct snd_emu10k1 *emu) { int size; diff --git a/sound/pci/emu10k1/emu10k1_patch.c b/sound/pci/emu10k1/emu10k1_patch.c index e10f027bde03..662a45876a8b 100644 --- a/sound/pci/emu10k1/emu10k1_patch.c +++ b/sound/pci/emu10k1/emu10k1_patch.c @@ -123,7 +123,7 @@ snd_emu10k1_sample_new(struct snd_emux *rec, struct snd_sf_sample *sp, offset += size; data += size; -#if 0 /* not suppported yet */ +#if 0 /* not supported yet */ /* handle reverse (or bidirectional) loop */ if (sp->v.mode_flags & (SNDRV_SFNT_SAMPLE_BIDIR_LOOP|SNDRV_SFNT_SAMPLE_REVERSE_LOOP)) { /* copy loop in reverse */ diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c index 556fd6f456e3..cdff11d48ebd 100644 --- a/sound/pci/emu10k1/emu10k1x.c +++ b/sound/pci/emu10k1/emu10k1x.c @@ -842,7 +842,7 @@ static const struct snd_pcm_chmap_elem clfe_map[] = { { } }; -static int __devinit snd_emu10k1x_pcm(struct emu10k1x *emu, int device, struct snd_pcm **rpcm) +static int snd_emu10k1x_pcm(struct emu10k1x *emu, int device, struct snd_pcm **rpcm) { struct snd_pcm *pcm; const struct snd_pcm_chmap_elem *map = NULL; @@ -902,9 +902,9 @@ static int __devinit snd_emu10k1x_pcm(struct emu10k1x *emu, int device, struct s return 0; } -static int __devinit snd_emu10k1x_create(struct snd_card *card, - struct pci_dev *pci, - struct emu10k1x **rchip) +static int snd_emu10k1x_create(struct snd_card *card, + struct pci_dev *pci, + struct emu10k1x **rchip) { struct emu10k1x *chip; int err; @@ -1066,7 +1066,7 @@ static void snd_emu10k1x_proc_reg_write(struct snd_info_entry *entry, } } -static int __devinit snd_emu10k1x_proc_init(struct emu10k1x * emu) +static int snd_emu10k1x_proc_init(struct emu10k1x *emu) { struct snd_info_entry *entry; @@ -1115,7 +1115,7 @@ static int snd_emu10k1x_shared_spdif_put(struct snd_kcontrol *kcontrol, return change; } -static struct snd_kcontrol_new snd_emu10k1x_shared_spdif __devinitdata = +static struct snd_kcontrol_new snd_emu10k1x_shared_spdif = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Analog/Digital Output Jack", @@ -1194,7 +1194,7 @@ static struct snd_kcontrol_new snd_emu10k1x_spdif_control = .put = snd_emu10k1x_spdif_put }; -static int __devinit snd_emu10k1x_mixer(struct emu10k1x *emu) +static int snd_emu10k1x_mixer(struct emu10k1x *emu) { int err; struct snd_kcontrol *kctl; @@ -1507,8 +1507,9 @@ static void snd_emu10k1x_midi_free(struct snd_rawmidi *rmidi) midi->rmidi = NULL; } -static int __devinit emu10k1x_midi_init(struct emu10k1x *emu, - struct emu10k1x_midi *midi, int device, char *name) +static int emu10k1x_midi_init(struct emu10k1x *emu, + struct emu10k1x_midi *midi, int device, + char *name) { struct snd_rawmidi *rmidi; int err; @@ -1531,7 +1532,7 @@ static int __devinit emu10k1x_midi_init(struct emu10k1x *emu, return 0; } -static int __devinit snd_emu10k1x_midi(struct emu10k1x *emu) +static int snd_emu10k1x_midi(struct emu10k1x *emu) { struct emu10k1x_midi *midi = &emu->midi; int err; @@ -1548,8 +1549,8 @@ static int __devinit snd_emu10k1x_midi(struct emu10k1x *emu) return 0; } -static int __devinit snd_emu10k1x_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int snd_emu10k1x_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { static int dev; struct snd_card *card; @@ -1619,7 +1620,7 @@ static int __devinit snd_emu10k1x_probe(struct pci_dev *pci, return 0; } -static void __devexit snd_emu10k1x_remove(struct pci_dev *pci) +static void snd_emu10k1x_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); pci_set_drvdata(pci, NULL); @@ -1637,7 +1638,7 @@ static struct pci_driver emu10k1x_driver = { .name = KBUILD_MODNAME, .id_table = snd_emu10k1x_ids, .probe = snd_emu10k1x_probe, - .remove = __devexit_p(snd_emu10k1x_remove), + .remove = snd_emu10k1x_remove, }; module_pci_driver(emu10k1x_driver); diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c index 52419959178c..0275209ca82e 100644 --- a/sound/pci/emu10k1/emufx.c +++ b/sound/pci/emu10k1/emufx.c @@ -1073,7 +1073,7 @@ static int snd_emu10k1_ipcm_peek(struct snd_emu10k1 *emu, #define SND_EMU10K1_PLAYBACK_CHANNELS 8 #define SND_EMU10K1_CAPTURE_CHANNELS 4 -static void __devinit +static void snd_emu10k1_init_mono_control(struct snd_emu10k1_fx8010_control_gpr *ctl, const char *name, int gpr, int defval) { @@ -1094,7 +1094,7 @@ snd_emu10k1_init_mono_control(struct snd_emu10k1_fx8010_control_gpr *ctl, } } -static void __devinit +static void snd_emu10k1_init_stereo_control(struct snd_emu10k1_fx8010_control_gpr *ctl, const char *name, int gpr, int defval) { @@ -1116,7 +1116,7 @@ snd_emu10k1_init_stereo_control(struct snd_emu10k1_fx8010_control_gpr *ctl, } } -static void __devinit +static void snd_emu10k1_init_mono_onoff_control(struct snd_emu10k1_fx8010_control_gpr *ctl, const char *name, int gpr, int defval) { @@ -1129,7 +1129,7 @@ snd_emu10k1_init_mono_onoff_control(struct snd_emu10k1_fx8010_control_gpr *ctl, ctl->translation = EMU10K1_GPR_TRANSLATION_ONOFF; } -static void __devinit +static void snd_emu10k1_init_stereo_onoff_control(struct snd_emu10k1_fx8010_control_gpr *ctl, const char *name, int gpr, int defval) { @@ -1168,7 +1168,7 @@ static int snd_emu10k1_audigy_dsp_convert_32_to_2x16( * initial DSP configuration for Audigy */ -static int __devinit _snd_emu10k1_audigy_init_efx(struct snd_emu10k1 *emu) +static int _snd_emu10k1_audigy_init_efx(struct snd_emu10k1 *emu) { int err, i, z, gpr, nctl; int bit_shifter16; @@ -1757,14 +1757,14 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input)) /* when volume = max, then copy only to avoid volume modification */ /* with iMAC0 (negative values) */ -static void __devinit _volume(struct snd_emu10k1_fx8010_code *icode, u32 *ptr, u32 dst, u32 src, u32 vol) +static void _volume(struct snd_emu10k1_fx8010_code *icode, u32 *ptr, u32 dst, u32 src, u32 vol) { OP(icode, ptr, iMAC0, dst, C_00000000, src, vol); OP(icode, ptr, iANDXOR, C_00000000, vol, C_ffffffff, C_7fffffff); OP(icode, ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, C_00000001); OP(icode, ptr, iACC3, dst, src, C_00000000, C_00000000); } -static void __devinit _volume_add(struct snd_emu10k1_fx8010_code *icode, u32 *ptr, u32 dst, u32 src, u32 vol) +static void _volume_add(struct snd_emu10k1_fx8010_code *icode, u32 *ptr, u32 dst, u32 src, u32 vol) { OP(icode, ptr, iANDXOR, C_00000000, vol, C_ffffffff, C_7fffffff); OP(icode, ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, C_00000002); @@ -1772,7 +1772,7 @@ static void __devinit _volume_add(struct snd_emu10k1_fx8010_code *icode, u32 *pt OP(icode, ptr, iSKIP, C_00000000, C_7fffffff, C_7fffffff, C_00000001); OP(icode, ptr, iMAC0, dst, dst, src, vol); } -static void __devinit _volume_out(struct snd_emu10k1_fx8010_code *icode, u32 *ptr, u32 dst, u32 src, u32 vol) +static void _volume_out(struct snd_emu10k1_fx8010_code *icode, u32 *ptr, u32 dst, u32 src, u32 vol) { OP(icode, ptr, iANDXOR, C_00000000, vol, C_ffffffff, C_7fffffff); OP(icode, ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, C_00000002); @@ -1803,7 +1803,7 @@ static void __devinit _volume_out(struct snd_emu10k1_fx8010_code *icode, u32 *pt _SWITCH_NEG(icode, ptr, GPR(dst), GPR(src)) -static int __devinit _snd_emu10k1_init_efx(struct snd_emu10k1 *emu) +static int _snd_emu10k1_init_efx(struct snd_emu10k1 *emu) { int err, i, z, gpr, tmp, playback, capture; u32 ptr; @@ -2373,7 +2373,7 @@ static int __devinit _snd_emu10k1_init_efx(struct snd_emu10k1 *emu) return err; } -int __devinit snd_emu10k1_init_efx(struct snd_emu10k1 *emu) +int snd_emu10k1_init_efx(struct snd_emu10k1 *emu) { spin_lock_init(&emu->fx8010.irq_lock); INIT_LIST_HEAD(&emu->fx8010.gpr_ctl); @@ -2626,7 +2626,8 @@ static int snd_emu10k1_fx8010_release(struct snd_hwdep * hw, struct file *file) return 0; } -int __devinit snd_emu10k1_fx8010_new(struct snd_emu10k1 *emu, int device, struct snd_hwdep ** rhwdep) +int snd_emu10k1_fx8010_new(struct snd_emu10k1 *emu, int device, + struct snd_hwdep **rhwdep) { struct snd_hwdep *hw; int err; @@ -2647,7 +2648,7 @@ int __devinit snd_emu10k1_fx8010_new(struct snd_emu10k1 *emu, int device, struct } #ifdef CONFIG_PM_SLEEP -int __devinit snd_emu10k1_efx_alloc_pm_buffer(struct snd_emu10k1 *emu) +int snd_emu10k1_efx_alloc_pm_buffer(struct snd_emu10k1 *emu) { int len; diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c index 9d890a5aec5a..f6c3da0d377d 100644 --- a/sound/pci/emu10k1/emumixer.c +++ b/sound/pci/emu10k1/emumixer.c @@ -510,7 +510,7 @@ static int snd_emu1010_input_source_put(struct snd_kcontrol *kcontrol, .private_value = chid \ } -static struct snd_kcontrol_new snd_emu1010_output_enum_ctls[] __devinitdata = { +static struct snd_kcontrol_new snd_emu1010_output_enum_ctls[] = { EMU1010_SOURCE_OUTPUT("Dock DAC1 Left Playback Enum", 0), EMU1010_SOURCE_OUTPUT("Dock DAC1 Right Playback Enum", 1), EMU1010_SOURCE_OUTPUT("Dock DAC2 Left Playback Enum", 2), @@ -539,7 +539,7 @@ static struct snd_kcontrol_new snd_emu1010_output_enum_ctls[] __devinitdata = { /* 1616(m) cardbus */ -static struct snd_kcontrol_new snd_emu1616_output_enum_ctls[] __devinitdata = { +static struct snd_kcontrol_new snd_emu1616_output_enum_ctls[] = { EMU1010_SOURCE_OUTPUT("Dock DAC1 Left Playback Enum", 0), EMU1010_SOURCE_OUTPUT("Dock DAC1 Right Playback Enum", 1), EMU1010_SOURCE_OUTPUT("Dock DAC2 Left Playback Enum", 2), @@ -571,7 +571,7 @@ static struct snd_kcontrol_new snd_emu1616_output_enum_ctls[] __devinitdata = { .private_value = chid \ } -static struct snd_kcontrol_new snd_emu1010_input_enum_ctls[] __devinitdata = { +static struct snd_kcontrol_new snd_emu1010_input_enum_ctls[] = { EMU1010_SOURCE_INPUT("DSP 0 Capture Enum", 0), EMU1010_SOURCE_INPUT("DSP 1 Capture Enum", 1), EMU1010_SOURCE_INPUT("DSP 2 Capture Enum", 2), @@ -639,7 +639,7 @@ static int snd_emu1010_adc_pads_put(struct snd_kcontrol *kcontrol, struct snd_ct .private_value = chid \ } -static struct snd_kcontrol_new snd_emu1010_adc_pads[] __devinitdata = { +static struct snd_kcontrol_new snd_emu1010_adc_pads[] = { EMU1010_ADC_PADS("ADC1 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD1), EMU1010_ADC_PADS("ADC2 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD2), EMU1010_ADC_PADS("ADC3 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD3), @@ -687,7 +687,7 @@ static int snd_emu1010_dac_pads_put(struct snd_kcontrol *kcontrol, struct snd_ct .private_value = chid \ } -static struct snd_kcontrol_new snd_emu1010_dac_pads[] __devinitdata = { +static struct snd_kcontrol_new snd_emu1010_dac_pads[] = { EMU1010_DAC_PADS("DAC1 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD1), EMU1010_DAC_PADS("DAC2 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD2), EMU1010_DAC_PADS("DAC3 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD3), @@ -989,7 +989,7 @@ static int snd_audigy_i2c_volume_put(struct snd_kcontrol *kcontrol, } -static struct snd_kcontrol_new snd_audigy_i2c_volume_ctls[] __devinitdata = { +static struct snd_kcontrol_new snd_audigy_i2c_volume_ctls[] = { I2C_VOLUME("Mic Capture Volume", 0), I2C_VOLUME("Line Capture Volume", 0) }; @@ -1621,7 +1621,7 @@ static int snd_emu10k1_shared_spdif_put(struct snd_kcontrol *kcontrol, return change; } -static struct snd_kcontrol_new snd_emu10k1_shared_spdif __devinitdata = +static struct snd_kcontrol_new snd_emu10k1_shared_spdif = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "SB Live Analog/Digital Output Jack", @@ -1630,7 +1630,7 @@ static struct snd_kcontrol_new snd_emu10k1_shared_spdif __devinitdata = .put = snd_emu10k1_shared_spdif_put }; -static struct snd_kcontrol_new snd_audigy_shared_spdif __devinitdata = +static struct snd_kcontrol_new snd_audigy_shared_spdif = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Audigy Analog/Digital Output Jack", @@ -1668,7 +1668,7 @@ static int snd_audigy_capture_boost_put(struct snd_kcontrol *kcontrol, return snd_ac97_update(emu->ac97, AC97_REC_GAIN, val); } -static struct snd_kcontrol_new snd_audigy_capture_boost __devinitdata = +static struct snd_kcontrol_new snd_audigy_capture_boost = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Analog Capture Boost", @@ -1716,8 +1716,8 @@ static int rename_ctl(struct snd_card *card, const char *src, const char *dst) return -ENOENT; } -int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu, - int pcm_device, int multi_device) +int snd_emu10k1_mixer(struct snd_emu10k1 *emu, + int pcm_device, int multi_device) { int err, pcm; struct snd_kcontrol *kctl; diff --git a/sound/pci/emu10k1/emumpu401.c b/sound/pci/emu10k1/emumpu401.c index bab564824efe..1ec91246dfee 100644 --- a/sound/pci/emu10k1/emumpu401.c +++ b/sound/pci/emu10k1/emumpu401.c @@ -326,7 +326,7 @@ static void snd_emu10k1_midi_free(struct snd_rawmidi *rmidi) midi->rmidi = NULL; } -static int __devinit emu10k1_midi_init(struct snd_emu10k1 *emu, struct snd_emu10k1_midi *midi, int device, char *name) +static int emu10k1_midi_init(struct snd_emu10k1 *emu, struct snd_emu10k1_midi *midi, int device, char *name) { struct snd_rawmidi *rmidi; int err; @@ -349,7 +349,7 @@ static int __devinit emu10k1_midi_init(struct snd_emu10k1 *emu, struct snd_emu10 return 0; } -int __devinit snd_emu10k1_midi(struct snd_emu10k1 *emu) +int snd_emu10k1_midi(struct snd_emu10k1 *emu) { struct snd_emu10k1_midi *midi = &emu->midi; int err; @@ -366,7 +366,7 @@ int __devinit snd_emu10k1_midi(struct snd_emu10k1 *emu) return 0; } -int __devinit snd_emu10k1_audigy_midi(struct snd_emu10k1 *emu) +int snd_emu10k1_audigy_midi(struct snd_emu10k1 *emu) { struct snd_emu10k1_midi *midi; int err; diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c index 0e6664fa6cd9..748a286277eb 100644 --- a/sound/pci/emu10k1/emupcm.c +++ b/sound/pci/emu10k1/emupcm.c @@ -1391,7 +1391,7 @@ static struct snd_pcm_ops snd_emu10k1_efx_playback_ops = { .page = snd_pcm_sgbuf_ops_page, }; -int __devinit snd_emu10k1_pcm(struct snd_emu10k1 * emu, int device, struct snd_pcm ** rpcm) +int snd_emu10k1_pcm(struct snd_emu10k1 *emu, int device, struct snd_pcm **rpcm) { struct snd_pcm *pcm; struct snd_pcm_substream *substream; @@ -1426,7 +1426,8 @@ int __devinit snd_emu10k1_pcm(struct snd_emu10k1 * emu, int device, struct snd_p return 0; } -int __devinit snd_emu10k1_pcm_multi(struct snd_emu10k1 * emu, int device, struct snd_pcm ** rpcm) +int snd_emu10k1_pcm_multi(struct snd_emu10k1 *emu, int device, + struct snd_pcm **rpcm) { struct snd_pcm *pcm; struct snd_pcm_substream *substream; @@ -1469,7 +1470,8 @@ static struct snd_pcm_ops snd_emu10k1_capture_mic_ops = { .pointer = snd_emu10k1_capture_pointer, }; -int __devinit snd_emu10k1_pcm_mic(struct snd_emu10k1 * emu, int device, struct snd_pcm ** rpcm) +int snd_emu10k1_pcm_mic(struct snd_emu10k1 *emu, int device, + struct snd_pcm **rpcm) { struct snd_pcm *pcm; int err; @@ -1810,7 +1812,8 @@ static struct snd_pcm_ops snd_emu10k1_fx8010_playback_ops = { .ack = snd_emu10k1_fx8010_playback_transfer, }; -int __devinit snd_emu10k1_pcm_efx(struct snd_emu10k1 * emu, int device, struct snd_pcm ** rpcm) +int snd_emu10k1_pcm_efx(struct snd_emu10k1 *emu, int device, + struct snd_pcm **rpcm) { struct snd_pcm *pcm; struct snd_kcontrol *kctl; diff --git a/sound/pci/emu10k1/emuproc.c b/sound/pci/emu10k1/emuproc.c index bc38dd4d071f..2ca9f2e93139 100644 --- a/sound/pci/emu10k1/emuproc.c +++ b/sound/pci/emu10k1/emuproc.c @@ -577,7 +577,7 @@ static struct snd_info_entry_ops snd_emu10k1_proc_ops_fx8010 = { .read = snd_emu10k1_fx8010_read, }; -int __devinit snd_emu10k1_proc_init(struct snd_emu10k1 * emu) +int snd_emu10k1_proc_init(struct snd_emu10k1 *emu) { struct snd_info_entry *entry; #ifdef CONFIG_SND_DEBUG diff --git a/sound/pci/emu10k1/p16v.c b/sound/pci/emu10k1/p16v.c index 88cec6b7dd41..7e2025cd6d9c 100644 --- a/sound/pci/emu10k1/p16v.c +++ b/sound/pci/emu10k1/p16v.c @@ -637,7 +637,7 @@ int snd_p16v_free(struct snd_emu10k1 *chip) return 0; } -int __devinit snd_p16v_pcm(struct snd_emu10k1 *emu, int device, struct snd_pcm **rpcm) +int snd_p16v_pcm(struct snd_emu10k1 *emu, int device, struct snd_pcm **rpcm) { struct snd_pcm *pcm; struct snd_pcm_substream *substream; @@ -854,7 +854,7 @@ static const DECLARE_TLV_DB_SCALE(snd_p16v_db_scale1, -5175, 25, 1); .private_value = ((xreg) | ((xhl) << 8)) \ } -static struct snd_kcontrol_new p16v_mixer_controls[] __devinitdata = { +static struct snd_kcontrol_new p16v_mixer_controls[] = { P16V_VOL("HD Analog Front Playback Volume", PLAYBACK_VOLUME_MIXER9, 0), P16V_VOL("HD Analog Rear Playback Volume", PLAYBACK_VOLUME_MIXER10, 1), P16V_VOL("HD Analog Center/LFE Playback Volume", PLAYBACK_VOLUME_MIXER9, 1), @@ -880,7 +880,7 @@ static struct snd_kcontrol_new p16v_mixer_controls[] __devinitdata = { }; -int __devinit snd_p16v_mixer(struct snd_emu10k1 *emu) +int snd_p16v_mixer(struct snd_emu10k1 *emu) { int i, err; struct snd_card *card = emu->card; @@ -897,7 +897,7 @@ int __devinit snd_p16v_mixer(struct snd_emu10k1 *emu) #define NUM_CHS 1 /* up to 4, but only first channel is used */ -int __devinit snd_p16v_alloc_pm_buffer(struct snd_emu10k1 *emu) +int snd_p16v_alloc_pm_buffer(struct snd_emu10k1 *emu) { emu->p16v_saved = vmalloc(NUM_CHS * 4 * 0x80); if (! emu->p16v_saved) diff --git a/sound/pci/emu10k1/timer.c b/sound/pci/emu10k1/timer.c index 72321e946ccc..b69a7f8a216c 100644 --- a/sound/pci/emu10k1/timer.c +++ b/sound/pci/emu10k1/timer.c @@ -75,7 +75,7 @@ static struct snd_timer_hardware snd_emu10k1_timer_hw = { .precise_resolution = snd_emu10k1_timer_precise_resolution, }; -int __devinit snd_emu10k1_timer(struct snd_emu10k1 *emu, int device) +int snd_emu10k1_timer(struct snd_emu10k1 *emu, int device) { struct snd_timer *timer = NULL; struct snd_timer_id tid; diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c index 5674cc316530..db2dc835171d 100644 --- a/sound/pci/ens1370.c +++ b/sound/pci/ens1370.c @@ -1268,8 +1268,8 @@ static const struct snd_pcm_chmap_elem surround_map[] = { { } }; -static int __devinit snd_ensoniq_pcm(struct ensoniq * ensoniq, int device, - struct snd_pcm ** rpcm) +static int snd_ensoniq_pcm(struct ensoniq *ensoniq, int device, + struct snd_pcm **rpcm) { struct snd_pcm *pcm; int err; @@ -1310,8 +1310,8 @@ static int __devinit snd_ensoniq_pcm(struct ensoniq * ensoniq, int device, return 0; } -static int __devinit snd_ensoniq_pcm2(struct ensoniq * ensoniq, int device, - struct snd_pcm ** rpcm) +static int snd_ensoniq_pcm2(struct ensoniq *ensoniq, int device, + struct snd_pcm **rpcm) { struct snd_pcm *pcm; int err; @@ -1484,7 +1484,7 @@ static int snd_es1371_spdif_put(struct snd_kcontrol *kcontrol, /* spdif controls */ -static struct snd_kcontrol_new snd_es1371_mixer_spdif[] __devinitdata = { +static struct snd_kcontrol_new snd_es1371_mixer_spdif[] = { ES1371_SPDIF(SNDRV_CTL_NAME_IEC958("",PLAYBACK,SWITCH)), { .iface = SNDRV_CTL_ELEM_IFACE_PCM, @@ -1546,7 +1546,7 @@ static int snd_es1373_rear_put(struct snd_kcontrol *kcontrol, return change; } -static struct snd_kcontrol_new snd_ens1373_rear __devinitdata = +static struct snd_kcontrol_new snd_ens1373_rear = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "AC97 2ch->4ch Copy Switch", @@ -1591,7 +1591,7 @@ static int snd_es1373_line_put(struct snd_kcontrol *kcontrol, return changed; } -static struct snd_kcontrol_new snd_ens1373_line __devinitdata = +static struct snd_kcontrol_new snd_ens1373_line = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Line In->Rear Out Switch", @@ -1625,7 +1625,7 @@ static int es1371_quirk_lookup(struct ensoniq *ensoniq, return 0; } -static struct es1371_quirk es1371_spdif_present[] __devinitdata = { +static struct es1371_quirk es1371_spdif_present[] = { { .vid = PCI_VENDOR_ID_ENSONIQ, .did = PCI_DEVICE_ID_ENSONIQ_CT5880, .rev = CT5880REV_CT5880_C }, { .vid = PCI_VENDOR_ID_ENSONIQ, .did = PCI_DEVICE_ID_ENSONIQ_CT5880, .rev = CT5880REV_CT5880_D }, { .vid = PCI_VENDOR_ID_ENSONIQ, .did = PCI_DEVICE_ID_ENSONIQ_CT5880, .rev = CT5880REV_CT5880_E }, @@ -1634,14 +1634,14 @@ static struct es1371_quirk es1371_spdif_present[] __devinitdata = { { .vid = PCI_ANY_ID, .did = PCI_ANY_ID } }; -static struct snd_pci_quirk ens1373_line_quirk[] __devinitdata = { +static struct snd_pci_quirk ens1373_line_quirk[] = { SND_PCI_QUIRK_ID(0x1274, 0x2000), /* GA-7DXR */ SND_PCI_QUIRK_ID(0x1458, 0xa000), /* GA-8IEXP */ { } /* end */ }; -static int __devinit snd_ensoniq_1371_mixer(struct ensoniq *ensoniq, - int has_spdif, int has_line) +static int snd_ensoniq_1371_mixer(struct ensoniq *ensoniq, + int has_spdif, int has_line) { struct snd_card *card = ensoniq->card; struct snd_ac97_bus *pbus; @@ -1749,7 +1749,7 @@ static int snd_ensoniq_control_put(struct snd_kcontrol *kcontrol, * ENS1370 mixer */ -static struct snd_kcontrol_new snd_es1370_controls[2] __devinitdata = { +static struct snd_kcontrol_new snd_es1370_controls[2] = { ENSONIQ_CONTROL("PCM 0 Output also on Line-In Jack", ES_1370_XCTL0), ENSONIQ_CONTROL("Mic +5V bias", ES_1370_XCTL1) }; @@ -1762,7 +1762,7 @@ static void snd_ensoniq_mixer_free_ak4531(struct snd_ak4531 *ak4531) ensoniq->u.es1370.ak4531 = NULL; } -static int __devinit snd_ensoniq_1370_mixer(struct ensoniq * ensoniq) +static int snd_ensoniq_1370_mixer(struct ensoniq *ensoniq) { struct snd_card *card = ensoniq->card; struct snd_ak4531 ak4531; @@ -1796,7 +1796,7 @@ static int __devinit snd_ensoniq_1370_mixer(struct ensoniq * ensoniq) #ifdef SUPPORT_JOYSTICK #ifdef CHIP1371 -static int __devinit snd_ensoniq_get_joystick_port(int dev) +static int snd_ensoniq_get_joystick_port(int dev) { switch (joystick_port[dev]) { case 0: /* disabled */ @@ -1819,7 +1819,7 @@ static inline int snd_ensoniq_get_joystick_port(int dev) } #endif -static int __devinit snd_ensoniq_create_gameport(struct ensoniq *ensoniq, int dev) +static int snd_ensoniq_create_gameport(struct ensoniq *ensoniq, int dev) { struct gameport *gp; int io_port; @@ -1913,7 +1913,7 @@ static void snd_ensoniq_proc_read(struct snd_info_entry *entry, #endif } -static void __devinit snd_ensoniq_proc_init(struct ensoniq * ensoniq) +static void snd_ensoniq_proc_init(struct ensoniq *ensoniq) { struct snd_info_entry *entry; @@ -1960,7 +1960,7 @@ static int snd_ensoniq_dev_free(struct snd_device *device) } #ifdef CHIP1371 -static struct snd_pci_quirk es1371_amplifier_hack[] __devinitdata = { +static struct snd_pci_quirk es1371_amplifier_hack[] = { SND_PCI_QUIRK_ID(0x107b, 0x2150), /* Gateway Solo 2150 */ SND_PCI_QUIRK_ID(0x13bd, 0x100c), /* EV1938 on Mebius PC-MJ100V */ SND_PCI_QUIRK_ID(0x1102, 0x5938), /* Targa Xtender300 */ @@ -2106,9 +2106,9 @@ static SIMPLE_DEV_PM_OPS(snd_ensoniq_pm, snd_ensoniq_suspend, snd_ensoniq_resume #define SND_ENSONIQ_PM_OPS NULL #endif /* CONFIG_PM_SLEEP */ -static int __devinit snd_ensoniq_create(struct snd_card *card, - struct pci_dev *pci, - struct ensoniq ** rensoniq) +static int snd_ensoniq_create(struct snd_card *card, + struct pci_dev *pci, + struct ensoniq **rensoniq) { struct ensoniq *ensoniq; int err; @@ -2361,8 +2361,8 @@ static struct snd_rawmidi_ops snd_ensoniq_midi_input = .trigger = snd_ensoniq_midi_input_trigger, }; -static int __devinit snd_ensoniq_midi(struct ensoniq * ensoniq, int device, - struct snd_rawmidi **rrawmidi) +static int snd_ensoniq_midi(struct ensoniq *ensoniq, int device, + struct snd_rawmidi **rrawmidi) { struct snd_rawmidi *rmidi; int err; @@ -2422,8 +2422,8 @@ static irqreturn_t snd_audiopci_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static int __devinit snd_audiopci_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int snd_audiopci_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { static int dev; struct snd_card *card; @@ -2494,7 +2494,7 @@ static int __devinit snd_audiopci_probe(struct pci_dev *pci, return 0; } -static void __devexit snd_audiopci_remove(struct pci_dev *pci) +static void snd_audiopci_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); pci_set_drvdata(pci, NULL); @@ -2504,7 +2504,7 @@ static struct pci_driver ens137x_driver = { .name = KBUILD_MODNAME, .id_table = snd_audiopci_ids, .probe = snd_audiopci_probe, - .remove = __devexit_p(snd_audiopci_remove), + .remove = snd_audiopci_remove, .driver = { .pm = SND_ENSONIQ_PM_OPS, }, diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c index 394c5d413530..8423403954ab 100644 --- a/sound/pci/es1938.c +++ b/sound/pci/es1938.c @@ -1027,7 +1027,7 @@ static struct snd_pcm_ops snd_es1938_capture_ops = { .copy = snd_es1938_capture_copy, }; -static int __devinit snd_es1938_new_pcm(struct es1938 *chip, int device) +static int snd_es1938_new_pcm(struct es1938 *chip, int device) { struct snd_pcm *pcm; int err; @@ -1539,7 +1539,7 @@ static SIMPLE_DEV_PM_OPS(es1938_pm, es1938_suspend, es1938_resume); #endif /* CONFIG_PM_SLEEP */ #ifdef SUPPORT_JOYSTICK -static int __devinit snd_es1938_create_gameport(struct es1938 *chip) +static int snd_es1938_create_gameport(struct es1938 *chip) { struct gameport *gp; @@ -1594,9 +1594,9 @@ static int snd_es1938_dev_free(struct snd_device *device) return snd_es1938_free(chip); } -static int __devinit snd_es1938_create(struct snd_card *card, - struct pci_dev * pci, - struct es1938 ** rchip) +static int snd_es1938_create(struct snd_card *card, + struct pci_dev *pci, + struct es1938 **rchip) { struct es1938 *chip; int err; @@ -1754,7 +1754,7 @@ static irqreturn_t snd_es1938_interrupt(int irq, void *dev_id) #define ES1938_DMA_SIZE 64 -static int __devinit snd_es1938_mixer(struct es1938 *chip) +static int snd_es1938_mixer(struct es1938 *chip) { struct snd_card *card; unsigned int idx; @@ -1792,8 +1792,8 @@ static int __devinit snd_es1938_mixer(struct es1938 *chip) } -static int __devinit snd_es1938_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int snd_es1938_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { static int dev; struct snd_card *card; @@ -1878,7 +1878,7 @@ static int __devinit snd_es1938_probe(struct pci_dev *pci, return 0; } -static void __devexit snd_es1938_remove(struct pci_dev *pci) +static void snd_es1938_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); pci_set_drvdata(pci, NULL); @@ -1888,7 +1888,7 @@ static struct pci_driver es1938_driver = { .name = KBUILD_MODNAME, .id_table = snd_es1938_ids, .probe = snd_es1938_probe, - .remove = __devexit_p(snd_es1938_remove), + .remove = snd_es1938_remove, .driver = { .pm = ES1938_PM_OPS, }, diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c index 7266020c16cb..a1f32b5ae0d1 100644 --- a/sound/pci/es1968.c +++ b/sound/pci/es1968.c @@ -1429,7 +1429,7 @@ static void snd_es1968_free_dmabuf(struct es1968 *chip) } } -static int __devinit +static int snd_es1968_init_dmabuf(struct es1968 *chip) { int err; @@ -1704,7 +1704,7 @@ static struct snd_pcm_ops snd_es1968_capture_ops = { */ #define CLOCK_MEASURE_BUFSIZE 16768 /* enough large for a single shot */ -static void __devinit es1968_measure_clock(struct es1968 *chip) +static void es1968_measure_clock(struct es1968 *chip) { int i, apu; unsigned int pa, offset, t; @@ -1806,7 +1806,7 @@ static void snd_es1968_pcm_free(struct snd_pcm *pcm) esm->pcm = NULL; } -static int __devinit +static int snd_es1968_pcm(struct es1968 *chip, int device) { struct snd_pcm *pcm; @@ -2016,7 +2016,7 @@ static irqreturn_t snd_es1968_interrupt(int irq, void *dev_id) * Mixer stuff */ -static int __devinit +static int snd_es1968_mixer(struct es1968 *chip) { struct snd_ac97_bus *pbus; @@ -2291,7 +2291,7 @@ static void snd_es1968_chip_init(struct es1968 *chip) outb(0x88, iobase+0x1f); /* it appears some maestros (dell 7500) only work if these are set, - regardless of wether we use the assp or not. */ + regardless of whether we use the assp or not. */ outb(0, iobase + ASSP_CONTROL_B); outb(3, iobase + ASSP_CONTROL_A); /* M: Reserved bits... */ @@ -2465,7 +2465,7 @@ static SIMPLE_DEV_PM_OPS(es1968_pm, es1968_suspend, es1968_resume); #ifdef SUPPORT_JOYSTICK #define JOYSTICK_ADDR 0x200 -static int __devinit snd_es1968_create_gameport(struct es1968 *chip, int dev) +static int snd_es1968_create_gameport(struct es1968 *chip, int dev) { struct gameport *gp; struct resource *r; @@ -2516,7 +2516,7 @@ static inline void snd_es1968_free_gameport(struct es1968 *chip) { } #endif #ifdef CONFIG_SND_ES1968_INPUT -static int __devinit snd_es1968_input_register(struct es1968 *chip) +static int snd_es1968_input_register(struct es1968 *chip) { struct input_dev *input_dev; int err; @@ -2653,7 +2653,7 @@ struct ess_device_list { unsigned short vendor; /* subsystem vendor id */ }; -static struct ess_device_list pm_whitelist[] __devinitdata = { +static struct ess_device_list pm_whitelist[] = { { TYPE_MAESTRO2E, 0x0e11 }, /* Compaq Armada */ { TYPE_MAESTRO2E, 0x1028 }, { TYPE_MAESTRO2E, 0x103c }, @@ -2664,19 +2664,19 @@ static struct ess_device_list pm_whitelist[] __devinitdata = { { TYPE_MAESTRO2, 0x125d }, /* a PCI card, e.g. SF64-PCE2 */ }; -static struct ess_device_list mpu_blacklist[] __devinitdata = { +static struct ess_device_list mpu_blacklist[] = { { TYPE_MAESTRO2, 0x125d }, }; -static int __devinit snd_es1968_create(struct snd_card *card, - struct pci_dev *pci, - int total_bufsize, - int play_streams, - int capt_streams, - int chip_type, - int do_pm, - int radio_nr, - struct es1968 **chip_ret) +static int snd_es1968_create(struct snd_card *card, + struct pci_dev *pci, + int total_bufsize, + int play_streams, + int capt_streams, + int chip_type, + int do_pm, + int radio_nr, + struct es1968 **chip_ret) { static struct snd_device_ops ops = { .dev_free = snd_es1968_dev_free, @@ -2795,8 +2795,8 @@ static int __devinit snd_es1968_create(struct snd_card *card, /* */ -static int __devinit snd_es1968_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int snd_es1968_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { static int dev; struct snd_card *card; @@ -2906,7 +2906,7 @@ static int __devinit snd_es1968_probe(struct pci_dev *pci, return 0; } -static void __devexit snd_es1968_remove(struct pci_dev *pci) +static void snd_es1968_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); pci_set_drvdata(pci, NULL); @@ -2916,7 +2916,7 @@ static struct pci_driver es1968_driver = { .name = KBUILD_MODNAME, .id_table = snd_es1968_ids, .probe = snd_es1968_probe, - .remove = __devexit_p(snd_es1968_remove), + .remove = snd_es1968_remove, .driver = { .pm = ES1968_PM_OPS, }, diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c index c5806f89be1e..4f07fda5adf2 100644 --- a/sound/pci/fm801.c +++ b/sound/pci/fm801.c @@ -689,7 +689,7 @@ static struct snd_pcm_ops snd_fm801_capture_ops = { .pointer = snd_fm801_capture_pointer, }; -static int __devinit snd_fm801_pcm(struct fm801 *chip, int device, struct snd_pcm ** rpcm) +static int snd_fm801_pcm(struct fm801 *chip, int device, struct snd_pcm **rpcm) { struct snd_pcm *pcm; int err; @@ -984,7 +984,7 @@ static const DECLARE_TLV_DB_SCALE(db_scale_dsp, -3450, 150, 0); #define FM801_CONTROLS ARRAY_SIZE(snd_fm801_controls) -static struct snd_kcontrol_new snd_fm801_controls[] __devinitdata = { +static struct snd_kcontrol_new snd_fm801_controls[] = { FM801_DOUBLE_TLV("Wave Playback Volume", FM801_PCM_VOL, 0, 8, 31, 1, db_scale_dsp), FM801_SINGLE("Wave Playback Switch", FM801_PCM_VOL, 15, 1, 1), @@ -1005,7 +1005,7 @@ FM801_SINGLE("FM Playback Switch", FM801_FM_VOL, 15, 1, 1), #define FM801_CONTROLS_MULTI ARRAY_SIZE(snd_fm801_controls_multi) -static struct snd_kcontrol_new snd_fm801_controls_multi[] __devinitdata = { +static struct snd_kcontrol_new snd_fm801_controls_multi[] = { FM801_SINGLE("AC97 2ch->4ch Copy Switch", FM801_CODEC_CTRL, 7, 1, 0), FM801_SINGLE("AC97 18-bit Switch", FM801_CODEC_CTRL, 10, 1, 0), FM801_SINGLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH), FM801_I2S_MODE, 8, 1, 0), @@ -1030,7 +1030,7 @@ static void snd_fm801_mixer_free_ac97(struct snd_ac97 *ac97) } } -static int __devinit snd_fm801_mixer(struct fm801 *chip) +static int snd_fm801_mixer(struct fm801 *chip) { struct snd_ac97_template ac97; unsigned int i; @@ -1191,11 +1191,11 @@ static int snd_fm801_dev_free(struct snd_device *device) return snd_fm801_free(chip); } -static int __devinit snd_fm801_create(struct snd_card *card, - struct pci_dev * pci, - int tea575x_tuner, - int radio_nr, - struct fm801 ** rchip) +static int snd_fm801_create(struct snd_card *card, + struct pci_dev *pci, + int tea575x_tuner, + int radio_nr, + struct fm801 **rchip) { struct fm801 *chip; int err; @@ -1296,8 +1296,8 @@ static int __devinit snd_fm801_create(struct snd_card *card, return 0; } -static int __devinit snd_card_fm801_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int snd_card_fm801_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { static int dev; struct snd_card *card; @@ -1367,7 +1367,7 @@ static int __devinit snd_card_fm801_probe(struct pci_dev *pci, return 0; } -static void __devexit snd_card_fm801_remove(struct pci_dev *pci) +static void snd_card_fm801_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); pci_set_drvdata(pci, NULL); @@ -1439,7 +1439,7 @@ static struct pci_driver fm801_driver = { .name = KBUILD_MODNAME, .id_table = snd_fm801_ids, .probe = snd_card_fm801_probe, - .remove = __devexit_p(snd_card_fm801_remove), + .remove = snd_card_fm801_remove, .driver = { .pm = SND_FM801_PM_OPS, }, diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig index 11b4b77a8215..80a7d44bcf81 100644 --- a/sound/pci/hda/Kconfig +++ b/sound/pci/hda/Kconfig @@ -40,8 +40,8 @@ config SND_HDA_HWDEP with codecs for debugging purposes. config SND_HDA_RECONFIG - bool "Allow dynamic codec reconfiguration (EXPERIMENTAL)" - depends on SND_HDA_HWDEP && EXPERIMENTAL + bool "Allow dynamic codec reconfiguration" + depends on SND_HDA_HWDEP help Say Y here to enable the HD-audio codec re-configuration feature. This adds the sysfs interfaces to allow user to clear the whole @@ -75,7 +75,6 @@ config SND_HDA_INPUT_JACK config SND_HDA_PATCH_LOADER bool "Support initialization patch loading for HD-audio" - depends on EXPERIMENTAL select FW_LOADER select SND_HDA_HWDEP select SND_HDA_RECONFIG @@ -90,6 +89,7 @@ config SND_HDA_PATCH_LOADER config SND_HDA_CODEC_REALTEK bool "Build Realtek HD-audio codec support" default y + select SND_HDA_GENERIC help Say Y here to include Realtek HD-audio codec support in snd-hda-intel driver, such as ALC880. @@ -102,6 +102,7 @@ config SND_HDA_CODEC_REALTEK config SND_HDA_CODEC_ANALOG bool "Build Analog Device HD-audio codec support" default y + select SND_HDA_GENERIC help Say Y here to include Analog Device HD-audio codec support in snd-hda-intel driver, such as AD1986A. @@ -114,6 +115,7 @@ config SND_HDA_CODEC_ANALOG config SND_HDA_CODEC_SIGMATEL bool "Build IDT/Sigmatel HD-audio codec support" default y + select SND_HDA_GENERIC help Say Y here to include IDT (Sigmatel) HD-audio codec support in snd-hda-intel driver, such as STAC9200. @@ -126,6 +128,7 @@ config SND_HDA_CODEC_SIGMATEL config SND_HDA_CODEC_VIA bool "Build VIA HD-audio codec support" default y + select SND_HDA_GENERIC help Say Y here to include VIA HD-audio codec support in snd-hda-intel driver, such as VT1708. @@ -151,8 +154,8 @@ config SND_HDA_CODEC_HDMI config SND_HDA_CODEC_CIRRUS bool "Build Cirrus Logic codec support" - depends on SND_HDA_INTEL default y + select SND_HDA_GENERIC help Say Y here to include Cirrus Logic codec support in snd-hda-intel driver, such as CS4206. @@ -165,6 +168,7 @@ config SND_HDA_CODEC_CIRRUS config SND_HDA_CODEC_CONEXANT bool "Build Conexant HD-audio codec support" default y + select SND_HDA_GENERIC help Say Y here to include Conexant HD-audio codec support in snd-hda-intel driver, such as CX20549. @@ -176,8 +180,8 @@ config SND_HDA_CODEC_CONEXANT config SND_HDA_CODEC_CA0110 bool "Build Creative CA0110-IBG codec support" - depends on SND_HDA_INTEL default y + select SND_HDA_GENERIC help Say Y here to include Creative CA0110-IBG codec support in snd-hda-intel driver, found on some Creative X-Fi cards. @@ -189,7 +193,6 @@ config SND_HDA_CODEC_CA0110 config SND_HDA_CODEC_CA0132 bool "Build Creative CA0132 codec support" - depends on SND_HDA_INTEL default y help Say Y here to include Creative CA0132 codec support in @@ -214,6 +217,7 @@ config SND_HDA_CODEC_CA0132_DSP config SND_HDA_CODEC_CMEDIA bool "Build C-Media HD-audio codec support" default y + select SND_HDA_GENERIC help Say Y here to include C-Media HD-audio codec support in snd-hda-intel driver, such as CMI9880. diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile index bd4149f1aaf4..24a251497a1f 100644 --- a/sound/pci/hda/Makefile +++ b/sound/pci/hda/Makefile @@ -8,6 +8,7 @@ snd-hda-codec-$(CONFIG_SND_HDA_INPUT_BEEP) += hda_beep.o # for trace-points CFLAGS_hda_codec.o := -I$(src) +CFLAGS_hda_intel.o := -I$(src) snd-hda-codec-realtek-objs := patch_realtek.o snd-hda-codec-cmedia-objs := patch_cmedia.o diff --git a/sound/pci/hda/hda_auto_parser.c b/sound/pci/hda/hda_auto_parser.c index 4ec6dc88b7f8..a3ea76a4c9d2 100644 --- a/sound/pci/hda/hda_auto_parser.c +++ b/sound/pci/hda/hda_auto_parser.c @@ -11,6 +11,7 @@ #include <linux/slab.h> #include <linux/export.h> +#include <linux/sort.h> #include <sound/core.h> #include "hda_codec.h" #include "hda_local.h" @@ -30,29 +31,30 @@ static int is_in_nid_list(hda_nid_t nid, const hda_nid_t *list) return 0; } +/* a pair of input pin and its sequence */ +struct auto_out_pin { + hda_nid_t pin; + short seq; +}; + +static int compare_seq(const void *ap, const void *bp) +{ + const struct auto_out_pin *a = ap; + const struct auto_out_pin *b = bp; + return (int)(a->seq - b->seq); +} /* * Sort an associated group of pins according to their sequence numbers. + * then store it to a pin array. */ -static void sort_pins_by_sequence(hda_nid_t *pins, short *sequences, +static void sort_pins_by_sequence(hda_nid_t *pins, struct auto_out_pin *list, int num_pins) { - int i, j; - short seq; - hda_nid_t nid; - - for (i = 0; i < num_pins; i++) { - for (j = i + 1; j < num_pins; j++) { - if (sequences[i] > sequences[j]) { - seq = sequences[i]; - sequences[i] = sequences[j]; - sequences[j] = seq; - nid = pins[i]; - pins[i] = pins[j]; - pins[j] = nid; - } - } - } + int i; + sort(list, num_pins, sizeof(list[0]), compare_seq, NULL); + for (i = 0; i < num_pins; i++) + pins[i] = list[i].pin; } @@ -67,21 +69,11 @@ static void add_auto_cfg_input_pin(struct auto_pin_cfg *cfg, hda_nid_t nid, } } -/* sort inputs in the order of AUTO_PIN_* type */ -static void sort_autocfg_input_pins(struct auto_pin_cfg *cfg) +static int compare_input_type(const void *ap, const void *bp) { - int i, j; - - for (i = 0; i < cfg->num_inputs; i++) { - for (j = i + 1; j < cfg->num_inputs; j++) { - if (cfg->inputs[i].type > cfg->inputs[j].type) { - struct auto_pin_cfg_item tmp; - tmp = cfg->inputs[i]; - cfg->inputs[i] = cfg->inputs[j]; - cfg->inputs[j] = tmp; - } - } - } + const struct auto_pin_cfg_item *a = ap; + const struct auto_pin_cfg_item *b = bp; + return (int)(a->type - b->type); } /* Reorder the surround channels @@ -105,6 +97,28 @@ static void reorder_outputs(unsigned int nums, hda_nid_t *pins) } } +/* check whether the given pin has a proper pin I/O capability bit */ +static bool check_pincap_validity(struct hda_codec *codec, hda_nid_t pin, + unsigned int dev) +{ + unsigned int pincap = snd_hda_query_pin_caps(codec, pin); + + /* some old hardware don't return the proper pincaps */ + if (!pincap) + return true; + + switch (dev) { + case AC_JACK_LINE_OUT: + case AC_JACK_SPEAKER: + case AC_JACK_HP_OUT: + case AC_JACK_SPDIF_OUT: + case AC_JACK_DIG_OTHER_OUT: + return !!(pincap & AC_PINCAP_OUT); + default: + return !!(pincap & AC_PINCAP_IN); + } +} + /* * Parse all pin widgets and store the useful pin nids to cfg * @@ -129,16 +143,19 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec, { hda_nid_t nid, end_nid; short seq, assoc_line_out; - short sequences_line_out[ARRAY_SIZE(cfg->line_out_pins)]; - short sequences_speaker[ARRAY_SIZE(cfg->speaker_pins)]; - short sequences_hp[ARRAY_SIZE(cfg->hp_pins)]; + struct auto_out_pin line_out[ARRAY_SIZE(cfg->line_out_pins)]; + struct auto_out_pin speaker_out[ARRAY_SIZE(cfg->speaker_pins)]; + struct auto_out_pin hp_out[ARRAY_SIZE(cfg->hp_pins)]; int i; + if (!snd_hda_get_int_hint(codec, "parser_flags", &i)) + cond_flags = i; + memset(cfg, 0, sizeof(*cfg)); - memset(sequences_line_out, 0, sizeof(sequences_line_out)); - memset(sequences_speaker, 0, sizeof(sequences_speaker)); - memset(sequences_hp, 0, sizeof(sequences_hp)); + memset(line_out, 0, sizeof(line_out)); + memset(speaker_out, 0, sizeof(speaker_out)); + memset(hp_out, 0, sizeof(hp_out)); assoc_line_out = 0; end_nid = codec->start_nid + codec->num_nodes; @@ -164,10 +181,14 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec, /* workaround for buggy BIOS setups */ if (dev == AC_JACK_LINE_OUT) { - if (conn == AC_JACK_PORT_FIXED) + if (conn == AC_JACK_PORT_FIXED || + conn == AC_JACK_PORT_BOTH) dev = AC_JACK_SPEAKER; } + if (!check_pincap_validity(codec, nid, dev)) + continue; + switch (dev) { case AC_JACK_LINE_OUT: seq = get_defcfg_sequence(def_conf); @@ -184,8 +205,8 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec, continue; if (cfg->line_outs >= ARRAY_SIZE(cfg->line_out_pins)) continue; - cfg->line_out_pins[cfg->line_outs] = nid; - sequences_line_out[cfg->line_outs] = seq; + line_out[cfg->line_outs].pin = nid; + line_out[cfg->line_outs].seq = seq; cfg->line_outs++; break; case AC_JACK_SPEAKER: @@ -193,8 +214,8 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec, assoc = get_defcfg_association(def_conf); if (cfg->speaker_outs >= ARRAY_SIZE(cfg->speaker_pins)) continue; - cfg->speaker_pins[cfg->speaker_outs] = nid; - sequences_speaker[cfg->speaker_outs] = (assoc << 4) | seq; + speaker_out[cfg->speaker_outs].pin = nid; + speaker_out[cfg->speaker_outs].seq = (assoc << 4) | seq; cfg->speaker_outs++; break; case AC_JACK_HP_OUT: @@ -202,8 +223,8 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec, assoc = get_defcfg_association(def_conf); if (cfg->hp_outs >= ARRAY_SIZE(cfg->hp_pins)) continue; - cfg->hp_pins[cfg->hp_outs] = nid; - sequences_hp[cfg->hp_outs] = (assoc << 4) | seq; + hp_out[cfg->hp_outs].pin = nid; + hp_out[cfg->hp_outs].seq = (assoc << 4) | seq; cfg->hp_outs++; break; case AC_JACK_MIC_IN: @@ -248,34 +269,28 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec, int i = 0; while (i < cfg->hp_outs) { /* The real HPs should have the sequence 0x0f */ - if ((sequences_hp[i] & 0x0f) == 0x0f) { + if ((hp_out[i].seq & 0x0f) == 0x0f) { i++; continue; } /* Move it to the line-out table */ - cfg->line_out_pins[cfg->line_outs] = cfg->hp_pins[i]; - sequences_line_out[cfg->line_outs] = sequences_hp[i]; - cfg->line_outs++; + line_out[cfg->line_outs++] = hp_out[i]; cfg->hp_outs--; - memmove(cfg->hp_pins + i, cfg->hp_pins + i + 1, - sizeof(cfg->hp_pins[0]) * (cfg->hp_outs - i)); - memmove(sequences_hp + i, sequences_hp + i + 1, - sizeof(sequences_hp[0]) * (cfg->hp_outs - i)); + memmove(hp_out + i, hp_out + i + 1, + sizeof(hp_out[0]) * (cfg->hp_outs - i)); } - memset(cfg->hp_pins + cfg->hp_outs, 0, - sizeof(hda_nid_t) * (AUTO_CFG_MAX_OUTS - cfg->hp_outs)); + memset(hp_out + cfg->hp_outs, 0, + sizeof(hp_out[0]) * (AUTO_CFG_MAX_OUTS - cfg->hp_outs)); if (!cfg->hp_outs) cfg->line_out_type = AUTO_PIN_HP_OUT; } /* sort by sequence */ - sort_pins_by_sequence(cfg->line_out_pins, sequences_line_out, - cfg->line_outs); - sort_pins_by_sequence(cfg->speaker_pins, sequences_speaker, + sort_pins_by_sequence(cfg->line_out_pins, line_out, cfg->line_outs); + sort_pins_by_sequence(cfg->speaker_pins, speaker_out, cfg->speaker_outs); - sort_pins_by_sequence(cfg->hp_pins, sequences_hp, - cfg->hp_outs); + sort_pins_by_sequence(cfg->hp_pins, hp_out, cfg->hp_outs); /* * FIX-UP: if no line-outs are detected, try to use speaker or HP pin @@ -304,7 +319,9 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec, reorder_outputs(cfg->hp_outs, cfg->hp_pins); reorder_outputs(cfg->speaker_outs, cfg->speaker_pins); - sort_autocfg_input_pins(cfg); + /* sort inputs in the order of AUTO_PIN_* type */ + sort(cfg->inputs, cfg->num_inputs, sizeof(cfg->inputs[0]), + compare_input_type, NULL); /* * debug prints of the parsed results @@ -375,7 +392,7 @@ static const char *hda_get_input_pin_label(struct hda_codec *codec, { unsigned int def_conf; static const char * const mic_names[] = { - "Internal Mic", "Dock Mic", "Mic", "Front Mic", "Rear Mic", + "Internal Mic", "Dock Mic", "Mic", "Rear Mic", "Front Mic" }; int attr; @@ -406,6 +423,8 @@ static const char *hda_get_input_pin_label(struct hda_codec *codec, return "SPDIF In"; case AC_JACK_DIG_OTHER_IN: return "Digital In"; + case AC_JACK_HP_OUT: + return "Headphone Mic"; default: return "Misc"; } @@ -564,6 +583,9 @@ static int fill_audio_out_name(struct hda_codec *codec, hda_nid_t nid, return 1; } +#define is_hdmi_cfg(conf) \ + (get_defcfg_location(conf) == AC_JACK_LOC_HDMI) + /** * snd_hda_get_pin_label - Get a label for the given I/O pin * @@ -584,6 +606,7 @@ int snd_hda_get_pin_label(struct hda_codec *codec, hda_nid_t nid, unsigned int def_conf = snd_hda_codec_get_pincfg(codec, nid); const char *name = NULL; int i; + bool hdmi; if (indexp) *indexp = 0; @@ -602,16 +625,18 @@ int snd_hda_get_pin_label(struct hda_codec *codec, hda_nid_t nid, label, maxlen, indexp); case AC_JACK_SPDIF_OUT: case AC_JACK_DIG_OTHER_OUT: - if (get_defcfg_location(def_conf) == AC_JACK_LOC_HDMI) - name = "HDMI"; - else - name = "SPDIF"; - if (cfg && indexp) { - i = find_idx_in_nid_list(nid, cfg->dig_out_pins, - cfg->dig_outs); - if (i >= 0) - *indexp = i; - } + hdmi = is_hdmi_cfg(def_conf); + name = hdmi ? "HDMI" : "SPDIF"; + if (cfg && indexp) + for (i = 0; i < cfg->dig_outs; i++) { + hda_nid_t pin = cfg->dig_out_pins[i]; + unsigned int c; + if (pin == nid) + break; + c = snd_hda_codec_get_pincfg(codec, pin); + if (hdmi == is_hdmi_cfg(c)) + (*indexp)++; + } break; default: if (cfg) { @@ -634,28 +659,27 @@ int snd_hda_get_pin_label(struct hda_codec *codec, hda_nid_t nid, } EXPORT_SYMBOL_HDA(snd_hda_get_pin_label); -int snd_hda_gen_add_verbs(struct hda_gen_spec *spec, - const struct hda_verb *list) +int snd_hda_add_verbs(struct hda_codec *codec, + const struct hda_verb *list) { const struct hda_verb **v; - v = snd_array_new(&spec->verbs); + v = snd_array_new(&codec->verbs); if (!v) return -ENOMEM; *v = list; return 0; } -EXPORT_SYMBOL_HDA(snd_hda_gen_add_verbs); +EXPORT_SYMBOL_HDA(snd_hda_add_verbs); -void snd_hda_gen_apply_verbs(struct hda_codec *codec) +void snd_hda_apply_verbs(struct hda_codec *codec) { - struct hda_gen_spec *spec = codec->spec; int i; - for (i = 0; i < spec->verbs.used; i++) { - struct hda_verb **v = snd_array_elem(&spec->verbs, i); + for (i = 0; i < codec->verbs.used; i++) { + struct hda_verb **v = snd_array_elem(&codec->verbs, i); snd_hda_sequence_write(codec, *v); } } -EXPORT_SYMBOL_HDA(snd_hda_gen_apply_verbs); +EXPORT_SYMBOL_HDA(snd_hda_apply_verbs); void snd_hda_apply_pincfgs(struct hda_codec *codec, const struct hda_pintbl *cfg) @@ -665,20 +689,22 @@ void snd_hda_apply_pincfgs(struct hda_codec *codec, } EXPORT_SYMBOL_HDA(snd_hda_apply_pincfgs); -void snd_hda_apply_fixup(struct hda_codec *codec, int action) +static void set_pin_targets(struct hda_codec *codec, + const struct hda_pintbl *cfg) { - struct hda_gen_spec *spec = codec->spec; - int id = spec->fixup_id; -#ifdef CONFIG_SND_DEBUG_VERBOSE - const char *modelname = spec->fixup_name; -#endif - int depth = 0; + for (; cfg->nid; cfg++) + snd_hda_set_pin_ctl_cache(codec, cfg->nid, cfg->val); +} - if (!spec->fixup_list) - return; +static void apply_fixup(struct hda_codec *codec, int id, int action, int depth) +{ + const char *modelname = codec->fixup_name; while (id >= 0) { - const struct hda_fixup *fix = spec->fixup_list + id; + const struct hda_fixup *fix = codec->fixup_list + id; + + if (fix->chained_before) + apply_fixup(codec, fix->chain_id, action, depth + 1); switch (fix->type) { case HDA_FIXUP_PINS: @@ -695,7 +721,7 @@ void snd_hda_apply_fixup(struct hda_codec *codec, int action) snd_printdd(KERN_INFO SFX "%s: Apply fix-verbs for %s\n", codec->chip_name, modelname); - snd_hda_gen_add_verbs(codec->spec, fix->v.verbs); + snd_hda_add_verbs(codec, fix->v.verbs); break; case HDA_FIXUP_FUNC: if (!fix->v.func) @@ -705,19 +731,33 @@ void snd_hda_apply_fixup(struct hda_codec *codec, int action) codec->chip_name, modelname); fix->v.func(codec, fix, action); break; + case HDA_FIXUP_PINCTLS: + if (action != HDA_FIXUP_ACT_PROBE || !fix->v.pins) + break; + snd_printdd(KERN_INFO SFX + "%s: Apply pinctl for %s\n", + codec->chip_name, modelname); + set_pin_targets(codec, fix->v.pins); + break; default: snd_printk(KERN_ERR SFX "%s: Invalid fixup type %d\n", codec->chip_name, fix->type); break; } - if (!fix->chained) + if (!fix->chained || fix->chained_before) break; if (++depth > 10) break; id = fix->chain_id; } } + +void snd_hda_apply_fixup(struct hda_codec *codec, int action) +{ + if (codec->fixup_list) + apply_fixup(codec, codec->fixup_id, action, 0); +} EXPORT_SYMBOL_HDA(snd_hda_apply_fixup); void snd_hda_pick_fixup(struct hda_codec *codec, @@ -725,15 +765,14 @@ void snd_hda_pick_fixup(struct hda_codec *codec, const struct snd_pci_quirk *quirk, const struct hda_fixup *fixlist) { - struct hda_gen_spec *spec = codec->spec; const struct snd_pci_quirk *q; int id = -1; const char *name = NULL; /* when model=nofixup is given, don't pick up any fixups */ if (codec->modelname && !strcmp(codec->modelname, "nofixup")) { - spec->fixup_list = NULL; - spec->fixup_id = -1; + codec->fixup_list = NULL; + codec->fixup_id = -1; return; } @@ -771,10 +810,10 @@ void snd_hda_pick_fixup(struct hda_codec *codec, } } - spec->fixup_id = id; + codec->fixup_id = id; if (id >= 0) { - spec->fixup_list = fixlist; - spec->fixup_name = name; + codec->fixup_list = fixlist; + codec->fixup_name = name; } } EXPORT_SYMBOL_HDA(snd_hda_pick_fixup); diff --git a/sound/pci/hda/hda_auto_parser.h b/sound/pci/hda/hda_auto_parser.h index 632ad0ad3007..f74807138b49 100644 --- a/sound/pci/hda/hda_auto_parser.h +++ b/sound/pci/hda/hda_auto_parser.h @@ -51,8 +51,9 @@ enum { INPUT_PIN_ATTR_INT, /* internal mic/line-in */ INPUT_PIN_ATTR_DOCK, /* docking mic/line-in */ INPUT_PIN_ATTR_NORMAL, /* mic/line-in jack */ - INPUT_PIN_ATTR_FRONT, /* mic/line-in jack in front */ INPUT_PIN_ATTR_REAR, /* mic/line-in jack in rear */ + INPUT_PIN_ATTR_FRONT, /* mic/line-in jack in front */ + INPUT_PIN_ATTR_LAST = INPUT_PIN_ATTR_FRONT, }; int snd_hda_get_input_pin_attr(unsigned int def_conf); @@ -89,82 +90,4 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec, #define snd_hda_parse_pin_def_config(codec, cfg, ignore) \ snd_hda_parse_pin_defcfg(codec, cfg, ignore, 0) -/* - */ - -struct hda_gen_spec { - /* fix-up list */ - int fixup_id; - const struct hda_fixup *fixup_list; - const char *fixup_name; - - /* additional init verbs */ - struct snd_array verbs; -}; - - -/* - * Fix-up pin default configurations and add default verbs - */ - -struct hda_pintbl { - hda_nid_t nid; - u32 val; -}; - -struct hda_model_fixup { - const int id; - const char *name; -}; - -struct hda_fixup { - int type; - bool chained; - int chain_id; - union { - const struct hda_pintbl *pins; - const struct hda_verb *verbs; - void (*func)(struct hda_codec *codec, - const struct hda_fixup *fix, - int action); - } v; -}; - -/* fixup types */ -enum { - HDA_FIXUP_INVALID, - HDA_FIXUP_PINS, - HDA_FIXUP_VERBS, - HDA_FIXUP_FUNC, -}; - -/* fixup action definitions */ -enum { - HDA_FIXUP_ACT_PRE_PROBE, - HDA_FIXUP_ACT_PROBE, - HDA_FIXUP_ACT_INIT, - HDA_FIXUP_ACT_BUILD, -}; - -int snd_hda_gen_add_verbs(struct hda_gen_spec *spec, - const struct hda_verb *list); -void snd_hda_gen_apply_verbs(struct hda_codec *codec); -void snd_hda_apply_pincfgs(struct hda_codec *codec, - const struct hda_pintbl *cfg); -void snd_hda_apply_fixup(struct hda_codec *codec, int action); -void snd_hda_pick_fixup(struct hda_codec *codec, - const struct hda_model_fixup *models, - const struct snd_pci_quirk *quirk, - const struct hda_fixup *fixlist); - -static inline void snd_hda_gen_init(struct hda_gen_spec *spec) -{ - snd_array_init(&spec->verbs, sizeof(struct hda_verb *), 8); -} - -static inline void snd_hda_gen_free(struct hda_gen_spec *spec) -{ - snd_array_free(&spec->verbs); -} - #endif /* __SOUND_HDA_AUTO_PARSER_H */ diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 70d4848b5cd0..f82a64da2f1b 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -95,6 +95,7 @@ int snd_hda_delete_codec_preset(struct hda_codec_preset_list *preset) EXPORT_SYMBOL_HDA(snd_hda_delete_codec_preset); #ifdef CONFIG_PM +#define codec_in_pm(codec) ((codec)->in_pm) static void hda_power_work(struct work_struct *work); static void hda_keep_power_on(struct hda_codec *codec); #define hda_codec_is_power_on(codec) ((codec)->power_on) @@ -104,6 +105,7 @@ static inline void hda_call_pm_notify(struct hda_bus *bus, bool power_up) bus->ops.pm_notify(bus, power_up); } #else +#define codec_in_pm(codec) 0 static inline void hda_keep_power_on(struct hda_codec *codec) {} #define hda_codec_is_power_on(codec) 1 #define hda_call_pm_notify(bus, state) {} @@ -220,15 +222,21 @@ static int codec_exec_verb(struct hda_codec *codec, unsigned int cmd, again: snd_hda_power_up(codec); mutex_lock(&bus->cmd_mutex); - trace_hda_send_cmd(codec, cmd); - err = bus->ops.command(bus, cmd); + for (;;) { + trace_hda_send_cmd(codec, cmd); + err = bus->ops.command(bus, cmd); + if (err != -EAGAIN) + break; + /* process pending verbs */ + bus->ops.get_response(bus, codec->addr); + } if (!err && res) { *res = bus->ops.get_response(bus, codec->addr); trace_hda_get_response(codec, *res); } mutex_unlock(&bus->cmd_mutex); snd_hda_power_down(codec); - if (res && *res == -1 && bus->rirb_error) { + if (!codec_in_pm(codec) && res && *res == -1 && bus->rirb_error) { if (bus->response_reset) { snd_printd("hda_codec: resetting BUS due to " "fatal communication error\n"); @@ -238,7 +246,7 @@ static int codec_exec_verb(struct hda_codec *codec, unsigned int cmd, goto again; } /* clear reset-flag when the communication gets recovered */ - if (!err) + if (!err || codec_in_pm(codec)) bus->response_reset = 0; return err; } @@ -326,20 +334,51 @@ int snd_hda_get_sub_nodes(struct hda_codec *codec, hda_nid_t nid, } EXPORT_SYMBOL_HDA(snd_hda_get_sub_nodes); +/* connection list element */ +struct hda_conn_list { + struct list_head list; + int len; + hda_nid_t nid; + hda_nid_t conns[0]; +}; + /* look up the cached results */ -static hda_nid_t *lookup_conn_list(struct snd_array *array, hda_nid_t nid) +static struct hda_conn_list * +lookup_conn_list(struct hda_codec *codec, hda_nid_t nid) { - int i, len; - for (i = 0; i < array->used; ) { - hda_nid_t *p = snd_array_elem(array, i); - if (nid == *p) + struct hda_conn_list *p; + list_for_each_entry(p, &codec->conn_list, list) { + if (p->nid == nid) return p; - len = p[1]; - i += len + 2; } return NULL; } +static int add_conn_list(struct hda_codec *codec, hda_nid_t nid, int len, + const hda_nid_t *list) +{ + struct hda_conn_list *p; + + p = kmalloc(sizeof(*p) + len * sizeof(hda_nid_t), GFP_KERNEL); + if (!p) + return -ENOMEM; + p->len = len; + p->nid = nid; + memcpy(p->conns, list, len * sizeof(hda_nid_t)); + list_add(&p->list, &codec->conn_list); + return 0; +} + +static void remove_conn_list(struct hda_codec *codec) +{ + while (!list_empty(&codec->conn_list)) { + struct hda_conn_list *p; + p = list_first_entry(&codec->conn_list, typeof(*p), list); + list_del(&p->list); + kfree(p); + } +} + /* read the connection and add to the cache */ static int read_and_add_raw_conns(struct hda_codec *codec, hda_nid_t nid) { @@ -353,6 +392,49 @@ static int read_and_add_raw_conns(struct hda_codec *codec, hda_nid_t nid) } /** + * snd_hda_get_conn_list - get connection list + * @codec: the HDA codec + * @nid: NID to parse + * @len: number of connection list entries + * @listp: the pointer to store NID list + * + * Parses the connection list of the given widget and stores the pointer + * to the list of NIDs. + * + * Returns the number of connections, or a negative error code. + * + * Note that the returned pointer isn't protected against the list + * modification. If snd_hda_override_conn_list() might be called + * concurrently, protect with a mutex appropriately. + */ +int snd_hda_get_conn_list(struct hda_codec *codec, hda_nid_t nid, + const hda_nid_t **listp) +{ + bool added = false; + + for (;;) { + int err; + const struct hda_conn_list *p; + + /* if the connection-list is already cached, read it */ + p = lookup_conn_list(codec, nid); + if (p) { + if (listp) + *listp = p->conns; + return p->len; + } + if (snd_BUG_ON(added)) + return -EINVAL; + + err = read_and_add_raw_conns(codec, nid); + if (err < 0) + return err; + added = true; + } +} +EXPORT_SYMBOL_HDA(snd_hda_get_conn_list); + +/** * snd_hda_get_connections - copy connection list * @codec: the HDA codec * @nid: NID to parse @@ -367,39 +449,20 @@ static int read_and_add_raw_conns(struct hda_codec *codec, hda_nid_t nid) int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid, hda_nid_t *conn_list, int max_conns) { - struct snd_array *array = &codec->conn_lists; - int len; - hda_nid_t *p; - bool added = false; + const hda_nid_t *list; + int len = snd_hda_get_conn_list(codec, nid, &list); - again: - mutex_lock(&codec->hash_mutex); - len = -1; - /* if the connection-list is already cached, read it */ - p = lookup_conn_list(array, nid); - if (p) { - len = p[1]; - if (conn_list && len > max_conns) { + if (len > 0 && conn_list) { + if (len > max_conns) { snd_printk(KERN_ERR "hda_codec: " "Too many connections %d for NID 0x%x\n", len, nid); - mutex_unlock(&codec->hash_mutex); return -EINVAL; } - if (conn_list && len) - memcpy(conn_list, p + 2, len * sizeof(hda_nid_t)); + memcpy(conn_list, list, len * sizeof(hda_nid_t)); } - mutex_unlock(&codec->hash_mutex); - if (len >= 0) - return len; - if (snd_BUG_ON(added)) - return -EINVAL; - len = read_and_add_raw_conns(codec, nid); - if (len < 0) - return len; - added = true; - goto again; + return len; } EXPORT_SYMBOL_HDA(snd_hda_get_connections); @@ -422,6 +485,7 @@ int snd_hda_get_raw_connections(struct hda_codec *codec, hda_nid_t nid, unsigned int shift, num_elems, mask; unsigned int wcaps; hda_nid_t prev_nid; + int null_count = 0; if (snd_BUG_ON(!conn_list || max_conns <= 0)) return -EINVAL; @@ -472,7 +536,7 @@ int snd_hda_get_raw_connections(struct hda_codec *codec, hda_nid_t nid, } range_val = !!(parm & (1 << (shift-1))); /* ranges */ val = parm & mask; - if (val == 0) { + if (val == 0 && null_count++) { /* no second chance */ snd_printk(KERN_WARNING "hda_codec: " "invalid CONNECT_LIST verb %x[%i]:%x\n", nid, i, parm); @@ -510,15 +574,6 @@ int snd_hda_get_raw_connections(struct hda_codec *codec, hda_nid_t nid, return conns; } -static bool add_conn_list(struct snd_array *array, hda_nid_t nid) -{ - hda_nid_t *p = snd_array_new(array); - if (!p) - return false; - *p = nid; - return true; -} - /** * snd_hda_override_conn_list - add/modify the connection-list to cache * @codec: the HDA codec @@ -534,28 +589,15 @@ static bool add_conn_list(struct snd_array *array, hda_nid_t nid) int snd_hda_override_conn_list(struct hda_codec *codec, hda_nid_t nid, int len, const hda_nid_t *list) { - struct snd_array *array = &codec->conn_lists; - hda_nid_t *p; - int i, old_used; + struct hda_conn_list *p; - mutex_lock(&codec->hash_mutex); - p = lookup_conn_list(array, nid); - if (p) - *p = -1; /* invalidate the old entry */ - - old_used = array->used; - if (!add_conn_list(array, nid) || !add_conn_list(array, len)) - goto error_add; - for (i = 0; i < len; i++) - if (!add_conn_list(array, list[i])) - goto error_add; - mutex_unlock(&codec->hash_mutex); - return 0; + p = lookup_conn_list(codec, nid); + if (p) { + list_del(&p->list); + kfree(p); + } - error_add: - array->used = old_used; - mutex_unlock(&codec->hash_mutex); - return -ENOMEM; + return add_conn_list(codec, nid, len, list); } EXPORT_SYMBOL_HDA(snd_hda_override_conn_list); @@ -573,16 +615,16 @@ EXPORT_SYMBOL_HDA(snd_hda_override_conn_list); int snd_hda_get_conn_index(struct hda_codec *codec, hda_nid_t mux, hda_nid_t nid, int recursive) { - hda_nid_t conn[HDA_MAX_NUM_INPUTS]; + const hda_nid_t *conn; int i, nums; - nums = snd_hda_get_connections(codec, mux, conn, ARRAY_SIZE(conn)); + nums = snd_hda_get_conn_list(codec, mux, &conn); for (i = 0; i < nums; i++) if (conn[i] == nid) return i; if (!recursive) return -1; - if (recursive > 5) { + if (recursive > 10) { snd_printd("hda_codec: too deep connection for 0x%x\n", nid); return -1; } @@ -736,7 +778,7 @@ static int snd_hda_bus_dev_register(struct snd_device *device) * * Returns 0 if successful, or a negative error code. */ -int /*__devinit*/ snd_hda_bus_new(struct snd_card *card, +int snd_hda_bus_new(struct snd_card *card, const struct hda_bus_template *temp, struct hda_bus **busp) { @@ -906,7 +948,7 @@ static int get_codec_name(struct hda_codec *codec) /* * look for an AFG and MFG nodes */ -static void /*__devinit*/ setup_fg_nodes(struct hda_codec *codec) +static void setup_fg_nodes(struct hda_codec *codec) { int i, total_nodes, function_id; hda_nid_t nid; @@ -991,19 +1033,6 @@ static struct hda_pincfg *look_up_pincfg(struct hda_codec *codec, return NULL; } -/* write a config value for the given NID */ -static void set_pincfg(struct hda_codec *codec, hda_nid_t nid, - unsigned int cfg) -{ - int i; - for (i = 0; i < 4; i++) { - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_CONFIG_DEFAULT_BYTES_0 + i, - cfg & 0xff); - cfg >>= 8; - } -} - /* set the current pin config value for the given NID. * the value is cached, and read via snd_hda_codec_get_pincfg() */ @@ -1011,12 +1040,10 @@ int snd_hda_add_pincfg(struct hda_codec *codec, struct snd_array *list, hda_nid_t nid, unsigned int cfg) { struct hda_pincfg *pin; - unsigned int oldcfg; if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN) return -EINVAL; - oldcfg = snd_hda_codec_get_pincfg(codec, nid); pin = look_up_pincfg(codec, list, nid); if (!pin) { pin = snd_array_new(list); @@ -1025,13 +1052,6 @@ int snd_hda_add_pincfg(struct hda_codec *codec, struct snd_array *list, pin->nid = nid; } pin->cfg = cfg; - - /* change only when needed; e.g. if the pincfg is already present - * in user_pins[], don't write it - */ - cfg = snd_hda_codec_get_pincfg(codec, nid); - if (oldcfg != cfg) - set_pincfg(codec, nid, cfg); return 0; } @@ -1066,9 +1086,16 @@ unsigned int snd_hda_codec_get_pincfg(struct hda_codec *codec, hda_nid_t nid) struct hda_pincfg *pin; #ifdef CONFIG_SND_HDA_HWDEP - pin = look_up_pincfg(codec, &codec->user_pins, nid); - if (pin) - return pin->cfg; + { + unsigned int cfg = 0; + mutex_lock(&codec->user_mutex); + pin = look_up_pincfg(codec, &codec->user_pins, nid); + if (pin) + cfg = pin->cfg; + mutex_unlock(&codec->user_mutex); + if (cfg) + return cfg; + } #endif pin = look_up_pincfg(codec, &codec->driver_pins, nid); if (pin) @@ -1080,16 +1107,31 @@ unsigned int snd_hda_codec_get_pincfg(struct hda_codec *codec, hda_nid_t nid) } EXPORT_SYMBOL_HDA(snd_hda_codec_get_pincfg); -/* restore all current pin configs */ -static void restore_pincfgs(struct hda_codec *codec) +/* remember the current pinctl target value */ +int snd_hda_codec_set_pin_target(struct hda_codec *codec, hda_nid_t nid, + unsigned int val) { - int i; - for (i = 0; i < codec->init_pins.used; i++) { - struct hda_pincfg *pin = snd_array_elem(&codec->init_pins, i); - set_pincfg(codec, pin->nid, - snd_hda_codec_get_pincfg(codec, pin->nid)); - } + struct hda_pincfg *pin; + + pin = look_up_pincfg(codec, &codec->init_pins, nid); + if (!pin) + return -EINVAL; + pin->target = val; + return 0; +} +EXPORT_SYMBOL_HDA(snd_hda_codec_set_pin_target); + +/* return the current pinctl target value */ +int snd_hda_codec_get_pin_target(struct hda_codec *codec, hda_nid_t nid) +{ + struct hda_pincfg *pin; + + pin = look_up_pincfg(codec, &codec->init_pins, nid); + if (!pin) + return 0; + return pin->target; } +EXPORT_SYMBOL_HDA(snd_hda_codec_get_pin_target); /** * snd_hda_shutup_pins - Shut up all pins @@ -1135,21 +1177,30 @@ static void restore_shutup_pins(struct hda_codec *codec) } #endif +static void hda_jackpoll_work(struct work_struct *work) +{ + struct hda_codec *codec = + container_of(work, struct hda_codec, jackpoll_work.work); + if (!codec->jackpoll_interval) + return; + + snd_hda_jack_set_dirty_all(codec); + snd_hda_jack_poll_all(codec); + queue_delayed_work(codec->bus->workq, &codec->jackpoll_work, + codec->jackpoll_interval); +} + static void init_hda_cache(struct hda_cache_rec *cache, unsigned int record_size); static void free_hda_cache(struct hda_cache_rec *cache); -/* restore the initial pin cfgs and release all pincfg lists */ -static void restore_init_pincfgs(struct hda_codec *codec) +/* release all pincfg lists */ +static void free_init_pincfgs(struct hda_codec *codec) { - /* first free driver_pins and user_pins, then call restore_pincfg - * so that only the values in init_pins are restored - */ snd_array_free(&codec->driver_pins); #ifdef CONFIG_SND_HDA_HWDEP snd_array_free(&codec->user_pins); #endif - restore_pincfgs(codec); snd_array_free(&codec->init_pins); } @@ -1190,8 +1241,9 @@ static void snd_hda_codec_free(struct hda_codec *codec) { if (!codec) return; + cancel_delayed_work_sync(&codec->jackpoll_work); snd_hda_jack_tbl_clear(codec); - restore_init_pincfgs(codec); + free_init_pincfgs(codec); #ifdef CONFIG_PM cancel_delayed_work(&codec->power_work); flush_workqueue(codec->bus->workq); @@ -1200,8 +1252,8 @@ static void snd_hda_codec_free(struct hda_codec *codec) snd_array_free(&codec->mixers); snd_array_free(&codec->nids); snd_array_free(&codec->cvt_setups); - snd_array_free(&codec->conn_lists); snd_array_free(&codec->spdif_out); + remove_conn_list(codec); codec->bus->caddr_tbl[codec->addr] = NULL; if (codec->patch_ops.free) codec->patch_ops.free(codec); @@ -1224,6 +1276,8 @@ static bool snd_hda_codec_get_supported_ps(struct hda_codec *codec, static unsigned int hda_set_power_state(struct hda_codec *codec, unsigned int power_state); +static unsigned int default_power_filter(struct hda_codec *codec, hda_nid_t nid, + unsigned int power_state); /** * snd_hda_codec_new - create a HDA codec @@ -1233,7 +1287,7 @@ static unsigned int hda_set_power_state(struct hda_codec *codec, * * Returns 0 if successful, or a negative error code. */ -int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, +int snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, struct hda_codec **codecp) { @@ -1271,8 +1325,12 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, snd_array_init(&codec->init_pins, sizeof(struct hda_pincfg), 16); snd_array_init(&codec->driver_pins, sizeof(struct hda_pincfg), 16); snd_array_init(&codec->cvt_setups, sizeof(struct hda_cvt_setup), 8); - snd_array_init(&codec->conn_lists, sizeof(hda_nid_t), 64); snd_array_init(&codec->spdif_out, sizeof(struct hda_spdif_out), 16); + snd_array_init(&codec->jacktbl, sizeof(struct hda_jack_tbl), 16); + snd_array_init(&codec->verbs, sizeof(struct hda_verb *), 8); + INIT_LIST_HEAD(&codec->conn_list); + + INIT_DELAYED_WORK(&codec->jackpoll_work, hda_jackpoll_work); #ifdef CONFIG_PM spin_lock_init(&codec->power_lock); @@ -1340,6 +1398,7 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, #endif codec->epss = snd_hda_codec_get_supported_ps(codec, fg, AC_PWRST_EPSS); + codec->power_filter = default_power_filter; /* power-up all before initialization */ hda_set_power_state(codec, AC_PWRST_D0); @@ -1470,7 +1529,7 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, "NID=0x%x, stream=0x%x, channel=%d, format=0x%x\n", nid, stream_tag, channel_id, format); p = get_hda_cvt_setup(codec, nid); - if (!p) + if (!p || p->active) return; if (codec->pcm_format_first) @@ -1517,7 +1576,7 @@ void __snd_hda_codec_cleanup_stream(struct hda_codec *codec, hda_nid_t nid, snd_printdd("hda_codec_cleanup_stream: NID=0x%x\n", nid); p = get_hda_cvt_setup(codec, nid); - if (p) { + if (p && p->active) { /* here we just clear the active flag when do_now isn't set; * actual clean-ups will be done later in * purify_inactive_streams() called from snd_hda_codec_prpapre() @@ -1586,7 +1645,7 @@ static void hda_cleanup_all_streams(struct hda_codec *codec) #define INFO_AMP_VOL(ch) (1 << (1 + (ch))) /* initialize the hash table */ -static void /*__devinit*/ init_hda_cache(struct hda_cache_rec *cache, +static void init_hda_cache(struct hda_cache_rec *cache, unsigned int record_size) { memset(cache, 0, sizeof(*cache)); @@ -1629,6 +1688,7 @@ static struct hda_cache_head *get_alloc_hash(struct hda_cache_rec *cache, cur = snd_array_index(&cache->buf, info); info->key = key; info->val = 0; + info->dirty = 0; idx = key % (u16)ARRAY_SIZE(cache->hash); info->next = cache->hash[idx]; cache->hash[idx] = cur; @@ -1783,7 +1843,7 @@ EXPORT_SYMBOL_HDA(snd_hda_override_pin_caps); */ static struct hda_amp_info * update_amp_hash(struct hda_codec *codec, hda_nid_t nid, int ch, - int direction, int index) + int direction, int index, bool init_only) { struct hda_amp_info *info; unsigned int parm, val = 0; @@ -1809,14 +1869,15 @@ update_amp_hash(struct hda_codec *codec, hda_nid_t nid, int ch, } info->vol[ch] = val; info->head.val |= INFO_AMP_VOL(ch); - } + } else if (init_only) + return NULL; return info; } /* * write the current volume in info to the h/w */ -static void put_vol_mute(struct hda_codec *codec, struct hda_amp_info *info, +static void put_vol_mute(struct hda_codec *codec, unsigned int amp_caps, hda_nid_t nid, int ch, int direction, int index, int val) { @@ -1825,8 +1886,8 @@ static void put_vol_mute(struct hda_codec *codec, struct hda_amp_info *info, parm = ch ? AC_AMP_SET_RIGHT : AC_AMP_SET_LEFT; parm |= direction == HDA_OUTPUT ? AC_AMP_SET_OUTPUT : AC_AMP_SET_INPUT; parm |= index << AC_AMP_SET_INDEX_SHIFT; - if ((val & HDA_AMP_MUTE) && !(info->amp_caps & AC_AMPCAP_MUTE) && - (info->amp_caps & AC_AMPCAP_MIN_MUTE)) + if ((val & HDA_AMP_MUTE) && !(amp_caps & AC_AMPCAP_MUTE) && + (amp_caps & AC_AMPCAP_MIN_MUTE)) ; /* set the zero value as a fake mute */ else parm |= val; @@ -1850,7 +1911,7 @@ int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch, unsigned int val = 0; mutex_lock(&codec->hash_mutex); - info = update_amp_hash(codec, nid, ch, direction, index); + info = update_amp_hash(codec, nid, ch, direction, index, false); if (info) val = info->vol[ch]; mutex_unlock(&codec->hash_mutex); @@ -1858,30 +1919,20 @@ int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch, } EXPORT_SYMBOL_HDA(snd_hda_codec_amp_read); -/** - * snd_hda_codec_amp_update - update the AMP value - * @codec: HD-audio codec - * @nid: NID to read the AMP value - * @ch: channel (left=0 or right=1) - * @direction: #HDA_INPUT or #HDA_OUTPUT - * @idx: the index value (only for input direction) - * @mask: bit mask to set - * @val: the bits value to set - * - * Update the AMP value with a bit mask. - * Returns 0 if the value is unchanged, 1 if changed. - */ -int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch, - int direction, int idx, int mask, int val) +static int codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch, + int direction, int idx, int mask, int val, + bool init_only) { struct hda_amp_info *info; + unsigned int caps; + unsigned int cache_only; if (snd_BUG_ON(mask & ~0xff)) mask &= 0xff; val &= mask; mutex_lock(&codec->hash_mutex); - info = update_amp_hash(codec, nid, ch, direction, idx); + info = update_amp_hash(codec, nid, ch, direction, idx, init_only); if (!info) { mutex_unlock(&codec->hash_mutex); return 0; @@ -1892,10 +1943,32 @@ int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch, return 0; } info->vol[ch] = val; + cache_only = info->head.dirty = codec->cached_write; + caps = info->amp_caps; mutex_unlock(&codec->hash_mutex); - put_vol_mute(codec, info, nid, ch, direction, idx, val); + if (!cache_only) + put_vol_mute(codec, caps, nid, ch, direction, idx, val); return 1; } + +/** + * snd_hda_codec_amp_update - update the AMP value + * @codec: HD-audio codec + * @nid: NID to read the AMP value + * @ch: channel (left=0 or right=1) + * @direction: #HDA_INPUT or #HDA_OUTPUT + * @idx: the index value (only for input direction) + * @mask: bit mask to set + * @val: the bits value to set + * + * Update the AMP value with a bit mask. + * Returns 0 if the value is unchanged, 1 if changed. + */ +int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch, + int direction, int idx, int mask, int val) +{ + return codec_amp_update(codec, nid, ch, direction, idx, mask, val, false); +} EXPORT_SYMBOL_HDA(snd_hda_codec_amp_update); /** @@ -1924,7 +1997,31 @@ int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid, } EXPORT_SYMBOL_HDA(snd_hda_codec_amp_stereo); -#ifdef CONFIG_PM +/* Works like snd_hda_codec_amp_update() but it writes the value only at + * the first access. If the amp was already initialized / updated beforehand, + * this does nothing. + */ +int snd_hda_codec_amp_init(struct hda_codec *codec, hda_nid_t nid, int ch, + int dir, int idx, int mask, int val) +{ + return codec_amp_update(codec, nid, ch, dir, idx, mask, val, true); +} +EXPORT_SYMBOL_HDA(snd_hda_codec_amp_init); + +int snd_hda_codec_amp_init_stereo(struct hda_codec *codec, hda_nid_t nid, + int dir, int idx, int mask, int val) +{ + int ch, ret = 0; + + if (snd_BUG_ON(mask & ~0xff)) + mask &= 0xff; + for (ch = 0; ch < 2; ch++) + ret |= snd_hda_codec_amp_init(codec, nid, ch, dir, + idx, mask, val); + return ret; +} +EXPORT_SYMBOL_HDA(snd_hda_codec_amp_init_stereo); + /** * snd_hda_codec_resume_amp - Resume all AMP commands from the cache * @codec: HD-audio codec @@ -1933,28 +2030,40 @@ EXPORT_SYMBOL_HDA(snd_hda_codec_amp_stereo); */ void snd_hda_codec_resume_amp(struct hda_codec *codec) { - struct hda_amp_info *buffer = codec->amp_cache.buf.list; int i; - for (i = 0; i < codec->amp_cache.buf.used; i++, buffer++) { - u32 key = buffer->head.key; + mutex_lock(&codec->hash_mutex); + codec->cached_write = 0; + for (i = 0; i < codec->amp_cache.buf.used; i++) { + struct hda_amp_info *buffer; + u32 key; hda_nid_t nid; unsigned int idx, dir, ch; + struct hda_amp_info info; + + buffer = snd_array_elem(&codec->amp_cache.buf, i); + if (!buffer->head.dirty) + continue; + buffer->head.dirty = 0; + info = *buffer; + key = info.head.key; if (!key) continue; nid = key & 0xff; idx = (key >> 16) & 0xff; dir = (key >> 24) & 0xff; for (ch = 0; ch < 2; ch++) { - if (!(buffer->head.val & INFO_AMP_VOL(ch))) + if (!(info.head.val & INFO_AMP_VOL(ch))) continue; - put_vol_mute(codec, buffer, nid, ch, dir, idx, - buffer->vol[ch]); + mutex_unlock(&codec->hash_mutex); + put_vol_mute(codec, info.amp_caps, nid, ch, dir, idx, + info.vol[ch]); + mutex_lock(&codec->hash_mutex); } } + mutex_unlock(&codec->hash_mutex); } EXPORT_SYMBOL_HDA(snd_hda_codec_resume_amp); -#endif /* CONFIG_PM */ static u32 get_amp_max_value(struct hda_codec *codec, hda_nid_t nid, int dir, unsigned int ofs) @@ -2151,12 +2260,12 @@ EXPORT_SYMBOL_HDA(snd_hda_set_vmaster_tlv); /* find a mixer control element with the given name */ static struct snd_kcontrol * -_snd_hda_find_mixer_ctl(struct hda_codec *codec, - const char *name, int idx) +find_mixer_ctl(struct hda_codec *codec, const char *name, int dev, int idx) { struct snd_ctl_elem_id id; memset(&id, 0, sizeof(id)); id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; + id.device = dev; id.index = idx; if (snd_BUG_ON(strlen(name) >= sizeof(id.name))) return NULL; @@ -2174,15 +2283,16 @@ _snd_hda_find_mixer_ctl(struct hda_codec *codec, struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec, const char *name) { - return _snd_hda_find_mixer_ctl(codec, name, 0); + return find_mixer_ctl(codec, name, 0, 0); } EXPORT_SYMBOL_HDA(snd_hda_find_mixer_ctl); -static int find_empty_mixer_ctl_idx(struct hda_codec *codec, const char *name) +static int find_empty_mixer_ctl_idx(struct hda_codec *codec, const char *name, + int dev) { int idx; for (idx = 0; idx < 16; idx++) { /* 16 ctlrs should be large enough */ - if (!_snd_hda_find_mixer_ctl(codec, name, idx)) + if (!find_mixer_ctl(codec, name, dev, idx)) return idx; } return -EBUSY; @@ -2349,7 +2459,7 @@ int snd_hda_codec_reset(struct hda_codec *codec) return -EBUSY; /* OK, let it free */ - + cancel_delayed_work_sync(&codec->jackpoll_work); #ifdef CONFIG_PM cancel_delayed_work_sync(&codec->power_work); codec->power_on = 0; @@ -2378,9 +2488,9 @@ int snd_hda_codec_reset(struct hda_codec *codec) init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head)); /* free only driver_pins so that init_pins + user_pins are restored */ snd_array_free(&codec->driver_pins); - restore_pincfgs(codec); snd_array_free(&codec->cvt_setups); snd_array_free(&codec->spdif_out); + snd_array_free(&codec->verbs); codec->num_pcms = 0; codec->pcm_info = NULL; codec->preset = NULL; @@ -2550,7 +2660,7 @@ static int vmaster_mute_mode_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { static const char * const texts[] = { - "Off", "On", "Follow Master" + "On", "Off", "Follow Master" }; unsigned int index; @@ -3133,26 +3243,48 @@ static struct snd_kcontrol_new dig_mixes[] = { }; /** - * snd_hda_create_spdif_out_ctls - create Output SPDIF-related controls + * snd_hda_create_dig_out_ctls - create Output SPDIF-related controls * @codec: the HDA codec - * @nid: audio out widget NID - * - * Creates controls related with the SPDIF output. - * Called from each patch supporting the SPDIF out. + * @associated_nid: NID that new ctls associated with + * @cvt_nid: converter NID + * @type: HDA_PCM_TYPE_* + * Creates controls related with the digital output. + * Called from each patch supporting the digital out. * * Returns 0 if successful, or a negative error code. */ -int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, - hda_nid_t associated_nid, - hda_nid_t cvt_nid) +int snd_hda_create_dig_out_ctls(struct hda_codec *codec, + hda_nid_t associated_nid, + hda_nid_t cvt_nid, + int type) { int err; struct snd_kcontrol *kctl; struct snd_kcontrol_new *dig_mix; - int idx; + int idx, dev = 0; + const int spdif_pcm_dev = 1; struct hda_spdif_out *spdif; - idx = find_empty_mixer_ctl_idx(codec, "IEC958 Playback Switch"); + if (codec->primary_dig_out_type == HDA_PCM_TYPE_HDMI && + type == HDA_PCM_TYPE_SPDIF) { + dev = spdif_pcm_dev; + } else if (codec->primary_dig_out_type == HDA_PCM_TYPE_SPDIF && + type == HDA_PCM_TYPE_HDMI) { + for (idx = 0; idx < codec->spdif_out.used; idx++) { + spdif = snd_array_elem(&codec->spdif_out, idx); + for (dig_mix = dig_mixes; dig_mix->name; dig_mix++) { + kctl = find_mixer_ctl(codec, dig_mix->name, 0, idx); + if (!kctl) + break; + kctl->id.device = spdif_pcm_dev; + } + } + codec->primary_dig_out_type = HDA_PCM_TYPE_HDMI; + } + if (!codec->primary_dig_out_type) + codec->primary_dig_out_type = type; + + idx = find_empty_mixer_ctl_idx(codec, "IEC958 Playback Switch", dev); if (idx < 0) { printk(KERN_ERR "hda_codec: too many IEC958 outputs\n"); return -EBUSY; @@ -3162,6 +3294,7 @@ int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, kctl = snd_ctl_new1(dig_mix, codec); if (!kctl) return -ENOMEM; + kctl->id.device = dev; kctl->id.index = idx; kctl->private_value = codec->spdif_out.used - 1; err = snd_hda_ctl_add(codec, associated_nid, kctl); @@ -3174,7 +3307,7 @@ int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, spdif->status = convert_to_spdif_status(spdif->ctls); return 0; } -EXPORT_SYMBOL_HDA(snd_hda_create_spdif_out_ctls); +EXPORT_SYMBOL_HDA(snd_hda_create_dig_out_ctls); /* get the hda_spdif_out entry from the given NID * call within spdif_mutex lock @@ -3349,7 +3482,7 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid) struct snd_kcontrol_new *dig_mix; int idx; - idx = find_empty_mixer_ctl_idx(codec, "IEC958 Capture Switch"); + idx = find_empty_mixer_ctl_idx(codec, "IEC958 Capture Switch", 0); if (idx < 0) { printk(KERN_ERR "hda_codec: too many IEC958 inputs\n"); return -EBUSY; @@ -3371,12 +3504,11 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid) } EXPORT_SYMBOL_HDA(snd_hda_create_spdif_in_ctls); -#ifdef CONFIG_PM /* * command cache */ -/* build a 32bit cache key with the widget id and the command parameter */ +/* build a 31bit cache key with the widget id and the command parameter */ #define build_cmd_cache_key(nid, verb) ((verb << 8) | nid) #define get_cmd_cache_nid(key) ((key) & 0xff) #define get_cmd_cache_cmd(key) (((key) >> 8) & 0xffff) @@ -3396,20 +3528,28 @@ EXPORT_SYMBOL_HDA(snd_hda_create_spdif_in_ctls); int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid, int direct, unsigned int verb, unsigned int parm) { - int err = snd_hda_codec_write(codec, nid, direct, verb, parm); + int err; struct hda_cache_head *c; u32 key; + unsigned int cache_only; + + cache_only = codec->cached_write; + if (!cache_only) { + err = snd_hda_codec_write(codec, nid, direct, verb, parm); + if (err < 0) + return err; + } - if (err < 0) - return err; /* parm may contain the verb stuff for get/set amp */ verb = verb | (parm >> 8); parm &= 0xff; key = build_cmd_cache_key(nid, verb); mutex_lock(&codec->bus->cmd_mutex); c = get_alloc_hash(&codec->cmd_cache, key); - if (c) + if (c) { c->val = parm; + c->dirty = cache_only; + } mutex_unlock(&codec->bus->cmd_mutex); return 0; } @@ -3458,16 +3598,27 @@ EXPORT_SYMBOL_HDA(snd_hda_codec_update_cache); */ void snd_hda_codec_resume_cache(struct hda_codec *codec) { - struct hda_cache_head *buffer = codec->cmd_cache.buf.list; int i; - for (i = 0; i < codec->cmd_cache.buf.used; i++, buffer++) { - u32 key = buffer->key; + mutex_lock(&codec->hash_mutex); + codec->cached_write = 0; + for (i = 0; i < codec->cmd_cache.buf.used; i++) { + struct hda_cache_head *buffer; + u32 key; + + buffer = snd_array_elem(&codec->cmd_cache.buf, i); + key = buffer->key; if (!key) continue; + if (!buffer->dirty) + continue; + buffer->dirty = 0; + mutex_unlock(&codec->hash_mutex); snd_hda_codec_write(codec, get_cmd_cache_nid(key), 0, get_cmd_cache_cmd(key), buffer->val); + mutex_lock(&codec->hash_mutex); } + mutex_unlock(&codec->hash_mutex); } EXPORT_SYMBOL_HDA(snd_hda_codec_resume_cache); @@ -3488,32 +3639,36 @@ void snd_hda_sequence_write_cache(struct hda_codec *codec, seq->param); } EXPORT_SYMBOL_HDA(snd_hda_sequence_write_cache); -#endif /* CONFIG_PM */ + +/** + * snd_hda_codec_flush_cache - Execute all pending (cached) amps / verbs + * @codec: HD-audio codec + */ +void snd_hda_codec_flush_cache(struct hda_codec *codec) +{ + snd_hda_codec_resume_amp(codec); + snd_hda_codec_resume_cache(codec); +} +EXPORT_SYMBOL_HDA(snd_hda_codec_flush_cache); void snd_hda_codec_set_power_to_all(struct hda_codec *codec, hda_nid_t fg, - unsigned int power_state, - bool eapd_workaround) + unsigned int power_state) { hda_nid_t nid = codec->start_nid; int i; for (i = 0; i < codec->num_nodes; i++, nid++) { unsigned int wcaps = get_wcaps(codec, nid); + unsigned int state = power_state; if (!(wcaps & AC_WCAP_POWER)) continue; - /* don't power down the widget if it controls eapd and - * EAPD_BTLENABLE is set. - */ - if (eapd_workaround && power_state == AC_PWRST_D3 && - get_wcaps_type(wcaps) == AC_WID_PIN && - (snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD)) { - int eapd = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_EAPD_BTLENABLE, 0); - if (eapd & 0x02) + if (codec->power_filter) { + state = codec->power_filter(codec, nid, power_state); + if (state != power_state && power_state == AC_PWRST_D3) continue; } snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE, - power_state); + state); } } EXPORT_SYMBOL_HDA(snd_hda_codec_set_power_to_all); @@ -3560,6 +3715,21 @@ static unsigned int hda_sync_power_state(struct hda_codec *codec, return state; } +/* don't power down the widget if it controls eapd and EAPD_BTLENABLE is set */ +static unsigned int default_power_filter(struct hda_codec *codec, hda_nid_t nid, + unsigned int power_state) +{ + if (power_state == AC_PWRST_D3 && + get_wcaps_type(get_wcaps(codec, nid)) == AC_WID_PIN && + (snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD)) { + int eapd = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_EAPD_BTLENABLE, 0); + if (eapd & 0x02) + return AC_PWRST_D0; + } + return power_state; +} + /* * set power state of the codec, and return the power state */ @@ -3585,8 +3755,7 @@ static unsigned int hda_set_power_state(struct hda_codec *codec, snd_hda_codec_read(codec, fg, 0, AC_VERB_SET_POWER_STATE, power_state); - snd_hda_codec_set_power_to_all(codec, fg, power_state, - true); + snd_hda_codec_set_power_to_all(codec, fg, power_state); } state = hda_sync_power_state(codec, fg, power_state); if (!(state & AC_PWRST_ERROR)) @@ -3596,6 +3765,32 @@ static unsigned int hda_set_power_state(struct hda_codec *codec, return state; } +/* sync power states of all widgets; + * this is called at the end of codec parsing + */ +static void sync_power_up_states(struct hda_codec *codec) +{ + hda_nid_t nid = codec->start_nid; + int i; + + /* don't care if no or standard filter is used */ + if (!codec->power_filter || codec->power_filter == default_power_filter) + return; + + for (i = 0; i < codec->num_nodes; i++, nid++) { + unsigned int wcaps = get_wcaps(codec, nid); + unsigned int target; + if (!(wcaps & AC_WCAP_POWER)) + continue; + target = codec->power_filter(codec, nid, AC_PWRST_D0); + if (target == AC_PWRST_D0) + continue; + if (!snd_hda_check_power_state(codec, nid, target)) + snd_hda_codec_write(codec, nid, 0, + AC_VERB_SET_POWER_STATE, target); + } +} + #ifdef CONFIG_SND_HDA_HWDEP /* execute additional init verbs */ static void hda_exec_init_verbs(struct hda_codec *codec) @@ -3616,6 +3811,8 @@ static unsigned int hda_call_codec_suspend(struct hda_codec *codec, bool in_wq) { unsigned int state; + codec->in_pm = 1; + if (codec->patch_ops.suspend) codec->patch_ops.suspend(codec); hda_cleanup_all_streams(codec); @@ -3630,20 +3827,40 @@ static unsigned int hda_call_codec_suspend(struct hda_codec *codec, bool in_wq) codec->power_transition = 0; codec->power_jiffies = jiffies; spin_unlock(&codec->power_lock); + codec->in_pm = 0; return state; } +/* mark all entries of cmd and amp caches dirty */ +static void hda_mark_cmd_cache_dirty(struct hda_codec *codec) +{ + int i; + for (i = 0; i < codec->cmd_cache.buf.used; i++) { + struct hda_cache_head *cmd; + cmd = snd_array_elem(&codec->cmd_cache.buf, i); + cmd->dirty = 1; + } + for (i = 0; i < codec->amp_cache.buf.used; i++) { + struct hda_amp_info *amp; + amp = snd_array_elem(&codec->amp_cache.buf, i); + amp->head.dirty = 1; + } +} + /* * kick up codec; used both from PM and power-save */ static void hda_call_codec_resume(struct hda_codec *codec) { + codec->in_pm = 1; + + hda_mark_cmd_cache_dirty(codec); + /* set as if powered on for avoiding re-entering the resume * in the resume / power-save sequence */ hda_keep_power_on(codec); hda_set_power_state(codec, AC_PWRST_D0); - restore_pincfgs(codec); /* restore all current pin configs */ restore_shutup_pins(codec); hda_exec_init_verbs(codec); snd_hda_jack_set_dirty_all(codec); @@ -3655,7 +3872,13 @@ static void hda_call_codec_resume(struct hda_codec *codec) snd_hda_codec_resume_amp(codec); snd_hda_codec_resume_cache(codec); } - snd_hda_jack_report_sync(codec); + + if (codec->jackpoll_interval) + hda_jackpoll_work(&codec->jackpoll_work.work); + else + snd_hda_jack_report_sync(codec); + + codec->in_pm = 0; snd_hda_power_down(codec); /* flag down before returning */ } #endif /* CONFIG_PM */ @@ -3669,7 +3892,7 @@ static void hda_call_codec_resume(struct hda_codec *codec) * * Returns 0 if successful, otherwise a negative error code. */ -int /*__devinit*/ snd_hda_build_controls(struct hda_bus *bus) +int snd_hda_build_controls(struct hda_bus *bus) { struct hda_codec *codec; @@ -3703,13 +3926,14 @@ static int add_std_chmaps(struct hda_codec *codec) struct hda_pcm_stream *hinfo = &codec->pcm_info[i].stream[str]; struct snd_pcm_chmap *chmap; + const struct snd_pcm_chmap_elem *elem; if (codec->pcm_info[i].own_chmap) continue; if (!pcm || !hinfo->substreams) continue; - err = snd_pcm_add_chmap_ctls(pcm, str, - snd_pcm_std_chmaps, + elem = hinfo->chmap ? hinfo->chmap : snd_pcm_std_chmaps; + err = snd_pcm_add_chmap_ctls(pcm, str, elem, hinfo->channels_max, 0, &chmap); if (err < 0) @@ -3720,6 +3944,19 @@ static int add_std_chmaps(struct hda_codec *codec) return 0; } +/* default channel maps for 2.1 speakers; + * since HD-audio supports only stereo, odd number channels are omitted + */ +const struct snd_pcm_chmap_elem snd_pcm_2_1_chmaps[] = { + { .channels = 2, + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR } }, + { .channels = 4, + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, + SNDRV_CHMAP_LFE, SNDRV_CHMAP_LFE } }, + { } +}; +EXPORT_SYMBOL_GPL(snd_pcm_2_1_chmaps); + int snd_hda_codec_build_controls(struct hda_codec *codec) { int err = 0; @@ -3737,7 +3974,11 @@ int snd_hda_codec_build_controls(struct hda_codec *codec) if (err < 0) return err; - snd_hda_jack_report_sync(codec); /* call at the last init point */ + if (codec->jackpoll_interval) + hda_jackpoll_work(&codec->jackpoll_work.work); + else + snd_hda_jack_report_sync(codec); /* call at the last init point */ + sync_power_up_states(codec); return 0; } @@ -4449,7 +4690,7 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, addr = codec->addr; else if (!idx && !knew->index) { idx = find_empty_mixer_ctl_idx(codec, - knew->name); + knew->name, 0); if (idx <= 0) return err; } else @@ -4762,6 +5003,34 @@ EXPORT_SYMBOL_HDA(snd_hda_input_mux_put); /* + * process kcontrol info callback of a simple string enum array + * when @num_items is 0 or @texts is NULL, assume a boolean enum array + */ +int snd_hda_enum_helper_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo, + int num_items, const char * const *texts) +{ + static const char * const texts_default[] = { + "Disabled", "Enabled" + }; + + if (!texts || !num_items) { + num_items = 2; + texts = texts_default; + } + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = num_items; + if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) + uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; + strcpy(uinfo->value.enumerated.name, + texts[uinfo->value.enumerated.item]); + return 0; +} +EXPORT_SYMBOL_HDA(snd_hda_enum_helper_info); + +/* * Multi-channel / digital-out PCM helper functions */ @@ -4769,10 +5038,20 @@ EXPORT_SYMBOL_HDA(snd_hda_input_mux_put); static void setup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid, unsigned int stream_tag, unsigned int format) { - struct hda_spdif_out *spdif = snd_hda_spdif_out_of_nid(codec, nid); - - /* turn off SPDIF once; otherwise the IEC958 bits won't be updated */ - if (codec->spdif_status_reset && (spdif->ctls & AC_DIG1_ENABLE)) + struct hda_spdif_out *spdif; + unsigned int curr_fmt; + bool reset; + + spdif = snd_hda_spdif_out_of_nid(codec, nid); + curr_fmt = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_STREAM_FORMAT, 0); + reset = codec->spdif_status_reset && + (spdif->ctls & AC_DIG1_ENABLE) && + curr_fmt != format; + + /* turn off SPDIF if needed; otherwise the IEC958 bits won't be + updated */ + if (reset) set_dig_out_convert(codec, nid, spdif->ctls & ~AC_DIG1_ENABLE & 0xff, -1); @@ -4784,7 +5063,7 @@ static void setup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid, format); } /* turn on again (if needed) */ - if (codec->spdif_status_reset && (spdif->ctls & AC_DIG1_ENABLE)) + if (reset) set_dig_out_convert(codec, nid, spdif->ctls & 0xff, -1); } @@ -5051,23 +5330,62 @@ unsigned int snd_hda_get_default_vref(struct hda_codec *codec, hda_nid_t pin) } EXPORT_SYMBOL_HDA(snd_hda_get_default_vref); -int _snd_hda_set_pin_ctl(struct hda_codec *codec, hda_nid_t pin, - unsigned int val, bool cached) +/* correct the pin ctl value for matching with the pin cap */ +unsigned int snd_hda_correct_pin_ctl(struct hda_codec *codec, + hda_nid_t pin, unsigned int val) { - if (val) { - unsigned int cap = snd_hda_query_pin_caps(codec, pin); - if (cap && (val & AC_PINCTL_OUT_EN)) { - if (!(cap & AC_PINCAP_OUT)) - val &= ~(AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN); - else if ((val & AC_PINCTL_HP_EN) && - !(cap & AC_PINCAP_HP_DRV)) - val &= ~AC_PINCTL_HP_EN; - } - if (cap && (val & AC_PINCTL_IN_EN)) { - if (!(cap & AC_PINCAP_IN)) - val &= ~(AC_PINCTL_IN_EN | AC_PINCTL_VREFEN); + static unsigned int cap_lists[][2] = { + { AC_PINCTL_VREF_100, AC_PINCAP_VREF_100 }, + { AC_PINCTL_VREF_80, AC_PINCAP_VREF_80 }, + { AC_PINCTL_VREF_50, AC_PINCAP_VREF_50 }, + { AC_PINCTL_VREF_GRD, AC_PINCAP_VREF_GRD }, + }; + unsigned int cap; + + if (!val) + return 0; + cap = snd_hda_query_pin_caps(codec, pin); + if (!cap) + return val; /* don't know what to do... */ + + if (val & AC_PINCTL_OUT_EN) { + if (!(cap & AC_PINCAP_OUT)) + val &= ~(AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN); + else if ((val & AC_PINCTL_HP_EN) && !(cap & AC_PINCAP_HP_DRV)) + val &= ~AC_PINCTL_HP_EN; + } + + if (val & AC_PINCTL_IN_EN) { + if (!(cap & AC_PINCAP_IN)) + val &= ~(AC_PINCTL_IN_EN | AC_PINCTL_VREFEN); + else { + unsigned int vcap, vref; + int i; + vcap = (cap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT; + vref = val & AC_PINCTL_VREFEN; + for (i = 0; i < ARRAY_SIZE(cap_lists); i++) { + if (vref == cap_lists[i][0] && + !(vcap & cap_lists[i][1])) { + if (i == ARRAY_SIZE(cap_lists) - 1) + vref = AC_PINCTL_VREF_HIZ; + else + vref = cap_lists[i + 1][0]; + } + } + val &= ~AC_PINCTL_VREFEN; + val |= vref; } } + + return val; +} +EXPORT_SYMBOL_HDA(snd_hda_correct_pin_ctl); + +int _snd_hda_set_pin_ctl(struct hda_codec *codec, hda_nid_t pin, + unsigned int val, bool cached) +{ + val = snd_hda_correct_pin_ctl(codec, pin, val); + snd_hda_codec_set_pin_target(codec, pin, val); if (cached) return snd_hda_codec_update_cache(codec, pin, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, val); @@ -5128,6 +5446,7 @@ int snd_hda_suspend(struct hda_bus *bus) struct hda_codec *codec; list_for_each_entry(codec, &bus->codec_list, list) { + cancel_delayed_work_sync(&codec->jackpoll_work); if (hda_codec_is_power_on(codec)) hda_call_codec_suspend(codec, false); } diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index c9f53bd587b0..6c592722efcd 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -730,9 +730,10 @@ struct hda_codec_ops { /* record for amp information cache */ struct hda_cache_head { - u32 key; /* hash key */ + u32 key:31; /* hash key */ + u32 dirty:1; u16 val; /* assigned value */ - u16 next; /* next link; -1 = terminal */ + u16 next; }; struct hda_amp_info { @@ -768,6 +769,7 @@ struct hda_pcm_stream { u32 rates; /* supported rates */ u64 formats; /* supported formats (SNDRV_PCM_FMTBIT_) */ unsigned int maxbps; /* supported max. bit per sample */ + const struct snd_pcm_chmap_elem *chmap; /* chmap to override */ struct hda_pcm_ops ops; }; @@ -840,19 +842,21 @@ struct hda_codec { struct hda_cache_rec amp_cache; /* cache for amp access */ struct hda_cache_rec cmd_cache; /* cache for other commands */ - struct snd_array conn_lists; /* connection-list array */ + struct list_head conn_list; /* linked-list of connection-list */ struct mutex spdif_mutex; struct mutex control_mutex; struct mutex hash_mutex; struct snd_array spdif_out; unsigned int spdif_in_enable; /* SPDIF input enable? */ + int primary_dig_out_type; /* primary digital out PCM type */ const hda_nid_t *slave_dig_outs; /* optional digital out slave widgets */ struct snd_array init_pins; /* initial (BIOS) pin configurations */ struct snd_array driver_pins; /* pin configs set by codec parser */ struct snd_array cvt_setups; /* audio convert setups */ #ifdef CONFIG_SND_HDA_HWDEP + struct mutex user_mutex; struct snd_hwdep *hwdep; /* assigned hwdep device */ struct snd_array init_verbs; /* additional init verbs */ struct snd_array hints; /* additional hints */ @@ -874,12 +878,16 @@ struct hda_codec { unsigned int pins_shutup:1; /* pins are shut up */ unsigned int no_trigger_sense:1; /* don't trigger at pin-sensing */ unsigned int no_jack_detect:1; /* Machine has no jack-detection */ + unsigned int inv_eapd:1; /* broken h/w: inverted EAPD control */ + unsigned int inv_jack_detect:1; /* broken h/w: inverted detection bit */ unsigned int pcm_format_first:1; /* PCM format must be set first */ unsigned int epss:1; /* supporting EPSS? */ + unsigned int cached_write:1; /* write only to caches */ #ifdef CONFIG_PM unsigned int power_on :1; /* current (global) power-state */ unsigned int d3_stop_clk:1; /* support D3 operation without BCLK */ unsigned int pm_down_notified:1; /* PM notified to controller */ + unsigned int in_pm:1; /* suspend/resume being performed */ int power_transition; /* power-state in transition */ int power_count; /* current (global) power refcount */ struct delayed_work power_work; /* delayed task for powerdown */ @@ -889,17 +897,31 @@ struct hda_codec { spinlock_t power_lock; #endif + /* filter the requested power state per nid */ + unsigned int (*power_filter)(struct hda_codec *codec, hda_nid_t nid, + unsigned int power_state); + /* codec-specific additional proc output */ void (*proc_widget_hook)(struct snd_info_buffer *buffer, struct hda_codec *codec, hda_nid_t nid); /* jack detection */ struct snd_array jacktbl; + unsigned long jackpoll_interval; /* In jiffies. Zero means no poll, rely on unsol events */ + struct delayed_work jackpoll_work; #ifdef CONFIG_SND_HDA_INPUT_JACK /* jack detection */ struct snd_array jacks; #endif + + /* fix-up list */ + int fixup_id; + const struct hda_fixup *fixup_list; + const char *fixup_name; + + /* additional init verbs */ + struct snd_array verbs; }; /* direction */ @@ -938,6 +960,8 @@ snd_hda_get_num_conns(struct hda_codec *codec, hda_nid_t nid) } int snd_hda_get_raw_connections(struct hda_codec *codec, hda_nid_t nid, hda_nid_t *conn_list, int max_conns); +int snd_hda_get_conn_list(struct hda_codec *codec, hda_nid_t nid, + const hda_nid_t **listp); int snd_hda_override_conn_list(struct hda_codec *codec, hda_nid_t nid, int nums, const hda_nid_t *list); int snd_hda_get_conn_index(struct hda_codec *codec, hda_nid_t mux, @@ -958,7 +982,6 @@ void snd_hda_sequence_write(struct hda_codec *codec, int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex); /* cached write */ -#ifdef CONFIG_PM int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid, int direct, unsigned int verb, unsigned int parm); void snd_hda_sequence_write_cache(struct hda_codec *codec, @@ -966,17 +989,14 @@ void snd_hda_sequence_write_cache(struct hda_codec *codec, int snd_hda_codec_update_cache(struct hda_codec *codec, hda_nid_t nid, int direct, unsigned int verb, unsigned int parm); void snd_hda_codec_resume_cache(struct hda_codec *codec); -#else -#define snd_hda_codec_write_cache snd_hda_codec_write -#define snd_hda_codec_update_cache snd_hda_codec_write -#define snd_hda_sequence_write_cache snd_hda_sequence_write -#endif +/* both for cmd & amp caches */ +void snd_hda_codec_flush_cache(struct hda_codec *codec); /* the struct for codec->pin_configs */ struct hda_pincfg { hda_nid_t nid; - unsigned char ctrl; /* current pin control value */ - unsigned char pad; /* reserved */ + unsigned char ctrl; /* original pin control value */ + unsigned char target; /* target pin control value */ unsigned int cfg; /* default configuration */ }; @@ -1034,14 +1054,15 @@ unsigned int snd_hda_calc_stream_format(unsigned int rate, int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid, unsigned int format); +extern const struct snd_pcm_chmap_elem snd_pcm_2_1_chmaps[]; + /* * Misc */ void snd_hda_get_codec_name(struct hda_codec *codec, char *name, int namelen); void snd_hda_bus_reboot_notify(struct hda_bus *bus); void snd_hda_codec_set_power_to_all(struct hda_codec *codec, hda_nid_t fg, - unsigned int power_state, - bool eapd_workaround); + unsigned int power_state); int snd_hda_lock_devices(struct hda_bus *bus); void snd_hda_unlock_devices(struct hda_bus *bus); diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index b81d3d0b952d..6af5aded1ed5 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -23,836 +23,3210 @@ #include <linux/init.h> #include <linux/slab.h> #include <linux/export.h> +#include <linux/sort.h> +#include <linux/delay.h> +#include <linux/ctype.h> +#include <linux/string.h> +#include <linux/bitops.h> #include <sound/core.h> +#include <sound/jack.h> #include "hda_codec.h" #include "hda_local.h" +#include "hda_auto_parser.h" +#include "hda_jack.h" +#include "hda_generic.h" -/* widget node for parsing */ -struct hda_gnode { - hda_nid_t nid; /* NID of this widget */ - unsigned short nconns; /* number of input connections */ - hda_nid_t *conn_list; - hda_nid_t slist[2]; /* temporay list */ - unsigned int wid_caps; /* widget capabilities */ - unsigned char type; /* widget type */ - unsigned char pin_ctl; /* pin controls */ - unsigned char checked; /* the flag indicates that the node is already parsed */ - unsigned int pin_caps; /* pin widget capabilities */ - unsigned int def_cfg; /* default configuration */ - unsigned int amp_out_caps; /* AMP out capabilities */ - unsigned int amp_in_caps; /* AMP in capabilities */ - struct list_head list; -}; -/* patch-specific record */ +/* initialize hda_gen_spec struct */ +int snd_hda_gen_spec_init(struct hda_gen_spec *spec) +{ + snd_array_init(&spec->kctls, sizeof(struct snd_kcontrol_new), 32); + snd_array_init(&spec->paths, sizeof(struct nid_path), 8); + snd_array_init(&spec->loopback_list, sizeof(struct hda_amp_list), 8); + mutex_init(&spec->pcm_mutex); + return 0; +} +EXPORT_SYMBOL_HDA(snd_hda_gen_spec_init); -#define MAX_PCM_VOLS 2 -struct pcm_vol { - struct hda_gnode *node; /* Node for PCM volume */ - unsigned int index; /* connection of PCM volume */ -}; +struct snd_kcontrol_new * +snd_hda_gen_add_kctl(struct hda_gen_spec *spec, const char *name, + const struct snd_kcontrol_new *temp) +{ + struct snd_kcontrol_new *knew = snd_array_new(&spec->kctls); + if (!knew) + return NULL; + *knew = *temp; + if (name) + knew->name = kstrdup(name, GFP_KERNEL); + else if (knew->name) + knew->name = kstrdup(knew->name, GFP_KERNEL); + if (!knew->name) + return NULL; + return knew; +} +EXPORT_SYMBOL_HDA(snd_hda_gen_add_kctl); -struct hda_gspec { - struct hda_gnode *dac_node[2]; /* DAC node */ - struct hda_gnode *out_pin_node[2]; /* Output pin (Line-Out) node */ - struct pcm_vol pcm_vol[MAX_PCM_VOLS]; /* PCM volumes */ - unsigned int pcm_vol_nodes; /* number of PCM volumes */ +static void free_kctls(struct hda_gen_spec *spec) +{ + if (spec->kctls.list) { + struct snd_kcontrol_new *kctl = spec->kctls.list; + int i; + for (i = 0; i < spec->kctls.used; i++) + kfree(kctl[i].name); + } + snd_array_free(&spec->kctls); +} - struct hda_gnode *adc_node; /* ADC node */ - struct hda_gnode *cap_vol_node; /* Node for capture volume */ - unsigned int cur_cap_src; /* current capture source */ - struct hda_input_mux input_mux; +void snd_hda_gen_spec_free(struct hda_gen_spec *spec) +{ + if (!spec) + return; + free_kctls(spec); + snd_array_free(&spec->paths); + snd_array_free(&spec->loopback_list); +} +EXPORT_SYMBOL_HDA(snd_hda_gen_spec_free); - unsigned int def_amp_in_caps; - unsigned int def_amp_out_caps; +/* + * store user hints + */ +static void parse_user_hints(struct hda_codec *codec) +{ + struct hda_gen_spec *spec = codec->spec; + int val; - struct hda_pcm pcm_rec; /* PCM information */ + val = snd_hda_get_bool_hint(codec, "jack_detect"); + if (val >= 0) + codec->no_jack_detect = !val; + val = snd_hda_get_bool_hint(codec, "inv_jack_detect"); + if (val >= 0) + codec->inv_jack_detect = !!val; + val = snd_hda_get_bool_hint(codec, "trigger_sense"); + if (val >= 0) + codec->no_trigger_sense = !val; + val = snd_hda_get_bool_hint(codec, "inv_eapd"); + if (val >= 0) + codec->inv_eapd = !!val; + val = snd_hda_get_bool_hint(codec, "pcm_format_first"); + if (val >= 0) + codec->pcm_format_first = !!val; + val = snd_hda_get_bool_hint(codec, "sticky_stream"); + if (val >= 0) + codec->no_sticky_stream = !val; + val = snd_hda_get_bool_hint(codec, "spdif_status_reset"); + if (val >= 0) + codec->spdif_status_reset = !!val; + val = snd_hda_get_bool_hint(codec, "pin_amp_workaround"); + if (val >= 0) + codec->pin_amp_workaround = !!val; + val = snd_hda_get_bool_hint(codec, "single_adc_amp"); + if (val >= 0) + codec->single_adc_amp = !!val; - struct list_head nid_list; /* list of widgets */ + val = snd_hda_get_bool_hint(codec, "auto_mute"); + if (val >= 0) + spec->suppress_auto_mute = !val; + val = snd_hda_get_bool_hint(codec, "auto_mic"); + if (val >= 0) + spec->suppress_auto_mic = !val; + val = snd_hda_get_bool_hint(codec, "line_in_auto_switch"); + if (val >= 0) + spec->line_in_auto_switch = !!val; + val = snd_hda_get_bool_hint(codec, "need_dac_fix"); + if (val >= 0) + spec->need_dac_fix = !!val; + val = snd_hda_get_bool_hint(codec, "primary_hp"); + if (val >= 0) + spec->no_primary_hp = !val; + val = snd_hda_get_bool_hint(codec, "multi_cap_vol"); + if (val >= 0) + spec->multi_cap_vol = !!val; + val = snd_hda_get_bool_hint(codec, "inv_dmic_split"); + if (val >= 0) + spec->inv_dmic_split = !!val; + val = snd_hda_get_bool_hint(codec, "indep_hp"); + if (val >= 0) + spec->indep_hp = !!val; + val = snd_hda_get_bool_hint(codec, "add_stereo_mix_input"); + if (val >= 0) + spec->add_stereo_mix_input = !!val; + val = snd_hda_get_bool_hint(codec, "add_out_jack_modes"); + if (val >= 0) + spec->add_out_jack_modes = !!val; + val = snd_hda_get_bool_hint(codec, "add_in_jack_modes"); + if (val >= 0) + spec->add_in_jack_modes = !!val; + val = snd_hda_get_bool_hint(codec, "power_down_unused"); + if (val >= 0) + spec->power_down_unused = !!val; -#ifdef CONFIG_PM -#define MAX_LOOPBACK_AMPS 7 - struct hda_loopback_check loopback; - int num_loopbacks; - struct hda_amp_list loopback_list[MAX_LOOPBACK_AMPS + 1]; -#endif -}; + if (!snd_hda_get_int_hint(codec, "mixer_nid", &val)) + spec->mixer_nid = val; +} /* - * retrieve the default device type from the default config value + * pin control value accesses */ -#define defcfg_type(node) (((node)->def_cfg & AC_DEFCFG_DEVICE) >> \ - AC_DEFCFG_DEVICE_SHIFT) -#define defcfg_location(node) (((node)->def_cfg & AC_DEFCFG_LOCATION) >> \ - AC_DEFCFG_LOCATION_SHIFT) -#define defcfg_port_conn(node) (((node)->def_cfg & AC_DEFCFG_PORT_CONN) >> \ - AC_DEFCFG_PORT_CONN_SHIFT) -/* - * destructor - */ -static void snd_hda_generic_free(struct hda_codec *codec) +#define update_pin_ctl(codec, pin, val) \ + snd_hda_codec_update_cache(codec, pin, 0, \ + AC_VERB_SET_PIN_WIDGET_CONTROL, val) + +/* restore the pinctl based on the cached value */ +static inline void restore_pin_ctl(struct hda_codec *codec, hda_nid_t pin) { - struct hda_gspec *spec = codec->spec; - struct hda_gnode *node, *n; + update_pin_ctl(codec, pin, snd_hda_codec_get_pin_target(codec, pin)); +} - if (! spec) +/* set the pinctl target value and write it if requested */ +static void set_pin_target(struct hda_codec *codec, hda_nid_t pin, + unsigned int val, bool do_write) +{ + if (!pin) return; - /* free all widgets */ - list_for_each_entry_safe(node, n, &spec->nid_list, list) { - if (node->conn_list != node->slist) - kfree(node->conn_list); - kfree(node); - } - kfree(spec); + val = snd_hda_correct_pin_ctl(codec, pin, val); + snd_hda_codec_set_pin_target(codec, pin, val); + if (do_write) + update_pin_ctl(codec, pin, val); } +/* set pinctl target values for all given pins */ +static void set_pin_targets(struct hda_codec *codec, int num_pins, + hda_nid_t *pins, unsigned int val) +{ + int i; + for (i = 0; i < num_pins; i++) + set_pin_target(codec, pins[i], val, false); +} /* - * add a new widget node and read its attributes + * parsing paths */ -static int add_new_node(struct hda_codec *codec, struct hda_gspec *spec, hda_nid_t nid) + +/* return the position of NID in the list, or -1 if not found */ +static int find_idx_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums) { - struct hda_gnode *node; - int nconns; - hda_nid_t conn_list[HDA_MAX_CONNECTIONS]; + int i; + for (i = 0; i < nums; i++) + if (list[i] == nid) + return i; + return -1; +} - node = kzalloc(sizeof(*node), GFP_KERNEL); - if (node == NULL) - return -ENOMEM; - node->nid = nid; - node->wid_caps = get_wcaps(codec, nid); - node->type = get_wcaps_type(node->wid_caps); - if (node->wid_caps & AC_WCAP_CONN_LIST) { - nconns = snd_hda_get_connections(codec, nid, conn_list, - HDA_MAX_CONNECTIONS); - if (nconns < 0) { - kfree(node); - return nconns; - } - } else { - nconns = 0; - } - if (nconns <= ARRAY_SIZE(node->slist)) - node->conn_list = node->slist; - else { - node->conn_list = kmalloc(sizeof(hda_nid_t) * nconns, - GFP_KERNEL); - if (! node->conn_list) { - snd_printk(KERN_ERR "hda-generic: cannot malloc\n"); - kfree(node); - return -ENOMEM; +/* return true if the given NID is contained in the path */ +static bool is_nid_contained(struct nid_path *path, hda_nid_t nid) +{ + return find_idx_in_nid_list(nid, path->path, path->depth) >= 0; +} + +static struct nid_path *get_nid_path(struct hda_codec *codec, + hda_nid_t from_nid, hda_nid_t to_nid, + int anchor_nid) +{ + struct hda_gen_spec *spec = codec->spec; + int i; + + for (i = 0; i < spec->paths.used; i++) { + struct nid_path *path = snd_array_elem(&spec->paths, i); + if (path->depth <= 0) + continue; + if ((!from_nid || path->path[0] == from_nid) && + (!to_nid || path->path[path->depth - 1] == to_nid)) { + if (!anchor_nid || + (anchor_nid > 0 && is_nid_contained(path, anchor_nid)) || + (anchor_nid < 0 && !is_nid_contained(path, anchor_nid))) + return path; } } - memcpy(node->conn_list, conn_list, nconns * sizeof(hda_nid_t)); - node->nconns = nconns; + return NULL; +} - if (node->type == AC_WID_PIN) { - node->pin_caps = snd_hda_query_pin_caps(codec, node->nid); - node->pin_ctl = snd_hda_codec_read(codec, node->nid, 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0); - node->def_cfg = snd_hda_codec_get_pincfg(codec, node->nid); +/* get the path between the given NIDs; + * passing 0 to either @pin or @dac behaves as a wildcard + */ +struct nid_path *snd_hda_get_nid_path(struct hda_codec *codec, + hda_nid_t from_nid, hda_nid_t to_nid) +{ + return get_nid_path(codec, from_nid, to_nid, 0); +} +EXPORT_SYMBOL_HDA(snd_hda_get_nid_path); + +/* get the index number corresponding to the path instance; + * the index starts from 1, for easier checking the invalid value + */ +int snd_hda_get_path_idx(struct hda_codec *codec, struct nid_path *path) +{ + struct hda_gen_spec *spec = codec->spec; + struct nid_path *array = spec->paths.list; + ssize_t idx; + + if (!spec->paths.used) + return 0; + idx = path - array; + if (idx < 0 || idx >= spec->paths.used) + return 0; + return idx + 1; +} +EXPORT_SYMBOL_HDA(snd_hda_get_path_idx); + +/* get the path instance corresponding to the given index number */ +struct nid_path *snd_hda_get_path_from_idx(struct hda_codec *codec, int idx) +{ + struct hda_gen_spec *spec = codec->spec; + + if (idx <= 0 || idx > spec->paths.used) + return NULL; + return snd_array_elem(&spec->paths, idx - 1); +} +EXPORT_SYMBOL_HDA(snd_hda_get_path_from_idx); + +/* check whether the given DAC is already found in any existing paths */ +static bool is_dac_already_used(struct hda_codec *codec, hda_nid_t nid) +{ + struct hda_gen_spec *spec = codec->spec; + int i; + + for (i = 0; i < spec->paths.used; i++) { + struct nid_path *path = snd_array_elem(&spec->paths, i); + if (path->path[0] == nid) + return true; } + return false; +} - if (node->wid_caps & AC_WCAP_OUT_AMP) { - if (node->wid_caps & AC_WCAP_AMP_OVRD) - node->amp_out_caps = snd_hda_param_read(codec, node->nid, AC_PAR_AMP_OUT_CAP); - if (! node->amp_out_caps) - node->amp_out_caps = spec->def_amp_out_caps; +/* check whether the given two widgets can be connected */ +static bool is_reachable_path(struct hda_codec *codec, + hda_nid_t from_nid, hda_nid_t to_nid) +{ + if (!from_nid || !to_nid) + return false; + return snd_hda_get_conn_index(codec, to_nid, from_nid, true) >= 0; +} + +/* nid, dir and idx */ +#define AMP_VAL_COMPARE_MASK (0xffff | (1U << 18) | (0x0f << 19)) + +/* check whether the given ctl is already assigned in any path elements */ +static bool is_ctl_used(struct hda_codec *codec, unsigned int val, int type) +{ + struct hda_gen_spec *spec = codec->spec; + int i; + + val &= AMP_VAL_COMPARE_MASK; + for (i = 0; i < spec->paths.used; i++) { + struct nid_path *path = snd_array_elem(&spec->paths, i); + if ((path->ctls[type] & AMP_VAL_COMPARE_MASK) == val) + return true; } - if (node->wid_caps & AC_WCAP_IN_AMP) { - if (node->wid_caps & AC_WCAP_AMP_OVRD) - node->amp_in_caps = snd_hda_param_read(codec, node->nid, AC_PAR_AMP_IN_CAP); - if (! node->amp_in_caps) - node->amp_in_caps = spec->def_amp_in_caps; + return false; +} + +/* check whether a control with the given (nid, dir, idx) was assigned */ +static bool is_ctl_associated(struct hda_codec *codec, hda_nid_t nid, + int dir, int idx, int type) +{ + unsigned int val = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir); + return is_ctl_used(codec, val, type); +} + +static void print_nid_path(const char *pfx, struct nid_path *path) +{ + char buf[40]; + int 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)); } - list_add_tail(&node->list, &spec->nid_list); - return 0; + snd_printdd("%s path: depth=%d %s\n", pfx, path->depth, buf); } +/* called recursively */ +static bool __parse_nid_path(struct hda_codec *codec, + hda_nid_t from_nid, hda_nid_t to_nid, + int anchor_nid, struct nid_path *path, + int depth) +{ + const hda_nid_t *conn; + int i, nums; + + if (to_nid == anchor_nid) + anchor_nid = 0; /* anchor passed */ + else if (to_nid == (hda_nid_t)(-anchor_nid)) + return false; /* hit the exclusive nid */ + + nums = snd_hda_get_conn_list(codec, to_nid, &conn); + for (i = 0; i < nums; i++) { + if (conn[i] != from_nid) { + /* special case: when from_nid is 0, + * try to find an empty DAC + */ + if (from_nid || + get_wcaps_type(get_wcaps(codec, conn[i])) != AC_WID_AUD_OUT || + is_dac_already_used(codec, conn[i])) + continue; + } + /* anchor is not requested or already passed? */ + if (anchor_nid <= 0) + goto found; + } + if (depth >= MAX_NID_PATH_DEPTH) + return false; + for (i = 0; i < nums; i++) { + unsigned int type; + type = get_wcaps_type(get_wcaps(codec, conn[i])); + if (type == AC_WID_AUD_OUT || type == AC_WID_AUD_IN || + type == AC_WID_PIN) + continue; + if (__parse_nid_path(codec, from_nid, conn[i], + anchor_nid, path, depth + 1)) + goto found; + } + return false; + + found: + path->path[path->depth] = conn[i]; + path->idx[path->depth + 1] = i; + if (nums > 1 && get_wcaps_type(get_wcaps(codec, to_nid)) != AC_WID_AUD_MIX) + path->multi[path->depth + 1] = 1; + path->depth++; + return true; +} + +/* parse the widget path from the given nid to the target nid; + * when @from_nid is 0, try to find an empty DAC; + * when @anchor_nid is set to a positive value, only paths through the widget + * with the given value are evaluated. + * when @anchor_nid is set to a negative value, paths through the widget + * with the negative of given value are excluded, only other paths are chosen. + * when @anchor_nid is zero, no special handling about path selection. + */ +bool snd_hda_parse_nid_path(struct hda_codec *codec, hda_nid_t from_nid, + hda_nid_t to_nid, int anchor_nid, + struct nid_path *path) +{ + if (__parse_nid_path(codec, from_nid, to_nid, anchor_nid, path, 1)) { + path->path[path->depth] = to_nid; + path->depth++; + return true; + } + return false; +} +EXPORT_SYMBOL_HDA(snd_hda_parse_nid_path); + /* - * build the AFG subtree + * parse the path between the given NIDs and add to the path list. + * if no valid path is found, return NULL */ -static int build_afg_tree(struct hda_codec *codec) +struct nid_path * +snd_hda_add_new_path(struct hda_codec *codec, hda_nid_t from_nid, + hda_nid_t to_nid, int anchor_nid) { - struct hda_gspec *spec = codec->spec; - int i, nodes, err; - hda_nid_t nid; + struct hda_gen_spec *spec = codec->spec; + struct nid_path *path; - if (snd_BUG_ON(!spec)) - return -EINVAL; + if (from_nid && to_nid && !is_reachable_path(codec, from_nid, to_nid)) + return NULL; - spec->def_amp_out_caps = snd_hda_param_read(codec, codec->afg, AC_PAR_AMP_OUT_CAP); - spec->def_amp_in_caps = snd_hda_param_read(codec, codec->afg, AC_PAR_AMP_IN_CAP); + /* check whether the path has been already added */ + path = get_nid_path(codec, from_nid, to_nid, anchor_nid); + if (path) + return path; - nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid); - if (! nid || nodes < 0) { - printk(KERN_ERR "Invalid AFG subtree\n"); - return -EINVAL; - } + path = snd_array_new(&spec->paths); + if (!path) + return NULL; + memset(path, 0, sizeof(*path)); + if (snd_hda_parse_nid_path(codec, from_nid, to_nid, anchor_nid, path)) + return path; + /* push back */ + spec->paths.used--; + return NULL; +} +EXPORT_SYMBOL_HDA(snd_hda_add_new_path); - /* parse all nodes belonging to the AFG */ - for (i = 0; i < nodes; i++, nid++) { - if ((err = add_new_node(codec, spec, nid)) < 0) - return err; +/* clear the given path as invalid so that it won't be picked up later */ +static void invalidate_nid_path(struct hda_codec *codec, int idx) +{ + struct nid_path *path = snd_hda_get_path_from_idx(codec, idx); + if (!path) + return; + memset(path, 0, sizeof(*path)); +} + +/* look for an empty DAC slot */ +static hda_nid_t look_for_dac(struct hda_codec *codec, hda_nid_t pin, + bool is_digital) +{ + struct hda_gen_spec *spec = codec->spec; + bool cap_digital; + int i; + + for (i = 0; i < spec->num_all_dacs; i++) { + hda_nid_t nid = spec->all_dacs[i]; + if (!nid || is_dac_already_used(codec, nid)) + continue; + cap_digital = !!(get_wcaps(codec, nid) & AC_WCAP_DIGITAL); + if (is_digital != cap_digital) + continue; + if (is_reachable_path(codec, nid, pin)) + return nid; } + return 0; +} + +/* replace the channels in the composed amp value with the given number */ +static unsigned int amp_val_replace_channels(unsigned int val, unsigned int chs) +{ + val &= ~(0x3U << 16); + val |= chs << 16; + return val; +} + +/* check whether the widget has the given amp capability for the direction */ +static bool check_amp_caps(struct hda_codec *codec, hda_nid_t nid, + int dir, unsigned int bits) +{ + if (!nid) + return false; + if (get_wcaps(codec, nid) & (1 << (dir + 1))) + if (query_amp_caps(codec, nid, dir) & bits) + return true; + return false; +} + +static bool same_amp_caps(struct hda_codec *codec, hda_nid_t nid1, + hda_nid_t nid2, int dir) +{ + if (!(get_wcaps(codec, nid1) & (1 << (dir + 1)))) + return !(get_wcaps(codec, nid2) & (1 << (dir + 1))); + return (query_amp_caps(codec, nid1, dir) == + query_amp_caps(codec, nid2, dir)); +} + +#define nid_has_mute(codec, nid, dir) \ + check_amp_caps(codec, nid, dir, AC_AMPCAP_MUTE) +#define nid_has_volume(codec, nid, dir) \ + check_amp_caps(codec, nid, dir, AC_AMPCAP_NUM_STEPS) +/* look for a widget suitable for assigning a mute switch in the path */ +static hda_nid_t look_for_out_mute_nid(struct hda_codec *codec, + struct nid_path *path) +{ + int i; + + for (i = path->depth - 1; i >= 0; i--) { + if (nid_has_mute(codec, path->path[i], HDA_OUTPUT)) + return path->path[i]; + if (i != path->depth - 1 && i != 0 && + nid_has_mute(codec, path->path[i], HDA_INPUT)) + return path->path[i]; + } return 0; } +/* look for a widget suitable for assigning a volume ctl in the path */ +static hda_nid_t look_for_out_vol_nid(struct hda_codec *codec, + struct nid_path *path) +{ + int i; + + for (i = path->depth - 1; i >= 0; i--) { + if (nid_has_volume(codec, path->path[i], HDA_OUTPUT)) + return path->path[i]; + } + return 0; +} /* - * look for the node record for the given NID + * path activation / deactivation */ -/* FIXME: should avoid the braindead linear search */ -static struct hda_gnode *hda_get_node(struct hda_gspec *spec, hda_nid_t nid) + +/* can have the amp-in capability? */ +static bool has_amp_in(struct hda_codec *codec, struct nid_path *path, int idx) { - struct hda_gnode *node; + hda_nid_t nid = path->path[idx]; + unsigned int caps = get_wcaps(codec, nid); + unsigned int type = get_wcaps_type(caps); - list_for_each_entry(node, &spec->nid_list, list) { - if (node->nid == nid) - return node; + if (!(caps & AC_WCAP_IN_AMP)) + return false; + if (type == AC_WID_PIN && idx > 0) /* only for input pins */ + return false; + return true; +} + +/* can have the amp-out capability? */ +static bool has_amp_out(struct hda_codec *codec, struct nid_path *path, int idx) +{ + hda_nid_t nid = path->path[idx]; + unsigned int caps = get_wcaps(codec, nid); + unsigned int type = get_wcaps_type(caps); + + if (!(caps & AC_WCAP_OUT_AMP)) + return false; + if (type == AC_WID_PIN && !idx) /* only for output pins */ + return false; + return true; +} + +/* check whether the given (nid,dir,idx) is active */ +static bool is_active_nid(struct hda_codec *codec, hda_nid_t nid, + unsigned int dir, unsigned int idx) +{ + struct hda_gen_spec *spec = codec->spec; + int i, n; + + for (n = 0; n < spec->paths.used; n++) { + struct nid_path *path = snd_array_elem(&spec->paths, n); + if (!path->active) + continue; + for (i = 0; i < path->depth; i++) { + if (path->path[i] == nid) { + if (dir == HDA_OUTPUT || path->idx[i] == idx) + return true; + break; + } + } } - return NULL; + return false; } -/* - * unmute (and set max vol) the output amplifier +/* get the default amp value for the target state */ +static int get_amp_val_to_activate(struct hda_codec *codec, hda_nid_t nid, + int dir, unsigned int caps, bool enable) +{ + unsigned int val = 0; + + if (caps & AC_AMPCAP_NUM_STEPS) { + /* set to 0dB */ + if (enable) + val = (caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT; + } + if (caps & AC_AMPCAP_MUTE) { + if (!enable) + val |= HDA_AMP_MUTE; + } + return val; +} + +/* initialize the amp value (only at the first time) */ +static void init_amp(struct hda_codec *codec, hda_nid_t nid, int dir, int idx) +{ + unsigned int caps = query_amp_caps(codec, nid, dir); + int val = get_amp_val_to_activate(codec, nid, dir, caps, false); + snd_hda_codec_amp_init_stereo(codec, nid, dir, idx, 0xff, val); +} + +/* calculate amp value mask we can modify; + * if the given amp is controlled by mixers, don't touch it */ -static int unmute_output(struct hda_codec *codec, struct hda_gnode *node) -{ - unsigned int val, ofs; - snd_printdd("UNMUTE OUT: NID=0x%x\n", node->nid); - val = (node->amp_out_caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT; - ofs = (node->amp_out_caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT; - if (val >= ofs) - val -= ofs; - snd_hda_codec_amp_stereo(codec, node->nid, HDA_OUTPUT, 0, 0xff, val); - return 0; +static unsigned int get_amp_mask_to_modify(struct hda_codec *codec, + hda_nid_t nid, int dir, int idx, + unsigned int caps) +{ + unsigned int mask = 0xff; + + if (caps & AC_AMPCAP_MUTE) { + if (is_ctl_associated(codec, nid, dir, idx, NID_PATH_MUTE_CTL)) + mask &= ~0x80; + } + if (caps & AC_AMPCAP_NUM_STEPS) { + if (is_ctl_associated(codec, nid, dir, idx, NID_PATH_VOL_CTL) || + is_ctl_associated(codec, nid, dir, idx, NID_PATH_BOOST_CTL)) + mask &= ~0x7f; + } + return mask; } -/* - * unmute (and set max vol) the input amplifier +static void activate_amp(struct hda_codec *codec, hda_nid_t nid, int dir, + int idx, int idx_to_check, bool enable) +{ + unsigned int caps; + unsigned int mask, val; + + if (!enable && is_active_nid(codec, nid, dir, idx_to_check)) + return; + + caps = query_amp_caps(codec, nid, dir); + val = get_amp_val_to_activate(codec, nid, dir, caps, enable); + mask = get_amp_mask_to_modify(codec, nid, dir, idx_to_check, caps); + if (!mask) + return; + + val &= mask; + snd_hda_codec_amp_stereo(codec, nid, dir, idx, mask, val); +} + +static void activate_amp_out(struct hda_codec *codec, struct nid_path *path, + int i, bool enable) +{ + hda_nid_t nid = path->path[i]; + init_amp(codec, nid, HDA_OUTPUT, 0); + activate_amp(codec, nid, HDA_OUTPUT, 0, 0, enable); +} + +static void activate_amp_in(struct hda_codec *codec, struct nid_path *path, + int i, bool enable, bool add_aamix) +{ + struct hda_gen_spec *spec = codec->spec; + const hda_nid_t *conn; + int n, nums, idx; + int type; + hda_nid_t nid = path->path[i]; + + nums = snd_hda_get_conn_list(codec, nid, &conn); + type = get_wcaps_type(get_wcaps(codec, nid)); + if (type == AC_WID_PIN || + (type == AC_WID_AUD_IN && codec->single_adc_amp)) { + nums = 1; + idx = 0; + } else + idx = path->idx[i]; + + for (n = 0; n < nums; n++) + init_amp(codec, nid, HDA_INPUT, n); + + /* here is a little bit tricky in comparison with activate_amp_out(); + * when aa-mixer is available, we need to enable the path as well + */ + for (n = 0; n < nums; n++) { + if (n != idx && (!add_aamix || conn[n] != spec->mixer_merge_nid)) + continue; + activate_amp(codec, nid, HDA_INPUT, n, idx, enable); + } +} + +/* activate or deactivate the given path + * if @add_aamix is set, enable the input from aa-mix NID as well (if any) */ -static int unmute_input(struct hda_codec *codec, struct hda_gnode *node, unsigned int index) -{ - unsigned int val, ofs; - snd_printdd("UNMUTE IN: NID=0x%x IDX=0x%x\n", node->nid, index); - val = (node->amp_in_caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT; - ofs = (node->amp_in_caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT; - if (val >= ofs) - val -= ofs; - snd_hda_codec_amp_stereo(codec, node->nid, HDA_INPUT, index, 0xff, val); - return 0; +void snd_hda_activate_path(struct hda_codec *codec, struct nid_path *path, + bool enable, bool add_aamix) +{ + struct hda_gen_spec *spec = codec->spec; + int i; + + if (!enable) + path->active = false; + + for (i = path->depth - 1; i >= 0; i--) { + hda_nid_t nid = path->path[i]; + if (enable && spec->power_down_unused) { + /* make sure the widget is powered up */ + if (!snd_hda_check_power_state(codec, nid, AC_PWRST_D0)) + snd_hda_codec_write(codec, nid, 0, + AC_VERB_SET_POWER_STATE, + AC_PWRST_D0); + } + if (enable && path->multi[i]) + snd_hda_codec_write_cache(codec, nid, 0, + AC_VERB_SET_CONNECT_SEL, + path->idx[i]); + if (has_amp_in(codec, path, i)) + activate_amp_in(codec, path, i, enable, add_aamix); + if (has_amp_out(codec, path, i)) + activate_amp_out(codec, path, i, enable); + } + + if (enable) + path->active = true; } +EXPORT_SYMBOL_HDA(snd_hda_activate_path); + +/* if the given path is inactive, put widgets into D3 (only if suitable) */ +static void path_power_down_sync(struct hda_codec *codec, struct nid_path *path) +{ + struct hda_gen_spec *spec = codec->spec; + bool changed; + int i; + + if (!spec->power_down_unused || path->active) + return; + + for (i = 0; i < path->depth; i++) { + hda_nid_t nid = path->path[i]; + if (!snd_hda_check_power_state(codec, nid, AC_PWRST_D3)) { + snd_hda_codec_write(codec, nid, 0, + AC_VERB_SET_POWER_STATE, + AC_PWRST_D3); + changed = true; + } + } + + if (changed) { + msleep(10); + snd_hda_codec_read(codec, path->path[0], 0, + AC_VERB_GET_POWER_STATE, 0); + } +} + +/* turn on/off EAPD on the given pin */ +static void set_pin_eapd(struct hda_codec *codec, hda_nid_t pin, bool enable) +{ + struct hda_gen_spec *spec = codec->spec; + if (spec->own_eapd_ctl || + !(snd_hda_query_pin_caps(codec, pin) & AC_PINCAP_EAPD)) + return; + if (codec->inv_eapd) + enable = !enable; + snd_hda_codec_update_cache(codec, pin, 0, + AC_VERB_SET_EAPD_BTLENABLE, + enable ? 0x02 : 0x00); +} + +/* re-initialize the path specified by the given path index */ +static void resume_path_from_idx(struct hda_codec *codec, int path_idx) +{ + struct nid_path *path = snd_hda_get_path_from_idx(codec, path_idx); + if (path) + snd_hda_activate_path(codec, path, path->active, false); +} + /* - * select the input connection of the given node. + * Helper functions for creating mixer ctl elements */ -static int select_input_connection(struct hda_codec *codec, struct hda_gnode *node, - unsigned int index) + +enum { + HDA_CTL_WIDGET_VOL, + HDA_CTL_WIDGET_MUTE, + HDA_CTL_BIND_MUTE, +}; +static const struct snd_kcontrol_new control_templates[] = { + HDA_CODEC_VOLUME(NULL, 0, 0, 0), + HDA_CODEC_MUTE(NULL, 0, 0, 0), + HDA_BIND_MUTE(NULL, 0, 0, 0), +}; + +/* add dynamic controls from template */ +static struct snd_kcontrol_new * +add_control(struct hda_gen_spec *spec, int type, const char *name, + int cidx, unsigned long val) { - snd_printdd("CONNECT: NID=0x%x IDX=0x%x\n", node->nid, index); - return snd_hda_codec_write_cache(codec, node->nid, 0, - AC_VERB_SET_CONNECT_SEL, index); + struct snd_kcontrol_new *knew; + + knew = snd_hda_gen_add_kctl(spec, name, &control_templates[type]); + if (!knew) + return NULL; + knew->index = cidx; + if (get_amp_nid_(val)) + knew->subdevice = HDA_SUBDEV_AMP_FLAG; + knew->private_value = val; + return knew; } -/* - * clear checked flag of each node in the node list +static int add_control_with_pfx(struct hda_gen_spec *spec, int type, + const char *pfx, const char *dir, + const char *sfx, int cidx, unsigned long val) +{ + char name[32]; + snprintf(name, sizeof(name), "%s %s %s", pfx, dir, sfx); + if (!add_control(spec, type, name, cidx, val)) + return -ENOMEM; + return 0; +} + +#define add_pb_vol_ctrl(spec, type, pfx, val) \ + add_control_with_pfx(spec, type, pfx, "Playback", "Volume", 0, val) +#define add_pb_sw_ctrl(spec, type, pfx, val) \ + add_control_with_pfx(spec, type, pfx, "Playback", "Switch", 0, val) +#define __add_pb_vol_ctrl(spec, type, pfx, cidx, val) \ + add_control_with_pfx(spec, type, pfx, "Playback", "Volume", cidx, val) +#define __add_pb_sw_ctrl(spec, type, pfx, cidx, val) \ + add_control_with_pfx(spec, type, pfx, "Playback", "Switch", cidx, val) + +static int add_vol_ctl(struct hda_codec *codec, const char *pfx, int cidx, + unsigned int chs, struct nid_path *path) +{ + unsigned int val; + if (!path) + return 0; + val = path->ctls[NID_PATH_VOL_CTL]; + if (!val) + return 0; + val = amp_val_replace_channels(val, chs); + return __add_pb_vol_ctrl(codec->spec, HDA_CTL_WIDGET_VOL, pfx, cidx, val); +} + +/* return the channel bits suitable for the given path->ctls[] */ +static int get_default_ch_nums(struct hda_codec *codec, struct nid_path *path, + int type) +{ + int chs = 1; /* mono (left only) */ + if (path) { + hda_nid_t nid = get_amp_nid_(path->ctls[type]); + if (nid && (get_wcaps(codec, nid) & AC_WCAP_STEREO)) + chs = 3; /* stereo */ + } + return chs; +} + +static int add_stereo_vol(struct hda_codec *codec, const char *pfx, int cidx, + struct nid_path *path) +{ + int chs = get_default_ch_nums(codec, path, NID_PATH_VOL_CTL); + return add_vol_ctl(codec, pfx, cidx, chs, path); +} + +/* create a mute-switch for the given mixer widget; + * if it has multiple sources (e.g. DAC and loopback), create a bind-mute */ -static void clear_check_flags(struct hda_gspec *spec) +static int add_sw_ctl(struct hda_codec *codec, const char *pfx, int cidx, + unsigned int chs, struct nid_path *path) +{ + unsigned int val; + int type = HDA_CTL_WIDGET_MUTE; + + if (!path) + return 0; + val = path->ctls[NID_PATH_MUTE_CTL]; + if (!val) + return 0; + val = amp_val_replace_channels(val, chs); + if (get_amp_direction_(val) == HDA_INPUT) { + hda_nid_t nid = get_amp_nid_(val); + int nums = snd_hda_get_num_conns(codec, nid); + if (nums > 1) { + type = HDA_CTL_BIND_MUTE; + val |= nums << 19; + } + } + return __add_pb_sw_ctrl(codec->spec, type, pfx, cidx, val); +} + +static int add_stereo_sw(struct hda_codec *codec, const char *pfx, + int cidx, struct nid_path *path) +{ + int chs = get_default_ch_nums(codec, path, NID_PATH_MUTE_CTL); + return add_sw_ctl(codec, pfx, cidx, chs, path); +} + +/* any ctl assigned to the path with the given index? */ +static bool path_has_mixer(struct hda_codec *codec, int path_idx, int ctl_type) +{ + struct nid_path *path = snd_hda_get_path_from_idx(codec, path_idx); + return path && path->ctls[ctl_type]; +} + +static const char * const channel_name[4] = { + "Front", "Surround", "CLFE", "Side" +}; + +/* give some appropriate ctl name prefix for the given line out channel */ +static const char *get_line_out_pfx(struct hda_codec *codec, int ch, + int *index, int ctl_type) { - struct hda_gnode *node; + struct hda_gen_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + + *index = 0; + if (cfg->line_outs == 1 && !spec->multi_ios && + !cfg->hp_outs && !cfg->speaker_outs) + return spec->vmaster_mute.hook ? "PCM" : "Master"; + + /* if there is really a single DAC used in the whole output paths, + * use it master (or "PCM" if a vmaster hook is present) + */ + if (spec->multiout.num_dacs == 1 && !spec->mixer_nid && + !spec->multiout.hp_out_nid[0] && !spec->multiout.extra_out_nid[0]) + return spec->vmaster_mute.hook ? "PCM" : "Master"; + + /* multi-io channels */ + if (ch >= cfg->line_outs) + return channel_name[ch]; + + switch (cfg->line_out_type) { + case AUTO_PIN_SPEAKER_OUT: + /* if the primary channel vol/mute is shared with HP volume, + * don't name it as Speaker + */ + if (!ch && cfg->hp_outs && + !path_has_mixer(codec, spec->hp_paths[0], ctl_type)) + break; + if (cfg->line_outs == 1) + return "Speaker"; + if (cfg->line_outs == 2) + return ch ? "Bass Speaker" : "Speaker"; + break; + case AUTO_PIN_HP_OUT: + /* if the primary channel vol/mute is shared with spk volume, + * don't name it as Headphone + */ + if (!ch && cfg->speaker_outs && + !path_has_mixer(codec, spec->speaker_paths[0], ctl_type)) + break; + /* for multi-io case, only the primary out */ + if (ch && spec->multi_ios) + break; + *index = ch; + return "Headphone"; + } + + /* for a single channel output, we don't have to name the channel */ + if (cfg->line_outs == 1 && !spec->multi_ios) + return "PCM"; - list_for_each_entry(node, &spec->nid_list, list) { - node->checked = 0; + if (ch >= ARRAY_SIZE(channel_name)) { + snd_BUG(); + return "PCM"; } + + return channel_name[ch]; } /* - * parse the output path recursively until reach to an audio output widget + * Parse output paths + */ + +/* badness definition */ +enum { + /* No primary DAC is found for the main output */ + BAD_NO_PRIMARY_DAC = 0x10000, + /* No DAC is found for the extra output */ + BAD_NO_DAC = 0x4000, + /* No possible multi-ios */ + BAD_MULTI_IO = 0x103, + /* No individual DAC for extra output */ + BAD_NO_EXTRA_DAC = 0x102, + /* No individual DAC for extra surrounds */ + BAD_NO_EXTRA_SURR_DAC = 0x101, + /* Primary DAC shared with main surrounds */ + BAD_SHARED_SURROUND = 0x100, + /* Primary DAC shared with main CLFE */ + BAD_SHARED_CLFE = 0x10, + /* Primary DAC shared with extra surrounds */ + BAD_SHARED_EXTRA_SURROUND = 0x10, + /* Volume widget is shared */ + BAD_SHARED_VOL = 0x10, +}; + +/* look for widgets in the given path which are appropriate for + * volume and mute controls, and assign the values to ctls[]. * - * returns 0 if not found, 1 if found, or a negative error code. + * When no appropriate widget is found in the path, the badness value + * is incremented depending on the situation. The function returns the + * total badness for both volume and mute controls. */ -static int parse_output_path(struct hda_codec *codec, struct hda_gspec *spec, - struct hda_gnode *node, int dac_idx) +static int assign_out_path_ctls(struct hda_codec *codec, struct nid_path *path) { - int i, err; - struct hda_gnode *child; + hda_nid_t nid; + unsigned int val; + int badness = 0; + + if (!path) + return BAD_SHARED_VOL * 2; + + if (path->ctls[NID_PATH_VOL_CTL] || + path->ctls[NID_PATH_MUTE_CTL]) + return 0; /* already evaluated */ - if (node->checked) + nid = look_for_out_vol_nid(codec, path); + if (nid) { + val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); + if (is_ctl_used(codec, val, NID_PATH_VOL_CTL)) + badness += BAD_SHARED_VOL; + else + path->ctls[NID_PATH_VOL_CTL] = val; + } else + badness += BAD_SHARED_VOL; + nid = look_for_out_mute_nid(codec, path); + if (nid) { + unsigned int wid_type = get_wcaps_type(get_wcaps(codec, nid)); + if (wid_type == AC_WID_PIN || wid_type == AC_WID_AUD_OUT || + nid_has_mute(codec, nid, HDA_OUTPUT)) + val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); + else + val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT); + if (is_ctl_used(codec, val, NID_PATH_MUTE_CTL)) + badness += BAD_SHARED_VOL; + else + path->ctls[NID_PATH_MUTE_CTL] = val; + } else + badness += BAD_SHARED_VOL; + return badness; +} + +struct badness_table { + int no_primary_dac; /* no primary DAC */ + int no_dac; /* no secondary DACs */ + int shared_primary; /* primary DAC is shared with main output */ + int shared_surr; /* secondary DAC shared with main or primary */ + int shared_clfe; /* third DAC shared with main or primary */ + int shared_surr_main; /* secondary DAC sahred with main/DAC0 */ +}; + +static struct badness_table main_out_badness = { + .no_primary_dac = BAD_NO_PRIMARY_DAC, + .no_dac = BAD_NO_DAC, + .shared_primary = BAD_NO_PRIMARY_DAC, + .shared_surr = BAD_SHARED_SURROUND, + .shared_clfe = BAD_SHARED_CLFE, + .shared_surr_main = BAD_SHARED_SURROUND, +}; + +static struct badness_table extra_out_badness = { + .no_primary_dac = BAD_NO_DAC, + .no_dac = BAD_NO_DAC, + .shared_primary = BAD_NO_EXTRA_DAC, + .shared_surr = BAD_SHARED_EXTRA_SURROUND, + .shared_clfe = BAD_SHARED_EXTRA_SURROUND, + .shared_surr_main = BAD_NO_EXTRA_SURR_DAC, +}; + +/* get the DAC of the primary output corresponding to the given array index */ +static hda_nid_t get_primary_out(struct hda_codec *codec, int idx) +{ + struct hda_gen_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + + if (cfg->line_outs > idx) + return spec->private_dac_nids[idx]; + idx -= cfg->line_outs; + if (spec->multi_ios > idx) + return spec->multi_io[idx].dac; + return 0; +} + +/* return the DAC if it's reachable, otherwise zero */ +static inline hda_nid_t try_dac(struct hda_codec *codec, + hda_nid_t dac, hda_nid_t pin) +{ + return is_reachable_path(codec, dac, pin) ? dac : 0; +} + +/* try to assign DACs to pins and return the resultant badness */ +static int try_assign_dacs(struct hda_codec *codec, int num_outs, + const hda_nid_t *pins, hda_nid_t *dacs, + int *path_idx, + const struct badness_table *bad) +{ + struct hda_gen_spec *spec = codec->spec; + int i, j; + int badness = 0; + hda_nid_t dac; + + if (!num_outs) return 0; - node->checked = 1; - if (node->type == AC_WID_AUD_OUT) { - if (node->wid_caps & AC_WCAP_DIGITAL) { - snd_printdd("Skip Digital OUT node %x\n", node->nid); - return 0; + for (i = 0; i < num_outs; i++) { + struct nid_path *path; + hda_nid_t pin = pins[i]; + + path = snd_hda_get_path_from_idx(codec, path_idx[i]); + if (path) { + badness += assign_out_path_ctls(codec, path); + continue; + } + + dacs[i] = look_for_dac(codec, pin, false); + if (!dacs[i] && !i) { + /* try to steal the DAC of surrounds for the front */ + for (j = 1; j < num_outs; j++) { + if (is_reachable_path(codec, dacs[j], pin)) { + dacs[0] = dacs[j]; + dacs[j] = 0; + invalidate_nid_path(codec, path_idx[j]); + path_idx[j] = 0; + break; + } + } + } + dac = dacs[i]; + if (!dac) { + if (num_outs > 2) + dac = try_dac(codec, get_primary_out(codec, i), pin); + if (!dac) + dac = try_dac(codec, dacs[0], pin); + if (!dac) + dac = try_dac(codec, get_primary_out(codec, i), pin); + if (dac) { + if (!i) + badness += bad->shared_primary; + else if (i == 1) + badness += bad->shared_surr; + else + badness += bad->shared_clfe; + } else if (is_reachable_path(codec, spec->private_dac_nids[0], pin)) { + dac = spec->private_dac_nids[0]; + badness += bad->shared_surr_main; + } else if (!i) + badness += bad->no_primary_dac; + else + badness += bad->no_dac; } - snd_printdd("AUD_OUT found %x\n", node->nid); - if (spec->dac_node[dac_idx]) { - /* already DAC node is assigned, just unmute & connect */ - return node == spec->dac_node[dac_idx]; + if (!dac) + continue; + path = snd_hda_add_new_path(codec, dac, pin, -spec->mixer_nid); + if (!path && !i && spec->mixer_nid) { + /* try with aamix */ + path = snd_hda_add_new_path(codec, dac, pin, 0); } - spec->dac_node[dac_idx] = node; - if ((node->wid_caps & AC_WCAP_OUT_AMP) && - spec->pcm_vol_nodes < MAX_PCM_VOLS) { - spec->pcm_vol[spec->pcm_vol_nodes].node = node; - spec->pcm_vol[spec->pcm_vol_nodes].index = 0; - spec->pcm_vol_nodes++; + if (!path) { + dac = dacs[i] = 0; + badness += bad->no_dac; + } else { + /* print_nid_path("output", path); */ + path->active = true; + path_idx[i] = snd_hda_get_path_idx(codec, path); + badness += assign_out_path_ctls(codec, path); } - return 1; /* found */ } - for (i = 0; i < node->nconns; i++) { - child = hda_get_node(spec, node->conn_list[i]); - if (! child) + return badness; +} + +/* return NID if the given pin has only a single connection to a certain DAC */ +static hda_nid_t get_dac_if_single(struct hda_codec *codec, hda_nid_t pin) +{ + struct hda_gen_spec *spec = codec->spec; + int i; + hda_nid_t nid_found = 0; + + for (i = 0; i < spec->num_all_dacs; i++) { + hda_nid_t nid = spec->all_dacs[i]; + if (!nid || is_dac_already_used(codec, nid)) continue; - err = parse_output_path(codec, spec, child, dac_idx); - if (err < 0) - return err; - else if (err > 0) { - /* found one, - * select the path, unmute both input and output - */ - if (node->nconns > 1) - select_input_connection(codec, node, i); - unmute_input(codec, node, i); - unmute_output(codec, node); - if (spec->dac_node[dac_idx] && - spec->pcm_vol_nodes < MAX_PCM_VOLS && - !(spec->dac_node[dac_idx]->wid_caps & - AC_WCAP_OUT_AMP)) { - if ((node->wid_caps & AC_WCAP_IN_AMP) || - (node->wid_caps & AC_WCAP_OUT_AMP)) { - int n = spec->pcm_vol_nodes; - spec->pcm_vol[n].node = node; - spec->pcm_vol[n].index = i; - spec->pcm_vol_nodes++; - } - } - return 1; + if (is_reachable_path(codec, nid, pin)) { + if (nid_found) + return 0; + nid_found = nid; } } - return 0; + return nid_found; +} + +/* check whether the given pin can be a multi-io pin */ +static bool can_be_multiio_pin(struct hda_codec *codec, + unsigned int location, hda_nid_t nid) +{ + unsigned int defcfg, caps; + + defcfg = snd_hda_codec_get_pincfg(codec, nid); + if (get_defcfg_connect(defcfg) != AC_JACK_PORT_COMPLEX) + return false; + if (location && get_defcfg_location(defcfg) != location) + return false; + caps = snd_hda_query_pin_caps(codec, nid); + if (!(caps & AC_PINCAP_OUT)) + return false; + return true; +} + +/* count the number of input pins that are capable to be multi-io */ +static int count_multiio_pins(struct hda_codec *codec, hda_nid_t reference_pin) +{ + struct hda_gen_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + unsigned int defcfg = snd_hda_codec_get_pincfg(codec, reference_pin); + unsigned int location = get_defcfg_location(defcfg); + int type, i; + int num_pins = 0; + + for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) { + for (i = 0; i < cfg->num_inputs; i++) { + if (cfg->inputs[i].type != type) + continue; + if (can_be_multiio_pin(codec, location, + cfg->inputs[i].pin)) + num_pins++; + } + } + return num_pins; } /* - * Look for the output PIN widget with the given jack type - * and parse the output path to that PIN. + * multi-io helper * - * Returns the PIN node when the path to DAC is established. + * When hardwired is set, try to fill ony hardwired pins, and returns + * zero if any pins are filled, non-zero if nothing found. + * When hardwired is off, try to fill possible input pins, and returns + * the badness value. */ -static struct hda_gnode *parse_output_jack(struct hda_codec *codec, - struct hda_gspec *spec, - int jack_type) +static int fill_multi_ios(struct hda_codec *codec, + hda_nid_t reference_pin, + bool hardwired) { - struct hda_gnode *node; - int err; + struct hda_gen_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + int type, i, j, num_pins, old_pins; + unsigned int defcfg = snd_hda_codec_get_pincfg(codec, reference_pin); + unsigned int location = get_defcfg_location(defcfg); + int badness = 0; + struct nid_path *path; - list_for_each_entry(node, &spec->nid_list, list) { - if (node->type != AC_WID_PIN) - continue; - /* output capable? */ - if (! (node->pin_caps & AC_PINCAP_OUT)) - continue; - if (defcfg_port_conn(node) == AC_JACK_PORT_NONE) - continue; /* unconnected */ - if (jack_type >= 0) { - if (jack_type != defcfg_type(node)) + old_pins = spec->multi_ios; + if (old_pins >= 2) + goto end_fill; + + num_pins = count_multiio_pins(codec, reference_pin); + if (num_pins < 2) + goto end_fill; + + for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) { + for (i = 0; i < cfg->num_inputs; i++) { + hda_nid_t nid = cfg->inputs[i].pin; + hda_nid_t dac = 0; + + if (cfg->inputs[i].type != type) continue; - if (node->wid_caps & AC_WCAP_DIGITAL) - continue; /* skip SPDIF */ - } else { - /* output as default? */ - if (! (node->pin_ctl & AC_PINCTL_OUT_EN)) + if (!can_be_multiio_pin(codec, location, nid)) + continue; + for (j = 0; j < spec->multi_ios; j++) { + if (nid == spec->multi_io[j].pin) + break; + } + if (j < spec->multi_ios) continue; + + if (hardwired) + dac = get_dac_if_single(codec, nid); + else if (!dac) + dac = look_for_dac(codec, nid, false); + if (!dac) { + badness++; + continue; + } + path = snd_hda_add_new_path(codec, dac, nid, + -spec->mixer_nid); + if (!path) { + badness++; + continue; + } + /* print_nid_path("multiio", path); */ + spec->multi_io[spec->multi_ios].pin = nid; + spec->multi_io[spec->multi_ios].dac = dac; + spec->out_paths[cfg->line_outs + spec->multi_ios] = + snd_hda_get_path_idx(codec, path); + spec->multi_ios++; + if (spec->multi_ios >= 2) + break; + } + } + end_fill: + if (badness) + badness = BAD_MULTI_IO; + if (old_pins == spec->multi_ios) { + if (hardwired) + return 1; /* nothing found */ + else + return badness; /* no badness if nothing found */ + } + if (!hardwired && spec->multi_ios < 2) { + /* cancel newly assigned paths */ + spec->paths.used -= spec->multi_ios - old_pins; + spec->multi_ios = old_pins; + return badness; + } + + /* assign volume and mute controls */ + for (i = old_pins; i < spec->multi_ios; i++) { + path = snd_hda_get_path_from_idx(codec, spec->out_paths[cfg->line_outs + i]); + badness += assign_out_path_ctls(codec, path); + } + + return badness; +} + +/* map DACs for all pins in the list if they are single connections */ +static bool map_singles(struct hda_codec *codec, int outs, + const hda_nid_t *pins, hda_nid_t *dacs, int *path_idx) +{ + struct hda_gen_spec *spec = codec->spec; + int i; + bool found = false; + for (i = 0; i < outs; i++) { + struct nid_path *path; + hda_nid_t dac; + if (dacs[i]) + continue; + dac = get_dac_if_single(codec, pins[i]); + if (!dac) + continue; + path = snd_hda_add_new_path(codec, dac, pins[i], + -spec->mixer_nid); + if (!path && !i && spec->mixer_nid) + path = snd_hda_add_new_path(codec, dac, pins[i], 0); + if (path) { + dacs[i] = dac; + found = true; + /* print_nid_path("output", path); */ + path->active = true; + path_idx[i] = snd_hda_get_path_idx(codec, path); } - clear_check_flags(spec); - err = parse_output_path(codec, spec, node, 0); + } + return found; +} + +/* create a new path including aamix if available, and return its index */ +static int check_aamix_out_path(struct hda_codec *codec, int path_idx) +{ + struct hda_gen_spec *spec = codec->spec; + struct nid_path *path; + hda_nid_t dac, pin; + + path = snd_hda_get_path_from_idx(codec, path_idx); + if (!path || !path->depth || + is_nid_contained(path, spec->mixer_nid)) + return 0; + dac = path->path[0]; + pin = path->path[path->depth - 1]; + path = snd_hda_add_new_path(codec, dac, pin, spec->mixer_nid); + if (!path) { + if (dac != spec->multiout.dac_nids[0]) + dac = spec->multiout.dac_nids[0]; + else if (spec->multiout.hp_out_nid[0]) + dac = spec->multiout.hp_out_nid[0]; + else if (spec->multiout.extra_out_nid[0]) + dac = spec->multiout.extra_out_nid[0]; + if (dac) + path = snd_hda_add_new_path(codec, dac, pin, + spec->mixer_nid); + } + if (!path) + return 0; + /* print_nid_path("output-aamix", path); */ + path->active = false; /* unused as default */ + return snd_hda_get_path_idx(codec, path); +} + +/* fill the empty entries in the dac array for speaker/hp with the + * shared dac pointed by the paths + */ +static void refill_shared_dacs(struct hda_codec *codec, int num_outs, + hda_nid_t *dacs, int *path_idx) +{ + struct nid_path *path; + int i; + + for (i = 0; i < num_outs; i++) { + if (dacs[i]) + continue; + path = snd_hda_get_path_from_idx(codec, path_idx[i]); + if (!path) + continue; + dacs[i] = path->path[0]; + } +} + +/* fill in the dac_nids table from the parsed pin configuration */ +static int fill_and_eval_dacs(struct hda_codec *codec, + bool fill_hardwired, + bool fill_mio_first) +{ + struct hda_gen_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + int i, err, badness; + + /* set num_dacs once to full for look_for_dac() */ + spec->multiout.num_dacs = cfg->line_outs; + spec->multiout.dac_nids = spec->private_dac_nids; + memset(spec->private_dac_nids, 0, sizeof(spec->private_dac_nids)); + memset(spec->multiout.hp_out_nid, 0, sizeof(spec->multiout.hp_out_nid)); + memset(spec->multiout.extra_out_nid, 0, sizeof(spec->multiout.extra_out_nid)); + spec->multi_ios = 0; + snd_array_free(&spec->paths); + + /* clear path indices */ + memset(spec->out_paths, 0, sizeof(spec->out_paths)); + memset(spec->hp_paths, 0, sizeof(spec->hp_paths)); + memset(spec->speaker_paths, 0, sizeof(spec->speaker_paths)); + memset(spec->aamix_out_paths, 0, sizeof(spec->aamix_out_paths)); + memset(spec->digout_paths, 0, sizeof(spec->digout_paths)); + memset(spec->input_paths, 0, sizeof(spec->input_paths)); + memset(spec->loopback_paths, 0, sizeof(spec->loopback_paths)); + memset(&spec->digin_path, 0, sizeof(spec->digin_path)); + + badness = 0; + + /* fill hard-wired DACs first */ + if (fill_hardwired) { + bool mapped; + do { + mapped = map_singles(codec, cfg->line_outs, + cfg->line_out_pins, + spec->private_dac_nids, + spec->out_paths); + mapped |= map_singles(codec, cfg->hp_outs, + cfg->hp_pins, + spec->multiout.hp_out_nid, + spec->hp_paths); + mapped |= map_singles(codec, cfg->speaker_outs, + cfg->speaker_pins, + spec->multiout.extra_out_nid, + spec->speaker_paths); + if (fill_mio_first && cfg->line_outs == 1 && + cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { + err = fill_multi_ios(codec, cfg->line_out_pins[0], true); + if (!err) + mapped = true; + } + } while (mapped); + } + + badness += try_assign_dacs(codec, cfg->line_outs, cfg->line_out_pins, + spec->private_dac_nids, spec->out_paths, + &main_out_badness); + + if (fill_mio_first && + cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { + /* try to fill multi-io first */ + err = fill_multi_ios(codec, cfg->line_out_pins[0], false); + if (err < 0) + return err; + /* we don't count badness at this stage yet */ + } + + if (cfg->line_out_type != AUTO_PIN_HP_OUT) { + err = try_assign_dacs(codec, cfg->hp_outs, cfg->hp_pins, + spec->multiout.hp_out_nid, + spec->hp_paths, + &extra_out_badness); + if (err < 0) + return err; + badness += err; + } + if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { + err = try_assign_dacs(codec, cfg->speaker_outs, + cfg->speaker_pins, + spec->multiout.extra_out_nid, + spec->speaker_paths, + &extra_out_badness); + if (err < 0) + return err; + badness += err; + } + if (cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { + err = fill_multi_ios(codec, cfg->line_out_pins[0], false); if (err < 0) - return NULL; - if (! err && spec->out_pin_node[0]) { - err = parse_output_path(codec, spec, node, 1); + return err; + badness += err; + } + + if (spec->mixer_nid) { + spec->aamix_out_paths[0] = + check_aamix_out_path(codec, spec->out_paths[0]); + if (cfg->line_out_type != AUTO_PIN_HP_OUT) + spec->aamix_out_paths[1] = + check_aamix_out_path(codec, spec->hp_paths[0]); + if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) + spec->aamix_out_paths[2] = + check_aamix_out_path(codec, spec->speaker_paths[0]); + } + + if (cfg->hp_outs && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) + if (count_multiio_pins(codec, cfg->hp_pins[0]) >= 2) + spec->multi_ios = 1; /* give badness */ + + /* re-count num_dacs and squash invalid entries */ + spec->multiout.num_dacs = 0; + for (i = 0; i < cfg->line_outs; i++) { + if (spec->private_dac_nids[i]) + spec->multiout.num_dacs++; + else { + memmove(spec->private_dac_nids + i, + spec->private_dac_nids + i + 1, + sizeof(hda_nid_t) * (cfg->line_outs - i - 1)); + spec->private_dac_nids[cfg->line_outs - 1] = 0; + } + } + + spec->ext_channel_count = spec->min_channel_count = + spec->multiout.num_dacs * 2; + + if (spec->multi_ios == 2) { + for (i = 0; i < 2; i++) + spec->private_dac_nids[spec->multiout.num_dacs++] = + spec->multi_io[i].dac; + } else if (spec->multi_ios) { + spec->multi_ios = 0; + badness += BAD_MULTI_IO; + } + + /* re-fill the shared DAC for speaker / headphone */ + if (cfg->line_out_type != AUTO_PIN_HP_OUT) + refill_shared_dacs(codec, cfg->hp_outs, + spec->multiout.hp_out_nid, + spec->hp_paths); + if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) + refill_shared_dacs(codec, cfg->speaker_outs, + spec->multiout.extra_out_nid, + spec->speaker_paths); + + return badness; +} + +#define DEBUG_BADNESS + +#ifdef DEBUG_BADNESS +#define debug_badness snd_printdd +#else +#define debug_badness(...) +#endif + +#ifdef DEBUG_BADNESS +static inline void print_nid_path_idx(struct hda_codec *codec, + const char *pfx, int idx) +{ + struct nid_path *path; + + path = snd_hda_get_path_from_idx(codec, idx); + if (path) + print_nid_path(pfx, path); +} + +static void debug_show_configs(struct hda_codec *codec, + struct auto_pin_cfg *cfg) +{ + struct hda_gen_spec *spec = codec->spec; + static const char * const lo_type[3] = { "LO", "SP", "HP" }; + int i; + + debug_badness("multi_outs = %x/%x/%x/%x : %x/%x/%x/%x (type %s)\n", + cfg->line_out_pins[0], cfg->line_out_pins[1], + cfg->line_out_pins[2], cfg->line_out_pins[3], + spec->multiout.dac_nids[0], + spec->multiout.dac_nids[1], + spec->multiout.dac_nids[2], + spec->multiout.dac_nids[3], + lo_type[cfg->line_out_type]); + for (i = 0; i < cfg->line_outs; i++) + print_nid_path_idx(codec, " out", spec->out_paths[i]); + if (spec->multi_ios > 0) + debug_badness("multi_ios(%d) = %x/%x : %x/%x\n", + spec->multi_ios, + spec->multi_io[0].pin, spec->multi_io[1].pin, + spec->multi_io[0].dac, spec->multi_io[1].dac); + for (i = 0; i < spec->multi_ios; i++) + print_nid_path_idx(codec, " mio", + spec->out_paths[cfg->line_outs + i]); + if (cfg->hp_outs) + debug_badness("hp_outs = %x/%x/%x/%x : %x/%x/%x/%x\n", + cfg->hp_pins[0], cfg->hp_pins[1], + cfg->hp_pins[2], cfg->hp_pins[3], + spec->multiout.hp_out_nid[0], + spec->multiout.hp_out_nid[1], + spec->multiout.hp_out_nid[2], + spec->multiout.hp_out_nid[3]); + for (i = 0; i < cfg->hp_outs; i++) + print_nid_path_idx(codec, " hp ", spec->hp_paths[i]); + if (cfg->speaker_outs) + debug_badness("spk_outs = %x/%x/%x/%x : %x/%x/%x/%x\n", + cfg->speaker_pins[0], cfg->speaker_pins[1], + cfg->speaker_pins[2], cfg->speaker_pins[3], + spec->multiout.extra_out_nid[0], + spec->multiout.extra_out_nid[1], + spec->multiout.extra_out_nid[2], + spec->multiout.extra_out_nid[3]); + for (i = 0; i < cfg->speaker_outs; i++) + print_nid_path_idx(codec, " spk", spec->speaker_paths[i]); + for (i = 0; i < 3; i++) + print_nid_path_idx(codec, " mix", spec->aamix_out_paths[i]); +} +#else +#define debug_show_configs(codec, cfg) /* NOP */ +#endif + +/* find all available DACs of the codec */ +static void fill_all_dac_nids(struct hda_codec *codec) +{ + struct hda_gen_spec *spec = codec->spec; + int i; + hda_nid_t nid = codec->start_nid; + + spec->num_all_dacs = 0; + memset(spec->all_dacs, 0, sizeof(spec->all_dacs)); + for (i = 0; i < codec->num_nodes; i++, nid++) { + if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_AUD_OUT) + continue; + if (spec->num_all_dacs >= ARRAY_SIZE(spec->all_dacs)) { + snd_printk(KERN_ERR "hda: Too many DACs!\n"); + break; + } + spec->all_dacs[spec->num_all_dacs++] = nid; + } +} + +static int parse_output_paths(struct hda_codec *codec) +{ + struct hda_gen_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + struct auto_pin_cfg *best_cfg; + unsigned int val; + int best_badness = INT_MAX; + int badness; + bool fill_hardwired = true, fill_mio_first = true; + bool best_wired = true, best_mio = true; + bool hp_spk_swapped = false; + + best_cfg = kmalloc(sizeof(*best_cfg), GFP_KERNEL); + if (!best_cfg) + return -ENOMEM; + *best_cfg = *cfg; + + for (;;) { + badness = fill_and_eval_dacs(codec, fill_hardwired, + fill_mio_first); + if (badness < 0) { + kfree(best_cfg); + return badness; + } + debug_badness("==> lo_type=%d, wired=%d, mio=%d, badness=0x%x\n", + cfg->line_out_type, fill_hardwired, fill_mio_first, + badness); + debug_show_configs(codec, cfg); + if (badness < best_badness) { + best_badness = badness; + *best_cfg = *cfg; + best_wired = fill_hardwired; + best_mio = fill_mio_first; + } + if (!badness) + break; + fill_mio_first = !fill_mio_first; + if (!fill_mio_first) + continue; + fill_hardwired = !fill_hardwired; + if (!fill_hardwired) + continue; + if (hp_spk_swapped) + break; + hp_spk_swapped = true; + if (cfg->speaker_outs > 0 && + cfg->line_out_type == AUTO_PIN_HP_OUT) { + cfg->hp_outs = cfg->line_outs; + memcpy(cfg->hp_pins, cfg->line_out_pins, + sizeof(cfg->hp_pins)); + cfg->line_outs = cfg->speaker_outs; + memcpy(cfg->line_out_pins, cfg->speaker_pins, + sizeof(cfg->speaker_pins)); + cfg->speaker_outs = 0; + memset(cfg->speaker_pins, 0, sizeof(cfg->speaker_pins)); + cfg->line_out_type = AUTO_PIN_SPEAKER_OUT; + fill_hardwired = true; + continue; + } + if (cfg->hp_outs > 0 && + cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) { + cfg->speaker_outs = cfg->line_outs; + memcpy(cfg->speaker_pins, cfg->line_out_pins, + sizeof(cfg->speaker_pins)); + cfg->line_outs = cfg->hp_outs; + memcpy(cfg->line_out_pins, cfg->hp_pins, + sizeof(cfg->hp_pins)); + cfg->hp_outs = 0; + memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins)); + cfg->line_out_type = AUTO_PIN_HP_OUT; + fill_hardwired = true; + continue; + } + break; + } + + if (badness) { + debug_badness("==> restoring best_cfg\n"); + *cfg = *best_cfg; + fill_and_eval_dacs(codec, best_wired, best_mio); + } + debug_badness("==> Best config: lo_type=%d, wired=%d, mio=%d\n", + cfg->line_out_type, best_wired, best_mio); + debug_show_configs(codec, cfg); + + if (cfg->line_out_pins[0]) { + struct nid_path *path; + path = snd_hda_get_path_from_idx(codec, spec->out_paths[0]); + if (path) + spec->vmaster_nid = look_for_out_vol_nid(codec, path); + if (spec->vmaster_nid) + snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid, + HDA_OUTPUT, spec->vmaster_tlv); + } + + /* set initial pinctl targets */ + if (spec->prefer_hp_amp || cfg->line_out_type == AUTO_PIN_HP_OUT) + val = PIN_HP; + else + val = PIN_OUT; + set_pin_targets(codec, cfg->line_outs, cfg->line_out_pins, val); + if (cfg->line_out_type != AUTO_PIN_HP_OUT) + set_pin_targets(codec, cfg->hp_outs, cfg->hp_pins, PIN_HP); + if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { + val = spec->prefer_hp_amp ? PIN_HP : PIN_OUT; + set_pin_targets(codec, cfg->speaker_outs, + cfg->speaker_pins, val); + } + + kfree(best_cfg); + return 0; +} + +/* add playback controls from the parsed DAC table */ +static int create_multi_out_ctls(struct hda_codec *codec, + const struct auto_pin_cfg *cfg) +{ + struct hda_gen_spec *spec = codec->spec; + int i, err, noutputs; + + noutputs = cfg->line_outs; + if (spec->multi_ios > 0 && cfg->line_outs < 3) + noutputs += spec->multi_ios; + + for (i = 0; i < noutputs; i++) { + const char *name; + int index; + struct nid_path *path; + + path = snd_hda_get_path_from_idx(codec, spec->out_paths[i]); + if (!path) + continue; + + name = get_line_out_pfx(codec, i, &index, NID_PATH_VOL_CTL); + if (!name || !strcmp(name, "CLFE")) { + /* Center/LFE */ + err = add_vol_ctl(codec, "Center", 0, 1, path); if (err < 0) - return NULL; + return err; + err = add_vol_ctl(codec, "LFE", 0, 2, path); + if (err < 0) + return err; + } else { + err = add_stereo_vol(codec, name, index, path); + if (err < 0) + return err; } - if (err > 0) { - /* unmute the PIN output */ - unmute_output(codec, node); - /* set PIN-Out enable */ - snd_hda_codec_write_cache(codec, node->nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - AC_PINCTL_OUT_EN | - ((node->pin_caps & AC_PINCAP_HP_DRV) ? - AC_PINCTL_HP_EN : 0)); - return node; + + name = get_line_out_pfx(codec, i, &index, NID_PATH_MUTE_CTL); + if (!name || !strcmp(name, "CLFE")) { + err = add_sw_ctl(codec, "Center", 0, 1, path); + if (err < 0) + return err; + err = add_sw_ctl(codec, "LFE", 0, 2, path); + if (err < 0) + return err; + } else { + err = add_stereo_sw(codec, name, index, path); + if (err < 0) + return err; } } - return NULL; + return 0; } +static int create_extra_out(struct hda_codec *codec, int path_idx, + const char *pfx, int cidx) +{ + struct nid_path *path; + int err; + + path = snd_hda_get_path_from_idx(codec, path_idx); + if (!path) + return 0; + err = add_stereo_vol(codec, pfx, cidx, path); + if (err < 0) + return err; + err = add_stereo_sw(codec, pfx, cidx, path); + if (err < 0) + return err; + return 0; +} + +/* add playback controls for speaker and HP outputs */ +static int create_extra_outs(struct hda_codec *codec, int num_pins, + const int *paths, const char *pfx) +{ + int i; + + for (i = 0; i < num_pins; i++) { + const char *name; + char tmp[44]; + int err, idx = 0; + + if (num_pins == 2 && i == 1 && !strcmp(pfx, "Speaker")) + name = "Bass Speaker"; + else if (num_pins >= 3) { + snprintf(tmp, sizeof(tmp), "%s %s", + pfx, channel_name[i]); + name = tmp; + } else { + name = pfx; + idx = i; + } + err = create_extra_out(codec, paths[i], name, idx); + if (err < 0) + return err; + } + return 0; +} + +static int create_hp_out_ctls(struct hda_codec *codec) +{ + struct hda_gen_spec *spec = codec->spec; + return create_extra_outs(codec, spec->autocfg.hp_outs, + spec->hp_paths, + "Headphone"); +} + +static int create_speaker_out_ctls(struct hda_codec *codec) +{ + struct hda_gen_spec *spec = codec->spec; + return create_extra_outs(codec, spec->autocfg.speaker_outs, + spec->speaker_paths, + "Speaker"); +} /* - * parse outputs + * independent HP controls */ -static int parse_output(struct hda_codec *codec) + +static int indep_hp_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) { - struct hda_gspec *spec = codec->spec; - struct hda_gnode *node; + return snd_hda_enum_bool_helper_info(kcontrol, uinfo); +} - /* - * Look for the output PIN widget - */ - /* first, look for the line-out pin */ - node = parse_output_jack(codec, spec, AC_JACK_LINE_OUT); - if (node) /* found, remember the PIN node */ - spec->out_pin_node[0] = node; - else { - /* if no line-out is found, try speaker out */ - node = parse_output_jack(codec, spec, AC_JACK_SPEAKER); - if (node) - spec->out_pin_node[0] = node; - } - /* look for the HP-out pin */ - node = parse_output_jack(codec, spec, AC_JACK_HP_OUT); - if (node) { - if (! spec->out_pin_node[0]) - spec->out_pin_node[0] = node; +static int indep_hp_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct hda_gen_spec *spec = codec->spec; + ucontrol->value.enumerated.item[0] = spec->indep_hp_enabled; + return 0; +} + +static void update_aamix_paths(struct hda_codec *codec, bool do_mix, + int nomix_path_idx, int mix_path_idx, + int out_type); + +static int indep_hp_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct hda_gen_spec *spec = codec->spec; + unsigned int select = ucontrol->value.enumerated.item[0]; + int ret = 0; + + mutex_lock(&spec->pcm_mutex); + if (spec->active_streams) { + ret = -EBUSY; + goto unlock; + } + + if (spec->indep_hp_enabled != select) { + hda_nid_t *dacp; + if (spec->autocfg.line_out_type == AUTO_PIN_HP_OUT) + dacp = &spec->private_dac_nids[0]; + else + dacp = &spec->multiout.hp_out_nid[0]; + + /* update HP aamix paths in case it conflicts with indep HP */ + if (spec->have_aamix_ctl) { + if (spec->autocfg.line_out_type == AUTO_PIN_HP_OUT) + update_aamix_paths(codec, spec->aamix_mode, + spec->out_paths[0], + spec->aamix_out_paths[0], + spec->autocfg.line_out_type); + else + update_aamix_paths(codec, spec->aamix_mode, + spec->hp_paths[0], + spec->aamix_out_paths[1], + AUTO_PIN_HP_OUT); + } + + spec->indep_hp_enabled = select; + if (spec->indep_hp_enabled) + *dacp = 0; + else + *dacp = spec->alt_dac_nid; + + /* update HP auto-mute state too */ + if (spec->hp_automute_hook) + spec->hp_automute_hook(codec, NULL); else - spec->out_pin_node[1] = node; + snd_hda_gen_hp_automute(codec, NULL); + + ret = 1; } + unlock: + mutex_unlock(&spec->pcm_mutex); + return ret; +} - if (! spec->out_pin_node[0]) { - /* no line-out or HP pins found, - * then choose for the first output pin - */ - spec->out_pin_node[0] = parse_output_jack(codec, spec, -1); - if (! spec->out_pin_node[0]) - snd_printd("hda_generic: no proper output path found\n"); +static const struct snd_kcontrol_new indep_hp_ctl = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Independent HP", + .info = indep_hp_info, + .get = indep_hp_get, + .put = indep_hp_put, +}; + + +static int create_indep_hp_ctls(struct hda_codec *codec) +{ + struct hda_gen_spec *spec = codec->spec; + hda_nid_t dac; + + if (!spec->indep_hp) + return 0; + if (spec->autocfg.line_out_type == AUTO_PIN_HP_OUT) + dac = spec->multiout.dac_nids[0]; + else + dac = spec->multiout.hp_out_nid[0]; + if (!dac) { + spec->indep_hp = 0; + return 0; } + spec->indep_hp_enabled = false; + spec->alt_dac_nid = dac; + if (!snd_hda_gen_add_kctl(spec, NULL, &indep_hp_ctl)) + return -ENOMEM; return 0; } /* - * input MUX + * channel mode enum control */ -/* control callbacks */ -static int capture_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) +static int ch_mode_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct hda_gspec *spec = codec->spec; - return snd_hda_input_mux_info(&spec->input_mux, uinfo); + struct hda_gen_spec *spec = codec->spec; + int chs; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = spec->multi_ios + 1; + if (uinfo->value.enumerated.item > spec->multi_ios) + uinfo->value.enumerated.item = spec->multi_ios; + chs = uinfo->value.enumerated.item * 2 + spec->min_channel_count; + sprintf(uinfo->value.enumerated.name, "%dch", chs); + return 0; } -static int capture_source_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +static int ch_mode_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct hda_gspec *spec = codec->spec; + struct hda_gen_spec *spec = codec->spec; + ucontrol->value.enumerated.item[0] = + (spec->ext_channel_count - spec->min_channel_count) / 2; + return 0; +} + +static inline struct nid_path * +get_multiio_path(struct hda_codec *codec, int idx) +{ + struct hda_gen_spec *spec = codec->spec; + return snd_hda_get_path_from_idx(codec, + spec->out_paths[spec->autocfg.line_outs + idx]); +} + +static void update_automute_all(struct hda_codec *codec); + +static int set_multi_io(struct hda_codec *codec, int idx, bool output) +{ + struct hda_gen_spec *spec = codec->spec; + hda_nid_t nid = spec->multi_io[idx].pin; + struct nid_path *path; + + path = get_multiio_path(codec, idx); + if (!path) + return -EINVAL; + + if (path->active == output) + return 0; + + if (output) { + set_pin_target(codec, nid, PIN_OUT, true); + snd_hda_activate_path(codec, path, true, true); + set_pin_eapd(codec, nid, true); + } else { + set_pin_eapd(codec, nid, false); + snd_hda_activate_path(codec, path, false, true); + set_pin_target(codec, nid, spec->multi_io[idx].ctl_in, true); + path_power_down_sync(codec, path); + } + + /* update jack retasking in case it modifies any of them */ + update_automute_all(codec); - ucontrol->value.enumerated.item[0] = spec->cur_cap_src; return 0; } -static int capture_source_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +static int ch_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct hda_gspec *spec = codec->spec; - return snd_hda_input_mux_put(codec, &spec->input_mux, ucontrol, - spec->adc_node->nid, &spec->cur_cap_src); + struct hda_gen_spec *spec = codec->spec; + int i, ch; + + ch = ucontrol->value.enumerated.item[0]; + if (ch < 0 || ch > spec->multi_ios) + return -EINVAL; + if (ch == (spec->ext_channel_count - spec->min_channel_count) / 2) + return 0; + spec->ext_channel_count = ch * 2 + spec->min_channel_count; + for (i = 0; i < spec->multi_ios; i++) + set_multi_io(codec, i, i < ch); + spec->multiout.max_channels = max(spec->ext_channel_count, + spec->const_channel_count); + if (spec->need_dac_fix) + spec->multiout.num_dacs = spec->multiout.max_channels / 2; + return 1; } -/* - * return the string name of the given input PIN widget - */ -static const char *get_input_type(struct hda_gnode *node, unsigned int *pinctl) -{ - unsigned int location = defcfg_location(node); - switch (defcfg_type(node)) { - case AC_JACK_LINE_IN: - if ((location & 0x0f) == AC_JACK_LOC_FRONT) - return "Front Line"; - return "Line"; - case AC_JACK_CD: -#if 0 - if (pinctl) - *pinctl |= AC_PINCTL_VREF_GRD; -#endif - return "CD"; - case AC_JACK_AUX: - if ((location & 0x0f) == AC_JACK_LOC_FRONT) - return "Front Aux"; - return "Aux"; - case AC_JACK_MIC_IN: - if (pinctl && - (node->pin_caps & - (AC_PINCAP_VREF_80 << AC_PINCAP_VREF_SHIFT))) - *pinctl |= AC_PINCTL_VREF_80; - if ((location & 0x0f) == AC_JACK_LOC_FRONT) - return "Front Mic"; - return "Mic"; - case AC_JACK_SPDIF_IN: - return "SPDIF"; - case AC_JACK_DIG_OTHER_IN: - return "Digital"; +static const struct snd_kcontrol_new channel_mode_enum = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Channel Mode", + .info = ch_mode_info, + .get = ch_mode_get, + .put = ch_mode_put, +}; + +static int create_multi_channel_mode(struct hda_codec *codec) +{ + struct hda_gen_spec *spec = codec->spec; + + if (spec->multi_ios > 0) { + if (!snd_hda_gen_add_kctl(spec, NULL, &channel_mode_enum)) + return -ENOMEM; } - return NULL; + return 0; } /* - * parse the nodes recursively until reach to the input PIN - * - * returns 0 if not found, 1 if found, or a negative error code. + * aamix loopback enable/disable switch */ -static int parse_adc_sub_nodes(struct hda_codec *codec, struct hda_gspec *spec, - struct hda_gnode *node, int idx) + +#define loopback_mixing_info indep_hp_info + +static int loopback_mixing_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - int i, err; - unsigned int pinctl; - const char *type; + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct hda_gen_spec *spec = codec->spec; + ucontrol->value.enumerated.item[0] = spec->aamix_mode; + return 0; +} - if (node->checked) +static void update_aamix_paths(struct hda_codec *codec, bool do_mix, + int nomix_path_idx, int mix_path_idx, + int out_type) +{ + struct hda_gen_spec *spec = codec->spec; + struct nid_path *nomix_path, *mix_path; + + nomix_path = snd_hda_get_path_from_idx(codec, nomix_path_idx); + mix_path = snd_hda_get_path_from_idx(codec, mix_path_idx); + if (!nomix_path || !mix_path) + return; + + /* if HP aamix path is driven from a different DAC and the + * independent HP mode is ON, can't turn on aamix path + */ + if (out_type == AUTO_PIN_HP_OUT && spec->indep_hp_enabled && + mix_path->path[0] != spec->alt_dac_nid) + do_mix = false; + + if (do_mix) { + snd_hda_activate_path(codec, nomix_path, false, true); + snd_hda_activate_path(codec, mix_path, true, true); + path_power_down_sync(codec, nomix_path); + } else { + snd_hda_activate_path(codec, mix_path, false, true); + snd_hda_activate_path(codec, nomix_path, true, true); + path_power_down_sync(codec, mix_path); + } +} + +static int loopback_mixing_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct hda_gen_spec *spec = codec->spec; + unsigned int val = ucontrol->value.enumerated.item[0]; + + if (val == spec->aamix_mode) return 0; + spec->aamix_mode = val; + update_aamix_paths(codec, val, spec->out_paths[0], + spec->aamix_out_paths[0], + spec->autocfg.line_out_type); + update_aamix_paths(codec, val, spec->hp_paths[0], + spec->aamix_out_paths[1], + AUTO_PIN_HP_OUT); + update_aamix_paths(codec, val, spec->speaker_paths[0], + spec->aamix_out_paths[2], + AUTO_PIN_SPEAKER_OUT); + return 1; +} - node->checked = 1; - if (node->type != AC_WID_PIN) { - for (i = 0; i < node->nconns; i++) { - struct hda_gnode *child; - child = hda_get_node(spec, node->conn_list[i]); - if (! child) - continue; - err = parse_adc_sub_nodes(codec, spec, child, idx); - if (err < 0) - return err; - if (err > 0) { - /* found one, - * select the path, unmute both input and output - */ - if (node->nconns > 1) - select_input_connection(codec, node, i); - unmute_input(codec, node, i); - unmute_output(codec, node); - return err; - } - } +static const struct snd_kcontrol_new loopback_mixing_enum = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Loopback Mixing", + .info = loopback_mixing_info, + .get = loopback_mixing_get, + .put = loopback_mixing_put, +}; + +static int create_loopback_mixing_ctl(struct hda_codec *codec) +{ + struct hda_gen_spec *spec = codec->spec; + + if (!spec->mixer_nid) + return 0; + if (!(spec->aamix_out_paths[0] || spec->aamix_out_paths[1] || + spec->aamix_out_paths[2])) return 0; + if (!snd_hda_gen_add_kctl(spec, NULL, &loopback_mixing_enum)) + return -ENOMEM; + spec->have_aamix_ctl = 1; + return 0; +} + +/* + * shared headphone/mic handling + */ + +static void call_update_outputs(struct hda_codec *codec); + +/* for shared I/O, change the pin-control accordingly */ +static void update_shared_mic_hp(struct hda_codec *codec, bool set_as_mic) +{ + struct hda_gen_spec *spec = codec->spec; + unsigned int val; + hda_nid_t pin = spec->autocfg.inputs[1].pin; + /* NOTE: this assumes that there are only two inputs, the + * first is the real internal mic and the second is HP/mic jack. + */ + + val = snd_hda_get_default_vref(codec, pin); + + /* This pin does not have vref caps - let's enable vref on pin 0x18 + instead, as suggested by Realtek */ + if (val == AC_PINCTL_VREF_HIZ && spec->shared_mic_vref_pin) { + const hda_nid_t vref_pin = spec->shared_mic_vref_pin; + unsigned int vref_val = snd_hda_get_default_vref(codec, vref_pin); + if (vref_val != AC_PINCTL_VREF_HIZ) + snd_hda_set_pin_ctl_cache(codec, vref_pin, + PIN_IN | (set_as_mic ? vref_val : 0)); } - /* input capable? */ - if (! (node->pin_caps & AC_PINCAP_IN)) + val = set_as_mic ? val | PIN_IN : PIN_HP; + set_pin_target(codec, pin, val, true); + + spec->automute_speaker = !set_as_mic; + call_update_outputs(codec); +} + +/* create a shared input with the headphone out */ +static int create_shared_input(struct hda_codec *codec) +{ + struct hda_gen_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + unsigned int defcfg; + hda_nid_t nid; + + /* only one internal input pin? */ + if (cfg->num_inputs != 1) + return 0; + defcfg = snd_hda_codec_get_pincfg(codec, cfg->inputs[0].pin); + if (snd_hda_get_input_pin_attr(defcfg) != INPUT_PIN_ATTR_INT) return 0; - if (defcfg_port_conn(node) == AC_JACK_PORT_NONE) - return 0; /* unconnected */ + if (cfg->hp_outs == 1 && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) + nid = cfg->hp_pins[0]; /* OK, we have a single HP-out */ + else if (cfg->line_outs == 1 && cfg->line_out_type == AUTO_PIN_HP_OUT) + nid = cfg->line_out_pins[0]; /* OK, we have a single line-out */ + else + return 0; /* both not available */ - if (node->wid_caps & AC_WCAP_DIGITAL) - return 0; /* skip SPDIF */ + if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_IN)) + return 0; /* no input */ - if (spec->input_mux.num_items >= HDA_MAX_NUM_INPUTS) { - snd_printk(KERN_ERR "hda_generic: Too many items for capture\n"); - return -EINVAL; - } + cfg->inputs[1].pin = nid; + cfg->inputs[1].type = AUTO_PIN_MIC; + cfg->num_inputs = 2; + spec->shared_mic_hp = 1; + snd_printdd("hda-codec: Enable shared I/O jack on NID 0x%x\n", nid); + return 0; +} - pinctl = AC_PINCTL_IN_EN; - /* create a proper capture source label */ - type = get_input_type(node, &pinctl); - if (! type) { - /* input as default? */ - if (! (node->pin_ctl & AC_PINCTL_IN_EN)) - return 0; - type = "Input"; +/* + * output jack mode + */ +static int out_jack_mode_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + static const char * const texts[] = { + "Line Out", "Headphone Out", + }; + return snd_hda_enum_helper_info(kcontrol, uinfo, 2, texts); +} + +static int out_jack_mode_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = kcontrol->private_value; + if (snd_hda_codec_get_pin_target(codec, nid) == PIN_HP) + ucontrol->value.enumerated.item[0] = 1; + else + ucontrol->value.enumerated.item[0] = 0; + return 0; +} + +static int out_jack_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = kcontrol->private_value; + unsigned int val; + + val = ucontrol->value.enumerated.item[0] ? PIN_HP : PIN_OUT; + if (snd_hda_codec_get_pin_target(codec, nid) == val) + return 0; + snd_hda_set_pin_ctl_cache(codec, nid, val); + return 1; +} + +static const struct snd_kcontrol_new out_jack_mode_enum = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .info = out_jack_mode_info, + .get = out_jack_mode_get, + .put = out_jack_mode_put, +}; + +static bool find_kctl_name(struct hda_codec *codec, const char *name, int idx) +{ + struct hda_gen_spec *spec = codec->spec; + int i; + + for (i = 0; i < spec->kctls.used; i++) { + struct snd_kcontrol_new *kctl = snd_array_elem(&spec->kctls, i); + if (!strcmp(kctl->name, name) && kctl->index == idx) + return true; } - snd_hda_add_imux_item(&spec->input_mux, type, idx, NULL); + return false; +} + +static void get_jack_mode_name(struct hda_codec *codec, hda_nid_t pin, + char *name, size_t name_len) +{ + struct hda_gen_spec *spec = codec->spec; + int idx = 0; - /* unmute the PIN external input */ - unmute_input(codec, node, 0); /* index = 0? */ - /* set PIN-In enable */ - snd_hda_codec_write_cache(codec, node->nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, pinctl); + snd_hda_get_pin_label(codec, pin, &spec->autocfg, name, name_len, &idx); + strlcat(name, " Jack Mode", name_len); - return 1; /* found */ + for (; find_kctl_name(codec, name, idx); idx++) + ; +} + +static int create_out_jack_modes(struct hda_codec *codec, int num_pins, + hda_nid_t *pins) +{ + struct hda_gen_spec *spec = codec->spec; + int i; + + for (i = 0; i < num_pins; i++) { + hda_nid_t pin = pins[i]; + unsigned int pincap = snd_hda_query_pin_caps(codec, pin); + if ((pincap & AC_PINCAP_OUT) && (pincap & AC_PINCAP_HP_DRV)) { + struct snd_kcontrol_new *knew; + char name[44]; + get_jack_mode_name(codec, pin, name, sizeof(name)); + knew = snd_hda_gen_add_kctl(spec, name, + &out_jack_mode_enum); + if (!knew) + return -ENOMEM; + knew->private_value = pin; + } + } + + return 0; } /* - * parse input + * input jack mode */ -static int parse_input_path(struct hda_codec *codec, struct hda_gnode *adc_node) + +/* from AC_PINCTL_VREF_HIZ to AC_PINCTL_VREF_100 */ +#define NUM_VREFS 6 + +static const char * const vref_texts[NUM_VREFS] = { + "Line In", "Mic 50pc Bias", "Mic 0V Bias", + "", "Mic 80pc Bias", "Mic 100pc Bias" +}; + +static unsigned int get_vref_caps(struct hda_codec *codec, hda_nid_t pin) { - struct hda_gspec *spec = codec->spec; - struct hda_gnode *node; - int i, err; + unsigned int pincap; - snd_printdd("AUD_IN = %x\n", adc_node->nid); - clear_check_flags(spec); + pincap = snd_hda_query_pin_caps(codec, pin); + pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT; + /* filter out unusual vrefs */ + pincap &= ~(AC_PINCAP_VREF_GRD | AC_PINCAP_VREF_100); + return pincap; +} - // awk added - fixed no recording due to muted widget - unmute_input(codec, adc_node, 0); - - /* - * check each connection of the ADC - * if it reaches to a proper input PIN, add the path as the - * input path. - */ - /* first, check the direct connections to PIN widgets */ - for (i = 0; i < adc_node->nconns; i++) { - node = hda_get_node(spec, adc_node->conn_list[i]); - if (node && node->type == AC_WID_PIN) { - err = parse_adc_sub_nodes(codec, spec, node, i); - if (err < 0) - return err; +/* convert from the enum item index to the vref ctl index (0=HIZ, 1=50%...) */ +static int get_vref_idx(unsigned int vref_caps, unsigned int item_idx) +{ + unsigned int i, n = 0; + + for (i = 0; i < NUM_VREFS; i++) { + if (vref_caps & (1 << i)) { + if (n == item_idx) + return i; + n++; } } - /* ... then check the rests, more complicated connections */ - for (i = 0; i < adc_node->nconns; i++) { - node = hda_get_node(spec, adc_node->conn_list[i]); - if (node && node->type != AC_WID_PIN) { - err = parse_adc_sub_nodes(codec, spec, node, i); - if (err < 0) - return err; - } + return 0; +} + +/* convert back from the vref ctl index to the enum item index */ +static int cvt_from_vref_idx(unsigned int vref_caps, unsigned int idx) +{ + unsigned int i, n = 0; + + for (i = 0; i < NUM_VREFS; i++) { + if (i == idx) + return n; + if (vref_caps & (1 << i)) + n++; } + return 0; +} + +static int in_jack_mode_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = kcontrol->private_value; + unsigned int vref_caps = get_vref_caps(codec, nid); + + snd_hda_enum_helper_info(kcontrol, uinfo, hweight32(vref_caps), + vref_texts); + /* set the right text */ + strcpy(uinfo->value.enumerated.name, + vref_texts[get_vref_idx(vref_caps, uinfo->value.enumerated.item)]); + return 0; +} + +static int in_jack_mode_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = kcontrol->private_value; + unsigned int vref_caps = get_vref_caps(codec, nid); + unsigned int idx; + + idx = snd_hda_codec_get_pin_target(codec, nid) & AC_PINCTL_VREFEN; + ucontrol->value.enumerated.item[0] = cvt_from_vref_idx(vref_caps, idx); + return 0; +} - if (! spec->input_mux.num_items) - return 0; /* no input path found... */ +static int in_jack_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = kcontrol->private_value; + unsigned int vref_caps = get_vref_caps(codec, nid); + unsigned int val, idx; - snd_printdd("[Capture Source] NID=0x%x, #SRC=%d\n", adc_node->nid, spec->input_mux.num_items); - for (i = 0; i < spec->input_mux.num_items; i++) - snd_printdd(" [%s] IDX=0x%x\n", spec->input_mux.items[i].label, - spec->input_mux.items[i].index); + val = snd_hda_codec_get_pin_target(codec, nid); + idx = cvt_from_vref_idx(vref_caps, val & AC_PINCTL_VREFEN); + if (idx == ucontrol->value.enumerated.item[0]) + return 0; - spec->adc_node = adc_node; + val &= ~AC_PINCTL_VREFEN; + val |= get_vref_idx(vref_caps, ucontrol->value.enumerated.item[0]); + snd_hda_set_pin_ctl_cache(codec, nid, val); return 1; } +static const struct snd_kcontrol_new in_jack_mode_enum = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .info = in_jack_mode_info, + .get = in_jack_mode_get, + .put = in_jack_mode_put, +}; + +static int create_in_jack_mode(struct hda_codec *codec, hda_nid_t pin) +{ + struct hda_gen_spec *spec = codec->spec; + unsigned int defcfg; + struct snd_kcontrol_new *knew; + char name[44]; + + /* no jack mode for fixed pins */ + defcfg = snd_hda_codec_get_pincfg(codec, pin); + if (snd_hda_get_input_pin_attr(defcfg) == INPUT_PIN_ATTR_INT) + return 0; + + /* no multiple vref caps? */ + if (hweight32(get_vref_caps(codec, pin)) <= 1) + return 0; + + get_jack_mode_name(codec, pin, name, sizeof(name)); + knew = snd_hda_gen_add_kctl(spec, name, &in_jack_mode_enum); + if (!knew) + return -ENOMEM; + knew->private_value = pin; + return 0; +} + + /* - * parse input + * Parse input paths */ -static int parse_input(struct hda_codec *codec) + +/* add the powersave loopback-list entry */ +static int add_loopback_list(struct hda_gen_spec *spec, hda_nid_t mix, int idx) { - struct hda_gspec *spec = codec->spec; - struct hda_gnode *node; - int err; + struct hda_amp_list *list; - /* - * At first we look for an audio input widget. - * If it reaches to certain input PINs, we take it as the - * input path. - */ - list_for_each_entry(node, &spec->nid_list, list) { - if (node->wid_caps & AC_WCAP_DIGITAL) - continue; /* skip SPDIF */ - if (node->type == AC_WID_AUD_IN) { - err = parse_input_path(codec, node); - if (err < 0) - return err; - else if (err > 0) - return 0; + list = snd_array_new(&spec->loopback_list); + if (!list) + return -ENOMEM; + list->nid = mix; + list->dir = HDA_INPUT; + list->idx = idx; + spec->loopback.amplist = spec->loopback_list.list; + return 0; +} + +/* create input playback/capture controls for the given pin */ +static int new_analog_input(struct hda_codec *codec, int input_idx, + hda_nid_t pin, const char *ctlname, int ctlidx, + hda_nid_t mix_nid) +{ + struct hda_gen_spec *spec = codec->spec; + struct nid_path *path; + unsigned int val; + int err, idx; + + if (!nid_has_volume(codec, mix_nid, HDA_INPUT) && + !nid_has_mute(codec, mix_nid, HDA_INPUT)) + return 0; /* no need for analog loopback */ + + path = snd_hda_add_new_path(codec, pin, mix_nid, 0); + if (!path) + return -EINVAL; + print_nid_path("loopback", path); + spec->loopback_paths[input_idx] = snd_hda_get_path_idx(codec, path); + + idx = path->idx[path->depth - 1]; + if (nid_has_volume(codec, mix_nid, HDA_INPUT)) { + val = HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT); + err = __add_pb_vol_ctrl(spec, HDA_CTL_WIDGET_VOL, ctlname, ctlidx, val); + if (err < 0) + return err; + path->ctls[NID_PATH_VOL_CTL] = val; + } + + if (nid_has_mute(codec, mix_nid, HDA_INPUT)) { + val = HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT); + err = __add_pb_sw_ctrl(spec, HDA_CTL_WIDGET_MUTE, ctlname, ctlidx, val); + if (err < 0) + return err; + path->ctls[NID_PATH_MUTE_CTL] = val; + } + + path->active = true; + err = add_loopback_list(spec, mix_nid, idx); + if (err < 0) + return err; + + if (spec->mixer_nid != spec->mixer_merge_nid && + !spec->loopback_merge_path) { + path = snd_hda_add_new_path(codec, spec->mixer_nid, + spec->mixer_merge_nid, 0); + if (path) { + print_nid_path("loopback-merge", path); + path->active = true; + spec->loopback_merge_path = + snd_hda_get_path_idx(codec, path); } } - snd_printd("hda_generic: no proper input path found\n"); + return 0; } -#ifdef CONFIG_PM -static void add_input_loopback(struct hda_codec *codec, hda_nid_t nid, - int dir, int idx) +static int is_input_pin(struct hda_codec *codec, hda_nid_t nid) { - struct hda_gspec *spec = codec->spec; - struct hda_amp_list *p; + unsigned int pincap = snd_hda_query_pin_caps(codec, nid); + return (pincap & AC_PINCAP_IN) != 0; +} - if (spec->num_loopbacks >= MAX_LOOPBACK_AMPS) { - snd_printk(KERN_ERR "hda_generic: Too many loopback ctls\n"); - return; +/* Parse the codec tree and retrieve ADCs */ +static int fill_adc_nids(struct hda_codec *codec) +{ + struct hda_gen_spec *spec = codec->spec; + hda_nid_t nid; + hda_nid_t *adc_nids = spec->adc_nids; + int max_nums = ARRAY_SIZE(spec->adc_nids); + int i, nums = 0; + + nid = codec->start_nid; + for (i = 0; i < codec->num_nodes; i++, nid++) { + unsigned int caps = get_wcaps(codec, nid); + int type = get_wcaps_type(caps); + + if (type != AC_WID_AUD_IN || (caps & AC_WCAP_DIGITAL)) + continue; + adc_nids[nums] = nid; + if (++nums >= max_nums) + break; } - p = &spec->loopback_list[spec->num_loopbacks++]; - p->nid = nid; - p->dir = dir; - p->idx = idx; - spec->loopback.amplist = spec->loopback_list; + spec->num_adc_nids = nums; + + /* copy the detected ADCs to all_adcs[] */ + spec->num_all_adcs = nums; + memcpy(spec->all_adcs, spec->adc_nids, nums * sizeof(hda_nid_t)); + + return nums; +} + +/* filter out invalid adc_nids that don't give all active input pins; + * if needed, check whether dynamic ADC-switching is available + */ +static int check_dyn_adc_switch(struct hda_codec *codec) +{ + struct hda_gen_spec *spec = codec->spec; + struct hda_input_mux *imux = &spec->input_mux; + unsigned int ok_bits; + int i, n, nums; + + again: + nums = 0; + ok_bits = 0; + for (n = 0; n < spec->num_adc_nids; n++) { + for (i = 0; i < imux->num_items; i++) { + if (!spec->input_paths[i][n]) + break; + } + if (i >= imux->num_items) { + ok_bits |= (1 << n); + nums++; + } + } + + if (!ok_bits) { + if (spec->shared_mic_hp) { + spec->shared_mic_hp = 0; + imux->num_items = 1; + goto again; + } + + /* check whether ADC-switch is possible */ + for (i = 0; i < imux->num_items; i++) { + for (n = 0; n < spec->num_adc_nids; n++) { + if (spec->input_paths[i][n]) { + spec->dyn_adc_idx[i] = n; + break; + } + } + } + + snd_printdd("hda-codec: enabling ADC switching\n"); + spec->dyn_adc_switch = 1; + } else if (nums != spec->num_adc_nids) { + /* shrink the invalid adcs and input paths */ + nums = 0; + for (n = 0; n < spec->num_adc_nids; n++) { + if (!(ok_bits & (1 << n))) + continue; + if (n != nums) { + spec->adc_nids[nums] = spec->adc_nids[n]; + for (i = 0; i < imux->num_items; i++) { + invalidate_nid_path(codec, + spec->input_paths[i][nums]); + spec->input_paths[i][nums] = + spec->input_paths[i][n]; + } + } + nums++; + } + spec->num_adc_nids = nums; + } + + if (imux->num_items == 1 || spec->shared_mic_hp) { + snd_printdd("hda-codec: reducing to a single ADC\n"); + spec->num_adc_nids = 1; /* reduce to a single ADC */ + } + + /* single index for individual volumes ctls */ + if (!spec->dyn_adc_switch && spec->multi_cap_vol) + spec->num_adc_nids = 1; + + return 0; +} + +/* parse capture source paths from the given pin and create imux items */ +static int parse_capture_source(struct hda_codec *codec, hda_nid_t pin, + int cfg_idx, int num_adcs, + const char *label, int anchor) +{ + struct hda_gen_spec *spec = codec->spec; + struct hda_input_mux *imux = &spec->input_mux; + int imux_idx = imux->num_items; + bool imux_added = false; + int c; + + for (c = 0; c < num_adcs; c++) { + struct nid_path *path; + hda_nid_t adc = spec->adc_nids[c]; + + if (!is_reachable_path(codec, pin, adc)) + continue; + path = snd_hda_add_new_path(codec, pin, adc, anchor); + if (!path) + continue; + print_nid_path("input", path); + spec->input_paths[imux_idx][c] = + snd_hda_get_path_idx(codec, path); + + if (!imux_added) { + spec->imux_pins[imux->num_items] = pin; + snd_hda_add_imux_item(imux, label, cfg_idx, NULL); + imux_added = true; + } + } + + return 0; } -#else -#define add_input_loopback(codec,nid,dir,idx) -#endif /* - * create mixer controls if possible + * create playback/capture controls for input pins */ -static int create_mixer(struct hda_codec *codec, struct hda_gnode *node, - unsigned int index, const char *type, - const char *dir_sfx, int is_loopback) + +/* fill the label for each input at first */ +static int fill_input_pin_labels(struct hda_codec *codec) { - char name[32]; - int err; - int created = 0; - struct snd_kcontrol_new knew; + struct hda_gen_spec *spec = codec->spec; + const struct auto_pin_cfg *cfg = &spec->autocfg; + int i; - if (type) - sprintf(name, "%s %s Switch", type, dir_sfx); - else - sprintf(name, "%s Switch", dir_sfx); - if ((node->wid_caps & AC_WCAP_IN_AMP) && - (node->amp_in_caps & AC_AMPCAP_MUTE)) { - knew = (struct snd_kcontrol_new)HDA_CODEC_MUTE(name, node->nid, index, HDA_INPUT); - if (is_loopback) - add_input_loopback(codec, node->nid, HDA_INPUT, index); - snd_printdd("[%s] NID=0x%x, DIR=IN, IDX=0x%x\n", name, node->nid, index); - err = snd_hda_ctl_add(codec, node->nid, - snd_ctl_new1(&knew, codec)); - if (err < 0) - return err; - created = 1; - } else if ((node->wid_caps & AC_WCAP_OUT_AMP) && - (node->amp_out_caps & AC_AMPCAP_MUTE)) { - knew = (struct snd_kcontrol_new)HDA_CODEC_MUTE(name, node->nid, 0, HDA_OUTPUT); - if (is_loopback) - add_input_loopback(codec, node->nid, HDA_OUTPUT, 0); - snd_printdd("[%s] NID=0x%x, DIR=OUT\n", name, node->nid); - err = snd_hda_ctl_add(codec, node->nid, - snd_ctl_new1(&knew, codec)); - if (err < 0) - return err; - created = 1; + for (i = 0; i < cfg->num_inputs; i++) { + hda_nid_t pin = cfg->inputs[i].pin; + const char *label; + int j, idx; + + if (!is_input_pin(codec, pin)) + continue; + + label = hda_get_autocfg_input_label(codec, cfg, i); + idx = 0; + for (j = i - 1; j >= 0; j--) { + if (spec->input_labels[j] && + !strcmp(spec->input_labels[j], label)) { + idx = spec->input_label_idxs[j] + 1; + break; + } + } + + spec->input_labels[i] = label; + spec->input_label_idxs[i] = idx; } - if (type) - sprintf(name, "%s %s Volume", type, dir_sfx); - else - sprintf(name, "%s Volume", dir_sfx); - if ((node->wid_caps & AC_WCAP_IN_AMP) && - (node->amp_in_caps & AC_AMPCAP_NUM_STEPS)) { - knew = (struct snd_kcontrol_new)HDA_CODEC_VOLUME(name, node->nid, index, HDA_INPUT); - snd_printdd("[%s] NID=0x%x, DIR=IN, IDX=0x%x\n", name, node->nid, index); - err = snd_hda_ctl_add(codec, node->nid, - snd_ctl_new1(&knew, codec)); + return 0; +} + +#define CFG_IDX_MIX 99 /* a dummy cfg->input idx for stereo mix */ + +static int create_input_ctls(struct hda_codec *codec) +{ + struct hda_gen_spec *spec = codec->spec; + const struct auto_pin_cfg *cfg = &spec->autocfg; + hda_nid_t mixer = spec->mixer_nid; + int num_adcs; + int i, err; + unsigned int val; + + num_adcs = fill_adc_nids(codec); + if (num_adcs < 0) + return 0; + + err = fill_input_pin_labels(codec); + if (err < 0) + return err; + + for (i = 0; i < cfg->num_inputs; i++) { + hda_nid_t pin; + + pin = cfg->inputs[i].pin; + if (!is_input_pin(codec, pin)) + continue; + + val = PIN_IN; + if (cfg->inputs[i].type == AUTO_PIN_MIC) + val |= snd_hda_get_default_vref(codec, pin); + set_pin_target(codec, pin, val, false); + + if (mixer) { + if (is_reachable_path(codec, pin, mixer)) { + err = new_analog_input(codec, i, pin, + spec->input_labels[i], + spec->input_label_idxs[i], + mixer); + if (err < 0) + return err; + } + } + + err = parse_capture_source(codec, pin, i, num_adcs, + spec->input_labels[i], -mixer); if (err < 0) return err; - created = 1; - } else if ((node->wid_caps & AC_WCAP_OUT_AMP) && - (node->amp_out_caps & AC_AMPCAP_NUM_STEPS)) { - knew = (struct snd_kcontrol_new)HDA_CODEC_VOLUME(name, node->nid, 0, HDA_OUTPUT); - snd_printdd("[%s] NID=0x%x, DIR=OUT\n", name, node->nid); - err = snd_hda_ctl_add(codec, node->nid, - snd_ctl_new1(&knew, codec)); + + if (spec->add_in_jack_modes) { + err = create_in_jack_mode(codec, pin); + if (err < 0) + return err; + } + } + + if (mixer && spec->add_stereo_mix_input) { + err = parse_capture_source(codec, mixer, CFG_IDX_MIX, num_adcs, + "Stereo Mix", 0); if (err < 0) return err; - created = 1; } - return created; + return 0; } + /* - * check whether the controls with the given name and direction suffix already exist + * input source mux */ -static int check_existing_control(struct hda_codec *codec, const char *type, const char *dir) -{ - struct snd_ctl_elem_id id; - memset(&id, 0, sizeof(id)); - sprintf(id.name, "%s %s Volume", type, dir); - id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; - if (snd_ctl_find_id(codec->bus->card, &id)) - return 1; - sprintf(id.name, "%s %s Switch", type, dir); - id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; - if (snd_ctl_find_id(codec->bus->card, &id)) - return 1; + +/* get the input path specified by the given adc and imux indices */ +static struct nid_path *get_input_path(struct hda_codec *codec, int adc_idx, int imux_idx) +{ + struct hda_gen_spec *spec = codec->spec; + if (imux_idx < 0 || imux_idx >= HDA_MAX_NUM_INPUTS) { + snd_BUG(); + return NULL; + } + if (spec->dyn_adc_switch) + adc_idx = spec->dyn_adc_idx[imux_idx]; + if (adc_idx < 0 || adc_idx >= AUTO_CFG_MAX_INS) { + snd_BUG(); + return NULL; + } + return snd_hda_get_path_from_idx(codec, spec->input_paths[imux_idx][adc_idx]); +} + +static int mux_select(struct hda_codec *codec, unsigned int adc_idx, + unsigned int idx); + +static int mux_enum_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct hda_gen_spec *spec = codec->spec; + return snd_hda_input_mux_info(&spec->input_mux, uinfo); +} + +static int mux_enum_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct hda_gen_spec *spec = codec->spec; + /* the ctls are created at once with multiple counts */ + 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 mux_enum_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); + return mux_select(codec, adc_idx, + ucontrol->value.enumerated.item[0]); +} + +static const struct snd_kcontrol_new cap_src_temp = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Input Source", + .info = mux_enum_info, + .get = mux_enum_get, + .put = mux_enum_put, +}; + /* - * build output mixer controls + * capture volume and capture switch ctls */ -static int create_output_mixers(struct hda_codec *codec, - const char * const *names) + +typedef int (*put_call_t)(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); + +/* call the given amp update function for all amps in the imux list at once */ +static int cap_put_caller(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol, + put_call_t func, int type) { - struct hda_gspec *spec = codec->spec; - int i, err; + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct hda_gen_spec *spec = codec->spec; + const struct hda_input_mux *imux; + struct nid_path *path; + int i, adc_idx, err = 0; - for (i = 0; i < spec->pcm_vol_nodes; i++) { - err = create_mixer(codec, spec->pcm_vol[i].node, - spec->pcm_vol[i].index, - names[i], "Playback", 0); + imux = &spec->input_mux; + adc_idx = kcontrol->id.index; + mutex_lock(&codec->control_mutex); + /* we use the cache-only update at first since multiple input paths + * may shared the same amp; by updating only caches, the redundant + * writes to hardware can be reduced. + */ + codec->cached_write = 1; + for (i = 0; i < imux->num_items; i++) { + path = get_input_path(codec, adc_idx, i); + if (!path || !path->ctls[type]) + continue; + kcontrol->private_value = path->ctls[type]; + err = func(kcontrol, ucontrol); if (err < 0) - return err; + goto error; } - return 0; + error: + codec->cached_write = 0; + mutex_unlock(&codec->control_mutex); + snd_hda_codec_flush_cache(codec); /* flush the updates */ + if (err >= 0 && spec->cap_sync_hook) + spec->cap_sync_hook(codec, ucontrol); + return err; } -static int build_output_controls(struct hda_codec *codec) +/* capture volume ctl callbacks */ +#define cap_vol_info snd_hda_mixer_amp_volume_info +#define cap_vol_get snd_hda_mixer_amp_volume_get +#define cap_vol_tlv snd_hda_mixer_amp_tlv + +static int cap_vol_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - struct hda_gspec *spec = codec->spec; - static const char * const types_speaker[] = { "Speaker", "Headphone" }; - static const char * const types_line[] = { "Front", "Headphone" }; + return cap_put_caller(kcontrol, ucontrol, + snd_hda_mixer_amp_volume_put, + NID_PATH_VOL_CTL); +} - switch (spec->pcm_vol_nodes) { - case 1: - return create_mixer(codec, spec->pcm_vol[0].node, - spec->pcm_vol[0].index, - "Master", "Playback", 0); - case 2: - if (defcfg_type(spec->out_pin_node[0]) == AC_JACK_SPEAKER) - return create_output_mixers(codec, types_speaker); - else - return create_output_mixers(codec, types_line); +static const struct snd_kcontrol_new cap_vol_temp = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Capture Volume", + .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_TLV_READ | + SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK), + .info = cap_vol_info, + .get = cap_vol_get, + .put = cap_vol_put, + .tlv = { .c = cap_vol_tlv }, +}; + +/* capture switch ctl callbacks */ +#define cap_sw_info snd_ctl_boolean_stereo_info +#define cap_sw_get snd_hda_mixer_amp_switch_get + +static int cap_sw_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + return cap_put_caller(kcontrol, ucontrol, + snd_hda_mixer_amp_switch_put, + NID_PATH_MUTE_CTL); +} + +static const struct snd_kcontrol_new cap_sw_temp = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Capture Switch", + .info = cap_sw_info, + .get = cap_sw_get, + .put = cap_sw_put, +}; + +static int parse_capvol_in_path(struct hda_codec *codec, struct nid_path *path) +{ + hda_nid_t nid; + int i, depth; + + path->ctls[NID_PATH_VOL_CTL] = path->ctls[NID_PATH_MUTE_CTL] = 0; + for (depth = 0; depth < 3; depth++) { + if (depth >= path->depth) + return -EINVAL; + i = path->depth - depth - 1; + nid = path->path[i]; + if (!path->ctls[NID_PATH_VOL_CTL]) { + if (nid_has_volume(codec, nid, HDA_OUTPUT)) + path->ctls[NID_PATH_VOL_CTL] = + HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); + else if (nid_has_volume(codec, nid, HDA_INPUT)) { + int idx = path->idx[i]; + if (!depth && codec->single_adc_amp) + idx = 0; + path->ctls[NID_PATH_VOL_CTL] = + HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_INPUT); + } + } + if (!path->ctls[NID_PATH_MUTE_CTL]) { + if (nid_has_mute(codec, nid, HDA_OUTPUT)) + path->ctls[NID_PATH_MUTE_CTL] = + HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); + else if (nid_has_mute(codec, nid, HDA_INPUT)) { + int idx = path->idx[i]; + if (!depth && codec->single_adc_amp) + idx = 0; + path->ctls[NID_PATH_MUTE_CTL] = + HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_INPUT); + } + } } return 0; } -/* create capture volume/switch */ -static int build_input_controls(struct hda_codec *codec) +static bool is_inv_dmic_pin(struct hda_codec *codec, hda_nid_t nid) { - struct hda_gspec *spec = codec->spec; - struct hda_gnode *adc_node = spec->adc_node; - int i, err; - static struct snd_kcontrol_new cap_sel = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .info = capture_source_info, - .get = capture_source_get, - .put = capture_source_put, - }; + struct hda_gen_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + unsigned int val; + int i; + + if (!spec->inv_dmic_split) + return false; + for (i = 0; i < cfg->num_inputs; i++) { + if (cfg->inputs[i].pin != nid) + continue; + if (cfg->inputs[i].type != AUTO_PIN_MIC) + return false; + val = snd_hda_codec_get_pincfg(codec, nid); + return snd_hda_get_input_pin_attr(val) == INPUT_PIN_ATTR_INT; + } + return false; +} - if (! adc_node || ! spec->input_mux.num_items) - return 0; /* not found */ +/* capture switch put callback for a single control with hook call */ +static int cap_single_sw_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct hda_gen_spec *spec = codec->spec; + int ret; - spec->cur_cap_src = 0; - select_input_connection(codec, adc_node, - spec->input_mux.items[0].index); + ret = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); + if (ret < 0) + return ret; - /* create capture volume and switch controls if the ADC has an amp */ - /* do we have only a single item? */ - if (spec->input_mux.num_items == 1) { - err = create_mixer(codec, adc_node, - spec->input_mux.items[0].index, - NULL, "Capture", 0); - if (err < 0) - return err; + if (spec->cap_sync_hook) + spec->cap_sync_hook(codec, ucontrol); + + return ret; +} + +static int add_single_cap_ctl(struct hda_codec *codec, const char *label, + int idx, bool is_switch, unsigned int ctl, + bool inv_dmic) +{ + struct hda_gen_spec *spec = codec->spec; + char tmpname[44]; + int type = is_switch ? HDA_CTL_WIDGET_MUTE : HDA_CTL_WIDGET_VOL; + const char *sfx = is_switch ? "Switch" : "Volume"; + unsigned int chs = inv_dmic ? 1 : 3; + struct snd_kcontrol_new *knew; + + if (!ctl) return 0; - } - /* create input MUX if multiple sources are available */ - err = snd_hda_ctl_add(codec, spec->adc_node->nid, - snd_ctl_new1(&cap_sel, codec)); + if (label) + snprintf(tmpname, sizeof(tmpname), + "%s Capture %s", label, sfx); + else + snprintf(tmpname, sizeof(tmpname), + "Capture %s", sfx); + knew = add_control(spec, type, tmpname, idx, + amp_val_replace_channels(ctl, chs)); + if (!knew) + return -ENOMEM; + if (is_switch) + knew->put = cap_single_sw_put; + if (!inv_dmic) + return 0; + + /* Make independent right kcontrol */ + if (label) + snprintf(tmpname, sizeof(tmpname), + "Inverted %s Capture %s", label, sfx); + else + snprintf(tmpname, sizeof(tmpname), + "Inverted Capture %s", sfx); + knew = add_control(spec, type, tmpname, idx, + amp_val_replace_channels(ctl, 2)); + if (!knew) + return -ENOMEM; + if (is_switch) + knew->put = cap_single_sw_put; + return 0; +} + +/* create single (and simple) capture volume and switch controls */ +static int create_single_cap_vol_ctl(struct hda_codec *codec, int idx, + unsigned int vol_ctl, unsigned int sw_ctl, + bool inv_dmic) +{ + int err; + err = add_single_cap_ctl(codec, NULL, idx, false, vol_ctl, inv_dmic); if (err < 0) return err; + err = add_single_cap_ctl(codec, NULL, idx, true, sw_ctl, inv_dmic); + if (err < 0) + return err; + return 0; +} + +/* create bound capture volume and switch controls */ +static int create_bind_cap_vol_ctl(struct hda_codec *codec, int idx, + unsigned int vol_ctl, unsigned int sw_ctl) +{ + struct hda_gen_spec *spec = codec->spec; + struct snd_kcontrol_new *knew; - /* no volume control? */ - if (! (adc_node->wid_caps & AC_WCAP_IN_AMP) || - ! (adc_node->amp_in_caps & AC_AMPCAP_NUM_STEPS)) + if (vol_ctl) { + knew = snd_hda_gen_add_kctl(spec, NULL, &cap_vol_temp); + if (!knew) + return -ENOMEM; + knew->index = idx; + knew->private_value = vol_ctl; + knew->subdevice = HDA_SUBDEV_AMP_FLAG; + } + if (sw_ctl) { + knew = snd_hda_gen_add_kctl(spec, NULL, &cap_sw_temp); + if (!knew) + return -ENOMEM; + knew->index = idx; + knew->private_value = sw_ctl; + knew->subdevice = HDA_SUBDEV_AMP_FLAG; + } + return 0; +} + +/* return the vol ctl when used first in the imux list */ +static unsigned int get_first_cap_ctl(struct hda_codec *codec, int idx, int type) +{ + struct nid_path *path; + unsigned int ctl; + int i; + + path = get_input_path(codec, 0, idx); + if (!path) return 0; + ctl = path->ctls[type]; + if (!ctl) + return 0; + for (i = 0; i < idx - 1; i++) { + path = get_input_path(codec, 0, i); + if (path && path->ctls[type] == ctl) + return 0; + } + return ctl; +} + +/* create individual capture volume and switch controls per input */ +static int create_multi_cap_vol_ctl(struct hda_codec *codec) +{ + struct hda_gen_spec *spec = codec->spec; + struct hda_input_mux *imux = &spec->input_mux; + int i, err, type; + + for (i = 0; i < imux->num_items; i++) { + bool inv_dmic; + int idx; + + idx = imux->items[i].index; + if (idx >= spec->autocfg.num_inputs) + continue; + inv_dmic = is_inv_dmic_pin(codec, spec->imux_pins[i]); - for (i = 0; i < spec->input_mux.num_items; i++) { - struct snd_kcontrol_new knew; - char name[32]; - sprintf(name, "%s Capture Volume", - spec->input_mux.items[i].label); - knew = (struct snd_kcontrol_new) - HDA_CODEC_VOLUME(name, adc_node->nid, - spec->input_mux.items[i].index, - HDA_INPUT); - err = snd_hda_ctl_add(codec, adc_node->nid, - snd_ctl_new1(&knew, codec)); + for (type = 0; type < 2; type++) { + err = add_single_cap_ctl(codec, + spec->input_labels[idx], + spec->input_label_idxs[idx], + type, + get_first_cap_ctl(codec, i, type), + inv_dmic); + if (err < 0) + return err; + } + } + return 0; +} + +static int create_capture_mixers(struct hda_codec *codec) +{ + struct hda_gen_spec *spec = codec->spec; + struct hda_input_mux *imux = &spec->input_mux; + int i, n, nums, err; + + if (spec->dyn_adc_switch) + nums = 1; + else + nums = spec->num_adc_nids; + + if (!spec->auto_mic && imux->num_items > 1) { + struct snd_kcontrol_new *knew; + const char *name; + name = nums > 1 ? "Input Source" : "Capture Source"; + knew = snd_hda_gen_add_kctl(spec, name, &cap_src_temp); + if (!knew) + return -ENOMEM; + knew->count = nums; + } + + for (n = 0; n < nums; n++) { + bool multi = false; + bool multi_cap_vol = spec->multi_cap_vol; + bool inv_dmic = false; + int vol, sw; + + vol = sw = 0; + for (i = 0; i < imux->num_items; i++) { + struct nid_path *path; + path = get_input_path(codec, n, i); + if (!path) + continue; + parse_capvol_in_path(codec, path); + if (!vol) + vol = path->ctls[NID_PATH_VOL_CTL]; + else if (vol != path->ctls[NID_PATH_VOL_CTL]) { + multi = true; + if (!same_amp_caps(codec, vol, + path->ctls[NID_PATH_VOL_CTL], HDA_INPUT)) + multi_cap_vol = true; + } + if (!sw) + sw = path->ctls[NID_PATH_MUTE_CTL]; + else if (sw != path->ctls[NID_PATH_MUTE_CTL]) { + multi = true; + if (!same_amp_caps(codec, sw, + path->ctls[NID_PATH_MUTE_CTL], HDA_INPUT)) + multi_cap_vol = true; + } + if (is_inv_dmic_pin(codec, spec->imux_pins[i])) + inv_dmic = true; + } + + if (!multi) + err = create_single_cap_vol_ctl(codec, n, vol, sw, + inv_dmic); + else if (!multi_cap_vol) + err = create_bind_cap_vol_ctl(codec, n, vol, sw); + else + err = create_multi_cap_vol_ctl(codec); if (err < 0) return err; } @@ -860,226 +3234,1696 @@ static int build_input_controls(struct hda_codec *codec) return 0; } +/* + * add mic boosts if needed + */ + +/* check whether the given amp is feasible as a boost volume */ +static bool check_boost_vol(struct hda_codec *codec, hda_nid_t nid, + int dir, int idx) +{ + unsigned int step; + + if (!nid_has_volume(codec, nid, dir) || + is_ctl_associated(codec, nid, dir, idx, NID_PATH_VOL_CTL) || + is_ctl_associated(codec, nid, dir, idx, NID_PATH_BOOST_CTL)) + return false; + + step = (query_amp_caps(codec, nid, dir) & AC_AMPCAP_STEP_SIZE) + >> AC_AMPCAP_STEP_SIZE_SHIFT; + if (step < 0x20) + return false; + return true; +} + +/* look for a boost amp in a widget close to the pin */ +static unsigned int look_for_boost_amp(struct hda_codec *codec, + struct nid_path *path) +{ + unsigned int val = 0; + hda_nid_t nid; + int depth; + + for (depth = 0; depth < 3; depth++) { + if (depth >= path->depth - 1) + break; + nid = path->path[depth]; + if (depth && check_boost_vol(codec, nid, HDA_OUTPUT, 0)) { + val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); + break; + } else if (check_boost_vol(codec, nid, HDA_INPUT, + path->idx[depth])) { + val = HDA_COMPOSE_AMP_VAL(nid, 3, path->idx[depth], + HDA_INPUT); + break; + } + } + + return val; +} + +static int parse_mic_boost(struct hda_codec *codec) +{ + struct hda_gen_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + struct hda_input_mux *imux = &spec->input_mux; + int i; + + if (!spec->num_adc_nids) + return 0; + + for (i = 0; i < imux->num_items; i++) { + struct nid_path *path; + unsigned int val; + int idx; + char boost_label[44]; + + idx = imux->items[i].index; + if (idx >= imux->num_items) + continue; + + /* check only line-in and mic pins */ + if (cfg->inputs[idx].type > AUTO_PIN_LINE_IN) + continue; + + path = get_input_path(codec, 0, i); + if (!path) + continue; + + val = look_for_boost_amp(codec, path); + if (!val) + continue; + + /* create a boost control */ + snprintf(boost_label, sizeof(boost_label), + "%s Boost Volume", spec->input_labels[idx]); + if (!add_control(spec, HDA_CTL_WIDGET_VOL, boost_label, + spec->input_label_idxs[idx], val)) + return -ENOMEM; + + path->ctls[NID_PATH_BOOST_CTL] = val; + } + return 0; +} /* - * parse the nodes recursively until reach to the output PIN. - * - * returns 0 - if not found, - * 1 - if found, but no mixer is created - * 2 - if found and mixer was already created, (just skip) - * a negative error code + * parse digital I/Os and set up NIDs in BIOS auto-parse mode + */ +static void parse_digital(struct hda_codec *codec) +{ + struct hda_gen_spec *spec = codec->spec; + struct nid_path *path; + int i, nums; + hda_nid_t dig_nid, pin; + + /* support multiple SPDIFs; the secondary is set up as a slave */ + nums = 0; + for (i = 0; i < spec->autocfg.dig_outs; i++) { + pin = spec->autocfg.dig_out_pins[i]; + dig_nid = look_for_dac(codec, pin, true); + if (!dig_nid) + continue; + path = snd_hda_add_new_path(codec, dig_nid, pin, 0); + if (!path) + continue; + print_nid_path("digout", path); + path->active = true; + spec->digout_paths[i] = snd_hda_get_path_idx(codec, path); + set_pin_target(codec, pin, PIN_OUT, false); + if (!nums) { + spec->multiout.dig_out_nid = dig_nid; + spec->dig_out_type = spec->autocfg.dig_out_type[0]; + } else { + spec->multiout.slave_dig_outs = spec->slave_dig_outs; + if (nums >= ARRAY_SIZE(spec->slave_dig_outs) - 1) + break; + spec->slave_dig_outs[nums - 1] = dig_nid; + } + nums++; + } + + if (spec->autocfg.dig_in_pin) { + pin = spec->autocfg.dig_in_pin; + dig_nid = codec->start_nid; + for (i = 0; i < codec->num_nodes; i++, dig_nid++) { + unsigned int wcaps = get_wcaps(codec, dig_nid); + if (get_wcaps_type(wcaps) != AC_WID_AUD_IN) + continue; + if (!(wcaps & AC_WCAP_DIGITAL)) + continue; + path = snd_hda_add_new_path(codec, pin, dig_nid, 0); + if (path) { + print_nid_path("digin", path); + path->active = true; + spec->dig_in_nid = dig_nid; + spec->digin_path = snd_hda_get_path_idx(codec, path); + set_pin_target(codec, pin, PIN_IN, false); + break; + } + } + } +} + + +/* + * input MUX handling + */ + +static bool dyn_adc_pcm_resetup(struct hda_codec *codec, int cur); + +/* select the given imux item; either unmute exclusively or select the route */ +static int mux_select(struct hda_codec *codec, unsigned int adc_idx, + unsigned int idx) +{ + struct hda_gen_spec *spec = codec->spec; + const struct hda_input_mux *imux; + struct nid_path *old_path, *path; + + imux = &spec->input_mux; + if (!imux->num_items) + return 0; + + if (idx >= imux->num_items) + idx = imux->num_items - 1; + if (spec->cur_mux[adc_idx] == idx) + return 0; + + old_path = get_input_path(codec, adc_idx, spec->cur_mux[adc_idx]); + if (!old_path) + return 0; + if (old_path->active) + snd_hda_activate_path(codec, old_path, false, false); + + spec->cur_mux[adc_idx] = idx; + + if (spec->shared_mic_hp) + update_shared_mic_hp(codec, spec->cur_mux[adc_idx]); + + if (spec->dyn_adc_switch) + dyn_adc_pcm_resetup(codec, idx); + + path = get_input_path(codec, adc_idx, idx); + if (!path) + return 0; + if (path->active) + return 0; + snd_hda_activate_path(codec, path, true, false); + if (spec->cap_sync_hook) + spec->cap_sync_hook(codec, NULL); + path_power_down_sync(codec, old_path); + return 1; +} + + +/* + * Jack detections for HP auto-mute and mic-switch + */ + +/* check each pin in the given array; returns true if any of them is plugged */ +static bool detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins) +{ + int i, present = 0; + + for (i = 0; i < num_pins; i++) { + hda_nid_t nid = pins[i]; + if (!nid) + break; + /* don't detect pins retasked as inputs */ + if (snd_hda_codec_get_pin_target(codec, nid) & AC_PINCTL_IN_EN) + continue; + present |= snd_hda_jack_detect(codec, nid); + } + return present; +} + +/* standard HP/line-out auto-mute helper */ +static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins, + bool mute) +{ + struct hda_gen_spec *spec = codec->spec; + int i; + + for (i = 0; i < num_pins; i++) { + hda_nid_t nid = pins[i]; + unsigned int val; + if (!nid) + break; + /* don't reset VREF value in case it's controlling + * the amp (see alc861_fixup_asus_amp_vref_0f()) + */ + if (spec->keep_vref_in_automute) + val = snd_hda_codec_get_pin_target(codec, nid) & ~PIN_HP; + else + val = 0; + if (!mute) + val |= snd_hda_codec_get_pin_target(codec, nid); + /* here we call update_pin_ctl() so that the pinctl is changed + * without changing the pinctl target value; + * the original target value will be still referred at the + * init / resume again + */ + update_pin_ctl(codec, nid, val); + set_pin_eapd(codec, nid, !mute); + } +} + +/* Toggle outputs muting */ +void snd_hda_gen_update_outputs(struct hda_codec *codec) +{ + struct hda_gen_spec *spec = codec->spec; + int on; + + /* Control HP pins/amps depending on master_mute state; + * in general, HP pins/amps control should be enabled in all cases, + * but currently set only for master_mute, just to be safe + */ + if (!spec->shared_mic_hp) /* don't change HP-pin when shared with mic */ + do_automute(codec, ARRAY_SIZE(spec->autocfg.hp_pins), + spec->autocfg.hp_pins, spec->master_mute); + + if (!spec->automute_speaker) + on = 0; + else + on = spec->hp_jack_present | spec->line_jack_present; + on |= spec->master_mute; + spec->speaker_muted = on; + do_automute(codec, ARRAY_SIZE(spec->autocfg.speaker_pins), + spec->autocfg.speaker_pins, on); + + /* toggle line-out mutes if needed, too */ + /* if LO is a copy of either HP or Speaker, don't need to handle it */ + if (spec->autocfg.line_out_pins[0] == spec->autocfg.hp_pins[0] || + spec->autocfg.line_out_pins[0] == spec->autocfg.speaker_pins[0]) + return; + if (!spec->automute_lo) + on = 0; + else + on = spec->hp_jack_present; + on |= spec->master_mute; + spec->line_out_muted = on; + do_automute(codec, ARRAY_SIZE(spec->autocfg.line_out_pins), + spec->autocfg.line_out_pins, on); +} +EXPORT_SYMBOL_HDA(snd_hda_gen_update_outputs); + +static void call_update_outputs(struct hda_codec *codec) +{ + struct hda_gen_spec *spec = codec->spec; + if (spec->automute_hook) + spec->automute_hook(codec); + else + snd_hda_gen_update_outputs(codec); +} + +/* standard HP-automute helper */ +void snd_hda_gen_hp_automute(struct hda_codec *codec, struct hda_jack_tbl *jack) +{ + struct hda_gen_spec *spec = codec->spec; + hda_nid_t *pins = spec->autocfg.hp_pins; + int num_pins = ARRAY_SIZE(spec->autocfg.hp_pins); + + /* No detection for the first HP jack during indep-HP mode */ + if (spec->indep_hp_enabled) { + pins++; + num_pins--; + } + + spec->hp_jack_present = detect_jacks(codec, num_pins, pins); + if (!spec->detect_hp || (!spec->automute_speaker && !spec->automute_lo)) + return; + call_update_outputs(codec); +} +EXPORT_SYMBOL_HDA(snd_hda_gen_hp_automute); + +/* standard line-out-automute helper */ +void snd_hda_gen_line_automute(struct hda_codec *codec, struct hda_jack_tbl *jack) +{ + struct hda_gen_spec *spec = codec->spec; + + if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT) + return; + /* check LO jack only when it's different from HP */ + if (spec->autocfg.line_out_pins[0] == spec->autocfg.hp_pins[0]) + return; + + spec->line_jack_present = + detect_jacks(codec, ARRAY_SIZE(spec->autocfg.line_out_pins), + spec->autocfg.line_out_pins); + if (!spec->automute_speaker || !spec->detect_lo) + return; + call_update_outputs(codec); +} +EXPORT_SYMBOL_HDA(snd_hda_gen_line_automute); + +/* standard mic auto-switch helper */ +void snd_hda_gen_mic_autoswitch(struct hda_codec *codec, struct hda_jack_tbl *jack) +{ + struct hda_gen_spec *spec = codec->spec; + int i; + + if (!spec->auto_mic) + return; + + for (i = spec->am_num_entries - 1; i > 0; i--) { + hda_nid_t pin = spec->am_entry[i].pin; + /* don't detect pins retasked as outputs */ + if (snd_hda_codec_get_pin_target(codec, pin) & AC_PINCTL_OUT_EN) + continue; + if (snd_hda_jack_detect(codec, pin)) { + mux_select(codec, 0, spec->am_entry[i].idx); + return; + } + } + mux_select(codec, 0, spec->am_entry[0].idx); +} +EXPORT_SYMBOL_HDA(snd_hda_gen_mic_autoswitch); + +/* update jack retasking */ +static void update_automute_all(struct hda_codec *codec) +{ + struct hda_gen_spec *spec = codec->spec; + + if (spec->hp_automute_hook) + spec->hp_automute_hook(codec, NULL); + else + snd_hda_gen_hp_automute(codec, NULL); + if (spec->line_automute_hook) + spec->line_automute_hook(codec, NULL); + else + snd_hda_gen_line_automute(codec, NULL); + if (spec->mic_autoswitch_hook) + spec->mic_autoswitch_hook(codec, NULL); + else + snd_hda_gen_mic_autoswitch(codec, NULL); +} + +/* + * Auto-Mute mode mixer enum support + */ +static int automute_mode_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct hda_gen_spec *spec = codec->spec; + static const char * const texts3[] = { + "Disabled", "Speaker Only", "Line Out+Speaker" + }; + + if (spec->automute_speaker_possible && spec->automute_lo_possible) + return snd_hda_enum_helper_info(kcontrol, uinfo, 3, texts3); + return snd_hda_enum_bool_helper_info(kcontrol, uinfo); +} + +static int automute_mode_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct hda_gen_spec *spec = codec->spec; + unsigned int val = 0; + if (spec->automute_speaker) + val++; + if (spec->automute_lo) + val++; + + ucontrol->value.enumerated.item[0] = val; + return 0; +} + +static int automute_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct hda_gen_spec *spec = codec->spec; + + switch (ucontrol->value.enumerated.item[0]) { + case 0: + if (!spec->automute_speaker && !spec->automute_lo) + return 0; + spec->automute_speaker = 0; + spec->automute_lo = 0; + break; + case 1: + if (spec->automute_speaker_possible) { + if (!spec->automute_lo && spec->automute_speaker) + return 0; + spec->automute_speaker = 1; + spec->automute_lo = 0; + } else if (spec->automute_lo_possible) { + if (spec->automute_lo) + return 0; + spec->automute_lo = 1; + } else + return -EINVAL; + break; + case 2: + if (!spec->automute_lo_possible || !spec->automute_speaker_possible) + return -EINVAL; + if (spec->automute_speaker && spec->automute_lo) + return 0; + spec->automute_speaker = 1; + spec->automute_lo = 1; + break; + default: + return -EINVAL; + } + call_update_outputs(codec); + return 1; +} + +static const struct snd_kcontrol_new automute_mode_enum = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Auto-Mute Mode", + .info = automute_mode_info, + .get = automute_mode_get, + .put = automute_mode_put, +}; + +static int add_automute_mode_enum(struct hda_codec *codec) +{ + struct hda_gen_spec *spec = codec->spec; + + if (!snd_hda_gen_add_kctl(spec, NULL, &automute_mode_enum)) + return -ENOMEM; + return 0; +} + +/* + * Check the availability of HP/line-out auto-mute; + * Set up appropriately if really supported */ -static int parse_loopback_path(struct hda_codec *codec, struct hda_gspec *spec, - struct hda_gnode *node, struct hda_gnode *dest_node, - const char *type) +static int check_auto_mute_availability(struct hda_codec *codec) { + struct hda_gen_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + int present = 0; int i, err; - if (node->checked) + if (spec->suppress_auto_mute) return 0; - node->checked = 1; - if (node == dest_node) { - /* loopback connection found */ - return 1; + if (cfg->hp_pins[0]) + present++; + if (cfg->line_out_pins[0]) + present++; + if (cfg->speaker_pins[0]) + present++; + if (present < 2) /* need two different output types */ + return 0; + + if (!cfg->speaker_pins[0] && + cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) { + memcpy(cfg->speaker_pins, cfg->line_out_pins, + sizeof(cfg->speaker_pins)); + cfg->speaker_outs = cfg->line_outs; + } + + if (!cfg->hp_pins[0] && + cfg->line_out_type == AUTO_PIN_HP_OUT) { + memcpy(cfg->hp_pins, cfg->line_out_pins, + sizeof(cfg->hp_pins)); + cfg->hp_outs = cfg->line_outs; } - for (i = 0; i < node->nconns; i++) { - struct hda_gnode *child = hda_get_node(spec, node->conn_list[i]); - if (! child) + for (i = 0; i < cfg->hp_outs; i++) { + hda_nid_t nid = cfg->hp_pins[i]; + if (!is_jack_detectable(codec, nid)) continue; - err = parse_loopback_path(codec, spec, child, dest_node, type); - if (err < 0) - return err; - else if (err >= 1) { - if (err == 1) { - err = create_mixer(codec, node, i, type, - "Playback", 1); - if (err < 0) - return err; - if (err > 0) - return 2; /* ok, created */ - /* not created, maybe in the lower path */ - err = 1; + snd_printdd("hda-codec: Enable HP auto-muting on NID 0x%x\n", + nid); + snd_hda_jack_detect_enable_callback(codec, nid, HDA_GEN_HP_EVENT, + spec->hp_automute_hook ? + spec->hp_automute_hook : + snd_hda_gen_hp_automute); + spec->detect_hp = 1; + } + + if (cfg->line_out_type == AUTO_PIN_LINE_OUT && cfg->line_outs) { + if (cfg->speaker_outs) + for (i = 0; i < cfg->line_outs; i++) { + hda_nid_t nid = cfg->line_out_pins[i]; + if (!is_jack_detectable(codec, nid)) + continue; + snd_printdd("hda-codec: Enable Line-Out auto-muting on NID 0x%x\n", nid); + snd_hda_jack_detect_enable_callback(codec, nid, + HDA_GEN_FRONT_EVENT, + spec->line_automute_hook ? + spec->line_automute_hook : + snd_hda_gen_line_automute); + spec->detect_lo = 1; } - /* connect and unmute */ - if (node->nconns > 1) - select_input_connection(codec, node, i); - unmute_input(codec, node, i); - unmute_output(codec, node); + spec->automute_lo_possible = spec->detect_hp; + } + + spec->automute_speaker_possible = cfg->speaker_outs && + (spec->detect_hp || spec->detect_lo); + + spec->automute_lo = spec->automute_lo_possible; + spec->automute_speaker = spec->automute_speaker_possible; + + if (spec->automute_speaker_possible || spec->automute_lo_possible) { + /* create a control for automute mode */ + err = add_automute_mode_enum(codec); + if (err < 0) return err; - } } return 0; } +/* check whether all auto-mic pins are valid; setup indices if OK */ +static bool auto_mic_check_imux(struct hda_codec *codec) +{ + struct hda_gen_spec *spec = codec->spec; + const struct hda_input_mux *imux; + int i; + + imux = &spec->input_mux; + for (i = 0; i < spec->am_num_entries; i++) { + spec->am_entry[i].idx = + find_idx_in_nid_list(spec->am_entry[i].pin, + spec->imux_pins, imux->num_items); + if (spec->am_entry[i].idx < 0) + return false; /* no corresponding imux */ + } + + /* we don't need the jack detection for the first pin */ + for (i = 1; i < spec->am_num_entries; i++) + snd_hda_jack_detect_enable_callback(codec, + spec->am_entry[i].pin, + HDA_GEN_MIC_EVENT, + spec->mic_autoswitch_hook ? + spec->mic_autoswitch_hook : + snd_hda_gen_mic_autoswitch); + return true; +} + +static int compare_attr(const void *ap, const void *bp) +{ + const struct automic_entry *a = ap; + const struct automic_entry *b = bp; + return (int)(a->attr - b->attr); +} + /* - * parse the tree and build the loopback controls + * Check the availability of auto-mic switch; + * Set up if really supported */ -static int build_loopback_controls(struct hda_codec *codec) +static int check_auto_mic_availability(struct hda_codec *codec) { - struct hda_gspec *spec = codec->spec; - struct hda_gnode *node; - int err; - const char *type; + struct hda_gen_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + unsigned int types; + int i, num_pins; - if (! spec->out_pin_node[0]) + if (spec->suppress_auto_mic) return 0; - list_for_each_entry(node, &spec->nid_list, list) { - if (node->type != AC_WID_PIN) - continue; - /* input capable? */ - if (! (node->pin_caps & AC_PINCAP_IN)) + types = 0; + num_pins = 0; + for (i = 0; i < cfg->num_inputs; i++) { + hda_nid_t nid = cfg->inputs[i].pin; + unsigned int attr; + attr = snd_hda_codec_get_pincfg(codec, nid); + attr = snd_hda_get_input_pin_attr(attr); + if (types & (1 << attr)) + return 0; /* already occupied */ + switch (attr) { + case INPUT_PIN_ATTR_INT: + if (cfg->inputs[i].type != AUTO_PIN_MIC) + return 0; /* invalid type */ + break; + case INPUT_PIN_ATTR_UNUSED: + return 0; /* invalid entry */ + default: + if (cfg->inputs[i].type > AUTO_PIN_LINE_IN) + return 0; /* invalid type */ + if (!spec->line_in_auto_switch && + cfg->inputs[i].type != AUTO_PIN_MIC) + return 0; /* only mic is allowed */ + if (!is_jack_detectable(codec, nid)) + return 0; /* no unsol support */ + break; + } + if (num_pins >= MAX_AUTO_MIC_PINS) return 0; - type = get_input_type(node, NULL); - if (type) { - if (check_existing_control(codec, type, "Playback")) - continue; - clear_check_flags(spec); - err = parse_loopback_path(codec, spec, - spec->out_pin_node[0], - node, type); + types |= (1 << attr); + spec->am_entry[num_pins].pin = nid; + spec->am_entry[num_pins].attr = attr; + num_pins++; + } + + if (num_pins < 2) + return 0; + + spec->am_num_entries = num_pins; + /* sort the am_entry in the order of attr so that the pin with a + * higher attr will be selected when the jack is plugged. + */ + sort(spec->am_entry, num_pins, sizeof(spec->am_entry[0]), + compare_attr, NULL); + + if (!auto_mic_check_imux(codec)) + return 0; + + spec->auto_mic = 1; + spec->num_adc_nids = 1; + spec->cur_mux[0] = spec->am_entry[0].idx; + snd_printdd("hda-codec: Enable auto-mic switch on NID 0x%x/0x%x/0x%x\n", + spec->am_entry[0].pin, + spec->am_entry[1].pin, + spec->am_entry[2].pin); + + return 0; +} + +/* power_filter hook; make inactive widgets into power down */ +static unsigned int snd_hda_gen_path_power_filter(struct hda_codec *codec, + hda_nid_t nid, + unsigned int power_state) +{ + if (power_state != AC_PWRST_D0) + return power_state; + if (get_wcaps_type(get_wcaps(codec, nid)) >= AC_WID_POWER) + return power_state; + if (is_active_nid(codec, nid, HDA_OUTPUT, 0)) + return power_state; + return AC_PWRST_D3; +} + + +/* + * Parse the given BIOS configuration and set up the hda_gen_spec + * + * return 1 if successful, 0 if the proper config is not found, + * or a negative error code + */ +int snd_hda_gen_parse_auto_config(struct hda_codec *codec, + struct auto_pin_cfg *cfg) +{ + struct hda_gen_spec *spec = codec->spec; + int err; + + parse_user_hints(codec); + + if (spec->mixer_nid && !spec->mixer_merge_nid) + spec->mixer_merge_nid = spec->mixer_nid; + + if (cfg != &spec->autocfg) { + spec->autocfg = *cfg; + cfg = &spec->autocfg; + } + + fill_all_dac_nids(codec); + + if (!cfg->line_outs) { + if (cfg->dig_outs || cfg->dig_in_pin) { + spec->multiout.max_channels = 2; + spec->no_analog = 1; + goto dig_only; + } + return 0; /* can't find valid BIOS pin config */ + } + + if (!spec->no_primary_hp && + cfg->line_out_type == AUTO_PIN_SPEAKER_OUT && + cfg->line_outs <= cfg->hp_outs) { + /* use HP as primary out */ + cfg->speaker_outs = cfg->line_outs; + memcpy(cfg->speaker_pins, cfg->line_out_pins, + sizeof(cfg->speaker_pins)); + cfg->line_outs = cfg->hp_outs; + memcpy(cfg->line_out_pins, cfg->hp_pins, sizeof(cfg->hp_pins)); + cfg->hp_outs = 0; + memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins)); + cfg->line_out_type = AUTO_PIN_HP_OUT; + } + + err = parse_output_paths(codec); + if (err < 0) + return err; + err = create_multi_channel_mode(codec); + if (err < 0) + return err; + err = create_multi_out_ctls(codec, cfg); + if (err < 0) + return err; + err = create_hp_out_ctls(codec); + if (err < 0) + return err; + err = create_speaker_out_ctls(codec); + if (err < 0) + return err; + err = create_indep_hp_ctls(codec); + if (err < 0) + return err; + err = create_loopback_mixing_ctl(codec); + if (err < 0) + return err; + err = create_shared_input(codec); + if (err < 0) + return err; + err = create_input_ctls(codec); + if (err < 0) + return err; + + spec->const_channel_count = spec->ext_channel_count; + /* check the multiple speaker and headphone pins */ + if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) + spec->const_channel_count = max(spec->const_channel_count, + cfg->speaker_outs * 2); + if (cfg->line_out_type != AUTO_PIN_HP_OUT) + spec->const_channel_count = max(spec->const_channel_count, + cfg->hp_outs * 2); + spec->multiout.max_channels = max(spec->ext_channel_count, + spec->const_channel_count); + + err = check_auto_mute_availability(codec); + if (err < 0) + return err; + + err = check_dyn_adc_switch(codec); + if (err < 0) + return err; + + if (!spec->shared_mic_hp) { + err = check_auto_mic_availability(codec); + if (err < 0) + return err; + } + + err = create_capture_mixers(codec); + if (err < 0) + return err; + + err = parse_mic_boost(codec); + if (err < 0) + return err; + + if (spec->add_out_jack_modes) { + if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { + err = create_out_jack_modes(codec, cfg->line_outs, + cfg->line_out_pins); + if (err < 0) + return err; + } + if (cfg->line_out_type != AUTO_PIN_HP_OUT) { + err = create_out_jack_modes(codec, cfg->hp_outs, + cfg->hp_pins); if (err < 0) return err; - if (! err) - continue; } } - return 0; + + dig_only: + parse_digital(codec); + + if (spec->power_down_unused) + codec->power_filter = snd_hda_gen_path_power_filter; + + return 1; } +EXPORT_SYMBOL_HDA(snd_hda_gen_parse_auto_config); + /* - * build mixer controls + * Build control elements */ -static int build_generic_controls(struct hda_codec *codec) + +/* slave controls for virtual master */ +static const char * const slave_pfxs[] = { + "Front", "Surround", "Center", "LFE", "Side", + "Headphone", "Speaker", "Mono", "Line Out", + "CLFE", "Bass Speaker", "PCM", + "Speaker Front", "Speaker Surround", "Speaker CLFE", "Speaker Side", + "Headphone Front", "Headphone Surround", "Headphone CLFE", + "Headphone Side", + NULL, +}; + +int snd_hda_gen_build_controls(struct hda_codec *codec) { + struct hda_gen_spec *spec = codec->spec; int err; - if ((err = build_input_controls(codec)) < 0 || - (err = build_output_controls(codec)) < 0 || - (err = build_loopback_controls(codec)) < 0) + if (spec->kctls.used) { + err = snd_hda_add_new_ctls(codec, spec->kctls.list); + if (err < 0) + return err; + } + + if (spec->multiout.dig_out_nid) { + err = snd_hda_create_dig_out_ctls(codec, + spec->multiout.dig_out_nid, + spec->multiout.dig_out_nid, + spec->pcm_rec[1].pcm_type); + if (err < 0) + return err; + if (!spec->no_analog) { + 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->no_analog && + !snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) { + err = snd_hda_add_vmaster(codec, "Master Playback Volume", + spec->vmaster_tlv, slave_pfxs, + "Playback Volume"); + if (err < 0) + return err; + } + if (!spec->no_analog && + !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) { + err = __snd_hda_add_vmaster(codec, "Master Playback Switch", + NULL, slave_pfxs, + "Playback Switch", + true, &spec->vmaster_mute.sw_kctl); + if (err < 0) + return err; + if (spec->vmaster_mute.hook) + snd_hda_add_vmaster_hook(codec, &spec->vmaster_mute, + spec->vmaster_mute_enum); + } + + free_kctls(spec); /* no longer needed */ + + if (spec->shared_mic_hp) { + int err; + int nid = spec->autocfg.inputs[1].pin; + err = snd_hda_jack_add_kctl(codec, nid, "Headphone Mic", 0); + if (err < 0) + return err; + err = snd_hda_jack_detect_enable(codec, nid, 0); + if (err < 0) + return err; + } + + err = snd_hda_jack_add_kctls(codec, &spec->autocfg); + if (err < 0) return err; return 0; } +EXPORT_SYMBOL_HDA(snd_hda_gen_build_controls); + /* - * PCM + * PCM definitions */ -static struct hda_pcm_stream generic_pcm_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, -}; -static int generic_pcm2_prepare(struct hda_pcm_stream *hinfo, +static void call_pcm_playback_hook(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream, + int action) +{ + struct hda_gen_spec *spec = codec->spec; + if (spec->pcm_playback_hook) + spec->pcm_playback_hook(hinfo, codec, substream, action); +} + +static void call_pcm_capture_hook(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream, + int action) +{ + struct hda_gen_spec *spec = codec->spec; + if (spec->pcm_capture_hook) + spec->pcm_capture_hook(hinfo, codec, substream, action); +} + +/* + * Analog playback callbacks + */ +static int playback_pcm_open(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct hda_gen_spec *spec = codec->spec; + int err; + + mutex_lock(&spec->pcm_mutex); + err = snd_hda_multi_out_analog_open(codec, + &spec->multiout, substream, + hinfo); + if (!err) { + spec->active_streams |= 1 << STREAM_MULTI_OUT; + call_pcm_playback_hook(hinfo, codec, substream, + HDA_GEN_PCM_ACT_OPEN); + } + mutex_unlock(&spec->pcm_mutex); + return err; +} + +static int 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 hda_gspec *spec = codec->spec; + struct hda_gen_spec *spec = codec->spec; + int err; - snd_hda_codec_setup_stream(codec, hinfo->nid, stream_tag, 0, format); - snd_hda_codec_setup_stream(codec, spec->dac_node[1]->nid, - stream_tag, 0, format); - return 0; + err = snd_hda_multi_out_analog_prepare(codec, &spec->multiout, + stream_tag, format, substream); + if (!err) + call_pcm_playback_hook(hinfo, codec, substream, + HDA_GEN_PCM_ACT_PREPARE); + return err; } -static int generic_pcm2_cleanup(struct hda_pcm_stream *hinfo, +static int playback_pcm_cleanup(struct hda_pcm_stream *hinfo, struct hda_codec *codec, struct snd_pcm_substream *substream) { - struct hda_gspec *spec = codec->spec; + struct hda_gen_spec *spec = codec->spec; + int err; + + err = snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); + if (!err) + call_pcm_playback_hook(hinfo, codec, substream, + HDA_GEN_PCM_ACT_CLEANUP); + return err; +} + +static int playback_pcm_close(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct hda_gen_spec *spec = codec->spec; + mutex_lock(&spec->pcm_mutex); + spec->active_streams &= ~(1 << STREAM_MULTI_OUT); + call_pcm_playback_hook(hinfo, codec, substream, + HDA_GEN_PCM_ACT_CLOSE); + mutex_unlock(&spec->pcm_mutex); + return 0; +} + +static int capture_pcm_open(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + call_pcm_capture_hook(hinfo, codec, substream, HDA_GEN_PCM_ACT_OPEN); + return 0; +} + +static int capture_pcm_prepare(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + unsigned int stream_tag, + unsigned int format, + struct snd_pcm_substream *substream) +{ + snd_hda_codec_setup_stream(codec, hinfo->nid, stream_tag, 0, format); + call_pcm_capture_hook(hinfo, codec, substream, + HDA_GEN_PCM_ACT_PREPARE); + return 0; +} +static int capture_pcm_cleanup(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ snd_hda_codec_cleanup_stream(codec, hinfo->nid); - snd_hda_codec_cleanup_stream(codec, spec->dac_node[1]->nid); + call_pcm_capture_hook(hinfo, codec, substream, + HDA_GEN_PCM_ACT_CLEANUP); + return 0; +} + +static int capture_pcm_close(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + call_pcm_capture_hook(hinfo, codec, substream, HDA_GEN_PCM_ACT_CLOSE); return 0; } -static int build_generic_pcms(struct hda_codec *codec) +static int alt_playback_pcm_open(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) { - struct hda_gspec *spec = codec->spec; - struct hda_pcm *info = &spec->pcm_rec; + struct hda_gen_spec *spec = codec->spec; + int err = 0; - if (! spec->dac_node[0] && ! spec->adc_node) { - snd_printd("hda_generic: no PCM found\n"); - return 0; + mutex_lock(&spec->pcm_mutex); + if (!spec->indep_hp_enabled) + err = -EBUSY; + else + spec->active_streams |= 1 << STREAM_INDEP_HP; + call_pcm_playback_hook(hinfo, codec, substream, + HDA_GEN_PCM_ACT_OPEN); + mutex_unlock(&spec->pcm_mutex); + return err; +} + +static int alt_playback_pcm_close(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct hda_gen_spec *spec = codec->spec; + mutex_lock(&spec->pcm_mutex); + spec->active_streams &= ~(1 << STREAM_INDEP_HP); + call_pcm_playback_hook(hinfo, codec, substream, + HDA_GEN_PCM_ACT_CLOSE); + mutex_unlock(&spec->pcm_mutex); + return 0; +} + +static int alt_playback_pcm_prepare(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + unsigned int stream_tag, + unsigned int format, + struct snd_pcm_substream *substream) +{ + snd_hda_codec_setup_stream(codec, hinfo->nid, stream_tag, 0, format); + call_pcm_playback_hook(hinfo, codec, substream, + HDA_GEN_PCM_ACT_PREPARE); + return 0; +} + +static int alt_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + snd_hda_codec_cleanup_stream(codec, hinfo->nid); + call_pcm_playback_hook(hinfo, codec, substream, + HDA_GEN_PCM_ACT_CLEANUP); + return 0; +} + +/* + * Digital out + */ +static int dig_playback_pcm_open(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct hda_gen_spec *spec = codec->spec; + return snd_hda_multi_out_dig_open(codec, &spec->multiout); +} + +static int 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 hda_gen_spec *spec = codec->spec; + return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, + stream_tag, format, substream); +} + +static int dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct hda_gen_spec *spec = codec->spec; + return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout); +} + +static int dig_playback_pcm_close(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct hda_gen_spec *spec = codec->spec; + return snd_hda_multi_out_dig_close(codec, &spec->multiout); +} + +/* + * Analog capture + */ +#define alt_capture_pcm_open capture_pcm_open +#define alt_capture_pcm_close capture_pcm_close + +static int alt_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 hda_gen_spec *spec = codec->spec; + + snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1], + stream_tag, 0, format); + call_pcm_capture_hook(hinfo, codec, substream, + HDA_GEN_PCM_ACT_PREPARE); + return 0; +} + +static int alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct hda_gen_spec *spec = codec->spec; + + snd_hda_codec_cleanup_stream(codec, + spec->adc_nids[substream->number + 1]); + call_pcm_capture_hook(hinfo, codec, substream, + HDA_GEN_PCM_ACT_CLEANUP); + return 0; +} + +/* + */ +static const struct hda_pcm_stream pcm_analog_playback = { + .substreams = 1, + .channels_min = 2, + .channels_max = 8, + /* NID is set in build_pcms */ + .ops = { + .open = playback_pcm_open, + .close = playback_pcm_close, + .prepare = playback_pcm_prepare, + .cleanup = playback_pcm_cleanup + }, +}; + +static const struct hda_pcm_stream pcm_analog_capture = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, + /* NID is set in build_pcms */ + .ops = { + .open = capture_pcm_open, + .close = capture_pcm_close, + .prepare = capture_pcm_prepare, + .cleanup = capture_pcm_cleanup + }, +}; + +static const struct hda_pcm_stream pcm_analog_alt_playback = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, + /* NID is set in build_pcms */ + .ops = { + .open = alt_playback_pcm_open, + .close = alt_playback_pcm_close, + .prepare = alt_playback_pcm_prepare, + .cleanup = alt_playback_pcm_cleanup + }, +}; + +static const struct hda_pcm_stream pcm_analog_alt_capture = { + .substreams = 2, /* can be overridden */ + .channels_min = 2, + .channels_max = 2, + /* NID is set in build_pcms */ + .ops = { + .open = alt_capture_pcm_open, + .close = alt_capture_pcm_close, + .prepare = alt_capture_pcm_prepare, + .cleanup = alt_capture_pcm_cleanup + }, +}; + +static const struct hda_pcm_stream pcm_digital_playback = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, + /* NID is set in build_pcms */ + .ops = { + .open = dig_playback_pcm_open, + .close = dig_playback_pcm_close, + .prepare = dig_playback_pcm_prepare, + .cleanup = dig_playback_pcm_cleanup + }, +}; + +static const struct hda_pcm_stream pcm_digital_capture = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, + /* NID is set in build_pcms */ +}; + +/* Used by build_pcms to flag that a PCM has no playback stream */ +static const struct hda_pcm_stream pcm_null_stream = { + .substreams = 0, + .channels_min = 0, + .channels_max = 0, +}; + +/* + * dynamic changing ADC PCM streams + */ +static bool dyn_adc_pcm_resetup(struct hda_codec *codec, int cur) +{ + struct hda_gen_spec *spec = codec->spec; + hda_nid_t new_adc = spec->adc_nids[spec->dyn_adc_idx[cur]]; + + 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); + return true; } + return false; +} + +/* analog capture with dynamic dual-adc changes */ +static int dyn_adc_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 hda_gen_spec *spec = codec->spec; + spec->cur_adc = spec->adc_nids[spec->dyn_adc_idx[spec->cur_mux[0]]]; + 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 dyn_adc_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct hda_gen_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 dyn_adc_pcm_analog_capture = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, + .nid = 0, /* fill later */ + .ops = { + .prepare = dyn_adc_capture_pcm_prepare, + .cleanup = dyn_adc_capture_pcm_cleanup + }, +}; + +static void fill_pcm_stream_name(char *str, size_t len, const char *sfx, + const char *chip_name) +{ + char *p; + + if (*str) + return; + strlcpy(str, chip_name, len); + + /* drop non-alnum chars after a space */ + for (p = strchr(str, ' '); p; p = strchr(p + 1, ' ')) { + if (!isalnum(p[1])) { + *p = 0; + break; + } + } + strlcat(str, sfx, len); +} + +/* build PCM streams based on the parsed results */ +int snd_hda_gen_build_pcms(struct hda_codec *codec) +{ + struct hda_gen_spec *spec = codec->spec; + struct hda_pcm *info = spec->pcm_rec; + const struct hda_pcm_stream *p; + bool have_multi_adcs; codec->num_pcms = 1; codec->pcm_info = info; - info->name = "HDA Generic"; - if (spec->dac_node[0]) { - info->stream[0] = generic_pcm_playback; - info->stream[0].nid = spec->dac_node[0]->nid; - if (spec->dac_node[1]) { - info->stream[0].ops.prepare = generic_pcm2_prepare; - info->stream[0].ops.cleanup = generic_pcm2_cleanup; + if (spec->no_analog) + goto skip_analog; + + fill_pcm_stream_name(spec->stream_name_analog, + sizeof(spec->stream_name_analog), + " Analog", codec->chip_name); + info->name = spec->stream_name_analog; + + if (spec->multiout.num_dacs > 0) { + p = spec->stream_analog_playback; + if (!p) + p = &pcm_analog_playback; + info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p; + info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0]; + info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = + spec->multiout.max_channels; + if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT && + spec->autocfg.line_outs == 2) + info->stream[SNDRV_PCM_STREAM_PLAYBACK].chmap = + snd_pcm_2_1_chmaps; + } + if (spec->num_adc_nids) { + p = spec->stream_analog_capture; + if (!p) { + if (spec->dyn_adc_switch) + p = &dyn_adc_pcm_analog_capture; + else + p = &pcm_analog_capture; + } + info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p; + info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; + } + + skip_analog: + /* SPDIF for stream index #1 */ + if (spec->multiout.dig_out_nid || spec->dig_in_nid) { + fill_pcm_stream_name(spec->stream_name_digital, + sizeof(spec->stream_name_digital), + " Digital", codec->chip_name); + codec->num_pcms = 2; + codec->slave_dig_outs = spec->multiout.slave_dig_outs; + info = spec->pcm_rec + 1; + info->name = spec->stream_name_digital; + if (spec->dig_out_type) + info->pcm_type = spec->dig_out_type; + else + info->pcm_type = HDA_PCM_TYPE_SPDIF; + if (spec->multiout.dig_out_nid) { + p = spec->stream_digital_playback; + if (!p) + p = &pcm_digital_playback; + info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p; + info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid; + } + if (spec->dig_in_nid) { + p = spec->stream_digital_capture; + if (!p) + p = &pcm_digital_capture; + info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p; + info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid; + } + } + + if (spec->no_analog) + return 0; + + /* If the use of more than one ADC is requested for the current + * model, configure a second analog capture-only PCM. + */ + have_multi_adcs = (spec->num_adc_nids > 1) && + !spec->dyn_adc_switch && !spec->auto_mic; + /* Additional Analaog capture for index #2 */ + if (spec->alt_dac_nid || have_multi_adcs) { + fill_pcm_stream_name(spec->stream_name_alt_analog, + sizeof(spec->stream_name_alt_analog), + " Alt Analog", codec->chip_name); + codec->num_pcms = 3; + info = spec->pcm_rec + 2; + info->name = spec->stream_name_alt_analog; + if (spec->alt_dac_nid) { + p = spec->stream_analog_alt_playback; + if (!p) + p = &pcm_analog_alt_playback; + info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p; + info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = + spec->alt_dac_nid; + } else { + info->stream[SNDRV_PCM_STREAM_PLAYBACK] = + pcm_null_stream; + info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0; + } + if (have_multi_adcs) { + p = spec->stream_analog_alt_capture; + if (!p) + p = &pcm_analog_alt_capture; + info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p; + info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = + spec->adc_nids[1]; + info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = + spec->num_adc_nids - 1; + } else { + info->stream[SNDRV_PCM_STREAM_CAPTURE] = + pcm_null_stream; + info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = 0; + } + } + + return 0; +} +EXPORT_SYMBOL_HDA(snd_hda_gen_build_pcms); + + +/* + * Standard auto-parser initializations + */ + +/* configure the given path as a proper output */ +static void set_output_and_unmute(struct hda_codec *codec, int path_idx) +{ + struct nid_path *path; + hda_nid_t pin; + + path = snd_hda_get_path_from_idx(codec, path_idx); + if (!path || !path->depth) + return; + pin = path->path[path->depth - 1]; + restore_pin_ctl(codec, pin); + snd_hda_activate_path(codec, path, path->active, true); + set_pin_eapd(codec, pin, path->active); +} + +/* initialize primary output paths */ +static void init_multi_out(struct hda_codec *codec) +{ + struct hda_gen_spec *spec = codec->spec; + int i; + + for (i = 0; i < spec->autocfg.line_outs; i++) + set_output_and_unmute(codec, spec->out_paths[i]); +} + + +static void __init_extra_out(struct hda_codec *codec, int num_outs, int *paths) +{ + int i; + + for (i = 0; i < num_outs; i++) + set_output_and_unmute(codec, paths[i]); +} + +/* initialize hp and speaker paths */ +static void init_extra_out(struct hda_codec *codec) +{ + struct hda_gen_spec *spec = codec->spec; + + if (spec->autocfg.line_out_type != AUTO_PIN_HP_OUT) + __init_extra_out(codec, spec->autocfg.hp_outs, spec->hp_paths); + if (spec->autocfg.line_out_type != AUTO_PIN_SPEAKER_OUT) + __init_extra_out(codec, spec->autocfg.speaker_outs, + spec->speaker_paths); +} + +/* initialize multi-io paths */ +static void init_multi_io(struct hda_codec *codec) +{ + struct hda_gen_spec *spec = codec->spec; + int i; + + for (i = 0; i < spec->multi_ios; i++) { + hda_nid_t pin = spec->multi_io[i].pin; + struct nid_path *path; + path = get_multiio_path(codec, i); + if (!path) + continue; + if (!spec->multi_io[i].ctl_in) + spec->multi_io[i].ctl_in = + snd_hda_codec_get_pin_target(codec, pin); + snd_hda_activate_path(codec, path, path->active, true); + } +} + +/* set up input pins and loopback paths */ +static void init_analog_input(struct hda_codec *codec) +{ + struct hda_gen_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + int i; + + for (i = 0; i < cfg->num_inputs; i++) { + hda_nid_t nid = cfg->inputs[i].pin; + if (is_input_pin(codec, nid)) + restore_pin_ctl(codec, nid); + + /* init loopback inputs */ + if (spec->mixer_nid) { + resume_path_from_idx(codec, spec->loopback_paths[i]); + resume_path_from_idx(codec, spec->loopback_merge_path); + } + } +} + +/* initialize ADC paths */ +static void init_input_src(struct hda_codec *codec) +{ + struct hda_gen_spec *spec = codec->spec; + struct hda_input_mux *imux = &spec->input_mux; + struct nid_path *path; + int i, c, nums; + + if (spec->dyn_adc_switch) + nums = 1; + else + nums = spec->num_adc_nids; + + for (c = 0; c < nums; c++) { + for (i = 0; i < imux->num_items; i++) { + path = get_input_path(codec, c, i); + if (path) { + bool active = path->active; + if (i == spec->cur_mux[c]) + active = true; + snd_hda_activate_path(codec, path, active, false); + } } } - if (spec->adc_node) { - info->stream[1] = generic_pcm_playback; - info->stream[1].nid = spec->adc_node->nid; + + if (spec->shared_mic_hp) + update_shared_mic_hp(codec, spec->cur_mux[0]); + + if (spec->cap_sync_hook) + spec->cap_sync_hook(codec, NULL); +} + +/* set right pin controls for digital I/O */ +static void init_digital(struct hda_codec *codec) +{ + struct hda_gen_spec *spec = codec->spec; + int i; + hda_nid_t pin; + + for (i = 0; i < spec->autocfg.dig_outs; i++) + set_output_and_unmute(codec, spec->digout_paths[i]); + pin = spec->autocfg.dig_in_pin; + if (pin) { + restore_pin_ctl(codec, pin); + resume_path_from_idx(codec, spec->digin_path); + } +} + +/* clear unsol-event tags on unused pins; Conexant codecs seem to leave + * invalid unsol tags by some reason + */ +static void clear_unsol_on_unused_pins(struct hda_codec *codec) +{ + int i; + + for (i = 0; i < codec->init_pins.used; i++) { + struct hda_pincfg *pin = snd_array_elem(&codec->init_pins, i); + hda_nid_t nid = pin->nid; + if (is_jack_detectable(codec, nid) && + !snd_hda_jack_tbl_get(codec, nid)) + snd_hda_codec_update_cache(codec, nid, 0, + AC_VERB_SET_UNSOLICITED_ENABLE, 0); } +} + +/* + * initialize the generic spec; + * this can be put as patch_ops.init function + */ +int snd_hda_gen_init(struct hda_codec *codec) +{ + struct hda_gen_spec *spec = codec->spec; + + if (spec->init_hook) + spec->init_hook(codec); + + snd_hda_apply_verbs(codec); + + codec->cached_write = 1; + + init_multi_out(codec); + init_extra_out(codec); + init_multi_io(codec); + init_analog_input(codec); + init_input_src(codec); + init_digital(codec); + clear_unsol_on_unused_pins(codec); + + /* call init functions of standard auto-mute helpers */ + update_automute_all(codec); + + snd_hda_codec_flush_cache(codec); + + if (spec->vmaster_mute.sw_kctl && spec->vmaster_mute.hook) + snd_hda_sync_vmaster_hook(&spec->vmaster_mute); + + hda_call_check_power_status(codec, 0x01); return 0; } +EXPORT_SYMBOL_HDA(snd_hda_gen_init); + +/* + * free the generic spec; + * this can be put as patch_ops.free function + */ +void snd_hda_gen_free(struct hda_codec *codec) +{ + snd_hda_gen_spec_free(codec->spec); + kfree(codec->spec); + codec->spec = NULL; +} +EXPORT_SYMBOL_HDA(snd_hda_gen_free); #ifdef CONFIG_PM -static int generic_check_power_status(struct hda_codec *codec, hda_nid_t nid) +/* + * check the loopback power save state; + * this can be put as patch_ops.check_power_status function + */ +int snd_hda_gen_check_power_status(struct hda_codec *codec, hda_nid_t nid) { - struct hda_gspec *spec = codec->spec; + struct hda_gen_spec *spec = codec->spec; return snd_hda_check_amp_list_power(codec, &spec->loopback, nid); } +EXPORT_SYMBOL_HDA(snd_hda_gen_check_power_status); #endif /* + * the generic codec support */ -static struct hda_codec_ops generic_patch_ops = { - .build_controls = build_generic_controls, - .build_pcms = build_generic_pcms, - .free = snd_hda_generic_free, + +static const struct hda_codec_ops generic_patch_ops = { + .build_controls = snd_hda_gen_build_controls, + .build_pcms = snd_hda_gen_build_pcms, + .init = snd_hda_gen_init, + .free = snd_hda_gen_free, + .unsol_event = snd_hda_jack_unsol_event, #ifdef CONFIG_PM - .check_power_status = generic_check_power_status, + .check_power_status = snd_hda_gen_check_power_status, #endif }; -/* - * the generic parser - */ int snd_hda_parse_generic_codec(struct hda_codec *codec) { - struct hda_gspec *spec; + struct hda_gen_spec *spec; int err; - if(!codec->afg) - return 0; - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) { - printk(KERN_ERR "hda_generic: can't allocate spec\n"); + if (!spec) return -ENOMEM; - } + snd_hda_gen_spec_init(spec); codec->spec = spec; - INIT_LIST_HEAD(&spec->nid_list); - if ((err = build_afg_tree(codec)) < 0) - goto error; + err = snd_hda_parse_pin_defcfg(codec, &spec->autocfg, NULL, 0); + if (err < 0) + return err; - if ((err = parse_input(codec)) < 0 || - (err = parse_output(codec)) < 0) + err = snd_hda_gen_parse_auto_config(codec, &spec->autocfg); + if (err < 0) goto error; codec->patch_ops = generic_patch_ops; - return 0; - error: - snd_hda_generic_free(codec); +error: + snd_hda_gen_free(codec); return err; } -EXPORT_SYMBOL(snd_hda_parse_generic_codec); +EXPORT_SYMBOL_HDA(snd_hda_parse_generic_codec); diff --git a/sound/pci/hda/hda_generic.h b/sound/pci/hda/hda_generic.h new file mode 100644 index 000000000000..009b57be96d3 --- /dev/null +++ b/sound/pci/hda/hda_generic.h @@ -0,0 +1,303 @@ +/* + * Generic BIOS auto-parser helper functions for HD-audio + * + * Copyright (c) 2012 Takashi Iwai <tiwai@suse.de> + * + * This driver 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; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef __SOUND_HDA_GENERIC_H +#define __SOUND_HDA_GENERIC_H + +/* unsol event tags */ +enum { + HDA_GEN_HP_EVENT = 1, HDA_GEN_FRONT_EVENT, HDA_GEN_MIC_EVENT, + HDA_GEN_LAST_EVENT = HDA_GEN_MIC_EVENT +}; + +/* table entry for multi-io paths */ +struct hda_multi_io { + hda_nid_t pin; /* multi-io widget pin NID */ + hda_nid_t dac; /* DAC to be connected */ + unsigned int ctl_in; /* cached input-pin control value */ +}; + +/* Widget connection path + * + * For output, stored in the order of DAC -> ... -> pin, + * for input, pin -> ... -> ADC. + * + * idx[i] contains the source index number to select on of the widget path[i]; + * e.g. idx[1] is the index of the DAC (path[0]) selected by path[1] widget + * multi[] indicates whether it's a selector widget with multi-connectors + * (i.e. the connection selection is mandatory) + * vol_ctl and mute_ctl contains the NIDs for the assigned mixers + */ + +#define MAX_NID_PATH_DEPTH 10 + +enum { + NID_PATH_VOL_CTL, + NID_PATH_MUTE_CTL, + NID_PATH_BOOST_CTL, + NID_PATH_NUM_CTLS +}; + +struct nid_path { + int depth; + hda_nid_t path[MAX_NID_PATH_DEPTH]; + unsigned char idx[MAX_NID_PATH_DEPTH]; + unsigned char multi[MAX_NID_PATH_DEPTH]; + unsigned int ctls[NID_PATH_NUM_CTLS]; /* NID_PATH_XXX_CTL */ + bool active; +}; + +/* mic/line-in auto switching entry */ + +#define MAX_AUTO_MIC_PINS 3 + +struct automic_entry { + hda_nid_t pin; /* pin */ + int idx; /* imux index, -1 = invalid */ + unsigned int attr; /* pin attribute (INPUT_PIN_ATTR_*) */ +}; + +/* active stream id */ +enum { STREAM_MULTI_OUT, STREAM_INDEP_HP }; + +/* PCM hook action */ +enum { + HDA_GEN_PCM_ACT_OPEN, + HDA_GEN_PCM_ACT_PREPARE, + HDA_GEN_PCM_ACT_CLEANUP, + HDA_GEN_PCM_ACT_CLOSE, +}; + +struct hda_gen_spec { + char stream_name_analog[32]; /* analog PCM stream */ + const struct hda_pcm_stream *stream_analog_playback; + const struct hda_pcm_stream *stream_analog_capture; + + char stream_name_alt_analog[32]; /* alternative analog PCM stream */ + const struct hda_pcm_stream *stream_analog_alt_playback; + const struct hda_pcm_stream *stream_analog_alt_capture; + + char stream_name_digital[32]; /* digital PCM stream */ + const struct hda_pcm_stream *stream_digital_playback; + const struct hda_pcm_stream *stream_digital_capture; + + /* PCM */ + unsigned int active_streams; + struct mutex pcm_mutex; + + /* playback */ + struct hda_multi_out multiout; /* playback set-up + * max_channels, dacs must be set + * dig_out_nid and hp_nid are optional + */ + hda_nid_t alt_dac_nid; + hda_nid_t slave_dig_outs[3]; /* optional - for auto-parsing */ + int dig_out_type; + + /* capture */ + unsigned int num_adc_nids; + hda_nid_t adc_nids[AUTO_CFG_MAX_INS]; + hda_nid_t dig_in_nid; /* digital-in NID; optional */ + hda_nid_t mixer_nid; /* analog-mixer NID */ + hda_nid_t mixer_merge_nid; /* aamix merge-point NID (optional) */ + const char *input_labels[HDA_MAX_NUM_INPUTS]; + int input_label_idxs[HDA_MAX_NUM_INPUTS]; + + /* capture setup for dynamic dual-adc switch */ + hda_nid_t cur_adc; + unsigned int cur_adc_stream_tag; + unsigned int cur_adc_format; + + /* capture source */ + struct hda_input_mux input_mux; + unsigned int cur_mux[3]; + + /* channel model */ + /* min_channel_count contains the minimum channel count for primary + * outputs. When multi_ios is set, the channels can be configured + * between min_channel_count and (min_channel_count + multi_ios * 2). + * + * ext_channel_count contains the current channel count of the primary + * out. This varies in the range above. + * + * Meanwhile, const_channel_count is the channel count for all outputs + * including headphone and speakers. It's a constant value, and the + * PCM is set up as max(ext_channel_count, const_channel_count). + */ + int min_channel_count; /* min. channel count for primary out */ + int ext_channel_count; /* current channel count for primary */ + int const_channel_count; /* channel count for all */ + + /* PCM information */ + struct hda_pcm pcm_rec[3]; /* used in build_pcms() */ + + /* dynamic controls, init_verbs and input_mux */ + struct auto_pin_cfg autocfg; + struct snd_array kctls; + hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS]; + hda_nid_t imux_pins[HDA_MAX_NUM_INPUTS]; + unsigned int dyn_adc_idx[HDA_MAX_NUM_INPUTS]; + hda_nid_t shared_mic_vref_pin; + + /* DAC/ADC lists */ + int num_all_dacs; + hda_nid_t all_dacs[16]; + int num_all_adcs; + hda_nid_t all_adcs[AUTO_CFG_MAX_INS]; + + /* path list */ + struct snd_array paths; + + /* path indices */ + int out_paths[AUTO_CFG_MAX_OUTS]; + int hp_paths[AUTO_CFG_MAX_OUTS]; + int speaker_paths[AUTO_CFG_MAX_OUTS]; + int aamix_out_paths[3]; + int digout_paths[AUTO_CFG_MAX_OUTS]; + int input_paths[HDA_MAX_NUM_INPUTS][AUTO_CFG_MAX_INS]; + int loopback_paths[HDA_MAX_NUM_INPUTS]; + int loopback_merge_path; + int digin_path; + + /* auto-mic stuff */ + int am_num_entries; + struct automic_entry am_entry[MAX_AUTO_MIC_PINS]; + + /* for pin sensing */ + /* current status; set in hda_geneic.c */ + unsigned int hp_jack_present:1; + unsigned int line_jack_present:1; + unsigned int speaker_muted:1; /* current status of speaker mute */ + unsigned int line_out_muted:1; /* current status of LO mute */ + + /* internal states of automute / autoswitch behavior */ + unsigned int auto_mic:1; + unsigned int automute_speaker:1; /* automute speaker outputs */ + unsigned int automute_lo:1; /* automute LO outputs */ + + /* capabilities detected by parser */ + unsigned int detect_hp:1; /* Headphone detection enabled */ + unsigned int detect_lo:1; /* Line-out detection enabled */ + unsigned int automute_speaker_possible:1; /* there are speakers and either LO or HP */ + unsigned int automute_lo_possible:1; /* there are line outs and HP */ + + /* additional parameters set by codec drivers */ + unsigned int master_mute:1; /* master mute over all */ + unsigned int keep_vref_in_automute:1; /* Don't clear VREF in automute */ + unsigned int line_in_auto_switch:1; /* allow line-in auto switch */ + + /* parser behavior flags; set before snd_hda_gen_parse_auto_config() */ + unsigned int suppress_auto_mute:1; /* suppress input jack auto mute */ + unsigned int suppress_auto_mic:1; /* suppress input jack auto switch */ + + /* other parse behavior flags */ + unsigned int need_dac_fix:1; /* need to limit DACs for multi channels */ + unsigned int shared_mic_hp:1; /* HP/Mic-in sharing */ + unsigned int no_primary_hp:1; /* Don't prefer HP pins to speaker pins */ + unsigned int multi_cap_vol:1; /* allow multiple capture xxx volumes */ + unsigned int inv_dmic_split:1; /* inverted dmic w/a for conexant */ + unsigned int own_eapd_ctl:1; /* set EAPD by own function */ + unsigned int vmaster_mute_enum:1; /* add vmaster mute mode enum */ + unsigned int indep_hp:1; /* independent HP supported */ + unsigned int prefer_hp_amp:1; /* enable HP amp for speaker if any */ + unsigned int add_stereo_mix_input:1; /* add aamix as a capture src */ + unsigned int add_out_jack_modes:1; /* add output jack mode enum ctls */ + unsigned int add_in_jack_modes:1; /* add input jack mode enum ctls */ + unsigned int power_down_unused:1; /* power down unused widgets */ + + /* other internal flags */ + unsigned int no_analog:1; /* digital I/O only */ + unsigned int dyn_adc_switch:1; /* switch ADCs (for ALC275) */ + unsigned int indep_hp_enabled:1; /* independent HP enabled */ + unsigned int have_aamix_ctl:1; + + /* loopback mixing mode */ + bool aamix_mode; + + /* for virtual master */ + hda_nid_t vmaster_nid; + unsigned int vmaster_tlv[4]; + struct hda_vmaster_mute_hook vmaster_mute; + + struct hda_loopback_check loopback; + struct snd_array loopback_list; + + /* multi-io */ + int multi_ios; + struct hda_multi_io multi_io[4]; + + /* hooks */ + void (*init_hook)(struct hda_codec *codec); + void (*automute_hook)(struct hda_codec *codec); + void (*cap_sync_hook)(struct hda_codec *codec, + struct snd_ctl_elem_value *ucontrol); + + /* PCM hooks */ + void (*pcm_playback_hook)(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream, + int action); + void (*pcm_capture_hook)(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream, + int action); + + /* automute / autoswitch hooks */ + void (*hp_automute_hook)(struct hda_codec *codec, + struct hda_jack_tbl *tbl); + void (*line_automute_hook)(struct hda_codec *codec, + struct hda_jack_tbl *tbl); + void (*mic_autoswitch_hook)(struct hda_codec *codec, + struct hda_jack_tbl *tbl); +}; + +int snd_hda_gen_spec_init(struct hda_gen_spec *spec); +void snd_hda_gen_spec_free(struct hda_gen_spec *spec); + +int snd_hda_gen_init(struct hda_codec *codec); +void snd_hda_gen_free(struct hda_codec *codec); + +struct nid_path *snd_hda_get_nid_path(struct hda_codec *codec, + hda_nid_t from_nid, hda_nid_t to_nid); +int snd_hda_get_path_idx(struct hda_codec *codec, struct nid_path *path); +struct nid_path *snd_hda_get_path_from_idx(struct hda_codec *codec, int idx); +bool snd_hda_parse_nid_path(struct hda_codec *codec, hda_nid_t from_nid, + hda_nid_t to_nid, int anchor_nid, + struct nid_path *path); +struct nid_path * +snd_hda_add_new_path(struct hda_codec *codec, hda_nid_t from_nid, + hda_nid_t to_nid, int anchor_nid); +void snd_hda_activate_path(struct hda_codec *codec, struct nid_path *path, + bool enable, bool add_aamix); + +struct snd_kcontrol_new * +snd_hda_gen_add_kctl(struct hda_gen_spec *spec, const char *name, + const struct snd_kcontrol_new *temp); + +int snd_hda_gen_parse_auto_config(struct hda_codec *codec, + struct auto_pin_cfg *cfg); +int snd_hda_gen_build_controls(struct hda_codec *codec); +int snd_hda_gen_build_pcms(struct hda_codec *codec); + +/* standard jack event callbacks */ +void snd_hda_gen_hp_automute(struct hda_codec *codec, + struct hda_jack_tbl *jack); +void snd_hda_gen_line_automute(struct hda_codec *codec, + struct hda_jack_tbl *jack); +void snd_hda_gen_mic_autoswitch(struct hda_codec *codec, + struct hda_jack_tbl *jack); +void snd_hda_gen_update_outputs(struct hda_codec *codec); + +#ifdef CONFIG_PM +int snd_hda_gen_check_power_status(struct hda_codec *codec, hda_nid_t nid); +#endif + +#endif /* __SOUND_HDA_GENERIC_H */ diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c index 1af86d40eb23..ce67608734b5 100644 --- a/sound/pci/hda/hda_hwdep.c +++ b/sound/pci/hda/hda_hwdep.c @@ -125,7 +125,7 @@ static void hwdep_free(struct snd_hwdep *hwdep) clear_hwdep_elements(hwdep->private_data); } -int /*__devinit*/ snd_hda_create_hwdep(struct hda_codec *codec) +int snd_hda_create_hwdep(struct hda_codec *codec) { char hwname[16]; struct snd_hwdep *hwdep; @@ -148,6 +148,7 @@ int /*__devinit*/ snd_hda_create_hwdep(struct hda_codec *codec) hwdep->ops.ioctl_compat = hda_hwdep_ioctl_compat; #endif + mutex_init(&codec->user_mutex); snd_array_init(&codec->init_verbs, sizeof(struct hda_verb), 32); snd_array_init(&codec->hints, sizeof(struct hda_hint), 32); snd_array_init(&codec->user_pins, sizeof(struct hda_pincfg), 16); @@ -346,12 +347,14 @@ static ssize_t init_verbs_show(struct device *dev, struct snd_hwdep *hwdep = dev_get_drvdata(dev); struct hda_codec *codec = hwdep->private_data; int i, len = 0; + mutex_lock(&codec->user_mutex); for (i = 0; i < codec->init_verbs.used; i++) { struct hda_verb *v = snd_array_elem(&codec->init_verbs, i); len += snprintf(buf + len, PAGE_SIZE - len, "0x%02x 0x%03x 0x%04x\n", v->nid, v->verb, v->param); } + mutex_unlock(&codec->user_mutex); return len; } @@ -364,12 +367,16 @@ static int parse_init_verbs(struct hda_codec *codec, const char *buf) return -EINVAL; if (!nid || !verb) return -EINVAL; + mutex_lock(&codec->user_mutex); v = snd_array_new(&codec->init_verbs); - if (!v) + if (!v) { + mutex_unlock(&codec->user_mutex); return -ENOMEM; + } v->nid = nid; v->verb = verb; v->param = param; + mutex_unlock(&codec->user_mutex); return 0; } @@ -392,11 +399,13 @@ static ssize_t hints_show(struct device *dev, struct snd_hwdep *hwdep = dev_get_drvdata(dev); struct hda_codec *codec = hwdep->private_data; int i, len = 0; + mutex_lock(&codec->user_mutex); for (i = 0; i < codec->hints.used; i++) { struct hda_hint *hint = snd_array_elem(&codec->hints, i); len += snprintf(buf + len, PAGE_SIZE - len, "%s = %s\n", hint->key, hint->val); } + mutex_unlock(&codec->user_mutex); return len; } @@ -431,6 +440,7 @@ static int parse_hints(struct hda_codec *codec, const char *buf) { char *key, *val; struct hda_hint *hint; + int err = 0; buf = skip_spaces(buf); if (!*buf || *buf == '#' || *buf == '\n') @@ -450,26 +460,31 @@ static int parse_hints(struct hda_codec *codec, const char *buf) val = skip_spaces(val); remove_trail_spaces(key); remove_trail_spaces(val); + mutex_lock(&codec->user_mutex); hint = get_hint(codec, key); if (hint) { /* replace */ kfree(hint->key); hint->key = key; hint->val = val; - return 0; + goto unlock; } /* allocate a new hint entry */ if (codec->hints.used >= MAX_HINTS) hint = NULL; else hint = snd_array_new(&codec->hints); - if (!hint) { - kfree(key); - return -ENOMEM; + if (hint) { + hint->key = key; + hint->val = val; + } else { + err = -ENOMEM; } - hint->key = key; - hint->val = val; - return 0; + unlock: + mutex_unlock(&codec->user_mutex); + if (err) + kfree(key); + return err; } static ssize_t hints_store(struct device *dev, @@ -489,11 +504,13 @@ static ssize_t pin_configs_show(struct hda_codec *codec, char *buf) { int i, len = 0; + mutex_lock(&codec->user_mutex); for (i = 0; i < list->used; i++) { struct hda_pincfg *pin = snd_array_elem(list, i); len += sprintf(buf + len, "0x%02x 0x%08x\n", pin->nid, pin->cfg); } + mutex_unlock(&codec->user_mutex); return len; } @@ -528,13 +545,16 @@ static ssize_t driver_pin_configs_show(struct device *dev, static int parse_user_pin_configs(struct hda_codec *codec, const char *buf) { - int nid, cfg; + int nid, cfg, err; if (sscanf(buf, "%i %i", &nid, &cfg) != 2) return -EINVAL; if (!nid) return -EINVAL; - return snd_hda_add_pincfg(codec, &codec->user_pins, nid, cfg); + mutex_lock(&codec->user_mutex); + err = snd_hda_add_pincfg(codec, &codec->user_pins, nid, cfg); + mutex_unlock(&codec->user_mutex); + return err; } static ssize_t user_pin_configs_store(struct device *dev, @@ -600,19 +620,50 @@ EXPORT_SYMBOL_HDA(snd_hda_get_hint); int snd_hda_get_bool_hint(struct hda_codec *codec, const char *key) { - const char *p = snd_hda_get_hint(codec, key); + const char *p; + int ret; + + mutex_lock(&codec->user_mutex); + p = snd_hda_get_hint(codec, key); if (!p || !*p) - return -ENOENT; - switch (toupper(*p)) { - case 'T': /* true */ - case 'Y': /* yes */ - case '1': - return 1; + ret = -ENOENT; + else { + switch (toupper(*p)) { + case 'T': /* true */ + case 'Y': /* yes */ + case '1': + ret = 1; + break; + default: + ret = 0; + break; + } } - return 0; + mutex_unlock(&codec->user_mutex); + return ret; } EXPORT_SYMBOL_HDA(snd_hda_get_bool_hint); +int snd_hda_get_int_hint(struct hda_codec *codec, const char *key, int *valp) +{ + const char *p; + unsigned long val; + int ret; + + mutex_lock(&codec->user_mutex); + p = snd_hda_get_hint(codec, key); + if (!p) + ret = -ENOENT; + else if (strict_strtoul(p, 0, &val)) + ret = -EINVAL; + else { + *valp = val; + ret = 0; + } + mutex_unlock(&codec->user_mutex); + return ret; +} +EXPORT_SYMBOL_HDA(snd_hda_get_int_hint); #endif /* CONFIG_SND_HDA_RECONFIG */ #ifdef CONFIG_SND_HDA_PATCH_LOADER diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 99e61b985d29..4b099c603fe1 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -47,6 +47,10 @@ #include <linux/reboot.h> #include <linux/io.h> #include <linux/pm_runtime.h> +#include <linux/clocksource.h> +#include <linux/time.h> +#include <linux/completion.h> + #ifdef CONFIG_X86 /* for snoop control */ #include <asm/pgtable.h> @@ -68,6 +72,7 @@ static int position_fix[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1}; static int bdl_pos_adj[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1}; static int probe_mask[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1}; static int probe_only[SNDRV_CARDS]; +static int jackpoll_ms[SNDRV_CARDS]; static bool single_cmd; static int enable_msi = -1; #ifdef CONFIG_SND_HDA_PATCH_LOADER @@ -95,6 +100,8 @@ module_param_array(probe_mask, int, NULL, 0444); MODULE_PARM_DESC(probe_mask, "Bitmask to probe codecs (default = -1)."); module_param_array(probe_only, int, NULL, 0444); MODULE_PARM_DESC(probe_only, "Only probing and no codec initialization."); +module_param_array(jackpoll_ms, int, NULL, 0444); +MODULE_PARM_DESC(jackpoll_ms, "Ms between polling for jack events (default = 0, using unsol events only)"); module_param(single_cmd, bool, 0444); MODULE_PARM_DESC(single_cmd, "Use single command to communicate with codecs " "(for debugging only)."); @@ -127,8 +134,8 @@ MODULE_PARM_DESC(power_save, "Automatic power-saving timeout " * this may give more power-saving, but will take longer time to * wake up. */ -static bool power_save_controller = 1; -module_param(power_save_controller, bool, 0644); +static int power_save_controller = -1; +module_param(power_save_controller, bint, 0644); MODULE_PARM_DESC(power_save_controller, "Reset controller in power save mode."); #endif /* CONFIG_PM */ @@ -185,7 +192,7 @@ MODULE_DESCRIPTION("Intel HDA driver"); #ifdef CONFIG_SND_VERBOSE_PRINTK #define SFX /* nop */ #else -#define SFX "hda-intel: " +#define SFX "hda-intel " #endif #if defined(CONFIG_PM) && defined(CONFIG_VGA_SWITCHEROO) @@ -416,6 +423,9 @@ struct azx_dev { unsigned int insufficient :1; unsigned int wc_marked:1; unsigned int no_period_wakeup:1; + + struct timecounter azx_tc; + struct cyclecounter azx_cc; }; /* CORB/RIRB */ @@ -460,6 +470,7 @@ struct azx { /* locks */ spinlock_t reg_lock; struct mutex open_mutex; + struct completion probe_wait; /* streams (x num_streams) */ struct azx_dev *azx_dev; @@ -518,6 +529,9 @@ struct azx { struct list_head list; }; +#define CREATE_TRACE_POINTS +#include "hda_intel_trace.h" + /* driver types */ enum { AZX_DRIVER_ICH, @@ -556,6 +570,15 @@ enum { #define AZX_DCAPS_ALIGN_BUFSIZE (1 << 22) /* buffer size alignment */ #define AZX_DCAPS_4K_BDLE_BOUNDARY (1 << 23) /* BDLE in 4k boundary */ #define AZX_DCAPS_COUNT_LPIB_DELAY (1 << 25) /* Take LPIB as delay */ +#define AZX_DCAPS_PM_RUNTIME (1 << 26) /* runtime PM support */ + +/* quirks for Intel PCH */ +#define AZX_DCAPS_INTEL_PCH_NOPM \ + (AZX_DCAPS_SCH_SNOOP | AZX_DCAPS_BUFSIZE | \ + AZX_DCAPS_COUNT_LPIB_DELAY) + +#define AZX_DCAPS_INTEL_PCH \ + (AZX_DCAPS_INTEL_PCH_NOPM | AZX_DCAPS_PM_RUNTIME) /* quirks for ATI SB / AMD Hudson */ #define AZX_DCAPS_PRESET_ATI_SB \ @@ -583,15 +606,7 @@ enum { #define use_vga_switcheroo(chip) 0 #endif -#if defined(SUPPORT_VGA_SWITCHEROO) || defined(CONFIG_SND_HDA_PATCH_LOADER) -#define DELAYED_INIT_MARK -#define DELAYED_INITDATA_MARK -#else -#define DELAYED_INIT_MARK __devinit -#define DELAYED_INITDATA_MARK __devinitdata -#endif - -static char *driver_short_names[] DELAYED_INITDATA_MARK = { +static char *driver_short_names[] = { [AZX_DRIVER_ICH] = "HDA Intel", [AZX_DRIVER_PCH] = "HDA Intel PCH", [AZX_DRIVER_SCH] = "HDA Intel MID", @@ -641,29 +656,43 @@ static char *driver_short_names[] DELAYED_INITDATA_MARK = { #define get_azx_dev(substream) (substream->runtime->private_data) #ifdef CONFIG_X86 -static void __mark_pages_wc(struct azx *chip, void *addr, size_t size, bool on) +static void __mark_pages_wc(struct azx *chip, struct snd_dma_buffer *dmab, bool on) { + int pages; + if (azx_snoop(chip)) return; - if (addr && size) { - int pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; + if (!dmab || !dmab->area || !dmab->bytes) + return; + +#ifdef CONFIG_SND_DMA_SGBUF + if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_SG) { + struct snd_sg_buf *sgbuf = dmab->private_data; if (on) - set_memory_wc((unsigned long)addr, pages); + set_pages_array_wc(sgbuf->page_table, sgbuf->pages); else - set_memory_wb((unsigned long)addr, pages); + set_pages_array_wb(sgbuf->page_table, sgbuf->pages); + return; } +#endif + + pages = (dmab->bytes + PAGE_SIZE - 1) >> PAGE_SHIFT; + if (on) + set_memory_wc((unsigned long)dmab->area, pages); + else + set_memory_wb((unsigned long)dmab->area, pages); } static inline void mark_pages_wc(struct azx *chip, struct snd_dma_buffer *buf, bool on) { - __mark_pages_wc(chip, buf->area, buf->bytes, on); + __mark_pages_wc(chip, buf, on); } static inline void mark_runtime_wc(struct azx *chip, struct azx_dev *azx_dev, - struct snd_pcm_runtime *runtime, bool on) + struct snd_pcm_substream *substream, bool on) { if (azx_dev->wc_marked != on) { - __mark_pages_wc(chip, runtime->dma_area, runtime->dma_bytes, on); + __mark_pages_wc(chip, snd_pcm_get_dma_buf(substream), on); azx_dev->wc_marked = on; } } @@ -674,7 +703,7 @@ static inline void mark_pages_wc(struct azx *chip, struct snd_dma_buffer *buf, { } static inline void mark_runtime_wc(struct azx *chip, struct azx_dev *azx_dev, - struct snd_pcm_runtime *runtime, bool on) + struct snd_pcm_substream *substream, bool on) { } #endif @@ -697,7 +726,7 @@ static int azx_alloc_cmd_io(struct azx *chip) snd_dma_pci_data(chip->pci), PAGE_SIZE, &chip->rb); if (err < 0) { - snd_printk(KERN_ERR SFX "cannot allocate CORB/RIRB\n"); + snd_printk(KERN_ERR SFX "%s: cannot allocate CORB/RIRB\n", pci_name(chip->pci)); return err; } mark_pages_wc(chip, &chip->rb, true); @@ -782,15 +811,27 @@ static int azx_corb_send_cmd(struct hda_bus *bus, u32 val) { struct azx *chip = bus->private_data; unsigned int addr = azx_command_addr(val); - unsigned int wp; + unsigned int wp, rp; spin_lock_irq(&chip->reg_lock); /* add command to corb */ - wp = azx_readb(chip, CORBWP); + wp = azx_readw(chip, CORBWP); + if (wp == 0xffff) { + /* something wrong, controller likely turned to D3 */ + spin_unlock_irq(&chip->reg_lock); + return -EIO; + } wp++; wp %= ICH6_MAX_CORB_ENTRIES; + rp = azx_readw(chip, CORBRP); + if (wp == rp) { + /* oops, it's full */ + spin_unlock_irq(&chip->reg_lock); + return -EAGAIN; + } + chip->rirb.cmds[addr]++; chip->corb.buf[wp] = cpu_to_le32(val); azx_writel(chip, CORBWP, wp); @@ -809,7 +850,12 @@ static void azx_update_rirb(struct azx *chip) unsigned int addr; u32 res, res_ex; - wp = azx_readb(chip, RIRBWP); + wp = azx_readw(chip, RIRBWP); + if (wp == 0xffff) { + /* something wrong, controller likely turned to D3 */ + return; + } + if (wp == chip->rirb.wp) return; chip->rirb.wp = wp; @@ -829,8 +875,9 @@ static void azx_update_rirb(struct azx *chip) smp_wmb(); chip->rirb.cmds[addr]--; } else - snd_printk(KERN_ERR SFX "spurious response %#x:%#x, " + snd_printk(KERN_ERR SFX "%s: spurious response %#x:%#x, " "last cmd=%#08x\n", + pci_name(chip->pci), res, res_ex, chip->last_cmd[addr]); } @@ -873,9 +920,9 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus, } if (!chip->polling_mode && chip->poll_count < 2) { - snd_printdd(SFX "azx_get_response timeout, " + snd_printdd(SFX "%s: azx_get_response timeout, " "polling the codec once: last cmd=0x%08x\n", - chip->last_cmd[addr]); + pci_name(chip->pci), chip->last_cmd[addr]); do_poll = 1; chip->poll_count++; goto again; @@ -883,17 +930,17 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus, if (!chip->polling_mode) { - snd_printk(KERN_WARNING SFX "azx_get_response timeout, " + snd_printk(KERN_WARNING SFX "%s: azx_get_response timeout, " "switching to polling mode: last cmd=0x%08x\n", - chip->last_cmd[addr]); + pci_name(chip->pci), chip->last_cmd[addr]); chip->polling_mode = 1; goto again; } if (chip->msi) { - snd_printk(KERN_WARNING SFX "No response from codec, " + snd_printk(KERN_WARNING SFX "%s: No response from codec, " "disabling MSI: last cmd=0x%08x\n", - chip->last_cmd[addr]); + pci_name(chip->pci), chip->last_cmd[addr]); free_irq(chip->irq, chip); chip->irq = -1; pci_disable_msi(chip->pci); @@ -959,8 +1006,8 @@ static int azx_single_wait_for_response(struct azx *chip, unsigned int addr) udelay(1); } if (printk_ratelimit()) - snd_printd(SFX "get_response timeout: IRS=0x%x\n", - azx_readw(chip, IRS)); + snd_printd(SFX "%s: get_response timeout: IRS=0x%x\n", + pci_name(chip->pci), azx_readw(chip, IRS)); chip->rirb.res[addr] = -1; return -EIO; } @@ -987,8 +1034,8 @@ static int azx_single_send_cmd(struct hda_bus *bus, u32 val) udelay(1); } if (printk_ratelimit()) - snd_printd(SFX "send_cmd timeout: IRS=0x%x, val=0x%x\n", - azx_readw(chip, IRS), val); + snd_printd(SFX "%s: send_cmd timeout: IRS=0x%x, val=0x%x\n", + pci_name(chip->pci), azx_readw(chip, IRS), val); return -EIO; } @@ -1050,7 +1097,7 @@ static void azx_load_dsp_cleanup(struct hda_bus *bus, /* reset codec link */ static int azx_reset(struct azx *chip, int full_reset) { - int count; + unsigned long timeout; if (!full_reset) goto __skip; @@ -1061,29 +1108,31 @@ static int azx_reset(struct azx *chip, int full_reset) /* reset controller */ azx_writel(chip, GCTL, azx_readl(chip, GCTL) & ~ICH6_GCTL_RESET); - count = 50; - while (azx_readb(chip, GCTL) && --count) - msleep(1); + timeout = jiffies + msecs_to_jiffies(100); + while (azx_readb(chip, GCTL) && + time_before(jiffies, timeout)) + usleep_range(500, 1000); /* delay for >= 100us for codec PLL to settle per spec * Rev 0.9 section 5.5.1 */ - msleep(1); + usleep_range(500, 1000); /* Bring controller out of reset */ azx_writeb(chip, GCTL, azx_readb(chip, GCTL) | ICH6_GCTL_RESET); - count = 50; - while (!azx_readb(chip, GCTL) && --count) - msleep(1); + timeout = jiffies + msecs_to_jiffies(100); + while (!azx_readb(chip, GCTL) && + time_before(jiffies, timeout)) + usleep_range(500, 1000); /* Brent Chartrand said to wait >= 540us for codecs to initialize */ - msleep(1); + usleep_range(1000, 1200); __skip: /* check to see if controller is ready */ if (!azx_readb(chip, GCTL)) { - snd_printd(SFX "azx_reset: controller not ready!\n"); + snd_printd(SFX "%s: azx_reset: controller not ready!\n", pci_name(chip->pci)); return -EBUSY; } @@ -1095,7 +1144,7 @@ static int azx_reset(struct azx *chip, int full_reset) /* detect codecs */ if (!chip->codec_mask) { chip->codec_mask = azx_readw(chip, STATESTS); - snd_printdd(SFX "codec_mask = 0x%x\n", chip->codec_mask); + snd_printdd(SFX "%s: codec_mask = 0x%x\n", pci_name(chip->pci), chip->codec_mask); } return 0; @@ -1239,7 +1288,7 @@ static void azx_init_pci(struct azx *chip) * The PCI register TCSEL is defined in the Intel manuals. */ if (!(chip->driver_caps & AZX_DCAPS_NO_TCSEL)) { - snd_printdd(SFX "Clearing TCSEL\n"); + snd_printdd(SFX "%s: Clearing TCSEL\n", pci_name(chip->pci)); update_pci_byte(chip->pci, ICH6_PCIREG_TCSEL, 0x07, 0); } @@ -1247,7 +1296,7 @@ static void azx_init_pci(struct azx *chip) * we need to enable snoop. */ if (chip->driver_caps & AZX_DCAPS_ATI_SNOOP) { - snd_printdd(SFX "Setting ATI snoop: %d\n", azx_snoop(chip)); + snd_printdd(SFX "%s: Setting ATI snoop: %d\n", pci_name(chip->pci), azx_snoop(chip)); update_pci_byte(chip->pci, ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR, 0x07, azx_snoop(chip) ? ATI_SB450_HDAUDIO_ENABLE_SNOOP : 0); @@ -1255,7 +1304,7 @@ static void azx_init_pci(struct azx *chip) /* For NVIDIA HDA, enable snoop */ if (chip->driver_caps & AZX_DCAPS_NVIDIA_SNOOP) { - snd_printdd(SFX "Setting Nvidia snoop: %d\n", azx_snoop(chip)); + snd_printdd(SFX "%s: Setting Nvidia snoop: %d\n", pci_name(chip->pci), azx_snoop(chip)); update_pci_byte(chip->pci, NVIDIA_HDA_TRANSREG_ADDR, 0x0f, NVIDIA_HDA_ENABLE_COHBITS); @@ -1280,8 +1329,8 @@ static void azx_init_pci(struct azx *chip) pci_read_config_word(chip->pci, INTEL_SCH_HDA_DEVC, &snoop); } - snd_printdd(SFX "SCH snoop: %s\n", - (snoop & INTEL_SCH_HDA_DEVC_NOSNOOP) + snd_printdd(SFX "%s: SCH snoop: %s\n", + pci_name(chip->pci), (snoop & INTEL_SCH_HDA_DEVC_NOSNOOP) ? "Disabled" : "Enabled"); } } @@ -1441,8 +1490,8 @@ static int azx_setup_periods(struct azx *chip, pos_align; pos_adj = frames_to_bytes(runtime, pos_adj); if (pos_adj >= period_bytes) { - snd_printk(KERN_WARNING SFX "Too big adjustment %d\n", - bdl_pos_adj[chip->dev_index]); + snd_printk(KERN_WARNING SFX "%s: Too big adjustment %d\n", + pci_name(chip->pci), bdl_pos_adj[chip->dev_index]); pos_adj = 0; } else { ofs = setup_bdle(chip, snd_pcm_get_dma_buf(substream), @@ -1469,8 +1518,8 @@ static int azx_setup_periods(struct azx *chip, return 0; error: - snd_printk(KERN_ERR SFX "Too many BDL entries: buffer=%d, period=%d\n", - azx_dev->bufsize, period_bytes); + snd_printk(KERN_ERR SFX "%s: Too many BDL entries: buffer=%d, period=%d\n", + pci_name(chip->pci), azx_dev->bufsize, period_bytes); return -EINVAL; } @@ -1567,7 +1616,7 @@ static int probe_codec(struct azx *chip, int addr) mutex_unlock(&chip->bus->cmd_mutex); if (res == -1) return -EIO; - snd_printdd(SFX "codec #%d probed OK\n", addr); + snd_printdd(SFX "%s: codec #%d probed OK\n", pci_name(chip->pci), addr); return 0; } @@ -1594,17 +1643,33 @@ static void azx_bus_reset(struct hda_bus *bus) bus->in_reset = 0; } +static int get_jackpoll_interval(struct azx *chip) +{ + int i = jackpoll_ms[chip->dev_index]; + unsigned int j; + if (i == 0) + return 0; + if (i < 50 || i > 60000) + j = 0; + else + j = msecs_to_jiffies(i); + if (j == 0) + snd_printk(KERN_WARNING SFX + "jackpoll_ms value out of range: %d\n", i); + return j; +} + /* * Codec initialization */ /* number of codec slots for each chipset: 0 = default slots (i.e. 4) */ -static unsigned int azx_max_codecs[AZX_NUM_DRIVERS] DELAYED_INITDATA_MARK = { +static unsigned int azx_max_codecs[AZX_NUM_DRIVERS] = { [AZX_DRIVER_NVIDIA] = 8, [AZX_DRIVER_TERA] = 1, }; -static int DELAYED_INIT_MARK azx_codec_create(struct azx *chip, const char *model) +static int azx_codec_create(struct azx *chip, const char *model) { struct hda_bus_template bus_temp; int c, codecs, err; @@ -1633,7 +1698,7 @@ static int DELAYED_INIT_MARK azx_codec_create(struct azx *chip, const char *mode return err; if (chip->driver_caps & AZX_DCAPS_RIRB_DELAY) { - snd_printd(SFX "Enable delay in RIRB handling\n"); + snd_printd(SFX "%s: Enable delay in RIRB handling\n", pci_name(chip->pci)); chip->bus->needs_damn_long_delay = 1; } @@ -1650,8 +1715,8 @@ static int DELAYED_INIT_MARK azx_codec_create(struct azx *chip, const char *mode * that don't exist */ snd_printk(KERN_WARNING SFX - "Codec #%d probe error; " - "disabling it...\n", c); + "%s: Codec #%d probe error; " + "disabling it...\n", pci_name(chip->pci), c); chip->codec_mask &= ~(1 << c); /* More badly, accessing to a non-existing * codec often screws up the controller chip, @@ -1671,7 +1736,8 @@ static int DELAYED_INIT_MARK azx_codec_create(struct azx *chip, const char *mode * access works around the stall. Grrr... */ if (chip->driver_caps & AZX_DCAPS_SYNC_WRITE) { - snd_printd(SFX "Enable sync_write for stable communication\n"); + snd_printd(SFX "%s: Enable sync_write for stable communication\n", + pci_name(chip->pci)); chip->bus->sync_write = 1; chip->bus->allow_bus_reset = 1; } @@ -1683,19 +1749,20 @@ static int DELAYED_INIT_MARK azx_codec_create(struct azx *chip, const char *mode err = snd_hda_codec_new(chip->bus, c, &codec); if (err < 0) continue; + codec->jackpoll_interval = get_jackpoll_interval(chip); codec->beep_mode = chip->beep_mode; codecs++; } } if (!codecs) { - snd_printk(KERN_ERR SFX "no codecs initialized\n"); + snd_printk(KERN_ERR SFX "%s: no codecs initialized\n", pci_name(chip->pci)); return -ENXIO; } return 0; } /* configure each codec instance */ -static int __devinit azx_codec_configure(struct azx *chip) +static int azx_codec_configure(struct azx *chip) { struct hda_codec *codec; list_for_each_entry(codec, &chip->bus->codec_list, list) { @@ -1745,6 +1812,64 @@ static inline void azx_release_device(struct azx_dev *azx_dev) azx_dev->opened = 0; } +static cycle_t azx_cc_read(const struct cyclecounter *cc) +{ + struct azx_dev *azx_dev = container_of(cc, struct azx_dev, azx_cc); + struct snd_pcm_substream *substream = azx_dev->substream; + struct azx_pcm *apcm = snd_pcm_substream_chip(substream); + struct azx *chip = apcm->chip; + + return azx_readl(chip, WALLCLK); +} + +static void azx_timecounter_init(struct snd_pcm_substream *substream, + bool force, cycle_t last) +{ + struct azx_dev *azx_dev = get_azx_dev(substream); + struct timecounter *tc = &azx_dev->azx_tc; + struct cyclecounter *cc = &azx_dev->azx_cc; + u64 nsec; + + cc->read = azx_cc_read; + cc->mask = CLOCKSOURCE_MASK(32); + + /* + * Converting from 24 MHz to ns means applying a 125/3 factor. + * To avoid any saturation issues in intermediate operations, + * the 125 factor is applied first. The division is applied + * last after reading the timecounter value. + * Applying the 1/3 factor as part of the multiplication + * requires at least 20 bits for a decent precision, however + * overflows occur after about 4 hours or less, not a option. + */ + + cc->mult = 125; /* saturation after 195 years */ + cc->shift = 0; + + nsec = 0; /* audio time is elapsed time since trigger */ + timecounter_init(tc, cc, nsec); + if (force) + /* + * force timecounter to use predefined value, + * used for synchronized starts + */ + tc->cycle_last = last; +} + +static int azx_get_wallclock_tstamp(struct snd_pcm_substream *substream, + struct timespec *ts) +{ + struct azx_dev *azx_dev = get_azx_dev(substream); + u64 nsec; + + nsec = timecounter_read(&azx_dev->azx_tc); + nsec = div_u64(nsec, 3); /* can be optimized */ + + *ts = ns_to_timespec(nsec); + + return 0; +} + static struct snd_pcm_hardware azx_pcm_hw = { .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | @@ -1754,6 +1879,7 @@ static struct snd_pcm_hardware azx_pcm_hw = { /* SNDRV_PCM_INFO_RESUME |*/ SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_SYNC_START | + SNDRV_PCM_INFO_HAS_WALL_CLOCK | SNDRV_PCM_INFO_NO_PERIOD_WAKEUP), .formats = SNDRV_PCM_FMTBIT_S16_LE, .rates = SNDRV_PCM_RATE_48000, @@ -1793,6 +1919,12 @@ static int azx_pcm_open(struct snd_pcm_substream *substream) runtime->hw.rates = hinfo->rates; snd_pcm_limit_hw_rates(runtime); snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); + + /* avoid wrap-around with wall-clock */ + snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_TIME, + 20, + 178000000); + if (chip->align_buffer_size) /* constrain buffer sizes to be multiple of 128 bytes. This is more efficient in terms of memory @@ -1832,6 +1964,12 @@ static int azx_pcm_open(struct snd_pcm_substream *substream) mutex_unlock(&chip->open_mutex); return -EINVAL; } + + /* disable WALLCLOCK timestamps for capture streams + until we figure out how to handle digital inputs */ + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) + runtime->hw.info &= ~SNDRV_PCM_INFO_HAS_WALL_CLOCK; + spin_lock_irqsave(&chip->reg_lock, flags); azx_dev->substream = substream; azx_dev->running = 0; @@ -1868,11 +2006,10 @@ static int azx_pcm_hw_params(struct snd_pcm_substream *substream, { struct azx_pcm *apcm = snd_pcm_substream_chip(substream); struct azx *chip = apcm->chip; - struct snd_pcm_runtime *runtime = substream->runtime; struct azx_dev *azx_dev = get_azx_dev(substream); int ret; - mark_runtime_wc(chip, azx_dev, runtime, false); + mark_runtime_wc(chip, azx_dev, substream, false); azx_dev->bufsize = 0; azx_dev->period_bytes = 0; azx_dev->format_val = 0; @@ -1880,7 +2017,7 @@ static int azx_pcm_hw_params(struct snd_pcm_substream *substream, params_buffer_bytes(hw_params)); if (ret < 0) return ret; - mark_runtime_wc(chip, azx_dev, runtime, true); + mark_runtime_wc(chip, azx_dev, substream, true); return ret; } @@ -1889,7 +2026,6 @@ static int azx_pcm_hw_free(struct snd_pcm_substream *substream) struct azx_pcm *apcm = snd_pcm_substream_chip(substream); struct azx_dev *azx_dev = get_azx_dev(substream); struct azx *chip = apcm->chip; - struct snd_pcm_runtime *runtime = substream->runtime; struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream]; /* reset BDL address */ @@ -1902,7 +2038,7 @@ static int azx_pcm_hw_free(struct snd_pcm_substream *substream) snd_hda_codec_cleanup(apcm->codec, hinfo, substream); - mark_runtime_wc(chip, azx_dev, runtime, false); + mark_runtime_wc(chip, azx_dev, substream, false); return snd_pcm_lib_free_pages(substream); } @@ -1927,16 +2063,16 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream) ctls); if (!format_val) { snd_printk(KERN_ERR SFX - "invalid format_val, rate=%d, ch=%d, format=%d\n", - runtime->rate, runtime->channels, runtime->format); + "%s: invalid format_val, rate=%d, ch=%d, format=%d\n", + pci_name(chip->pci), runtime->rate, runtime->channels, runtime->format); return -EINVAL; } bufsize = snd_pcm_lib_buffer_bytes(substream); period_bytes = snd_pcm_lib_period_bytes(substream); - snd_printdd(SFX "azx_pcm_prepare: bufsize=0x%x, format=0x%x\n", - bufsize, format_val); + snd_printdd(SFX "%s: azx_pcm_prepare: bufsize=0x%x, format=0x%x\n", + pci_name(chip->pci), bufsize, format_val); if (bufsize != azx_dev->bufsize || period_bytes != azx_dev->period_bytes || @@ -1978,6 +2114,9 @@ static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) int rstart = 0, start, nsync = 0, sbits = 0; int nwait, timeout; + azx_dev = get_azx_dev(substream); + trace_azx_pcm_trigger(chip, azx_dev, cmd); + switch (cmd) { case SNDRV_PCM_TRIGGER_START: rstart = 1; @@ -2068,6 +2207,22 @@ static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) azx_readl(chip, OLD_SSYNC) & ~sbits); else azx_writel(chip, SSYNC, azx_readl(chip, SSYNC) & ~sbits); + if (start) { + azx_timecounter_init(substream, 0, 0); + if (nsync > 1) { + cycle_t cycle_last; + + /* same start cycle for master and group */ + azx_dev = get_azx_dev(substream); + cycle_last = azx_dev->azx_tc.cycle_last; + + snd_pcm_group_for_each_entry(s, substream) { + if (s->pcm->card != substream->pcm->card) + continue; + azx_timecounter_init(s, 1, cycle_last); + } + } + } spin_unlock(&chip->reg_lock); return 0; } @@ -2134,6 +2289,7 @@ static unsigned int azx_get_position(struct azx *chip, { unsigned int pos; int stream = azx_dev->substream->stream; + int delay = 0; switch (chip->position_fix[stream]) { case POS_FIX_LPIB: @@ -2167,7 +2323,6 @@ static unsigned int azx_get_position(struct azx *chip, chip->position_fix[stream] == POS_FIX_POSBUF && (chip->driver_caps & AZX_DCAPS_COUNT_LPIB_DELAY)) { unsigned int lpib_pos = azx_sd_readl(azx_dev, SD_LPIB); - int delay; if (stream == SNDRV_PCM_STREAM_PLAYBACK) delay = pos - lpib_pos; else @@ -2176,15 +2331,16 @@ static unsigned int azx_get_position(struct azx *chip, delay += azx_dev->bufsize; if (delay >= azx_dev->period_bytes) { snd_printk(KERN_WARNING SFX - "Unstable LPIB (%d >= %d); " + "%s: Unstable LPIB (%d >= %d); " "disabling LPIB delay counting\n", - delay, azx_dev->period_bytes); + pci_name(chip->pci), delay, azx_dev->period_bytes); delay = 0; chip->driver_caps &= ~AZX_DCAPS_COUNT_LPIB_DELAY; } azx_dev->substream->runtime->delay = bytes_to_frames(azx_dev->substream->runtime, delay); } + trace_azx_get_position(chip, azx_dev, pos, delay); return pos; } @@ -2210,13 +2366,11 @@ static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev) { u32 wallclk; unsigned int pos; - int stream; wallclk = azx_readl(chip, WALLCLK) - azx_dev->start_wallclk; if (wallclk < (azx_dev->period_wallclk * 2) / 3) return -1; /* bogus (too early) interrupt */ - stream = azx_dev->substream->stream; pos = azx_get_position(chip, azx_dev, true); if (WARN_ONCE(!azx_dev->period_bytes, @@ -2307,6 +2461,7 @@ static struct snd_pcm_ops azx_pcm_ops = { .prepare = azx_pcm_prepare, .trigger = azx_pcm_trigger, .pointer = azx_pcm_pointer, + .wall_clock = azx_get_wallclock_tstamp, .mmap = azx_pcm_mmap, .page = snd_pcm_sgbuf_ops_page, }; @@ -2335,7 +2490,8 @@ azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec, list_for_each_entry(apcm, &chip->pcm_list, list) { if (apcm->pcm->device == pcm_dev) { - snd_printk(KERN_ERR SFX "PCM %d already exists\n", pcm_dev); + snd_printk(KERN_ERR SFX "%s: PCM %d already exists\n", + pci_name(chip->pci), pcm_dev); return -EBUSY; } } @@ -2376,7 +2532,7 @@ azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec, /* * mixer creation - all stuff is implemented in hda module */ -static int __devinit azx_mixer_create(struct azx *chip) +static int azx_mixer_create(struct azx *chip) { return snd_hda_build_controls(chip->bus); } @@ -2385,7 +2541,7 @@ static int __devinit azx_mixer_create(struct azx *chip) /* * initialize SD streams */ -static int __devinit azx_init_stream(struct azx *chip) +static int azx_init_stream(struct azx *chip) { int i; @@ -2537,6 +2693,9 @@ static void azx_power_notify(struct hda_bus *bus, bool power_up) { struct azx *chip = bus->private_data; + if (!(chip->driver_caps & AZX_DCAPS_PM_RUNTIME)) + return; + if (power_up) pm_runtime_get_sync(&chip->pci->dev); else @@ -2597,6 +2756,9 @@ static int azx_suspend(struct device *dev) struct azx *chip = card->private_data; struct azx_pcm *p; + if (chip->disabled) + return 0; + snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); azx_clear_irq_pending(chip); list_for_each_entry(p, &chip->pcm_list, list) @@ -2622,6 +2784,9 @@ static int azx_resume(struct device *dev) struct snd_card *card = dev_get_drvdata(dev); struct azx *chip = card->private_data; + if (chip->disabled) + return 0; + pci_set_power_state(pci, PCI_D0); pci_restore_state(pci); if (pci_enable_device(pci) < 0) { @@ -2652,9 +2817,6 @@ static int azx_runtime_suspend(struct device *dev) struct snd_card *card = dev_get_drvdata(dev); struct azx *chip = card->private_data; - if (!power_save_controller) - return -EAGAIN; - azx_stop_chip(chip); azx_clear_irq_pending(chip); return 0; @@ -2669,12 +2831,27 @@ static int azx_runtime_resume(struct device *dev) azx_init_chip(chip, 1); return 0; } + +static int azx_runtime_idle(struct device *dev) +{ + struct snd_card *card = dev_get_drvdata(dev); + struct azx *chip = card->private_data; + + if (power_save_controller > 0) + return 0; + if (!power_save_controller || + !(chip->driver_caps & AZX_DCAPS_PM_RUNTIME)) + return -EBUSY; + + return 0; +} + #endif /* CONFIG_PM_RUNTIME */ #ifdef CONFIG_PM static const struct dev_pm_ops azx_pm = { SET_SYSTEM_SLEEP_PM_OPS(azx_suspend, azx_resume) - SET_RUNTIME_PM_OPS(azx_runtime_suspend, azx_runtime_resume, NULL) + SET_RUNTIME_PM_OPS(azx_runtime_suspend, azx_runtime_resume, azx_runtime_idle) }; #define AZX_PM_OPS &azx_pm @@ -2706,11 +2883,11 @@ static void azx_notifier_unregister(struct azx *chip) unregister_reboot_notifier(&chip->reboot_notifier); } -static int DELAYED_INIT_MARK azx_first_init(struct azx *chip); -static int DELAYED_INIT_MARK azx_probe_continue(struct azx *chip); +static int azx_first_init(struct azx *chip); +static int azx_probe_continue(struct azx *chip); #ifdef SUPPORT_VGA_SWITCHEROO -static struct pci_dev __devinit *get_bound_vga(struct pci_dev *pci); +static struct pci_dev *get_bound_vga(struct pci_dev *pci); static void azx_vs_set_state(struct pci_dev *pci, enum vga_switcheroo_state state) @@ -2719,6 +2896,7 @@ static void azx_vs_set_state(struct pci_dev *pci, struct azx *chip = card->private_data; bool disabled; + wait_for_completion(&chip->probe_wait); if (chip->init_failed) return; @@ -2742,15 +2920,14 @@ static void azx_vs_set_state(struct pci_dev *pci, } } else { snd_printk(KERN_INFO SFX - "%s %s via VGA-switcheroo\n", - disabled ? "Disabling" : "Enabling", - pci_name(chip->pci)); + "%s: %s via VGA-switcheroo\n", pci_name(chip->pci), + disabled ? "Disabling" : "Enabling"); if (disabled) { azx_suspend(&pci->dev); chip->disabled = true; if (snd_hda_lock_devices(chip->bus)) - snd_printk(KERN_WARNING SFX - "Cannot lock devices!\n"); + snd_printk(KERN_WARNING SFX "%s: Cannot lock devices!\n", + pci_name(chip->pci)); } else { snd_hda_unlock_devices(chip->bus); chip->disabled = false; @@ -2764,6 +2941,7 @@ static bool azx_vs_can_switch(struct pci_dev *pci) struct snd_card *card = pci_get_drvdata(pci); struct azx *chip = card->private_data; + wait_for_completion(&chip->probe_wait); if (chip->init_failed) return false; if (chip->disabled || !chip->bus) @@ -2774,7 +2952,7 @@ static bool azx_vs_can_switch(struct pci_dev *pci) return true; } -static void __devinit init_vga_switcheroo(struct azx *chip) +static void init_vga_switcheroo(struct azx *chip) { struct pci_dev *p = get_bound_vga(chip->pci); if (p) { @@ -2791,7 +2969,7 @@ static const struct vga_switcheroo_client_ops azx_vs_ops = { .can_switch = azx_vs_can_switch, }; -static int __devinit register_vga_switcheroo(struct azx *chip) +static int register_vga_switcheroo(struct azx *chip) { int err; @@ -2825,6 +3003,9 @@ static int azx_free(struct azx *chip) azx_notifier_unregister(chip); + chip->init_failed = 1; /* to be sure */ + complete_all(&chip->probe_wait); + if (use_vga_switcheroo(chip)) { if (chip->disabled && chip->bus) snd_hda_unlock_devices(chip->bus); @@ -2883,7 +3064,7 @@ static int azx_dev_free(struct snd_device *device) /* * Check of disabled HDMI controller by vga-switcheroo */ -static struct pci_dev __devinit *get_bound_vga(struct pci_dev *pci) +static struct pci_dev *get_bound_vga(struct pci_dev *pci) { struct pci_dev *p; @@ -2906,7 +3087,7 @@ static struct pci_dev __devinit *get_bound_vga(struct pci_dev *pci) return NULL; } -static bool __devinit check_hdmi_disabled(struct pci_dev *pci) +static bool check_hdmi_disabled(struct pci_dev *pci) { bool vga_inactive = false; struct pci_dev *p = get_bound_vga(pci); @@ -2923,7 +3104,7 @@ static bool __devinit check_hdmi_disabled(struct pci_dev *pci) /* * white/black-listing for position_fix */ -static struct snd_pci_quirk position_fix_list[] __devinitdata = { +static struct snd_pci_quirk position_fix_list[] = { SND_PCI_QUIRK(0x1028, 0x01cc, "Dell D820", POS_FIX_LPIB), SND_PCI_QUIRK(0x1028, 0x01de, "Dell Precision 390", POS_FIX_LPIB), SND_PCI_QUIRK(0x103c, 0x306d, "HP dv3", POS_FIX_LPIB), @@ -2941,7 +3122,7 @@ static struct snd_pci_quirk position_fix_list[] __devinitdata = { {} }; -static int __devinit check_position_fix(struct azx *chip, int fix) +static int check_position_fix(struct azx *chip, int fix) { const struct snd_pci_quirk *q; @@ -2965,11 +3146,11 @@ static int __devinit check_position_fix(struct azx *chip, int fix) /* Check VIA/ATI HD Audio Controller exist */ if (chip->driver_caps & AZX_DCAPS_POSFIX_VIA) { - snd_printd(SFX "Using VIACOMBO position fix\n"); + snd_printd(SFX "%s: Using VIACOMBO position fix\n", pci_name(chip->pci)); return POS_FIX_VIACOMBO; } if (chip->driver_caps & AZX_DCAPS_POSFIX_LPIB) { - snd_printd(SFX "Using LPIB position fix\n"); + snd_printd(SFX "%s: Using LPIB position fix\n", pci_name(chip->pci)); return POS_FIX_LPIB; } return POS_FIX_AUTO; @@ -2978,7 +3159,7 @@ static int __devinit check_position_fix(struct azx *chip, int fix) /* * black-lists for probe_mask */ -static struct snd_pci_quirk probe_mask_list[] __devinitdata = { +static struct snd_pci_quirk probe_mask_list[] = { /* Thinkpad often breaks the controller communication when accessing * to the non-working (or non-existing) modem codec slot. */ @@ -2999,7 +3180,7 @@ static struct snd_pci_quirk probe_mask_list[] __devinitdata = { #define AZX_FORCE_CODEC_MASK 0x100 -static void __devinit check_probe_mask(struct azx *chip, int dev) +static void check_probe_mask(struct azx *chip, int dev) { const struct snd_pci_quirk *q; @@ -3027,7 +3208,7 @@ static void __devinit check_probe_mask(struct azx *chip, int dev) /* * white/black-list for enable_msi */ -static struct snd_pci_quirk msi_black_list[] __devinitdata = { +static struct snd_pci_quirk msi_black_list[] = { SND_PCI_QUIRK(0x1043, 0x81f2, "ASUS", 0), /* Athlon64 X2 + nvidia */ SND_PCI_QUIRK(0x1043, 0x81f6, "ASUS", 0), /* nvidia */ SND_PCI_QUIRK(0x1043, 0x822d, "ASUS", 0), /* Athlon64 X2 + nvidia MCP55 */ @@ -3036,7 +3217,7 @@ static struct snd_pci_quirk msi_black_list[] __devinitdata = { {} }; -static void __devinit check_msi(struct azx *chip) +static void check_msi(struct azx *chip) { const struct snd_pci_quirk *q; @@ -3062,7 +3243,7 @@ static void __devinit check_msi(struct azx *chip) } /* check the snoop mode availability */ -static void __devinit azx_check_snoop_available(struct azx *chip) +static void azx_check_snoop_available(struct azx *chip) { bool snoop = chip->snoop; @@ -3085,8 +3266,8 @@ static void __devinit azx_check_snoop_available(struct azx *chip) } if (snoop != chip->snoop) { - snd_printk(KERN_INFO SFX "Force to %s mode\n", - snoop ? "snoop" : "non-snoop"); + snd_printk(KERN_INFO SFX "%s: Force to %s mode\n", + pci_name(chip->pci), snoop ? "snoop" : "non-snoop"); chip->snoop = snoop; } } @@ -3094,9 +3275,9 @@ static void __devinit azx_check_snoop_available(struct azx *chip) /* * constructor */ -static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, - int dev, unsigned int driver_caps, - struct azx **rchip) +static int azx_create(struct snd_card *card, struct pci_dev *pci, + int dev, unsigned int driver_caps, + struct azx **rchip) { static struct snd_device_ops ops = { .dev_free = azx_dev_free, @@ -3112,7 +3293,7 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (!chip) { - snd_printk(KERN_ERR SFX "cannot allocate chip\n"); + snd_printk(KERN_ERR SFX "%s: Cannot allocate chip\n", pci_name(pci)); pci_disable_device(pci); return -ENOMEM; } @@ -3130,6 +3311,7 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, INIT_LIST_HEAD(&chip->pcm_list); INIT_LIST_HEAD(&chip->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]); @@ -3157,29 +3339,10 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, } } - if (check_hdmi_disabled(pci)) { - snd_printk(KERN_INFO SFX "VGA controller for %s is disabled\n", - pci_name(pci)); - if (use_vga_switcheroo(chip)) { - snd_printk(KERN_INFO SFX "Delaying initialization\n"); - chip->disabled = true; - goto ok; - } - kfree(chip); - pci_disable_device(pci); - return -ENXIO; - } - - err = azx_first_init(chip); - if (err < 0) { - azx_free(chip); - return err; - } - - ok: err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); if (err < 0) { - snd_printk(KERN_ERR SFX "Error creating device [card]!\n"); + snd_printk(KERN_ERR SFX "%s: Error creating device [card]!\n", + pci_name(chip->pci)); azx_free(chip); return err; } @@ -3188,7 +3351,7 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, return 0; } -static int DELAYED_INIT_MARK azx_first_init(struct azx *chip) +static int azx_first_init(struct azx *chip) { int dev = chip->dev_index; struct pci_dev *pci = chip->pci; @@ -3214,7 +3377,7 @@ static int DELAYED_INIT_MARK azx_first_init(struct azx *chip) chip->addr = pci_resource_start(pci, 0); chip->remap_addr = pci_ioremap_bar(pci, 0); if (chip->remap_addr == NULL) { - snd_printk(KERN_ERR SFX "ioremap error\n"); + snd_printk(KERN_ERR SFX "%s: ioremap error\n", pci_name(chip->pci)); return -ENXIO; } @@ -3229,7 +3392,7 @@ static int DELAYED_INIT_MARK azx_first_init(struct azx *chip) synchronize_irq(chip->irq); gcap = azx_readw(chip, GCAP); - snd_printdd(SFX "chipset global capabilities = 0x%x\n", gcap); + snd_printdd(SFX "%s: chipset global capabilities = 0x%x\n", pci_name(chip->pci), gcap); /* disable SB600 64bit support for safety */ if (chip->pci->vendor == PCI_VENDOR_ID_ATI) { @@ -3246,7 +3409,7 @@ static int DELAYED_INIT_MARK azx_first_init(struct azx *chip) /* disable 64bit DMA address on some devices */ if (chip->driver_caps & AZX_DCAPS_NO_64BIT) { - snd_printd(SFX "Disabling 64bit DMA\n"); + snd_printd(SFX "%s: Disabling 64bit DMA\n", pci_name(chip->pci)); gcap &= ~ICH6_GCAP_64OK; } @@ -3301,7 +3464,7 @@ static int DELAYED_INIT_MARK azx_first_init(struct azx *chip) chip->azx_dev = kcalloc(chip->num_streams, sizeof(*chip->azx_dev), GFP_KERNEL); if (!chip->azx_dev) { - snd_printk(KERN_ERR SFX "cannot malloc azx_dev\n"); + snd_printk(KERN_ERR SFX "%s: cannot malloc azx_dev\n", pci_name(chip->pci)); return -ENOMEM; } @@ -3311,7 +3474,7 @@ static int DELAYED_INIT_MARK azx_first_init(struct azx *chip) snd_dma_pci_data(chip->pci), BDL_SIZE, &chip->azx_dev[i].bdl); if (err < 0) { - snd_printk(KERN_ERR SFX "cannot allocate BDL\n"); + snd_printk(KERN_ERR SFX "%s: cannot allocate BDL\n", pci_name(chip->pci)); return -ENOMEM; } mark_pages_wc(chip, &chip->azx_dev[i].bdl, true); @@ -3321,7 +3484,7 @@ static int DELAYED_INIT_MARK azx_first_init(struct azx *chip) snd_dma_pci_data(chip->pci), chip->num_streams * 8, &chip->posbuf); if (err < 0) { - snd_printk(KERN_ERR SFX "cannot allocate posbuf\n"); + snd_printk(KERN_ERR SFX "%s: cannot allocate posbuf\n", pci_name(chip->pci)); return -ENOMEM; } mark_pages_wc(chip, &chip->posbuf, true); @@ -3339,7 +3502,7 @@ static int DELAYED_INIT_MARK azx_first_init(struct azx *chip) /* codec detection */ if (!chip->codec_mask) { - snd_printk(KERN_ERR SFX "no codecs found!\n"); + snd_printk(KERN_ERR SFX "%s: no codecs found!\n", pci_name(chip->pci)); return -ENODEV; } @@ -3375,7 +3538,8 @@ static void azx_firmware_cb(const struct firmware *fw, void *context) struct pci_dev *pci = chip->pci; if (!fw) { - snd_printk(KERN_ERR SFX "Cannot load firmware, aborting\n"); + snd_printk(KERN_ERR SFX "%s: Cannot load firmware, aborting\n", + pci_name(chip->pci)); goto error; } @@ -3393,8 +3557,8 @@ static void azx_firmware_cb(const struct firmware *fw, void *context) } #endif -static int __devinit azx_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int azx_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { static int dev; struct snd_card *card; @@ -3411,7 +3575,7 @@ static int __devinit azx_probe(struct pci_dev *pci, err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card); if (err < 0) { - snd_printk(KERN_ERR SFX "Error creating card!\n"); + snd_printk(KERN_ERR "hda-intel: Error creating card!\n"); return err; } @@ -3421,12 +3585,34 @@ static int __devinit azx_probe(struct pci_dev *pci, if (err < 0) goto out_free; card->private_data = chip; + + pci_set_drvdata(pci, card); + + err = register_vga_switcheroo(chip); + if (err < 0) { + snd_printk(KERN_ERR SFX + "%s: Error registering VGA-switcheroo client\n", pci_name(pci)); + goto out_free; + } + + if (check_hdmi_disabled(pci)) { + snd_printk(KERN_INFO SFX "%s: VGA controller is disabled\n", + pci_name(pci)); + snd_printk(KERN_INFO SFX "%s: Delaying initialization\n", pci_name(pci)); + chip->disabled = true; + } + probe_now = !chip->disabled; + if (probe_now) { + err = azx_first_init(chip); + if (err < 0) + goto out_free; + } #ifdef CONFIG_SND_HDA_PATCH_LOADER if (patch[dev] && *patch[dev]) { - snd_printk(KERN_ERR SFX "Applying patch firmware '%s'\n", - patch[dev]); + snd_printk(KERN_ERR SFX "%s: Applying patch firmware '%s'\n", + pci_name(pci), patch[dev]); err = request_firmware_nowait(THIS_MODULE, true, patch[dev], &pci->dev, GFP_KERNEL, card, azx_firmware_cb); @@ -3442,27 +3628,20 @@ static int __devinit azx_probe(struct pci_dev *pci, goto out_free; } - pci_set_drvdata(pci, card); - if (pci_dev_run_wake(pci)) pm_runtime_put_noidle(&pci->dev); - err = register_vga_switcheroo(chip); - if (err < 0) { - snd_printk(KERN_ERR SFX - "Error registering VGA-switcheroo client\n"); - goto out_free; - } - dev++; + complete_all(&chip->probe_wait); return 0; out_free: snd_card_free(card); + pci_set_drvdata(pci, NULL); return err; } -static int DELAYED_INIT_MARK azx_probe_continue(struct azx *chip) +static int azx_probe_continue(struct azx *chip) { int dev = chip->dev_index; int err; @@ -3481,8 +3660,10 @@ static int DELAYED_INIT_MARK azx_probe_continue(struct azx *chip) chip->fw->data); if (err < 0) goto out_free; +#ifndef CONFIG_PM release_firmware(chip->fw); /* no longer needed */ chip->fw = NULL; +#endif } #endif if ((probe_only[dev] & 1) == 0) { @@ -3517,7 +3698,7 @@ out_free: return err; } -static void __devexit azx_remove(struct pci_dev *pci) +static void azx_remove(struct pci_dev *pci) { struct snd_card *card = pci_get_drvdata(pci); @@ -3533,46 +3714,38 @@ static void __devexit azx_remove(struct pci_dev *pci) static DEFINE_PCI_DEVICE_TABLE(azx_ids) = { /* CPT */ { PCI_DEVICE(0x8086, 0x1c20), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP | - AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY }, + .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH_NOPM }, /* PBG */ { PCI_DEVICE(0x8086, 0x1d20), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP | - AZX_DCAPS_BUFSIZE}, + .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH_NOPM }, /* Panther Point */ { PCI_DEVICE(0x8086, 0x1e20), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP | - AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY }, + .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH_NOPM }, /* Lynx Point */ { PCI_DEVICE(0x8086, 0x8c20), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP | - AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY }, + .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, /* Lynx Point-LP */ { PCI_DEVICE(0x8086, 0x9c20), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP | - AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY }, + .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, /* Lynx Point-LP */ { PCI_DEVICE(0x8086, 0x9c21), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP | - AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY }, + .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, /* Haswell */ + { PCI_DEVICE(0x8086, 0x0a0c), + .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH }, { PCI_DEVICE(0x8086, 0x0c0c), - .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_SCH_SNOOP | - AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY }, + .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH }, { PCI_DEVICE(0x8086, 0x0d0c), - .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_SCH_SNOOP | - AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY }, + .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH }, /* 5 Series/3400 */ { PCI_DEVICE(0x8086, 0x3b56), - .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_SCH_SNOOP | - AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY }, - /* SCH */ + .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH }, + /* Poulsbo */ { PCI_DEVICE(0x8086, 0x811b), - .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_SCH_SNOOP | - AZX_DCAPS_BUFSIZE | AZX_DCAPS_POSFIX_LPIB }, /* Poulsbo */ + .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_NOPM }, + /* Oaktrail */ { PCI_DEVICE(0x8086, 0x080a), - .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_SCH_SNOOP | - AZX_DCAPS_BUFSIZE | AZX_DCAPS_POSFIX_LPIB }, /* Oaktrail */ + .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_NOPM }, /* ICH */ { PCI_DEVICE(0x8086, 0x2668), .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC | @@ -3713,7 +3886,7 @@ static struct pci_driver azx_driver = { .name = KBUILD_MODNAME, .id_table = azx_ids, .probe = azx_probe, - .remove = __devexit_p(azx_remove), + .remove = azx_remove, .driver = { .pm = AZX_PM_OPS, }, diff --git a/sound/pci/hda/hda_intel_trace.h b/sound/pci/hda/hda_intel_trace.h new file mode 100644 index 000000000000..7b5e4c2cf9d5 --- /dev/null +++ b/sound/pci/hda/hda_intel_trace.h @@ -0,0 +1,62 @@ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM hda_intel +#define TRACE_INCLUDE_FILE hda_intel_trace + +#if !defined(_TRACE_HDA_INTEL_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_HDA_INTEL_H + +#include <linux/tracepoint.h> + +struct azx; +struct azx_dev; + +TRACE_EVENT(azx_pcm_trigger, + + TP_PROTO(struct azx *chip, struct azx_dev *dev, int cmd), + + TP_ARGS(chip, dev, cmd), + + TP_STRUCT__entry( + __field( int, card ) + __field( int, idx ) + __field( int, cmd ) + ), + + TP_fast_assign( + __entry->card = (chip)->card->number; + __entry->idx = (dev)->index; + __entry->cmd = cmd; + ), + + TP_printk("[%d:%d] cmd=%d", __entry->card, __entry->idx, __entry->cmd) +); + +TRACE_EVENT(azx_get_position, + + TP_PROTO(struct azx *chip, struct azx_dev *dev, unsigned int pos, unsigned int delay), + + TP_ARGS(chip, dev, pos, delay), + + TP_STRUCT__entry( + __field( int, card ) + __field( int, idx ) + __field( unsigned int, pos ) + __field( unsigned int, delay ) + ), + + TP_fast_assign( + __entry->card = (chip)->card->number; + __entry->idx = (dev)->index; + __entry->pos = pos; + __entry->delay = delay; + ), + + TP_printk("[%d:%d] pos=%u, delay=%u", __entry->card, __entry->idx, __entry->pos, __entry->delay) +); + +#endif /* _TRACE_HDA_INTEL_H */ + +/* This part must be outside protection */ +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . +#include <trace/define_trace.h> diff --git a/sound/pci/hda/hda_jack.c b/sound/pci/hda/hda_jack.c index 5c690cb873d4..1d035efeff4f 100644 --- a/sound/pci/hda/hda_jack.c +++ b/sound/pci/hda/hda_jack.c @@ -29,7 +29,8 @@ bool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid) if (get_defcfg_misc(snd_hda_codec_get_pincfg(codec, nid)) & AC_DEFCFG_MISC_NO_PRESENCE) return false; - if (!(get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP)) + if (!(get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) && + !codec->jackpoll_interval) return false; return true; } @@ -39,6 +40,7 @@ EXPORT_SYMBOL_HDA(is_jack_detectable); static u32 read_pin_sense(struct hda_codec *codec, hda_nid_t nid) { u32 pincap; + u32 val; if (!codec->no_trigger_sense) { pincap = snd_hda_query_pin_caps(codec, nid); @@ -46,8 +48,11 @@ static u32 read_pin_sense(struct hda_codec *codec, hda_nid_t nid) snd_hda_codec_read(codec, nid, 0, AC_VERB_SET_PIN_SENSE, 0); } - return snd_hda_codec_read(codec, nid, 0, + val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0); + if (codec->inv_jack_detect) + val ^= AC_PINSENSE_PRESENCE; + return val; } /** @@ -95,7 +100,6 @@ snd_hda_jack_tbl_new(struct hda_codec *codec, hda_nid_t nid) struct hda_jack_tbl *jack = snd_hda_jack_tbl_get(codec, nid); if (jack) return jack; - snd_array_init(&codec->jacktbl, sizeof(*jack), 16); jack = snd_array_new(&codec->jacktbl); if (!jack) return NULL; @@ -122,6 +126,8 @@ void snd_hda_jack_tbl_clear(struct hda_codec *codec) snd_array_free(&codec->jacktbl); } +#define get_jack_plug_state(sense) !!(sense & AC_PINSENSE_PRESENCE) + /* update the cached value and notification flag if needed */ static void jack_detect_update(struct hda_codec *codec, struct hda_jack_tbl *jack) @@ -134,7 +140,21 @@ static void jack_detect_update(struct hda_codec *codec, else jack->pin_sense = read_pin_sense(codec, jack->nid); + /* A gating jack indicates the jack is invalid if gating is unplugged */ + if (jack->gating_jack && !snd_hda_jack_detect(codec, jack->gating_jack)) + jack->pin_sense &= ~AC_PINSENSE_PRESENCE; + jack->jack_dirty = 0; + + /* If a jack is gated by this one update it. */ + if (jack->gated_jack) { + struct hda_jack_tbl *gated = + snd_hda_jack_tbl_get(codec, jack->gated_jack); + if (gated) { + gated->jack_dirty = 1; + jack_detect_update(codec, gated); + } + } } /** @@ -173,8 +193,6 @@ u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid) } EXPORT_SYMBOL_HDA(snd_hda_pin_sense); -#define get_jack_plug_state(sense) !!(sense & AC_PINSENSE_PRESENCE) - /** * snd_hda_jack_detect - query pin Presence Detect status * @codec: the CODEC to sense @@ -206,6 +224,8 @@ int snd_hda_jack_detect_enable_callback(struct hda_codec *codec, hda_nid_t nid, jack->action = action; if (cb) jack->callback = cb; + if (codec->jackpoll_interval > 0) + return 0; /* No unsol if we're polling instead */ return snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | jack->tag); @@ -220,16 +240,46 @@ int snd_hda_jack_detect_enable(struct hda_codec *codec, hda_nid_t nid, EXPORT_SYMBOL_HDA(snd_hda_jack_detect_enable); /** + * snd_hda_jack_set_gating_jack - Set gating jack. + * + * Indicates the gated jack is only valid when the gating jack is plugged. + */ +int snd_hda_jack_set_gating_jack(struct hda_codec *codec, hda_nid_t gated_nid, + hda_nid_t gating_nid) +{ + struct hda_jack_tbl *gated = snd_hda_jack_tbl_get(codec, gated_nid); + struct hda_jack_tbl *gating = snd_hda_jack_tbl_get(codec, gating_nid); + + if (!gated || !gating) + return -EINVAL; + + gated->gating_jack = gating_nid; + gating->gated_jack = gated_nid; + + return 0; +} +EXPORT_SYMBOL_HDA(snd_hda_jack_set_gating_jack); + +/** * snd_hda_jack_report_sync - sync the states of all jacks and report if changed */ void snd_hda_jack_report_sync(struct hda_codec *codec) { - struct hda_jack_tbl *jack = codec->jacktbl.list; + struct hda_jack_tbl *jack; int i, state; + /* update all jacks at first */ + jack = codec->jacktbl.list; for (i = 0; i < codec->jacktbl.used; i++, jack++) - if (jack->nid) { + if (jack->nid) jack_detect_update(codec, jack); + + /* report the updated jacks; it's done after updating all jacks + * to make sure that all gating jacks properly have been set + */ + jack = codec->jacktbl.list; + for (i = 0; i < codec->jacktbl.used; i++, jack++) + if (jack->nid) { if (!jack->kctl) continue; state = get_jack_plug_state(jack->pin_sense); @@ -422,6 +472,19 @@ int snd_hda_jack_add_kctls(struct hda_codec *codec, } EXPORT_SYMBOL_HDA(snd_hda_jack_add_kctls); +static void call_jack_callback(struct hda_codec *codec, + struct hda_jack_tbl *jack) +{ + if (jack->callback) + jack->callback(codec, jack); + if (jack->gated_jack) { + struct hda_jack_tbl *gated = + snd_hda_jack_tbl_get(codec, jack->gated_jack); + if (gated && gated->callback) + gated->callback(codec, gated); + } +} + void snd_hda_jack_unsol_event(struct hda_codec *codec, unsigned int res) { struct hda_jack_tbl *event; @@ -432,10 +495,29 @@ void snd_hda_jack_unsol_event(struct hda_codec *codec, unsigned int res) return; event->jack_dirty = 1; - if (event->callback) - event->callback(codec, event); - + call_jack_callback(codec, event); snd_hda_jack_report_sync(codec); } EXPORT_SYMBOL_HDA(snd_hda_jack_unsol_event); +void snd_hda_jack_poll_all(struct hda_codec *codec) +{ + struct hda_jack_tbl *jack = codec->jacktbl.list; + int i, changes = 0; + + for (i = 0; i < codec->jacktbl.used; i++, jack++) { + unsigned int old_sense; + if (!jack->nid || !jack->jack_dirty || jack->phantom_jack) + continue; + old_sense = get_jack_plug_state(jack->pin_sense); + jack_detect_update(codec, jack); + if (old_sense == get_jack_plug_state(jack->pin_sense)) + continue; + changes = 1; + call_jack_callback(codec, jack); + } + if (changes) + snd_hda_jack_report_sync(codec); +} +EXPORT_SYMBOL_HDA(snd_hda_jack_poll_all); + diff --git a/sound/pci/hda/hda_jack.h b/sound/pci/hda/hda_jack.h index af8dd4724da5..ec12abd45263 100644 --- a/sound/pci/hda/hda_jack.h +++ b/sound/pci/hda/hda_jack.h @@ -28,6 +28,8 @@ struct hda_jack_tbl { unsigned int jack_detect:1; /* capable of jack-detection? */ unsigned int jack_dirty:1; /* needs to update? */ unsigned int phantom_jack:1; /* a fixed, always present port? */ + hda_nid_t gating_jack; /* valid when gating jack plugged */ + hda_nid_t gated_jack; /* gated is dependent on this jack */ struct snd_kcontrol *kctl; /* assigned kctl for jack-detection */ #ifdef CONFIG_SND_HDA_INPUT_JACK int type; @@ -69,6 +71,8 @@ int snd_hda_jack_detect_enable_callback(struct hda_codec *codec, hda_nid_t nid, unsigned char action, hda_jack_callback cb); +int snd_hda_jack_set_gating_jack(struct hda_codec *codec, hda_nid_t gated_nid, + hda_nid_t gating_nid); u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid); int snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid); @@ -84,4 +88,6 @@ void snd_hda_jack_report_sync(struct hda_codec *codec); void snd_hda_jack_unsol_event(struct hda_codec *codec, unsigned int res); +void snd_hda_jack_poll_all(struct hda_codec *codec); + #endif /* __SOUND_HDA_JACK_H */ diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 09dbdc37f781..05f1d594d17b 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -133,9 +133,11 @@ int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch, int direction, int idx, int mask, int val); int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid, int dir, int idx, int mask, int val); -#ifdef CONFIG_PM +int snd_hda_codec_amp_init(struct hda_codec *codec, hda_nid_t nid, int ch, + int direction, int idx, int mask, int val); +int snd_hda_codec_amp_init_stereo(struct hda_codec *codec, hda_nid_t nid, + int dir, int idx, int mask, int val); void snd_hda_codec_resume_amp(struct hda_codec *codec); -#endif void snd_hda_set_vmaster_tlv(struct hda_codec *codec, hda_nid_t nid, int dir, unsigned int *tlv); @@ -240,9 +242,11 @@ int snd_hda_mixer_bind_tlv(struct snd_kcontrol *kcontrol, int op_flag, /* * SPDIF I/O */ -int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, - hda_nid_t associated_nid, - hda_nid_t cvt_nid); +int snd_hda_create_dig_out_ctls(struct hda_codec *codec, + hda_nid_t associated_nid, + hda_nid_t cvt_nid, int type); +#define snd_hda_create_spdif_out_ctls(codec, anid, cnid) \ + snd_hda_create_dig_out_ctls(codec, anid, cnid, HDA_PCM_TYPE_SPDIF) int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid); /* @@ -382,6 +386,61 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, const struct snd_kcontrol_new *knew); /* + * Fix-up pin default configurations and add default verbs + */ + +struct hda_pintbl { + hda_nid_t nid; + u32 val; +}; + +struct hda_model_fixup { + const int id; + const char *name; +}; + +struct hda_fixup { + int type; + bool chained:1; /* call the chained fixup(s) after this */ + bool chained_before:1; /* call the chained fixup(s) before this */ + int chain_id; + union { + const struct hda_pintbl *pins; + const struct hda_verb *verbs; + void (*func)(struct hda_codec *codec, + const struct hda_fixup *fix, + int action); + } v; +}; + +/* fixup types */ +enum { + HDA_FIXUP_INVALID, + HDA_FIXUP_PINS, + HDA_FIXUP_VERBS, + HDA_FIXUP_FUNC, + HDA_FIXUP_PINCTLS, +}; + +/* fixup action definitions */ +enum { + HDA_FIXUP_ACT_PRE_PROBE, + HDA_FIXUP_ACT_PROBE, + HDA_FIXUP_ACT_INIT, + HDA_FIXUP_ACT_BUILD, +}; + +int snd_hda_add_verbs(struct hda_codec *codec, const struct hda_verb *list); +void snd_hda_apply_verbs(struct hda_codec *codec); +void snd_hda_apply_pincfgs(struct hda_codec *codec, + const struct hda_pintbl *cfg); +void snd_hda_apply_fixup(struct hda_codec *codec, int action); +void snd_hda_pick_fixup(struct hda_codec *codec, + const struct hda_model_fixup *models, + const struct snd_pci_quirk *quirk, + const struct hda_fixup *fixlist); + +/* * unsolicited event handler */ @@ -429,6 +488,8 @@ struct hda_bus_unsolicited { #define PIN_HP_AMP (AC_PINCTL_HP_EN) unsigned int snd_hda_get_default_vref(struct hda_codec *codec, hda_nid_t pin); +unsigned int snd_hda_correct_pin_ctl(struct hda_codec *codec, + hda_nid_t pin, unsigned int val); int _snd_hda_set_pin_ctl(struct hda_codec *codec, hda_nid_t pin, unsigned int val, bool cached); @@ -468,6 +529,10 @@ snd_hda_set_pin_ctl_cache(struct hda_codec *codec, hda_nid_t pin, return _snd_hda_set_pin_ctl(codec, pin, val, true); } +int snd_hda_codec_get_pin_target(struct hda_codec *codec, hda_nid_t nid); +int snd_hda_codec_set_pin_target(struct hda_codec *codec, hda_nid_t nid, + unsigned int val); + /* * get widget capabilities */ @@ -550,6 +615,7 @@ static inline int snd_hda_hwdep_add_sysfs(struct hda_codec *codec) #ifdef CONFIG_SND_HDA_RECONFIG const char *snd_hda_get_hint(struct hda_codec *codec, const char *key); int snd_hda_get_bool_hint(struct hda_codec *codec, const char *key); +int snd_hda_get_int_hint(struct hda_codec *codec, const char *key, int *valp); #else static inline const char *snd_hda_get_hint(struct hda_codec *codec, const char *key) @@ -562,6 +628,12 @@ int snd_hda_get_bool_hint(struct hda_codec *codec, const char *key) { return -ENOENT; } + +static inline +int snd_hda_get_int_hint(struct hda_codec *codec, const char *key, int *valp) +{ + return -ENOENT; +} #endif /* @@ -585,6 +657,19 @@ int snd_hda_check_amp_list_power(struct hda_codec *codec, struct hda_loopback_check *check, hda_nid_t nid); +/* check whether the actual power state matches with the target state */ +static inline bool +snd_hda_check_power_state(struct hda_codec *codec, hda_nid_t nid, + unsigned int target_state) +{ + unsigned int state = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_POWER_STATE, 0); + if (state & AC_PWRST_ERROR) + return true; + state = (state >> 4) & 0x0f; + return (state != target_state); +} + /* * AMP control callbacks */ @@ -594,11 +679,21 @@ int snd_hda_check_amp_list_power(struct hda_codec *codec, #define get_amp_channels(kc) (((kc)->private_value >> 16) & 0x3) #define get_amp_direction_(pv) (((pv) >> 18) & 0x1) #define get_amp_direction(kc) get_amp_direction_((kc)->private_value) -#define get_amp_index(kc) (((kc)->private_value >> 19) & 0xf) +#define get_amp_index_(pv) (((pv) >> 19) & 0xf) +#define get_amp_index(kc) get_amp_index_((kc)->private_value) #define get_amp_offset(kc) (((kc)->private_value >> 23) & 0x3f) #define get_amp_min_mute(kc) (((kc)->private_value >> 29) & 0x1) /* + * enum control helper + */ +int snd_hda_enum_helper_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo, + int num_entries, const char * const *texts); +#define snd_hda_enum_bool_helper_info(kcontrol, uinfo) \ + snd_hda_enum_helper_info(kcontrol, uinfo, 0, NULL) + +/* * CEA Short Audio Descriptor data */ struct cea_sad { diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index 045e5d32f5de..5e02f26606b6 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -138,16 +138,17 @@ static void print_amp_vals(struct snd_info_buffer *buffer, dir = dir == HDA_OUTPUT ? AC_AMP_GET_OUTPUT : AC_AMP_GET_INPUT; for (i = 0; i < indices; i++) { snd_iprintf(buffer, " ["); + val = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_AMP_GAIN_MUTE, + AC_AMP_GET_LEFT | dir | i); + snd_iprintf(buffer, "0x%02x", val); if (stereo) { val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_AMP_GAIN_MUTE, - AC_AMP_GET_LEFT | dir | i); - snd_iprintf(buffer, "0x%02x ", val); + AC_AMP_GET_RIGHT | dir | i); + snd_iprintf(buffer, " 0x%02x", val); } - val = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_AMP_GAIN_MUTE, - AC_AMP_GET_RIGHT | dir | i); - snd_iprintf(buffer, "0x%02x]", val); + snd_iprintf(buffer, "]"); } snd_iprintf(buffer, "\n"); } @@ -603,6 +604,8 @@ static void print_codec_info(struct snd_info_entry *entry, print_amp_caps(buffer, codec, codec->afg, HDA_INPUT); snd_iprintf(buffer, "Default Amp-Out caps: "); print_amp_caps(buffer, codec, codec->afg, HDA_OUTPUT); + snd_iprintf(buffer, "State of AFG node 0x%02x:\n", codec->afg); + print_power_state(buffer, codec, codec->afg); nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid); if (! nid || nodes < 0) { diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 1eeba7386666..df8014b27596 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -20,7 +20,6 @@ */ #include <linux/init.h> -#include <linux/delay.h> #include <linux/slab.h> #include <linux/pci.h> #include <linux/module.h> @@ -31,11 +30,24 @@ #include "hda_auto_parser.h" #include "hda_beep.h" #include "hda_jack.h" +#include "hda_generic.h" + +#define ENABLE_AD_STATIC_QUIRKS struct ad198x_spec { + struct hda_gen_spec gen; + + /* for auto parser */ + int smux_paths[4]; + unsigned int cur_smux; + hda_nid_t eapd_nid; + + unsigned int beep_amp; /* beep amp value, set via set_beep_amp() */ + hda_nid_t beep_dev_nid; + +#ifdef ENABLE_AD_STATIC_QUIRKS const struct snd_kcontrol_new *mixers[6]; int num_mixers; - unsigned int beep_amp; /* beep amp value, set via set_beep_amp() */ const struct hda_verb *init_verbs[6]; /* initialization verbs * don't forget NULL termination! */ @@ -49,11 +61,6 @@ struct ad198x_spec { unsigned int cur_eapd; unsigned int need_dac_fix; - const hda_nid_t *alt_dac_nid; - const struct hda_pcm_stream *stream_analog_alt_playback; - int independent_hp; - int num_active_streams; - /* capture */ unsigned int num_adc_nids; const hda_nid_t *adc_nids; @@ -73,15 +80,8 @@ struct ad198x_spec { unsigned int spdif_route; - /* dynamic controls, init_verbs and input_mux */ - struct auto_pin_cfg autocfg; - struct snd_array kctls; - struct hda_input_mux private_imux; - hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS]; - unsigned int jack_present: 1; unsigned int inv_jack_detect: 1;/* inverted jack-detection */ - unsigned int inv_eapd: 1; /* inverted EAPD implementation */ unsigned int analog_beep: 1; /* analog beep input present */ unsigned int avoid_init_slave_vol:1; @@ -92,8 +92,10 @@ struct ad198x_spec { hda_nid_t vmaster_nid; const char * const *slave_vols; const char * const *slave_sws; +#endif /* ENABLE_AD_STATIC_QUIRKS */ }; +#ifdef ENABLE_AD_STATIC_QUIRKS /* * input MUX handling (common part) */ @@ -149,8 +151,7 @@ static const char * const ad1988_6stack_fp_slave_pfxs[] = { "Front", "Surround", "Center", "LFE", "Side", "IEC958", NULL }; - -static void ad198x_free_kctls(struct hda_codec *codec); +#endif /* ENABLE_AD_STATIC_QUIRKS */ #ifdef CONFIG_SND_HDA_INPUT_BEEP /* additional beep mixers; the actual parameters are overwritten at build */ @@ -172,6 +173,34 @@ static const struct snd_kcontrol_new ad_beep2_mixer[] = { #define set_beep_amp(spec, nid, idx, dir) /* NOP */ #endif +#ifdef CONFIG_SND_HDA_INPUT_BEEP +static int create_beep_ctls(struct hda_codec *codec) +{ + struct ad198x_spec *spec = codec->spec; + const struct snd_kcontrol_new *knew; + + if (!spec->beep_amp) + return 0; + + knew = spec->analog_beep ? ad_beep2_mixer : ad_beep_mixer; + for ( ; knew->name; knew++) { + int err; + struct snd_kcontrol *kctl; + kctl = snd_ctl_new1(knew, codec); + if (!kctl) + return -ENOMEM; + kctl->private_value = spec->beep_amp; + err = snd_hda_ctl_add(codec, 0, kctl); + if (err < 0) + return err; + } + return 0; +} +#else +#define create_beep_ctls(codec) 0 +#endif + +#ifdef ENABLE_AD_STATIC_QUIRKS static int ad198x_build_controls(struct hda_codec *codec) { struct ad198x_spec *spec = codec->spec; @@ -203,22 +232,9 @@ static int ad198x_build_controls(struct hda_codec *codec) } /* create beep controls if needed */ -#ifdef CONFIG_SND_HDA_INPUT_BEEP - if (spec->beep_amp) { - const struct snd_kcontrol_new *knew; - knew = spec->analog_beep ? ad_beep2_mixer : ad_beep_mixer; - for ( ; knew->name; knew++) { - struct snd_kcontrol *kctl; - kctl = snd_ctl_new1(knew, codec); - if (!kctl) - return -ENOMEM; - kctl->private_value = spec->beep_amp; - err = snd_hda_ctl_add(codec, 0, kctl); - if (err < 0) - return err; - } - } -#endif + err = create_beep_ctls(codec); + if (err < 0) + return err; /* if we have no master control, let's create it */ if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) { @@ -244,8 +260,6 @@ static int ad198x_build_controls(struct hda_codec *codec) return err; } - ad198x_free_kctls(codec); /* no longer needed */ - /* assign Capture Source enums to NID */ kctl = snd_hda_find_mixer_ctl(codec, "Capture Source"); if (!kctl) @@ -277,72 +291,6 @@ static int ad198x_check_power_status(struct hda_codec *codec, hda_nid_t nid) } #endif -static void activate_ctl(struct hda_codec *codec, const char *name, int active) -{ - struct snd_kcontrol *ctl = snd_hda_find_mixer_ctl(codec, name); - if (ctl) { - ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE; - ctl->vd[0].access |= active ? 0 : - SNDRV_CTL_ELEM_ACCESS_INACTIVE; - ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_WRITE; - ctl->vd[0].access |= active ? - SNDRV_CTL_ELEM_ACCESS_WRITE : 0; - snd_ctl_notify(codec->bus->card, - SNDRV_CTL_EVENT_MASK_INFO, &ctl->id); - } -} - -static void set_stream_active(struct hda_codec *codec, bool active) -{ - struct ad198x_spec *spec = codec->spec; - if (active) - spec->num_active_streams++; - else - spec->num_active_streams--; - activate_ctl(codec, "Independent HP", spec->num_active_streams == 0); -} - -static int ad1988_independent_hp_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - static const char * const texts[] = { "OFF", "ON", NULL}; - int index; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 2; - index = uinfo->value.enumerated.item; - if (index >= 2) - index = 1; - strcpy(uinfo->value.enumerated.name, texts[index]); - return 0; -} - -static int ad1988_independent_hp_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ad198x_spec *spec = codec->spec; - ucontrol->value.enumerated.item[0] = spec->independent_hp; - return 0; -} - -static int ad1988_independent_hp_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ad198x_spec *spec = codec->spec; - unsigned int select = ucontrol->value.enumerated.item[0]; - if (spec->independent_hp != select) { - spec->independent_hp = select; - if (spec->independent_hp) - spec->multiout.hp_nid = 0; - else - spec->multiout.hp_nid = spec->alt_dac_nid[0]; - return 1; - } - return 0; -} - /* * Analog playback callbacks */ @@ -351,15 +299,8 @@ static int ad198x_playback_pcm_open(struct hda_pcm_stream *hinfo, struct snd_pcm_substream *substream) { struct ad198x_spec *spec = codec->spec; - int err; - set_stream_active(codec, true); - err = snd_hda_multi_out_analog_open(codec, &spec->multiout, substream, + return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream, hinfo); - if (err < 0) { - set_stream_active(codec, false); - return err; - } - return 0; } static int ad198x_playback_pcm_prepare(struct hda_pcm_stream *hinfo, @@ -381,43 +322,6 @@ static int ad198x_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); } -static int ad198x_playback_pcm_close(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - set_stream_active(codec, false); - return 0; -} - -static int ad1988_alt_playback_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct ad198x_spec *spec = codec->spec; - if (!spec->independent_hp) - return -EBUSY; - set_stream_active(codec, true); - return 0; -} - -static int ad1988_alt_playback_pcm_close(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - set_stream_active(codec, false); - return 0; -} - -static const struct hda_pcm_stream ad198x_pcm_analog_alt_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - .ops = { - .open = ad1988_alt_playback_pcm_open, - .close = ad1988_alt_playback_pcm_close - }, -}; - /* * Digital out */ @@ -491,7 +395,6 @@ static const struct hda_pcm_stream ad198x_pcm_analog_playback = { .open = ad198x_playback_pcm_open, .prepare = ad198x_playback_pcm_prepare, .cleanup = ad198x_playback_pcm_cleanup, - .close = ad198x_playback_pcm_close }, }; @@ -556,43 +459,19 @@ static int ad198x_build_pcms(struct hda_codec *codec) } } - if (spec->alt_dac_nid && spec->stream_analog_alt_playback) { - codec->num_pcms++; - info = spec->pcm_rec + 2; - info->name = "AD198x Headphone"; - info->pcm_type = HDA_PCM_TYPE_AUDIO; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = - *spec->stream_analog_alt_playback; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = - spec->alt_dac_nid[0]; - } - return 0; } - -static void ad198x_free_kctls(struct hda_codec *codec) -{ - struct ad198x_spec *spec = codec->spec; - - if (spec->kctls.list) { - struct snd_kcontrol_new *kctl = spec->kctls.list; - int i; - for (i = 0; i < spec->kctls.used; i++) - kfree(kctl[i].name); - } - snd_array_free(&spec->kctls); -} +#endif /* ENABLE_AD_STATIC_QUIRKS */ static void ad198x_power_eapd_write(struct hda_codec *codec, hda_nid_t front, hda_nid_t hp) { - struct ad198x_spec *spec = codec->spec; if (snd_hda_query_pin_caps(codec, front) & AC_PINCAP_EAPD) snd_hda_codec_write(codec, front, 0, AC_VERB_SET_EAPD_BTLENABLE, - !spec->inv_eapd ? 0x00 : 0x02); + !codec->inv_eapd ? 0x00 : 0x02); if (snd_hda_query_pin_caps(codec, hp) & AC_PINCAP_EAPD) snd_hda_codec_write(codec, hp, 0, AC_VERB_SET_EAPD_BTLENABLE, - !spec->inv_eapd ? 0x00 : 0x02); + !codec->inv_eapd ? 0x00 : 0x02); } static void ad198x_power_eapd(struct hda_codec *codec) @@ -636,8 +515,7 @@ static void ad198x_free(struct hda_codec *codec) if (!spec) return; - ad198x_shutup(codec); - ad198x_free_kctls(codec); + snd_hda_gen_spec_free(&spec->gen); kfree(spec); snd_hda_detach_beep_device(codec); } @@ -650,6 +528,7 @@ static int ad198x_suspend(struct hda_codec *codec) } #endif +#ifdef ENABLE_AD_STATIC_QUIRKS static const struct hda_codec_ops ad198x_patch_ops = { .build_controls = ad198x_build_controls, .build_pcms = ad198x_build_pcms, @@ -674,7 +553,7 @@ static int ad198x_eapd_get(struct snd_kcontrol *kcontrol, { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct ad198x_spec *spec = codec->spec; - if (spec->inv_eapd) + if (codec->inv_eapd) ucontrol->value.integer.value[0] = ! spec->cur_eapd; else ucontrol->value.integer.value[0] = spec->cur_eapd; @@ -689,7 +568,7 @@ static int ad198x_eapd_put(struct snd_kcontrol *kcontrol, hda_nid_t nid = kcontrol->private_value & 0xff; unsigned int eapd; eapd = !!ucontrol->value.integer.value[0]; - if (spec->inv_eapd) + if (codec->inv_eapd) eapd = !eapd; if (eapd == spec->cur_eapd) return 0; @@ -706,12 +585,75 @@ static int ad198x_ch_mode_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); +#endif /* ENABLE_AD_STATIC_QUIRKS */ + + +/* + * Automatic parse of I/O pins from the BIOS configuration + */ + +static int ad198x_auto_build_controls(struct hda_codec *codec) +{ + int err; + + err = snd_hda_gen_build_controls(codec); + if (err < 0) + return err; + err = create_beep_ctls(codec); + if (err < 0) + return err; + return 0; +} + +static const struct hda_codec_ops ad198x_auto_patch_ops = { + .build_controls = ad198x_auto_build_controls, + .build_pcms = snd_hda_gen_build_pcms, + .init = snd_hda_gen_init, + .free = ad198x_free, + .unsol_event = snd_hda_jack_unsol_event, +#ifdef CONFIG_PM + .check_power_status = snd_hda_gen_check_power_status, + .suspend = ad198x_suspend, +#endif + .reboot_notify = ad198x_shutup, +}; + + +static int ad198x_parse_auto_config(struct hda_codec *codec) +{ + struct ad198x_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->gen.autocfg; + int err; + + codec->spdif_status_reset = 1; + codec->no_trigger_sense = 1; + codec->no_sticky_stream = 1; + + spec->gen.indep_hp = 1; + + err = snd_hda_parse_pin_defcfg(codec, cfg, NULL, 0); + if (err < 0) + return err; + err = snd_hda_gen_parse_auto_config(codec, cfg); + if (err < 0) + return err; + + if (spec->beep_dev_nid) { + err = snd_hda_attach_beep_device(codec, spec->beep_dev_nid); + if (err < 0) + return err; + } + codec->patch_ops = ad198x_auto_patch_ops; + + return 0; +} /* * AD1986A specific */ +#ifdef ENABLE_AD_STATIC_QUIRKS #define AD1986A_SPDIF_OUT 0x02 #define AD1986A_FRONT_DAC 0x03 #define AD1986A_SURR_DAC 0x04 @@ -996,15 +938,7 @@ static int ad1986a_hp_master_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - long *valp = ucontrol->value.integer.value; - int change; - - change = snd_hda_codec_amp_update(codec, 0x1a, 0, HDA_OUTPUT, 0, - HDA_AMP_MUTE, - valp[0] ? 0 : HDA_AMP_MUTE); - change |= snd_hda_codec_amp_update(codec, 0x1a, 1, HDA_OUTPUT, 0, - HDA_AMP_MUTE, - valp[1] ? 0 : HDA_AMP_MUTE); + int change = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); if (change) ad1986a_update_hp(codec); return change; @@ -1177,6 +1111,7 @@ static int ad1986a_samsung_p50_init(struct hda_codec *codec) /* models */ enum { + AD1986A_AUTO, AD1986A_6STACK, AD1986A_3STACK, AD1986A_LAPTOP, @@ -1189,6 +1124,7 @@ enum { }; static const char * const ad1986a_models[AD1986A_MODELS] = { + [AD1986A_AUTO] = "auto", [AD1986A_6STACK] = "6stack", [AD1986A_3STACK] = "3stack", [AD1986A_LAPTOP] = "laptop", @@ -1246,17 +1182,111 @@ static int is_jack_available(struct hda_codec *codec, hda_nid_t nid) unsigned int conf = snd_hda_codec_get_pincfg(codec, nid); return get_defcfg_connect(conf) != AC_JACK_PORT_NONE; } +#endif /* ENABLE_AD_STATIC_QUIRKS */ -static int patch_ad1986a(struct hda_codec *codec) +static int alloc_ad_spec(struct hda_codec *codec) { struct ad198x_spec *spec; - int err, board_config; spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) + if (!spec) return -ENOMEM; - codec->spec = spec; + snd_hda_gen_spec_init(&spec->gen); + return 0; +} + +/* + * AD1986A fixup codes + */ + +/* Lenovo N100 seems to report the reversed bit for HP jack-sensing */ +static void ad_fixup_inv_jack_detect(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + if (action == HDA_FIXUP_ACT_PRE_PROBE) + codec->inv_jack_detect = 1; +} + +enum { + AD1986A_FIXUP_INV_JACK_DETECT, +}; + +static const struct hda_fixup ad1986a_fixups[] = { + [AD1986A_FIXUP_INV_JACK_DETECT] = { + .type = HDA_FIXUP_FUNC, + .v.func = ad_fixup_inv_jack_detect, + }, +}; + +static const struct snd_pci_quirk ad1986a_fixup_tbl[] = { + SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo N100", AD1986A_FIXUP_INV_JACK_DETECT), + {} +}; + +/* + */ +static int ad1986a_parse_auto_config(struct hda_codec *codec) +{ + int err; + struct ad198x_spec *spec; + + err = alloc_ad_spec(codec); + if (err < 0) + return err; + spec = codec->spec; + + /* AD1986A has the inverted EAPD implementation */ + codec->inv_eapd = 1; + + spec->gen.mixer_nid = 0x07; + spec->beep_dev_nid = 0x19; + set_beep_amp(spec, 0x18, 0, HDA_OUTPUT); + + /* AD1986A has a hardware problem that it can't share a stream + * with multiple output pins. The copy of front to surrounds + * causes noisy or silent outputs at a certain timing, e.g. + * changing the volume. + * So, let's disable the shared stream. + */ + spec->gen.multiout.no_share_stream = 1; + + snd_hda_pick_fixup(codec, NULL, ad1986a_fixup_tbl, ad1986a_fixups); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); + + err = ad198x_parse_auto_config(codec); + if (err < 0) { + ad198x_free(codec); + return err; + } + + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); + + return 0; +} + +#ifdef ENABLE_AD_STATIC_QUIRKS +static int patch_ad1986a(struct hda_codec *codec) +{ + struct ad198x_spec *spec; + int err, board_config; + + board_config = snd_hda_check_board_config(codec, AD1986A_MODELS, + ad1986a_models, + ad1986a_cfg_tbl); + if (board_config < 0) { + printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", + codec->chip_name); + board_config = AD1986A_AUTO; + } + + if (board_config == AD1986A_AUTO) + return ad1986a_parse_auto_config(codec); + + err = alloc_ad_spec(codec); + if (err < 0) + return err; + spec = codec->spec; err = snd_hda_attach_beep_device(codec, 0x19); if (err < 0) { @@ -1281,14 +1311,11 @@ static int patch_ad1986a(struct hda_codec *codec) spec->loopback.amplist = ad1986a_loopbacks; #endif spec->vmaster_nid = 0x1b; - spec->inv_eapd = 1; /* AD1986A has the inverted EAPD implementation */ + codec->inv_eapd = 1; /* AD1986A has the inverted EAPD implementation */ codec->patch_ops = ad198x_patch_ops; /* override some parameters */ - board_config = snd_hda_check_board_config(codec, AD1986A_MODELS, - ad1986a_models, - ad1986a_cfg_tbl); switch (board_config) { case AD1986A_3STACK: spec->num_mixers = 2; @@ -1399,11 +1426,15 @@ static int patch_ad1986a(struct hda_codec *codec) return 0; } +#else /* ENABLE_AD_STATIC_QUIRKS */ +#define patch_ad1986a ad1986a_parse_auto_config +#endif /* ENABLE_AD_STATIC_QUIRKS */ /* * AD1983 specific */ +#ifdef ENABLE_AD_STATIC_QUIRKS #define AD1983_SPDIF_OUT 0x02 #define AD1983_DAC 0x03 #define AD1983_ADC 0x04 @@ -1544,16 +1575,141 @@ static const struct hda_amp_list ad1983_loopbacks[] = { }; #endif +/* models */ +enum { + AD1983_AUTO, + AD1983_BASIC, + AD1983_MODELS +}; + +static const char * const ad1983_models[AD1983_MODELS] = { + [AD1983_AUTO] = "auto", + [AD1983_BASIC] = "basic", +}; +#endif /* ENABLE_AD_STATIC_QUIRKS */ + + +/* + * SPDIF mux control for AD1983 auto-parser + */ +static int ad1983_auto_smux_enum_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct ad198x_spec *spec = codec->spec; + static const char * const texts2[] = { "PCM", "ADC" }; + static const char * const texts3[] = { "PCM", "ADC1", "ADC2" }; + hda_nid_t dig_out = spec->gen.multiout.dig_out_nid; + int num_conns = snd_hda_get_num_conns(codec, dig_out); + + if (num_conns == 2) + return snd_hda_enum_helper_info(kcontrol, uinfo, 2, texts2); + else if (num_conns == 3) + return snd_hda_enum_helper_info(kcontrol, uinfo, 3, texts3); + else + return -EINVAL; +} + +static int ad1983_auto_smux_enum_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct ad198x_spec *spec = codec->spec; + + ucontrol->value.enumerated.item[0] = spec->cur_smux; + return 0; +} + +static int ad1983_auto_smux_enum_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct ad198x_spec *spec = codec->spec; + unsigned int val = ucontrol->value.enumerated.item[0]; + hda_nid_t dig_out = spec->gen.multiout.dig_out_nid; + int num_conns = snd_hda_get_num_conns(codec, dig_out); + + if (val >= num_conns) + return -EINVAL; + if (spec->cur_smux == val) + return 0; + spec->cur_smux = val; + snd_hda_codec_write_cache(codec, dig_out, 0, + AC_VERB_SET_CONNECT_SEL, val); + return 1; +} + +static struct snd_kcontrol_new ad1983_auto_smux_mixer = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "IEC958 Playback Source", + .info = ad1983_auto_smux_enum_info, + .get = ad1983_auto_smux_enum_get, + .put = ad1983_auto_smux_enum_put, +}; + +static int ad1983_add_spdif_mux_ctl(struct hda_codec *codec) +{ + struct ad198x_spec *spec = codec->spec; + hda_nid_t dig_out = spec->gen.multiout.dig_out_nid; + int num_conns; + + if (!dig_out) + return 0; + num_conns = snd_hda_get_num_conns(codec, dig_out); + if (num_conns != 2 && num_conns != 3) + return 0; + if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &ad1983_auto_smux_mixer)) + return -ENOMEM; + return 0; +} + +static int ad1983_parse_auto_config(struct hda_codec *codec) +{ + struct ad198x_spec *spec; + int err; + + err = alloc_ad_spec(codec); + if (err < 0) + return err; + spec = codec->spec; + + spec->beep_dev_nid = 0x10; + set_beep_amp(spec, 0x10, 0, HDA_OUTPUT); + err = ad198x_parse_auto_config(codec); + if (err < 0) + goto error; + err = ad1983_add_spdif_mux_ctl(codec); + if (err < 0) + goto error; + return 0; + + error: + ad198x_free(codec); + return err; +} + +#ifdef ENABLE_AD_STATIC_QUIRKS static int patch_ad1983(struct hda_codec *codec) { struct ad198x_spec *spec; + int board_config; int err; - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; + board_config = snd_hda_check_board_config(codec, AD1983_MODELS, + ad1983_models, NULL); + if (board_config < 0) { + printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", + codec->chip_name); + board_config = AD1983_AUTO; + } - codec->spec = spec; + if (board_config == AD1983_AUTO) + return ad1983_parse_auto_config(codec); + + err = alloc_ad_spec(codec); + if (err < 0) + return err; + spec = codec->spec; err = snd_hda_attach_beep_device(codec, 0x10); if (err < 0) { @@ -1587,12 +1743,16 @@ static int patch_ad1983(struct hda_codec *codec) return 0; } +#else /* ENABLE_AD_STATIC_QUIRKS */ +#define patch_ad1983 ad1983_parse_auto_config +#endif /* ENABLE_AD_STATIC_QUIRKS */ /* * AD1981 HD specific */ +#ifdef ENABLE_AD_STATIC_QUIRKS #define AD1981_SPDIF_OUT 0x02 #define AD1981_DAC 0x03 #define AD1981_ADC 0x04 @@ -1923,6 +2083,7 @@ static const struct hda_input_mux ad1981_thinkpad_capture_source = { /* models */ enum { + AD1981_AUTO, AD1981_BASIC, AD1981_HP, AD1981_THINKPAD, @@ -1931,6 +2092,7 @@ enum { }; static const char * const ad1981_models[AD1981_MODELS] = { + [AD1981_AUTO] = "auto", [AD1981_HP] = "hp", [AD1981_THINKPAD] = "thinkpad", [AD1981_BASIC] = "basic", @@ -1949,17 +2111,126 @@ static const struct snd_pci_quirk ad1981_cfg_tbl[] = { SND_PCI_QUIRK(0x30b0, 0x103c, "HP nx6320", AD1981_HP), {} }; +#endif /* ENABLE_AD_STATIC_QUIRKS */ + + +/* follow EAPD via vmaster hook */ +static void ad_vmaster_eapd_hook(void *private_data, int enabled) +{ + struct hda_codec *codec = private_data; + struct ad198x_spec *spec = codec->spec; + snd_hda_codec_update_cache(codec, spec->eapd_nid, 0, + AC_VERB_SET_EAPD_BTLENABLE, + enabled ? 0x02 : 0x00); +} + +static void ad1981_fixup_hp_eapd(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct ad198x_spec *spec = codec->spec; + + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + spec->gen.vmaster_mute.hook = ad_vmaster_eapd_hook; + spec->eapd_nid = 0x05; + } +} + +/* set the upper-limit for mixer amp to 0dB for avoiding the possible + * damage by overloading + */ +static void ad1981_fixup_amp_override(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + if (action == HDA_FIXUP_ACT_PRE_PROBE) + snd_hda_override_amp_caps(codec, 0x11, HDA_INPUT, + (0x17 << AC_AMPCAP_OFFSET_SHIFT) | + (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) | + (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) | + (1 << AC_AMPCAP_MUTE_SHIFT)); +} + +enum { + AD1981_FIXUP_AMP_OVERRIDE, + AD1981_FIXUP_HP_EAPD, +}; + +static const struct hda_fixup ad1981_fixups[] = { + [AD1981_FIXUP_AMP_OVERRIDE] = { + .type = HDA_FIXUP_FUNC, + .v.func = ad1981_fixup_amp_override, + }, + [AD1981_FIXUP_HP_EAPD] = { + .type = HDA_FIXUP_FUNC, + .v.func = ad1981_fixup_hp_eapd, + .chained = true, + .chain_id = AD1981_FIXUP_AMP_OVERRIDE, + }, +}; + +static const struct snd_pci_quirk ad1981_fixup_tbl[] = { + SND_PCI_QUIRK_VENDOR(0x1014, "Lenovo", AD1981_FIXUP_AMP_OVERRIDE), + SND_PCI_QUIRK_VENDOR(0x103c, "HP", AD1981_FIXUP_HP_EAPD), + SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", AD1981_FIXUP_AMP_OVERRIDE), + /* HP nx6320 (reversed SSID, H/W bug) */ + SND_PCI_QUIRK(0x30b0, 0x103c, "HP nx6320", AD1981_FIXUP_HP_EAPD), + {} +}; + +static int ad1981_parse_auto_config(struct hda_codec *codec) +{ + struct ad198x_spec *spec; + int err; + err = alloc_ad_spec(codec); + if (err < 0) + return -ENOMEM; + spec = codec->spec; + + spec->gen.mixer_nid = 0x0e; + spec->beep_dev_nid = 0x10; + set_beep_amp(spec, 0x0d, 0, HDA_OUTPUT); + + snd_hda_pick_fixup(codec, NULL, ad1981_fixup_tbl, ad1981_fixups); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); + + err = ad198x_parse_auto_config(codec); + if (err < 0) + goto error; + err = ad1983_add_spdif_mux_ctl(codec); + if (err < 0) + goto error; + + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); + + return 0; + + error: + ad198x_free(codec); + return err; +} + +#ifdef ENABLE_AD_STATIC_QUIRKS static int patch_ad1981(struct hda_codec *codec) { struct ad198x_spec *spec; int err, board_config; - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; + board_config = snd_hda_check_board_config(codec, AD1981_MODELS, + ad1981_models, + ad1981_cfg_tbl); + if (board_config < 0) { + printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", + codec->chip_name); + board_config = AD1981_AUTO; + } - codec->spec = spec; + if (board_config == AD1981_AUTO) + return ad1981_parse_auto_config(codec); + + err = alloc_ad_spec(codec); + if (err < 0) + return -ENOMEM; + spec = codec->spec; err = snd_hda_attach_beep_device(codec, 0x10); if (err < 0) { @@ -1989,9 +2260,6 @@ static int patch_ad1981(struct hda_codec *codec) codec->patch_ops = ad198x_patch_ops; /* override some parameters */ - board_config = snd_hda_check_board_config(codec, AD1981_MODELS, - ad1981_models, - ad1981_cfg_tbl); switch (board_config) { case AD1981_HP: spec->mixers[0] = ad1981_hp_mixers; @@ -2041,6 +2309,9 @@ static int patch_ad1981(struct hda_codec *codec) return 0; } +#else /* ENABLE_AD_STATIC_QUIRKS */ +#define patch_ad1981 ad1981_parse_auto_config +#endif /* ENABLE_AD_STATIC_QUIRKS */ /* @@ -2129,15 +2400,16 @@ static int patch_ad1981(struct hda_codec *codec) */ +#ifdef ENABLE_AD_STATIC_QUIRKS /* models */ enum { + AD1988_AUTO, AD1988_6STACK, AD1988_6STACK_DIG, AD1988_3STACK, AD1988_3STACK_DIG, AD1988_LAPTOP, AD1988_LAPTOP_DIG, - AD1988_AUTO, AD1988_MODEL_LAST, }; @@ -2242,17 +2514,6 @@ static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol, return err; } -static const struct snd_kcontrol_new ad1988_hp_mixers[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Independent HP", - .info = ad1988_independent_hp_info, - .get = ad1988_independent_hp_get, - .put = ad1988_independent_hp_put, - }, - { } /* end */ -}; - /* 6-stack mode */ static const struct snd_kcontrol_new ad1988_6stack_mixers1[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT), @@ -2815,422 +3076,185 @@ static const struct hda_amp_list ad1988_loopbacks[] = { { } /* end */ }; #endif +#endif /* ENABLE_AD_STATIC_QUIRKS */ -/* - * Automatic parse of I/O pins from the BIOS configuration - */ - -enum { - AD_CTL_WIDGET_VOL, - AD_CTL_WIDGET_MUTE, - AD_CTL_BIND_MUTE, -}; -static const struct snd_kcontrol_new ad1988_control_templates[] = { - HDA_CODEC_VOLUME(NULL, 0, 0, 0), - HDA_CODEC_MUTE(NULL, 0, 0, 0), - HDA_BIND_MUTE(NULL, 0, 0, 0), -}; - -/* add dynamic controls */ -static int add_control(struct ad198x_spec *spec, int type, const char *name, - unsigned long val) -{ - struct snd_kcontrol_new *knew; - - snd_array_init(&spec->kctls, sizeof(*knew), 32); - knew = snd_array_new(&spec->kctls); - if (!knew) - return -ENOMEM; - *knew = ad1988_control_templates[type]; - knew->name = kstrdup(name, GFP_KERNEL); - if (! knew->name) - return -ENOMEM; - if (get_amp_nid_(val)) - knew->subdevice = HDA_SUBDEV_AMP_FLAG; - knew->private_value = val; - return 0; -} - -#define AD1988_PIN_CD_NID 0x18 -#define AD1988_PIN_BEEP_NID 0x10 - -static const hda_nid_t ad1988_mixer_nids[8] = { - /* A B C D E F G H */ - 0x22, 0x2b, 0x2c, 0x29, 0x26, 0x2a, 0x27, 0x28 -}; - -static inline hda_nid_t ad1988_idx_to_dac(struct hda_codec *codec, int idx) -{ - static const hda_nid_t idx_to_dac[8] = { - /* A B C D E F G H */ - 0x03, 0x06, 0x05, 0x04, 0x0a, 0x06, 0x05, 0x0a - }; - static const hda_nid_t idx_to_dac_rev2[8] = { - /* A B C D E F G H */ - 0x03, 0x05, 0x0a, 0x04, 0x06, 0x05, 0x0a, 0x06 - }; - if (is_rev2(codec)) - return idx_to_dac_rev2[idx]; - else - return idx_to_dac[idx]; -} - -static const hda_nid_t ad1988_boost_nids[8] = { - 0x38, 0x39, 0x3a, 0x3d, 0x3c, 0x3b, 0, 0 -}; - -static int ad1988_pin_idx(hda_nid_t nid) -{ - static const hda_nid_t ad1988_io_pins[8] = { - 0x11, 0x14, 0x15, 0x12, 0x17, 0x16, 0x24, 0x25 - }; - int i; - for (i = 0; i < ARRAY_SIZE(ad1988_io_pins); i++) - if (ad1988_io_pins[i] == nid) - return i; - return 0; /* should be -1 */ -} - -static int ad1988_pin_to_loopback_idx(hda_nid_t nid) -{ - static const int loopback_idx[8] = { - 2, 0, 1, 3, 4, 5, 1, 4 - }; - switch (nid) { - case AD1988_PIN_CD_NID: - return 6; - default: - return loopback_idx[ad1988_pin_idx(nid)]; - } -} - -static int ad1988_pin_to_adc_idx(hda_nid_t nid) +static int ad1988_auto_smux_enum_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) { - static const int adc_idx[8] = { - 0, 1, 2, 8, 4, 3, 6, 7 + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + static const char * const texts[] = { + "PCM", "ADC1", "ADC2", "ADC3", }; - switch (nid) { - case AD1988_PIN_CD_NID: - return 5; - default: - return adc_idx[ad1988_pin_idx(nid)]; - } + int num_conns = snd_hda_get_num_conns(codec, 0x0b) + 1; + if (num_conns > 4) + num_conns = 4; + return snd_hda_enum_helper_info(kcontrol, uinfo, num_conns, texts); } -/* fill in the dac_nids table from the parsed pin configuration */ -static int ad1988_auto_fill_dac_nids(struct hda_codec *codec, - const struct auto_pin_cfg *cfg) +static int ad1988_auto_smux_enum_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct ad198x_spec *spec = codec->spec; - int i, idx; - - spec->multiout.dac_nids = spec->private_dac_nids; - - /* check the pins hardwired to audio widget */ - for (i = 0; i < cfg->line_outs; i++) { - idx = ad1988_pin_idx(cfg->line_out_pins[i]); - spec->private_dac_nids[i] = ad1988_idx_to_dac(codec, idx); - } - spec->multiout.num_dacs = cfg->line_outs; - return 0; -} - -/* add playback controls from the parsed DAC table */ -static int ad1988_auto_create_multi_out_ctls(struct ad198x_spec *spec, - const struct auto_pin_cfg *cfg) -{ - char name[32]; - static const char * const chname[4] = { - "Front", "Surround", NULL /*CLFE*/, "Side" - }; - hda_nid_t nid; - int i, err; - for (i = 0; i < cfg->line_outs; i++) { - hda_nid_t dac = spec->multiout.dac_nids[i]; - if (! dac) - continue; - nid = ad1988_mixer_nids[ad1988_pin_idx(cfg->line_out_pins[i])]; - if (i == 2) { - /* Center/LFE */ - err = add_control(spec, AD_CTL_WIDGET_VOL, - "Center Playback Volume", - HDA_COMPOSE_AMP_VAL(dac, 1, 0, HDA_OUTPUT)); - if (err < 0) - return err; - err = add_control(spec, AD_CTL_WIDGET_VOL, - "LFE Playback Volume", - HDA_COMPOSE_AMP_VAL(dac, 2, 0, HDA_OUTPUT)); - if (err < 0) - return err; - err = add_control(spec, AD_CTL_BIND_MUTE, - "Center Playback Switch", - HDA_COMPOSE_AMP_VAL(nid, 1, 2, HDA_INPUT)); - if (err < 0) - return err; - err = add_control(spec, AD_CTL_BIND_MUTE, - "LFE Playback Switch", - HDA_COMPOSE_AMP_VAL(nid, 2, 2, HDA_INPUT)); - if (err < 0) - return err; - } else { - sprintf(name, "%s Playback Volume", chname[i]); - err = add_control(spec, AD_CTL_WIDGET_VOL, name, - HDA_COMPOSE_AMP_VAL(dac, 3, 0, HDA_OUTPUT)); - if (err < 0) - return err; - sprintf(name, "%s Playback Switch", chname[i]); - err = add_control(spec, AD_CTL_BIND_MUTE, name, - HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT)); - if (err < 0) - return err; - } - } + ucontrol->value.enumerated.item[0] = spec->cur_smux; return 0; } -/* add playback controls for speaker and HP outputs */ -static int ad1988_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin, - const char *pfx) +static int ad1988_auto_smux_enum_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct ad198x_spec *spec = codec->spec; - hda_nid_t nid; - int i, idx, err; - char name[32]; + unsigned int val = ucontrol->value.enumerated.item[0]; + struct nid_path *path; + int num_conns = snd_hda_get_num_conns(codec, 0x0b) + 1; - if (! pin) + if (val >= num_conns) + return -EINVAL; + if (spec->cur_smux == val) return 0; - idx = ad1988_pin_idx(pin); - nid = ad1988_idx_to_dac(codec, idx); - /* check whether the corresponding DAC was already taken */ - for (i = 0; i < spec->autocfg.line_outs; i++) { - hda_nid_t pin = spec->autocfg.line_out_pins[i]; - hda_nid_t dac = ad1988_idx_to_dac(codec, ad1988_pin_idx(pin)); - if (dac == nid) - break; - } - if (i >= spec->autocfg.line_outs) { - /* specify the DAC as the extra output */ - if (!spec->multiout.hp_nid) - spec->multiout.hp_nid = nid; - else - spec->multiout.extra_out_nid[0] = nid; - /* control HP volume/switch on the output mixer amp */ - sprintf(name, "%s Playback Volume", pfx); - err = add_control(spec, AD_CTL_WIDGET_VOL, name, - HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT)); - if (err < 0) - return err; - } - nid = ad1988_mixer_nids[idx]; - sprintf(name, "%s Playback Switch", pfx); - if ((err = add_control(spec, AD_CTL_BIND_MUTE, name, - HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT))) < 0) - return err; - return 0; + mutex_lock(&codec->control_mutex); + codec->cached_write = 1; + path = snd_hda_get_path_from_idx(codec, + spec->smux_paths[spec->cur_smux]); + if (path) + snd_hda_activate_path(codec, path, false, true); + path = snd_hda_get_path_from_idx(codec, spec->smux_paths[val]); + if (path) + snd_hda_activate_path(codec, path, true, true); + spec->cur_smux = val; + codec->cached_write = 0; + mutex_unlock(&codec->control_mutex); + snd_hda_codec_flush_cache(codec); /* flush the updates */ + return 1; } -/* create input playback/capture controls for the given pin */ -static int new_analog_input(struct ad198x_spec *spec, hda_nid_t pin, - const char *ctlname, int ctlidx, int boost) +static struct snd_kcontrol_new ad1988_auto_smux_mixer = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "IEC958 Playback Source", + .info = ad1988_auto_smux_enum_info, + .get = ad1988_auto_smux_enum_get, + .put = ad1988_auto_smux_enum_put, +}; + +static int ad1988_auto_init(struct hda_codec *codec) { - char name[32]; - int err, idx; + struct ad198x_spec *spec = codec->spec; + int i, err; - sprintf(name, "%s Playback Volume", ctlname); - idx = ad1988_pin_to_loopback_idx(pin); - if ((err = add_control(spec, AD_CTL_WIDGET_VOL, name, - HDA_COMPOSE_AMP_VAL(0x20, 3, idx, HDA_INPUT))) < 0) - return err; - sprintf(name, "%s Playback Switch", ctlname); - if ((err = add_control(spec, AD_CTL_WIDGET_MUTE, name, - HDA_COMPOSE_AMP_VAL(0x20, 3, idx, HDA_INPUT))) < 0) + err = snd_hda_gen_init(codec); + if (err < 0) return err; - if (boost) { - hda_nid_t bnid; - idx = ad1988_pin_idx(pin); - bnid = ad1988_boost_nids[idx]; - if (bnid) { - sprintf(name, "%s Boost Volume", ctlname); - return add_control(spec, AD_CTL_WIDGET_VOL, name, - HDA_COMPOSE_AMP_VAL(bnid, 3, idx, HDA_OUTPUT)); + if (!spec->gen.autocfg.dig_outs) + return 0; - } + for (i = 0; i < 4; i++) { + struct nid_path *path; + path = snd_hda_get_path_from_idx(codec, spec->smux_paths[i]); + if (path) + snd_hda_activate_path(codec, path, path->active, false); } + return 0; } -/* create playback/capture controls for input pins */ -static int ad1988_auto_create_analog_input_ctls(struct hda_codec *codec, - const struct auto_pin_cfg *cfg) +static int ad1988_add_spdif_mux_ctl(struct hda_codec *codec) { struct ad198x_spec *spec = codec->spec; - struct hda_input_mux *imux = &spec->private_imux; - int i, err, type, type_idx; - - for (i = 0; i < cfg->num_inputs; i++) { - const char *label; - type = cfg->inputs[i].type; - label = hda_get_autocfg_input_label(codec, cfg, i); - snd_hda_add_imux_item(imux, label, - ad1988_pin_to_adc_idx(cfg->inputs[i].pin), - &type_idx); - err = new_analog_input(spec, cfg->inputs[i].pin, - label, type_idx, - type == AUTO_PIN_MIC); - if (err < 0) - return err; - } - snd_hda_add_imux_item(imux, "Mix", 9, NULL); + int i, num_conns; + /* we create four static faked paths, since AD codecs have odd + * widget connections regarding the SPDIF out source + */ + static struct nid_path fake_paths[4] = { + { + .depth = 3, + .path = { 0x02, 0x1d, 0x1b }, + .idx = { 0, 0, 0 }, + .multi = { 0, 0, 0 }, + }, + { + .depth = 4, + .path = { 0x08, 0x0b, 0x1d, 0x1b }, + .idx = { 0, 0, 1, 0 }, + .multi = { 0, 1, 0, 0 }, + }, + { + .depth = 4, + .path = { 0x09, 0x0b, 0x1d, 0x1b }, + .idx = { 0, 1, 1, 0 }, + .multi = { 0, 1, 0, 0 }, + }, + { + .depth = 4, + .path = { 0x0f, 0x0b, 0x1d, 0x1b }, + .idx = { 0, 2, 1, 0 }, + .multi = { 0, 1, 0, 0 }, + }, + }; - if ((err = add_control(spec, AD_CTL_WIDGET_VOL, - "Analog Mix Playback Volume", - HDA_COMPOSE_AMP_VAL(0x21, 3, 0x0, HDA_OUTPUT))) < 0) - return err; - if ((err = add_control(spec, AD_CTL_WIDGET_MUTE, - "Analog Mix Playback Switch", - HDA_COMPOSE_AMP_VAL(0x21, 3, 0x0, HDA_OUTPUT))) < 0) - return err; + /* SPDIF source mux appears to be present only on AD1988A */ + if (!spec->gen.autocfg.dig_outs || + get_wcaps_type(get_wcaps(codec, 0x1d)) != AC_WID_AUD_MIX) + return 0; - return 0; -} + num_conns = snd_hda_get_num_conns(codec, 0x0b) + 1; + if (num_conns != 3 && num_conns != 4) + return 0; -static void ad1988_auto_set_output_and_unmute(struct hda_codec *codec, - hda_nid_t nid, int pin_type, - int dac_idx) -{ - /* set as output */ - snd_hda_set_pin_ctl(codec, nid, pin_type); - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); - switch (nid) { - case 0x11: /* port-A - DAC 03 */ - snd_hda_codec_write(codec, 0x37, 0, AC_VERB_SET_CONNECT_SEL, 0x00); - break; - case 0x14: /* port-B - DAC 06 */ - snd_hda_codec_write(codec, 0x30, 0, AC_VERB_SET_CONNECT_SEL, 0x02); - break; - case 0x15: /* port-C - DAC 05 */ - snd_hda_codec_write(codec, 0x31, 0, AC_VERB_SET_CONNECT_SEL, 0x00); - break; - case 0x17: /* port-E - DAC 0a */ - snd_hda_codec_write(codec, 0x32, 0, AC_VERB_SET_CONNECT_SEL, 0x01); - break; - case 0x13: /* mono - DAC 04 */ - snd_hda_codec_write(codec, 0x36, 0, AC_VERB_SET_CONNECT_SEL, 0x01); - break; + for (i = 0; i < num_conns; i++) { + struct nid_path *path = snd_array_new(&spec->gen.paths); + if (!path) + return -ENOMEM; + *path = fake_paths[i]; + if (!i) + path->active = 1; + spec->smux_paths[i] = snd_hda_get_path_idx(codec, path); } -} -static void ad1988_auto_init_multi_out(struct hda_codec *codec) -{ - struct ad198x_spec *spec = codec->spec; - int i; + if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &ad1988_auto_smux_mixer)) + return -ENOMEM; - for (i = 0; i < spec->autocfg.line_outs; i++) { - hda_nid_t nid = spec->autocfg.line_out_pins[i]; - ad1988_auto_set_output_and_unmute(codec, nid, PIN_OUT, i); - } -} + codec->patch_ops.init = ad1988_auto_init; -static void ad1988_auto_init_extra_out(struct hda_codec *codec) -{ - struct ad198x_spec *spec = codec->spec; - hda_nid_t pin; - - pin = spec->autocfg.speaker_pins[0]; - if (pin) /* connect to front */ - ad1988_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0); - pin = spec->autocfg.hp_pins[0]; - if (pin) /* connect to front */ - ad1988_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); + return 0; } -static void ad1988_auto_init_analog_input(struct hda_codec *codec) -{ - struct ad198x_spec *spec = codec->spec; - const struct auto_pin_cfg *cfg = &spec->autocfg; - int i, idx; - - for (i = 0; i < cfg->num_inputs; i++) { - hda_nid_t nid = cfg->inputs[i].pin; - int type = cfg->inputs[i].type; - int val; - switch (nid) { - case 0x15: /* port-C */ - snd_hda_codec_write(codec, 0x33, 0, AC_VERB_SET_CONNECT_SEL, 0x0); - break; - case 0x17: /* port-E */ - snd_hda_codec_write(codec, 0x34, 0, AC_VERB_SET_CONNECT_SEL, 0x0); - break; - } - val = PIN_IN; - if (type == AUTO_PIN_MIC) - val |= snd_hda_get_default_vref(codec, nid); - snd_hda_set_pin_ctl(codec, nid, val); - if (nid != AD1988_PIN_CD_NID) - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, - AMP_OUT_MUTE); - idx = ad1988_pin_idx(nid); - if (ad1988_boost_nids[idx]) - snd_hda_codec_write(codec, ad1988_boost_nids[idx], 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_OUT_ZERO); - } -} +/* + */ -/* parse the BIOS configuration and set up the alc_spec */ -/* return 1 if successful, 0 if the proper config is not found, or a negative error code */ static int ad1988_parse_auto_config(struct hda_codec *codec) { - struct ad198x_spec *spec = codec->spec; + struct ad198x_spec *spec; int err; - if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL)) < 0) - return err; - if ((err = ad1988_auto_fill_dac_nids(codec, &spec->autocfg)) < 0) - return err; - if (! spec->autocfg.line_outs) - return 0; /* can't find valid BIOS pin config */ - if ((err = ad1988_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 0 || - (err = ad1988_auto_create_extra_out(codec, - spec->autocfg.speaker_pins[0], - "Speaker")) < 0 || - (err = ad1988_auto_create_extra_out(codec, spec->autocfg.hp_pins[0], - "Headphone")) < 0 || - (err = ad1988_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0) + err = alloc_ad_spec(codec); + if (err < 0) return err; + spec = codec->spec; - spec->multiout.max_channels = spec->multiout.num_dacs * 2; - - if (spec->autocfg.dig_outs) - spec->multiout.dig_out_nid = AD1988_SPDIF_OUT; - if (spec->autocfg.dig_in_pin) - spec->dig_in_nid = AD1988_SPDIF_IN; - - if (spec->kctls.list) - spec->mixers[spec->num_mixers++] = spec->kctls.list; - - spec->init_verbs[spec->num_init_verbs++] = ad1988_6stack_init_verbs; - - spec->input_mux = &spec->private_imux; - - return 1; -} - -/* init callback for auto-configuration model -- overriding the default init */ -static int ad1988_auto_init(struct hda_codec *codec) -{ - ad198x_init(codec); - ad1988_auto_init_multi_out(codec); - ad1988_auto_init_extra_out(codec); - ad1988_auto_init_analog_input(codec); + spec->gen.mixer_nid = 0x20; + spec->gen.mixer_merge_nid = 0x21; + spec->beep_dev_nid = 0x10; + set_beep_amp(spec, 0x10, 0, HDA_OUTPUT); + err = ad198x_parse_auto_config(codec); + if (err < 0) + goto error; + err = ad1988_add_spdif_mux_ctl(codec); + if (err < 0) + goto error; return 0; + + error: + ad198x_free(codec); + return err; } /* */ +#ifdef ENABLE_AD_STATIC_QUIRKS static const char * const ad1988_models[AD1988_MODEL_LAST] = { [AD1988_6STACK] = "6stack", [AD1988_6STACK_DIG] = "6stack-dig", @@ -3255,15 +3279,6 @@ static int patch_ad1988(struct hda_codec *codec) struct ad198x_spec *spec; int err, board_config; - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; - - codec->spec = spec; - - if (is_rev2(codec)) - snd_printk(KERN_INFO "patch_analog: AD1988A rev.2 is detected, enable workarounds\n"); - board_config = snd_hda_check_board_config(codec, AD1988_MODEL_LAST, ad1988_models, ad1988_cfg_tbl); if (board_config < 0) { @@ -3272,17 +3287,16 @@ static int patch_ad1988(struct hda_codec *codec) board_config = AD1988_AUTO; } - if (board_config == AD1988_AUTO) { - /* automatic parse from the BIOS config */ - err = ad1988_parse_auto_config(codec); - if (err < 0) { - ad198x_free(codec); - return err; - } else if (! err) { - printk(KERN_INFO "hda_codec: Cannot set up configuration from BIOS. Using 6-stack mode...\n"); - board_config = AD1988_6STACK; - } - } + if (board_config == AD1988_AUTO) + return ad1988_parse_auto_config(codec); + + err = alloc_ad_spec(codec); + if (err < 0) + return err; + spec = codec->spec; + + if (is_rev2(codec)) + snd_printk(KERN_INFO "patch_analog: AD1988A rev.2 is detected, enable workarounds\n"); err = snd_hda_attach_beep_device(codec, 0x10); if (err < 0) { @@ -3346,7 +3360,7 @@ static int patch_ad1988(struct hda_codec *codec) spec->input_mux = &ad1988_laptop_capture_source; spec->num_mixers = 1; spec->mixers[0] = ad1988_laptop_mixers; - spec->inv_eapd = 1; /* inverted EAPD */ + codec->inv_eapd = 1; /* inverted EAPD */ spec->num_init_verbs = 1; spec->init_verbs[0] = ad1988_laptop_init_verbs; if (board_config == AD1988_LAPTOP_DIG) @@ -3354,15 +3368,6 @@ static int patch_ad1988(struct hda_codec *codec) break; } - if (spec->autocfg.hp_pins[0]) { - spec->mixers[spec->num_mixers++] = ad1988_hp_mixers; - spec->slave_vols = ad1988_6stack_fp_slave_pfxs; - spec->slave_sws = ad1988_6stack_fp_slave_pfxs; - spec->alt_dac_nid = ad1988_alt_dac_nid; - spec->stream_analog_alt_playback = - &ad198x_pcm_analog_alt_playback; - } - spec->num_adc_nids = ARRAY_SIZE(ad1988_adc_nids); spec->adc_nids = ad1988_adc_nids; spec->capsrc_nids = ad1988_capsrc_nids; @@ -3390,9 +3395,6 @@ static int patch_ad1988(struct hda_codec *codec) codec->patch_ops = ad198x_patch_ops; switch (board_config) { - case AD1988_AUTO: - codec->patch_ops.init = ad1988_auto_init; - break; case AD1988_LAPTOP: case AD1988_LAPTOP_DIG: codec->patch_ops.unsol_event = ad1988_laptop_unsol_event; @@ -3408,6 +3410,9 @@ static int patch_ad1988(struct hda_codec *codec) return 0; } +#else /* ENABLE_AD_STATIC_QUIRKS */ +#define patch_ad1988 ad1988_parse_auto_config +#endif /* ENABLE_AD_STATIC_QUIRKS */ /* @@ -3428,6 +3433,7 @@ static int patch_ad1988(struct hda_codec *codec) * but no build-up framework is given, so far. */ +#ifdef ENABLE_AD_STATIC_QUIRKS static const hda_nid_t ad1884_dac_nids[1] = { 0x04, }; @@ -3570,16 +3576,115 @@ static const char * const ad1884_slave_vols[] = { NULL }; -static int patch_ad1884(struct hda_codec *codec) +enum { + AD1884_AUTO, + AD1884_BASIC, + AD1884_MODELS +}; + +static const char * const ad1884_models[AD1884_MODELS] = { + [AD1884_AUTO] = "auto", + [AD1884_BASIC] = "basic", +}; +#endif /* ENABLE_AD_STATIC_QUIRKS */ + + +/* set the upper-limit for mixer amp to 0dB for avoiding the possible + * damage by overloading + */ +static void ad1884_fixup_amp_override(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + if (action == HDA_FIXUP_ACT_PRE_PROBE) + snd_hda_override_amp_caps(codec, 0x20, HDA_INPUT, + (0x17 << AC_AMPCAP_OFFSET_SHIFT) | + (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) | + (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) | + (1 << AC_AMPCAP_MUTE_SHIFT)); +} + +static void ad1884_fixup_hp_eapd(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct ad198x_spec *spec = codec->spec; + + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + if (spec->gen.autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT) + spec->eapd_nid = spec->gen.autocfg.line_out_pins[0]; + else + spec->eapd_nid = spec->gen.autocfg.speaker_pins[0]; + if (spec->eapd_nid) + spec->gen.vmaster_mute.hook = ad_vmaster_eapd_hook; + } +} + +enum { + AD1884_FIXUP_AMP_OVERRIDE, + AD1884_FIXUP_HP_EAPD, +}; + +static const struct hda_fixup ad1884_fixups[] = { + [AD1884_FIXUP_AMP_OVERRIDE] = { + .type = HDA_FIXUP_FUNC, + .v.func = ad1884_fixup_amp_override, + }, + [AD1884_FIXUP_HP_EAPD] = { + .type = HDA_FIXUP_FUNC, + .v.func = ad1884_fixup_hp_eapd, + .chained = true, + .chain_id = AD1884_FIXUP_AMP_OVERRIDE, + }, +}; + +static const struct snd_pci_quirk ad1884_fixup_tbl[] = { + SND_PCI_QUIRK_VENDOR(0x103c, "HP", AD1884_FIXUP_HP_EAPD), + {} +}; + + +static int ad1884_parse_auto_config(struct hda_codec *codec) { struct ad198x_spec *spec; int err; - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; + err = alloc_ad_spec(codec); + if (err < 0) + return err; + spec = codec->spec; - codec->spec = spec; + spec->gen.mixer_nid = 0x20; + spec->beep_dev_nid = 0x10; + set_beep_amp(spec, 0x10, 0, HDA_OUTPUT); + + snd_hda_pick_fixup(codec, NULL, ad1884_fixup_tbl, ad1884_fixups); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); + + err = ad198x_parse_auto_config(codec); + if (err < 0) + goto error; + err = ad1983_add_spdif_mux_ctl(codec); + if (err < 0) + goto error; + + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); + + return 0; + + error: + ad198x_free(codec); + return err; +} + +#ifdef ENABLE_AD_STATIC_QUIRKS +static int patch_ad1884_basic(struct hda_codec *codec) +{ + struct ad198x_spec *spec; + int err; + + err = alloc_ad_spec(codec); + if (err < 0) + return err; + spec = codec->spec; err = snd_hda_attach_beep_device(codec, 0x10); if (err < 0) { @@ -3618,6 +3723,29 @@ static int patch_ad1884(struct hda_codec *codec) return 0; } +static int patch_ad1884(struct hda_codec *codec) +{ + int board_config; + + board_config = snd_hda_check_board_config(codec, AD1884_MODELS, + ad1884_models, NULL); + if (board_config < 0) { + printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", + codec->chip_name); + board_config = AD1884_AUTO; + } + + if (board_config == AD1884_AUTO) + return ad1884_parse_auto_config(codec); + else + return patch_ad1884_basic(codec); +} +#else /* ENABLE_AD_STATIC_QUIRKS */ +#define patch_ad1884 ad1884_parse_auto_config +#endif /* ENABLE_AD_STATIC_QUIRKS */ + + +#ifdef ENABLE_AD_STATIC_QUIRKS /* * Lenovo Thinkpad T61/X61 */ @@ -3790,6 +3918,7 @@ static int ad1984_build_pcms(struct hda_codec *codec) /* models */ enum { + AD1984_AUTO, AD1984_BASIC, AD1984_THINKPAD, AD1984_DELL_DESKTOP, @@ -3797,6 +3926,7 @@ enum { }; static const char * const ad1984_models[AD1984_MODELS] = { + [AD1984_AUTO] = "auto", [AD1984_BASIC] = "basic", [AD1984_THINKPAD] = "thinkpad", [AD1984_DELL_DESKTOP] = "dell_desktop", @@ -3815,12 +3945,22 @@ static int patch_ad1984(struct hda_codec *codec) struct ad198x_spec *spec; int board_config, err; - err = patch_ad1884(codec); + board_config = snd_hda_check_board_config(codec, AD1984_MODELS, + ad1984_models, ad1984_cfg_tbl); + if (board_config < 0) { + printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", + codec->chip_name); + board_config = AD1984_AUTO; + } + + if (board_config == AD1984_AUTO) + return ad1884_parse_auto_config(codec); + + err = patch_ad1884_basic(codec); if (err < 0) return err; spec = codec->spec; - board_config = snd_hda_check_board_config(codec, AD1984_MODELS, - ad1984_models, ad1984_cfg_tbl); + switch (board_config) { case AD1984_BASIC: /* additional digital mics */ @@ -3847,6 +3987,9 @@ static int patch_ad1984(struct hda_codec *codec) } return 0; } +#else /* ENABLE_AD_STATIC_QUIRKS */ +#define patch_ad1984 ad1884_parse_auto_config +#endif /* ENABLE_AD_STATIC_QUIRKS */ /* @@ -3867,6 +4010,7 @@ static int patch_ad1984(struct hda_codec *codec) * We share the single DAC for both HP and line-outs (see AD1884/1984). */ +#ifdef ENABLE_AD_STATIC_QUIRKS static const hda_nid_t ad1884a_dac_nids[1] = { 0x03, }; @@ -4537,6 +4681,7 @@ static int ad1984a_touchsmart_init(struct hda_codec *codec) */ enum { + AD1884A_AUTO, AD1884A_DESKTOP, AD1884A_LAPTOP, AD1884A_MOBILE, @@ -4547,6 +4692,7 @@ enum { }; static const char * const ad1884a_models[AD1884A_MODELS] = { + [AD1884A_AUTO] = "auto", [AD1884A_DESKTOP] = "desktop", [AD1884A_LAPTOP] = "laptop", [AD1884A_MOBILE] = "mobile", @@ -4575,11 +4721,22 @@ static int patch_ad1884a(struct hda_codec *codec) struct ad198x_spec *spec; int err, board_config; - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; + board_config = snd_hda_check_board_config(codec, AD1884A_MODELS, + ad1884a_models, + ad1884a_cfg_tbl); + if (board_config < 0) { + printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", + codec->chip_name); + board_config = AD1884A_AUTO; + } - codec->spec = spec; + if (board_config == AD1884A_AUTO) + return ad1884_parse_auto_config(codec); + + err = alloc_ad_spec(codec); + if (err < 0) + return err; + spec = codec->spec; err = snd_hda_attach_beep_device(codec, 0x10); if (err < 0) { @@ -4607,9 +4764,6 @@ static int patch_ad1884a(struct hda_codec *codec) codec->patch_ops = ad198x_patch_ops; /* override some parameters */ - board_config = snd_hda_check_board_config(codec, AD1884A_MODELS, - ad1884a_models, - ad1884a_cfg_tbl); switch (board_config) { case AD1884A_LAPTOP: spec->mixers[0] = ad1884a_laptop_mixers; @@ -4680,6 +4834,9 @@ static int patch_ad1884a(struct hda_codec *codec) return 0; } +#else /* ENABLE_AD_STATIC_QUIRKS */ +#define patch_ad1884a ad1884_parse_auto_config +#endif /* ENABLE_AD_STATIC_QUIRKS */ /* @@ -4694,6 +4851,7 @@ static int patch_ad1884a(struct hda_codec *codec) * port-G - rear clfe-out (6stack) */ +#ifdef ENABLE_AD_STATIC_QUIRKS static const hda_nid_t ad1882_dac_nids[3] = { 0x04, 0x03, 0x05 }; @@ -4970,6 +5128,7 @@ static const struct hda_amp_list ad1882_loopbacks[] = { /* models */ enum { + AD1882_AUTO, AD1882_3STACK, AD1882_6STACK, AD1882_3STACK_AUTOMUTE, @@ -4977,22 +5136,61 @@ enum { }; static const char * const ad1882_models[AD1986A_MODELS] = { + [AD1882_AUTO] = "auto", [AD1882_3STACK] = "3stack", [AD1882_6STACK] = "6stack", [AD1882_3STACK_AUTOMUTE] = "3stack-automute", }; +#endif /* ENABLE_AD_STATIC_QUIRKS */ + +static int ad1882_parse_auto_config(struct hda_codec *codec) +{ + struct ad198x_spec *spec; + int err; + + err = alloc_ad_spec(codec); + if (err < 0) + return err; + spec = codec->spec; + + spec->gen.mixer_nid = 0x20; + spec->gen.mixer_merge_nid = 0x21; + spec->beep_dev_nid = 0x10; + set_beep_amp(spec, 0x10, 0, HDA_OUTPUT); + err = ad198x_parse_auto_config(codec); + if (err < 0) + goto error; + err = ad1988_add_spdif_mux_ctl(codec); + if (err < 0) + goto error; + return 0; + error: + ad198x_free(codec); + return err; +} +#ifdef ENABLE_AD_STATIC_QUIRKS static int patch_ad1882(struct hda_codec *codec) { struct ad198x_spec *spec; int err, board_config; - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; + board_config = snd_hda_check_board_config(codec, AD1882_MODELS, + ad1882_models, NULL); + if (board_config < 0) { + printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", + codec->chip_name); + board_config = AD1882_AUTO; + } - codec->spec = spec; + if (board_config == AD1882_AUTO) + return ad1882_parse_auto_config(codec); + + err = alloc_ad_spec(codec); + if (err < 0) + return err; + spec = codec->spec; err = snd_hda_attach_beep_device(codec, 0x10); if (err < 0) { @@ -5029,8 +5227,6 @@ static int patch_ad1882(struct hda_codec *codec) codec->patch_ops = ad198x_patch_ops; /* override some parameters */ - board_config = snd_hda_check_board_config(codec, AD1882_MODELS, - ad1882_models, NULL); switch (board_config) { default: case AD1882_3STACK: @@ -5060,6 +5256,9 @@ static int patch_ad1882(struct hda_codec *codec) return 0; } +#else /* ENABLE_AD_STATIC_QUIRKS */ +#define patch_ad1882 ad1882_parse_auto_config +#endif /* ENABLE_AD_STATIC_QUIRKS */ /* diff --git a/sound/pci/hda/patch_ca0110.c b/sound/pci/hda/patch_ca0110.c index 19ae14f739cb..30b3a4bc06ee 100644 --- a/sound/pci/hda/patch_ca0110.c +++ b/sound/pci/hda/patch_ca0110.c @@ -19,7 +19,6 @@ */ #include <linux/init.h> -#include <linux/delay.h> #include <linux/slab.h> #include <linux/pci.h> #include <linux/module.h> @@ -27,502 +26,46 @@ #include "hda_codec.h" #include "hda_local.h" #include "hda_auto_parser.h" +#include "hda_jack.h" +#include "hda_generic.h" -/* - */ - -struct ca0110_spec { - struct auto_pin_cfg autocfg; - struct hda_multi_out multiout; - hda_nid_t out_pins[AUTO_CFG_MAX_OUTS]; - hda_nid_t dacs[AUTO_CFG_MAX_OUTS]; - hda_nid_t hp_dac; - hda_nid_t input_pins[AUTO_PIN_LAST]; - hda_nid_t adcs[AUTO_PIN_LAST]; - hda_nid_t dig_out; - hda_nid_t dig_in; - unsigned int num_inputs; - char input_labels[AUTO_PIN_LAST][32]; - struct hda_pcm pcm_rec[2]; /* PCM information */ -}; - -/* - * PCM callbacks - */ -static int ca0110_playback_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct ca0110_spec *spec = codec->spec; - return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream, - hinfo); -} - -static int ca0110_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 ca0110_spec *spec = codec->spec; - return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, - stream_tag, format, substream); -} - -static int ca0110_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct ca0110_spec *spec = codec->spec; - return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); -} - -/* - * Digital out - */ -static int ca0110_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct ca0110_spec *spec = codec->spec; - return snd_hda_multi_out_dig_open(codec, &spec->multiout); -} - -static int ca0110_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct ca0110_spec *spec = codec->spec; - return snd_hda_multi_out_dig_close(codec, &spec->multiout); -} - -static int ca0110_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 ca0110_spec *spec = codec->spec; - return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag, - format, substream); -} - -/* - * Analog capture - */ -static int ca0110_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 ca0110_spec *spec = codec->spec; - - snd_hda_codec_setup_stream(codec, spec->adcs[substream->number], - stream_tag, 0, format); - return 0; -} - -static int ca0110_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct ca0110_spec *spec = codec->spec; - - snd_hda_codec_cleanup_stream(codec, spec->adcs[substream->number]); - return 0; -} - -/* - */ - -static const char * const dirstr[2] = { "Playback", "Capture" }; - -static int _add_switch(struct hda_codec *codec, hda_nid_t nid, const char *pfx, - int chan, int dir) -{ - char namestr[44]; - int type = dir ? HDA_INPUT : HDA_OUTPUT; - struct snd_kcontrol_new knew = - HDA_CODEC_MUTE_MONO(namestr, nid, chan, 0, type); - sprintf(namestr, "%s %s Switch", pfx, dirstr[dir]); - return snd_hda_ctl_add(codec, nid, snd_ctl_new1(&knew, codec)); -} - -static int _add_volume(struct hda_codec *codec, hda_nid_t nid, const char *pfx, - int chan, int dir) -{ - char namestr[44]; - int type = dir ? HDA_INPUT : HDA_OUTPUT; - struct snd_kcontrol_new knew = - HDA_CODEC_VOLUME_MONO(namestr, nid, chan, 0, type); - sprintf(namestr, "%s %s Volume", pfx, dirstr[dir]); - return snd_hda_ctl_add(codec, nid, snd_ctl_new1(&knew, codec)); -} - -#define add_out_switch(codec, nid, pfx) _add_switch(codec, nid, pfx, 3, 0) -#define add_out_volume(codec, nid, pfx) _add_volume(codec, nid, pfx, 3, 0) -#define add_in_switch(codec, nid, pfx) _add_switch(codec, nid, pfx, 3, 1) -#define add_in_volume(codec, nid, pfx) _add_volume(codec, nid, pfx, 3, 1) -#define add_mono_switch(codec, nid, pfx, chan) \ - _add_switch(codec, nid, pfx, chan, 0) -#define add_mono_volume(codec, nid, pfx, chan) \ - _add_volume(codec, nid, pfx, chan, 0) - -static int ca0110_build_controls(struct hda_codec *codec) -{ - struct ca0110_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - static const char * const prefix[AUTO_CFG_MAX_OUTS] = { - "Front", "Surround", NULL, "Side", "Multi" - }; - hda_nid_t mutenid; - int i, err; - - for (i = 0; i < spec->multiout.num_dacs; i++) { - if (get_wcaps(codec, spec->out_pins[i]) & AC_WCAP_OUT_AMP) - mutenid = spec->out_pins[i]; - else - mutenid = spec->multiout.dac_nids[i]; - if (!prefix[i]) { - err = add_mono_switch(codec, mutenid, - "Center", 1); - if (err < 0) - return err; - err = add_mono_switch(codec, mutenid, - "LFE", 1); - if (err < 0) - return err; - err = add_mono_volume(codec, spec->multiout.dac_nids[i], - "Center", 1); - if (err < 0) - return err; - err = add_mono_volume(codec, spec->multiout.dac_nids[i], - "LFE", 1); - if (err < 0) - return err; - } else { - err = add_out_switch(codec, mutenid, - prefix[i]); - if (err < 0) - return err; - err = add_out_volume(codec, spec->multiout.dac_nids[i], - prefix[i]); - if (err < 0) - return err; - } - } - if (cfg->hp_outs) { - if (get_wcaps(codec, cfg->hp_pins[0]) & AC_WCAP_OUT_AMP) - mutenid = cfg->hp_pins[0]; - else - mutenid = spec->multiout.dac_nids[i]; - - err = add_out_switch(codec, mutenid, "Headphone"); - if (err < 0) - return err; - if (spec->hp_dac) { - err = add_out_volume(codec, spec->hp_dac, "Headphone"); - if (err < 0) - return err; - } - } - for (i = 0; i < spec->num_inputs; i++) { - const char *label = spec->input_labels[i]; - if (get_wcaps(codec, spec->input_pins[i]) & AC_WCAP_IN_AMP) - mutenid = spec->input_pins[i]; - else - mutenid = spec->adcs[i]; - err = add_in_switch(codec, mutenid, label); - if (err < 0) - return err; - err = add_in_volume(codec, spec->adcs[i], label); - if (err < 0) - return err; - } - - if (spec->dig_out) { - err = snd_hda_create_spdif_out_ctls(codec, spec->dig_out, - spec->dig_out); - 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) { - err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in); - if (err < 0) - return err; - err = add_in_volume(codec, spec->dig_in, "IEC958"); - } - return 0; -} - -/* - */ -static const struct hda_pcm_stream ca0110_pcm_analog_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 8, - .ops = { - .open = ca0110_playback_pcm_open, - .prepare = ca0110_playback_pcm_prepare, - .cleanup = ca0110_playback_pcm_cleanup - }, -}; - -static const struct hda_pcm_stream ca0110_pcm_analog_capture = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - .ops = { - .prepare = ca0110_capture_pcm_prepare, - .cleanup = ca0110_capture_pcm_cleanup - }, -}; - -static const struct hda_pcm_stream ca0110_pcm_digital_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - .ops = { - .open = ca0110_dig_playback_pcm_open, - .close = ca0110_dig_playback_pcm_close, - .prepare = ca0110_dig_playback_pcm_prepare - }, -}; - -static const struct hda_pcm_stream ca0110_pcm_digital_capture = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, -}; - -static int ca0110_build_pcms(struct hda_codec *codec) -{ - struct ca0110_spec *spec = codec->spec; - struct hda_pcm *info = spec->pcm_rec; - - codec->pcm_info = info; - codec->num_pcms = 0; - - info->name = "CA0110 Analog"; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ca0110_pcm_analog_playback; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->dacs[0]; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = - spec->multiout.max_channels; - info->stream[SNDRV_PCM_STREAM_CAPTURE] = ca0110_pcm_analog_capture; - info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_inputs; - info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adcs[0]; - codec->num_pcms++; - - if (!spec->dig_out && !spec->dig_in) - return 0; - - info++; - info->name = "CA0110 Digital"; - info->pcm_type = HDA_PCM_TYPE_SPDIF; - if (spec->dig_out) { - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = - ca0110_pcm_digital_playback; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->dig_out; - } - if (spec->dig_in) { - info->stream[SNDRV_PCM_STREAM_CAPTURE] = - ca0110_pcm_digital_capture; - info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in; - } - codec->num_pcms++; - - return 0; -} - -static void init_output(struct hda_codec *codec, hda_nid_t pin, hda_nid_t dac) -{ - if (pin) { - snd_hda_set_pin_ctl(codec, pin, PIN_HP); - if (get_wcaps(codec, pin) & AC_WCAP_OUT_AMP) - snd_hda_codec_write(codec, pin, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_OUT_UNMUTE); - } - if (dac) - snd_hda_codec_write(codec, dac, 0, - AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO); -} - -static void init_input(struct hda_codec *codec, hda_nid_t pin, hda_nid_t adc) -{ - if (pin) { - snd_hda_set_pin_ctl(codec, pin, PIN_IN | - snd_hda_get_default_vref(codec, pin)); - if (get_wcaps(codec, pin) & AC_WCAP_IN_AMP) - snd_hda_codec_write(codec, pin, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_IN_UNMUTE(0)); - } - if (adc) - snd_hda_codec_write(codec, adc, 0, AC_VERB_SET_AMP_GAIN_MUTE, - AMP_IN_UNMUTE(0)); -} - -static int ca0110_init(struct hda_codec *codec) -{ - struct ca0110_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int i; - - for (i = 0; i < spec->multiout.num_dacs; i++) - init_output(codec, spec->out_pins[i], - spec->multiout.dac_nids[i]); - init_output(codec, cfg->hp_pins[0], spec->hp_dac); - init_output(codec, cfg->dig_out_pins[0], spec->dig_out); - - for (i = 0; i < spec->num_inputs; i++) - init_input(codec, spec->input_pins[i], spec->adcs[i]); - init_input(codec, cfg->dig_in_pin, spec->dig_in); - return 0; -} - -static void ca0110_free(struct hda_codec *codec) -{ - kfree(codec->spec); -} static const struct hda_codec_ops ca0110_patch_ops = { - .build_controls = ca0110_build_controls, - .build_pcms = ca0110_build_pcms, - .init = ca0110_init, - .free = ca0110_free, + .build_controls = snd_hda_gen_build_controls, + .build_pcms = snd_hda_gen_build_pcms, + .init = snd_hda_gen_init, + .free = snd_hda_gen_free, + .unsol_event = snd_hda_jack_unsol_event, }; - -static void parse_line_outs(struct hda_codec *codec) -{ - struct ca0110_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int i, n; - unsigned int def_conf; - hda_nid_t nid; - - n = 0; - for (i = 0; i < cfg->line_outs; i++) { - nid = cfg->line_out_pins[i]; - def_conf = snd_hda_codec_get_pincfg(codec, nid); - if (!def_conf) - continue; /* invalid pin */ - if (snd_hda_get_connections(codec, nid, &spec->dacs[i], 1) != 1) - continue; - spec->out_pins[n++] = nid; - } - spec->multiout.dac_nids = spec->dacs; - spec->multiout.num_dacs = n; - spec->multiout.max_channels = n * 2; -} - -static void parse_hp_out(struct hda_codec *codec) -{ - struct ca0110_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int i; - unsigned int def_conf; - hda_nid_t nid, dac; - - if (!cfg->hp_outs) - return; - nid = cfg->hp_pins[0]; - def_conf = snd_hda_codec_get_pincfg(codec, nid); - if (!def_conf) { - cfg->hp_outs = 0; - return; - } - if (snd_hda_get_connections(codec, nid, &dac, 1) != 1) - return; - - for (i = 0; i < cfg->line_outs; i++) - if (dac == spec->dacs[i]) - break; - if (i >= cfg->line_outs) { - spec->hp_dac = dac; - spec->multiout.hp_nid = dac; - } -} - -static void parse_input(struct hda_codec *codec) -{ - struct ca0110_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - hda_nid_t nid, pin; - int n, i, j; - - n = 0; - nid = codec->start_nid; - for (i = 0; i < codec->num_nodes; i++, nid++) { - unsigned int wcaps = get_wcaps(codec, nid); - unsigned int type = get_wcaps_type(wcaps); - if (type != AC_WID_AUD_IN) - continue; - if (snd_hda_get_connections(codec, nid, &pin, 1) != 1) - continue; - if (pin == cfg->dig_in_pin) { - spec->dig_in = nid; - continue; - } - for (j = 0; j < cfg->num_inputs; j++) - if (cfg->inputs[j].pin == pin) - break; - if (j >= cfg->num_inputs) - continue; - spec->input_pins[n] = pin; - snd_hda_get_pin_label(codec, pin, cfg, - spec->input_labels[n], - sizeof(spec->input_labels[n]), NULL); - spec->adcs[n] = nid; - n++; - } - spec->num_inputs = n; -} - -static void parse_digital(struct hda_codec *codec) -{ - struct ca0110_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - - if (cfg->dig_outs && - snd_hda_get_connections(codec, cfg->dig_out_pins[0], - &spec->dig_out, 1) == 1) - spec->multiout.dig_out_nid = spec->dig_out; -} - static int ca0110_parse_auto_config(struct hda_codec *codec) { - struct ca0110_spec *spec = codec->spec; + struct hda_gen_spec *spec = codec->spec; int err; - err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); + err = snd_hda_parse_pin_defcfg(codec, &spec->autocfg, NULL, 0); + if (err < 0) + return err; + err = snd_hda_gen_parse_auto_config(codec, &spec->autocfg); if (err < 0) return err; - parse_line_outs(codec); - parse_hp_out(codec); - parse_digital(codec); - parse_input(codec); return 0; } static int patch_ca0110(struct hda_codec *codec) { - struct ca0110_spec *spec; + struct hda_gen_spec *spec; int err; spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (!spec) return -ENOMEM; + snd_hda_gen_spec_init(spec); codec->spec = spec; + spec->multi_cap_vol = 1; codec->bus->needs_damn_long_delay = 1; err = ca0110_parse_auto_config(codec); @@ -534,8 +77,7 @@ static int patch_ca0110(struct hda_codec *codec) return 0; error: - kfree(codec->spec); - codec->spec = NULL; + snd_hda_gen_free(codec); return err; } diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index d5f3a26d608d..72ebb8a36b13 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -19,16 +19,16 @@ */ #include <linux/init.h> -#include <linux/delay.h> #include <linux/slab.h> #include <linux/pci.h> #include <linux/module.h> #include <sound/core.h> +#include <sound/tlv.h> #include "hda_codec.h" #include "hda_local.h" #include "hda_auto_parser.h" #include "hda_jack.h" -#include <sound/tlv.h> +#include "hda_generic.h" /* */ @@ -36,44 +36,17 @@ struct cs_spec { struct hda_gen_spec gen; - struct auto_pin_cfg autocfg; - struct hda_multi_out multiout; - struct snd_kcontrol *vmaster_sw; - struct snd_kcontrol *vmaster_vol; - - hda_nid_t dac_nid[AUTO_CFG_MAX_OUTS]; - hda_nid_t slave_dig_outs[2]; - - unsigned int input_idx[AUTO_PIN_LAST]; - unsigned int capsrc_idx[AUTO_PIN_LAST]; - hda_nid_t adc_nid[AUTO_PIN_LAST]; - unsigned int adc_idx[AUTO_PIN_LAST]; - unsigned int num_inputs; - unsigned int cur_input; - unsigned int automic_idx; - hda_nid_t cur_adc; - unsigned int cur_adc_stream_tag; - unsigned int cur_adc_format; - hda_nid_t dig_in; - - const struct hda_bind_ctls *capture_bind[2]; - unsigned int gpio_mask; unsigned int gpio_dir; unsigned int gpio_data; unsigned int gpio_eapd_hp; /* EAPD GPIO bit for headphones */ unsigned int gpio_eapd_speaker; /* EAPD GPIO bit for speakers */ - struct hda_pcm pcm_rec[2]; /* PCM information */ - - unsigned int hp_detect:1; - unsigned int mic_detect:1; /* CS421x */ unsigned int spdif_detect:1; + unsigned int spdif_present:1; unsigned int sense_b:1; hda_nid_t vendor_nid; - struct hda_input_mux input_mux; - unsigned int last_input; }; /* available models with CS420x */ @@ -84,7 +57,7 @@ enum { CS420X_GPIO_13, CS420X_GPIO_23, CS420X_MBP101, - CS420X_MBP101_COEF, + CS420X_MBP81, CS420X_AUTO, /* aliases */ CS420X_IMAC27_122 = CS420X_GPIO_23, @@ -179,908 +152,43 @@ static inline void cs_vendor_coef_set(struct hda_codec *codec, unsigned int idx, AC_VERB_SET_PROC_COEF, coef); } - -#define HP_EVENT 1 -#define MIC_EVENT 2 - -/* - * PCM callbacks - */ -static int cs_playback_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct cs_spec *spec = codec->spec; - return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream, - hinfo); -} - -static int cs_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 cs_spec *spec = codec->spec; - return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, - stream_tag, format, substream); -} - -static int cs_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct cs_spec *spec = codec->spec; - return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); -} - -/* - * Digital out - */ -static int cs_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct cs_spec *spec = codec->spec; - return snd_hda_multi_out_dig_open(codec, &spec->multiout); -} - -static int cs_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct cs_spec *spec = codec->spec; - return snd_hda_multi_out_dig_close(codec, &spec->multiout); -} - -static int cs_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 cs_spec *spec = codec->spec; - return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag, - format, substream); -} - -static int cs_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct cs_spec *spec = codec->spec; - return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout); -} - -static void cs_update_input_select(struct hda_codec *codec) -{ - struct cs_spec *spec = codec->spec; - if (spec->cur_adc) - snd_hda_codec_write(codec, spec->cur_adc, 0, - AC_VERB_SET_CONNECT_SEL, - spec->adc_idx[spec->cur_input]); -} - -/* - * Analog capture - */ -static int cs_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 cs_spec *spec = codec->spec; - spec->cur_adc = spec->adc_nid[spec->cur_input]; - spec->cur_adc_stream_tag = stream_tag; - spec->cur_adc_format = format; - cs_update_input_select(codec); - snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format); - return 0; -} - -static int cs_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct cs_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 cs_pcm_analog_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - .ops = { - .open = cs_playback_pcm_open, - .prepare = cs_playback_pcm_prepare, - .cleanup = cs_playback_pcm_cleanup - }, -}; - -static const struct hda_pcm_stream cs_pcm_analog_capture = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - .ops = { - .prepare = cs_capture_pcm_prepare, - .cleanup = cs_capture_pcm_cleanup - }, -}; - -static const struct hda_pcm_stream cs_pcm_digital_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - .ops = { - .open = cs_dig_playback_pcm_open, - .close = cs_dig_playback_pcm_close, - .prepare = cs_dig_playback_pcm_prepare, - .cleanup = cs_dig_playback_pcm_cleanup - }, -}; - -static const struct hda_pcm_stream cs_pcm_digital_capture = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, -}; - -static int cs_build_pcms(struct hda_codec *codec) -{ - struct cs_spec *spec = codec->spec; - struct hda_pcm *info = spec->pcm_rec; - - codec->pcm_info = info; - codec->num_pcms = 0; - - info->name = "Cirrus Analog"; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = cs_pcm_analog_playback; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->dac_nid[0]; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = - spec->multiout.max_channels; - info->stream[SNDRV_PCM_STREAM_CAPTURE] = cs_pcm_analog_capture; - info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = - spec->adc_nid[spec->cur_input]; - codec->num_pcms++; - - if (!spec->multiout.dig_out_nid && !spec->dig_in) - return 0; - - info++; - info->name = "Cirrus Digital"; - info->pcm_type = spec->autocfg.dig_out_type[0]; - if (!info->pcm_type) - info->pcm_type = HDA_PCM_TYPE_SPDIF; - if (spec->multiout.dig_out_nid) { - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = - cs_pcm_digital_playback; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = - spec->multiout.dig_out_nid; - } - if (spec->dig_in) { - info->stream[SNDRV_PCM_STREAM_CAPTURE] = - cs_pcm_digital_capture; - info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in; - } - codec->num_pcms++; - - return 0; -} - -/* - * parse codec topology - */ - -static hda_nid_t get_dac(struct hda_codec *codec, hda_nid_t pin) -{ - hda_nid_t dac; - if (!pin) - return 0; - if (snd_hda_get_connections(codec, pin, &dac, 1) != 1) - return 0; - return dac; -} - -static int is_ext_mic(struct hda_codec *codec, unsigned int idx) -{ - struct cs_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - hda_nid_t pin = cfg->inputs[idx].pin; - unsigned int val; - if (!is_jack_detectable(codec, pin)) - return 0; - val = snd_hda_codec_get_pincfg(codec, pin); - return (snd_hda_get_input_pin_attr(val) != INPUT_PIN_ATTR_INT); -} - -static hda_nid_t get_adc(struct hda_codec *codec, hda_nid_t pin, - unsigned int *idxp) -{ - int i, idx; - hda_nid_t nid; - - nid = codec->start_nid; - for (i = 0; i < codec->num_nodes; i++, nid++) { - unsigned int type; - type = get_wcaps_type(get_wcaps(codec, nid)); - if (type != AC_WID_AUD_IN) - continue; - idx = snd_hda_get_conn_index(codec, nid, pin, false); - if (idx >= 0) { - *idxp = idx; - return nid; - } - } - return 0; -} - -static int is_active_pin(struct hda_codec *codec, hda_nid_t nid) -{ - unsigned int val; - val = snd_hda_codec_get_pincfg(codec, nid); - return (get_defcfg_connect(val) != AC_JACK_PORT_NONE); -} - -static int parse_output(struct hda_codec *codec) -{ - struct cs_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int i, extra_nids; - hda_nid_t dac; - - for (i = 0; i < cfg->line_outs; i++) { - dac = get_dac(codec, cfg->line_out_pins[i]); - if (!dac) - break; - spec->dac_nid[i] = dac; - } - spec->multiout.num_dacs = i; - spec->multiout.dac_nids = spec->dac_nid; - spec->multiout.max_channels = i * 2; - - /* add HP and speakers */ - extra_nids = 0; - for (i = 0; i < cfg->hp_outs; i++) { - dac = get_dac(codec, cfg->hp_pins[i]); - if (!dac) - break; - if (!i) - spec->multiout.hp_nid = dac; - else - spec->multiout.extra_out_nid[extra_nids++] = dac; - } - for (i = 0; i < cfg->speaker_outs; i++) { - dac = get_dac(codec, cfg->speaker_pins[i]); - if (!dac) - break; - spec->multiout.extra_out_nid[extra_nids++] = dac; - } - - if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) { - cfg->speaker_outs = cfg->line_outs; - memcpy(cfg->speaker_pins, cfg->line_out_pins, - sizeof(cfg->speaker_pins)); - cfg->line_outs = 0; - } - - return 0; -} - -static int parse_input(struct hda_codec *codec) -{ - struct cs_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int i; - - for (i = 0; i < cfg->num_inputs; i++) { - hda_nid_t pin = cfg->inputs[i].pin; - spec->input_idx[spec->num_inputs] = i; - spec->capsrc_idx[i] = spec->num_inputs++; - spec->cur_input = i; - spec->adc_nid[i] = get_adc(codec, pin, &spec->adc_idx[i]); - } - if (!spec->num_inputs) - return 0; - - /* check whether the automatic mic switch is available */ - if (spec->num_inputs == 2 && - cfg->inputs[0].type == AUTO_PIN_MIC && - cfg->inputs[1].type == AUTO_PIN_MIC) { - if (is_ext_mic(codec, cfg->inputs[0].pin)) { - if (!is_ext_mic(codec, cfg->inputs[1].pin)) { - spec->mic_detect = 1; - spec->automic_idx = 0; - } - } else { - if (is_ext_mic(codec, cfg->inputs[1].pin)) { - spec->mic_detect = 1; - spec->automic_idx = 1; - } - } - } - return 0; -} - - -static int parse_digital_output(struct hda_codec *codec) -{ - struct cs_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - hda_nid_t nid; - - if (!cfg->dig_outs) - return 0; - if (snd_hda_get_connections(codec, cfg->dig_out_pins[0], &nid, 1) < 1) - return 0; - spec->multiout.dig_out_nid = nid; - spec->multiout.share_spdif = 1; - if (cfg->dig_outs > 1 && - snd_hda_get_connections(codec, cfg->dig_out_pins[1], &nid, 1) > 0) { - spec->slave_dig_outs[0] = nid; - codec->slave_dig_outs = spec->slave_dig_outs; - } - return 0; -} - -static int parse_digital_input(struct hda_codec *codec) -{ - struct cs_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int idx; - - if (cfg->dig_in_pin) - spec->dig_in = get_adc(codec, cfg->dig_in_pin, &idx); - return 0; -} - -/* - * create mixer controls - */ - -static const char * const dir_sfx[2] = { "Playback", "Capture" }; - -static int add_mute(struct hda_codec *codec, const char *name, int index, - unsigned int pval, int dir, struct snd_kcontrol **kctlp) -{ - char tmp[44]; - struct snd_kcontrol_new knew = - HDA_CODEC_MUTE_IDX(tmp, index, 0, 0, HDA_OUTPUT); - knew.private_value = pval; - snprintf(tmp, sizeof(tmp), "%s %s Switch", name, dir_sfx[dir]); - *kctlp = snd_ctl_new1(&knew, codec); - (*kctlp)->id.subdevice = HDA_SUBDEV_AMP_FLAG; - return snd_hda_ctl_add(codec, 0, *kctlp); -} - -static int add_volume(struct hda_codec *codec, const char *name, - int index, unsigned int pval, int dir, - struct snd_kcontrol **kctlp) -{ - char tmp[44]; - struct snd_kcontrol_new knew = - HDA_CODEC_VOLUME_IDX(tmp, index, 0, 0, HDA_OUTPUT); - knew.private_value = pval; - snprintf(tmp, sizeof(tmp), "%s %s Volume", name, dir_sfx[dir]); - *kctlp = snd_ctl_new1(&knew, codec); - (*kctlp)->id.subdevice = HDA_SUBDEV_AMP_FLAG; - return snd_hda_ctl_add(codec, 0, *kctlp); -} - -static void fix_volume_caps(struct hda_codec *codec, hda_nid_t dac) -{ - unsigned int caps; - - /* set the upper-limit for mixer amp to 0dB */ - caps = query_amp_caps(codec, dac, HDA_OUTPUT); - caps &= ~(0x7f << AC_AMPCAP_NUM_STEPS_SHIFT); - caps |= ((caps >> AC_AMPCAP_OFFSET_SHIFT) & 0x7f) - << AC_AMPCAP_NUM_STEPS_SHIFT; - snd_hda_override_amp_caps(codec, dac, HDA_OUTPUT, caps); -} - -static int add_vmaster(struct hda_codec *codec, hda_nid_t dac) -{ - struct cs_spec *spec = codec->spec; - unsigned int tlv[4]; - int err; - - spec->vmaster_sw = - snd_ctl_make_virtual_master("Master Playback Switch", NULL); - err = snd_hda_ctl_add(codec, dac, spec->vmaster_sw); - if (err < 0) - return err; - - snd_hda_set_vmaster_tlv(codec, dac, HDA_OUTPUT, tlv); - spec->vmaster_vol = - snd_ctl_make_virtual_master("Master Playback Volume", tlv); - err = snd_hda_ctl_add(codec, dac, spec->vmaster_vol); - if (err < 0) - return err; - return 0; -} - -static int add_output(struct hda_codec *codec, hda_nid_t dac, int idx, - int num_ctls, int type) -{ - struct cs_spec *spec = codec->spec; - const char *name; - int err, index; - struct snd_kcontrol *kctl; - static const char * const speakers[] = { - "Front Speaker", "Surround Speaker", "Bass Speaker" - }; - static const char * const line_outs[] = { - "Front Line Out", "Surround Line Out", "Bass Line Out" - }; - - fix_volume_caps(codec, dac); - if (!spec->vmaster_sw) { - err = add_vmaster(codec, dac); - if (err < 0) - return err; - } - - index = 0; - switch (type) { - case AUTO_PIN_HP_OUT: - name = "Headphone"; - index = idx; - break; - case AUTO_PIN_SPEAKER_OUT: - if (num_ctls > 1) - name = speakers[idx]; - else - name = "Speaker"; - break; - default: - if (num_ctls > 1) - name = line_outs[idx]; - else - name = "Line Out"; - break; - } - - err = add_mute(codec, name, index, - HDA_COMPOSE_AMP_VAL(dac, 3, 0, HDA_OUTPUT), 0, &kctl); - if (err < 0) - return err; - err = snd_ctl_add_slave(spec->vmaster_sw, kctl); - if (err < 0) - return err; - - err = add_volume(codec, name, index, - HDA_COMPOSE_AMP_VAL(dac, 3, 0, HDA_OUTPUT), 0, &kctl); - if (err < 0) - return err; - err = snd_ctl_add_slave(spec->vmaster_vol, kctl); - if (err < 0) - return err; - - return 0; -} - -static int build_output(struct hda_codec *codec) -{ - struct cs_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int i, err; - - for (i = 0; i < cfg->line_outs; i++) { - err = add_output(codec, get_dac(codec, cfg->line_out_pins[i]), - i, cfg->line_outs, cfg->line_out_type); - if (err < 0) - return err; - } - for (i = 0; i < cfg->hp_outs; i++) { - err = add_output(codec, get_dac(codec, cfg->hp_pins[i]), - i, cfg->hp_outs, AUTO_PIN_HP_OUT); - if (err < 0) - return err; - } - for (i = 0; i < cfg->speaker_outs; i++) { - err = add_output(codec, get_dac(codec, cfg->speaker_pins[i]), - i, cfg->speaker_outs, AUTO_PIN_SPEAKER_OUT); - if (err < 0) - return err; - } - return 0; -} - -/* - */ - -static const struct snd_kcontrol_new cs_capture_ctls[] = { - HDA_BIND_SW("Capture Switch", 0), - HDA_BIND_VOL("Capture Volume", 0), -}; - -static int change_cur_input(struct hda_codec *codec, unsigned int idx, - int force) -{ - struct cs_spec *spec = codec->spec; - - if (spec->cur_input == idx && !force) - return 0; - if (spec->cur_adc && spec->cur_adc != spec->adc_nid[idx]) { - /* stream is running, let's swap the current ADC */ - __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1); - spec->cur_adc = spec->adc_nid[idx]; - snd_hda_codec_setup_stream(codec, spec->cur_adc, - spec->cur_adc_stream_tag, 0, - spec->cur_adc_format); - } - spec->cur_input = idx; - cs_update_input_select(codec); - return 1; -} - -static int cs_capture_source_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct cs_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - unsigned int idx; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = spec->num_inputs; - if (uinfo->value.enumerated.item >= spec->num_inputs) - uinfo->value.enumerated.item = spec->num_inputs - 1; - idx = spec->input_idx[uinfo->value.enumerated.item]; - snd_hda_get_pin_label(codec, cfg->inputs[idx].pin, cfg, - uinfo->value.enumerated.name, - sizeof(uinfo->value.enumerated.name), NULL); - return 0; -} - -static int cs_capture_source_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct cs_spec *spec = codec->spec; - ucontrol->value.enumerated.item[0] = spec->capsrc_idx[spec->cur_input]; - return 0; -} - -static int cs_capture_source_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct cs_spec *spec = codec->spec; - unsigned int idx = ucontrol->value.enumerated.item[0]; - - if (idx >= spec->num_inputs) - return -EINVAL; - idx = spec->input_idx[idx]; - return change_cur_input(codec, idx, 0); -} - -static const struct snd_kcontrol_new cs_capture_source = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, - .info = cs_capture_source_info, - .get = cs_capture_source_get, - .put = cs_capture_source_put, -}; - -static const struct hda_bind_ctls *make_bind_capture(struct hda_codec *codec, - struct hda_ctl_ops *ops) -{ - struct cs_spec *spec = codec->spec; - struct hda_bind_ctls *bind; - int i, n; - - bind = kzalloc(sizeof(*bind) + sizeof(long) * (spec->num_inputs + 1), - GFP_KERNEL); - if (!bind) - return NULL; - bind->ops = ops; - n = 0; - for (i = 0; i < AUTO_PIN_LAST; i++) { - if (!spec->adc_nid[i]) - continue; - bind->values[n++] = - HDA_COMPOSE_AMP_VAL(spec->adc_nid[i], 3, - spec->adc_idx[i], HDA_INPUT); - } - return bind; -} - -/* add a (input-boost) volume control to the given input pin */ -static int add_input_volume_control(struct hda_codec *codec, - struct auto_pin_cfg *cfg, - int item) -{ - hda_nid_t pin = cfg->inputs[item].pin; - u32 caps; - const char *label; - struct snd_kcontrol *kctl; - - if (!(get_wcaps(codec, pin) & AC_WCAP_IN_AMP)) - return 0; - caps = query_amp_caps(codec, pin, HDA_INPUT); - caps = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT; - if (caps <= 1) - return 0; - label = hda_get_autocfg_input_label(codec, cfg, item); - return add_volume(codec, label, 0, - HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_INPUT), 1, &kctl); -} - -static int build_input(struct hda_codec *codec) -{ - struct cs_spec *spec = codec->spec; - int i, err; - - if (!spec->num_inputs) - return 0; - - /* make bind-capture */ - spec->capture_bind[0] = make_bind_capture(codec, &snd_hda_bind_sw); - spec->capture_bind[1] = make_bind_capture(codec, &snd_hda_bind_vol); - for (i = 0; i < 2; i++) { - struct snd_kcontrol *kctl; - int n; - if (!spec->capture_bind[i]) - return -ENOMEM; - kctl = snd_ctl_new1(&cs_capture_ctls[i], codec); - if (!kctl) - return -ENOMEM; - kctl->private_value = (long)spec->capture_bind[i]; - err = snd_hda_ctl_add(codec, 0, kctl); - if (err < 0) - return err; - for (n = 0; n < AUTO_PIN_LAST; n++) { - if (!spec->adc_nid[n]) - continue; - err = snd_hda_add_nid(codec, kctl, 0, spec->adc_nid[n]); - if (err < 0) - return err; - } - } - - if (spec->num_inputs > 1 && !spec->mic_detect) { - err = snd_hda_ctl_add(codec, 0, - snd_ctl_new1(&cs_capture_source, codec)); - if (err < 0) - return err; - } - - for (i = 0; i < spec->num_inputs; i++) { - err = add_input_volume_control(codec, &spec->autocfg, i); - if (err < 0) - return err; - } - - return 0; -} - -/* - */ - -static int build_digital_output(struct hda_codec *codec) -{ - struct cs_spec *spec = codec->spec; - int err; - - if (!spec->multiout.dig_out_nid) - return 0; - - 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; - return 0; -} - -static int build_digital_input(struct hda_codec *codec) -{ - struct cs_spec *spec = codec->spec; - if (spec->dig_in) - return snd_hda_create_spdif_in_ctls(codec, spec->dig_in); - return 0; -} - /* * auto-mute and auto-mic switching * CS421x auto-output redirecting * HP/SPK/SPDIF */ -static void cs_automute(struct hda_codec *codec, struct hda_jack_tbl *tbl) +static void cs_automute(struct hda_codec *codec) { struct cs_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - unsigned int hp_present; - unsigned int spdif_present; - hda_nid_t nid; - int i; - - spdif_present = 0; - if (cfg->dig_outs) { - nid = cfg->dig_out_pins[0]; - if (is_jack_detectable(codec, nid)) { - /* - TODO: SPDIF output redirect when SENSE_B is enabled. - Shared (SENSE_A) jack (e.g HP/mini-TOSLINK) - assumed. - */ - if (snd_hda_jack_detect(codec, nid) - /* && spec->sense_b */) - spdif_present = 1; - } - } - hp_present = 0; - for (i = 0; i < cfg->hp_outs; i++) { - nid = cfg->hp_pins[i]; - if (!is_jack_detectable(codec, nid)) - continue; - hp_present = snd_hda_jack_detect(codec, nid); - if (hp_present) - break; - } + /* mute HPs if spdif jack (SENSE_B) is present */ + spec->gen.master_mute = !!(spec->spdif_present && spec->sense_b); - /* mute speakers if spdif or hp jack is plugged in */ - for (i = 0; i < cfg->speaker_outs; i++) { - int pin_ctl = hp_present ? 0 : PIN_OUT; - /* detect on spdif is specific to CS4210 */ - if (spdif_present && (spec->vendor_nid == CS4210_VENDOR_NID)) - pin_ctl = 0; + snd_hda_gen_update_outputs(codec); - nid = cfg->speaker_pins[i]; - snd_hda_set_pin_ctl(codec, nid, pin_ctl); - } if (spec->gpio_eapd_hp) { - unsigned int gpio = hp_present ? + unsigned int gpio = spec->gen.hp_jack_present ? spec->gpio_eapd_hp : spec->gpio_eapd_speaker; snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, gpio); } - - /* specific to CS4210 */ - if (spec->vendor_nid == CS4210_VENDOR_NID) { - /* mute HPs if spdif jack (SENSE_B) is present */ - for (i = 0; i < cfg->hp_outs; i++) { - nid = cfg->hp_pins[i]; - snd_hda_set_pin_ctl(codec, nid, - (spdif_present && spec->sense_b) ? 0 : PIN_HP); - } - - /* SPDIF TX on/off */ - if (cfg->dig_outs) { - nid = cfg->dig_out_pins[0]; - snd_hda_set_pin_ctl(codec, nid, - spdif_present ? PIN_OUT : 0); - - } - /* Update board GPIOs if neccessary ... */ - } } -/* - * Auto-input redirect for CS421x - * Switch max 3 inputs of a single ADC (nid 3) -*/ - -static void cs_automic(struct hda_codec *codec, struct hda_jack_tbl *tbl) +static bool is_active_pin(struct hda_codec *codec, hda_nid_t nid) { - struct cs_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - hda_nid_t nid; - unsigned int present; - - nid = cfg->inputs[spec->automic_idx].pin; - present = snd_hda_jack_detect(codec, nid); - - /* specific to CS421x, single ADC */ - if (spec->vendor_nid == CS420X_VENDOR_NID) { - if (present) - change_cur_input(codec, spec->automic_idx, 0); - else - change_cur_input(codec, !spec->automic_idx, 0); - } else { - if (present) { - if (spec->cur_input != spec->automic_idx) { - spec->last_input = spec->cur_input; - spec->cur_input = spec->automic_idx; - } - } else { - spec->cur_input = spec->last_input; - } - cs_update_input_select(codec); - } -} - -/* - */ - -static void init_output(struct hda_codec *codec) -{ - struct cs_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int i; - - /* mute first */ - for (i = 0; i < spec->multiout.num_dacs; i++) - snd_hda_codec_write(codec, spec->multiout.dac_nids[i], 0, - AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); - if (spec->multiout.hp_nid) - snd_hda_codec_write(codec, spec->multiout.hp_nid, 0, - AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); - for (i = 0; i < ARRAY_SIZE(spec->multiout.extra_out_nid); i++) { - if (!spec->multiout.extra_out_nid[i]) - break; - snd_hda_codec_write(codec, spec->multiout.extra_out_nid[i], 0, - AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); - } - - /* set appropriate pin controls */ - for (i = 0; i < cfg->line_outs; i++) - snd_hda_set_pin_ctl(codec, cfg->line_out_pins[i], PIN_OUT); - /* HP */ - for (i = 0; i < cfg->hp_outs; i++) { - hda_nid_t nid = cfg->hp_pins[i]; - snd_hda_set_pin_ctl(codec, nid, PIN_HP); - if (!cfg->speaker_outs) - continue; - if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) { - snd_hda_jack_detect_enable_callback(codec, nid, HP_EVENT, cs_automute); - spec->hp_detect = 1; - } - } - - /* Speaker */ - for (i = 0; i < cfg->speaker_outs; i++) - snd_hda_set_pin_ctl(codec, cfg->speaker_pins[i], PIN_OUT); - - /* SPDIF is enabled on presence detect for CS421x */ - if (spec->hp_detect || spec->spdif_detect) - cs_automute(codec, NULL); + unsigned int val; + val = snd_hda_codec_get_pincfg(codec, nid); + return (get_defcfg_connect(val) != AC_JACK_PORT_NONE); } -static void init_input(struct hda_codec *codec) +static void init_input_coef(struct hda_codec *codec) { struct cs_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; unsigned int coef; - int i; - for (i = 0; i < cfg->num_inputs; i++) { - unsigned int ctl; - hda_nid_t pin = cfg->inputs[i].pin; - if (!spec->adc_nid[i]) - continue; - /* set appropriate pin control and mute first */ - ctl = PIN_IN; - if (cfg->inputs[i].type == AUTO_PIN_MIC) - ctl |= snd_hda_get_default_vref(codec, pin); - snd_hda_set_pin_ctl(codec, pin, ctl); - snd_hda_codec_write(codec, spec->adc_nid[i], 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_IN_MUTE(spec->adc_idx[i])); - if (spec->mic_detect && spec->automic_idx == i) - snd_hda_jack_detect_enable_callback(codec, pin, MIC_EVENT, cs_automic); - } /* CS420x has multiple ADC, CS421x has single ADC */ if (spec->vendor_nid == CS420X_VENDOR_NID) { - change_cur_input(codec, spec->cur_input, 1); - if (spec->mic_detect) - cs_automic(codec, NULL); - - coef = 0x000a; /* ADC1/2 - Digital and Analog Soft Ramp */ - cs_vendor_coef_set(codec, IDX_ADC_CFG, coef); - coef = cs_vendor_coef_get(codec, IDX_BEEP_CFG); if (is_active_pin(codec, CS_DMIC2_PIN_NID)) coef |= 1 << 4; /* DMIC2 2 chan on, GPIO1 off */ @@ -1091,13 +199,6 @@ static void init_input(struct hda_codec *codec) */ cs_vendor_coef_set(codec, IDX_BEEP_CFG, coef); - } else { - if (spec->mic_detect) - cs_automic(codec, NULL); - else { - spec->cur_adc = spec->adc_nid[spec->cur_input]; - cs_update_input_select(codec); - } } } @@ -1110,6 +211,9 @@ static const struct hda_verb cs_coef_init_verbs[] = { | 0x1000 /* Enable DACs High Pass Filter */ | 0x0400 /* Disable Coefficient Auto increment */ )}, + /* ADC1/2 - Digital and Analog Soft Ramp */ + {0x11, AC_VERB_SET_COEF_INDEX, IDX_ADC_CFG}, + {0x11, AC_VERB_SET_PROC_COEF, 0x000a}, /* Beep */ {0x11, AC_VERB_SET_COEF_INDEX, IDX_BEEP_CFG}, {0x11, AC_VERB_SET_PROC_COEF, 0x0007}, /* Enable Beep thru DAC1/2/3 */ @@ -1166,16 +270,8 @@ static const struct hda_verb cs_errata_init_verbs[] = { {} /* terminator */ }; -static const struct hda_verb mbp101_init_verbs[] = { - {0x11, AC_VERB_SET_COEF_INDEX, 0x0002}, - {0x11, AC_VERB_SET_PROC_COEF, 0x100a}, - {0x11, AC_VERB_SET_COEF_INDEX, 0x0004}, - {0x11, AC_VERB_SET_PROC_COEF, 0x000f}, - {} -}; - /* SPDIF setup */ -static void init_digital(struct hda_codec *codec) +static void init_digital_coef(struct hda_codec *codec) { unsigned int coef; @@ -1198,6 +294,8 @@ static int cs_init(struct hda_codec *codec) snd_hda_sequence_write(codec, cs_coef_init_verbs); + snd_hda_gen_init(codec); + if (spec->gpio_mask) { snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_MASK, spec->gpio_mask); @@ -1207,53 +305,17 @@ static int cs_init(struct hda_codec *codec) spec->gpio_data); } - init_output(codec); - init_input(codec); - init_digital(codec); + init_input_coef(codec); + init_digital_coef(codec); return 0; } -static int cs_build_controls(struct hda_codec *codec) -{ - struct cs_spec *spec = codec->spec; - int err; - - err = build_output(codec); - if (err < 0) - return err; - err = build_input(codec); - if (err < 0) - return err; - err = build_digital_output(codec); - if (err < 0) - return err; - err = build_digital_input(codec); - if (err < 0) - return err; - err = cs_init(codec); - if (err < 0) - return err; - - err = snd_hda_jack_add_kctls(codec, &spec->autocfg); - if (err < 0) - return err; - - return 0; -} - -static void cs_free(struct hda_codec *codec) -{ - struct cs_spec *spec = codec->spec; - kfree(spec->capture_bind[0]); - kfree(spec->capture_bind[1]); - snd_hda_gen_free(&spec->gen); - kfree(codec->spec); -} +#define cs_free snd_hda_gen_free static const struct hda_codec_ops cs_patch_ops = { - .build_controls = cs_build_controls, - .build_pcms = cs_build_pcms, + .build_controls = snd_hda_gen_build_controls, + .build_pcms = snd_hda_gen_build_pcms, .init = cs_init, .free = cs_free, .unsol_event = snd_hda_jack_unsol_event, @@ -1264,22 +326,14 @@ static int cs_parse_auto_config(struct hda_codec *codec) struct cs_spec *spec = codec->spec; int err; - err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); + err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, NULL, 0); if (err < 0) return err; - err = parse_output(codec); - if (err < 0) - return err; - err = parse_input(codec); - if (err < 0) - return err; - err = parse_digital_output(codec); - if (err < 0) - return err; - err = parse_digital_input(codec); + err = snd_hda_gen_parse_auto_config(codec, &spec->gen.autocfg); if (err < 0) return err; + return 0; } @@ -1290,6 +344,7 @@ static const struct hda_model_fixup cs420x_models[] = { { .id = CS420X_IMAC27_122, .name = "imac27_122" }, { .id = CS420X_APPLE, .name = "apple" }, { .id = CS420X_MBP101, .name = "mbp101" }, + { .id = CS420X_MBP81, .name = "mbp81" }, {} }; @@ -1302,6 +357,7 @@ static const struct snd_pci_quirk cs420x_fixup_tbl[] = { /*SND_PCI_QUIRK(0x8086, 0x7270, "IMac 27 Inch", CS420X_IMAC27),*/ /* codec SSID */ + SND_PCI_QUIRK(0x106b, 0x1c00, "MacBookPro 8,1", CS420X_MBP81), SND_PCI_QUIRK(0x106b, 0x2000, "iMac 12,2", CS420X_IMAC27_122), SND_PCI_QUIRK(0x106b, 0x2800, "MacBookPro 10,1", CS420X_MBP101), SND_PCI_QUIRK_VENDOR(0x106b, "Apple", CS420X_APPLE), @@ -1412,28 +468,43 @@ static const struct hda_fixup cs420x_fixups[] = { .type = HDA_FIXUP_PINS, .v.pins = mbp101_pincfgs, .chained = true, - .chain_id = CS420X_MBP101_COEF, + .chain_id = CS420X_GPIO_13, }, - [CS420X_MBP101_COEF] = { + [CS420X_MBP81] = { .type = HDA_FIXUP_VERBS, - .v.verbs = mbp101_init_verbs, + .v.verbs = (const struct hda_verb[]) { + /* internal mic ADC2: right only, single ended */ + {0x11, AC_VERB_SET_COEF_INDEX, IDX_ADC_CFG}, + {0x11, AC_VERB_SET_PROC_COEF, 0x102a}, + {} + }, .chained = true, .chain_id = CS420X_GPIO_13, }, }; -static int patch_cs420x(struct hda_codec *codec) +static struct cs_spec *cs_alloc_spec(struct hda_codec *codec, int vendor_nid) { struct cs_spec *spec; - int err; spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (!spec) - return -ENOMEM; + return NULL; codec->spec = spec; - snd_hda_gen_init(&spec->gen); + spec->vendor_nid = vendor_nid; + snd_hda_gen_spec_init(&spec->gen); - spec->vendor_nid = CS420X_VENDOR_NID; + return spec; +} + +static int patch_cs420x(struct hda_codec *codec) +{ + struct cs_spec *spec; + int err; + + spec = cs_alloc_spec(codec, CS420X_VENDOR_NID); + if (!spec) + return -ENOMEM; snd_hda_pick_fixup(codec, cs420x_models, cs420x_fixup_tbl, cs420x_fixups); @@ -1451,7 +522,6 @@ static int patch_cs420x(struct hda_codec *codec) error: cs_free(codec); - codec->spec = NULL; return err; } @@ -1610,7 +680,7 @@ static int cs421x_boost_vol_put(struct snd_kcontrol *kcontrol, } } -static const struct snd_kcontrol_new cs421x_speaker_bost_ctl = { +static const struct snd_kcontrol_new cs421x_speaker_boost_ctl = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | @@ -1655,20 +725,44 @@ static void cs4210_pinmux_init(struct hda_codec *codec) } } -static void init_cs421x_digital(struct hda_codec *codec) +static void cs4210_spdif_automute(struct hda_codec *codec, + struct hda_jack_tbl *tbl) { struct cs_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int i; + bool spdif_present = false; + hda_nid_t spdif_pin = spec->gen.autocfg.dig_out_pins[0]; + + /* detect on spdif is specific to CS4210 */ + if (!spec->spdif_detect || + spec->vendor_nid != CS4210_VENDOR_NID) + return; + + spdif_present = snd_hda_jack_detect(codec, spdif_pin); + if (spdif_present == spec->spdif_present) + return; + spec->spdif_present = spdif_present; + /* SPDIF TX on/off */ + if (spdif_present) + snd_hda_set_pin_ctl(codec, spdif_pin, + spdif_present ? PIN_OUT : 0); + + cs_automute(codec); +} + +static void parse_cs421x_digital(struct hda_codec *codec) +{ + struct cs_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->gen.autocfg; + int i; for (i = 0; i < cfg->dig_outs; i++) { hda_nid_t nid = cfg->dig_out_pins[i]; - if (!cfg->speaker_outs) - continue; if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) { - snd_hda_jack_detect_enable_callback(codec, nid, SPDIF_EVENT, cs_automute); spec->spdif_detect = 1; + snd_hda_jack_detect_enable_callback(codec, nid, + SPDIF_EVENT, + cs4210_spdif_automute); } } } @@ -1683,6 +777,8 @@ static int cs421x_init(struct hda_codec *codec) cs4210_pinmux_init(codec); } + snd_hda_gen_init(codec); + if (spec->gpio_mask) { snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_MASK, spec->gpio_mask); @@ -1692,233 +788,61 @@ static int cs421x_init(struct hda_codec *codec) spec->gpio_data); } - init_output(codec); - init_input(codec); - init_cs421x_digital(codec); - - return 0; -} - -/* - * CS4210 Input MUX (1 ADC) - */ -static int cs421x_mux_enum_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct cs_spec *spec = codec->spec; - - return snd_hda_input_mux_info(&spec->input_mux, uinfo); -} - -static int cs421x_mux_enum_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct cs_spec *spec = codec->spec; - - ucontrol->value.enumerated.item[0] = spec->cur_input; - return 0; -} - -static int cs421x_mux_enum_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct cs_spec *spec = codec->spec; - - return snd_hda_input_mux_put(codec, &spec->input_mux, ucontrol, - spec->adc_nid[0], &spec->cur_input); - -} - -static const struct snd_kcontrol_new cs421x_capture_source = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, - .info = cs421x_mux_enum_info, - .get = cs421x_mux_enum_get, - .put = cs421x_mux_enum_put, -}; - -static int cs421x_add_input_volume_control(struct hda_codec *codec, int item) -{ - struct cs_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - const struct hda_input_mux *imux = &spec->input_mux; - hda_nid_t pin = cfg->inputs[item].pin; - struct snd_kcontrol *kctl; - u32 caps; - - if (!(get_wcaps(codec, pin) & AC_WCAP_IN_AMP)) - return 0; - - caps = query_amp_caps(codec, pin, HDA_INPUT); - caps = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT; - if (caps <= 1) - return 0; - - return add_volume(codec, imux->items[item].label, 0, - HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_INPUT), 1, &kctl); -} - -/* add a (input-boost) volume control to the given input pin */ -static int build_cs421x_input(struct hda_codec *codec) -{ - struct cs_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - struct hda_input_mux *imux = &spec->input_mux; - int i, err, type_idx; - const char *label; - - if (!spec->num_inputs) - return 0; - - /* make bind-capture */ - spec->capture_bind[0] = make_bind_capture(codec, &snd_hda_bind_sw); - spec->capture_bind[1] = make_bind_capture(codec, &snd_hda_bind_vol); - for (i = 0; i < 2; i++) { - struct snd_kcontrol *kctl; - int n; - if (!spec->capture_bind[i]) - return -ENOMEM; - kctl = snd_ctl_new1(&cs_capture_ctls[i], codec); - if (!kctl) - return -ENOMEM; - kctl->private_value = (long)spec->capture_bind[i]; - err = snd_hda_ctl_add(codec, 0, kctl); - if (err < 0) - return err; - for (n = 0; n < AUTO_PIN_LAST; n++) { - if (!spec->adc_nid[n]) - continue; - err = snd_hda_add_nid(codec, kctl, 0, spec->adc_nid[n]); - if (err < 0) - return err; - } - } - - /* Add Input MUX Items + Capture Volume/Switch */ - for (i = 0; i < spec->num_inputs; i++) { - label = hda_get_autocfg_input_label(codec, cfg, i); - snd_hda_add_imux_item(imux, label, spec->adc_idx[i], &type_idx); - - err = cs421x_add_input_volume_control(codec, i); - if (err < 0) - return err; - } - - /* - Add 'Capture Source' Switch if - * 2 inputs and no mic detec - * 3 inputs - */ - if ((spec->num_inputs == 2 && !spec->mic_detect) || - (spec->num_inputs == 3)) { + init_input_coef(codec); - err = snd_hda_ctl_add(codec, spec->adc_nid[0], - snd_ctl_new1(&cs421x_capture_source, codec)); - if (err < 0) - return err; - } + cs4210_spdif_automute(codec, NULL); return 0; } -/* Single DAC (Mute/Gain) */ -static int build_cs421x_output(struct hda_codec *codec) +static int cs421x_build_controls(struct hda_codec *codec) { - hda_nid_t dac = CS4210_DAC_NID; struct cs_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - struct snd_kcontrol *kctl; int err; - char *name = "Master"; - - fix_volume_caps(codec, dac); - err = add_mute(codec, name, 0, - HDA_COMPOSE_AMP_VAL(dac, 3, 0, HDA_OUTPUT), 0, &kctl); + err = snd_hda_gen_build_controls(codec); if (err < 0) return err; - err = add_volume(codec, name, 0, - HDA_COMPOSE_AMP_VAL(dac, 3, 0, HDA_OUTPUT), 0, &kctl); - if (err < 0) - return err; - - if (cfg->speaker_outs && (spec->vendor_nid == CS4210_VENDOR_NID)) { + if (spec->gen.autocfg.speaker_outs && + spec->vendor_nid == CS4210_VENDOR_NID) { err = snd_hda_ctl_add(codec, 0, - snd_ctl_new1(&cs421x_speaker_bost_ctl, codec)); + snd_ctl_new1(&cs421x_speaker_boost_ctl, codec)); if (err < 0) return err; } - return err; -} - -static int cs421x_build_controls(struct hda_codec *codec) -{ - struct cs_spec *spec = codec->spec; - int err; - - err = build_cs421x_output(codec); - if (err < 0) - return err; - err = build_cs421x_input(codec); - if (err < 0) - return err; - err = build_digital_output(codec); - if (err < 0) - return err; - err = cs421x_init(codec); - if (err < 0) - return err; - - err = snd_hda_jack_add_kctls(codec, &spec->autocfg); - if (err < 0) - return err; - return 0; } -static int parse_cs421x_input(struct hda_codec *codec) +static void fix_volume_caps(struct hda_codec *codec, hda_nid_t dac) { - struct cs_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int i; - - for (i = 0; i < cfg->num_inputs; i++) { - hda_nid_t pin = cfg->inputs[i].pin; - spec->adc_nid[i] = get_adc(codec, pin, &spec->adc_idx[i]); - spec->cur_input = spec->last_input = i; - spec->num_inputs++; + unsigned int caps; - /* check whether the automatic mic switch is available */ - if (is_ext_mic(codec, i) && cfg->num_inputs >= 2) { - spec->mic_detect = 1; - spec->automic_idx = i; - } - } - return 0; + /* set the upper-limit for mixer amp to 0dB */ + caps = query_amp_caps(codec, dac, HDA_OUTPUT); + caps &= ~(0x7f << AC_AMPCAP_NUM_STEPS_SHIFT); + caps |= ((caps >> AC_AMPCAP_OFFSET_SHIFT) & 0x7f) + << AC_AMPCAP_NUM_STEPS_SHIFT; + snd_hda_override_amp_caps(codec, dac, HDA_OUTPUT, caps); } static int cs421x_parse_auto_config(struct hda_codec *codec) { struct cs_spec *spec = codec->spec; + hda_nid_t dac = CS4210_DAC_NID; int err; - err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); - if (err < 0) - return err; - err = parse_output(codec); - if (err < 0) - return err; - err = parse_cs421x_input(codec); + fix_volume_caps(codec, dac); + + err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, NULL, 0); if (err < 0) return err; - err = parse_digital_output(codec); + + err = snd_hda_gen_parse_auto_config(codec, &spec->gen.autocfg); if (err < 0) return err; + + parse_cs421x_digital(codec); return 0; } @@ -1951,7 +875,7 @@ static int cs421x_suspend(struct hda_codec *codec) static const struct hda_codec_ops cs421x_patch_ops = { .build_controls = cs421x_build_controls, - .build_pcms = cs_build_pcms, + .build_pcms = snd_hda_gen_build_pcms, .init = cs421x_init, .free = cs_free, .unsol_event = snd_hda_jack_unsol_event, @@ -1965,13 +889,9 @@ static int patch_cs4210(struct hda_codec *codec) struct cs_spec *spec; int err; - spec = kzalloc(sizeof(*spec), GFP_KERNEL); + spec = cs_alloc_spec(codec, CS4210_VENDOR_NID); if (!spec) return -ENOMEM; - codec->spec = spec; - snd_hda_gen_init(&spec->gen); - - spec->vendor_nid = CS4210_VENDOR_NID; snd_hda_pick_fixup(codec, cs421x_models, cs421x_fixup_tbl, cs421x_fixups); @@ -1996,7 +916,6 @@ static int patch_cs4210(struct hda_codec *codec) error: cs_free(codec); - codec->spec = NULL; return err; } @@ -2005,13 +924,9 @@ static int patch_cs4213(struct hda_codec *codec) struct cs_spec *spec; int err; - spec = kzalloc(sizeof(*spec), GFP_KERNEL); + spec = cs_alloc_spec(codec, CS4213_VENDOR_NID); if (!spec) return -ENOMEM; - codec->spec = spec; - snd_hda_gen_init(&spec->gen); - - spec->vendor_nid = CS4213_VENDOR_NID; err = cs421x_parse_auto_config(codec); if (err < 0) @@ -2022,7 +937,6 @@ static int patch_cs4213(struct hda_codec *codec) error: cs_free(codec); - codec->spec = NULL; return err; } diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c index c8fdaaefe702..9c6ce73b03c5 100644 --- a/sound/pci/hda/patch_cmedia.c +++ b/sound/pci/hda/patch_cmedia.c @@ -22,7 +22,6 @@ */ #include <linux/init.h> -#include <linux/delay.h> #include <linux/slab.h> #include <linux/pci.h> #include <linux/module.h> @@ -30,6 +29,9 @@ #include "hda_codec.h" #include "hda_local.h" #include "hda_auto_parser.h" +#include "hda_jack.h" +#include "hda_generic.h" + #define NUM_PINS 11 @@ -45,6 +47,10 @@ enum { }; struct cmi_spec { + struct hda_gen_spec gen; + + /* 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 */ @@ -356,77 +362,6 @@ static int cmi9880_build_controls(struct hda_codec *codec) return 0; } -/* fill in the multi_dac_nids table, which will decide - which audio widget to use for each channel */ -static int cmi9880_fill_multi_dac_nids(struct hda_codec *codec, const struct auto_pin_cfg *cfg) -{ - struct cmi_spec *spec = codec->spec; - hda_nid_t nid; - int assigned[4]; - int i, j; - - /* clear the table, only one c-media dac assumed here */ - memset(spec->dac_nids, 0, sizeof(spec->dac_nids)); - memset(assigned, 0, sizeof(assigned)); - /* check the pins we found */ - for (i = 0; i < cfg->line_outs; i++) { - nid = cfg->line_out_pins[i]; - /* nid 0x0b~0x0e is hardwired to audio widget 0x3~0x6 */ - if (nid >= 0x0b && nid <= 0x0e) { - spec->dac_nids[i] = (nid - 0x0b) + 0x03; - assigned[nid - 0x0b] = 1; - } - } - /* left pin can be connect to any audio widget */ - for (i = 0; i < cfg->line_outs; i++) { - nid = cfg->line_out_pins[i]; - if (nid <= 0x0e) - continue; - /* search for an empty channel */ - for (j = 0; j < cfg->line_outs; j++) { - if (! assigned[j]) { - spec->dac_nids[i] = j + 0x03; - assigned[j] = 1; - break; - } - } - } - spec->num_dacs = cfg->line_outs; - return 0; -} - -/* create multi_init table, which is used for multichannel initialization */ -static int cmi9880_fill_multi_init(struct hda_codec *codec, const struct auto_pin_cfg *cfg) -{ - struct cmi_spec *spec = codec->spec; - hda_nid_t nid; - int i, j, k; - - /* clear the table, only one c-media dac assumed here */ - memset(spec->multi_init, 0, sizeof(spec->multi_init)); - for (j = 0, i = 0; i < cfg->line_outs; i++) { - nid = cfg->line_out_pins[i]; - /* set as output */ - spec->multi_init[j].nid = nid; - spec->multi_init[j].verb = AC_VERB_SET_PIN_WIDGET_CONTROL; - spec->multi_init[j].param = PIN_OUT; - j++; - if (nid > 0x0e) { - /* set connection */ - spec->multi_init[j].nid = nid; - spec->multi_init[j].verb = AC_VERB_SET_CONNECT_SEL; - spec->multi_init[j].param = 0; - /* find the index in connect list */ - k = snd_hda_get_conn_index(codec, nid, - spec->dac_nids[i], 0); - if (k >= 0) - spec->multi_init[j].param = k; - j++; - } - } - return 0; -} - static int cmi9880_init(struct hda_codec *codec) { struct cmi_spec *spec = codec->spec; @@ -632,6 +567,36 @@ static const struct hda_codec_ops cmi9880_patch_ops = { .free = cmi9880_free, }; +/* + * stuff for auto-parser + */ +static const struct hda_codec_ops cmi_auto_patch_ops = { + .build_controls = snd_hda_gen_build_controls, + .build_pcms = snd_hda_gen_build_pcms, + .init = snd_hda_gen_init, + .free = snd_hda_gen_free, + .unsol_event = snd_hda_jack_unsol_event, +}; + +static int cmi_parse_auto_config(struct hda_codec *codec) +{ + struct cmi_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->gen.autocfg; + int err; + + snd_hda_gen_spec_init(&spec->gen); + + err = snd_hda_parse_pin_defcfg(codec, cfg, NULL, 0); + if (err < 0) + return err; + err = snd_hda_gen_parse_auto_config(codec, cfg); + if (err < 0) + return err; + + codec->patch_ops = cmi_auto_patch_ops; + return 0; +} + static int patch_cmi9880(struct hda_codec *codec) { struct cmi_spec *spec; @@ -650,6 +615,15 @@ static int patch_cmi9880(struct hda_codec *codec) spec->board_config = CMI_AUTO; /* try everything */ } + if (spec->board_config == CMI_AUTO) { + int err = cmi_parse_auto_config(codec); + if (err < 0) { + snd_hda_gen_free(codec); + return err; + } + return 0; + } + /* copy default DAC NIDs */ memcpy(spec->dac_nids, cmi9880_dac_nids, sizeof(spec->dac_nids)); spec->num_dacs = 4; @@ -678,59 +652,13 @@ static int patch_cmi9880(struct hda_codec *codec) } 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; - case CMI_AUTO: - { - unsigned int port_e, port_f, port_g, port_h; - unsigned int port_spdifi, port_spdifo; - struct auto_pin_cfg cfg; - - /* collect pin default configuration */ - port_e = snd_hda_codec_get_pincfg(codec, 0x0f); - port_f = snd_hda_codec_get_pincfg(codec, 0x10); - spec->front_panel = 1; - if (get_defcfg_connect(port_e) == AC_JACK_PORT_NONE || - get_defcfg_connect(port_f) == AC_JACK_PORT_NONE) { - port_g = snd_hda_codec_get_pincfg(codec, 0x1f); - port_h = snd_hda_codec_get_pincfg(codec, 0x20); - spec->channel_modes = cmi9880_channel_modes; - /* no front panel */ - if (get_defcfg_connect(port_g) == AC_JACK_PORT_NONE || - get_defcfg_connect(port_h) == AC_JACK_PORT_NONE) { - /* no optional rear panel */ - spec->board_config = CMI_MINIMAL; - spec->front_panel = 0; - spec->num_channel_modes = 2; - } else { - spec->board_config = CMI_MIN_FP; - spec->num_channel_modes = 3; - } - spec->input_mux = &cmi9880_basic_mux; - spec->multiout.max_channels = cmi9880_channel_modes[0].channels; - } else { - spec->input_mux = &cmi9880_basic_mux; - port_spdifi = snd_hda_codec_get_pincfg(codec, 0x13); - port_spdifo = snd_hda_codec_get_pincfg(codec, 0x12); - if (get_defcfg_connect(port_spdifo) != AC_JACK_PORT_NONE) - spec->multiout.dig_out_nid = CMI_DIG_OUT_NID; - if (get_defcfg_connect(port_spdifi) != AC_JACK_PORT_NONE) - spec->dig_in_nid = CMI_DIG_IN_NID; - spec->multiout.max_channels = 8; - } - snd_hda_parse_pin_def_config(codec, &cfg, NULL); - if (cfg.line_outs) { - spec->multiout.max_channels = cfg.line_outs * 2; - cmi9880_fill_multi_dac_nids(codec, &cfg); - cmi9880_fill_multi_init(codec, &cfg); - } else - snd_printd("patch_cmedia: cannot detect association in defcfg\n"); - break; - } } spec->multiout.num_dacs = spec->num_dacs; diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 03b1dc317ff0..7d941ef54172 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -33,6 +33,9 @@ #include "hda_auto_parser.h" #include "hda_beep.h" #include "hda_jack.h" +#include "hda_generic.h" + +#define ENABLE_CXT_STATIC_QUIRKS #define CXT_PIN_DIR_IN 0x00 #define CXT_PIN_DIR_OUT 0x01 @@ -53,27 +56,19 @@ #define AUTO_MIC_PORTB (1 << 1) #define AUTO_MIC_PORTC (1 << 2) -struct pin_dac_pair { - hda_nid_t pin; - hda_nid_t dac; - int type; -}; - -struct imux_info { - hda_nid_t pin; /* input pin NID */ - hda_nid_t adc; /* connected ADC NID */ - hda_nid_t boost; /* optional boost volume NID */ - int index; /* corresponding to autocfg.input */ -}; - struct conexant_spec { struct hda_gen_spec gen; + unsigned int beep_amp; + + /* extra EAPD pins */ + unsigned int num_eapds; + hda_nid_t eapds[4]; + +#ifdef ENABLE_CXT_STATIC_QUIRKS const struct snd_kcontrol_new *mixers[5]; int num_mixers; hda_nid_t vmaster_nid; - struct hda_vmaster_mute_hook vmaster_mute; - bool vmaster_mute_led; const struct hda_verb *init_verbs[5]; /* initialization verbs * don't forget NULL @@ -90,11 +85,6 @@ struct conexant_spec { unsigned int hp_present; unsigned int line_present; unsigned int auto_mic; - int auto_mic_ext; /* imux_pins[] index for ext mic */ - int auto_mic_dock; /* imux_pins[] index for dock mic */ - int auto_mic_int; /* imux_pins[] index for int mic */ - unsigned int need_dac_fix; - hda_nid_t slave_dig_outs[2]; /* capture */ unsigned int num_adc_nids; @@ -122,30 +112,13 @@ struct conexant_spec { unsigned int spdif_route; - /* dynamic controls, init_verbs and input_mux */ - struct auto_pin_cfg autocfg; - struct hda_input_mux private_imux; - struct imux_info imux_info[HDA_MAX_NUM_INPUTS]; - hda_nid_t private_adc_nids[HDA_MAX_NUM_INPUTS]; - hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS]; - struct pin_dac_pair dac_info[8]; - int dac_info_filled; - unsigned int port_d_mode; - unsigned int auto_mute:1; /* used in auto-parser */ - unsigned int detect_line:1; /* Line-out detection enabled */ - unsigned int automute_lines:1; /* automute line-out as well */ - unsigned int automute_hp_lo:1; /* both HP and LO available */ 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 pin_eapd_ctrls:1; - unsigned int fixup_stereo_dmic:1; - - unsigned int adc_switching:1; unsigned int ext_mic_present; unsigned int recording; @@ -161,14 +134,48 @@ struct conexant_spec { unsigned int dc_enable; unsigned int dc_input_bias; /* offset into cxt5066_olpc_dc_bias */ unsigned int mic_boost; /* offset into cxt5066_analog_mic_boost */ +#endif /* ENABLE_CXT_STATIC_QUIRKS */ +}; - unsigned int beep_amp; - /* extra EAPD pins */ - unsigned int num_eapds; - hda_nid_t eapds[4]; +#ifdef CONFIG_SND_HDA_INPUT_BEEP +#define set_beep_amp(spec, nid, idx, dir) \ + ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir)) +/* additional beep mixers; the actual parameters are overwritten at build */ +static const struct snd_kcontrol_new cxt_beep_mixer[] = { + HDA_CODEC_VOLUME_MONO("Beep Playback Volume", 0, 1, 0, HDA_OUTPUT), + HDA_CODEC_MUTE_BEEP_MONO("Beep Playback Switch", 0, 1, 0, HDA_OUTPUT), + { } /* end */ }; +/* create beep controls if needed */ +static int add_beep_ctls(struct hda_codec *codec) +{ + struct conexant_spec *spec = codec->spec; + int err; + + if (spec->beep_amp) { + const struct snd_kcontrol_new *knew; + for (knew = cxt_beep_mixer; knew->name; knew++) { + struct snd_kcontrol *kctl; + kctl = snd_ctl_new1(knew, codec); + if (!kctl) + return -ENOMEM; + kctl->private_value = spec->beep_amp; + err = snd_hda_ctl_add(codec, 0, kctl); + if (err < 0) + return err; + } + } + return 0; +} +#else +#define set_beep_amp(spec, nid, idx, dir) /* NOP */ +#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) @@ -381,8 +388,6 @@ static int conexant_build_pcms(struct hda_codec *codec) info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid; } - if (spec->slave_dig_outs[0]) - codec->slave_dig_outs = spec->slave_dig_outs; } return 0; @@ -430,7 +435,7 @@ static void conexant_set_power(struct hda_codec *codec, hda_nid_t fg, /* 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, true); + snd_hda_codec_set_power_to_all(codec, fg, power_state); } static int conexant_init(struct hda_codec *codec) @@ -446,7 +451,6 @@ static int conexant_init(struct hda_codec *codec) static void conexant_free(struct hda_codec *codec) { struct conexant_spec *spec = codec->spec; - snd_hda_gen_free(&spec->gen); snd_hda_detach_beep_device(codec); kfree(spec); } @@ -462,17 +466,8 @@ static const struct snd_kcontrol_new cxt_capture_mixers[] = { {} }; -#ifdef CONFIG_SND_HDA_INPUT_BEEP -/* additional beep mixers; the actual parameters are overwritten at build */ -static const struct snd_kcontrol_new cxt_beep_mixer[] = { - HDA_CODEC_VOLUME_MONO("Beep Playback Volume", 0, 1, 0, HDA_OUTPUT), - HDA_CODEC_MUTE_BEEP_MONO("Beep Playback Switch", 0, 1, 0, HDA_OUTPUT), - { } /* end */ -}; -#endif - static const char * const slave_pfxs[] = { - "Headphone", "Speaker", "Front", "Surround", "CLFE", + "Headphone", "Speaker", "Bass Speaker", "Front", "Surround", "CLFE", NULL }; @@ -519,10 +514,9 @@ static int conexant_build_controls(struct hda_codec *codec) } 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", true, - &spec->vmaster_mute.sw_kctl); + err = snd_hda_add_vmaster(codec, "Master Playback Switch", + NULL, slave_pfxs, + "Playback Switch"); if (err < 0) return err; } @@ -533,33 +527,12 @@ static int conexant_build_controls(struct hda_codec *codec) return err; } -#ifdef CONFIG_SND_HDA_INPUT_BEEP - /* create beep controls if needed */ - if (spec->beep_amp) { - const struct snd_kcontrol_new *knew; - for (knew = cxt_beep_mixer; knew->name; knew++) { - struct snd_kcontrol *kctl; - kctl = snd_ctl_new1(knew, codec); - if (!kctl) - return -ENOMEM; - kctl->private_value = spec->beep_amp; - err = snd_hda_ctl_add(codec, 0, kctl); - if (err < 0) - return err; - } - } -#endif - - return 0; -} + err = add_beep_ctls(codec); + if (err < 0) + return err; -#ifdef CONFIG_PM -static int conexant_suspend(struct hda_codec *codec) -{ - snd_hda_shutup_pins(codec); return 0; } -#endif static const struct hda_codec_ops conexant_patch_ops = { .build_controls = conexant_build_controls, @@ -567,19 +540,8 @@ static const struct hda_codec_ops conexant_patch_ops = { .init = conexant_init, .free = conexant_free, .set_power_state = conexant_set_power, -#ifdef CONFIG_PM - .suspend = conexant_suspend, -#endif - .reboot_notify = snd_hda_shutup_pins, }; -#ifdef CONFIG_SND_HDA_INPUT_BEEP -#define set_beep_amp(spec, nid, idx, dir) \ - ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir)) -#else -#define set_beep_amp(spec, nid, idx, dir) /* NOP */ -#endif - static int patch_conexant_auto(struct hda_codec *codec); /* * EAPD control @@ -663,8 +625,6 @@ static int conexant_ch_mode_put(struct snd_kcontrol *kcontrol, int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode, spec->num_channel_mode, &spec->multiout.max_channels); - if (err >= 0 && spec->need_dac_fix) - spec->multiout.num_dacs = spec->multiout.max_channels / 2; return err; } @@ -2503,10 +2463,6 @@ static void conexant_check_dig_outs(struct hda_codec *codec, continue; if (snd_hda_get_connections(codec, *dig_pins, nid_loc, 1) != 1) continue; - if (spec->slave_dig_outs[0]) - nid_loc++; - else - nid_loc = spec->slave_dig_outs; } } @@ -3148,641 +3104,12 @@ static int patch_cxt5066(struct hda_codec *codec) return 0; } -/* - * Automatic parser for CX20641 & co - */ - -static int cx_auto_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; - hda_nid_t adc = spec->imux_info[spec->cur_mux[0]].adc; - if (spec->adc_switching) { - spec->cur_adc = adc; - spec->cur_adc_stream_tag = stream_tag; - spec->cur_adc_format = format; - } - snd_hda_codec_setup_stream(codec, adc, stream_tag, 0, format); - return 0; -} - -static int cx_auto_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 cx_auto_pcm_analog_capture = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - .nid = 0, /* fill later */ - .ops = { - .prepare = cx_auto_capture_pcm_prepare, - .cleanup = cx_auto_capture_pcm_cleanup - }, -}; - -static const hda_nid_t cx_auto_adc_nids[] = { 0x14 }; - -#define get_connection_index(codec, mux, nid)\ - snd_hda_get_conn_index(codec, mux, nid, 0) - -/* get an unassigned DAC from the given list. - * Return the nid if found and reduce the DAC list, or return zero if - * not found - */ -static hda_nid_t get_unassigned_dac(struct hda_codec *codec, hda_nid_t pin, - hda_nid_t *dacs, int *num_dacs) -{ - int i, nums = *num_dacs; - hda_nid_t ret = 0; - - for (i = 0; i < nums; i++) { - if (get_connection_index(codec, pin, dacs[i]) >= 0) { - ret = dacs[i]; - break; - } - } - if (!ret) - return 0; - if (--nums > 0) - memmove(dacs, dacs + 1, nums * sizeof(hda_nid_t)); - *num_dacs = nums; - return ret; -} - -#define MAX_AUTO_DACS 5 - -#define DAC_SLAVE_FLAG 0x8000 /* filled dac is a slave */ - -/* fill analog DAC list from the widget tree */ -static int fill_cx_auto_dacs(struct hda_codec *codec, hda_nid_t *dacs) -{ - hda_nid_t nid, end_nid; - int nums = 0; - - end_nid = codec->start_nid + codec->num_nodes; - for (nid = codec->start_nid; nid < end_nid; nid++) { - unsigned int wcaps = get_wcaps(codec, nid); - unsigned int type = get_wcaps_type(wcaps); - if (type == AC_WID_AUD_OUT && !(wcaps & AC_WCAP_DIGITAL)) { - dacs[nums++] = nid; - if (nums >= MAX_AUTO_DACS) - break; - } - } - return nums; -} - -/* fill pin_dac_pair list from the pin and dac list */ -static int fill_dacs_for_pins(struct hda_codec *codec, hda_nid_t *pins, - int num_pins, hda_nid_t *dacs, int *rest, - struct pin_dac_pair *filled, int nums, - int type) -{ - int i, start = nums; - - for (i = 0; i < num_pins; i++, nums++) { - filled[nums].pin = pins[i]; - filled[nums].type = type; - filled[nums].dac = get_unassigned_dac(codec, pins[i], dacs, rest); - if (filled[nums].dac) - continue; - if (filled[start].dac && get_connection_index(codec, pins[i], filled[start].dac) >= 0) { - filled[nums].dac = filled[start].dac | DAC_SLAVE_FLAG; - continue; - } - if (filled[0].dac && get_connection_index(codec, pins[i], filled[0].dac) >= 0) { - filled[nums].dac = filled[0].dac | DAC_SLAVE_FLAG; - continue; - } - snd_printdd("Failed to find a DAC for pin 0x%x", pins[i]); - } - return nums; -} - -/* parse analog output paths */ -static void cx_auto_parse_output(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - hda_nid_t dacs[MAX_AUTO_DACS]; - int i, j, nums, rest; - - rest = fill_cx_auto_dacs(codec, dacs); - /* parse all analog output pins */ - nums = fill_dacs_for_pins(codec, cfg->line_out_pins, cfg->line_outs, - dacs, &rest, spec->dac_info, 0, - AUTO_PIN_LINE_OUT); - nums = fill_dacs_for_pins(codec, cfg->hp_pins, cfg->hp_outs, - dacs, &rest, spec->dac_info, nums, - AUTO_PIN_HP_OUT); - nums = fill_dacs_for_pins(codec, cfg->speaker_pins, cfg->speaker_outs, - dacs, &rest, spec->dac_info, nums, - AUTO_PIN_SPEAKER_OUT); - spec->dac_info_filled = nums; - /* fill multiout struct */ - for (i = 0; i < nums; i++) { - hda_nid_t dac = spec->dac_info[i].dac; - if (!dac || (dac & DAC_SLAVE_FLAG)) - continue; - switch (spec->dac_info[i].type) { - case AUTO_PIN_LINE_OUT: - spec->private_dac_nids[spec->multiout.num_dacs] = dac; - spec->multiout.num_dacs++; - break; - case AUTO_PIN_HP_OUT: - case AUTO_PIN_SPEAKER_OUT: - if (!spec->multiout.hp_nid) { - spec->multiout.hp_nid = dac; - break; - } - for (j = 0; j < ARRAY_SIZE(spec->multiout.extra_out_nid); j++) - if (!spec->multiout.extra_out_nid[j]) { - spec->multiout.extra_out_nid[j] = dac; - break; - } - break; - } - } - spec->multiout.dac_nids = spec->private_dac_nids; - spec->multiout.max_channels = spec->multiout.num_dacs * 2; - - for (i = 0; i < cfg->hp_outs; i++) { - if (is_jack_detectable(codec, cfg->hp_pins[i])) { - spec->auto_mute = 1; - break; - } - } - if (spec->auto_mute && - cfg->line_out_pins[0] && - cfg->line_out_type != AUTO_PIN_SPEAKER_OUT && - cfg->line_out_pins[0] != cfg->hp_pins[0] && - cfg->line_out_pins[0] != cfg->speaker_pins[0]) { - for (i = 0; i < cfg->line_outs; i++) { - if (is_jack_detectable(codec, cfg->line_out_pins[i])) { - spec->detect_line = 1; - break; - } - } - spec->automute_lines = spec->detect_line; - } - - spec->vmaster_nid = spec->private_dac_nids[0]; -} - -static void cx_auto_turn_eapd(struct hda_codec *codec, int num_pins, - hda_nid_t *pins, bool on); - -static void do_automute(struct hda_codec *codec, int num_pins, - hda_nid_t *pins, bool on) -{ - struct conexant_spec *spec = codec->spec; - int i; - for (i = 0; i < num_pins; i++) - snd_hda_set_pin_ctl(codec, pins[i], on ? PIN_OUT : 0); - if (spec->pin_eapd_ctrls) - cx_auto_turn_eapd(codec, num_pins, pins, on); -} - -static int detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins) -{ - int i, present = 0; - - for (i = 0; i < num_pins; i++) { - hda_nid_t nid = pins[i]; - if (!nid || !is_jack_detectable(codec, nid)) - break; - present |= snd_hda_jack_detect(codec, nid); - } - return present; -} - -/* auto-mute/unmute speaker and line outs according to headphone jack */ -static void cx_auto_update_speakers(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int on = 1; - - /* turn on HP EAPD when HP jacks are present */ - if (spec->pin_eapd_ctrls) { - if (spec->auto_mute) - on = spec->hp_present; - cx_auto_turn_eapd(codec, cfg->hp_outs, cfg->hp_pins, on); - } - - /* mute speakers in auto-mode if HP or LO jacks are plugged */ - if (spec->auto_mute) - on = !(spec->hp_present || - (spec->detect_line && spec->line_present)); - do_automute(codec, cfg->speaker_outs, cfg->speaker_pins, on); - - /* toggle line-out mutes if needed, too */ - /* if LO is a copy of either HP or Speaker, don't need to handle it */ - if (cfg->line_out_pins[0] == cfg->hp_pins[0] || - cfg->line_out_pins[0] == cfg->speaker_pins[0]) - return; - if (spec->auto_mute) { - /* mute LO in auto-mode when HP jack is present */ - if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT || - spec->automute_lines) - on = !spec->hp_present; - else - on = 1; - } - do_automute(codec, cfg->line_outs, cfg->line_out_pins, on); -} - -static void cx_auto_hp_automute(struct hda_codec *codec, struct hda_jack_tbl *jack) -{ - struct conexant_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - - if (!spec->auto_mute) - return; - spec->hp_present = detect_jacks(codec, cfg->hp_outs, cfg->hp_pins); - cx_auto_update_speakers(codec); -} - -static void cx_auto_line_automute(struct hda_codec *codec, struct hda_jack_tbl *jack) -{ - struct conexant_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - - if (!spec->auto_mute || !spec->detect_line) - return; - spec->line_present = detect_jacks(codec, cfg->line_outs, - cfg->line_out_pins); - cx_auto_update_speakers(codec); -} - -static int cx_automute_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; - static const char * const texts2[] = { - "Disabled", "Enabled" - }; - static const char * const texts3[] = { - "Disabled", "Speaker Only", "Line Out+Speaker" - }; - const char * const *texts; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - if (spec->automute_hp_lo) { - uinfo->value.enumerated.items = 3; - texts = texts3; - } else { - uinfo->value.enumerated.items = 2; - texts = texts2; - } - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); - return 0; -} - -static int cx_automute_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; - unsigned int val; - if (!spec->auto_mute) - val = 0; - else if (!spec->automute_lines) - val = 1; - else - val = 2; - ucontrol->value.enumerated.item[0] = val; - return 0; -} - -static int cx_automute_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; - - switch (ucontrol->value.enumerated.item[0]) { - case 0: - if (!spec->auto_mute) - return 0; - spec->auto_mute = 0; - break; - case 1: - if (spec->auto_mute && !spec->automute_lines) - return 0; - spec->auto_mute = 1; - spec->automute_lines = 0; - break; - case 2: - if (!spec->automute_hp_lo) - return -EINVAL; - if (spec->auto_mute && spec->automute_lines) - return 0; - spec->auto_mute = 1; - spec->automute_lines = 1; - break; - default: - return -EINVAL; - } - cx_auto_update_speakers(codec); - return 1; -} - -static const struct snd_kcontrol_new cx_automute_mode_enum[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Auto-Mute Mode", - .info = cx_automute_mode_info, - .get = cx_automute_mode_get, - .put = cx_automute_mode_put, - }, - { } -}; - -static int cx_auto_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->private_imux, uinfo); -} - -static int cx_auto_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->cur_mux[0]; - return 0; -} - -/* look for the route the given pin from mux and return the index; - * if do_select is set, actually select the route. - */ -static int __select_input_connection(struct hda_codec *codec, hda_nid_t mux, - hda_nid_t pin, hda_nid_t *srcp, - bool do_select, int depth) -{ - struct conexant_spec *spec = codec->spec; - hda_nid_t conn[HDA_MAX_NUM_INPUTS]; - int startidx, i, nums; - - switch (get_wcaps_type(get_wcaps(codec, mux))) { - case AC_WID_AUD_IN: - case AC_WID_AUD_SEL: - case AC_WID_AUD_MIX: - break; - default: - return -1; - } - - nums = snd_hda_get_connections(codec, mux, conn, ARRAY_SIZE(conn)); - for (i = 0; i < nums; i++) - if (conn[i] == pin) { - if (do_select) - snd_hda_codec_write(codec, mux, 0, - AC_VERB_SET_CONNECT_SEL, i); - if (srcp) - *srcp = mux; - return i; - } - depth++; - if (depth == 2) - return -1; - - /* Try to rotate around connections to avoid one boost controlling - another input path as well */ - startidx = 0; - for (i = 0; i < spec->private_imux.num_items; i++) - if (spec->imux_info[i].pin == pin) { - startidx = i; - break; - } - - for (i = 0; i < nums; i++) { - int j = (i + startidx) % nums; - int ret = __select_input_connection(codec, conn[j], pin, srcp, - do_select, depth); - if (ret >= 0) { - if (do_select) - snd_hda_codec_write(codec, mux, 0, - AC_VERB_SET_CONNECT_SEL, j); - return j; - } - } - return -1; -} - -static void select_input_connection(struct hda_codec *codec, hda_nid_t mux, - hda_nid_t pin) -{ - __select_input_connection(codec, mux, pin, NULL, true, 0); -} - -static int get_input_connection(struct hda_codec *codec, hda_nid_t mux, - hda_nid_t pin) -{ - return __select_input_connection(codec, mux, pin, NULL, false, 0); -} - -static int cx_auto_mux_enum_update(struct hda_codec *codec, - const struct hda_input_mux *imux, - unsigned int idx) -{ - struct conexant_spec *spec = codec->spec; - hda_nid_t adc; - int changed = 1; - - if (!imux->num_items) - return 0; - if (idx >= imux->num_items) - idx = imux->num_items - 1; - if (spec->cur_mux[0] == idx) - changed = 0; - adc = spec->imux_info[idx].adc; - select_input_connection(codec, spec->imux_info[idx].adc, - spec->imux_info[idx].pin); - if (spec->cur_adc && spec->cur_adc != adc) { - /* stream is running, let's swap the current ADC */ - __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1); - spec->cur_adc = adc; - snd_hda_codec_setup_stream(codec, adc, - spec->cur_adc_stream_tag, 0, - spec->cur_adc_format); - } - spec->cur_mux[0] = idx; - return changed; -} - -static int cx_auto_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; - - return cx_auto_mux_enum_update(codec, &spec->private_imux, - ucontrol->value.enumerated.item[0]); -} - -static const struct snd_kcontrol_new cx_auto_capture_mixers[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .info = cx_auto_mux_enum_info, - .get = cx_auto_mux_enum_get, - .put = cx_auto_mux_enum_put - }, - {} -}; - -static bool select_automic(struct hda_codec *codec, int idx, bool detect) -{ - struct conexant_spec *spec = codec->spec; - if (idx < 0) - return false; - if (detect && !snd_hda_jack_detect(codec, spec->imux_info[idx].pin)) - return false; - cx_auto_mux_enum_update(codec, &spec->private_imux, idx); - return true; -} - -/* automatic switch internal and external mic */ -static void cx_auto_automic(struct hda_codec *codec, struct hda_jack_tbl *jack) -{ - struct conexant_spec *spec = codec->spec; +#endif /* ENABLE_CXT_STATIC_QUIRKS */ - if (!spec->auto_mic) - return; - if (!select_automic(codec, spec->auto_mic_ext, true)) - if (!select_automic(codec, spec->auto_mic_dock, true)) - select_automic(codec, spec->auto_mic_int, false); -} -/* check whether the pin config is suitable for auto-mic switching; - * auto-mic is enabled only when one int-mic and one ext- and/or - * one dock-mic exist +/* + * Automatic parser for CX20641 & co */ -static void cx_auto_check_auto_mic(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - int pset[INPUT_PIN_ATTR_NORMAL + 1]; - int i; - - for (i = 0; i < ARRAY_SIZE(pset); i++) - pset[i] = -1; - for (i = 0; i < spec->private_imux.num_items; i++) { - hda_nid_t pin = spec->imux_info[i].pin; - unsigned int def_conf = snd_hda_codec_get_pincfg(codec, pin); - int type, attr; - attr = snd_hda_get_input_pin_attr(def_conf); - if (attr == INPUT_PIN_ATTR_UNUSED) - return; /* invalid entry */ - if (attr > INPUT_PIN_ATTR_NORMAL) - attr = INPUT_PIN_ATTR_NORMAL; - if (attr != INPUT_PIN_ATTR_INT && - !is_jack_detectable(codec, pin)) - return; /* non-detectable pin */ - type = get_defcfg_device(def_conf); - if (type != AC_JACK_MIC_IN && - (attr != INPUT_PIN_ATTR_DOCK || type != AC_JACK_LINE_IN)) - return; /* no valid input type */ - if (pset[attr] >= 0) - return; /* already occupied */ - pset[attr] = i; - } - if (pset[INPUT_PIN_ATTR_INT] < 0 || - (pset[INPUT_PIN_ATTR_NORMAL] < 0 && pset[INPUT_PIN_ATTR_DOCK])) - return; /* no input to switch*/ - spec->auto_mic = 1; - spec->auto_mic_ext = pset[INPUT_PIN_ATTR_NORMAL]; - spec->auto_mic_dock = pset[INPUT_PIN_ATTR_DOCK]; - spec->auto_mic_int = pset[INPUT_PIN_ATTR_INT]; -} - -static void cx_auto_parse_input(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - struct hda_input_mux *imux; - int i, j; - - imux = &spec->private_imux; - for (i = 0; i < cfg->num_inputs; i++) { - for (j = 0; j < spec->num_adc_nids; j++) { - hda_nid_t adc = spec->adc_nids[j]; - int idx = get_input_connection(codec, adc, - cfg->inputs[i].pin); - if (idx >= 0) { - const char *label; - label = hda_get_autocfg_input_label(codec, cfg, i); - spec->imux_info[imux->num_items].index = i; - spec->imux_info[imux->num_items].boost = 0; - spec->imux_info[imux->num_items].adc = adc; - spec->imux_info[imux->num_items].pin = - cfg->inputs[i].pin; - snd_hda_add_imux_item(imux, label, idx, NULL); - break; - } - } - } - if (imux->num_items >= 2 && cfg->num_inputs == imux->num_items) - cx_auto_check_auto_mic(codec); - if (imux->num_items > 1) { - for (i = 1; i < imux->num_items; i++) { - if (spec->imux_info[i].adc != spec->imux_info[0].adc) { - spec->adc_switching = 1; - break; - } - } - } -} - -/* get digital-input audio widget corresponding to the given pin */ -static hda_nid_t cx_auto_get_dig_in(struct hda_codec *codec, hda_nid_t pin) -{ - hda_nid_t nid, end_nid; - - end_nid = codec->start_nid + codec->num_nodes; - for (nid = codec->start_nid; nid < end_nid; nid++) { - unsigned int wcaps = get_wcaps(codec, nid); - unsigned int type = get_wcaps_type(wcaps); - if (type == AC_WID_AUD_IN && (wcaps & AC_WCAP_DIGITAL)) { - if (get_connection_index(codec, nid, pin) >= 0) - return nid; - } - } - return 0; -} - -static void cx_auto_parse_digital(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - hda_nid_t nid; - - if (cfg->dig_outs && - snd_hda_get_connections(codec, cfg->dig_out_pins[0], &nid, 1) == 1) - spec->multiout.dig_out_nid = nid; - if (cfg->dig_in_pin) - spec->dig_in_nid = cx_auto_get_dig_in(codec, cfg->dig_in_pin); -} #ifdef CONFIG_SND_HDA_INPUT_BEEP static void cx_auto_parse_beep(struct hda_codec *codec) @@ -3824,24 +3151,8 @@ static void cx_auto_parse_eapd(struct hda_codec *codec) * OTOH, if only one or two EAPDs are found, it's an old chip, * thus it might control over all pins. */ - spec->pin_eapd_ctrls = spec->num_eapds > 2; -} - -static int cx_auto_parse_auto_config(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - int err; - - err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); - if (err < 0) - return err; - - cx_auto_parse_output(codec); - cx_auto_parse_input(codec); - cx_auto_parse_digital(codec); - cx_auto_parse_beep(codec); - cx_auto_parse_eapd(codec); - return 0; + if (spec->num_eapds > 2) + spec->gen.own_eapd_ctl = 1; } static void cx_auto_turn_eapd(struct hda_codec *codec, int num_pins, @@ -3856,547 +3167,39 @@ static void cx_auto_turn_eapd(struct hda_codec *codec, int num_pins, } } -static void select_connection(struct hda_codec *codec, hda_nid_t pin, - hda_nid_t src) -{ - int idx = get_connection_index(codec, pin, src); - if (idx >= 0) - snd_hda_codec_write(codec, pin, 0, - AC_VERB_SET_CONNECT_SEL, idx); -} - -static void mute_outputs(struct hda_codec *codec, int num_nids, - const hda_nid_t *nids) -{ - int i, val; - - for (i = 0; i < num_nids; i++) { - hda_nid_t nid = nids[i]; - if (!(get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)) - continue; - if (query_amp_caps(codec, nid, HDA_OUTPUT) & AC_AMPCAP_MUTE) - val = AMP_OUT_MUTE; - else - val = AMP_OUT_ZERO; - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_AMP_GAIN_MUTE, val); - } -} - -static void enable_unsol_pins(struct hda_codec *codec, int num_pins, - hda_nid_t *pins, unsigned int action, - hda_jack_callback cb) -{ - int i; - for (i = 0; i < num_pins; i++) - snd_hda_jack_detect_enable_callback(codec, pins[i], action, cb); -} - -static bool found_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums) -{ - int i; - for (i = 0; i < nums; i++) - if (list[i] == nid) - return true; - return false; -} - -/* is the given NID found in any of autocfg items? */ -static bool found_in_autocfg(struct auto_pin_cfg *cfg, hda_nid_t nid) -{ - int i; - - if (found_in_nid_list(nid, cfg->line_out_pins, cfg->line_outs) || - found_in_nid_list(nid, cfg->hp_pins, cfg->hp_outs) || - found_in_nid_list(nid, cfg->speaker_pins, cfg->speaker_outs) || - found_in_nid_list(nid, cfg->dig_out_pins, cfg->dig_outs)) - return true; - for (i = 0; i < cfg->num_inputs; i++) - if (cfg->inputs[i].pin == nid) - return true; - if (cfg->dig_in_pin == nid) - return true; - return false; -} - -/* clear unsol-event tags on unused pins; Conexant codecs seem to leave - * invalid unsol tags by some reason - */ -static void clear_unsol_on_unused_pins(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int i; - - for (i = 0; i < codec->init_pins.used; i++) { - struct hda_pincfg *pin = snd_array_elem(&codec->init_pins, i); - if (!found_in_autocfg(cfg, pin->nid)) - snd_hda_codec_write(codec, pin->nid, 0, - AC_VERB_SET_UNSOLICITED_ENABLE, 0); - } -} - /* turn on/off EAPD according to Master switch */ static void cx_auto_vmaster_hook(void *private_data, int enabled) { struct hda_codec *codec = private_data; struct conexant_spec *spec = codec->spec; - if (enabled && spec->pin_eapd_ctrls) { - cx_auto_update_speakers(codec); - return; - } cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, enabled); } -static void cx_auto_init_output(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - hda_nid_t nid; - int i; - - mute_outputs(codec, spec->multiout.num_dacs, spec->multiout.dac_nids); - for (i = 0; i < cfg->hp_outs; i++) { - unsigned int val = PIN_OUT; - if (snd_hda_query_pin_caps(codec, cfg->hp_pins[i]) & - AC_PINCAP_HP_DRV) - val |= AC_PINCTL_HP_EN; - snd_hda_set_pin_ctl(codec, cfg->hp_pins[i], val); - } - mute_outputs(codec, cfg->hp_outs, cfg->hp_pins); - mute_outputs(codec, cfg->line_outs, cfg->line_out_pins); - mute_outputs(codec, cfg->speaker_outs, cfg->speaker_pins); - for (i = 0; i < spec->dac_info_filled; i++) { - nid = spec->dac_info[i].dac; - if (!nid) - nid = spec->multiout.dac_nids[0]; - else if (nid & DAC_SLAVE_FLAG) - nid &= ~DAC_SLAVE_FLAG; - select_connection(codec, spec->dac_info[i].pin, nid); - } - if (spec->auto_mute) { - enable_unsol_pins(codec, cfg->hp_outs, cfg->hp_pins, - CONEXANT_HP_EVENT, cx_auto_hp_automute); - spec->hp_present = detect_jacks(codec, cfg->hp_outs, - cfg->hp_pins); - if (spec->detect_line) { - enable_unsol_pins(codec, cfg->line_outs, - cfg->line_out_pins, - CONEXANT_LINE_EVENT, - cx_auto_line_automute); - spec->line_present = - detect_jacks(codec, cfg->line_outs, - cfg->line_out_pins); - } - } - cx_auto_update_speakers(codec); - /* turn on all EAPDs if no individual EAPD control is available */ - if (!spec->pin_eapd_ctrls) - cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, true); - clear_unsol_on_unused_pins(codec); -} - -static void cx_auto_init_input(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int i, val; - - for (i = 0; i < spec->num_adc_nids; i++) { - hda_nid_t nid = spec->adc_nids[i]; - if (!(get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) - continue; - if (query_amp_caps(codec, nid, HDA_INPUT) & AC_AMPCAP_MUTE) - val = AMP_IN_MUTE(0); - else - val = AMP_IN_UNMUTE(0); - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, - val); - } - - for (i = 0; i < cfg->num_inputs; i++) { - hda_nid_t pin = cfg->inputs[i].pin; - unsigned int type = PIN_IN; - if (cfg->inputs[i].type == AUTO_PIN_MIC) - type |= snd_hda_get_default_vref(codec, pin); - snd_hda_set_pin_ctl(codec, pin, type); - } - - if (spec->auto_mic) { - if (spec->auto_mic_ext >= 0) { - snd_hda_jack_detect_enable_callback(codec, - cfg->inputs[spec->auto_mic_ext].pin, - CONEXANT_MIC_EVENT, cx_auto_automic); - } - if (spec->auto_mic_dock >= 0) { - snd_hda_jack_detect_enable_callback(codec, - cfg->inputs[spec->auto_mic_dock].pin, - CONEXANT_MIC_EVENT, cx_auto_automic); - } - cx_auto_automic(codec, NULL); - } else { - select_input_connection(codec, spec->imux_info[0].adc, - spec->imux_info[0].pin); - } -} - -static void cx_auto_init_digital(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - - if (spec->multiout.dig_out_nid) - snd_hda_set_pin_ctl(codec, cfg->dig_out_pins[0], PIN_OUT); - if (spec->dig_in_nid) - snd_hda_set_pin_ctl(codec, cfg->dig_in_pin, PIN_IN); -} - -static int cx_auto_init(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - snd_hda_gen_apply_verbs(codec); - cx_auto_init_output(codec); - cx_auto_init_input(codec); - cx_auto_init_digital(codec); - snd_hda_sync_vmaster_hook(&spec->vmaster_mute); - return 0; -} - -static int cx_auto_add_volume_idx(struct hda_codec *codec, const char *basename, - const char *dir, int cidx, - hda_nid_t nid, int hda_dir, int amp_idx, int chs) -{ - static char name[44]; - static struct snd_kcontrol_new knew[] = { - HDA_CODEC_VOLUME(name, 0, 0, 0), - HDA_CODEC_MUTE(name, 0, 0, 0), - }; - static const char * const sfx[2] = { "Volume", "Switch" }; - int i, err; - - for (i = 0; i < 2; i++) { - struct snd_kcontrol *kctl; - knew[i].private_value = HDA_COMPOSE_AMP_VAL(nid, chs, amp_idx, - hda_dir); - knew[i].subdevice = HDA_SUBDEV_AMP_FLAG; - knew[i].index = cidx; - snprintf(name, sizeof(name), "%s%s %s", basename, dir, sfx[i]); - kctl = snd_ctl_new1(&knew[i], codec); - if (!kctl) - return -ENOMEM; - err = snd_hda_ctl_add(codec, nid, kctl); - if (err < 0) - return err; - if (!(query_amp_caps(codec, nid, hda_dir) & - (AC_AMPCAP_MUTE | AC_AMPCAP_MIN_MUTE))) - break; - } - return 0; -} - -#define cx_auto_add_volume(codec, str, dir, cidx, nid, hda_dir) \ - cx_auto_add_volume_idx(codec, str, dir, cidx, nid, hda_dir, 0, 3) - -#define cx_auto_add_pb_volume(codec, nid, str, idx) \ - cx_auto_add_volume(codec, str, " Playback", idx, nid, HDA_OUTPUT) - -static int try_add_pb_volume(struct hda_codec *codec, hda_nid_t dac, - hda_nid_t pin, const char *name, int idx) -{ - unsigned int caps; - if (dac && !(dac & DAC_SLAVE_FLAG)) { - caps = query_amp_caps(codec, dac, HDA_OUTPUT); - if (caps & AC_AMPCAP_NUM_STEPS) - return cx_auto_add_pb_volume(codec, dac, name, idx); - } - caps = query_amp_caps(codec, pin, HDA_OUTPUT); - if (caps & AC_AMPCAP_NUM_STEPS) - return cx_auto_add_pb_volume(codec, pin, name, idx); - return 0; -} - -static int cx_auto_build_output_controls(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - int i, err; - int num_line = 0, num_hp = 0, num_spk = 0; - static const char * const texts[3] = { "Front", "Surround", "CLFE" }; - - if (spec->dac_info_filled == 1) - return try_add_pb_volume(codec, spec->dac_info[0].dac, - spec->dac_info[0].pin, - "Master", 0); - - for (i = 0; i < spec->dac_info_filled; i++) { - const char *label; - int idx, type; - hda_nid_t dac = spec->dac_info[i].dac; - type = spec->dac_info[i].type; - if (type == AUTO_PIN_LINE_OUT) - type = spec->autocfg.line_out_type; - switch (type) { - case AUTO_PIN_LINE_OUT: - default: - label = texts[num_line++]; - idx = 0; - break; - case AUTO_PIN_HP_OUT: - label = "Headphone"; - idx = num_hp++; - break; - case AUTO_PIN_SPEAKER_OUT: - label = "Speaker"; - idx = num_spk++; - break; - } - err = try_add_pb_volume(codec, dac, - spec->dac_info[i].pin, - label, idx); - if (err < 0) - return err; - } - - if (spec->auto_mute) { - err = snd_hda_add_new_ctls(codec, cx_automute_mode_enum); - if (err < 0) - return err; - } - - return 0; -} - -/* Returns zero if this is a normal stereo channel, and non-zero if it should - be split in two independent channels. - dest_label must be at least 44 characters. */ -static int cx_auto_get_rightch_label(struct hda_codec *codec, const char *label, - char *dest_label, int nid) -{ - struct conexant_spec *spec = codec->spec; - int i; - - if (!spec->fixup_stereo_dmic) - return 0; - - for (i = 0; i < AUTO_CFG_MAX_INS; i++) { - int def_conf; - if (spec->autocfg.inputs[i].pin != nid) - continue; - - if (spec->autocfg.inputs[i].type != AUTO_PIN_MIC) - return 0; - def_conf = snd_hda_codec_get_pincfg(codec, nid); - if (snd_hda_get_input_pin_attr(def_conf) != INPUT_PIN_ATTR_INT) - return 0; - - /* Finally found the inverted internal mic! */ - snprintf(dest_label, 44, "Inverted %s", label); - return 1; - } - return 0; -} - -static int cx_auto_add_capture_volume(struct hda_codec *codec, hda_nid_t nid, - const char *label, const char *pfx, - int cidx) -{ - struct conexant_spec *spec = codec->spec; - int i; - - for (i = 0; i < spec->num_adc_nids; i++) { - char rightch_label[44]; - hda_nid_t adc_nid = spec->adc_nids[i]; - int idx = get_input_connection(codec, adc_nid, nid); - if (idx < 0) - continue; - if (codec->single_adc_amp) - idx = 0; - - if (cx_auto_get_rightch_label(codec, label, rightch_label, nid)) { - /* Make two independent kcontrols for left and right */ - int err = cx_auto_add_volume_idx(codec, label, pfx, - cidx, adc_nid, HDA_INPUT, idx, 1); - if (err < 0) - return err; - return cx_auto_add_volume_idx(codec, rightch_label, pfx, - cidx, adc_nid, HDA_INPUT, idx, 2); - } - return cx_auto_add_volume_idx(codec, label, pfx, - cidx, adc_nid, HDA_INPUT, idx, 3); - } - return 0; -} - -static int cx_auto_add_boost_volume(struct hda_codec *codec, int idx, - const char *label, int cidx) -{ - struct conexant_spec *spec = codec->spec; - hda_nid_t mux, nid; - int i, con; - - nid = spec->imux_info[idx].pin; - if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP) { - char rightch_label[44]; - if (cx_auto_get_rightch_label(codec, label, rightch_label, nid)) { - int err = cx_auto_add_volume_idx(codec, label, " Boost", - cidx, nid, HDA_INPUT, 0, 1); - if (err < 0) - return err; - return cx_auto_add_volume_idx(codec, rightch_label, " Boost", - cidx, nid, HDA_INPUT, 0, 2); - } - return cx_auto_add_volume(codec, label, " Boost", cidx, - nid, HDA_INPUT); - } - con = __select_input_connection(codec, spec->imux_info[idx].adc, nid, - &mux, false, 0); - if (con < 0) - return 0; - for (i = 0; i < idx; i++) { - if (spec->imux_info[i].boost == mux) - return 0; /* already present */ - } - - if (get_wcaps(codec, mux) & AC_WCAP_OUT_AMP) { - spec->imux_info[idx].boost = mux; - return cx_auto_add_volume(codec, label, " Boost", cidx, - mux, HDA_OUTPUT); - } - return 0; -} - -static int cx_auto_build_input_controls(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - struct hda_input_mux *imux = &spec->private_imux; - const char *prev_label; - int input_conn[HDA_MAX_NUM_INPUTS]; - int i, j, err, cidx; - int multi_connection; - - if (!imux->num_items) - return 0; - - multi_connection = 0; - for (i = 0; i < imux->num_items; i++) { - cidx = get_input_connection(codec, spec->imux_info[i].adc, - spec->imux_info[i].pin); - if (cidx < 0) - continue; - input_conn[i] = spec->imux_info[i].adc; - if (!codec->single_adc_amp) - input_conn[i] |= cidx << 8; - if (i > 0 && input_conn[i] != input_conn[0]) - multi_connection = 1; - } - - prev_label = NULL; - cidx = 0; - for (i = 0; i < imux->num_items; i++) { - hda_nid_t nid = spec->imux_info[i].pin; - const char *label; - - label = hda_get_autocfg_input_label(codec, &spec->autocfg, - spec->imux_info[i].index); - if (label == prev_label) - cidx++; - else - cidx = 0; - prev_label = label; - - err = cx_auto_add_boost_volume(codec, i, label, cidx); - if (err < 0) - return err; - - if (!multi_connection) { - if (i > 0) - continue; - err = cx_auto_add_capture_volume(codec, nid, - "Capture", "", cidx); - } else { - bool dup_found = false; - for (j = 0; j < i; j++) { - if (input_conn[j] == input_conn[i]) { - dup_found = true; - break; - } - } - if (dup_found) - continue; - err = cx_auto_add_capture_volume(codec, nid, - label, " Capture", cidx); - } - if (err < 0) - return err; - } - - if (spec->private_imux.num_items > 1 && !spec->auto_mic) { - err = snd_hda_add_new_ctls(codec, cx_auto_capture_mixers); - if (err < 0) - return err; - } - - return 0; -} - static int cx_auto_build_controls(struct hda_codec *codec) { - struct conexant_spec *spec = codec->spec; int err; - err = cx_auto_build_output_controls(codec); + err = snd_hda_gen_build_controls(codec); if (err < 0) return err; - err = cx_auto_build_input_controls(codec); - if (err < 0) - return err; - err = conexant_build_controls(codec); - if (err < 0) - return err; - err = snd_hda_jack_add_kctls(codec, &spec->autocfg); + + err = add_beep_ctls(codec); if (err < 0) return err; - if (spec->vmaster_mute.sw_kctl) { - spec->vmaster_mute.hook = cx_auto_vmaster_hook; - err = snd_hda_add_vmaster_hook(codec, &spec->vmaster_mute, - spec->vmaster_mute_led); - if (err < 0) - return err; - } - return 0; -} - -static int cx_auto_search_adcs(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - hda_nid_t nid, end_nid; - end_nid = codec->start_nid + codec->num_nodes; - for (nid = codec->start_nid; nid < end_nid; nid++) { - unsigned int caps = get_wcaps(codec, nid); - if (get_wcaps_type(caps) != AC_WID_AUD_IN) - continue; - if (caps & AC_WCAP_DIGITAL) - continue; - if (snd_BUG_ON(spec->num_adc_nids >= - ARRAY_SIZE(spec->private_adc_nids))) - break; - spec->private_adc_nids[spec->num_adc_nids++] = nid; - } - spec->adc_nids = spec->private_adc_nids; return 0; } static const struct hda_codec_ops cx_auto_patch_ops = { .build_controls = cx_auto_build_controls, - .build_pcms = conexant_build_pcms, - .init = cx_auto_init, - .free = conexant_free, + .build_pcms = snd_hda_gen_build_pcms, + .init = snd_hda_gen_init, + .free = snd_hda_gen_free, .unsol_event = snd_hda_jack_unsol_event, #ifdef CONFIG_PM - .suspend = conexant_suspend, + .check_power_status = snd_hda_gen_check_power_status, #endif - .reboot_notify = snd_hda_shutup_pins, }; /* @@ -4405,14 +3208,30 @@ static const struct hda_codec_ops cx_auto_patch_ops = { enum { CXT_PINCFG_LENOVO_X200, CXT_PINCFG_LENOVO_TP410, + CXT_PINCFG_LEMOTE_A1004, + CXT_PINCFG_LEMOTE_A1205, CXT_FIXUP_STEREO_DMIC, + CXT_FIXUP_INC_MIC_BOOST, }; static void cxt_fixup_stereo_dmic(struct hda_codec *codec, const struct hda_fixup *fix, int action) { struct conexant_spec *spec = codec->spec; - spec->fixup_stereo_dmic = 1; + spec->gen.inv_dmic_split = 1; +} + +static void cxt5066_increase_mic_boost(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + if (action != HDA_FIXUP_ACT_PRE_PROBE) + return; + + snd_hda_override_amp_caps(codec, 0x17, HDA_OUTPUT, + (0x3 << AC_AMPCAP_OFFSET_SHIFT) | + (0x4 << AC_AMPCAP_NUM_STEPS_SHIFT) | + (0x27 << AC_AMPCAP_STEP_SIZE_SHIFT) | + (0 << AC_AMPCAP_MUTE_SHIFT)); } /* ThinkPad X200 & co with cxt5051 */ @@ -4432,6 +3251,18 @@ static const struct hda_pintbl cxt_pincfg_lenovo_tp410[] = { {} }; +/* Lemote A1004/A1205 with cxt5066 */ +static const struct hda_pintbl cxt_pincfg_lemote[] = { + { 0x1a, 0x90a10020 }, /* Internal mic */ + { 0x1b, 0x03a11020 }, /* External mic */ + { 0x1d, 0x400101f0 }, /* Not used */ + { 0x1e, 0x40a701f0 }, /* Not used */ + { 0x20, 0x404501f0 }, /* Not used */ + { 0x22, 0x404401f0 }, /* Not used */ + { 0x23, 0x40a701f0 }, /* Not used */ + {} +}; + static const struct hda_fixup cxt_fixups[] = { [CXT_PINCFG_LENOVO_X200] = { .type = HDA_FIXUP_PINS, @@ -4441,10 +3272,24 @@ static const struct hda_fixup cxt_fixups[] = { .type = HDA_FIXUP_PINS, .v.pins = cxt_pincfg_lenovo_tp410, }, + [CXT_PINCFG_LEMOTE_A1004] = { + .type = HDA_FIXUP_PINS, + .chained = true, + .chain_id = CXT_FIXUP_INC_MIC_BOOST, + .v.pins = cxt_pincfg_lemote, + }, + [CXT_PINCFG_LEMOTE_A1205] = { + .type = HDA_FIXUP_PINS, + .v.pins = cxt_pincfg_lemote, + }, [CXT_FIXUP_STEREO_DMIC] = { .type = HDA_FIXUP_FUNC, .v.func = cxt_fixup_stereo_dmic, }, + [CXT_FIXUP_INC_MIC_BOOST] = { + .type = HDA_FIXUP_FUNC, + .v.func = cxt5066_increase_mic_boost, + }, }; static const struct snd_pci_quirk cxt5051_fixups[] = { @@ -4453,6 +3298,7 @@ static const struct snd_pci_quirk cxt5051_fixups[] = { }; static const struct snd_pci_quirk cxt5066_fixups[] = { + SND_PCI_QUIRK(0x1025, 0x0543, "Acer Aspire One 522", CXT_FIXUP_STEREO_DMIC), SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400", CXT_PINCFG_LENOVO_TP410), SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo T410", CXT_PINCFG_LENOVO_TP410), SND_PCI_QUIRK(0x17aa, 0x215f, "Lenovo T510", CXT_PINCFG_LENOVO_TP410), @@ -4461,6 +3307,8 @@ static const struct snd_pci_quirk cxt5066_fixups[] = { SND_PCI_QUIRK(0x17aa, 0x3975, "Lenovo U300s", CXT_FIXUP_STEREO_DMIC), SND_PCI_QUIRK(0x17aa, 0x3977, "Lenovo IdeaPad U310", CXT_FIXUP_STEREO_DMIC), SND_PCI_QUIRK(0x17aa, 0x397b, "Lenovo S205", CXT_FIXUP_STEREO_DMIC), + SND_PCI_QUIRK(0x1c06, 0x2011, "Lemote A1004", CXT_PINCFG_LEMOTE_A1004), + SND_PCI_QUIRK(0x1c06, 0x2012, "Lemote A1205", CXT_PINCFG_LEMOTE_A1205), {} }; @@ -4491,13 +3339,22 @@ static int patch_conexant_auto(struct hda_codec *codec) spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (!spec) return -ENOMEM; + snd_hda_gen_spec_init(&spec->gen); codec->spec = spec; - snd_hda_gen_init(&spec->gen); + + cx_auto_parse_beep(codec); + cx_auto_parse_eapd(codec); + if (spec->gen.own_eapd_ctl) + spec->gen.vmaster_mute.hook = cx_auto_vmaster_hook; switch (codec->vendor_id) { case 0x14f15045: codec->single_adc_amp = 1; break; + case 0x14f15047: + codec->pin_amp_workaround = 1; + spec->gen.mixer_nid = 0x19; + break; case 0x14f15051: add_cx5051_fake_mutes(codec); codec->pin_amp_workaround = 1; @@ -4509,8 +3366,6 @@ static int patch_conexant_auto(struct hda_codec *codec) break; } - snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); - /* Show mute-led control only on HP laptops * This is a sort of white-list: on HP laptops, EAPD corresponds * only to the mute-LED without actualy amp function. Meanwhile, @@ -4519,20 +3374,20 @@ static int patch_conexant_auto(struct hda_codec *codec) */ switch (codec->subsystem_id >> 16) { case 0x103c: - spec->vmaster_mute_led = 1; + spec->gen.vmaster_mute_enum = 1; break; } - err = cx_auto_search_adcs(codec); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); + + err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, NULL, 0); if (err < 0) - return err; - err = cx_auto_parse_auto_config(codec); - if (err < 0) { - kfree(codec->spec); - codec->spec = NULL; - return err; - } - spec->capture_stream = &cx_auto_pcm_analog_capture; + goto error; + + err = snd_hda_gen_parse_auto_config(codec, &spec->gen.autocfg); + if (err < 0) + goto error; + codec->patch_ops = cx_auto_patch_ops; if (spec->beep_amp) snd_hda_attach_beep_device(codec, spec->beep_amp); @@ -4549,8 +3404,19 @@ static int patch_conexant_auto(struct hda_codec *codec) } return 0; + + error: + snd_hda_gen_free(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 + /* */ @@ -4595,6 +3461,12 @@ static const struct hda_codec_preset snd_hda_preset_conexant[] = { .patch = patch_conexant_auto }, { .id = 0x14f15111, .name = "CX20753/4", .patch = patch_conexant_auto }, + { .id = 0x14f15113, .name = "CX20755", + .patch = patch_conexant_auto }, + { .id = 0x14f15114, .name = "CX20756", + .patch = patch_conexant_auto }, + { .id = 0x14f15115, .name = "CX20757", + .patch = patch_conexant_auto }, {} /* terminator */ }; @@ -4618,6 +3490,9 @@ MODULE_ALIAS("snd-hda-codec-id:14f150b9"); MODULE_ALIAS("snd-hda-codec-id:14f1510f"); MODULE_ALIAS("snd-hda-codec-id:14f15110"); MODULE_ALIAS("snd-hda-codec-id:14f15111"); +MODULE_ALIAS("snd-hda-codec-id:14f15113"); +MODULE_ALIAS("snd-hda-codec-id:14f15114"); +MODULE_ALIAS("snd-hda-codec-id:14f15115"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Conexant HD-audio codec"); diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 71555cc54db1..85236da79046 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -431,9 +431,11 @@ static void hdmi_init_pin(struct hda_codec *codec, hda_nid_t pin_nid) if (get_wcaps(codec, pin_nid) & AC_WCAP_OUT_AMP) snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); - /* Disable pin out until stream is active*/ + /* Enable pin out: some machines with GM965 gets broken output when + * the pin is disabled or changed while using with HDMI + */ snd_hda_codec_write(codec, pin_nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, 0); + AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); } static int hdmi_get_channel_count(struct hda_codec *codec, hda_nid_t cvt_nid) @@ -712,9 +714,10 @@ static void hdmi_setup_fake_chmap(unsigned char *map, int ca) static void hdmi_setup_channel_mapping(struct hda_codec *codec, hda_nid_t pin_nid, bool non_pcm, int ca, - int channels, unsigned char *map) + int channels, unsigned char *map, + bool chmap_set) { - if (!non_pcm && map) { + if (!non_pcm && chmap_set) { hdmi_manual_setup_channel_mapping(codec, pin_nid, channels, map); } else { @@ -903,7 +906,8 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, int pin_idx, pin_nid, channels); hdmi_setup_channel_mapping(codec, pin_nid, non_pcm, ca, - channels, per_pin->chmap); + channels, per_pin->chmap, + per_pin->chmap_set); hdmi_stop_infoframe_trans(codec, pin_nid); hdmi_fill_audio_infoframe(codec, pin_nid, ai.bytes, sizeof(ai)); @@ -913,7 +917,8 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, int pin_idx, * accordingly */ if (per_pin->non_pcm != non_pcm) hdmi_setup_channel_mapping(codec, pin_nid, non_pcm, ca, - channels, per_pin->chmap); + channels, per_pin->chmap, + per_pin->chmap_set); } per_pin->non_pcm = non_pcm; @@ -1098,8 +1103,12 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo, if (!static_hdmi_pcm && eld->eld_valid) { snd_hdmi_eld_update_pcm_info(eld, hinfo); if (hinfo->channels_min > hinfo->channels_max || - !hinfo->rates || !hinfo->formats) + !hinfo->rates || !hinfo->formats) { + per_cvt->assigned = 0; + hinfo->nid = 0; + snd_hda_spdif_ctls_unassign(codec, pin_idx); return -ENODEV; + } } /* Store the updated parameters */ @@ -1193,12 +1202,11 @@ static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid) struct hdmi_spec_per_pin *per_pin; int err; - caps = snd_hda_param_read(codec, pin_nid, AC_PAR_PIN_CAP); + caps = snd_hda_query_pin_caps(codec, pin_nid); if (!(caps & (AC_PINCAP_HDMI | AC_PINCAP_DP))) return 0; - config = snd_hda_codec_read(codec, pin_nid, 0, - AC_VERB_GET_CONFIG_DEFAULT, 0); + config = snd_hda_codec_get_pincfg(codec, pin_nid); if (get_defcfg_connect(config) == AC_JACK_PORT_NONE) return 0; @@ -1272,7 +1280,7 @@ static int hdmi_parse_codec(struct hda_codec *codec) unsigned int caps; unsigned int type; - caps = snd_hda_param_read(codec, nid, AC_PAR_AUDIO_WIDGET_CAP); + caps = get_wcaps(codec, nid); type = get_wcaps_type(caps); if (!(caps & AC_WCAP_DIGITAL)) @@ -1288,13 +1296,17 @@ static int hdmi_parse_codec(struct hda_codec *codec) } } +#ifdef CONFIG_PM + /* We're seeing some problems with unsolicited hot plug events on + * PantherPoint after S3, if this is not enabled */ + if (codec->vendor_id == 0x80862806) + codec->bus->power_keep_link_on = 1; /* * G45/IbexPeak don't support EPSS: the unsolicited pin hot plug event * can be lost and presence sense verb will become inaccurate if the * HDA link is powered off at hot plug or hw initialization time. */ -#ifdef CONFIG_PM - if (!(snd_hda_param_read(codec, codec->afg, AC_PAR_POWER_STATE) & + else if (!(snd_hda_param_read(codec, codec->afg, AC_PAR_POWER_STATE) & AC_PWRST_EPSS)) codec->bus->power_keep_link_on = 1; #endif @@ -1338,7 +1350,6 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, struct hdmi_spec *spec = codec->spec; int pin_idx = hinfo_to_pin_index(spec, hinfo); hda_nid_t pin_nid = spec->pins[pin_idx].pin_nid; - int pinctl; bool non_pcm; non_pcm = check_non_pcm_per_cvt(codec, cvt_nid); @@ -1347,11 +1358,6 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, hdmi_setup_audio_infoframe(codec, pin_idx, non_pcm, substream); - pinctl = snd_hda_codec_read(codec, pin_nid, 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); - snd_hda_codec_write(codec, pin_nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, pinctl | PIN_OUT); - return hdmi_setup_stream(codec, cvt_nid, pin_nid, stream_tag, format); } @@ -1371,7 +1377,6 @@ static int hdmi_pcm_close(struct hda_pcm_stream *hinfo, int cvt_idx, pin_idx; struct hdmi_spec_per_cvt *per_cvt; struct hdmi_spec_per_pin *per_pin; - int pinctl; if (hinfo->nid) { cvt_idx = cvt_nid_to_cvt_index(spec, hinfo->nid); @@ -1388,11 +1393,6 @@ static int hdmi_pcm_close(struct hda_pcm_stream *hinfo, return -EINVAL; per_pin = &spec->pins[pin_idx]; - pinctl = snd_hda_codec_read(codec, per_pin->pin_nid, 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); - snd_hda_codec_write(codec, per_pin->pin_nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - pinctl & ~PIN_OUT); snd_hda_spdif_ctls_unassign(codec, pin_idx); per_pin->chmap_set = false; memset(per_pin->chmap, 0, sizeof(per_pin->chmap)); @@ -1509,7 +1509,7 @@ static int hdmi_chmap_ctl_put(struct snd_kcontrol *kcontrol, ctl_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); substream = snd_pcm_chmap_substream(info, ctl_idx); if (!substream || !substream->runtime) - return -EBADFD; + return 0; /* just for avoiding error from alsactl restore */ switch (substream->runtime->status->state) { case SNDRV_PCM_STATE_OPEN: case SNDRV_PCM_STATE_SETUP: @@ -1589,9 +1589,10 @@ static int generic_hdmi_build_controls(struct hda_codec *codec) if (err < 0) return err; - err = snd_hda_create_spdif_out_ctls(codec, - per_pin->pin_nid, - per_pin->mux_nids[0]); + err = snd_hda_create_dig_out_ctls(codec, + per_pin->pin_nid, + per_pin->mux_nids[0], + HDA_PCM_TYPE_HDMI); if (err < 0) return err; snd_hda_spdif_ctls_unassign(codec, pin_idx); @@ -1687,6 +1688,30 @@ static const struct hda_codec_ops generic_hdmi_patch_ops = { .unsol_event = hdmi_unsol_event, }; +static void intel_haswell_fixup_connect_list(struct hda_codec *codec) +{ + unsigned int vendor_param; + hda_nid_t list[3] = {0x2, 0x3, 0x4}; + + vendor_param = snd_hda_codec_read(codec, 0x08, 0, 0xf81, 0); + if (vendor_param == -1 || vendor_param & 0x02) + return; + + /* enable DP1.2 mode */ + vendor_param |= 0x02; + snd_hda_codec_read(codec, 0x08, 0, 0x781, vendor_param); + + vendor_param = snd_hda_codec_read(codec, 0x08, 0, 0xf81, 0); + if (vendor_param == -1 || !(vendor_param & 0x02)) + return; + + /* override 3 pins connection list */ + snd_hda_override_conn_list(codec, 0x05, 3, list); + snd_hda_override_conn_list(codec, 0x06, 3, list); + snd_hda_override_conn_list(codec, 0x07, 3, list); +} + + static int patch_generic_hdmi(struct hda_codec *codec) { struct hdmi_spec *spec; @@ -1696,6 +1721,10 @@ static int patch_generic_hdmi(struct hda_codec *codec) return -ENOMEM; codec->spec = spec; + + if (codec->vendor_id == 0x80862807) + intel_haswell_fixup_connect_list(codec); + if (hdmi_parse_codec(codec) < 0) { codec->spec = NULL; kfree(spec); diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 68fd49294b26..de512c52fa96 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -27,6 +27,7 @@ #include <linux/delay.h> #include <linux/slab.h> #include <linux/pci.h> +#include <linux/dmi.h> #include <linux/module.h> #include <sound/core.h> #include <sound/jack.h> @@ -35,12 +36,10 @@ #include "hda_auto_parser.h" #include "hda_beep.h" #include "hda_jack.h" +#include "hda_generic.h" /* unsol event tags */ -#define ALC_FRONT_EVENT 0x01 -#define ALC_DCVOL_EVENT 0x02 -#define ALC_HP_EVENT 0x04 -#define ALC_MIC_EVENT 0x08 +#define ALC_DCVOL_EVENT 0x08 /* for GPIO Poll */ #define GPIO_MASK 0x03 @@ -67,355 +66,42 @@ struct alc_customize_define { unsigned int fixup:1; /* Means that this sku is set by driver, not read from hw */ }; -struct alc_multi_io { - hda_nid_t pin; /* multi-io widget pin NID */ - hda_nid_t dac; /* DAC to be connected */ - unsigned int ctl_in; /* cached input-pin control value */ -}; - -enum { - ALC_AUTOMUTE_PIN, /* change the pin control */ - ALC_AUTOMUTE_AMP, /* mute/unmute the pin AMP */ - ALC_AUTOMUTE_MIXER, /* mute/unmute mixer widget AMP */ -}; - -#define MAX_VOL_NIDS 0x40 - -/* make compatible with old code */ -#define alc_apply_pincfgs snd_hda_apply_pincfgs -#define alc_apply_fixup snd_hda_apply_fixup -#define alc_pick_fixup snd_hda_pick_fixup -#define alc_fixup hda_fixup -#define alc_pincfg hda_pintbl -#define alc_model_fixup hda_model_fixup - -#define ALC_FIXUP_PINS HDA_FIXUP_PINS -#define ALC_FIXUP_VERBS HDA_FIXUP_VERBS -#define ALC_FIXUP_FUNC HDA_FIXUP_FUNC - -#define ALC_FIXUP_ACT_PRE_PROBE HDA_FIXUP_ACT_PRE_PROBE -#define ALC_FIXUP_ACT_PROBE HDA_FIXUP_ACT_PROBE -#define ALC_FIXUP_ACT_INIT HDA_FIXUP_ACT_INIT -#define ALC_FIXUP_ACT_BUILD HDA_FIXUP_ACT_BUILD - - struct alc_spec { - struct hda_gen_spec gen; + struct hda_gen_spec gen; /* must be at head */ /* codec parameterization */ const struct snd_kcontrol_new *mixers[5]; /* mixer arrays */ unsigned int num_mixers; - const struct snd_kcontrol_new *cap_mixer; /* capture mixer */ unsigned int beep_amp; /* beep amp value, set via set_beep_amp() */ - char stream_name_analog[32]; /* analog PCM stream */ - const struct hda_pcm_stream *stream_analog_playback; - const struct hda_pcm_stream *stream_analog_capture; - const struct hda_pcm_stream *stream_analog_alt_playback; - const struct hda_pcm_stream *stream_analog_alt_capture; - - char stream_name_digital[32]; /* digital PCM stream */ - const struct hda_pcm_stream *stream_digital_playback; - const struct hda_pcm_stream *stream_digital_capture; - - /* playback */ - struct hda_multi_out multiout; /* playback set-up - * max_channels, dacs must be set - * dig_out_nid and hp_nid are optional - */ - hda_nid_t alt_dac_nid; - hda_nid_t slave_dig_outs[3]; /* optional - for auto-parsing */ - int dig_out_type; - - /* capture */ - unsigned int num_adc_nids; - const hda_nid_t *adc_nids; - const hda_nid_t *capsrc_nids; - hda_nid_t dig_in_nid; /* digital-in NID; optional */ - hda_nid_t mixer_nid; /* analog-mixer NID */ - DECLARE_BITMAP(vol_ctls, MAX_VOL_NIDS << 1); - DECLARE_BITMAP(sw_ctls, MAX_VOL_NIDS << 1); - - /* capture setup for dynamic dual-adc switch */ - hda_nid_t cur_adc; - unsigned int cur_adc_stream_tag; - unsigned int cur_adc_format; - - /* capture source */ - unsigned int num_mux_defs; - const struct hda_input_mux *input_mux; - unsigned int cur_mux[3]; - hda_nid_t ext_mic_pin; - hda_nid_t dock_mic_pin; - hda_nid_t int_mic_pin; - - /* channel model */ - const struct hda_channel_mode *channel_mode; - int num_channel_mode; - int need_dac_fix; - int const_channel_count; - int ext_channel_count; - - /* PCM information */ - struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */ - - /* dynamic controls, init_verbs and input_mux */ - struct auto_pin_cfg autocfg; struct alc_customize_define cdefine; - struct snd_array kctls; - struct hda_input_mux private_imux[3]; - hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS]; - hda_nid_t private_adc_nids[AUTO_CFG_MAX_OUTS]; - hda_nid_t private_capsrc_nids[AUTO_CFG_MAX_OUTS]; - hda_nid_t imux_pins[HDA_MAX_NUM_INPUTS]; - unsigned int dyn_adc_idx[HDA_MAX_NUM_INPUTS]; - int int_mic_idx, ext_mic_idx, dock_mic_idx; /* for auto-mic */ + unsigned int parse_flags; /* flag for snd_hda_parse_pin_defcfg() */ + + /* inverted dmic fix */ + unsigned int inv_dmic_fixup:1; /* has inverted digital-mic workaround */ + unsigned int inv_dmic_muted:1; /* R-ch of inv d-mic is muted? */ hda_nid_t inv_dmic_pin; + /* mute LED for HP laptops, see alc269_fixup_mic_mute_hook() */ + int mute_led_polarity; + hda_nid_t mute_led_nid; + /* hooks */ void (*init_hook)(struct hda_codec *codec); #ifdef CONFIG_PM void (*power_hook)(struct hda_codec *codec); #endif void (*shutup)(struct hda_codec *codec); - void (*automute_hook)(struct hda_codec *codec); - - /* for pin sensing */ - unsigned int hp_jack_present:1; - unsigned int line_jack_present:1; - unsigned int master_mute:1; - unsigned int auto_mic:1; - unsigned int auto_mic_valid_imux:1; /* valid imux for auto-mic */ - unsigned int automute_speaker:1; /* automute speaker outputs */ - unsigned int automute_lo:1; /* automute LO outputs */ - unsigned int detect_hp:1; /* Headphone detection enabled */ - unsigned int detect_lo:1; /* Line-out detection enabled */ - unsigned int automute_speaker_possible:1; /* there are speakers and either LO or HP */ - unsigned int automute_lo_possible:1; /* there are line outs and HP */ - unsigned int keep_vref_in_automute:1; /* Don't clear VREF in automute */ - - /* other flags */ - unsigned int no_analog :1; /* digital I/O only */ - unsigned int dyn_adc_switch:1; /* switch ADCs (for ALC275) */ - unsigned int single_input_src:1; - unsigned int vol_in_capsrc:1; /* use capsrc volume (ADC has no vol) */ - unsigned int parse_flags; /* passed to snd_hda_parse_pin_defcfg() */ - unsigned int shared_mic_hp:1; /* HP/Mic-in sharing */ - unsigned int inv_dmic_fixup:1; /* has inverted digital-mic workaround */ - unsigned int inv_dmic_muted:1; /* R-ch of inv d-mic is muted? */ - unsigned int no_primary_hp:1; /* Don't prefer HP pins to speaker pins */ - - /* auto-mute control */ - int automute_mode; - hda_nid_t automute_mixer_nid[AUTO_CFG_MAX_OUTS]; int init_amp; int codec_variant; /* flag for other variants */ - /* for virtual master */ - hda_nid_t vmaster_nid; - struct hda_vmaster_mute_hook vmaster_mute; -#ifdef CONFIG_PM - struct hda_loopback_check loopback; - int num_loopbacks; - struct hda_amp_list loopback_list[8]; -#endif - /* for PLL fix */ hda_nid_t pll_nid; unsigned int pll_coef_idx, pll_coef_bit; unsigned int coef0; - - /* multi-io */ - int multi_ios; - struct alc_multi_io multi_io[4]; - - /* bind volumes */ - struct snd_array bind_ctls; }; -static bool check_amp_caps(struct hda_codec *codec, hda_nid_t nid, - int dir, unsigned int bits) -{ - if (!nid) - return false; - if (get_wcaps(codec, nid) & (1 << (dir + 1))) - if (query_amp_caps(codec, nid, dir) & bits) - return true; - return false; -} - -#define nid_has_mute(codec, nid, dir) \ - check_amp_caps(codec, nid, dir, AC_AMPCAP_MUTE) -#define nid_has_volume(codec, nid, dir) \ - check_amp_caps(codec, nid, dir, AC_AMPCAP_NUM_STEPS) - -/* - * input MUX handling - */ -static int alc_mux_enum_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct alc_spec *spec = codec->spec; - unsigned int mux_idx = snd_ctl_get_ioffidx(kcontrol, &uinfo->id); - if (mux_idx >= spec->num_mux_defs) - mux_idx = 0; - if (!spec->input_mux[mux_idx].num_items && mux_idx > 0) - mux_idx = 0; - return snd_hda_input_mux_info(&spec->input_mux[mux_idx], uinfo); -} - -static int alc_mux_enum_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct alc_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 bool alc_dyn_adc_pcm_resetup(struct hda_codec *codec, int cur) -{ - struct alc_spec *spec = codec->spec; - hda_nid_t new_adc = spec->adc_nids[spec->dyn_adc_idx[cur]]; - - 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); - return true; - } - return false; -} - -static inline hda_nid_t get_capsrc(struct alc_spec *spec, int idx) -{ - return spec->capsrc_nids ? - spec->capsrc_nids[idx] : spec->adc_nids[idx]; -} - -static void call_update_outputs(struct hda_codec *codec); -static void alc_inv_dmic_sync(struct hda_codec *codec, bool force); - -/* for shared I/O, change the pin-control accordingly */ -static void update_shared_mic_hp(struct hda_codec *codec, bool set_as_mic) -{ - struct alc_spec *spec = codec->spec; - unsigned int val; - hda_nid_t pin = spec->autocfg.inputs[1].pin; - /* NOTE: this assumes that there are only two inputs, the - * first is the real internal mic and the second is HP/mic jack. - */ - - val = snd_hda_get_default_vref(codec, pin); - - /* This pin does not have vref caps - let's enable vref on pin 0x18 - instead, as suggested by Realtek */ - if (val == AC_PINCTL_VREF_HIZ) { - const hda_nid_t vref_pin = 0x18; - /* Sanity check pin 0x18 */ - if (get_wcaps_type(get_wcaps(codec, vref_pin)) == AC_WID_PIN && - get_defcfg_connect(snd_hda_codec_get_pincfg(codec, vref_pin)) == AC_JACK_PORT_NONE) { - unsigned int vref_val = snd_hda_get_default_vref(codec, vref_pin); - if (vref_val != AC_PINCTL_VREF_HIZ) - snd_hda_set_pin_ctl(codec, vref_pin, PIN_IN | (set_as_mic ? vref_val : 0)); - } - } - - val = set_as_mic ? val | PIN_IN : PIN_HP; - snd_hda_set_pin_ctl(codec, pin, val); - - spec->automute_speaker = !set_as_mic; - call_update_outputs(codec); -} - -/* select the given imux item; either unmute exclusively or select the route */ -static int alc_mux_select(struct hda_codec *codec, unsigned int adc_idx, - unsigned int idx, bool force) -{ - struct alc_spec *spec = codec->spec; - const struct hda_input_mux *imux; - unsigned int mux_idx; - int i, type, num_conns; - hda_nid_t nid; - - if (!spec->input_mux) - return 0; - - mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx; - imux = &spec->input_mux[mux_idx]; - if (!imux->num_items && mux_idx > 0) - imux = &spec->input_mux[0]; - if (!imux->num_items) - return 0; - - if (idx >= imux->num_items) - idx = imux->num_items - 1; - if (spec->cur_mux[adc_idx] == idx && !force) - return 0; - spec->cur_mux[adc_idx] = idx; - - if (spec->shared_mic_hp) - update_shared_mic_hp(codec, spec->cur_mux[adc_idx]); - - if (spec->dyn_adc_switch) { - alc_dyn_adc_pcm_resetup(codec, idx); - adc_idx = spec->dyn_adc_idx[idx]; - } - - nid = get_capsrc(spec, adc_idx); - - /* no selection? */ - num_conns = snd_hda_get_num_conns(codec, nid); - if (num_conns <= 1) - return 1; - - type = get_wcaps_type(get_wcaps(codec, nid)); - if (type == AC_WID_AUD_MIX) { - /* Matrix-mixer style (e.g. ALC882) */ - int active = imux->items[idx].index; - for (i = 0; i < num_conns; i++) { - unsigned int v = (i == active) ? 0 : HDA_AMP_MUTE; - snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, i, - HDA_AMP_MUTE, v); - } - } else { - /* MUX style (e.g. ALC880) */ - snd_hda_codec_write_cache(codec, nid, 0, - AC_VERB_SET_CONNECT_SEL, - imux->items[idx].index); - } - alc_inv_dmic_sync(codec, true); - return 1; -} - -static int alc_mux_enum_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - return alc_mux_select(codec, adc_idx, - ucontrol->value.enumerated.item[0], false); -} - -/* - * set up the input pin config (depending on the given auto-pin type) - */ -static void alc_set_input_pin(struct hda_codec *codec, hda_nid_t nid, - int auto_pin_type) -{ - unsigned int val = PIN_IN; - if (auto_pin_type == AUTO_PIN_MIC) - val |= snd_hda_get_default_vref(codec, nid); - snd_hda_set_pin_ctl(codec, nid, val); -} - /* * Append the given mixer and verb elements for the later use * The mixer array is referred in build_controls(), and init_verbs are @@ -485,171 +171,6 @@ static void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid, alc_fix_pll(codec); } -/* - * Jack detections for HP auto-mute and mic-switch - */ - -/* check each pin in the given array; returns true if any of them is plugged */ -static bool detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins) -{ - int i, present = 0; - - for (i = 0; i < num_pins; i++) { - hda_nid_t nid = pins[i]; - if (!nid) - break; - present |= snd_hda_jack_detect(codec, nid); - } - return present; -} - -/* standard HP/line-out auto-mute helper */ -static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins, - bool mute, bool hp_out) -{ - struct alc_spec *spec = codec->spec; - unsigned int mute_bits = mute ? HDA_AMP_MUTE : 0; - unsigned int pin_bits = mute ? 0 : (hp_out ? PIN_HP : PIN_OUT); - int i; - - for (i = 0; i < num_pins; i++) { - hda_nid_t nid = pins[i]; - unsigned int val; - if (!nid) - break; - switch (spec->automute_mode) { - case ALC_AUTOMUTE_PIN: - /* don't reset VREF value in case it's controlling - * the amp (see alc861_fixup_asus_amp_vref_0f()) - */ - if (spec->keep_vref_in_automute) { - val = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); - val &= ~PIN_HP; - } else - val = 0; - val |= pin_bits; - snd_hda_set_pin_ctl(codec, nid, val); - break; - case ALC_AUTOMUTE_AMP: - snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, - HDA_AMP_MUTE, mute_bits); - break; - case ALC_AUTOMUTE_MIXER: - nid = spec->automute_mixer_nid[i]; - if (!nid) - break; - snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0, - HDA_AMP_MUTE, mute_bits); - snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 1, - HDA_AMP_MUTE, mute_bits); - break; - } - } -} - -/* Toggle outputs muting */ -static void update_outputs(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - int on; - - /* Control HP pins/amps depending on master_mute state; - * in general, HP pins/amps control should be enabled in all cases, - * but currently set only for master_mute, just to be safe - */ - if (!spec->shared_mic_hp) /* don't change HP-pin when shared with mic */ - do_automute(codec, ARRAY_SIZE(spec->autocfg.hp_pins), - spec->autocfg.hp_pins, spec->master_mute, true); - - if (!spec->automute_speaker) - on = 0; - else - on = spec->hp_jack_present | spec->line_jack_present; - on |= spec->master_mute; - do_automute(codec, ARRAY_SIZE(spec->autocfg.speaker_pins), - spec->autocfg.speaker_pins, on, false); - - /* toggle line-out mutes if needed, too */ - /* if LO is a copy of either HP or Speaker, don't need to handle it */ - if (spec->autocfg.line_out_pins[0] == spec->autocfg.hp_pins[0] || - spec->autocfg.line_out_pins[0] == spec->autocfg.speaker_pins[0]) - return; - if (!spec->automute_lo) - on = 0; - else - on = spec->hp_jack_present; - on |= spec->master_mute; - do_automute(codec, ARRAY_SIZE(spec->autocfg.line_out_pins), - spec->autocfg.line_out_pins, on, false); -} - -static void call_update_outputs(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - if (spec->automute_hook) - spec->automute_hook(codec); - else - update_outputs(codec); -} - -/* standard HP-automute helper */ -static void alc_hp_automute(struct hda_codec *codec, struct hda_jack_tbl *jack) -{ - struct alc_spec *spec = codec->spec; - - spec->hp_jack_present = - detect_jacks(codec, ARRAY_SIZE(spec->autocfg.hp_pins), - spec->autocfg.hp_pins); - if (!spec->detect_hp || (!spec->automute_speaker && !spec->automute_lo)) - return; - call_update_outputs(codec); -} - -/* standard line-out-automute helper */ -static void alc_line_automute(struct hda_codec *codec, struct hda_jack_tbl *jack) -{ - struct alc_spec *spec = codec->spec; - - if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT) - return; - /* check LO jack only when it's different from HP */ - if (spec->autocfg.line_out_pins[0] == spec->autocfg.hp_pins[0]) - return; - - spec->line_jack_present = - detect_jacks(codec, ARRAY_SIZE(spec->autocfg.line_out_pins), - spec->autocfg.line_out_pins); - if (!spec->automute_speaker || !spec->detect_lo) - return; - call_update_outputs(codec); -} - -#define get_connection_index(codec, mux, nid) \ - snd_hda_get_conn_index(codec, mux, nid, 0) - -/* standard mic auto-switch helper */ -static void alc_mic_automute(struct hda_codec *codec, struct hda_jack_tbl *jack) -{ - struct alc_spec *spec = codec->spec; - hda_nid_t *pins = spec->imux_pins; - - if (!spec->auto_mic || !spec->auto_mic_valid_imux) - return; - if (snd_BUG_ON(!spec->adc_nids)) - return; - if (snd_BUG_ON(spec->int_mic_idx < 0 || spec->ext_mic_idx < 0)) - return; - - if (snd_hda_jack_detect(codec, pins[spec->ext_mic_idx])) - alc_mux_select(codec, 0, spec->ext_mic_idx, false); - else if (spec->dock_mic_idx >= 0 && - snd_hda_jack_detect(codec, pins[spec->dock_mic_idx])) - alc_mux_select(codec, 0, spec->dock_mic_idx, false); - else - alc_mux_select(codec, 0, spec->int_mic_idx, false); -} - /* update the master volume per volume-knob's unsol event */ static void alc_update_knob_master(struct hda_codec *codec, struct hda_jack_tbl *jack) { @@ -679,14 +200,6 @@ static void alc880_unsol_event(struct hda_codec *codec, unsigned int res) snd_hda_jack_unsol_event(codec, res >> 2); } -/* call init functions of standard auto-mute helpers */ -static void alc_inithook(struct hda_codec *codec) -{ - alc_hp_automute(codec, NULL); - alc_line_automute(codec, NULL); - alc_mic_automute(codec, NULL); -} - /* additional initialization for ALC888 variants */ static void alc888_coef_init(struct hda_codec *codec) { @@ -807,366 +320,6 @@ static void alc_auto_init_amp(struct hda_codec *codec, int type) } } -/* - * Auto-Mute mode mixer enum support - */ -static int alc_automute_mode_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct alc_spec *spec = codec->spec; - static const char * const texts2[] = { - "Disabled", "Enabled" - }; - static const char * const texts3[] = { - "Disabled", "Speaker Only", "Line Out+Speaker" - }; - const char * const *texts; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - if (spec->automute_speaker_possible && spec->automute_lo_possible) { - uinfo->value.enumerated.items = 3; - texts = texts3; - } else { - uinfo->value.enumerated.items = 2; - texts = texts2; - } - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); - return 0; -} - -static int alc_automute_mode_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct alc_spec *spec = codec->spec; - unsigned int val = 0; - if (spec->automute_speaker) - val++; - if (spec->automute_lo) - val++; - - ucontrol->value.enumerated.item[0] = val; - return 0; -} - -static int alc_automute_mode_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct alc_spec *spec = codec->spec; - - switch (ucontrol->value.enumerated.item[0]) { - case 0: - if (!spec->automute_speaker && !spec->automute_lo) - return 0; - spec->automute_speaker = 0; - spec->automute_lo = 0; - break; - case 1: - if (spec->automute_speaker_possible) { - if (!spec->automute_lo && spec->automute_speaker) - return 0; - spec->automute_speaker = 1; - spec->automute_lo = 0; - } else if (spec->automute_lo_possible) { - if (spec->automute_lo) - return 0; - spec->automute_lo = 1; - } else - return -EINVAL; - break; - case 2: - if (!spec->automute_lo_possible || !spec->automute_speaker_possible) - return -EINVAL; - if (spec->automute_speaker && spec->automute_lo) - return 0; - spec->automute_speaker = 1; - spec->automute_lo = 1; - break; - default: - return -EINVAL; - } - call_update_outputs(codec); - return 1; -} - -static const struct snd_kcontrol_new alc_automute_mode_enum = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Auto-Mute Mode", - .info = alc_automute_mode_info, - .get = alc_automute_mode_get, - .put = alc_automute_mode_put, -}; - -static struct snd_kcontrol_new *alc_kcontrol_new(struct alc_spec *spec) -{ - snd_array_init(&spec->kctls, sizeof(struct snd_kcontrol_new), 32); - return snd_array_new(&spec->kctls); -} - -static int alc_add_automute_mode_enum(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - struct snd_kcontrol_new *knew; - - knew = alc_kcontrol_new(spec); - if (!knew) - return -ENOMEM; - *knew = alc_automute_mode_enum; - knew->name = kstrdup("Auto-Mute Mode", GFP_KERNEL); - if (!knew->name) - return -ENOMEM; - return 0; -} - -/* - * Check the availability of HP/line-out auto-mute; - * Set up appropriately if really supported - */ -static void alc_init_automute(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int present = 0; - int i; - - if (cfg->hp_pins[0]) - present++; - if (cfg->line_out_pins[0]) - present++; - if (cfg->speaker_pins[0]) - present++; - if (present < 2) /* need two different output types */ - return; - - if (!cfg->speaker_pins[0] && - cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) { - memcpy(cfg->speaker_pins, cfg->line_out_pins, - sizeof(cfg->speaker_pins)); - cfg->speaker_outs = cfg->line_outs; - } - - if (!cfg->hp_pins[0] && - cfg->line_out_type == AUTO_PIN_HP_OUT) { - memcpy(cfg->hp_pins, cfg->line_out_pins, - sizeof(cfg->hp_pins)); - cfg->hp_outs = cfg->line_outs; - } - - spec->automute_mode = ALC_AUTOMUTE_PIN; - - for (i = 0; i < cfg->hp_outs; i++) { - hda_nid_t nid = cfg->hp_pins[i]; - if (!is_jack_detectable(codec, nid)) - continue; - snd_printdd("realtek: Enable HP auto-muting on NID 0x%x\n", - nid); - snd_hda_jack_detect_enable_callback(codec, nid, ALC_HP_EVENT, - alc_hp_automute); - spec->detect_hp = 1; - } - - if (cfg->line_out_type == AUTO_PIN_LINE_OUT && cfg->line_outs) { - if (cfg->speaker_outs) - for (i = 0; i < cfg->line_outs; i++) { - hda_nid_t nid = cfg->line_out_pins[i]; - if (!is_jack_detectable(codec, nid)) - continue; - snd_printdd("realtek: Enable Line-Out " - "auto-muting on NID 0x%x\n", nid); - snd_hda_jack_detect_enable_callback(codec, nid, ALC_FRONT_EVENT, - alc_line_automute); - spec->detect_lo = 1; - } - spec->automute_lo_possible = spec->detect_hp; - } - - spec->automute_speaker_possible = cfg->speaker_outs && - (spec->detect_hp || spec->detect_lo); - - spec->automute_lo = spec->automute_lo_possible; - spec->automute_speaker = spec->automute_speaker_possible; - - if (spec->automute_speaker_possible || spec->automute_lo_possible) - /* create a control for automute mode */ - alc_add_automute_mode_enum(codec); -} - -/* return the position of NID in the list, or -1 if not found */ -static int find_idx_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums) -{ - int i; - for (i = 0; i < nums; i++) - if (list[i] == nid) - return i; - return -1; -} - -/* check whether dynamic ADC-switching is available */ -static bool alc_check_dyn_adc_switch(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - struct hda_input_mux *imux = &spec->private_imux[0]; - int i, n, idx; - hda_nid_t cap, pin; - - if (imux != spec->input_mux) /* no dynamic imux? */ - return false; - - for (n = 0; n < spec->num_adc_nids; n++) { - cap = spec->private_capsrc_nids[n]; - for (i = 0; i < imux->num_items; i++) { - pin = spec->imux_pins[i]; - if (!pin) - return false; - if (get_connection_index(codec, cap, pin) < 0) - break; - } - if (i >= imux->num_items) - return true; /* no ADC-switch is needed */ - } - - for (i = 0; i < imux->num_items; i++) { - pin = spec->imux_pins[i]; - for (n = 0; n < spec->num_adc_nids; n++) { - cap = spec->private_capsrc_nids[n]; - idx = get_connection_index(codec, cap, pin); - if (idx >= 0) { - imux->items[i].index = idx; - spec->dyn_adc_idx[i] = n; - break; - } - } - } - - snd_printdd("realtek: enabling ADC switching\n"); - spec->dyn_adc_switch = 1; - return true; -} - -/* check whether all auto-mic pins are valid; setup indices if OK */ -static bool alc_auto_mic_check_imux(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - const struct hda_input_mux *imux; - - if (!spec->auto_mic) - return false; - if (spec->auto_mic_valid_imux) - return true; /* already checked */ - - /* fill up imux indices */ - if (!alc_check_dyn_adc_switch(codec)) { - spec->auto_mic = 0; - return false; - } - - imux = spec->input_mux; - spec->ext_mic_idx = find_idx_in_nid_list(spec->ext_mic_pin, - spec->imux_pins, imux->num_items); - spec->int_mic_idx = find_idx_in_nid_list(spec->int_mic_pin, - spec->imux_pins, imux->num_items); - spec->dock_mic_idx = find_idx_in_nid_list(spec->dock_mic_pin, - spec->imux_pins, imux->num_items); - if (spec->ext_mic_idx < 0 || spec->int_mic_idx < 0) { - spec->auto_mic = 0; - return false; /* no corresponding imux */ - } - - snd_hda_jack_detect_enable_callback(codec, spec->ext_mic_pin, - ALC_MIC_EVENT, alc_mic_automute); - if (spec->dock_mic_pin) - snd_hda_jack_detect_enable_callback(codec, spec->dock_mic_pin, - ALC_MIC_EVENT, - alc_mic_automute); - - spec->auto_mic_valid_imux = 1; - spec->auto_mic = 1; - return true; -} - -/* - * Check the availability of auto-mic switch; - * Set up if really supported - */ -static void alc_init_auto_mic(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - hda_nid_t fixed, ext, dock; - int i; - - if (spec->shared_mic_hp) - return; /* no auto-mic for the shared I/O */ - - spec->ext_mic_idx = spec->int_mic_idx = spec->dock_mic_idx = -1; - - fixed = ext = dock = 0; - for (i = 0; i < cfg->num_inputs; i++) { - hda_nid_t nid = cfg->inputs[i].pin; - unsigned int defcfg; - defcfg = snd_hda_codec_get_pincfg(codec, nid); - switch (snd_hda_get_input_pin_attr(defcfg)) { - case INPUT_PIN_ATTR_INT: - if (fixed) - return; /* already occupied */ - if (cfg->inputs[i].type != AUTO_PIN_MIC) - return; /* invalid type */ - fixed = nid; - break; - case INPUT_PIN_ATTR_UNUSED: - return; /* invalid entry */ - case INPUT_PIN_ATTR_DOCK: - if (dock) - return; /* already occupied */ - if (cfg->inputs[i].type > AUTO_PIN_LINE_IN) - return; /* invalid type */ - dock = nid; - break; - default: - if (ext) - return; /* already occupied */ - if (cfg->inputs[i].type != AUTO_PIN_MIC) - return; /* invalid type */ - ext = nid; - break; - } - } - if (!ext && dock) { - ext = dock; - dock = 0; - } - if (!ext || !fixed) - return; - if (!is_jack_detectable(codec, ext)) - return; /* no unsol support */ - if (dock && !is_jack_detectable(codec, dock)) - return; /* no unsol support */ - - /* check imux indices */ - spec->ext_mic_pin = ext; - spec->int_mic_pin = fixed; - spec->dock_mic_pin = dock; - - spec->auto_mic = 1; - if (!alc_auto_mic_check_imux(codec)) - return; - - snd_printdd("realtek: Enable auto-mic switch on NID 0x%x/0x%x/0x%x\n", - ext, fixed, dock); -} - -/* check the availabilities of auto-mute and auto-mic switches */ -static void alc_auto_check_switches(struct hda_codec *codec) -{ - alc_init_automute(codec); - alc_init_auto_mic(codec); -} /* * Realtek SSID verification @@ -1252,6 +405,15 @@ do_sku: return 0; } +/* return the position of NID in the list, or -1 if not found */ +static int find_idx_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums) +{ + int i; + for (i = 0; i < nums; i++) + if (list[i] == nid) + return i; + return -1; +} /* return true if the given NID is found in the list */ static bool found_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums) { @@ -1354,9 +516,9 @@ do_sku: * 15 : 1 --> enable the function "Mute internal speaker * when the external headphone out jack is plugged" */ - if (!spec->autocfg.hp_pins[0] && - !(spec->autocfg.line_out_pins[0] && - spec->autocfg.line_out_type == AUTO_PIN_HP_OUT)) { + if (!spec->gen.autocfg.hp_pins[0] && + !(spec->gen.autocfg.line_out_pins[0] && + spec->gen.autocfg.line_out_type == AUTO_PIN_HP_OUT)) { hda_nid_t nid; tmp = (ass >> 11) & 0x3; /* HP to chassis */ if (tmp == 0) @@ -1369,10 +531,10 @@ do_sku: nid = porti; else return 1; - if (found_in_nid_list(nid, spec->autocfg.line_out_pins, - spec->autocfg.line_outs)) + if (found_in_nid_list(nid, spec->gen.autocfg.line_out_pins, + spec->gen.autocfg.line_outs)) return 1; - spec->autocfg.hp_pins[0] = nid; + spec->gen.autocfg.hp_pins[0] = nid; } return 1; } @@ -1422,252 +584,54 @@ static unsigned int alc_get_coef0(struct hda_codec *codec) } /* - * Digital I/O handling */ -/* set right pin controls for digital I/O */ -static void alc_auto_init_digital(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - int i; - hda_nid_t pin, dac; - - for (i = 0; i < spec->autocfg.dig_outs; i++) { - pin = spec->autocfg.dig_out_pins[i]; - if (!pin) - continue; - snd_hda_set_pin_ctl(codec, pin, PIN_OUT); - if (!i) - dac = spec->multiout.dig_out_nid; - else - dac = spec->slave_dig_outs[i - 1]; - if (!dac || !(get_wcaps(codec, dac) & AC_WCAP_OUT_AMP)) - continue; - snd_hda_codec_write(codec, dac, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_OUT_UNMUTE); - } - pin = spec->autocfg.dig_in_pin; - if (pin) - snd_hda_set_pin_ctl(codec, pin, PIN_IN); -} - -/* parse digital I/Os and set up NIDs in BIOS auto-parse mode */ -static void alc_auto_parse_digital(struct hda_codec *codec) +static hda_nid_t get_adc_nid(struct hda_codec *codec, int adc_idx, int imux_idx) { - struct alc_spec *spec = codec->spec; - int i, err, nums; - hda_nid_t dig_nid; - - /* support multiple SPDIFs; the secondary is set up as a slave */ - nums = 0; - for (i = 0; i < spec->autocfg.dig_outs; i++) { - hda_nid_t conn[4]; - err = snd_hda_get_connections(codec, - spec->autocfg.dig_out_pins[i], - conn, ARRAY_SIZE(conn)); - if (err <= 0) - continue; - dig_nid = conn[0]; /* assume the first element is audio-out */ - if (!nums) { - spec->multiout.dig_out_nid = dig_nid; - spec->dig_out_type = spec->autocfg.dig_out_type[0]; - } else { - spec->multiout.slave_dig_outs = spec->slave_dig_outs; - if (nums >= ARRAY_SIZE(spec->slave_dig_outs) - 1) - break; - spec->slave_dig_outs[nums - 1] = dig_nid; - } - nums++; - } - - if (spec->autocfg.dig_in_pin) { - dig_nid = codec->start_nid; - for (i = 0; i < codec->num_nodes; i++, dig_nid++) { - unsigned int wcaps = get_wcaps(codec, dig_nid); - if (get_wcaps_type(wcaps) != AC_WID_AUD_IN) - continue; - if (!(wcaps & AC_WCAP_DIGITAL)) - continue; - if (!(wcaps & AC_WCAP_CONN_LIST)) - continue; - err = get_connection_index(codec, dig_nid, - spec->autocfg.dig_in_pin); - if (err >= 0) { - spec->dig_in_nid = dig_nid; - break; - } - } - } -} - -/* - * capture mixer elements - */ -static int alc_cap_vol_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct alc_spec *spec = codec->spec; - unsigned long val; - int err; - - mutex_lock(&codec->control_mutex); - if (spec->vol_in_capsrc) - val = HDA_COMPOSE_AMP_VAL(spec->capsrc_nids[0], 3, 0, HDA_OUTPUT); - else - val = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0, HDA_INPUT); - kcontrol->private_value = val; - err = snd_hda_mixer_amp_volume_info(kcontrol, uinfo); - mutex_unlock(&codec->control_mutex); - return err; -} - -static int alc_cap_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag, - unsigned int size, unsigned int __user *tlv) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct alc_spec *spec = codec->spec; - unsigned long val; - int err; - - mutex_lock(&codec->control_mutex); - if (spec->vol_in_capsrc) - val = HDA_COMPOSE_AMP_VAL(spec->capsrc_nids[0], 3, 0, HDA_OUTPUT); - else - val = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0, HDA_INPUT); - kcontrol->private_value = val; - err = snd_hda_mixer_amp_tlv(kcontrol, op_flag, size, tlv); - mutex_unlock(&codec->control_mutex); - return err; + struct hda_gen_spec *spec = codec->spec; + if (spec->dyn_adc_switch) + adc_idx = spec->dyn_adc_idx[imux_idx]; + return spec->adc_nids[adc_idx]; } -typedef int (*getput_call_t)(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol); - -static int alc_cap_getput_caller(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol, - getput_call_t func, bool is_put) +static void alc_inv_dmic_sync_adc(struct hda_codec *codec, int adc_idx) { - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct alc_spec *spec = codec->spec; - int i, err = 0; - - mutex_lock(&codec->control_mutex); - if (is_put && spec->dyn_adc_switch) { - for (i = 0; i < spec->num_adc_nids; i++) { - kcontrol->private_value = - HDA_COMPOSE_AMP_VAL(spec->adc_nids[i], - 3, 0, HDA_INPUT); - err = func(kcontrol, ucontrol); - if (err < 0) - goto error; - } - } else { - i = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - if (spec->vol_in_capsrc) - kcontrol->private_value = - HDA_COMPOSE_AMP_VAL(spec->capsrc_nids[i], - 3, 0, HDA_OUTPUT); - else - kcontrol->private_value = - HDA_COMPOSE_AMP_VAL(spec->adc_nids[i], - 3, 0, HDA_INPUT); - err = func(kcontrol, ucontrol); - } - if (err >= 0 && is_put) - alc_inv_dmic_sync(codec, false); - error: - mutex_unlock(&codec->control_mutex); - return err; -} - -static int alc_cap_vol_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - return alc_cap_getput_caller(kcontrol, ucontrol, - snd_hda_mixer_amp_volume_get, false); -} - -static int alc_cap_vol_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - return alc_cap_getput_caller(kcontrol, ucontrol, - snd_hda_mixer_amp_volume_put, true); -} - -/* capture mixer elements */ -#define alc_cap_sw_info snd_ctl_boolean_stereo_info - -static int alc_cap_sw_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - return alc_cap_getput_caller(kcontrol, ucontrol, - snd_hda_mixer_amp_switch_get, false); -} - -static int alc_cap_sw_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - return alc_cap_getput_caller(kcontrol, ucontrol, - snd_hda_mixer_amp_switch_put, true); -} + struct hda_input_mux *imux = &spec->gen.input_mux; + struct nid_path *path; + hda_nid_t nid; + int i, dir, parm; + unsigned int val; -#define _DEFINE_CAPMIX(num) \ - { \ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = "Capture Switch", \ - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ - .count = num, \ - .info = alc_cap_sw_info, \ - .get = alc_cap_sw_get, \ - .put = alc_cap_sw_put, \ - }, \ - { \ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = "Capture Volume", \ - .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | \ - SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ - SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK), \ - .count = num, \ - .info = alc_cap_vol_info, \ - .get = alc_cap_vol_get, \ - .put = alc_cap_vol_put, \ - .tlv = { .c = alc_cap_vol_tlv }, \ + for (i = 0; i < imux->num_items; i++) { + if (spec->gen.imux_pins[i] == spec->inv_dmic_pin) + break; } + if (i >= imux->num_items) + return; -#define _DEFINE_CAPSRC(num) \ - { \ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - /* .name = "Capture Source", */ \ - .name = "Input Source", \ - .count = num, \ - .info = alc_mux_enum_info, \ - .get = alc_mux_enum_get, \ - .put = alc_mux_enum_put, \ - } + path = snd_hda_get_nid_path(codec, spec->inv_dmic_pin, + get_adc_nid(codec, adc_idx, i)); + val = path->ctls[NID_PATH_MUTE_CTL]; + if (!val) + return; + nid = get_amp_nid_(val); + dir = get_amp_direction_(val); + parm = AC_AMP_SET_RIGHT | + (dir == HDA_OUTPUT ? AC_AMP_SET_OUTPUT : AC_AMP_SET_INPUT); -#define DEFINE_CAPMIX(num) \ -static const struct snd_kcontrol_new alc_capture_mixer ## num[] = { \ - _DEFINE_CAPMIX(num), \ - _DEFINE_CAPSRC(num), \ - { } /* end */ \ -} + /* flush all cached amps at first */ + snd_hda_codec_flush_cache(codec); -#define DEFINE_CAPMIX_NOSRC(num) \ -static const struct snd_kcontrol_new alc_capture_mixer_nosrc ## num[] = { \ - _DEFINE_CAPMIX(num), \ - { } /* end */ \ + /* we care only right channel */ + val = snd_hda_codec_amp_read(codec, nid, 1, dir, 0); + if (val & 0x80) /* if already muted, we don't need to touch */ + return; + val |= 0x80; + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, + parm | val); } -/* up to three ADCs */ -DEFINE_CAPMIX(1); -DEFINE_CAPMIX(2); -DEFINE_CAPMIX(3); -DEFINE_CAPMIX_NOSRC(1); -DEFINE_CAPMIX_NOSRC(2); -DEFINE_CAPMIX_NOSRC(3); - /* * Inverted digital-mic handling * @@ -1686,43 +650,31 @@ DEFINE_CAPMIX_NOSRC(3); static void alc_inv_dmic_sync(struct hda_codec *codec, bool force) { struct alc_spec *spec = codec->spec; - int i; + int src, nums; if (!spec->inv_dmic_fixup) return; if (!spec->inv_dmic_muted && !force) return; - for (i = 0; i < spec->num_adc_nids; i++) { - int src = spec->dyn_adc_switch ? 0 : i; + nums = spec->gen.dyn_adc_switch ? 1 : spec->gen.num_adc_nids; + for (src = 0; src < nums; src++) { bool dmic_fixup = false; - hda_nid_t nid; - int parm, dir, v; if (spec->inv_dmic_muted && - spec->imux_pins[spec->cur_mux[src]] == spec->inv_dmic_pin) + spec->gen.imux_pins[spec->gen.cur_mux[src]] == spec->inv_dmic_pin) dmic_fixup = true; if (!dmic_fixup && !force) continue; - if (spec->vol_in_capsrc) { - nid = spec->capsrc_nids[i]; - parm = AC_AMP_SET_RIGHT | AC_AMP_SET_OUTPUT; - dir = HDA_OUTPUT; - } else { - nid = spec->adc_nids[i]; - parm = AC_AMP_SET_RIGHT | AC_AMP_SET_INPUT; - dir = HDA_INPUT; - } - /* we care only right channel */ - v = snd_hda_codec_amp_read(codec, nid, 1, dir, 0); - if (v & 0x80) /* if already muted, we don't need to touch */ - continue; - if (dmic_fixup) /* add mute for d-mic */ - v |= 0x80; - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, - parm | v); + alc_inv_dmic_sync_adc(codec, src); } } +static void alc_inv_dmic_hook(struct hda_codec *codec, + struct snd_ctl_elem_value *ucontrol) +{ + alc_inv_dmic_sync(codec, false); +} + static int alc_inv_dmic_sw_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -1749,6 +701,7 @@ static int alc_inv_dmic_sw_put(struct snd_kcontrol *kcontrol, static const struct snd_kcontrol_new alc_inv_dmic_sw = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Inverted Internal Mic Capture Switch", .info = snd_ctl_boolean_mono_info, .get = alc_inv_dmic_sw_get, .put = alc_inv_dmic_sw_put, @@ -1757,55 +710,24 @@ static const struct snd_kcontrol_new alc_inv_dmic_sw = { static int alc_add_inv_dmic_mixer(struct hda_codec *codec, hda_nid_t nid) { struct alc_spec *spec = codec->spec; - struct snd_kcontrol_new *knew = alc_kcontrol_new(spec); - if (!knew) - return -ENOMEM; - *knew = alc_inv_dmic_sw; - knew->name = kstrdup("Inverted Internal Mic Capture Switch", GFP_KERNEL); - if (!knew->name) + + if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &alc_inv_dmic_sw)) return -ENOMEM; spec->inv_dmic_fixup = 1; spec->inv_dmic_muted = 0; spec->inv_dmic_pin = nid; + spec->gen.cap_sync_hook = alc_inv_dmic_hook; return 0; } /* typically the digital mic is put at node 0x12 */ static void alc_fixup_inv_dmic_0x12(struct hda_codec *codec, - const struct alc_fixup *fix, int action) + const struct hda_fixup *fix, int action) { - if (action == ALC_FIXUP_ACT_PROBE) + if (action == HDA_FIXUP_ACT_PROBE) alc_add_inv_dmic_mixer(codec, 0x12); } -/* - * virtual master controls - */ - -/* - * slave controls for virtual master - */ -static const char * const alc_slave_pfxs[] = { - "Front", "Surround", "Center", "LFE", "Side", - "Headphone", "Speaker", "Mono", "Line Out", - "CLFE", "Bass Speaker", "PCM", - NULL, -}; - -/* - * build control elements - */ - -#define NID_MAPPING (-1) - -#define SUBDEV_SPEAKER_ (0 << 6) -#define SUBDEV_HP_ (1 << 6) -#define SUBDEV_LINE_ (2 << 6) -#define SUBDEV_SPEAKER(x) (SUBDEV_SPEAKER_ | ((x) & 0x3f)) -#define SUBDEV_HP(x) (SUBDEV_HP_ | ((x) & 0x3f)) -#define SUBDEV_LINE(x) (SUBDEV_LINE_ | ((x) & 0x3f)) - -static void alc_free_kctls(struct hda_codec *codec); #ifdef CONFIG_SND_HDA_INPUT_BEEP /* additional beep mixers; the actual parameters are overwritten at build */ @@ -1816,44 +738,20 @@ static const struct snd_kcontrol_new alc_beep_mixer[] = { }; #endif -static int __alc_build_controls(struct hda_codec *codec) +static int alc_build_controls(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - struct snd_kcontrol *kctl = NULL; - const struct snd_kcontrol_new *knew; - int i, j, err; - unsigned int u; - hda_nid_t nid; + int i, err; + + err = snd_hda_gen_build_controls(codec); + if (err < 0) + return 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->cap_mixer) { - err = snd_hda_add_new_ctls(codec, spec->cap_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; - if (!spec->no_analog) { - 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; - } #ifdef CONFIG_SND_HDA_INPUT_BEEP /* create beep controls if needed */ @@ -1872,130 +770,7 @@ static int __alc_build_controls(struct hda_codec *codec) } #endif - /* if we have no master control, let's create it */ - if (!spec->no_analog && - !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, alc_slave_pfxs, - "Playback Volume"); - if (err < 0) - return err; - } - if (!spec->no_analog && - !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) { - err = __snd_hda_add_vmaster(codec, "Master Playback Switch", - NULL, alc_slave_pfxs, - "Playback Switch", - true, &spec->vmaster_mute.sw_kctl); - if (err < 0) - return err; - } - - /* assign Capture Source enums to NID */ - if (spec->capsrc_nids || spec->adc_nids) { - kctl = snd_hda_find_mixer_ctl(codec, "Capture Source"); - if (!kctl) - kctl = snd_hda_find_mixer_ctl(codec, "Input Source"); - for (i = 0; kctl && i < kctl->count; i++) { - err = snd_hda_add_nid(codec, kctl, i, - get_capsrc(spec, i)); - if (err < 0) - return err; - } - } - if (spec->cap_mixer && spec->adc_nids) { - const char *kname = kctl ? kctl->id.name : NULL; - for (knew = spec->cap_mixer; knew->name; knew++) { - if (kname && strcmp(knew->name, kname) == 0) - continue; - kctl = snd_hda_find_mixer_ctl(codec, knew->name); - 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; - } - } - } - - /* other nid->control mapping */ - for (i = 0; i < spec->num_mixers; i++) { - for (knew = spec->mixers[i]; knew->name; knew++) { - if (knew->iface != NID_MAPPING) - continue; - kctl = snd_hda_find_mixer_ctl(codec, knew->name); - if (kctl == NULL) - continue; - u = knew->subdevice; - for (j = 0; j < 4; j++, u >>= 8) { - nid = u & 0x3f; - if (nid == 0) - continue; - switch (u & 0xc0) { - case SUBDEV_SPEAKER_: - nid = spec->autocfg.speaker_pins[nid]; - break; - case SUBDEV_LINE_: - nid = spec->autocfg.line_out_pins[nid]; - break; - case SUBDEV_HP_: - nid = spec->autocfg.hp_pins[nid]; - break; - default: - continue; - } - err = snd_hda_add_nid(codec, kctl, 0, nid); - if (err < 0) - return err; - } - u = knew->private_value; - for (j = 0; j < 4; j++, u >>= 8) { - nid = u & 0xff; - if (nid == 0) - continue; - err = snd_hda_add_nid(codec, kctl, 0, nid); - if (err < 0) - return err; - } - } - } - - alc_free_kctls(codec); /* no longer needed */ - - return 0; -} - -static int alc_build_jacks(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - if (spec->shared_mic_hp) { - int err; - int nid = spec->autocfg.inputs[1].pin; - err = snd_hda_jack_add_kctl(codec, nid, "Headphone Mic", 0); - if (err < 0) - return err; - err = snd_hda_jack_detect_enable(codec, nid, 0); - if (err < 0) - return err; - } - - return snd_hda_jack_add_kctls(codec, &spec->autocfg); -} - -static int alc_build_controls(struct hda_codec *codec) -{ - int err = __alc_build_controls(codec); - if (err < 0) - return err; - - err = alc_build_jacks(codec); - if (err < 0) - return err; - alc_apply_fixup(codec, ALC_FIXUP_ACT_BUILD); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_BUILD); return 0; } @@ -2004,9 +779,6 @@ static int alc_build_controls(struct hda_codec *codec) * Common callbacks */ -static void alc_init_special_input_src(struct hda_codec *codec); -static void alc_auto_init_std(struct hda_codec *codec); - static int alc_init(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; @@ -2017,343 +789,9 @@ static int alc_init(struct hda_codec *codec) alc_fix_pll(codec); alc_auto_init_amp(codec, spec->init_amp); - snd_hda_gen_apply_verbs(codec); - alc_init_special_input_src(codec); - alc_auto_init_std(codec); + snd_hda_gen_init(codec); - alc_apply_fixup(codec, ALC_FIXUP_ACT_INIT); - - hda_call_check_power_status(codec, 0x01); - return 0; -} - -#ifdef CONFIG_PM -static int alc_check_power_status(struct hda_codec *codec, hda_nid_t nid) -{ - struct alc_spec *spec = codec->spec; - return snd_hda_check_amp_list_power(codec, &spec->loopback, nid); -} -#endif - -/* - * Analog playback callbacks - */ -static int alc_playback_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct alc_spec *spec = codec->spec; - return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream, - hinfo); -} - -static int alc_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 alc_spec *spec = codec->spec; - return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, - stream_tag, format, substream); -} - -static int alc_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct alc_spec *spec = codec->spec; - return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); -} - -/* - * Digital out - */ -static int alc_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct alc_spec *spec = codec->spec; - return snd_hda_multi_out_dig_open(codec, &spec->multiout); -} - -static int alc_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 alc_spec *spec = codec->spec; - return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, - stream_tag, format, substream); -} - -static int alc_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct alc_spec *spec = codec->spec; - return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout); -} - -static int alc_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct alc_spec *spec = codec->spec; - return snd_hda_multi_out_dig_close(codec, &spec->multiout); -} - -/* - * Analog capture - */ -static int alc_alt_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 alc_spec *spec = codec->spec; - - snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1], - stream_tag, 0, format); - return 0; -} - -static int alc_alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct alc_spec *spec = codec->spec; - - snd_hda_codec_cleanup_stream(codec, - spec->adc_nids[substream->number + 1]); - return 0; -} - -/* analog capture with dynamic dual-adc changes */ -static int dyn_adc_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 alc_spec *spec = codec->spec; - spec->cur_adc = spec->adc_nids[spec->dyn_adc_idx[spec->cur_mux[0]]]; - 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 dyn_adc_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct alc_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 dyn_adc_pcm_analog_capture = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - .nid = 0, /* fill later */ - .ops = { - .prepare = dyn_adc_capture_pcm_prepare, - .cleanup = dyn_adc_capture_pcm_cleanup - }, -}; - -/* - */ -static const struct hda_pcm_stream alc_pcm_analog_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 8, - /* NID is set in alc_build_pcms */ - .ops = { - .open = alc_playback_pcm_open, - .prepare = alc_playback_pcm_prepare, - .cleanup = alc_playback_pcm_cleanup - }, -}; - -static const struct hda_pcm_stream alc_pcm_analog_capture = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - /* NID is set in alc_build_pcms */ -}; - -static const struct hda_pcm_stream alc_pcm_analog_alt_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - /* NID is set in alc_build_pcms */ -}; - -static const struct hda_pcm_stream alc_pcm_analog_alt_capture = { - .substreams = 2, /* can be overridden */ - .channels_min = 2, - .channels_max = 2, - /* NID is set in alc_build_pcms */ - .ops = { - .prepare = alc_alt_capture_pcm_prepare, - .cleanup = alc_alt_capture_pcm_cleanup - }, -}; - -static const struct hda_pcm_stream alc_pcm_digital_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - /* NID is set in alc_build_pcms */ - .ops = { - .open = alc_dig_playback_pcm_open, - .close = alc_dig_playback_pcm_close, - .prepare = alc_dig_playback_pcm_prepare, - .cleanup = alc_dig_playback_pcm_cleanup - }, -}; - -static const struct hda_pcm_stream alc_pcm_digital_capture = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - /* NID is set in alc_build_pcms */ -}; - -/* Used by alc_build_pcms to flag that a PCM has no playback stream */ -static const struct hda_pcm_stream alc_pcm_null_stream = { - .substreams = 0, - .channels_min = 0, - .channels_max = 0, -}; - -static int alc_build_pcms(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - struct hda_pcm *info = spec->pcm_rec; - const struct hda_pcm_stream *p; - bool have_multi_adcs; - int i; - - codec->num_pcms = 1; - codec->pcm_info = info; - - if (spec->no_analog) - goto skip_analog; - - snprintf(spec->stream_name_analog, sizeof(spec->stream_name_analog), - "%s Analog", codec->chip_name); - info->name = spec->stream_name_analog; - - if (spec->multiout.num_dacs > 0) { - p = spec->stream_analog_playback; - if (!p) - p = &alc_pcm_analog_playback; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0]; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = - spec->multiout.max_channels; - } - if (spec->adc_nids) { - p = spec->stream_analog_capture; - if (!p) { - if (spec->dyn_adc_switch) - p = &dyn_adc_pcm_analog_capture; - else - p = &alc_pcm_analog_capture; - } - info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p; - info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; - } - - if (spec->channel_mode) { - info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 0; - for (i = 0; i < spec->num_channel_mode; i++) { - if (spec->channel_mode[i].channels > info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max) { - info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->channel_mode[i].channels; - } - } - } - - skip_analog: - /* SPDIF for stream index #1 */ - if (spec->multiout.dig_out_nid || spec->dig_in_nid) { - snprintf(spec->stream_name_digital, - sizeof(spec->stream_name_digital), - "%s Digital", codec->chip_name); - codec->num_pcms = 2; - codec->slave_dig_outs = spec->multiout.slave_dig_outs; - info = spec->pcm_rec + 1; - info->name = spec->stream_name_digital; - if (spec->dig_out_type) - info->pcm_type = spec->dig_out_type; - else - info->pcm_type = HDA_PCM_TYPE_SPDIF; - if (spec->multiout.dig_out_nid) { - p = spec->stream_digital_playback; - if (!p) - p = &alc_pcm_digital_playback; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid; - } - if (spec->dig_in_nid) { - p = spec->stream_digital_capture; - if (!p) - p = &alc_pcm_digital_capture; - info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p; - info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid; - } - /* FIXME: do we need this for all Realtek codec models? */ - codec->spdif_status_reset = 1; - } - - if (spec->no_analog) - return 0; - - /* If the use of more than one ADC is requested for the current - * model, configure a second analog capture-only PCM. - */ - have_multi_adcs = (spec->num_adc_nids > 1) && - !spec->dyn_adc_switch && !spec->auto_mic && - (!spec->input_mux || spec->input_mux->num_items > 1); - /* Additional Analaog capture for index #2 */ - if (spec->alt_dac_nid || have_multi_adcs) { - codec->num_pcms = 3; - info = spec->pcm_rec + 2; - info->name = spec->stream_name_analog; - if (spec->alt_dac_nid) { - p = spec->stream_analog_alt_playback; - if (!p) - p = &alc_pcm_analog_alt_playback; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = - spec->alt_dac_nid; - } else { - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = - alc_pcm_null_stream; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0; - } - if (have_multi_adcs) { - p = spec->stream_analog_alt_capture; - if (!p) - p = &alc_pcm_analog_alt_capture; - info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p; - info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = - spec->adc_nids[1]; - info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = - spec->num_adc_nids - 1; - } else { - info->stream[SNDRV_PCM_STREAM_CAPTURE] = - alc_pcm_null_stream; - info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = 0; - } - } + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_INIT); return 0; } @@ -2367,31 +805,6 @@ static inline void alc_shutup(struct hda_codec *codec) snd_hda_shutup_pins(codec); } -static void alc_free_kctls(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - if (spec->kctls.list) { - struct snd_kcontrol_new *kctl = spec->kctls.list; - int i; - for (i = 0; i < spec->kctls.used; i++) - kfree(kctl[i].name); - } - snd_array_free(&spec->kctls); -} - -static void alc_free_bind_ctls(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - if (spec->bind_ctls.list) { - struct hda_bind_ctls **ctl = spec->bind_ctls.list; - int i; - for (i = 0; i < spec->bind_ctls.used; i++) - kfree(ctl[i]); - } - snd_array_free(&spec->bind_ctls); -} - static void alc_free(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; @@ -2399,12 +812,9 @@ static void alc_free(struct hda_codec *codec) if (!spec) return; - alc_shutup(codec); - alc_free_kctls(codec); - alc_free_bind_ctls(codec); - snd_hda_gen_free(&spec->gen); - kfree(spec); + snd_hda_gen_spec_free(&spec->gen); snd_hda_detach_beep_device(codec); + kfree(spec); } #ifdef CONFIG_PM @@ -2440,16 +850,14 @@ static int alc_resume(struct hda_codec *codec) */ static const struct hda_codec_ops alc_patch_ops = { .build_controls = alc_build_controls, - .build_pcms = alc_build_pcms, + .build_pcms = snd_hda_gen_build_pcms, .init = alc_init, .free = alc_free, .unsol_event = snd_hda_jack_unsol_event, #ifdef CONFIG_PM .resume = alc_resume, -#endif -#ifdef CONFIG_PM .suspend = alc_suspend, - .check_power_status = alc_check_power_status, + .check_power_status = snd_hda_gen_check_power_status, #endif .reboot_notify = alc_shutup, }; @@ -2509,1737 +917,6 @@ static int alc_codec_rename_from_preset(struct hda_codec *codec) return 0; } -/* - * Automatic parse of I/O pins from the BIOS configuration - */ - -enum { - ALC_CTL_WIDGET_VOL, - ALC_CTL_WIDGET_MUTE, - ALC_CTL_BIND_MUTE, - ALC_CTL_BIND_VOL, - ALC_CTL_BIND_SW, -}; -static const struct snd_kcontrol_new alc_control_templates[] = { - HDA_CODEC_VOLUME(NULL, 0, 0, 0), - HDA_CODEC_MUTE(NULL, 0, 0, 0), - HDA_BIND_MUTE(NULL, 0, 0, 0), - HDA_BIND_VOL(NULL, 0), - HDA_BIND_SW(NULL, 0), -}; - -/* add dynamic controls */ -static int add_control(struct alc_spec *spec, int type, const char *name, - int cidx, unsigned long val) -{ - struct snd_kcontrol_new *knew; - - knew = alc_kcontrol_new(spec); - if (!knew) - return -ENOMEM; - *knew = alc_control_templates[type]; - knew->name = kstrdup(name, GFP_KERNEL); - if (!knew->name) - return -ENOMEM; - knew->index = cidx; - if (get_amp_nid_(val)) - knew->subdevice = HDA_SUBDEV_AMP_FLAG; - knew->private_value = val; - return 0; -} - -static int add_control_with_pfx(struct alc_spec *spec, int type, - const char *pfx, const char *dir, - const char *sfx, int cidx, unsigned long val) -{ - char name[32]; - snprintf(name, sizeof(name), "%s %s %s", pfx, dir, sfx); - return add_control(spec, type, name, cidx, val); -} - -#define add_pb_vol_ctrl(spec, type, pfx, val) \ - add_control_with_pfx(spec, type, pfx, "Playback", "Volume", 0, val) -#define add_pb_sw_ctrl(spec, type, pfx, val) \ - add_control_with_pfx(spec, type, pfx, "Playback", "Switch", 0, val) -#define __add_pb_vol_ctrl(spec, type, pfx, cidx, val) \ - add_control_with_pfx(spec, type, pfx, "Playback", "Volume", cidx, val) -#define __add_pb_sw_ctrl(spec, type, pfx, cidx, val) \ - add_control_with_pfx(spec, type, pfx, "Playback", "Switch", cidx, val) - -static const char * const channel_name[4] = { - "Front", "Surround", "CLFE", "Side" -}; - -static const char *alc_get_line_out_pfx(struct alc_spec *spec, int ch, - bool can_be_master, int *index) -{ - struct auto_pin_cfg *cfg = &spec->autocfg; - - *index = 0; - if (cfg->line_outs == 1 && !spec->multi_ios && - !cfg->hp_outs && !cfg->speaker_outs && can_be_master) - return "Master"; - - switch (cfg->line_out_type) { - case AUTO_PIN_SPEAKER_OUT: - if (cfg->line_outs == 1) - return "Speaker"; - if (cfg->line_outs == 2) - return ch ? "Bass Speaker" : "Speaker"; - break; - case AUTO_PIN_HP_OUT: - /* for multi-io case, only the primary out */ - if (ch && spec->multi_ios) - break; - *index = ch; - return "Headphone"; - default: - if (cfg->line_outs == 1 && !spec->multi_ios) - return "PCM"; - break; - } - if (ch >= ARRAY_SIZE(channel_name)) { - snd_BUG(); - return "PCM"; - } - - return channel_name[ch]; -} - -#ifdef CONFIG_PM -/* add the powersave loopback-list entry */ -static void add_loopback_list(struct alc_spec *spec, hda_nid_t mix, int idx) -{ - struct hda_amp_list *list; - - if (spec->num_loopbacks >= ARRAY_SIZE(spec->loopback_list) - 1) - return; - list = spec->loopback_list + spec->num_loopbacks; - list->nid = mix; - list->dir = HDA_INPUT; - list->idx = idx; - spec->num_loopbacks++; - spec->loopback.amplist = spec->loopback_list; -} -#else -#define add_loopback_list(spec, mix, idx) /* NOP */ -#endif - -/* create input playback/capture controls for the given pin */ -static int new_analog_input(struct alc_spec *spec, hda_nid_t pin, - const char *ctlname, int ctlidx, - int idx, hda_nid_t mix_nid) -{ - int err; - - err = __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname, ctlidx, - HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT)); - if (err < 0) - return err; - err = __add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname, ctlidx, - HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT)); - if (err < 0) - return err; - add_loopback_list(spec, mix_nid, idx); - return 0; -} - -static int alc_is_input_pin(struct hda_codec *codec, hda_nid_t nid) -{ - unsigned int pincap = snd_hda_query_pin_caps(codec, nid); - return (pincap & AC_PINCAP_IN) != 0; -} - -/* Parse the codec tree and retrieve ADCs and corresponding capsrc MUXs */ -static int alc_auto_fill_adc_caps(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - hda_nid_t nid; - hda_nid_t *adc_nids = spec->private_adc_nids; - hda_nid_t *cap_nids = spec->private_capsrc_nids; - int max_nums = ARRAY_SIZE(spec->private_adc_nids); - int i, nums = 0; - - nid = codec->start_nid; - for (i = 0; i < codec->num_nodes; i++, nid++) { - hda_nid_t src; - unsigned int caps = get_wcaps(codec, nid); - int type = get_wcaps_type(caps); - - if (type != AC_WID_AUD_IN || (caps & AC_WCAP_DIGITAL)) - continue; - adc_nids[nums] = nid; - cap_nids[nums] = nid; - src = nid; - for (;;) { - int n; - type = get_wcaps_type(get_wcaps(codec, src)); - if (type == AC_WID_PIN) - break; - if (type == AC_WID_AUD_SEL) { - cap_nids[nums] = src; - break; - } - n = snd_hda_get_num_conns(codec, src); - if (n > 1) { - cap_nids[nums] = src; - break; - } else if (n != 1) - break; - if (snd_hda_get_connections(codec, src, &src, 1) != 1) - break; - } - if (++nums >= max_nums) - break; - } - spec->adc_nids = spec->private_adc_nids; - spec->capsrc_nids = spec->private_capsrc_nids; - spec->num_adc_nids = nums; - return nums; -} - -/* create playback/capture controls for input pins */ -static int alc_auto_create_input_ctls(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - const struct auto_pin_cfg *cfg = &spec->autocfg; - hda_nid_t mixer = spec->mixer_nid; - struct hda_input_mux *imux = &spec->private_imux[0]; - int num_adcs; - int i, c, err, idx, type_idx = 0; - const char *prev_label = NULL; - - num_adcs = alc_auto_fill_adc_caps(codec); - if (num_adcs < 0) - return 0; - - for (i = 0; i < cfg->num_inputs; i++) { - hda_nid_t pin; - const char *label; - - pin = cfg->inputs[i].pin; - if (!alc_is_input_pin(codec, pin)) - continue; - - label = hda_get_autocfg_input_label(codec, cfg, i); - if (spec->shared_mic_hp && !strcmp(label, "Misc")) - label = "Headphone Mic"; - if (prev_label && !strcmp(label, prev_label)) - type_idx++; - else - type_idx = 0; - prev_label = label; - - if (mixer) { - idx = get_connection_index(codec, mixer, pin); - if (idx >= 0) { - err = new_analog_input(spec, pin, - label, type_idx, - idx, mixer); - if (err < 0) - return err; - } - } - - for (c = 0; c < num_adcs; c++) { - hda_nid_t cap = get_capsrc(spec, c); - idx = get_connection_index(codec, cap, pin); - if (idx >= 0) { - spec->imux_pins[imux->num_items] = pin; - snd_hda_add_imux_item(imux, label, idx, NULL); - break; - } - } - } - - spec->num_mux_defs = 1; - spec->input_mux = imux; - - return 0; -} - -/* create a shared input with the headphone out */ -static int alc_auto_create_shared_input(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - unsigned int defcfg; - hda_nid_t nid; - - /* only one internal input pin? */ - if (cfg->num_inputs != 1) - return 0; - defcfg = snd_hda_codec_get_pincfg(codec, cfg->inputs[0].pin); - if (snd_hda_get_input_pin_attr(defcfg) != INPUT_PIN_ATTR_INT) - return 0; - - if (cfg->hp_outs == 1 && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) - nid = cfg->hp_pins[0]; /* OK, we have a single HP-out */ - else if (cfg->line_outs == 1 && cfg->line_out_type == AUTO_PIN_HP_OUT) - nid = cfg->line_out_pins[0]; /* OK, we have a single line-out */ - else - return 0; /* both not available */ - - if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_IN)) - return 0; /* no input */ - - cfg->inputs[1].pin = nid; - cfg->inputs[1].type = AUTO_PIN_MIC; - cfg->num_inputs = 2; - spec->shared_mic_hp = 1; - snd_printdd("realtek: Enable shared I/O jack on NID 0x%x\n", nid); - return 0; -} - -static void alc_set_pin_output(struct hda_codec *codec, hda_nid_t nid, - unsigned int pin_type) -{ - snd_hda_set_pin_ctl(codec, nid, pin_type); - /* unmute pin */ - if (nid_has_mute(codec, nid, HDA_OUTPUT)) - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, - AMP_OUT_UNMUTE); -} - -static int get_pin_type(int line_out_type) -{ - if (line_out_type == AUTO_PIN_HP_OUT) - return PIN_HP; - else - return PIN_OUT; -} - -static void alc_auto_init_analog_input(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int i; - - for (i = 0; i < cfg->num_inputs; i++) { - hda_nid_t nid = cfg->inputs[i].pin; - if (alc_is_input_pin(codec, nid)) { - alc_set_input_pin(codec, nid, cfg->inputs[i].type); - if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP) - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_OUT_MUTE); - } - } - - /* mute all loopback inputs */ - if (spec->mixer_nid) { - int nums = snd_hda_get_num_conns(codec, spec->mixer_nid); - for (i = 0; i < nums; i++) - snd_hda_codec_write(codec, spec->mixer_nid, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_IN_MUTE(i)); - } -} - -/* convert from MIX nid to DAC */ -static hda_nid_t alc_auto_mix_to_dac(struct hda_codec *codec, hda_nid_t nid) -{ - hda_nid_t list[5]; - int i, num; - - if (get_wcaps_type(get_wcaps(codec, nid)) == AC_WID_AUD_OUT) - return nid; - num = snd_hda_get_connections(codec, nid, list, ARRAY_SIZE(list)); - for (i = 0; i < num; i++) { - if (get_wcaps_type(get_wcaps(codec, list[i])) == AC_WID_AUD_OUT) - return list[i]; - } - return 0; -} - -/* go down to the selector widget before the mixer */ -static hda_nid_t alc_go_down_to_selector(struct hda_codec *codec, hda_nid_t pin) -{ - hda_nid_t srcs[5]; - int num = snd_hda_get_connections(codec, pin, srcs, - ARRAY_SIZE(srcs)); - if (num != 1 || - get_wcaps_type(get_wcaps(codec, srcs[0])) != AC_WID_AUD_SEL) - return pin; - return srcs[0]; -} - -/* get MIX nid connected to the given pin targeted to DAC */ -static hda_nid_t alc_auto_dac_to_mix(struct hda_codec *codec, hda_nid_t pin, - hda_nid_t dac) -{ - hda_nid_t mix[5]; - int i, num; - - pin = alc_go_down_to_selector(codec, pin); - num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix)); - for (i = 0; i < num; i++) { - if (alc_auto_mix_to_dac(codec, mix[i]) == dac) - return mix[i]; - } - return 0; -} - -/* select the connection from pin to DAC if needed */ -static int alc_auto_select_dac(struct hda_codec *codec, hda_nid_t pin, - hda_nid_t dac) -{ - hda_nid_t mix[5]; - int i, num; - - pin = alc_go_down_to_selector(codec, pin); - num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix)); - if (num < 2) - return 0; - for (i = 0; i < num; i++) { - if (alc_auto_mix_to_dac(codec, mix[i]) == dac) { - snd_hda_codec_update_cache(codec, pin, 0, - AC_VERB_SET_CONNECT_SEL, i); - return 0; - } - } - return 0; -} - -static bool alc_is_dac_already_used(struct hda_codec *codec, hda_nid_t nid) -{ - struct alc_spec *spec = codec->spec; - int i; - if (found_in_nid_list(nid, spec->multiout.dac_nids, - ARRAY_SIZE(spec->private_dac_nids)) || - found_in_nid_list(nid, spec->multiout.hp_out_nid, - ARRAY_SIZE(spec->multiout.hp_out_nid)) || - found_in_nid_list(nid, spec->multiout.extra_out_nid, - ARRAY_SIZE(spec->multiout.extra_out_nid))) - return true; - for (i = 0; i < spec->multi_ios; i++) { - if (spec->multi_io[i].dac == nid) - return true; - } - return false; -} - -/* look for an empty DAC slot */ -static hda_nid_t alc_auto_look_for_dac(struct hda_codec *codec, hda_nid_t pin) -{ - hda_nid_t srcs[5]; - int i, num; - - pin = alc_go_down_to_selector(codec, pin); - num = snd_hda_get_connections(codec, pin, srcs, ARRAY_SIZE(srcs)); - for (i = 0; i < num; i++) { - hda_nid_t nid = alc_auto_mix_to_dac(codec, srcs[i]); - if (!nid) - continue; - if (!alc_is_dac_already_used(codec, nid)) - return nid; - } - return 0; -} - -/* check whether the DAC is reachable from the pin */ -static bool alc_auto_is_dac_reachable(struct hda_codec *codec, - hda_nid_t pin, hda_nid_t dac) -{ - hda_nid_t srcs[5]; - int i, num; - - if (!pin || !dac) - return false; - pin = alc_go_down_to_selector(codec, pin); - num = snd_hda_get_connections(codec, pin, srcs, ARRAY_SIZE(srcs)); - for (i = 0; i < num; i++) { - hda_nid_t nid = alc_auto_mix_to_dac(codec, srcs[i]); - if (nid == dac) - return true; - } - return false; -} - -static hda_nid_t get_dac_if_single(struct hda_codec *codec, hda_nid_t pin) -{ - struct alc_spec *spec = codec->spec; - hda_nid_t sel = alc_go_down_to_selector(codec, pin); - hda_nid_t nid, nid_found, srcs[5]; - int i, num = snd_hda_get_connections(codec, sel, srcs, - ARRAY_SIZE(srcs)); - if (num == 1) - return alc_auto_look_for_dac(codec, pin); - nid_found = 0; - for (i = 0; i < num; i++) { - if (srcs[i] == spec->mixer_nid) - continue; - nid = alc_auto_mix_to_dac(codec, srcs[i]); - if (nid && !alc_is_dac_already_used(codec, nid)) { - if (nid_found) - return 0; - nid_found = nid; - } - } - return nid_found; -} - -/* mark up volume and mute control NIDs: used during badness parsing and - * at creating actual controls - */ -static inline unsigned int get_ctl_pos(unsigned int data) -{ - hda_nid_t nid = get_amp_nid_(data); - unsigned int dir; - if (snd_BUG_ON(nid >= MAX_VOL_NIDS)) - return 0; - dir = get_amp_direction_(data); - return (nid << 1) | dir; -} - -#define is_ctl_used(bits, data) \ - test_bit(get_ctl_pos(data), bits) -#define mark_ctl_usage(bits, data) \ - set_bit(get_ctl_pos(data), bits) - -static void clear_vol_marks(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - memset(spec->vol_ctls, 0, sizeof(spec->vol_ctls)); - memset(spec->sw_ctls, 0, sizeof(spec->sw_ctls)); -} - -/* badness definition */ -enum { - /* No primary DAC is found for the main output */ - BAD_NO_PRIMARY_DAC = 0x10000, - /* No DAC is found for the extra output */ - BAD_NO_DAC = 0x4000, - /* No possible multi-ios */ - BAD_MULTI_IO = 0x103, - /* No individual DAC for extra output */ - BAD_NO_EXTRA_DAC = 0x102, - /* No individual DAC for extra surrounds */ - BAD_NO_EXTRA_SURR_DAC = 0x101, - /* Primary DAC shared with main surrounds */ - BAD_SHARED_SURROUND = 0x100, - /* Primary DAC shared with main CLFE */ - BAD_SHARED_CLFE = 0x10, - /* Primary DAC shared with extra surrounds */ - BAD_SHARED_EXTRA_SURROUND = 0x10, - /* Volume widget is shared */ - BAD_SHARED_VOL = 0x10, -}; - -static hda_nid_t alc_look_for_out_mute_nid(struct hda_codec *codec, - hda_nid_t pin, hda_nid_t dac); -static hda_nid_t alc_look_for_out_vol_nid(struct hda_codec *codec, - hda_nid_t pin, hda_nid_t dac); - -static int eval_shared_vol_badness(struct hda_codec *codec, hda_nid_t pin, - hda_nid_t dac) -{ - struct alc_spec *spec = codec->spec; - hda_nid_t nid; - unsigned int val; - int badness = 0; - - nid = alc_look_for_out_vol_nid(codec, pin, dac); - if (nid) { - val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); - if (is_ctl_used(spec->vol_ctls, nid)) - badness += BAD_SHARED_VOL; - else - mark_ctl_usage(spec->vol_ctls, val); - } else - badness += BAD_SHARED_VOL; - nid = alc_look_for_out_mute_nid(codec, pin, dac); - if (nid) { - unsigned int wid_type = get_wcaps_type(get_wcaps(codec, nid)); - if (wid_type == AC_WID_PIN || wid_type == AC_WID_AUD_OUT) - val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); - else - val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT); - if (is_ctl_used(spec->sw_ctls, val)) - badness += BAD_SHARED_VOL; - else - mark_ctl_usage(spec->sw_ctls, val); - } else - badness += BAD_SHARED_VOL; - return badness; -} - -struct badness_table { - int no_primary_dac; /* no primary DAC */ - int no_dac; /* no secondary DACs */ - int shared_primary; /* primary DAC is shared with main output */ - int shared_surr; /* secondary DAC shared with main or primary */ - int shared_clfe; /* third DAC shared with main or primary */ - int shared_surr_main; /* secondary DAC sahred with main/DAC0 */ -}; - -static struct badness_table main_out_badness = { - .no_primary_dac = BAD_NO_PRIMARY_DAC, - .no_dac = BAD_NO_DAC, - .shared_primary = BAD_NO_PRIMARY_DAC, - .shared_surr = BAD_SHARED_SURROUND, - .shared_clfe = BAD_SHARED_CLFE, - .shared_surr_main = BAD_SHARED_SURROUND, -}; - -static struct badness_table extra_out_badness = { - .no_primary_dac = BAD_NO_DAC, - .no_dac = BAD_NO_DAC, - .shared_primary = BAD_NO_EXTRA_DAC, - .shared_surr = BAD_SHARED_EXTRA_SURROUND, - .shared_clfe = BAD_SHARED_EXTRA_SURROUND, - .shared_surr_main = BAD_NO_EXTRA_SURR_DAC, -}; - -/* try to assign DACs to pins and return the resultant badness */ -static int alc_auto_fill_dacs(struct hda_codec *codec, int num_outs, - const hda_nid_t *pins, hda_nid_t *dacs, - const struct badness_table *bad) -{ - struct alc_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int i, j; - int badness = 0; - hda_nid_t dac; - - if (!num_outs) - return 0; - - for (i = 0; i < num_outs; i++) { - hda_nid_t pin = pins[i]; - if (!dacs[i]) - dacs[i] = alc_auto_look_for_dac(codec, pin); - if (!dacs[i] && !i) { - for (j = 1; j < num_outs; j++) { - if (alc_auto_is_dac_reachable(codec, pin, dacs[j])) { - dacs[0] = dacs[j]; - dacs[j] = 0; - break; - } - } - } - dac = dacs[i]; - if (!dac) { - if (alc_auto_is_dac_reachable(codec, pin, dacs[0])) - dac = dacs[0]; - else if (cfg->line_outs > i && - alc_auto_is_dac_reachable(codec, pin, - spec->private_dac_nids[i])) - dac = spec->private_dac_nids[i]; - if (dac) { - if (!i) - badness += bad->shared_primary; - else if (i == 1) - badness += bad->shared_surr; - else - badness += bad->shared_clfe; - } else if (alc_auto_is_dac_reachable(codec, pin, - spec->private_dac_nids[0])) { - dac = spec->private_dac_nids[0]; - badness += bad->shared_surr_main; - } else if (!i) - badness += bad->no_primary_dac; - else - badness += bad->no_dac; - } - if (dac) - badness += eval_shared_vol_badness(codec, pin, dac); - } - - return badness; -} - -static int alc_auto_fill_multi_ios(struct hda_codec *codec, - hda_nid_t reference_pin, - bool hardwired, int offset); - -static bool alc_map_singles(struct hda_codec *codec, int outs, - const hda_nid_t *pins, hda_nid_t *dacs) -{ - int i; - bool found = false; - for (i = 0; i < outs; i++) { - if (dacs[i]) - continue; - dacs[i] = get_dac_if_single(codec, pins[i]); - if (dacs[i]) - found = true; - } - return found; -} - -/* fill in the dac_nids table from the parsed pin configuration */ -static int fill_and_eval_dacs(struct hda_codec *codec, - bool fill_hardwired, - bool fill_mio_first) -{ - struct alc_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int i, err, badness; - - /* set num_dacs once to full for alc_auto_look_for_dac() */ - spec->multiout.num_dacs = cfg->line_outs; - spec->multiout.dac_nids = spec->private_dac_nids; - memset(spec->private_dac_nids, 0, sizeof(spec->private_dac_nids)); - memset(spec->multiout.hp_out_nid, 0, sizeof(spec->multiout.hp_out_nid)); - memset(spec->multiout.extra_out_nid, 0, sizeof(spec->multiout.extra_out_nid)); - spec->multi_ios = 0; - clear_vol_marks(codec); - badness = 0; - - /* fill hard-wired DACs first */ - if (fill_hardwired) { - bool mapped; - do { - mapped = alc_map_singles(codec, cfg->line_outs, - cfg->line_out_pins, - spec->private_dac_nids); - mapped |= alc_map_singles(codec, cfg->hp_outs, - cfg->hp_pins, - spec->multiout.hp_out_nid); - mapped |= alc_map_singles(codec, cfg->speaker_outs, - cfg->speaker_pins, - spec->multiout.extra_out_nid); - if (fill_mio_first && cfg->line_outs == 1 && - cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { - err = alc_auto_fill_multi_ios(codec, cfg->line_out_pins[0], true, 0); - if (!err) - mapped = true; - } - } while (mapped); - } - - badness += alc_auto_fill_dacs(codec, cfg->line_outs, cfg->line_out_pins, - spec->private_dac_nids, - &main_out_badness); - - /* re-count num_dacs and squash invalid entries */ - spec->multiout.num_dacs = 0; - for (i = 0; i < cfg->line_outs; i++) { - if (spec->private_dac_nids[i]) - spec->multiout.num_dacs++; - else { - memmove(spec->private_dac_nids + i, - spec->private_dac_nids + i + 1, - sizeof(hda_nid_t) * (cfg->line_outs - i - 1)); - spec->private_dac_nids[cfg->line_outs - 1] = 0; - } - } - - if (fill_mio_first && - cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { - /* try to fill multi-io first */ - err = alc_auto_fill_multi_ios(codec, cfg->line_out_pins[0], false, 0); - if (err < 0) - return err; - /* we don't count badness at this stage yet */ - } - - if (cfg->line_out_type != AUTO_PIN_HP_OUT) { - err = alc_auto_fill_dacs(codec, cfg->hp_outs, cfg->hp_pins, - spec->multiout.hp_out_nid, - &extra_out_badness); - if (err < 0) - return err; - badness += err; - } - if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { - err = alc_auto_fill_dacs(codec, cfg->speaker_outs, - cfg->speaker_pins, - spec->multiout.extra_out_nid, - &extra_out_badness); - if (err < 0) - return err; - badness += err; - } - if (cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { - err = alc_auto_fill_multi_ios(codec, cfg->line_out_pins[0], false, 0); - if (err < 0) - return err; - badness += err; - } - if (cfg->hp_outs && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) { - /* try multi-ios with HP + inputs */ - int offset = 0; - if (cfg->line_outs >= 3) - offset = 1; - err = alc_auto_fill_multi_ios(codec, cfg->hp_pins[0], false, - offset); - if (err < 0) - return err; - badness += err; - } - - if (spec->multi_ios == 2) { - for (i = 0; i < 2; i++) - spec->private_dac_nids[spec->multiout.num_dacs++] = - spec->multi_io[i].dac; - spec->ext_channel_count = 2; - } else if (spec->multi_ios) { - spec->multi_ios = 0; - badness += BAD_MULTI_IO; - } - - return badness; -} - -#define DEBUG_BADNESS - -#ifdef DEBUG_BADNESS -#define debug_badness snd_printdd -#else -#define debug_badness(...) -#endif - -static void debug_show_configs(struct alc_spec *spec, struct auto_pin_cfg *cfg) -{ - debug_badness("multi_outs = %x/%x/%x/%x : %x/%x/%x/%x\n", - cfg->line_out_pins[0], cfg->line_out_pins[1], - cfg->line_out_pins[2], cfg->line_out_pins[2], - spec->multiout.dac_nids[0], - spec->multiout.dac_nids[1], - spec->multiout.dac_nids[2], - spec->multiout.dac_nids[3]); - if (spec->multi_ios > 0) - debug_badness("multi_ios(%d) = %x/%x : %x/%x\n", - spec->multi_ios, - spec->multi_io[0].pin, spec->multi_io[1].pin, - spec->multi_io[0].dac, spec->multi_io[1].dac); - debug_badness("hp_outs = %x/%x/%x/%x : %x/%x/%x/%x\n", - cfg->hp_pins[0], cfg->hp_pins[1], - cfg->hp_pins[2], cfg->hp_pins[2], - spec->multiout.hp_out_nid[0], - spec->multiout.hp_out_nid[1], - spec->multiout.hp_out_nid[2], - spec->multiout.hp_out_nid[3]); - debug_badness("spk_outs = %x/%x/%x/%x : %x/%x/%x/%x\n", - cfg->speaker_pins[0], cfg->speaker_pins[1], - cfg->speaker_pins[2], cfg->speaker_pins[3], - spec->multiout.extra_out_nid[0], - spec->multiout.extra_out_nid[1], - spec->multiout.extra_out_nid[2], - spec->multiout.extra_out_nid[3]); -} - -static int alc_auto_fill_dac_nids(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - struct auto_pin_cfg *best_cfg; - int best_badness = INT_MAX; - int badness; - bool fill_hardwired = true, fill_mio_first = true; - bool best_wired = true, best_mio = true; - bool hp_spk_swapped = false; - - best_cfg = kmalloc(sizeof(*best_cfg), GFP_KERNEL); - if (!best_cfg) - return -ENOMEM; - *best_cfg = *cfg; - - for (;;) { - badness = fill_and_eval_dacs(codec, fill_hardwired, - fill_mio_first); - if (badness < 0) { - kfree(best_cfg); - return badness; - } - debug_badness("==> lo_type=%d, wired=%d, mio=%d, badness=0x%x\n", - cfg->line_out_type, fill_hardwired, fill_mio_first, - badness); - debug_show_configs(spec, cfg); - if (badness < best_badness) { - best_badness = badness; - *best_cfg = *cfg; - best_wired = fill_hardwired; - best_mio = fill_mio_first; - } - if (!badness) - break; - fill_mio_first = !fill_mio_first; - if (!fill_mio_first) - continue; - fill_hardwired = !fill_hardwired; - if (!fill_hardwired) - continue; - if (hp_spk_swapped) - break; - hp_spk_swapped = true; - if (cfg->speaker_outs > 0 && - cfg->line_out_type == AUTO_PIN_HP_OUT) { - cfg->hp_outs = cfg->line_outs; - memcpy(cfg->hp_pins, cfg->line_out_pins, - sizeof(cfg->hp_pins)); - cfg->line_outs = cfg->speaker_outs; - memcpy(cfg->line_out_pins, cfg->speaker_pins, - sizeof(cfg->speaker_pins)); - cfg->speaker_outs = 0; - memset(cfg->speaker_pins, 0, sizeof(cfg->speaker_pins)); - cfg->line_out_type = AUTO_PIN_SPEAKER_OUT; - fill_hardwired = true; - continue; - } - if (cfg->hp_outs > 0 && - cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) { - cfg->speaker_outs = cfg->line_outs; - memcpy(cfg->speaker_pins, cfg->line_out_pins, - sizeof(cfg->speaker_pins)); - cfg->line_outs = cfg->hp_outs; - memcpy(cfg->line_out_pins, cfg->hp_pins, - sizeof(cfg->hp_pins)); - cfg->hp_outs = 0; - memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins)); - cfg->line_out_type = AUTO_PIN_HP_OUT; - fill_hardwired = true; - continue; - } - break; - } - - if (badness) { - *cfg = *best_cfg; - fill_and_eval_dacs(codec, best_wired, best_mio); - } - debug_badness("==> Best config: lo_type=%d, wired=%d, mio=%d\n", - cfg->line_out_type, best_wired, best_mio); - debug_show_configs(spec, cfg); - - if (cfg->line_out_pins[0]) - spec->vmaster_nid = - alc_look_for_out_vol_nid(codec, cfg->line_out_pins[0], - spec->multiout.dac_nids[0]); - - /* clear the bitmap flags for creating controls */ - clear_vol_marks(codec); - kfree(best_cfg); - return 0; -} - -static int alc_auto_add_vol_ctl(struct hda_codec *codec, - const char *pfx, int cidx, - hda_nid_t nid, unsigned int chs) -{ - struct alc_spec *spec = codec->spec; - unsigned int val; - if (!nid) - return 0; - val = HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT); - if (is_ctl_used(spec->vol_ctls, val) && chs != 2) /* exclude LFE */ - return 0; - mark_ctl_usage(spec->vol_ctls, val); - return __add_pb_vol_ctrl(codec->spec, ALC_CTL_WIDGET_VOL, pfx, cidx, - val); -} - -static int alc_auto_add_stereo_vol(struct hda_codec *codec, - const char *pfx, int cidx, - hda_nid_t nid) -{ - int chs = 1; - if (get_wcaps(codec, nid) & AC_WCAP_STEREO) - chs = 3; - return alc_auto_add_vol_ctl(codec, pfx, cidx, nid, chs); -} - -/* create a mute-switch for the given mixer widget; - * if it has multiple sources (e.g. DAC and loopback), create a bind-mute - */ -static int alc_auto_add_sw_ctl(struct hda_codec *codec, - const char *pfx, int cidx, - hda_nid_t nid, unsigned int chs) -{ - struct alc_spec *spec = codec->spec; - int wid_type; - int type; - unsigned long val; - if (!nid) - return 0; - wid_type = get_wcaps_type(get_wcaps(codec, nid)); - if (wid_type == AC_WID_PIN || wid_type == AC_WID_AUD_OUT) { - type = ALC_CTL_WIDGET_MUTE; - val = HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT); - } else if (snd_hda_get_num_conns(codec, nid) == 1) { - type = ALC_CTL_WIDGET_MUTE; - val = HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_INPUT); - } else { - type = ALC_CTL_BIND_MUTE; - val = HDA_COMPOSE_AMP_VAL(nid, chs, 2, HDA_INPUT); - } - if (is_ctl_used(spec->sw_ctls, val) && chs != 2) /* exclude LFE */ - return 0; - mark_ctl_usage(spec->sw_ctls, val); - return __add_pb_sw_ctrl(codec->spec, type, pfx, cidx, val); -} - -static int alc_auto_add_stereo_sw(struct hda_codec *codec, const char *pfx, - int cidx, hda_nid_t nid) -{ - int chs = 1; - if (get_wcaps(codec, nid) & AC_WCAP_STEREO) - chs = 3; - return alc_auto_add_sw_ctl(codec, pfx, cidx, nid, chs); -} - -static hda_nid_t alc_look_for_out_mute_nid(struct hda_codec *codec, - hda_nid_t pin, hda_nid_t dac) -{ - hda_nid_t mix = alc_auto_dac_to_mix(codec, pin, dac); - if (nid_has_mute(codec, pin, HDA_OUTPUT)) - return pin; - else if (mix && nid_has_mute(codec, mix, HDA_INPUT)) - return mix; - else if (nid_has_mute(codec, dac, HDA_OUTPUT)) - return dac; - return 0; -} - -static hda_nid_t alc_look_for_out_vol_nid(struct hda_codec *codec, - hda_nid_t pin, hda_nid_t dac) -{ - hda_nid_t mix = alc_auto_dac_to_mix(codec, pin, dac); - if (nid_has_volume(codec, dac, HDA_OUTPUT)) - return dac; - else if (nid_has_volume(codec, mix, HDA_OUTPUT)) - return mix; - else if (nid_has_volume(codec, pin, HDA_OUTPUT)) - return pin; - return 0; -} - -/* add playback controls from the parsed DAC table */ -static int alc_auto_create_multi_out_ctls(struct hda_codec *codec, - const struct auto_pin_cfg *cfg) -{ - struct alc_spec *spec = codec->spec; - int i, err, noutputs; - - noutputs = cfg->line_outs; - if (spec->multi_ios > 0 && cfg->line_outs < 3) - noutputs += spec->multi_ios; - - for (i = 0; i < noutputs; i++) { - const char *name; - int index; - hda_nid_t dac, pin; - hda_nid_t sw, vol; - - dac = spec->multiout.dac_nids[i]; - if (!dac) - continue; - if (i >= cfg->line_outs) { - pin = spec->multi_io[i - 1].pin; - index = 0; - name = channel_name[i]; - } else { - pin = cfg->line_out_pins[i]; - name = alc_get_line_out_pfx(spec, i, true, &index); - } - - sw = alc_look_for_out_mute_nid(codec, pin, dac); - vol = alc_look_for_out_vol_nid(codec, pin, dac); - if (!name || !strcmp(name, "CLFE")) { - /* Center/LFE */ - err = alc_auto_add_vol_ctl(codec, "Center", 0, vol, 1); - if (err < 0) - return err; - err = alc_auto_add_vol_ctl(codec, "LFE", 0, vol, 2); - if (err < 0) - return err; - err = alc_auto_add_sw_ctl(codec, "Center", 0, sw, 1); - if (err < 0) - return err; - err = alc_auto_add_sw_ctl(codec, "LFE", 0, sw, 2); - if (err < 0) - return err; - } else { - err = alc_auto_add_stereo_vol(codec, name, index, vol); - if (err < 0) - return err; - err = alc_auto_add_stereo_sw(codec, name, index, sw); - if (err < 0) - return err; - } - } - return 0; -} - -static int alc_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin, - hda_nid_t dac, const char *pfx, - int cidx) -{ - struct alc_spec *spec = codec->spec; - hda_nid_t sw, vol; - int err; - - if (!dac) { - unsigned int val; - /* the corresponding DAC is already occupied */ - if (!(get_wcaps(codec, pin) & AC_WCAP_OUT_AMP)) - return 0; /* no way */ - /* create a switch only */ - val = HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT); - if (is_ctl_used(spec->sw_ctls, val)) - return 0; /* already created */ - mark_ctl_usage(spec->sw_ctls, val); - return __add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, cidx, val); - } - - sw = alc_look_for_out_mute_nid(codec, pin, dac); - vol = alc_look_for_out_vol_nid(codec, pin, dac); - err = alc_auto_add_stereo_vol(codec, pfx, cidx, vol); - if (err < 0) - return err; - err = alc_auto_add_stereo_sw(codec, pfx, cidx, sw); - if (err < 0) - return err; - return 0; -} - -static struct hda_bind_ctls *new_bind_ctl(struct hda_codec *codec, - unsigned int nums, - struct hda_ctl_ops *ops) -{ - struct alc_spec *spec = codec->spec; - struct hda_bind_ctls **ctlp, *ctl; - snd_array_init(&spec->bind_ctls, sizeof(ctl), 8); - ctlp = snd_array_new(&spec->bind_ctls); - if (!ctlp) - return NULL; - ctl = kzalloc(sizeof(*ctl) + sizeof(long) * (nums + 1), GFP_KERNEL); - *ctlp = ctl; - if (ctl) - ctl->ops = ops; - return ctl; -} - -/* add playback controls for speaker and HP outputs */ -static int alc_auto_create_extra_outs(struct hda_codec *codec, int num_pins, - const hda_nid_t *pins, - const hda_nid_t *dacs, - const char *pfx) -{ - struct alc_spec *spec = codec->spec; - struct hda_bind_ctls *ctl; - char name[32]; - int i, n, err; - - if (!num_pins || !pins[0]) - return 0; - - if (num_pins == 1) { - hda_nid_t dac = *dacs; - if (!dac) - dac = spec->multiout.dac_nids[0]; - return alc_auto_create_extra_out(codec, *pins, dac, pfx, 0); - } - - for (i = 0; i < num_pins; i++) { - hda_nid_t dac; - if (dacs[num_pins - 1]) - dac = dacs[i]; /* with individual volumes */ - else - dac = 0; - if (num_pins == 2 && i == 1 && !strcmp(pfx, "Speaker")) { - err = alc_auto_create_extra_out(codec, pins[i], dac, - "Bass Speaker", 0); - } else if (num_pins >= 3) { - snprintf(name, sizeof(name), "%s %s", - pfx, channel_name[i]); - err = alc_auto_create_extra_out(codec, pins[i], dac, - name, 0); - } else { - err = alc_auto_create_extra_out(codec, pins[i], dac, - pfx, i); - } - if (err < 0) - return err; - } - if (dacs[num_pins - 1]) - return 0; - - /* Let's create a bind-controls for volumes */ - ctl = new_bind_ctl(codec, num_pins, &snd_hda_bind_vol); - if (!ctl) - return -ENOMEM; - n = 0; - for (i = 0; i < num_pins; i++) { - hda_nid_t vol; - if (!pins[i] || !dacs[i]) - continue; - vol = alc_look_for_out_vol_nid(codec, pins[i], dacs[i]); - if (vol) - ctl->values[n++] = - HDA_COMPOSE_AMP_VAL(vol, 3, 0, HDA_OUTPUT); - } - if (n) { - snprintf(name, sizeof(name), "%s Playback Volume", pfx); - err = add_control(spec, ALC_CTL_BIND_VOL, name, 0, (long)ctl); - if (err < 0) - return err; - } - return 0; -} - -static int alc_auto_create_hp_out(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - return alc_auto_create_extra_outs(codec, spec->autocfg.hp_outs, - spec->autocfg.hp_pins, - spec->multiout.hp_out_nid, - "Headphone"); -} - -static int alc_auto_create_speaker_out(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - return alc_auto_create_extra_outs(codec, spec->autocfg.speaker_outs, - spec->autocfg.speaker_pins, - spec->multiout.extra_out_nid, - "Speaker"); -} - -static void alc_auto_set_output_and_unmute(struct hda_codec *codec, - hda_nid_t pin, int pin_type, - hda_nid_t dac) -{ - int i, num; - hda_nid_t nid, mix = 0; - hda_nid_t srcs[HDA_MAX_CONNECTIONS]; - - alc_set_pin_output(codec, pin, pin_type); - nid = alc_go_down_to_selector(codec, pin); - num = snd_hda_get_connections(codec, nid, srcs, ARRAY_SIZE(srcs)); - for (i = 0; i < num; i++) { - if (alc_auto_mix_to_dac(codec, srcs[i]) != dac) - continue; - mix = srcs[i]; - break; - } - if (!mix) - return; - - /* need the manual connection? */ - if (num > 1) - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, i); - /* unmute mixer widget inputs */ - if (nid_has_mute(codec, mix, HDA_INPUT)) { - snd_hda_codec_write(codec, mix, 0, AC_VERB_SET_AMP_GAIN_MUTE, - AMP_IN_UNMUTE(0)); - snd_hda_codec_write(codec, mix, 0, AC_VERB_SET_AMP_GAIN_MUTE, - AMP_IN_UNMUTE(1)); - } - /* initialize volume */ - nid = alc_look_for_out_vol_nid(codec, pin, dac); - if (nid) - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, - AMP_OUT_ZERO); - - /* unmute DAC if it's not assigned to a mixer */ - nid = alc_look_for_out_mute_nid(codec, pin, dac); - if (nid == mix && nid_has_mute(codec, dac, HDA_OUTPUT)) - snd_hda_codec_write(codec, dac, 0, AC_VERB_SET_AMP_GAIN_MUTE, - AMP_OUT_ZERO); -} - -static void alc_auto_init_multi_out(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - int pin_type = get_pin_type(spec->autocfg.line_out_type); - int i; - - for (i = 0; i <= HDA_SIDE; i++) { - hda_nid_t nid = spec->autocfg.line_out_pins[i]; - if (nid) - alc_auto_set_output_and_unmute(codec, nid, pin_type, - spec->multiout.dac_nids[i]); - } -} - -static void alc_auto_init_extra_out(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - int i; - hda_nid_t pin, dac; - - for (i = 0; i < spec->autocfg.hp_outs; i++) { - if (spec->autocfg.line_out_type == AUTO_PIN_HP_OUT) - break; - pin = spec->autocfg.hp_pins[i]; - if (!pin) - break; - dac = spec->multiout.hp_out_nid[i]; - if (!dac) { - if (i > 0 && spec->multiout.hp_out_nid[0]) - dac = spec->multiout.hp_out_nid[0]; - else - dac = spec->multiout.dac_nids[0]; - } - alc_auto_set_output_and_unmute(codec, pin, PIN_HP, dac); - } - for (i = 0; i < spec->autocfg.speaker_outs; i++) { - if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT) - break; - pin = spec->autocfg.speaker_pins[i]; - if (!pin) - break; - dac = spec->multiout.extra_out_nid[i]; - if (!dac) { - if (i > 0 && spec->multiout.extra_out_nid[0]) - dac = spec->multiout.extra_out_nid[0]; - else - dac = spec->multiout.dac_nids[0]; - } - alc_auto_set_output_and_unmute(codec, pin, PIN_OUT, dac); - } -} - -/* check whether the given pin can be a multi-io pin */ -static bool can_be_multiio_pin(struct hda_codec *codec, - unsigned int location, hda_nid_t nid) -{ - unsigned int defcfg, caps; - - defcfg = snd_hda_codec_get_pincfg(codec, nid); - if (get_defcfg_connect(defcfg) != AC_JACK_PORT_COMPLEX) - return false; - if (location && get_defcfg_location(defcfg) != location) - return false; - caps = snd_hda_query_pin_caps(codec, nid); - if (!(caps & AC_PINCAP_OUT)) - return false; - return true; -} - -/* - * multi-io helper - * - * When hardwired is set, try to fill ony hardwired pins, and returns - * zero if any pins are filled, non-zero if nothing found. - * When hardwired is off, try to fill possible input pins, and returns - * the badness value. - */ -static int alc_auto_fill_multi_ios(struct hda_codec *codec, - hda_nid_t reference_pin, - bool hardwired, int offset) -{ - struct alc_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int type, i, j, dacs, num_pins, old_pins; - unsigned int defcfg = snd_hda_codec_get_pincfg(codec, reference_pin); - unsigned int location = get_defcfg_location(defcfg); - int badness = 0; - - old_pins = spec->multi_ios; - if (old_pins >= 2) - goto end_fill; - - num_pins = 0; - for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) { - for (i = 0; i < cfg->num_inputs; i++) { - if (cfg->inputs[i].type != type) - continue; - if (can_be_multiio_pin(codec, location, - cfg->inputs[i].pin)) - num_pins++; - } - } - if (num_pins < 2) - goto end_fill; - - dacs = spec->multiout.num_dacs; - for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) { - for (i = 0; i < cfg->num_inputs; i++) { - hda_nid_t nid = cfg->inputs[i].pin; - hda_nid_t dac = 0; - - if (cfg->inputs[i].type != type) - continue; - if (!can_be_multiio_pin(codec, location, nid)) - continue; - for (j = 0; j < spec->multi_ios; j++) { - if (nid == spec->multi_io[j].pin) - break; - } - if (j < spec->multi_ios) - continue; - - if (offset && offset + spec->multi_ios < dacs) { - dac = spec->private_dac_nids[offset + spec->multi_ios]; - if (!alc_auto_is_dac_reachable(codec, nid, dac)) - dac = 0; - } - if (hardwired) - dac = get_dac_if_single(codec, nid); - else if (!dac) - dac = alc_auto_look_for_dac(codec, nid); - if (!dac) { - badness++; - continue; - } - spec->multi_io[spec->multi_ios].pin = nid; - spec->multi_io[spec->multi_ios].dac = dac; - spec->multi_ios++; - if (spec->multi_ios >= 2) - break; - } - } - end_fill: - if (badness) - badness = BAD_MULTI_IO; - if (old_pins == spec->multi_ios) { - if (hardwired) - return 1; /* nothing found */ - else - return badness; /* no badness if nothing found */ - } - if (!hardwired && spec->multi_ios < 2) { - spec->multi_ios = old_pins; - return badness; - } - - return 0; -} - -static int alc_auto_ch_mode_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct alc_spec *spec = codec->spec; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = spec->multi_ios + 1; - if (uinfo->value.enumerated.item > spec->multi_ios) - uinfo->value.enumerated.item = spec->multi_ios; - sprintf(uinfo->value.enumerated.name, "%dch", - (uinfo->value.enumerated.item + 1) * 2); - return 0; -} - -static int alc_auto_ch_mode_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct alc_spec *spec = codec->spec; - ucontrol->value.enumerated.item[0] = (spec->ext_channel_count - 1) / 2; - return 0; -} - -static int alc_set_multi_io(struct hda_codec *codec, int idx, bool output) -{ - struct alc_spec *spec = codec->spec; - hda_nid_t nid = spec->multi_io[idx].pin; - - if (!spec->multi_io[idx].ctl_in) - spec->multi_io[idx].ctl_in = - snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); - if (output) { - snd_hda_set_pin_ctl_cache(codec, nid, PIN_OUT); - if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP) - snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, - HDA_AMP_MUTE, 0); - alc_auto_select_dac(codec, nid, spec->multi_io[idx].dac); - } else { - if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP) - snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, - HDA_AMP_MUTE, HDA_AMP_MUTE); - snd_hda_set_pin_ctl_cache(codec, nid, - spec->multi_io[idx].ctl_in); - } - return 0; -} - -static int alc_auto_ch_mode_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct alc_spec *spec = codec->spec; - int i, ch; - - ch = ucontrol->value.enumerated.item[0]; - if (ch < 0 || ch > spec->multi_ios) - return -EINVAL; - if (ch == (spec->ext_channel_count - 1) / 2) - return 0; - spec->ext_channel_count = (ch + 1) * 2; - for (i = 0; i < spec->multi_ios; i++) - alc_set_multi_io(codec, i, i < ch); - spec->multiout.max_channels = spec->ext_channel_count; - if (spec->need_dac_fix && !spec->const_channel_count) - spec->multiout.num_dacs = spec->multiout.max_channels / 2; - return 1; -} - -static const struct snd_kcontrol_new alc_auto_channel_mode_enum = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = alc_auto_ch_mode_info, - .get = alc_auto_ch_mode_get, - .put = alc_auto_ch_mode_put, -}; - -static int alc_auto_add_multi_channel_mode(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - if (spec->multi_ios > 0) { - struct snd_kcontrol_new *knew; - - knew = alc_kcontrol_new(spec); - if (!knew) - return -ENOMEM; - *knew = alc_auto_channel_mode_enum; - knew->name = kstrdup("Channel Mode", GFP_KERNEL); - if (!knew->name) - return -ENOMEM; - } - return 0; -} - -/* filter out invalid adc_nids (and capsrc_nids) that don't give all - * active input pins - */ -static void alc_remove_invalid_adc_nids(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - const struct hda_input_mux *imux; - hda_nid_t adc_nids[ARRAY_SIZE(spec->private_adc_nids)]; - hda_nid_t capsrc_nids[ARRAY_SIZE(spec->private_adc_nids)]; - int i, n, nums; - - imux = spec->input_mux; - if (!imux) - return; - if (spec->dyn_adc_switch) - return; - - again: - nums = 0; - for (n = 0; n < spec->num_adc_nids; n++) { - hda_nid_t cap = spec->private_capsrc_nids[n]; - int num_conns = snd_hda_get_num_conns(codec, cap); - for (i = 0; i < imux->num_items; i++) { - hda_nid_t pin = spec->imux_pins[i]; - if (pin) { - if (get_connection_index(codec, cap, pin) < 0) - break; - } else if (num_conns <= imux->items[i].index) - break; - } - if (i >= imux->num_items) { - adc_nids[nums] = spec->private_adc_nids[n]; - capsrc_nids[nums++] = cap; - } - } - if (!nums) { - /* check whether ADC-switch is possible */ - if (!alc_check_dyn_adc_switch(codec)) { - if (spec->shared_mic_hp) { - spec->shared_mic_hp = 0; - spec->private_imux[0].num_items = 1; - goto again; - } - printk(KERN_WARNING "hda_codec: %s: no valid ADC found;" - " using fallback 0x%x\n", - codec->chip_name, spec->private_adc_nids[0]); - spec->num_adc_nids = 1; - spec->auto_mic = 0; - return; - } - } else if (nums != spec->num_adc_nids) { - memcpy(spec->private_adc_nids, adc_nids, - nums * sizeof(hda_nid_t)); - memcpy(spec->private_capsrc_nids, capsrc_nids, - nums * sizeof(hda_nid_t)); - spec->num_adc_nids = nums; - } - - if (spec->auto_mic) - alc_auto_mic_check_imux(codec); /* check auto-mic setups */ - else if (spec->input_mux->num_items == 1 || spec->shared_mic_hp) - spec->num_adc_nids = 1; /* reduce to a single ADC */ -} - -/* - * initialize ADC paths - */ -static void alc_auto_init_adc(struct hda_codec *codec, int adc_idx) -{ - struct alc_spec *spec = codec->spec; - hda_nid_t nid; - - nid = spec->adc_nids[adc_idx]; - /* mute ADC */ - if (nid_has_mute(codec, nid, HDA_INPUT)) { - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_IN_MUTE(0)); - return; - } - if (!spec->capsrc_nids) - return; - nid = spec->capsrc_nids[adc_idx]; - if (nid_has_mute(codec, nid, HDA_OUTPUT)) - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_OUT_MUTE); -} - -static void alc_auto_init_input_src(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - int c, nums; - - for (c = 0; c < spec->num_adc_nids; c++) - alc_auto_init_adc(codec, c); - if (spec->dyn_adc_switch) - nums = 1; - else - nums = spec->num_adc_nids; - for (c = 0; c < nums; c++) - alc_mux_select(codec, c, spec->cur_mux[c], true); -} - -/* add mic boosts if needed */ -static int alc_auto_add_mic_boost(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int i, err; - int type_idx = 0; - hda_nid_t nid; - const char *prev_label = NULL; - - for (i = 0; i < cfg->num_inputs; i++) { - if (cfg->inputs[i].type > AUTO_PIN_MIC) - break; - nid = cfg->inputs[i].pin; - if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP) { - const char *label; - char boost_label[32]; - - label = hda_get_autocfg_input_label(codec, cfg, i); - if (spec->shared_mic_hp && !strcmp(label, "Misc")) - label = "Headphone Mic"; - if (prev_label && !strcmp(label, prev_label)) - type_idx++; - else - type_idx = 0; - prev_label = label; - - snprintf(boost_label, sizeof(boost_label), - "%s Boost Volume", label); - err = add_control(spec, ALC_CTL_WIDGET_VOL, - boost_label, type_idx, - HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT)); - if (err < 0) - return err; - } - } - return 0; -} - -/* select or unmute the given capsrc route */ -static void select_or_unmute_capsrc(struct hda_codec *codec, hda_nid_t cap, - int idx) -{ - if (get_wcaps_type(get_wcaps(codec, cap)) == AC_WID_AUD_MIX) { - snd_hda_codec_amp_stereo(codec, cap, HDA_INPUT, idx, - HDA_AMP_MUTE, 0); - } else if (snd_hda_get_num_conns(codec, cap) > 1) { - snd_hda_codec_write_cache(codec, cap, 0, - AC_VERB_SET_CONNECT_SEL, idx); - } -} - -/* set the default connection to that pin */ -static int init_capsrc_for_pin(struct hda_codec *codec, hda_nid_t pin) -{ - struct alc_spec *spec = codec->spec; - int i; - - if (!pin) - return 0; - for (i = 0; i < spec->num_adc_nids; i++) { - hda_nid_t cap = get_capsrc(spec, i); - int idx; - - idx = get_connection_index(codec, cap, pin); - if (idx < 0) - continue; - select_or_unmute_capsrc(codec, cap, idx); - return i; /* return the found index */ - } - return -1; /* not found */ -} - -/* initialize some special cases for input sources */ -static void alc_init_special_input_src(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - int i; - - for (i = 0; i < spec->autocfg.num_inputs; i++) - init_capsrc_for_pin(codec, spec->autocfg.inputs[i].pin); -} - -/* assign appropriate capture mixers */ -static void set_capture_mixer(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - static const struct snd_kcontrol_new *caps[2][3] = { - { alc_capture_mixer_nosrc1, - alc_capture_mixer_nosrc2, - alc_capture_mixer_nosrc3 }, - { alc_capture_mixer1, - alc_capture_mixer2, - alc_capture_mixer3 }, - }; - - /* check whether either of ADC or MUX has a volume control */ - if (!nid_has_volume(codec, spec->adc_nids[0], HDA_INPUT)) { - if (!spec->capsrc_nids) - return; /* no volume */ - if (!nid_has_volume(codec, spec->capsrc_nids[0], HDA_OUTPUT)) - return; /* no volume in capsrc, too */ - spec->vol_in_capsrc = 1; - } - - if (spec->num_adc_nids > 0) { - int mux = 0; - int num_adcs = 0; - - if (spec->input_mux && spec->input_mux->num_items > 1) - mux = 1; - if (spec->auto_mic) { - num_adcs = 1; - mux = 0; - } else if (spec->dyn_adc_switch) - num_adcs = 1; - if (!num_adcs) { - if (spec->num_adc_nids > 3) - spec->num_adc_nids = 3; - else if (!spec->num_adc_nids) - return; - num_adcs = spec->num_adc_nids; - } - spec->cap_mixer = caps[mux][num_adcs - 1]; - } -} - -/* - * standard auto-parser initializations - */ -static void alc_auto_init_std(struct hda_codec *codec) -{ - alc_auto_init_multi_out(codec); - alc_auto_init_extra_out(codec); - alc_auto_init_analog_input(codec); - alc_auto_init_input_src(codec); - alc_auto_init_digital(codec); - alc_inithook(codec); -} /* * Digital-beep handlers @@ -4282,81 +959,20 @@ static int alc_parse_auto_config(struct hda_codec *codec, const hda_nid_t *ssid_nids) { struct alc_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; + struct auto_pin_cfg *cfg = &spec->gen.autocfg; int err; err = snd_hda_parse_pin_defcfg(codec, cfg, ignore_nids, spec->parse_flags); if (err < 0) return err; - if (!cfg->line_outs) { - if (cfg->dig_outs || cfg->dig_in_pin) { - spec->multiout.max_channels = 2; - spec->no_analog = 1; - goto dig_only; - } - return 0; /* can't find valid BIOS pin config */ - } - - if (!spec->no_primary_hp && - cfg->line_out_type == AUTO_PIN_SPEAKER_OUT && - cfg->line_outs <= cfg->hp_outs) { - /* use HP as primary out */ - cfg->speaker_outs = cfg->line_outs; - memcpy(cfg->speaker_pins, cfg->line_out_pins, - sizeof(cfg->speaker_pins)); - cfg->line_outs = cfg->hp_outs; - memcpy(cfg->line_out_pins, cfg->hp_pins, sizeof(cfg->hp_pins)); - cfg->hp_outs = 0; - memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins)); - cfg->line_out_type = AUTO_PIN_HP_OUT; - } - - err = alc_auto_fill_dac_nids(codec); - if (err < 0) - return err; - err = alc_auto_add_multi_channel_mode(codec); - if (err < 0) - return err; - err = alc_auto_create_multi_out_ctls(codec, cfg); - if (err < 0) - return err; - err = alc_auto_create_hp_out(codec); - if (err < 0) - return err; - err = alc_auto_create_speaker_out(codec); - if (err < 0) - return err; - err = alc_auto_create_shared_input(codec); - if (err < 0) - return err; - err = alc_auto_create_input_ctls(codec); - if (err < 0) - return err; - - spec->multiout.max_channels = spec->multiout.num_dacs * 2; - - dig_only: - alc_auto_parse_digital(codec); - - if (!spec->no_analog) - alc_remove_invalid_adc_nids(codec); if (ssid_nids) alc_ssid_check(codec, ssid_nids); - if (!spec->no_analog) { - alc_auto_check_switches(codec); - err = alc_auto_add_mic_boost(codec); - if (err < 0) - return err; - } - - if (spec->kctls.list) - add_mixer(spec, spec->kctls.list); - - if (!spec->no_analog && !spec->cap_mixer) - set_capture_mixer(codec); + err = snd_hda_gen_parse_auto_config(codec, cfg); + if (err < 0) + return err; return 1; } @@ -4370,8 +986,12 @@ static int alc_alloc_spec(struct hda_codec *codec, hda_nid_t mixer_nid) if (!spec) return -ENOMEM; codec->spec = spec; - spec->mixer_nid = mixer_nid; - snd_hda_gen_init(&spec->gen); + snd_hda_gen_spec_init(&spec->gen); + spec->gen.mixer_nid = mixer_nid; + spec->gen.own_eapd_ctl = 1; + codec->single_adc_amp = 1; + /* FIXME: do we need this for all Realtek codec models? */ + codec->spdif_status_reset = 1; err = alc_codec_rename_from_preset(codec); if (err < 0) { @@ -4414,27 +1034,28 @@ enum { ALC880_FIXUP_6ST_BASE, ALC880_FIXUP_6ST, ALC880_FIXUP_6ST_DIG, + ALC880_FIXUP_6ST_AUTOMUTE, }; /* enable the volume-knob widget support on NID 0x21 */ static void alc880_fixup_vol_knob(struct hda_codec *codec, - const struct alc_fixup *fix, int action) + const struct hda_fixup *fix, int action) { - if (action == ALC_FIXUP_ACT_PROBE) + if (action == HDA_FIXUP_ACT_PROBE) snd_hda_jack_detect_enable_callback(codec, 0x21, ALC_DCVOL_EVENT, alc_update_knob_master); } -static const struct alc_fixup alc880_fixups[] = { +static const struct hda_fixup alc880_fixups[] = { [ALC880_FIXUP_GPIO1] = { - .type = ALC_FIXUP_VERBS, + .type = HDA_FIXUP_VERBS, .v.verbs = alc_gpio1_init_verbs, }, [ALC880_FIXUP_GPIO2] = { - .type = ALC_FIXUP_VERBS, + .type = HDA_FIXUP_VERBS, .v.verbs = alc_gpio2_init_verbs, }, [ALC880_FIXUP_MEDION_RIM] = { - .type = ALC_FIXUP_VERBS, + .type = HDA_FIXUP_VERBS, .v.verbs = (const struct hda_verb[]) { { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 }, { 0x20, AC_VERB_SET_PROC_COEF, 0x3060 }, @@ -4444,8 +1065,8 @@ static const struct alc_fixup alc880_fixups[] = { .chain_id = ALC880_FIXUP_GPIO2, }, [ALC880_FIXUP_LG] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { /* disable bogus unused pins */ { 0x16, 0x411111f0 }, { 0x18, 0x411111f0 }, @@ -4454,8 +1075,8 @@ static const struct alc_fixup alc880_fixups[] = { } }, [ALC880_FIXUP_W810] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { /* disable bogus unused pins */ { 0x17, 0x411111f0 }, { } @@ -4464,7 +1085,7 @@ static const struct alc_fixup alc880_fixups[] = { .chain_id = ALC880_FIXUP_GPIO2, }, [ALC880_FIXUP_EAPD_COEF] = { - .type = ALC_FIXUP_VERBS, + .type = HDA_FIXUP_VERBS, .v.verbs = (const struct hda_verb[]) { /* change to EAPD mode */ { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 }, @@ -4473,7 +1094,7 @@ static const struct alc_fixup alc880_fixups[] = { }, }, [ALC880_FIXUP_TCL_S700] = { - .type = ALC_FIXUP_VERBS, + .type = HDA_FIXUP_VERBS, .v.verbs = (const struct hda_verb[]) { /* change to EAPD mode */ { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 }, @@ -4484,13 +1105,13 @@ static const struct alc_fixup alc880_fixups[] = { .chain_id = ALC880_FIXUP_GPIO2, }, [ALC880_FIXUP_VOL_KNOB] = { - .type = ALC_FIXUP_FUNC, + .type = HDA_FIXUP_FUNC, .v.func = alc880_fixup_vol_knob, }, [ALC880_FIXUP_FUJITSU] = { /* override all pins as BIOS on old Amilo is broken */ - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x14, 0x0121411f }, /* HP */ { 0x15, 0x99030120 }, /* speaker */ { 0x16, 0x99030130 }, /* bass speaker */ @@ -4509,8 +1130,8 @@ static const struct alc_fixup alc880_fixups[] = { }, [ALC880_FIXUP_F1734] = { /* almost compatible with FUJITSU, but no bass and SPDIF */ - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x14, 0x0121411f }, /* HP */ { 0x15, 0x99030120 }, /* speaker */ { 0x16, 0x411111f0 }, /* N/A */ @@ -4529,8 +1150,8 @@ static const struct alc_fixup alc880_fixups[] = { }, [ALC880_FIXUP_UNIWILL] = { /* need to fix HP and speaker pins to be parsed correctly */ - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x14, 0x0121411f }, /* HP */ { 0x15, 0x99030120 }, /* speaker */ { 0x16, 0x99030130 }, /* bass speaker */ @@ -4538,8 +1159,8 @@ static const struct alc_fixup alc880_fixups[] = { }, }, [ALC880_FIXUP_UNIWILL_DIG] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { /* disable bogus unused pins */ { 0x17, 0x411111f0 }, { 0x19, 0x411111f0 }, @@ -4549,8 +1170,8 @@ static const struct alc_fixup alc880_fixups[] = { } }, [ALC880_FIXUP_Z71V] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { /* set up the whole pins as BIOS is utterly broken */ { 0x14, 0x99030120 }, /* speaker */ { 0x15, 0x0121411f }, /* HP */ @@ -4567,8 +1188,8 @@ static const struct alc_fixup alc880_fixups[] = { } }, [ALC880_FIXUP_3ST_BASE] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x14, 0x01014010 }, /* line-out */ { 0x15, 0x411111f0 }, /* N/A */ { 0x16, 0x411111f0 }, /* N/A */ @@ -4585,8 +1206,8 @@ static const struct alc_fixup alc880_fixups[] = { } }, [ALC880_FIXUP_3ST] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x1e, 0x411111f0 }, /* N/A */ { } }, @@ -4594,8 +1215,8 @@ static const struct alc_fixup alc880_fixups[] = { .chain_id = ALC880_FIXUP_3ST_BASE, }, [ALC880_FIXUP_3ST_DIG] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x1e, 0x0144111e }, /* SPDIF */ { } }, @@ -4603,8 +1224,8 @@ static const struct alc_fixup alc880_fixups[] = { .chain_id = ALC880_FIXUP_3ST_BASE, }, [ALC880_FIXUP_5ST_BASE] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x14, 0x01014010 }, /* front */ { 0x15, 0x411111f0 }, /* N/A */ { 0x16, 0x01011411 }, /* CLFE */ @@ -4621,8 +1242,8 @@ static const struct alc_fixup alc880_fixups[] = { } }, [ALC880_FIXUP_5ST] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x1e, 0x411111f0 }, /* N/A */ { } }, @@ -4630,8 +1251,8 @@ static const struct alc_fixup alc880_fixups[] = { .chain_id = ALC880_FIXUP_5ST_BASE, }, [ALC880_FIXUP_5ST_DIG] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x1e, 0x0144111e }, /* SPDIF */ { } }, @@ -4639,8 +1260,8 @@ static const struct alc_fixup alc880_fixups[] = { .chain_id = ALC880_FIXUP_5ST_BASE, }, [ALC880_FIXUP_6ST_BASE] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x14, 0x01014010 }, /* front */ { 0x15, 0x01016412 }, /* surr */ { 0x16, 0x01011411 }, /* CLFE */ @@ -4657,8 +1278,8 @@ static const struct alc_fixup alc880_fixups[] = { } }, [ALC880_FIXUP_6ST] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x1e, 0x411111f0 }, /* N/A */ { } }, @@ -4666,14 +1287,23 @@ static const struct alc_fixup alc880_fixups[] = { .chain_id = ALC880_FIXUP_6ST_BASE, }, [ALC880_FIXUP_6ST_DIG] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x1e, 0x0144111e }, /* SPDIF */ { } }, .chained = true, .chain_id = ALC880_FIXUP_6ST_BASE, }, + [ALC880_FIXUP_6ST_AUTOMUTE] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x1b, 0x0121401f }, /* HP with jack detect */ + { } + }, + .chained_before = true, + .chain_id = ALC880_FIXUP_6ST_BASE, + }, }; static const struct snd_pci_quirk alc880_fixup_tbl[] = { @@ -4688,6 +1318,7 @@ static const struct snd_pci_quirk alc880_fixup_tbl[] = { SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_FIXUP_VOL_KNOB), SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_FIXUP_W810), SND_PCI_QUIRK(0x161f, 0x205d, "Medion Rim 2150", ALC880_FIXUP_MEDION_RIM), + SND_PCI_QUIRK(0x1631, 0xe011, "PB 13201056", ALC880_FIXUP_6ST_AUTOMUTE), SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_FIXUP_F1734), SND_PCI_QUIRK(0x1734, 0x1094, "FSC Amilo M1451G", ALC880_FIXUP_FUJITSU), SND_PCI_QUIRK(0x1734, 0x10ac, "FSC AMILO Xi 1526", ALC880_FIXUP_F1734), @@ -4743,13 +1374,14 @@ static const struct snd_pci_quirk alc880_fixup_tbl[] = { {} }; -static const struct alc_model_fixup alc880_fixup_models[] = { +static const struct hda_model_fixup alc880_fixup_models[] = { {.id = ALC880_FIXUP_3ST, .name = "3stack"}, {.id = ALC880_FIXUP_3ST_DIG, .name = "3stack-digout"}, {.id = ALC880_FIXUP_5ST, .name = "5stack"}, {.id = ALC880_FIXUP_5ST_DIG, .name = "5stack-digout"}, {.id = ALC880_FIXUP_6ST, .name = "6stack"}, {.id = ALC880_FIXUP_6ST_DIG, .name = "6stack-digout"}, + {.id = ALC880_FIXUP_6ST_AUTOMUTE, .name = "6stack-automute"}, {} }; @@ -4767,18 +1399,18 @@ static int patch_alc880(struct hda_codec *codec) return err; spec = codec->spec; - spec->need_dac_fix = 1; + spec->gen.need_dac_fix = 1; - alc_pick_fixup(codec, alc880_fixup_models, alc880_fixup_tbl, + snd_hda_pick_fixup(codec, alc880_fixup_models, alc880_fixup_tbl, alc880_fixups); - alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); /* automatic parse from the BIOS config */ err = alc880_parse_auto_config(codec); if (err < 0) goto error; - if (!spec->no_analog) { + if (!spec->gen.no_analog) { err = snd_hda_attach_beep_device(codec, 0x1); if (err < 0) goto error; @@ -4789,7 +1421,7 @@ static int patch_alc880(struct hda_codec *codec) codec->patch_ops.unsol_event = alc880_unsol_event; - alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); return 0; @@ -4821,38 +1453,39 @@ enum { ALC260_FIXUP_REPLACER, ALC260_FIXUP_HP_B1900, ALC260_FIXUP_KN1, + ALC260_FIXUP_FSC_S7020, }; static void alc260_gpio1_automute(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, - spec->hp_jack_present); + spec->gen.hp_jack_present); } static void alc260_fixup_gpio1_toggle(struct hda_codec *codec, - const struct alc_fixup *fix, int action) + const struct hda_fixup *fix, int action) { struct alc_spec *spec = codec->spec; - if (action == ALC_FIXUP_ACT_PROBE) { + if (action == HDA_FIXUP_ACT_PROBE) { /* although the machine has only one output pin, we need to * toggle GPIO1 according to the jack state */ - spec->automute_hook = alc260_gpio1_automute; - spec->detect_hp = 1; - spec->automute_speaker = 1; - spec->autocfg.hp_pins[0] = 0x0f; /* copy it for automute */ - snd_hda_jack_detect_enable_callback(codec, 0x0f, ALC_HP_EVENT, - alc_hp_automute); - snd_hda_gen_add_verbs(&spec->gen, alc_gpio1_init_verbs); + spec->gen.automute_hook = alc260_gpio1_automute; + spec->gen.detect_hp = 1; + spec->gen.automute_speaker = 1; + spec->gen.autocfg.hp_pins[0] = 0x0f; /* copy it for automute */ + snd_hda_jack_detect_enable_callback(codec, 0x0f, HDA_GEN_HP_EVENT, + snd_hda_gen_hp_automute); + snd_hda_add_verbs(codec, alc_gpio1_init_verbs); } } static void alc260_fixup_kn1(struct hda_codec *codec, - const struct alc_fixup *fix, int action) + const struct hda_fixup *fix, int action) { struct alc_spec *spec = codec->spec; - static const struct alc_pincfg pincfgs[] = { + static const struct hda_pintbl pincfgs[] = { { 0x0f, 0x02214000 }, /* HP/speaker */ { 0x12, 0x90a60160 }, /* int mic */ { 0x13, 0x02a19000 }, /* ext mic */ @@ -4869,32 +1502,41 @@ static void alc260_fixup_kn1(struct hda_codec *codec, }; switch (action) { - case ALC_FIXUP_ACT_PRE_PROBE: - alc_apply_pincfgs(codec, pincfgs); + case HDA_FIXUP_ACT_PRE_PROBE: + snd_hda_apply_pincfgs(codec, pincfgs); break; - case ALC_FIXUP_ACT_PROBE: + case HDA_FIXUP_ACT_PROBE: spec->init_amp = ALC_INIT_NONE; break; } } -static const struct alc_fixup alc260_fixups[] = { +static void alc260_fixup_fsc_s7020(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.add_out_jack_modes = 1; +} + +static const struct hda_fixup alc260_fixups[] = { [ALC260_FIXUP_HP_DC5750] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x11, 0x90130110 }, /* speaker */ { } } }, [ALC260_FIXUP_HP_PIN_0F] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x0f, 0x01214000 }, /* HP */ { } } }, [ALC260_FIXUP_COEF] = { - .type = ALC_FIXUP_VERBS, + .type = HDA_FIXUP_VERBS, .v.verbs = (const struct hda_verb[]) { { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 }, { 0x20, AC_VERB_SET_PROC_COEF, 0x3040 }, @@ -4904,17 +1546,17 @@ static const struct alc_fixup alc260_fixups[] = { .chain_id = ALC260_FIXUP_HP_PIN_0F, }, [ALC260_FIXUP_GPIO1] = { - .type = ALC_FIXUP_VERBS, + .type = HDA_FIXUP_VERBS, .v.verbs = alc_gpio1_init_verbs, }, [ALC260_FIXUP_GPIO1_TOGGLE] = { - .type = ALC_FIXUP_FUNC, + .type = HDA_FIXUP_FUNC, .v.func = alc260_fixup_gpio1_toggle, .chained = true, .chain_id = ALC260_FIXUP_HP_PIN_0F, }, [ALC260_FIXUP_REPLACER] = { - .type = ALC_FIXUP_VERBS, + .type = HDA_FIXUP_VERBS, .v.verbs = (const struct hda_verb[]) { { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 }, { 0x20, AC_VERB_SET_PROC_COEF, 0x3050 }, @@ -4924,15 +1566,19 @@ static const struct alc_fixup alc260_fixups[] = { .chain_id = ALC260_FIXUP_GPIO1_TOGGLE, }, [ALC260_FIXUP_HP_B1900] = { - .type = ALC_FIXUP_FUNC, + .type = HDA_FIXUP_FUNC, .v.func = alc260_fixup_gpio1_toggle, .chained = true, .chain_id = ALC260_FIXUP_COEF, }, [ALC260_FIXUP_KN1] = { - .type = ALC_FIXUP_FUNC, + .type = HDA_FIXUP_FUNC, .v.func = alc260_fixup_kn1, }, + [ALC260_FIXUP_FSC_S7020] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc260_fixup_fsc_s7020, + }, }; static const struct snd_pci_quirk alc260_fixup_tbl[] = { @@ -4941,6 +1587,7 @@ static const struct snd_pci_quirk alc260_fixup_tbl[] = { SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_FIXUP_GPIO1), SND_PCI_QUIRK(0x103c, 0x280a, "HP dc5750", ALC260_FIXUP_HP_DC5750), SND_PCI_QUIRK(0x103c, 0x30ba, "HP Presario B1900", ALC260_FIXUP_HP_B1900), + SND_PCI_QUIRK(0x10cf, 0x1326, "FSC LifeBook S7020", ALC260_FIXUP_FSC_S7020), SND_PCI_QUIRK(0x1509, 0x4540, "Favorit 100XS", ALC260_FIXUP_GPIO1), SND_PCI_QUIRK(0x152d, 0x0729, "Quanta KN1", ALC260_FIXUP_KN1), SND_PCI_QUIRK(0x161f, 0x2057, "Replacer 672V", ALC260_FIXUP_REPLACER), @@ -4960,16 +1607,21 @@ static int patch_alc260(struct hda_codec *codec) return err; spec = codec->spec; + /* as quite a few machines require HP amp for speaker outputs, + * it's easier to enable it unconditionally; even if it's unneeded, + * it's almost harmless. + */ + spec->gen.prefer_hp_amp = 1; - alc_pick_fixup(codec, NULL, alc260_fixup_tbl, alc260_fixups); - alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); + snd_hda_pick_fixup(codec, NULL, alc260_fixup_tbl, alc260_fixups); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); /* automatic parse from the BIOS config */ err = alc260_parse_auto_config(codec); if (err < 0) goto error; - if (!spec->no_analog) { + if (!spec->gen.no_analog) { err = snd_hda_attach_beep_device(codec, 0x1); if (err < 0) goto error; @@ -4979,7 +1631,7 @@ static int patch_alc260(struct hda_codec *codec) codec->patch_ops = alc_patch_ops; spec->shutup = alc_eapd_shutup; - alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); return 0; @@ -5033,9 +1685,9 @@ enum { }; static void alc889_fixup_coef(struct hda_codec *codec, - const struct alc_fixup *fix, int action) + const struct hda_fixup *fix, int action) { - if (action != ALC_FIXUP_ACT_INIT) + if (action != HDA_FIXUP_ACT_INIT) return; alc889_coef_init(codec); } @@ -5075,9 +1727,9 @@ static void alc882_gpio_mute(struct hda_codec *codec, int pin, int muted) /* set up GPIO at initialization */ static void alc885_fixup_macpro_gpio(struct hda_codec *codec, - const struct alc_fixup *fix, int action) + const struct hda_fixup *fix, int action) { - if (action != ALC_FIXUP_ACT_INIT) + if (action != HDA_FIXUP_ACT_INIT) return; alc882_gpio_mute(codec, 0, 0); alc882_gpio_mute(codec, 1, 0); @@ -5088,9 +1740,9 @@ static void alc885_fixup_macpro_gpio(struct hda_codec *codec, * work correctly (bko#42740) */ static void alc889_fixup_dac_route(struct hda_codec *codec, - const struct alc_fixup *fix, int action) + const struct hda_fixup *fix, int action) { - if (action == ALC_FIXUP_ACT_PRE_PROBE) { + if (action == HDA_FIXUP_ACT_PRE_PROBE) { /* fake the connections during parsing the tree */ hda_nid_t conn1[2] = { 0x0c, 0x0d }; hda_nid_t conn2[2] = { 0x0e, 0x0f }; @@ -5098,7 +1750,7 @@ static void alc889_fixup_dac_route(struct hda_codec *codec, snd_hda_override_conn_list(codec, 0x15, 2, conn1); snd_hda_override_conn_list(codec, 0x18, 2, conn2); snd_hda_override_conn_list(codec, 0x1a, 2, conn2); - } else if (action == ALC_FIXUP_ACT_PROBE) { + } else if (action == HDA_FIXUP_ACT_PROBE) { /* restore the connections */ hda_nid_t conn[5] = { 0x0c, 0x0d, 0x0e, 0x0f, 0x26 }; snd_hda_override_conn_list(codec, 0x14, 5, conn); @@ -5110,62 +1762,60 @@ static void alc889_fixup_dac_route(struct hda_codec *codec, /* Set VREF on HP pin */ static void alc889_fixup_mbp_vref(struct hda_codec *codec, - const struct alc_fixup *fix, int action) + const struct hda_fixup *fix, int action) { struct alc_spec *spec = codec->spec; static hda_nid_t nids[2] = { 0x14, 0x15 }; int i; - if (action != ALC_FIXUP_ACT_INIT) + if (action != HDA_FIXUP_ACT_INIT) return; for (i = 0; i < ARRAY_SIZE(nids); i++) { unsigned int val = snd_hda_codec_get_pincfg(codec, nids[i]); if (get_defcfg_device(val) != AC_JACK_HP_OUT) continue; - val = snd_hda_codec_read(codec, nids[i], 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); + val = snd_hda_codec_get_pin_target(codec, nids[i]); val |= AC_PINCTL_VREF_80; snd_hda_set_pin_ctl(codec, nids[i], val); - spec->keep_vref_in_automute = 1; + spec->gen.keep_vref_in_automute = 1; break; } } /* Set VREF on speaker pins on imac91 */ static void alc889_fixup_imac91_vref(struct hda_codec *codec, - const struct alc_fixup *fix, int action) + const struct hda_fixup *fix, int action) { struct alc_spec *spec = codec->spec; static hda_nid_t nids[2] = { 0x18, 0x1a }; int i; - if (action != ALC_FIXUP_ACT_INIT) + if (action != HDA_FIXUP_ACT_INIT) return; for (i = 0; i < ARRAY_SIZE(nids); i++) { unsigned int val; - val = snd_hda_codec_read(codec, nids[i], 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); + val = snd_hda_codec_get_pin_target(codec, nids[i]); val |= AC_PINCTL_VREF_50; snd_hda_set_pin_ctl(codec, nids[i], val); } - spec->keep_vref_in_automute = 1; + spec->gen.keep_vref_in_automute = 1; } /* Don't take HP output as primary * strangely, the speaker output doesn't work on VAIO Z through DAC 0x05 */ static void alc882_fixup_no_primary_hp(struct hda_codec *codec, - const struct alc_fixup *fix, int action) + const struct hda_fixup *fix, int action) { struct alc_spec *spec = codec->spec; - if (action == ALC_FIXUP_ACT_PRE_PROBE) - spec->no_primary_hp = 1; + if (action == HDA_FIXUP_ACT_PRE_PROBE) + spec->gen.no_primary_hp = 1; } -static const struct alc_fixup alc882_fixups[] = { +static const struct hda_fixup alc882_fixups[] = { [ALC882_FIXUP_ABIT_AW9D_MAX] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x15, 0x01080104 }, /* side */ { 0x16, 0x01011012 }, /* rear */ { 0x17, 0x01016011 }, /* clfe */ @@ -5173,47 +1823,47 @@ static const struct alc_fixup alc882_fixups[] = { } }, [ALC882_FIXUP_LENOVO_Y530] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x15, 0x99130112 }, /* rear int speakers */ { 0x16, 0x99130111 }, /* subwoofer */ { } } }, [ALC882_FIXUP_PB_M5210] = { - .type = ALC_FIXUP_VERBS, - .v.verbs = (const struct hda_verb[]) { - { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50 }, + .type = HDA_FIXUP_PINCTLS, + .v.pins = (const struct hda_pintbl[]) { + { 0x19, PIN_VREF50 }, {} } }, [ALC882_FIXUP_ACER_ASPIRE_7736] = { - .type = ALC_FIXUP_FUNC, + .type = HDA_FIXUP_FUNC, .v.func = alc_fixup_sku_ignore, }, [ALC882_FIXUP_ASUS_W90V] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x16, 0x99130110 }, /* fix sequence for CLFE */ { } } }, [ALC889_FIXUP_CD] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x1c, 0x993301f0 }, /* CD */ { } } }, [ALC889_FIXUP_VAIO_TT] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x17, 0x90170111 }, /* hidden surround speaker */ { } } }, [ALC888_FIXUP_EEE1601] = { - .type = ALC_FIXUP_VERBS, + .type = HDA_FIXUP_VERBS, .v.verbs = (const struct hda_verb[]) { { 0x20, AC_VERB_SET_COEF_INDEX, 0x0b }, { 0x20, AC_VERB_SET_PROC_COEF, 0x0838 }, @@ -5221,7 +1871,7 @@ static const struct alc_fixup alc882_fixups[] = { } }, [ALC882_FIXUP_EAPD] = { - .type = ALC_FIXUP_VERBS, + .type = HDA_FIXUP_VERBS, .v.verbs = (const struct hda_verb[]) { /* change to EAPD mode */ { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 }, @@ -5230,7 +1880,7 @@ static const struct alc_fixup alc882_fixups[] = { } }, [ALC883_FIXUP_EAPD] = { - .type = ALC_FIXUP_VERBS, + .type = HDA_FIXUP_VERBS, .v.verbs = (const struct hda_verb[]) { /* change to EAPD mode */ { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 }, @@ -5239,7 +1889,7 @@ static const struct alc_fixup alc882_fixups[] = { } }, [ALC883_FIXUP_ACER_EAPD] = { - .type = ALC_FIXUP_VERBS, + .type = HDA_FIXUP_VERBS, .v.verbs = (const struct hda_verb[]) { /* eanable EAPD on Acer laptops */ { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 }, @@ -5248,30 +1898,30 @@ static const struct alc_fixup alc882_fixups[] = { } }, [ALC882_FIXUP_GPIO1] = { - .type = ALC_FIXUP_VERBS, + .type = HDA_FIXUP_VERBS, .v.verbs = alc_gpio1_init_verbs, }, [ALC882_FIXUP_GPIO2] = { - .type = ALC_FIXUP_VERBS, + .type = HDA_FIXUP_VERBS, .v.verbs = alc_gpio2_init_verbs, }, [ALC882_FIXUP_GPIO3] = { - .type = ALC_FIXUP_VERBS, + .type = HDA_FIXUP_VERBS, .v.verbs = alc_gpio3_init_verbs, }, [ALC882_FIXUP_ASUS_W2JC] = { - .type = ALC_FIXUP_VERBS, + .type = HDA_FIXUP_VERBS, .v.verbs = alc_gpio1_init_verbs, .chained = true, .chain_id = ALC882_FIXUP_EAPD, }, [ALC889_FIXUP_COEF] = { - .type = ALC_FIXUP_FUNC, + .type = HDA_FIXUP_FUNC, .v.func = alc889_fixup_coef, }, [ALC882_FIXUP_ACER_ASPIRE_4930G] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x16, 0x99130111 }, /* CLFE speaker */ { 0x17, 0x99130112 }, /* surround speaker */ { } @@ -5280,8 +1930,8 @@ static const struct alc_fixup alc882_fixups[] = { .chain_id = ALC882_FIXUP_GPIO1, }, [ALC882_FIXUP_ACER_ASPIRE_8930G] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x16, 0x99130111 }, /* CLFE speaker */ { 0x1b, 0x99130112 }, /* surround speaker */ { } @@ -5291,7 +1941,7 @@ static const struct alc_fixup alc882_fixups[] = { }, [ALC882_FIXUP_ASPIRE_8930G_VERBS] = { /* additional init verbs for Acer Aspire 8930G */ - .type = ALC_FIXUP_VERBS, + .type = HDA_FIXUP_VERBS, .v.verbs = (const struct hda_verb[]) { /* Enable all DACs */ /* DAC DISABLE/MUTE 1? */ @@ -5325,31 +1975,31 @@ static const struct alc_fixup alc882_fixups[] = { .chain_id = ALC882_FIXUP_GPIO1, }, [ALC885_FIXUP_MACPRO_GPIO] = { - .type = ALC_FIXUP_FUNC, + .type = HDA_FIXUP_FUNC, .v.func = alc885_fixup_macpro_gpio, }, [ALC889_FIXUP_DAC_ROUTE] = { - .type = ALC_FIXUP_FUNC, + .type = HDA_FIXUP_FUNC, .v.func = alc889_fixup_dac_route, }, [ALC889_FIXUP_MBP_VREF] = { - .type = ALC_FIXUP_FUNC, + .type = HDA_FIXUP_FUNC, .v.func = alc889_fixup_mbp_vref, .chained = true, .chain_id = ALC882_FIXUP_GPIO1, }, [ALC889_FIXUP_IMAC91_VREF] = { - .type = ALC_FIXUP_FUNC, + .type = HDA_FIXUP_FUNC, .v.func = alc889_fixup_imac91_vref, .chained = true, .chain_id = ALC882_FIXUP_GPIO1, }, [ALC882_FIXUP_INV_DMIC] = { - .type = ALC_FIXUP_FUNC, + .type = HDA_FIXUP_FUNC, .v.func = alc_fixup_inv_dmic_0x12, }, [ALC882_FIXUP_NO_PRIMARY_HP] = { - .type = ALC_FIXUP_FUNC, + .type = HDA_FIXUP_FUNC, .v.func = alc882_fixup_no_primary_hp, }, }; @@ -5424,7 +2074,7 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = { {} }; -static const struct alc_model_fixup alc882_fixup_models[] = { +static const struct hda_model_fixup alc882_fixup_models[] = { {.id = ALC882_FIXUP_ACER_ASPIRE_4930G, .name = "acer-aspire-4930g"}, {.id = ALC882_FIXUP_ACER_ASPIRE_8930G, .name = "acer-aspire-8930g"}, {.id = ALC883_FIXUP_ACER_EAPD, .name = "acer-aspire"}, @@ -5467,9 +2117,9 @@ static int patch_alc882(struct hda_codec *codec) break; } - alc_pick_fixup(codec, alc882_fixup_models, alc882_fixup_tbl, + snd_hda_pick_fixup(codec, alc882_fixup_models, alc882_fixup_tbl, alc882_fixups); - alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); alc_auto_parse_customize_define(codec); @@ -5478,7 +2128,7 @@ static int patch_alc882(struct hda_codec *codec) if (err < 0) goto error; - if (!spec->no_analog && has_cdefine_beep(codec)) { + if (!spec->gen.no_analog && has_cdefine_beep(codec)) { err = snd_hda_attach_beep_device(codec, 0x1); if (err < 0) goto error; @@ -5487,7 +2137,7 @@ static int patch_alc882(struct hda_codec *codec) codec->patch_ops = alc_patch_ops; - alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); return 0; @@ -5512,6 +2162,7 @@ static int alc262_parse_auto_config(struct hda_codec *codec) */ enum { ALC262_FIXUP_FSC_H270, + ALC262_FIXUP_FSC_S7110, ALC262_FIXUP_HP_Z200, ALC262_FIXUP_TYAN, ALC262_FIXUP_LENOVO_3000, @@ -5520,41 +2171,50 @@ enum { ALC262_FIXUP_INV_DMIC, }; -static const struct alc_fixup alc262_fixups[] = { +static const struct hda_fixup alc262_fixups[] = { [ALC262_FIXUP_FSC_H270] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x14, 0x99130110 }, /* speaker */ { 0x15, 0x0221142f }, /* front HP */ { 0x1b, 0x0121141f }, /* rear HP */ { } } }, + [ALC262_FIXUP_FSC_S7110] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x15, 0x90170110 }, /* speaker */ + { } + }, + .chained = true, + .chain_id = ALC262_FIXUP_BENQ, + }, [ALC262_FIXUP_HP_Z200] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x16, 0x99130120 }, /* internal speaker */ { } } }, [ALC262_FIXUP_TYAN] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x14, 0x1993e1f0 }, /* int AUX */ { } } }, [ALC262_FIXUP_LENOVO_3000] = { - .type = ALC_FIXUP_VERBS, - .v.verbs = (const struct hda_verb[]) { - { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50 }, + .type = HDA_FIXUP_PINCTLS, + .v.pins = (const struct hda_pintbl[]) { + { 0x19, PIN_VREF50 }, {} }, .chained = true, .chain_id = ALC262_FIXUP_BENQ, }, [ALC262_FIXUP_BENQ] = { - .type = ALC_FIXUP_VERBS, + .type = HDA_FIXUP_VERBS, .v.verbs = (const struct hda_verb[]) { { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 }, { 0x20, AC_VERB_SET_PROC_COEF, 0x3070 }, @@ -5562,7 +2222,7 @@ static const struct alc_fixup alc262_fixups[] = { } }, [ALC262_FIXUP_BENQ_T31] = { - .type = ALC_FIXUP_VERBS, + .type = HDA_FIXUP_VERBS, .v.verbs = (const struct hda_verb[]) { { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 }, { 0x20, AC_VERB_SET_PROC_COEF, 0x3050 }, @@ -5570,14 +2230,14 @@ static const struct alc_fixup alc262_fixups[] = { } }, [ALC262_FIXUP_INV_DMIC] = { - .type = ALC_FIXUP_FUNC, + .type = HDA_FIXUP_FUNC, .v.func = alc_fixup_inv_dmic_0x12, }, }; static const struct snd_pci_quirk alc262_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x170b, "HP Z200", ALC262_FIXUP_HP_Z200), - SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FIXUP_BENQ), + SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu Lifebook S7110", ALC262_FIXUP_FSC_S7110), SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FIXUP_BENQ), SND_PCI_QUIRK(0x10f1, 0x2915, "Tyan Thunder n6650W", ALC262_FIXUP_TYAN), SND_PCI_QUIRK(0x1734, 0x1147, "FSC Celsius H270", ALC262_FIXUP_FSC_H270), @@ -5587,7 +2247,7 @@ static const struct snd_pci_quirk alc262_fixup_tbl[] = { {} }; -static const struct alc_model_fixup alc262_fixup_models[] = { +static const struct hda_model_fixup alc262_fixup_models[] = { {.id = ALC262_FIXUP_INV_DMIC, .name = "inv-dmic"}, {} }; @@ -5604,6 +2264,7 @@ static int patch_alc262(struct hda_codec *codec) return err; spec = codec->spec; + spec->gen.shared_mic_vref_pin = 0x18; #if 0 /* pshou 07/11/05 set a zero PCM sample to DAC when FIFO is @@ -5619,9 +2280,9 @@ static int patch_alc262(struct hda_codec *codec) #endif alc_fix_pll_init(codec, 0x20, 0x0a, 10); - alc_pick_fixup(codec, alc262_fixup_models, alc262_fixup_tbl, + snd_hda_pick_fixup(codec, alc262_fixup_models, alc262_fixup_tbl, alc262_fixups); - alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); alc_auto_parse_customize_define(codec); @@ -5630,7 +2291,7 @@ static int patch_alc262(struct hda_codec *codec) if (err < 0) goto error; - if (!spec->no_analog && has_cdefine_beep(codec)) { + if (!spec->gen.no_analog && has_cdefine_beep(codec)) { err = snd_hda_attach_beep_device(codec, 0x1); if (err < 0) goto error; @@ -5640,7 +2301,7 @@ static int patch_alc262(struct hda_codec *codec) codec->patch_ops = alc_patch_ops; spec->shutup = alc_eapd_shutup; - alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); return 0; @@ -5681,13 +2342,13 @@ enum { ALC268_FIXUP_HP_EAPD, }; -static const struct alc_fixup alc268_fixups[] = { +static const struct hda_fixup alc268_fixups[] = { [ALC268_FIXUP_INV_DMIC] = { - .type = ALC_FIXUP_FUNC, + .type = HDA_FIXUP_FUNC, .v.func = alc_fixup_inv_dmic_0x12, }, [ALC268_FIXUP_HP_EAPD] = { - .type = ALC_FIXUP_VERBS, + .type = HDA_FIXUP_VERBS, .v.verbs = (const struct hda_verb[]) { {0x15, AC_VERB_SET_EAPD_BTLENABLE, 0}, {} @@ -5695,13 +2356,14 @@ static const struct alc_fixup alc268_fixups[] = { }, }; -static const struct alc_model_fixup alc268_fixup_models[] = { +static const struct hda_model_fixup alc268_fixup_models[] = { {.id = ALC268_FIXUP_INV_DMIC, .name = "inv-dmic"}, {.id = ALC268_FIXUP_HP_EAPD, .name = "hp-eapd"}, {} }; static const struct snd_pci_quirk alc268_fixup_tbl[] = { + SND_PCI_QUIRK(0x1025, 0x015b, "Acer AOA 150 (ZG5)", ALC268_FIXUP_INV_DMIC), /* below is codec SSID since multiple Toshiba laptops have the * same PCI SSID 1179:ff00 */ @@ -5718,9 +2380,10 @@ static int alc268_parse_auto_config(struct hda_codec *codec) struct alc_spec *spec = codec->spec; int err = alc_parse_auto_config(codec, NULL, alc268_ssids); if (err > 0) { - if (!spec->no_analog && spec->autocfg.speaker_pins[0] != 0x1d) { + if (!spec->gen.no_analog && + spec->gen.autocfg.speaker_pins[0] != 0x1d) { add_mixer(spec, alc268_beep_mixer); - snd_hda_gen_add_verbs(&spec->gen, alc268_beep_init_verbs); + snd_hda_add_verbs(codec, alc268_beep_init_verbs); } } return err; @@ -5740,8 +2403,8 @@ static int patch_alc268(struct hda_codec *codec) spec = codec->spec; - alc_pick_fixup(codec, alc268_fixup_models, alc268_fixup_tbl, alc268_fixups); - alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); + snd_hda_pick_fixup(codec, alc268_fixup_models, alc268_fixup_tbl, alc268_fixups); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); /* automatic parse from the BIOS config */ err = alc268_parse_auto_config(codec); @@ -5772,7 +2435,7 @@ static int patch_alc268(struct hda_codec *codec) codec->patch_ops = alc_patch_ops; spec->shutup = alc_eapd_shutup; - alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); return 0; @@ -5784,6 +2447,35 @@ static int patch_alc268(struct hda_codec *codec) /* * ALC269 */ + +static int playback_pcm_open(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct hda_gen_spec *spec = codec->spec; + return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream, + hinfo); +} + +static int 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 hda_gen_spec *spec = codec->spec; + return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, + stream_tag, format, substream); +} + +static int playback_pcm_cleanup(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct hda_gen_spec *spec = codec->spec; + return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); +} + static const struct hda_pcm_stream alc269_44k_pcm_analog_playback = { .substreams = 1, .channels_min = 2, @@ -5791,9 +2483,9 @@ static const struct hda_pcm_stream alc269_44k_pcm_analog_playback = { .rates = SNDRV_PCM_RATE_44100, /* fixed rate */ /* NID is set in alc_build_pcms */ .ops = { - .open = alc_playback_pcm_open, - .prepare = alc_playback_pcm_prepare, - .cleanup = alc_playback_pcm_cleanup + .open = playback_pcm_open, + .prepare = playback_pcm_prepare, + .cleanup = playback_pcm_cleanup }, }; @@ -5811,6 +2503,9 @@ enum { ALC269_TYPE_ALC269VB, ALC269_TYPE_ALC269VC, ALC269_TYPE_ALC269VD, + ALC269_TYPE_ALC280, + ALC269_TYPE_ALC282, + ALC269_TYPE_ALC284, }; /* @@ -5827,10 +2522,13 @@ static int alc269_parse_auto_config(struct hda_codec *codec) switch (spec->codec_variant) { case ALC269_TYPE_ALC269VA: case ALC269_TYPE_ALC269VC: + case ALC269_TYPE_ALC280: + case ALC269_TYPE_ALC284: ssids = alc269va_ssids; break; case ALC269_TYPE_ALC269VB: case ALC269_TYPE_ALC269VD: + case ALC269_TYPE_ALC282: ssids = alc269_ssids; break; default: @@ -5895,27 +2593,27 @@ static int alc269_resume(struct hda_codec *codec) #endif /* CONFIG_PM */ static void alc269_fixup_pincfg_no_hp_to_lineout(struct hda_codec *codec, - const struct alc_fixup *fix, int action) + const struct hda_fixup *fix, int action) { struct alc_spec *spec = codec->spec; - if (action == ALC_FIXUP_ACT_PRE_PROBE) + if (action == HDA_FIXUP_ACT_PRE_PROBE) spec->parse_flags = HDA_PINCFG_NO_HP_FIXUP; } static void alc269_fixup_hweq(struct hda_codec *codec, - const struct alc_fixup *fix, int action) + const struct hda_fixup *fix, int action) { int coef; - if (action != ALC_FIXUP_ACT_INIT) + if (action != HDA_FIXUP_ACT_INIT) return; coef = alc_read_coef_idx(codec, 0x1e); alc_write_coef_idx(codec, 0x1e, coef | 0x80); } static void alc271_fixup_dmic(struct hda_codec *codec, - const struct alc_fixup *fix, int action) + const struct hda_fixup *fix, int action) { static const struct hda_verb verbs[] = { {0x20, AC_VERB_SET_COEF_INDEX, 0x0d}, @@ -5932,26 +2630,26 @@ static void alc271_fixup_dmic(struct hda_codec *codec, } static void alc269_fixup_pcm_44k(struct hda_codec *codec, - const struct alc_fixup *fix, int action) + const struct hda_fixup *fix, int action) { struct alc_spec *spec = codec->spec; - if (action != ALC_FIXUP_ACT_PROBE) + if (action != HDA_FIXUP_ACT_PROBE) return; /* Due to a hardware problem on Lenovo Ideadpad, we need to * fix the sample rate of analog I/O to 44.1kHz */ - spec->stream_analog_playback = &alc269_44k_pcm_analog_playback; - spec->stream_analog_capture = &alc269_44k_pcm_analog_capture; + spec->gen.stream_analog_playback = &alc269_44k_pcm_analog_playback; + spec->gen.stream_analog_capture = &alc269_44k_pcm_analog_capture; } static void alc269_fixup_stereo_dmic(struct hda_codec *codec, - const struct alc_fixup *fix, int action) + const struct hda_fixup *fix, int action) { int coef; - if (action != ALC_FIXUP_ACT_INIT) + if (action != HDA_FIXUP_ACT_INIT) return; /* The digital-mic unit sends PDM (differential signal) instead of * the standard PCM, thus you can't record a valid mono stream as is. @@ -5964,7 +2662,7 @@ static void alc269_fixup_stereo_dmic(struct hda_codec *codec, static void alc269_quanta_automute(struct hda_codec *codec) { - update_outputs(codec); + snd_hda_gen_update_outputs(codec); snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 0x0c); @@ -5978,37 +2676,80 @@ static void alc269_quanta_automute(struct hda_codec *codec) } static void alc269_fixup_quanta_mute(struct hda_codec *codec, - const struct alc_fixup *fix, int action) + const struct hda_fixup *fix, int action) { struct alc_spec *spec = codec->spec; - if (action != ALC_FIXUP_ACT_PROBE) + if (action != HDA_FIXUP_ACT_PROBE) return; - spec->automute_hook = alc269_quanta_automute; + spec->gen.automute_hook = alc269_quanta_automute; } -/* update mute-LED according to the speaker mute state via mic2 VREF pin */ -static void alc269_fixup_mic2_mute_hook(void *private_data, int enabled) +/* update mute-LED according to the speaker mute state via mic VREF pin */ +static void alc269_fixup_mic_mute_hook(void *private_data, int enabled) { struct hda_codec *codec = private_data; - unsigned int pinval = enabled ? 0x20 : 0x24; - snd_hda_set_pin_ctl_cache(codec, 0x19, pinval); + struct alc_spec *spec = codec->spec; + unsigned int pinval; + + if (spec->mute_led_polarity) + enabled = !enabled; + pinval = AC_PINCTL_IN_EN | + (enabled ? AC_PINCTL_VREF_HIZ : AC_PINCTL_VREF_80); + if (spec->mute_led_nid) + snd_hda_set_pin_ctl_cache(codec, spec->mute_led_nid, pinval); } -static void alc269_fixup_mic2_mute(struct hda_codec *codec, - const struct alc_fixup *fix, int action) +static void alc269_fixup_hp_mute_led(struct hda_codec *codec, + const struct hda_fixup *fix, int action) { struct alc_spec *spec = codec->spec; - switch (action) { - case ALC_FIXUP_ACT_BUILD: - spec->vmaster_mute.hook = alc269_fixup_mic2_mute_hook; - snd_hda_add_vmaster_hook(codec, &spec->vmaster_mute, true); - /* fallthru */ - case ALC_FIXUP_ACT_INIT: - snd_hda_sync_vmaster_hook(&spec->vmaster_mute); + const struct dmi_device *dev = NULL; + + if (action != HDA_FIXUP_ACT_PRE_PROBE) + return; + + while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, NULL, dev))) { + int pol, pin; + if (sscanf(dev->name, "HP_Mute_LED_%d_%x", &pol, &pin) != 2) + continue; + if (pin < 0x0a || pin >= 0x10) + break; + spec->mute_led_polarity = pol; + spec->mute_led_nid = pin - 0x0a + 0x18; + spec->gen.vmaster_mute.hook = alc269_fixup_mic_mute_hook; + spec->gen.vmaster_mute_enum = 1; + snd_printd("Detected mute LED for %x:%d\n", spec->mute_led_nid, + spec->mute_led_polarity); break; } } +static void alc269_fixup_hp_mute_led_mic2(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->mute_led_polarity = 0; + spec->mute_led_nid = 0x19; + spec->gen.vmaster_mute.hook = alc269_fixup_mic_mute_hook; + spec->gen.vmaster_mute_enum = 1; + } +} + +static void alc271_hp_gate_mic_jack(struct hda_codec *codec, + const struct hda_fixup *fix, + int action) +{ + struct alc_spec *spec = codec->spec; + + if (action == HDA_FIXUP_ACT_PROBE) { + if (snd_BUG_ON(!spec->gen.am_entry[1].pin || + !spec->gen.autocfg.hp_pins[0])) + return; + snd_hda_jack_set_gating_jack(codec, spec->gen.am_entry[1].pin, + spec->gen.autocfg.hp_pins[0]); + } +} enum { ALC269_FIXUP_SONY_VAIO, @@ -6027,22 +2768,25 @@ enum { ALC269_FIXUP_DMIC, ALC269VB_FIXUP_AMIC, ALC269VB_FIXUP_DMIC, - ALC269_FIXUP_MIC2_MUTE_LED, + ALC269_FIXUP_HP_MUTE_LED, + ALC269_FIXUP_HP_MUTE_LED_MIC2, ALC269_FIXUP_INV_DMIC, ALC269_FIXUP_LENOVO_DOCK, ALC269_FIXUP_PINCFG_NO_HP_TO_LINEOUT, + ALC271_FIXUP_AMIC_MIC2, + ALC271_FIXUP_HP_GATE_MIC_JACK, }; -static const struct alc_fixup alc269_fixups[] = { +static const struct hda_fixup alc269_fixups[] = { [ALC269_FIXUP_SONY_VAIO] = { - .type = ALC_FIXUP_VERBS, - .v.verbs = (const struct hda_verb[]) { - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREFGRD}, + .type = HDA_FIXUP_PINCTLS, + .v.pins = (const struct hda_pintbl[]) { + {0x19, PIN_VREFGRD}, {} } }, [ALC275_FIXUP_SONY_VAIO_GPIO2] = { - .type = ALC_FIXUP_VERBS, + .type = HDA_FIXUP_VERBS, .v.verbs = (const struct hda_verb[]) { {0x01, AC_VERB_SET_GPIO_MASK, 0x04}, {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x04}, @@ -6053,7 +2797,7 @@ static const struct alc_fixup alc269_fixups[] = { .chain_id = ALC269_FIXUP_SONY_VAIO }, [ALC269_FIXUP_DELL_M101Z] = { - .type = ALC_FIXUP_VERBS, + .type = HDA_FIXUP_VERBS, .v.verbs = (const struct hda_verb[]) { /* Enables internal speaker */ {0x20, AC_VERB_SET_COEF_INDEX, 13}, @@ -6062,50 +2806,50 @@ static const struct alc_fixup alc269_fixups[] = { } }, [ALC269_FIXUP_SKU_IGNORE] = { - .type = ALC_FIXUP_FUNC, + .type = HDA_FIXUP_FUNC, .v.func = alc_fixup_sku_ignore, }, [ALC269_FIXUP_ASUS_G73JW] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x17, 0x99130111 }, /* subwoofer */ { } } }, [ALC269_FIXUP_LENOVO_EAPD] = { - .type = ALC_FIXUP_VERBS, + .type = HDA_FIXUP_VERBS, .v.verbs = (const struct hda_verb[]) { {0x14, AC_VERB_SET_EAPD_BTLENABLE, 0}, {} } }, [ALC275_FIXUP_SONY_HWEQ] = { - .type = ALC_FIXUP_FUNC, + .type = HDA_FIXUP_FUNC, .v.func = alc269_fixup_hweq, .chained = true, .chain_id = ALC275_FIXUP_SONY_VAIO_GPIO2 }, [ALC271_FIXUP_DMIC] = { - .type = ALC_FIXUP_FUNC, + .type = HDA_FIXUP_FUNC, .v.func = alc271_fixup_dmic, }, [ALC269_FIXUP_PCM_44K] = { - .type = ALC_FIXUP_FUNC, + .type = HDA_FIXUP_FUNC, .v.func = alc269_fixup_pcm_44k, .chained = true, .chain_id = ALC269_FIXUP_QUANTA_MUTE }, [ALC269_FIXUP_STEREO_DMIC] = { - .type = ALC_FIXUP_FUNC, + .type = HDA_FIXUP_FUNC, .v.func = alc269_fixup_stereo_dmic, }, [ALC269_FIXUP_QUANTA_MUTE] = { - .type = ALC_FIXUP_FUNC, + .type = HDA_FIXUP_FUNC, .v.func = alc269_fixup_quanta_mute, }, [ALC269_FIXUP_LIFEBOOK] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x1a, 0x2101103f }, /* dock line-out */ { 0x1b, 0x23a11040 }, /* dock mic-in */ { } @@ -6114,8 +2858,8 @@ static const struct alc_fixup alc269_fixups[] = { .chain_id = ALC269_FIXUP_QUANTA_MUTE }, [ALC269_FIXUP_AMIC] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x14, 0x99130110 }, /* speaker */ { 0x15, 0x0121401f }, /* HP out */ { 0x18, 0x01a19c20 }, /* mic */ @@ -6124,8 +2868,8 @@ static const struct alc_fixup alc269_fixups[] = { }, }, [ALC269_FIXUP_DMIC] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x12, 0x99a3092f }, /* int-mic */ { 0x14, 0x99130110 }, /* speaker */ { 0x15, 0x0121401f }, /* HP out */ @@ -6134,8 +2878,8 @@ static const struct alc_fixup alc269_fixups[] = { }, }, [ALC269VB_FIXUP_AMIC] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x14, 0x99130110 }, /* speaker */ { 0x18, 0x01a19c20 }, /* mic */ { 0x19, 0x99a3092f }, /* int-mic */ @@ -6144,8 +2888,8 @@ static const struct alc_fixup alc269_fixups[] = { }, }, [ALC269VB_FIXUP_DMIC] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x12, 0x99a3092f }, /* int-mic */ { 0x14, 0x99130110 }, /* speaker */ { 0x18, 0x01a19c20 }, /* mic */ @@ -6153,17 +2897,21 @@ static const struct alc_fixup alc269_fixups[] = { { } }, }, - [ALC269_FIXUP_MIC2_MUTE_LED] = { - .type = ALC_FIXUP_FUNC, - .v.func = alc269_fixup_mic2_mute, + [ALC269_FIXUP_HP_MUTE_LED] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc269_fixup_hp_mute_led, + }, + [ALC269_FIXUP_HP_MUTE_LED_MIC2] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc269_fixup_hp_mute_led_mic2, }, [ALC269_FIXUP_INV_DMIC] = { - .type = ALC_FIXUP_FUNC, + .type = HDA_FIXUP_FUNC, .v.func = alc_fixup_inv_dmic_0x12, }, [ALC269_FIXUP_LENOVO_DOCK] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x19, 0x23a11040 }, /* dock mic */ { 0x1b, 0x2121103f }, /* dock headphone */ { } @@ -6172,15 +2920,32 @@ static const struct alc_fixup alc269_fixups[] = { .chain_id = ALC269_FIXUP_PINCFG_NO_HP_TO_LINEOUT }, [ALC269_FIXUP_PINCFG_NO_HP_TO_LINEOUT] = { - .type = ALC_FIXUP_FUNC, + .type = HDA_FIXUP_FUNC, .v.func = alc269_fixup_pincfg_no_hp_to_lineout, }, + [ALC271_FIXUP_AMIC_MIC2] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x14, 0x99130110 }, /* speaker */ + { 0x19, 0x01a19c20 }, /* mic */ + { 0x1b, 0x99a7012f }, /* int-mic */ + { 0x21, 0x0121401f }, /* HP out */ + { } + }, + }, + [ALC271_FIXUP_HP_GATE_MIC_JACK] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc271_hp_gate_mic_jack, + .chained = true, + .chain_id = ALC271_FIXUP_AMIC_MIC2, + }, }; static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1025, 0x029b, "Acer 1810TZ", ALC269_FIXUP_INV_DMIC), SND_PCI_QUIRK(0x1025, 0x0349, "Acer AOD260", ALC269_FIXUP_INV_DMIC), - SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_MIC2_MUTE_LED), + SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2), + SND_PCI_QUIRK_VENDOR(0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED), SND_PCI_QUIRK(0x1043, 0x1427, "Asus Zenbook UX31E", ALC269VB_FIXUP_DMIC), SND_PCI_QUIRK(0x1043, 0x1517, "Asus Zenbook UX31A", ALC269VB_FIXUP_DMIC), SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW), @@ -6195,6 +2960,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x104d, 0x9084, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ), SND_PCI_QUIRK_VENDOR(0x104d, "Sony VAIO", ALC269_FIXUP_SONY_VAIO), SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z), + 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(0x10cf, 0x1475, "Lifebook", ALC269_FIXUP_LIFEBOOK), SND_PCI_QUIRK(0x17aa, 0x20f2, "Thinkpad SL410/510", ALC269_FIXUP_SKU_IGNORE), @@ -6261,7 +3028,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { {} }; -static const struct alc_model_fixup alc269_fixup_models[] = { +static const struct hda_model_fixup alc269_fixup_models[] = { {.id = ALC269_FIXUP_AMIC, .name = "laptop-amic"}, {.id = ALC269_FIXUP_DMIC, .name = "laptop-dmic"}, {.id = ALC269_FIXUP_STEREO_DMIC, .name = "alc269-dmic"}, @@ -6328,14 +3095,16 @@ static int patch_alc269(struct hda_codec *codec) return err; spec = codec->spec; + spec->gen.shared_mic_vref_pin = 0x18; - alc_pick_fixup(codec, alc269_fixup_models, + snd_hda_pick_fixup(codec, alc269_fixup_models, alc269_fixup_tbl, alc269_fixups); - alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); alc_auto_parse_customize_define(codec); - if (codec->vendor_id == 0x10ec0269) { + switch (codec->vendor_id) { + case 0x10ec0269: spec->codec_variant = ALC269_TYPE_ALC269VA; switch (alc_get_coef0(codec) & 0x00f0) { case 0x0010: @@ -6360,6 +3129,20 @@ static int patch_alc269(struct hda_codec *codec) goto error; spec->init_hook = alc269_fill_coef; alc269_fill_coef(codec); + break; + + case 0x10ec0280: + case 0x10ec0290: + spec->codec_variant = ALC269_TYPE_ALC280; + break; + case 0x10ec0282: + case 0x10ec0283: + spec->codec_variant = ALC269_TYPE_ALC282; + break; + case 0x10ec0284: + case 0x10ec0292: + spec->codec_variant = ALC269_TYPE_ALC284; + break; } /* automatic parse from the BIOS config */ @@ -6367,7 +3150,7 @@ static int patch_alc269(struct hda_codec *codec) if (err < 0) goto error; - if (!spec->no_analog && has_cdefine_beep(codec)) { + if (!spec->gen.no_analog && has_cdefine_beep(codec)) { err = snd_hda_attach_beep_device(codec, 0x1); if (err < 0) goto error; @@ -6380,7 +3163,7 @@ static int patch_alc269(struct hda_codec *codec) #endif spec->shutup = alc269_shutup; - alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); return 0; @@ -6410,49 +3193,48 @@ enum { /* On some laptops, VREF of pin 0x0f is abused for controlling the main amp */ static void alc861_fixup_asus_amp_vref_0f(struct hda_codec *codec, - const struct alc_fixup *fix, int action) + const struct hda_fixup *fix, int action) { struct alc_spec *spec = codec->spec; unsigned int val; - if (action != ALC_FIXUP_ACT_INIT) + if (action != HDA_FIXUP_ACT_INIT) return; - val = snd_hda_codec_read(codec, 0x0f, 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); + val = snd_hda_codec_get_pin_target(codec, 0x0f); if (!(val & (AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN))) val |= AC_PINCTL_IN_EN; val |= AC_PINCTL_VREF_50; snd_hda_set_pin_ctl(codec, 0x0f, val); - spec->keep_vref_in_automute = 1; + spec->gen.keep_vref_in_automute = 1; } /* suppress the jack-detection */ static void alc_fixup_no_jack_detect(struct hda_codec *codec, - const struct alc_fixup *fix, int action) + const struct hda_fixup *fix, int action) { - if (action == ALC_FIXUP_ACT_PRE_PROBE) + if (action == HDA_FIXUP_ACT_PRE_PROBE) codec->no_jack_detect = 1; } -static const struct alc_fixup alc861_fixups[] = { +static const struct hda_fixup alc861_fixups[] = { [ALC861_FIXUP_FSC_AMILO_PI1505] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x0b, 0x0221101f }, /* HP */ { 0x0f, 0x90170310 }, /* speaker */ { } } }, [ALC861_FIXUP_AMP_VREF_0F] = { - .type = ALC_FIXUP_FUNC, + .type = HDA_FIXUP_FUNC, .v.func = alc861_fixup_asus_amp_vref_0f, }, [ALC861_FIXUP_NO_JACK_DETECT] = { - .type = ALC_FIXUP_FUNC, + .type = HDA_FIXUP_FUNC, .v.func = alc_fixup_no_jack_detect, }, [ALC861_FIXUP_ASUS_A6RP] = { - .type = ALC_FIXUP_FUNC, + .type = HDA_FIXUP_FUNC, .v.func = alc861_fixup_asus_amp_vref_0f, .chained = true, .chain_id = ALC861_FIXUP_NO_JACK_DETECT, @@ -6482,15 +3264,15 @@ static int patch_alc861(struct hda_codec *codec) spec = codec->spec; - alc_pick_fixup(codec, NULL, alc861_fixup_tbl, alc861_fixups); - alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); + snd_hda_pick_fixup(codec, NULL, alc861_fixup_tbl, alc861_fixups); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); /* automatic parse from the BIOS config */ err = alc861_parse_auto_config(codec); if (err < 0) goto error; - if (!spec->no_analog) { + if (!spec->gen.no_analog) { err = snd_hda_attach_beep_device(codec, 0x23); if (err < 0) goto error; @@ -6502,7 +3284,7 @@ static int patch_alc861(struct hda_codec *codec) spec->power_hook = alc_power_eapd; #endif - alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); return 0; @@ -6532,17 +3314,17 @@ enum { /* exclude VREF80 */ static void alc861vd_fixup_dallas(struct hda_codec *codec, - const struct alc_fixup *fix, int action) + const struct hda_fixup *fix, int action) { - if (action == ALC_FIXUP_ACT_PRE_PROBE) { - snd_hda_override_pin_caps(codec, 0x18, 0x00001714); - snd_hda_override_pin_caps(codec, 0x19, 0x0000171c); + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + snd_hda_override_pin_caps(codec, 0x18, 0x00000734); + snd_hda_override_pin_caps(codec, 0x19, 0x0000073c); } } -static const struct alc_fixup alc861vd_fixups[] = { +static const struct hda_fixup alc861vd_fixups[] = { [ALC660VD_FIX_ASUS_GPIO1] = { - .type = ALC_FIXUP_VERBS, + .type = HDA_FIXUP_VERBS, .v.verbs = (const struct hda_verb[]) { /* reset GPIO1 */ {0x01, AC_VERB_SET_GPIO_MASK, 0x03}, @@ -6552,7 +3334,7 @@ static const struct alc_fixup alc861vd_fixups[] = { } }, [ALC861VD_FIX_DALLAS] = { - .type = ALC_FIXUP_FUNC, + .type = HDA_FIXUP_FUNC, .v.func = alc861vd_fixup_dallas, }, }; @@ -6577,15 +3359,15 @@ static int patch_alc861vd(struct hda_codec *codec) spec = codec->spec; - alc_pick_fixup(codec, NULL, alc861vd_fixup_tbl, alc861vd_fixups); - alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); + snd_hda_pick_fixup(codec, NULL, alc861vd_fixup_tbl, alc861vd_fixups); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); /* automatic parse from the BIOS config */ err = alc861vd_parse_auto_config(codec); if (err < 0) goto error; - if (!spec->no_analog) { + if (!spec->gen.no_analog) { err = snd_hda_attach_beep_device(codec, 0x23); if (err < 0) goto error; @@ -6596,7 +3378,7 @@ static int patch_alc861vd(struct hda_codec *codec) spec->shutup = alc_eapd_shutup; - alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); return 0; @@ -6637,9 +3419,9 @@ static int alc662_parse_auto_config(struct hda_codec *codec) } static void alc272_fixup_mario(struct hda_codec *codec, - const struct alc_fixup *fix, int action) + const struct hda_fixup *fix, int action) { - if (action != ALC_FIXUP_ACT_PROBE) + if (action != HDA_FIXUP_ACT_PRE_PROBE) return; if (snd_hda_override_amp_caps(codec, 0x2, HDA_OUTPUT, (0x3b << AC_AMPCAP_OFFSET_SHIFT) | @@ -6670,39 +3452,39 @@ enum { ALC662_FIXUP_INV_DMIC, }; -static const struct alc_fixup alc662_fixups[] = { +static const struct hda_fixup alc662_fixups[] = { [ALC662_FIXUP_ASPIRE] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x15, 0x99130112 }, /* subwoofer */ { } } }, [ALC662_FIXUP_IDEAPAD] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x17, 0x99130112 }, /* subwoofer */ { } } }, [ALC272_FIXUP_MARIO] = { - .type = ALC_FIXUP_FUNC, + .type = HDA_FIXUP_FUNC, .v.func = alc272_fixup_mario, }, [ALC662_FIXUP_CZC_P10T] = { - .type = ALC_FIXUP_VERBS, + .type = HDA_FIXUP_VERBS, .v.verbs = (const struct hda_verb[]) { {0x14, AC_VERB_SET_EAPD_BTLENABLE, 0}, {} } }, [ALC662_FIXUP_SKU_IGNORE] = { - .type = ALC_FIXUP_FUNC, + .type = HDA_FIXUP_FUNC, .v.func = alc_fixup_sku_ignore, }, [ALC662_FIXUP_HP_RP5800] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x14, 0x0221201f }, /* HP out */ { } }, @@ -6710,8 +3492,8 @@ static const struct alc_fixup alc662_fixups[] = { .chain_id = ALC662_FIXUP_SKU_IGNORE }, [ALC662_FIXUP_ASUS_MODE1] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x14, 0x99130110 }, /* speaker */ { 0x18, 0x01a19c20 }, /* mic */ { 0x19, 0x99a3092f }, /* int-mic */ @@ -6722,8 +3504,8 @@ static const struct alc_fixup alc662_fixups[] = { .chain_id = ALC662_FIXUP_SKU_IGNORE }, [ALC662_FIXUP_ASUS_MODE2] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x14, 0x99130110 }, /* speaker */ { 0x18, 0x01a19820 }, /* mic */ { 0x19, 0x99a3092f }, /* int-mic */ @@ -6734,8 +3516,8 @@ static const struct alc_fixup alc662_fixups[] = { .chain_id = ALC662_FIXUP_SKU_IGNORE }, [ALC662_FIXUP_ASUS_MODE3] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x14, 0x99130110 }, /* speaker */ { 0x15, 0x0121441f }, /* HP */ { 0x18, 0x01a19840 }, /* mic */ @@ -6747,8 +3529,8 @@ static const struct alc_fixup alc662_fixups[] = { .chain_id = ALC662_FIXUP_SKU_IGNORE }, [ALC662_FIXUP_ASUS_MODE4] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x14, 0x99130110 }, /* speaker */ { 0x16, 0x99130111 }, /* speaker */ { 0x18, 0x01a19840 }, /* mic */ @@ -6760,8 +3542,8 @@ static const struct alc_fixup alc662_fixups[] = { .chain_id = ALC662_FIXUP_SKU_IGNORE }, [ALC662_FIXUP_ASUS_MODE5] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x14, 0x99130110 }, /* speaker */ { 0x15, 0x0121441f }, /* HP */ { 0x16, 0x99130111 }, /* speaker */ @@ -6773,8 +3555,8 @@ static const struct alc_fixup alc662_fixups[] = { .chain_id = ALC662_FIXUP_SKU_IGNORE }, [ALC662_FIXUP_ASUS_MODE6] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x14, 0x99130110 }, /* speaker */ { 0x15, 0x01211420 }, /* HP2 */ { 0x18, 0x01a19840 }, /* mic */ @@ -6786,8 +3568,8 @@ static const struct alc_fixup alc662_fixups[] = { .chain_id = ALC662_FIXUP_SKU_IGNORE }, [ALC662_FIXUP_ASUS_MODE7] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x14, 0x99130110 }, /* speaker */ { 0x17, 0x99130111 }, /* speaker */ { 0x18, 0x01a19840 }, /* mic */ @@ -6800,8 +3582,8 @@ static const struct alc_fixup alc662_fixups[] = { .chain_id = ALC662_FIXUP_SKU_IGNORE }, [ALC662_FIXUP_ASUS_MODE8] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x14, 0x99130110 }, /* speaker */ { 0x12, 0x99a30970 }, /* int-mic */ { 0x15, 0x01214020 }, /* HP */ @@ -6814,18 +3596,18 @@ static const struct alc_fixup alc662_fixups[] = { .chain_id = ALC662_FIXUP_SKU_IGNORE }, [ALC662_FIXUP_NO_JACK_DETECT] = { - .type = ALC_FIXUP_FUNC, + .type = HDA_FIXUP_FUNC, .v.func = alc_fixup_no_jack_detect, }, [ALC662_FIXUP_ZOTAC_Z68] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x1b, 0x02214020 }, /* Front HP */ { } } }, [ALC662_FIXUP_INV_DMIC] = { - .type = ALC_FIXUP_FUNC, + .type = HDA_FIXUP_FUNC, .v.func = alc_fixup_inv_dmic_0x12, }, }; @@ -6905,7 +3687,7 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = { {} }; -static const struct alc_model_fixup alc662_fixup_models[] = { +static const struct hda_model_fixup alc662_fixup_models[] = { {.id = ALC272_FIXUP_MARIO, .name = "mario"}, {.id = ALC662_FIXUP_ASUS_MODE1, .name = "asus-mode1"}, {.id = ALC662_FIXUP_ASUS_MODE2, .name = "asus-mode2"}, @@ -6966,9 +3748,9 @@ static int patch_alc662(struct hda_codec *codec) spec->init_hook = alc662_fill_coef; alc662_fill_coef(codec); - alc_pick_fixup(codec, alc662_fixup_models, + snd_hda_pick_fixup(codec, alc662_fixup_models, alc662_fixup_tbl, alc662_fixups); - alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); alc_auto_parse_customize_define(codec); @@ -6984,7 +3766,7 @@ static int patch_alc662(struct hda_codec *codec) if (err < 0) goto error; - if (!spec->no_analog && has_cdefine_beep(codec)) { + if (!spec->gen.no_analog && has_cdefine_beep(codec)) { err = snd_hda_attach_beep_device(codec, 0x1); if (err < 0) goto error; @@ -7006,7 +3788,7 @@ static int patch_alc662(struct hda_codec *codec) codec->patch_ops = alc_patch_ops; spec->shutup = alc_eapd_shutup; - alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); return 0; @@ -7064,7 +3846,9 @@ static const struct hda_codec_preset snd_hda_preset_realtek[] = { { .id = 0x10ec0280, .name = "ALC280", .patch = patch_alc269 }, { .id = 0x10ec0282, .name = "ALC282", .patch = patch_alc269 }, { .id = 0x10ec0283, .name = "ALC283", .patch = patch_alc269 }, + { .id = 0x10ec0284, .name = "ALC284", .patch = patch_alc269 }, { .id = 0x10ec0290, .name = "ALC290", .patch = patch_alc269 }, + { .id = 0x10ec0292, .name = "ALC292", .patch = patch_alc269 }, { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660", .patch = patch_alc861 }, { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd }, diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 9ba8af056170..83d5335ac348 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -31,7 +31,6 @@ #include <linux/dmi.h> #include <linux/module.h> #include <sound/core.h> -#include <sound/asoundef.h> #include <sound/jack.h> #include <sound/tlv.h> #include "hda_codec.h" @@ -39,18 +38,14 @@ #include "hda_auto_parser.h" #include "hda_beep.h" #include "hda_jack.h" +#include "hda_generic.h" enum { - STAC_VREF_EVENT = 1, - STAC_INSERT_EVENT, + STAC_VREF_EVENT = 8, STAC_PWR_EVENT, - STAC_HP_EVENT, - STAC_LO_EVENT, - STAC_MIC_EVENT, }; enum { - STAC_AUTO, STAC_REF, STAC_9200_OQO, STAC_9200_DELL_D21, @@ -66,11 +61,11 @@ enum { STAC_9200_M4, STAC_9200_M4_2, STAC_9200_PANASONIC, + STAC_9200_EAPD_INIT, STAC_9200_MODELS }; enum { - STAC_9205_AUTO, STAC_9205_REF, STAC_9205_DELL_M42, STAC_9205_DELL_M43, @@ -80,7 +75,6 @@ enum { }; enum { - STAC_92HD73XX_AUTO, STAC_92HD73XX_NO_JD, /* no jack-detection */ STAC_92HD73XX_REF, STAC_92HD73XX_INTEL, @@ -93,7 +87,6 @@ enum { }; enum { - STAC_92HD83XXX_AUTO, STAC_92HD83XXX_REF, STAC_92HD83XXX_PWR_REF, STAC_DELL_S14, @@ -105,11 +98,12 @@ enum { STAC_92HD83XXX_HP_INV_LED, STAC_92HD83XXX_HP_MIC_LED, STAC_92HD83XXX_HEADSET_JACK, + STAC_92HD83XXX_HP, + STAC_HP_ENVY_BASS, STAC_92HD83XXX_MODELS }; enum { - STAC_92HD71BXX_AUTO, STAC_92HD71BXX_REF, STAC_DELL_M4_1, STAC_DELL_M4_2, @@ -118,12 +112,13 @@ enum { STAC_HP_DV4, STAC_HP_DV5, STAC_HP_HDX, - STAC_HP_DV4_1222NR, + STAC_92HD71BXX_HP, + STAC_92HD71BXX_NO_DMIC, + STAC_92HD71BXX_NO_SMUX, STAC_92HD71BXX_MODELS }; enum { - STAC_925x_AUTO, STAC_925x_REF, STAC_M1, STAC_M1_2, @@ -136,7 +131,6 @@ enum { }; enum { - STAC_922X_AUTO, STAC_D945_REF, STAC_D945GTP3, STAC_D945GTP5, @@ -145,67 +139,45 @@ enum { STAC_INTEL_MAC_V3, STAC_INTEL_MAC_V4, STAC_INTEL_MAC_V5, - STAC_INTEL_MAC_AUTO, /* This model is selected if no module parameter - * is given, one of the above models will be - * chosen according to the subsystem id. */ - /* for backward compatibility */ - STAC_MACMINI, - STAC_MACBOOK, - STAC_MACBOOK_PRO_V1, - STAC_MACBOOK_PRO_V2, - STAC_IMAC_INTEL, - STAC_IMAC_INTEL_20, + STAC_INTEL_MAC_AUTO, STAC_ECS_202, STAC_922X_DELL_D81, STAC_922X_DELL_D82, STAC_922X_DELL_M81, STAC_922X_DELL_M82, + STAC_922X_INTEL_MAC_GPIO, STAC_922X_MODELS }; enum { - STAC_927X_AUTO, STAC_D965_REF_NO_JD, /* no jack-detection */ STAC_D965_REF, STAC_D965_3ST, STAC_D965_5ST, STAC_D965_5ST_NO_FP, + STAC_D965_VERBS, STAC_DELL_3ST, STAC_DELL_BIOS, + STAC_DELL_BIOS_SPDIF, + STAC_927X_DELL_DMIC, STAC_927X_VOLKNOB, STAC_927X_MODELS }; enum { - STAC_9872_AUTO, STAC_9872_VAIO, STAC_9872_MODELS }; -struct sigmatel_mic_route { - hda_nid_t pin; - signed char mux_idx; - signed char dmux_idx; -}; - -#define MAX_PINS_NUM 16 -#define MAX_ADCS_NUM 4 -#define MAX_DMICS_NUM 4 - struct sigmatel_spec { - struct snd_kcontrol_new *mixers[4]; - unsigned int num_mixers; + struct hda_gen_spec gen; - int board_config; unsigned int eapd_switch: 1; - unsigned int surr_switch: 1; - unsigned int alt_switch: 1; - unsigned int hp_detect: 1; - unsigned int spdif_mute: 1; - unsigned int check_volume_offset:1; - unsigned int auto_mic:1; unsigned int linear_tone_beep:1; unsigned int headset_jack:1; /* 4-pin headset jack (hp + mono mic) */ + unsigned int volknob_init:1; /* special volume-knob initialization */ + unsigned int powerdown_adcs:1; + unsigned int have_spdif_mux:1; /* gpio lines */ unsigned int eapd_mask; @@ -217,6 +189,7 @@ struct sigmatel_spec { unsigned int gpio_led_polarity; unsigned int vref_mute_led_nid; /* pin NID for mute-LED vref control */ unsigned int vref_led; + int default_polarity; unsigned int mic_mute_led_gpio; /* capture mute LED GPIO */ bool mic_mute_led_on; /* current mic mute state */ @@ -226,6 +199,7 @@ struct sigmatel_spec { /* analog loopback */ const struct snd_kcontrol_new *aloopback_ctl; + unsigned int aloopback; unsigned char aloopback_mask; unsigned char aloopback_shift; @@ -233,647 +207,778 @@ struct sigmatel_spec { unsigned int power_map_bits; unsigned int num_pwrs; const hda_nid_t *pwr_nids; - const hda_nid_t *dac_list; - - /* playback */ - struct hda_input_mux *mono_mux; - unsigned int cur_mmux; - struct hda_multi_out multiout; - hda_nid_t dac_nids[5]; - hda_nid_t hp_dacs[5]; - hda_nid_t speaker_dacs[5]; - - int volume_offset; - - /* capture */ - const hda_nid_t *adc_nids; - unsigned int num_adcs; - const hda_nid_t *mux_nids; - unsigned int num_muxes; - const hda_nid_t *dmic_nids; - unsigned int num_dmics; - const hda_nid_t *dmux_nids; - unsigned int num_dmuxes; - const hda_nid_t *smux_nids; - unsigned int num_smuxes; - unsigned int num_analog_muxes; - - const unsigned long *capvols; /* amp-volume attr: HDA_COMPOSE_AMP_VAL() */ - const unsigned long *capsws; /* amp-mute attr: HDA_COMPOSE_AMP_VAL() */ - unsigned int num_caps; /* number of capture volume/switch elements */ - - struct sigmatel_mic_route ext_mic; - struct sigmatel_mic_route int_mic; - struct sigmatel_mic_route dock_mic; + unsigned int active_adcs; - const char * const *spdif_labels; - - hda_nid_t dig_in_nid; - hda_nid_t mono_nid; + /* beep widgets */ hda_nid_t anabeep_nid; hda_nid_t digbeep_nid; - /* pin widgets */ - const hda_nid_t *pin_nids; - unsigned int num_pins; - - /* codec specific stuff */ - const struct hda_verb *init; - const struct snd_kcontrol_new *mixer; - - /* capture source */ - struct hda_input_mux *dinput_mux; - unsigned int cur_dmux[2]; - struct hda_input_mux *input_mux; - unsigned int cur_mux[3]; - struct hda_input_mux *sinput_mux; + /* SPDIF-out mux */ + const char * const *spdif_labels; + struct hda_input_mux spdif_mux; unsigned int cur_smux[2]; - unsigned int cur_amux; - hda_nid_t *amp_nids; - unsigned int powerdown_adcs; - - /* i/o switches */ - unsigned int io_switch[2]; - unsigned int clfe_swap; - hda_nid_t line_switch; /* shared line-in for input and output */ - hda_nid_t mic_switch; /* shared mic-in for input and output */ - hda_nid_t hp_switch; /* NID of HP as line-out */ - unsigned int aloopback; - - struct hda_pcm pcm_rec[2]; /* PCM information */ - - /* dynamic controls and input_mux */ - struct auto_pin_cfg autocfg; - struct snd_array kctls; - struct hda_input_mux private_dimux; - struct hda_input_mux private_imux; - struct hda_input_mux private_smux; - struct hda_input_mux private_mono_mux; - - /* auto spec */ - unsigned auto_pin_cnt; - hda_nid_t auto_pin_nids[MAX_PINS_NUM]; - unsigned auto_adc_cnt; - hda_nid_t auto_adc_nids[MAX_ADCS_NUM]; - hda_nid_t auto_mux_nids[MAX_ADCS_NUM]; - hda_nid_t auto_dmux_nids[MAX_ADCS_NUM]; - unsigned long auto_capvols[MAX_ADCS_NUM]; - unsigned auto_dmic_cnt; - hda_nid_t auto_dmic_nids[MAX_DMICS_NUM]; - - struct hda_vmaster_mute_hook vmaster_mute; }; #define AC_VERB_IDT_SET_POWER_MAP 0x7ec #define AC_VERB_IDT_GET_POWER_MAP 0xfec -static const hda_nid_t stac9200_adc_nids[1] = { - 0x03, -}; - -static const hda_nid_t stac9200_mux_nids[1] = { - 0x0c, -}; - -static const hda_nid_t stac9200_dac_nids[1] = { - 0x02, -}; - static const hda_nid_t stac92hd73xx_pwr_nids[8] = { 0x0a, 0x0b, 0x0c, 0xd, 0x0e, 0x0f, 0x10, 0x11 }; -static const hda_nid_t stac92hd73xx_slave_dig_outs[2] = { - 0x26, 0, -}; - -static const hda_nid_t stac92hd73xx_adc_nids[2] = { - 0x1a, 0x1b -}; - -#define STAC92HD73XX_NUM_DMICS 2 -static const hda_nid_t stac92hd73xx_dmic_nids[STAC92HD73XX_NUM_DMICS + 1] = { - 0x13, 0x14, 0 -}; - -#define STAC92HD73_DAC_COUNT 5 - -static const hda_nid_t stac92hd73xx_mux_nids[2] = { - 0x20, 0x21, +static const hda_nid_t stac92hd83xxx_pwr_nids[7] = { + 0x0a, 0x0b, 0x0c, 0xd, 0x0e, + 0x0f, 0x10 }; -static const hda_nid_t stac92hd73xx_dmux_nids[2] = { - 0x20, 0x21, +static const hda_nid_t stac92hd71bxx_pwr_nids[3] = { + 0x0a, 0x0d, 0x0f }; -static const hda_nid_t stac92hd73xx_smux_nids[2] = { - 0x22, 0x23, -}; -#define STAC92HD73XX_NUM_CAPS 2 -static const unsigned long stac92hd73xx_capvols[] = { - HDA_COMPOSE_AMP_VAL(0x20, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT), -}; -#define stac92hd73xx_capsws stac92hd73xx_capvols +/* + * PCM hooks + */ +static void stac_playback_pcm_hook(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream, + int action) +{ + struct sigmatel_spec *spec = codec->spec; + if (action == HDA_GEN_PCM_ACT_OPEN && spec->stream_delay) + msleep(spec->stream_delay); +} -#define STAC92HD83_DAC_COUNT 3 +static void stac_capture_pcm_hook(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream, + int action) +{ + struct sigmatel_spec *spec = codec->spec; + int i, idx = 0; -static const hda_nid_t stac92hd83xxx_pwr_nids[7] = { - 0x0a, 0x0b, 0x0c, 0xd, 0x0e, - 0x0f, 0x10 -}; + if (!spec->powerdown_adcs) + return; -static const hda_nid_t stac92hd83xxx_slave_dig_outs[2] = { - 0x1e, 0, -}; + for (i = 0; i < spec->gen.num_all_adcs; i++) { + if (spec->gen.all_adcs[i] == hinfo->nid) { + idx = i; + break; + } + } -static const hda_nid_t stac92hd83xxx_dmic_nids[] = { - 0x11, 0x20, -}; + switch (action) { + case HDA_GEN_PCM_ACT_OPEN: + msleep(40); + snd_hda_codec_write(codec, hinfo->nid, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D0); + spec->active_adcs |= (1 << idx); + break; + case HDA_GEN_PCM_ACT_CLOSE: + snd_hda_codec_write(codec, hinfo->nid, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D3); + spec->active_adcs &= ~(1 << idx); + break; + } +} -static const hda_nid_t stac92hd71bxx_pwr_nids[3] = { - 0x0a, 0x0d, 0x0f -}; +/* + * Early 2006 Intel Macintoshes with STAC9220X5 codecs seem to have a + * funky external mute control using GPIO pins. + */ -static const hda_nid_t stac92hd71bxx_adc_nids[2] = { - 0x12, 0x13, -}; +static void stac_gpio_set(struct hda_codec *codec, unsigned int mask, + unsigned int dir_mask, unsigned int data) +{ + unsigned int gpiostate, gpiomask, gpiodir; -static const hda_nid_t stac92hd71bxx_mux_nids[2] = { - 0x1a, 0x1b -}; + snd_printdd("%s msk %x dir %x gpio %x\n", __func__, mask, dir_mask, data); -static const hda_nid_t stac92hd71bxx_dmux_nids[2] = { - 0x1c, 0x1d, -}; + gpiostate = snd_hda_codec_read(codec, codec->afg, 0, + AC_VERB_GET_GPIO_DATA, 0); + gpiostate = (gpiostate & ~dir_mask) | (data & dir_mask); -static const hda_nid_t stac92hd71bxx_smux_nids[2] = { - 0x24, 0x25, -}; + gpiomask = snd_hda_codec_read(codec, codec->afg, 0, + AC_VERB_GET_GPIO_MASK, 0); + gpiomask |= mask; -#define STAC92HD71BXX_NUM_DMICS 2 -static const hda_nid_t stac92hd71bxx_dmic_nids[STAC92HD71BXX_NUM_DMICS + 1] = { - 0x18, 0x19, 0 -}; + gpiodir = snd_hda_codec_read(codec, codec->afg, 0, + AC_VERB_GET_GPIO_DIRECTION, 0); + gpiodir |= dir_mask; -static const hda_nid_t stac92hd71bxx_dmic_5port_nids[STAC92HD71BXX_NUM_DMICS] = { - 0x18, 0 -}; + /* Configure GPIOx as CMOS */ + snd_hda_codec_write(codec, codec->afg, 0, 0x7e7, 0); -static const hda_nid_t stac92hd71bxx_slave_dig_outs[2] = { - 0x22, 0 -}; + snd_hda_codec_write(codec, codec->afg, 0, + AC_VERB_SET_GPIO_MASK, gpiomask); + snd_hda_codec_read(codec, codec->afg, 0, + AC_VERB_SET_GPIO_DIRECTION, gpiodir); /* sync */ -#define STAC92HD71BXX_NUM_CAPS 2 -static const unsigned long stac92hd71bxx_capvols[] = { - HDA_COMPOSE_AMP_VAL(0x1c, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x1d, 3, 0, HDA_OUTPUT), -}; -#define stac92hd71bxx_capsws stac92hd71bxx_capvols + msleep(1); -static const hda_nid_t stac925x_adc_nids[1] = { - 0x03, -}; + snd_hda_codec_read(codec, codec->afg, 0, + AC_VERB_SET_GPIO_DATA, gpiostate); /* sync */ +} -static const hda_nid_t stac925x_mux_nids[1] = { - 0x0f, -}; +/* hook for controlling mic-mute LED GPIO */ +static void stac_capture_led_hook(struct hda_codec *codec, + struct snd_ctl_elem_value *ucontrol) +{ + struct sigmatel_spec *spec = codec->spec; + bool mute; -static const hda_nid_t stac925x_dac_nids[1] = { - 0x02, -}; + if (!ucontrol) + return; -#define STAC925X_NUM_DMICS 1 -static const hda_nid_t stac925x_dmic_nids[STAC925X_NUM_DMICS + 1] = { - 0x15, 0 -}; + mute = !(ucontrol->value.integer.value[0] || + ucontrol->value.integer.value[1]); + if (spec->mic_mute_led_on != mute) { + spec->mic_mute_led_on = mute; + if (mute) + spec->gpio_data |= spec->mic_mute_led_gpio; + else + spec->gpio_data &= ~spec->mic_mute_led_gpio; + stac_gpio_set(codec, spec->gpio_mask, + spec->gpio_dir, spec->gpio_data); + } +} -static const hda_nid_t stac925x_dmux_nids[1] = { - 0x14, -}; +static int stac_vrefout_set(struct hda_codec *codec, + hda_nid_t nid, unsigned int new_vref) +{ + int error, pinctl; -static const unsigned long stac925x_capvols[] = { - HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_OUTPUT), -}; -static const unsigned long stac925x_capsws[] = { - HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), -}; + snd_printdd("%s, nid %x ctl %x\n", __func__, nid, new_vref); + pinctl = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_PIN_WIDGET_CONTROL, 0); -static const hda_nid_t stac922x_adc_nids[2] = { - 0x06, 0x07, -}; + if (pinctl < 0) + return pinctl; -static const hda_nid_t stac922x_mux_nids[2] = { - 0x12, 0x13, -}; + pinctl &= 0xff; + pinctl &= ~AC_PINCTL_VREFEN; + pinctl |= (new_vref & AC_PINCTL_VREFEN); -#define STAC922X_NUM_CAPS 2 -static const unsigned long stac922x_capvols[] = { - HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_INPUT), - HDA_COMPOSE_AMP_VAL(0x18, 3, 0, HDA_INPUT), -}; -#define stac922x_capsws stac922x_capvols + error = snd_hda_set_pin_ctl_cache(codec, nid, pinctl); + if (error < 0) + return error; -static const hda_nid_t stac927x_slave_dig_outs[2] = { - 0x1f, 0, -}; + return 1; +} -static const hda_nid_t stac927x_adc_nids[3] = { - 0x07, 0x08, 0x09 -}; +/* update mute-LED accoring to the master switch */ +static void stac_update_led_status(struct hda_codec *codec, int enabled) +{ + struct sigmatel_spec *spec = codec->spec; + int muted = !enabled; -static const hda_nid_t stac927x_mux_nids[3] = { - 0x15, 0x16, 0x17 -}; + if (!spec->gpio_led) + return; -static const hda_nid_t stac927x_smux_nids[1] = { - 0x21, -}; + /* LED state is inverted on these systems */ + if (spec->gpio_led_polarity) + muted = !muted; -static const hda_nid_t stac927x_dac_nids[6] = { - 0x02, 0x03, 0x04, 0x05, 0x06, 0 -}; + if (!spec->vref_mute_led_nid) { + if (muted) + spec->gpio_data |= spec->gpio_led; + else + spec->gpio_data &= ~spec->gpio_led; + stac_gpio_set(codec, spec->gpio_mask, + spec->gpio_dir, spec->gpio_data); + } else { + spec->vref_led = muted ? AC_PINCTL_VREF_50 : AC_PINCTL_VREF_GRD; + stac_vrefout_set(codec, spec->vref_mute_led_nid, + spec->vref_led); + } +} -static const hda_nid_t stac927x_dmux_nids[1] = { - 0x1b, -}; +/* vmaster hook to update mute LED */ +static void stac_vmaster_hook(void *private_data, int val) +{ + stac_update_led_status(private_data, val); +} -#define STAC927X_NUM_DMICS 2 -static const hda_nid_t stac927x_dmic_nids[STAC927X_NUM_DMICS + 1] = { - 0x13, 0x14, 0 -}; +/* automute hook to handle GPIO mute and EAPD updates */ +static void stac_update_outputs(struct hda_codec *codec) +{ + struct sigmatel_spec *spec = codec->spec; -#define STAC927X_NUM_CAPS 3 -static const unsigned long stac927x_capvols[] = { - HDA_COMPOSE_AMP_VAL(0x18, 3, 0, HDA_INPUT), - HDA_COMPOSE_AMP_VAL(0x19, 3, 0, HDA_INPUT), - HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_INPUT), -}; -static const unsigned long stac927x_capsws[] = { - HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x1c, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x1d, 3, 0, HDA_OUTPUT), -}; + if (spec->gpio_mute) + spec->gen.master_mute = + !(snd_hda_codec_read(codec, codec->afg, 0, + AC_VERB_GET_GPIO_DATA, 0) & spec->gpio_mute); -static const char * const stac927x_spdif_labels[5] = { - "Digital Playback", "ADAT", "Analog Mux 1", - "Analog Mux 2", "Analog Mux 3" -}; + snd_hda_gen_update_outputs(codec); -static const hda_nid_t stac9205_adc_nids[2] = { - 0x12, 0x13 -}; + if (spec->eapd_mask && spec->eapd_switch) { + unsigned int val = spec->gpio_data; + if (spec->gen.speaker_muted) + val &= ~spec->eapd_mask; + else + val |= spec->eapd_mask; + if (spec->gpio_data != val) + stac_gpio_set(codec, spec->gpio_mask, spec->gpio_dir, + val); + } +} -static const hda_nid_t stac9205_mux_nids[2] = { - 0x19, 0x1a -}; +static void stac_toggle_power_map(struct hda_codec *codec, hda_nid_t nid, + bool enable, bool do_write) +{ + struct sigmatel_spec *spec = codec->spec; + unsigned int idx, val; -static const hda_nid_t stac9205_dmux_nids[1] = { - 0x1d, -}; + for (idx = 0; idx < spec->num_pwrs; idx++) { + if (spec->pwr_nids[idx] == nid) + break; + } + if (idx >= spec->num_pwrs) + return; -static const hda_nid_t stac9205_smux_nids[1] = { - 0x21, -}; + idx = 1 << idx; -#define STAC9205_NUM_DMICS 2 -static const hda_nid_t stac9205_dmic_nids[STAC9205_NUM_DMICS + 1] = { - 0x17, 0x18, 0 -}; + val = spec->power_map_bits; + if (enable) + val &= ~idx; + else + val |= idx; -#define STAC9205_NUM_CAPS 2 -static const unsigned long stac9205_capvols[] = { - HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_INPUT), - HDA_COMPOSE_AMP_VAL(0x1c, 3, 0, HDA_INPUT), -}; -static const unsigned long stac9205_capsws[] = { - HDA_COMPOSE_AMP_VAL(0x1d, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x1e, 3, 0, HDA_OUTPUT), -}; + /* power down unused output ports */ + if (val != spec->power_map_bits) { + spec->power_map_bits = val; + if (do_write) + snd_hda_codec_write(codec, codec->afg, 0, + AC_VERB_IDT_SET_POWER_MAP, val); + } +} -static const hda_nid_t stac9200_pin_nids[8] = { - 0x08, 0x09, 0x0d, 0x0e, - 0x0f, 0x10, 0x11, 0x12, -}; +/* update power bit per jack plug/unplug */ +static void jack_update_power(struct hda_codec *codec, + struct hda_jack_tbl *jack) +{ + struct sigmatel_spec *spec = codec->spec; + int i; -static const hda_nid_t stac925x_pin_nids[8] = { - 0x07, 0x08, 0x0a, 0x0b, - 0x0c, 0x0d, 0x10, 0x11, -}; + if (!spec->num_pwrs) + return; -static const hda_nid_t stac922x_pin_nids[10] = { - 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, - 0x0f, 0x10, 0x11, 0x15, 0x1b, -}; + if (jack && jack->nid) { + stac_toggle_power_map(codec, jack->nid, + snd_hda_jack_detect(codec, jack->nid), + true); + return; + } -static const hda_nid_t stac92hd73xx_pin_nids[13] = { - 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, - 0x0f, 0x10, 0x11, 0x12, 0x13, - 0x14, 0x22, 0x23 -}; + /* update all jacks */ + for (i = 0; i < spec->num_pwrs; i++) { + hda_nid_t nid = spec->pwr_nids[i]; + jack = snd_hda_jack_tbl_get(codec, nid); + if (!jack || !jack->action) + continue; + if (jack->action == STAC_PWR_EVENT || + jack->action <= HDA_GEN_LAST_EVENT) + stac_toggle_power_map(codec, nid, + snd_hda_jack_detect(codec, nid), + false); + } -#define STAC92HD71BXX_NUM_PINS 13 -static const hda_nid_t stac92hd71bxx_pin_nids_4port[STAC92HD71BXX_NUM_PINS] = { - 0x0a, 0x0b, 0x0c, 0x0d, 0x00, - 0x00, 0x14, 0x18, 0x19, 0x1e, - 0x1f, 0x20, 0x27 -}; -static const hda_nid_t stac92hd71bxx_pin_nids_6port[STAC92HD71BXX_NUM_PINS] = { - 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, - 0x0f, 0x14, 0x18, 0x19, 0x1e, - 0x1f, 0x20, 0x27 -}; + snd_hda_codec_write(codec, codec->afg, 0, AC_VERB_IDT_SET_POWER_MAP, + spec->power_map_bits); +} -static const hda_nid_t stac927x_pin_nids[14] = { - 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, - 0x0f, 0x10, 0x11, 0x12, 0x13, - 0x14, 0x21, 0x22, 0x23, -}; +static void stac_hp_automute(struct hda_codec *codec, + struct hda_jack_tbl *jack) +{ + snd_hda_gen_hp_automute(codec, jack); + jack_update_power(codec, jack); +} -static const hda_nid_t stac9205_pin_nids[12] = { - 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, - 0x0f, 0x14, 0x16, 0x17, 0x18, - 0x21, 0x22, -}; +static void stac_line_automute(struct hda_codec *codec, + struct hda_jack_tbl *jack) +{ + snd_hda_gen_line_automute(codec, jack); + jack_update_power(codec, jack); +} -static int stac92xx_dmux_enum_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) +static void stac_mic_autoswitch(struct hda_codec *codec, + struct hda_jack_tbl *jack) { - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct sigmatel_spec *spec = codec->spec; - return snd_hda_input_mux_info(spec->dinput_mux, uinfo); + snd_hda_gen_mic_autoswitch(codec, jack); + jack_update_power(codec, jack); } -static int stac92xx_dmux_enum_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static void stac_vref_event(struct hda_codec *codec, struct hda_jack_tbl *event) { - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct sigmatel_spec *spec = codec->spec; - unsigned int dmux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); + unsigned int data; - ucontrol->value.enumerated.item[0] = spec->cur_dmux[dmux_idx]; - return 0; + data = snd_hda_codec_read(codec, codec->afg, 0, + AC_VERB_GET_GPIO_DATA, 0); + /* toggle VREF state based on GPIOx status */ + snd_hda_codec_write(codec, codec->afg, 0, 0x7e0, + !!(data & (1 << event->private_data))); } -static int stac92xx_dmux_enum_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +/* initialize the power map and enable the power event to jacks that + * haven't been assigned to automute + */ +static void stac_init_power_map(struct hda_codec *codec) { - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct sigmatel_spec *spec = codec->spec; - unsigned int dmux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); + int i; - return snd_hda_input_mux_put(codec, spec->dinput_mux, ucontrol, - spec->dmux_nids[dmux_idx], &spec->cur_dmux[dmux_idx]); + for (i = 0; i < spec->num_pwrs; i++) { + hda_nid_t nid = spec->pwr_nids[i]; + unsigned int def_conf = snd_hda_codec_get_pincfg(codec, nid); + def_conf = get_defcfg_connect(def_conf); + 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))) { + snd_hda_jack_detect_enable_callback(codec, nid, + STAC_PWR_EVENT, + jack_update_power); + } else { + if (def_conf == AC_JACK_PORT_NONE) + stac_toggle_power_map(codec, nid, false, false); + else + stac_toggle_power_map(codec, nid, true, false); + } + } } -static int stac92xx_smux_enum_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) +/* + */ + +static inline bool get_int_hint(struct hda_codec *codec, const char *key, + int *valp) { - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct sigmatel_spec *spec = codec->spec; - return snd_hda_input_mux_info(spec->sinput_mux, uinfo); + return !snd_hda_get_int_hint(codec, key, valp); } -static int stac92xx_smux_enum_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +/* override some hints from the hwdep entry */ +static void stac_store_hints(struct hda_codec *codec) { - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct sigmatel_spec *spec = codec->spec; - unsigned int smux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); + int val; - ucontrol->value.enumerated.item[0] = spec->cur_smux[smux_idx]; - return 0; + if (get_int_hint(codec, "gpio_mask", &spec->gpio_mask)) { + spec->eapd_mask = spec->gpio_dir = spec->gpio_data = + spec->gpio_mask; + } + if (get_int_hint(codec, "gpio_dir", &spec->gpio_dir)) + spec->gpio_mask &= spec->gpio_mask; + if (get_int_hint(codec, "gpio_data", &spec->gpio_data)) + spec->gpio_dir &= spec->gpio_mask; + if (get_int_hint(codec, "eapd_mask", &spec->eapd_mask)) + spec->eapd_mask &= spec->gpio_mask; + if (get_int_hint(codec, "gpio_mute", &spec->gpio_mute)) + spec->gpio_mute &= spec->gpio_mask; + val = snd_hda_get_bool_hint(codec, "eapd_switch"); + if (val >= 0) + spec->eapd_switch = val; } -static int stac92xx_smux_enum_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +/* + * loopback controls + */ + +#define stac_aloopback_info snd_ctl_boolean_mono_info + +static int stac_aloopback_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); struct sigmatel_spec *spec = codec->spec; - struct hda_input_mux *smux = &spec->private_smux; - unsigned int smux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - int err, val; - hda_nid_t nid; - - err = snd_hda_input_mux_put(codec, spec->sinput_mux, ucontrol, - spec->smux_nids[smux_idx], &spec->cur_smux[smux_idx]); - if (err < 0) - return err; - if (spec->spdif_mute) { - if (smux_idx == 0) - nid = spec->multiout.dig_out_nid; - else - nid = codec->slave_dig_outs[smux_idx - 1]; - if (spec->cur_smux[smux_idx] == smux->num_items - 1) - val = HDA_AMP_MUTE; - else - val = 0; - /* un/mute SPDIF out */ - snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, - HDA_AMP_MUTE, val); - } + ucontrol->value.integer.value[0] = !!(spec->aloopback & + (spec->aloopback_mask << idx)); return 0; } -static int stac_vrefout_set(struct hda_codec *codec, - hda_nid_t nid, unsigned int new_vref) +static int stac_aloopback_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - int error, pinctl; + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct sigmatel_spec *spec = codec->spec; + unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); + unsigned int dac_mode; + unsigned int val, idx_val; - snd_printdd("%s, nid %x ctl %x\n", __func__, nid, new_vref); - pinctl = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); + idx_val = spec->aloopback_mask << idx; + if (ucontrol->value.integer.value[0]) + val = spec->aloopback | idx_val; + else + val = spec->aloopback & ~idx_val; + if (spec->aloopback == val) + return 0; - if (pinctl < 0) - return pinctl; + spec->aloopback = val; - pinctl &= 0xff; - pinctl &= ~AC_PINCTL_VREFEN; - pinctl |= (new_vref & AC_PINCTL_VREFEN); + /* Only return the bits defined by the shift value of the + * first two bytes of the mask + */ + dac_mode = snd_hda_codec_read(codec, codec->afg, 0, + kcontrol->private_value & 0xFFFF, 0x0); + dac_mode >>= spec->aloopback_shift; - error = snd_hda_set_pin_ctl_cache(codec, nid, pinctl); - if (error < 0) - return error; + if (spec->aloopback & idx_val) { + snd_hda_power_up(codec); + dac_mode |= idx_val; + } else { + snd_hda_power_down(codec); + dac_mode &= ~idx_val; + } + + snd_hda_codec_write_cache(codec, codec->afg, 0, + kcontrol->private_value >> 16, dac_mode); return 1; } -static unsigned int stac92xx_vref_set(struct hda_codec *codec, - hda_nid_t nid, unsigned int new_vref) +#define STAC_ANALOG_LOOPBACK(verb_read, verb_write, cnt) \ + { \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = "Analog Loopback", \ + .count = cnt, \ + .info = stac_aloopback_info, \ + .get = stac_aloopback_get, \ + .put = stac_aloopback_put, \ + .private_value = verb_read | (verb_write << 16), \ + } + +/* + * Mute LED handling on HP laptops + */ + +/* check whether it's a HP laptop with a docking port */ +static bool hp_bnb2011_with_dock(struct hda_codec *codec) { - int error; - unsigned int pincfg; - pincfg = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); + if (codec->vendor_id != 0x111d7605 && + codec->vendor_id != 0x111d76d1) + return false; + + switch (codec->subsystem_id) { + case 0x103c1618: + case 0x103c1619: + case 0x103c161a: + case 0x103c161b: + case 0x103c161c: + case 0x103c161d: + case 0x103c161e: + case 0x103c161f: - pincfg &= 0xff; - pincfg &= ~(AC_PINCTL_VREFEN | AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN); - pincfg |= new_vref; + case 0x103c162a: + case 0x103c162b: - if (new_vref == AC_PINCTL_VREF_HIZ) - pincfg |= AC_PINCTL_OUT_EN; - else - pincfg |= AC_PINCTL_IN_EN; + case 0x103c1630: + case 0x103c1631: - error = snd_hda_set_pin_ctl_cache(codec, nid, pincfg); - if (error < 0) - return error; - else - return 1; + case 0x103c1633: + case 0x103c1634: + case 0x103c1635: + + case 0x103c3587: + case 0x103c3588: + case 0x103c3589: + case 0x103c358a: + + case 0x103c3667: + case 0x103c3668: + case 0x103c3669: + + return true; + } + return false; } -static unsigned int stac92xx_vref_get(struct hda_codec *codec, hda_nid_t nid) +static bool hp_blike_system(u32 subsystem_id) { - unsigned int vref; - vref = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); - vref &= AC_PINCTL_VREFEN; - return vref; + switch (subsystem_id) { + case 0x103c1520: + case 0x103c1521: + case 0x103c1523: + case 0x103c1524: + case 0x103c1525: + case 0x103c1722: + case 0x103c1723: + case 0x103c1724: + case 0x103c1725: + case 0x103c1726: + case 0x103c1727: + case 0x103c1728: + case 0x103c1729: + case 0x103c172a: + case 0x103c172b: + case 0x103c307e: + case 0x103c307f: + case 0x103c3080: + case 0x103c3081: + case 0x103c7007: + case 0x103c7008: + return true; + } + return false; } -static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) +static void set_hp_led_gpio(struct hda_codec *codec) { - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct sigmatel_spec *spec = codec->spec; - return snd_hda_input_mux_info(spec->input_mux, uinfo); + unsigned int gpio; + + if (spec->gpio_led) + return; + + gpio = snd_hda_param_read(codec, codec->afg, AC_PAR_GPIO_CAP); + gpio &= AC_GPIO_IO_COUNT; + if (gpio > 3) + spec->gpio_led = 0x08; /* GPIO 3 */ + else + spec->gpio_led = 0x01; /* GPIO 0 */ } -static int stac92xx_mux_enum_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +/* + * This method searches for the mute LED GPIO configuration + * provided as OEM string in SMBIOS. The format of that string + * is HP_Mute_LED_P_G or HP_Mute_LED_P + * where P can be 0 or 1 and defines mute LED GPIO control state (low/high) + * that corresponds to the NOT muted state of the master volume + * and G is the index of the GPIO to use as the mute LED control (0..9) + * If _G portion is missing it is assigned based on the codec ID + * + * So, HP B-series like systems may have HP_Mute_LED_0 (current models) + * or HP_Mute_LED_0_3 (future models) OEM SMBIOS strings + * + * + * The dv-series laptops don't seem to have the HP_Mute_LED* strings in + * SMBIOS - at least the ones I have seen do not have them - which include + * my own system (HP Pavilion dv6-1110ax) and my cousin's + * HP Pavilion dv9500t CTO. + * Need more information on whether it is true across the entire series. + * -- kunal + */ +static int find_mute_led_cfg(struct hda_codec *codec, int default_polarity) { - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct sigmatel_spec *spec = codec->spec; - unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); + const struct dmi_device *dev = NULL; - ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx]; + if (get_int_hint(codec, "gpio_led", &spec->gpio_led)) { + get_int_hint(codec, "gpio_led_polarity", + &spec->gpio_led_polarity); + return 1; + } + + while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, NULL, dev))) { + if (sscanf(dev->name, "HP_Mute_LED_%d_%x", + &spec->gpio_led_polarity, + &spec->gpio_led) == 2) { + unsigned int max_gpio; + max_gpio = snd_hda_param_read(codec, codec->afg, + AC_PAR_GPIO_CAP); + max_gpio &= AC_GPIO_IO_COUNT; + if (spec->gpio_led < max_gpio) + spec->gpio_led = 1 << spec->gpio_led; + else + spec->vref_mute_led_nid = spec->gpio_led; + return 1; + } + if (sscanf(dev->name, "HP_Mute_LED_%d", + &spec->gpio_led_polarity) == 1) { + set_hp_led_gpio(codec); + return 1; + } + /* BIOS bug: unfilled OEM string */ + if (strstr(dev->name, "HP_Mute_LED_P_G")) { + set_hp_led_gpio(codec); + if (default_polarity >= 0) + spec->gpio_led_polarity = default_polarity; + else + spec->gpio_led_polarity = 1; + return 1; + } + } + + /* + * Fallback case - if we don't find the DMI strings, + * we statically set the GPIO - if not a B-series system + * and default polarity is provided + */ + if (!hp_blike_system(codec->subsystem_id) && + (default_polarity == 0 || default_polarity == 1)) { + set_hp_led_gpio(codec); + spec->gpio_led_polarity = default_polarity; + return 1; + } return 0; } -static int stac92xx_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +/* + * PC beep controls + */ + +/* create PC beep volume controls */ +static int stac_auto_create_beep_ctls(struct hda_codec *codec, + hda_nid_t nid) { - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct sigmatel_spec *spec = codec->spec; - unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - const struct hda_input_mux *imux = spec->input_mux; - unsigned int idx, prev_idx, didx; - - idx = ucontrol->value.enumerated.item[0]; - if (idx >= imux->num_items) - idx = imux->num_items - 1; - prev_idx = spec->cur_mux[adc_idx]; - if (prev_idx == idx) - return 0; - if (idx < spec->num_analog_muxes) { - snd_hda_codec_write_cache(codec, spec->mux_nids[adc_idx], 0, - AC_VERB_SET_CONNECT_SEL, - imux->items[idx].index); - if (prev_idx >= spec->num_analog_muxes && - spec->mux_nids[adc_idx] != spec->dmux_nids[adc_idx]) { - imux = spec->dinput_mux; - /* 0 = analog */ - snd_hda_codec_write_cache(codec, - spec->dmux_nids[adc_idx], 0, - AC_VERB_SET_CONNECT_SEL, - imux->items[0].index); - } - } else { - imux = spec->dinput_mux; - /* first dimux item is hardcoded to select analog imux, - * so lets skip it - */ - didx = idx - spec->num_analog_muxes + 1; - snd_hda_codec_write_cache(codec, spec->dmux_nids[adc_idx], 0, - AC_VERB_SET_CONNECT_SEL, - imux->items[didx].index); + u32 caps = query_amp_caps(codec, nid, HDA_OUTPUT); + struct snd_kcontrol_new *knew; + static struct snd_kcontrol_new abeep_mute_ctl = + HDA_CODEC_MUTE(NULL, 0, 0, 0); + static struct snd_kcontrol_new dbeep_mute_ctl = + HDA_CODEC_MUTE_BEEP(NULL, 0, 0, 0); + static struct snd_kcontrol_new beep_vol_ctl = + HDA_CODEC_VOLUME(NULL, 0, 0, 0); + + /* check for mute support for the the amp */ + if ((caps & AC_AMPCAP_MUTE) >> AC_AMPCAP_MUTE_SHIFT) { + const struct snd_kcontrol_new *temp; + if (spec->anabeep_nid == nid) + temp = &abeep_mute_ctl; + else + temp = &dbeep_mute_ctl; + knew = snd_hda_gen_add_kctl(&spec->gen, + "Beep Playback Switch", temp); + if (!knew) + return -ENOMEM; + knew->private_value = + HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT); } - spec->cur_mux[adc_idx] = idx; - return 1; + + /* check to see if there is volume support for the amp */ + if ((caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT) { + knew = snd_hda_gen_add_kctl(&spec->gen, + "Beep Playback Volume", + &beep_vol_ctl); + if (!knew) + return -ENOMEM; + knew->private_value = + HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT); + } + return 0; } -static int stac92xx_mono_mux_enum_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) +#ifdef CONFIG_SND_HDA_INPUT_BEEP +#define stac_dig_beep_switch_info snd_ctl_boolean_mono_info + +static int stac_dig_beep_switch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct sigmatel_spec *spec = codec->spec; - return snd_hda_input_mux_info(spec->mono_mux, uinfo); + ucontrol->value.integer.value[0] = codec->beep->enabled; + return 0; } -static int stac92xx_mono_mux_enum_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int stac_dig_beep_switch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + return snd_hda_enable_beep_device(codec, ucontrol->value.integer.value[0]); +} + +static const struct snd_kcontrol_new stac_dig_beep_ctrl = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Beep Playback Switch", + .info = stac_dig_beep_switch_info, + .get = stac_dig_beep_switch_get, + .put = stac_dig_beep_switch_put, +}; + +static int stac_beep_switch_ctl(struct hda_codec *codec) +{ struct sigmatel_spec *spec = codec->spec; - ucontrol->value.enumerated.item[0] = spec->cur_mmux; + if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &stac_dig_beep_ctrl)) + return -ENOMEM; return 0; } +#endif -static int stac92xx_mono_mux_enum_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +/* + * SPDIF-out mux controls + */ + +static int stac_smux_enum_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct sigmatel_spec *spec = codec->spec; - - return snd_hda_input_mux_put(codec, spec->mono_mux, ucontrol, - spec->mono_nid, &spec->cur_mmux); + return snd_hda_input_mux_info(&spec->spdif_mux, uinfo); } -#define stac92xx_aloopback_info snd_ctl_boolean_mono_info - -static int stac92xx_aloopback_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int stac_smux_enum_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); struct sigmatel_spec *spec = codec->spec; + unsigned int smux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - ucontrol->value.integer.value[0] = !!(spec->aloopback & - (spec->aloopback_mask << idx)); + ucontrol->value.enumerated.item[0] = spec->cur_smux[smux_idx]; return 0; } -static int stac92xx_aloopback_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int stac_smux_enum_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct sigmatel_spec *spec = codec->spec; - unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - unsigned int dac_mode; - unsigned int val, idx_val; + unsigned int smux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - idx_val = spec->aloopback_mask << idx; - if (ucontrol->value.integer.value[0]) - val = spec->aloopback | idx_val; - else - val = spec->aloopback & ~idx_val; - if (spec->aloopback == val) - return 0; + return snd_hda_input_mux_put(codec, &spec->spdif_mux, ucontrol, + spec->gen.autocfg.dig_out_pins[smux_idx], + &spec->cur_smux[smux_idx]); +} - spec->aloopback = val; +static struct snd_kcontrol_new stac_smux_mixer = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "IEC958 Playback Source", + /* count set later */ + .info = stac_smux_enum_info, + .get = stac_smux_enum_get, + .put = stac_smux_enum_put, +}; - /* Only return the bits defined by the shift value of the - * first two bytes of the mask - */ - dac_mode = snd_hda_codec_read(codec, codec->afg, 0, - kcontrol->private_value & 0xFFFF, 0x0); - dac_mode >>= spec->aloopback_shift; +static const char * const stac_spdif_labels[] = { + "Digital Playback", "Analog Mux 1", "Analog Mux 2", NULL +}; - if (spec->aloopback & idx_val) { - snd_hda_power_up(codec); - dac_mode |= idx_val; - } else { - snd_hda_power_down(codec); - dac_mode &= ~idx_val; +static int stac_create_spdif_mux_ctls(struct hda_codec *codec) +{ + struct sigmatel_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->gen.autocfg; + const char * const *labels = spec->spdif_labels; + struct snd_kcontrol_new *kctl; + int i, num_cons; + + if (cfg->dig_outs < 1) + return 0; + + num_cons = snd_hda_get_num_conns(codec, cfg->dig_out_pins[0]); + if (num_cons <= 1) + return 0; + + if (!labels) + labels = stac_spdif_labels; + 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_codec_write_cache(codec, codec->afg, 0, - kcontrol->private_value >> 16, dac_mode); + kctl = snd_hda_gen_add_kctl(&spec->gen, NULL, &stac_smux_mixer); + if (!kctl) + return -ENOMEM; + kctl->count = cfg->dig_outs; - return 1; + return 0; } +/* + */ + static const struct hda_verb stac9200_core_init[] = { /* set dac0mux for dac converter */ { 0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, @@ -936,17 +1041,15 @@ static const struct hda_verb stac925x_core_init[] = { }; static const struct hda_verb stac922x_core_init[] = { - /* set master volume and direct control */ + /* set master volume and direct control */ { 0x16, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, {} }; static const struct hda_verb d965_core_init[] = { - /* set master volume and direct control */ - { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, /* unmute node 0x1b */ { 0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - /* select node 0x03 as DAC */ + /* select node 0x03 as DAC */ { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x01}, {} }; @@ -962,7 +1065,7 @@ static const struct hda_verb dell_3st_core_init[] = { }; static const struct hda_verb stac927x_core_init[] = { - /* set master volume and direct control */ + /* set master volume and direct control */ { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, /* enable analog pc beep path */ { 0x01, AC_VERB_SET_DIGI_CONVERT_2, 1 << 5}, @@ -978,260 +1081,103 @@ static const struct hda_verb stac927x_volknob_core_init[] = { }; static const struct hda_verb stac9205_core_init[] = { - /* set master volume and direct control */ + /* set master volume and direct control */ { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, /* enable analog pc beep path */ { 0x01, AC_VERB_SET_DIGI_CONVERT_2, 1 << 5}, {} }; -#define STAC_MONO_MUX \ - { \ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = "Mono Mux", \ - .count = 1, \ - .info = stac92xx_mono_mux_enum_info, \ - .get = stac92xx_mono_mux_enum_get, \ - .put = stac92xx_mono_mux_enum_put, \ - } +static const struct snd_kcontrol_new stac92hd73xx_6ch_loopback = + STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 3); -#define STAC_ANALOG_LOOPBACK(verb_read, verb_write, cnt) \ - { \ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = "Analog Loopback", \ - .count = cnt, \ - .info = stac92xx_aloopback_info, \ - .get = stac92xx_aloopback_get, \ - .put = stac92xx_aloopback_put, \ - .private_value = verb_read | (verb_write << 16), \ - } +static const struct snd_kcontrol_new stac92hd73xx_8ch_loopback = + STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 4); -#define DC_BIAS(xname, idx, nid) \ - { \ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = xname, \ - .index = idx, \ - .info = stac92xx_dc_bias_info, \ - .get = stac92xx_dc_bias_get, \ - .put = stac92xx_dc_bias_put, \ - .private_value = nid, \ - } +static const struct snd_kcontrol_new stac92hd73xx_10ch_loopback = + STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 5); -static const struct snd_kcontrol_new stac9200_mixer[] = { - HDA_CODEC_VOLUME_MIN_MUTE("PCM Playback Volume", 0xb, 0, HDA_OUTPUT), - HDA_CODEC_MUTE("PCM Playback Switch", 0xb, 0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x0a, 0, HDA_OUTPUT), - HDA_CODEC_MUTE("Capture Switch", 0x0a, 0, HDA_OUTPUT), - { } /* end */ -}; +static const struct snd_kcontrol_new stac92hd71bxx_loopback = + STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2); -static const struct snd_kcontrol_new stac92hd73xx_6ch_loopback[] = { - STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 3), - {} -}; +static const struct snd_kcontrol_new stac9205_loopback = + STAC_ANALOG_LOOPBACK(0xFE0, 0x7E0, 1); -static const struct snd_kcontrol_new stac92hd73xx_8ch_loopback[] = { - STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 4), - {} -}; +static const struct snd_kcontrol_new stac927x_loopback = + STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB, 1); -static const struct snd_kcontrol_new stac92hd73xx_10ch_loopback[] = { - STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 5), +static const struct hda_pintbl ref9200_pin_configs[] = { + { 0x08, 0x01c47010 }, + { 0x09, 0x01447010 }, + { 0x0d, 0x0221401f }, + { 0x0e, 0x01114010 }, + { 0x0f, 0x02a19020 }, + { 0x10, 0x01a19021 }, + { 0x11, 0x90100140 }, + { 0x12, 0x01813122 }, {} }; - -static const struct snd_kcontrol_new stac92hd71bxx_loopback[] = { - STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2) -}; - -static const struct snd_kcontrol_new stac925x_mixer[] = { - HDA_CODEC_VOLUME_MIN_MUTE("PCM Playback Volume", 0xe, 0, HDA_OUTPUT), - HDA_CODEC_MUTE("PCM Playback Switch", 0x0e, 0, HDA_OUTPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new stac9205_loopback[] = { - STAC_ANALOG_LOOPBACK(0xFE0, 0x7E0, 1), +static const struct hda_pintbl gateway9200_m4_pin_configs[] = { + { 0x08, 0x400000fe }, + { 0x09, 0x404500f4 }, + { 0x0d, 0x400100f0 }, + { 0x0e, 0x90110010 }, + { 0x0f, 0x400100f1 }, + { 0x10, 0x02a1902e }, + { 0x11, 0x500000f2 }, + { 0x12, 0x500000f3 }, {} }; -static const struct snd_kcontrol_new stac927x_loopback[] = { - STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB, 1), +static const struct hda_pintbl gateway9200_m4_2_pin_configs[] = { + { 0x08, 0x400000fe }, + { 0x09, 0x404500f4 }, + { 0x0d, 0x400100f0 }, + { 0x0e, 0x90110010 }, + { 0x0f, 0x400100f1 }, + { 0x10, 0x02a1902e }, + { 0x11, 0x500000f2 }, + { 0x12, 0x500000f3 }, {} }; -static struct snd_kcontrol_new stac_dmux_mixer = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Digital Input Source", - /* count set later */ - .info = stac92xx_dmux_enum_info, - .get = stac92xx_dmux_enum_get, - .put = stac92xx_dmux_enum_put, -}; - -static struct snd_kcontrol_new stac_smux_mixer = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "IEC958 Playback Source", - /* count set later */ - .info = stac92xx_smux_enum_info, - .get = stac92xx_smux_enum_get, - .put = stac92xx_smux_enum_put, -}; - -static const char * const slave_pfxs[] = { - "Front", "Surround", "Center", "LFE", "Side", - "Headphone", "Speaker", "IEC958", "PCM", - NULL -}; - -static void stac92xx_update_led_status(struct hda_codec *codec, int enabled); - -static void stac92xx_vmaster_hook(void *private_data, int val) -{ - stac92xx_update_led_status(private_data, val); -} - -static void stac92xx_free_kctls(struct hda_codec *codec); - -static int stac92xx_build_controls(struct hda_codec *codec) -{ - struct sigmatel_spec *spec = codec->spec; - unsigned int vmaster_tlv[4]; - int err; - int i; - - if (spec->mixer) { - err = snd_hda_add_new_ctls(codec, spec->mixer); - if (err < 0) - return 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->auto_mic && spec->num_dmuxes > 0 && - snd_hda_get_bool_hint(codec, "separate_dmux") == 1) { - stac_dmux_mixer.count = spec->num_dmuxes; - err = snd_hda_ctl_add(codec, 0, - snd_ctl_new1(&stac_dmux_mixer, codec)); - if (err < 0) - return err; - } - if (spec->num_smuxes > 0) { - int wcaps = get_wcaps(codec, spec->multiout.dig_out_nid); - struct hda_input_mux *smux = &spec->private_smux; - /* check for mute support on SPDIF out */ - if (wcaps & AC_WCAP_OUT_AMP) { - snd_hda_add_imux_item(smux, "Off", 0, NULL); - spec->spdif_mute = 1; - } - stac_smux_mixer.count = spec->num_smuxes; - err = snd_hda_ctl_add(codec, 0, - snd_ctl_new1(&stac_smux_mixer, codec)); - 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 && !(spec->gpio_dir & 0x01)) { - 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 */ - snd_hda_set_vmaster_tlv(codec, spec->multiout.dac_nids[0], - HDA_OUTPUT, vmaster_tlv); - /* correct volume offset */ - vmaster_tlv[2] += vmaster_tlv[3] * spec->volume_offset; - /* minimum value is actually mute */ - vmaster_tlv[3] |= TLV_DB_SCALE_MUTE; - err = snd_hda_add_vmaster(codec, "Master Playback Volume", - vmaster_tlv, slave_pfxs, - "Playback Volume"); - if (err < 0) - return err; - - err = __snd_hda_add_vmaster(codec, "Master Playback Switch", - NULL, slave_pfxs, - "Playback Switch", true, - &spec->vmaster_mute.sw_kctl); - if (err < 0) - return err; - - if (spec->gpio_led) { - spec->vmaster_mute.hook = stac92xx_vmaster_hook; - err = snd_hda_add_vmaster_hook(codec, &spec->vmaster_mute, true); - if (err < 0) - return err; - } - - if (spec->aloopback_ctl && - snd_hda_get_bool_hint(codec, "loopback") == 1) { - err = snd_hda_add_new_ctls(codec, spec->aloopback_ctl); - if (err < 0) - return err; - } - - stac92xx_free_kctls(codec); /* no longer needed */ - - err = snd_hda_jack_add_kctls(codec, &spec->autocfg); - if (err < 0) - return err; - - return 0; -} - -static const unsigned int ref9200_pin_configs[8] = { - 0x01c47010, 0x01447010, 0x0221401f, 0x01114010, - 0x02a19020, 0x01a19021, 0x90100140, 0x01813122, -}; - -static const unsigned int gateway9200_m4_pin_configs[8] = { - 0x400000fe, 0x404500f4, 0x400100f0, 0x90110010, - 0x400100f1, 0x02a1902e, 0x500000f2, 0x500000f3, -}; -static const unsigned int gateway9200_m4_2_pin_configs[8] = { - 0x400000fe, 0x404500f4, 0x400100f0, 0x90110010, - 0x400100f1, 0x02a1902e, 0x500000f2, 0x500000f3, -}; - /* STAC 9200 pin configs for 102801A8 102801DE 102801E8 */ -static const unsigned int dell9200_d21_pin_configs[8] = { - 0x400001f0, 0x400001f1, 0x02214030, 0x01014010, - 0x02a19020, 0x01a19021, 0x90100140, 0x01813122, +static const struct hda_pintbl dell9200_d21_pin_configs[] = { + { 0x08, 0x400001f0 }, + { 0x09, 0x400001f1 }, + { 0x0d, 0x02214030 }, + { 0x0e, 0x01014010 }, + { 0x0f, 0x02a19020 }, + { 0x10, 0x01a19021 }, + { 0x11, 0x90100140 }, + { 0x12, 0x01813122 }, + {} }; -/* +/* STAC 9200 pin configs for 102801C0 102801C1 */ -static const unsigned int dell9200_d22_pin_configs[8] = { - 0x400001f0, 0x400001f1, 0x0221401f, 0x01014010, - 0x01813020, 0x02a19021, 0x90100140, 0x400001f2, +static const struct hda_pintbl dell9200_d22_pin_configs[] = { + { 0x08, 0x400001f0 }, + { 0x09, 0x400001f1 }, + { 0x0d, 0x0221401f }, + { 0x0e, 0x01014010 }, + { 0x0f, 0x01813020 }, + { 0x10, 0x02a19021 }, + { 0x11, 0x90100140 }, + { 0x12, 0x400001f2 }, + {} }; -/* +/* STAC 9200 pin configs for 102801C4 (Dell Dimension E310) 102801C5 @@ -1240,9 +1186,16 @@ static const unsigned int dell9200_d22_pin_configs[8] = { 102801DA 102801E3 */ -static const unsigned int dell9200_d23_pin_configs[8] = { - 0x400001f0, 0x400001f1, 0x0221401f, 0x01014010, - 0x01813020, 0x01a19021, 0x90100140, 0x400001f2, +static const struct hda_pintbl dell9200_d23_pin_configs[] = { + { 0x08, 0x400001f0 }, + { 0x09, 0x400001f1 }, + { 0x0d, 0x0221401f }, + { 0x0e, 0x01014010 }, + { 0x0f, 0x01813020 }, + { 0x10, 0x01a19021 }, + { 0x11, 0x90100140 }, + { 0x12, 0x400001f2 }, + {} }; @@ -1251,9 +1204,16 @@ static const unsigned int dell9200_d23_pin_configs[8] = { 102801B5 (Dell Inspiron 630m) 102801D8 (Dell Inspiron 640m) */ -static const unsigned int dell9200_m21_pin_configs[8] = { - 0x40c003fa, 0x03441340, 0x0321121f, 0x90170310, - 0x408003fb, 0x03a11020, 0x401003fc, 0x403003fd, +static const struct hda_pintbl dell9200_m21_pin_configs[] = { + { 0x08, 0x40c003fa }, + { 0x09, 0x03441340 }, + { 0x0d, 0x0321121f }, + { 0x0e, 0x90170310 }, + { 0x0f, 0x408003fb }, + { 0x10, 0x03a11020 }, + { 0x11, 0x401003fc }, + { 0x12, 0x403003fd }, + {} }; /* @@ -1264,9 +1224,16 @@ static const unsigned int dell9200_m21_pin_configs[8] = { 102801D4 102801D6 */ -static const unsigned int dell9200_m22_pin_configs[8] = { - 0x40c003fa, 0x0144131f, 0x0321121f, 0x90170310, - 0x90a70321, 0x03a11020, 0x401003fb, 0x40f000fc, +static const struct hda_pintbl dell9200_m22_pin_configs[] = { + { 0x08, 0x40c003fa }, + { 0x09, 0x0144131f }, + { 0x0d, 0x0321121f }, + { 0x0e, 0x90170310 }, + { 0x0f, 0x90a70321 }, + { 0x10, 0x03a11020 }, + { 0x11, 0x401003fb }, + { 0x12, 0x40f000fc }, + {} }; /* @@ -1274,9 +1241,16 @@ static const unsigned int dell9200_m22_pin_configs[8] = { 102801CE (Dell XPS M1710) 102801CF (Dell Precision M90) */ -static const unsigned int dell9200_m23_pin_configs[8] = { - 0x40c003fa, 0x01441340, 0x0421421f, 0x90170310, - 0x408003fb, 0x04a1102e, 0x90170311, 0x403003fc, +static const struct hda_pintbl dell9200_m23_pin_configs[] = { + { 0x08, 0x40c003fa }, + { 0x09, 0x01441340 }, + { 0x0d, 0x0421421f }, + { 0x0e, 0x90170310 }, + { 0x0f, 0x408003fb }, + { 0x10, 0x04a1102e }, + { 0x11, 0x90170311 }, + { 0x12, 0x403003fc }, + {} }; /* @@ -1286,9 +1260,16 @@ static const unsigned int dell9200_m23_pin_configs[8] = { 102801CB (Dell Latitude 120L) 102801D3 */ -static const unsigned int dell9200_m24_pin_configs[8] = { - 0x40c003fa, 0x404003fb, 0x0321121f, 0x90170310, - 0x408003fc, 0x03a11020, 0x401003fd, 0x403003fe, +static const struct hda_pintbl dell9200_m24_pin_configs[] = { + { 0x08, 0x40c003fa }, + { 0x09, 0x404003fb }, + { 0x0d, 0x0321121f }, + { 0x0e, 0x90170310 }, + { 0x0f, 0x408003fc }, + { 0x10, 0x03a11020 }, + { 0x11, 0x401003fd }, + { 0x12, 0x403003fe }, + {} }; /* @@ -1297,9 +1278,16 @@ static const unsigned int dell9200_m24_pin_configs[8] = { 102801EE 102801EF */ -static const unsigned int dell9200_m25_pin_configs[8] = { - 0x40c003fa, 0x01441340, 0x0421121f, 0x90170310, - 0x408003fb, 0x04a11020, 0x401003fc, 0x403003fd, +static const struct hda_pintbl dell9200_m25_pin_configs[] = { + { 0x08, 0x40c003fa }, + { 0x09, 0x01441340 }, + { 0x0d, 0x0421121f }, + { 0x0e, 0x90170310 }, + { 0x0f, 0x408003fb }, + { 0x10, 0x04a11020 }, + { 0x11, 0x401003fc }, + { 0x12, 0x403003fd }, + {} }; /* @@ -1307,64 +1295,159 @@ static const unsigned int dell9200_m25_pin_configs[8] = { 102801F5 (Dell Inspiron 1501) 102801F6 */ -static const unsigned int dell9200_m26_pin_configs[8] = { - 0x40c003fa, 0x404003fb, 0x0421121f, 0x90170310, - 0x408003fc, 0x04a11020, 0x401003fd, 0x403003fe, +static const struct hda_pintbl dell9200_m26_pin_configs[] = { + { 0x08, 0x40c003fa }, + { 0x09, 0x404003fb }, + { 0x0d, 0x0421121f }, + { 0x0e, 0x90170310 }, + { 0x0f, 0x408003fc }, + { 0x10, 0x04a11020 }, + { 0x11, 0x401003fd }, + { 0x12, 0x403003fe }, + {} }; /* STAC 9200-32 102801CD (Dell Inspiron E1705/9400) */ -static const unsigned int dell9200_m27_pin_configs[8] = { - 0x40c003fa, 0x01441340, 0x0421121f, 0x90170310, - 0x90170310, 0x04a11020, 0x90170310, 0x40f003fc, +static const struct hda_pintbl dell9200_m27_pin_configs[] = { + { 0x08, 0x40c003fa }, + { 0x09, 0x01441340 }, + { 0x0d, 0x0421121f }, + { 0x0e, 0x90170310 }, + { 0x0f, 0x90170310 }, + { 0x10, 0x04a11020 }, + { 0x11, 0x90170310 }, + { 0x12, 0x40f003fc }, + {} }; -static const unsigned int oqo9200_pin_configs[8] = { - 0x40c000f0, 0x404000f1, 0x0221121f, 0x02211210, - 0x90170111, 0x90a70120, 0x400000f2, 0x400000f3, +static const struct hda_pintbl oqo9200_pin_configs[] = { + { 0x08, 0x40c000f0 }, + { 0x09, 0x404000f1 }, + { 0x0d, 0x0221121f }, + { 0x0e, 0x02211210 }, + { 0x0f, 0x90170111 }, + { 0x10, 0x90a70120 }, + { 0x11, 0x400000f2 }, + { 0x12, 0x400000f3 }, + {} }; -static const unsigned int *stac9200_brd_tbl[STAC_9200_MODELS] = { - [STAC_REF] = ref9200_pin_configs, - [STAC_9200_OQO] = oqo9200_pin_configs, - [STAC_9200_DELL_D21] = dell9200_d21_pin_configs, - [STAC_9200_DELL_D22] = dell9200_d22_pin_configs, - [STAC_9200_DELL_D23] = dell9200_d23_pin_configs, - [STAC_9200_DELL_M21] = dell9200_m21_pin_configs, - [STAC_9200_DELL_M22] = dell9200_m22_pin_configs, - [STAC_9200_DELL_M23] = dell9200_m23_pin_configs, - [STAC_9200_DELL_M24] = dell9200_m24_pin_configs, - [STAC_9200_DELL_M25] = dell9200_m25_pin_configs, - [STAC_9200_DELL_M26] = dell9200_m26_pin_configs, - [STAC_9200_DELL_M27] = dell9200_m27_pin_configs, - [STAC_9200_M4] = gateway9200_m4_pin_configs, - [STAC_9200_M4_2] = gateway9200_m4_2_pin_configs, - [STAC_9200_PANASONIC] = ref9200_pin_configs, +static void stac9200_fixup_panasonic(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct sigmatel_spec *spec = codec->spec; + + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + spec->gpio_mask = spec->gpio_dir = 0x09; + spec->gpio_data = 0x00; + /* CF-74 has no headphone detection, and the driver should *NOT* + * do detection and HP/speaker toggle because the hardware does it. + */ + spec->gen.suppress_auto_mute = 1; + } +} + + +static const struct hda_fixup stac9200_fixups[] = { + [STAC_REF] = { + .type = HDA_FIXUP_PINS, + .v.pins = ref9200_pin_configs, + }, + [STAC_9200_OQO] = { + .type = HDA_FIXUP_PINS, + .v.pins = oqo9200_pin_configs, + .chained = true, + .chain_id = STAC_9200_EAPD_INIT, + }, + [STAC_9200_DELL_D21] = { + .type = HDA_FIXUP_PINS, + .v.pins = dell9200_d21_pin_configs, + }, + [STAC_9200_DELL_D22] = { + .type = HDA_FIXUP_PINS, + .v.pins = dell9200_d22_pin_configs, + }, + [STAC_9200_DELL_D23] = { + .type = HDA_FIXUP_PINS, + .v.pins = dell9200_d23_pin_configs, + }, + [STAC_9200_DELL_M21] = { + .type = HDA_FIXUP_PINS, + .v.pins = dell9200_m21_pin_configs, + }, + [STAC_9200_DELL_M22] = { + .type = HDA_FIXUP_PINS, + .v.pins = dell9200_m22_pin_configs, + }, + [STAC_9200_DELL_M23] = { + .type = HDA_FIXUP_PINS, + .v.pins = dell9200_m23_pin_configs, + }, + [STAC_9200_DELL_M24] = { + .type = HDA_FIXUP_PINS, + .v.pins = dell9200_m24_pin_configs, + }, + [STAC_9200_DELL_M25] = { + .type = HDA_FIXUP_PINS, + .v.pins = dell9200_m25_pin_configs, + }, + [STAC_9200_DELL_M26] = { + .type = HDA_FIXUP_PINS, + .v.pins = dell9200_m26_pin_configs, + }, + [STAC_9200_DELL_M27] = { + .type = HDA_FIXUP_PINS, + .v.pins = dell9200_m27_pin_configs, + }, + [STAC_9200_M4] = { + .type = HDA_FIXUP_PINS, + .v.pins = gateway9200_m4_pin_configs, + .chained = true, + .chain_id = STAC_9200_EAPD_INIT, + }, + [STAC_9200_M4_2] = { + .type = HDA_FIXUP_PINS, + .v.pins = gateway9200_m4_2_pin_configs, + .chained = true, + .chain_id = STAC_9200_EAPD_INIT, + }, + [STAC_9200_PANASONIC] = { + .type = HDA_FIXUP_FUNC, + .v.func = stac9200_fixup_panasonic, + }, + [STAC_9200_EAPD_INIT] = { + .type = HDA_FIXUP_VERBS, + .v.verbs = (const struct hda_verb[]) { + {0x08, AC_VERB_SET_EAPD_BTLENABLE, 0x02}, + {} + }, + }, }; -static const char * const stac9200_models[STAC_9200_MODELS] = { - [STAC_AUTO] = "auto", - [STAC_REF] = "ref", - [STAC_9200_OQO] = "oqo", - [STAC_9200_DELL_D21] = "dell-d21", - [STAC_9200_DELL_D22] = "dell-d22", - [STAC_9200_DELL_D23] = "dell-d23", - [STAC_9200_DELL_M21] = "dell-m21", - [STAC_9200_DELL_M22] = "dell-m22", - [STAC_9200_DELL_M23] = "dell-m23", - [STAC_9200_DELL_M24] = "dell-m24", - [STAC_9200_DELL_M25] = "dell-m25", - [STAC_9200_DELL_M26] = "dell-m26", - [STAC_9200_DELL_M27] = "dell-m27", - [STAC_9200_M4] = "gateway-m4", - [STAC_9200_M4_2] = "gateway-m4-2", - [STAC_9200_PANASONIC] = "panasonic", +static const struct hda_model_fixup stac9200_models[] = { + { .id = STAC_REF, .name = "ref" }, + { .id = STAC_9200_OQO, .name = "oqo" }, + { .id = STAC_9200_DELL_D21, .name = "dell-d21" }, + { .id = STAC_9200_DELL_D22, .name = "dell-d22" }, + { .id = STAC_9200_DELL_D23, .name = "dell-d23" }, + { .id = STAC_9200_DELL_M21, .name = "dell-m21" }, + { .id = STAC_9200_DELL_M22, .name = "dell-m22" }, + { .id = STAC_9200_DELL_M23, .name = "dell-m23" }, + { .id = STAC_9200_DELL_M24, .name = "dell-m24" }, + { .id = STAC_9200_DELL_M25, .name = "dell-m25" }, + { .id = STAC_9200_DELL_M26, .name = "dell-m26" }, + { .id = STAC_9200_DELL_M27, .name = "dell-m27" }, + { .id = STAC_9200_M4, .name = "gateway-m4" }, + { .id = STAC_9200_M4_2, .name = "gateway-m4-2" }, + { .id = STAC_9200_PANASONIC, .name = "panasonic" }, + {} }; -static const struct snd_pci_quirk stac9200_cfg_tbl[] = { +static const struct snd_pci_quirk stac9200_fixup_tbl[] = { /* SigmaTel reference board */ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_REF), @@ -1440,70 +1523,159 @@ static const struct snd_pci_quirk stac9200_cfg_tbl[] = { {} /* terminator */ }; -static const unsigned int ref925x_pin_configs[8] = { - 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021, - 0x90a70320, 0x02214210, 0x01019020, 0x9033032e, +static const struct hda_pintbl ref925x_pin_configs[] = { + { 0x07, 0x40c003f0 }, + { 0x08, 0x424503f2 }, + { 0x0a, 0x01813022 }, + { 0x0b, 0x02a19021 }, + { 0x0c, 0x90a70320 }, + { 0x0d, 0x02214210 }, + { 0x10, 0x01019020 }, + { 0x11, 0x9033032e }, + {} }; -static const unsigned int stac925xM1_pin_configs[8] = { - 0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020, - 0x40a000f0, 0x90100210, 0x400003f1, 0x9033032e, +static const struct hda_pintbl stac925xM1_pin_configs[] = { + { 0x07, 0x40c003f4 }, + { 0x08, 0x424503f2 }, + { 0x0a, 0x400000f3 }, + { 0x0b, 0x02a19020 }, + { 0x0c, 0x40a000f0 }, + { 0x0d, 0x90100210 }, + { 0x10, 0x400003f1 }, + { 0x11, 0x9033032e }, + {} }; -static const unsigned int stac925xM1_2_pin_configs[8] = { - 0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020, - 0x40a000f0, 0x90100210, 0x400003f1, 0x9033032e, +static const struct hda_pintbl stac925xM1_2_pin_configs[] = { + { 0x07, 0x40c003f4 }, + { 0x08, 0x424503f2 }, + { 0x0a, 0x400000f3 }, + { 0x0b, 0x02a19020 }, + { 0x0c, 0x40a000f0 }, + { 0x0d, 0x90100210 }, + { 0x10, 0x400003f1 }, + { 0x11, 0x9033032e }, + {} }; -static const unsigned int stac925xM2_pin_configs[8] = { - 0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020, - 0x40a000f0, 0x90100210, 0x400003f1, 0x9033032e, +static const struct hda_pintbl stac925xM2_pin_configs[] = { + { 0x07, 0x40c003f4 }, + { 0x08, 0x424503f2 }, + { 0x0a, 0x400000f3 }, + { 0x0b, 0x02a19020 }, + { 0x0c, 0x40a000f0 }, + { 0x0d, 0x90100210 }, + { 0x10, 0x400003f1 }, + { 0x11, 0x9033032e }, + {} }; -static const unsigned int stac925xM2_2_pin_configs[8] = { - 0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020, - 0x40a000f0, 0x90100210, 0x400003f1, 0x9033032e, +static const struct hda_pintbl stac925xM2_2_pin_configs[] = { + { 0x07, 0x40c003f4 }, + { 0x08, 0x424503f2 }, + { 0x0a, 0x400000f3 }, + { 0x0b, 0x02a19020 }, + { 0x0c, 0x40a000f0 }, + { 0x0d, 0x90100210 }, + { 0x10, 0x400003f1 }, + { 0x11, 0x9033032e }, + {} }; -static const unsigned int stac925xM3_pin_configs[8] = { - 0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020, - 0x40a000f0, 0x90100210, 0x400003f1, 0x503303f3, +static const struct hda_pintbl stac925xM3_pin_configs[] = { + { 0x07, 0x40c003f4 }, + { 0x08, 0x424503f2 }, + { 0x0a, 0x400000f3 }, + { 0x0b, 0x02a19020 }, + { 0x0c, 0x40a000f0 }, + { 0x0d, 0x90100210 }, + { 0x10, 0x400003f1 }, + { 0x11, 0x503303f3 }, + {} }; -static const unsigned int stac925xM5_pin_configs[8] = { - 0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020, - 0x40a000f0, 0x90100210, 0x400003f1, 0x9033032e, +static const struct hda_pintbl stac925xM5_pin_configs[] = { + { 0x07, 0x40c003f4 }, + { 0x08, 0x424503f2 }, + { 0x0a, 0x400000f3 }, + { 0x0b, 0x02a19020 }, + { 0x0c, 0x40a000f0 }, + { 0x0d, 0x90100210 }, + { 0x10, 0x400003f1 }, + { 0x11, 0x9033032e }, + {} }; -static const unsigned int stac925xM6_pin_configs[8] = { - 0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020, - 0x40a000f0, 0x90100210, 0x400003f1, 0x90330320, +static const struct hda_pintbl stac925xM6_pin_configs[] = { + { 0x07, 0x40c003f4 }, + { 0x08, 0x424503f2 }, + { 0x0a, 0x400000f3 }, + { 0x0b, 0x02a19020 }, + { 0x0c, 0x40a000f0 }, + { 0x0d, 0x90100210 }, + { 0x10, 0x400003f1 }, + { 0x11, 0x90330320 }, + {} }; -static const unsigned int *stac925x_brd_tbl[STAC_925x_MODELS] = { - [STAC_REF] = ref925x_pin_configs, - [STAC_M1] = stac925xM1_pin_configs, - [STAC_M1_2] = stac925xM1_2_pin_configs, - [STAC_M2] = stac925xM2_pin_configs, - [STAC_M2_2] = stac925xM2_2_pin_configs, - [STAC_M3] = stac925xM3_pin_configs, - [STAC_M5] = stac925xM5_pin_configs, - [STAC_M6] = stac925xM6_pin_configs, +static const struct hda_fixup stac925x_fixups[] = { + [STAC_REF] = { + .type = HDA_FIXUP_PINS, + .v.pins = ref925x_pin_configs, + }, + [STAC_M1] = { + .type = HDA_FIXUP_PINS, + .v.pins = stac925xM1_pin_configs, + }, + [STAC_M1_2] = { + .type = HDA_FIXUP_PINS, + .v.pins = stac925xM1_2_pin_configs, + }, + [STAC_M2] = { + .type = HDA_FIXUP_PINS, + .v.pins = stac925xM2_pin_configs, + }, + [STAC_M2_2] = { + .type = HDA_FIXUP_PINS, + .v.pins = stac925xM2_2_pin_configs, + }, + [STAC_M3] = { + .type = HDA_FIXUP_PINS, + .v.pins = stac925xM3_pin_configs, + }, + [STAC_M5] = { + .type = HDA_FIXUP_PINS, + .v.pins = stac925xM5_pin_configs, + }, + [STAC_M6] = { + .type = HDA_FIXUP_PINS, + .v.pins = stac925xM6_pin_configs, + }, }; -static const char * const stac925x_models[STAC_925x_MODELS] = { - [STAC_925x_AUTO] = "auto", - [STAC_REF] = "ref", - [STAC_M1] = "m1", - [STAC_M1_2] = "m1-2", - [STAC_M2] = "m2", - [STAC_M2_2] = "m2-2", - [STAC_M3] = "m3", - [STAC_M5] = "m5", - [STAC_M6] = "m6", +static const struct hda_model_fixup stac925x_models[] = { + { .id = STAC_REF, .name = "ref" }, + { .id = STAC_M1, .name = "m1" }, + { .id = STAC_M1_2, .name = "m1-2" }, + { .id = STAC_M2, .name = "m2" }, + { .id = STAC_M2_2, .name = "m2-2" }, + { .id = STAC_M3, .name = "m3" }, + { .id = STAC_M5, .name = "m5" }, + { .id = STAC_M6, .name = "m6" }, + {} }; -static const struct snd_pci_quirk stac925x_codec_id_cfg_tbl[] = { +static const struct snd_pci_quirk stac925x_fixup_tbl[] = { + /* SigmaTel reference board */ + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_REF), + SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101, "DFI LanParty", STAC_REF), + SND_PCI_QUIRK(0x8384, 0x7632, "Stac9202 Reference Board", STAC_REF), + + /* Default table for unknown ID */ + SND_PCI_QUIRK(0x1002, 0x437b, "Gateway mobile", STAC_M2_2), + + /* gateway machines are checked via codec ssid */ SND_PCI_QUIRK(0x107b, 0x0316, "Gateway M255", STAC_M2), SND_PCI_QUIRK(0x107b, 0x0366, "Gateway MP6954", STAC_M5), SND_PCI_QUIRK(0x107b, 0x0461, "Gateway NX560XL", STAC_M1), @@ -1517,67 +1689,202 @@ static const struct snd_pci_quirk stac925x_codec_id_cfg_tbl[] = { {} /* terminator */ }; -static const struct snd_pci_quirk stac925x_cfg_tbl[] = { - /* SigmaTel reference board */ - SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_REF), - SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101, "DFI LanParty", STAC_REF), - SND_PCI_QUIRK(0x8384, 0x7632, "Stac9202 Reference Board", STAC_REF), - - /* Default table for unknown ID */ - SND_PCI_QUIRK(0x1002, 0x437b, "Gateway mobile", STAC_M2_2), - - {} /* terminator */ +static const struct hda_pintbl ref92hd73xx_pin_configs[] = { + { 0x0a, 0x02214030 }, + { 0x0b, 0x02a19040 }, + { 0x0c, 0x01a19020 }, + { 0x0d, 0x02214030 }, + { 0x0e, 0x0181302e }, + { 0x0f, 0x01014010 }, + { 0x10, 0x01014020 }, + { 0x11, 0x01014030 }, + { 0x12, 0x02319040 }, + { 0x13, 0x90a000f0 }, + { 0x14, 0x90a000f0 }, + { 0x22, 0x01452050 }, + { 0x23, 0x01452050 }, + {} }; -static const unsigned int ref92hd73xx_pin_configs[13] = { - 0x02214030, 0x02a19040, 0x01a19020, 0x02214030, - 0x0181302e, 0x01014010, 0x01014020, 0x01014030, - 0x02319040, 0x90a000f0, 0x90a000f0, 0x01452050, - 0x01452050, +static const struct hda_pintbl dell_m6_pin_configs[] = { + { 0x0a, 0x0321101f }, + { 0x0b, 0x4f00000f }, + { 0x0c, 0x4f0000f0 }, + { 0x0d, 0x90170110 }, + { 0x0e, 0x03a11020 }, + { 0x0f, 0x0321101f }, + { 0x10, 0x4f0000f0 }, + { 0x11, 0x4f0000f0 }, + { 0x12, 0x4f0000f0 }, + { 0x13, 0x90a60160 }, + { 0x14, 0x4f0000f0 }, + { 0x22, 0x4f0000f0 }, + { 0x23, 0x4f0000f0 }, + {} }; -static const unsigned int dell_m6_pin_configs[13] = { - 0x0321101f, 0x4f00000f, 0x4f0000f0, 0x90170110, - 0x03a11020, 0x0321101f, 0x4f0000f0, 0x4f0000f0, - 0x4f0000f0, 0x90a60160, 0x4f0000f0, 0x4f0000f0, - 0x4f0000f0, +static const struct hda_pintbl alienware_m17x_pin_configs[] = { + { 0x0a, 0x0321101f }, + { 0x0b, 0x0321101f }, + { 0x0c, 0x03a11020 }, + { 0x0d, 0x03014020 }, + { 0x0e, 0x90170110 }, + { 0x0f, 0x4f0000f0 }, + { 0x10, 0x4f0000f0 }, + { 0x11, 0x4f0000f0 }, + { 0x12, 0x4f0000f0 }, + { 0x13, 0x90a60160 }, + { 0x14, 0x4f0000f0 }, + { 0x22, 0x4f0000f0 }, + { 0x23, 0x904601b0 }, + {} }; -static const unsigned int alienware_m17x_pin_configs[13] = { - 0x0321101f, 0x0321101f, 0x03a11020, 0x03014020, - 0x90170110, 0x4f0000f0, 0x4f0000f0, 0x4f0000f0, - 0x4f0000f0, 0x90a60160, 0x4f0000f0, 0x4f0000f0, - 0x904601b0, +static const struct hda_pintbl intel_dg45id_pin_configs[] = { + { 0x0a, 0x02214230 }, + { 0x0b, 0x02A19240 }, + { 0x0c, 0x01013214 }, + { 0x0d, 0x01014210 }, + { 0x0e, 0x01A19250 }, + { 0x0f, 0x01011212 }, + { 0x10, 0x01016211 }, + {} }; -static const unsigned int intel_dg45id_pin_configs[13] = { - 0x02214230, 0x02A19240, 0x01013214, 0x01014210, - 0x01A19250, 0x01011212, 0x01016211 -}; +static void stac92hd73xx_fixup_ref(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct sigmatel_spec *spec = codec->spec; + + if (action != HDA_FIXUP_ACT_PRE_PROBE) + return; + + snd_hda_apply_pincfgs(codec, ref92hd73xx_pin_configs); + spec->gpio_mask = spec->gpio_dir = spec->gpio_data = 0; +} + +static void stac92hd73xx_fixup_dell(struct hda_codec *codec) +{ + struct sigmatel_spec *spec = codec->spec; + + snd_hda_apply_pincfgs(codec, dell_m6_pin_configs); + spec->eapd_switch = 0; +} + +static void stac92hd73xx_fixup_dell_eq(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct sigmatel_spec *spec = codec->spec; + + if (action != HDA_FIXUP_ACT_PRE_PROBE) + return; + + stac92hd73xx_fixup_dell(codec); + snd_hda_add_verbs(codec, dell_eq_core_init); + spec->volknob_init = 1; +} + +/* Analog Mics */ +static void stac92hd73xx_fixup_dell_m6_amic(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + if (action != HDA_FIXUP_ACT_PRE_PROBE) + return; + + stac92hd73xx_fixup_dell(codec); + snd_hda_codec_set_pincfg(codec, 0x0b, 0x90A70170); +} + +/* Digital Mics */ +static void stac92hd73xx_fixup_dell_m6_dmic(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + if (action != HDA_FIXUP_ACT_PRE_PROBE) + return; + + stac92hd73xx_fixup_dell(codec); + snd_hda_codec_set_pincfg(codec, 0x13, 0x90A60160); +} -static const unsigned int *stac92hd73xx_brd_tbl[STAC_92HD73XX_MODELS] = { - [STAC_92HD73XX_REF] = ref92hd73xx_pin_configs, - [STAC_DELL_M6_AMIC] = dell_m6_pin_configs, - [STAC_DELL_M6_DMIC] = dell_m6_pin_configs, - [STAC_DELL_M6_BOTH] = dell_m6_pin_configs, - [STAC_DELL_EQ] = dell_m6_pin_configs, - [STAC_ALIENWARE_M17X] = alienware_m17x_pin_configs, - [STAC_92HD73XX_INTEL] = intel_dg45id_pin_configs, +/* Both */ +static void stac92hd73xx_fixup_dell_m6_both(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + if (action != HDA_FIXUP_ACT_PRE_PROBE) + return; + + stac92hd73xx_fixup_dell(codec); + snd_hda_codec_set_pincfg(codec, 0x0b, 0x90A70170); + snd_hda_codec_set_pincfg(codec, 0x13, 0x90A60160); +} + +static void stac92hd73xx_fixup_alienware_m17x(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct sigmatel_spec *spec = codec->spec; + + if (action != HDA_FIXUP_ACT_PRE_PROBE) + return; + + snd_hda_apply_pincfgs(codec, alienware_m17x_pin_configs); + spec->eapd_switch = 0; +} + +static void stac92hd73xx_fixup_no_jd(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + if (action == HDA_FIXUP_ACT_PRE_PROBE) + codec->no_jack_detect = 1; +} + +static const struct hda_fixup stac92hd73xx_fixups[] = { + [STAC_92HD73XX_REF] = { + .type = HDA_FIXUP_FUNC, + .v.func = stac92hd73xx_fixup_ref, + }, + [STAC_DELL_M6_AMIC] = { + .type = HDA_FIXUP_FUNC, + .v.func = stac92hd73xx_fixup_dell_m6_amic, + }, + [STAC_DELL_M6_DMIC] = { + .type = HDA_FIXUP_FUNC, + .v.func = stac92hd73xx_fixup_dell_m6_dmic, + }, + [STAC_DELL_M6_BOTH] = { + .type = HDA_FIXUP_FUNC, + .v.func = stac92hd73xx_fixup_dell_m6_both, + }, + [STAC_DELL_EQ] = { + .type = HDA_FIXUP_FUNC, + .v.func = stac92hd73xx_fixup_dell_eq, + }, + [STAC_ALIENWARE_M17X] = { + .type = HDA_FIXUP_FUNC, + .v.func = stac92hd73xx_fixup_alienware_m17x, + }, + [STAC_92HD73XX_INTEL] = { + .type = HDA_FIXUP_PINS, + .v.pins = intel_dg45id_pin_configs, + }, + [STAC_92HD73XX_NO_JD] = { + .type = HDA_FIXUP_FUNC, + .v.func = stac92hd73xx_fixup_no_jd, + } }; -static const char * const stac92hd73xx_models[STAC_92HD73XX_MODELS] = { - [STAC_92HD73XX_AUTO] = "auto", - [STAC_92HD73XX_NO_JD] = "no-jd", - [STAC_92HD73XX_REF] = "ref", - [STAC_92HD73XX_INTEL] = "intel", - [STAC_DELL_M6_AMIC] = "dell-m6-amic", - [STAC_DELL_M6_DMIC] = "dell-m6-dmic", - [STAC_DELL_M6_BOTH] = "dell-m6", - [STAC_DELL_EQ] = "dell-eq", - [STAC_ALIENWARE_M17X] = "alienware", +static const struct hda_model_fixup stac92hd73xx_models[] = { + { .id = STAC_92HD73XX_NO_JD, .name = "no-jd" }, + { .id = STAC_92HD73XX_REF, .name = "ref" }, + { .id = STAC_92HD73XX_INTEL, .name = "intel" }, + { .id = STAC_DELL_M6_AMIC, .name = "dell-m6-amic" }, + { .id = STAC_DELL_M6_DMIC, .name = "dell-m6-dmic" }, + { .id = STAC_DELL_M6_BOTH, .name = "dell-m6" }, + { .id = STAC_DELL_EQ, .name = "dell-eq" }, + { .id = STAC_ALIENWARE_M17X, .name = "alienware" }, + {} }; -static const struct snd_pci_quirk stac92hd73xx_cfg_tbl[] = { +static const struct snd_pci_quirk stac92hd73xx_fixup_tbl[] = { /* SigmaTel reference board */ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_92HD73XX_REF), @@ -1615,10 +1922,7 @@ static const struct snd_pci_quirk stac92hd73xx_cfg_tbl[] = { "Dell Studio XPS 1645", STAC_DELL_M6_DMIC), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0413, "Dell Studio 1558", STAC_DELL_M6_DMIC), - {} /* terminator */ -}; - -static const struct snd_pci_quirk stac92hd73xx_codec_id_cfg_tbl[] = { + /* codec SSID matching */ SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02a1, "Alienware M17x", STAC_ALIENWARE_M17X), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x043a, @@ -1628,68 +1932,240 @@ static const struct snd_pci_quirk stac92hd73xx_codec_id_cfg_tbl[] = { {} /* terminator */ }; -static const unsigned int ref92hd83xxx_pin_configs[10] = { - 0x02214030, 0x02211010, 0x02a19020, 0x02170130, - 0x01014050, 0x01819040, 0x01014020, 0x90a3014e, - 0x01451160, 0x98560170, +static const struct hda_pintbl ref92hd83xxx_pin_configs[] = { + { 0x0a, 0x02214030 }, + { 0x0b, 0x02211010 }, + { 0x0c, 0x02a19020 }, + { 0x0d, 0x02170130 }, + { 0x0e, 0x01014050 }, + { 0x0f, 0x01819040 }, + { 0x10, 0x01014020 }, + { 0x11, 0x90a3014e }, + { 0x1f, 0x01451160 }, + { 0x20, 0x98560170 }, + {} }; -static const unsigned int dell_s14_pin_configs[10] = { - 0x0221403f, 0x0221101f, 0x02a19020, 0x90170110, - 0x40f000f0, 0x40f000f0, 0x40f000f0, 0x90a60160, - 0x40f000f0, 0x40f000f0, +static const struct hda_pintbl dell_s14_pin_configs[] = { + { 0x0a, 0x0221403f }, + { 0x0b, 0x0221101f }, + { 0x0c, 0x02a19020 }, + { 0x0d, 0x90170110 }, + { 0x0e, 0x40f000f0 }, + { 0x0f, 0x40f000f0 }, + { 0x10, 0x40f000f0 }, + { 0x11, 0x90a60160 }, + { 0x1f, 0x40f000f0 }, + { 0x20, 0x40f000f0 }, + {} }; -static const unsigned int dell_vostro_3500_pin_configs[10] = { - 0x02a11020, 0x0221101f, 0x400000f0, 0x90170110, - 0x400000f1, 0x400000f2, 0x400000f3, 0x90a60160, - 0x400000f4, 0x400000f5, +static const struct hda_pintbl dell_vostro_3500_pin_configs[] = { + { 0x0a, 0x02a11020 }, + { 0x0b, 0x0221101f }, + { 0x0c, 0x400000f0 }, + { 0x0d, 0x90170110 }, + { 0x0e, 0x400000f1 }, + { 0x0f, 0x400000f2 }, + { 0x10, 0x400000f3 }, + { 0x11, 0x90a60160 }, + { 0x1f, 0x400000f4 }, + { 0x20, 0x400000f5 }, + {} }; -static const unsigned int hp_dv7_4000_pin_configs[10] = { - 0x03a12050, 0x0321201f, 0x40f000f0, 0x90170110, - 0x40f000f0, 0x40f000f0, 0x90170110, 0xd5a30140, - 0x40f000f0, 0x40f000f0, +static const struct hda_pintbl hp_dv7_4000_pin_configs[] = { + { 0x0a, 0x03a12050 }, + { 0x0b, 0x0321201f }, + { 0x0c, 0x40f000f0 }, + { 0x0d, 0x90170110 }, + { 0x0e, 0x40f000f0 }, + { 0x0f, 0x40f000f0 }, + { 0x10, 0x90170110 }, + { 0x11, 0xd5a30140 }, + { 0x1f, 0x40f000f0 }, + { 0x20, 0x40f000f0 }, + {} }; -static const unsigned int hp_zephyr_pin_configs[10] = { - 0x01813050, 0x0421201f, 0x04a1205e, 0x96130310, - 0x96130310, 0x0101401f, 0x1111611f, 0xd5a30130, - 0, 0, +static const struct hda_pintbl hp_zephyr_pin_configs[] = { + { 0x0a, 0x01813050 }, + { 0x0b, 0x0421201f }, + { 0x0c, 0x04a1205e }, + { 0x0d, 0x96130310 }, + { 0x0e, 0x96130310 }, + { 0x0f, 0x0101401f }, + { 0x10, 0x1111611f }, + { 0x11, 0xd5a30130 }, + {} }; -static const unsigned int hp_cNB11_intquad_pin_configs[10] = { - 0x40f000f0, 0x0221101f, 0x02a11020, 0x92170110, - 0x40f000f0, 0x92170110, 0x40f000f0, 0xd5a30130, - 0x40f000f0, 0x40f000f0, +static const struct hda_pintbl hp_cNB11_intquad_pin_configs[] = { + { 0x0a, 0x40f000f0 }, + { 0x0b, 0x0221101f }, + { 0x0c, 0x02a11020 }, + { 0x0d, 0x92170110 }, + { 0x0e, 0x40f000f0 }, + { 0x0f, 0x92170110 }, + { 0x10, 0x40f000f0 }, + { 0x11, 0xd5a30130 }, + { 0x1f, 0x40f000f0 }, + { 0x20, 0x40f000f0 }, + {} }; -static const unsigned int *stac92hd83xxx_brd_tbl[STAC_92HD83XXX_MODELS] = { - [STAC_92HD83XXX_REF] = ref92hd83xxx_pin_configs, - [STAC_92HD83XXX_PWR_REF] = ref92hd83xxx_pin_configs, - [STAC_DELL_S14] = dell_s14_pin_configs, - [STAC_DELL_VOSTRO_3500] = dell_vostro_3500_pin_configs, - [STAC_92HD83XXX_HP_cNB11_INTQUAD] = hp_cNB11_intquad_pin_configs, - [STAC_HP_DV7_4000] = hp_dv7_4000_pin_configs, - [STAC_HP_ZEPHYR] = hp_zephyr_pin_configs, +static void stac92hd83xxx_fixup_hp(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct sigmatel_spec *spec = codec->spec; + + if (action != HDA_FIXUP_ACT_PRE_PROBE) + return; + + if (hp_bnb2011_with_dock(codec)) { + snd_hda_codec_set_pincfg(codec, 0xa, 0x2101201f); + snd_hda_codec_set_pincfg(codec, 0xf, 0x2181205e); + } + + if (find_mute_led_cfg(codec, spec->default_polarity)) + snd_printd("mute LED gpio %d polarity %d\n", + spec->gpio_led, + spec->gpio_led_polarity); +} + +static void stac92hd83xxx_fixup_hp_zephyr(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + if (action != HDA_FIXUP_ACT_PRE_PROBE) + return; + + snd_hda_apply_pincfgs(codec, hp_zephyr_pin_configs); + snd_hda_add_verbs(codec, stac92hd83xxx_hp_zephyr_init); +} + +static void stac92hd83xxx_fixup_hp_led(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct sigmatel_spec *spec = codec->spec; + + if (action == HDA_FIXUP_ACT_PRE_PROBE) + spec->default_polarity = 0; +} + +static void stac92hd83xxx_fixup_hp_inv_led(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct sigmatel_spec *spec = codec->spec; + + if (action == HDA_FIXUP_ACT_PRE_PROBE) + spec->default_polarity = 1; +} + +static void stac92hd83xxx_fixup_hp_mic_led(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct sigmatel_spec *spec = codec->spec; + + if (action == HDA_FIXUP_ACT_PRE_PROBE) + spec->mic_mute_led_gpio = 0x08; /* GPIO3 */ +} + +static void stac92hd83xxx_fixup_headset_jack(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct sigmatel_spec *spec = codec->spec; + + if (action == HDA_FIXUP_ACT_PRE_PROBE) + spec->headset_jack = 1; +} + +static const struct hda_fixup stac92hd83xxx_fixups[] = { + [STAC_92HD83XXX_REF] = { + .type = HDA_FIXUP_PINS, + .v.pins = ref92hd83xxx_pin_configs, + }, + [STAC_92HD83XXX_PWR_REF] = { + .type = HDA_FIXUP_PINS, + .v.pins = ref92hd83xxx_pin_configs, + }, + [STAC_DELL_S14] = { + .type = HDA_FIXUP_PINS, + .v.pins = dell_s14_pin_configs, + }, + [STAC_DELL_VOSTRO_3500] = { + .type = HDA_FIXUP_PINS, + .v.pins = dell_vostro_3500_pin_configs, + }, + [STAC_92HD83XXX_HP_cNB11_INTQUAD] = { + .type = HDA_FIXUP_PINS, + .v.pins = hp_cNB11_intquad_pin_configs, + .chained = true, + .chain_id = STAC_92HD83XXX_HP, + }, + [STAC_92HD83XXX_HP] = { + .type = HDA_FIXUP_FUNC, + .v.func = stac92hd83xxx_fixup_hp, + }, + [STAC_HP_DV7_4000] = { + .type = HDA_FIXUP_PINS, + .v.pins = hp_dv7_4000_pin_configs, + .chained = true, + .chain_id = STAC_92HD83XXX_HP, + }, + [STAC_HP_ZEPHYR] = { + .type = HDA_FIXUP_FUNC, + .v.func = stac92hd83xxx_fixup_hp_zephyr, + .chained = true, + .chain_id = STAC_92HD83XXX_HP, + }, + [STAC_92HD83XXX_HP_LED] = { + .type = HDA_FIXUP_FUNC, + .v.func = stac92hd83xxx_fixup_hp_led, + .chained = true, + .chain_id = STAC_92HD83XXX_HP, + }, + [STAC_92HD83XXX_HP_INV_LED] = { + .type = HDA_FIXUP_FUNC, + .v.func = stac92hd83xxx_fixup_hp_inv_led, + .chained = true, + .chain_id = STAC_92HD83XXX_HP, + }, + [STAC_92HD83XXX_HP_MIC_LED] = { + .type = HDA_FIXUP_FUNC, + .v.func = stac92hd83xxx_fixup_hp_mic_led, + .chained = true, + .chain_id = STAC_92HD83XXX_HP, + }, + [STAC_92HD83XXX_HEADSET_JACK] = { + .type = HDA_FIXUP_FUNC, + .v.func = stac92hd83xxx_fixup_headset_jack, + }, + [STAC_HP_ENVY_BASS] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x0f, 0x90170111 }, + {} + }, + }, }; -static const char * const stac92hd83xxx_models[STAC_92HD83XXX_MODELS] = { - [STAC_92HD83XXX_AUTO] = "auto", - [STAC_92HD83XXX_REF] = "ref", - [STAC_92HD83XXX_PWR_REF] = "mic-ref", - [STAC_DELL_S14] = "dell-s14", - [STAC_DELL_VOSTRO_3500] = "dell-vostro-3500", - [STAC_92HD83XXX_HP_cNB11_INTQUAD] = "hp_cNB11_intquad", - [STAC_HP_DV7_4000] = "hp-dv7-4000", - [STAC_HP_ZEPHYR] = "hp-zephyr", - [STAC_92HD83XXX_HP_LED] = "hp-led", - [STAC_92HD83XXX_HP_INV_LED] = "hp-inv-led", - [STAC_92HD83XXX_HP_MIC_LED] = "hp-mic-led", - [STAC_92HD83XXX_HEADSET_JACK] = "headset-jack", +static const struct hda_model_fixup stac92hd83xxx_models[] = { + { .id = STAC_92HD83XXX_REF, .name = "ref" }, + { .id = STAC_92HD83XXX_PWR_REF, .name = "mic-ref" }, + { .id = STAC_DELL_S14, .name = "dell-s14" }, + { .id = STAC_DELL_VOSTRO_3500, .name = "dell-vostro-3500" }, + { .id = STAC_92HD83XXX_HP_cNB11_INTQUAD, .name = "hp_cNB11_intquad" }, + { .id = STAC_HP_DV7_4000, .name = "hp-dv7-4000" }, + { .id = STAC_HP_ZEPHYR, .name = "hp-zephyr" }, + { .id = STAC_92HD83XXX_HP_LED, .name = "hp-led" }, + { .id = STAC_92HD83XXX_HP_INV_LED, .name = "hp-inv-led" }, + { .id = STAC_92HD83XXX_HP_MIC_LED, .name = "hp-mic-led" }, + { .id = STAC_92HD83XXX_HEADSET_JACK, .name = "headset-jack" }, + { .id = STAC_HP_ENVY_BASS, .name = "hp-envy-bass" }, + {} }; -static const struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = { +static const struct snd_pci_quirk stac92hd83xxx_fixup_tbl[] = { /* SigmaTel reference board */ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_92HD83XXX_REF), @@ -1724,13 +2200,17 @@ static const struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = { SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1658, "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1659, - "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), + "HP Pavilion dv7", STAC_HP_DV7_4000), SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x165A, "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x165B, "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1888, + "HP Envy Spectre", STAC_HP_ENVY_BASS), SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x18df, "HP Folio", STAC_92HD83XXX_HP_MIC_LED), + SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xff00, 0x1900, + "HP", STAC_92HD83XXX_HP_MIC_LED), SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3388, "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3389, @@ -1765,76 +2245,297 @@ static const struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = { "HP Mini", STAC_92HD83XXX_HP_LED), SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x144E, "HP Pavilion dv5", STAC_92HD83XXX_HP_INV_LED), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x148a, + "HP Mini", STAC_92HD83XXX_HP_LED), + SND_PCI_QUIRK_VENDOR(PCI_VENDOR_ID_HP, "HP", STAC_92HD83XXX_HP), {} /* terminator */ }; -static const struct snd_pci_quirk stac92hd83xxx_codec_id_cfg_tbl[] = { - SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3561, - "HP", STAC_HP_ZEPHYR), - {} /* terminator */ +/* HP dv7 bass switch - GPIO5 */ +#define stac_hp_bass_gpio_info snd_ctl_boolean_mono_info +static int stac_hp_bass_gpio_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct sigmatel_spec *spec = codec->spec; + ucontrol->value.integer.value[0] = !!(spec->gpio_data & 0x20); + return 0; +} + +static int stac_hp_bass_gpio_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct sigmatel_spec *spec = codec->spec; + unsigned int gpio_data; + + gpio_data = (spec->gpio_data & ~0x20) | + (ucontrol->value.integer.value[0] ? 0x20 : 0); + if (gpio_data == spec->gpio_data) + return 0; + spec->gpio_data = gpio_data; + stac_gpio_set(codec, spec->gpio_mask, spec->gpio_dir, spec->gpio_data); + return 1; +} + +static const struct snd_kcontrol_new stac_hp_bass_sw_ctrl = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .info = stac_hp_bass_gpio_info, + .get = stac_hp_bass_gpio_get, + .put = stac_hp_bass_gpio_put, }; -static const unsigned int ref92hd71bxx_pin_configs[STAC92HD71BXX_NUM_PINS] = { - 0x02214030, 0x02a19040, 0x01a19020, 0x01014010, - 0x0181302e, 0x01014010, 0x01019020, 0x90a000f0, - 0x90a000f0, 0x01452050, 0x01452050, 0x00000000, - 0x00000000 +static int stac_add_hp_bass_switch(struct hda_codec *codec) +{ + struct sigmatel_spec *spec = codec->spec; + + if (!snd_hda_gen_add_kctl(&spec->gen, "Bass Speaker Playback Switch", + &stac_hp_bass_sw_ctrl)) + return -ENOMEM; + + spec->gpio_mask |= 0x20; + spec->gpio_dir |= 0x20; + spec->gpio_data |= 0x20; + return 0; +} + +static const struct hda_pintbl ref92hd71bxx_pin_configs[] = { + { 0x0a, 0x02214030 }, + { 0x0b, 0x02a19040 }, + { 0x0c, 0x01a19020 }, + { 0x0d, 0x01014010 }, + { 0x0e, 0x0181302e }, + { 0x0f, 0x01014010 }, + { 0x14, 0x01019020 }, + { 0x18, 0x90a000f0 }, + { 0x19, 0x90a000f0 }, + { 0x1e, 0x01452050 }, + { 0x1f, 0x01452050 }, + {} }; -static const unsigned int dell_m4_1_pin_configs[STAC92HD71BXX_NUM_PINS] = { - 0x0421101f, 0x04a11221, 0x40f000f0, 0x90170110, - 0x23a1902e, 0x23014250, 0x40f000f0, 0x90a000f0, - 0x40f000f0, 0x4f0000f0, 0x4f0000f0, 0x00000000, - 0x00000000 +static const struct hda_pintbl dell_m4_1_pin_configs[] = { + { 0x0a, 0x0421101f }, + { 0x0b, 0x04a11221 }, + { 0x0c, 0x40f000f0 }, + { 0x0d, 0x90170110 }, + { 0x0e, 0x23a1902e }, + { 0x0f, 0x23014250 }, + { 0x14, 0x40f000f0 }, + { 0x18, 0x90a000f0 }, + { 0x19, 0x40f000f0 }, + { 0x1e, 0x4f0000f0 }, + { 0x1f, 0x4f0000f0 }, + {} }; -static const unsigned int dell_m4_2_pin_configs[STAC92HD71BXX_NUM_PINS] = { - 0x0421101f, 0x04a11221, 0x90a70330, 0x90170110, - 0x23a1902e, 0x23014250, 0x40f000f0, 0x40f000f0, - 0x40f000f0, 0x044413b0, 0x044413b0, 0x00000000, - 0x00000000 +static const struct hda_pintbl dell_m4_2_pin_configs[] = { + { 0x0a, 0x0421101f }, + { 0x0b, 0x04a11221 }, + { 0x0c, 0x90a70330 }, + { 0x0d, 0x90170110 }, + { 0x0e, 0x23a1902e }, + { 0x0f, 0x23014250 }, + { 0x14, 0x40f000f0 }, + { 0x18, 0x40f000f0 }, + { 0x19, 0x40f000f0 }, + { 0x1e, 0x044413b0 }, + { 0x1f, 0x044413b0 }, + {} }; -static const unsigned int dell_m4_3_pin_configs[STAC92HD71BXX_NUM_PINS] = { - 0x0421101f, 0x04a11221, 0x90a70330, 0x90170110, - 0x40f000f0, 0x40f000f0, 0x40f000f0, 0x90a000f0, - 0x40f000f0, 0x044413b0, 0x044413b0, 0x00000000, - 0x00000000 +static const struct hda_pintbl dell_m4_3_pin_configs[] = { + { 0x0a, 0x0421101f }, + { 0x0b, 0x04a11221 }, + { 0x0c, 0x90a70330 }, + { 0x0d, 0x90170110 }, + { 0x0e, 0x40f000f0 }, + { 0x0f, 0x40f000f0 }, + { 0x14, 0x40f000f0 }, + { 0x18, 0x90a000f0 }, + { 0x19, 0x40f000f0 }, + { 0x1e, 0x044413b0 }, + { 0x1f, 0x044413b0 }, + {} }; -static const unsigned int *stac92hd71bxx_brd_tbl[STAC_92HD71BXX_MODELS] = { - [STAC_92HD71BXX_REF] = ref92hd71bxx_pin_configs, - [STAC_DELL_M4_1] = dell_m4_1_pin_configs, - [STAC_DELL_M4_2] = dell_m4_2_pin_configs, - [STAC_DELL_M4_3] = dell_m4_3_pin_configs, - [STAC_HP_M4] = NULL, - [STAC_HP_DV4] = NULL, - [STAC_HP_DV5] = NULL, - [STAC_HP_HDX] = NULL, - [STAC_HP_DV4_1222NR] = NULL, +static void stac92hd71bxx_fixup_ref(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct sigmatel_spec *spec = codec->spec; + + if (action != HDA_FIXUP_ACT_PRE_PROBE) + return; + + snd_hda_apply_pincfgs(codec, ref92hd71bxx_pin_configs); + spec->gpio_mask = spec->gpio_dir = spec->gpio_data = 0; +} + +static void stac92hd71bxx_fixup_hp_m4(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct sigmatel_spec *spec = codec->spec; + struct hda_jack_tbl *jack; + + if (action != HDA_FIXUP_ACT_PRE_PROBE) + return; + + /* Enable VREF power saving on GPIO1 detect */ + snd_hda_codec_write_cache(codec, codec->afg, 0, + AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x02); + snd_hda_jack_detect_enable_callback(codec, codec->afg, + STAC_VREF_EVENT, + stac_vref_event); + jack = snd_hda_jack_tbl_get(codec, codec->afg); + if (jack) + jack->private_data = 0x02; + + spec->gpio_mask |= 0x02; + + /* enable internal microphone */ + snd_hda_codec_set_pincfg(codec, 0x0e, 0x01813040); +} + +static void stac92hd71bxx_fixup_hp_dv4(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct sigmatel_spec *spec = codec->spec; + + if (action != HDA_FIXUP_ACT_PRE_PROBE) + return; + spec->gpio_led = 0x01; +} + +static void stac92hd71bxx_fixup_hp_dv5(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + unsigned int cap; + + switch (action) { + case HDA_FIXUP_ACT_PRE_PROBE: + snd_hda_codec_set_pincfg(codec, 0x0d, 0x90170010); + break; + + case HDA_FIXUP_ACT_PROBE: + /* enable bass on HP dv7 */ + cap = snd_hda_param_read(codec, 0x1, AC_PAR_GPIO_CAP); + cap &= AC_GPIO_IO_COUNT; + if (cap >= 6) + stac_add_hp_bass_switch(codec); + break; + } +} + +static void stac92hd71bxx_fixup_hp_hdx(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct sigmatel_spec *spec = codec->spec; + + if (action != HDA_FIXUP_ACT_PRE_PROBE) + return; + spec->gpio_led = 0x08; +} + + +static void stac92hd71bxx_fixup_hp(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct sigmatel_spec *spec = codec->spec; + + if (action != HDA_FIXUP_ACT_PRE_PROBE) + return; + + if (hp_blike_system(codec->subsystem_id)) { + unsigned int pin_cfg = snd_hda_codec_get_pincfg(codec, 0x0f); + if (get_defcfg_device(pin_cfg) == AC_JACK_LINE_OUT || + get_defcfg_device(pin_cfg) == AC_JACK_SPEAKER || + get_defcfg_device(pin_cfg) == AC_JACK_HP_OUT) { + /* It was changed in the BIOS to just satisfy MS DTM. + * Lets turn it back into slaved HP + */ + pin_cfg = (pin_cfg & (~AC_DEFCFG_DEVICE)) + | (AC_JACK_HP_OUT << + AC_DEFCFG_DEVICE_SHIFT); + pin_cfg = (pin_cfg & (~(AC_DEFCFG_DEF_ASSOC + | AC_DEFCFG_SEQUENCE))) + | 0x1f; + snd_hda_codec_set_pincfg(codec, 0x0f, pin_cfg); + } + } + + if (find_mute_led_cfg(codec, 1)) + snd_printd("mute LED gpio %d polarity %d\n", + spec->gpio_led, + spec->gpio_led_polarity); + +} + +static const struct hda_fixup stac92hd71bxx_fixups[] = { + [STAC_92HD71BXX_REF] = { + .type = HDA_FIXUP_FUNC, + .v.func = stac92hd71bxx_fixup_ref, + }, + [STAC_DELL_M4_1] = { + .type = HDA_FIXUP_PINS, + .v.pins = dell_m4_1_pin_configs, + }, + [STAC_DELL_M4_2] = { + .type = HDA_FIXUP_PINS, + .v.pins = dell_m4_2_pin_configs, + }, + [STAC_DELL_M4_3] = { + .type = HDA_FIXUP_PINS, + .v.pins = dell_m4_3_pin_configs, + }, + [STAC_HP_M4] = { + .type = HDA_FIXUP_FUNC, + .v.func = stac92hd71bxx_fixup_hp_m4, + .chained = true, + .chain_id = STAC_92HD71BXX_HP, + }, + [STAC_HP_DV4] = { + .type = HDA_FIXUP_FUNC, + .v.func = stac92hd71bxx_fixup_hp_dv4, + .chained = true, + .chain_id = STAC_HP_DV5, + }, + [STAC_HP_DV5] = { + .type = HDA_FIXUP_FUNC, + .v.func = stac92hd71bxx_fixup_hp_dv5, + .chained = true, + .chain_id = STAC_92HD71BXX_HP, + }, + [STAC_HP_HDX] = { + .type = HDA_FIXUP_FUNC, + .v.func = stac92hd71bxx_fixup_hp_hdx, + .chained = true, + .chain_id = STAC_92HD71BXX_HP, + }, + [STAC_92HD71BXX_HP] = { + .type = HDA_FIXUP_FUNC, + .v.func = stac92hd71bxx_fixup_hp, + }, }; -static const char * const stac92hd71bxx_models[STAC_92HD71BXX_MODELS] = { - [STAC_92HD71BXX_AUTO] = "auto", - [STAC_92HD71BXX_REF] = "ref", - [STAC_DELL_M4_1] = "dell-m4-1", - [STAC_DELL_M4_2] = "dell-m4-2", - [STAC_DELL_M4_3] = "dell-m4-3", - [STAC_HP_M4] = "hp-m4", - [STAC_HP_DV4] = "hp-dv4", - [STAC_HP_DV5] = "hp-dv5", - [STAC_HP_HDX] = "hp-hdx", - [STAC_HP_DV4_1222NR] = "hp-dv4-1222nr", +static const struct hda_model_fixup stac92hd71bxx_models[] = { + { .id = STAC_92HD71BXX_REF, .name = "ref" }, + { .id = STAC_DELL_M4_1, .name = "dell-m4-1" }, + { .id = STAC_DELL_M4_2, .name = "dell-m4-2" }, + { .id = STAC_DELL_M4_3, .name = "dell-m4-3" }, + { .id = STAC_HP_M4, .name = "hp-m4" }, + { .id = STAC_HP_DV4, .name = "hp-dv4" }, + { .id = STAC_HP_DV5, .name = "hp-dv5" }, + { .id = STAC_HP_HDX, .name = "hp-hdx" }, + { .id = STAC_HP_DV4, .name = "hp-dv4-1222nr" }, + {} }; -static const struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = { +static const struct snd_pci_quirk stac92hd71bxx_fixup_tbl[] = { /* SigmaTel reference board */ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_92HD71BXX_REF), SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101, "DFI LanParty", STAC_92HD71BXX_REF), - SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30fb, - "HP dv4-1222nr", STAC_HP_DV4_1222NR), SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x1720, "HP", STAC_HP_DV5), SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x3080, @@ -1857,6 +2558,7 @@ static const struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = { "HP DV6", STAC_HP_DV5), SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x7010, "HP", STAC_HP_DV5), + SND_PCI_QUIRK_VENDOR(PCI_VENDOR_ID_HP, "HP", STAC_92HD71BXX_HP), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0233, "unknown Dell", STAC_DELL_M4_1), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0234, @@ -1884,10 +2586,18 @@ static const struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = { {} /* terminator */ }; -static const unsigned int ref922x_pin_configs[10] = { - 0x01014010, 0x01016011, 0x01012012, 0x0221401f, - 0x01813122, 0x01011014, 0x01441030, 0x01c41030, - 0x40000100, 0x40000100, +static const struct hda_pintbl ref922x_pin_configs[] = { + { 0x0a, 0x01014010 }, + { 0x0b, 0x01016011 }, + { 0x0c, 0x01012012 }, + { 0x0d, 0x0221401f }, + { 0x0e, 0x01813122 }, + { 0x0f, 0x01011014 }, + { 0x10, 0x01441030 }, + { 0x11, 0x01c41030 }, + { 0x15, 0x40000100 }, + { 0x1b, 0x40000100 }, + {} }; /* @@ -1898,10 +2608,18 @@ static const unsigned int ref922x_pin_configs[10] = { 102801D1 102801D2 */ -static const unsigned int dell_922x_d81_pin_configs[10] = { - 0x02214030, 0x01a19021, 0x01111012, 0x01114010, - 0x02a19020, 0x01117011, 0x400001f0, 0x400001f1, - 0x01813122, 0x400001f2, +static const struct hda_pintbl dell_922x_d81_pin_configs[] = { + { 0x0a, 0x02214030 }, + { 0x0b, 0x01a19021 }, + { 0x0c, 0x01111012 }, + { 0x0d, 0x01114010 }, + { 0x0e, 0x02a19020 }, + { 0x0f, 0x01117011 }, + { 0x10, 0x400001f0 }, + { 0x11, 0x400001f1 }, + { 0x15, 0x01813122 }, + { 0x1b, 0x400001f2 }, + {} }; /* @@ -1909,130 +2627,311 @@ static const unsigned int dell_922x_d81_pin_configs[10] = { 102801AC 102801D0 */ -static const unsigned int dell_922x_d82_pin_configs[10] = { - 0x02214030, 0x01a19021, 0x01111012, 0x01114010, - 0x02a19020, 0x01117011, 0x01451140, 0x400001f0, - 0x01813122, 0x400001f1, +static const struct hda_pintbl dell_922x_d82_pin_configs[] = { + { 0x0a, 0x02214030 }, + { 0x0b, 0x01a19021 }, + { 0x0c, 0x01111012 }, + { 0x0d, 0x01114010 }, + { 0x0e, 0x02a19020 }, + { 0x0f, 0x01117011 }, + { 0x10, 0x01451140 }, + { 0x11, 0x400001f0 }, + { 0x15, 0x01813122 }, + { 0x1b, 0x400001f1 }, + {} }; /* STAC 922X pin configs for 102801BF */ -static const unsigned int dell_922x_m81_pin_configs[10] = { - 0x0321101f, 0x01112024, 0x01111222, 0x91174220, - 0x03a11050, 0x01116221, 0x90a70330, 0x01452340, - 0x40C003f1, 0x405003f0, +static const struct hda_pintbl dell_922x_m81_pin_configs[] = { + { 0x0a, 0x0321101f }, + { 0x0b, 0x01112024 }, + { 0x0c, 0x01111222 }, + { 0x0d, 0x91174220 }, + { 0x0e, 0x03a11050 }, + { 0x0f, 0x01116221 }, + { 0x10, 0x90a70330 }, + { 0x11, 0x01452340 }, + { 0x15, 0x40C003f1 }, + { 0x1b, 0x405003f0 }, + {} }; /* STAC 9221 A1 pin configs for 102801D7 (Dell XPS M1210) */ -static const unsigned int dell_922x_m82_pin_configs[10] = { - 0x02211211, 0x408103ff, 0x02a1123e, 0x90100310, - 0x408003f1, 0x0221121f, 0x03451340, 0x40c003f2, - 0x508003f3, 0x405003f4, +static const struct hda_pintbl dell_922x_m82_pin_configs[] = { + { 0x0a, 0x02211211 }, + { 0x0b, 0x408103ff }, + { 0x0c, 0x02a1123e }, + { 0x0d, 0x90100310 }, + { 0x0e, 0x408003f1 }, + { 0x0f, 0x0221121f }, + { 0x10, 0x03451340 }, + { 0x11, 0x40c003f2 }, + { 0x15, 0x508003f3 }, + { 0x1b, 0x405003f4 }, + {} }; -static const unsigned int d945gtp3_pin_configs[10] = { - 0x0221401f, 0x01a19022, 0x01813021, 0x01014010, - 0x40000100, 0x40000100, 0x40000100, 0x40000100, - 0x02a19120, 0x40000100, +static const struct hda_pintbl d945gtp3_pin_configs[] = { + { 0x0a, 0x0221401f }, + { 0x0b, 0x01a19022 }, + { 0x0c, 0x01813021 }, + { 0x0d, 0x01014010 }, + { 0x0e, 0x40000100 }, + { 0x0f, 0x40000100 }, + { 0x10, 0x40000100 }, + { 0x11, 0x40000100 }, + { 0x15, 0x02a19120 }, + { 0x1b, 0x40000100 }, + {} }; -static const unsigned int d945gtp5_pin_configs[10] = { - 0x0221401f, 0x01011012, 0x01813024, 0x01014010, - 0x01a19021, 0x01016011, 0x01452130, 0x40000100, - 0x02a19320, 0x40000100, +static const struct hda_pintbl d945gtp5_pin_configs[] = { + { 0x0a, 0x0221401f }, + { 0x0b, 0x01011012 }, + { 0x0c, 0x01813024 }, + { 0x0d, 0x01014010 }, + { 0x0e, 0x01a19021 }, + { 0x0f, 0x01016011 }, + { 0x10, 0x01452130 }, + { 0x11, 0x40000100 }, + { 0x15, 0x02a19320 }, + { 0x1b, 0x40000100 }, + {} }; -static const unsigned int intel_mac_v1_pin_configs[10] = { - 0x0121e21f, 0x400000ff, 0x9017e110, 0x400000fd, - 0x400000fe, 0x0181e020, 0x1145e030, 0x11c5e240, - 0x400000fc, 0x400000fb, +static const struct hda_pintbl intel_mac_v1_pin_configs[] = { + { 0x0a, 0x0121e21f }, + { 0x0b, 0x400000ff }, + { 0x0c, 0x9017e110 }, + { 0x0d, 0x400000fd }, + { 0x0e, 0x400000fe }, + { 0x0f, 0x0181e020 }, + { 0x10, 0x1145e030 }, + { 0x11, 0x11c5e240 }, + { 0x15, 0x400000fc }, + { 0x1b, 0x400000fb }, + {} }; -static const unsigned int intel_mac_v2_pin_configs[10] = { - 0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd, - 0x400000fe, 0x0181e020, 0x1145e230, 0x500000fa, - 0x400000fc, 0x400000fb, +static const struct hda_pintbl intel_mac_v2_pin_configs[] = { + { 0x0a, 0x0121e21f }, + { 0x0b, 0x90a7012e }, + { 0x0c, 0x9017e110 }, + { 0x0d, 0x400000fd }, + { 0x0e, 0x400000fe }, + { 0x0f, 0x0181e020 }, + { 0x10, 0x1145e230 }, + { 0x11, 0x500000fa }, + { 0x15, 0x400000fc }, + { 0x1b, 0x400000fb }, + {} }; -static const unsigned int intel_mac_v3_pin_configs[10] = { - 0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd, - 0x400000fe, 0x0181e020, 0x1145e230, 0x11c5e240, - 0x400000fc, 0x400000fb, +static const struct hda_pintbl intel_mac_v3_pin_configs[] = { + { 0x0a, 0x0121e21f }, + { 0x0b, 0x90a7012e }, + { 0x0c, 0x9017e110 }, + { 0x0d, 0x400000fd }, + { 0x0e, 0x400000fe }, + { 0x0f, 0x0181e020 }, + { 0x10, 0x1145e230 }, + { 0x11, 0x11c5e240 }, + { 0x15, 0x400000fc }, + { 0x1b, 0x400000fb }, + {} }; -static const unsigned int intel_mac_v4_pin_configs[10] = { - 0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f, - 0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240, - 0x400000fc, 0x400000fb, +static const struct hda_pintbl intel_mac_v4_pin_configs[] = { + { 0x0a, 0x0321e21f }, + { 0x0b, 0x03a1e02e }, + { 0x0c, 0x9017e110 }, + { 0x0d, 0x9017e11f }, + { 0x0e, 0x400000fe }, + { 0x0f, 0x0381e020 }, + { 0x10, 0x1345e230 }, + { 0x11, 0x13c5e240 }, + { 0x15, 0x400000fc }, + { 0x1b, 0x400000fb }, + {} }; -static const unsigned int intel_mac_v5_pin_configs[10] = { - 0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f, - 0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240, - 0x400000fc, 0x400000fb, +static const struct hda_pintbl intel_mac_v5_pin_configs[] = { + { 0x0a, 0x0321e21f }, + { 0x0b, 0x03a1e02e }, + { 0x0c, 0x9017e110 }, + { 0x0d, 0x9017e11f }, + { 0x0e, 0x400000fe }, + { 0x0f, 0x0381e020 }, + { 0x10, 0x1345e230 }, + { 0x11, 0x13c5e240 }, + { 0x15, 0x400000fc }, + { 0x1b, 0x400000fb }, + {} }; -static const unsigned int ecs202_pin_configs[10] = { - 0x0221401f, 0x02a19020, 0x01a19020, 0x01114010, - 0x408000f0, 0x01813022, 0x074510a0, 0x40c400f1, - 0x9037012e, 0x40e000f2, +static const struct hda_pintbl ecs202_pin_configs[] = { + { 0x0a, 0x0221401f }, + { 0x0b, 0x02a19020 }, + { 0x0c, 0x01a19020 }, + { 0x0d, 0x01114010 }, + { 0x0e, 0x408000f0 }, + { 0x0f, 0x01813022 }, + { 0x10, 0x074510a0 }, + { 0x11, 0x40c400f1 }, + { 0x15, 0x9037012e }, + { 0x1b, 0x40e000f2 }, + {} }; -static const unsigned int *stac922x_brd_tbl[STAC_922X_MODELS] = { - [STAC_D945_REF] = ref922x_pin_configs, - [STAC_D945GTP3] = d945gtp3_pin_configs, - [STAC_D945GTP5] = d945gtp5_pin_configs, - [STAC_INTEL_MAC_V1] = intel_mac_v1_pin_configs, - [STAC_INTEL_MAC_V2] = intel_mac_v2_pin_configs, - [STAC_INTEL_MAC_V3] = intel_mac_v3_pin_configs, - [STAC_INTEL_MAC_V4] = intel_mac_v4_pin_configs, - [STAC_INTEL_MAC_V5] = intel_mac_v5_pin_configs, - [STAC_INTEL_MAC_AUTO] = intel_mac_v3_pin_configs, - /* for backward compatibility */ - [STAC_MACMINI] = intel_mac_v3_pin_configs, - [STAC_MACBOOK] = intel_mac_v5_pin_configs, - [STAC_MACBOOK_PRO_V1] = intel_mac_v3_pin_configs, - [STAC_MACBOOK_PRO_V2] = intel_mac_v3_pin_configs, - [STAC_IMAC_INTEL] = intel_mac_v2_pin_configs, - [STAC_IMAC_INTEL_20] = intel_mac_v3_pin_configs, - [STAC_ECS_202] = ecs202_pin_configs, - [STAC_922X_DELL_D81] = dell_922x_d81_pin_configs, - [STAC_922X_DELL_D82] = dell_922x_d82_pin_configs, - [STAC_922X_DELL_M81] = dell_922x_m81_pin_configs, - [STAC_922X_DELL_M82] = dell_922x_m82_pin_configs, +/* codec SSIDs for Intel Mac sharing the same PCI SSID 8384:7680 */ +static const struct snd_pci_quirk stac922x_intel_mac_fixup_tbl[] = { + SND_PCI_QUIRK(0x106b, 0x0800, "Mac", STAC_INTEL_MAC_V1), + SND_PCI_QUIRK(0x106b, 0x0600, "Mac", STAC_INTEL_MAC_V2), + SND_PCI_QUIRK(0x106b, 0x0700, "Mac", STAC_INTEL_MAC_V2), + SND_PCI_QUIRK(0x106b, 0x0e00, "Mac", STAC_INTEL_MAC_V3), + SND_PCI_QUIRK(0x106b, 0x0f00, "Mac", STAC_INTEL_MAC_V3), + SND_PCI_QUIRK(0x106b, 0x1600, "Mac", STAC_INTEL_MAC_V3), + SND_PCI_QUIRK(0x106b, 0x1700, "Mac", STAC_INTEL_MAC_V3), + SND_PCI_QUIRK(0x106b, 0x0200, "Mac", STAC_INTEL_MAC_V3), + SND_PCI_QUIRK(0x106b, 0x1e00, "Mac", STAC_INTEL_MAC_V3), + SND_PCI_QUIRK(0x106b, 0x1a00, "Mac", STAC_INTEL_MAC_V4), + SND_PCI_QUIRK(0x106b, 0x0a00, "Mac", STAC_INTEL_MAC_V5), + SND_PCI_QUIRK(0x106b, 0x2200, "Mac", STAC_INTEL_MAC_V5), + {} +}; + +static const struct hda_fixup stac922x_fixups[]; + +/* remap the fixup from codec SSID and apply it */ +static void stac922x_fixup_intel_mac_auto(struct hda_codec *codec, + const struct hda_fixup *fix, + int action) +{ + if (action != HDA_FIXUP_ACT_PRE_PROBE) + return; + snd_hda_pick_fixup(codec, NULL, stac922x_intel_mac_fixup_tbl, + stac922x_fixups); + if (codec->fixup_id != STAC_INTEL_MAC_AUTO) + snd_hda_apply_fixup(codec, action); +} + +static void stac922x_fixup_intel_mac_gpio(struct hda_codec *codec, + const struct hda_fixup *fix, + int action) +{ + struct sigmatel_spec *spec = codec->spec; + + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + spec->gpio_mask = spec->gpio_dir = 0x03; + spec->gpio_data = 0x03; + } +} + +static const struct hda_fixup stac922x_fixups[] = { + [STAC_D945_REF] = { + .type = HDA_FIXUP_PINS, + .v.pins = ref922x_pin_configs, + }, + [STAC_D945GTP3] = { + .type = HDA_FIXUP_PINS, + .v.pins = d945gtp3_pin_configs, + }, + [STAC_D945GTP5] = { + .type = HDA_FIXUP_PINS, + .v.pins = d945gtp5_pin_configs, + }, + [STAC_INTEL_MAC_AUTO] = { + .type = HDA_FIXUP_FUNC, + .v.func = stac922x_fixup_intel_mac_auto, + }, + [STAC_INTEL_MAC_V1] = { + .type = HDA_FIXUP_PINS, + .v.pins = intel_mac_v1_pin_configs, + .chained = true, + .chain_id = STAC_922X_INTEL_MAC_GPIO, + }, + [STAC_INTEL_MAC_V2] = { + .type = HDA_FIXUP_PINS, + .v.pins = intel_mac_v2_pin_configs, + .chained = true, + .chain_id = STAC_922X_INTEL_MAC_GPIO, + }, + [STAC_INTEL_MAC_V3] = { + .type = HDA_FIXUP_PINS, + .v.pins = intel_mac_v3_pin_configs, + .chained = true, + .chain_id = STAC_922X_INTEL_MAC_GPIO, + }, + [STAC_INTEL_MAC_V4] = { + .type = HDA_FIXUP_PINS, + .v.pins = intel_mac_v4_pin_configs, + .chained = true, + .chain_id = STAC_922X_INTEL_MAC_GPIO, + }, + [STAC_INTEL_MAC_V5] = { + .type = HDA_FIXUP_PINS, + .v.pins = intel_mac_v5_pin_configs, + .chained = true, + .chain_id = STAC_922X_INTEL_MAC_GPIO, + }, + [STAC_922X_INTEL_MAC_GPIO] = { + .type = HDA_FIXUP_FUNC, + .v.func = stac922x_fixup_intel_mac_gpio, + }, + [STAC_ECS_202] = { + .type = HDA_FIXUP_PINS, + .v.pins = ecs202_pin_configs, + }, + [STAC_922X_DELL_D81] = { + .type = HDA_FIXUP_PINS, + .v.pins = dell_922x_d81_pin_configs, + }, + [STAC_922X_DELL_D82] = { + .type = HDA_FIXUP_PINS, + .v.pins = dell_922x_d82_pin_configs, + }, + [STAC_922X_DELL_M81] = { + .type = HDA_FIXUP_PINS, + .v.pins = dell_922x_m81_pin_configs, + }, + [STAC_922X_DELL_M82] = { + .type = HDA_FIXUP_PINS, + .v.pins = dell_922x_m82_pin_configs, + }, }; -static const char * const stac922x_models[STAC_922X_MODELS] = { - [STAC_922X_AUTO] = "auto", - [STAC_D945_REF] = "ref", - [STAC_D945GTP5] = "5stack", - [STAC_D945GTP3] = "3stack", - [STAC_INTEL_MAC_V1] = "intel-mac-v1", - [STAC_INTEL_MAC_V2] = "intel-mac-v2", - [STAC_INTEL_MAC_V3] = "intel-mac-v3", - [STAC_INTEL_MAC_V4] = "intel-mac-v4", - [STAC_INTEL_MAC_V5] = "intel-mac-v5", - [STAC_INTEL_MAC_AUTO] = "intel-mac-auto", +static const struct hda_model_fixup stac922x_models[] = { + { .id = STAC_D945_REF, .name = "ref" }, + { .id = STAC_D945GTP5, .name = "5stack" }, + { .id = STAC_D945GTP3, .name = "3stack" }, + { .id = STAC_INTEL_MAC_V1, .name = "intel-mac-v1" }, + { .id = STAC_INTEL_MAC_V2, .name = "intel-mac-v2" }, + { .id = STAC_INTEL_MAC_V3, .name = "intel-mac-v3" }, + { .id = STAC_INTEL_MAC_V4, .name = "intel-mac-v4" }, + { .id = STAC_INTEL_MAC_V5, .name = "intel-mac-v5" }, + { .id = STAC_INTEL_MAC_AUTO, .name = "intel-mac-auto" }, + { .id = STAC_ECS_202, .name = "ecs202" }, + { .id = STAC_922X_DELL_D81, .name = "dell-d81" }, + { .id = STAC_922X_DELL_D82, .name = "dell-d82" }, + { .id = STAC_922X_DELL_M81, .name = "dell-m81" }, + { .id = STAC_922X_DELL_M82, .name = "dell-m82" }, /* for backward compatibility */ - [STAC_MACMINI] = "macmini", - [STAC_MACBOOK] = "macbook", - [STAC_MACBOOK_PRO_V1] = "macbook-pro-v1", - [STAC_MACBOOK_PRO_V2] = "macbook-pro", - [STAC_IMAC_INTEL] = "imac-intel", - [STAC_IMAC_INTEL_20] = "imac-intel-20", - [STAC_ECS_202] = "ecs202", - [STAC_922X_DELL_D81] = "dell-d81", - [STAC_922X_DELL_D82] = "dell-d82", - [STAC_922X_DELL_M81] = "dell-m81", - [STAC_922X_DELL_M82] = "dell-m82", + { .id = STAC_INTEL_MAC_V3, .name = "macmini" }, + { .id = STAC_INTEL_MAC_V5, .name = "macbook" }, + { .id = STAC_INTEL_MAC_V3, .name = "macbook-pro-v1" }, + { .id = STAC_INTEL_MAC_V3, .name = "macbook-pro" }, + { .id = STAC_INTEL_MAC_V2, .name = "imac-intel" }, + { .id = STAC_INTEL_MAC_V3, .name = "imac-intel-20" }, + {} }; -static const struct snd_pci_quirk stac922x_cfg_tbl[] = { +static const struct snd_pci_quirk stac922x_fixup_tbl[] = { /* SigmaTel reference board */ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_D945_REF), @@ -2095,9 +2994,10 @@ static const struct snd_pci_quirk stac922x_cfg_tbl[] = { SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0204, "Intel D945", STAC_D945_REF), /* other systems */ + /* Apple Intel Mac (Mac Mini, MacBook, MacBook Pro...) */ - SND_PCI_QUIRK(0x8384, 0x7680, - "Mac", STAC_INTEL_MAC_AUTO), + SND_PCI_QUIRK(0x8384, 0x7680, "Mac", STAC_INTEL_MAC_AUTO), + /* Dell systems */ SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a7, "unknown Dell", STAC_922X_DELL_D81), @@ -2123,65 +3023,229 @@ static const struct snd_pci_quirk stac922x_cfg_tbl[] = { {} /* terminator */ }; -static const unsigned int ref927x_pin_configs[14] = { - 0x02214020, 0x02a19080, 0x0181304e, 0x01014010, - 0x01a19040, 0x01011012, 0x01016011, 0x0101201f, - 0x183301f0, 0x18a001f0, 0x18a001f0, 0x01442070, - 0x01c42190, 0x40000100, +static const struct hda_pintbl ref927x_pin_configs[] = { + { 0x0a, 0x02214020 }, + { 0x0b, 0x02a19080 }, + { 0x0c, 0x0181304e }, + { 0x0d, 0x01014010 }, + { 0x0e, 0x01a19040 }, + { 0x0f, 0x01011012 }, + { 0x10, 0x01016011 }, + { 0x11, 0x0101201f }, + { 0x12, 0x183301f0 }, + { 0x13, 0x18a001f0 }, + { 0x14, 0x18a001f0 }, + { 0x21, 0x01442070 }, + { 0x22, 0x01c42190 }, + { 0x23, 0x40000100 }, + {} }; -static const unsigned int d965_3st_pin_configs[14] = { - 0x0221401f, 0x02a19120, 0x40000100, 0x01014011, - 0x01a19021, 0x01813024, 0x40000100, 0x40000100, - 0x40000100, 0x40000100, 0x40000100, 0x40000100, - 0x40000100, 0x40000100 +static const struct hda_pintbl d965_3st_pin_configs[] = { + { 0x0a, 0x0221401f }, + { 0x0b, 0x02a19120 }, + { 0x0c, 0x40000100 }, + { 0x0d, 0x01014011 }, + { 0x0e, 0x01a19021 }, + { 0x0f, 0x01813024 }, + { 0x10, 0x40000100 }, + { 0x11, 0x40000100 }, + { 0x12, 0x40000100 }, + { 0x13, 0x40000100 }, + { 0x14, 0x40000100 }, + { 0x21, 0x40000100 }, + { 0x22, 0x40000100 }, + { 0x23, 0x40000100 }, + {} }; -static const unsigned int d965_5st_pin_configs[14] = { - 0x02214020, 0x02a19080, 0x0181304e, 0x01014010, - 0x01a19040, 0x01011012, 0x01016011, 0x40000100, - 0x40000100, 0x40000100, 0x40000100, 0x01442070, - 0x40000100, 0x40000100 +static const struct hda_pintbl d965_5st_pin_configs[] = { + { 0x0a, 0x02214020 }, + { 0x0b, 0x02a19080 }, + { 0x0c, 0x0181304e }, + { 0x0d, 0x01014010 }, + { 0x0e, 0x01a19040 }, + { 0x0f, 0x01011012 }, + { 0x10, 0x01016011 }, + { 0x11, 0x40000100 }, + { 0x12, 0x40000100 }, + { 0x13, 0x40000100 }, + { 0x14, 0x40000100 }, + { 0x21, 0x01442070 }, + { 0x22, 0x40000100 }, + { 0x23, 0x40000100 }, + {} }; -static const unsigned int d965_5st_no_fp_pin_configs[14] = { - 0x40000100, 0x40000100, 0x0181304e, 0x01014010, - 0x01a19040, 0x01011012, 0x01016011, 0x40000100, - 0x40000100, 0x40000100, 0x40000100, 0x01442070, - 0x40000100, 0x40000100 +static const struct hda_pintbl d965_5st_no_fp_pin_configs[] = { + { 0x0a, 0x40000100 }, + { 0x0b, 0x40000100 }, + { 0x0c, 0x0181304e }, + { 0x0d, 0x01014010 }, + { 0x0e, 0x01a19040 }, + { 0x0f, 0x01011012 }, + { 0x10, 0x01016011 }, + { 0x11, 0x40000100 }, + { 0x12, 0x40000100 }, + { 0x13, 0x40000100 }, + { 0x14, 0x40000100 }, + { 0x21, 0x01442070 }, + { 0x22, 0x40000100 }, + { 0x23, 0x40000100 }, + {} }; -static const unsigned int dell_3st_pin_configs[14] = { - 0x02211230, 0x02a11220, 0x01a19040, 0x01114210, - 0x01111212, 0x01116211, 0x01813050, 0x01112214, - 0x403003fa, 0x90a60040, 0x90a60040, 0x404003fb, - 0x40c003fc, 0x40000100 +static const struct hda_pintbl dell_3st_pin_configs[] = { + { 0x0a, 0x02211230 }, + { 0x0b, 0x02a11220 }, + { 0x0c, 0x01a19040 }, + { 0x0d, 0x01114210 }, + { 0x0e, 0x01111212 }, + { 0x0f, 0x01116211 }, + { 0x10, 0x01813050 }, + { 0x11, 0x01112214 }, + { 0x12, 0x403003fa }, + { 0x13, 0x90a60040 }, + { 0x14, 0x90a60040 }, + { 0x21, 0x404003fb }, + { 0x22, 0x40c003fc }, + { 0x23, 0x40000100 }, + {} }; -static const unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = { - [STAC_D965_REF_NO_JD] = ref927x_pin_configs, - [STAC_D965_REF] = ref927x_pin_configs, - [STAC_D965_3ST] = d965_3st_pin_configs, - [STAC_D965_5ST] = d965_5st_pin_configs, - [STAC_D965_5ST_NO_FP] = d965_5st_no_fp_pin_configs, - [STAC_DELL_3ST] = dell_3st_pin_configs, - [STAC_DELL_BIOS] = NULL, - [STAC_927X_VOLKNOB] = NULL, +static void stac927x_fixup_ref_no_jd(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + /* no jack detecion for ref-no-jd model */ + if (action == HDA_FIXUP_ACT_PRE_PROBE) + codec->no_jack_detect = 1; +} + +static void stac927x_fixup_ref(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct sigmatel_spec *spec = codec->spec; + + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + snd_hda_apply_pincfgs(codec, ref927x_pin_configs); + spec->eapd_mask = spec->gpio_mask = 0; + spec->gpio_dir = spec->gpio_data = 0; + } +} + +static void stac927x_fixup_dell_dmic(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct sigmatel_spec *spec = codec->spec; + + if (action != HDA_FIXUP_ACT_PRE_PROBE) + return; + + if (codec->subsystem_id != 0x1028022f) { + /* GPIO2 High = Enable EAPD */ + spec->eapd_mask = spec->gpio_mask = 0x04; + spec->gpio_dir = spec->gpio_data = 0x04; + } + + snd_hda_add_verbs(codec, dell_3st_core_init); + spec->volknob_init = 1; +} + +static void stac927x_fixup_volknob(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct sigmatel_spec *spec = codec->spec; + + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + snd_hda_add_verbs(codec, stac927x_volknob_core_init); + spec->volknob_init = 1; + } +} + +static const struct hda_fixup stac927x_fixups[] = { + [STAC_D965_REF_NO_JD] = { + .type = HDA_FIXUP_FUNC, + .v.func = stac927x_fixup_ref_no_jd, + .chained = true, + .chain_id = STAC_D965_REF, + }, + [STAC_D965_REF] = { + .type = HDA_FIXUP_FUNC, + .v.func = stac927x_fixup_ref, + }, + [STAC_D965_3ST] = { + .type = HDA_FIXUP_PINS, + .v.pins = d965_3st_pin_configs, + .chained = true, + .chain_id = STAC_D965_VERBS, + }, + [STAC_D965_5ST] = { + .type = HDA_FIXUP_PINS, + .v.pins = d965_5st_pin_configs, + .chained = true, + .chain_id = STAC_D965_VERBS, + }, + [STAC_D965_VERBS] = { + .type = HDA_FIXUP_VERBS, + .v.verbs = d965_core_init, + }, + [STAC_D965_5ST_NO_FP] = { + .type = HDA_FIXUP_PINS, + .v.pins = d965_5st_no_fp_pin_configs, + }, + [STAC_DELL_3ST] = { + .type = HDA_FIXUP_PINS, + .v.pins = dell_3st_pin_configs, + .chained = true, + .chain_id = STAC_927X_DELL_DMIC, + }, + [STAC_DELL_BIOS] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + /* configure the analog microphone on some laptops */ + { 0x0c, 0x90a79130 }, + /* correct the front output jack as a hp out */ + { 0x0f, 0x0227011f }, + /* correct the front input jack as a mic */ + { 0x0e, 0x02a79130 }, + {} + }, + .chained = true, + .chain_id = STAC_927X_DELL_DMIC, + }, + [STAC_DELL_BIOS_SPDIF] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + /* correct the device field to SPDIF out */ + { 0x21, 0x01442070 }, + {} + }, + .chained = true, + .chain_id = STAC_DELL_BIOS, + }, + [STAC_927X_DELL_DMIC] = { + .type = HDA_FIXUP_FUNC, + .v.func = stac927x_fixup_dell_dmic, + }, + [STAC_927X_VOLKNOB] = { + .type = HDA_FIXUP_FUNC, + .v.func = stac927x_fixup_volknob, + }, }; -static const char * const stac927x_models[STAC_927X_MODELS] = { - [STAC_927X_AUTO] = "auto", - [STAC_D965_REF_NO_JD] = "ref-no-jd", - [STAC_D965_REF] = "ref", - [STAC_D965_3ST] = "3stack", - [STAC_D965_5ST] = "5stack", - [STAC_D965_5ST_NO_FP] = "5stack-no-fp", - [STAC_DELL_3ST] = "dell-3stack", - [STAC_DELL_BIOS] = "dell-bios", - [STAC_927X_VOLKNOB] = "volknob", +static const struct hda_model_fixup stac927x_models[] = { + { .id = STAC_D965_REF_NO_JD, .name = "ref-no-jd" }, + { .id = STAC_D965_REF, .name = "ref" }, + { .id = STAC_D965_3ST, .name = "3stack" }, + { .id = STAC_D965_5ST, .name = "5stack" }, + { .id = STAC_D965_5ST_NO_FP, .name = "5stack-no-fp" }, + { .id = STAC_DELL_3ST, .name = "dell-3stack" }, + { .id = STAC_DELL_BIOS, .name = "dell-bios" }, + { .id = STAC_927X_VOLKNOB, .name = "volknob" }, + {} }; -static const struct snd_pci_quirk stac927x_cfg_tbl[] = { +static const struct snd_pci_quirk stac927x_fixup_tbl[] = { /* SigmaTel reference board */ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_D965_REF), @@ -2203,12 +3267,12 @@ static const struct snd_pci_quirk stac927x_cfg_tbl[] = { SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f3, "Dell Inspiron 1420", STAC_DELL_BIOS), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f7, "Dell XPS M1730", STAC_DELL_BIOS), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0227, "Dell Vostro 1400 ", STAC_DELL_BIOS), - SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x022e, "Dell ", STAC_DELL_BIOS), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x022e, "Dell ", STAC_DELL_BIOS_SPDIF), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x022f, "Dell Inspiron 1525", STAC_DELL_BIOS), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0242, "Dell ", STAC_DELL_BIOS), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0243, "Dell ", STAC_DELL_BIOS), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02ff, "Dell ", STAC_DELL_BIOS), - SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0209, "Dell XPS 1330", STAC_DELL_BIOS), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0209, "Dell XPS 1330", STAC_DELL_BIOS_SPDIF), /* 965 based 5 stack systems */ SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_INTEL, 0xff00, 0x2300, "Intel D965", STAC_D965_5ST), @@ -2219,10 +3283,20 @@ static const struct snd_pci_quirk stac927x_cfg_tbl[] = { {} /* terminator */ }; -static const unsigned int ref9205_pin_configs[12] = { - 0x40000100, 0x40000100, 0x01016011, 0x01014010, - 0x01813122, 0x01a19021, 0x01019020, 0x40000100, - 0x90a000f0, 0x90a000f0, 0x01441030, 0x01c41030 +static const struct hda_pintbl ref9205_pin_configs[] = { + { 0x0a, 0x40000100 }, + { 0x0b, 0x40000100 }, + { 0x0c, 0x01016011 }, + { 0x0d, 0x01014010 }, + { 0x0e, 0x01813122 }, + { 0x0f, 0x01a19021 }, + { 0x14, 0x01019020 }, + { 0x16, 0x40000100 }, + { 0x17, 0x90a000f0 }, + { 0x18, 0x90a000f0 }, + { 0x21, 0x01441030 }, + { 0x22, 0x01c41030 }, + {} }; /* @@ -2236,10 +3310,20 @@ static const unsigned int ref9205_pin_configs[12] = { 10280228 (Dell Vostro 1500) 10280229 (Dell Vostro 1700) */ -static const unsigned int dell_9205_m42_pin_configs[12] = { - 0x0321101F, 0x03A11020, 0x400003FA, 0x90170310, - 0x400003FB, 0x400003FC, 0x400003FD, 0x40F000F9, - 0x90A60330, 0x400003FF, 0x0144131F, 0x40C003FE, +static const struct hda_pintbl dell_9205_m42_pin_configs[] = { + { 0x0a, 0x0321101F }, + { 0x0b, 0x03A11020 }, + { 0x0c, 0x400003FA }, + { 0x0d, 0x90170310 }, + { 0x0e, 0x400003FB }, + { 0x0f, 0x400003FC }, + { 0x14, 0x400003FD }, + { 0x16, 0x40F000F9 }, + { 0x17, 0x90A60330 }, + { 0x18, 0x400003FF }, + { 0x21, 0x0144131F }, + { 0x22, 0x40C003FE }, + {} }; /* @@ -2252,36 +3336,126 @@ static const unsigned int dell_9205_m42_pin_configs[12] = { 10280200 10280201 */ -static const unsigned int dell_9205_m43_pin_configs[12] = { - 0x0321101f, 0x03a11020, 0x90a70330, 0x90170310, - 0x400000fe, 0x400000ff, 0x400000fd, 0x40f000f9, - 0x400000fa, 0x400000fc, 0x0144131f, 0x40c003f8, +static const struct hda_pintbl dell_9205_m43_pin_configs[] = { + { 0x0a, 0x0321101f }, + { 0x0b, 0x03a11020 }, + { 0x0c, 0x90a70330 }, + { 0x0d, 0x90170310 }, + { 0x0e, 0x400000fe }, + { 0x0f, 0x400000ff }, + { 0x14, 0x400000fd }, + { 0x16, 0x40f000f9 }, + { 0x17, 0x400000fa }, + { 0x18, 0x400000fc }, + { 0x21, 0x0144131f }, + { 0x22, 0x40c003f8 }, + /* Enable SPDIF in/out */ + { 0x1f, 0x01441030 }, + { 0x20, 0x1c410030 }, + {} }; -static const unsigned int dell_9205_m44_pin_configs[12] = { - 0x0421101f, 0x04a11020, 0x400003fa, 0x90170310, - 0x400003fb, 0x400003fc, 0x400003fd, 0x400003f9, - 0x90a60330, 0x400003ff, 0x01441340, 0x40c003fe, +static const struct hda_pintbl dell_9205_m44_pin_configs[] = { + { 0x0a, 0x0421101f }, + { 0x0b, 0x04a11020 }, + { 0x0c, 0x400003fa }, + { 0x0d, 0x90170310 }, + { 0x0e, 0x400003fb }, + { 0x0f, 0x400003fc }, + { 0x14, 0x400003fd }, + { 0x16, 0x400003f9 }, + { 0x17, 0x90a60330 }, + { 0x18, 0x400003ff }, + { 0x21, 0x01441340 }, + { 0x22, 0x40c003fe }, + {} }; -static const unsigned int *stac9205_brd_tbl[STAC_9205_MODELS] = { - [STAC_9205_REF] = ref9205_pin_configs, - [STAC_9205_DELL_M42] = dell_9205_m42_pin_configs, - [STAC_9205_DELL_M43] = dell_9205_m43_pin_configs, - [STAC_9205_DELL_M44] = dell_9205_m44_pin_configs, - [STAC_9205_EAPD] = NULL, +static void stac9205_fixup_ref(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct sigmatel_spec *spec = codec->spec; + + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + snd_hda_apply_pincfgs(codec, ref9205_pin_configs); + /* SPDIF-In enabled */ + spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0; + } +} + +static void stac9205_fixup_dell_m43(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct sigmatel_spec *spec = codec->spec; + struct hda_jack_tbl *jack; + + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + snd_hda_apply_pincfgs(codec, dell_9205_m43_pin_configs); + + /* Enable unsol response for GPIO4/Dock HP connection */ + snd_hda_codec_write_cache(codec, codec->afg, 0, + AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x10); + snd_hda_jack_detect_enable_callback(codec, codec->afg, + STAC_VREF_EVENT, + stac_vref_event); + jack = snd_hda_jack_tbl_get(codec, codec->afg); + if (jack) + jack->private_data = 0x01; + + spec->gpio_dir = 0x0b; + spec->eapd_mask = 0x01; + spec->gpio_mask = 0x1b; + spec->gpio_mute = 0x10; + /* GPIO0 High = EAPD, GPIO1 Low = Headphone Mute, + * GPIO3 Low = DRM + */ + spec->gpio_data = 0x01; + } +} + +static void stac9205_fixup_eapd(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct sigmatel_spec *spec = codec->spec; + + if (action == HDA_FIXUP_ACT_PRE_PROBE) + spec->eapd_switch = 0; +} + +static const struct hda_fixup stac9205_fixups[] = { + [STAC_9205_REF] = { + .type = HDA_FIXUP_FUNC, + .v.func = stac9205_fixup_ref, + }, + [STAC_9205_DELL_M42] = { + .type = HDA_FIXUP_PINS, + .v.pins = dell_9205_m42_pin_configs, + }, + [STAC_9205_DELL_M43] = { + .type = HDA_FIXUP_FUNC, + .v.func = stac9205_fixup_dell_m43, + }, + [STAC_9205_DELL_M44] = { + .type = HDA_FIXUP_PINS, + .v.pins = dell_9205_m44_pin_configs, + }, + [STAC_9205_EAPD] = { + .type = HDA_FIXUP_FUNC, + .v.func = stac9205_fixup_eapd, + }, + {} }; -static const char * const stac9205_models[STAC_9205_MODELS] = { - [STAC_9205_AUTO] = "auto", - [STAC_9205_REF] = "ref", - [STAC_9205_DELL_M42] = "dell-m42", - [STAC_9205_DELL_M43] = "dell-m43", - [STAC_9205_DELL_M44] = "dell-m44", - [STAC_9205_EAPD] = "eapd", +static const struct hda_model_fixup stac9205_models[] = { + { .id = STAC_9205_REF, .name = "ref" }, + { .id = STAC_9205_DELL_M42, .name = "dell-m42" }, + { .id = STAC_9205_DELL_M43, .name = "dell-m43" }, + { .id = STAC_9205_DELL_M44, .name = "dell-m44" }, + { .id = STAC_9205_EAPD, .name = "eapd" }, + {} }; -static const struct snd_pci_quirk stac9205_cfg_tbl[] = { +static const struct snd_pci_quirk stac9205_fixup_tbl[] = { /* SigmaTel reference board */ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_9205_REF), @@ -2328,1636 +3502,35 @@ static const struct snd_pci_quirk stac9205_cfg_tbl[] = { {} /* terminator */ }; -static void stac92xx_set_config_regs(struct hda_codec *codec, - const unsigned int *pincfgs) -{ - int i; - struct sigmatel_spec *spec = codec->spec; - - if (!pincfgs) - return; - - for (i = 0; i < spec->num_pins; i++) - if (spec->pin_nids[i] && pincfgs[i]) - snd_hda_codec_set_pincfg(codec, spec->pin_nids[i], - pincfgs[i]); -} - -/* - * Analog playback callbacks - */ -static int stac92xx_playback_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct sigmatel_spec *spec = codec->spec; - if (spec->stream_delay) - msleep(spec->stream_delay); - return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream, - hinfo); -} - -static int stac92xx_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 sigmatel_spec *spec = codec->spec; - return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag, format, substream); -} - -static int stac92xx_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct sigmatel_spec *spec = codec->spec; - return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); -} - -/* - * Digital playback callbacks - */ -static int stac92xx_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct sigmatel_spec *spec = codec->spec; - return snd_hda_multi_out_dig_open(codec, &spec->multiout); -} - -static int stac92xx_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct sigmatel_spec *spec = codec->spec; - return snd_hda_multi_out_dig_close(codec, &spec->multiout); -} - -static int stac92xx_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 sigmatel_spec *spec = codec->spec; - return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, - stream_tag, format, substream); -} - -static int stac92xx_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct sigmatel_spec *spec = codec->spec; - return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout); -} - - -/* - * Analog capture callbacks - */ -static int stac92xx_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 sigmatel_spec *spec = codec->spec; - hda_nid_t nid = spec->adc_nids[substream->number]; - - if (spec->powerdown_adcs) { - msleep(40); - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D0); - } - snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format); - return 0; -} - -static int stac92xx_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct sigmatel_spec *spec = codec->spec; - hda_nid_t nid = spec->adc_nids[substream->number]; - - snd_hda_codec_cleanup_stream(codec, nid); - if (spec->powerdown_adcs) - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D3); - return 0; -} - -static const struct hda_pcm_stream stac92xx_pcm_digital_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - /* NID is set in stac92xx_build_pcms */ - .ops = { - .open = stac92xx_dig_playback_pcm_open, - .close = stac92xx_dig_playback_pcm_close, - .prepare = stac92xx_dig_playback_pcm_prepare, - .cleanup = stac92xx_dig_playback_pcm_cleanup - }, -}; - -static const struct hda_pcm_stream stac92xx_pcm_digital_capture = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - /* NID is set in stac92xx_build_pcms */ -}; - -static const struct hda_pcm_stream stac92xx_pcm_analog_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 8, - .nid = 0x02, /* NID to query formats and rates */ - .ops = { - .open = stac92xx_playback_pcm_open, - .prepare = stac92xx_playback_pcm_prepare, - .cleanup = stac92xx_playback_pcm_cleanup - }, -}; - -static const struct hda_pcm_stream stac92xx_pcm_analog_alt_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - .nid = 0x06, /* NID to query formats and rates */ - .ops = { - .open = stac92xx_playback_pcm_open, - .prepare = stac92xx_playback_pcm_prepare, - .cleanup = stac92xx_playback_pcm_cleanup - }, -}; - -static const struct hda_pcm_stream stac92xx_pcm_analog_capture = { - .channels_min = 2, - .channels_max = 2, - /* NID + .substreams is set in stac92xx_build_pcms */ - .ops = { - .prepare = stac92xx_capture_pcm_prepare, - .cleanup = stac92xx_capture_pcm_cleanup - }, -}; - -static int stac92xx_build_pcms(struct hda_codec *codec) -{ - struct sigmatel_spec *spec = codec->spec; - struct hda_pcm *info = spec->pcm_rec; - - codec->num_pcms = 1; - codec->pcm_info = info; - - info->name = "STAC92xx Analog"; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_playback; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = - spec->multiout.dac_nids[0]; - info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_analog_capture; - info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; - info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adcs; - - if (spec->alt_switch) { - codec->num_pcms++; - info++; - info->name = "STAC92xx Analog Alt"; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_alt_playback; - } - - if (spec->multiout.dig_out_nid || spec->dig_in_nid) { - codec->num_pcms++; - info++; - info->name = "STAC92xx Digital"; - info->pcm_type = spec->autocfg.dig_out_type[0]; - if (spec->multiout.dig_out_nid) { - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_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] = stac92xx_pcm_digital_capture; - info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid; - } - } - - return 0; -} - -static void stac92xx_auto_set_pinctl(struct hda_codec *codec, hda_nid_t nid, int pin_type) - -{ - snd_hda_set_pin_ctl_cache(codec, nid, pin_type); -} - -#define stac92xx_hp_switch_info snd_ctl_boolean_mono_info - -static int stac92xx_hp_switch_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct sigmatel_spec *spec = codec->spec; - - ucontrol->value.integer.value[0] = !!spec->hp_switch; - return 0; -} - -static void stac_issue_unsol_event(struct hda_codec *codec, hda_nid_t nid); - -static int stac92xx_hp_switch_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct sigmatel_spec *spec = codec->spec; - int nid = kcontrol->private_value; - - spec->hp_switch = ucontrol->value.integer.value[0] ? nid : 0; - - /* check to be sure that the ports are up to date with - * switch changes - */ - stac_issue_unsol_event(codec, nid); - - return 1; -} - -static int stac92xx_dc_bias_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - int i; - static const char * const texts[] = { - "Mic In", "Line In", "Line Out" - }; - - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct sigmatel_spec *spec = codec->spec; - hda_nid_t nid = kcontrol->private_value; - - if (nid == spec->mic_switch || nid == spec->line_switch) - i = 3; - else - i = 2; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->value.enumerated.items = i; - uinfo->count = 1; - if (uinfo->value.enumerated.item >= i) - uinfo->value.enumerated.item = i-1; - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); - - return 0; -} - -static int stac92xx_dc_bias_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - hda_nid_t nid = kcontrol->private_value; - unsigned int vref = stac92xx_vref_get(codec, nid); - - if (vref == snd_hda_get_default_vref(codec, nid)) - ucontrol->value.enumerated.item[0] = 0; - else if (vref == AC_PINCTL_VREF_GRD) - ucontrol->value.enumerated.item[0] = 1; - else if (vref == AC_PINCTL_VREF_HIZ) - ucontrol->value.enumerated.item[0] = 2; - - return 0; -} - -static int stac92xx_dc_bias_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - unsigned int new_vref = 0; - int error; - hda_nid_t nid = kcontrol->private_value; - - if (ucontrol->value.enumerated.item[0] == 0) - new_vref = snd_hda_get_default_vref(codec, nid); - else if (ucontrol->value.enumerated.item[0] == 1) - new_vref = AC_PINCTL_VREF_GRD; - else if (ucontrol->value.enumerated.item[0] == 2) - new_vref = AC_PINCTL_VREF_HIZ; - else - return 0; - - if (new_vref != stac92xx_vref_get(codec, nid)) { - error = stac92xx_vref_set(codec, nid, new_vref); - return error; - } - - return 0; -} - -static int stac92xx_io_switch_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - char *texts[2]; - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct sigmatel_spec *spec = codec->spec; - - if (kcontrol->private_value == spec->line_switch) - texts[0] = "Line In"; - else - texts[0] = "Mic In"; - texts[1] = "Line Out"; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->value.enumerated.items = 2; - uinfo->count = 1; - - if (uinfo->value.enumerated.item >= 2) - uinfo->value.enumerated.item = 1; - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); - - return 0; -} - -static int stac92xx_io_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct sigmatel_spec *spec = codec->spec; - hda_nid_t nid = kcontrol->private_value; - int io_idx = (nid == spec->mic_switch) ? 1 : 0; - - ucontrol->value.enumerated.item[0] = spec->io_switch[io_idx]; - return 0; -} - -static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct sigmatel_spec *spec = codec->spec; - hda_nid_t nid = kcontrol->private_value; - int io_idx = (nid == spec->mic_switch) ? 1 : 0; - unsigned short val = !!ucontrol->value.enumerated.item[0]; - - spec->io_switch[io_idx] = val; - - if (val) - stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_OUT_EN); - else { - unsigned int pinctl = AC_PINCTL_IN_EN; - if (io_idx) /* set VREF for mic */ - pinctl |= snd_hda_get_default_vref(codec, nid); - stac92xx_auto_set_pinctl(codec, nid, pinctl); - } - - /* check the auto-mute again: we need to mute/unmute the speaker - * appropriately according to the pin direction - */ - if (spec->hp_detect) - stac_issue_unsol_event(codec, nid); - - return 1; -} - -#define stac92xx_clfe_switch_info snd_ctl_boolean_mono_info - -static int stac92xx_clfe_switch_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct sigmatel_spec *spec = codec->spec; - - ucontrol->value.integer.value[0] = spec->clfe_swap; - return 0; -} - -static int stac92xx_clfe_switch_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct sigmatel_spec *spec = codec->spec; - hda_nid_t nid = kcontrol->private_value & 0xff; - unsigned int val = !!ucontrol->value.integer.value[0]; - - if (spec->clfe_swap == val) - return 0; - - spec->clfe_swap = val; - - snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE, - spec->clfe_swap ? 0x4 : 0x0); - - return 1; -} - -#define STAC_CODEC_HP_SWITCH(xname) \ - { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = xname, \ - .index = 0, \ - .info = stac92xx_hp_switch_info, \ - .get = stac92xx_hp_switch_get, \ - .put = stac92xx_hp_switch_put, \ - } - -#define STAC_CODEC_IO_SWITCH(xname, xpval) \ - { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = xname, \ - .index = 0, \ - .info = stac92xx_io_switch_info, \ - .get = stac92xx_io_switch_get, \ - .put = stac92xx_io_switch_put, \ - .private_value = xpval, \ - } - -#define STAC_CODEC_CLFE_SWITCH(xname, xpval) \ - { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = xname, \ - .index = 0, \ - .info = stac92xx_clfe_switch_info, \ - .get = stac92xx_clfe_switch_get, \ - .put = stac92xx_clfe_switch_put, \ - .private_value = xpval, \ - } - -enum { - STAC_CTL_WIDGET_VOL, - STAC_CTL_WIDGET_MUTE, - STAC_CTL_WIDGET_MUTE_BEEP, - STAC_CTL_WIDGET_MONO_MUX, - STAC_CTL_WIDGET_HP_SWITCH, - STAC_CTL_WIDGET_IO_SWITCH, - STAC_CTL_WIDGET_CLFE_SWITCH, - STAC_CTL_WIDGET_DC_BIAS -}; - -static const struct snd_kcontrol_new stac92xx_control_templates[] = { - HDA_CODEC_VOLUME(NULL, 0, 0, 0), - HDA_CODEC_MUTE(NULL, 0, 0, 0), - HDA_CODEC_MUTE_BEEP(NULL, 0, 0, 0), - STAC_MONO_MUX, - STAC_CODEC_HP_SWITCH(NULL), - STAC_CODEC_IO_SWITCH(NULL, 0), - STAC_CODEC_CLFE_SWITCH(NULL, 0), - DC_BIAS(NULL, 0, 0), -}; - -/* add dynamic controls */ -static struct snd_kcontrol_new * -stac_control_new(struct sigmatel_spec *spec, - const struct snd_kcontrol_new *ktemp, - const char *name, - unsigned int subdev) -{ - struct snd_kcontrol_new *knew; - - snd_array_init(&spec->kctls, sizeof(*knew), 32); - knew = snd_array_new(&spec->kctls); - if (!knew) - return NULL; - *knew = *ktemp; - knew->name = kstrdup(name, GFP_KERNEL); - if (!knew->name) { - /* roolback */ - memset(knew, 0, sizeof(*knew)); - spec->kctls.alloced--; - return NULL; - } - knew->subdevice = subdev; - return knew; -} - -static struct snd_kcontrol_new * -add_control_temp(struct sigmatel_spec *spec, - const struct snd_kcontrol_new *ktemp, - int idx, const char *name, - unsigned long val) -{ - struct snd_kcontrol_new *knew = stac_control_new(spec, ktemp, name, - HDA_SUBDEV_AMP_FLAG); - if (!knew) - return NULL; - knew->index = idx; - knew->private_value = val; - return knew; -} - -static int stac92xx_add_control_temp(struct sigmatel_spec *spec, - const struct snd_kcontrol_new *ktemp, - int idx, const char *name, - unsigned long val) -{ - return add_control_temp(spec, ktemp, idx, name, val) ? 0 : -ENOMEM; -} - -static inline int stac92xx_add_control_idx(struct sigmatel_spec *spec, - int type, int idx, const char *name, - unsigned long val) -{ - return stac92xx_add_control_temp(spec, - &stac92xx_control_templates[type], - idx, name, val); -} - - -/* add dynamic controls */ -static inline int stac92xx_add_control(struct sigmatel_spec *spec, int type, - const char *name, unsigned long val) -{ - return stac92xx_add_control_idx(spec, type, 0, name, val); -} - -static const struct snd_kcontrol_new stac_input_src_temp = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Input Source", - .info = stac92xx_mux_enum_info, - .get = stac92xx_mux_enum_get, - .put = stac92xx_mux_enum_put, -}; - -static inline int stac92xx_add_jack_mode_control(struct hda_codec *codec, - hda_nid_t nid, int idx) -{ - int def_conf = snd_hda_codec_get_pincfg(codec, nid); - int control = 0; - struct sigmatel_spec *spec = codec->spec; - char name[22]; - - if (snd_hda_get_input_pin_attr(def_conf) != INPUT_PIN_ATTR_INT) { - if (spec->headset_jack && snd_hda_get_input_pin_attr(def_conf) - != INPUT_PIN_ATTR_DOCK) - return 0; - if (snd_hda_get_default_vref(codec, nid) == AC_PINCTL_VREF_GRD - && nid == spec->line_switch) - control = STAC_CTL_WIDGET_IO_SWITCH; - else if (snd_hda_query_pin_caps(codec, nid) - & (AC_PINCAP_VREF_GRD << AC_PINCAP_VREF_SHIFT)) - control = STAC_CTL_WIDGET_DC_BIAS; - else if (nid == spec->mic_switch) - control = STAC_CTL_WIDGET_IO_SWITCH; - } - - if (control) { - snd_hda_get_pin_label(codec, nid, &spec->autocfg, - name, sizeof(name), NULL); - return stac92xx_add_control(codec->spec, control, - strcat(name, " Jack Mode"), nid); - } - - return 0; -} - -static int stac92xx_add_input_source(struct sigmatel_spec *spec) -{ - struct snd_kcontrol_new *knew; - struct hda_input_mux *imux = &spec->private_imux; - - if (spec->auto_mic) - return 0; /* no need for input source */ - if (!spec->num_adcs || imux->num_items <= 1) - return 0; /* no need for input source control */ - knew = stac_control_new(spec, &stac_input_src_temp, - stac_input_src_temp.name, 0); - if (!knew) - return -ENOMEM; - knew->count = spec->num_adcs; - return 0; -} - -/* check whether the line-input can be used as line-out */ -static hda_nid_t check_line_out_switch(struct hda_codec *codec) -{ - struct sigmatel_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - hda_nid_t nid; - unsigned int pincap; - int i; - - if (cfg->line_out_type != AUTO_PIN_LINE_OUT) - return 0; - for (i = 0; i < cfg->num_inputs; i++) { - if (cfg->inputs[i].type == AUTO_PIN_LINE_IN) { - nid = cfg->inputs[i].pin; - pincap = snd_hda_query_pin_caps(codec, nid); - if (pincap & AC_PINCAP_OUT) - return nid; - } - } - return 0; -} - -static hda_nid_t get_unassigned_dac(struct hda_codec *codec, hda_nid_t nid); - -/* check whether the mic-input can be used as line-out */ -static hda_nid_t check_mic_out_switch(struct hda_codec *codec, hda_nid_t *dac) -{ - struct sigmatel_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - unsigned int def_conf, pincap; - int i; - - *dac = 0; - if (cfg->line_out_type != AUTO_PIN_LINE_OUT) - return 0; - for (i = 0; i < cfg->num_inputs; i++) { - hda_nid_t nid = cfg->inputs[i].pin; - if (cfg->inputs[i].type != AUTO_PIN_MIC) - continue; - def_conf = snd_hda_codec_get_pincfg(codec, nid); - /* some laptops have an internal analog microphone - * which can't be used as a output */ - if (snd_hda_get_input_pin_attr(def_conf) != INPUT_PIN_ATTR_INT) { - pincap = snd_hda_query_pin_caps(codec, nid); - if (pincap & AC_PINCAP_OUT) { - *dac = get_unassigned_dac(codec, nid); - if (*dac) - return nid; - } - } - } - return 0; -} - -static int is_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid) -{ - int i; - - for (i = 0; i < spec->multiout.num_dacs; i++) { - if (spec->multiout.dac_nids[i] == nid) - return 1; - } - - return 0; -} - -static int check_all_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid) -{ - int i; - if (is_in_dac_nids(spec, nid)) - return 1; - for (i = 0; i < spec->autocfg.hp_outs; i++) - if (spec->hp_dacs[i] == nid) - return 1; - for (i = 0; i < spec->autocfg.speaker_outs; i++) - if (spec->speaker_dacs[i] == nid) - return 1; - return 0; -} - -static hda_nid_t get_unassigned_dac(struct hda_codec *codec, hda_nid_t nid) -{ - struct sigmatel_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int j, conn_len; - hda_nid_t conn[HDA_MAX_CONNECTIONS], fallback_dac; - unsigned int wcaps, wtype; - - conn_len = snd_hda_get_connections(codec, nid, conn, - HDA_MAX_CONNECTIONS); - /* 92HD88: trace back up the link of nids to find the DAC */ - while (conn_len == 1 && (get_wcaps_type(get_wcaps(codec, conn[0])) - != AC_WID_AUD_OUT)) { - nid = conn[0]; - conn_len = snd_hda_get_connections(codec, nid, conn, - HDA_MAX_CONNECTIONS); - } - for (j = 0; j < conn_len; j++) { - wcaps = get_wcaps(codec, conn[j]); - wtype = get_wcaps_type(wcaps); - /* we check only analog outputs */ - if (wtype != AC_WID_AUD_OUT || (wcaps & AC_WCAP_DIGITAL)) - continue; - /* if this route has a free DAC, assign it */ - if (!check_all_dac_nids(spec, conn[j])) { - if (conn_len > 1) { - /* select this DAC in the pin's input mux */ - snd_hda_codec_write_cache(codec, nid, 0, - AC_VERB_SET_CONNECT_SEL, j); - } - return conn[j]; - } - } - - /* if all DACs are already assigned, connect to the primary DAC, - unless we're assigning a secondary headphone */ - fallback_dac = spec->multiout.dac_nids[0]; - if (spec->multiout.hp_nid) { - for (j = 0; j < cfg->hp_outs; j++) - if (cfg->hp_pins[j] == nid) { - fallback_dac = spec->multiout.hp_nid; - break; - } - } - - if (conn_len > 1) { - for (j = 0; j < conn_len; j++) { - if (conn[j] == fallback_dac) { - snd_hda_codec_write_cache(codec, nid, 0, - AC_VERB_SET_CONNECT_SEL, j); - break; - } - } - } - return 0; -} - -static int add_spec_dacs(struct sigmatel_spec *spec, hda_nid_t nid); -static int add_spec_extra_dacs(struct sigmatel_spec *spec, hda_nid_t nid); - -/* - * Fill in the dac_nids table from the parsed pin configuration - * This function only works when every pin in line_out_pins[] - * contains atleast one DAC in its connection list. Some 92xx - * codecs are not connected directly to a DAC, such as the 9200 - * and 9202/925x. For those, dac_nids[] must be hard-coded. - */ -static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec) -{ - struct sigmatel_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int i; - hda_nid_t nid, dac; - - for (i = 0; i < cfg->line_outs; i++) { - nid = cfg->line_out_pins[i]; - dac = get_unassigned_dac(codec, nid); - if (!dac) { - if (spec->multiout.num_dacs > 0) { - /* we have already working output pins, - * so let's drop the broken ones again - */ - cfg->line_outs = spec->multiout.num_dacs; - break; - } - /* error out, no available DAC found */ - snd_printk(KERN_ERR - "%s: No available DAC for pin 0x%x\n", - __func__, nid); - return -ENODEV; - } - add_spec_dacs(spec, dac); - } - - for (i = 0; i < cfg->hp_outs; i++) { - nid = cfg->hp_pins[i]; - dac = get_unassigned_dac(codec, nid); - if (dac) { - if (!spec->multiout.hp_nid) - spec->multiout.hp_nid = dac; - else - add_spec_extra_dacs(spec, dac); - } - spec->hp_dacs[i] = dac; - } - - for (i = 0; i < cfg->speaker_outs; i++) { - nid = cfg->speaker_pins[i]; - dac = get_unassigned_dac(codec, nid); - if (dac) - add_spec_extra_dacs(spec, dac); - spec->speaker_dacs[i] = dac; - } - - /* add line-in as output */ - nid = check_line_out_switch(codec); - if (nid) { - dac = get_unassigned_dac(codec, nid); - if (dac) { - snd_printdd("STAC: Add line-in 0x%x as output %d\n", - nid, cfg->line_outs); - cfg->line_out_pins[cfg->line_outs] = nid; - cfg->line_outs++; - spec->line_switch = nid; - add_spec_dacs(spec, dac); - } - } - /* add mic as output */ - nid = check_mic_out_switch(codec, &dac); - if (nid && dac) { - snd_printdd("STAC: Add mic-in 0x%x as output %d\n", - nid, cfg->line_outs); - cfg->line_out_pins[cfg->line_outs] = nid; - cfg->line_outs++; - spec->mic_switch = nid; - add_spec_dacs(spec, dac); - } - - snd_printd("stac92xx: dac_nids=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n", - spec->multiout.num_dacs, - spec->multiout.dac_nids[0], - spec->multiout.dac_nids[1], - spec->multiout.dac_nids[2], - spec->multiout.dac_nids[3], - spec->multiout.dac_nids[4]); - - return 0; -} - -/* create volume control/switch for the given prefx type */ -static int create_controls_idx(struct hda_codec *codec, const char *pfx, - int idx, hda_nid_t nid, int chs) +static int stac_parse_auto_config(struct hda_codec *codec) { struct sigmatel_spec *spec = codec->spec; - char name[32]; int err; - if (!spec->check_volume_offset) { - unsigned int caps, step, nums, db_scale; - caps = query_amp_caps(codec, nid, HDA_OUTPUT); - step = (caps & AC_AMPCAP_STEP_SIZE) >> - AC_AMPCAP_STEP_SIZE_SHIFT; - step = (step + 1) * 25; /* in .01dB unit */ - nums = (caps & AC_AMPCAP_NUM_STEPS) >> - AC_AMPCAP_NUM_STEPS_SHIFT; - db_scale = nums * step; - /* if dB scale is over -64dB, and finer enough, - * let's reduce it to half - */ - if (db_scale > 6400 && nums >= 0x1f) - spec->volume_offset = nums / 2; - spec->check_volume_offset = 1; - } - - sprintf(name, "%s Playback Volume", pfx); - err = stac92xx_add_control_idx(spec, STAC_CTL_WIDGET_VOL, idx, name, - HDA_COMPOSE_AMP_VAL_OFS(nid, chs, 0, HDA_OUTPUT, - spec->volume_offset)); - if (err < 0) - return err; - sprintf(name, "%s Playback Switch", pfx); - err = stac92xx_add_control_idx(spec, STAC_CTL_WIDGET_MUTE, idx, name, - HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT)); + err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, NULL, 0); if (err < 0) return err; - return 0; -} -#define create_controls(codec, pfx, nid, chs) \ - create_controls_idx(codec, pfx, 0, nid, chs) + /* add hooks */ + spec->gen.pcm_playback_hook = stac_playback_pcm_hook; + spec->gen.pcm_capture_hook = stac_capture_pcm_hook; -static int add_spec_dacs(struct sigmatel_spec *spec, hda_nid_t nid) -{ - if (spec->multiout.num_dacs > 4) { - printk(KERN_WARNING "stac92xx: No space for DAC 0x%x\n", nid); - return 1; - } else { - snd_BUG_ON(spec->multiout.dac_nids != spec->dac_nids); - spec->dac_nids[spec->multiout.num_dacs] = nid; - spec->multiout.num_dacs++; - } - return 0; -} + spec->gen.automute_hook = stac_update_outputs; + spec->gen.hp_automute_hook = stac_hp_automute; + spec->gen.line_automute_hook = stac_line_automute; + spec->gen.mic_autoswitch_hook = stac_mic_autoswitch; -static int add_spec_extra_dacs(struct sigmatel_spec *spec, hda_nid_t nid) -{ - int i; - for (i = 0; i < ARRAY_SIZE(spec->multiout.extra_out_nid); i++) { - if (!spec->multiout.extra_out_nid[i]) { - spec->multiout.extra_out_nid[i] = nid; - return 0; - } - } - printk(KERN_WARNING "stac92xx: No space for extra DAC 0x%x\n", nid); - return 1; -} - -/* Create output controls - * The mixer elements are named depending on the given type (AUTO_PIN_XXX_OUT) - */ -static int create_multi_out_ctls(struct hda_codec *codec, int num_outs, - const hda_nid_t *pins, - const hda_nid_t *dac_nids, - int type) -{ - struct sigmatel_spec *spec = codec->spec; - static const char * const chname[4] = { - "Front", "Surround", NULL /*CLFE*/, "Side" - }; - hda_nid_t nid; - int i, err; - unsigned int wid_caps; - - for (i = 0; i < num_outs && i < ARRAY_SIZE(chname); i++) { - if (type == AUTO_PIN_HP_OUT && !spec->hp_detect) { - if (is_jack_detectable(codec, pins[i])) - spec->hp_detect = 1; - } - nid = dac_nids[i]; - if (!nid) - continue; - if (type != AUTO_PIN_HP_OUT && i == 2) { - /* Center/LFE */ - err = create_controls(codec, "Center", nid, 1); - if (err < 0) - return err; - err = create_controls(codec, "LFE", nid, 2); - if (err < 0) - return err; - - wid_caps = get_wcaps(codec, nid); - - if (wid_caps & AC_WCAP_LR_SWAP) { - err = stac92xx_add_control(spec, - STAC_CTL_WIDGET_CLFE_SWITCH, - "Swap Center/LFE Playback Switch", nid); - - if (err < 0) - return err; - } - - } else { - const char *name; - int idx; - switch (type) { - case AUTO_PIN_HP_OUT: - name = "Headphone"; - idx = i; - break; - case AUTO_PIN_SPEAKER_OUT: - if (num_outs <= 1) { - name = "Speaker"; - idx = i; - break; - } - /* Fall through in case of multi speaker outs */ - default: - name = chname[i]; - idx = 0; - break; - } - err = create_controls_idx(codec, name, idx, nid, 3); - if (err < 0) - return err; - } - } - return 0; -} - -static void stac_gpio_set(struct hda_codec *codec, unsigned int mask, - unsigned int dir_mask, unsigned int data); - -/* hook for controlling mic-mute LED GPIO */ -static int stac92xx_capture_sw_put_led(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct sigmatel_spec *spec = codec->spec; - int err; - bool mute; - - err = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); - if (err <= 0) - return err; - mute = !(ucontrol->value.integer.value[0] && - ucontrol->value.integer.value[1]); - if (spec->mic_mute_led_on != mute) { - spec->mic_mute_led_on = mute; - if (mute) - spec->gpio_data |= spec->mic_mute_led_gpio; - else - spec->gpio_data &= ~spec->mic_mute_led_gpio; - stac_gpio_set(codec, spec->gpio_mask, - spec->gpio_dir, spec->gpio_data); - } - return err; -} - -static int stac92xx_add_capvol_ctls(struct hda_codec *codec, unsigned long vol, - unsigned long sw, int idx) -{ - struct sigmatel_spec *spec = codec->spec; - struct snd_kcontrol_new *knew; - int err; - - err = stac92xx_add_control_idx(codec->spec, STAC_CTL_WIDGET_VOL, idx, - "Capture Volume", vol); - if (err < 0) - return err; - - knew = add_control_temp(spec, - &stac92xx_control_templates[STAC_CTL_WIDGET_MUTE], - idx, "Capture Switch", sw); - if (!knew) - return -ENOMEM; - /* add a LED hook for some HP laptops */ - if (spec->mic_mute_led_gpio) - knew->put = stac92xx_capture_sw_put_led; - - return 0; -} - -/* add playback controls from the parsed DAC table */ -static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec, - const struct auto_pin_cfg *cfg) -{ - struct sigmatel_spec *spec = codec->spec; - hda_nid_t nid; - int err; - int idx; - - err = create_multi_out_ctls(codec, cfg->line_outs, cfg->line_out_pins, - spec->multiout.dac_nids, - cfg->line_out_type); - if (err < 0) - return err; - - if (cfg->hp_outs > 1 && cfg->line_out_type == AUTO_PIN_LINE_OUT) { - err = stac92xx_add_control(spec, - STAC_CTL_WIDGET_HP_SWITCH, - "Headphone as Line Out Switch", - cfg->hp_pins[cfg->hp_outs - 1]); - if (err < 0) - return err; - } - - for (idx = 0; idx < cfg->num_inputs; idx++) { - if (cfg->inputs[idx].type > AUTO_PIN_LINE_IN) - break; - nid = cfg->inputs[idx].pin; - err = stac92xx_add_jack_mode_control(codec, nid, idx); - if (err < 0) - return err; - } - - return 0; -} - -/* add playback controls for Speaker and HP outputs */ -static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec, - struct auto_pin_cfg *cfg) -{ - struct sigmatel_spec *spec = codec->spec; - int err; - - err = create_multi_out_ctls(codec, cfg->hp_outs, cfg->hp_pins, - spec->hp_dacs, AUTO_PIN_HP_OUT); - if (err < 0) - return err; - - err = create_multi_out_ctls(codec, cfg->speaker_outs, cfg->speaker_pins, - spec->speaker_dacs, AUTO_PIN_SPEAKER_OUT); + err = snd_hda_gen_parse_auto_config(codec, &spec->gen.autocfg); if (err < 0) return err; - return 0; -} - -/* labels for mono mux outputs */ -static const char * const stac92xx_mono_labels[4] = { - "DAC0", "DAC1", "Mixer", "DAC2" -}; - -/* create mono mux for mono out on capable codecs */ -static int stac92xx_auto_create_mono_output_ctls(struct hda_codec *codec) -{ - struct sigmatel_spec *spec = codec->spec; - struct hda_input_mux *mono_mux = &spec->private_mono_mux; - int i, num_cons; - hda_nid_t con_lst[ARRAY_SIZE(stac92xx_mono_labels)]; - - num_cons = snd_hda_get_connections(codec, - spec->mono_nid, - con_lst, - HDA_MAX_NUM_INPUTS); - if (num_cons <= 0 || num_cons > ARRAY_SIZE(stac92xx_mono_labels)) - return -EINVAL; - - for (i = 0; i < num_cons; i++) - snd_hda_add_imux_item(mono_mux, stac92xx_mono_labels[i], i, - NULL); - - return stac92xx_add_control(spec, STAC_CTL_WIDGET_MONO_MUX, - "Mono Mux", spec->mono_nid); -} - -/* create PC beep volume controls */ -static int stac92xx_auto_create_beep_ctls(struct hda_codec *codec, - hda_nid_t nid) -{ - struct sigmatel_spec *spec = codec->spec; - u32 caps = query_amp_caps(codec, nid, HDA_OUTPUT); - int err, type = STAC_CTL_WIDGET_MUTE_BEEP; - - if (spec->anabeep_nid == nid) - type = STAC_CTL_WIDGET_MUTE; - - /* check for mute support for the the amp */ - if ((caps & AC_AMPCAP_MUTE) >> AC_AMPCAP_MUTE_SHIFT) { - err = stac92xx_add_control(spec, type, - "Beep Playback Switch", - HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT)); - if (err < 0) - return err; - } - - /* check to see if there is volume support for the amp */ - if ((caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT) { - err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, - "Beep Playback Volume", - HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT)); - if (err < 0) - return err; - } - return 0; -} - -#ifdef CONFIG_SND_HDA_INPUT_BEEP -#define stac92xx_dig_beep_switch_info snd_ctl_boolean_mono_info - -static int stac92xx_dig_beep_switch_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - ucontrol->value.integer.value[0] = codec->beep->enabled; - return 0; -} - -static int stac92xx_dig_beep_switch_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - return snd_hda_enable_beep_device(codec, ucontrol->value.integer.value[0]); -} - -static const struct snd_kcontrol_new stac92xx_dig_beep_ctrl = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .info = stac92xx_dig_beep_switch_info, - .get = stac92xx_dig_beep_switch_get, - .put = stac92xx_dig_beep_switch_put, -}; - -static int stac92xx_beep_switch_ctl(struct hda_codec *codec) -{ - return stac92xx_add_control_temp(codec->spec, &stac92xx_dig_beep_ctrl, - 0, "Beep Playback Switch", 0); -} -#endif - -static int stac92xx_auto_create_mux_input_ctls(struct hda_codec *codec) -{ - struct sigmatel_spec *spec = codec->spec; - int i, j, err = 0; - - for (i = 0; i < spec->num_muxes; i++) { - hda_nid_t nid; - unsigned int wcaps; - unsigned long val; - - nid = spec->mux_nids[i]; - wcaps = get_wcaps(codec, nid); - if (!(wcaps & AC_WCAP_OUT_AMP)) - continue; - - /* check whether already the same control was created as - * normal Capture Volume. - */ - val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); - for (j = 0; j < spec->num_caps; j++) { - if (spec->capvols[j] == val) - break; - } - if (j < spec->num_caps) - continue; - - err = stac92xx_add_control_idx(spec, STAC_CTL_WIDGET_VOL, i, - "Mux Capture Volume", val); - if (err < 0) - return err; - } - return 0; -}; - -static const char * const stac92xx_spdif_labels[3] = { - "Digital Playback", "Analog Mux 1", "Analog Mux 2", -}; - -static int stac92xx_auto_create_spdif_mux_ctls(struct hda_codec *codec) -{ - struct sigmatel_spec *spec = codec->spec; - struct hda_input_mux *spdif_mux = &spec->private_smux; - const char * const *labels = spec->spdif_labels; - int i, num_cons; - hda_nid_t con_lst[HDA_MAX_NUM_INPUTS]; - - num_cons = snd_hda_get_connections(codec, - spec->smux_nids[0], - con_lst, - HDA_MAX_NUM_INPUTS); - if (num_cons <= 0) - return -EINVAL; - - if (!labels) - labels = stac92xx_spdif_labels; - - for (i = 0; i < num_cons; i++) - snd_hda_add_imux_item(spdif_mux, labels[i], i, NULL); - - return 0; -} - -/* labels for dmic mux inputs */ -static const char * const stac92xx_dmic_labels[5] = { - "Analog Inputs", "Digital Mic 1", "Digital Mic 2", - "Digital Mic 3", "Digital Mic 4" -}; - -static hda_nid_t get_connected_node(struct hda_codec *codec, hda_nid_t mux, - int idx) -{ - hda_nid_t conn[HDA_MAX_NUM_INPUTS]; - int nums; - nums = snd_hda_get_connections(codec, mux, conn, ARRAY_SIZE(conn)); - if (idx >= 0 && idx < nums) - return conn[idx]; - return 0; -} - -/* look for NID recursively */ -#define get_connection_index(codec, mux, nid) \ - snd_hda_get_conn_index(codec, mux, nid, 1) - -/* create a volume assigned to the given pin (only if supported) */ -/* return 1 if the volume control is created */ -static int create_elem_capture_vol(struct hda_codec *codec, hda_nid_t nid, - const char *label, int idx, int direction) -{ - unsigned int caps, nums; - char name[32]; - int err; - - if (direction == HDA_OUTPUT) - caps = AC_WCAP_OUT_AMP; - else - caps = AC_WCAP_IN_AMP; - if (!(get_wcaps(codec, nid) & caps)) - return 0; - caps = query_amp_caps(codec, nid, direction); - nums = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT; - if (!nums) - return 0; - snprintf(name, sizeof(name), "%s Capture Volume", label); - err = stac92xx_add_control_idx(codec->spec, STAC_CTL_WIDGET_VOL, idx, name, - HDA_COMPOSE_AMP_VAL(nid, 3, 0, direction)); - if (err < 0) - return err; - return 1; -} - -/* create playback/capture controls for input pins on dmic capable codecs */ -static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec, - const struct auto_pin_cfg *cfg) -{ - struct sigmatel_spec *spec = codec->spec; - struct hda_input_mux *imux = &spec->private_imux; - struct hda_input_mux *dimux = &spec->private_dimux; - int err, i; - unsigned int def_conf; - - snd_hda_add_imux_item(dimux, stac92xx_dmic_labels[0], 0, NULL); - - for (i = 0; i < spec->num_dmics; i++) { - hda_nid_t nid; - int index, type_idx; - char label[32]; - - nid = spec->dmic_nids[i]; - if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN) - continue; - def_conf = snd_hda_codec_get_pincfg(codec, nid); - if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE) - continue; - - index = get_connection_index(codec, spec->dmux_nids[0], nid); - if (index < 0) - continue; - - snd_hda_get_pin_label(codec, nid, &spec->autocfg, - label, sizeof(label), NULL); - snd_hda_add_imux_item(dimux, label, index, &type_idx); - if (snd_hda_get_bool_hint(codec, "separate_dmux") != 1) - snd_hda_add_imux_item(imux, label, index, &type_idx); - - err = create_elem_capture_vol(codec, nid, label, type_idx, - HDA_INPUT); - if (err < 0) - return err; - if (!err) { - err = create_elem_capture_vol(codec, nid, label, - type_idx, HDA_OUTPUT); - if (err < 0) - return err; - if (!err) { - nid = get_connected_node(codec, - spec->dmux_nids[0], index); - if (nid) - err = create_elem_capture_vol(codec, - nid, label, - type_idx, HDA_INPUT); - if (err < 0) - return err; - } - } - } - - return 0; -} - -static int check_mic_pin(struct hda_codec *codec, hda_nid_t nid, - hda_nid_t *fixed, hda_nid_t *ext, hda_nid_t *dock) -{ - unsigned int cfg; - unsigned int type; - - if (!nid) - return 0; - cfg = snd_hda_codec_get_pincfg(codec, nid); - type = get_defcfg_device(cfg); - switch (snd_hda_get_input_pin_attr(cfg)) { - case INPUT_PIN_ATTR_INT: - if (*fixed) - return 1; /* already occupied */ - if (type != AC_JACK_MIC_IN) - return 1; /* invalid type */ - *fixed = nid; - break; - case INPUT_PIN_ATTR_UNUSED: - break; - case INPUT_PIN_ATTR_DOCK: - if (*dock) - return 1; /* already occupied */ - if (type != AC_JACK_MIC_IN && type != AC_JACK_LINE_IN) - return 1; /* invalid type */ - *dock = nid; - break; - default: - if (*ext) - return 1; /* already occupied */ - if (type != AC_JACK_MIC_IN) - return 1; /* invalid type */ - *ext = nid; - break; - } - return 0; -} - -static int set_mic_route(struct hda_codec *codec, - struct sigmatel_mic_route *mic, - hda_nid_t pin) -{ - struct sigmatel_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int i; - - mic->pin = pin; - if (pin == 0) - return 0; - for (i = 0; i < cfg->num_inputs; i++) { - if (pin == cfg->inputs[i].pin) - break; - } - if (i < cfg->num_inputs && cfg->inputs[i].type == AUTO_PIN_MIC) { - /* analog pin */ - i = get_connection_index(codec, spec->mux_nids[0], pin); - if (i < 0) - return -1; - mic->mux_idx = i; - mic->dmux_idx = -1; - if (spec->dmux_nids) - mic->dmux_idx = get_connection_index(codec, - spec->dmux_nids[0], - spec->mux_nids[0]); - } else if (spec->dmux_nids) { - /* digital pin */ - i = get_connection_index(codec, spec->dmux_nids[0], pin); - if (i < 0) - return -1; - mic->dmux_idx = i; - mic->mux_idx = -1; - if (spec->mux_nids) - mic->mux_idx = get_connection_index(codec, - spec->mux_nids[0], - spec->dmux_nids[0]); - } - return 0; -} - -/* return non-zero if the device is for automatic mic switch */ -static int stac_check_auto_mic(struct hda_codec *codec) -{ - struct sigmatel_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - hda_nid_t fixed, ext, dock; - int i; - - fixed = ext = dock = 0; - for (i = 0; i < cfg->num_inputs; i++) - if (check_mic_pin(codec, cfg->inputs[i].pin, - &fixed, &ext, &dock)) - return 0; - for (i = 0; i < spec->num_dmics; i++) - if (check_mic_pin(codec, spec->dmic_nids[i], - &fixed, &ext, &dock)) - return 0; - if (!fixed || (!ext && !dock)) - return 0; /* no input to switch */ - if (!is_jack_detectable(codec, ext)) - return 0; /* no unsol support */ - if (set_mic_route(codec, &spec->ext_mic, ext) || - set_mic_route(codec, &spec->int_mic, fixed) || - set_mic_route(codec, &spec->dock_mic, dock)) - return 0; /* something is wrong */ - return 1; -} - -/* create playback/capture controls for input pins */ -static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) -{ - struct sigmatel_spec *spec = codec->spec; - struct hda_input_mux *imux = &spec->private_imux; - int i, j; - const char *label; - - for (i = 0; i < cfg->num_inputs; i++) { - hda_nid_t nid = cfg->inputs[i].pin; - int index, err, type_idx; - - index = -1; - for (j = 0; j < spec->num_muxes; j++) { - index = get_connection_index(codec, spec->mux_nids[j], - nid); - if (index >= 0) - break; - } - if (index < 0) - continue; - - label = hda_get_autocfg_input_label(codec, cfg, i); - snd_hda_add_imux_item(imux, label, index, &type_idx); - - err = create_elem_capture_vol(codec, nid, - label, type_idx, - HDA_INPUT); - if (err < 0) - return err; - } - spec->num_analog_muxes = imux->num_items; - - if (imux->num_items) { - /* - * Set the current input for the muxes. - * The STAC9221 has two input muxes with identical source - * NID lists. Hopefully this won't get confused. - */ - for (i = 0; i < spec->num_muxes; i++) { - snd_hda_codec_write_cache(codec, spec->mux_nids[i], 0, - AC_VERB_SET_CONNECT_SEL, - imux->items[0].index); - } - } - - return 0; -} - -static void stac92xx_auto_init_multi_out(struct hda_codec *codec) -{ - struct sigmatel_spec *spec = codec->spec; - int i; - - for (i = 0; i < spec->autocfg.line_outs; i++) { - hda_nid_t nid = spec->autocfg.line_out_pins[i]; - stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_OUT_EN); - } -} - -static void stac92xx_auto_init_hp_out(struct hda_codec *codec) -{ - struct sigmatel_spec *spec = codec->spec; - int i; - - for (i = 0; i < spec->autocfg.hp_outs; i++) { - hda_nid_t pin; - pin = spec->autocfg.hp_pins[i]; - if (pin) /* connect to front */ - stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN); - } - for (i = 0; i < spec->autocfg.speaker_outs; i++) { - hda_nid_t pin; - pin = spec->autocfg.speaker_pins[i]; - if (pin) /* connect to front */ - stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN); - } -} - -static int is_dual_headphones(struct hda_codec *codec) -{ - struct sigmatel_spec *spec = codec->spec; - int i, valid_hps; - - if (spec->autocfg.line_out_type != AUTO_PIN_SPEAKER_OUT || - spec->autocfg.hp_outs <= 1) - return 0; - valid_hps = 0; - for (i = 0; i < spec->autocfg.hp_outs; i++) { - hda_nid_t nid = spec->autocfg.hp_pins[i]; - unsigned int cfg = snd_hda_codec_get_pincfg(codec, nid); - if (get_defcfg_location(cfg) & AC_JACK_LOC_SEPARATE) - continue; - valid_hps++; - } - return (valid_hps > 1); -} - - -static int stac92xx_parse_auto_config(struct hda_codec *codec) -{ - struct sigmatel_spec *spec = codec->spec; - hda_nid_t dig_out = 0, dig_in = 0; - int hp_swap = 0; - int i, err; - - if ((err = snd_hda_parse_pin_def_config(codec, - &spec->autocfg, - spec->dmic_nids)) < 0) - return err; - if (! spec->autocfg.line_outs) - return 0; /* can't find valid pin config */ - - /* If we have no real line-out pin and multiple hp-outs, HPs should - * be set up as multi-channel outputs. - */ - if (is_dual_headphones(codec)) { - /* Copy hp_outs to line_outs, backup line_outs in - * speaker_outs so that the following routines can handle - * HP pins as primary outputs. - */ - snd_printdd("stac92xx: Enabling multi-HPs workaround\n"); - memcpy(spec->autocfg.speaker_pins, spec->autocfg.line_out_pins, - sizeof(spec->autocfg.line_out_pins)); - spec->autocfg.speaker_outs = spec->autocfg.line_outs; - memcpy(spec->autocfg.line_out_pins, spec->autocfg.hp_pins, - sizeof(spec->autocfg.hp_pins)); - spec->autocfg.line_outs = spec->autocfg.hp_outs; - spec->autocfg.line_out_type = AUTO_PIN_HP_OUT; - spec->autocfg.hp_outs = 0; - hp_swap = 1; - } - if (spec->autocfg.mono_out_pin) { - int dir = get_wcaps(codec, spec->autocfg.mono_out_pin) & - (AC_WCAP_OUT_AMP | AC_WCAP_IN_AMP); - u32 caps = query_amp_caps(codec, - spec->autocfg.mono_out_pin, dir); - hda_nid_t conn_list[1]; - - /* get the mixer node and then the mono mux if it exists */ - if (snd_hda_get_connections(codec, - spec->autocfg.mono_out_pin, conn_list, 1) && - snd_hda_get_connections(codec, conn_list[0], - conn_list, 1) > 0) { - - int wcaps = get_wcaps(codec, conn_list[0]); - int wid_type = get_wcaps_type(wcaps); - /* LR swap check, some stac925x have a mux that - * changes the DACs output path instead of the - * mono-mux path. - */ - if (wid_type == AC_WID_AUD_SEL && - !(wcaps & AC_WCAP_LR_SWAP)) - spec->mono_nid = conn_list[0]; - } - if (dir) { - hda_nid_t nid = spec->autocfg.mono_out_pin; - - /* most mono outs have a least a mute/unmute switch */ - dir = (dir & AC_WCAP_OUT_AMP) ? HDA_OUTPUT : HDA_INPUT; - err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, - "Mono Playback Switch", - HDA_COMPOSE_AMP_VAL(nid, 1, 0, dir)); - if (err < 0) - return err; - /* check for volume support for the amp */ - if ((caps & AC_AMPCAP_NUM_STEPS) - >> AC_AMPCAP_NUM_STEPS_SHIFT) { - err = stac92xx_add_control(spec, - STAC_CTL_WIDGET_VOL, - "Mono Playback Volume", - HDA_COMPOSE_AMP_VAL(nid, 1, 0, dir)); - if (err < 0) - return err; - } - } - - stac92xx_auto_set_pinctl(codec, spec->autocfg.mono_out_pin, - AC_PINCTL_OUT_EN); - } - - if (!spec->multiout.num_dacs) { - err = stac92xx_auto_fill_dac_nids(codec); - if (err < 0) - return err; - err = stac92xx_auto_create_multi_out_ctls(codec, - &spec->autocfg); - if (err < 0) - return err; - } + /* minimum value is actually mute */ + spec->gen.vmaster_tlv[3] |= TLV_DB_SCALE_MUTE; /* setup analog beep controls */ if (spec->anabeep_nid > 0) { - err = stac92xx_auto_create_beep_ctls(codec, - spec->anabeep_nid); + err = stac_auto_create_beep_ctls(codec, + spec->anabeep_nid); if (err < 0) return err; } @@ -3968,7 +3541,7 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec) hda_nid_t nid = spec->digbeep_nid; unsigned int caps; - err = stac92xx_auto_create_beep_ctls(codec, nid); + err = stac_auto_create_beep_ctls(codec, nid); if (err < 0) return err; err = snd_hda_attach_beep_device(codec, nid); @@ -3980,7 +3553,7 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec) /* if no beep switch is available, make its own one */ caps = query_amp_caps(codec, nid, HDA_OUTPUT); if (!(caps & AC_AMPCAP_MUTE)) { - err = stac92xx_beep_switch_ctl(codec); + err = stac_beep_switch_ctl(codec); if (err < 0) return err; } @@ -3988,387 +3561,33 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec) } #endif - err = stac92xx_auto_create_hp_ctls(codec, &spec->autocfg); - if (err < 0) - return err; - - /* All output parsing done, now restore the swapped hp pins */ - if (hp_swap) { - memcpy(spec->autocfg.hp_pins, spec->autocfg.line_out_pins, - sizeof(spec->autocfg.hp_pins)); - spec->autocfg.hp_outs = spec->autocfg.line_outs; - spec->autocfg.line_out_type = AUTO_PIN_HP_OUT; - spec->autocfg.line_outs = 0; - } - - if (stac_check_auto_mic(codec)) { - spec->auto_mic = 1; - /* only one capture for auto-mic */ - spec->num_adcs = 1; - spec->num_caps = 1; - spec->num_muxes = 1; - } + if (spec->gpio_led) + spec->gen.vmaster_mute.hook = stac_vmaster_hook; - for (i = 0; i < spec->num_caps; i++) { - err = stac92xx_add_capvol_ctls(codec, spec->capvols[i], - spec->capsws[i], i); - if (err < 0) - return err; + if (spec->aloopback_ctl && + snd_hda_get_bool_hint(codec, "loopback") == 1) { + if (!snd_hda_gen_add_kctl(&spec->gen, NULL, spec->aloopback_ctl)) + return -ENOMEM; } - err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg); - if (err < 0) - return err; - - if (spec->mono_nid > 0) { - err = stac92xx_auto_create_mono_output_ctls(codec); - if (err < 0) - return err; - } - if (spec->num_dmics > 0 && !spec->dinput_mux) - if ((err = stac92xx_auto_create_dmic_input_ctls(codec, - &spec->autocfg)) < 0) - return err; - if (spec->num_muxes > 0) { - err = stac92xx_auto_create_mux_input_ctls(codec); + if (spec->have_spdif_mux) { + err = stac_create_spdif_mux_ctls(codec); if (err < 0) return err; } - if (spec->num_smuxes > 0) { - err = stac92xx_auto_create_spdif_mux_ctls(codec); - if (err < 0) - return err; - } - - err = stac92xx_add_input_source(spec); - if (err < 0) - return err; - spec->multiout.max_channels = spec->multiout.num_dacs * 2; - if (spec->multiout.max_channels > 2) - spec->surr_switch = 1; - - /* find digital out and in converters */ - for (i = codec->start_nid; i < codec->start_nid + codec->num_nodes; i++) { - unsigned int wid_caps = get_wcaps(codec, i); - if (wid_caps & AC_WCAP_DIGITAL) { - switch (get_wcaps_type(wid_caps)) { - case AC_WID_AUD_OUT: - if (!dig_out) - dig_out = i; - break; - case AC_WID_AUD_IN: - if (!dig_in) - dig_in = i; - break; - } - } - } - if (spec->autocfg.dig_outs) - spec->multiout.dig_out_nid = dig_out; - if (dig_in && spec->autocfg.dig_in_pin) - spec->dig_in_nid = dig_in; - - if (spec->kctls.list) - spec->mixers[spec->num_mixers++] = spec->kctls.list; - - spec->input_mux = &spec->private_imux; - if (!spec->dinput_mux) - spec->dinput_mux = &spec->private_dimux; - spec->sinput_mux = &spec->private_smux; - spec->mono_mux = &spec->private_mono_mux; - return 1; -} - -/* add playback controls for HP output */ -static int stac9200_auto_create_hp_ctls(struct hda_codec *codec, - struct auto_pin_cfg *cfg) -{ - struct sigmatel_spec *spec = codec->spec; - hda_nid_t pin = cfg->hp_pins[0]; - - if (! pin) - return 0; - - if (is_jack_detectable(codec, pin)) - spec->hp_detect = 1; + stac_init_power_map(codec); return 0; } -/* add playback controls for LFE output */ -static int stac9200_auto_create_lfe_ctls(struct hda_codec *codec, - struct auto_pin_cfg *cfg) -{ - struct sigmatel_spec *spec = codec->spec; - int err; - hda_nid_t lfe_pin = 0x0; - int i; - /* - * search speaker outs and line outs for a mono speaker pin - * with an amp. If one is found, add LFE controls - * for it. - */ - for (i = 0; i < spec->autocfg.speaker_outs && lfe_pin == 0x0; i++) { - hda_nid_t pin = spec->autocfg.speaker_pins[i]; - unsigned int wcaps = get_wcaps(codec, pin); - wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP); - if (wcaps == AC_WCAP_OUT_AMP) - /* found a mono speaker with an amp, must be lfe */ - lfe_pin = pin; - } - - /* if speaker_outs is 0, then speakers may be in line_outs */ - if (lfe_pin == 0 && spec->autocfg.speaker_outs == 0) { - for (i = 0; i < spec->autocfg.line_outs && lfe_pin == 0x0; i++) { - hda_nid_t pin = spec->autocfg.line_out_pins[i]; - unsigned int defcfg; - defcfg = snd_hda_codec_get_pincfg(codec, pin); - if (get_defcfg_device(defcfg) == AC_JACK_SPEAKER) { - unsigned int wcaps = get_wcaps(codec, pin); - wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP); - if (wcaps == AC_WCAP_OUT_AMP) - /* found a mono speaker with an amp, - must be lfe */ - lfe_pin = pin; - } - } - } - - if (lfe_pin) { - err = create_controls(codec, "LFE", lfe_pin, 1); - if (err < 0) - return err; - } - - return 0; -} - -static int stac9200_parse_auto_config(struct hda_codec *codec) +static int stac_init(struct hda_codec *codec) { struct sigmatel_spec *spec = codec->spec; - int err; - - if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL)) < 0) - return err; - - if ((err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0) - return err; - - if ((err = stac9200_auto_create_hp_ctls(codec, &spec->autocfg)) < 0) - return err; - - if ((err = stac9200_auto_create_lfe_ctls(codec, &spec->autocfg)) < 0) - return err; - - if (spec->num_muxes > 0) { - err = stac92xx_auto_create_mux_input_ctls(codec); - if (err < 0) - return err; - } - - err = stac92xx_add_input_source(spec); - if (err < 0) - return err; - - if (spec->autocfg.dig_outs) - spec->multiout.dig_out_nid = 0x05; - if (spec->autocfg.dig_in_pin) - spec->dig_in_nid = 0x04; - - if (spec->kctls.list) - spec->mixers[spec->num_mixers++] = spec->kctls.list; - - spec->input_mux = &spec->private_imux; - spec->dinput_mux = &spec->private_dimux; - - return 1; -} - -/* - * Early 2006 Intel Macintoshes with STAC9220X5 codecs seem to have a - * funky external mute control using GPIO pins. - */ - -static void stac_gpio_set(struct hda_codec *codec, unsigned int mask, - unsigned int dir_mask, unsigned int data) -{ - unsigned int gpiostate, gpiomask, gpiodir; - - snd_printdd("%s msk %x dir %x gpio %x\n", __func__, mask, dir_mask, data); - - gpiostate = snd_hda_codec_read(codec, codec->afg, 0, - AC_VERB_GET_GPIO_DATA, 0); - gpiostate = (gpiostate & ~dir_mask) | (data & dir_mask); - - gpiomask = snd_hda_codec_read(codec, codec->afg, 0, - AC_VERB_GET_GPIO_MASK, 0); - gpiomask |= mask; - - gpiodir = snd_hda_codec_read(codec, codec->afg, 0, - AC_VERB_GET_GPIO_DIRECTION, 0); - gpiodir |= dir_mask; - - /* Configure GPIOx as CMOS */ - snd_hda_codec_write(codec, codec->afg, 0, 0x7e7, 0); - - snd_hda_codec_write(codec, codec->afg, 0, - AC_VERB_SET_GPIO_MASK, gpiomask); - snd_hda_codec_read(codec, codec->afg, 0, - AC_VERB_SET_GPIO_DIRECTION, gpiodir); /* sync */ - - msleep(1); - - snd_hda_codec_read(codec, codec->afg, 0, - AC_VERB_SET_GPIO_DATA, gpiostate); /* sync */ -} - -static int stac_add_event(struct hda_codec *codec, hda_nid_t nid, - unsigned char type, int data) -{ - struct hda_jack_tbl *event; - - event = snd_hda_jack_tbl_new(codec, nid); - if (!event) - return -ENOMEM; - event->action = type; - event->private_data = data; - - return 0; -} - -static void handle_unsol_event(struct hda_codec *codec, - struct hda_jack_tbl *event); - -/* check if given nid is a valid pin and no other events are assigned - * to it. If OK, assign the event, set the unsol flag, and returns 1. - * Otherwise, returns zero. - */ -static int enable_pin_detect(struct hda_codec *codec, hda_nid_t nid, - unsigned int type) -{ - struct hda_jack_tbl *event; - - if (!is_jack_detectable(codec, nid)) - return 0; - event = snd_hda_jack_tbl_new(codec, nid); - if (!event) - return -ENOMEM; - if (event->action && event->action != type) - return 0; - event->action = type; - event->callback = handle_unsol_event; - snd_hda_jack_detect_enable(codec, nid, 0); - return 1; -} - -static int is_nid_out_jack_pin(struct auto_pin_cfg *cfg, hda_nid_t nid) -{ - int i; - for (i = 0; i < cfg->hp_outs; i++) - if (cfg->hp_pins[i] == nid) - return 1; /* nid is a HP-Out */ - for (i = 0; i < cfg->line_outs; i++) - if (cfg->line_out_pins[i] == nid) - return 1; /* nid is a line-Out */ - return 0; /* nid is not a HP-Out */ -}; - -static void stac92xx_power_down(struct hda_codec *codec) -{ - struct sigmatel_spec *spec = codec->spec; - - /* power down inactive DACs */ - const hda_nid_t *dac; - for (dac = spec->dac_list; *dac; dac++) - if (!check_all_dac_nids(spec, *dac)) - snd_hda_codec_write(codec, *dac, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D3); -} - -static void stac_toggle_power_map(struct hda_codec *codec, hda_nid_t nid, - int enable); - -static inline int get_int_hint(struct hda_codec *codec, const char *key, - int *valp) -{ - const char *p; - p = snd_hda_get_hint(codec, key); - if (p) { - unsigned long val; - if (!strict_strtoul(p, 0, &val)) { - *valp = val; - return 1; - } - } - return 0; -} - -/* override some hints from the hwdep entry */ -static void stac_store_hints(struct hda_codec *codec) -{ - struct sigmatel_spec *spec = codec->spec; - int val; - - val = snd_hda_get_bool_hint(codec, "hp_detect"); - if (val >= 0) - spec->hp_detect = val; - if (get_int_hint(codec, "gpio_mask", &spec->gpio_mask)) { - spec->eapd_mask = spec->gpio_dir = spec->gpio_data = - spec->gpio_mask; - } - if (get_int_hint(codec, "gpio_dir", &spec->gpio_dir)) - spec->gpio_mask &= spec->gpio_mask; - if (get_int_hint(codec, "gpio_data", &spec->gpio_data)) - spec->gpio_dir &= spec->gpio_mask; - if (get_int_hint(codec, "eapd_mask", &spec->eapd_mask)) - spec->eapd_mask &= spec->gpio_mask; - if (get_int_hint(codec, "gpio_mute", &spec->gpio_mute)) - spec->gpio_mute &= spec->gpio_mask; - val = snd_hda_get_bool_hint(codec, "eapd_switch"); - if (val >= 0) - spec->eapd_switch = val; -} - -static void stac_issue_unsol_events(struct hda_codec *codec, int num_pins, - const hda_nid_t *pins) -{ - while (num_pins--) - stac_issue_unsol_event(codec, *pins++); -} - -/* fake event to set up pins */ -static void stac_fake_hp_events(struct hda_codec *codec) -{ - struct sigmatel_spec *spec = codec->spec; - - if (spec->autocfg.hp_outs) - stac_issue_unsol_events(codec, spec->autocfg.hp_outs, - spec->autocfg.hp_pins); - if (spec->autocfg.line_outs && - spec->autocfg.line_out_pins[0] != spec->autocfg.hp_pins[0]) - stac_issue_unsol_events(codec, spec->autocfg.line_outs, - spec->autocfg.line_out_pins); -} - -static int stac92xx_init(struct hda_codec *codec) -{ - struct sigmatel_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; unsigned int gpio; int i; - if (spec->init) - snd_hda_sequence_write(codec, spec->init); - - /* power down adcs initially */ - if (spec->powerdown_adcs) - for (i = 0; i < spec->num_adcs; i++) - snd_hda_codec_write(codec, - spec->adc_nids[i], 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D3); - /* override some hints */ stac_store_hints(codec); @@ -4381,180 +3600,33 @@ static int stac92xx_init(struct hda_codec *codec) gpio |= spec->eapd_mask; stac_gpio_set(codec, spec->gpio_mask, spec->gpio_dir, gpio); - /* set up pins */ - if (spec->hp_detect) { - /* Enable unsolicited responses on the HP widget */ - for (i = 0; i < cfg->hp_outs; i++) { - hda_nid_t nid = cfg->hp_pins[i]; - enable_pin_detect(codec, nid, STAC_HP_EVENT); - } - if (cfg->line_out_type == AUTO_PIN_LINE_OUT && - cfg->speaker_outs > 0) { - /* enable pin-detect for line-outs as well */ - for (i = 0; i < cfg->line_outs; i++) { - hda_nid_t nid = cfg->line_out_pins[i]; - enable_pin_detect(codec, nid, STAC_LO_EVENT); - } - } - - /* force to enable the first line-out; the others are set up - * in unsol_event - */ - stac92xx_auto_set_pinctl(codec, spec->autocfg.line_out_pins[0], - AC_PINCTL_OUT_EN); - /* fake event to set up pins */ - stac_fake_hp_events(codec); - } else { - stac92xx_auto_init_multi_out(codec); - stac92xx_auto_init_hp_out(codec); - for (i = 0; i < cfg->hp_outs; i++) - stac_toggle_power_map(codec, cfg->hp_pins[i], 1); - } - if (spec->auto_mic) { - /* initialize connection to analog input */ - if (spec->dmux_nids) - snd_hda_codec_write_cache(codec, spec->dmux_nids[0], 0, - AC_VERB_SET_CONNECT_SEL, 0); - if (enable_pin_detect(codec, spec->ext_mic.pin, STAC_MIC_EVENT)) - stac_issue_unsol_event(codec, spec->ext_mic.pin); - if (enable_pin_detect(codec, spec->dock_mic.pin, - STAC_MIC_EVENT)) - stac_issue_unsol_event(codec, spec->dock_mic.pin); - } - for (i = 0; i < cfg->num_inputs; i++) { - hda_nid_t nid = cfg->inputs[i].pin; - int type = cfg->inputs[i].type; - unsigned int pinctl, conf; - if (type == AUTO_PIN_MIC) { - /* for mic pins, force to initialize */ - pinctl = snd_hda_get_default_vref(codec, nid); - pinctl |= AC_PINCTL_IN_EN; - stac92xx_auto_set_pinctl(codec, nid, pinctl); - } else { - pinctl = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); - /* if PINCTL already set then skip */ - /* Also, if both INPUT and OUTPUT are set, - * it must be a BIOS bug; need to override, too - */ - if (!(pinctl & AC_PINCTL_IN_EN) || - (pinctl & AC_PINCTL_OUT_EN)) { - pinctl &= ~AC_PINCTL_OUT_EN; - pinctl |= AC_PINCTL_IN_EN; - stac92xx_auto_set_pinctl(codec, nid, pinctl); - } - } - conf = snd_hda_codec_get_pincfg(codec, nid); - if (get_defcfg_connect(conf) != AC_JACK_PORT_FIXED) { - if (enable_pin_detect(codec, nid, STAC_INSERT_EVENT)) - stac_issue_unsol_event(codec, nid); - } - } - for (i = 0; i < spec->num_dmics; i++) - stac92xx_auto_set_pinctl(codec, spec->dmic_nids[i], - AC_PINCTL_IN_EN); - if (cfg->dig_out_pins[0]) - stac92xx_auto_set_pinctl(codec, cfg->dig_out_pins[0], - AC_PINCTL_OUT_EN); - if (cfg->dig_in_pin) - stac92xx_auto_set_pinctl(codec, cfg->dig_in_pin, - AC_PINCTL_IN_EN); - for (i = 0; i < spec->num_pwrs; i++) { - hda_nid_t nid = spec->pwr_nids[i]; - unsigned int pinctl, def_conf; - - def_conf = snd_hda_codec_get_pincfg(codec, nid); - def_conf = get_defcfg_connect(def_conf); - if (def_conf == AC_JACK_PORT_NONE) { - /* power off unused ports */ - stac_toggle_power_map(codec, nid, 0); - continue; - } - if (def_conf == AC_JACK_PORT_FIXED) { - /* no need for jack detection for fixed pins */ - stac_toggle_power_map(codec, nid, 1); - continue; - } - /* power on when no jack detection is available */ - /* or when the VREF is used for controlling LED */ - if (!spec->hp_detect || - spec->vref_mute_led_nid == nid || - !is_jack_detectable(codec, nid)) { - stac_toggle_power_map(codec, nid, 1); - continue; - } - - if (is_nid_out_jack_pin(cfg, nid)) - continue; /* already has an unsol event */ - - pinctl = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); - /* outputs are only ports capable of power management - * any attempts on powering down a input port cause the - * referenced VREF to act quirky. - */ - if (pinctl & AC_PINCTL_IN_EN) { - stac_toggle_power_map(codec, nid, 1); - continue; - } - if (enable_pin_detect(codec, nid, STAC_PWR_EVENT)) { - stac_issue_unsol_event(codec, nid); - continue; - } - /* none of the above, turn the port OFF */ - stac_toggle_power_map(codec, nid, 0); - } - - /* sync mute LED */ - if (spec->gpio_led) { - if (spec->vmaster_mute.hook) - snd_hda_sync_vmaster_hook(&spec->vmaster_mute); - else /* the very first init call doesn't have vmaster yet */ - stac92xx_update_led_status(codec, false); - } + snd_hda_gen_init(codec); /* sync the power-map */ if (spec->num_pwrs) snd_hda_codec_write(codec, codec->afg, 0, AC_VERB_IDT_SET_POWER_MAP, spec->power_map_bits); - if (spec->dac_list) - stac92xx_power_down(codec); - return 0; -} - -static void stac92xx_free_kctls(struct hda_codec *codec) -{ - struct sigmatel_spec *spec = codec->spec; - if (spec->kctls.list) { - struct snd_kcontrol_new *kctl = spec->kctls.list; - int i; - for (i = 0; i < spec->kctls.used; i++) - kfree(kctl[i].name); + /* power down inactive ADCs */ + if (spec->powerdown_adcs) { + for (i = 0; i < spec->gen.num_all_adcs; i++) { + if (spec->active_adcs & (1 << i)) + continue; + snd_hda_codec_write(codec, spec->gen.all_adcs[i], 0, + AC_VERB_SET_POWER_STATE, + AC_PWRST_D3); + } } - snd_array_free(&spec->kctls); -} - -static void stac92xx_shutup_pins(struct hda_codec *codec) -{ - unsigned int i, def_conf; - 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); - def_conf = snd_hda_codec_get_pincfg(codec, pin->nid); - if (get_defcfg_connect(def_conf) != AC_JACK_PORT_NONE) - snd_hda_set_pin_ctl(codec, pin->nid, 0); - } + return 0; } -static void stac92xx_shutup(struct hda_codec *codec) +static void stac_shutup(struct hda_codec *codec) { struct sigmatel_spec *spec = codec->spec; - stac92xx_shutup_pins(codec); + snd_hda_shutup_pins(codec); if (spec->eapd_mask) stac_gpio_set(codec, spec->gpio_mask, @@ -4562,469 +3634,18 @@ static void stac92xx_shutup(struct hda_codec *codec) ~spec->eapd_mask); } -static void stac92xx_free(struct hda_codec *codec) +static void stac_free(struct hda_codec *codec) { struct sigmatel_spec *spec = codec->spec; - if (! spec) + if (!spec) return; - stac92xx_shutup(codec); - + snd_hda_gen_spec_free(&spec->gen); kfree(spec); snd_hda_detach_beep_device(codec); } -static void stac92xx_set_pinctl(struct hda_codec *codec, hda_nid_t nid, - unsigned int flag) -{ - unsigned int old_ctl, pin_ctl; - - pin_ctl = snd_hda_codec_read(codec, nid, - 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00); - - if (pin_ctl & AC_PINCTL_IN_EN) { - /* - * we need to check the current set-up direction of - * shared input pins since they can be switched via - * "xxx as Output" mixer switch - */ - struct sigmatel_spec *spec = codec->spec; - if (nid == spec->line_switch || nid == spec->mic_switch) - return; - } - - old_ctl = pin_ctl; - /* if setting pin direction bits, clear the current - direction bits first */ - if (flag & (AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN)) - pin_ctl &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN); - - pin_ctl |= flag; - if (old_ctl != pin_ctl) - snd_hda_set_pin_ctl_cache(codec, nid, pin_ctl); -} - -static void stac92xx_reset_pinctl(struct hda_codec *codec, hda_nid_t nid, - unsigned int flag) -{ - unsigned int pin_ctl = snd_hda_codec_read(codec, nid, - 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00); - if (pin_ctl & flag) - snd_hda_set_pin_ctl_cache(codec, nid, pin_ctl & ~flag); -} - -static inline int get_pin_presence(struct hda_codec *codec, hda_nid_t nid) -{ - if (!nid) - return 0; - return snd_hda_jack_detect(codec, nid); -} - -static void stac92xx_line_out_detect(struct hda_codec *codec, - int presence) -{ - struct sigmatel_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int i; - - if (cfg->speaker_outs == 0) - return; - - for (i = 0; i < cfg->line_outs; i++) { - if (presence) - break; - presence = get_pin_presence(codec, cfg->line_out_pins[i]); - if (presence) { - unsigned int pinctl; - pinctl = snd_hda_codec_read(codec, - cfg->line_out_pins[i], 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); - if (pinctl & AC_PINCTL_IN_EN) - presence = 0; /* mic- or line-input */ - } - } - - if (presence) { - /* disable speakers */ - for (i = 0; i < cfg->speaker_outs; i++) - stac92xx_reset_pinctl(codec, cfg->speaker_pins[i], - AC_PINCTL_OUT_EN); - if (spec->eapd_mask && spec->eapd_switch) - stac_gpio_set(codec, spec->gpio_mask, - spec->gpio_dir, spec->gpio_data & - ~spec->eapd_mask); - } else { - /* enable speakers */ - for (i = 0; i < cfg->speaker_outs; i++) - stac92xx_set_pinctl(codec, cfg->speaker_pins[i], - AC_PINCTL_OUT_EN); - if (spec->eapd_mask && spec->eapd_switch) - stac_gpio_set(codec, spec->gpio_mask, - spec->gpio_dir, spec->gpio_data | - spec->eapd_mask); - } -} - -/* return non-zero if the hp-pin of the given array index isn't - * a jack-detection target - */ -static int no_hp_sensing(struct sigmatel_spec *spec, int i) -{ - struct auto_pin_cfg *cfg = &spec->autocfg; - - /* ignore sensing of shared line and mic jacks */ - if (cfg->hp_pins[i] == spec->line_switch) - return 1; - if (cfg->hp_pins[i] == spec->mic_switch) - return 1; - /* ignore if the pin is set as line-out */ - if (cfg->hp_pins[i] == spec->hp_switch) - return 1; - return 0; -} - -static void stac92xx_hp_detect(struct hda_codec *codec) -{ - struct sigmatel_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int i, presence; - - presence = 0; - if (spec->gpio_mute) - presence = !(snd_hda_codec_read(codec, codec->afg, 0, - AC_VERB_GET_GPIO_DATA, 0) & spec->gpio_mute); - - for (i = 0; i < cfg->hp_outs; i++) { - if (presence) - break; - if (no_hp_sensing(spec, i)) - continue; - presence = get_pin_presence(codec, cfg->hp_pins[i]); - if (presence) { - unsigned int pinctl; - pinctl = snd_hda_codec_read(codec, cfg->hp_pins[i], 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); - if (pinctl & AC_PINCTL_IN_EN) - presence = 0; /* mic- or line-input */ - } - } - - if (presence) { - /* disable lineouts */ - if (spec->hp_switch) - stac92xx_reset_pinctl(codec, spec->hp_switch, - AC_PINCTL_OUT_EN); - for (i = 0; i < cfg->line_outs; i++) - stac92xx_reset_pinctl(codec, cfg->line_out_pins[i], - AC_PINCTL_OUT_EN); - } else { - /* enable lineouts */ - if (spec->hp_switch) - stac92xx_set_pinctl(codec, spec->hp_switch, - AC_PINCTL_OUT_EN); - for (i = 0; i < cfg->line_outs; i++) - stac92xx_set_pinctl(codec, cfg->line_out_pins[i], - AC_PINCTL_OUT_EN); - } - stac92xx_line_out_detect(codec, presence); - /* toggle hp outs */ - for (i = 0; i < cfg->hp_outs; i++) { - unsigned int val = AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN; - if (no_hp_sensing(spec, i)) - continue; - if (1 /*presence*/) - stac92xx_set_pinctl(codec, cfg->hp_pins[i], val); -#if 0 /* FIXME */ -/* Resetting the pinctl like below may lead to (a sort of) regressions - * on some devices since they use the HP pin actually for line/speaker - * outs although the default pin config shows a different pin (that is - * wrong and useless). - * - * So, it's basically a problem of default pin configs, likely a BIOS issue. - * But, disabling the code below just works around it, and I'm too tired of - * bug reports with such devices... - */ - else - stac92xx_reset_pinctl(codec, cfg->hp_pins[i], val); -#endif /* FIXME */ - } -} - -static void stac_toggle_power_map(struct hda_codec *codec, hda_nid_t nid, - int enable) -{ - struct sigmatel_spec *spec = codec->spec; - unsigned int idx, val; - - for (idx = 0; idx < spec->num_pwrs; idx++) { - if (spec->pwr_nids[idx] == nid) - break; - } - if (idx >= spec->num_pwrs) - return; - - idx = 1 << idx; - - val = spec->power_map_bits; - if (enable) - val &= ~idx; - else - val |= idx; - - /* power down unused output ports */ - if (val != spec->power_map_bits) { - spec->power_map_bits = val; - snd_hda_codec_write(codec, codec->afg, 0, - AC_VERB_IDT_SET_POWER_MAP, val); - } -} - -static void stac92xx_pin_sense(struct hda_codec *codec, hda_nid_t nid) -{ - stac_toggle_power_map(codec, nid, get_pin_presence(codec, nid)); -} - -/* get the pin connection (fixed, none, etc) */ -static unsigned int stac_get_defcfg_connect(struct hda_codec *codec, int idx) -{ - struct sigmatel_spec *spec = codec->spec; - unsigned int cfg; - - cfg = snd_hda_codec_get_pincfg(codec, spec->pin_nids[idx]); - return get_defcfg_connect(cfg); -} - -static int stac92xx_connected_ports(struct hda_codec *codec, - const hda_nid_t *nids, int num_nids) -{ - struct sigmatel_spec *spec = codec->spec; - int idx, num; - unsigned int def_conf; - - for (num = 0; num < num_nids; num++) { - for (idx = 0; idx < spec->num_pins; idx++) - if (spec->pin_nids[idx] == nids[num]) - break; - if (idx >= spec->num_pins) - break; - def_conf = stac_get_defcfg_connect(codec, idx); - if (def_conf == AC_JACK_PORT_NONE) - break; - } - return num; -} - -static void stac92xx_mic_detect(struct hda_codec *codec) -{ - struct sigmatel_spec *spec = codec->spec; - struct sigmatel_mic_route *mic; - - if (get_pin_presence(codec, spec->ext_mic.pin)) - mic = &spec->ext_mic; - else if (get_pin_presence(codec, spec->dock_mic.pin)) - mic = &spec->dock_mic; - else - mic = &spec->int_mic; - if (mic->dmux_idx >= 0) - snd_hda_codec_write_cache(codec, spec->dmux_nids[0], 0, - AC_VERB_SET_CONNECT_SEL, - mic->dmux_idx); - if (mic->mux_idx >= 0) - snd_hda_codec_write_cache(codec, spec->mux_nids[0], 0, - AC_VERB_SET_CONNECT_SEL, - mic->mux_idx); -} - -static void handle_unsol_event(struct hda_codec *codec, - struct hda_jack_tbl *event) -{ - struct sigmatel_spec *spec = codec->spec; - int data; - - switch (event->action) { - case STAC_HP_EVENT: - case STAC_LO_EVENT: - stac92xx_hp_detect(codec); - break; - case STAC_MIC_EVENT: - stac92xx_mic_detect(codec); - break; - } - - switch (event->action) { - case STAC_HP_EVENT: - case STAC_LO_EVENT: - case STAC_MIC_EVENT: - case STAC_INSERT_EVENT: - case STAC_PWR_EVENT: - if (spec->num_pwrs > 0) - stac92xx_pin_sense(codec, event->nid); - - switch (codec->subsystem_id) { - case 0x103c308f: - if (event->nid == 0xb) { - int pin = AC_PINCTL_IN_EN; - - if (get_pin_presence(codec, 0xa) - && get_pin_presence(codec, 0xb)) - pin |= AC_PINCTL_VREF_80; - if (!get_pin_presence(codec, 0xb)) - pin |= AC_PINCTL_VREF_80; - - /* toggle VREF state based on mic + hp pin - * status - */ - stac92xx_auto_set_pinctl(codec, 0x0a, pin); - } - } - break; - case STAC_VREF_EVENT: - data = snd_hda_codec_read(codec, codec->afg, 0, - AC_VERB_GET_GPIO_DATA, 0); - /* toggle VREF state based on GPIOx status */ - snd_hda_codec_write(codec, codec->afg, 0, 0x7e0, - !!(data & (1 << event->private_data))); - break; - } -} - -static void stac_issue_unsol_event(struct hda_codec *codec, hda_nid_t nid) -{ - struct hda_jack_tbl *event = snd_hda_jack_tbl_get(codec, nid); - if (!event) - return; - handle_unsol_event(codec, event); -} - -static int hp_blike_system(u32 subsystem_id); - -static void set_hp_led_gpio(struct hda_codec *codec) -{ - struct sigmatel_spec *spec = codec->spec; - unsigned int gpio; - - if (spec->gpio_led) - return; - - gpio = snd_hda_param_read(codec, codec->afg, AC_PAR_GPIO_CAP); - gpio &= AC_GPIO_IO_COUNT; - if (gpio > 3) - spec->gpio_led = 0x08; /* GPIO 3 */ - else - spec->gpio_led = 0x01; /* GPIO 0 */ -} - -/* - * This method searches for the mute LED GPIO configuration - * provided as OEM string in SMBIOS. The format of that string - * is HP_Mute_LED_P_G or HP_Mute_LED_P - * where P can be 0 or 1 and defines mute LED GPIO control state (low/high) - * that corresponds to the NOT muted state of the master volume - * and G is the index of the GPIO to use as the mute LED control (0..9) - * If _G portion is missing it is assigned based on the codec ID - * - * So, HP B-series like systems may have HP_Mute_LED_0 (current models) - * or HP_Mute_LED_0_3 (future models) OEM SMBIOS strings - * - * - * The dv-series laptops don't seem to have the HP_Mute_LED* strings in - * SMBIOS - at least the ones I have seen do not have them - which include - * my own system (HP Pavilion dv6-1110ax) and my cousin's - * HP Pavilion dv9500t CTO. - * Need more information on whether it is true across the entire series. - * -- kunal - */ -static int find_mute_led_cfg(struct hda_codec *codec, int default_polarity) -{ - struct sigmatel_spec *spec = codec->spec; - const struct dmi_device *dev = NULL; - - if (get_int_hint(codec, "gpio_led", &spec->gpio_led)) { - get_int_hint(codec, "gpio_led_polarity", - &spec->gpio_led_polarity); - return 1; - } - if ((codec->subsystem_id >> 16) == PCI_VENDOR_ID_HP) { - while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, - NULL, dev))) { - if (sscanf(dev->name, "HP_Mute_LED_%d_%x", - &spec->gpio_led_polarity, - &spec->gpio_led) == 2) { - unsigned int max_gpio; - max_gpio = snd_hda_param_read(codec, codec->afg, - AC_PAR_GPIO_CAP); - max_gpio &= AC_GPIO_IO_COUNT; - if (spec->gpio_led < max_gpio) - spec->gpio_led = 1 << spec->gpio_led; - else - spec->vref_mute_led_nid = spec->gpio_led; - return 1; - } - if (sscanf(dev->name, "HP_Mute_LED_%d", - &spec->gpio_led_polarity) == 1) { - set_hp_led_gpio(codec); - return 1; - } - /* BIOS bug: unfilled OEM string */ - if (strstr(dev->name, "HP_Mute_LED_P_G")) { - set_hp_led_gpio(codec); - switch (codec->subsystem_id) { - case 0x103c148a: - spec->gpio_led_polarity = 0; - break; - default: - spec->gpio_led_polarity = 1; - break; - } - return 1; - } - } - - /* - * Fallback case - if we don't find the DMI strings, - * we statically set the GPIO - if not a B-series system - * and default polarity is provided - */ - if (!hp_blike_system(codec->subsystem_id) && - (default_polarity == 0 || default_polarity == 1)) { - set_hp_led_gpio(codec); - spec->gpio_led_polarity = default_polarity; - return 1; - } - } - return 0; -} - -static int hp_blike_system(u32 subsystem_id) -{ - switch (subsystem_id) { - case 0x103c1520: - case 0x103c1521: - case 0x103c1523: - case 0x103c1524: - case 0x103c1525: - case 0x103c1722: - case 0x103c1723: - case 0x103c1724: - case 0x103c1725: - case 0x103c1726: - case 0x103c1727: - case 0x103c1728: - case 0x103c1729: - case 0x103c172a: - case 0x103c172b: - case 0x103c307e: - case 0x103c307f: - case 0x103c3080: - case 0x103c3081: - case 0x103c7007: - case 0x103c7008: - return 1; - } - return 0; -} - #ifdef CONFIG_PROC_FS static void stac92hd_proc_hook(struct snd_info_buffer *buffer, struct hda_codec *codec, hda_nid_t nid) @@ -5073,24 +3694,22 @@ static void stac927x_proc_hook(struct snd_info_buffer *buffer, #endif #ifdef CONFIG_PM -static int stac92xx_resume(struct hda_codec *codec) +static int stac_resume(struct hda_codec *codec) { - stac92xx_init(codec); + codec->patch_ops.init(codec); snd_hda_codec_resume_amp(codec); snd_hda_codec_resume_cache(codec); - /* fake event to set up pins again to override cached values */ - stac_fake_hp_events(codec); return 0; } -static int stac92xx_suspend(struct hda_codec *codec) +static int stac_suspend(struct hda_codec *codec) { - stac92xx_shutup(codec); + stac_shutup(codec); return 0; } -static void stac92xx_set_power_state(struct hda_codec *codec, hda_nid_t fg, - unsigned int power_state) +static void stac_set_power_state(struct hda_codec *codec, hda_nid_t fg, + unsigned int power_state) { unsigned int afg_power_state = power_state; struct sigmatel_spec *spec = codec->spec; @@ -5107,114 +3726,68 @@ static void stac92xx_set_power_state(struct hda_codec *codec, hda_nid_t fg, } snd_hda_codec_read(codec, fg, 0, AC_VERB_SET_POWER_STATE, afg_power_state); - snd_hda_codec_set_power_to_all(codec, fg, power_state, true); + snd_hda_codec_set_power_to_all(codec, fg, power_state); } #else -#define stac92xx_suspend NULL -#define stac92xx_resume NULL -#define stac92xx_set_power_state NULL +#define stac_suspend NULL +#define stac_resume NULL +#define stac_set_power_state NULL #endif /* CONFIG_PM */ -/* update mute-LED accoring to the master switch */ -static void stac92xx_update_led_status(struct hda_codec *codec, int enabled) -{ - struct sigmatel_spec *spec = codec->spec; - int muted = !enabled; - - if (!spec->gpio_led) - return; - - /* LED state is inverted on these systems */ - if (spec->gpio_led_polarity) - muted = !muted; - - if (!spec->vref_mute_led_nid) { - if (muted) - spec->gpio_data |= spec->gpio_led; - else - spec->gpio_data &= ~spec->gpio_led; - stac_gpio_set(codec, spec->gpio_mask, - spec->gpio_dir, spec->gpio_data); - } else { - spec->vref_led = muted ? AC_PINCTL_VREF_50 : AC_PINCTL_VREF_GRD; - stac_vrefout_set(codec, spec->vref_mute_led_nid, - spec->vref_led); - } -} - -static const struct hda_codec_ops stac92xx_patch_ops = { - .build_controls = stac92xx_build_controls, - .build_pcms = stac92xx_build_pcms, - .init = stac92xx_init, - .free = stac92xx_free, +static const struct hda_codec_ops stac_patch_ops = { + .build_controls = snd_hda_gen_build_controls, + .build_pcms = snd_hda_gen_build_pcms, + .init = stac_init, + .free = stac_free, .unsol_event = snd_hda_jack_unsol_event, #ifdef CONFIG_PM - .suspend = stac92xx_suspend, - .resume = stac92xx_resume, + .suspend = stac_suspend, + .resume = stac_resume, #endif - .reboot_notify = stac92xx_shutup, + .reboot_notify = stac_shutup, }; +static int alloc_stac_spec(struct hda_codec *codec) +{ + struct sigmatel_spec *spec; + + spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (!spec) + return -ENOMEM; + snd_hda_gen_spec_init(&spec->gen); + codec->spec = spec; + codec->no_trigger_sense = 1; /* seems common with STAC/IDT codecs */ + return 0; +} + static int patch_stac9200(struct hda_codec *codec) { struct sigmatel_spec *spec; int err; - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; + err = alloc_stac_spec(codec); + if (err < 0) + return err; - codec->no_trigger_sense = 1; - codec->spec = spec; + spec = codec->spec; spec->linear_tone_beep = 1; - spec->num_pins = ARRAY_SIZE(stac9200_pin_nids); - spec->pin_nids = stac9200_pin_nids; - spec->board_config = snd_hda_check_board_config(codec, STAC_9200_MODELS, - stac9200_models, - stac9200_cfg_tbl); - if (spec->board_config < 0) - snd_printdd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", - codec->chip_name); - else - stac92xx_set_config_regs(codec, - stac9200_brd_tbl[spec->board_config]); - - spec->multiout.max_channels = 2; - spec->multiout.num_dacs = 1; - spec->multiout.dac_nids = stac9200_dac_nids; - spec->adc_nids = stac9200_adc_nids; - spec->mux_nids = stac9200_mux_nids; - spec->num_muxes = 1; - spec->num_dmics = 0; - spec->num_adcs = 1; - spec->num_pwrs = 0; - - if (spec->board_config == STAC_9200_M4 || - spec->board_config == STAC_9200_M4_2 || - spec->board_config == STAC_9200_OQO) - spec->init = stac9200_eapd_init; - else - spec->init = stac9200_core_init; - spec->mixer = stac9200_mixer; + spec->gen.own_eapd_ctl = 1; - if (spec->board_config == STAC_9200_PANASONIC) { - spec->gpio_mask = spec->gpio_dir = 0x09; - spec->gpio_data = 0x00; - } + codec->patch_ops = stac_patch_ops; + + snd_hda_add_verbs(codec, stac9200_eapd_init); + + snd_hda_pick_fixup(codec, stac9200_models, stac9200_fixup_tbl, + stac9200_fixups); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); - err = stac9200_parse_auto_config(codec); + err = stac_parse_auto_config(codec); if (err < 0) { - stac92xx_free(codec); + stac_free(codec); return err; } - /* CF-74 has no headphone detection, and the driver should *NOT* - * do detection and HP/speaker toggle because the hardware does it. - */ - if (spec->board_config == STAC_9200_PANASONIC) - spec->hp_detect = 0; - - codec->patch_ops = stac92xx_patch_ops; + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); return 0; } @@ -5224,81 +3797,29 @@ static int patch_stac925x(struct hda_codec *codec) struct sigmatel_spec *spec; int err; - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; + err = alloc_stac_spec(codec); + if (err < 0) + return err; - codec->no_trigger_sense = 1; - codec->spec = spec; + spec = codec->spec; spec->linear_tone_beep = 1; - spec->num_pins = ARRAY_SIZE(stac925x_pin_nids); - spec->pin_nids = stac925x_pin_nids; - - /* Check first for codec ID */ - spec->board_config = snd_hda_check_board_codec_sid_config(codec, - STAC_925x_MODELS, - stac925x_models, - stac925x_codec_id_cfg_tbl); - - /* Now checks for PCI ID, if codec ID is not found */ - if (spec->board_config < 0) - spec->board_config = snd_hda_check_board_config(codec, - STAC_925x_MODELS, - stac925x_models, - stac925x_cfg_tbl); - again: - if (spec->board_config < 0) - snd_printdd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", - codec->chip_name); - else - stac92xx_set_config_regs(codec, - stac925x_brd_tbl[spec->board_config]); - - spec->multiout.max_channels = 2; - spec->multiout.num_dacs = 1; - spec->multiout.dac_nids = stac925x_dac_nids; - spec->adc_nids = stac925x_adc_nids; - spec->mux_nids = stac925x_mux_nids; - spec->num_muxes = 1; - spec->num_adcs = 1; - spec->num_pwrs = 0; - switch (codec->vendor_id) { - case 0x83847632: /* STAC9202 */ - case 0x83847633: /* STAC9202D */ - case 0x83847636: /* STAC9251 */ - case 0x83847637: /* STAC9251D */ - spec->num_dmics = STAC925X_NUM_DMICS; - spec->dmic_nids = stac925x_dmic_nids; - spec->num_dmuxes = ARRAY_SIZE(stac925x_dmux_nids); - spec->dmux_nids = stac925x_dmux_nids; - break; - default: - spec->num_dmics = 0; - break; - } + spec->gen.own_eapd_ctl = 1; - spec->init = stac925x_core_init; - spec->mixer = stac925x_mixer; - spec->num_caps = 1; - spec->capvols = stac925x_capvols; - spec->capsws = stac925x_capsws; - - err = stac92xx_parse_auto_config(codec); - if (!err) { - if (spec->board_config < 0) { - printk(KERN_WARNING "hda_codec: No auto-config is " - "available, default to model=ref\n"); - spec->board_config = STAC_925x_REF; - goto again; - } - err = -EINVAL; - } + codec->patch_ops = stac_patch_ops; + + snd_hda_add_verbs(codec, stac925x_core_init); + + snd_hda_pick_fixup(codec, stac925x_models, stac925x_fixup_tbl, + stac925x_fixups); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); + + err = stac_parse_auto_config(codec); if (err < 0) { - stac92xx_free(codec); + stac_free(codec); return err; } - codec->patch_ops = stac92xx_patch_ops; + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); return 0; } @@ -5306,471 +3827,181 @@ static int patch_stac925x(struct hda_codec *codec) static int patch_stac92hd73xx(struct hda_codec *codec) { struct sigmatel_spec *spec; - hda_nid_t conn[STAC92HD73_DAC_COUNT + 2]; - int err = 0; + int err; int num_dacs; - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; + err = alloc_stac_spec(codec); + if (err < 0) + return err; - codec->no_trigger_sense = 1; - codec->spec = spec; + spec = codec->spec; spec->linear_tone_beep = 0; - codec->slave_dig_outs = stac92hd73xx_slave_dig_outs; - spec->num_pins = ARRAY_SIZE(stac92hd73xx_pin_nids); - spec->pin_nids = stac92hd73xx_pin_nids; - spec->board_config = snd_hda_check_board_config(codec, - STAC_92HD73XX_MODELS, - stac92hd73xx_models, - stac92hd73xx_cfg_tbl); - /* check codec subsystem id if not found */ - if (spec->board_config < 0) - spec->board_config = - snd_hda_check_board_codec_sid_config(codec, - STAC_92HD73XX_MODELS, stac92hd73xx_models, - stac92hd73xx_codec_id_cfg_tbl); -again: - if (spec->board_config < 0) - snd_printdd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", - codec->chip_name); - else - stac92xx_set_config_regs(codec, - stac92hd73xx_brd_tbl[spec->board_config]); - - num_dacs = snd_hda_get_connections(codec, 0x0a, - conn, STAC92HD73_DAC_COUNT + 2) - 1; + spec->gen.mixer_nid = 0x1d; + spec->have_spdif_mux = 1; + num_dacs = snd_hda_get_num_conns(codec, 0x0a) - 1; if (num_dacs < 3 || num_dacs > 5) { printk(KERN_WARNING "hda_codec: Could not determine " "number of channels defaulting to DAC count\n"); - num_dacs = STAC92HD73_DAC_COUNT; + num_dacs = 5; } - spec->init = stac92hd73xx_core_init; + switch (num_dacs) { case 0x3: /* 6 Channel */ - spec->aloopback_ctl = stac92hd73xx_6ch_loopback; + spec->aloopback_ctl = &stac92hd73xx_6ch_loopback; break; case 0x4: /* 8 Channel */ - spec->aloopback_ctl = stac92hd73xx_8ch_loopback; + spec->aloopback_ctl = &stac92hd73xx_8ch_loopback; break; case 0x5: /* 10 Channel */ - spec->aloopback_ctl = stac92hd73xx_10ch_loopback; + spec->aloopback_ctl = &stac92hd73xx_10ch_loopback; break; } - spec->multiout.dac_nids = spec->dac_nids; spec->aloopback_mask = 0x01; spec->aloopback_shift = 8; spec->digbeep_nid = 0x1c; - spec->mux_nids = stac92hd73xx_mux_nids; - spec->adc_nids = stac92hd73xx_adc_nids; - spec->dmic_nids = stac92hd73xx_dmic_nids; - spec->dmux_nids = stac92hd73xx_dmux_nids; - spec->smux_nids = stac92hd73xx_smux_nids; - - spec->num_muxes = ARRAY_SIZE(stac92hd73xx_mux_nids); - spec->num_adcs = ARRAY_SIZE(stac92hd73xx_adc_nids); - spec->num_dmuxes = ARRAY_SIZE(stac92hd73xx_dmux_nids); - - spec->num_caps = STAC92HD73XX_NUM_CAPS; - spec->capvols = stac92hd73xx_capvols; - spec->capsws = stac92hd73xx_capsws; - - switch (spec->board_config) { - case STAC_DELL_EQ: - spec->init = dell_eq_core_init; - /* fallthru */ - case STAC_DELL_M6_AMIC: - case STAC_DELL_M6_DMIC: - case STAC_DELL_M6_BOTH: - spec->num_smuxes = 0; - spec->eapd_switch = 0; - switch (spec->board_config) { - case STAC_DELL_M6_AMIC: /* Analog Mics */ - snd_hda_codec_set_pincfg(codec, 0x0b, 0x90A70170); - spec->num_dmics = 0; - break; - case STAC_DELL_M6_DMIC: /* Digital Mics */ - snd_hda_codec_set_pincfg(codec, 0x13, 0x90A60160); - spec->num_dmics = 1; - break; - case STAC_DELL_M6_BOTH: /* Both */ - snd_hda_codec_set_pincfg(codec, 0x0b, 0x90A70170); - snd_hda_codec_set_pincfg(codec, 0x13, 0x90A60160); - spec->num_dmics = 1; - break; - } - break; - case STAC_ALIENWARE_M17X: - spec->num_dmics = STAC92HD73XX_NUM_DMICS; - spec->num_smuxes = ARRAY_SIZE(stac92hd73xx_smux_nids); - spec->eapd_switch = 0; - break; - default: - spec->num_dmics = STAC92HD73XX_NUM_DMICS; - spec->num_smuxes = ARRAY_SIZE(stac92hd73xx_smux_nids); - spec->eapd_switch = 1; - break; - } - if (spec->board_config != STAC_92HD73XX_REF) { - /* GPIO0 High = Enable EAPD */ - spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x1; - spec->gpio_data = 0x01; - } + /* GPIO0 High = Enable EAPD */ + spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x1; + spec->gpio_data = 0x01; + + spec->eapd_switch = 1; spec->num_pwrs = ARRAY_SIZE(stac92hd73xx_pwr_nids); spec->pwr_nids = stac92hd73xx_pwr_nids; - err = stac92xx_parse_auto_config(codec); + spec->gen.own_eapd_ctl = 1; + spec->gen.power_down_unused = 1; - if (!err) { - if (spec->board_config < 0) { - printk(KERN_WARNING "hda_codec: No auto-config is " - "available, default to model=ref\n"); - spec->board_config = STAC_92HD73XX_REF; - goto again; - } - err = -EINVAL; - } + codec->patch_ops = stac_patch_ops; + + snd_hda_pick_fixup(codec, stac92hd73xx_models, stac92hd73xx_fixup_tbl, + stac92hd73xx_fixups); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); + if (!spec->volknob_init) + snd_hda_add_verbs(codec, stac92hd73xx_core_init); + + err = stac_parse_auto_config(codec); if (err < 0) { - stac92xx_free(codec); + stac_free(codec); return err; } - if (spec->board_config == STAC_92HD73XX_NO_JD) - spec->hp_detect = 0; - - codec->patch_ops = stac92xx_patch_ops; - codec->proc_widget_hook = stac92hd7x_proc_hook; - return 0; -} + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); -static int hp_bnb2011_with_dock(struct hda_codec *codec) -{ - if (codec->vendor_id != 0x111d7605 && - codec->vendor_id != 0x111d76d1) - return 0; - - switch (codec->subsystem_id) { - case 0x103c1618: - case 0x103c1619: - case 0x103c161a: - case 0x103c161b: - case 0x103c161c: - case 0x103c161d: - case 0x103c161e: - case 0x103c161f: - - case 0x103c162a: - case 0x103c162b: - - case 0x103c1630: - case 0x103c1631: - - case 0x103c1633: - case 0x103c1634: - case 0x103c1635: - - case 0x103c3587: - case 0x103c3588: - case 0x103c3589: - case 0x103c358a: - - case 0x103c3667: - case 0x103c3668: - case 0x103c3669: - - return 1; - } return 0; } -static void stac92hd8x_add_pin(struct hda_codec *codec, hda_nid_t nid) +static void stac_setup_gpio(struct hda_codec *codec) { struct sigmatel_spec *spec = codec->spec; - unsigned int def_conf = snd_hda_codec_get_pincfg(codec, nid); - int i; - - spec->auto_pin_nids[spec->auto_pin_cnt] = nid; - spec->auto_pin_cnt++; - if (get_defcfg_device(def_conf) == AC_JACK_MIC_IN && - get_defcfg_connect(def_conf) != AC_JACK_PORT_NONE) { - for (i = 0; i < ARRAY_SIZE(stac92hd83xxx_dmic_nids); i++) { - if (nid == stac92hd83xxx_dmic_nids[i]) { - spec->auto_dmic_nids[spec->auto_dmic_cnt] = nid; - spec->auto_dmic_cnt++; - } + if (spec->gpio_led) { + if (!spec->vref_mute_led_nid) { + spec->gpio_mask |= spec->gpio_led; + spec->gpio_dir |= spec->gpio_led; + spec->gpio_data |= spec->gpio_led; + } else { + codec->patch_ops.set_power_state = + stac_set_power_state; } } -} - -static void stac92hd8x_add_adc(struct hda_codec *codec, hda_nid_t nid) -{ - struct sigmatel_spec *spec = codec->spec; - - spec->auto_adc_nids[spec->auto_adc_cnt] = nid; - spec->auto_adc_cnt++; -} -static void stac92hd8x_add_mux(struct hda_codec *codec, hda_nid_t nid) -{ - int i, j; - struct sigmatel_spec *spec = codec->spec; + if (spec->mic_mute_led_gpio) { + spec->gpio_mask |= spec->mic_mute_led_gpio; + spec->gpio_dir |= spec->mic_mute_led_gpio; + spec->mic_mute_led_on = true; + spec->gpio_data |= spec->mic_mute_led_gpio; - for (i = 0; i < spec->auto_adc_cnt; i++) { - if (get_connection_index(codec, - spec->auto_adc_nids[i], nid) >= 0) { - /* mux and volume for adc_nids[i] */ - if (!spec->auto_mux_nids[i]) { - spec->auto_mux_nids[i] = nid; - /* 92hd codecs capture volume is in mux */ - spec->auto_capvols[i] = HDA_COMPOSE_AMP_VAL(nid, - 3, 0, HDA_OUTPUT); - } - for (j = 0; j < spec->auto_dmic_cnt; j++) { - if (get_connection_index(codec, nid, - spec->auto_dmic_nids[j]) >= 0) { - /* dmux for adc_nids[i] */ - if (!spec->auto_dmux_nids[i]) - spec->auto_dmux_nids[i] = nid; - break; - } - } - break; - } + spec->gen.cap_sync_hook = stac_capture_led_hook; } } -static void stac92hd8x_fill_auto_spec(struct hda_codec *codec) -{ - hda_nid_t nid, end_nid; - unsigned int wid_caps, wid_type; - struct sigmatel_spec *spec = codec->spec; - - end_nid = codec->start_nid + codec->num_nodes; - - for (nid = codec->start_nid; nid < end_nid; nid++) { - wid_caps = get_wcaps(codec, nid); - wid_type = get_wcaps_type(wid_caps); - - if (wid_type == AC_WID_PIN) - stac92hd8x_add_pin(codec, nid); - - if (wid_type == AC_WID_AUD_IN && !(wid_caps & AC_WCAP_DIGITAL)) - stac92hd8x_add_adc(codec, nid); - } - - for (nid = codec->start_nid; nid < end_nid; nid++) { - wid_caps = get_wcaps(codec, nid); - wid_type = get_wcaps_type(wid_caps); - - if (wid_type == AC_WID_AUD_SEL) - stac92hd8x_add_mux(codec, nid); - } - - spec->pin_nids = spec->auto_pin_nids; - spec->num_pins = spec->auto_pin_cnt; - spec->adc_nids = spec->auto_adc_nids; - spec->num_adcs = spec->auto_adc_cnt; - spec->capvols = spec->auto_capvols; - spec->capsws = spec->auto_capvols; - spec->num_caps = spec->auto_adc_cnt; - spec->mux_nids = spec->auto_mux_nids; - spec->num_muxes = spec->auto_adc_cnt; - spec->dmux_nids = spec->auto_dmux_nids; - spec->num_dmuxes = spec->auto_adc_cnt; - spec->dmic_nids = spec->auto_dmic_nids; - spec->num_dmics = spec->auto_dmic_cnt; -} - static int patch_stac92hd83xxx(struct hda_codec *codec) { struct sigmatel_spec *spec; - int default_polarity = -1; /* no default cfg */ int err; - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; - - if (hp_bnb2011_with_dock(codec)) { - snd_hda_codec_set_pincfg(codec, 0xa, 0x2101201f); - snd_hda_codec_set_pincfg(codec, 0xf, 0x2181205e); - } + err = alloc_stac_spec(codec); + if (err < 0) + return err; codec->epss = 0; /* longer delay needed for D3 */ - codec->no_trigger_sense = 1; - codec->spec = spec; - - stac92hd8x_fill_auto_spec(codec); + spec = codec->spec; spec->linear_tone_beep = 0; - codec->slave_dig_outs = stac92hd83xxx_slave_dig_outs; + spec->gen.own_eapd_ctl = 1; + spec->gen.power_down_unused = 1; + spec->gen.mixer_nid = 0x1b; + spec->digbeep_nid = 0x21; spec->pwr_nids = stac92hd83xxx_pwr_nids; spec->num_pwrs = ARRAY_SIZE(stac92hd83xxx_pwr_nids); - spec->multiout.dac_nids = spec->dac_nids; - spec->init = stac92hd83xxx_core_init; - - spec->board_config = snd_hda_check_board_config(codec, - STAC_92HD83XXX_MODELS, - stac92hd83xxx_models, - stac92hd83xxx_cfg_tbl); - /* check codec subsystem id if not found */ - if (spec->board_config < 0) - spec->board_config = - snd_hda_check_board_codec_sid_config(codec, - STAC_92HD83XXX_MODELS, stac92hd83xxx_models, - stac92hd83xxx_codec_id_cfg_tbl); -again: - if (spec->board_config < 0) - snd_printdd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", - codec->chip_name); - else - stac92xx_set_config_regs(codec, - stac92hd83xxx_brd_tbl[spec->board_config]); + spec->default_polarity = -1; /* no default cfg */ - codec->patch_ops = stac92xx_patch_ops; + codec->patch_ops = stac_patch_ops; - switch (spec->board_config) { - case STAC_HP_ZEPHYR: - spec->init = stac92hd83xxx_hp_zephyr_init; - break; - case STAC_92HD83XXX_HP_LED: - default_polarity = 0; - break; - case STAC_92HD83XXX_HP_INV_LED: - default_polarity = 1; - break; - case STAC_92HD83XXX_HP_MIC_LED: - spec->mic_mute_led_gpio = 0x08; /* GPIO3 */ - break; - case STAC_92HD83XXX_HEADSET_JACK: - spec->headset_jack = 1; - break; - } + snd_hda_add_verbs(codec, stac92hd83xxx_core_init); - if (find_mute_led_cfg(codec, default_polarity)) - snd_printd("mute LED gpio %d polarity %d\n", - spec->gpio_led, - spec->gpio_led_polarity); - - if (spec->gpio_led) { - if (!spec->vref_mute_led_nid) { - spec->gpio_mask |= spec->gpio_led; - spec->gpio_dir |= spec->gpio_led; - spec->gpio_data |= spec->gpio_led; - } else { - codec->patch_ops.set_power_state = - stac92xx_set_power_state; - } - } + snd_hda_pick_fixup(codec, stac92hd83xxx_models, stac92hd83xxx_fixup_tbl, + stac92hd83xxx_fixups); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); - if (spec->mic_mute_led_gpio) { - spec->gpio_mask |= spec->mic_mute_led_gpio; - spec->gpio_dir |= spec->mic_mute_led_gpio; - spec->mic_mute_led_on = true; - spec->gpio_data |= spec->mic_mute_led_gpio; - } - - err = stac92xx_parse_auto_config(codec); - if (!err) { - if (spec->board_config < 0) { - printk(KERN_WARNING "hda_codec: No auto-config is " - "available, default to model=ref\n"); - spec->board_config = STAC_92HD83XXX_REF; - goto again; - } - err = -EINVAL; - } + stac_setup_gpio(codec); + err = stac_parse_auto_config(codec); if (err < 0) { - stac92xx_free(codec); + stac_free(codec); return err; } codec->proc_widget_hook = stac92hd_proc_hook; + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); + return 0; } -static int stac92hd71bxx_connected_smuxes(struct hda_codec *codec, - hda_nid_t dig0pin) -{ - struct sigmatel_spec *spec = codec->spec; - int idx; - - for (idx = 0; idx < spec->num_pins; idx++) - if (spec->pin_nids[idx] == dig0pin) - break; - if ((idx + 2) >= spec->num_pins) - return 0; +static const hda_nid_t stac92hd95_pwr_nids[] = { + 0x0a, 0x0b, 0x0c, 0x0d +}; - /* dig1pin case */ - if (stac_get_defcfg_connect(codec, idx + 1) != AC_JACK_PORT_NONE) - return 2; +static int patch_stac92hd95(struct hda_codec *codec) +{ + struct sigmatel_spec *spec; + int err; - /* dig0pin + dig2pin case */ - if (stac_get_defcfg_connect(codec, idx + 2) != AC_JACK_PORT_NONE) - return 2; - if (stac_get_defcfg_connect(codec, idx) != AC_JACK_PORT_NONE) - return 1; - else - return 0; -} + err = alloc_stac_spec(codec); + if (err < 0) + return err; -/* HP dv7 bass switch - GPIO5 */ -#define stac_hp_bass_gpio_info snd_ctl_boolean_mono_info -static int stac_hp_bass_gpio_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct sigmatel_spec *spec = codec->spec; - ucontrol->value.integer.value[0] = !!(spec->gpio_data & 0x20); - return 0; -} + codec->epss = 0; /* longer delay needed for D3 */ -static int stac_hp_bass_gpio_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct sigmatel_spec *spec = codec->spec; - unsigned int gpio_data; + spec = codec->spec; + spec->linear_tone_beep = 0; + spec->gen.own_eapd_ctl = 1; + spec->gen.power_down_unused = 1; - gpio_data = (spec->gpio_data & ~0x20) | - (ucontrol->value.integer.value[0] ? 0x20 : 0); - if (gpio_data == spec->gpio_data) - return 0; - spec->gpio_data = gpio_data; - stac_gpio_set(codec, spec->gpio_mask, spec->gpio_dir, spec->gpio_data); - return 1; -} + spec->digbeep_nid = 0x19; + spec->pwr_nids = stac92hd95_pwr_nids; + spec->num_pwrs = ARRAY_SIZE(stac92hd95_pwr_nids); + spec->default_polarity = -1; /* no default cfg */ -static const struct snd_kcontrol_new stac_hp_bass_sw_ctrl = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .info = stac_hp_bass_gpio_info, - .get = stac_hp_bass_gpio_get, - .put = stac_hp_bass_gpio_put, -}; + codec->patch_ops = stac_patch_ops; -static int stac_add_hp_bass_switch(struct hda_codec *codec) -{ - struct sigmatel_spec *spec = codec->spec; + err = stac_parse_auto_config(codec); + if (err < 0) { + stac_free(codec); + return err; + } - if (!stac_control_new(spec, &stac_hp_bass_sw_ctrl, - "Bass Speaker Playback Switch", 0)) - return -ENOMEM; + codec->proc_widget_hook = stac92hd_proc_hook; - spec->gpio_mask |= 0x20; - spec->gpio_dir |= 0x20; - spec->gpio_data |= 0x20; return 0; } @@ -5778,84 +4009,32 @@ static int patch_stac92hd71bxx(struct hda_codec *codec) { struct sigmatel_spec *spec; const struct hda_verb *unmute_init = stac92hd71bxx_unmute_core_init; - unsigned int pin_cfg; - int err = 0; + int err; - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; + err = alloc_stac_spec(codec); + if (err < 0) + return err; - codec->no_trigger_sense = 1; - codec->spec = spec; + spec = codec->spec; spec->linear_tone_beep = 0; - codec->patch_ops = stac92xx_patch_ops; - spec->num_pins = STAC92HD71BXX_NUM_PINS; - switch (codec->vendor_id) { - case 0x111d76b6: - case 0x111d76b7: - spec->pin_nids = stac92hd71bxx_pin_nids_4port; - break; - case 0x111d7603: - case 0x111d7608: - /* On 92HD75Bx 0x27 isn't a pin nid */ - spec->num_pins--; - /* fallthrough */ - default: - spec->pin_nids = stac92hd71bxx_pin_nids_6port; - } - spec->num_pwrs = ARRAY_SIZE(stac92hd71bxx_pwr_nids); - spec->board_config = snd_hda_check_board_config(codec, - STAC_92HD71BXX_MODELS, - stac92hd71bxx_models, - stac92hd71bxx_cfg_tbl); -again: - if (spec->board_config < 0) - snd_printdd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", - codec->chip_name); - else - stac92xx_set_config_regs(codec, - stac92hd71bxx_brd_tbl[spec->board_config]); + spec->gen.own_eapd_ctl = 1; + spec->gen.power_down_unused = 1; + spec->gen.mixer_nid = 0x17; + spec->have_spdif_mux = 1; - if (spec->board_config != STAC_92HD71BXX_REF) { - /* GPIO0 = EAPD */ - spec->gpio_mask = 0x01; - spec->gpio_dir = 0x01; - spec->gpio_data = 0x01; - } - - spec->dmic_nids = stac92hd71bxx_dmic_nids; - spec->dmux_nids = stac92hd71bxx_dmux_nids; + codec->patch_ops = stac_patch_ops; - spec->num_caps = STAC92HD71BXX_NUM_CAPS; - spec->capvols = stac92hd71bxx_capvols; - spec->capsws = stac92hd71bxx_capsws; + /* GPIO0 = EAPD */ + spec->gpio_mask = 0x01; + spec->gpio_dir = 0x01; + spec->gpio_data = 0x01; switch (codec->vendor_id) { case 0x111d76b6: /* 4 Port without Analog Mixer */ case 0x111d76b7: unmute_init++; - /* fallthru */ - case 0x111d76b4: /* 6 Port without Analog Mixer */ - case 0x111d76b5: - codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs; - spec->num_dmics = stac92xx_connected_ports(codec, - stac92hd71bxx_dmic_nids, - STAC92HD71BXX_NUM_DMICS); break; case 0x111d7608: /* 5 Port with Analog Mixer */ - switch (spec->board_config) { - case STAC_HP_M4: - /* Enable VREF power saving on GPIO1 detect */ - err = stac_add_event(codec, codec->afg, - STAC_VREF_EVENT, 0x02); - if (err < 0) - return err; - snd_hda_codec_write_cache(codec, codec->afg, 0, - AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x02); - snd_hda_jack_detect_enable(codec, codec->afg, 0); - spec->gpio_mask |= 0x02; - break; - } if ((codec->revision_id & 0xf) == 0 || (codec->revision_id & 0xf) == 1) spec->stream_delay = 40; /* 40 milliseconds */ @@ -5864,158 +4043,45 @@ again: unmute_init++; snd_hda_codec_set_pincfg(codec, 0x0f, 0x40f000f0); snd_hda_codec_set_pincfg(codec, 0x19, 0x40f000f3); - spec->dmic_nids = stac92hd71bxx_dmic_5port_nids; - spec->num_dmics = stac92xx_connected_ports(codec, - stac92hd71bxx_dmic_5port_nids, - STAC92HD71BXX_NUM_DMICS - 1); break; case 0x111d7603: /* 6 Port with Analog Mixer */ if ((codec->revision_id & 0xf) == 1) spec->stream_delay = 40; /* 40 milliseconds */ - /* fallthru */ - default: - codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs; - spec->num_dmics = stac92xx_connected_ports(codec, - stac92hd71bxx_dmic_nids, - STAC92HD71BXX_NUM_DMICS); break; } if (get_wcaps_type(get_wcaps(codec, 0x28)) == AC_WID_VOL_KNB) - spec->init = stac92hd71bxx_core_init; + snd_hda_add_verbs(codec, stac92hd71bxx_core_init); if (get_wcaps(codec, 0xa) & AC_WCAP_IN_AMP) snd_hda_sequence_write_cache(codec, unmute_init); - spec->aloopback_ctl = stac92hd71bxx_loopback; + spec->aloopback_ctl = &stac92hd71bxx_loopback; spec->aloopback_mask = 0x50; spec->aloopback_shift = 0; spec->powerdown_adcs = 1; spec->digbeep_nid = 0x26; - spec->mux_nids = stac92hd71bxx_mux_nids; - spec->adc_nids = stac92hd71bxx_adc_nids; - spec->smux_nids = stac92hd71bxx_smux_nids; + spec->num_pwrs = ARRAY_SIZE(stac92hd71bxx_pwr_nids); spec->pwr_nids = stac92hd71bxx_pwr_nids; - spec->num_muxes = ARRAY_SIZE(stac92hd71bxx_mux_nids); - spec->num_adcs = ARRAY_SIZE(stac92hd71bxx_adc_nids); - spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids); - spec->num_smuxes = stac92hd71bxx_connected_smuxes(codec, 0x1e); - - snd_printdd("Found board config: %d\n", spec->board_config); - - switch (spec->board_config) { - case STAC_HP_M4: - /* enable internal microphone */ - snd_hda_codec_set_pincfg(codec, 0x0e, 0x01813040); - stac92xx_auto_set_pinctl(codec, 0x0e, - AC_PINCTL_IN_EN | AC_PINCTL_VREF_80); - /* fallthru */ - case STAC_DELL_M4_2: - spec->num_dmics = 0; - spec->num_smuxes = 0; - spec->num_dmuxes = 0; - break; - case STAC_DELL_M4_1: - case STAC_DELL_M4_3: - spec->num_dmics = 1; - spec->num_smuxes = 0; - spec->num_dmuxes = 1; - break; - case STAC_HP_DV4_1222NR: - spec->num_dmics = 1; - /* I don't know if it needs 1 or 2 smuxes - will wait for - * bug reports to fix if needed - */ - spec->num_smuxes = 1; - spec->num_dmuxes = 1; - /* fallthrough */ - case STAC_HP_DV4: - spec->gpio_led = 0x01; - /* fallthrough */ - case STAC_HP_DV5: - snd_hda_codec_set_pincfg(codec, 0x0d, 0x90170010); - stac92xx_auto_set_pinctl(codec, 0x0d, AC_PINCTL_OUT_EN); - /* HP dv6 gives the headphone pin as a line-out. Thus we - * need to set hp_detect flag here to force to enable HP - * detection. - */ - spec->hp_detect = 1; - break; - case STAC_HP_HDX: - spec->num_dmics = 1; - spec->num_dmuxes = 1; - spec->num_smuxes = 1; - spec->gpio_led = 0x08; - break; - } - - if (hp_blike_system(codec->subsystem_id)) { - pin_cfg = snd_hda_codec_get_pincfg(codec, 0x0f); - if (get_defcfg_device(pin_cfg) == AC_JACK_LINE_OUT || - get_defcfg_device(pin_cfg) == AC_JACK_SPEAKER || - get_defcfg_device(pin_cfg) == AC_JACK_HP_OUT) { - /* It was changed in the BIOS to just satisfy MS DTM. - * Lets turn it back into slaved HP - */ - pin_cfg = (pin_cfg & (~AC_DEFCFG_DEVICE)) - | (AC_JACK_HP_OUT << - AC_DEFCFG_DEVICE_SHIFT); - pin_cfg = (pin_cfg & (~(AC_DEFCFG_DEF_ASSOC - | AC_DEFCFG_SEQUENCE))) - | 0x1f; - snd_hda_codec_set_pincfg(codec, 0x0f, pin_cfg); - } - } - - if (find_mute_led_cfg(codec, 1)) - snd_printd("mute LED gpio %d polarity %d\n", - spec->gpio_led, - spec->gpio_led_polarity); + snd_hda_pick_fixup(codec, stac92hd71bxx_models, stac92hd71bxx_fixup_tbl, + stac92hd71bxx_fixups); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); - if (spec->gpio_led) { - if (!spec->vref_mute_led_nid) { - spec->gpio_mask |= spec->gpio_led; - spec->gpio_dir |= spec->gpio_led; - spec->gpio_data |= spec->gpio_led; - } else { - codec->patch_ops.set_power_state = - stac92xx_set_power_state; - } - } - - spec->multiout.dac_nids = spec->dac_nids; - - err = stac92xx_parse_auto_config(codec); - if (!err) { - if (spec->board_config < 0) { - printk(KERN_WARNING "hda_codec: No auto-config is " - "available, default to model=ref\n"); - spec->board_config = STAC_92HD71BXX_REF; - goto again; - } - err = -EINVAL; - } + stac_setup_gpio(codec); + err = stac_parse_auto_config(codec); if (err < 0) { - stac92xx_free(codec); + stac_free(codec); return err; } - /* enable bass on HP dv7 */ - if (spec->board_config == STAC_HP_DV4 || - spec->board_config == STAC_HP_DV5) { - unsigned int cap; - cap = snd_hda_param_read(codec, 0x1, AC_PAR_GPIO_CAP); - cap &= AC_GPIO_IO_COUNT; - if (cap >= 6) - stac_add_hp_bass_switch(codec); - } - codec->proc_widget_hook = stac92hd7x_proc_hook; + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); + return 0; } @@ -6024,95 +4090,17 @@ static int patch_stac922x(struct hda_codec *codec) struct sigmatel_spec *spec; int err; - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; + err = alloc_stac_spec(codec); + if (err < 0) + return err; - codec->no_trigger_sense = 1; - codec->spec = spec; + spec = codec->spec; spec->linear_tone_beep = 1; - spec->num_pins = ARRAY_SIZE(stac922x_pin_nids); - spec->pin_nids = stac922x_pin_nids; - spec->board_config = snd_hda_check_board_config(codec, STAC_922X_MODELS, - stac922x_models, - stac922x_cfg_tbl); - if (spec->board_config == STAC_INTEL_MAC_AUTO) { - spec->gpio_mask = spec->gpio_dir = 0x03; - spec->gpio_data = 0x03; - /* Intel Macs have all same PCI SSID, so we need to check - * codec SSID to distinguish the exact models - */ - printk(KERN_INFO "hda_codec: STAC922x, Apple subsys_id=%x\n", codec->subsystem_id); - switch (codec->subsystem_id) { + spec->gen.own_eapd_ctl = 1; - case 0x106b0800: - spec->board_config = STAC_INTEL_MAC_V1; - break; - case 0x106b0600: - case 0x106b0700: - spec->board_config = STAC_INTEL_MAC_V2; - break; - case 0x106b0e00: - case 0x106b0f00: - case 0x106b1600: - case 0x106b1700: - case 0x106b0200: - case 0x106b1e00: - spec->board_config = STAC_INTEL_MAC_V3; - break; - case 0x106b1a00: - case 0x00000100: - spec->board_config = STAC_INTEL_MAC_V4; - break; - case 0x106b0a00: - case 0x106b2200: - spec->board_config = STAC_INTEL_MAC_V5; - break; - default: - spec->board_config = STAC_INTEL_MAC_V3; - break; - } - } - - again: - if (spec->board_config < 0) - snd_printdd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", - codec->chip_name); - else - stac92xx_set_config_regs(codec, - stac922x_brd_tbl[spec->board_config]); + codec->patch_ops = stac_patch_ops; - spec->adc_nids = stac922x_adc_nids; - spec->mux_nids = stac922x_mux_nids; - spec->num_muxes = ARRAY_SIZE(stac922x_mux_nids); - spec->num_adcs = ARRAY_SIZE(stac922x_adc_nids); - spec->num_dmics = 0; - spec->num_pwrs = 0; - - spec->init = stac922x_core_init; - - spec->num_caps = STAC922X_NUM_CAPS; - spec->capvols = stac922x_capvols; - spec->capsws = stac922x_capsws; - - spec->multiout.dac_nids = spec->dac_nids; - - err = stac92xx_parse_auto_config(codec); - if (!err) { - if (spec->board_config < 0) { - printk(KERN_WARNING "hda_codec: No auto-config is " - "available, default to model=ref\n"); - spec->board_config = STAC_D945_REF; - goto again; - } - err = -EINVAL; - } - if (err < 0) { - stac92xx_free(codec); - return err; - } - - codec->patch_ops = stac92xx_patch_ops; + snd_hda_add_verbs(codec, stac922x_core_init); /* Fix Mux capture level; max to 2 */ snd_hda_override_amp_caps(codec, 0x12, HDA_OUTPUT, @@ -6121,124 +4109,67 @@ static int patch_stac922x(struct hda_codec *codec) (0x27 << AC_AMPCAP_STEP_SIZE_SHIFT) | (0 << AC_AMPCAP_MUTE_SHIFT)); + snd_hda_pick_fixup(codec, stac922x_models, stac922x_fixup_tbl, + stac922x_fixups); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); + + err = stac_parse_auto_config(codec); + if (err < 0) { + stac_free(codec); + return err; + } + + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); + return 0; } +static const char * const stac927x_spdif_labels[] = { + "Digital Playback", "ADAT", "Analog Mux 1", + "Analog Mux 2", "Analog Mux 3", NULL +}; + static int patch_stac927x(struct hda_codec *codec) { struct sigmatel_spec *spec; int err; - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; + err = alloc_stac_spec(codec); + if (err < 0) + return err; - codec->no_trigger_sense = 1; - codec->spec = spec; + spec = codec->spec; spec->linear_tone_beep = 1; - codec->slave_dig_outs = stac927x_slave_dig_outs; - spec->num_pins = ARRAY_SIZE(stac927x_pin_nids); - spec->pin_nids = stac927x_pin_nids; - spec->board_config = snd_hda_check_board_config(codec, STAC_927X_MODELS, - stac927x_models, - stac927x_cfg_tbl); - again: - if (spec->board_config < 0) - snd_printdd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", - codec->chip_name); - else - stac92xx_set_config_regs(codec, - stac927x_brd_tbl[spec->board_config]); - - spec->digbeep_nid = 0x23; - spec->adc_nids = stac927x_adc_nids; - spec->num_adcs = ARRAY_SIZE(stac927x_adc_nids); - spec->mux_nids = stac927x_mux_nids; - spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids); - spec->smux_nids = stac927x_smux_nids; - spec->num_smuxes = ARRAY_SIZE(stac927x_smux_nids); + spec->gen.own_eapd_ctl = 1; + spec->have_spdif_mux = 1; spec->spdif_labels = stac927x_spdif_labels; - spec->dac_list = stac927x_dac_nids; - spec->multiout.dac_nids = spec->dac_nids; - if (spec->board_config != STAC_D965_REF) { - /* GPIO0 High = Enable EAPD */ - spec->eapd_mask = spec->gpio_mask = 0x01; - spec->gpio_dir = spec->gpio_data = 0x01; - } - - switch (spec->board_config) { - case STAC_D965_3ST: - case STAC_D965_5ST: - /* GPIO0 High = Enable EAPD */ - spec->num_dmics = 0; - spec->init = d965_core_init; - break; - case STAC_DELL_BIOS: - switch (codec->subsystem_id) { - case 0x10280209: - case 0x1028022e: - /* correct the device field to SPDIF out */ - snd_hda_codec_set_pincfg(codec, 0x21, 0x01442070); - break; - } - /* configure the analog microphone on some laptops */ - snd_hda_codec_set_pincfg(codec, 0x0c, 0x90a79130); - /* correct the front output jack as a hp out */ - snd_hda_codec_set_pincfg(codec, 0x0f, 0x0227011f); - /* correct the front input jack as a mic */ - snd_hda_codec_set_pincfg(codec, 0x0e, 0x02a79130); - /* fallthru */ - case STAC_DELL_3ST: - if (codec->subsystem_id != 0x1028022f) { - /* GPIO2 High = Enable EAPD */ - spec->eapd_mask = spec->gpio_mask = 0x04; - spec->gpio_dir = spec->gpio_data = 0x04; - } - spec->dmic_nids = stac927x_dmic_nids; - spec->num_dmics = STAC927X_NUM_DMICS; - - spec->init = dell_3st_core_init; - spec->dmux_nids = stac927x_dmux_nids; - spec->num_dmuxes = ARRAY_SIZE(stac927x_dmux_nids); - break; - case STAC_927X_VOLKNOB: - spec->num_dmics = 0; - spec->init = stac927x_volknob_core_init; - break; - default: - spec->num_dmics = 0; - spec->init = stac927x_core_init; - break; - } + spec->digbeep_nid = 0x23; - spec->num_caps = STAC927X_NUM_CAPS; - spec->capvols = stac927x_capvols; - spec->capsws = stac927x_capsws; + /* GPIO0 High = Enable EAPD */ + spec->eapd_mask = spec->gpio_mask = 0x01; + spec->gpio_dir = spec->gpio_data = 0x01; - spec->num_pwrs = 0; - spec->aloopback_ctl = stac927x_loopback; + spec->aloopback_ctl = &stac927x_loopback; spec->aloopback_mask = 0x40; spec->aloopback_shift = 0; spec->eapd_switch = 1; - err = stac92xx_parse_auto_config(codec); - if (!err) { - if (spec->board_config < 0) { - printk(KERN_WARNING "hda_codec: No auto-config is " - "available, default to model=ref\n"); - spec->board_config = STAC_D965_REF; - goto again; - } - err = -EINVAL; - } + codec->patch_ops = stac_patch_ops; + + snd_hda_pick_fixup(codec, stac927x_models, stac927x_fixup_tbl, + stac927x_fixups); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); + + if (!spec->volknob_init) + snd_hda_add_verbs(codec, stac927x_core_init); + + err = stac_parse_auto_config(codec); if (err < 0) { - stac92xx_free(codec); + stac_free(codec); return err; } - codec->patch_ops = stac92xx_patch_ops; - codec->proc_widget_hook = stac927x_proc_hook; /* @@ -6253,9 +4184,7 @@ static int patch_stac927x(struct hda_codec *codec) */ codec->bus->needs_damn_long_delay = 1; - /* no jack detecion for ref-no-jd model */ - if (spec->board_config == STAC_D965_REF_NO_JD) - spec->hp_detect = 0; + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); return 0; } @@ -6265,105 +4194,46 @@ static int patch_stac9205(struct hda_codec *codec) struct sigmatel_spec *spec; int err; - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; + err = alloc_stac_spec(codec); + if (err < 0) + return err; - codec->no_trigger_sense = 1; - codec->spec = spec; + spec = codec->spec; spec->linear_tone_beep = 1; - spec->num_pins = ARRAY_SIZE(stac9205_pin_nids); - spec->pin_nids = stac9205_pin_nids; - spec->board_config = snd_hda_check_board_config(codec, STAC_9205_MODELS, - stac9205_models, - stac9205_cfg_tbl); - again: - if (spec->board_config < 0) - snd_printdd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", - codec->chip_name); - else - stac92xx_set_config_regs(codec, - stac9205_brd_tbl[spec->board_config]); + spec->gen.own_eapd_ctl = 1; + spec->have_spdif_mux = 1; spec->digbeep_nid = 0x23; - spec->adc_nids = stac9205_adc_nids; - spec->num_adcs = ARRAY_SIZE(stac9205_adc_nids); - spec->mux_nids = stac9205_mux_nids; - spec->num_muxes = ARRAY_SIZE(stac9205_mux_nids); - spec->smux_nids = stac9205_smux_nids; - spec->num_smuxes = ARRAY_SIZE(stac9205_smux_nids); - spec->dmic_nids = stac9205_dmic_nids; - spec->num_dmics = STAC9205_NUM_DMICS; - spec->dmux_nids = stac9205_dmux_nids; - spec->num_dmuxes = ARRAY_SIZE(stac9205_dmux_nids); - spec->num_pwrs = 0; - - spec->init = stac9205_core_init; - spec->aloopback_ctl = stac9205_loopback; - - spec->num_caps = STAC9205_NUM_CAPS; - spec->capvols = stac9205_capvols; - spec->capsws = stac9205_capsws; + + snd_hda_add_verbs(codec, stac9205_core_init); + spec->aloopback_ctl = &stac9205_loopback; spec->aloopback_mask = 0x40; spec->aloopback_shift = 0; - /* Turn on/off EAPD per HP plugging */ - if (spec->board_config != STAC_9205_EAPD) - spec->eapd_switch = 1; - spec->multiout.dac_nids = spec->dac_nids; - switch (spec->board_config){ - case STAC_9205_DELL_M43: - /* Enable SPDIF in/out */ - snd_hda_codec_set_pincfg(codec, 0x1f, 0x01441030); - snd_hda_codec_set_pincfg(codec, 0x20, 0x1c410030); + /* GPIO0 High = EAPD */ + spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x1; + spec->gpio_data = 0x01; - /* Enable unsol response for GPIO4/Dock HP connection */ - err = stac_add_event(codec, codec->afg, STAC_VREF_EVENT, 0x01); - if (err < 0) - return err; - snd_hda_codec_write_cache(codec, codec->afg, 0, - AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x10); - snd_hda_jack_detect_enable(codec, codec->afg, 0); + /* Turn on/off EAPD per HP plugging */ + spec->eapd_switch = 1; - spec->gpio_dir = 0x0b; - spec->eapd_mask = 0x01; - spec->gpio_mask = 0x1b; - spec->gpio_mute = 0x10; - /* GPIO0 High = EAPD, GPIO1 Low = Headphone Mute, - * GPIO3 Low = DRM - */ - spec->gpio_data = 0x01; - break; - case STAC_9205_REF: - /* SPDIF-In enabled */ - break; - default: - /* GPIO0 High = EAPD */ - spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x1; - spec->gpio_data = 0x01; - break; - } + codec->patch_ops = stac_patch_ops; - err = stac92xx_parse_auto_config(codec); - if (!err) { - if (spec->board_config < 0) { - printk(KERN_WARNING "hda_codec: No auto-config is " - "available, default to model=ref\n"); - spec->board_config = STAC_9205_REF; - goto again; - } - err = -EINVAL; - } + snd_hda_pick_fixup(codec, stac9205_models, stac9205_fixup_tbl, + stac9205_fixups); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); + + err = stac_parse_auto_config(codec); if (err < 0) { - stac92xx_free(codec); + stac_free(codec); return err; } - codec->patch_ops = stac92xx_patch_ops; - codec->proc_widget_hook = stac9205_proc_hook; + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); + return 0; } @@ -6377,40 +4247,32 @@ static const struct hda_verb stac9872_core_init[] = { {} }; -static const hda_nid_t stac9872_pin_nids[] = { - 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x11, 0x13, 0x14, -}; - -static const hda_nid_t stac9872_adc_nids[] = { - 0x8 /*,0x6*/ -}; - -static const hda_nid_t stac9872_mux_nids[] = { - 0x15 -}; - -static const unsigned long stac9872_capvols[] = { - HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT), -}; -#define stac9872_capsws stac9872_capvols - -static const unsigned int stac9872_vaio_pin_configs[9] = { - 0x03211020, 0x411111f0, 0x411111f0, 0x03a15030, - 0x411111f0, 0x90170110, 0x411111f0, 0x411111f0, - 0x90a7013e +static const struct hda_pintbl stac9872_vaio_pin_configs[] = { + { 0x0a, 0x03211020 }, + { 0x0b, 0x411111f0 }, + { 0x0c, 0x411111f0 }, + { 0x0d, 0x03a15030 }, + { 0x0e, 0x411111f0 }, + { 0x0f, 0x90170110 }, + { 0x11, 0x411111f0 }, + { 0x13, 0x411111f0 }, + { 0x14, 0x90a7013e }, + {} }; -static const char * const stac9872_models[STAC_9872_MODELS] = { - [STAC_9872_AUTO] = "auto", - [STAC_9872_VAIO] = "vaio", +static const struct hda_model_fixup stac9872_models[] = { + { .id = STAC_9872_VAIO, .name = "vaio" }, + {} }; -static const unsigned int *stac9872_brd_tbl[STAC_9872_MODELS] = { - [STAC_9872_VAIO] = stac9872_vaio_pin_configs, +static const struct hda_fixup stac9872_fixups[] = { + [STAC_9872_VAIO] = { + .type = HDA_FIXUP_PINS, + .v.pins = stac9872_vaio_pin_configs, + }, }; -static const struct snd_pci_quirk stac9872_cfg_tbl[] = { +static const struct snd_pci_quirk stac9872_fixup_tbl[] = { SND_PCI_QUIRK_MASK(0x104d, 0xfff0, 0x81e0, "Sony VAIO F/S", STAC_9872_VAIO), {} /* terminator */ @@ -6421,42 +4283,30 @@ static int patch_stac9872(struct hda_codec *codec) struct sigmatel_spec *spec; int err; - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; - codec->no_trigger_sense = 1; - codec->spec = spec; + err = alloc_stac_spec(codec); + if (err < 0) + return err; + + spec = codec->spec; spec->linear_tone_beep = 1; - spec->num_pins = ARRAY_SIZE(stac9872_pin_nids); - spec->pin_nids = stac9872_pin_nids; - - spec->board_config = snd_hda_check_board_config(codec, STAC_9872_MODELS, - stac9872_models, - stac9872_cfg_tbl); - if (spec->board_config < 0) - snd_printdd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", - codec->chip_name); - else - stac92xx_set_config_regs(codec, - stac9872_brd_tbl[spec->board_config]); - - spec->multiout.dac_nids = spec->dac_nids; - spec->num_adcs = ARRAY_SIZE(stac9872_adc_nids); - spec->adc_nids = stac9872_adc_nids; - spec->num_muxes = ARRAY_SIZE(stac9872_mux_nids); - spec->mux_nids = stac9872_mux_nids; - spec->init = stac9872_core_init; - spec->num_caps = 1; - spec->capvols = stac9872_capvols; - spec->capsws = stac9872_capsws; - - err = stac92xx_parse_auto_config(codec); + spec->gen.own_eapd_ctl = 1; + + codec->patch_ops = stac_patch_ops; + + snd_hda_add_verbs(codec, stac9872_core_init); + + snd_hda_pick_fixup(codec, stac9872_models, stac9872_fixup_tbl, + stac9872_fixups); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); + + err = stac_parse_auto_config(codec); if (err < 0) { - stac92xx_free(codec); + stac_free(codec); return -EINVAL; } - spec->input_mux = &spec->private_imux; - codec->patch_ops = stac92xx_patch_ops; + + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); + return 0; } @@ -6527,6 +4377,7 @@ static const struct hda_codec_preset snd_hda_preset_sigmatel[] = { { .id = 0x111d7674, .name = "92HD73D1X5", .patch = patch_stac92hd73xx }, { .id = 0x111d7675, .name = "92HD73C1X5", .patch = patch_stac92hd73xx }, { .id = 0x111d7676, .name = "92HD73E1X5", .patch = patch_stac92hd73xx }, + { .id = 0x111d7695, .name = "92HD95", .patch = patch_stac92hd95 }, { .id = 0x111d76b0, .name = "92HD71B8X", .patch = patch_stac92hd71bxx }, { .id = 0x111d76b1, .name = "92HD71B8X", .patch = patch_stac92hd71bxx }, { .id = 0x111d76b2, .name = "92HD71B7X", .patch = patch_stac92hd71bxx }, diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 019e1a00414a..c35338a8771d 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -56,6 +56,7 @@ #include "hda_local.h" #include "hda_auto_parser.h" #include "hda_jack.h" +#include "hda_generic.h" /* Pin Widget NID */ #define VT1708_HP_PIN_NID 0x20 @@ -76,6 +77,8 @@ enum VIA_HDA_CODEC { VT2002P, VT1812, VT1802, + VT1705CF, + VT1808, CODEC_TYPES, }; @@ -84,39 +87,6 @@ enum VIA_HDA_CODEC { (spec)->codec_type == VT1812 ||\ (spec)->codec_type == VT1802) -#define MAX_NID_PATH_DEPTH 5 - -/* output-path: DAC -> ... -> pin - * idx[] contains the source index number of the next widget; - * e.g. idx[0] is the index of the DAC selected by path[1] widget - * multi[] indicates whether it's a selector widget with multi-connectors - * (i.e. the connection selection is mandatory) - * vol_ctl and mute_ctl contains the NIDs for the assigned mixers - */ -struct nid_path { - int depth; - hda_nid_t path[MAX_NID_PATH_DEPTH]; - unsigned char idx[MAX_NID_PATH_DEPTH]; - unsigned char multi[MAX_NID_PATH_DEPTH]; - unsigned int vol_ctl; - unsigned int mute_ctl; -}; - -/* input-path */ -struct via_input { - hda_nid_t pin; /* input-pin or aa-mix */ - int adc_idx; /* ADC index to be used */ - int mux_idx; /* MUX index (if any) */ - const char *label; /* input-source label */ -}; - -#define VIA_MAX_ADCS 3 - -enum { - STREAM_MULTI_OUT = (1 << 0), - STREAM_INDEP_HP = (1 << 1), -}; - struct via_spec { struct hda_gen_spec gen; @@ -127,77 +97,7 @@ struct via_spec { const struct hda_verb *init_verbs[5]; unsigned int num_iverbs; - char stream_name_analog[32]; - char stream_name_hp[32]; - const struct hda_pcm_stream *stream_analog_playback; - const struct hda_pcm_stream *stream_analog_capture; - - char stream_name_digital[32]; - const struct hda_pcm_stream *stream_digital_playback; - const struct hda_pcm_stream *stream_digital_capture; - - /* playback */ - struct hda_multi_out multiout; - hda_nid_t slave_dig_outs[2]; - hda_nid_t hp_dac_nid; - hda_nid_t speaker_dac_nid; - int hp_indep_shared; /* indep HP-DAC is shared with side ch */ - int opened_streams; /* STREAM_* bits */ - int active_streams; /* STREAM_* bits */ - int aamix_mode; /* loopback is enabled for output-path? */ - - /* Output-paths: - * There are different output-paths depending on the setup. - * out_path, hp_path and speaker_path are primary paths. If both - * direct DAC and aa-loopback routes are available, these contain - * the former paths. Meanwhile *_mix_path contain the paths with - * loopback mixer. (Since the loopback is only for front channel, - * no out_mix_path for surround channels.) - * The HP output has another path, hp_indep_path, which is used in - * the independent-HP mode. - */ - struct nid_path out_path[HDA_SIDE + 1]; - struct nid_path out_mix_path; - struct nid_path hp_path; - struct nid_path hp_mix_path; - struct nid_path hp_indep_path; - struct nid_path speaker_path; - struct nid_path speaker_mix_path; - - /* capture */ - unsigned int num_adc_nids; - hda_nid_t adc_nids[VIA_MAX_ADCS]; - hda_nid_t mux_nids[VIA_MAX_ADCS]; - hda_nid_t aa_mix_nid; - hda_nid_t dig_in_nid; - - /* capture source */ - bool dyn_adc_switch; - int num_inputs; - struct via_input inputs[AUTO_CFG_MAX_INS + 1]; - unsigned int cur_mux[VIA_MAX_ADCS]; - - /* dynamic DAC switching */ - unsigned int cur_dac_stream_tag; - unsigned int cur_dac_format; - unsigned int cur_hp_stream_tag; - unsigned int cur_hp_format; - - /* dynamic ADC switching */ - hda_nid_t cur_adc; - unsigned int cur_adc_stream_tag; - unsigned int cur_adc_format; - - /* PCM information */ - struct hda_pcm pcm_rec[3]; - - /* dynamic controls, init_verbs and input_mux */ - struct auto_pin_cfg autocfg; - struct snd_array kctls; - hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS]; - /* HP mode source */ - unsigned int hp_independent_mode; unsigned int dmic_enabled; unsigned int no_pin_power_ctl; enum VIA_HDA_CODEC codec_type; @@ -205,35 +105,22 @@ struct via_spec { /* analog low-power control */ bool alc_mode; - /* smart51 setup */ - unsigned int smart51_nums; - hda_nid_t smart51_pins[2]; - int smart51_idxs[2]; - const char *smart51_labels[2]; - unsigned int smart51_enabled; - /* work to check hp jack state */ - struct hda_codec *codec; - struct delayed_work vt1708_hp_work; int hp_work_active; int vt1708_jack_detect; - int vt1708_hp_present; void (*set_widgets_power_state)(struct hda_codec *codec); - - struct hda_loopback_check loopback; - int num_loopbacks; - struct hda_amp_list loopback_list[8]; - - /* bind capture-volume */ - struct hda_bind_ctls *bind_cap_vol; - struct hda_bind_ctls *bind_cap_sw; - - struct mutex config_mutex; + unsigned int dac_stream_tag[4]; }; static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec); -static struct via_spec * via_new_spec(struct hda_codec *codec) +static void via_playback_pcm_hook(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream, + int action); +static void via_hp_automute(struct hda_codec *codec, struct hda_jack_tbl *tbl); + +static struct via_spec *via_new_spec(struct hda_codec *codec) { struct via_spec *spec; @@ -241,14 +128,15 @@ static struct via_spec * via_new_spec(struct hda_codec *codec) if (spec == NULL) return NULL; - mutex_init(&spec->config_mutex); codec->spec = spec; - spec->codec = codec; + snd_hda_gen_spec_init(&spec->gen); spec->codec_type = get_codec_type(codec); /* VT1708BCE & VT1708S are almost same */ if (spec->codec_type == VT1708BCE) spec->codec_type = VT1708S; - snd_hda_gen_init(&spec->gen); + spec->no_pin_power_ctl = 1; + spec->gen.indep_hp = 1; + spec->gen.pcm_playback_hook = via_playback_pcm_hook; return spec; } @@ -295,21 +183,15 @@ static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec) codec_type = VT1708S; else if ((dev_id & 0xfff) == 0x446) codec_type = VT1802; + else if (dev_id == 0x4760) + codec_type = VT1705CF; + else if (dev_id == 0x4761 || dev_id == 0x4762) + codec_type = VT1808; else codec_type = UNKNOWN; return codec_type; }; -#define VIA_JACK_EVENT 0x20 -#define VIA_HP_EVENT 0x01 -#define VIA_LINE_EVENT 0x03 - -enum { - VIA_CTL_WIDGET_VOL, - VIA_CTL_WIDGET_MUTE, - VIA_CTL_WIDGET_ANALOG_MUTE, -}; - static void analog_low_current_mode(struct hda_codec *codec); static bool is_aa_path_mute(struct hda_codec *codec); @@ -317,31 +199,34 @@ static bool is_aa_path_mute(struct hda_codec *codec); (snd_hda_get_bool_hint(codec, "analog_loopback_hp_detect") == 1 && \ !is_aa_path_mute(codec)) -static void vt1708_stop_hp_work(struct via_spec *spec) +static void vt1708_stop_hp_work(struct hda_codec *codec) { - if (spec->codec_type != VT1708 || spec->autocfg.hp_pins[0] == 0) + struct via_spec *spec = codec->spec; + if (spec->codec_type != VT1708 || !spec->gen.autocfg.hp_outs) return; if (spec->hp_work_active) { - snd_hda_codec_write(spec->codec, 0x1, 0, 0xf81, 1); - cancel_delayed_work_sync(&spec->vt1708_hp_work); - spec->hp_work_active = 0; + snd_hda_codec_write(codec, 0x1, 0, 0xf81, 1); + cancel_delayed_work_sync(&codec->jackpoll_work); + spec->hp_work_active = false; + codec->jackpoll_interval = 0; } } -static void vt1708_update_hp_work(struct via_spec *spec) +static void vt1708_update_hp_work(struct hda_codec *codec) { - if (spec->codec_type != VT1708 || spec->autocfg.hp_pins[0] == 0) + struct via_spec *spec = codec->spec; + if (spec->codec_type != VT1708 || !spec->gen.autocfg.hp_outs) return; - if (spec->vt1708_jack_detect && - (spec->active_streams || hp_detect_with_aa(spec->codec))) { + if (spec->vt1708_jack_detect) { if (!spec->hp_work_active) { - snd_hda_codec_write(spec->codec, 0x1, 0, 0xf81, 0); - schedule_delayed_work(&spec->vt1708_hp_work, - msecs_to_jiffies(100)); - spec->hp_work_active = 1; + codec->jackpoll_interval = msecs_to_jiffies(100); + snd_hda_codec_write(codec, 0x1, 0, 0xf81, 0); + queue_delayed_work(codec->bus->workq, + &codec->jackpoll_work, 0); + spec->hp_work_active = true; } - } else if (!hp_detect_with_aa(spec->codec)) - vt1708_stop_hp_work(spec); + } else if (!hp_detect_with_aa(codec)) + vt1708_stop_hp_work(codec); } static void set_widgets_power_state(struct hda_codec *codec) @@ -351,364 +236,51 @@ static void set_widgets_power_state(struct hda_codec *codec) spec->set_widgets_power_state(codec); } -static int analog_input_switch_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - int change = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - - set_widgets_power_state(codec); - analog_low_current_mode(snd_kcontrol_chip(kcontrol)); - vt1708_update_hp_work(codec->spec); - return change; -} - -/* modify .put = snd_hda_mixer_amp_switch_put */ -#define ANALOG_INPUT_MUTE \ - { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = NULL, \ - .index = 0, \ - .info = snd_hda_mixer_amp_switch_info, \ - .get = snd_hda_mixer_amp_switch_get, \ - .put = analog_input_switch_put, \ - .private_value = HDA_COMPOSE_AMP_VAL(0, 3, 0, 0) } - -static const struct snd_kcontrol_new via_control_templates[] = { - HDA_CODEC_VOLUME(NULL, 0, 0, 0), - HDA_CODEC_MUTE(NULL, 0, 0, 0), - ANALOG_INPUT_MUTE, -}; - - -/* add dynamic controls */ -static struct snd_kcontrol_new *__via_clone_ctl(struct via_spec *spec, - const struct snd_kcontrol_new *tmpl, - const char *name) -{ - struct snd_kcontrol_new *knew; - - snd_array_init(&spec->kctls, sizeof(*knew), 32); - knew = snd_array_new(&spec->kctls); - if (!knew) - return NULL; - *knew = *tmpl; - if (!name) - name = tmpl->name; - if (name) { - knew->name = kstrdup(name, GFP_KERNEL); - if (!knew->name) - return NULL; - } - return knew; -} - -static int __via_add_control(struct via_spec *spec, int type, const char *name, - int idx, unsigned long val) -{ - struct snd_kcontrol_new *knew; - - knew = __via_clone_ctl(spec, &via_control_templates[type], name); - if (!knew) - return -ENOMEM; - knew->index = idx; - if (get_amp_nid_(val)) - knew->subdevice = HDA_SUBDEV_AMP_FLAG; - knew->private_value = val; - return 0; -} - -#define via_add_control(spec, type, name, val) \ - __via_add_control(spec, type, name, 0, val) - -#define via_clone_control(spec, tmpl) __via_clone_ctl(spec, tmpl, NULL) - -static void via_free_kctls(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - - if (spec->kctls.list) { - struct snd_kcontrol_new *kctl = spec->kctls.list; - int i; - for (i = 0; i < spec->kctls.used; i++) - kfree(kctl[i].name); - } - snd_array_free(&spec->kctls); -} - -/* create input playback/capture controls for the given pin */ -static int via_new_analog_input(struct via_spec *spec, const char *ctlname, - int type_idx, int idx, int mix_nid) -{ - char name[32]; - int err; - - sprintf(name, "%s Playback Volume", ctlname); - err = __via_add_control(spec, VIA_CTL_WIDGET_VOL, name, type_idx, - HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT)); - if (err < 0) - return err; - sprintf(name, "%s Playback Switch", ctlname); - err = __via_add_control(spec, VIA_CTL_WIDGET_ANALOG_MUTE, name, type_idx, - HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT)); - if (err < 0) - return err; - return 0; -} - -#define get_connection_index(codec, mux, nid) \ - snd_hda_get_conn_index(codec, mux, nid, 0) - -static bool check_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir, - unsigned int mask) -{ - unsigned int caps; - if (!nid) - return false; - caps = get_wcaps(codec, nid); - if (dir == HDA_INPUT) - caps &= AC_WCAP_IN_AMP; - else - caps &= AC_WCAP_OUT_AMP; - if (!caps) - return false; - if (query_amp_caps(codec, nid, dir) & mask) - return true; - return false; -} - -#define have_mute(codec, nid, dir) \ - check_amp_caps(codec, nid, dir, AC_AMPCAP_MUTE) - -/* enable/disable the output-route mixers */ -static void activate_output_mix(struct hda_codec *codec, struct nid_path *path, - hda_nid_t mix_nid, int idx, bool enable) +static void update_power_state(struct hda_codec *codec, hda_nid_t nid, + unsigned int parm) { - int i, num, val; - - if (!path) + if (snd_hda_check_power_state(codec, nid, parm)) return; - num = snd_hda_get_num_conns(codec, mix_nid); - for (i = 0; i < num; i++) { - if (i == idx) - val = AMP_IN_UNMUTE(i); - else - val = AMP_IN_MUTE(i); - snd_hda_codec_write(codec, mix_nid, 0, - AC_VERB_SET_AMP_GAIN_MUTE, val); - } + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE, parm); } -/* enable/disable the output-route */ -static void activate_output_path(struct hda_codec *codec, struct nid_path *path, - bool enable, bool force) +static void update_conv_power_state(struct hda_codec *codec, hda_nid_t nid, + unsigned int parm, unsigned int index) { struct via_spec *spec = codec->spec; - int i; - for (i = 0; i < path->depth; i++) { - hda_nid_t src, dst; - int idx = path->idx[i]; - src = path->path[i]; - if (i < path->depth - 1) - dst = path->path[i + 1]; - else - dst = 0; - if (enable && path->multi[i]) - snd_hda_codec_write(codec, dst, 0, - AC_VERB_SET_CONNECT_SEL, idx); - if (!force && (dst == spec->aa_mix_nid)) - continue; - if (have_mute(codec, dst, HDA_INPUT)) - activate_output_mix(codec, path, dst, idx, enable); - if (!force && (src == path->vol_ctl || src == path->mute_ctl)) - continue; - if (have_mute(codec, src, HDA_OUTPUT)) { - int val = enable ? AMP_OUT_UNMUTE : AMP_OUT_MUTE; - snd_hda_codec_write(codec, src, 0, - AC_VERB_SET_AMP_GAIN_MUTE, val); - } - } -} - -/* set the given pin as output */ -static void init_output_pin(struct hda_codec *codec, hda_nid_t pin, - int pin_type) -{ - if (!pin) - return; - snd_hda_set_pin_ctl(codec, pin, pin_type); - if (snd_hda_query_pin_caps(codec, pin) & AC_PINCAP_EAPD) - snd_hda_codec_write(codec, pin, 0, - AC_VERB_SET_EAPD_BTLENABLE, 0x02); -} + unsigned int format; -static void via_auto_init_output(struct hda_codec *codec, - struct nid_path *path, int pin_type) -{ - unsigned int caps; - hda_nid_t pin; - - if (!path->depth) + if (snd_hda_check_power_state(codec, nid, parm)) return; - pin = path->path[path->depth - 1]; - - init_output_pin(codec, pin, pin_type); - if (get_wcaps(codec, pin) & AC_WCAP_OUT_AMP) - caps = query_amp_caps(codec, pin, HDA_OUTPUT); - else - caps = 0; - if (caps & AC_AMPCAP_MUTE) { - unsigned int val; - val = (caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT; - snd_hda_codec_write(codec, pin, 0, AC_VERB_SET_AMP_GAIN_MUTE, - AMP_OUT_MUTE | val); - } - activate_output_path(codec, path, true, true); /* force on */ -} + format = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0); + if (format && (spec->dac_stream_tag[index] != format)) + spec->dac_stream_tag[index] = format; -static void via_auto_init_multi_out(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - struct nid_path *path; - int i; - - for (i = 0; i < spec->autocfg.line_outs + spec->smart51_nums; i++) { - path = &spec->out_path[i]; - if (!i && spec->aamix_mode && spec->out_mix_path.depth) - path = &spec->out_mix_path; - via_auto_init_output(codec, path, PIN_OUT); - } -} - -/* deactivate the inactive headphone-paths */ -static void deactivate_hp_paths(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - int shared = spec->hp_indep_shared; - - if (spec->hp_independent_mode) { - activate_output_path(codec, &spec->hp_path, false, false); - activate_output_path(codec, &spec->hp_mix_path, false, false); - if (shared) - activate_output_path(codec, &spec->out_path[shared], - false, false); - } else if (spec->aamix_mode || !spec->hp_path.depth) { - activate_output_path(codec, &spec->hp_indep_path, false, false); - activate_output_path(codec, &spec->hp_path, false, false); - } else { - activate_output_path(codec, &spec->hp_indep_path, false, false); - activate_output_path(codec, &spec->hp_mix_path, false, false); - } -} - -static void via_auto_init_hp_out(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - - if (!spec->hp_path.depth) { - via_auto_init_output(codec, &spec->hp_mix_path, PIN_HP); - return; + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE, parm); + if (parm == AC_PWRST_D0) { + format = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0); + if (!format && (spec->dac_stream_tag[index] != format)) + snd_hda_codec_write(codec, nid, 0, + AC_VERB_SET_CHANNEL_STREAMID, + spec->dac_stream_tag[index]); } - deactivate_hp_paths(codec); - if (spec->hp_independent_mode) - via_auto_init_output(codec, &spec->hp_indep_path, PIN_HP); - else if (spec->aamix_mode) - via_auto_init_output(codec, &spec->hp_mix_path, PIN_HP); - else - via_auto_init_output(codec, &spec->hp_path, PIN_HP); } -static void via_auto_init_speaker_out(struct hda_codec *codec) +static bool smart51_enabled(struct hda_codec *codec) { struct via_spec *spec = codec->spec; - - if (!spec->autocfg.speaker_outs) - return; - if (!spec->speaker_path.depth) { - via_auto_init_output(codec, &spec->speaker_mix_path, PIN_OUT); - return; - } - if (!spec->aamix_mode) { - activate_output_path(codec, &spec->speaker_mix_path, - false, false); - via_auto_init_output(codec, &spec->speaker_path, PIN_OUT); - } else { - activate_output_path(codec, &spec->speaker_path, false, false); - via_auto_init_output(codec, &spec->speaker_mix_path, PIN_OUT); - } + return spec->gen.ext_channel_count > 2; } -static bool is_smart51_pins(struct hda_codec *codec, hda_nid_t pin); -static void via_hp_automute(struct hda_codec *codec); - -static void via_auto_init_analog_input(struct hda_codec *codec) +static bool is_smart51_pins(struct hda_codec *codec, hda_nid_t pin) { struct via_spec *spec = codec->spec; - const struct auto_pin_cfg *cfg = &spec->autocfg; - hda_nid_t conn[HDA_MAX_CONNECTIONS]; - unsigned int ctl; - int i, num_conns; - - /* init ADCs */ - for (i = 0; i < spec->num_adc_nids; i++) { - hda_nid_t nid = spec->adc_nids[i]; - if (!(get_wcaps(codec, nid) & AC_WCAP_IN_AMP) || - !(query_amp_caps(codec, nid, HDA_INPUT) & AC_AMPCAP_MUTE)) - continue; - snd_hda_codec_write(codec, spec->adc_nids[i], 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_IN_UNMUTE(0)); - } - - /* init pins */ - for (i = 0; i < cfg->num_inputs; i++) { - hda_nid_t nid = cfg->inputs[i].pin; - if (spec->smart51_enabled && is_smart51_pins(codec, nid)) - ctl = PIN_OUT; - else { - ctl = PIN_IN; - if (cfg->inputs[i].type == AUTO_PIN_MIC) - ctl |= snd_hda_get_default_vref(codec, nid); - } - snd_hda_set_pin_ctl(codec, nid, ctl); - } - - /* init input-src */ - for (i = 0; i < spec->num_adc_nids; i++) { - int adc_idx = spec->inputs[spec->cur_mux[i]].adc_idx; - /* secondary ADCs must have the unique MUX */ - if (i > 0 && !spec->mux_nids[i]) - break; - if (spec->mux_nids[adc_idx]) { - int mux_idx = spec->inputs[spec->cur_mux[i]].mux_idx; - snd_hda_codec_write(codec, spec->mux_nids[adc_idx], 0, - AC_VERB_SET_CONNECT_SEL, - mux_idx); - } - if (spec->dyn_adc_switch) - break; /* only one input-src */ - } - - /* init aa-mixer */ - if (!spec->aa_mix_nid) - return; - num_conns = snd_hda_get_connections(codec, spec->aa_mix_nid, conn, - ARRAY_SIZE(conn)); - for (i = 0; i < num_conns; i++) { - unsigned int caps = get_wcaps(codec, conn[i]); - if (get_wcaps_type(caps) == AC_WID_PIN) - snd_hda_codec_write(codec, spec->aa_mix_nid, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_IN_MUTE(i)); - } -} + int i; -static void update_power_state(struct hda_codec *codec, hda_nid_t nid, - unsigned int parm) -{ - if (snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_POWER_STATE, 0) == parm) - return; - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE, parm); + for (i = 0; i < spec->gen.multi_ios; i++) + if (spec->gen.multi_io[i].pin == pin) + return true; + return false; } static void set_pin_power_state(struct hda_codec *codec, hda_nid_t nid, @@ -725,7 +297,7 @@ static void set_pin_power_state(struct hda_codec *codec, hda_nid_t nid, no_presence |= spec->no_pin_power_ctl; if (!no_presence) present = snd_hda_jack_detect(codec, nid); - if ((spec->smart51_enabled && is_smart51_pins(codec, nid)) + if ((smart51_enabled(codec) && is_smart51_pins(codec, nid)) || ((no_presence || present) && get_defcfg_connect(def_conf) != AC_JACK_PORT_NONE)) { *affected_parm = AC_PWRST_D0; /* if it's connected */ @@ -739,18 +311,7 @@ static void set_pin_power_state(struct hda_codec *codec, hda_nid_t nid, static int via_pin_power_ctl_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static const char * const texts[] = { - "Disabled", "Enabled" - }; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 2; - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); - return 0; + return snd_hda_enum_bool_helper_info(kcontrol, uinfo); } static int via_pin_power_ctl_get(struct snd_kcontrol *kcontrol, @@ -777,277 +338,29 @@ static int via_pin_power_ctl_put(struct snd_kcontrol *kcontrol, return 1; } -static const struct snd_kcontrol_new via_pin_power_ctl_enum = { +static const struct snd_kcontrol_new via_pin_power_ctl_enum[] = { + { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Dynamic Power-Control", .info = via_pin_power_ctl_info, .get = via_pin_power_ctl_get, .put = via_pin_power_ctl_put, + }, + {} /* terminator */ }; -static int via_independent_hp_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - static const char * const texts[] = { "OFF", "ON" }; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 2; - if (uinfo->value.enumerated.item >= 2) - uinfo->value.enumerated.item = 1; - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); - return 0; -} - -static int via_independent_hp_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct via_spec *spec = codec->spec; - - ucontrol->value.enumerated.item[0] = spec->hp_independent_mode; - return 0; -} - -/* adjust spec->multiout setup according to the current flags */ -static void setup_playback_multi_pcm(struct via_spec *spec) -{ - const struct auto_pin_cfg *cfg = &spec->autocfg; - spec->multiout.num_dacs = cfg->line_outs + spec->smart51_nums; - spec->multiout.hp_nid = 0; - if (!spec->hp_independent_mode) { - if (!spec->hp_indep_shared) - spec->multiout.hp_nid = spec->hp_dac_nid; - } else { - if (spec->hp_indep_shared) - spec->multiout.num_dacs = cfg->line_outs - 1; - } -} - -/* update DAC setups according to indep-HP switch; - * this function is called only when indep-HP is modified - */ -static void switch_indep_hp_dacs(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - int shared = spec->hp_indep_shared; - hda_nid_t shared_dac, hp_dac; - - if (!spec->opened_streams) - return; - - shared_dac = shared ? spec->multiout.dac_nids[shared] : 0; - hp_dac = spec->hp_dac_nid; - if (spec->hp_independent_mode) { - /* switch to indep-HP mode */ - if (spec->active_streams & STREAM_MULTI_OUT) { - __snd_hda_codec_cleanup_stream(codec, hp_dac, 1); - __snd_hda_codec_cleanup_stream(codec, shared_dac, 1); - } - if (spec->active_streams & STREAM_INDEP_HP) - snd_hda_codec_setup_stream(codec, hp_dac, - spec->cur_hp_stream_tag, 0, - spec->cur_hp_format); - } else { - /* back to HP or shared-DAC */ - if (spec->active_streams & STREAM_INDEP_HP) - __snd_hda_codec_cleanup_stream(codec, hp_dac, 1); - if (spec->active_streams & STREAM_MULTI_OUT) { - hda_nid_t dac; - int ch; - if (shared_dac) { /* reset mutli-ch DAC */ - dac = shared_dac; - ch = shared * 2; - } else { /* reset HP DAC */ - dac = hp_dac; - ch = 0; - } - snd_hda_codec_setup_stream(codec, dac, - spec->cur_dac_stream_tag, ch, - spec->cur_dac_format); - } - } - setup_playback_multi_pcm(spec); -} - -static int via_independent_hp_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct via_spec *spec = codec->spec; - int cur, shared; - - mutex_lock(&spec->config_mutex); - cur = !!ucontrol->value.enumerated.item[0]; - if (spec->hp_independent_mode == cur) { - mutex_unlock(&spec->config_mutex); - return 0; - } - spec->hp_independent_mode = cur; - shared = spec->hp_indep_shared; - deactivate_hp_paths(codec); - if (cur) - activate_output_path(codec, &spec->hp_indep_path, true, false); - else { - if (shared) - activate_output_path(codec, &spec->out_path[shared], - true, false); - if (spec->aamix_mode || !spec->hp_path.depth) - activate_output_path(codec, &spec->hp_mix_path, - true, false); - else - activate_output_path(codec, &spec->hp_path, - true, false); - } - - switch_indep_hp_dacs(codec); - mutex_unlock(&spec->config_mutex); - - /* update jack power state */ - set_widgets_power_state(codec); - via_hp_automute(codec); - return 1; -} - -static const struct snd_kcontrol_new via_hp_mixer = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Independent HP", - .info = via_independent_hp_info, - .get = via_independent_hp_get, - .put = via_independent_hp_put, -}; - -static int via_hp_build(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - struct snd_kcontrol_new *knew; - hda_nid_t nid; - - nid = spec->autocfg.hp_pins[0]; - knew = via_clone_control(spec, &via_hp_mixer); - if (knew == NULL) - return -ENOMEM; - - knew->subdevice = HDA_SUBDEV_NID_FLAG | nid; - - return 0; -} - -static void notify_aa_path_ctls(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - int i; - - for (i = 0; i < spec->smart51_nums; i++) { - struct snd_kcontrol *ctl; - struct snd_ctl_elem_id id; - memset(&id, 0, sizeof(id)); - id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; - sprintf(id.name, "%s Playback Volume", spec->smart51_labels[i]); - ctl = snd_hda_find_mixer_ctl(codec, id.name); - if (ctl) - snd_ctl_notify(codec->bus->card, - SNDRV_CTL_EVENT_MASK_VALUE, - &ctl->id); - } -} - -static void mute_aa_path(struct hda_codec *codec, int mute) -{ - struct via_spec *spec = codec->spec; - int val = mute ? HDA_AMP_MUTE : HDA_AMP_UNMUTE; - int i; - - /* check AA path's mute status */ - for (i = 0; i < spec->smart51_nums; i++) { - if (spec->smart51_idxs[i] < 0) - continue; - snd_hda_codec_amp_stereo(codec, spec->aa_mix_nid, - HDA_INPUT, spec->smart51_idxs[i], - HDA_AMP_MUTE, val); - } -} - -static bool is_smart51_pins(struct hda_codec *codec, hda_nid_t pin) -{ - struct via_spec *spec = codec->spec; - int i; - - for (i = 0; i < spec->smart51_nums; i++) - if (spec->smart51_pins[i] == pin) - return true; - return false; -} - -static int via_smart51_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct via_spec *spec = codec->spec; - - *ucontrol->value.integer.value = spec->smart51_enabled; - return 0; -} - -static int via_smart51_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct via_spec *spec = codec->spec; - int out_in = *ucontrol->value.integer.value - ? AC_PINCTL_OUT_EN : AC_PINCTL_IN_EN; - int i; - - for (i = 0; i < spec->smart51_nums; i++) { - hda_nid_t nid = spec->smart51_pins[i]; - unsigned int parm; - - parm = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); - parm &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN); - parm |= out_in; - snd_hda_set_pin_ctl(codec, nid, parm); - if (out_in == AC_PINCTL_OUT_EN) { - mute_aa_path(codec, 1); - notify_aa_path_ctls(codec); - } - } - spec->smart51_enabled = *ucontrol->value.integer.value; - set_widgets_power_state(codec); - return 1; -} - -static const struct snd_kcontrol_new via_smart51_mixer = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Smart 5.1", - .count = 1, - .info = snd_ctl_boolean_mono_info, - .get = via_smart51_get, - .put = via_smart51_put, -}; - -static int via_smart51_build(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - - if (!spec->smart51_nums) - return 0; - if (!via_clone_control(spec, &via_smart51_mixer)) - return -ENOMEM; - return 0; -} - /* check AA path's mute status */ static bool is_aa_path_mute(struct hda_codec *codec) { struct via_spec *spec = codec->spec; const struct hda_amp_list *p; - int i, ch, v; + int ch, v; - for (i = 0; i < spec->num_loopbacks; i++) { - p = &spec->loopback_list[i]; + p = spec->gen.loopback.amplist; + if (!p) + return true; + for (; p->nid; p++) { for (ch = 0; ch < 2; ch++) { v = snd_hda_codec_amp_read(codec, p->nid, ch, p->dir, p->idx); @@ -1068,7 +381,7 @@ static void __analog_low_current_mode(struct hda_codec *codec, bool force) if (spec->no_pin_power_ctl) enable = false; else - enable = is_aa_path_mute(codec) && !spec->opened_streams; + enable = is_aa_path_mute(codec) && !spec->gen.active_streams; if (enable == spec->alc_mode && !force) return; spec->alc_mode = enable; @@ -1096,6 +409,11 @@ static void __analog_low_current_mode(struct hda_codec *codec, bool force) verb = 0xf93; parm = enable ? 0x00 : 0xe0; /* 0x00: 4/40x, 0xe0: 1x */ break; + case VT1705CF: + case VT1808: + verb = 0xf82; + parm = enable ? 0x00 : 0xe0; /* 0x00: 4/40x, 0xe0: 1x */ + break; default: return; /* other codecs are not supported */ } @@ -1108,366 +426,17 @@ static void analog_low_current_mode(struct hda_codec *codec) return __analog_low_current_mode(codec, false); } -/* - * generic initialization of ADC, input mixers and output mixers - */ -static const struct hda_verb vt1708_init_verbs[] = { - /* power down jack detect function */ - {0x1, 0xf81, 0x1}, - { } -}; - -static void set_stream_open(struct hda_codec *codec, int bit, bool active) -{ - struct via_spec *spec = codec->spec; - - if (active) - spec->opened_streams |= bit; - else - spec->opened_streams &= ~bit; - analog_low_current_mode(codec); -} - -static int via_playback_multi_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct via_spec *spec = codec->spec; - const struct auto_pin_cfg *cfg = &spec->autocfg; - int err; - - spec->multiout.num_dacs = cfg->line_outs + spec->smart51_nums; - spec->multiout.max_channels = spec->multiout.num_dacs * 2; - set_stream_open(codec, STREAM_MULTI_OUT, true); - err = snd_hda_multi_out_analog_open(codec, &spec->multiout, substream, - hinfo); - if (err < 0) { - set_stream_open(codec, STREAM_MULTI_OUT, false); - return err; - } - return 0; -} - -static int via_playback_multi_pcm_close(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - set_stream_open(codec, STREAM_MULTI_OUT, false); - return 0; -} - -static int via_playback_hp_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct via_spec *spec = codec->spec; - - if (snd_BUG_ON(!spec->hp_dac_nid)) - return -EINVAL; - set_stream_open(codec, STREAM_INDEP_HP, true); - return 0; -} - -static int via_playback_hp_pcm_close(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - set_stream_open(codec, STREAM_INDEP_HP, false); - return 0; -} - -static int via_playback_multi_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct via_spec *spec = codec->spec; - - mutex_lock(&spec->config_mutex); - setup_playback_multi_pcm(spec); - snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag, - format, substream); - /* remember for dynamic DAC switch with indep-HP */ - spec->active_streams |= STREAM_MULTI_OUT; - spec->cur_dac_stream_tag = stream_tag; - spec->cur_dac_format = format; - mutex_unlock(&spec->config_mutex); - vt1708_update_hp_work(spec); - return 0; -} - -static int via_playback_hp_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct via_spec *spec = codec->spec; - - mutex_lock(&spec->config_mutex); - if (spec->hp_independent_mode) - snd_hda_codec_setup_stream(codec, spec->hp_dac_nid, - stream_tag, 0, format); - spec->active_streams |= STREAM_INDEP_HP; - spec->cur_hp_stream_tag = stream_tag; - spec->cur_hp_format = format; - mutex_unlock(&spec->config_mutex); - vt1708_update_hp_work(spec); - return 0; -} - -static int via_playback_multi_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct via_spec *spec = codec->spec; - - mutex_lock(&spec->config_mutex); - snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); - spec->active_streams &= ~STREAM_MULTI_OUT; - mutex_unlock(&spec->config_mutex); - vt1708_update_hp_work(spec); - return 0; -} - -static int via_playback_hp_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct via_spec *spec = codec->spec; - - mutex_lock(&spec->config_mutex); - if (spec->hp_independent_mode) - snd_hda_codec_setup_stream(codec, spec->hp_dac_nid, 0, 0, 0); - spec->active_streams &= ~STREAM_INDEP_HP; - mutex_unlock(&spec->config_mutex); - vt1708_update_hp_work(spec); - return 0; -} - -/* - * Digital out - */ -static int via_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct via_spec *spec = codec->spec; - return snd_hda_multi_out_dig_open(codec, &spec->multiout); -} - -static int via_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct via_spec *spec = codec->spec; - return snd_hda_multi_out_dig_close(codec, &spec->multiout); -} - -static int via_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 via_spec *spec = codec->spec; - return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, - stream_tag, format, substream); -} - -static int via_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct via_spec *spec = codec->spec; - snd_hda_multi_out_dig_cleanup(codec, &spec->multiout); - return 0; -} - -/* - * Analog capture - */ -static int via_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 via_spec *spec = codec->spec; - - snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], - stream_tag, 0, format); - return 0; -} - -static int via_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct via_spec *spec = codec->spec; - snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]); - return 0; -} - -/* analog capture with dynamic ADC switching */ -static int via_dyn_adc_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 via_spec *spec = codec->spec; - int adc_idx = spec->inputs[spec->cur_mux[0]].adc_idx; - - mutex_lock(&spec->config_mutex); - spec->cur_adc = spec->adc_nids[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); - mutex_unlock(&spec->config_mutex); - return 0; -} - -static int via_dyn_adc_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct via_spec *spec = codec->spec; - - mutex_lock(&spec->config_mutex); - snd_hda_codec_cleanup_stream(codec, spec->cur_adc); - spec->cur_adc = 0; - mutex_unlock(&spec->config_mutex); - return 0; -} - -/* re-setup the stream if running; called from input-src put */ -static bool via_dyn_adc_pcm_resetup(struct hda_codec *codec, int cur) -{ - struct via_spec *spec = codec->spec; - int adc_idx = spec->inputs[cur].adc_idx; - hda_nid_t adc = spec->adc_nids[adc_idx]; - bool ret = false; - - mutex_lock(&spec->config_mutex); - if (spec->cur_adc && spec->cur_adc != adc) { - /* stream is running, let's swap the current ADC */ - __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1); - spec->cur_adc = adc; - snd_hda_codec_setup_stream(codec, adc, - spec->cur_adc_stream_tag, 0, - spec->cur_adc_format); - ret = true; - } - mutex_unlock(&spec->config_mutex); - return ret; -} - -static const struct hda_pcm_stream via_pcm_analog_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 8, - /* NID is set in via_build_pcms */ - .ops = { - .open = via_playback_multi_pcm_open, - .close = via_playback_multi_pcm_close, - .prepare = via_playback_multi_pcm_prepare, - .cleanup = via_playback_multi_pcm_cleanup - }, -}; - -static const struct hda_pcm_stream via_pcm_hp_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - /* NID is set in via_build_pcms */ - .ops = { - .open = via_playback_hp_pcm_open, - .close = via_playback_hp_pcm_close, - .prepare = via_playback_hp_pcm_prepare, - .cleanup = via_playback_hp_pcm_cleanup - }, -}; - -static const struct hda_pcm_stream vt1708_pcm_analog_s16_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 8, - /* NID is set in via_build_pcms */ - /* We got noisy outputs on the right channel on VT1708 when - * 24bit samples are used. Until any workaround is found, - * disable the 24bit format, so far. - */ - .formats = SNDRV_PCM_FMTBIT_S16_LE, - .ops = { - .open = via_playback_multi_pcm_open, - .close = via_playback_multi_pcm_close, - .prepare = via_playback_multi_pcm_prepare, - .cleanup = via_playback_multi_pcm_cleanup - }, -}; - -static const struct hda_pcm_stream via_pcm_analog_capture = { - .substreams = 1, /* will be changed in via_build_pcms() */ - .channels_min = 2, - .channels_max = 2, - /* NID is set in via_build_pcms */ - .ops = { - .prepare = via_capture_pcm_prepare, - .cleanup = via_capture_pcm_cleanup - }, -}; - -static const struct hda_pcm_stream via_pcm_dyn_adc_analog_capture = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - /* NID is set in via_build_pcms */ - .ops = { - .prepare = via_dyn_adc_capture_pcm_prepare, - .cleanup = via_dyn_adc_capture_pcm_cleanup, - }, -}; - -static const struct hda_pcm_stream via_pcm_digital_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - /* NID is set in via_build_pcms */ - .ops = { - .open = via_dig_playback_pcm_open, - .close = via_dig_playback_pcm_close, - .prepare = via_dig_playback_pcm_prepare, - .cleanup = via_dig_playback_pcm_cleanup - }, -}; - -static const struct hda_pcm_stream via_pcm_digital_capture = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, -}; - -/* - * slave controls for virtual master - */ -static const char * const via_slave_pfxs[] = { - "Front", "Surround", "Center", "LFE", "Side", - "Headphone", "Speaker", - NULL, -}; - static int via_build_controls(struct hda_codec *codec) { struct via_spec *spec = codec->spec; - struct snd_kcontrol *kctl; int err, i; - spec->no_pin_power_ctl = 1; + err = snd_hda_gen_build_controls(codec); + if (err < 0) + return err; + if (spec->set_widgets_power_state) - if (!via_clone_control(spec, &via_pin_power_ctl_enum)) - return -ENOMEM; + spec->mixers[spec->num_mixers++] = via_pin_power_ctl_enum; for (i = 0; i < spec->num_mixers; i++) { err = snd_hda_add_new_ctls(codec, spec->mixers[i]); @@ -1475,148 +444,16 @@ static int via_build_controls(struct hda_codec *codec) 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 (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) { - unsigned int vmaster_tlv[4]; - snd_hda_set_vmaster_tlv(codec, spec->multiout.dac_nids[0], - HDA_OUTPUT, vmaster_tlv); - err = snd_hda_add_vmaster(codec, "Master Playback Volume", - vmaster_tlv, via_slave_pfxs, - "Playback Volume"); - if (err < 0) - return err; - } - if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) { - err = snd_hda_add_vmaster(codec, "Master Playback Switch", - NULL, via_slave_pfxs, - "Playback Switch"); - if (err < 0) - return err; - } - - /* assign Capture Source enums to NID */ - kctl = snd_hda_find_mixer_ctl(codec, "Input Source"); - for (i = 0; kctl && i < kctl->count; i++) { - if (!spec->mux_nids[i]) - continue; - err = snd_hda_add_nid(codec, kctl, i, spec->mux_nids[i]); - if (err < 0) - return err; - } - - via_free_kctls(codec); /* no longer needed */ - - err = snd_hda_jack_add_kctls(codec, &spec->autocfg); - if (err < 0) - return err; - return 0; } -static int via_build_pcms(struct hda_codec *codec) +static void via_playback_pcm_hook(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream, + int action) { - struct via_spec *spec = codec->spec; - struct hda_pcm *info = spec->pcm_rec; - - codec->num_pcms = 0; - codec->pcm_info = info; - - if (spec->multiout.num_dacs || spec->num_adc_nids) { - snprintf(spec->stream_name_analog, - sizeof(spec->stream_name_analog), - "%s Analog", codec->chip_name); - info->name = spec->stream_name_analog; - - if (spec->multiout.num_dacs) { - if (!spec->stream_analog_playback) - spec->stream_analog_playback = - &via_pcm_analog_playback; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = - *spec->stream_analog_playback; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = - spec->multiout.dac_nids[0]; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = - spec->multiout.max_channels; - } - - if (!spec->stream_analog_capture) { - if (spec->dyn_adc_switch) - spec->stream_analog_capture = - &via_pcm_dyn_adc_analog_capture; - else - spec->stream_analog_capture = - &via_pcm_analog_capture; - } - if (spec->num_adc_nids) { - info->stream[SNDRV_PCM_STREAM_CAPTURE] = - *spec->stream_analog_capture; - info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = - spec->adc_nids[0]; - if (!spec->dyn_adc_switch) - info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = - spec->num_adc_nids; - } - codec->num_pcms++; - info++; - } - - if (spec->multiout.dig_out_nid || spec->dig_in_nid) { - snprintf(spec->stream_name_digital, - sizeof(spec->stream_name_digital), - "%s Digital", codec->chip_name); - info->name = spec->stream_name_digital; - info->pcm_type = HDA_PCM_TYPE_SPDIF; - if (spec->multiout.dig_out_nid) { - if (!spec->stream_digital_playback) - spec->stream_digital_playback = - &via_pcm_digital_playback; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = - *spec->stream_digital_playback; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = - spec->multiout.dig_out_nid; - } - if (spec->dig_in_nid) { - if (!spec->stream_digital_capture) - spec->stream_digital_capture = - &via_pcm_digital_capture; - info->stream[SNDRV_PCM_STREAM_CAPTURE] = - *spec->stream_digital_capture; - info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = - spec->dig_in_nid; - } - codec->num_pcms++; - info++; - } - - if (spec->hp_dac_nid) { - snprintf(spec->stream_name_hp, sizeof(spec->stream_name_hp), - "%s HP", codec->chip_name); - info->name = spec->stream_name_hp; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = via_pcm_hp_playback; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = - spec->hp_dac_nid; - codec->num_pcms++; - info++; - } - return 0; + analog_low_current_mode(codec); + vt1708_update_hp_work(codec); } static void via_free(struct hda_codec *codec) @@ -1626,79 +463,22 @@ static void via_free(struct hda_codec *codec) if (!spec) return; - via_free_kctls(codec); - vt1708_stop_hp_work(spec); - kfree(spec->bind_cap_vol); - kfree(spec->bind_cap_sw); - snd_hda_gen_free(&spec->gen); + vt1708_stop_hp_work(codec); + snd_hda_gen_spec_free(&spec->gen); kfree(spec); } -/* mute/unmute outputs */ -static void toggle_output_mutes(struct hda_codec *codec, int num_pins, - hda_nid_t *pins, bool mute) -{ - int i; - for (i = 0; i < num_pins; i++) { - unsigned int parm = snd_hda_codec_read(codec, pins[i], 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); - if (parm & AC_PINCTL_IN_EN) - continue; - if (mute) - parm &= ~AC_PINCTL_OUT_EN; - else - parm |= AC_PINCTL_OUT_EN; - snd_hda_set_pin_ctl(codec, pins[i], parm); - } -} - -/* mute internal speaker if line-out is plugged */ -static void via_line_automute(struct hda_codec *codec, int present) -{ - struct via_spec *spec = codec->spec; - - if (!spec->autocfg.speaker_outs) - return; - if (!present) - present = snd_hda_jack_detect(codec, - spec->autocfg.line_out_pins[0]); - toggle_output_mutes(codec, spec->autocfg.speaker_outs, - spec->autocfg.speaker_pins, - present); -} - -/* mute internal speaker if HP is plugged */ -static void via_hp_automute(struct hda_codec *codec) -{ - int present = 0; - int nums; - struct via_spec *spec = codec->spec; - - if (!spec->hp_independent_mode && spec->autocfg.hp_pins[0] && - (spec->codec_type != VT1708 || spec->vt1708_jack_detect) && - is_jack_detectable(codec, spec->autocfg.hp_pins[0])) - present = snd_hda_jack_detect(codec, spec->autocfg.hp_pins[0]); - - if (spec->smart51_enabled) - nums = spec->autocfg.line_outs + spec->smart51_nums; - else - nums = spec->autocfg.line_outs; - toggle_output_mutes(codec, nums, spec->autocfg.line_out_pins, present); - - via_line_automute(codec, present); -} - #ifdef CONFIG_PM static int via_suspend(struct hda_codec *codec) { struct via_spec *spec = codec->spec; - vt1708_stop_hp_work(spec); + vt1708_stop_hp_work(codec); if (spec->codec_type == VT1802) { /* Fix pop noise on headphones */ int i; - for (i = 0; i < spec->autocfg.hp_outs; i++) - snd_hda_set_pin_ctl(codec, spec->autocfg.hp_pins[i], 0); + for (i = 0; i < spec->gen.autocfg.hp_outs; i++) + snd_hda_set_pin_ctl(codec, spec->gen.autocfg.hp_pins[i], 0); } return 0; @@ -1709,7 +489,10 @@ static int via_suspend(struct hda_codec *codec) static int via_check_power_status(struct hda_codec *codec, hda_nid_t nid) { struct via_spec *spec = codec->spec; - return snd_hda_check_amp_list_power(codec, &spec->loopback, nid); + set_widgets_power_state(codec); + analog_low_current_mode(codec); + vt1708_update_hp_work(codec); + return snd_hda_check_amp_list_power(codec, &spec->gen.loopback, nid); } #endif @@ -1720,7 +503,7 @@ static int via_init(struct hda_codec *codec); static const struct hda_codec_ops via_patch_ops = { .build_controls = via_build_controls, - .build_pcms = via_build_pcms, + .build_pcms = snd_hda_gen_build_pcms, .init = via_init, .free = via_free, .unsol_event = snd_hda_jack_unsol_event, @@ -1730,840 +513,12 @@ static const struct hda_codec_ops via_patch_ops = { #endif }; -static bool is_empty_dac(struct hda_codec *codec, hda_nid_t dac) -{ - struct via_spec *spec = codec->spec; - int i; - - for (i = 0; i < spec->multiout.num_dacs; i++) { - if (spec->multiout.dac_nids[i] == dac) - return false; - } - if (spec->hp_dac_nid == dac) - return false; - return true; -} - -static bool __parse_output_path(struct hda_codec *codec, hda_nid_t nid, - hda_nid_t target_dac, int with_aa_mix, - struct nid_path *path, int depth) -{ - struct via_spec *spec = codec->spec; - hda_nid_t conn[8]; - int i, nums; - - if (nid == spec->aa_mix_nid) { - if (!with_aa_mix) - return false; - with_aa_mix = 2; /* mark aa-mix is included */ - } - - nums = snd_hda_get_connections(codec, nid, conn, ARRAY_SIZE(conn)); - for (i = 0; i < nums; i++) { - if (get_wcaps_type(get_wcaps(codec, conn[i])) != AC_WID_AUD_OUT) - continue; - if (conn[i] == target_dac || is_empty_dac(codec, conn[i])) { - /* aa-mix is requested but not included? */ - if (!(spec->aa_mix_nid && with_aa_mix == 1)) - goto found; - } - } - if (depth >= MAX_NID_PATH_DEPTH) - return false; - for (i = 0; i < nums; i++) { - unsigned int type; - type = get_wcaps_type(get_wcaps(codec, conn[i])); - if (type == AC_WID_AUD_OUT) - continue; - if (__parse_output_path(codec, conn[i], target_dac, - with_aa_mix, path, depth + 1)) - goto found; - } - return false; - - found: - path->path[path->depth] = conn[i]; - path->idx[path->depth] = i; - if (nums > 1 && get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_AUD_MIX) - path->multi[path->depth] = 1; - path->depth++; - return true; -} - -static bool parse_output_path(struct hda_codec *codec, hda_nid_t nid, - hda_nid_t target_dac, int with_aa_mix, - struct nid_path *path) -{ - if (__parse_output_path(codec, nid, target_dac, with_aa_mix, path, 1)) { - path->path[path->depth] = nid; - path->depth++; - snd_printdd("output-path: depth=%d, %02x/%02x/%02x/%02x/%02x\n", - path->depth, path->path[0], path->path[1], - path->path[2], path->path[3], path->path[4]); - return true; - } - return false; -} - -static int via_auto_fill_dac_nids(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - const struct auto_pin_cfg *cfg = &spec->autocfg; - int i; - hda_nid_t nid; - spec->multiout.num_dacs = 0; - spec->multiout.dac_nids = spec->private_dac_nids; - for (i = 0; i < cfg->line_outs; i++) { - hda_nid_t dac = 0; - nid = cfg->line_out_pins[i]; - if (!nid) - continue; - if (parse_output_path(codec, nid, 0, 0, &spec->out_path[i])) - dac = spec->out_path[i].path[0]; - if (!i && parse_output_path(codec, nid, dac, 1, - &spec->out_mix_path)) - dac = spec->out_mix_path.path[0]; - if (dac) - spec->private_dac_nids[spec->multiout.num_dacs++] = dac; - } - if (!spec->out_path[0].depth && spec->out_mix_path.depth) { - spec->out_path[0] = spec->out_mix_path; - spec->out_mix_path.depth = 0; - } - return 0; -} - -static int create_ch_ctls(struct hda_codec *codec, const char *pfx, - int chs, bool check_dac, struct nid_path *path) -{ - struct via_spec *spec = codec->spec; - char name[32]; - hda_nid_t dac, pin, sel, nid; - int err; - - dac = check_dac ? path->path[0] : 0; - pin = path->path[path->depth - 1]; - sel = path->depth > 1 ? path->path[1] : 0; - - if (dac && check_amp_caps(codec, dac, HDA_OUTPUT, AC_AMPCAP_NUM_STEPS)) - nid = dac; - else if (check_amp_caps(codec, pin, HDA_OUTPUT, AC_AMPCAP_NUM_STEPS)) - nid = pin; - else if (check_amp_caps(codec, sel, HDA_OUTPUT, AC_AMPCAP_NUM_STEPS)) - nid = sel; - else - nid = 0; - if (nid) { - sprintf(name, "%s Playback Volume", pfx); - err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, - HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT)); - if (err < 0) - return err; - path->vol_ctl = nid; - } - - if (dac && check_amp_caps(codec, dac, HDA_OUTPUT, AC_AMPCAP_MUTE)) - nid = dac; - else if (check_amp_caps(codec, pin, HDA_OUTPUT, AC_AMPCAP_MUTE)) - nid = pin; - else if (check_amp_caps(codec, sel, HDA_OUTPUT, AC_AMPCAP_MUTE)) - nid = sel; - else - nid = 0; - if (nid) { - sprintf(name, "%s Playback Switch", pfx); - err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, - HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT)); - if (err < 0) - return err; - path->mute_ctl = nid; - } - return 0; -} - -static void mangle_smart51(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - struct auto_pin_cfg_item *ins = cfg->inputs; - int i, j, nums, attr; - int pins[AUTO_CFG_MAX_INS]; - - for (attr = INPUT_PIN_ATTR_REAR; attr >= INPUT_PIN_ATTR_NORMAL; attr--) { - nums = 0; - for (i = 0; i < cfg->num_inputs; i++) { - unsigned int def; - if (ins[i].type > AUTO_PIN_LINE_IN) - continue; - def = snd_hda_codec_get_pincfg(codec, ins[i].pin); - if (snd_hda_get_input_pin_attr(def) != attr) - continue; - for (j = 0; j < nums; j++) - if (ins[pins[j]].type < ins[i].type) { - memmove(pins + j + 1, pins + j, - (nums - j) * sizeof(int)); - break; - } - pins[j] = i; - nums++; - } - if (cfg->line_outs + nums < 3) - continue; - for (i = 0; i < nums; i++) { - hda_nid_t pin = ins[pins[i]].pin; - spec->smart51_pins[spec->smart51_nums++] = pin; - cfg->line_out_pins[cfg->line_outs++] = pin; - if (cfg->line_outs == 3) - break; - } - return; - } -} - -static void copy_path_mixer_ctls(struct nid_path *dst, struct nid_path *src) -{ - dst->vol_ctl = src->vol_ctl; - dst->mute_ctl = src->mute_ctl; -} - -/* add playback controls from the parsed DAC table */ -static int via_auto_create_multi_out_ctls(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - struct nid_path *path; - static const char * const chname[4] = { - "Front", "Surround", "C/LFE", "Side" - }; - int i, idx, err; - int old_line_outs; - - /* check smart51 */ - old_line_outs = cfg->line_outs; - if (cfg->line_outs == 1) - mangle_smart51(codec); - - err = via_auto_fill_dac_nids(codec); - if (err < 0) - return err; - - if (spec->multiout.num_dacs < 3) { - spec->smart51_nums = 0; - cfg->line_outs = old_line_outs; - } - for (i = 0; i < cfg->line_outs; i++) { - hda_nid_t pin, dac; - pin = cfg->line_out_pins[i]; - dac = spec->multiout.dac_nids[i]; - if (!pin || !dac) - continue; - path = spec->out_path + i; - if (i == HDA_CLFE) { - err = create_ch_ctls(codec, "Center", 1, true, path); - if (err < 0) - return err; - err = create_ch_ctls(codec, "LFE", 2, true, path); - if (err < 0) - return err; - } else { - const char *pfx = chname[i]; - if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT && - cfg->line_outs == 1) - pfx = "Speaker"; - err = create_ch_ctls(codec, pfx, 3, true, path); - if (err < 0) - return err; - } - if (path != spec->out_path + i) - copy_path_mixer_ctls(&spec->out_path[i], path); - if (path == spec->out_path && spec->out_mix_path.depth) - copy_path_mixer_ctls(&spec->out_mix_path, path); - } - - idx = get_connection_index(codec, spec->aa_mix_nid, - spec->multiout.dac_nids[0]); - if (idx >= 0) { - /* add control to mixer */ - const char *name; - name = spec->out_mix_path.depth ? - "PCM Loopback Playback Volume" : "PCM Playback Volume"; - err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, - HDA_COMPOSE_AMP_VAL(spec->aa_mix_nid, 3, - idx, HDA_INPUT)); - if (err < 0) - return err; - name = spec->out_mix_path.depth ? - "PCM Loopback Playback Switch" : "PCM Playback Switch"; - err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, - HDA_COMPOSE_AMP_VAL(spec->aa_mix_nid, 3, - idx, HDA_INPUT)); - if (err < 0) - return err; - } - - cfg->line_outs = old_line_outs; - - return 0; -} - -static int via_auto_create_hp_ctls(struct hda_codec *codec, hda_nid_t pin) -{ - struct via_spec *spec = codec->spec; - struct nid_path *path; - bool check_dac; - int i, err; - - if (!pin) - return 0; - - if (!parse_output_path(codec, pin, 0, 0, &spec->hp_indep_path)) { - for (i = HDA_SIDE; i >= HDA_CLFE; i--) { - if (i < spec->multiout.num_dacs && - parse_output_path(codec, pin, - spec->multiout.dac_nids[i], 0, - &spec->hp_indep_path)) { - spec->hp_indep_shared = i; - break; - } - } - } - if (spec->hp_indep_path.depth) { - spec->hp_dac_nid = spec->hp_indep_path.path[0]; - if (!spec->hp_indep_shared) - spec->hp_path = spec->hp_indep_path; - } - /* optionally check front-path w/o AA-mix */ - if (!spec->hp_path.depth) - parse_output_path(codec, pin, - spec->multiout.dac_nids[HDA_FRONT], 0, - &spec->hp_path); - - if (!parse_output_path(codec, pin, spec->multiout.dac_nids[HDA_FRONT], - 1, &spec->hp_mix_path) && !spec->hp_path.depth) - return 0; - - if (spec->hp_path.depth) { - path = &spec->hp_path; - check_dac = true; - } else { - path = &spec->hp_mix_path; - check_dac = false; - } - err = create_ch_ctls(codec, "Headphone", 3, check_dac, path); - if (err < 0) - return err; - if (check_dac) - copy_path_mixer_ctls(&spec->hp_mix_path, path); - else - copy_path_mixer_ctls(&spec->hp_path, path); - if (spec->hp_indep_path.depth) - copy_path_mixer_ctls(&spec->hp_indep_path, path); - return 0; -} - -static int via_auto_create_speaker_ctls(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - struct nid_path *path; - bool check_dac; - hda_nid_t pin, dac = 0; - int err; - - pin = spec->autocfg.speaker_pins[0]; - if (!spec->autocfg.speaker_outs || !pin) - return 0; - - if (parse_output_path(codec, pin, 0, 0, &spec->speaker_path)) - dac = spec->speaker_path.path[0]; - if (!dac) - parse_output_path(codec, pin, - spec->multiout.dac_nids[HDA_FRONT], 0, - &spec->speaker_path); - if (!parse_output_path(codec, pin, spec->multiout.dac_nids[HDA_FRONT], - 1, &spec->speaker_mix_path) && !dac) - return 0; - - /* no AA-path for front? */ - if (!spec->out_mix_path.depth && spec->speaker_mix_path.depth) - dac = 0; - - spec->speaker_dac_nid = dac; - spec->multiout.extra_out_nid[0] = dac; - if (dac) { - path = &spec->speaker_path; - check_dac = true; - } else { - path = &spec->speaker_mix_path; - check_dac = false; - } - err = create_ch_ctls(codec, "Speaker", 3, check_dac, path); - if (err < 0) - return err; - if (check_dac) - copy_path_mixer_ctls(&spec->speaker_mix_path, path); - else - copy_path_mixer_ctls(&spec->speaker_path, path); - return 0; -} - -#define via_aamix_ctl_info via_pin_power_ctl_info - -static int via_aamix_ctl_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct via_spec *spec = codec->spec; - ucontrol->value.enumerated.item[0] = spec->aamix_mode; - return 0; -} - -static void update_aamix_paths(struct hda_codec *codec, int do_mix, - struct nid_path *nomix, struct nid_path *mix) -{ - if (do_mix) { - activate_output_path(codec, nomix, false, false); - activate_output_path(codec, mix, true, false); - } else { - activate_output_path(codec, mix, false, false); - activate_output_path(codec, nomix, true, false); - } -} - -static int via_aamix_ctl_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct via_spec *spec = codec->spec; - unsigned int val = ucontrol->value.enumerated.item[0]; - - if (val == spec->aamix_mode) - return 0; - spec->aamix_mode = val; - /* update front path */ - update_aamix_paths(codec, val, &spec->out_path[0], &spec->out_mix_path); - /* update HP path */ - if (!spec->hp_independent_mode) { - update_aamix_paths(codec, val, &spec->hp_path, - &spec->hp_mix_path); - } - /* update speaker path */ - update_aamix_paths(codec, val, &spec->speaker_path, - &spec->speaker_mix_path); - return 1; -} - -static const struct snd_kcontrol_new via_aamix_ctl_enum = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Loopback Mixing", - .info = via_aamix_ctl_info, - .get = via_aamix_ctl_get, - .put = via_aamix_ctl_put, -}; - -static int via_auto_create_loopback_switch(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - - if (!spec->aa_mix_nid) - return 0; /* no loopback switching available */ - if (!(spec->out_mix_path.depth || spec->hp_mix_path.depth || - spec->speaker_path.depth)) - return 0; /* no loopback switching available */ - if (!via_clone_control(spec, &via_aamix_ctl_enum)) - return -ENOMEM; - return 0; -} - -/* look for ADCs */ -static int via_fill_adcs(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - hda_nid_t nid = codec->start_nid; - int i; - - for (i = 0; i < codec->num_nodes; i++, nid++) { - unsigned int wcaps = get_wcaps(codec, nid); - if (get_wcaps_type(wcaps) != AC_WID_AUD_IN) - continue; - if (wcaps & AC_WCAP_DIGITAL) - continue; - if (!(wcaps & AC_WCAP_CONN_LIST)) - continue; - if (spec->num_adc_nids >= ARRAY_SIZE(spec->adc_nids)) - return -ENOMEM; - spec->adc_nids[spec->num_adc_nids++] = nid; - } - return 0; -} - -/* input-src control */ -static int via_mux_enum_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct via_spec *spec = codec->spec; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = spec->num_inputs; - if (uinfo->value.enumerated.item >= spec->num_inputs) - uinfo->value.enumerated.item = spec->num_inputs - 1; - strcpy(uinfo->value.enumerated.name, - spec->inputs[uinfo->value.enumerated.item].label); - return 0; -} - -static int via_mux_enum_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct via_spec *spec = codec->spec; - unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - - ucontrol->value.enumerated.item[0] = spec->cur_mux[idx]; - return 0; -} - -static int via_mux_enum_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct via_spec *spec = codec->spec; - unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - hda_nid_t mux; - int cur; - - cur = ucontrol->value.enumerated.item[0]; - if (cur < 0 || cur >= spec->num_inputs) - return -EINVAL; - if (spec->cur_mux[idx] == cur) - return 0; - spec->cur_mux[idx] = cur; - if (spec->dyn_adc_switch) { - int adc_idx = spec->inputs[cur].adc_idx; - mux = spec->mux_nids[adc_idx]; - via_dyn_adc_pcm_resetup(codec, cur); - } else { - mux = spec->mux_nids[idx]; - if (snd_BUG_ON(!mux)) - return -EINVAL; - } - - if (mux) { - /* switch to D0 beofre change index */ - update_power_state(codec, mux, AC_PWRST_D0); - snd_hda_codec_write(codec, mux, 0, - AC_VERB_SET_CONNECT_SEL, - spec->inputs[cur].mux_idx); - } - - /* update jack power state */ - set_widgets_power_state(codec); - return 0; -} - -static const struct snd_kcontrol_new via_input_src_ctl = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .info = via_mux_enum_info, - .get = via_mux_enum_get, - .put = via_mux_enum_put, +static const struct hda_verb vt1708_init_verbs[] = { + /* power down jack detect function */ + {0x1, 0xf81, 0x1}, + { } }; - -static int create_input_src_ctls(struct hda_codec *codec, int count) -{ - struct via_spec *spec = codec->spec; - struct snd_kcontrol_new *knew; - - if (spec->num_inputs <= 1 || !count) - return 0; /* no need for single src */ - - knew = via_clone_control(spec, &via_input_src_ctl); - if (!knew) - return -ENOMEM; - knew->count = count; - return 0; -} - -/* add the powersave loopback-list entry */ -static void add_loopback_list(struct via_spec *spec, hda_nid_t mix, int idx) -{ - struct hda_amp_list *list; - - if (spec->num_loopbacks >= ARRAY_SIZE(spec->loopback_list) - 1) - return; - list = spec->loopback_list + spec->num_loopbacks; - list->nid = mix; - list->dir = HDA_INPUT; - list->idx = idx; - spec->num_loopbacks++; - spec->loopback.amplist = spec->loopback_list; -} - -static bool is_reachable_nid(struct hda_codec *codec, hda_nid_t src, - hda_nid_t dst) -{ - return snd_hda_get_conn_index(codec, src, dst, 1) >= 0; -} - -/* add the input-route to the given pin */ -static bool add_input_route(struct hda_codec *codec, hda_nid_t pin) -{ - struct via_spec *spec = codec->spec; - int c, idx; - - spec->inputs[spec->num_inputs].adc_idx = -1; - spec->inputs[spec->num_inputs].pin = pin; - for (c = 0; c < spec->num_adc_nids; c++) { - if (spec->mux_nids[c]) { - idx = get_connection_index(codec, spec->mux_nids[c], - pin); - if (idx < 0) - continue; - spec->inputs[spec->num_inputs].mux_idx = idx; - } else { - if (!is_reachable_nid(codec, spec->adc_nids[c], pin)) - continue; - } - spec->inputs[spec->num_inputs].adc_idx = c; - /* Can primary ADC satisfy all inputs? */ - if (!spec->dyn_adc_switch && - spec->num_inputs > 0 && spec->inputs[0].adc_idx != c) { - snd_printd(KERN_INFO - "via: dynamic ADC switching enabled\n"); - spec->dyn_adc_switch = 1; - } - return true; - } - return false; -} - -static int get_mux_nids(struct hda_codec *codec); - -/* parse input-routes; fill ADCs, MUXs and input-src entries */ -static int parse_analog_inputs(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - const struct auto_pin_cfg *cfg = &spec->autocfg; - int i, err; - - err = via_fill_adcs(codec); - if (err < 0) - return err; - err = get_mux_nids(codec); - if (err < 0) - return err; - - /* fill all input-routes */ - for (i = 0; i < cfg->num_inputs; i++) { - if (add_input_route(codec, cfg->inputs[i].pin)) - spec->inputs[spec->num_inputs++].label = - hda_get_autocfg_input_label(codec, cfg, i); - } - - /* check for internal loopback recording */ - if (spec->aa_mix_nid && - add_input_route(codec, spec->aa_mix_nid)) - spec->inputs[spec->num_inputs++].label = "Stereo Mixer"; - - return 0; -} - -/* create analog-loopback volume/switch controls */ -static int create_loopback_ctls(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - const struct auto_pin_cfg *cfg = &spec->autocfg; - const char *prev_label = NULL; - int type_idx = 0; - int i, j, err, idx; - - if (!spec->aa_mix_nid) - return 0; - - for (i = 0; i < cfg->num_inputs; i++) { - hda_nid_t pin = cfg->inputs[i].pin; - const char *label = hda_get_autocfg_input_label(codec, cfg, i); - - if (prev_label && !strcmp(label, prev_label)) - type_idx++; - else - type_idx = 0; - prev_label = label; - idx = get_connection_index(codec, spec->aa_mix_nid, pin); - if (idx >= 0) { - err = via_new_analog_input(spec, label, type_idx, - idx, spec->aa_mix_nid); - if (err < 0) - return err; - add_loopback_list(spec, spec->aa_mix_nid, idx); - } - - /* remember the label for smart51 control */ - for (j = 0; j < spec->smart51_nums; j++) { - if (spec->smart51_pins[j] == pin) { - spec->smart51_idxs[j] = idx; - spec->smart51_labels[j] = label; - break; - } - } - } - return 0; -} - -/* create mic-boost controls (if present) */ -static int create_mic_boost_ctls(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - const struct auto_pin_cfg *cfg = &spec->autocfg; - const char *prev_label = NULL; - int type_idx = 0; - int i, err; - - for (i = 0; i < cfg->num_inputs; i++) { - hda_nid_t pin = cfg->inputs[i].pin; - unsigned int caps; - const char *label; - char name[32]; - - if (cfg->inputs[i].type != AUTO_PIN_MIC) - continue; - caps = query_amp_caps(codec, pin, HDA_INPUT); - if (caps == -1 || !(caps & AC_AMPCAP_NUM_STEPS)) - continue; - label = hda_get_autocfg_input_label(codec, cfg, i); - if (prev_label && !strcmp(label, prev_label)) - type_idx++; - else - type_idx = 0; - prev_label = label; - snprintf(name, sizeof(name), "%s Boost Volume", label); - err = __via_add_control(spec, VIA_CTL_WIDGET_VOL, name, type_idx, - HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_INPUT)); - if (err < 0) - return err; - } - return 0; -} - -/* create capture and input-src controls for multiple streams */ -static int create_multi_adc_ctls(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - int i, err; - - /* create capture mixer elements */ - for (i = 0; i < spec->num_adc_nids; i++) { - hda_nid_t adc = spec->adc_nids[i]; - err = __via_add_control(spec, VIA_CTL_WIDGET_VOL, - "Capture Volume", i, - HDA_COMPOSE_AMP_VAL(adc, 3, 0, - HDA_INPUT)); - if (err < 0) - return err; - err = __via_add_control(spec, VIA_CTL_WIDGET_MUTE, - "Capture Switch", i, - HDA_COMPOSE_AMP_VAL(adc, 3, 0, - HDA_INPUT)); - if (err < 0) - return err; - } - - /* input-source control */ - for (i = 0; i < spec->num_adc_nids; i++) - if (!spec->mux_nids[i]) - break; - err = create_input_src_ctls(codec, i); - if (err < 0) - return err; - return 0; -} - -/* bind capture volume/switch */ -static struct snd_kcontrol_new via_bind_cap_vol_ctl = - HDA_BIND_VOL("Capture Volume", 0); -static struct snd_kcontrol_new via_bind_cap_sw_ctl = - HDA_BIND_SW("Capture Switch", 0); - -static int init_bind_ctl(struct via_spec *spec, struct hda_bind_ctls **ctl_ret, - struct hda_ctl_ops *ops) -{ - struct hda_bind_ctls *ctl; - int i; - - ctl = kzalloc(sizeof(*ctl) + sizeof(long) * 4, GFP_KERNEL); - if (!ctl) - return -ENOMEM; - ctl->ops = ops; - for (i = 0; i < spec->num_adc_nids; i++) - ctl->values[i] = - HDA_COMPOSE_AMP_VAL(spec->adc_nids[i], 3, 0, HDA_INPUT); - *ctl_ret = ctl; - return 0; -} - -/* create capture and input-src controls for dynamic ADC-switch case */ -static int create_dyn_adc_ctls(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - struct snd_kcontrol_new *knew; - int err; - - /* set up the bind capture ctls */ - err = init_bind_ctl(spec, &spec->bind_cap_vol, &snd_hda_bind_vol); - if (err < 0) - return err; - err = init_bind_ctl(spec, &spec->bind_cap_sw, &snd_hda_bind_sw); - if (err < 0) - return err; - - /* create capture mixer elements */ - knew = via_clone_control(spec, &via_bind_cap_vol_ctl); - if (!knew) - return -ENOMEM; - knew->private_value = (long)spec->bind_cap_vol; - - knew = via_clone_control(spec, &via_bind_cap_sw_ctl); - if (!knew) - return -ENOMEM; - knew->private_value = (long)spec->bind_cap_sw; - - /* input-source control */ - err = create_input_src_ctls(codec, 1); - if (err < 0) - return err; - return 0; -} - -/* parse and create capture-related stuff */ -static int via_auto_create_analog_input_ctls(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - int err; - - err = parse_analog_inputs(codec); - if (err < 0) - return err; - if (spec->dyn_adc_switch) - err = create_dyn_adc_ctls(codec); - else - err = create_multi_adc_ctls(codec); - if (err < 0) - return err; - err = create_loopback_ctls(codec); - if (err < 0) - return err; - err = create_mic_boost_ctls(codec); - if (err < 0) - return err; - return 0; -} - static void vt1708_set_pinconfig_connect(struct hda_codec *codec, hda_nid_t nid) { unsigned int def_conf; @@ -2606,102 +561,32 @@ static int vt1708_jack_detect_put(struct snd_kcontrol *kcontrol, if (spec->vt1708_jack_detect == val) return 0; spec->vt1708_jack_detect = val; - if (spec->vt1708_jack_detect && - snd_hda_get_bool_hint(codec, "analog_loopback_hp_detect") != 1) { - mute_aa_path(codec, 1); - notify_aa_path_ctls(codec); - } - via_hp_automute(codec); - vt1708_update_hp_work(spec); + vt1708_update_hp_work(codec); return 1; } -static const struct snd_kcontrol_new vt1708_jack_detect_ctl = { +static const struct snd_kcontrol_new vt1708_jack_detect_ctl[] = { + { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Jack Detect", .count = 1, .info = snd_ctl_boolean_mono_info, .get = vt1708_jack_detect_get, .put = vt1708_jack_detect_put, + }, + {} /* terminator */ }; -static void fill_dig_outs(struct hda_codec *codec); -static void fill_dig_in(struct hda_codec *codec); - -static int via_parse_auto_config(struct hda_codec *codec) +static void via_hp_automute(struct hda_codec *codec, struct hda_jack_tbl *tbl) { - struct via_spec *spec = codec->spec; - int err; - - err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); - if (err < 0) - return err; - if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0]) - return -EINVAL; - - err = via_auto_create_multi_out_ctls(codec); - if (err < 0) - return err; - err = via_auto_create_hp_ctls(codec, spec->autocfg.hp_pins[0]); - if (err < 0) - return err; - err = via_auto_create_speaker_ctls(codec); - if (err < 0) - return err; - err = via_auto_create_loopback_switch(codec); - if (err < 0) - return err; - err = via_auto_create_analog_input_ctls(codec); - if (err < 0) - return err; - - spec->multiout.max_channels = spec->multiout.num_dacs * 2; - - fill_dig_outs(codec); - fill_dig_in(codec); - - if (spec->kctls.list) - spec->mixers[spec->num_mixers++] = spec->kctls.list; - - - if (spec->hp_dac_nid && spec->hp_mix_path.depth) { - err = via_hp_build(codec); - if (err < 0) - return err; - } - - err = via_smart51_build(codec); - if (err < 0) - return err; - - /* assign slave outs */ - if (spec->slave_dig_outs[0]) - codec->slave_dig_outs = spec->slave_dig_outs; - - return 1; -} - -static void via_auto_init_dig_outs(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - if (spec->multiout.dig_out_nid) - init_output_pin(codec, spec->autocfg.dig_out_pins[0], PIN_OUT); - if (spec->slave_dig_outs[0]) - init_output_pin(codec, spec->autocfg.dig_out_pins[1], PIN_OUT); -} - -static void via_auto_init_dig_in(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - if (!spec->dig_in_nid) - return; - snd_hda_set_pin_ctl(codec, spec->autocfg.dig_in_pin, PIN_IN); + set_widgets_power_state(codec); + snd_hda_gen_hp_automute(codec, tbl); } -static void via_jack_output_event(struct hda_codec *codec, struct hda_jack_tbl *tbl) +static void via_line_automute(struct hda_codec *codec, struct hda_jack_tbl *tbl) { set_widgets_power_state(codec); - via_hp_automute(codec); + snd_hda_gen_line_automute(codec, tbl); } static void via_jack_powerstate_event(struct hda_codec *codec, struct hda_jack_tbl *tbl) @@ -2709,41 +594,55 @@ static void via_jack_powerstate_event(struct hda_codec *codec, struct hda_jack_t set_widgets_power_state(codec); } -/* initialize the unsolicited events */ -static void via_auto_init_unsol_event(struct hda_codec *codec) +#define VIA_JACK_EVENT (HDA_GEN_LAST_EVENT + 1) + +static void via_set_jack_unsol_events(struct hda_codec *codec) { struct via_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - unsigned int ev; + struct auto_pin_cfg *cfg = &spec->gen.autocfg; + hda_nid_t pin; int i; - hda_jack_callback cb; - - if (cfg->hp_pins[0] && is_jack_detectable(codec, cfg->hp_pins[0])) - snd_hda_jack_detect_enable_callback(codec, cfg->hp_pins[0], - VIA_HP_EVENT | VIA_JACK_EVENT, - via_jack_output_event); + spec->gen.hp_automute_hook = via_hp_automute; if (cfg->speaker_pins[0]) - ev = VIA_LINE_EVENT; - else - ev = 0; - cb = ev ? via_jack_output_event : via_jack_powerstate_event; + spec->gen.line_automute_hook = via_line_automute; for (i = 0; i < cfg->line_outs; i++) { - if (cfg->line_out_pins[i] && - is_jack_detectable(codec, cfg->line_out_pins[i])) - snd_hda_jack_detect_enable_callback(codec, cfg->line_out_pins[i], - ev | VIA_JACK_EVENT, cb); + pin = cfg->line_out_pins[i]; + if (pin && !snd_hda_jack_tbl_get(codec, pin) && + is_jack_detectable(codec, pin)) + snd_hda_jack_detect_enable_callback(codec, pin, + VIA_JACK_EVENT, + via_jack_powerstate_event); } for (i = 0; i < cfg->num_inputs; i++) { - if (is_jack_detectable(codec, cfg->inputs[i].pin)) - snd_hda_jack_detect_enable_callback(codec, cfg->inputs[i].pin, + pin = cfg->line_out_pins[i]; + if (pin && !snd_hda_jack_tbl_get(codec, pin) && + is_jack_detectable(codec, pin)) + snd_hda_jack_detect_enable_callback(codec, pin, VIA_JACK_EVENT, via_jack_powerstate_event); } } +static int via_parse_auto_config(struct hda_codec *codec) +{ + struct via_spec *spec = codec->spec; + int err; + + err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, NULL, 0); + if (err < 0) + return err; + + err = snd_hda_gen_parse_auto_config(codec, &spec->gen.autocfg); + if (err < 0) + return err; + + via_set_jack_unsol_events(codec); + return 0; +} + static int via_init(struct hda_codec *codec) { struct via_spec *spec = codec->spec; @@ -2756,63 +655,47 @@ static int via_init(struct hda_codec *codec) set_widgets_power_state(codec); __analog_low_current_mode(codec, true); - via_auto_init_multi_out(codec); - via_auto_init_hp_out(codec); - via_auto_init_speaker_out(codec); - via_auto_init_analog_input(codec); - via_auto_init_dig_outs(codec); - via_auto_init_dig_in(codec); - - via_auto_init_unsol_event(codec); + snd_hda_gen_init(codec); - via_hp_automute(codec); - vt1708_update_hp_work(spec); + vt1708_update_hp_work(codec); return 0; } -static void vt1708_update_hp_jack_state(struct work_struct *work) +static int vt1708_build_controls(struct hda_codec *codec) { - struct via_spec *spec = container_of(work, struct via_spec, - vt1708_hp_work.work); - if (spec->codec_type != VT1708) - return; - snd_hda_jack_set_dirty_all(spec->codec); - /* if jack state toggled */ - if (spec->vt1708_hp_present - != snd_hda_jack_detect(spec->codec, spec->autocfg.hp_pins[0])) { - spec->vt1708_hp_present ^= 1; - via_hp_automute(spec->codec); - } - if (spec->vt1708_jack_detect) - schedule_delayed_work(&spec->vt1708_hp_work, - msecs_to_jiffies(100)); + /* In order not to create "Phantom Jack" controls, + temporary enable jackpoll */ + int err; + int old_interval = codec->jackpoll_interval; + codec->jackpoll_interval = msecs_to_jiffies(100); + err = via_build_controls(codec); + codec->jackpoll_interval = old_interval; + return err; } -static int get_mux_nids(struct hda_codec *codec) +static int vt1708_build_pcms(struct hda_codec *codec) { struct via_spec *spec = codec->spec; - hda_nid_t nid, conn[8]; - unsigned int type; - int i, n; - - for (i = 0; i < spec->num_adc_nids; i++) { - nid = spec->adc_nids[i]; - while (nid) { - type = get_wcaps_type(get_wcaps(codec, nid)); - if (type == AC_WID_PIN) - break; - n = snd_hda_get_connections(codec, nid, conn, - ARRAY_SIZE(conn)); - if (n <= 0) - break; - if (n > 1) { - spec->mux_nids[i] = nid; - break; - } - nid = conn[0]; - } + int i, err; + + err = snd_hda_gen_build_pcms(codec); + if (err < 0 || codec->vendor_id != 0x11061708) + return err; + + /* We got noisy outputs on the right channel on VT1708 when + * 24bit samples are used. Until any workaround is found, + * disable the 24bit format, so far. + */ + for (i = 0; i < codec->num_pcms; i++) { + struct hda_pcm *info = &spec->gen.pcm_rec[i]; + if (!info->stream[SNDRV_PCM_STREAM_PLAYBACK].substreams || + info->pcm_type != HDA_PCM_TYPE_AUDIO) + continue; + info->stream[SNDRV_PCM_STREAM_PLAYBACK].formats = + SNDRV_PCM_FMTBIT_S16_LE; } + return 0; } @@ -2826,7 +709,15 @@ static int patch_vt1708(struct hda_codec *codec) if (spec == NULL) return -ENOMEM; - spec->aa_mix_nid = 0x17; + spec->gen.mixer_nid = 0x17; + + /* set jackpoll_interval while parsing the codec */ + codec->jackpoll_interval = msecs_to_jiffies(100); + spec->vt1708_jack_detect = 1; + + /* don't support the input jack switching due to lack of unsol event */ + /* (it may work with polling, though, but it needs testing) */ + spec->gen.suppress_auto_mic = 1; /* Add HP and CD pin config connect bit re-config action */ vt1708_set_pinconfig_connect(codec, VT1708_HP_PIN_NID); @@ -2840,18 +731,17 @@ static int patch_vt1708(struct hda_codec *codec) } /* add jack detect on/off control */ - if (!via_clone_control(spec, &vt1708_jack_detect_ctl)) - return -ENOMEM; - - /* disable 32bit format on VT1708 */ - if (codec->vendor_id == 0x11061708) - spec->stream_analog_playback = &vt1708_pcm_analog_s16_playback; + spec->mixers[spec->num_mixers++] = vt1708_jack_detect_ctl; spec->init_verbs[spec->num_iverbs++] = vt1708_init_verbs; codec->patch_ops = via_patch_ops; + codec->patch_ops.build_controls = vt1708_build_controls; + codec->patch_ops.build_pcms = vt1708_build_pcms; + + /* clear jackpoll_interval again; it's set dynamically */ + codec->jackpoll_interval = 0; - INIT_DELAYED_WORK(&spec->vt1708_hp_work, vt1708_update_hp_jack_state); return 0; } @@ -2865,7 +755,7 @@ static int patch_vt1709(struct hda_codec *codec) if (spec == NULL) return -ENOMEM; - spec->aa_mix_nid = 0x18; + spec->gen.mixer_nid = 0x18; err = via_parse_auto_config(codec); if (err < 0) { @@ -2909,7 +799,7 @@ static void set_widgets_power_state_vt1708B(struct hda_codec *codec) /* PW0 (19h), SW1 (18h), AOW1 (11h) */ parm = AC_PWRST_D3; set_pin_power_state(codec, 0x19, &parm); - if (spec->smart51_enabled) + if (smart51_enabled(codec)) set_pin_power_state(codec, 0x1b, &parm); update_power_state(codec, 0x18, parm); update_power_state(codec, 0x11, parm); @@ -2918,7 +808,7 @@ static void set_widgets_power_state_vt1708B(struct hda_codec *codec) if (is_8ch) { parm = AC_PWRST_D3; set_pin_power_state(codec, 0x22, &parm); - if (spec->smart51_enabled) + if (smart51_enabled(codec)) set_pin_power_state(codec, 0x1a, &parm); update_power_state(codec, 0x26, parm); update_power_state(codec, 0x24, parm); @@ -2926,7 +816,7 @@ static void set_widgets_power_state_vt1708B(struct hda_codec *codec) /* PW7(23h), SW2(27h), AOW2(25h) */ parm = AC_PWRST_D3; set_pin_power_state(codec, 0x23, &parm); - if (spec->smart51_enabled) + if (smart51_enabled(codec)) set_pin_power_state(codec, 0x1a, &parm); update_power_state(codec, 0x27, parm); update_power_state(codec, 0x25, parm); @@ -2946,7 +836,7 @@ static void set_widgets_power_state_vt1708B(struct hda_codec *codec) if (is_8ch) { update_power_state(codec, 0x25, parm); update_power_state(codec, 0x27, parm); - } else if (codec->vendor_id == 0x11064397 && spec->hp_independent_mode) + } else if (codec->vendor_id == 0x11064397 && spec->gen.indep_hp_enabled) update_power_state(codec, 0x25, parm); } @@ -2964,7 +854,7 @@ static int patch_vt1708B(struct hda_codec *codec) if (spec == NULL) return -ENOMEM; - spec->aa_mix_nid = 0x16; + spec->gen.mixer_nid = 0x16; /* automatic parse from the BIOS config */ err = via_parse_auto_config(codec); @@ -2989,58 +879,6 @@ static const struct hda_verb vt1708S_init_verbs[] = { { } }; -/* fill out digital output widgets; one for master and one for slave outputs */ -static void fill_dig_outs(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - int i; - - for (i = 0; i < spec->autocfg.dig_outs; i++) { - hda_nid_t nid; - int conn; - - nid = spec->autocfg.dig_out_pins[i]; - if (!nid) - continue; - conn = snd_hda_get_connections(codec, nid, &nid, 1); - if (conn < 1) - continue; - if (!spec->multiout.dig_out_nid) - spec->multiout.dig_out_nid = nid; - else { - spec->slave_dig_outs[0] = nid; - break; /* at most two dig outs */ - } - } -} - -static void fill_dig_in(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - hda_nid_t dig_nid; - int i, err; - - if (!spec->autocfg.dig_in_pin) - return; - - dig_nid = codec->start_nid; - for (i = 0; i < codec->num_nodes; i++, dig_nid++) { - unsigned int wcaps = get_wcaps(codec, dig_nid); - if (get_wcaps_type(wcaps) != AC_WID_AUD_IN) - continue; - if (!(wcaps & AC_WCAP_DIGITAL)) - continue; - if (!(wcaps & AC_WCAP_CONN_LIST)) - continue; - err = get_connection_index(codec, dig_nid, - spec->autocfg.dig_in_pin); - if (err >= 0) { - spec->dig_in_nid = dig_nid; - break; - } - } -} - static void override_mic_boost(struct hda_codec *codec, hda_nid_t pin, int offset, int num_steps, int step_size) { @@ -3061,21 +899,10 @@ static int patch_vt1708S(struct hda_codec *codec) if (spec == NULL) return -ENOMEM; - spec->aa_mix_nid = 0x16; + spec->gen.mixer_nid = 0x16; override_mic_boost(codec, 0x1a, 0, 3, 40); override_mic_boost(codec, 0x1e, 0, 3, 40); - /* automatic parse from the BIOS config */ - err = via_parse_auto_config(codec); - if (err < 0) { - via_free(codec); - return err; - } - - spec->init_verbs[spec->num_iverbs++] = vt1708S_init_verbs; - - codec->patch_ops = via_patch_ops; - /* correct names for VT1708BCE */ if (get_codec_type(codec) == VT1708BCE) { kfree(codec->chip_name); @@ -3092,6 +919,18 @@ static int patch_vt1708S(struct hda_codec *codec) sizeof(codec->bus->card->mixername), "%s %s", codec->vendor_name, codec->chip_name); } + + /* automatic parse from the BIOS config */ + err = via_parse_auto_config(codec); + if (err < 0) { + via_free(codec); + return err; + } + + spec->init_verbs[spec->num_iverbs++] = vt1708S_init_verbs; + + codec->patch_ops = via_patch_ops; + spec->set_widgets_power_state = set_widgets_power_state_vt1708B; return 0; } @@ -3146,7 +985,7 @@ static int patch_vt1702(struct hda_codec *codec) if (spec == NULL) return -ENOMEM; - spec->aa_mix_nid = 0x1a; + spec->gen.mixer_nid = 0x1a; /* limit AA path volume to 0 dB */ snd_hda_override_amp_caps(codec, 0x1A, HDA_INPUT, @@ -3213,17 +1052,17 @@ static void set_widgets_power_state_vt1718S(struct hda_codec *codec) /* PW2 (26h), AOW2 (ah) */ parm = AC_PWRST_D3; set_pin_power_state(codec, 0x26, &parm); - if (spec->smart51_enabled) + if (smart51_enabled(codec)) set_pin_power_state(codec, 0x2b, &parm); update_power_state(codec, 0xa, parm); /* PW0 (24h), AOW0 (8h) */ parm = AC_PWRST_D3; set_pin_power_state(codec, 0x24, &parm); - if (!spec->hp_independent_mode) /* check for redirected HP */ + if (!spec->gen.indep_hp_enabled) /* check for redirected HP */ set_pin_power_state(codec, 0x28, &parm); update_power_state(codec, 0x8, parm); - if (!spec->hp_independent_mode && parm2 != AC_PWRST_D3) + if (!spec->gen.indep_hp_enabled && parm2 != AC_PWRST_D3) parm = parm2; update_power_state(codec, 0xb, parm); /* MW9 (21h), Mw2 (1ah), AOW0 (8h) */ @@ -3232,11 +1071,11 @@ static void set_widgets_power_state_vt1718S(struct hda_codec *codec) /* PW1 (25h), AOW1 (9h) */ parm = AC_PWRST_D3; set_pin_power_state(codec, 0x25, &parm); - if (spec->smart51_enabled) + if (smart51_enabled(codec)) set_pin_power_state(codec, 0x2a, &parm); update_power_state(codec, 0x9, parm); - if (spec->hp_independent_mode) { + if (spec->gen.indep_hp_enabled) { /* PW4 (28h), MW3 (1bh), MUX1(34h), AOW4 (ch) */ parm = AC_PWRST_D3; set_pin_power_state(codec, 0x28, &parm); @@ -3256,9 +1095,9 @@ static int add_secret_dac_path(struct hda_codec *codec) hda_nid_t conn[8]; hda_nid_t nid; - if (!spec->aa_mix_nid) + if (!spec->gen.mixer_nid) return 0; - nums = snd_hda_get_connections(codec, spec->aa_mix_nid, conn, + nums = snd_hda_get_connections(codec, spec->gen.mixer_nid, conn, ARRAY_SIZE(conn) - 1); for (i = 0; i < nums; i++) { if (get_wcaps_type(get_wcaps(codec, conn[i])) == AC_WID_AUD_OUT) @@ -3273,7 +1112,7 @@ static int add_secret_dac_path(struct hda_codec *codec) !(caps & AC_WCAP_DIGITAL)) { conn[nums++] = nid; return snd_hda_override_conn_list(codec, - spec->aa_mix_nid, + spec->gen.mixer_nid, nums, conn); } } @@ -3291,7 +1130,7 @@ static int patch_vt1718S(struct hda_codec *codec) if (spec == NULL) return -ENOMEM; - spec->aa_mix_nid = 0x21; + spec->gen.mixer_nid = 0x21; override_mic_boost(codec, 0x2b, 0, 3, 40); override_mic_boost(codec, 0x29, 0, 3, 40); add_secret_dac_path(codec); @@ -3422,7 +1261,7 @@ static void set_widgets_power_state_vt1716S(struct hda_codec *codec) parm = AC_PWRST_D3; set_pin_power_state(codec, 0x19, &parm); /* Smart 5.1 PW2(1bh) */ - if (spec->smart51_enabled) + if (smart51_enabled(codec)) set_pin_power_state(codec, 0x1b, &parm); update_power_state(codec, 0x18, parm); update_power_state(codec, 0x11, parm); @@ -3431,12 +1270,12 @@ static void set_widgets_power_state_vt1716S(struct hda_codec *codec) parm = AC_PWRST_D3; set_pin_power_state(codec, 0x23, &parm); /* Smart 5.1 PW1(1ah) */ - if (spec->smart51_enabled) + if (smart51_enabled(codec)) set_pin_power_state(codec, 0x1a, &parm); update_power_state(codec, 0x27, parm); /* Smart 5.1 PW5(1eh) */ - if (spec->smart51_enabled) + if (smart51_enabled(codec)) set_pin_power_state(codec, 0x1e, &parm); update_power_state(codec, 0x25, parm); @@ -3448,7 +1287,7 @@ static void set_widgets_power_state_vt1716S(struct hda_codec *codec) mono_out = 0; else { present = snd_hda_jack_detect(codec, 0x1d); - if (!spec->hp_independent_mode && present) + if (!spec->gen.indep_hp_enabled && present) mono_out = 0; else mono_out = 1; @@ -3463,7 +1302,7 @@ static void set_widgets_power_state_vt1716S(struct hda_codec *codec) set_pin_power_state(codec, 0x1c, &parm); set_pin_power_state(codec, 0x1d, &parm); /* HP Independent Mode, power on AOW3 */ - if (spec->hp_independent_mode) + if (spec->gen.indep_hp_enabled) update_power_state(codec, 0x25, parm); /* force to D0 for internal Speaker */ @@ -3482,7 +1321,7 @@ static int patch_vt1716S(struct hda_codec *codec) if (spec == NULL) return -ENOMEM; - spec->aa_mix_nid = 0x16; + spec->gen.mixer_nid = 0x16; override_mic_boost(codec, 0x1a, 0, 3, 40); override_mic_boost(codec, 0x1e, 0, 3, 40); @@ -3495,9 +1334,7 @@ static int patch_vt1716S(struct hda_codec *codec) spec->init_verbs[spec->num_iverbs++] = vt1716S_init_verbs; - spec->mixers[spec->num_mixers] = vt1716s_dmic_mixer; - spec->num_mixers++; - + spec->mixers[spec->num_mixers++] = vt1716s_dmic_mixer; spec->mixers[spec->num_mixers++] = vt1716S_mono_out_mixer; codec->patch_ops = via_patch_ops; @@ -3582,7 +1419,7 @@ static void set_widgets_power_state_vt2002P(struct hda_codec *codec) update_power_state(codec, 0x35, parm); } - if (spec->hp_independent_mode) + if (spec->gen.indep_hp_enabled) update_power_state(codec, 0x9, AC_PWRST_D0); /* Class-D */ @@ -3680,7 +1517,7 @@ static int patch_vt2002P(struct hda_codec *codec) if (spec == NULL) return -ENOMEM; - spec->aa_mix_nid = 0x21; + spec->gen.mixer_nid = 0x21; override_mic_boost(codec, 0x2b, 0, 3, 40); override_mic_boost(codec, 0x29, 0, 3, 40); if (spec->codec_type == VT1802) @@ -3751,7 +1588,7 @@ static void set_widgets_power_state_vt1812(struct hda_codec *codec) set_pin_power_state(codec, 0x25, &parm); update_power_state(codec, 0x15, parm); update_power_state(codec, 0x35, parm); - if (spec->hp_independent_mode) + if (spec->gen.indep_hp_enabled) update_power_state(codec, 0x9, AC_PWRST_D0); /* Internal Speaker */ @@ -3804,7 +1641,7 @@ static int patch_vt1812(struct hda_codec *codec) if (spec == NULL) return -ENOMEM; - spec->aa_mix_nid = 0x21; + spec->gen.mixer_nid = 0x21; override_mic_boost(codec, 0x2b, 0, 3, 40); override_mic_boost(codec, 0x29, 0, 3, 40); add_secret_dac_path(codec); @@ -3824,6 +1661,125 @@ static int patch_vt1812(struct hda_codec *codec) return 0; } +/* patch for vt3476 */ + +static const struct hda_verb vt3476_init_verbs[] = { + /* Enable DMic 8/16/32K */ + {0x1, 0xF7B, 0x30}, + /* Enable Boost Volume backdoor */ + {0x1, 0xFB9, 0x20}, + /* Enable AOW-MW9 path */ + {0x1, 0xFB8, 0x10}, + { } +}; + +static void set_widgets_power_state_vt3476(struct hda_codec *codec) +{ + struct via_spec *spec = codec->spec; + int imux_is_smixer; + unsigned int parm, parm2; + /* MUX10 (1eh) = stereo mixer */ + imux_is_smixer = + snd_hda_codec_read(codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 4; + /* inputs */ + /* PW 5/6/7 (29h/2ah/2bh) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x29, &parm); + set_pin_power_state(codec, 0x2a, &parm); + set_pin_power_state(codec, 0x2b, &parm); + if (imux_is_smixer) + parm = AC_PWRST_D0; + /* MUX10/11 (1eh/1fh), AIW 0/1 (10h/11h) */ + update_power_state(codec, 0x1e, parm); + update_power_state(codec, 0x1f, parm); + update_power_state(codec, 0x10, parm); + update_power_state(codec, 0x11, parm); + + /* outputs */ + /* PW3 (27h), MW3(37h), AOW3 (bh) */ + if (spec->codec_type == VT1705CF) { + parm = AC_PWRST_D3; + update_power_state(codec, 0x27, parm); + update_power_state(codec, 0x37, parm); + } else { + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x27, &parm); + update_power_state(codec, 0x37, parm); + } + + /* PW2 (26h), MW2(36h), AOW2 (ah) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x26, &parm); + update_power_state(codec, 0x36, parm); + if (smart51_enabled(codec)) { + /* PW7(2bh), MW7(3bh), MUX7(1Bh) */ + set_pin_power_state(codec, 0x2b, &parm); + update_power_state(codec, 0x3b, parm); + update_power_state(codec, 0x1b, parm); + } + update_conv_power_state(codec, 0xa, parm, 2); + + /* PW1 (25h), MW1(35h), AOW1 (9h) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x25, &parm); + update_power_state(codec, 0x35, parm); + if (smart51_enabled(codec)) { + /* PW6(2ah), MW6(3ah), MUX6(1ah) */ + set_pin_power_state(codec, 0x2a, &parm); + update_power_state(codec, 0x3a, parm); + update_power_state(codec, 0x1a, parm); + } + update_conv_power_state(codec, 0x9, parm, 1); + + /* PW4 (28h), MW4 (38h), MUX4(18h), AOW3(bh)/AOW0(8h) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x28, &parm); + update_power_state(codec, 0x38, parm); + update_power_state(codec, 0x18, parm); + if (spec->gen.indep_hp_enabled) + update_conv_power_state(codec, 0xb, parm, 3); + parm2 = parm; /* for pin 0x0b */ + + /* PW0 (24h), MW0(34h), MW9(3fh), AOW0 (8h) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x24, &parm); + update_power_state(codec, 0x34, parm); + if (!spec->gen.indep_hp_enabled && parm2 != AC_PWRST_D3) + parm = parm2; + update_conv_power_state(codec, 0x8, parm, 0); + /* MW9 (21h), Mw2 (1ah), AOW0 (8h) */ + update_power_state(codec, 0x3f, imux_is_smixer ? AC_PWRST_D0 : parm); +} + +static int patch_vt3476(struct hda_codec *codec) +{ + struct via_spec *spec; + int err; + + /* create a codec specific record */ + spec = via_new_spec(codec); + if (spec == NULL) + return -ENOMEM; + + spec->gen.mixer_nid = 0x3f; + add_secret_dac_path(codec); + + /* automatic parse from the BIOS config */ + err = via_parse_auto_config(codec); + if (err < 0) { + via_free(codec); + return err; + } + + spec->init_verbs[spec->num_iverbs++] = vt3476_init_verbs; + + codec->patch_ops = via_patch_ops; + + spec->set_widgets_power_state = set_widgets_power_state_vt3476; + + return 0; +} + /* * patch entries */ @@ -3917,6 +1873,12 @@ static const struct hda_codec_preset snd_hda_preset_via[] = { .patch = patch_vt2002P}, { .id = 0x11068446, .name = "VT1802", .patch = patch_vt2002P}, + { .id = 0x11064760, .name = "VT1705CF", + .patch = patch_vt3476}, + { .id = 0x11064761, .name = "VT1708SCE", + .patch = patch_vt3476}, + { .id = 0x11064762, .name = "VT1808", + .patch = patch_vt3476}, {} /* terminator */ }; diff --git a/sound/pci/ice1712/Makefile b/sound/pci/ice1712/Makefile index f7ce33f00ea5..7e50c1324556 100644 --- a/sound/pci/ice1712/Makefile +++ b/sound/pci/ice1712/Makefile @@ -5,7 +5,7 @@ snd-ice17xx-ak4xxx-objs := ak4xxx.o snd-ice1712-objs := ice1712.o delta.o hoontech.o ews.o -snd-ice1724-objs := ice1724.o amp.o revo.o aureon.o vt1720_mobo.o pontis.o prodigy192.o prodigy_hifi.o juli.o phase.o wtm.o se.o maya44.o quartet.o +snd-ice1724-objs := ice1724.o amp.o revo.o aureon.o vt1720_mobo.o pontis.o prodigy192.o prodigy_hifi.o juli.o phase.o wtm.o se.o maya44.o quartet.o psc724.o wm8766.o wm8776.o # Toplevel Module Dependency obj-$(CONFIG_SND_ICE1712) += snd-ice1712.o snd-ice17xx-ak4xxx.o diff --git a/sound/pci/ice1712/amp.c b/sound/pci/ice1712/amp.c index e525da2673be..2f9b93467867 100644 --- a/sound/pci/ice1712/amp.c +++ b/sound/pci/ice1712/amp.c @@ -21,7 +21,6 @@ * */ -#include <asm/io.h> #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/init.h> @@ -38,7 +37,7 @@ static void wm_put(struct snd_ice1712 *ice, int reg, unsigned short val) snd_vt1724_write_i2c(ice, WM_DEV, cval >> 8, cval & 0xff); } -static int __devinit snd_vt1724_amp_init(struct snd_ice1712 *ice) +static int snd_vt1724_amp_init(struct snd_ice1712 *ice) { static const unsigned short wm_inits[] = { WM_ATTEN_L, 0x0000, /* 0 db */ @@ -66,7 +65,7 @@ static int __devinit snd_vt1724_amp_init(struct snd_ice1712 *ice) return 0; } -static int __devinit snd_vt1724_amp_add_controls(struct snd_ice1712 *ice) +static int snd_vt1724_amp_add_controls(struct snd_ice1712 *ice) { if (ice->ac97) /* we use pins 39 and 41 of the VT1616 for left and right @@ -78,7 +77,7 @@ static int __devinit snd_vt1724_amp_add_controls(struct snd_ice1712 *ice) /* entry point */ -struct snd_ice1712_card_info snd_vt1724_amp_cards[] __devinitdata = { +struct snd_ice1712_card_info snd_vt1724_amp_cards[] = { { .subvendor = VT1724_SUBDEVICE_AV710, .name = "Chaintech AV-710", diff --git a/sound/pci/ice1712/aureon.c b/sound/pci/ice1712/aureon.c index 20bcddea2eab..55902ec40344 100644 --- a/sound/pci/ice1712/aureon.c +++ b/sound/pci/ice1712/aureon.c @@ -46,7 +46,6 @@ * on mixer switch and other coll stuff. */ -#include <linux/io.h> #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/init.h> @@ -203,7 +202,8 @@ static void aureon_pca9554_write(struct snd_ice1712 *ice, unsigned char reg, static int aureon_universe_inmux_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - char *texts[3] = {"Internal Aux", "Wavetable", "Rear Line-In"}; + static const char * const texts[3] = + {"Internal Aux", "Wavetable", "Rear Line-In"}; uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; @@ -1433,7 +1433,7 @@ static int aureon_oversampling_put(struct snd_kcontrol *kcontrol, struct snd_ctl * mixers */ -static struct snd_kcontrol_new aureon_dac_controls[] __devinitdata = { +static struct snd_kcontrol_new aureon_dac_controls[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", @@ -1548,7 +1548,7 @@ static struct snd_kcontrol_new aureon_dac_controls[] __devinitdata = { } }; -static struct snd_kcontrol_new wm_controls[] __devinitdata = { +static struct snd_kcontrol_new wm_controls[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "PCM Playback Switch", @@ -1614,7 +1614,7 @@ static struct snd_kcontrol_new wm_controls[] __devinitdata = { } }; -static struct snd_kcontrol_new ac97_controls[] __devinitdata = { +static struct snd_kcontrol_new ac97_controls[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "AC97 Playback Switch", @@ -1719,7 +1719,7 @@ static struct snd_kcontrol_new ac97_controls[] __devinitdata = { } }; -static struct snd_kcontrol_new universe_ac97_controls[] __devinitdata = { +static struct snd_kcontrol_new universe_ac97_controls[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "AC97 Playback Switch", @@ -1851,7 +1851,7 @@ static struct snd_kcontrol_new universe_ac97_controls[] __devinitdata = { }; -static struct snd_kcontrol_new cs8415_controls[] __devinitdata = { +static struct snd_kcontrol_new cs8415_controls[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, SWITCH), @@ -1896,7 +1896,7 @@ static struct snd_kcontrol_new cs8415_controls[] __devinitdata = { } }; -static int __devinit aureon_add_controls(struct snd_ice1712 *ice) +static int aureon_add_controls(struct snd_ice1712 *ice) { unsigned int i, counts; int err; @@ -2124,7 +2124,7 @@ static int aureon_resume(struct snd_ice1712 *ice) /* * initialize the chip */ -static int __devinit aureon_init(struct snd_ice1712 *ice) +static int aureon_init(struct snd_ice1712 *ice) { struct aureon_spec *spec; int i, err; @@ -2174,7 +2174,7 @@ static int __devinit aureon_init(struct snd_ice1712 *ice) * hence the driver needs to sets up it properly. */ -static unsigned char aureon51_eeprom[] __devinitdata = { +static unsigned char aureon51_eeprom[] = { [ICE_EEP2_SYSCONF] = 0x0a, /* clock 512, spdif-in/ADC, 3DACs */ [ICE_EEP2_ACLINK] = 0x80, /* I2S */ [ICE_EEP2_I2S] = 0xfc, /* vol, 96k, 24bit, 192k */ @@ -2190,7 +2190,7 @@ static unsigned char aureon51_eeprom[] __devinitdata = { [ICE_EEP2_GPIO_STATE2] = 0x00, }; -static unsigned char aureon71_eeprom[] __devinitdata = { +static unsigned char aureon71_eeprom[] = { [ICE_EEP2_SYSCONF] = 0x0b, /* clock 512, spdif-in/ADC, 4DACs */ [ICE_EEP2_ACLINK] = 0x80, /* I2S */ [ICE_EEP2_I2S] = 0xfc, /* vol, 96k, 24bit, 192k */ @@ -2207,7 +2207,7 @@ static unsigned char aureon71_eeprom[] __devinitdata = { }; #define prodigy71_eeprom aureon71_eeprom -static unsigned char aureon71_universe_eeprom[] __devinitdata = { +static unsigned char aureon71_universe_eeprom[] = { [ICE_EEP2_SYSCONF] = 0x2b, /* clock 512, mpu401, spdif-in/ADC, * 4DACs */ @@ -2225,7 +2225,7 @@ static unsigned char aureon71_universe_eeprom[] __devinitdata = { [ICE_EEP2_GPIO_STATE2] = 0x00, }; -static unsigned char prodigy71lt_eeprom[] __devinitdata = { +static unsigned char prodigy71lt_eeprom[] = { [ICE_EEP2_SYSCONF] = 0x4b, /* clock 384, spdif-in/ADC, 4DACs */ [ICE_EEP2_ACLINK] = 0x80, /* I2S */ [ICE_EEP2_I2S] = 0xfc, /* vol, 96k, 24bit, 192k */ @@ -2243,7 +2243,7 @@ static unsigned char prodigy71lt_eeprom[] __devinitdata = { #define prodigy71xt_eeprom prodigy71lt_eeprom /* entry point */ -struct snd_ice1712_card_info snd_vt1724_aureon_cards[] __devinitdata = { +struct snd_ice1712_card_info snd_vt1724_aureon_cards[] = { { .subvendor = VT1724_SUBDEVICE_AUREON51_SKY, .name = "Terratec Aureon 5.1-Sky", diff --git a/sound/pci/ice1712/delta.c b/sound/pci/ice1712/delta.c index 20c6b079d0df..9e28cc12969b 100644 --- a/sound/pci/ice1712/delta.c +++ b/sound/pci/ice1712/delta.c @@ -22,7 +22,6 @@ * */ -#include <asm/io.h> #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/init.h> @@ -432,7 +431,7 @@ static int snd_ice1712_delta1010lt_wordclock_status_get(struct snd_kcontrol *kco return 0; } -static struct snd_kcontrol_new snd_ice1712_delta1010lt_wordclock_status __devinitdata = +static struct snd_kcontrol_new snd_ice1712_delta1010lt_wordclock_status = { .access = (SNDRV_CTL_ELEM_ACCESS_READ), .iface = SNDRV_CTL_ELEM_IFACE_MIXER, @@ -445,7 +444,7 @@ static struct snd_kcontrol_new snd_ice1712_delta1010lt_wordclock_status __devini * initialize the chips on M-Audio cards */ -static struct snd_akm4xxx akm_audiophile __devinitdata = { +static struct snd_akm4xxx akm_audiophile = { .type = SND_AK4528, .num_adcs = 2, .num_dacs = 2, @@ -454,7 +453,7 @@ static struct snd_akm4xxx akm_audiophile __devinitdata = { } }; -static struct snd_ak4xxx_private akm_audiophile_priv __devinitdata = { +static struct snd_ak4xxx_private akm_audiophile_priv = { .caddr = 2, .cif = 0, .data_mask = ICE1712_DELTA_AP_DOUT, @@ -466,7 +465,7 @@ static struct snd_ak4xxx_private akm_audiophile_priv __devinitdata = { .mask_flags = 0, }; -static struct snd_akm4xxx akm_delta410 __devinitdata = { +static struct snd_akm4xxx akm_delta410 = { .type = SND_AK4529, .num_adcs = 2, .num_dacs = 8, @@ -475,7 +474,7 @@ static struct snd_akm4xxx akm_delta410 __devinitdata = { } }; -static struct snd_ak4xxx_private akm_delta410_priv __devinitdata = { +static struct snd_ak4xxx_private akm_delta410_priv = { .caddr = 0, .cif = 0, .data_mask = ICE1712_DELTA_AP_DOUT, @@ -487,7 +486,7 @@ static struct snd_ak4xxx_private akm_delta410_priv __devinitdata = { .mask_flags = 0, }; -static struct snd_akm4xxx akm_delta1010lt __devinitdata = { +static struct snd_akm4xxx akm_delta1010lt = { .type = SND_AK4524, .num_adcs = 8, .num_dacs = 8, @@ -497,7 +496,7 @@ static struct snd_akm4xxx akm_delta1010lt __devinitdata = { } }; -static struct snd_ak4xxx_private akm_delta1010lt_priv __devinitdata = { +static struct snd_ak4xxx_private akm_delta1010lt_priv = { .caddr = 2, .cif = 0, /* the default level of the CIF pin from AK4524 */ .data_mask = ICE1712_DELTA_1010LT_DOUT, @@ -509,7 +508,7 @@ static struct snd_ak4xxx_private akm_delta1010lt_priv __devinitdata = { .mask_flags = 0, }; -static struct snd_akm4xxx akm_delta66e __devinitdata = { +static struct snd_akm4xxx akm_delta66e = { .type = SND_AK4524, .num_adcs = 4, .num_dacs = 4, @@ -519,7 +518,7 @@ static struct snd_akm4xxx akm_delta66e __devinitdata = { } }; -static struct snd_ak4xxx_private akm_delta66e_priv __devinitdata = { +static struct snd_ak4xxx_private akm_delta66e_priv = { .caddr = 2, .cif = 0, /* the default level of the CIF pin from AK4524 */ .data_mask = ICE1712_DELTA_66E_DOUT, @@ -532,7 +531,7 @@ static struct snd_ak4xxx_private akm_delta66e_priv __devinitdata = { }; -static struct snd_akm4xxx akm_delta44 __devinitdata = { +static struct snd_akm4xxx akm_delta44 = { .type = SND_AK4524, .num_adcs = 4, .num_dacs = 4, @@ -542,7 +541,7 @@ static struct snd_akm4xxx akm_delta44 __devinitdata = { } }; -static struct snd_ak4xxx_private akm_delta44_priv __devinitdata = { +static struct snd_ak4xxx_private akm_delta44_priv = { .caddr = 2, .cif = 0, /* the default level of the CIF pin from AK4524 */ .data_mask = ICE1712_DELTA_CODEC_SERIAL_DATA, @@ -554,7 +553,7 @@ static struct snd_ak4xxx_private akm_delta44_priv __devinitdata = { .mask_flags = 0, }; -static struct snd_akm4xxx akm_vx442 __devinitdata = { +static struct snd_akm4xxx akm_vx442 = { .type = SND_AK4524, .num_adcs = 4, .num_dacs = 4, @@ -564,7 +563,7 @@ static struct snd_akm4xxx akm_vx442 __devinitdata = { } }; -static struct snd_ak4xxx_private akm_vx442_priv __devinitdata = { +static struct snd_ak4xxx_private akm_vx442_priv = { .caddr = 2, .cif = 0, .data_mask = ICE1712_VX442_DOUT, @@ -576,7 +575,7 @@ static struct snd_ak4xxx_private akm_vx442_priv __devinitdata = { .mask_flags = 0, }; -static int __devinit snd_ice1712_delta_init(struct snd_ice1712 *ice) +static int snd_ice1712_delta_init(struct snd_ice1712 *ice) { int err; struct snd_akm4xxx *ak; @@ -617,7 +616,7 @@ static int __devinit snd_ice1712_delta_init(struct snd_ice1712 *ice) ice->num_total_dacs = 4; /* two AK4324 codecs */ break; case ICE1712_SUBDEVICE_VX442: - case ICE1712_SUBDEVICE_DELTA66E: /* omni not suported yet */ + case ICE1712_SUBDEVICE_DELTA66E: /* omni not supported yet */ ice->num_total_dacs = 4; ice->num_total_adcs = 4; break; @@ -714,19 +713,19 @@ static int __devinit snd_ice1712_delta_init(struct snd_ice1712 *ice) * additional controls for M-Audio cards */ -static struct snd_kcontrol_new snd_ice1712_delta1010_wordclock_select __devinitdata = +static struct snd_kcontrol_new snd_ice1712_delta1010_wordclock_select = ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_MIXER, "Word Clock Sync", 0, ICE1712_DELTA_WORD_CLOCK_SELECT, 1, 0); -static struct snd_kcontrol_new snd_ice1712_delta1010lt_wordclock_select __devinitdata = +static struct snd_kcontrol_new snd_ice1712_delta1010lt_wordclock_select = ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_MIXER, "Word Clock Sync", 0, ICE1712_DELTA_1010LT_WORDCLOCK, 0, 0); -static struct snd_kcontrol_new snd_ice1712_delta1010_wordclock_status __devinitdata = +static struct snd_kcontrol_new snd_ice1712_delta1010_wordclock_status = ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_MIXER, "Word Clock Status", 0, ICE1712_DELTA_WORD_CLOCK_STATUS, 1, SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE); -static struct snd_kcontrol_new snd_ice1712_deltadio2496_spdif_in_select __devinitdata = +static struct snd_kcontrol_new snd_ice1712_deltadio2496_spdif_in_select = ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_MIXER, "IEC958 Input Optical", 0, ICE1712_DELTA_SPDIF_INPUT_SELECT, 0, 0); -static struct snd_kcontrol_new snd_ice1712_delta_spdif_in_status __devinitdata = +static struct snd_kcontrol_new snd_ice1712_delta_spdif_in_status = ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_MIXER, "Delta IEC958 Input Status", 0, ICE1712_DELTA_SPDIF_IN_STAT, 1, SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE); -static int __devinit snd_ice1712_delta_add_controls(struct snd_ice1712 *ice) +static int snd_ice1712_delta_add_controls(struct snd_ice1712 *ice) { int err; @@ -802,7 +801,7 @@ static int __devinit snd_ice1712_delta_add_controls(struct snd_ice1712 *ice) /* entry point */ -struct snd_ice1712_card_info snd_ice1712_delta_cards[] __devinitdata = { +struct snd_ice1712_card_info snd_ice1712_delta_cards[] = { { .subvendor = ICE1712_SUBDEVICE_DELTA1010, .name = "M Audio Delta 1010", diff --git a/sound/pci/ice1712/ews.c b/sound/pci/ice1712/ews.c index 6fe35b812040..bc2e7011c55d 100644 --- a/sound/pci/ice1712/ews.c +++ b/sound/pci/ice1712/ews.c @@ -22,7 +22,6 @@ * */ -#include <asm/io.h> #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/init.h> @@ -344,7 +343,7 @@ static void ews88_setup_spdif(struct snd_ice1712 *ice, int rate) /* */ -static struct snd_akm4xxx akm_ews88mt __devinitdata = { +static struct snd_akm4xxx akm_ews88mt = { .num_adcs = 8, .num_dacs = 8, .type = SND_AK4524, @@ -354,7 +353,7 @@ static struct snd_akm4xxx akm_ews88mt __devinitdata = { } }; -static struct snd_ak4xxx_private akm_ews88mt_priv __devinitdata = { +static struct snd_ak4xxx_private akm_ews88mt_priv = { .caddr = 2, .cif = 1, /* CIF high */ .data_mask = ICE1712_EWS88_SERIAL_DATA, @@ -366,7 +365,7 @@ static struct snd_ak4xxx_private akm_ews88mt_priv __devinitdata = { .mask_flags = 0, }; -static struct snd_akm4xxx akm_ewx2496 __devinitdata = { +static struct snd_akm4xxx akm_ewx2496 = { .num_adcs = 2, .num_dacs = 2, .type = SND_AK4524, @@ -375,7 +374,7 @@ static struct snd_akm4xxx akm_ewx2496 __devinitdata = { } }; -static struct snd_ak4xxx_private akm_ewx2496_priv __devinitdata = { +static struct snd_ak4xxx_private akm_ewx2496_priv = { .caddr = 2, .cif = 1, /* CIF high */ .data_mask = ICE1712_EWS88_SERIAL_DATA, @@ -387,7 +386,7 @@ static struct snd_ak4xxx_private akm_ewx2496_priv __devinitdata = { .mask_flags = 0, }; -static struct snd_akm4xxx akm_6fire __devinitdata = { +static struct snd_akm4xxx akm_6fire = { .num_adcs = 6, .num_dacs = 6, .type = SND_AK4524, @@ -396,7 +395,7 @@ static struct snd_akm4xxx akm_6fire __devinitdata = { } }; -static struct snd_ak4xxx_private akm_6fire_priv __devinitdata = { +static struct snd_ak4xxx_private akm_6fire_priv = { .caddr = 2, .cif = 1, /* CIF high */ .data_mask = ICE1712_6FIRE_SERIAL_DATA, @@ -420,7 +419,7 @@ static struct snd_ak4xxx_private akm_6fire_priv __devinitdata = { static int snd_ice1712_6fire_write_pca(struct snd_ice1712 *ice, unsigned char reg, unsigned char data); -static int __devinit snd_ice1712_ews_init(struct snd_ice1712 *ice) +static int snd_ice1712_ews_init(struct snd_ice1712 *ice) { int err; struct snd_akm4xxx *ak; @@ -576,7 +575,7 @@ static int __devinit snd_ice1712_ews_init(struct snd_ice1712 *ice) /* i/o sensitivity - this callback is shared among other devices, too */ static int snd_ice1712_ewx_io_sense_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo){ - static char *texts[2] = { + static const char * const texts[2] = { "+4dBu", "-10dBV", }; uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; @@ -616,7 +615,7 @@ static int snd_ice1712_ewx_io_sense_put(struct snd_kcontrol *kcontrol, struct sn return val != nval; } -static struct snd_kcontrol_new snd_ice1712_ewx2496_controls[] __devinitdata = { +static struct snd_kcontrol_new snd_ice1712_ewx2496_controls[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Input Sensitivity Switch", @@ -724,7 +723,7 @@ static int snd_ice1712_ews88mt_input_sense_put(struct snd_kcontrol *kcontrol, st return ndata != data; } -static struct snd_kcontrol_new snd_ice1712_ews88mt_input_sense __devinitdata = { +static struct snd_kcontrol_new snd_ice1712_ews88mt_input_sense = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Input Sensitivity Switch", .info = snd_ice1712_ewx_io_sense_info, @@ -733,7 +732,7 @@ static struct snd_kcontrol_new snd_ice1712_ews88mt_input_sense __devinitdata = { .count = 8, }; -static struct snd_kcontrol_new snd_ice1712_ews88mt_output_sense __devinitdata = { +static struct snd_kcontrol_new snd_ice1712_ews88mt_output_sense = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Output Sensitivity Switch", .info = snd_ice1712_ewx_io_sense_info, @@ -811,7 +810,7 @@ static int snd_ice1712_ews88d_control_put(struct snd_kcontrol *kcontrol, struct .private_value = xshift | (xinvert << 8),\ } -static struct snd_kcontrol_new snd_ice1712_ews88d_controls[] __devinitdata = { +static struct snd_kcontrol_new snd_ice1712_ews88d_controls[] = { EWS88D_CONTROL(SNDRV_CTL_ELEM_IFACE_MIXER, "IEC958 Input Optical", 0, 1, 0), /* inverted */ EWS88D_CONTROL(SNDRV_CTL_ELEM_IFACE_MIXER, "ADAT Output Optical", 1, 0, 0), EWS88D_CONTROL(SNDRV_CTL_ELEM_IFACE_MIXER, "ADAT External Master Clock", 2, 0, 0), @@ -899,7 +898,7 @@ static int snd_ice1712_6fire_control_put(struct snd_kcontrol *kcontrol, struct s static int snd_ice1712_6fire_select_input_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[4] = { + static const char * const texts[4] = { "Internal", "Front Input", "Rear Input", "Wave Table" }; uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; @@ -948,7 +947,7 @@ static int snd_ice1712_6fire_select_input_put(struct snd_kcontrol *kcontrol, str .private_value = xshift | (xinvert << 8),\ } -static struct snd_kcontrol_new snd_ice1712_6fire_controls[] __devinitdata = { +static struct snd_kcontrol_new snd_ice1712_6fire_controls[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Analog Input Select", @@ -964,7 +963,7 @@ static struct snd_kcontrol_new snd_ice1712_6fire_controls[] __devinitdata = { }; -static int __devinit snd_ice1712_ews_add_controls(struct snd_ice1712 *ice) +static int snd_ice1712_ews_add_controls(struct snd_ice1712 *ice) { unsigned int idx; int err; @@ -1030,7 +1029,7 @@ static int __devinit snd_ice1712_ews_add_controls(struct snd_ice1712 *ice) /* entry point */ -struct snd_ice1712_card_info snd_ice1712_ews_cards[] __devinitdata = { +struct snd_ice1712_card_info snd_ice1712_ews_cards[] = { { .subvendor = ICE1712_SUBDEVICE_EWX2496, .name = "TerraTec EWX24/96", diff --git a/sound/pci/ice1712/hoontech.c b/sound/pci/ice1712/hoontech.c index 6914189073a4..59e37c581691 100644 --- a/sound/pci/ice1712/hoontech.c +++ b/sound/pci/ice1712/hoontech.c @@ -21,7 +21,6 @@ * */ -#include <asm/io.h> #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/init.h> @@ -40,7 +39,7 @@ struct hoontech_spec { unsigned short boxconfig[4]; }; -static void __devinit snd_ice1712_stdsp24_gpio_write(struct snd_ice1712 *ice, unsigned char byte) +static void snd_ice1712_stdsp24_gpio_write(struct snd_ice1712 *ice, unsigned char byte) { byte |= ICE1712_STDSP24_CLOCK_BIT; udelay(100); @@ -53,7 +52,7 @@ static void __devinit snd_ice1712_stdsp24_gpio_write(struct snd_ice1712 *ice, un snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, byte); } -static void __devinit snd_ice1712_stdsp24_darear(struct snd_ice1712 *ice, int activate) +static void snd_ice1712_stdsp24_darear(struct snd_ice1712 *ice, int activate) { struct hoontech_spec *spec = ice->spec; mutex_lock(&ice->gpio_mutex); @@ -62,7 +61,7 @@ static void __devinit snd_ice1712_stdsp24_darear(struct snd_ice1712 *ice, int ac mutex_unlock(&ice->gpio_mutex); } -static void __devinit snd_ice1712_stdsp24_mute(struct snd_ice1712 *ice, int activate) +static void snd_ice1712_stdsp24_mute(struct snd_ice1712 *ice, int activate) { struct hoontech_spec *spec = ice->spec; mutex_lock(&ice->gpio_mutex); @@ -71,7 +70,7 @@ static void __devinit snd_ice1712_stdsp24_mute(struct snd_ice1712 *ice, int acti mutex_unlock(&ice->gpio_mutex); } -static void __devinit snd_ice1712_stdsp24_insel(struct snd_ice1712 *ice, int activate) +static void snd_ice1712_stdsp24_insel(struct snd_ice1712 *ice, int activate) { struct hoontech_spec *spec = ice->spec; mutex_lock(&ice->gpio_mutex); @@ -80,7 +79,7 @@ static void __devinit snd_ice1712_stdsp24_insel(struct snd_ice1712 *ice, int act mutex_unlock(&ice->gpio_mutex); } -static void __devinit snd_ice1712_stdsp24_box_channel(struct snd_ice1712 *ice, int box, int chn, int activate) +static void snd_ice1712_stdsp24_box_channel(struct snd_ice1712 *ice, int box, int chn, int activate) { struct hoontech_spec *spec = ice->spec; @@ -130,7 +129,7 @@ static void __devinit snd_ice1712_stdsp24_box_channel(struct snd_ice1712 *ice, i mutex_unlock(&ice->gpio_mutex); } -static void __devinit snd_ice1712_stdsp24_box_midi(struct snd_ice1712 *ice, int box, int master) +static void snd_ice1712_stdsp24_box_midi(struct snd_ice1712 *ice, int box, int master) { struct hoontech_spec *spec = ice->spec; @@ -158,7 +157,7 @@ static void __devinit snd_ice1712_stdsp24_box_midi(struct snd_ice1712 *ice, int mutex_unlock(&ice->gpio_mutex); } -static void __devinit snd_ice1712_stdsp24_midi2(struct snd_ice1712 *ice, int activate) +static void snd_ice1712_stdsp24_midi2(struct snd_ice1712 *ice, int activate) { struct hoontech_spec *spec = ice->spec; mutex_lock(&ice->gpio_mutex); @@ -167,7 +166,7 @@ static void __devinit snd_ice1712_stdsp24_midi2(struct snd_ice1712 *ice, int act mutex_unlock(&ice->gpio_mutex); } -static int __devinit snd_ice1712_hoontech_init(struct snd_ice1712 *ice) +static int snd_ice1712_hoontech_init(struct snd_ice1712 *ice) { struct hoontech_spec *spec; int box, chn; @@ -267,10 +266,10 @@ static void stdsp24_ak4524_lock(struct snd_akm4xxx *ak, int chip) snd_ice1712_write(ice, ICE1712_IREG_GPIO_WRITE_MASK, ~tmp); } -static int __devinit snd_ice1712_value_init(struct snd_ice1712 *ice) +static int snd_ice1712_value_init(struct snd_ice1712 *ice) { /* Hoontech STDSP24 with modified hardware */ - static struct snd_akm4xxx akm_stdsp24_mv __devinitdata = { + static struct snd_akm4xxx akm_stdsp24_mv = { .num_adcs = 2, .num_dacs = 2, .type = SND_AK4524, @@ -279,7 +278,7 @@ static int __devinit snd_ice1712_value_init(struct snd_ice1712 *ice) } }; - static struct snd_ak4xxx_private akm_stdsp24_mv_priv __devinitdata = { + static struct snd_ak4xxx_private akm_stdsp24_mv_priv = { .caddr = 2, .cif = 1, /* CIF high */ .data_mask = ICE1712_STDSP24_SERIAL_DATA, @@ -317,7 +316,7 @@ static int __devinit snd_ice1712_value_init(struct snd_ice1712 *ice) return 0; } -static int __devinit snd_ice1712_ez8_init(struct snd_ice1712 *ice) +static int snd_ice1712_ez8_init(struct snd_ice1712 *ice) { ice->gpio.write_mask = ice->eeprom.gpiomask; ice->gpio.direction = ice->eeprom.gpiodir; @@ -329,7 +328,7 @@ static int __devinit snd_ice1712_ez8_init(struct snd_ice1712 *ice) /* entry point */ -struct snd_ice1712_card_info snd_ice1712_hoontech_cards[] __devinitdata = { +struct snd_ice1712_card_info snd_ice1712_hoontech_cards[] = { { .subvendor = ICE1712_SUBDEVICE_STDSP24, .name = "Hoontech SoundTrack Audio DSP24", diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c index 5be2e120a14e..2ffdc35d5ffd 100644 --- a/sound/pci/ice1712/ice1712.c +++ b/sound/pci/ice1712/ice1712.c @@ -47,7 +47,6 @@ */ -#include <linux/io.h> #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/init.h> @@ -280,7 +279,7 @@ static int snd_ice1712_digmix_route_ac97_put(struct snd_kcontrol *kcontrol, stru return val != nval; } -static struct snd_kcontrol_new snd_ice1712_mixer_digmix_route_ac97 __devinitdata = { +static struct snd_kcontrol_new snd_ice1712_mixer_digmix_route_ac97 = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Digital Mixer To AC97", .info = snd_ice1712_digmix_route_ac97_info, @@ -388,7 +387,7 @@ static void setup_cs8427(struct snd_ice1712 *ice, int rate) /* * create and initialize callbacks for cs8427 interface */ -int __devinit snd_ice1712_init_cs8427(struct snd_ice1712 *ice, int addr) +int snd_ice1712_init_cs8427(struct snd_ice1712 *ice, int addr) { int err; @@ -879,7 +878,7 @@ static struct snd_pcm_ops snd_ice1712_capture_ops = { .pointer = snd_ice1712_capture_pointer, }; -static int __devinit snd_ice1712_pcm(struct snd_ice1712 *ice, int device, struct snd_pcm **rpcm) +static int snd_ice1712_pcm(struct snd_ice1712 *ice, int device, struct snd_pcm **rpcm) { struct snd_pcm *pcm; int err; @@ -909,7 +908,7 @@ static int __devinit snd_ice1712_pcm(struct snd_ice1712 *ice, int device, struct return 0; } -static int __devinit snd_ice1712_pcm_ds(struct snd_ice1712 *ice, int device, struct snd_pcm **rpcm) +static int snd_ice1712_pcm_ds(struct snd_ice1712 *ice, int device, struct snd_pcm **rpcm) { struct snd_pcm *pcm; int err; @@ -1254,7 +1253,7 @@ static struct snd_pcm_ops snd_ice1712_capture_pro_ops = { .pointer = snd_ice1712_capture_pro_pointer, }; -static int __devinit snd_ice1712_pcm_profi(struct snd_ice1712 *ice, int device, struct snd_pcm **rpcm) +static int snd_ice1712_pcm_profi(struct snd_ice1712 *ice, int device, struct snd_pcm **rpcm) { struct snd_pcm *pcm; int err; @@ -1388,7 +1387,7 @@ static int snd_ice1712_pro_mixer_volume_put(struct snd_kcontrol *kcontrol, struc static const DECLARE_TLV_DB_SCALE(db_scale_playback, -14400, 150, 0); -static struct snd_kcontrol_new snd_ice1712_multi_playback_ctrls[] __devinitdata = { +static struct snd_kcontrol_new snd_ice1712_multi_playback_ctrls[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Multi Playback Switch", @@ -1412,7 +1411,7 @@ static struct snd_kcontrol_new snd_ice1712_multi_playback_ctrls[] __devinitdata }, }; -static struct snd_kcontrol_new snd_ice1712_multi_capture_analog_switch __devinitdata = { +static struct snd_kcontrol_new snd_ice1712_multi_capture_analog_switch = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "H/W Multi Capture Switch", .info = snd_ice1712_pro_mixer_switch_info, @@ -1421,7 +1420,7 @@ static struct snd_kcontrol_new snd_ice1712_multi_capture_analog_switch __devinit .private_value = 10, }; -static struct snd_kcontrol_new snd_ice1712_multi_capture_spdif_switch __devinitdata = { +static struct snd_kcontrol_new snd_ice1712_multi_capture_spdif_switch = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = SNDRV_CTL_NAME_IEC958("Multi ", CAPTURE, SWITCH), .info = snd_ice1712_pro_mixer_switch_info, @@ -1431,7 +1430,7 @@ static struct snd_kcontrol_new snd_ice1712_multi_capture_spdif_switch __devinitd .count = 2, }; -static struct snd_kcontrol_new snd_ice1712_multi_capture_analog_volume __devinitdata = { +static struct snd_kcontrol_new snd_ice1712_multi_capture_analog_volume = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ), @@ -1443,7 +1442,7 @@ static struct snd_kcontrol_new snd_ice1712_multi_capture_analog_volume __devinit .tlv = { .p = db_scale_playback } }; -static struct snd_kcontrol_new snd_ice1712_multi_capture_spdif_volume __devinitdata = { +static struct snd_kcontrol_new snd_ice1712_multi_capture_spdif_volume = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = SNDRV_CTL_NAME_IEC958("Multi ", CAPTURE, VOLUME), .info = snd_ice1712_pro_mixer_volume_info, @@ -1453,7 +1452,7 @@ static struct snd_kcontrol_new snd_ice1712_multi_capture_spdif_volume __devinitd .count = 2, }; -static int __devinit snd_ice1712_build_pro_mixer(struct snd_ice1712 *ice) +static int snd_ice1712_build_pro_mixer(struct snd_ice1712 *ice) { struct snd_card *card = ice->card; unsigned int idx; @@ -1512,7 +1511,7 @@ static void snd_ice1712_mixer_free_ac97(struct snd_ac97 *ac97) ice->ac97 = NULL; } -static int __devinit snd_ice1712_ac97_mixer(struct snd_ice1712 *ice) +static int snd_ice1712_ac97_mixer(struct snd_ice1712 *ice) { int err, bus_num = 0; struct snd_ac97_template ac97; @@ -1611,7 +1610,7 @@ static void snd_ice1712_proc_read(struct snd_info_entry *entry, snd_iprintf(buffer, " GPIO_DIRECTION : 0x%02x\n", (unsigned)snd_ice1712_read(ice, ICE1712_IREG_GPIO_DIRECTION)); } -static void __devinit snd_ice1712_proc_init(struct snd_ice1712 *ice) +static void snd_ice1712_proc_init(struct snd_ice1712 *ice) { struct snd_info_entry *entry; @@ -1640,7 +1639,7 @@ static int snd_ice1712_eeprom_get(struct snd_kcontrol *kcontrol, return 0; } -static struct snd_kcontrol_new snd_ice1712_eeprom __devinitdata = { +static struct snd_kcontrol_new snd_ice1712_eeprom = { .iface = SNDRV_CTL_ELEM_IFACE_CARD, .name = "ICE1712 EEPROM", .access = SNDRV_CTL_ELEM_ACCESS_READ, @@ -1676,7 +1675,7 @@ static int snd_ice1712_spdif_default_put(struct snd_kcontrol *kcontrol, return 0; } -static struct snd_kcontrol_new snd_ice1712_spdif_default __devinitdata = +static struct snd_kcontrol_new snd_ice1712_spdif_default = { .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT), @@ -1727,7 +1726,7 @@ static int snd_ice1712_spdif_maskp_get(struct snd_kcontrol *kcontrol, return 0; } -static struct snd_kcontrol_new snd_ice1712_spdif_maskc __devinitdata = +static struct snd_kcontrol_new snd_ice1712_spdif_maskc = { .access = SNDRV_CTL_ELEM_ACCESS_READ, .iface = SNDRV_CTL_ELEM_IFACE_PCM, @@ -1736,7 +1735,7 @@ static struct snd_kcontrol_new snd_ice1712_spdif_maskc __devinitdata = .get = snd_ice1712_spdif_maskc_get, }; -static struct snd_kcontrol_new snd_ice1712_spdif_maskp __devinitdata = +static struct snd_kcontrol_new snd_ice1712_spdif_maskp = { .access = SNDRV_CTL_ELEM_ACCESS_READ, .iface = SNDRV_CTL_ELEM_IFACE_PCM, @@ -1763,7 +1762,7 @@ static int snd_ice1712_spdif_stream_put(struct snd_kcontrol *kcontrol, return 0; } -static struct snd_kcontrol_new snd_ice1712_spdif_stream __devinitdata = +static struct snd_kcontrol_new snd_ice1712_spdif_stream = { .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE), @@ -1894,7 +1893,7 @@ static int snd_ice1712_pro_internal_clock_put(struct snd_kcontrol *kcontrol, return change; } -static struct snd_kcontrol_new snd_ice1712_pro_internal_clock __devinitdata = { +static struct snd_kcontrol_new snd_ice1712_pro_internal_clock = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Multi Track Internal Clock", .info = snd_ice1712_pro_internal_clock_info, @@ -1965,7 +1964,7 @@ static int snd_ice1712_pro_internal_clock_default_put(struct snd_kcontrol *kcont return change; } -static struct snd_kcontrol_new snd_ice1712_pro_internal_clock_default __devinitdata = { +static struct snd_kcontrol_new snd_ice1712_pro_internal_clock_default = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Multi Track Internal Clock Default", .info = snd_ice1712_pro_internal_clock_default_info, @@ -1996,7 +1995,7 @@ static int snd_ice1712_pro_rate_locking_put(struct snd_kcontrol *kcontrol, return change; } -static struct snd_kcontrol_new snd_ice1712_pro_rate_locking __devinitdata = { +static struct snd_kcontrol_new snd_ice1712_pro_rate_locking = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Multi Track Rate Locking", .info = snd_ice1712_pro_rate_locking_info, @@ -2027,7 +2026,7 @@ static int snd_ice1712_pro_rate_reset_put(struct snd_kcontrol *kcontrol, return change; } -static struct snd_kcontrol_new snd_ice1712_pro_rate_reset __devinitdata = { +static struct snd_kcontrol_new snd_ice1712_pro_rate_reset = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Multi Track Rate Reset", .info = snd_ice1712_pro_rate_reset_info, @@ -2194,7 +2193,7 @@ static int snd_ice1712_pro_route_spdif_put(struct snd_kcontrol *kcontrol, return change; } -static struct snd_kcontrol_new snd_ice1712_mixer_pro_analog_route __devinitdata = { +static struct snd_kcontrol_new snd_ice1712_mixer_pro_analog_route = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "H/W Playback Route", .info = snd_ice1712_pro_route_info, @@ -2202,7 +2201,7 @@ static struct snd_kcontrol_new snd_ice1712_mixer_pro_analog_route __devinitdata .put = snd_ice1712_pro_route_analog_put, }; -static struct snd_kcontrol_new snd_ice1712_mixer_pro_spdif_route __devinitdata = { +static struct snd_kcontrol_new snd_ice1712_mixer_pro_spdif_route = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, NONE) "Route", .info = snd_ice1712_pro_route_info, @@ -2244,7 +2243,7 @@ static int snd_ice1712_pro_volume_rate_put(struct snd_kcontrol *kcontrol, return change; } -static struct snd_kcontrol_new snd_ice1712_mixer_pro_volume_rate __devinitdata = { +static struct snd_kcontrol_new snd_ice1712_mixer_pro_volume_rate = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Multi Track Volume Rate", .info = snd_ice1712_pro_volume_rate_info, @@ -2277,7 +2276,7 @@ static int snd_ice1712_pro_peak_get(struct snd_kcontrol *kcontrol, return 0; } -static struct snd_kcontrol_new snd_ice1712_mixer_pro_peak __devinitdata = { +static struct snd_kcontrol_new snd_ice1712_mixer_pro_peak = { .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = "Multi Track Peak", .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, @@ -2292,16 +2291,16 @@ static struct snd_kcontrol_new snd_ice1712_mixer_pro_peak __devinitdata = { /* * list of available boards */ -static struct snd_ice1712_card_info *card_tables[] __devinitdata = { +static struct snd_ice1712_card_info *card_tables[] = { snd_ice1712_hoontech_cards, snd_ice1712_delta_cards, snd_ice1712_ews_cards, NULL, }; -static unsigned char __devinit snd_ice1712_read_i2c(struct snd_ice1712 *ice, - unsigned char dev, - unsigned char addr) +static unsigned char snd_ice1712_read_i2c(struct snd_ice1712 *ice, + unsigned char dev, + unsigned char addr) { long t = 0x10000; @@ -2311,8 +2310,8 @@ static unsigned char __devinit snd_ice1712_read_i2c(struct snd_ice1712 *ice, return inb(ICEREG(ice, I2C_DATA)); } -static int __devinit snd_ice1712_read_eeprom(struct snd_ice1712 *ice, - const char *modelname) +static int snd_ice1712_read_eeprom(struct snd_ice1712 *ice, + const char *modelname) { int dev = 0xa0; /* EEPROM device address */ unsigned int i, size; @@ -2386,7 +2385,7 @@ static int __devinit snd_ice1712_read_eeprom(struct snd_ice1712 *ice, -static int __devinit snd_ice1712_chip_init(struct snd_ice1712 *ice) +static int snd_ice1712_chip_init(struct snd_ice1712 *ice) { outb(ICE1712_RESET | ICE1712_NATIVE, ICEREG(ice, CONTROL)); udelay(200); @@ -2433,7 +2432,7 @@ static int __devinit snd_ice1712_chip_init(struct snd_ice1712 *ice) return 0; } -int __devinit snd_ice1712_spdif_build_controls(struct snd_ice1712 *ice) +int snd_ice1712_spdif_build_controls(struct snd_ice1712 *ice) { int err; struct snd_kcontrol *kctl; @@ -2461,7 +2460,7 @@ int __devinit snd_ice1712_spdif_build_controls(struct snd_ice1712 *ice) } -static int __devinit snd_ice1712_build_controls(struct snd_ice1712 *ice) +static int snd_ice1712_build_controls(struct snd_ice1712 *ice) { int err; @@ -2531,13 +2530,13 @@ static int snd_ice1712_dev_free(struct snd_device *device) return snd_ice1712_free(ice); } -static int __devinit snd_ice1712_create(struct snd_card *card, - struct pci_dev *pci, - const char *modelname, - int omni, - int cs8427_timeout, - int dxr_enable, - struct snd_ice1712 **r_ice1712) +static int snd_ice1712_create(struct snd_card *card, + struct pci_dev *pci, + const char *modelname, + int omni, + int cs8427_timeout, + int dxr_enable, + struct snd_ice1712 **r_ice1712) { struct snd_ice1712 *ice; int err; @@ -2651,10 +2650,10 @@ static int __devinit snd_ice1712_create(struct snd_card *card, * */ -static struct snd_ice1712_card_info no_matched __devinitdata; +static struct snd_ice1712_card_info no_matched; -static int __devinit snd_ice1712_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int snd_ice1712_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { static int dev; struct snd_card *card; @@ -2686,6 +2685,7 @@ static int __devinit snd_ice1712_probe(struct pci_dev *pci, for (tbl = card_tables; *tbl; tbl++) { for (c = *tbl; c->subvendor; c++) { if (c->subvendor == ice->eeprom.subvendor) { + ice->card_info = c; strcpy(card->shortname, c->name); if (c->driver) /* specific driver? */ strcpy(card->driver, c->driver); @@ -2797,9 +2797,14 @@ static int __devinit snd_ice1712_probe(struct pci_dev *pci, return 0; } -static void __devexit snd_ice1712_remove(struct pci_dev *pci) +static void snd_ice1712_remove(struct pci_dev *pci) { - snd_card_free(pci_get_drvdata(pci)); + struct snd_card *card = pci_get_drvdata(pci); + struct snd_ice1712 *ice = card->private_data; + + if (ice->card_info && ice->card_info->chip_exit) + ice->card_info->chip_exit(ice); + snd_card_free(card); pci_set_drvdata(pci, NULL); } @@ -2807,7 +2812,7 @@ static struct pci_driver ice1712_driver = { .name = KBUILD_MODNAME, .id_table = snd_ice1712_ids, .probe = snd_ice1712_probe, - .remove = __devexit_p(snd_ice1712_remove), + .remove = snd_ice1712_remove, }; module_pci_driver(ice1712_driver); diff --git a/sound/pci/ice1712/ice1712.h b/sound/pci/ice1712/ice1712.h index d0e7d87f09f0..b209fc30b334 100644 --- a/sound/pci/ice1712/ice1712.h +++ b/sound/pci/ice1712/ice1712.h @@ -22,6 +22,7 @@ * */ +#include <linux/io.h> #include <sound/control.h> #include <sound/ac97_codec.h> #include <sound/rawmidi.h> @@ -288,6 +289,7 @@ struct snd_ice1712_spdif { } ops; }; +struct snd_ice1712_card_info; struct snd_ice1712 { unsigned long conp_dma_size; @@ -324,6 +326,7 @@ struct snd_ice1712 { struct snd_info_entry *proc_entry; struct snd_ice1712_eeprom eeprom; + struct snd_ice1712_card_info *card_info; unsigned int pro_volumes[20]; unsigned int omni:1; /* Delta Omni I/O */ @@ -381,7 +384,7 @@ struct snd_ice1712 { unsigned char (*set_mclk)(struct snd_ice1712 *ice, unsigned int rate); int (*set_spdif_clock)(struct snd_ice1712 *ice, int type); int (*get_spdif_master_type)(struct snd_ice1712 *ice); - char **ext_clock_names; + const char * const *ext_clock_names; int ext_clock_count; void (*pro_open)(struct snd_ice1712 *, struct snd_pcm_substream *); #ifdef CONFIG_PM_SLEEP @@ -513,10 +516,11 @@ static inline u8 snd_ice1712_read(struct snd_ice1712 *ice, u8 addr) struct snd_ice1712_card_info { unsigned int subvendor; - char *name; - char *model; - char *driver; + const char *name; + const char *model; + const char *driver; int (*chip_init)(struct snd_ice1712 *); + void (*chip_exit)(struct snd_ice1712 *); int (*build_controls)(struct snd_ice1712 *); unsigned int no_mpu401:1; unsigned int mpu401_1_info_flags; diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c index 245d874891ba..ce70e7f113e0 100644 --- a/sound/pci/ice1712/ice1724.c +++ b/sound/pci/ice1712/ice1724.c @@ -22,7 +22,6 @@ * */ -#include <linux/io.h> #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/init.h> @@ -54,6 +53,7 @@ #include "wtm.h" #include "se.h" #include "quartet.h" +#include "psc724.h" MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); MODULE_DESCRIPTION("VIA ICEnsemble ICE1724/1720 (Envy24HT/PT)"); @@ -106,7 +106,7 @@ static int PRO_RATE_LOCKED; static int PRO_RATE_RESET = 1; static unsigned int PRO_RATE_DEFAULT = 44100; -static char *ext_clock_names[1] = { "IEC958 In" }; +static const char * const ext_clock_names[1] = { "IEC958 In" }; /* * Basic I/O @@ -1135,7 +1135,7 @@ static struct snd_pcm_ops snd_vt1724_capture_pro_ops = { .pointer = snd_vt1724_pcm_pointer, }; -static int __devinit snd_vt1724_pcm_profi(struct snd_ice1712 *ice, int device) +static int snd_vt1724_pcm_profi(struct snd_ice1712 *ice, int device) { struct snd_pcm *pcm; int capt, err; @@ -1315,7 +1315,7 @@ static struct snd_pcm_ops snd_vt1724_capture_spdif_ops = { }; -static int __devinit snd_vt1724_pcm_spdif(struct snd_ice1712 *ice, int device) +static int snd_vt1724_pcm_spdif(struct snd_ice1712 *ice, int device) { char *name; struct snd_pcm *pcm; @@ -1449,7 +1449,7 @@ static struct snd_pcm_ops snd_vt1724_playback_indep_ops = { }; -static int __devinit snd_vt1724_pcm_indep(struct snd_ice1712 *ice, int device) +static int snd_vt1724_pcm_indep(struct snd_ice1712 *ice, int device) { struct snd_pcm *pcm; int play; @@ -1484,7 +1484,7 @@ static int __devinit snd_vt1724_pcm_indep(struct snd_ice1712 *ice, int device) * Mixer section */ -static int __devinit snd_vt1724_ac97_mixer(struct snd_ice1712 *ice) +static int snd_vt1724_ac97_mixer(struct snd_ice1712 *ice) { int err; @@ -1570,7 +1570,7 @@ static void snd_vt1724_proc_read(struct snd_info_entry *entry, idx, inb(ice->profi_port+idx)); } -static void __devinit snd_vt1724_proc_init(struct snd_ice1712 *ice) +static void snd_vt1724_proc_init(struct snd_ice1712 *ice) { struct snd_info_entry *entry; @@ -1599,7 +1599,7 @@ static int snd_vt1724_eeprom_get(struct snd_kcontrol *kcontrol, return 0; } -static struct snd_kcontrol_new snd_vt1724_eeprom __devinitdata = { +static struct snd_kcontrol_new snd_vt1724_eeprom = { .iface = SNDRV_CTL_ELEM_IFACE_CARD, .name = "ICE1724 EEPROM", .access = SNDRV_CTL_ELEM_ACCESS_READ, @@ -1712,7 +1712,7 @@ static int snd_vt1724_spdif_default_put(struct snd_kcontrol *kcontrol, return val != old; } -static struct snd_kcontrol_new snd_vt1724_spdif_default __devinitdata = +static struct snd_kcontrol_new snd_vt1724_spdif_default = { .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT), @@ -1744,7 +1744,7 @@ static int snd_vt1724_spdif_maskp_get(struct snd_kcontrol *kcontrol, return 0; } -static struct snd_kcontrol_new snd_vt1724_spdif_maskc __devinitdata = +static struct snd_kcontrol_new snd_vt1724_spdif_maskc = { .access = SNDRV_CTL_ELEM_ACCESS_READ, .iface = SNDRV_CTL_ELEM_IFACE_PCM, @@ -1753,7 +1753,7 @@ static struct snd_kcontrol_new snd_vt1724_spdif_maskc __devinitdata = .get = snd_vt1724_spdif_maskc_get, }; -static struct snd_kcontrol_new snd_vt1724_spdif_maskp __devinitdata = +static struct snd_kcontrol_new snd_vt1724_spdif_maskp = { .access = SNDRV_CTL_ELEM_ACCESS_READ, .iface = SNDRV_CTL_ELEM_IFACE_PCM, @@ -1790,7 +1790,7 @@ static int snd_vt1724_spdif_sw_put(struct snd_kcontrol *kcontrol, return old != val; } -static struct snd_kcontrol_new snd_vt1724_spdif_switch __devinitdata = +static struct snd_kcontrol_new snd_vt1724_spdif_switch = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* FIXME: the following conflict with IEC958 Playback Route */ @@ -1965,7 +1965,7 @@ static int snd_vt1724_pro_internal_clock_put(struct snd_kcontrol *kcontrol, return old_rate != new_rate; } -static struct snd_kcontrol_new snd_vt1724_pro_internal_clock __devinitdata = { +static struct snd_kcontrol_new snd_vt1724_pro_internal_clock = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Multi Track Internal Clock", .info = snd_vt1724_pro_internal_clock_info, @@ -1996,7 +1996,7 @@ static int snd_vt1724_pro_rate_locking_put(struct snd_kcontrol *kcontrol, return change; } -static struct snd_kcontrol_new snd_vt1724_pro_rate_locking __devinitdata = { +static struct snd_kcontrol_new snd_vt1724_pro_rate_locking = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Multi Track Rate Locking", .info = snd_vt1724_pro_rate_locking_info, @@ -2027,7 +2027,7 @@ static int snd_vt1724_pro_rate_reset_put(struct snd_kcontrol *kcontrol, return change; } -static struct snd_kcontrol_new snd_vt1724_pro_rate_reset __devinitdata = { +static struct snd_kcontrol_new snd_vt1724_pro_rate_reset = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Multi Track Rate Reset", .info = snd_vt1724_pro_rate_reset_info, @@ -2042,7 +2042,7 @@ static struct snd_kcontrol_new snd_vt1724_pro_rate_reset __devinitdata = { static int snd_vt1724_pro_route_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = { + static const char * const texts[] = { "PCM Out", /* 0 */ "H/W In 0", "H/W In 1", /* 1-2 */ "IEC958 In L", "IEC958 In R", /* 3-4 */ @@ -2149,7 +2149,7 @@ static int snd_vt1724_pro_route_spdif_put(struct snd_kcontrol *kcontrol, digital_route_shift(idx)); } -static struct snd_kcontrol_new snd_vt1724_mixer_pro_analog_route __devinitdata = +static struct snd_kcontrol_new snd_vt1724_mixer_pro_analog_route = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "H/W Playback Route", @@ -2158,7 +2158,7 @@ static struct snd_kcontrol_new snd_vt1724_mixer_pro_analog_route __devinitdata = .put = snd_vt1724_pro_route_analog_put, }; -static struct snd_kcontrol_new snd_vt1724_mixer_pro_spdif_route __devinitdata = { +static struct snd_kcontrol_new snd_vt1724_mixer_pro_spdif_route = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, NONE) "Route", .info = snd_vt1724_pro_route_info, @@ -2194,7 +2194,7 @@ static int snd_vt1724_pro_peak_get(struct snd_kcontrol *kcontrol, return 0; } -static struct snd_kcontrol_new snd_vt1724_mixer_pro_peak __devinitdata = { +static struct snd_kcontrol_new snd_vt1724_mixer_pro_peak = { .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = "Multi Track Peak", .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, @@ -2206,13 +2206,13 @@ static struct snd_kcontrol_new snd_vt1724_mixer_pro_peak __devinitdata = { * */ -static struct snd_ice1712_card_info no_matched __devinitdata; +static struct snd_ice1712_card_info no_matched; /* ooAoo cards with no controls */ -static unsigned char ooaoo_sq210_eeprom[] __devinitdata = { +static unsigned char ooaoo_sq210_eeprom[] = { [ICE_EEP2_SYSCONF] = 0x4c, /* 49MHz crystal, no mpu401, no ADC, 1xDACs */ [ICE_EEP2_ACLINK] = 0x80, /* I2S */ @@ -2232,7 +2232,7 @@ static unsigned char ooaoo_sq210_eeprom[] __devinitdata = { }; -struct snd_ice1712_card_info snd_vt1724_ooaoo_cards[] __devinitdata = { +static struct snd_ice1712_card_info snd_vt1724_ooaoo_cards[] = { { .name = "ooAoo SQ210a", .model = "sq210a", @@ -2242,7 +2242,7 @@ struct snd_ice1712_card_info snd_vt1724_ooaoo_cards[] __devinitdata = { { } /* terminator */ }; -static struct snd_ice1712_card_info *card_tables[] __devinitdata = { +static struct snd_ice1712_card_info *card_tables[] = { snd_vt1724_revo_cards, snd_vt1724_amp_cards, snd_vt1724_aureon_cards, @@ -2257,6 +2257,7 @@ static struct snd_ice1712_card_info *card_tables[] __devinitdata = { snd_vt1724_se_cards, snd_vt1724_qtet_cards, snd_vt1724_ooaoo_cards, + snd_vt1724_psc724_cards, NULL, }; @@ -2306,8 +2307,8 @@ void snd_vt1724_write_i2c(struct snd_ice1712 *ice, mutex_unlock(&ice->i2c_mutex); } -static int __devinit snd_vt1724_read_eeprom(struct snd_ice1712 *ice, - const char *modelname) +static int snd_vt1724_read_eeprom(struct snd_ice1712 *ice, + const char *modelname) { const int dev = 0xa0; /* EEPROM device address */ unsigned int i, size; @@ -2348,6 +2349,7 @@ static int __devinit snd_vt1724_read_eeprom(struct snd_ice1712 *ice, ice->eeprom.subvendor = c->subvendor; } else if (c->subvendor != ice->eeprom.subvendor) continue; + ice->card_info = c; if (!c->eeprom_size || !c->eeprom_data) goto found; /* if the EEPROM is given by the driver, use it */ @@ -2360,6 +2362,10 @@ static int __devinit snd_vt1724_read_eeprom(struct snd_ice1712 *ice, } printk(KERN_WARNING "ice1724: No matching model found for ID 0x%x\n", ice->eeprom.subvendor); +#ifdef CONFIG_PM_SLEEP + /* assume AC97-only card which can suspend without additional code */ + ice->pm_suspend_enabled = 1; +#endif found: ice->eeprom.size = snd_vt1724_read_i2c(ice, dev, 0x04); @@ -2371,7 +2377,7 @@ static int __devinit snd_vt1724_read_eeprom(struct snd_ice1712 *ice, return -EIO; } ice->eeprom.version = snd_vt1724_read_i2c(ice, dev, 0x05); - if (ice->eeprom.version != 2) + if (ice->eeprom.version != 1 && ice->eeprom.version != 2) printk(KERN_WARNING "ice1724: Invalid EEPROM version %i\n", ice->eeprom.version); size = ice->eeprom.size - 6; @@ -2424,7 +2430,7 @@ static int snd_vt1724_chip_init(struct snd_ice1712 *ice) return 0; } -static int __devinit snd_vt1724_spdif_build_controls(struct snd_ice1712 *ice) +static int snd_vt1724_spdif_build_controls(struct snd_ice1712 *ice) { int err; struct snd_kcontrol *kctl; @@ -2466,7 +2472,7 @@ static int __devinit snd_vt1724_spdif_build_controls(struct snd_ice1712 *ice) } -static int __devinit snd_vt1724_build_controls(struct snd_ice1712 *ice) +static int snd_vt1724_build_controls(struct snd_ice1712 *ice) { int err; @@ -2526,10 +2532,10 @@ static int snd_vt1724_dev_free(struct snd_device *device) return snd_vt1724_free(ice); } -static int __devinit snd_vt1724_create(struct snd_card *card, - struct pci_dev *pci, - const char *modelname, - struct snd_ice1712 **r_ice1712) +static int snd_vt1724_create(struct snd_card *card, + struct pci_dev *pci, + const char *modelname, + struct snd_ice1712 **r_ice1712) { struct snd_ice1712 *ice; int err; @@ -2616,8 +2622,8 @@ static int __devinit snd_vt1724_create(struct snd_card *card, * */ -static int __devinit snd_vt1724_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int snd_vt1724_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { static int dev; struct snd_card *card; @@ -2786,9 +2792,14 @@ __found: return 0; } -static void __devexit snd_vt1724_remove(struct pci_dev *pci) +static void snd_vt1724_remove(struct pci_dev *pci) { - snd_card_free(pci_get_drvdata(pci)); + struct snd_card *card = pci_get_drvdata(pci); + struct snd_ice1712 *ice = card->private_data; + + if (ice->card_info && ice->card_info->chip_exit) + ice->card_info->chip_exit(ice); + snd_card_free(card); pci_set_drvdata(pci, NULL); } @@ -2889,7 +2900,7 @@ static struct pci_driver vt1724_driver = { .name = KBUILD_MODNAME, .id_table = snd_vt1724_ids, .probe = snd_vt1724_probe, - .remove = __devexit_p(snd_vt1724_remove), + .remove = snd_vt1724_remove, .driver = { .pm = SND_VT1724_PM_OPS, }, diff --git a/sound/pci/ice1712/juli.c b/sound/pci/ice1712/juli.c index 14fd536b6452..8855933e710d 100644 --- a/sound/pci/ice1712/juli.c +++ b/sound/pci/ice1712/juli.c @@ -23,7 +23,6 @@ * */ -#include <asm/io.h> #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/init.h> @@ -283,7 +282,7 @@ static const struct snd_akm4xxx_dac_channel juli_dac[] = { }; -static struct snd_akm4xxx akm_juli_dac __devinitdata = { +static struct snd_akm4xxx akm_juli_dac = { .type = SND_AK4358, .num_dacs = 8, /* DAC1 - analog out DAC2 - analog in monitor @@ -358,7 +357,7 @@ static int juli_mute_put(struct snd_kcontrol *kcontrol, return 0; } -static struct snd_kcontrol_new juli_mute_controls[] __devinitdata = { +static struct snd_kcontrol_new juli_mute_controls[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", @@ -412,7 +411,7 @@ static struct snd_kcontrol_new juli_mute_controls[] __devinitdata = { }, }; -static char *slave_vols[] __devinitdata = { +static char *slave_vols[] = { PCM_VOLUME, MONITOR_AN_IN_VOLUME, MONITOR_DIG_IN_VOLUME, @@ -420,11 +419,11 @@ static char *slave_vols[] __devinitdata = { NULL }; -static __devinitdata +static DECLARE_TLV_DB_SCALE(juli_master_db_scale, -6350, 50, 1); -static struct snd_kcontrol __devinit *ctl_find(struct snd_card *card, - const char *name) +static struct snd_kcontrol *ctl_find(struct snd_card *card, + const char *name) { struct snd_ctl_elem_id sid; memset(&sid, 0, sizeof(sid)); @@ -434,8 +433,9 @@ static struct snd_kcontrol __devinit *ctl_find(struct snd_card *card, return snd_ctl_find_id(card, &sid); } -static void __devinit add_slaves(struct snd_card *card, - struct snd_kcontrol *master, char **list) +static void add_slaves(struct snd_card *card, + struct snd_kcontrol *master, + char * const *list) { for (; *list; list++) { struct snd_kcontrol *slave = ctl_find(card, *list); @@ -447,7 +447,7 @@ static void __devinit add_slaves(struct snd_card *card, } } -static int __devinit juli_add_controls(struct snd_ice1712 *ice) +static int juli_add_controls(struct snd_ice1712 *ice) { struct juli_spec *spec = ice->spec; int err; @@ -579,7 +579,7 @@ static void juli_ak4114_change(struct ak4114 *ak4114, unsigned char c0, } } -static int __devinit juli_init(struct snd_ice1712 *ice) +static int juli_init(struct snd_ice1712 *ice) { static const unsigned char ak4114_init_vals[] = { /* AK4117_REG_PWRDN */ AK4114_RST | AK4114_PWN | @@ -667,7 +667,7 @@ static int __devinit juli_init(struct snd_ice1712 *ice) * hence the driver needs to sets up it properly. */ -static unsigned char juli_eeprom[] __devinitdata = { +static unsigned char juli_eeprom[] = { [ICE_EEP2_SYSCONF] = 0x2b, /* clock 512, mpu401, 1xADC, 1xDACs, SPDIF in */ [ICE_EEP2_ACLINK] = 0x80, /* I2S */ @@ -686,7 +686,7 @@ static unsigned char juli_eeprom[] __devinitdata = { }; /* entry point */ -struct snd_ice1712_card_info snd_vt1724_juli_cards[] __devinitdata = { +struct snd_ice1712_card_info snd_vt1724_juli_cards[] = { { .subvendor = VT1724_SUBDEVICE_JULI, .name = "ESI Juli@", diff --git a/sound/pci/ice1712/maya44.c b/sound/pci/ice1712/maya44.c index 726fd4b92e19..63aa39f06f02 100644 --- a/sound/pci/ice1712/maya44.c +++ b/sound/pci/ice1712/maya44.c @@ -24,7 +24,6 @@ #include <linux/init.h> #include <linux/slab.h> -#include <linux/io.h> #include <sound/core.h> #include <sound/control.h> #include <sound/pcm.h> @@ -358,7 +357,7 @@ static void wm8776_select_input(struct snd_maya44 *chip, int idx, int line) static int maya_rec_src_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = { "Line", "Mic" }; + static const char * const texts[] = { "Line", "Mic" }; uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; @@ -407,7 +406,7 @@ static int maya_rec_src_put(struct snd_kcontrol *kcontrol, static int maya_pb_route_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = { + static const char * const texts[] = { "PCM Out", /* 0 */ "Input 1", "Input 2", "Input 3", "Input 4" }; @@ -455,7 +454,7 @@ static int maya_pb_route_put(struct snd_kcontrol *kcontrol, * controls to be added */ -static struct snd_kcontrol_new maya_controls[] __devinitdata = { +static struct snd_kcontrol_new maya_controls[] = { { .name = "Crossmix Playback Volume", .iface = SNDRV_CTL_ELEM_IFACE_MIXER, @@ -545,7 +544,7 @@ static struct snd_kcontrol_new maya_controls[] __devinitdata = { }, }; -static int __devinit maya44_add_controls(struct snd_ice1712 *ice) +static int maya44_add_controls(struct snd_ice1712 *ice) { int err, i; @@ -562,8 +561,8 @@ static int __devinit maya44_add_controls(struct snd_ice1712 *ice) /* * initialize a wm8776 chip */ -static void __devinit wm8776_init(struct snd_ice1712 *ice, - struct snd_wm8776 *wm, unsigned int addr) +static void wm8776_init(struct snd_ice1712 *ice, + struct snd_wm8776 *wm, unsigned int addr) { static const unsigned short inits_wm8776[] = { 0x02, 0x100, /* R2: headphone L+R muted + update */ @@ -693,14 +692,14 @@ static struct snd_pcm_hw_constraint_list dac_rates = { /* * chip addresses on I2C bus */ -static unsigned char wm8776_addr[2] __devinitdata = { +static unsigned char wm8776_addr[2] = { 0x34, 0x36, /* codec 0 & 1 */ }; /* * initialize the chip */ -static int __devinit maya44_init(struct snd_ice1712 *ice) +static int maya44_init(struct snd_ice1712 *ice) { int i; struct snd_maya44 *chip; @@ -743,7 +742,7 @@ static int __devinit maya44_init(struct snd_ice1712 *ice) * hence the driver needs to sets up it properly. */ -static unsigned char maya44_eeprom[] __devinitdata = { +static unsigned char maya44_eeprom[] = { [ICE_EEP2_SYSCONF] = 0x45, /* clock xin1=49.152MHz, mpu401, 2 stereo ADCs+DACs */ [ICE_EEP2_ACLINK] = 0x80, @@ -765,7 +764,7 @@ static unsigned char maya44_eeprom[] __devinitdata = { }; /* entry point */ -struct snd_ice1712_card_info snd_vt1724_maya44_cards[] __devinitdata = { +struct snd_ice1712_card_info snd_vt1724_maya44_cards[] = { { .subvendor = VT1724_SUBDEVICE_MAYA44, .name = "ESI Maya44", diff --git a/sound/pci/ice1712/phase.c b/sound/pci/ice1712/phase.c index de29be8c9657..0011e04f36a2 100644 --- a/sound/pci/ice1712/phase.c +++ b/sound/pci/ice1712/phase.c @@ -42,7 +42,6 @@ * Digital receiver: CS8414-CS (supported in this release) */ -#include <asm/io.h> #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/init.h> @@ -103,13 +102,13 @@ static const unsigned char wm_vol[256] = { #define WM_VOL_MAX (sizeof(wm_vol) - 1) #define WM_VOL_MUTE 0x8000 -static struct snd_akm4xxx akm_phase22 __devinitdata = { +static struct snd_akm4xxx akm_phase22 = { .type = SND_AK4524, .num_dacs = 2, .num_adcs = 2, }; -static struct snd_ak4xxx_private akm_phase22_priv __devinitdata = { +static struct snd_ak4xxx_private akm_phase22_priv = { .caddr = 2, .cif = 1, .data_mask = 1 << 4, @@ -121,7 +120,7 @@ static struct snd_ak4xxx_private akm_phase22_priv __devinitdata = { .mask_flags = 0, }; -static int __devinit phase22_init(struct snd_ice1712 *ice) +static int phase22_init(struct snd_ice1712 *ice) { struct snd_akm4xxx *ak; int err; @@ -158,7 +157,7 @@ static int __devinit phase22_init(struct snd_ice1712 *ice) return 0; } -static int __devinit phase22_add_controls(struct snd_ice1712 *ice) +static int phase22_add_controls(struct snd_ice1712 *ice) { int err = 0; @@ -172,7 +171,7 @@ static int __devinit phase22_add_controls(struct snd_ice1712 *ice) return 0; } -static unsigned char phase22_eeprom[] __devinitdata = { +static unsigned char phase22_eeprom[] = { [ICE_EEP2_SYSCONF] = 0x28, /* clock 512, mpu 401, spdif-in/1xADC, 1xDACs */ [ICE_EEP2_ACLINK] = 0x80, /* I2S */ @@ -189,7 +188,7 @@ static unsigned char phase22_eeprom[] __devinitdata = { [ICE_EEP2_GPIO_STATE2] = 0x00, }; -static unsigned char phase28_eeprom[] __devinitdata = { +static unsigned char phase28_eeprom[] = { [ICE_EEP2_SYSCONF] = 0x2b, /* clock 512, mpu401, spdif-in/1xADC, 4xDACs */ [ICE_EEP2_ACLINK] = 0x80, /* I2S */ @@ -379,7 +378,7 @@ static int wm_master_vol_put(struct snd_kcontrol *kcontrol, return change; } -static int __devinit phase28_init(struct snd_ice1712 *ice) +static int phase28_init(struct snd_ice1712 *ice) { static const unsigned short wm_inits_phase28[] = { /* These come first to reduce init pop noise */ @@ -722,7 +721,7 @@ static int phase28_deemp_put(struct snd_kcontrol *kcontrol, static int phase28_oversampling_info(struct snd_kcontrol *k, struct snd_ctl_elem_info *uinfo) { - static char *texts[2] = { "128x", "64x" }; + static const char * const texts[2] = { "128x", "64x" }; uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; @@ -770,7 +769,7 @@ static int phase28_oversampling_put(struct snd_kcontrol *kcontrol, static const DECLARE_TLV_DB_SCALE(db_scale_wm_dac, -12700, 100, 1); static const DECLARE_TLV_DB_SCALE(db_scale_wm_pcm, -6400, 50, 1); -static struct snd_kcontrol_new phase28_dac_controls[] __devinitdata = { +static struct snd_kcontrol_new phase28_dac_controls[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", @@ -885,7 +884,7 @@ static struct snd_kcontrol_new phase28_dac_controls[] __devinitdata = { } }; -static struct snd_kcontrol_new wm_controls[] __devinitdata = { +static struct snd_kcontrol_new wm_controls[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "PCM Playback Switch", @@ -919,7 +918,7 @@ static struct snd_kcontrol_new wm_controls[] __devinitdata = { } }; -static int __devinit phase28_add_controls(struct snd_ice1712 *ice) +static int phase28_add_controls(struct snd_ice1712 *ice) { unsigned int i, counts; int err; @@ -943,7 +942,7 @@ static int __devinit phase28_add_controls(struct snd_ice1712 *ice) return 0; } -struct snd_ice1712_card_info snd_vt1724_phase_cards[] __devinitdata = { +struct snd_ice1712_card_info snd_vt1724_phase_cards[] = { { .subvendor = VT1724_SUBDEVICE_PHASE22, .name = "Terratec PHASE 22", diff --git a/sound/pci/ice1712/pontis.c b/sound/pci/ice1712/pontis.c index 92c1160d7ab5..5555eb4b2400 100644 --- a/sound/pci/ice1712/pontis.c +++ b/sound/pci/ice1712/pontis.c @@ -21,7 +21,6 @@ * */ -#include <asm/io.h> #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/init.h> @@ -550,7 +549,7 @@ static const DECLARE_TLV_DB_SCALE(db_scale_volume, -6400, 50, 1); * mixers */ -static struct snd_kcontrol_new pontis_controls[] __devinitdata = { +static struct snd_kcontrol_new pontis_controls[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | @@ -697,7 +696,7 @@ static void cs_proc_init(struct snd_ice1712 *ice) } -static int __devinit pontis_add_controls(struct snd_ice1712 *ice) +static int pontis_add_controls(struct snd_ice1712 *ice) { unsigned int i; int err; @@ -718,7 +717,7 @@ static int __devinit pontis_add_controls(struct snd_ice1712 *ice) /* * initialize the chip */ -static int __devinit pontis_init(struct snd_ice1712 *ice) +static int pontis_init(struct snd_ice1712 *ice) { static const unsigned short wm_inits[] = { /* These come first to reduce init pop noise */ @@ -805,7 +804,7 @@ static int __devinit pontis_init(struct snd_ice1712 *ice) * hence the driver needs to sets up it properly. */ -static unsigned char pontis_eeprom[] __devinitdata = { +static unsigned char pontis_eeprom[] = { [ICE_EEP2_SYSCONF] = 0x08, /* clock 256, mpu401, spdif-in/ADC, 1DAC */ [ICE_EEP2_ACLINK] = 0x80, /* I2S */ [ICE_EEP2_I2S] = 0xf8, /* vol, 96k, 24bit, 192k */ @@ -822,7 +821,7 @@ static unsigned char pontis_eeprom[] __devinitdata = { }; /* entry point */ -struct snd_ice1712_card_info snd_vt1720_pontis_cards[] __devinitdata = { +struct snd_ice1712_card_info snd_vt1720_pontis_cards[] = { { .subvendor = VT1720_SUBDEVICE_PONTIS_MS300, .name = "Pontis MS300", diff --git a/sound/pci/ice1712/prodigy192.c b/sound/pci/ice1712/prodigy192.c index e36ddb94c382..e610339f7601 100644 --- a/sound/pci/ice1712/prodigy192.c +++ b/sound/pci/ice1712/prodigy192.c @@ -54,7 +54,6 @@ * */ -#include <asm/io.h> #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/init.h> @@ -283,7 +282,7 @@ static int stac9460_adc_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_el static int stac9460_mic_sw_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[2] = { "Line In", "Mic" }; + static const char * const texts[2] = { "Line In", "Mic" }; uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; @@ -369,7 +368,7 @@ static const DECLARE_TLV_DB_SCALE(db_scale_adc, 0, 150, 0); * mixers */ -static struct snd_kcontrol_new stac_controls[] __devinitdata = { +static struct snd_kcontrol_new stac_controls[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", @@ -562,7 +561,7 @@ static unsigned char prodigy192_ak4114_read(void *private_data, static int ak4114_input_sw_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[2] = { "Toslink", "Coax" }; + static const char * const texts[2] = { "Toslink", "Coax" }; uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; @@ -607,7 +606,7 @@ static int ak4114_input_sw_put(struct snd_kcontrol *kcontrol, } -static struct snd_kcontrol_new ak4114_controls[] __devinitdata = { +static struct snd_kcontrol_new ak4114_controls[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "MIODIO IEC958 Capture Input", @@ -672,7 +671,7 @@ static void stac9460_proc_init(struct snd_ice1712 *ice) } -static int __devinit prodigy192_add_controls(struct snd_ice1712 *ice) +static int prodigy192_add_controls(struct snd_ice1712 *ice) { struct prodigy192_spec *spec = ice->spec; unsigned int i; @@ -728,7 +727,7 @@ static int prodigy192_miodio_exists(struct snd_ice1712 *ice) /* * initialize the chip */ -static int __devinit prodigy192_init(struct snd_ice1712 *ice) +static int prodigy192_init(struct snd_ice1712 *ice) { static const unsigned short stac_inits_prodigy[] = { STAC946X_RESET, 0, @@ -784,7 +783,7 @@ static int __devinit prodigy192_init(struct snd_ice1712 *ice) * hence the driver needs to sets up it properly. */ -static unsigned char prodigy71_eeprom[] __devinitdata = { +static unsigned char prodigy71_eeprom[] = { [ICE_EEP2_SYSCONF] = 0x6a, /* 49MHz crystal, mpu401, * spdif-in+ 1 stereo ADC, * 3 stereo DACs @@ -808,7 +807,7 @@ static unsigned char prodigy71_eeprom[] __devinitdata = { /* entry point */ -struct snd_ice1712_card_info snd_vt1724_prodigy192_cards[] __devinitdata = { +struct snd_ice1712_card_info snd_vt1724_prodigy192_cards[] = { { .subvendor = VT1724_SUBDEVICE_PRODIGY192VE, .name = "Audiotrak Prodigy 192", diff --git a/sound/pci/ice1712/prodigy_hifi.c b/sound/pci/ice1712/prodigy_hifi.c index 7bf093c51ce5..2261d1e49150 100644 --- a/sound/pci/ice1712/prodigy_hifi.c +++ b/sound/pci/ice1712/prodigy_hifi.c @@ -25,7 +25,6 @@ */ -#include <asm/io.h> #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/init.h> @@ -299,7 +298,7 @@ static int ak4396_dac_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem static const DECLARE_TLV_DB_SCALE(db_scale_wm_dac, -12700, 100, 1); static const DECLARE_TLV_DB_LINEAR(ak4396_db_scale, TLV_DB_GAIN_MUTE, 0); -static struct snd_kcontrol_new prodigy_hd2_controls[] __devinitdata = { +static struct snd_kcontrol_new prodigy_hd2_controls[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | @@ -782,7 +781,7 @@ static int wm_chswap_put(struct snd_kcontrol *kcontrol, * mixers */ -static struct snd_kcontrol_new prodigy_hifi_controls[] __devinitdata = { +static struct snd_kcontrol_new prodigy_hifi_controls[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | @@ -939,7 +938,7 @@ static void wm_proc_init(struct snd_ice1712 *ice) } } -static int __devinit prodigy_hifi_add_controls(struct snd_ice1712 *ice) +static int prodigy_hifi_add_controls(struct snd_ice1712 *ice) { unsigned int i; int err; @@ -956,7 +955,7 @@ static int __devinit prodigy_hifi_add_controls(struct snd_ice1712 *ice) return 0; } -static int __devinit prodigy_hd2_add_controls(struct snd_ice1712 *ice) +static int prodigy_hd2_add_controls(struct snd_ice1712 *ice) { unsigned int i; int err; @@ -977,7 +976,7 @@ static int __devinit prodigy_hd2_add_controls(struct snd_ice1712 *ice) /* * initialize the chip */ -static int __devinit prodigy_hifi_init(struct snd_ice1712 *ice) +static int prodigy_hifi_init(struct snd_ice1712 *ice) { static unsigned short wm_inits[] = { /* These come first to reduce init pop noise */ @@ -1115,7 +1114,7 @@ static int prodigy_hd2_resume(struct snd_ice1712 *ice) } #endif -static int __devinit prodigy_hd2_init(struct snd_ice1712 *ice) +static int prodigy_hd2_init(struct snd_ice1712 *ice) { struct prodigy_hifi_spec *spec; @@ -1152,7 +1151,7 @@ static int __devinit prodigy_hd2_init(struct snd_ice1712 *ice) } -static unsigned char prodigy71hifi_eeprom[] __devinitdata = { +static unsigned char prodigy71hifi_eeprom[] = { 0x4b, /* SYSCONF: clock 512, spdif-in/ADC, 4DACs */ 0x80, /* ACLINK: I2S */ 0xfc, /* I2S: vol, 96k, 24bit, 192k */ @@ -1168,7 +1167,7 @@ static unsigned char prodigy71hifi_eeprom[] __devinitdata = { 0x00, /* GPIO_STATE2 */ }; -static unsigned char prodigyhd2_eeprom[] __devinitdata = { +static unsigned char prodigyhd2_eeprom[] = { 0x4b, /* SYSCONF: clock 512, spdif-in/ADC, 4DACs */ 0x80, /* ACLINK: I2S */ 0xfc, /* I2S: vol, 96k, 24bit, 192k */ @@ -1184,7 +1183,7 @@ static unsigned char prodigyhd2_eeprom[] __devinitdata = { 0x00, /* GPIO_STATE2 */ }; -static unsigned char fortissimo4_eeprom[] __devinitdata = { +static unsigned char fortissimo4_eeprom[] = { 0x43, /* SYSCONF: clock 512, ADC, 4DACs */ 0x80, /* ACLINK: I2S */ 0xfc, /* I2S: vol, 96k, 24bit, 192k */ @@ -1201,7 +1200,7 @@ static unsigned char fortissimo4_eeprom[] __devinitdata = { }; /* entry point */ -struct snd_ice1712_card_info snd_vt1724_prodigy_hifi_cards[] __devinitdata = { +struct snd_ice1712_card_info snd_vt1724_prodigy_hifi_cards[] = { { .subvendor = VT1724_SUBDEVICE_PRODIGY_HIFI, .name = "Audiotrak Prodigy 7.1 HiFi", diff --git a/sound/pci/ice1712/psc724.c b/sound/pci/ice1712/psc724.c new file mode 100644 index 000000000000..302ac6ddd545 --- /dev/null +++ b/sound/pci/ice1712/psc724.c @@ -0,0 +1,464 @@ +/* + * ALSA driver for ICEnsemble VT1724 (Envy24HT) + * + * Lowlevel functions for Philips PSC724 Ultimate Edge + * + * Copyright (c) 2012 Ondrej Zary <linux@rainbow-software.org> + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <sound/core.h> + +#include "ice1712.h" +#include "envy24ht.h" +#include "psc724.h" +#include "wm8766.h" +#include "wm8776.h" + +struct psc724_spec { + struct snd_wm8766 wm8766; + struct snd_wm8776 wm8776; + bool mute_all, jack_detect; + struct snd_ice1712 *ice; + struct delayed_work hp_work; + bool hp_connected; +}; + +/****************************************************************************/ +/* PHILIPS PSC724 ULTIMATE EDGE */ +/****************************************************************************/ +/* + * VT1722 (Envy24GT) - 6 outputs, 4 inputs (only 2 used), 24-bit/96kHz + * + * system configuration ICE_EEP2_SYSCONF=0x42 + * XIN1 49.152MHz + * no MPU401 + * one stereo ADC, no S/PDIF receiver + * three stereo DACs (FRONT, REAR, CENTER+LFE) + * + * AC-Link configuration ICE_EEP2_ACLINK=0x80 + * use I2S, not AC97 + * + * I2S converters feature ICE_EEP2_I2S=0x30 + * I2S codec has no volume/mute control feature (bug!) + * I2S codec does not support 96KHz or 192KHz (bug!) + * I2S codec 24bits + * + * S/PDIF configuration ICE_EEP2_SPDIF=0xc1 + * Enable integrated S/PDIF transmitter + * internal S/PDIF out implemented + * No S/PDIF input + * External S/PDIF out implemented + * + * + * ** connected chips ** + * + * WM8776 + * 2-channel DAC used for main output and stereo ADC (with 10-channel MUX) + * AIN1: LINE IN, AIN2: CD/VIDEO, AIN3: AUX, AIN4: Front MIC, AIN5: Rear MIC + * Controlled by I2C using VT1722 I2C interface: + * MODE (pin16) -- GND + * CE (pin17) -- GND I2C mode (address=0x34) + * DI (pin18) -- SDA (VT1722 pin70) + * CL (pin19) -- SCLK (VT1722 pin71) + * + * WM8766 + * 6-channel DAC used for rear & center/LFE outputs (only 4 channels used) + * Controlled by SPI using VT1722 GPIO pins: + * MODE (pin 1) -- GPIO19 (VT1722 pin99) + * ML/I2S (pin11) -- GPIO18 (VT1722 pin98) + * MC/IWL (pin12) -- GPIO17 (VT1722 pin97) + * MD/DM (pin13) -- GPIO16 (VT1722 pin96) + * MUTE (pin14) -- GPIO20 (VT1722 pin101) + * + * GPIO14 is used as input for headphone jack detection (1 = connected) + * GPIO22 is used as MUTE ALL output, grounding all 6 channels + * + * ** output pins and device names ** + * + * 5.1ch name -- output connector color -- device (-D option) + * + * FRONT 2ch -- green -- plughw:0,0 + * CENTER(Lch) SUBWOOFER(Rch) -- orange -- plughw:0,2,0 + * REAR 2ch -- black -- plughw:0,2,1 + */ + +/* codec access low-level functions */ + +#define GPIO_HP_JACK (1 << 14) +#define GPIO_MUTE_SUR (1 << 20) +#define GPIO_MUTE_ALL (1 << 22) + +#define JACK_INTERVAL 1000 + +#define PSC724_SPI_DELAY 1 + +#define PSC724_SPI_DATA (1 << 16) +#define PSC724_SPI_CLK (1 << 17) +#define PSC724_SPI_LOAD (1 << 18) +#define PSC724_SPI_MASK (PSC724_SPI_DATA | PSC724_SPI_CLK | PSC724_SPI_LOAD) + +static void psc724_wm8766_write(struct snd_wm8766 *wm, u16 addr, u16 data) +{ + struct psc724_spec *spec = container_of(wm, struct psc724_spec, wm8766); + struct snd_ice1712 *ice = spec->ice; + u32 st, bits; + int i; + + snd_ice1712_save_gpio_status(ice); + + st = ((addr & 0x7f) << 9) | (data & 0x1ff); + snd_ice1712_gpio_set_dir(ice, ice->gpio.direction | PSC724_SPI_MASK); + snd_ice1712_gpio_set_mask(ice, ice->gpio.write_mask & ~PSC724_SPI_MASK); + bits = snd_ice1712_gpio_read(ice) & ~PSC724_SPI_MASK; + snd_ice1712_gpio_write(ice, bits); + + for (i = 0; i < 16; i++) { + udelay(PSC724_SPI_DELAY); + bits &= ~PSC724_SPI_CLK; + /* MSB first */ + st <<= 1; + if (st & 0x10000) + bits |= PSC724_SPI_DATA; + else + bits &= ~PSC724_SPI_DATA; + snd_ice1712_gpio_write(ice, bits); + /* CLOCK high */ + udelay(PSC724_SPI_DELAY); + bits |= PSC724_SPI_CLK; + snd_ice1712_gpio_write(ice, bits); + } + /* LOAD high */ + udelay(PSC724_SPI_DELAY); + bits |= PSC724_SPI_LOAD; + snd_ice1712_gpio_write(ice, bits); + /* LOAD low, DATA and CLOCK high */ + udelay(PSC724_SPI_DELAY); + bits |= (PSC724_SPI_DATA | PSC724_SPI_CLK); + snd_ice1712_gpio_write(ice, bits); + + snd_ice1712_restore_gpio_status(ice); +} + +static void psc724_wm8776_write(struct snd_wm8776 *wm, u8 addr, u8 data) +{ + struct psc724_spec *spec = container_of(wm, struct psc724_spec, wm8776); + + snd_vt1724_write_i2c(spec->ice, 0x34, addr, data); +} + +/* mute all */ + +static void psc724_set_master_switch(struct snd_ice1712 *ice, bool on) +{ + unsigned int bits = snd_ice1712_gpio_read(ice); + struct psc724_spec *spec = ice->spec; + + spec->mute_all = !on; + if (on) + bits &= ~(GPIO_MUTE_ALL | GPIO_MUTE_SUR); + else + bits |= GPIO_MUTE_ALL | GPIO_MUTE_SUR; + snd_ice1712_gpio_write(ice, bits); +} + +static bool psc724_get_master_switch(struct snd_ice1712 *ice) +{ + struct psc724_spec *spec = ice->spec; + + return !spec->mute_all; +} + +/* jack detection */ + +static void psc724_set_jack_state(struct snd_ice1712 *ice, bool hp_connected) +{ + struct psc724_spec *spec = ice->spec; + struct snd_ctl_elem_id elem_id; + struct snd_kcontrol *kctl; + u16 power = spec->wm8776.regs[WM8776_REG_PWRDOWN] & ~WM8776_PWR_HPPD; + + psc724_set_master_switch(ice, !hp_connected); + if (!hp_connected) + power |= WM8776_PWR_HPPD; + snd_wm8776_set_power(&spec->wm8776, power); + spec->hp_connected = hp_connected; + /* notify about master speaker mute change */ + memset(&elem_id, 0, sizeof(elem_id)); + elem_id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; + strncpy(elem_id.name, "Master Speakers Playback Switch", + sizeof(elem_id.name)); + kctl = snd_ctl_find_id(ice->card, &elem_id); + snd_ctl_notify(ice->card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id); + /* and headphone mute change */ + strncpy(elem_id.name, spec->wm8776.ctl[WM8776_CTL_HP_SW].name, + sizeof(elem_id.name)); + kctl = snd_ctl_find_id(ice->card, &elem_id); + snd_ctl_notify(ice->card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id); +} + +static void psc724_update_hp_jack_state(struct work_struct *work) +{ + struct psc724_spec *spec = container_of(work, struct psc724_spec, + hp_work.work); + struct snd_ice1712 *ice = spec->ice; + bool hp_connected = snd_ice1712_gpio_read(ice) & GPIO_HP_JACK; + + schedule_delayed_work(&spec->hp_work, msecs_to_jiffies(JACK_INTERVAL)); + if (hp_connected == spec->hp_connected) + return; + psc724_set_jack_state(ice, hp_connected); +} + +static void psc724_set_jack_detection(struct snd_ice1712 *ice, bool on) +{ + struct psc724_spec *spec = ice->spec; + + if (spec->jack_detect == on) + return; + + spec->jack_detect = on; + if (on) { + bool hp_connected = snd_ice1712_gpio_read(ice) & GPIO_HP_JACK; + psc724_set_jack_state(ice, hp_connected); + schedule_delayed_work(&spec->hp_work, + msecs_to_jiffies(JACK_INTERVAL)); + } else + cancel_delayed_work_sync(&spec->hp_work); +} + +static bool psc724_get_jack_detection(struct snd_ice1712 *ice) +{ + struct psc724_spec *spec = ice->spec; + + return spec->jack_detect; +} + +/* mixer controls */ + +struct psc724_control { + const char *name; + void (*set)(struct snd_ice1712 *ice, bool on); + bool (*get)(struct snd_ice1712 *ice); +}; + +static const struct psc724_control psc724_cont[] = { + { + .name = "Master Speakers Playback Switch", + .set = psc724_set_master_switch, + .get = psc724_get_master_switch, + }, + { + .name = "Headphone Jack Detection Playback Switch", + .set = psc724_set_jack_detection, + .get = psc724_get_jack_detection, + }, +}; + +static int psc724_ctl_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); + int n = kcontrol->private_value; + + ucontrol->value.integer.value[0] = psc724_cont[n].get(ice); + + return 0; +} + +static int psc724_ctl_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); + int n = kcontrol->private_value; + + psc724_cont[n].set(ice, ucontrol->value.integer.value[0]); + + return 0; +} + +static const char *front_volume = "Front Playback Volume"; +static const char *front_switch = "Front Playback Switch"; +static const char *front_zc = "Front Zero Cross Detect Playback Switch"; +static const char *front_izd = "Front Infinite Zero Detect Playback Switch"; +static const char *front_phase = "Front Phase Invert Playback Switch"; +static const char *front_deemph = "Front Deemphasis Playback Switch"; +static const char *ain1_switch = "Line Capture Switch"; +static const char *ain2_switch = "CD Capture Switch"; +static const char *ain3_switch = "AUX Capture Switch"; +static const char *ain4_switch = "Front Mic Capture Switch"; +static const char *ain5_switch = "Rear Mic Capture Switch"; +static const char *rear_volume = "Surround Playback Volume"; +static const char *clfe_volume = "CLFE Playback Volume"; +static const char *rear_switch = "Surround Playback Switch"; +static const char *clfe_switch = "CLFE Playback Switch"; +static const char *rear_phase = "Surround Phase Invert Playback Switch"; +static const char *clfe_phase = "CLFE Phase Invert Playback Switch"; +static const char *rear_deemph = "Surround Deemphasis Playback Switch"; +static const char *clfe_deemph = "CLFE Deemphasis Playback Switch"; +static const char *rear_clfe_izd = "Rear Infinite Zero Detect Playback Switch"; +static const char *rear_clfe_zc = "Rear Zero Cross Detect Playback Switch"; + +static int psc724_add_controls(struct snd_ice1712 *ice) +{ + struct snd_kcontrol_new cont; + struct snd_kcontrol *ctl; + int err, i; + struct psc724_spec *spec = ice->spec; + + spec->wm8776.ctl[WM8776_CTL_DAC_VOL].name = front_volume; + spec->wm8776.ctl[WM8776_CTL_DAC_SW].name = front_switch; + spec->wm8776.ctl[WM8776_CTL_DAC_ZC_SW].name = front_zc; + spec->wm8776.ctl[WM8776_CTL_AUX_SW].name = NULL; + spec->wm8776.ctl[WM8776_CTL_DAC_IZD_SW].name = front_izd; + spec->wm8776.ctl[WM8776_CTL_PHASE_SW].name = front_phase; + spec->wm8776.ctl[WM8776_CTL_DEEMPH_SW].name = front_deemph; + spec->wm8776.ctl[WM8776_CTL_INPUT1_SW].name = ain1_switch; + spec->wm8776.ctl[WM8776_CTL_INPUT2_SW].name = ain2_switch; + spec->wm8776.ctl[WM8776_CTL_INPUT3_SW].name = ain3_switch; + spec->wm8776.ctl[WM8776_CTL_INPUT4_SW].name = ain4_switch; + spec->wm8776.ctl[WM8776_CTL_INPUT5_SW].name = ain5_switch; + snd_wm8776_build_controls(&spec->wm8776); + spec->wm8766.ctl[WM8766_CTL_CH1_VOL].name = rear_volume; + spec->wm8766.ctl[WM8766_CTL_CH2_VOL].name = clfe_volume; + spec->wm8766.ctl[WM8766_CTL_CH3_VOL].name = NULL; + spec->wm8766.ctl[WM8766_CTL_CH1_SW].name = rear_switch; + spec->wm8766.ctl[WM8766_CTL_CH2_SW].name = clfe_switch; + spec->wm8766.ctl[WM8766_CTL_CH3_SW].name = NULL; + spec->wm8766.ctl[WM8766_CTL_PHASE1_SW].name = rear_phase; + spec->wm8766.ctl[WM8766_CTL_PHASE2_SW].name = clfe_phase; + spec->wm8766.ctl[WM8766_CTL_PHASE3_SW].name = NULL; + spec->wm8766.ctl[WM8766_CTL_DEEMPH1_SW].name = rear_deemph; + spec->wm8766.ctl[WM8766_CTL_DEEMPH2_SW].name = clfe_deemph; + spec->wm8766.ctl[WM8766_CTL_DEEMPH3_SW].name = NULL; + spec->wm8766.ctl[WM8766_CTL_IZD_SW].name = rear_clfe_izd; + spec->wm8766.ctl[WM8766_CTL_ZC_SW].name = rear_clfe_zc; + snd_wm8766_build_controls(&spec->wm8766); + + memset(&cont, 0, sizeof(cont)); + cont.iface = SNDRV_CTL_ELEM_IFACE_MIXER; + for (i = 0; i < ARRAY_SIZE(psc724_cont); i++) { + cont.private_value = i; + cont.name = psc724_cont[i].name; + cont.access = SNDRV_CTL_ELEM_ACCESS_READWRITE; + cont.info = snd_ctl_boolean_mono_info; + cont.get = psc724_ctl_get; + cont.put = psc724_ctl_put; + ctl = snd_ctl_new1(&cont, ice); + if (!ctl) + return -ENOMEM; + err = snd_ctl_add(ice->card, ctl); + if (err < 0) + return err; + } + + return 0; +} + +static void psc724_set_pro_rate(struct snd_ice1712 *ice, unsigned int rate) +{ + struct psc724_spec *spec = ice->spec; + /* restore codec volume settings after rate change (PMCLK stop) */ + snd_wm8776_volume_restore(&spec->wm8776); + snd_wm8766_volume_restore(&spec->wm8766); +} + +/* power management */ + +#ifdef CONFIG_PM_SLEEP +static int psc724_resume(struct snd_ice1712 *ice) +{ + struct psc724_spec *spec = ice->spec; + + snd_wm8776_resume(&spec->wm8776); + snd_wm8766_resume(&spec->wm8766); + + return 0; +} +#endif + +/* init */ + +static int psc724_init(struct snd_ice1712 *ice) +{ + struct psc724_spec *spec; + + spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (!spec) + return -ENOMEM; + ice->spec = spec; + spec->ice = ice; + + ice->num_total_dacs = 6; + ice->num_total_adcs = 2; + spec->wm8776.ops.write = psc724_wm8776_write; + spec->wm8776.card = ice->card; + snd_wm8776_init(&spec->wm8776); + spec->wm8766.ops.write = psc724_wm8766_write; + spec->wm8766.card = ice->card; +#ifdef CONFIG_PM_SLEEP + ice->pm_resume = psc724_resume; + ice->pm_suspend_enabled = 1; +#endif + snd_wm8766_init(&spec->wm8766); + snd_wm8766_set_if(&spec->wm8766, + WM8766_IF_FMT_I2S | WM8766_IF_IWL_24BIT); + ice->gpio.set_pro_rate = psc724_set_pro_rate; + INIT_DELAYED_WORK(&spec->hp_work, psc724_update_hp_jack_state); + psc724_set_jack_detection(ice, true); + return 0; +} + +static void psc724_exit(struct snd_ice1712 *ice) +{ + struct psc724_spec *spec = ice->spec; + + cancel_delayed_work_sync(&spec->hp_work); +} + +/* PSC724 has buggy EEPROM (no 96&192kHz, all FFh GPIOs), so override it here */ +static unsigned char psc724_eeprom[] = { + [ICE_EEP2_SYSCONF] = 0x42, /* 49.152MHz, 1 ADC, 3 DACs */ + [ICE_EEP2_ACLINK] = 0x80, /* I2S */ + [ICE_EEP2_I2S] = 0xf0, /* I2S volume, 96kHz, 24bit */ + [ICE_EEP2_SPDIF] = 0xc1, /* spdif out-en, out-int, no input */ + /* GPIO outputs */ + [ICE_EEP2_GPIO_DIR2] = 0x5f, /* MUTE_ALL,WM8766 MUTE/MODE/ML/MC/MD */ + /* GPIO write enable */ + [ICE_EEP2_GPIO_MASK] = 0xff, /* read-only */ + [ICE_EEP2_GPIO_MASK1] = 0xff, /* read-only */ + [ICE_EEP2_GPIO_MASK2] = 0xa0, /* MUTE_ALL,WM8766 MUTE/MODE/ML/MC/MD */ + /* GPIO initial state */ + [ICE_EEP2_GPIO_STATE2] = 0x20, /* unmuted, all WM8766 pins low */ +}; + +struct snd_ice1712_card_info snd_vt1724_psc724_cards[] = { + { + .subvendor = VT1724_SUBDEVICE_PSC724, + .name = "Philips PSC724 Ultimate Edge", + .model = "psc724", + .chip_init = psc724_init, + .chip_exit = psc724_exit, + .build_controls = psc724_add_controls, + .eeprom_size = sizeof(psc724_eeprom), + .eeprom_data = psc724_eeprom, + }, + {} /*terminator*/ +}; diff --git a/sound/pci/ice1712/psc724.h b/sound/pci/ice1712/psc724.h new file mode 100644 index 000000000000..858e5fd0eebb --- /dev/null +++ b/sound/pci/ice1712/psc724.h @@ -0,0 +1,13 @@ +#ifndef __SOUND_PSC724_H +#define __SOUND_PSC724_H + +/* ID */ +#define PSC724_DEVICE_DESC \ + "{Philips,PSC724 Ultimate Edge}," + +#define VT1724_SUBDEVICE_PSC724 0xab170619 + +/* entry struct */ +extern struct snd_ice1712_card_info snd_vt1724_psc724_cards[]; + +#endif /* __SOUND_PSC724_H */ diff --git a/sound/pci/ice1712/quartet.c b/sound/pci/ice1712/quartet.c index 1948632787e6..975e0357bd5a 100644 --- a/sound/pci/ice1712/quartet.c +++ b/sound/pci/ice1712/quartet.c @@ -22,7 +22,6 @@ * */ -#include <asm/io.h> #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/init.h> @@ -47,7 +46,7 @@ struct qtet_kcontrol_private { unsigned int bit; void (*set_register)(struct snd_ice1712 *ice, unsigned int val); unsigned int (*get_register)(struct snd_ice1712 *ice); - unsigned char *texts[2]; + unsigned char * const texts[2]; }; enum { @@ -63,7 +62,7 @@ enum { OUT34_MON12, }; -static char *ext_clock_names[3] = {"IEC958 In", "Word Clock 1xFS", +static const char * const ext_clock_names[3] = {"IEC958 In", "Word Clock 1xFS", "Word Clock 256xFS"}; /* chip address on I2C bus */ @@ -387,7 +386,7 @@ static const struct snd_akm4xxx_adc_channel qtet_adc[] = { AK_CONTROL(PCM_34_CAPTURE_VOLUME, 2), }; -static struct snd_akm4xxx akm_qtet_dac __devinitdata = { +static struct snd_akm4xxx akm_qtet_dac = { .type = SND_AK4620, .num_dacs = 4, /* DAC1 - Output 12 */ @@ -551,7 +550,8 @@ static int qtet_mute_put(struct snd_kcontrol *kcontrol, static int qtet_ain12_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[3] = {"Line In 1/2", "Mic", "Mic + Low-cut"}; + static const char * const texts[3] = + {"Line In 1/2", "Mic", "Mic + Low-cut"}; uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; uinfo->value.enumerated.items = ARRAY_SIZE(texts); @@ -758,7 +758,7 @@ static int qtet_sw_put(struct snd_kcontrol *kcontrol, .put = qtet_sw_put,\ .private_value = xpriv } -static struct snd_kcontrol_new qtet_controls[] __devinitdata = { +static struct snd_kcontrol_new qtet_controls[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", @@ -795,17 +795,17 @@ static struct snd_kcontrol_new qtet_controls[] __devinitdata = { QTET_CONTROL("Output 3/4 to Monitor 1/2", sw, OUT34_MON12), }; -static char *slave_vols[] __devinitdata = { +static char *slave_vols[] = { PCM_12_PLAYBACK_VOLUME, PCM_34_PLAYBACK_VOLUME, NULL }; -static __devinitdata +static DECLARE_TLV_DB_SCALE(qtet_master_db_scale, -6350, 50, 1); -static struct snd_kcontrol __devinit *ctl_find(struct snd_card *card, - const char *name) +static struct snd_kcontrol *ctl_find(struct snd_card *card, + const char *name) { struct snd_ctl_elem_id sid; memset(&sid, 0, sizeof(sid)); @@ -815,8 +815,8 @@ static struct snd_kcontrol __devinit *ctl_find(struct snd_card *card, return snd_ctl_find_id(card, &sid); } -static void __devinit add_slaves(struct snd_card *card, - struct snd_kcontrol *master, char **list) +static void add_slaves(struct snd_card *card, + struct snd_kcontrol *master, char * const *list) { for (; *list; list++) { struct snd_kcontrol *slave = ctl_find(card, *list); @@ -825,7 +825,7 @@ static void __devinit add_slaves(struct snd_card *card, } } -static int __devinit qtet_add_controls(struct snd_ice1712 *ice) +static int qtet_add_controls(struct snd_ice1712 *ice) { struct qtet_spec *spec = ice->spec; int err, i; @@ -1007,7 +1007,7 @@ static void qtet_spdif_in_open(struct snd_ice1712 *ice, /* * initialize the chip */ -static int __devinit qtet_init(struct snd_ice1712 *ice) +static int qtet_init(struct snd_ice1712 *ice) { static const unsigned char ak4113_init_vals[] = { /* AK4113_REG_PWRDN */ AK4113_RST | AK4113_PWN | @@ -1095,7 +1095,7 @@ static int __devinit qtet_init(struct snd_ice1712 *ice) return 0; } -static unsigned char qtet_eeprom[] __devinitdata = { +static unsigned char qtet_eeprom[] = { [ICE_EEP2_SYSCONF] = 0x28, /* clock 256(24MHz), mpu401, 1xADC, 1xDACs, SPDIF in */ [ICE_EEP2_ACLINK] = 0x80, /* I2S */ @@ -1116,7 +1116,7 @@ static unsigned char qtet_eeprom[] __devinitdata = { }; /* entry point */ -struct snd_ice1712_card_info snd_vt1724_qtet_cards[] __devinitdata = { +struct snd_ice1712_card_info snd_vt1724_qtet_cards[] = { { .subvendor = VT1724_SUBDEVICE_QTET, .name = "Infrasonic Quartet", diff --git a/sound/pci/ice1712/revo.c b/sound/pci/ice1712/revo.c index b508bb360b97..7641080a9b5d 100644 --- a/sound/pci/ice1712/revo.c +++ b/sound/pci/ice1712/revo.c @@ -21,7 +21,6 @@ * */ -#include <asm/io.h> #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/init.h> @@ -235,7 +234,7 @@ static const struct snd_akm4xxx_adc_channel revo51_adc[] = { }, }; -static struct snd_akm4xxx akm_revo_front __devinitdata = { +static struct snd_akm4xxx akm_revo_front = { .type = SND_AK4381, .num_dacs = 2, .ops = { @@ -244,7 +243,7 @@ static struct snd_akm4xxx akm_revo_front __devinitdata = { .dac_info = revo71_front, }; -static struct snd_ak4xxx_private akm_revo_front_priv __devinitdata = { +static struct snd_ak4xxx_private akm_revo_front_priv = { .caddr = 1, .cif = 0, .data_mask = VT1724_REVO_CDOUT, @@ -256,7 +255,7 @@ static struct snd_ak4xxx_private akm_revo_front_priv __devinitdata = { .mask_flags = 0, }; -static struct snd_akm4xxx akm_revo_surround __devinitdata = { +static struct snd_akm4xxx akm_revo_surround = { .type = SND_AK4355, .idx_offset = 1, .num_dacs = 6, @@ -266,7 +265,7 @@ static struct snd_akm4xxx akm_revo_surround __devinitdata = { .dac_info = revo71_surround, }; -static struct snd_ak4xxx_private akm_revo_surround_priv __devinitdata = { +static struct snd_ak4xxx_private akm_revo_surround_priv = { .caddr = 3, .cif = 0, .data_mask = VT1724_REVO_CDOUT, @@ -278,7 +277,7 @@ static struct snd_ak4xxx_private akm_revo_surround_priv __devinitdata = { .mask_flags = 0, }; -static struct snd_akm4xxx akm_revo51 __devinitdata = { +static struct snd_akm4xxx akm_revo51 = { .type = SND_AK4358, .num_dacs = 8, .ops = { @@ -287,7 +286,7 @@ static struct snd_akm4xxx akm_revo51 __devinitdata = { .dac_info = revo51_dac, }; -static struct snd_ak4xxx_private akm_revo51_priv __devinitdata = { +static struct snd_ak4xxx_private akm_revo51_priv = { .caddr = 2, .cif = 0, .data_mask = VT1724_REVO_CDOUT, @@ -299,13 +298,13 @@ static struct snd_ak4xxx_private akm_revo51_priv __devinitdata = { .mask_flags = 0, }; -static struct snd_akm4xxx akm_revo51_adc __devinitdata = { +static struct snd_akm4xxx akm_revo51_adc = { .type = SND_AK5365, .num_adcs = 2, .adc_info = revo51_adc, }; -static struct snd_ak4xxx_private akm_revo51_adc_priv __devinitdata = { +static struct snd_ak4xxx_private akm_revo51_adc_priv = { .caddr = 2, .cif = 0, .data_mask = VT1724_REVO_CDOUT, @@ -346,7 +345,7 @@ static const struct snd_akm4xxx_dac_channel ap192_dac[] = { AK_DAC("PCM Playback Volume", 2) }; -static struct snd_akm4xxx akm_ap192 __devinitdata = { +static struct snd_akm4xxx akm_ap192 = { .type = SND_AK4358, .num_dacs = 2, .ops = { @@ -355,7 +354,7 @@ static struct snd_akm4xxx akm_ap192 __devinitdata = { .dac_info = ap192_dac, }; -static struct snd_ak4xxx_private akm_ap192_priv __devinitdata = { +static struct snd_ak4xxx_private akm_ap192_priv = { .caddr = 2, .cif = 0, .data_mask = VT1724_REVO_CDOUT, @@ -468,7 +467,7 @@ static unsigned char ap192_ak4114_read(void *private_data, unsigned char addr) return data; } -static int __devinit ap192_ak4114_init(struct snd_ice1712 *ice) +static int ap192_ak4114_init(struct snd_ice1712 *ice) { static const unsigned char ak4114_init_vals[] = { AK4114_RST | AK4114_PWN | AK4114_OCKS0 | AK4114_OCKS1, @@ -496,7 +495,7 @@ static int __devinit ap192_ak4114_init(struct snd_ice1712 *ice) return 0; /* error ignored; it's no fatal error */ } -static int __devinit revo_init(struct snd_ice1712 *ice) +static int revo_init(struct snd_ice1712 *ice) { struct snd_akm4xxx *ak; int err; @@ -574,7 +573,7 @@ static int __devinit revo_init(struct snd_ice1712 *ice) } -static int __devinit revo_add_controls(struct snd_ice1712 *ice) +static int revo_add_controls(struct snd_ice1712 *ice) { struct revo51_spec *spec; int err; @@ -607,7 +606,7 @@ static int __devinit revo_add_controls(struct snd_ice1712 *ice) } /* entry point */ -struct snd_ice1712_card_info snd_vt1724_revo_cards[] __devinitdata = { +struct snd_ice1712_card_info snd_vt1724_revo_cards[] = { { .subvendor = VT1724_SUBDEVICE_REVOLUTION71, .name = "M Audio Revolution-7.1", diff --git a/sound/pci/ice1712/se.c b/sound/pci/ice1712/se.c index 69673b95869d..ffd894bb4507 100644 --- a/sound/pci/ice1712/se.c +++ b/sound/pci/ice1712/se.c @@ -22,7 +22,6 @@ * */ -#include <asm/io.h> #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/init.h> @@ -114,7 +113,7 @@ struct se_spec { /* WM8740 interface */ /****************************************************************************/ -static void __devinit se200pci_WM8740_init(struct snd_ice1712 *ice) +static void se200pci_WM8740_init(struct snd_ice1712 *ice) { /* nothing to do */ } @@ -196,7 +195,7 @@ static void se200pci_WM8766_set_volume(struct snd_ice1712 *ice, int ch, } } -static void __devinit se200pci_WM8766_init(struct snd_ice1712 *ice) +static void se200pci_WM8766_init(struct snd_ice1712 *ice) { se200pci_WM8766_write(ice, 0x1f, 0x000); /* RESET ALL */ udelay(10); @@ -253,7 +252,7 @@ static void se200pci_WM8776_set_input_volume(struct snd_ice1712 *ice, se200pci_WM8776_write(ice, 0x0f, vol2 | 0x100); } -static const char *se200pci_sel[] = { +static const char * const se200pci_sel[] = { "LINE-IN", "CD-IN", "MIC-IN", "ALL-MIX", NULL }; @@ -278,7 +277,7 @@ static void se200pci_WM8776_set_afl(struct snd_ice1712 *ice, unsigned int afl) se200pci_WM8776_write(ice, 0x16, 0x001); } -static const char *se200pci_agc[] = { +static const char * const se200pci_agc[] = { "Off", "LimiterMode", "ALCMode", NULL }; @@ -300,10 +299,10 @@ static void se200pci_WM8776_set_agc(struct snd_ice1712 *ice, unsigned int agc) } } -static void __devinit se200pci_WM8776_init(struct snd_ice1712 *ice) +static void se200pci_WM8776_init(struct snd_ice1712 *ice) { int i; - static unsigned short __devinitdata default_values[] = { + static unsigned short default_values[] = { 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x000, 0x090, 0x000, 0x000, @@ -352,7 +351,7 @@ static void se200pci_set_pro_rate(struct snd_ice1712 *ice, unsigned int rate) } struct se200pci_control { - char *name; + const char *name; enum { WM8766, WM8776in, @@ -363,7 +362,7 @@ struct se200pci_control { } target; enum { VOLUME1, VOLUME2, BOOLEAN, ENUM } type; int ch; - const char **member; + const char * const *member; const char *comment; }; @@ -421,7 +420,7 @@ static const struct se200pci_control se200pci_cont[] = { static int se200pci_get_enum_count(int n) { - const char **member; + const char * const *member; int c; member = se200pci_cont[n].member; @@ -600,7 +599,7 @@ static int se200pci_cont_enum_put(struct snd_kcontrol *kc, static const DECLARE_TLV_DB_SCALE(db_scale_gain1, -12750, 50, 1); static const DECLARE_TLV_DB_SCALE(db_scale_gain2, -10350, 50, 1); -static int __devinit se200pci_add_controls(struct snd_ice1712 *ice) +static int se200pci_add_controls(struct snd_ice1712 *ice) { int i; struct snd_kcontrol_new cont; @@ -678,7 +677,7 @@ static int __devinit se200pci_add_controls(struct snd_ice1712 *ice) /* probe/initialize/setup */ /****************************************************************************/ -static int __devinit se_init(struct snd_ice1712 *ice) +static int se_init(struct snd_ice1712 *ice) { struct se_spec *spec; @@ -706,7 +705,7 @@ static int __devinit se_init(struct snd_ice1712 *ice) return -ENOENT; } -static int __devinit se_add_controls(struct snd_ice1712 *ice) +static int se_add_controls(struct snd_ice1712 *ice) { int err; @@ -723,7 +722,7 @@ static int __devinit se_add_controls(struct snd_ice1712 *ice) /* entry point */ /****************************************************************************/ -static unsigned char se200pci_eeprom[] __devinitdata = { +static unsigned char se200pci_eeprom[] = { [ICE_EEP2_SYSCONF] = 0x4b, /* 49.152Hz, spdif-in/ADC, 4DACs */ [ICE_EEP2_ACLINK] = 0x80, /* I2S */ [ICE_EEP2_I2S] = 0x78, /* 96k-ok, 24bit, 192k-ok */ @@ -742,7 +741,7 @@ static unsigned char se200pci_eeprom[] __devinitdata = { [ICE_EEP2_GPIO_STATE2] = 0x07, /* WM8766 ML/MC/MD */ }; -static unsigned char se90pci_eeprom[] __devinitdata = { +static unsigned char se90pci_eeprom[] = { [ICE_EEP2_SYSCONF] = 0x4b, /* 49.152Hz, spdif-in/ADC, 4DACs */ [ICE_EEP2_ACLINK] = 0x80, /* I2S */ [ICE_EEP2_I2S] = 0x78, /* 96k-ok, 24bit, 192k-ok */ @@ -751,7 +750,7 @@ static unsigned char se90pci_eeprom[] __devinitdata = { /* ALL GPIO bits are in input mode */ }; -struct snd_ice1712_card_info snd_vt1724_se_cards[] __devinitdata = { +struct snd_ice1712_card_info snd_vt1724_se_cards[] = { { .subvendor = VT1724_SUBDEVICE_SE200PCI, .name = "ONKYO SE200PCI", diff --git a/sound/pci/ice1712/vt1720_mobo.c b/sound/pci/ice1712/vt1720_mobo.c index 4c551e147c08..5dbb867e642c 100644 --- a/sound/pci/ice1712/vt1720_mobo.c +++ b/sound/pci/ice1712/vt1720_mobo.c @@ -21,7 +21,6 @@ * */ -#include <asm/io.h> #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/init.h> @@ -32,7 +31,7 @@ #include "vt1720_mobo.h" -static int __devinit k8x800_init(struct snd_ice1712 *ice) +static int k8x800_init(struct snd_ice1712 *ice) { ice->vt1720 = 1; @@ -46,7 +45,7 @@ static int __devinit k8x800_init(struct snd_ice1712 *ice) return 0; } -static int __devinit k8x800_add_controls(struct snd_ice1712 *ice) +static int k8x800_add_controls(struct snd_ice1712 *ice) { /* FIXME: needs some quirks for VT1616? */ return 0; @@ -54,7 +53,7 @@ static int __devinit k8x800_add_controls(struct snd_ice1712 *ice) /* EEPROM image */ -static unsigned char k8x800_eeprom[] __devinitdata = { +static unsigned char k8x800_eeprom[] = { [ICE_EEP2_SYSCONF] = 0x01, /* clock 256, 1ADC, 2DACs */ [ICE_EEP2_ACLINK] = 0x02, /* ACLINK, packed */ [ICE_EEP2_I2S] = 0x00, /* - */ @@ -70,7 +69,7 @@ static unsigned char k8x800_eeprom[] __devinitdata = { [ICE_EEP2_GPIO_STATE2] = 0x00, /* - */ }; -static unsigned char sn25p_eeprom[] __devinitdata = { +static unsigned char sn25p_eeprom[] = { [ICE_EEP2_SYSCONF] = 0x01, /* clock 256, 1ADC, 2DACs */ [ICE_EEP2_ACLINK] = 0x02, /* ACLINK, packed */ [ICE_EEP2_I2S] = 0x00, /* - */ @@ -88,7 +87,7 @@ static unsigned char sn25p_eeprom[] __devinitdata = { /* entry point */ -struct snd_ice1712_card_info snd_vt1720_mobo_cards[] __devinitdata = { +struct snd_ice1712_card_info snd_vt1720_mobo_cards[] = { { .subvendor = VT1720_SUBDEVICE_K8X800, .name = "Albatron K8X800 Pro II", diff --git a/sound/pci/ice1712/wm8766.c b/sound/pci/ice1712/wm8766.c new file mode 100644 index 000000000000..e473f8a88f9c --- /dev/null +++ b/sound/pci/ice1712/wm8766.c @@ -0,0 +1,361 @@ +/* + * ALSA driver for ICEnsemble VT17xx + * + * Lowlevel functions for WM8766 codec + * + * Copyright (c) 2012 Ondrej Zary <linux@rainbow-software.org> + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include <linux/delay.h> +#include <sound/core.h> +#include <sound/control.h> +#include <sound/tlv.h> +#include "wm8766.h" + +/* low-level access */ + +static void snd_wm8766_write(struct snd_wm8766 *wm, u16 addr, u16 data) +{ + if (addr < WM8766_REG_COUNT) + wm->regs[addr] = data; + wm->ops.write(wm, addr, data); +} + +/* mixer controls */ + +static const DECLARE_TLV_DB_SCALE(wm8766_tlv, -12750, 50, 1); + +static struct snd_wm8766_ctl snd_wm8766_default_ctl[WM8766_CTL_COUNT] = { + [WM8766_CTL_CH1_VOL] = { + .name = "Channel 1 Playback Volume", + .type = SNDRV_CTL_ELEM_TYPE_INTEGER, + .tlv = wm8766_tlv, + .reg1 = WM8766_REG_DACL1, + .reg2 = WM8766_REG_DACR1, + .mask1 = WM8766_VOL_MASK, + .mask2 = WM8766_VOL_MASK, + .max = 0xff, + .flags = WM8766_FLAG_STEREO | WM8766_FLAG_VOL_UPDATE, + }, + [WM8766_CTL_CH2_VOL] = { + .name = "Channel 2 Playback Volume", + .type = SNDRV_CTL_ELEM_TYPE_INTEGER, + .tlv = wm8766_tlv, + .reg1 = WM8766_REG_DACL2, + .reg2 = WM8766_REG_DACR2, + .mask1 = WM8766_VOL_MASK, + .mask2 = WM8766_VOL_MASK, + .max = 0xff, + .flags = WM8766_FLAG_STEREO | WM8766_FLAG_VOL_UPDATE, + }, + [WM8766_CTL_CH3_VOL] = { + .name = "Channel 3 Playback Volume", + .type = SNDRV_CTL_ELEM_TYPE_INTEGER, + .tlv = wm8766_tlv, + .reg1 = WM8766_REG_DACL3, + .reg2 = WM8766_REG_DACR3, + .mask1 = WM8766_VOL_MASK, + .mask2 = WM8766_VOL_MASK, + .max = 0xff, + .flags = WM8766_FLAG_STEREO | WM8766_FLAG_VOL_UPDATE, + }, + [WM8766_CTL_CH1_SW] = { + .name = "Channel 1 Playback Switch", + .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN, + .reg1 = WM8766_REG_DACCTRL2, + .mask1 = WM8766_DAC2_MUTE1, + .flags = WM8766_FLAG_INVERT, + }, + [WM8766_CTL_CH2_SW] = { + .name = "Channel 2 Playback Switch", + .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN, + .reg1 = WM8766_REG_DACCTRL2, + .mask1 = WM8766_DAC2_MUTE2, + .flags = WM8766_FLAG_INVERT, + }, + [WM8766_CTL_CH3_SW] = { + .name = "Channel 3 Playback Switch", + .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN, + .reg1 = WM8766_REG_DACCTRL2, + .mask1 = WM8766_DAC2_MUTE3, + .flags = WM8766_FLAG_INVERT, + }, + [WM8766_CTL_PHASE1_SW] = { + .name = "Channel 1 Phase Invert Playback Switch", + .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN, + .reg1 = WM8766_REG_IFCTRL, + .mask1 = WM8766_PHASE_INVERT1, + }, + [WM8766_CTL_PHASE2_SW] = { + .name = "Channel 2 Phase Invert Playback Switch", + .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN, + .reg1 = WM8766_REG_IFCTRL, + .mask1 = WM8766_PHASE_INVERT2, + }, + [WM8766_CTL_PHASE3_SW] = { + .name = "Channel 3 Phase Invert Playback Switch", + .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN, + .reg1 = WM8766_REG_IFCTRL, + .mask1 = WM8766_PHASE_INVERT3, + }, + [WM8766_CTL_DEEMPH1_SW] = { + .name = "Channel 1 Deemphasis Playback Switch", + .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN, + .reg1 = WM8766_REG_DACCTRL2, + .mask1 = WM8766_DAC2_DEEMP1, + }, + [WM8766_CTL_DEEMPH2_SW] = { + .name = "Channel 2 Deemphasis Playback Switch", + .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN, + .reg1 = WM8766_REG_DACCTRL2, + .mask1 = WM8766_DAC2_DEEMP2, + }, + [WM8766_CTL_DEEMPH3_SW] = { + .name = "Channel 3 Deemphasis Playback Switch", + .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN, + .reg1 = WM8766_REG_DACCTRL2, + .mask1 = WM8766_DAC2_DEEMP3, + }, + [WM8766_CTL_IZD_SW] = { + .name = "Infinite Zero Detect Playback Switch", + .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN, + .reg1 = WM8766_REG_DACCTRL1, + .mask1 = WM8766_DAC_IZD, + }, + [WM8766_CTL_ZC_SW] = { + .name = "Zero Cross Detect Playback Switch", + .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN, + .reg1 = WM8766_REG_DACCTRL2, + .mask1 = WM8766_DAC2_ZCD, + .flags = WM8766_FLAG_INVERT, + }, +}; + +/* exported functions */ + +void snd_wm8766_init(struct snd_wm8766 *wm) +{ + int i; + static const u16 default_values[] = { + 0x000, 0x100, + 0x120, 0x000, + 0x000, 0x100, 0x000, 0x100, 0x000, + 0x000, 0x080, + }; + + memcpy(wm->ctl, snd_wm8766_default_ctl, sizeof(wm->ctl)); + + snd_wm8766_write(wm, WM8766_REG_RESET, 0x00); /* reset */ + udelay(10); + /* load defaults */ + for (i = 0; i < ARRAY_SIZE(default_values); i++) + snd_wm8766_write(wm, i, default_values[i]); +} + +void snd_wm8766_resume(struct snd_wm8766 *wm) +{ + int i; + + for (i = 0; i < WM8766_REG_COUNT; i++) + snd_wm8766_write(wm, i, wm->regs[i]); +} + +void snd_wm8766_set_if(struct snd_wm8766 *wm, u16 dac) +{ + u16 val = wm->regs[WM8766_REG_IFCTRL] & ~WM8766_IF_MASK; + + dac &= WM8766_IF_MASK; + snd_wm8766_write(wm, WM8766_REG_IFCTRL, val | dac); +} + +void snd_wm8766_set_master_mode(struct snd_wm8766 *wm, u16 mode) +{ + u16 val = wm->regs[WM8766_REG_DACCTRL3] & ~WM8766_DAC3_MSTR_MASK; + + mode &= WM8766_DAC3_MSTR_MASK; + snd_wm8766_write(wm, WM8766_REG_DACCTRL3, val | mode); +} + +void snd_wm8766_set_power(struct snd_wm8766 *wm, u16 power) +{ + u16 val = wm->regs[WM8766_REG_DACCTRL3] & ~WM8766_DAC3_POWER_MASK; + + power &= WM8766_DAC3_POWER_MASK; + snd_wm8766_write(wm, WM8766_REG_DACCTRL3, val | power); +} + +void snd_wm8766_volume_restore(struct snd_wm8766 *wm) +{ + u16 val = wm->regs[WM8766_REG_DACR1]; + /* restore volume after MCLK stopped */ + snd_wm8766_write(wm, WM8766_REG_DACR1, val | WM8766_VOL_UPDATE); +} + +/* mixer callbacks */ + +static int snd_wm8766_volume_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct snd_wm8766 *wm = snd_kcontrol_chip(kcontrol); + int n = kcontrol->private_value; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = (wm->ctl[n].flags & WM8766_FLAG_STEREO) ? 2 : 1; + uinfo->value.integer.min = wm->ctl[n].min; + uinfo->value.integer.max = wm->ctl[n].max; + + return 0; +} + +static int snd_wm8766_enum_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct snd_wm8766 *wm = snd_kcontrol_chip(kcontrol); + int n = kcontrol->private_value; + + return snd_ctl_enum_info(uinfo, 1, wm->ctl[n].max, + wm->ctl[n].enum_names); +} + +static int snd_wm8766_ctl_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_wm8766 *wm = snd_kcontrol_chip(kcontrol); + int n = kcontrol->private_value; + u16 val1, val2; + + if (wm->ctl[n].get) + wm->ctl[n].get(wm, &val1, &val2); + else { + val1 = wm->regs[wm->ctl[n].reg1] & wm->ctl[n].mask1; + val1 >>= __ffs(wm->ctl[n].mask1); + if (wm->ctl[n].flags & WM8766_FLAG_STEREO) { + val2 = wm->regs[wm->ctl[n].reg2] & wm->ctl[n].mask2; + val2 >>= __ffs(wm->ctl[n].mask2); + if (wm->ctl[n].flags & WM8766_FLAG_VOL_UPDATE) + val2 &= ~WM8766_VOL_UPDATE; + } + } + if (wm->ctl[n].flags & WM8766_FLAG_INVERT) { + val1 = wm->ctl[n].max - (val1 - wm->ctl[n].min); + val2 = wm->ctl[n].max - (val2 - wm->ctl[n].min); + } + ucontrol->value.integer.value[0] = val1; + if (wm->ctl[n].flags & WM8766_FLAG_STEREO) + ucontrol->value.integer.value[1] = val2; + + return 0; +} + +static int snd_wm8766_ctl_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_wm8766 *wm = snd_kcontrol_chip(kcontrol); + int n = kcontrol->private_value; + u16 val, regval1, regval2; + + /* this also works for enum because value is an union */ + regval1 = ucontrol->value.integer.value[0]; + regval2 = ucontrol->value.integer.value[1]; + if (wm->ctl[n].flags & WM8766_FLAG_INVERT) { + regval1 = wm->ctl[n].max - (regval1 - wm->ctl[n].min); + regval2 = wm->ctl[n].max - (regval2 - wm->ctl[n].min); + } + if (wm->ctl[n].set) + wm->ctl[n].set(wm, regval1, regval2); + else { + val = wm->regs[wm->ctl[n].reg1] & ~wm->ctl[n].mask1; + val |= regval1 << __ffs(wm->ctl[n].mask1); + /* both stereo controls in one register */ + if (wm->ctl[n].flags & WM8766_FLAG_STEREO && + wm->ctl[n].reg1 == wm->ctl[n].reg2) { + val &= ~wm->ctl[n].mask2; + val |= regval2 << __ffs(wm->ctl[n].mask2); + } + snd_wm8766_write(wm, wm->ctl[n].reg1, val); + /* stereo controls in different registers */ + if (wm->ctl[n].flags & WM8766_FLAG_STEREO && + wm->ctl[n].reg1 != wm->ctl[n].reg2) { + val = wm->regs[wm->ctl[n].reg2] & ~wm->ctl[n].mask2; + val |= regval2 << __ffs(wm->ctl[n].mask2); + if (wm->ctl[n].flags & WM8766_FLAG_VOL_UPDATE) + val |= WM8766_VOL_UPDATE; + snd_wm8766_write(wm, wm->ctl[n].reg2, val); + } + } + + return 0; +} + +static int snd_wm8766_add_control(struct snd_wm8766 *wm, int num) +{ + struct snd_kcontrol_new cont; + struct snd_kcontrol *ctl; + + memset(&cont, 0, sizeof(cont)); + cont.iface = SNDRV_CTL_ELEM_IFACE_MIXER; + cont.private_value = num; + cont.name = wm->ctl[num].name; + cont.access = SNDRV_CTL_ELEM_ACCESS_READWRITE; + if (wm->ctl[num].flags & WM8766_FLAG_LIM || + wm->ctl[num].flags & WM8766_FLAG_ALC) + cont.access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE; + cont.tlv.p = NULL; + cont.get = snd_wm8766_ctl_get; + cont.put = snd_wm8766_ctl_put; + + switch (wm->ctl[num].type) { + case SNDRV_CTL_ELEM_TYPE_INTEGER: + cont.info = snd_wm8766_volume_info; + cont.access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ; + cont.tlv.p = wm->ctl[num].tlv; + break; + case SNDRV_CTL_ELEM_TYPE_BOOLEAN: + wm->ctl[num].max = 1; + if (wm->ctl[num].flags & WM8766_FLAG_STEREO) + cont.info = snd_ctl_boolean_stereo_info; + else + cont.info = snd_ctl_boolean_mono_info; + break; + case SNDRV_CTL_ELEM_TYPE_ENUMERATED: + cont.info = snd_wm8766_enum_info; + break; + default: + return -EINVAL; + } + ctl = snd_ctl_new1(&cont, wm); + if (!ctl) + return -ENOMEM; + wm->ctl[num].kctl = ctl; + + return snd_ctl_add(wm->card, ctl); +} + +int snd_wm8766_build_controls(struct snd_wm8766 *wm) +{ + int err, i; + + for (i = 0; i < WM8766_CTL_COUNT; i++) + if (wm->ctl[i].name) { + err = snd_wm8766_add_control(wm, i); + if (err < 0) + return err; + } + + return 0; +} diff --git a/sound/pci/ice1712/wm8766.h b/sound/pci/ice1712/wm8766.h new file mode 100644 index 000000000000..c119f84bd2c2 --- /dev/null +++ b/sound/pci/ice1712/wm8766.h @@ -0,0 +1,163 @@ +#ifndef __SOUND_WM8766_H +#define __SOUND_WM8766_H + +/* + * ALSA driver for ICEnsemble VT17xx + * + * Lowlevel functions for WM8766 codec + * + * Copyright (c) 2012 Ondrej Zary <linux@rainbow-software.org> + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#define WM8766_REG_DACL1 0x00 +#define WM8766_REG_DACR1 0x01 +#define WM8766_VOL_MASK 0x1ff /* incl. update bit */ +#define WM8766_VOL_UPDATE (1 << 8) /* update volume */ +#define WM8766_REG_DACCTRL1 0x02 +#define WM8766_DAC_MUTEALL (1 << 0) +#define WM8766_DAC_DEEMPALL (1 << 1) +#define WM8766_DAC_PDWN (1 << 2) +#define WM8766_DAC_ATC (1 << 3) +#define WM8766_DAC_IZD (1 << 4) +#define WM8766_DAC_PL_MASK 0x1e0 +#define WM8766_DAC_PL_LL (1 << 5) /* L chan: L signal */ +#define WM8766_DAC_PL_LR (2 << 5) /* L chan: R signal */ +#define WM8766_DAC_PL_LB (3 << 5) /* L chan: both */ +#define WM8766_DAC_PL_RL (1 << 7) /* R chan: L signal */ +#define WM8766_DAC_PL_RR (2 << 7) /* R chan: R signal */ +#define WM8766_DAC_PL_RB (3 << 7) /* R chan: both */ +#define WM8766_REG_IFCTRL 0x03 +#define WM8766_IF_FMT_RIGHTJ (0 << 0) +#define WM8766_IF_FMT_LEFTJ (1 << 0) +#define WM8766_IF_FMT_I2S (2 << 0) +#define WM8766_IF_FMT_DSP (3 << 0) +#define WM8766_IF_DSP_LATE (1 << 2) /* in DSP mode */ +#define WM8766_IF_LRC_INVERTED (1 << 2) /* in other modes */ +#define WM8766_IF_BCLK_INVERTED (1 << 3) +#define WM8766_IF_IWL_16BIT (0 << 4) +#define WM8766_IF_IWL_20BIT (1 << 4) +#define WM8766_IF_IWL_24BIT (2 << 4) +#define WM8766_IF_IWL_32BIT (3 << 4) +#define WM8766_IF_MASK 0x3f +#define WM8766_PHASE_INVERT1 (1 << 6) +#define WM8766_PHASE_INVERT2 (1 << 7) +#define WM8766_PHASE_INVERT3 (1 << 8) +#define WM8766_REG_DACL2 0x04 +#define WM8766_REG_DACR2 0x05 +#define WM8766_REG_DACL3 0x06 +#define WM8766_REG_DACR3 0x07 +#define WM8766_REG_MASTDA 0x08 +#define WM8766_REG_DACCTRL2 0x09 +#define WM8766_DAC2_ZCD (1 << 0) +#define WM8766_DAC2_ZFLAG_ALL (0 << 1) +#define WM8766_DAC2_ZFLAG_1 (1 << 1) +#define WM8766_DAC2_ZFLAG_2 (2 << 1) +#define WM8766_DAC2_ZFLAG_3 (3 << 1) +#define WM8766_DAC2_MUTE1 (1 << 3) +#define WM8766_DAC2_MUTE2 (1 << 4) +#define WM8766_DAC2_MUTE3 (1 << 5) +#define WM8766_DAC2_DEEMP1 (1 << 6) +#define WM8766_DAC2_DEEMP2 (1 << 7) +#define WM8766_DAC2_DEEMP3 (1 << 8) +#define WM8766_REG_DACCTRL3 0x0a +#define WM8766_DAC3_DACPD1 (1 << 1) +#define WM8766_DAC3_DACPD2 (1 << 2) +#define WM8766_DAC3_DACPD3 (1 << 3) +#define WM8766_DAC3_PWRDNALL (1 << 4) +#define WM8766_DAC3_POWER_MASK 0x1e +#define WM8766_DAC3_MASTER (1 << 5) +#define WM8766_DAC3_DAC128FS (0 << 6) +#define WM8766_DAC3_DAC192FS (1 << 6) +#define WM8766_DAC3_DAC256FS (2 << 6) +#define WM8766_DAC3_DAC384FS (3 << 6) +#define WM8766_DAC3_DAC512FS (4 << 6) +#define WM8766_DAC3_DAC768FS (5 << 6) +#define WM8766_DAC3_MSTR_MASK 0x1e0 +#define WM8766_REG_MUTE1 0x0c +#define WM8766_MUTE1_MPD (1 << 6) +#define WM8766_REG_MUTE2 0x0f +#define WM8766_MUTE2_MPD (1 << 5) +#define WM8766_REG_RESET 0x1f + +#define WM8766_REG_COUNT 0x10 /* don't cache the RESET register */ + +struct snd_wm8766; + +struct snd_wm8766_ops { + void (*write)(struct snd_wm8766 *wm, u16 addr, u16 data); +}; + +enum snd_wm8766_ctl_id { + WM8766_CTL_CH1_VOL, + WM8766_CTL_CH2_VOL, + WM8766_CTL_CH3_VOL, + WM8766_CTL_CH1_SW, + WM8766_CTL_CH2_SW, + WM8766_CTL_CH3_SW, + WM8766_CTL_PHASE1_SW, + WM8766_CTL_PHASE2_SW, + WM8766_CTL_PHASE3_SW, + WM8766_CTL_DEEMPH1_SW, + WM8766_CTL_DEEMPH2_SW, + WM8766_CTL_DEEMPH3_SW, + WM8766_CTL_IZD_SW, + WM8766_CTL_ZC_SW, + + WM8766_CTL_COUNT, +}; + +#define WM8766_ENUM_MAX 16 + +#define WM8766_FLAG_STEREO (1 << 0) +#define WM8766_FLAG_VOL_UPDATE (1 << 1) +#define WM8766_FLAG_INVERT (1 << 2) +#define WM8766_FLAG_LIM (1 << 3) +#define WM8766_FLAG_ALC (1 << 4) + +struct snd_wm8766_ctl { + struct snd_kcontrol *kctl; + const char *name; + snd_ctl_elem_type_t type; + const char *const enum_names[WM8766_ENUM_MAX]; + const unsigned int *tlv; + u16 reg1, reg2, mask1, mask2, min, max, flags; + void (*set)(struct snd_wm8766 *wm, u16 ch1, u16 ch2); + void (*get)(struct snd_wm8766 *wm, u16 *ch1, u16 *ch2); +}; + +enum snd_wm8766_agc_mode { WM8766_AGC_OFF, WM8766_AGC_LIM, WM8766_AGC_ALC }; + +struct snd_wm8766 { + struct snd_card *card; + struct snd_wm8766_ctl ctl[WM8766_CTL_COUNT]; + enum snd_wm8766_agc_mode agc_mode; + struct snd_wm8766_ops ops; + u16 regs[WM8766_REG_COUNT]; /* 9-bit registers */ +}; + + + +void snd_wm8766_init(struct snd_wm8766 *wm); +void snd_wm8766_resume(struct snd_wm8766 *wm); +void snd_wm8766_set_if(struct snd_wm8766 *wm, u16 dac); +void snd_wm8766_set_master_mode(struct snd_wm8766 *wm, u16 mode); +void snd_wm8766_set_power(struct snd_wm8766 *wm, u16 power); +void snd_wm8766_volume_restore(struct snd_wm8766 *wm); +int snd_wm8766_build_controls(struct snd_wm8766 *wm); + +#endif /* __SOUND_WM8766_H */ diff --git a/sound/pci/ice1712/wm8776.c b/sound/pci/ice1712/wm8776.c new file mode 100644 index 000000000000..a3c05fe5daf9 --- /dev/null +++ b/sound/pci/ice1712/wm8776.c @@ -0,0 +1,633 @@ +/* + * ALSA driver for ICEnsemble VT17xx + * + * Lowlevel functions for WM8776 codec + * + * Copyright (c) 2012 Ondrej Zary <linux@rainbow-software.org> + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include <linux/delay.h> +#include <sound/core.h> +#include <sound/control.h> +#include <sound/tlv.h> +#include "wm8776.h" + +/* low-level access */ + +static void snd_wm8776_write(struct snd_wm8776 *wm, u16 addr, u16 data) +{ + u8 bus_addr = addr << 1 | data >> 8; /* addr + 9th data bit */ + u8 bus_data = data & 0xff; /* remaining 8 data bits */ + + if (addr < WM8776_REG_RESET) + wm->regs[addr] = data; + wm->ops.write(wm, bus_addr, bus_data); +} + +/* register-level functions */ + +static void snd_wm8776_activate_ctl(struct snd_wm8776 *wm, + const char *ctl_name, + bool active) +{ + struct snd_card *card = wm->card; + struct snd_kcontrol *kctl; + struct snd_kcontrol_volatile *vd; + struct snd_ctl_elem_id elem_id; + unsigned int index_offset; + + memset(&elem_id, 0, sizeof(elem_id)); + strncpy(elem_id.name, ctl_name, sizeof(elem_id.name)); + elem_id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; + kctl = snd_ctl_find_id(card, &elem_id); + if (!kctl) + return; + index_offset = snd_ctl_get_ioff(kctl, &kctl->id); + vd = &kctl->vd[index_offset]; + if (active) + vd->access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE; + else + vd->access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE; + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_INFO, &kctl->id); +} + +static void snd_wm8776_update_agc_ctl(struct snd_wm8776 *wm) +{ + int i, flags_on = 0, flags_off = 0; + + switch (wm->agc_mode) { + case WM8776_AGC_OFF: + flags_off = WM8776_FLAG_LIM | WM8776_FLAG_ALC; + break; + case WM8776_AGC_LIM: + flags_off = WM8776_FLAG_ALC; + flags_on = WM8776_FLAG_LIM; + break; + case WM8776_AGC_ALC_R: + case WM8776_AGC_ALC_L: + case WM8776_AGC_ALC_STEREO: + flags_off = WM8776_FLAG_LIM; + flags_on = WM8776_FLAG_ALC; + break; + } + + for (i = 0; i < WM8776_CTL_COUNT; i++) + if (wm->ctl[i].flags & flags_off) + snd_wm8776_activate_ctl(wm, wm->ctl[i].name, false); + else if (wm->ctl[i].flags & flags_on) + snd_wm8776_activate_ctl(wm, wm->ctl[i].name, true); +} + +static void snd_wm8776_set_agc(struct snd_wm8776 *wm, u16 agc, u16 nothing) +{ + u16 alc1 = wm->regs[WM8776_REG_ALCCTRL1] & ~WM8776_ALC1_LCT_MASK; + u16 alc2 = wm->regs[WM8776_REG_ALCCTRL2] & ~WM8776_ALC2_LCEN; + + switch (agc) { + case 0: /* Off */ + wm->agc_mode = WM8776_AGC_OFF; + break; + case 1: /* Limiter */ + alc2 |= WM8776_ALC2_LCEN; + wm->agc_mode = WM8776_AGC_LIM; + break; + case 2: /* ALC Right */ + alc1 |= WM8776_ALC1_LCSEL_ALCR; + alc2 |= WM8776_ALC2_LCEN; + wm->agc_mode = WM8776_AGC_ALC_R; + break; + case 3: /* ALC Left */ + alc1 |= WM8776_ALC1_LCSEL_ALCL; + alc2 |= WM8776_ALC2_LCEN; + wm->agc_mode = WM8776_AGC_ALC_L; + break; + case 4: /* ALC Stereo */ + alc1 |= WM8776_ALC1_LCSEL_ALCSTEREO; + alc2 |= WM8776_ALC2_LCEN; + wm->agc_mode = WM8776_AGC_ALC_STEREO; + break; + } + snd_wm8776_write(wm, WM8776_REG_ALCCTRL1, alc1); + snd_wm8776_write(wm, WM8776_REG_ALCCTRL2, alc2); + snd_wm8776_update_agc_ctl(wm); +} + +static void snd_wm8776_get_agc(struct snd_wm8776 *wm, u16 *mode, u16 *nothing) +{ + *mode = wm->agc_mode; +} + +/* mixer controls */ + +static const DECLARE_TLV_DB_SCALE(wm8776_hp_tlv, -7400, 100, 1); +static const DECLARE_TLV_DB_SCALE(wm8776_dac_tlv, -12750, 50, 1); +static const DECLARE_TLV_DB_SCALE(wm8776_adc_tlv, -10350, 50, 1); +static const DECLARE_TLV_DB_SCALE(wm8776_lct_tlv, -1600, 100, 0); +static const DECLARE_TLV_DB_SCALE(wm8776_maxgain_tlv, 0, 400, 0); +static const DECLARE_TLV_DB_SCALE(wm8776_ngth_tlv, -7800, 600, 0); +static const DECLARE_TLV_DB_SCALE(wm8776_maxatten_lim_tlv, -1200, 100, 0); +static const DECLARE_TLV_DB_SCALE(wm8776_maxatten_alc_tlv, -2100, 400, 0); + +static struct snd_wm8776_ctl snd_wm8776_default_ctl[WM8776_CTL_COUNT] = { + [WM8776_CTL_DAC_VOL] = { + .name = "Master Playback Volume", + .type = SNDRV_CTL_ELEM_TYPE_INTEGER, + .tlv = wm8776_dac_tlv, + .reg1 = WM8776_REG_DACLVOL, + .reg2 = WM8776_REG_DACRVOL, + .mask1 = WM8776_DACVOL_MASK, + .mask2 = WM8776_DACVOL_MASK, + .max = 0xff, + .flags = WM8776_FLAG_STEREO | WM8776_FLAG_VOL_UPDATE, + }, + [WM8776_CTL_DAC_SW] = { + .name = "Master Playback Switch", + .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN, + .reg1 = WM8776_REG_DACCTRL1, + .reg2 = WM8776_REG_DACCTRL1, + .mask1 = WM8776_DAC_PL_LL, + .mask2 = WM8776_DAC_PL_RR, + .flags = WM8776_FLAG_STEREO, + }, + [WM8776_CTL_DAC_ZC_SW] = { + .name = "Master Zero Cross Detect Playback Switch", + .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN, + .reg1 = WM8776_REG_DACCTRL1, + .mask1 = WM8776_DAC_DZCEN, + }, + [WM8776_CTL_HP_VOL] = { + .name = "Headphone Playback Volume", + .type = SNDRV_CTL_ELEM_TYPE_INTEGER, + .tlv = wm8776_hp_tlv, + .reg1 = WM8776_REG_HPLVOL, + .reg2 = WM8776_REG_HPRVOL, + .mask1 = WM8776_HPVOL_MASK, + .mask2 = WM8776_HPVOL_MASK, + .min = 0x2f, + .max = 0x7f, + .flags = WM8776_FLAG_STEREO | WM8776_FLAG_VOL_UPDATE, + }, + [WM8776_CTL_HP_SW] = { + .name = "Headphone Playback Switch", + .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN, + .reg1 = WM8776_REG_PWRDOWN, + .mask1 = WM8776_PWR_HPPD, + .flags = WM8776_FLAG_INVERT, + }, + [WM8776_CTL_HP_ZC_SW] = { + .name = "Headphone Zero Cross Detect Playback Switch", + .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN, + .reg1 = WM8776_REG_HPLVOL, + .reg2 = WM8776_REG_HPRVOL, + .mask1 = WM8776_VOL_HPZCEN, + .mask2 = WM8776_VOL_HPZCEN, + .flags = WM8776_FLAG_STEREO, + }, + [WM8776_CTL_AUX_SW] = { + .name = "AUX Playback Switch", + .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN, + .reg1 = WM8776_REG_OUTMUX, + .mask1 = WM8776_OUTMUX_AUX, + }, + [WM8776_CTL_BYPASS_SW] = { + .name = "Bypass Playback Switch", + .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN, + .reg1 = WM8776_REG_OUTMUX, + .mask1 = WM8776_OUTMUX_BYPASS, + }, + [WM8776_CTL_DAC_IZD_SW] = { + .name = "Infinite Zero Detect Playback Switch", + .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN, + .reg1 = WM8776_REG_DACCTRL1, + .mask1 = WM8776_DAC_IZD, + }, + [WM8776_CTL_PHASE_SW] = { + .name = "Phase Invert Playback Switch", + .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN, + .reg1 = WM8776_REG_PHASESWAP, + .reg2 = WM8776_REG_PHASESWAP, + .mask1 = WM8776_PHASE_INVERTL, + .mask2 = WM8776_PHASE_INVERTR, + .flags = WM8776_FLAG_STEREO, + }, + [WM8776_CTL_DEEMPH_SW] = { + .name = "Deemphasis Playback Switch", + .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN, + .reg1 = WM8776_REG_DACCTRL2, + .mask1 = WM8776_DAC2_DEEMPH, + }, + [WM8776_CTL_ADC_VOL] = { + .name = "Input Capture Volume", + .type = SNDRV_CTL_ELEM_TYPE_INTEGER, + .tlv = wm8776_adc_tlv, + .reg1 = WM8776_REG_ADCLVOL, + .reg2 = WM8776_REG_ADCRVOL, + .mask1 = WM8776_ADC_GAIN_MASK, + .mask2 = WM8776_ADC_GAIN_MASK, + .max = 0xff, + .flags = WM8776_FLAG_STEREO | WM8776_FLAG_VOL_UPDATE, + }, + [WM8776_CTL_ADC_SW] = { + .name = "Input Capture Switch", + .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN, + .reg1 = WM8776_REG_ADCMUX, + .reg2 = WM8776_REG_ADCMUX, + .mask1 = WM8776_ADC_MUTEL, + .mask2 = WM8776_ADC_MUTER, + .flags = WM8776_FLAG_STEREO | WM8776_FLAG_INVERT, + }, + [WM8776_CTL_INPUT1_SW] = { + .name = "AIN1 Capture Switch", + .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN, + .reg1 = WM8776_REG_ADCMUX, + .mask1 = WM8776_ADC_MUX_AIN1, + }, + [WM8776_CTL_INPUT2_SW] = { + .name = "AIN2 Capture Switch", + .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN, + .reg1 = WM8776_REG_ADCMUX, + .mask1 = WM8776_ADC_MUX_AIN2, + }, + [WM8776_CTL_INPUT3_SW] = { + .name = "AIN3 Capture Switch", + .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN, + .reg1 = WM8776_REG_ADCMUX, + .mask1 = WM8776_ADC_MUX_AIN3, + }, + [WM8776_CTL_INPUT4_SW] = { + .name = "AIN4 Capture Switch", + .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN, + .reg1 = WM8776_REG_ADCMUX, + .mask1 = WM8776_ADC_MUX_AIN4, + }, + [WM8776_CTL_INPUT5_SW] = { + .name = "AIN5 Capture Switch", + .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN, + .reg1 = WM8776_REG_ADCMUX, + .mask1 = WM8776_ADC_MUX_AIN5, + }, + [WM8776_CTL_AGC_SEL] = { + .name = "AGC Select Capture Enum", + .type = SNDRV_CTL_ELEM_TYPE_ENUMERATED, + .enum_names = { "Off", "Limiter", "ALC Right", "ALC Left", + "ALC Stereo" }, + .max = 5, /* .enum_names item count */ + .set = snd_wm8776_set_agc, + .get = snd_wm8776_get_agc, + }, + [WM8776_CTL_LIM_THR] = { + .name = "Limiter Threshold Capture Volume", + .type = SNDRV_CTL_ELEM_TYPE_INTEGER, + .tlv = wm8776_lct_tlv, + .reg1 = WM8776_REG_ALCCTRL1, + .mask1 = WM8776_ALC1_LCT_MASK, + .max = 15, + .flags = WM8776_FLAG_LIM, + }, + [WM8776_CTL_LIM_ATK] = { + .name = "Limiter Attack Time Capture Enum", + .type = SNDRV_CTL_ELEM_TYPE_ENUMERATED, + .enum_names = { "0.25 ms", "0.5 ms", "1 ms", "2 ms", "4 ms", + "8 ms", "16 ms", "32 ms", "64 ms", "128 ms", "256 ms" }, + .max = 11, /* .enum_names item count */ + .reg1 = WM8776_REG_ALCCTRL3, + .mask1 = WM8776_ALC3_ATK_MASK, + .flags = WM8776_FLAG_LIM, + }, + [WM8776_CTL_LIM_DCY] = { + .name = "Limiter Decay Time Capture Enum", + .type = SNDRV_CTL_ELEM_TYPE_ENUMERATED, + .enum_names = { "1.2 ms", "2.4 ms", "4.8 ms", "9.6 ms", + "19.2 ms", "38.4 ms", "76.8 ms", "154 ms", "307 ms", + "614 ms", "1.23 s" }, + .max = 11, /* .enum_names item count */ + .reg1 = WM8776_REG_ALCCTRL3, + .mask1 = WM8776_ALC3_DCY_MASK, + .flags = WM8776_FLAG_LIM, + }, + [WM8776_CTL_LIM_TRANWIN] = { + .name = "Limiter Transient Window Capture Enum", + .type = SNDRV_CTL_ELEM_TYPE_ENUMERATED, + .enum_names = { "0 us", "62.5 us", "125 us", "250 us", "500 us", + "1 ms", "2 ms", "4 ms" }, + .max = 8, /* .enum_names item count */ + .reg1 = WM8776_REG_LIMITER, + .mask1 = WM8776_LIM_TRANWIN_MASK, + .flags = WM8776_FLAG_LIM, + }, + [WM8776_CTL_LIM_MAXATTN] = { + .name = "Limiter Maximum Attenuation Capture Volume", + .type = SNDRV_CTL_ELEM_TYPE_INTEGER, + .tlv = wm8776_maxatten_lim_tlv, + .reg1 = WM8776_REG_LIMITER, + .mask1 = WM8776_LIM_MAXATTEN_MASK, + .min = 3, + .max = 12, + .flags = WM8776_FLAG_LIM | WM8776_FLAG_INVERT, + }, + [WM8776_CTL_ALC_TGT] = { + .name = "ALC Target Level Capture Volume", + .type = SNDRV_CTL_ELEM_TYPE_INTEGER, + .tlv = wm8776_lct_tlv, + .reg1 = WM8776_REG_ALCCTRL1, + .mask1 = WM8776_ALC1_LCT_MASK, + .max = 15, + .flags = WM8776_FLAG_ALC, + }, + [WM8776_CTL_ALC_ATK] = { + .name = "ALC Attack Time Capture Enum", + .type = SNDRV_CTL_ELEM_TYPE_ENUMERATED, + .enum_names = { "8.40 ms", "16.8 ms", "33.6 ms", "67.2 ms", + "134 ms", "269 ms", "538 ms", "1.08 s", "2.15 s", + "4.3 s", "8.6 s" }, + .max = 11, /* .enum_names item count */ + .reg1 = WM8776_REG_ALCCTRL3, + .mask1 = WM8776_ALC3_ATK_MASK, + .flags = WM8776_FLAG_ALC, + }, + [WM8776_CTL_ALC_DCY] = { + .name = "ALC Decay Time Capture Enum", + .type = SNDRV_CTL_ELEM_TYPE_ENUMERATED, + .enum_names = { "33.5 ms", "67.0 ms", "134 ms", "268 ms", + "536 ms", "1.07 s", "2.14 s", "4.29 s", "8.58 s", + "17.2 s", "34.3 s" }, + .max = 11, /* .enum_names item count */ + .reg1 = WM8776_REG_ALCCTRL3, + .mask1 = WM8776_ALC3_DCY_MASK, + .flags = WM8776_FLAG_ALC, + }, + [WM8776_CTL_ALC_MAXGAIN] = { + .name = "ALC Maximum Gain Capture Volume", + .type = SNDRV_CTL_ELEM_TYPE_INTEGER, + .tlv = wm8776_maxgain_tlv, + .reg1 = WM8776_REG_ALCCTRL1, + .mask1 = WM8776_ALC1_MAXGAIN_MASK, + .min = 1, + .max = 7, + .flags = WM8776_FLAG_ALC, + }, + [WM8776_CTL_ALC_MAXATTN] = { + .name = "ALC Maximum Attenuation Capture Volume", + .type = SNDRV_CTL_ELEM_TYPE_INTEGER, + .tlv = wm8776_maxatten_alc_tlv, + .reg1 = WM8776_REG_LIMITER, + .mask1 = WM8776_LIM_MAXATTEN_MASK, + .min = 10, + .max = 15, + .flags = WM8776_FLAG_ALC | WM8776_FLAG_INVERT, + }, + [WM8776_CTL_ALC_HLD] = { + .name = "ALC Hold Time Capture Enum", + .type = SNDRV_CTL_ELEM_TYPE_ENUMERATED, + .enum_names = { "0 ms", "2.67 ms", "5.33 ms", "10.6 ms", + "21.3 ms", "42.7 ms", "85.3 ms", "171 ms", "341 ms", + "683 ms", "1.37 s", "2.73 s", "5.46 s", "10.9 s", + "21.8 s", "43.7 s" }, + .max = 16, /* .enum_names item count */ + .reg1 = WM8776_REG_ALCCTRL2, + .mask1 = WM8776_ALC2_HOLD_MASK, + .flags = WM8776_FLAG_ALC, + }, + [WM8776_CTL_NGT_SW] = { + .name = "Noise Gate Capture Switch", + .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN, + .reg1 = WM8776_REG_NOISEGATE, + .mask1 = WM8776_NGAT_ENABLE, + .flags = WM8776_FLAG_ALC, + }, + [WM8776_CTL_NGT_THR] = { + .name = "Noise Gate Threshold Capture Volume", + .type = SNDRV_CTL_ELEM_TYPE_INTEGER, + .tlv = wm8776_ngth_tlv, + .reg1 = WM8776_REG_NOISEGATE, + .mask1 = WM8776_NGAT_THR_MASK, + .max = 7, + .flags = WM8776_FLAG_ALC, + }, +}; + +/* exported functions */ + +void snd_wm8776_init(struct snd_wm8776 *wm) +{ + int i; + static const u16 default_values[] = { + 0x000, 0x100, 0x000, + 0x000, 0x100, 0x000, + 0x000, 0x090, 0x000, 0x000, + 0x022, 0x022, 0x022, + 0x008, 0x0cf, 0x0cf, 0x07b, 0x000, + 0x032, 0x000, 0x0a6, 0x001, 0x001 + }; + + memcpy(wm->ctl, snd_wm8776_default_ctl, sizeof(wm->ctl)); + + snd_wm8776_write(wm, WM8776_REG_RESET, 0x00); /* reset */ + udelay(10); + /* load defaults */ + for (i = 0; i < ARRAY_SIZE(default_values); i++) + snd_wm8776_write(wm, i, default_values[i]); +} + +void snd_wm8776_resume(struct snd_wm8776 *wm) +{ + int i; + + for (i = 0; i < WM8776_REG_COUNT; i++) + snd_wm8776_write(wm, i, wm->regs[i]); +} + +void snd_wm8776_set_dac_if(struct snd_wm8776 *wm, u16 dac) +{ + snd_wm8776_write(wm, WM8776_REG_DACIFCTRL, dac); +} + +void snd_wm8776_set_adc_if(struct snd_wm8776 *wm, u16 adc) +{ + snd_wm8776_write(wm, WM8776_REG_ADCIFCTRL, adc); +} + +void snd_wm8776_set_master_mode(struct snd_wm8776 *wm, u16 mode) +{ + snd_wm8776_write(wm, WM8776_REG_MSTRCTRL, mode); +} + +void snd_wm8776_set_power(struct snd_wm8776 *wm, u16 power) +{ + snd_wm8776_write(wm, WM8776_REG_PWRDOWN, power); +} + +void snd_wm8776_volume_restore(struct snd_wm8776 *wm) +{ + u16 val = wm->regs[WM8776_REG_DACRVOL]; + /* restore volume after MCLK stopped */ + snd_wm8776_write(wm, WM8776_REG_DACRVOL, val | WM8776_VOL_UPDATE); +} + +/* mixer callbacks */ + +static int snd_wm8776_volume_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct snd_wm8776 *wm = snd_kcontrol_chip(kcontrol); + int n = kcontrol->private_value; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = (wm->ctl[n].flags & WM8776_FLAG_STEREO) ? 2 : 1; + uinfo->value.integer.min = wm->ctl[n].min; + uinfo->value.integer.max = wm->ctl[n].max; + + return 0; +} + +static int snd_wm8776_enum_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct snd_wm8776 *wm = snd_kcontrol_chip(kcontrol); + int n = kcontrol->private_value; + + return snd_ctl_enum_info(uinfo, 1, wm->ctl[n].max, + wm->ctl[n].enum_names); +} + +static int snd_wm8776_ctl_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_wm8776 *wm = snd_kcontrol_chip(kcontrol); + int n = kcontrol->private_value; + u16 val1, val2; + + if (wm->ctl[n].get) + wm->ctl[n].get(wm, &val1, &val2); + else { + val1 = wm->regs[wm->ctl[n].reg1] & wm->ctl[n].mask1; + val1 >>= __ffs(wm->ctl[n].mask1); + if (wm->ctl[n].flags & WM8776_FLAG_STEREO) { + val2 = wm->regs[wm->ctl[n].reg2] & wm->ctl[n].mask2; + val2 >>= __ffs(wm->ctl[n].mask2); + if (wm->ctl[n].flags & WM8776_FLAG_VOL_UPDATE) + val2 &= ~WM8776_VOL_UPDATE; + } + } + if (wm->ctl[n].flags & WM8776_FLAG_INVERT) { + val1 = wm->ctl[n].max - (val1 - wm->ctl[n].min); + val2 = wm->ctl[n].max - (val2 - wm->ctl[n].min); + } + ucontrol->value.integer.value[0] = val1; + if (wm->ctl[n].flags & WM8776_FLAG_STEREO) + ucontrol->value.integer.value[1] = val2; + + return 0; +} + +static int snd_wm8776_ctl_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_wm8776 *wm = snd_kcontrol_chip(kcontrol); + int n = kcontrol->private_value; + u16 val, regval1, regval2; + + /* this also works for enum because value is an union */ + regval1 = ucontrol->value.integer.value[0]; + regval2 = ucontrol->value.integer.value[1]; + if (wm->ctl[n].flags & WM8776_FLAG_INVERT) { + regval1 = wm->ctl[n].max - (regval1 - wm->ctl[n].min); + regval2 = wm->ctl[n].max - (regval2 - wm->ctl[n].min); + } + if (wm->ctl[n].set) + wm->ctl[n].set(wm, regval1, regval2); + else { + val = wm->regs[wm->ctl[n].reg1] & ~wm->ctl[n].mask1; + val |= regval1 << __ffs(wm->ctl[n].mask1); + /* both stereo controls in one register */ + if (wm->ctl[n].flags & WM8776_FLAG_STEREO && + wm->ctl[n].reg1 == wm->ctl[n].reg2) { + val &= ~wm->ctl[n].mask2; + val |= regval2 << __ffs(wm->ctl[n].mask2); + } + snd_wm8776_write(wm, wm->ctl[n].reg1, val); + /* stereo controls in different registers */ + if (wm->ctl[n].flags & WM8776_FLAG_STEREO && + wm->ctl[n].reg1 != wm->ctl[n].reg2) { + val = wm->regs[wm->ctl[n].reg2] & ~wm->ctl[n].mask2; + val |= regval2 << __ffs(wm->ctl[n].mask2); + if (wm->ctl[n].flags & WM8776_FLAG_VOL_UPDATE) + val |= WM8776_VOL_UPDATE; + snd_wm8776_write(wm, wm->ctl[n].reg2, val); + } + } + + return 0; +} + +static int snd_wm8776_add_control(struct snd_wm8776 *wm, int num) +{ + struct snd_kcontrol_new cont; + struct snd_kcontrol *ctl; + + memset(&cont, 0, sizeof(cont)); + cont.iface = SNDRV_CTL_ELEM_IFACE_MIXER; + cont.private_value = num; + cont.name = wm->ctl[num].name; + cont.access = SNDRV_CTL_ELEM_ACCESS_READWRITE; + if (wm->ctl[num].flags & WM8776_FLAG_LIM || + wm->ctl[num].flags & WM8776_FLAG_ALC) + cont.access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE; + cont.tlv.p = NULL; + cont.get = snd_wm8776_ctl_get; + cont.put = snd_wm8776_ctl_put; + + switch (wm->ctl[num].type) { + case SNDRV_CTL_ELEM_TYPE_INTEGER: + cont.info = snd_wm8776_volume_info; + cont.access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ; + cont.tlv.p = wm->ctl[num].tlv; + break; + case SNDRV_CTL_ELEM_TYPE_BOOLEAN: + wm->ctl[num].max = 1; + if (wm->ctl[num].flags & WM8776_FLAG_STEREO) + cont.info = snd_ctl_boolean_stereo_info; + else + cont.info = snd_ctl_boolean_mono_info; + break; + case SNDRV_CTL_ELEM_TYPE_ENUMERATED: + cont.info = snd_wm8776_enum_info; + break; + default: + return -EINVAL; + } + ctl = snd_ctl_new1(&cont, wm); + if (!ctl) + return -ENOMEM; + + return snd_ctl_add(wm->card, ctl); +} + +int snd_wm8776_build_controls(struct snd_wm8776 *wm) +{ + int err, i; + + for (i = 0; i < WM8776_CTL_COUNT; i++) + if (wm->ctl[i].name) { + err = snd_wm8776_add_control(wm, i); + if (err < 0) + return err; + } + + return 0; +} diff --git a/sound/pci/ice1712/wm8776.h b/sound/pci/ice1712/wm8776.h new file mode 100644 index 000000000000..93a2d6971154 --- /dev/null +++ b/sound/pci/ice1712/wm8776.h @@ -0,0 +1,226 @@ +#ifndef __SOUND_WM8776_H +#define __SOUND_WM8776_H + +/* + * ALSA driver for ICEnsemble VT17xx + * + * Lowlevel functions for WM8776 codec + * + * Copyright (c) 2012 Ondrej Zary <linux@rainbow-software.org> + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#define WM8776_REG_HPLVOL 0x00 +#define WM8776_REG_HPRVOL 0x01 +#define WM8776_REG_HPMASTER 0x02 +#define WM8776_HPVOL_MASK 0x17f /* incl. update bit */ +#define WM8776_VOL_HPZCEN (1 << 7) /* zero cross detect */ +#define WM8776_VOL_UPDATE (1 << 8) /* update volume */ +#define WM8776_REG_DACLVOL 0x03 +#define WM8776_REG_DACRVOL 0x04 +#define WM8776_REG_DACMASTER 0x05 +#define WM8776_DACVOL_MASK 0x1ff /* incl. update bit */ +#define WM8776_REG_PHASESWAP 0x06 +#define WM8776_PHASE_INVERTL (1 << 0) +#define WM8776_PHASE_INVERTR (1 << 1) +#define WM8776_REG_DACCTRL1 0x07 +#define WM8776_DAC_DZCEN (1 << 0) +#define WM8776_DAC_ATC (1 << 1) +#define WM8776_DAC_IZD (1 << 2) +#define WM8776_DAC_TOD (1 << 3) +#define WM8776_DAC_PL_MASK 0xf0 +#define WM8776_DAC_PL_LL (1 << 4) /* L chan: L signal */ +#define WM8776_DAC_PL_LR (2 << 4) /* L chan: R signal */ +#define WM8776_DAC_PL_LB (3 << 4) /* L chan: both */ +#define WM8776_DAC_PL_RL (1 << 6) /* R chan: L signal */ +#define WM8776_DAC_PL_RR (2 << 6) /* R chan: R signal */ +#define WM8776_DAC_PL_RB (3 << 6) /* R chan: both */ +#define WM8776_REG_DACMUTE 0x08 +#define WM8776_DACMUTE (1 << 0) +#define WM8776_REG_DACCTRL2 0x09 +#define WM8776_DAC2_DEEMPH (1 << 0) +#define WM8776_DAC2_ZFLAG_DISABLE (0 << 1) +#define WM8776_DAC2_ZFLAG_OWN (1 << 1) +#define WM8776_DAC2_ZFLAG_BOTH (2 << 1) +#define WM8776_DAC2_ZFLAG_EITHER (3 << 1) +#define WM8776_REG_DACIFCTRL 0x0a +#define WM8776_FMT_RIGHTJ (0 << 0) +#define WM8776_FMT_LEFTJ (1 << 0) +#define WM8776_FMT_I2S (2 << 0) +#define WM8776_FMT_DSP (3 << 0) +#define WM8776_FMT_DSP_LATE (1 << 2) /* in DSP mode */ +#define WM8776_FMT_LRC_INVERTED (1 << 2) /* in other modes */ +#define WM8776_FMT_BCLK_INVERTED (1 << 3) +#define WM8776_FMT_16BIT (0 << 4) +#define WM8776_FMT_20BIT (1 << 4) +#define WM8776_FMT_24BIT (2 << 4) +#define WM8776_FMT_32BIT (3 << 4) +#define WM8776_REG_ADCIFCTRL 0x0b +#define WM8776_FMT_ADCMCLK_INVERTED (1 << 6) +#define WM8776_FMT_ADCHPD (1 << 8) +#define WM8776_REG_MSTRCTRL 0x0c +#define WM8776_IF_ADC256FS (2 << 0) +#define WM8776_IF_ADC384FS (3 << 0) +#define WM8776_IF_ADC512FS (4 << 0) +#define WM8776_IF_ADC768FS (5 << 0) +#define WM8776_IF_OVERSAMP64 (1 << 3) +#define WM8776_IF_DAC128FS (0 << 4) +#define WM8776_IF_DAC192FS (1 << 4) +#define WM8776_IF_DAC256FS (2 << 4) +#define WM8776_IF_DAC384FS (3 << 4) +#define WM8776_IF_DAC512FS (4 << 4) +#define WM8776_IF_DAC768FS (5 << 4) +#define WM8776_IF_DAC_MASTER (1 << 7) +#define WM8776_IF_ADC_MASTER (1 << 8) +#define WM8776_REG_PWRDOWN 0x0d +#define WM8776_PWR_PDWN (1 << 0) +#define WM8776_PWR_ADCPD (1 << 1) +#define WM8776_PWR_DACPD (1 << 2) +#define WM8776_PWR_HPPD (1 << 3) +#define WM8776_PWR_AINPD (1 << 6) +#define WM8776_REG_ADCLVOL 0x0e +#define WM8776_REG_ADCRVOL 0x0f +#define WM8776_ADC_GAIN_MASK 0xff +#define WM8776_ADC_ZCEN (1 << 8) +#define WM8776_REG_ALCCTRL1 0x10 +#define WM8776_ALC1_LCT_MASK 0x0f /* 0=-16dB, 1=-15dB..15=-1dB */ +#define WM8776_ALC1_MAXGAIN_MASK 0x70 /* 0,1=0dB, 2=+4dB...7=+24dB */ +#define WM8776_ALC1_LCSEL_MASK 0x180 +#define WM8776_ALC1_LCSEL_LIMITER (0 << 7) +#define WM8776_ALC1_LCSEL_ALCR (1 << 7) +#define WM8776_ALC1_LCSEL_ALCL (2 << 7) +#define WM8776_ALC1_LCSEL_ALCSTEREO (3 << 7) +#define WM8776_REG_ALCCTRL2 0x11 +#define WM8776_ALC2_HOLD_MASK 0x0f /*0=0ms, 1=2.67ms, 2=5.33ms.. */ +#define WM8776_ALC2_ZCEN (1 << 7) +#define WM8776_ALC2_LCEN (1 << 8) +#define WM8776_REG_ALCCTRL3 0x12 +#define WM8776_ALC3_ATK_MASK 0x0f +#define WM8776_ALC3_DCY_MASK 0xf0 +#define WM8776_ALC3_FDECAY (1 << 8) +#define WM8776_REG_NOISEGATE 0x13 +#define WM8776_NGAT_ENABLE (1 << 0) +#define WM8776_NGAT_THR_MASK 0x1c /*0=-78dB, 1=-72dB...7=-36dB */ +#define WM8776_REG_LIMITER 0x14 +#define WM8776_LIM_MAXATTEN_MASK 0x0f +#define WM8776_LIM_TRANWIN_MASK 0x70 /*0=0us, 1=62.5us, 2=125us.. */ +#define WM8776_REG_ADCMUX 0x15 +#define WM8776_ADC_MUX_AIN1 (1 << 0) +#define WM8776_ADC_MUX_AIN2 (1 << 1) +#define WM8776_ADC_MUX_AIN3 (1 << 2) +#define WM8776_ADC_MUX_AIN4 (1 << 3) +#define WM8776_ADC_MUX_AIN5 (1 << 4) +#define WM8776_ADC_MUTER (1 << 6) +#define WM8776_ADC_MUTEL (1 << 7) +#define WM8776_ADC_LRBOTH (1 << 8) +#define WM8776_REG_OUTMUX 0x16 +#define WM8776_OUTMUX_DAC (1 << 0) +#define WM8776_OUTMUX_AUX (1 << 1) +#define WM8776_OUTMUX_BYPASS (1 << 2) +#define WM8776_REG_RESET 0x17 + +#define WM8776_REG_COUNT 0x17 /* don't cache the RESET register */ + +struct snd_wm8776; + +struct snd_wm8776_ops { + void (*write)(struct snd_wm8776 *wm, u8 addr, u8 data); +}; + +enum snd_wm8776_ctl_id { + WM8776_CTL_DAC_VOL, + WM8776_CTL_DAC_SW, + WM8776_CTL_DAC_ZC_SW, + WM8776_CTL_HP_VOL, + WM8776_CTL_HP_SW, + WM8776_CTL_HP_ZC_SW, + WM8776_CTL_AUX_SW, + WM8776_CTL_BYPASS_SW, + WM8776_CTL_DAC_IZD_SW, + WM8776_CTL_PHASE_SW, + WM8776_CTL_DEEMPH_SW, + WM8776_CTL_ADC_VOL, + WM8776_CTL_ADC_SW, + WM8776_CTL_INPUT1_SW, + WM8776_CTL_INPUT2_SW, + WM8776_CTL_INPUT3_SW, + WM8776_CTL_INPUT4_SW, + WM8776_CTL_INPUT5_SW, + WM8776_CTL_AGC_SEL, + WM8776_CTL_LIM_THR, + WM8776_CTL_LIM_ATK, + WM8776_CTL_LIM_DCY, + WM8776_CTL_LIM_TRANWIN, + WM8776_CTL_LIM_MAXATTN, + WM8776_CTL_ALC_TGT, + WM8776_CTL_ALC_ATK, + WM8776_CTL_ALC_DCY, + WM8776_CTL_ALC_MAXGAIN, + WM8776_CTL_ALC_MAXATTN, + WM8776_CTL_ALC_HLD, + WM8776_CTL_NGT_SW, + WM8776_CTL_NGT_THR, + + WM8776_CTL_COUNT, +}; + +#define WM8776_ENUM_MAX 16 + +#define WM8776_FLAG_STEREO (1 << 0) +#define WM8776_FLAG_VOL_UPDATE (1 << 1) +#define WM8776_FLAG_INVERT (1 << 2) +#define WM8776_FLAG_LIM (1 << 3) +#define WM8776_FLAG_ALC (1 << 4) + +struct snd_wm8776_ctl { + const char *name; + snd_ctl_elem_type_t type; + const char *const enum_names[WM8776_ENUM_MAX]; + const unsigned int *tlv; + u16 reg1, reg2, mask1, mask2, min, max, flags; + void (*set)(struct snd_wm8776 *wm, u16 ch1, u16 ch2); + void (*get)(struct snd_wm8776 *wm, u16 *ch1, u16 *ch2); +}; + +enum snd_wm8776_agc_mode { + WM8776_AGC_OFF, + WM8776_AGC_LIM, + WM8776_AGC_ALC_R, + WM8776_AGC_ALC_L, + WM8776_AGC_ALC_STEREO +}; + +struct snd_wm8776 { + struct snd_card *card; + struct snd_wm8776_ctl ctl[WM8776_CTL_COUNT]; + enum snd_wm8776_agc_mode agc_mode; + struct snd_wm8776_ops ops; + u16 regs[WM8776_REG_COUNT]; /* 9-bit registers */ +}; + + + +void snd_wm8776_init(struct snd_wm8776 *wm); +void snd_wm8776_resume(struct snd_wm8776 *wm); +void snd_wm8776_set_dac_if(struct snd_wm8776 *wm, u16 dac); +void snd_wm8776_set_adc_if(struct snd_wm8776 *wm, u16 adc); +void snd_wm8776_set_master_mode(struct snd_wm8776 *wm, u16 mode); +void snd_wm8776_set_power(struct snd_wm8776 *wm, u16 power); +void snd_wm8776_volume_restore(struct snd_wm8776 *wm); +int snd_wm8776_build_controls(struct snd_wm8776 *wm); + +#endif /* __SOUND_WM8776_H */ diff --git a/sound/pci/ice1712/wtm.c b/sound/pci/ice1712/wtm.c index e618f789026e..bcf30a387b87 100644 --- a/sound/pci/ice1712/wtm.c +++ b/sound/pci/ice1712/wtm.c @@ -25,7 +25,6 @@ -#include <linux/io.h> #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/init.h> @@ -384,7 +383,7 @@ static int stac9460_mic_sw_put(struct snd_kcontrol *kcontrol, /* * Control tabs */ -static struct snd_kcontrol_new stac9640_controls[] __devinitdata = { +static struct snd_kcontrol_new stac9640_controls[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", @@ -448,7 +447,7 @@ static struct snd_kcontrol_new stac9640_controls[] __devinitdata = { /*INIT*/ -static int __devinit wtm_add_controls(struct snd_ice1712 *ice) +static int wtm_add_controls(struct snd_ice1712 *ice) { unsigned int i; int err; @@ -462,7 +461,7 @@ static int __devinit wtm_add_controls(struct snd_ice1712 *ice) return 0; } -static int __devinit wtm_init(struct snd_ice1712 *ice) +static int wtm_init(struct snd_ice1712 *ice) { static unsigned short stac_inits_prodigy[] = { STAC946X_RESET, 0, @@ -485,7 +484,7 @@ static int __devinit wtm_init(struct snd_ice1712 *ice) } -static unsigned char wtm_eeprom[] __devinitdata = { +static unsigned char wtm_eeprom[] = { 0x47, /*SYSCONF: clock 192KHz, 4ADC, 8DAC */ 0x80, /* ACLINK : I2S */ 0xf8, /* I2S: vol; 96k, 24bit, 192k */ @@ -503,7 +502,7 @@ static unsigned char wtm_eeprom[] __devinitdata = { /*entry point*/ -struct snd_ice1712_card_info snd_vt1724_wtm_cards[] __devinitdata = { +struct snd_ice1712_card_info snd_vt1724_wtm_cards[] = { { .subvendor = VT1724_SUBDEVICE_WTM, .name = "ESI Waveterminal 192M", diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index ea4b706c8d63..b8fe40531b9c 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c @@ -592,8 +592,8 @@ static unsigned short snd_intel8x0_codec_read(struct snd_ac97 *ac97, return res; } -static void __devinit snd_intel8x0_codec_read_test(struct intel8x0 *chip, - unsigned int codec) +static void snd_intel8x0_codec_read_test(struct intel8x0 *chip, + unsigned int codec) { unsigned int tmp; @@ -1507,8 +1507,8 @@ struct ich_pcm_table { int ac97_idx; }; -static int __devinit snd_intel8x0_pcm1(struct intel8x0 *chip, int device, - struct ich_pcm_table *rec) +static int snd_intel8x0_pcm1(struct intel8x0 *chip, int device, + struct ich_pcm_table *rec) { struct snd_pcm *pcm; int err; @@ -1564,7 +1564,7 @@ static int __devinit snd_intel8x0_pcm1(struct intel8x0 *chip, int device, return 0; } -static struct ich_pcm_table intel_pcms[] __devinitdata = { +static struct ich_pcm_table intel_pcms[] = { { .playback_ops = &snd_intel8x0_playback_ops, .capture_ops = &snd_intel8x0_capture_ops, @@ -1601,7 +1601,7 @@ static struct ich_pcm_table intel_pcms[] __devinitdata = { }, }; -static struct ich_pcm_table nforce_pcms[] __devinitdata = { +static struct ich_pcm_table nforce_pcms[] = { { .playback_ops = &snd_intel8x0_playback_ops, .capture_ops = &snd_intel8x0_capture_ops, @@ -1624,7 +1624,7 @@ static struct ich_pcm_table nforce_pcms[] __devinitdata = { }, }; -static struct ich_pcm_table ali_pcms[] __devinitdata = { +static struct ich_pcm_table ali_pcms[] = { { .playback_ops = &snd_intel8x0_ali_playback_ops, .capture_ops = &snd_intel8x0_ali_capture_ops, @@ -1656,7 +1656,7 @@ static struct ich_pcm_table ali_pcms[] __devinitdata = { #endif }; -static int __devinit snd_intel8x0_pcm(struct intel8x0 *chip) +static int snd_intel8x0_pcm(struct intel8x0 *chip) { int i, tblsize, device, err; struct ich_pcm_table *tbl, *rec; @@ -1719,7 +1719,7 @@ static void snd_intel8x0_mixer_free_ac97(struct snd_ac97 *ac97) chip->ac97[ac97->num] = NULL; } -static struct ac97_pcm ac97_pcm_defs[] __devinitdata = { +static struct ac97_pcm ac97_pcm_defs[] = { /* front PCM */ { .exclusive = 1, @@ -1789,7 +1789,7 @@ static struct ac97_pcm ac97_pcm_defs[] __devinitdata = { }, }; -static struct ac97_quirk ac97_quirks[] __devinitdata = { +static struct ac97_quirk ac97_quirks[] = { { .subvendor = 0x0e11, .subdevice = 0x000e, @@ -2196,8 +2196,8 @@ static struct ac97_quirk ac97_quirks[] __devinitdata = { { } /* terminator */ }; -static int __devinit snd_intel8x0_mixer(struct intel8x0 *chip, int ac97_clock, - const char *quirk_override) +static int snd_intel8x0_mixer(struct intel8x0 *chip, int ac97_clock, + const char *quirk_override) { struct snd_ac97_bus *pbus; struct snd_ac97_template ac97; @@ -2765,7 +2765,7 @@ static SIMPLE_DEV_PM_OPS(intel8x0_pm, intel8x0_suspend, intel8x0_resume); #define INTEL8X0_TESTBUF_SIZE 32768 /* enough large for one shot */ -static void __devinit intel8x0_measure_ac97_clock(struct intel8x0 *chip) +static void intel8x0_measure_ac97_clock(struct intel8x0 *chip) { struct snd_pcm_substream *subs; struct ichdev *ichdev; @@ -2883,7 +2883,7 @@ static void __devinit intel8x0_measure_ac97_clock(struct intel8x0 *chip) snd_ac97_update_power(chip->ac97[0], AC97_PCM_FRONT_DAC_RATE, 0); } -static struct snd_pci_quirk intel8x0_clock_list[] __devinitdata = { +static struct snd_pci_quirk intel8x0_clock_list[] = { SND_PCI_QUIRK(0x0e11, 0x008a, "AD1885", 41000), SND_PCI_QUIRK(0x1028, 0x00be, "AD1885", 44100), SND_PCI_QUIRK(0x1028, 0x0177, "AD1980", 48000), @@ -2892,7 +2892,7 @@ static struct snd_pci_quirk intel8x0_clock_list[] __devinitdata = { { } /* terminator */ }; -static int __devinit intel8x0_in_clock_list(struct intel8x0 *chip) +static int intel8x0_in_clock_list(struct intel8x0 *chip) { struct pci_dev *pci = chip->pci; const struct snd_pci_quirk *wl; @@ -2941,7 +2941,7 @@ static void snd_intel8x0_proc_read(struct snd_info_entry * entry, chip->ac97_sdin[2]); } -static void __devinit snd_intel8x0_proc_init(struct intel8x0 * chip) +static void snd_intel8x0_proc_init(struct intel8x0 *chip) { struct snd_info_entry *entry; @@ -2970,7 +2970,7 @@ static unsigned int sis_codec_bits[3] = { ICH_PCR, ICH_SCR, ICH_SIS_TCR }; -static int __devinit snd_intel8x0_inside_vm(struct pci_dev *pci) +static int snd_intel8x0_inside_vm(struct pci_dev *pci) { int result = inside_vm; char *msg = NULL; @@ -3009,10 +3009,10 @@ fini: return result; } -static int __devinit snd_intel8x0_create(struct snd_card *card, - struct pci_dev *pci, - unsigned long device_type, - struct intel8x0 ** r_intel8x0) +static int snd_intel8x0_create(struct snd_card *card, + struct pci_dev *pci, + unsigned long device_type, + struct intel8x0 **r_intel8x0) { struct intel8x0 *chip; int err; @@ -3227,7 +3227,7 @@ static int __devinit snd_intel8x0_create(struct snd_card *card, static struct shortname_table { unsigned int id; const char *s; -} shortnames[] __devinitdata = { +} shortnames[] = { { PCI_DEVICE_ID_INTEL_82801AA_5, "Intel 82801AA-ICH" }, { PCI_DEVICE_ID_INTEL_82801AB_5, "Intel 82901AB-ICH0" }, { PCI_DEVICE_ID_INTEL_82801BA_4, "Intel 82801BA-ICH2" }, @@ -3253,31 +3253,33 @@ static struct shortname_table { { 0, NULL }, }; -static struct snd_pci_quirk spdif_aclink_defaults[] __devinitdata = { +static struct snd_pci_quirk spdif_aclink_defaults[] = { SND_PCI_QUIRK(0x147b, 0x1c1a, "ASUS KN8", 1), { } /* end */ }; /* look up white/black list for SPDIF over ac-link */ -static int __devinit check_default_spdif_aclink(struct pci_dev *pci) +static int check_default_spdif_aclink(struct pci_dev *pci) { const struct snd_pci_quirk *w; w = snd_pci_quirk_lookup(pci, spdif_aclink_defaults); if (w) { if (w->value) - snd_printdd(KERN_INFO "intel8x0: Using SPDIF over " - "AC-Link for %s\n", w->name); + snd_printdd(KERN_INFO + "intel8x0: Using SPDIF over AC-Link for %s\n", + snd_pci_quirk_name(w)); else - snd_printdd(KERN_INFO "intel8x0: Using integrated " - "SPDIF DMA for %s\n", w->name); + snd_printdd(KERN_INFO + "intel8x0: Using integrated SPDIF DMA for %s\n", + snd_pci_quirk_name(w)); return w->value; } return 0; } -static int __devinit snd_intel8x0_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int snd_intel8x0_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { struct snd_card *card; struct intel8x0 *chip; @@ -3359,7 +3361,7 @@ static int __devinit snd_intel8x0_probe(struct pci_dev *pci, return 0; } -static void __devexit snd_intel8x0_remove(struct pci_dev *pci) +static void snd_intel8x0_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); pci_set_drvdata(pci, NULL); @@ -3369,7 +3371,7 @@ static struct pci_driver intel8x0_driver = { .name = KBUILD_MODNAME, .id_table = snd_intel8x0_ids, .probe = snd_intel8x0_probe, - .remove = __devexit_p(snd_intel8x0_remove), + .remove = snd_intel8x0_remove, .driver = { .pm = INTEL8X0_PM_OPS, }, diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c index 4d551736531e..fea09e8ea608 100644 --- a/sound/pci/intel8x0m.c +++ b/sound/pci/intel8x0m.c @@ -710,8 +710,8 @@ struct ich_pcm_table { int ac97_idx; }; -static int __devinit snd_intel8x0m_pcm1(struct intel8x0m *chip, int device, - struct ich_pcm_table *rec) +static int snd_intel8x0m_pcm1(struct intel8x0m *chip, int device, + struct ich_pcm_table *rec) { struct snd_pcm *pcm; int err; @@ -749,7 +749,7 @@ static int __devinit snd_intel8x0m_pcm1(struct intel8x0m *chip, int device, return 0; } -static struct ich_pcm_table intel_pcms[] __devinitdata = { +static struct ich_pcm_table intel_pcms[] = { { .suffix = "Modem", .playback_ops = &snd_intel8x0m_playback_ops, @@ -759,7 +759,7 @@ static struct ich_pcm_table intel_pcms[] __devinitdata = { }, }; -static int __devinit snd_intel8x0m_pcm(struct intel8x0m *chip) +static int snd_intel8x0m_pcm(struct intel8x0m *chip) { int i, tblsize, device, err; struct ich_pcm_table *tbl, *rec; @@ -819,7 +819,7 @@ static void snd_intel8x0m_mixer_free_ac97(struct snd_ac97 *ac97) } -static int __devinit snd_intel8x0m_mixer(struct intel8x0m *chip, int ac97_clock) +static int snd_intel8x0m_mixer(struct intel8x0m *chip, int ac97_clock) { struct snd_ac97_bus *pbus; struct snd_ac97_template ac97; @@ -1090,7 +1090,7 @@ static void snd_intel8x0m_proc_read(struct snd_info_entry * entry, (tmp & (ICH_PCR | ICH_SCR | ICH_TCR)) == 0 ? " none" : ""); } -static void __devinit snd_intel8x0m_proc_init(struct intel8x0m * chip) +static void snd_intel8x0m_proc_init(struct intel8x0m *chip) { struct snd_info_entry *entry; @@ -1113,10 +1113,10 @@ struct ich_reg_info { unsigned int offset; }; -static int __devinit snd_intel8x0m_create(struct snd_card *card, - struct pci_dev *pci, - unsigned long device_type, - struct intel8x0m **r_intel8x0m) +static int snd_intel8x0m_create(struct snd_card *card, + struct pci_dev *pci, + unsigned long device_type, + struct intel8x0m **r_intel8x0m) { struct intel8x0m *chip; int err; @@ -1252,7 +1252,7 @@ static int __devinit snd_intel8x0m_create(struct snd_card *card, static struct shortname_table { unsigned int id; const char *s; -} shortnames[] __devinitdata = { +} shortnames[] = { { PCI_DEVICE_ID_INTEL_82801AA_6, "Intel 82801AA-ICH" }, { PCI_DEVICE_ID_INTEL_82801AB_6, "Intel 82901AB-ICH0" }, { PCI_DEVICE_ID_INTEL_82801BA_6, "Intel 82801BA-ICH2" }, @@ -1275,8 +1275,8 @@ static struct shortname_table { { 0 }, }; -static int __devinit snd_intel8x0m_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int snd_intel8x0m_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { struct snd_card *card; struct intel8x0m *chip; @@ -1325,7 +1325,7 @@ static int __devinit snd_intel8x0m_probe(struct pci_dev *pci, return 0; } -static void __devexit snd_intel8x0m_remove(struct pci_dev *pci) +static void snd_intel8x0m_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); pci_set_drvdata(pci, NULL); @@ -1335,7 +1335,7 @@ static struct pci_driver intel8x0m_driver = { .name = KBUILD_MODNAME, .id_table = snd_intel8x0m_ids, .probe = snd_intel8x0m_probe, - .remove = __devexit_p(snd_intel8x0m_remove), + .remove = snd_intel8x0m_remove, .driver = { .pm = INTEL8X0M_PM_OPS, }, diff --git a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c index 8a67ce95f246..43b4228d9afe 100644 --- a/sound/pci/korg1212/korg1212.c +++ b/sound/pci/korg1212/korg1212.c @@ -2083,7 +2083,7 @@ static void snd_korg1212_proc_read(struct snd_info_entry *entry, snd_iprintf(buffer, " Error count: %ld\n", korg1212->totalerrorcnt); } -static void __devinit snd_korg1212_proc_init(struct snd_korg1212 *korg1212) +static void snd_korg1212_proc_init(struct snd_korg1212 *korg1212) { struct snd_info_entry *entry; @@ -2154,8 +2154,8 @@ static int snd_korg1212_dev_free(struct snd_device *device) return snd_korg1212_free(korg1212); } -static int __devinit snd_korg1212_create(struct snd_card *card, struct pci_dev *pci, - struct snd_korg1212 ** rchip) +static int snd_korg1212_create(struct snd_card *card, struct pci_dev *pci, + struct snd_korg1212 **rchip) { int err, rc; @@ -2429,7 +2429,7 @@ static int __devinit snd_korg1212_create(struct snd_card *card, struct pci_dev * * Card initialisation */ -static int __devinit +static int snd_korg1212_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { @@ -2470,7 +2470,7 @@ snd_korg1212_probe(struct pci_dev *pci, return 0; } -static void __devexit snd_korg1212_remove(struct pci_dev *pci) +static void snd_korg1212_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); pci_set_drvdata(pci, NULL); @@ -2480,7 +2480,7 @@ static struct pci_driver korg1212_driver = { .name = KBUILD_MODNAME, .id_table = snd_korg1212_ids, .probe = snd_korg1212_probe, - .remove = __devexit_p(snd_korg1212_remove), + .remove = snd_korg1212_remove, }; module_pci_driver(korg1212_driver); diff --git a/sound/pci/lola/lola.c b/sound/pci/lola/lola.c index ac15166bee68..322b638e8ec4 100644 --- a/sound/pci/lola/lola.c +++ b/sound/pci/lola/lola.c @@ -445,7 +445,7 @@ static void lola_reset_setups(struct lola *chip) lola_setup_all_analog_gains(chip, PLAY, false); /* output, update */ } -static int __devinit lola_parse_tree(struct lola *chip) +static int lola_parse_tree(struct lola *chip) { unsigned int val; int nid, err; @@ -568,8 +568,8 @@ static int lola_dev_free(struct snd_device *device) return 0; } -static int __devinit lola_create(struct snd_card *card, struct pci_dev *pci, - int dev, struct lola **rchip) +static int lola_create(struct snd_card *card, struct pci_dev *pci, + int dev, struct lola **rchip) { struct lola *chip; int err; @@ -702,8 +702,8 @@ static int __devinit lola_create(struct snd_card *card, struct pci_dev *pci, return err; } -static int __devinit lola_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int lola_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { static int dev; struct snd_card *card; @@ -756,7 +756,7 @@ out_free: return err; } -static void __devexit lola_remove(struct pci_dev *pci) +static void lola_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); pci_set_drvdata(pci, NULL); @@ -774,7 +774,7 @@ static struct pci_driver lola_driver = { .name = KBUILD_MODNAME, .id_table = lola_ids, .probe = lola_probe, - .remove = __devexit_p(lola_remove), + .remove = lola_remove, }; module_pci_driver(lola_driver); diff --git a/sound/pci/lola/lola_clock.c b/sound/pci/lola/lola_clock.c index 72f8ef0ac865..eb1d6b97df16 100644 --- a/sound/pci/lola/lola_clock.c +++ b/sound/pci/lola/lola_clock.c @@ -120,7 +120,7 @@ int lola_set_granularity(struct lola *chip, unsigned int val, bool force) * Clock widget handling */ -int __devinit lola_init_clock_widget(struct lola *chip, int nid) +int lola_init_clock_widget(struct lola *chip, int nid) { unsigned int val; int i, j, nitems, nb_verbs, idx, idx_list; diff --git a/sound/pci/lola/lola_mixer.c b/sound/pci/lola/lola_mixer.c index 6b8d64812951..52c8d6b0f39b 100644 --- a/sound/pci/lola/lola_mixer.c +++ b/sound/pci/lola/lola_mixer.c @@ -28,8 +28,8 @@ #include <sound/tlv.h> #include "lola.h" -static int __devinit lola_init_pin(struct lola *chip, struct lola_pin *pin, - int dir, int nid) +static int lola_init_pin(struct lola *chip, struct lola_pin *pin, + int dir, int nid) { unsigned int val; int err; @@ -91,7 +91,7 @@ static int __devinit lola_init_pin(struct lola *chip, struct lola_pin *pin, return 0; } -int __devinit lola_init_pins(struct lola *chip, int dir, int *nidp) +int lola_init_pins(struct lola *chip, int dir, int *nidp) { int i, err, nid; nid = *nidp; @@ -112,7 +112,7 @@ void lola_free_mixer(struct lola *chip) vfree(chip->mixer.array_saved); } -int __devinit lola_init_mixer_widget(struct lola *chip, int nid) +int lola_init_mixer_widget(struct lola *chip, int nid) { unsigned int val; int err; @@ -579,7 +579,7 @@ static int lola_analog_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag, return 0; } -static struct snd_kcontrol_new lola_analog_mixer __devinitdata = { +static struct snd_kcontrol_new lola_analog_mixer = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ | @@ -590,7 +590,7 @@ static struct snd_kcontrol_new lola_analog_mixer __devinitdata = { .tlv.c = lola_analog_vol_tlv, }; -static int __devinit create_analog_mixer(struct lola *chip, int dir, char *name) +static int create_analog_mixer(struct lola *chip, int dir, char *name) { if (!chip->pin[dir].num_pins) return 0; @@ -644,7 +644,7 @@ static int lola_input_src_put(struct snd_kcontrol *kcontrol, return lola_set_src_config(chip, mask, true); } -static struct snd_kcontrol_new lola_input_src_mixer __devinitdata = { +static struct snd_kcontrol_new lola_input_src_mixer = { .name = "Digital SRC Capture Switch", .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .info = lola_input_src_info, @@ -656,7 +656,7 @@ static struct snd_kcontrol_new lola_input_src_mixer __devinitdata = { * Lola16161 or Lola881 can have Hardware sample rate converters * on its digital input pins */ -static int __devinit create_input_src_mixer(struct lola *chip) +static int create_input_src_mixer(struct lola *chip) { if (!chip->input_src_caps_mask) return 0; @@ -726,7 +726,7 @@ static int lola_src_gain_put(struct snd_kcontrol *kcontrol, /* raw value: 0 = -84dB, 336 = 0dB, 408=18dB, incremented 1 for mute */ static const DECLARE_TLV_DB_SCALE(lola_src_gain_tlv, -8425, 25, 1); -static struct snd_kcontrol_new lola_src_gain_mixer __devinitdata = { +static struct snd_kcontrol_new lola_src_gain_mixer = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ), @@ -736,8 +736,8 @@ static struct snd_kcontrol_new lola_src_gain_mixer __devinitdata = { .tlv.p = lola_src_gain_tlv, }; -static int __devinit create_src_gain_mixer(struct lola *chip, - int num, int ofs, char *name) +static int create_src_gain_mixer(struct lola *chip, + int num, int ofs, char *name) { lola_src_gain_mixer.name = name; lola_src_gain_mixer.private_value = ofs + (num << 8); @@ -813,7 +813,7 @@ static int lola_dest_gain_put(struct snd_kcontrol *kcontrol, static const DECLARE_TLV_DB_SCALE(lola_dest_gain_tlv, -8425, 25, 1); -static struct snd_kcontrol_new lola_dest_gain_mixer __devinitdata = { +static struct snd_kcontrol_new lola_dest_gain_mixer = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ), @@ -823,9 +823,9 @@ static struct snd_kcontrol_new lola_dest_gain_mixer __devinitdata = { .tlv.p = lola_dest_gain_tlv, }; -static int __devinit create_dest_gain_mixer(struct lola *chip, - int src_num, int src_ofs, - int num, int ofs, char *name) +static int create_dest_gain_mixer(struct lola *chip, + int src_num, int src_ofs, + int num, int ofs, char *name) { lola_dest_gain_mixer.count = num; lola_dest_gain_mixer.name = name; @@ -838,7 +838,7 @@ static int __devinit create_dest_gain_mixer(struct lola *chip, /* */ -int __devinit lola_create_mixer(struct lola *chip) +int lola_create_mixer(struct lola *chip) { int err; diff --git a/sound/pci/lola/lola_pcm.c b/sound/pci/lola/lola_pcm.c index c44db68eecb5..5ea85e8b83ab 100644 --- a/sound/pci/lola/lola_pcm.c +++ b/sound/pci/lola/lola_pcm.c @@ -597,7 +597,7 @@ static struct snd_pcm_ops lola_pcm_ops = { .page = snd_pcm_sgbuf_ops_page, }; -int __devinit lola_create_pcm(struct lola *chip) +int lola_create_pcm(struct lola *chip) { struct snd_pcm *pcm; int i, err; @@ -690,7 +690,7 @@ static int lola_init_stream(struct lola *chip, struct lola_stream *str, return 0; } -int __devinit lola_init_pcm(struct lola *chip, int dir, int *nidp) +int lola_init_pcm(struct lola *chip, int dir, int *nidp) { struct lola_pcm *pcm = &chip->pcm[dir]; int i, nid, err; diff --git a/sound/pci/lola/lola_proc.c b/sound/pci/lola/lola_proc.c index 9d7daf897c9d..04df83defc09 100644 --- a/sound/pci/lola/lola_proc.c +++ b/sound/pci/lola/lola_proc.c @@ -206,7 +206,7 @@ static void lola_proc_regs_read(struct snd_info_entry *entry, } } -void __devinit lola_proc_debug_new(struct lola *chip) +void lola_proc_debug_new(struct lola *chip) { struct snd_info_entry *entry; diff --git a/sound/pci/lx6464es/lx6464es.c b/sound/pci/lx6464es/lx6464es.c index 5579b08bb35b..298bc9b72991 100644 --- a/sound/pci/lx6464es/lx6464es.c +++ b/sound/pci/lx6464es/lx6464es.c @@ -578,7 +578,7 @@ static int snd_lx6464es_dev_free(struct snd_device *device) } /* reset the dsp during initialization */ -static int __devinit lx_init_xilinx_reset(struct lx6464es *chip) +static int lx_init_xilinx_reset(struct lx6464es *chip) { int i; u32 plx_reg = lx_plx_reg_read(chip, ePLX_CHIPSC); @@ -620,7 +620,7 @@ static int __devinit lx_init_xilinx_reset(struct lx6464es *chip) return 0; } -static int __devinit lx_init_xilinx_test(struct lx6464es *chip) +static int lx_init_xilinx_test(struct lx6464es *chip) { u32 reg; @@ -650,7 +650,7 @@ static int __devinit lx_init_xilinx_test(struct lx6464es *chip) } /* initialize ethersound */ -static int __devinit lx_init_ethersound_config(struct lx6464es *chip) +static int lx_init_ethersound_config(struct lx6464es *chip) { int i; u32 orig_conf_es = lx_dsp_reg_read(chip, eReg_CONFES); @@ -690,7 +690,7 @@ static int __devinit lx_init_ethersound_config(struct lx6464es *chip) return 0; } -static int __devinit lx_init_get_version_features(struct lx6464es *chip) +static int lx_init_get_version_features(struct lx6464es *chip) { u32 dsp_version; @@ -759,7 +759,7 @@ static int lx_set_granularity(struct lx6464es *chip, u32 gran) } /* initialize and test the xilinx dsp chip */ -static int __devinit lx_init_dsp(struct lx6464es *chip) +static int lx_init_dsp(struct lx6464es *chip) { int err; int i; @@ -835,7 +835,7 @@ static struct snd_pcm_ops lx_ops_capture = { .pointer = lx_pcm_stream_pointer, }; -static int __devinit lx_pcm_create(struct lx6464es *chip) +static int lx_pcm_create(struct lx6464es *chip) { int err; struct snd_pcm *pcm; @@ -907,7 +907,7 @@ static int lx_control_playback_put(struct snd_kcontrol *kcontrol, return changed; } -static struct snd_kcontrol_new lx_control_playback_switch __devinitdata = { +static struct snd_kcontrol_new lx_control_playback_switch = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "PCM Playback Switch", .index = 0, @@ -954,7 +954,7 @@ static void lx_proc_levels_read(struct snd_info_entry *entry, snd_iprintf(buffer, "\n"); } -static int __devinit lx_proc_create(struct snd_card *card, struct lx6464es *chip) +static int lx_proc_create(struct snd_card *card, struct lx6464es *chip) { struct snd_info_entry *entry; int err = snd_card_proc_new(card, "levels", &entry); @@ -966,9 +966,9 @@ static int __devinit lx_proc_create(struct snd_card *card, struct lx6464es *chip } -static int __devinit snd_lx6464es_create(struct snd_card *card, - struct pci_dev *pci, - struct lx6464es **rchip) +static int snd_lx6464es_create(struct snd_card *card, + struct pci_dev *pci, + struct lx6464es **rchip) { struct lx6464es *chip; int err; @@ -1082,8 +1082,8 @@ alloc_failed: return err; } -static int __devinit snd_lx6464es_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int snd_lx6464es_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { static int dev; struct snd_card *card; @@ -1136,7 +1136,7 @@ out_free: } -static void __devexit snd_lx6464es_remove(struct pci_dev *pci) +static void snd_lx6464es_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); pci_set_drvdata(pci, NULL); @@ -1147,7 +1147,7 @@ static struct pci_driver lx6464es_driver = { .name = KBUILD_MODNAME, .id_table = snd_lx6464es_ids, .probe = snd_lx6464es_probe, - .remove = __devexit_p(snd_lx6464es_remove), + .remove = snd_lx6464es_remove, }; module_pci_driver(lx6464es_driver); diff --git a/sound/pci/lx6464es/lx_core.c b/sound/pci/lx6464es/lx_core.c index 8c3e7fcefd99..633c8607d053 100644 --- a/sound/pci/lx6464es/lx_core.c +++ b/sound/pci/lx6464es/lx_core.c @@ -385,7 +385,7 @@ polling_successful: /* low-level dsp access */ -int __devinit lx_dsp_get_version(struct lx6464es *chip, u32 *rdsp_version) +int lx_dsp_get_version(struct lx6464es *chip, u32 *rdsp_version) { u16 ret; unsigned long flags; diff --git a/sound/pci/lx6464es/lx_core.h b/sound/pci/lx6464es/lx_core.h index 4d7ff797a646..5ec5e04da1a5 100644 --- a/sound/pci/lx6464es/lx_core.h +++ b/sound/pci/lx6464es/lx_core.h @@ -109,7 +109,7 @@ struct lx_rmh { /* low-level dsp access */ -int __devinit lx_dsp_get_version(struct lx6464es *chip, u32 *rdsp_version); +int lx_dsp_get_version(struct lx6464es *chip, u32 *rdsp_version); int lx_dsp_get_clock_frequency(struct lx6464es *chip, u32 *rfreq); int lx_dsp_set_granularity(struct lx6464es *chip, u32 gran); int lx_dsp_read_async_events(struct lx6464es *chip, u32 *data); diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c index eb3cd3a4315e..c76ac1411210 100644 --- a/sound/pci/maestro3.c +++ b/sound/pci/maestro3.c @@ -822,7 +822,7 @@ static DEFINE_PCI_DEVICE_TABLE(snd_m3_ids) = { MODULE_DEVICE_TABLE(pci, snd_m3_ids); -static struct snd_pci_quirk m3_amp_quirk_list[] __devinitdata = { +static struct snd_pci_quirk m3_amp_quirk_list[] = { SND_PCI_QUIRK(0x0E11, 0x0094, "Compaq Evo N600c", 0x0c), SND_PCI_QUIRK(0x10f7, 0x833e, "Panasonic CF-28", 0x0d), SND_PCI_QUIRK(0x10f7, 0x833d, "Panasonic CF-72", 0x0d), @@ -831,7 +831,7 @@ static struct snd_pci_quirk m3_amp_quirk_list[] __devinitdata = { { } /* END */ }; -static struct snd_pci_quirk m3_irda_quirk_list[] __devinitdata = { +static struct snd_pci_quirk m3_irda_quirk_list[] = { SND_PCI_QUIRK(0x1028, 0x00b0, "Dell Inspiron 4000", 1), SND_PCI_QUIRK(0x1028, 0x00a4, "Dell Inspiron 8000", 1), SND_PCI_QUIRK(0x1028, 0x00e6, "Dell Inspiron 8100", 1), @@ -839,7 +839,7 @@ static struct snd_pci_quirk m3_irda_quirk_list[] __devinitdata = { }; /* hardware volume quirks */ -static struct snd_pci_quirk m3_hv_quirk_list[] __devinitdata = { +static struct snd_pci_quirk m3_hv_quirk_list[] = { /* Allegro chips */ SND_PCI_QUIRK(0x0E11, 0x002E, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), SND_PCI_QUIRK(0x0E11, 0x0094, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), @@ -917,7 +917,7 @@ static struct snd_pci_quirk m3_hv_quirk_list[] __devinitdata = { }; /* HP Omnibook quirks */ -static struct snd_pci_quirk m3_omnibook_quirk_list[] __devinitdata = { +static struct snd_pci_quirk m3_omnibook_quirk_list[] = { SND_PCI_QUIRK_ID(0x103c, 0x0010), /* HP OmniBook 6000 */ SND_PCI_QUIRK_ID(0x103c, 0x0011), /* HP OmniBook 500 */ { } /* END */ @@ -1856,7 +1856,7 @@ static struct snd_pcm_ops snd_m3_capture_ops = { .pointer = snd_m3_pcm_pointer, }; -static int __devinit +static int snd_m3_pcm(struct snd_m3 * chip, int device) { struct snd_pcm *pcm; @@ -2031,7 +2031,7 @@ static void snd_m3_ac97_reset(struct snd_m3 *chip) #endif } -static int __devinit snd_m3_mixer(struct snd_m3 *chip) +static int snd_m3_mixer(struct snd_m3 *chip) { struct snd_ac97_bus *pbus; struct snd_ac97_template ac97; @@ -2173,7 +2173,7 @@ static void snd_m3_assp_init(struct snd_m3 *chip) } -static int __devinit snd_m3_assp_client_init(struct snd_m3 *chip, struct m3_dma *s, int index) +static int snd_m3_assp_client_init(struct snd_m3 *chip, struct m3_dma *s, int index) { int data_bytes = 2 * ( MINISRC_TMP_BUFFER_SIZE / 2 + MINISRC_IN_BUFFER_SIZE / 2 + @@ -2488,7 +2488,7 @@ static SIMPLE_DEV_PM_OPS(m3_pm, m3_suspend, m3_resume); #endif /* CONFIG_PM_SLEEP */ #ifdef CONFIG_SND_MAESTRO3_INPUT -static int __devinit snd_m3_input_register(struct snd_m3 *chip) +static int snd_m3_input_register(struct snd_m3 *chip) { struct input_dev *input_dev; int err; @@ -2532,7 +2532,7 @@ static int snd_m3_dev_free(struct snd_device *device) return snd_m3_free(chip); } -static int __devinit +static int snd_m3_create(struct snd_card *card, struct pci_dev *pci, int enable_amp, int amp_gpio, @@ -2586,8 +2586,9 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci, else { quirk = snd_pci_quirk_lookup(pci, m3_amp_quirk_list); if (quirk) { - snd_printdd(KERN_INFO "maestro3: set amp-gpio " - "for '%s'\n", quirk->name); + snd_printdd(KERN_INFO + "maestro3: set amp-gpio for '%s'\n", + snd_pci_quirk_name(quirk)); chip->amp_gpio = quirk->value; } else if (chip->allegro_flag) chip->amp_gpio = GPO_EXT_AMP_ALLEGRO; @@ -2597,8 +2598,9 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci, quirk = snd_pci_quirk_lookup(pci, m3_irda_quirk_list); if (quirk) { - snd_printdd(KERN_INFO "maestro3: enabled irda workaround " - "for '%s'\n", quirk->name); + snd_printdd(KERN_INFO + "maestro3: enabled irda workaround for '%s'\n", + snd_pci_quirk_name(quirk)); chip->irda_workaround = 1; } quirk = snd_pci_quirk_lookup(pci, m3_hv_quirk_list); @@ -2700,7 +2702,7 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci, /* */ -static int __devinit +static int snd_m3_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { static int dev; @@ -2770,7 +2772,7 @@ snd_m3_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) return 0; } -static void __devexit snd_m3_remove(struct pci_dev *pci) +static void snd_m3_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); pci_set_drvdata(pci, NULL); @@ -2780,7 +2782,7 @@ static struct pci_driver m3_driver = { .name = KBUILD_MODNAME, .id_table = snd_m3_ids, .probe = snd_m3_probe, - .remove = __devexit_p(snd_m3_remove), + .remove = snd_m3_remove, .driver = { .pm = M3_PM_OPS, }, diff --git a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c index 0762610c99c0..01f7f37a8410 100644 --- a/sound/pci/mixart/mixart.c +++ b/sound/pci/mixart/mixart.c @@ -1004,7 +1004,7 @@ static int snd_mixart_chip_dev_free(struct snd_device *device) /* */ -static int __devinit snd_mixart_create(struct mixart_mgr *mgr, struct snd_card *card, int idx) +static int snd_mixart_create(struct mixart_mgr *mgr, struct snd_card *card, int idx) { int err; struct snd_mixart *chip; @@ -1180,7 +1180,7 @@ static void snd_mixart_proc_read(struct snd_info_entry *entry, } /* endif elf loaded */ } -static void __devinit snd_mixart_proc_init(struct snd_mixart *chip) +static void snd_mixart_proc_init(struct snd_mixart *chip) { struct snd_info_entry *entry; @@ -1209,8 +1209,8 @@ static void __devinit snd_mixart_proc_init(struct snd_mixart *chip) /* * probe function - creates the card manager */ -static int __devinit snd_mixart_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int snd_mixart_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { static int dev; struct mixart_mgr *mgr; @@ -1374,7 +1374,7 @@ static int __devinit snd_mixart_probe(struct pci_dev *pci, return 0; } -static void __devexit snd_mixart_remove(struct pci_dev *pci) +static void snd_mixart_remove(struct pci_dev *pci) { snd_mixart_free(pci_get_drvdata(pci)); pci_set_drvdata(pci, NULL); @@ -1384,7 +1384,7 @@ static struct pci_driver mixart_driver = { .name = KBUILD_MODNAME, .id_table = snd_mixart_ids, .probe = snd_mixart_probe, - .remove = __devexit_p(snd_mixart_remove), + .remove = snd_mixart_remove, }; module_pci_driver(mixart_driver); diff --git a/sound/pci/mixart/mixart_hwdep.c b/sound/pci/mixart/mixart_hwdep.c index e0f4d87555a0..ece1f831c16a 100644 --- a/sound/pci/mixart/mixart_hwdep.c +++ b/sound/pci/mixart/mixart_hwdep.c @@ -546,14 +546,6 @@ static int mixart_dsp_load(struct mixart_mgr* mgr, int index, const struct firmw } -#if defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE) -#if !defined(CONFIG_USE_MIXARTLOADER) && !defined(CONFIG_SND_MIXART) /* built-in kernel */ -#define SND_MIXART_FW_LOADER /* use the standard firmware loader */ -#endif -#endif - -#ifdef SND_MIXART_FW_LOADER - int snd_mixart_setup_firmware(struct mixart_mgr *mgr) { static char *fw_files[3] = { @@ -583,71 +575,3 @@ int snd_mixart_setup_firmware(struct mixart_mgr *mgr) MODULE_FIRMWARE("mixart/miXart8.xlx"); MODULE_FIRMWARE("mixart/miXart8.elf"); MODULE_FIRMWARE("mixart/miXart8AES.xlx"); - -#else /* old style firmware loading */ - -/* miXart hwdep interface id string */ -#define SND_MIXART_HWDEP_ID "miXart Loader" - -static int mixart_hwdep_dsp_status(struct snd_hwdep *hw, - struct snd_hwdep_dsp_status *info) -{ - struct mixart_mgr *mgr = hw->private_data; - - strcpy(info->id, "miXart"); - info->num_dsps = MIXART_HARDW_FILES_MAX_INDEX; - - if (mgr->dsp_loaded & (1 << MIXART_MOTHERBOARD_ELF_INDEX)) - info->chip_ready = 1; - - info->version = MIXART_DRIVER_VERSION; - return 0; -} - -static int mixart_hwdep_dsp_load(struct snd_hwdep *hw, - struct snd_hwdep_dsp_image *dsp) -{ - struct mixart_mgr* mgr = hw->private_data; - struct firmware fw; - int err; - - fw.size = dsp->length; - fw.data = vmalloc(dsp->length); - if (! fw.data) { - snd_printk(KERN_ERR "miXart: cannot allocate image size %d\n", - (int)dsp->length); - return -ENOMEM; - } - if (copy_from_user((void *) fw.data, dsp->image, dsp->length)) { - vfree(fw.data); - return -EFAULT; - } - err = mixart_dsp_load(mgr, dsp->index, &fw); - vfree(fw.data); - if (err < 0) - return err; - mgr->dsp_loaded |= 1 << dsp->index; - return err; -} - -int snd_mixart_setup_firmware(struct mixart_mgr *mgr) -{ - int err; - struct snd_hwdep *hw; - - /* only create hwdep interface for first cardX (see "index" module parameter)*/ - if ((err = snd_hwdep_new(mgr->chip[0]->card, SND_MIXART_HWDEP_ID, 0, &hw)) < 0) - return err; - - hw->iface = SNDRV_HWDEP_IFACE_MIXART; - hw->private_data = mgr; - hw->ops.dsp_status = mixart_hwdep_dsp_status; - hw->ops.dsp_load = mixart_hwdep_dsp_load; - hw->exclusive = 1; - sprintf(hw->name, SND_MIXART_HWDEP_ID); - mgr->dsp_loaded = 0; - - return snd_card_register(mgr->chip[0]->card); -} - -#endif /* SND_MIXART_FW_LOADER */ diff --git a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c index e80e9a1e84aa..6febedb05936 100644 --- a/sound/pci/nm256/nm256.c +++ b/sound/pci/nm256/nm256.c @@ -928,7 +928,7 @@ static struct snd_pcm_ops snd_nm256_capture_ops = { .mmap = snd_pcm_lib_mmap_iomem, }; -static int __devinit +static int snd_nm256_pcm(struct nm256 *chip, int device) { struct snd_pcm *pcm; @@ -1295,7 +1295,7 @@ snd_nm256_ac97_reset(struct snd_ac97 *ac97) } /* create an ac97 mixer interface */ -static int __devinit +static int snd_nm256_mixer(struct nm256 *chip) { struct snd_ac97_bus *pbus; @@ -1336,7 +1336,7 @@ snd_nm256_mixer(struct nm256 *chip) * RAM. */ -static int __devinit +static int snd_nm256_peek_for_sig(struct nm256 *chip) { /* The signature is located 1K below the end of video RAM. */ @@ -1472,7 +1472,7 @@ static int snd_nm256_dev_free(struct snd_device *device) return snd_nm256_free(chip); } -static int __devinit +static int snd_nm256_create(struct snd_card *card, struct pci_dev *pci, struct nm256 **chip_ret) { @@ -1639,7 +1639,7 @@ __error: enum { NM_BLACKLISTED, NM_RESET_WORKAROUND, NM_RESET_WORKAROUND_2 }; -static struct snd_pci_quirk nm256_quirks[] __devinitdata = { +static struct snd_pci_quirk nm256_quirks[] = { /* HP omnibook 4150 has cs4232 codec internally */ SND_PCI_QUIRK(0x103c, 0x0007, "HP omnibook 4150", NM_BLACKLISTED), /* Reset workarounds to avoid lock-ups */ @@ -1650,8 +1650,8 @@ static struct snd_pci_quirk nm256_quirks[] __devinitdata = { }; -static int __devinit snd_nm256_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int snd_nm256_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { struct snd_card *card; struct nm256 *chip; @@ -1660,7 +1660,8 @@ static int __devinit snd_nm256_probe(struct pci_dev *pci, q = snd_pci_quirk_lookup(pci, nm256_quirks); if (q) { - snd_printdd(KERN_INFO "nm256: Enabled quirk for %s.\n", q->name); + snd_printdd(KERN_INFO "nm256: Enabled quirk for %s.\n", + snd_pci_quirk_name(q)); switch (q->value) { case NM_BLACKLISTED: printk(KERN_INFO "nm256: The device is blacklisted. " @@ -1742,7 +1743,7 @@ static int __devinit snd_nm256_probe(struct pci_dev *pci, return 0; } -static void __devexit snd_nm256_remove(struct pci_dev *pci) +static void snd_nm256_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); pci_set_drvdata(pci, NULL); @@ -1753,7 +1754,7 @@ static struct pci_driver nm256_driver = { .name = KBUILD_MODNAME, .id_table = snd_nm256_ids, .probe = snd_nm256_probe, - .remove = __devexit_p(snd_nm256_remove), + .remove = snd_nm256_remove, .driver = { .pm = NM256_PM_OPS, }, diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c index 2becae155a48..ada6c256378e 100644 --- a/sound/pci/oxygen/oxygen.c +++ b/sound/pci/oxygen/oxygen.c @@ -756,8 +756,8 @@ static const struct oxygen_model model_generic = { .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, }; -static int __devinit get_oxygen_model(struct oxygen *chip, - const struct pci_device_id *id) +static int get_oxygen_model(struct oxygen *chip, + const struct pci_device_id *id) { static const char *const names[] = { [MODEL_MERIDIAN] = "AuzenTech X-Meridian", @@ -848,8 +848,8 @@ static int __devinit get_oxygen_model(struct oxygen *chip, return 0; } -static int __devinit generic_oxygen_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int generic_oxygen_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { static int dev; int err; @@ -871,7 +871,7 @@ static struct pci_driver oxygen_driver = { .name = KBUILD_MODNAME, .id_table = oxygen_ids, .probe = generic_oxygen_probe, - .remove = __devexit_p(oxygen_pci_remove), + .remove = oxygen_pci_remove, #ifdef CONFIG_PM_SLEEP .driver = { .pm = &oxygen_pci_pm, diff --git a/sound/pci/oxygen/virtuoso.c b/sound/pci/oxygen/virtuoso.c index 3d71423b23bc..64b9fda5f04a 100644 --- a/sound/pci/oxygen/virtuoso.c +++ b/sound/pci/oxygen/virtuoso.c @@ -52,13 +52,14 @@ static DEFINE_PCI_DEVICE_TABLE(xonar_ids) = { { OXYGEN_PCI_SUBID(0x1043, 0x835d) }, { OXYGEN_PCI_SUBID(0x1043, 0x835e) }, { OXYGEN_PCI_SUBID(0x1043, 0x838e) }, + { OXYGEN_PCI_SUBID(0x1043, 0x8522) }, { OXYGEN_PCI_SUBID_BROKEN_EEPROM }, { } }; MODULE_DEVICE_TABLE(pci, xonar_ids); -static int __devinit get_xonar_model(struct oxygen *chip, - const struct pci_device_id *id) +static int get_xonar_model(struct oxygen *chip, + const struct pci_device_id *id) { if (get_xonar_pcm179x_model(chip, id) >= 0) return 0; @@ -69,8 +70,8 @@ static int __devinit get_xonar_model(struct oxygen *chip, return -EINVAL; } -static int __devinit xonar_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int xonar_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { static int dev; int err; @@ -92,7 +93,7 @@ static struct pci_driver xonar_driver = { .name = KBUILD_MODNAME, .id_table = xonar_ids, .probe = xonar_probe, - .remove = __devexit_p(oxygen_pci_remove), + .remove = oxygen_pci_remove, #ifdef CONFIG_PM_SLEEP .driver = { .pm = &oxygen_pci_pm, diff --git a/sound/pci/oxygen/xonar_cs43xx.c b/sound/pci/oxygen/xonar_cs43xx.c index c8febf4b9bd6..d231b93d6ab5 100644 --- a/sound/pci/oxygen/xonar_cs43xx.c +++ b/sound/pci/oxygen/xonar_cs43xx.c @@ -431,8 +431,8 @@ static const struct oxygen_model model_xonar_d1 = { .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, }; -int __devinit get_xonar_cs43xx_model(struct oxygen *chip, - const struct pci_device_id *id) +int get_xonar_cs43xx_model(struct oxygen *chip, + const struct pci_device_id *id) { switch (id->subdevice) { case 0x834f: diff --git a/sound/pci/oxygen/xonar_pcm179x.c b/sound/pci/oxygen/xonar_pcm179x.c index 8433aa7c3d75..c8c7f2c9b355 100644 --- a/sound/pci/oxygen/xonar_pcm179x.c +++ b/sound/pci/oxygen/xonar_pcm179x.c @@ -1087,8 +1087,8 @@ static const struct oxygen_model model_xonar_st = { .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, }; -int __devinit get_xonar_pcm179x_model(struct oxygen *chip, - const struct pci_device_id *id) +int get_xonar_pcm179x_model(struct oxygen *chip, + const struct pci_device_id *id) { switch (id->subdevice) { case 0x8269: diff --git a/sound/pci/oxygen/xonar_wm87x6.c b/sound/pci/oxygen/xonar_wm87x6.c index 63cff90706bf..6ce68604c25e 100644 --- a/sound/pci/oxygen/xonar_wm87x6.c +++ b/sound/pci/oxygen/xonar_wm87x6.c @@ -1255,7 +1255,6 @@ static void dump_wm87x6_registers(struct oxygen *chip, } static const struct oxygen_model model_xonar_ds = { - .shortname = "Xonar DS", .longname = "Asus Virtuoso 66", .chip = "AV200", .init = xonar_ds_init, @@ -1321,12 +1320,17 @@ static const struct oxygen_model model_xonar_hdav_slim = { .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, }; -int __devinit get_xonar_wm87x6_model(struct oxygen *chip, - const struct pci_device_id *id) +int get_xonar_wm87x6_model(struct oxygen *chip, + const struct pci_device_id *id) { switch (id->subdevice) { case 0x838e: chip->model = model_xonar_ds; + chip->model.shortname = "Xonar DS"; + break; + case 0x8522: + chip->model = model_xonar_ds; + chip->model.shortname = "Xonar DSX"; break; case 0x835e: chip->model = model_xonar_hdav_slim; diff --git a/sound/pci/pcxhr/pcxhr.c b/sound/pci/pcxhr/pcxhr.c index be4f1456009a..b97384ad946d 100644 --- a/sound/pci/pcxhr/pcxhr.c +++ b/sound/pci/pcxhr/pcxhr.c @@ -1203,8 +1203,8 @@ static int pcxhr_chip_dev_free(struct snd_device *device) /* */ -static int __devinit pcxhr_create(struct pcxhr_mgr *mgr, - struct snd_card *card, int idx) +static int pcxhr_create(struct pcxhr_mgr *mgr, + struct snd_card *card, int idx) { int err; struct snd_pcxhr *chip; @@ -1453,7 +1453,7 @@ static void pcxhr_proc_ltc(struct snd_info_entry *entry, } } -static void __devinit pcxhr_proc_init(struct snd_pcxhr *chip) +static void pcxhr_proc_init(struct snd_pcxhr *chip) { struct snd_info_entry *entry; @@ -1513,8 +1513,8 @@ static int pcxhr_free(struct pcxhr_mgr *mgr) /* * probe function - creates the card manager */ -static int __devinit pcxhr_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int pcxhr_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { static int dev; struct pcxhr_mgr *mgr; @@ -1688,7 +1688,7 @@ static int __devinit pcxhr_probe(struct pci_dev *pci, return 0; } -static void __devexit pcxhr_remove(struct pci_dev *pci) +static void pcxhr_remove(struct pci_dev *pci) { pcxhr_free(pci_get_drvdata(pci)); pci_set_drvdata(pci, NULL); @@ -1698,7 +1698,7 @@ static struct pci_driver pcxhr_driver = { .name = KBUILD_MODNAME, .id_table = pcxhr_ids, .probe = pcxhr_probe, - .remove = __devexit_p(pcxhr_remove), + .remove = pcxhr_remove, }; module_pci_driver(pcxhr_driver); diff --git a/sound/pci/pcxhr/pcxhr_core.c b/sound/pci/pcxhr/pcxhr_core.c index b33db1e006e7..37b431b9b69d 100644 --- a/sound/pci/pcxhr/pcxhr_core.c +++ b/sound/pci/pcxhr/pcxhr_core.c @@ -1012,13 +1012,12 @@ static int pcxhr_handle_async_err(struct pcxhr_mgr *mgr, u32 err, enum pcxhr_async_err_src err_src, int pipe, int is_capture) { -#ifdef CONFIG_SND_DEBUG_VERBOSE static char* err_src_name[] = { [PCXHR_ERR_PIPE] = "Pipe", [PCXHR_ERR_STREAM] = "Stream", [PCXHR_ERR_AUDIO] = "Audio" }; -#endif + if (err & 0xfff) err &= 0xfff; else diff --git a/sound/pci/pcxhr/pcxhr_hwdep.c b/sound/pci/pcxhr/pcxhr_hwdep.c index bf207e317f71..d995175c1c48 100644 --- a/sound/pci/pcxhr/pcxhr_hwdep.c +++ b/sound/pci/pcxhr/pcxhr_hwdep.c @@ -35,13 +35,6 @@ #include "pcxhr_mix22.h" -#if defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE) -#if !defined(CONFIG_USE_PCXHRLOADER) && !defined(CONFIG_SND_PCXHR) /* built-in kernel */ -#define SND_PCXHR_FW_LOADER /* use the standard firmware loader */ -#endif -#endif - - static int pcxhr_sub_init(struct pcxhr_mgr *mgr); /* * get basic information and init pcxhr card @@ -362,8 +355,6 @@ static int pcxhr_dsp_load(struct pcxhr_mgr *mgr, int index, /* * fw loader entry */ -#ifdef SND_PCXHR_FW_LOADER - int pcxhr_setup_firmware(struct pcxhr_mgr *mgr) { static char *fw_files[][5] = { @@ -424,80 +415,3 @@ MODULE_FIRMWARE("pcxhr/xlxc924.dat"); MODULE_FIRMWARE("pcxhr/dspe924.e56"); MODULE_FIRMWARE("pcxhr/dspb924.b56"); MODULE_FIRMWARE("pcxhr/dspd222.d56"); - - -#else /* old style firmware loading */ - -/* pcxhr hwdep interface id string */ -#define PCXHR_HWDEP_ID "pcxhr loader" - - -static int pcxhr_hwdep_dsp_status(struct snd_hwdep *hw, - struct snd_hwdep_dsp_status *info) -{ - struct pcxhr_mgr *mgr = hw->private_data; - sprintf(info->id, "pcxhr%d", mgr->fw_file_set); - info->num_dsps = PCXHR_FIRMWARE_FILES_MAX_INDEX; - - if (hw->dsp_loaded & (1 << PCXHR_FIRMWARE_DSP_MAIN_INDEX)) - info->chip_ready = 1; - - info->version = PCXHR_DRIVER_VERSION; - return 0; -} - -static int pcxhr_hwdep_dsp_load(struct snd_hwdep *hw, - struct snd_hwdep_dsp_image *dsp) -{ - struct pcxhr_mgr *mgr = hw->private_data; - int err; - struct firmware fw; - - fw.size = dsp->length; - fw.data = vmalloc(fw.size); - if (! fw.data) { - snd_printk(KERN_ERR "pcxhr: cannot allocate dsp image " - "(%lu bytes)\n", (unsigned long)fw.size); - return -ENOMEM; - } - if (copy_from_user((void *)fw.data, dsp->image, dsp->length)) { - vfree(fw.data); - return -EFAULT; - } - err = pcxhr_dsp_load(mgr, dsp->index, &fw); - vfree(fw.data); - if (err < 0) - return err; - mgr->dsp_loaded |= 1 << dsp->index; - return 0; -} - -int pcxhr_setup_firmware(struct pcxhr_mgr *mgr) -{ - int err; - struct snd_hwdep *hw; - - /* only create hwdep interface for first cardX - * (see "index" module parameter) - */ - err = snd_hwdep_new(mgr->chip[0]->card, PCXHR_HWDEP_ID, 0, &hw); - if (err < 0) - return err; - - hw->iface = SNDRV_HWDEP_IFACE_PCXHR; - hw->private_data = mgr; - hw->ops.dsp_status = pcxhr_hwdep_dsp_status; - hw->ops.dsp_load = pcxhr_hwdep_dsp_load; - hw->exclusive = 1; - /* stereo cards don't need fw_file_0 -> dsp_loaded = 1 */ - hw->dsp_loaded = mgr->is_hr_stereo ? 1 : 0; - mgr->dsp_loaded = 0; - sprintf(hw->name, PCXHR_HWDEP_ID); - - err = snd_card_register(mgr->chip[0]->card); - if (err < 0) - return err; - return 0; -} - -#endif /* SND_PCXHR_FW_LOADER */ diff --git a/sound/pci/riptide/riptide.c b/sound/pci/riptide/riptide.c index 7d291542c5ba..63c1c8041554 100644 --- a/sound/pci/riptide/riptide.c +++ b/sound/pci/riptide/riptide.c @@ -1706,7 +1706,7 @@ static struct snd_pcm_ops snd_riptide_capture_ops = { .pointer = snd_riptide_pointer, }; -static int __devinit +static int snd_riptide_pcm(struct snd_riptide *chip, int device, struct snd_pcm **rpcm) { struct snd_pcm *pcm; @@ -1857,7 +1857,7 @@ static int snd_riptide_dev_free(struct snd_device *device) return snd_riptide_free(chip); } -static int __devinit +static int snd_riptide_create(struct snd_card *card, struct pci_dev *pci, struct snd_riptide **rchip) { @@ -1993,7 +1993,7 @@ snd_riptide_proc_read(struct snd_info_entry *entry, snd_iprintf(buffer, "\n"); } -static void __devinit snd_riptide_proc_init(struct snd_riptide *chip) +static void snd_riptide_proc_init(struct snd_riptide *chip) { struct snd_info_entry *entry; @@ -2001,7 +2001,7 @@ static void __devinit snd_riptide_proc_init(struct snd_riptide *chip) snd_info_set_text_ops(entry, chip, snd_riptide_proc_read); } -static int __devinit snd_riptide_mixer(struct snd_riptide *chip) +static int snd_riptide_mixer(struct snd_riptide *chip) { struct snd_ac97_bus *pbus; struct snd_ac97_template ac97; @@ -2027,7 +2027,7 @@ static int __devinit snd_riptide_mixer(struct snd_riptide *chip) #ifdef SUPPORT_JOYSTICK -static int __devinit +static int snd_riptide_joystick_probe(struct pci_dev *pci, const struct pci_device_id *id) { static int dev; @@ -2060,7 +2060,7 @@ snd_riptide_joystick_probe(struct pci_dev *pci, const struct pci_device_id *id) return 0; } -static void __devexit snd_riptide_joystick_remove(struct pci_dev *pci) +static void snd_riptide_joystick_remove(struct pci_dev *pci) { struct gameport *gameport = pci_get_drvdata(pci); if (gameport) { @@ -2071,7 +2071,7 @@ static void __devexit snd_riptide_joystick_remove(struct pci_dev *pci) } #endif -static int __devinit +static int snd_card_riptide_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { static int dev; @@ -2176,7 +2176,7 @@ snd_card_riptide_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) return err; } -static void __devexit snd_card_riptide_remove(struct pci_dev *pci) +static void snd_card_riptide_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); pci_set_drvdata(pci, NULL); @@ -2186,7 +2186,7 @@ static struct pci_driver driver = { .name = KBUILD_MODNAME, .id_table = snd_riptide_ids, .probe = snd_card_riptide_probe, - .remove = __devexit_p(snd_card_riptide_remove), + .remove = snd_card_riptide_remove, .driver = { .pm = RIPTIDE_PM_OPS, }, @@ -2197,7 +2197,7 @@ static struct pci_driver joystick_driver = { .name = KBUILD_MODNAME "-joystick", .id_table = snd_riptide_joystick_ids, .probe = snd_riptide_joystick_probe, - .remove = __devexit_p(snd_riptide_joystick_remove), + .remove = snd_riptide_joystick_remove, }; #endif diff --git a/sound/pci/rme32.c b/sound/pci/rme32.c index 46b3629dda22..2450663e1a18 100644 --- a/sound/pci/rme32.c +++ b/sound/pci/rme32.c @@ -1332,7 +1332,7 @@ snd_rme32_free_adat_pcm(struct snd_pcm *pcm) rme32->adat_pcm = NULL; } -static int __devinit snd_rme32_create(struct rme32 * rme32) +static int snd_rme32_create(struct rme32 *rme32) { struct pci_dev *pci = rme32->pci; int err; @@ -1554,7 +1554,7 @@ snd_rme32_proc_read(struct snd_info_entry * entry, struct snd_info_buffer *buffe } } -static void __devinit snd_rme32_proc_init(struct rme32 * rme32) +static void snd_rme32_proc_init(struct rme32 *rme32) { struct snd_info_entry *entry; @@ -1922,7 +1922,7 @@ static void snd_rme32_card_free(struct snd_card *card) snd_rme32_free(card->private_data); } -static int __devinit +static int snd_rme32_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { static int dev; @@ -1978,7 +1978,7 @@ snd_rme32_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) return 0; } -static void __devexit snd_rme32_remove(struct pci_dev *pci) +static void snd_rme32_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); pci_set_drvdata(pci, NULL); @@ -1988,7 +1988,7 @@ static struct pci_driver rme32_driver = { .name = KBUILD_MODNAME, .id_table = snd_rme32_ids, .probe = snd_rme32_probe, - .remove = __devexit_p(snd_rme32_remove), + .remove = snd_rme32_remove, }; module_pci_driver(rme32_driver); diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c index 9b98dc406988..5fb88ac82aa9 100644 --- a/sound/pci/rme96.c +++ b/sound/pci/rme96.c @@ -270,8 +270,7 @@ snd_rme96_playback_pointer(struct snd_pcm_substream *substream); static snd_pcm_uframes_t snd_rme96_capture_pointer(struct snd_pcm_substream *substream); -static void __devinit -snd_rme96_proc_init(struct rme96 *rme96); +static void snd_rme96_proc_init(struct rme96 *rme96); static int snd_rme96_create_switches(struct snd_card *card, @@ -1538,7 +1537,7 @@ snd_rme96_free_adat_pcm(struct snd_pcm *pcm) rme96->adat_pcm = NULL; } -static int __devinit +static int snd_rme96_create(struct rme96 *rme96) { struct pci_dev *pci = rme96->pci; @@ -1786,8 +1785,7 @@ snd_rme96_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer } } -static void __devinit -snd_rme96_proc_init(struct rme96 *rme96) +static void snd_rme96_proc_init(struct rme96 *rme96) { struct snd_info_entry *entry; @@ -2326,7 +2324,7 @@ static void snd_rme96_card_free(struct snd_card *card) snd_rme96_free(card->private_data); } -static int __devinit +static int snd_rme96_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { @@ -2389,7 +2387,7 @@ snd_rme96_probe(struct pci_dev *pci, return 0; } -static void __devexit snd_rme96_remove(struct pci_dev *pci) +static void snd_rme96_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); pci_set_drvdata(pci, NULL); @@ -2399,7 +2397,7 @@ static struct pci_driver rme96_driver = { .name = KBUILD_MODNAME, .id_table = snd_rme96_ids, .probe = snd_rme96_probe, - .remove = __devexit_p(snd_rme96_remove), + .remove = snd_rme96_remove, }; module_pci_driver(rme96_driver); diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c index 0d6930c4f4b7..94084cdb130c 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/sound/pci/rme9652/hdsp.c @@ -28,6 +28,7 @@ #include <linux/firmware.h> #include <linux/module.h> #include <linux/math64.h> +#include <linux/vmalloc.h> #include <sound/core.h> #include <sound/control.h> @@ -59,13 +60,11 @@ MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{RME Hammerfall-DSP}," "{RME HDSP-9652}," "{RME HDSP-9632}}"); -#ifdef HDSP_FW_LOADER MODULE_FIRMWARE("rpm_firmware.bin"); MODULE_FIRMWARE("multiface_firmware.bin"); MODULE_FIRMWARE("multiface_firmware_rev11.bin"); MODULE_FIRMWARE("digiface_firmware.bin"); MODULE_FIRMWARE("digiface_firmware_rev11.bin"); -#endif #define HDSP_MAX_CHANNELS 26 #define HDSP_MAX_DS_CHANNELS 14 @@ -155,10 +154,13 @@ MODULE_FIRMWARE("digiface_firmware_rev11.bin"); #define HDSP_BIGENDIAN_MODE 0x200 #define HDSP_RD_MULTIPLE 0x400 #define HDSP_9652_ENABLE_MIXER 0x800 +#define HDSP_S200 0x800 +#define HDSP_S300 (0x100 | HDSP_S200) /* dummy, purpose of 0x100 unknown */ +#define HDSP_CYCLIC_MODE 0x1000 #define HDSP_TDO 0x10000000 -#define HDSP_S_PROGRAM (HDSP_PROGRAM|HDSP_CONFIG_MODE_0) -#define HDSP_S_LOAD (HDSP_PROGRAM|HDSP_CONFIG_MODE_1) +#define HDSP_S_PROGRAM (HDSP_CYCLIC_MODE|HDSP_PROGRAM|HDSP_CONFIG_MODE_0) +#define HDSP_S_LOAD (HDSP_CYCLIC_MODE|HDSP_PROGRAM|HDSP_CONFIG_MODE_1) /* Control Register bits */ @@ -423,12 +425,7 @@ MODULE_FIRMWARE("digiface_firmware_rev11.bin"); #define HDSP_DMA_AREA_BYTES ((HDSP_MAX_CHANNELS+1) * HDSP_CHANNEL_BUFFER_BYTES) #define HDSP_DMA_AREA_KILOBYTES (HDSP_DMA_AREA_BYTES/1024) -/* use hotplug firmware loader? */ -#if defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE) -#if !defined(HDSP_USE_HWDEP_LOADER) -#define HDSP_FW_LOADER -#endif -#endif +#define HDSP_FIRMWARE_SIZE (24413 * 4) struct hdsp_9632_meters { u32 input_peak[16]; @@ -475,7 +472,8 @@ struct hdsp { enum HDSP_IO_Type io_type; /* ditto, but for code use */ unsigned short firmware_rev; unsigned short state; /* stores state bits */ - u32 firmware_cache[24413]; /* this helps recover from accidental iobox power failure */ + const struct firmware *firmware; + u32 *fw_uploaded; size_t period_bytes; /* guess what this is */ unsigned char max_channels; unsigned char qs_in_channels; /* quad speed mode for H9632 */ @@ -676,13 +674,23 @@ static unsigned int hdsp_read(struct hdsp *hdsp, int reg) static int hdsp_check_for_iobox (struct hdsp *hdsp) { + int i; + if (hdsp->io_type == H9652 || hdsp->io_type == H9632) return 0; - if (hdsp_read (hdsp, HDSP_statusRegister) & HDSP_ConfigError) { - snd_printk("Hammerfall-DSP: no IO box connected!\n"); - hdsp->state &= ~HDSP_FirmwareLoaded; - return -EIO; + for (i = 0; i < 500; i++) { + if (0 == (hdsp_read(hdsp, HDSP_statusRegister) & + HDSP_ConfigError)) { + if (i) { + snd_printd("Hammerfall-DSP: IO box found after %d ms\n", + (20 * i)); + } + return 0; + } + msleep(20); } - return 0; + snd_printk(KERN_ERR "Hammerfall-DSP: no IO box connected!\n"); + hdsp->state &= ~HDSP_FirmwareLoaded; + return -EIO; } static int hdsp_wait_for_iobox(struct hdsp *hdsp, unsigned int loops, @@ -712,6 +720,17 @@ static int snd_hdsp_load_firmware_from_cache(struct hdsp *hdsp) { int i; unsigned long flags; + const u32 *cache; + + if (hdsp->fw_uploaded) + cache = hdsp->fw_uploaded; + else { + if (!hdsp->firmware) + return -ENODEV; + cache = (u32 *)hdsp->firmware->data; + if (!cache) + return -ENODEV; + } if ((hdsp_read (hdsp, HDSP_statusRegister) & HDSP_DllError) != 0) { @@ -722,26 +741,25 @@ static int snd_hdsp_load_firmware_from_cache(struct hdsp *hdsp) { if (hdsp_fifo_wait (hdsp, 0, HDSP_LONG_WAIT)) { snd_printk ("Hammerfall-DSP: timeout waiting for download preparation\n"); + hdsp_write(hdsp, HDSP_control2Reg, HDSP_S200); return -EIO; } hdsp_write (hdsp, HDSP_control2Reg, HDSP_S_LOAD); - for (i = 0; i < 24413; ++i) { - hdsp_write(hdsp, HDSP_fifoData, hdsp->firmware_cache[i]); + for (i = 0; i < HDSP_FIRMWARE_SIZE / 4; ++i) { + hdsp_write(hdsp, HDSP_fifoData, cache[i]); if (hdsp_fifo_wait (hdsp, 127, HDSP_LONG_WAIT)) { snd_printk ("Hammerfall-DSP: timeout during firmware loading\n"); + hdsp_write(hdsp, HDSP_control2Reg, HDSP_S200); return -EIO; } } - ssleep(3); - - if (hdsp_fifo_wait (hdsp, 0, HDSP_LONG_WAIT)) { - snd_printk ("Hammerfall-DSP: timeout at end of firmware loading\n"); - return -EIO; - } + hdsp_fifo_wait(hdsp, 3, HDSP_LONG_WAIT); + hdsp_write(hdsp, HDSP_control2Reg, HDSP_S200); + ssleep(3); #ifdef SNDRV_BIG_ENDIAN hdsp->control2_register = HDSP_BIGENDIAN_MODE; #else @@ -767,24 +785,51 @@ static int hdsp_get_iobox_version (struct hdsp *hdsp) { if ((hdsp_read (hdsp, HDSP_statusRegister) & HDSP_DllError) != 0) { - hdsp_write (hdsp, HDSP_control2Reg, HDSP_PROGRAM); - hdsp_write (hdsp, HDSP_fifoData, 0); - if (hdsp_fifo_wait (hdsp, 0, HDSP_SHORT_WAIT) < 0) - return -EIO; + hdsp_write(hdsp, HDSP_control2Reg, HDSP_S_LOAD); + hdsp_write(hdsp, HDSP_fifoData, 0); - hdsp_write (hdsp, HDSP_control2Reg, HDSP_S_LOAD); + if (hdsp_fifo_wait(hdsp, 0, HDSP_SHORT_WAIT) < 0) { + hdsp_write(hdsp, HDSP_control2Reg, HDSP_S300); + hdsp_write(hdsp, HDSP_control2Reg, HDSP_S_LOAD); + } + + hdsp_write(hdsp, HDSP_control2Reg, HDSP_S200 | HDSP_PROGRAM); hdsp_write (hdsp, HDSP_fifoData, 0); + if (hdsp_fifo_wait(hdsp, 0, HDSP_SHORT_WAIT) < 0) { + hdsp->io_type = Multiface; + snd_printk("Hammerfall-DSP: Multiface found\n"); + return 0; + } - if (hdsp_fifo_wait(hdsp, 0, HDSP_SHORT_WAIT)) { - hdsp_write(hdsp, HDSP_control2Reg, HDSP_VERSION_BIT); - hdsp_write(hdsp, HDSP_control2Reg, HDSP_S_LOAD); - if (hdsp_fifo_wait(hdsp, 0, HDSP_SHORT_WAIT)) - hdsp->io_type = RPM; - else - hdsp->io_type = Multiface; - } else { + hdsp_write(hdsp, HDSP_control2Reg, HDSP_S_LOAD); + hdsp_write(hdsp, HDSP_fifoData, 0); + if (hdsp_fifo_wait(hdsp, 0, HDSP_SHORT_WAIT) == 0) { hdsp->io_type = Digiface; + snd_printk("Hammerfall-DSP: Digiface found\n"); + return 0; + } + + hdsp_write(hdsp, HDSP_control2Reg, HDSP_S300); + hdsp_write(hdsp, HDSP_control2Reg, HDSP_S_LOAD); + hdsp_write(hdsp, HDSP_fifoData, 0); + if (hdsp_fifo_wait(hdsp, 0, HDSP_SHORT_WAIT) == 0) { + hdsp->io_type = Multiface; + snd_printk("Hammerfall-DSP: Multiface found\n"); + return 0; } + + hdsp_write(hdsp, HDSP_control2Reg, HDSP_S300); + hdsp_write(hdsp, HDSP_control2Reg, HDSP_S_LOAD); + hdsp_write(hdsp, HDSP_fifoData, 0); + if (hdsp_fifo_wait(hdsp, 0, HDSP_SHORT_WAIT) < 0) { + hdsp->io_type = Multiface; + snd_printk("Hammerfall-DSP: Multiface found\n"); + return 0; + } + + hdsp->io_type = RPM; + snd_printk("Hammerfall-DSP: RPM found\n"); + return 0; } else { /* firmware was already loaded, get iobox type */ if (hdsp_read(hdsp, HDSP_status2Register) & HDSP_version2) @@ -798,9 +843,7 @@ static int hdsp_get_iobox_version (struct hdsp *hdsp) } -#ifdef HDSP_FW_LOADER static int hdsp_request_fw_loader(struct hdsp *hdsp); -#endif static int hdsp_check_for_firmware (struct hdsp *hdsp, int load_on_demand) { @@ -813,10 +856,8 @@ static int hdsp_check_for_firmware (struct hdsp *hdsp, int load_on_demand) snd_printk(KERN_ERR "Hammerfall-DSP: firmware not present.\n"); /* try to load firmware */ if (! (hdsp->state & HDSP_FirmwareCached)) { -#ifdef HDSP_FW_LOADER if (! hdsp_request_fw_loader(hdsp)) return 0; -#endif snd_printk(KERN_ERR "Hammerfall-DSP: No firmware loaded nor " "cached, please upload firmware.\n"); @@ -1672,171 +1713,50 @@ static int snd_hdsp_put_spdif_in(struct snd_kcontrol *kcontrol, struct snd_ctl_e return change; } -#define HDSP_SPDIF_OUT(xname, xindex) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ - .info = snd_hdsp_info_spdif_bits, \ - .get = snd_hdsp_get_spdif_out, .put = snd_hdsp_put_spdif_out } - -static int hdsp_spdif_out(struct hdsp *hdsp) -{ - return (hdsp->control_register & HDSP_SPDIFOpticalOut) ? 1 : 0; -} - -static int hdsp_set_spdif_output(struct hdsp *hdsp, int out) -{ - if (out) - hdsp->control_register |= HDSP_SPDIFOpticalOut; - else - hdsp->control_register &= ~HDSP_SPDIFOpticalOut; - hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register); - return 0; -} - -#define snd_hdsp_info_spdif_bits snd_ctl_boolean_mono_info - -static int snd_hdsp_get_spdif_out(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hdsp *hdsp = snd_kcontrol_chip(kcontrol); - - ucontrol->value.integer.value[0] = hdsp_spdif_out(hdsp); - return 0; -} - -static int snd_hdsp_put_spdif_out(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hdsp *hdsp = snd_kcontrol_chip(kcontrol); - int change; - unsigned int val; - - if (!snd_hdsp_use_is_exclusive(hdsp)) - return -EBUSY; - val = ucontrol->value.integer.value[0] & 1; - spin_lock_irq(&hdsp->lock); - change = (int)val != hdsp_spdif_out(hdsp); - hdsp_set_spdif_output(hdsp, val); - spin_unlock_irq(&hdsp->lock); - return change; +#define HDSP_TOGGLE_SETTING(xname, xindex) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .private_value = xindex, \ + .info = snd_hdsp_info_toggle_setting, \ + .get = snd_hdsp_get_toggle_setting, \ + .put = snd_hdsp_put_toggle_setting \ } -#define HDSP_SPDIF_PROFESSIONAL(xname, xindex) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ - .info = snd_hdsp_info_spdif_bits, \ - .get = snd_hdsp_get_spdif_professional, .put = snd_hdsp_put_spdif_professional } - -static int hdsp_spdif_professional(struct hdsp *hdsp) +static int hdsp_toggle_setting(struct hdsp *hdsp, u32 regmask) { - return (hdsp->control_register & HDSP_SPDIFProfessional) ? 1 : 0; + return (hdsp->control_register & regmask) ? 1 : 0; } -static int hdsp_set_spdif_professional(struct hdsp *hdsp, int val) +static int hdsp_set_toggle_setting(struct hdsp *hdsp, u32 regmask, int out) { - if (val) - hdsp->control_register |= HDSP_SPDIFProfessional; + if (out) + hdsp->control_register |= regmask; else - hdsp->control_register &= ~HDSP_SPDIFProfessional; + hdsp->control_register &= ~regmask; hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register); - return 0; -} - -static int snd_hdsp_get_spdif_professional(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hdsp *hdsp = snd_kcontrol_chip(kcontrol); - ucontrol->value.integer.value[0] = hdsp_spdif_professional(hdsp); return 0; } -static int snd_hdsp_put_spdif_professional(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hdsp *hdsp = snd_kcontrol_chip(kcontrol); - int change; - unsigned int val; +#define snd_hdsp_info_toggle_setting snd_ctl_boolean_mono_info - if (!snd_hdsp_use_is_exclusive(hdsp)) - return -EBUSY; - val = ucontrol->value.integer.value[0] & 1; - spin_lock_irq(&hdsp->lock); - change = (int)val != hdsp_spdif_professional(hdsp); - hdsp_set_spdif_professional(hdsp, val); - spin_unlock_irq(&hdsp->lock); - return change; -} - -#define HDSP_SPDIF_EMPHASIS(xname, xindex) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ - .info = snd_hdsp_info_spdif_bits, \ - .get = snd_hdsp_get_spdif_emphasis, .put = snd_hdsp_put_spdif_emphasis } - -static int hdsp_spdif_emphasis(struct hdsp *hdsp) -{ - return (hdsp->control_register & HDSP_SPDIFEmphasis) ? 1 : 0; -} - -static int hdsp_set_spdif_emphasis(struct hdsp *hdsp, int val) -{ - if (val) - hdsp->control_register |= HDSP_SPDIFEmphasis; - else - hdsp->control_register &= ~HDSP_SPDIFEmphasis; - hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register); - return 0; -} - -static int snd_hdsp_get_spdif_emphasis(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +static int snd_hdsp_get_toggle_setting(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { struct hdsp *hdsp = snd_kcontrol_chip(kcontrol); + u32 regmask = kcontrol->private_value; - ucontrol->value.integer.value[0] = hdsp_spdif_emphasis(hdsp); - return 0; -} - -static int snd_hdsp_put_spdif_emphasis(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hdsp *hdsp = snd_kcontrol_chip(kcontrol); - int change; - unsigned int val; - - if (!snd_hdsp_use_is_exclusive(hdsp)) - return -EBUSY; - val = ucontrol->value.integer.value[0] & 1; spin_lock_irq(&hdsp->lock); - change = (int)val != hdsp_spdif_emphasis(hdsp); - hdsp_set_spdif_emphasis(hdsp, val); + ucontrol->value.integer.value[0] = hdsp_toggle_setting(hdsp, regmask); spin_unlock_irq(&hdsp->lock); - return change; -} - -#define HDSP_SPDIF_NON_AUDIO(xname, xindex) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ - .info = snd_hdsp_info_spdif_bits, \ - .get = snd_hdsp_get_spdif_nonaudio, .put = snd_hdsp_put_spdif_nonaudio } - -static int hdsp_spdif_nonaudio(struct hdsp *hdsp) -{ - return (hdsp->control_register & HDSP_SPDIFNonAudio) ? 1 : 0; -} - -static int hdsp_set_spdif_nonaudio(struct hdsp *hdsp, int val) -{ - if (val) - hdsp->control_register |= HDSP_SPDIFNonAudio; - else - hdsp->control_register &= ~HDSP_SPDIFNonAudio; - hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register); - return 0; -} - -static int snd_hdsp_get_spdif_nonaudio(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hdsp *hdsp = snd_kcontrol_chip(kcontrol); - - ucontrol->value.integer.value[0] = hdsp_spdif_nonaudio(hdsp); return 0; } -static int snd_hdsp_put_spdif_nonaudio(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +static int snd_hdsp_put_toggle_setting(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { struct hdsp *hdsp = snd_kcontrol_chip(kcontrol); + u32 regmask = kcontrol->private_value; int change; unsigned int val; @@ -1844,8 +1764,9 @@ static int snd_hdsp_put_spdif_nonaudio(struct snd_kcontrol *kcontrol, struct snd return -EBUSY; val = ucontrol->value.integer.value[0] & 1; spin_lock_irq(&hdsp->lock); - change = (int)val != hdsp_spdif_nonaudio(hdsp); - hdsp_set_spdif_nonaudio(hdsp, val); + change = (int) val != hdsp_toggle_setting(hdsp, regmask); + if (change) + hdsp_set_toggle_setting(hdsp, regmask, val); spin_unlock_irq(&hdsp->lock); return change; } @@ -2449,114 +2370,6 @@ static int snd_hdsp_put_phone_gain(struct snd_kcontrol *kcontrol, struct snd_ctl return change; } -#define HDSP_XLR_BREAKOUT_CABLE(xname, xindex) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = xname, \ - .index = xindex, \ - .info = snd_hdsp_info_xlr_breakout_cable, \ - .get = snd_hdsp_get_xlr_breakout_cable, \ - .put = snd_hdsp_put_xlr_breakout_cable \ -} - -static int hdsp_xlr_breakout_cable(struct hdsp *hdsp) -{ - if (hdsp->control_register & HDSP_XLRBreakoutCable) - return 1; - return 0; -} - -static int hdsp_set_xlr_breakout_cable(struct hdsp *hdsp, int mode) -{ - if (mode) - hdsp->control_register |= HDSP_XLRBreakoutCable; - else - hdsp->control_register &= ~HDSP_XLRBreakoutCable; - hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register); - return 0; -} - -#define snd_hdsp_info_xlr_breakout_cable snd_ctl_boolean_mono_info - -static int snd_hdsp_get_xlr_breakout_cable(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hdsp *hdsp = snd_kcontrol_chip(kcontrol); - - ucontrol->value.enumerated.item[0] = hdsp_xlr_breakout_cable(hdsp); - return 0; -} - -static int snd_hdsp_put_xlr_breakout_cable(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hdsp *hdsp = snd_kcontrol_chip(kcontrol); - int change; - int val; - - if (!snd_hdsp_use_is_exclusive(hdsp)) - return -EBUSY; - val = ucontrol->value.integer.value[0] & 1; - spin_lock_irq(&hdsp->lock); - change = (int)val != hdsp_xlr_breakout_cable(hdsp); - hdsp_set_xlr_breakout_cable(hdsp, val); - spin_unlock_irq(&hdsp->lock); - return change; -} - -/* (De)activates old RME Analog Extension Board - These are connected to the internal ADAT connector - Switching this on desactivates external ADAT -*/ -#define HDSP_AEB(xname, xindex) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = xname, \ - .index = xindex, \ - .info = snd_hdsp_info_aeb, \ - .get = snd_hdsp_get_aeb, \ - .put = snd_hdsp_put_aeb \ -} - -static int hdsp_aeb(struct hdsp *hdsp) -{ - if (hdsp->control_register & HDSP_AnalogExtensionBoard) - return 1; - return 0; -} - -static int hdsp_set_aeb(struct hdsp *hdsp, int mode) -{ - if (mode) - hdsp->control_register |= HDSP_AnalogExtensionBoard; - else - hdsp->control_register &= ~HDSP_AnalogExtensionBoard; - hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register); - return 0; -} - -#define snd_hdsp_info_aeb snd_ctl_boolean_mono_info - -static int snd_hdsp_get_aeb(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hdsp *hdsp = snd_kcontrol_chip(kcontrol); - - ucontrol->value.enumerated.item[0] = hdsp_aeb(hdsp); - return 0; -} - -static int snd_hdsp_put_aeb(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hdsp *hdsp = snd_kcontrol_chip(kcontrol); - int change; - int val; - - if (!snd_hdsp_use_is_exclusive(hdsp)) - return -EBUSY; - val = ucontrol->value.integer.value[0] & 1; - spin_lock_irq(&hdsp->lock); - change = (int)val != hdsp_aeb(hdsp); - hdsp_set_aeb(hdsp, val); - spin_unlock_irq(&hdsp->lock); - return change; -} - #define HDSP_PREF_SYNC_REF(xname, xindex) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ .name = xname, \ @@ -2745,58 +2558,6 @@ static int snd_hdsp_get_autosync_ref(struct snd_kcontrol *kcontrol, struct snd_c return 0; } -#define HDSP_LINE_OUT(xname, xindex) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = xname, \ - .index = xindex, \ - .info = snd_hdsp_info_line_out, \ - .get = snd_hdsp_get_line_out, \ - .put = snd_hdsp_put_line_out \ -} - -static int hdsp_line_out(struct hdsp *hdsp) -{ - return (hdsp->control_register & HDSP_LineOut) ? 1 : 0; -} - -static int hdsp_set_line_output(struct hdsp *hdsp, int out) -{ - if (out) - hdsp->control_register |= HDSP_LineOut; - else - hdsp->control_register &= ~HDSP_LineOut; - hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register); - return 0; -} - -#define snd_hdsp_info_line_out snd_ctl_boolean_mono_info - -static int snd_hdsp_get_line_out(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hdsp *hdsp = snd_kcontrol_chip(kcontrol); - - spin_lock_irq(&hdsp->lock); - ucontrol->value.integer.value[0] = hdsp_line_out(hdsp); - spin_unlock_irq(&hdsp->lock); - return 0; -} - -static int snd_hdsp_put_line_out(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hdsp *hdsp = snd_kcontrol_chip(kcontrol); - int change; - unsigned int val; - - if (!snd_hdsp_use_is_exclusive(hdsp)) - return -EBUSY; - val = ucontrol->value.integer.value[0] & 1; - spin_lock_irq(&hdsp->lock); - change = (int)val != hdsp_line_out(hdsp); - hdsp_set_line_output(hdsp, val); - spin_unlock_irq(&hdsp->lock); - return change; -} - #define HDSP_PRECISE_POINTER(xname, xindex) \ { .iface = SNDRV_CTL_ELEM_IFACE_CARD, \ .name = xname, \ @@ -3188,7 +2949,7 @@ static struct snd_kcontrol_new snd_hdsp_9632_controls[] = { HDSP_DA_GAIN("DA Gain", 0), HDSP_AD_GAIN("AD Gain", 0), HDSP_PHONE_GAIN("Phones Gain", 0), -HDSP_XLR_BREAKOUT_CABLE("XLR Breakout Cable", 0), +HDSP_TOGGLE_SETTING("XLR Breakout Cable", HDSP_XLRBreakoutCable), HDSP_DDS_OFFSET("DDS Sample Rate Offset", 0) }; @@ -3230,10 +2991,10 @@ static struct snd_kcontrol_new snd_hdsp_controls[] = { }, HDSP_MIXER("Mixer", 0), HDSP_SPDIF_IN("IEC958 Input Connector", 0), -HDSP_SPDIF_OUT("IEC958 Output also on ADAT1", 0), -HDSP_SPDIF_PROFESSIONAL("IEC958 Professional Bit", 0), -HDSP_SPDIF_EMPHASIS("IEC958 Emphasis Bit", 0), -HDSP_SPDIF_NON_AUDIO("IEC958 Non-audio Bit", 0), +HDSP_TOGGLE_SETTING("IEC958 Output also on ADAT1", HDSP_SPDIFOpticalOut), +HDSP_TOGGLE_SETTING("IEC958 Professional Bit", HDSP_SPDIFProfessional), +HDSP_TOGGLE_SETTING("IEC958 Emphasis Bit", HDSP_SPDIFEmphasis), +HDSP_TOGGLE_SETTING("IEC958 Non-audio Bit", HDSP_SPDIFNonAudio), /* 'Sample Clock Source' complies with the alsa control naming scheme */ HDSP_CLOCK_SOURCE("Sample Clock Source", 0), { @@ -3253,7 +3014,7 @@ HDSP_AUTOSYNC_SAMPLE_RATE("External Rate", 0), HDSP_WC_SYNC_CHECK("Word Clock Lock Status", 0), HDSP_SPDIF_SYNC_CHECK("SPDIF Lock Status", 0), HDSP_ADATSYNC_SYNC_CHECK("ADAT Sync Lock Status", 0), -HDSP_LINE_OUT("Line Out", 0), +HDSP_TOGGLE_SETTING("Line Out", HDSP_LineOut), HDSP_PRECISE_POINTER("Precise Pointer", 0), HDSP_USE_MIDI_TASKLET("Use Midi Tasklet", 0), }; @@ -3570,7 +3331,9 @@ static struct snd_kcontrol_new snd_hdsp_rpm_controls[] = { HDSP_MIXER("Mixer", 0) }; -static struct snd_kcontrol_new snd_hdsp_96xx_aeb = HDSP_AEB("Analog Extension Board", 0); +static struct snd_kcontrol_new snd_hdsp_96xx_aeb = + HDSP_TOGGLE_SETTING("Analog Extension Board", + HDSP_AnalogExtensionBoard); static struct snd_kcontrol_new snd_hdsp_adat_sync_check = HDSP_ADAT_SYNC_CHECK; static int snd_hdsp_create_controls(struct snd_card *card, struct hdsp *hdsp) @@ -3673,9 +3436,7 @@ snd_hdsp_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) } } else { int err = -EINVAL; -#ifdef HDSP_FW_LOADER err = hdsp_request_fw_loader(hdsp); -#endif if (err < 0) { snd_iprintf(buffer, "No firmware loaded nor cached, " @@ -3995,7 +3756,9 @@ snd_hdsp_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) } snd_iprintf(buffer, "Phones Gain : %s\n", tmp); - snd_iprintf(buffer, "XLR Breakout Cable : %s\n", hdsp_xlr_breakout_cable(hdsp) ? "yes" : "no"); + snd_iprintf(buffer, "XLR Breakout Cable : %s\n", + hdsp_toggle_setting(hdsp, HDSP_XLRBreakoutCable) ? + "yes" : "no"); if (hdsp->control_register & HDSP_AnalogExtensionBoard) snd_iprintf(buffer, "AEB : on (ADAT1 internal)\n"); @@ -4020,7 +3783,7 @@ static void snd_hdsp_free_buffers(struct hdsp *hdsp) snd_hammerfall_free_buffer(&hdsp->playback_dma_buf, hdsp->pci); } -static int __devinit snd_hdsp_initialize_memory(struct hdsp *hdsp) +static int snd_hdsp_initialize_memory(struct hdsp *hdsp) { unsigned long pb_bus, cb_bus; @@ -5026,29 +4789,38 @@ static int snd_hdsp_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, unsigne for (i = 0; i < ((hdsp->io_type != Multiface && hdsp->io_type != RPM && hdsp->io_type != H9632) ? 3 : 1); ++i) info.adat_sync_check[i] = (unsigned char)hdsp_adat_sync_check(hdsp, i); info.spdif_in = (unsigned char)hdsp_spdif_in(hdsp); - info.spdif_out = (unsigned char)hdsp_spdif_out(hdsp); - info.spdif_professional = (unsigned char)hdsp_spdif_professional(hdsp); - info.spdif_emphasis = (unsigned char)hdsp_spdif_emphasis(hdsp); - info.spdif_nonaudio = (unsigned char)hdsp_spdif_nonaudio(hdsp); + info.spdif_out = (unsigned char)hdsp_toggle_setting(hdsp, + HDSP_SPDIFOpticalOut); + info.spdif_professional = (unsigned char) + hdsp_toggle_setting(hdsp, HDSP_SPDIFProfessional); + info.spdif_emphasis = (unsigned char) + hdsp_toggle_setting(hdsp, HDSP_SPDIFEmphasis); + info.spdif_nonaudio = (unsigned char) + hdsp_toggle_setting(hdsp, HDSP_SPDIFNonAudio); info.spdif_sample_rate = hdsp_spdif_sample_rate(hdsp); info.system_sample_rate = hdsp->system_sample_rate; info.autosync_sample_rate = hdsp_external_sample_rate(hdsp); info.system_clock_mode = (unsigned char)hdsp_system_clock_mode(hdsp); info.clock_source = (unsigned char)hdsp_clock_source(hdsp); info.autosync_ref = (unsigned char)hdsp_autosync_ref(hdsp); - info.line_out = (unsigned char)hdsp_line_out(hdsp); + info.line_out = (unsigned char) + hdsp_toggle_setting(hdsp, HDSP_LineOut); if (hdsp->io_type == H9632) { info.da_gain = (unsigned char)hdsp_da_gain(hdsp); info.ad_gain = (unsigned char)hdsp_ad_gain(hdsp); info.phone_gain = (unsigned char)hdsp_phone_gain(hdsp); - info.xlr_breakout_cable = (unsigned char)hdsp_xlr_breakout_cable(hdsp); + info.xlr_breakout_cable = + (unsigned char)hdsp_toggle_setting(hdsp, + HDSP_XLRBreakoutCable); } else if (hdsp->io_type == RPM) { info.da_gain = (unsigned char) hdsp_rpm_input12(hdsp); info.ad_gain = (unsigned char) hdsp_rpm_input34(hdsp); } if (hdsp->io_type == H9632 || hdsp->io_type == H9652) - info.analog_extension_board = (unsigned char)hdsp_aeb(hdsp); + info.analog_extension_board = + (unsigned char)hdsp_toggle_setting(hdsp, + HDSP_AnalogExtensionBoard); spin_unlock_irqrestore(&hdsp->lock, flags); if (copy_to_user(argp, &info, sizeof(info))) return -EFAULT; @@ -5100,8 +4872,18 @@ static int snd_hdsp_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, unsigne if (hdsp_check_for_iobox (hdsp)) return -EIO; - if (copy_from_user(hdsp->firmware_cache, firmware_data, sizeof(hdsp->firmware_cache)) != 0) + if (!hdsp->fw_uploaded) { + hdsp->fw_uploaded = vmalloc(HDSP_FIRMWARE_SIZE); + if (!hdsp->fw_uploaded) + return -ENOMEM; + } + + if (copy_from_user(hdsp->fw_uploaded, firmware_data, + HDSP_FIRMWARE_SIZE)) { + vfree(hdsp->fw_uploaded); + hdsp->fw_uploaded = NULL; return -EFAULT; + } hdsp->state |= HDSP_FirmwareCached; @@ -5330,7 +5112,6 @@ static int snd_hdsp_create_alsa_devices(struct snd_card *card, struct hdsp *hdsp return 0; } -#ifdef HDSP_FW_LOADER /* load firmware via hotplug fw loader */ static int hdsp_request_fw_loader(struct hdsp *hdsp) { @@ -5373,16 +5154,13 @@ static int hdsp_request_fw_loader(struct hdsp *hdsp) snd_printk(KERN_ERR "Hammerfall-DSP: cannot load firmware %s\n", fwfile); return -ENOENT; } - if (fw->size < sizeof(hdsp->firmware_cache)) { + if (fw->size < HDSP_FIRMWARE_SIZE) { snd_printk(KERN_ERR "Hammerfall-DSP: too short firmware size %d (expected %d)\n", - (int)fw->size, (int)sizeof(hdsp->firmware_cache)); - release_firmware(fw); + (int)fw->size, HDSP_FIRMWARE_SIZE); return -EINVAL; } - memcpy(hdsp->firmware_cache, fw->data, sizeof(hdsp->firmware_cache)); - - release_firmware(fw); + hdsp->firmware = fw; hdsp->state |= HDSP_FirmwareCached; @@ -5406,10 +5184,9 @@ static int hdsp_request_fw_loader(struct hdsp *hdsp) } return 0; } -#endif -static int __devinit snd_hdsp_create(struct snd_card *card, - struct hdsp *hdsp) +static int snd_hdsp_create(struct snd_card *card, + struct hdsp *hdsp) { struct pci_dev *pci = hdsp->pci; int err; @@ -5504,7 +5281,6 @@ static int __devinit snd_hdsp_create(struct snd_card *card, return err; if ((hdsp_read (hdsp, HDSP_statusRegister) & HDSP_DllError) != 0) { -#ifdef HDSP_FW_LOADER if ((err = hdsp_request_fw_loader(hdsp)) < 0) /* we don't fail as this can happen if userspace is not ready for @@ -5514,7 +5290,6 @@ static int __devinit snd_hdsp_create(struct snd_card *card, else /* init is complete, we return */ return 0; -#endif /* we defer initialization */ snd_printk(KERN_INFO "Hammerfall-DSP: card initialization pending : waiting for firmware\n"); if ((err = snd_hdsp_create_hwdep(card, hdsp)) < 0) @@ -5568,6 +5343,10 @@ static int snd_hdsp_free(struct hdsp *hdsp) snd_hdsp_free_buffers(hdsp); + if (hdsp->firmware) + release_firmware(hdsp->firmware); + vfree(hdsp->fw_uploaded); + if (hdsp->iobase) iounmap(hdsp->iobase); @@ -5586,8 +5365,8 @@ static void snd_hdsp_card_free(struct snd_card *card) snd_hdsp_free(hdsp); } -static int __devinit snd_hdsp_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int snd_hdsp_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { static int dev; struct hdsp *hdsp; @@ -5630,7 +5409,7 @@ static int __devinit snd_hdsp_probe(struct pci_dev *pci, return 0; } -static void __devexit snd_hdsp_remove(struct pci_dev *pci) +static void snd_hdsp_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); pci_set_drvdata(pci, NULL); @@ -5640,7 +5419,7 @@ static struct pci_driver hdsp_driver = { .name = KBUILD_MODNAME, .id_table = snd_hdsp_ids, .probe = snd_hdsp_probe, - .remove = __devexit_p(snd_hdsp_remove), + .remove = snd_hdsp_remove, }; module_pci_driver(hdsp_driver); diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index 748e36c66603..223c3d9cc69e 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -441,6 +441,7 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}"); */ /* status */ #define HDSPM_AES32_wcLock 0x0200000 +#define HDSPM_AES32_wcSync 0x0100000 #define HDSPM_AES32_wcFreq_bit 22 /* (status >> HDSPM_AES32_wcFreq_bit) & 0xF gives WC frequency (cf function HDSPM_bit2freq */ @@ -962,10 +963,10 @@ static DEFINE_PCI_DEVICE_TABLE(snd_hdspm_ids) = { MODULE_DEVICE_TABLE(pci, snd_hdspm_ids); /* prototypes */ -static int __devinit snd_hdspm_create_alsa_devices(struct snd_card *card, - struct hdspm * hdspm); -static int __devinit snd_hdspm_create_pcm(struct snd_card *card, - struct hdspm * hdspm); +static int snd_hdspm_create_alsa_devices(struct snd_card *card, + struct hdspm *hdspm); +static int snd_hdspm_create_pcm(struct snd_card *card, + struct hdspm *hdspm); static inline void snd_hdspm_initialize_midi_flush(struct hdspm *hdspm); static int hdspm_update_simple_mixer_controls(struct hdspm *hdspm); @@ -1845,8 +1846,8 @@ static struct snd_rawmidi_ops snd_hdspm_midi_input = .trigger = snd_hdspm_midi_input_trigger, }; -static int __devinit snd_hdspm_create_midi (struct snd_card *card, - struct hdspm *hdspm, int id) +static int snd_hdspm_create_midi(struct snd_card *card, + struct hdspm *hdspm, int id) { int err; char buf[32]; @@ -2887,162 +2888,50 @@ static int snd_hdspm_get_autosync_ref(struct snd_kcontrol *kcontrol, return 0; } - -#define HDSPM_LINE_OUT(xname, xindex) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = xname, \ - .index = xindex, \ - .info = snd_hdspm_info_line_out, \ - .get = snd_hdspm_get_line_out, \ - .put = snd_hdspm_put_line_out \ -} - -static int hdspm_line_out(struct hdspm * hdspm) -{ - return (hdspm->control_register & HDSPM_LineOut) ? 1 : 0; -} - - -static int hdspm_set_line_output(struct hdspm * hdspm, int out) -{ - if (out) - hdspm->control_register |= HDSPM_LineOut; - else - hdspm->control_register &= ~HDSPM_LineOut; - hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); - - return 0; -} - -#define snd_hdspm_info_line_out snd_ctl_boolean_mono_info - -static int snd_hdspm_get_line_out(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); - - spin_lock_irq(&hdspm->lock); - ucontrol->value.integer.value[0] = hdspm_line_out(hdspm); - spin_unlock_irq(&hdspm->lock); - return 0; -} - -static int snd_hdspm_put_line_out(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); - int change; - unsigned int val; - - if (!snd_hdspm_use_is_exclusive(hdspm)) - return -EBUSY; - val = ucontrol->value.integer.value[0] & 1; - spin_lock_irq(&hdspm->lock); - change = (int) val != hdspm_line_out(hdspm); - hdspm_set_line_output(hdspm, val); - spin_unlock_irq(&hdspm->lock); - return change; -} - - -#define HDSPM_TX_64(xname, xindex) \ +#define HDSPM_TOGGLE_SETTING(xname, xindex) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ .name = xname, \ - .index = xindex, \ - .info = snd_hdspm_info_tx_64, \ - .get = snd_hdspm_get_tx_64, \ - .put = snd_hdspm_put_tx_64 \ -} - -static int hdspm_tx_64(struct hdspm * hdspm) -{ - return (hdspm->control_register & HDSPM_TX_64ch) ? 1 : 0; -} - -static int hdspm_set_tx_64(struct hdspm * hdspm, int out) -{ - if (out) - hdspm->control_register |= HDSPM_TX_64ch; - else - hdspm->control_register &= ~HDSPM_TX_64ch; - hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); - - return 0; -} - -#define snd_hdspm_info_tx_64 snd_ctl_boolean_mono_info - -static int snd_hdspm_get_tx_64(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); - - spin_lock_irq(&hdspm->lock); - ucontrol->value.integer.value[0] = hdspm_tx_64(hdspm); - spin_unlock_irq(&hdspm->lock); - return 0; -} - -static int snd_hdspm_put_tx_64(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); - int change; - unsigned int val; - - if (!snd_hdspm_use_is_exclusive(hdspm)) - return -EBUSY; - val = ucontrol->value.integer.value[0] & 1; - spin_lock_irq(&hdspm->lock); - change = (int) val != hdspm_tx_64(hdspm); - hdspm_set_tx_64(hdspm, val); - spin_unlock_irq(&hdspm->lock); - return change; -} - - -#define HDSPM_C_TMS(xname, xindex) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = xname, \ - .index = xindex, \ - .info = snd_hdspm_info_c_tms, \ - .get = snd_hdspm_get_c_tms, \ - .put = snd_hdspm_put_c_tms \ + .private_value = xindex, \ + .info = snd_hdspm_info_toggle_setting, \ + .get = snd_hdspm_get_toggle_setting, \ + .put = snd_hdspm_put_toggle_setting \ } -static int hdspm_c_tms(struct hdspm * hdspm) +static int hdspm_toggle_setting(struct hdspm *hdspm, u32 regmask) { - return (hdspm->control_register & HDSPM_clr_tms) ? 1 : 0; + return (hdspm->control_register & regmask) ? 1 : 0; } -static int hdspm_set_c_tms(struct hdspm * hdspm, int out) +static int hdspm_set_toggle_setting(struct hdspm *hdspm, u32 regmask, int out) { if (out) - hdspm->control_register |= HDSPM_clr_tms; + hdspm->control_register |= regmask; else - hdspm->control_register &= ~HDSPM_clr_tms; + hdspm->control_register &= ~regmask; hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); return 0; } -#define snd_hdspm_info_c_tms snd_ctl_boolean_mono_info +#define snd_hdspm_info_toggle_setting snd_ctl_boolean_mono_info -static int snd_hdspm_get_c_tms(struct snd_kcontrol *kcontrol, +static int snd_hdspm_get_toggle_setting(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); + u32 regmask = kcontrol->private_value; spin_lock_irq(&hdspm->lock); - ucontrol->value.integer.value[0] = hdspm_c_tms(hdspm); + ucontrol->value.integer.value[0] = hdspm_toggle_setting(hdspm, regmask); spin_unlock_irq(&hdspm->lock); return 0; } -static int snd_hdspm_put_c_tms(struct snd_kcontrol *kcontrol, +static int snd_hdspm_put_toggle_setting(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); + u32 regmask = kcontrol->private_value; int change; unsigned int val; @@ -3050,232 +2939,8 @@ static int snd_hdspm_put_c_tms(struct snd_kcontrol *kcontrol, return -EBUSY; val = ucontrol->value.integer.value[0] & 1; spin_lock_irq(&hdspm->lock); - change = (int) val != hdspm_c_tms(hdspm); - hdspm_set_c_tms(hdspm, val); - spin_unlock_irq(&hdspm->lock); - return change; -} - - -#define HDSPM_SAFE_MODE(xname, xindex) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = xname, \ - .index = xindex, \ - .info = snd_hdspm_info_safe_mode, \ - .get = snd_hdspm_get_safe_mode, \ - .put = snd_hdspm_put_safe_mode \ -} - -static int hdspm_safe_mode(struct hdspm * hdspm) -{ - return (hdspm->control_register & HDSPM_AutoInp) ? 1 : 0; -} - -static int hdspm_set_safe_mode(struct hdspm * hdspm, int out) -{ - if (out) - hdspm->control_register |= HDSPM_AutoInp; - else - hdspm->control_register &= ~HDSPM_AutoInp; - hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); - - return 0; -} - -#define snd_hdspm_info_safe_mode snd_ctl_boolean_mono_info - -static int snd_hdspm_get_safe_mode(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); - - spin_lock_irq(&hdspm->lock); - ucontrol->value.integer.value[0] = hdspm_safe_mode(hdspm); - spin_unlock_irq(&hdspm->lock); - return 0; -} - -static int snd_hdspm_put_safe_mode(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); - int change; - unsigned int val; - - if (!snd_hdspm_use_is_exclusive(hdspm)) - return -EBUSY; - val = ucontrol->value.integer.value[0] & 1; - spin_lock_irq(&hdspm->lock); - change = (int) val != hdspm_safe_mode(hdspm); - hdspm_set_safe_mode(hdspm, val); - spin_unlock_irq(&hdspm->lock); - return change; -} - - -#define HDSPM_EMPHASIS(xname, xindex) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = xname, \ - .index = xindex, \ - .info = snd_hdspm_info_emphasis, \ - .get = snd_hdspm_get_emphasis, \ - .put = snd_hdspm_put_emphasis \ -} - -static int hdspm_emphasis(struct hdspm * hdspm) -{ - return (hdspm->control_register & HDSPM_Emphasis) ? 1 : 0; -} - -static int hdspm_set_emphasis(struct hdspm * hdspm, int emp) -{ - if (emp) - hdspm->control_register |= HDSPM_Emphasis; - else - hdspm->control_register &= ~HDSPM_Emphasis; - hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); - - return 0; -} - -#define snd_hdspm_info_emphasis snd_ctl_boolean_mono_info - -static int snd_hdspm_get_emphasis(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); - - spin_lock_irq(&hdspm->lock); - ucontrol->value.enumerated.item[0] = hdspm_emphasis(hdspm); - spin_unlock_irq(&hdspm->lock); - return 0; -} - -static int snd_hdspm_put_emphasis(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); - int change; - unsigned int val; - - if (!snd_hdspm_use_is_exclusive(hdspm)) - return -EBUSY; - val = ucontrol->value.integer.value[0] & 1; - spin_lock_irq(&hdspm->lock); - change = (int) val != hdspm_emphasis(hdspm); - hdspm_set_emphasis(hdspm, val); - spin_unlock_irq(&hdspm->lock); - return change; -} - - -#define HDSPM_DOLBY(xname, xindex) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = xname, \ - .index = xindex, \ - .info = snd_hdspm_info_dolby, \ - .get = snd_hdspm_get_dolby, \ - .put = snd_hdspm_put_dolby \ -} - -static int hdspm_dolby(struct hdspm * hdspm) -{ - return (hdspm->control_register & HDSPM_Dolby) ? 1 : 0; -} - -static int hdspm_set_dolby(struct hdspm * hdspm, int dol) -{ - if (dol) - hdspm->control_register |= HDSPM_Dolby; - else - hdspm->control_register &= ~HDSPM_Dolby; - hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); - - return 0; -} - -#define snd_hdspm_info_dolby snd_ctl_boolean_mono_info - -static int snd_hdspm_get_dolby(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); - - spin_lock_irq(&hdspm->lock); - ucontrol->value.enumerated.item[0] = hdspm_dolby(hdspm); - spin_unlock_irq(&hdspm->lock); - return 0; -} - -static int snd_hdspm_put_dolby(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); - int change; - unsigned int val; - - if (!snd_hdspm_use_is_exclusive(hdspm)) - return -EBUSY; - val = ucontrol->value.integer.value[0] & 1; - spin_lock_irq(&hdspm->lock); - change = (int) val != hdspm_dolby(hdspm); - hdspm_set_dolby(hdspm, val); - spin_unlock_irq(&hdspm->lock); - return change; -} - - -#define HDSPM_PROFESSIONAL(xname, xindex) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = xname, \ - .index = xindex, \ - .info = snd_hdspm_info_professional, \ - .get = snd_hdspm_get_professional, \ - .put = snd_hdspm_put_professional \ -} - -static int hdspm_professional(struct hdspm * hdspm) -{ - return (hdspm->control_register & HDSPM_Professional) ? 1 : 0; -} - -static int hdspm_set_professional(struct hdspm * hdspm, int dol) -{ - if (dol) - hdspm->control_register |= HDSPM_Professional; - else - hdspm->control_register &= ~HDSPM_Professional; - hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); - - return 0; -} - -#define snd_hdspm_info_professional snd_ctl_boolean_mono_info - -static int snd_hdspm_get_professional(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); - - spin_lock_irq(&hdspm->lock); - ucontrol->value.enumerated.item[0] = hdspm_professional(hdspm); - spin_unlock_irq(&hdspm->lock); - return 0; -} - -static int snd_hdspm_put_professional(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); - int change; - unsigned int val; - - if (!snd_hdspm_use_is_exclusive(hdspm)) - return -EBUSY; - val = ucontrol->value.integer.value[0] & 1; - spin_lock_irq(&hdspm->lock); - change = (int) val != hdspm_professional(hdspm); - hdspm_set_professional(hdspm, val); + change = (int) val != hdspm_toggle_setting(hdspm, regmask); + hdspm_set_toggle_setting(hdspm, regmask, val); spin_unlock_irq(&hdspm->lock); return change; } @@ -3803,10 +3468,12 @@ static int hdspm_wc_sync_check(struct hdspm *hdspm) switch (hdspm->io_type) { case AES32: status = hdspm_read(hdspm, HDSPM_statusRegister); - if (status & HDSPM_wcSync) - return 2; - else if (status & HDSPM_wcLock) - return 1; + if (status & HDSPM_AES32_wcLock) { + if (status & HDSPM_AES32_wcSync) + return 2; + else + return 1; + } return 0; break; @@ -4476,10 +4143,10 @@ static struct snd_kcontrol_new snd_hdspm_controls_madi[] = { HDSPM_SYNC_CHECK("MADI SyncCheck", 1), HDSPM_SYNC_CHECK("TCO SyncCheck", 2), HDSPM_SYNC_CHECK("SYNC IN SyncCheck", 3), - HDSPM_LINE_OUT("Line Out", 0), - HDSPM_TX_64("TX 64 channels mode", 0), - HDSPM_C_TMS("Clear Track Marker", 0), - HDSPM_SAFE_MODE("Safe Mode", 0), + HDSPM_TOGGLE_SETTING("Line Out", HDSPM_LineOut), + HDSPM_TOGGLE_SETTING("TX 64 channels mode", HDSPM_TX_64ch), + HDSPM_TOGGLE_SETTING("Clear Track Marker", HDSPM_clr_tms), + HDSPM_TOGGLE_SETTING("Safe Mode", HDSPM_AutoInp), HDSPM_INPUT_SELECT("Input Select", 0), HDSPM_MADI_SPEEDMODE("MADI Speed Mode", 0) }; @@ -4492,9 +4159,9 @@ static struct snd_kcontrol_new snd_hdspm_controls_madiface[] = { HDSPM_SYSTEM_SAMPLE_RATE("System Sample Rate", 0), HDSPM_AUTOSYNC_SAMPLE_RATE("External Rate", 0), HDSPM_SYNC_CHECK("MADI SyncCheck", 0), - HDSPM_TX_64("TX 64 channels mode", 0), - HDSPM_C_TMS("Clear Track Marker", 0), - HDSPM_SAFE_MODE("Safe Mode", 0), + HDSPM_TOGGLE_SETTING("TX 64 channels mode", HDSPM_TX_64ch), + HDSPM_TOGGLE_SETTING("Clear Track Marker", HDSPM_clr_tms), + HDSPM_TOGGLE_SETTING("Safe Mode", HDSPM_AutoInp), HDSPM_MADI_SPEEDMODE("MADI Speed Mode", 0) }; @@ -4587,11 +4254,11 @@ static struct snd_kcontrol_new snd_hdspm_controls_aes32[] = { HDSPM_AUTOSYNC_SAMPLE_RATE("AES8 Frequency", 8), HDSPM_AUTOSYNC_SAMPLE_RATE("TCO Frequency", 9), HDSPM_AUTOSYNC_SAMPLE_RATE("SYNC IN Frequency", 10), - HDSPM_LINE_OUT("Line Out", 0), - HDSPM_EMPHASIS("Emphasis", 0), - HDSPM_DOLBY("Non Audio", 0), - HDSPM_PROFESSIONAL("Professional", 0), - HDSPM_C_TMS("Clear Track Marker", 0), + HDSPM_TOGGLE_SETTING("Line Out", HDSPM_LineOut), + HDSPM_TOGGLE_SETTING("Emphasis", HDSPM_Emphasis), + HDSPM_TOGGLE_SETTING("Non Audio", HDSPM_Dolby), + HDSPM_TOGGLE_SETTING("Professional", HDSPM_Professional), + HDSPM_TOGGLE_SETTING("Clear Track Marker", HDSPM_clr_tms), HDSPM_DS_WIRE("Double Speed Wire Mode", 0), HDSPM_QS_WIRE("Quad Speed Wire Mode", 0), }; @@ -4994,6 +4661,7 @@ snd_hdspm_proc_read_aes32(struct snd_info_entry * entry, unsigned int status; unsigned int status2; unsigned int timecode; + unsigned int wcLock, wcSync; int pref_syncref; char *autosync_ref; int x; @@ -5087,8 +4755,11 @@ snd_hdspm_proc_read_aes32(struct snd_info_entry * entry, snd_iprintf(buffer, "--- Status:\n"); + wcLock = status & HDSPM_AES32_wcLock; + wcSync = wcLock && (status & HDSPM_AES32_wcSync); + snd_iprintf(buffer, "Word: %s Frequency: %d\n", - (status & HDSPM_AES32_wcLock) ? "Sync " : "No Lock", + (wcLock) ? (wcSync ? "Sync " : "Lock ") : "No Lock", HDSPM_bit2freq((status >> HDSPM_AES32_wcFreq_bit) & 0xF)); for (x = 0; x < 8; x++) { @@ -5233,7 +4904,7 @@ static void snd_hdspm_proc_ports_out(struct snd_info_entry *entry, } -static void __devinit snd_hdspm_proc_init(struct hdspm *hdspm) +static void snd_hdspm_proc_init(struct hdspm *hdspm) { struct snd_info_entry *entry; @@ -6266,7 +5937,7 @@ static int snd_hdspm_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, info.system_clock_mode = hdspm_system_clock_mode(hdspm); info.clock_source = hdspm_clock_source(hdspm); info.autosync_ref = hdspm_autosync_ref(hdspm); - info.line_out = hdspm_line_out(hdspm); + info.line_out = hdspm_toggle_setting(hdspm, HDSPM_LineOut); info.passthru = 0; spin_unlock_irq(&hdspm->lock); if (copy_to_user(argp, &info, sizeof(info))) @@ -6369,8 +6040,8 @@ static struct snd_pcm_ops snd_hdspm_capture_ops = { .page = snd_pcm_sgbuf_ops_page, }; -static int __devinit snd_hdspm_create_hwdep(struct snd_card *card, - struct hdspm * hdspm) +static int snd_hdspm_create_hwdep(struct snd_card *card, + struct hdspm *hdspm) { struct snd_hwdep *hw; int err; @@ -6395,7 +6066,7 @@ static int __devinit snd_hdspm_create_hwdep(struct snd_card *card, /*------------------------------------------------------------ memory interface ------------------------------------------------------------*/ -static int __devinit snd_hdspm_preallocate_memory(struct hdspm *hdspm) +static int snd_hdspm_preallocate_memory(struct hdspm *hdspm) { int err; struct snd_pcm *pcm; @@ -6436,8 +6107,8 @@ static void hdspm_set_sgbuf(struct hdspm *hdspm, /* ------------- ALSA Devices ---------------------------- */ -static int __devinit snd_hdspm_create_pcm(struct snd_card *card, - struct hdspm *hdspm) +static int snd_hdspm_create_pcm(struct snd_card *card, + struct hdspm *hdspm) { struct snd_pcm *pcm; int err; @@ -6472,8 +6143,8 @@ static inline void snd_hdspm_initialize_midi_flush(struct hdspm * hdspm) snd_hdspm_flush_midi_input(hdspm, i); } -static int __devinit snd_hdspm_create_alsa_devices(struct snd_card *card, - struct hdspm * hdspm) +static int snd_hdspm_create_alsa_devices(struct snd_card *card, + struct hdspm *hdspm) { int err, i; @@ -6531,8 +6202,9 @@ static int __devinit snd_hdspm_create_alsa_devices(struct snd_card *card, return 0; } -static int __devinit snd_hdspm_create(struct snd_card *card, - struct hdspm *hdspm) { +static int snd_hdspm_create(struct snd_card *card, + struct hdspm *hdspm) +{ struct pci_dev *pci = hdspm->pci; int err; @@ -6905,8 +6577,8 @@ static void snd_hdspm_card_free(struct snd_card *card) } -static int __devinit snd_hdspm_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int snd_hdspm_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { static int dev; struct hdspm *hdspm; @@ -6964,7 +6636,7 @@ static int __devinit snd_hdspm_probe(struct pci_dev *pci, return 0; } -static void __devexit snd_hdspm_remove(struct pci_dev *pci) +static void snd_hdspm_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); pci_set_drvdata(pci, NULL); @@ -6974,7 +6646,7 @@ static struct pci_driver hdspm_driver = { .name = KBUILD_MODNAME, .id_table = snd_hdspm_ids, .probe = snd_hdspm_probe, - .remove = __devexit_p(snd_hdspm_remove), + .remove = snd_hdspm_remove, }; module_pci_driver(hdspm_driver); diff --git a/sound/pci/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c index a15fc100ab0c..773a67fff4cd 100644 --- a/sound/pci/rme9652/rme9652.c +++ b/sound/pci/rme9652/rme9652.c @@ -1757,7 +1757,7 @@ snd_rme9652_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buff snd_iprintf(buffer, "\n"); } -static void __devinit snd_rme9652_proc_init(struct snd_rme9652 *rme9652) +static void snd_rme9652_proc_init(struct snd_rme9652 *rme9652) { struct snd_info_entry *entry; @@ -1788,7 +1788,7 @@ static int snd_rme9652_free(struct snd_rme9652 *rme9652) return 0; } -static int __devinit snd_rme9652_initialize_memory(struct snd_rme9652 *rme9652) +static int snd_rme9652_initialize_memory(struct snd_rme9652 *rme9652) { unsigned long pb_bus, cb_bus; @@ -2414,8 +2414,8 @@ static struct snd_pcm_ops snd_rme9652_capture_ops = { .copy = snd_rme9652_capture_copy, }; -static int __devinit snd_rme9652_create_pcm(struct snd_card *card, - struct snd_rme9652 *rme9652) +static int snd_rme9652_create_pcm(struct snd_card *card, + struct snd_rme9652 *rme9652) { struct snd_pcm *pcm; int err; @@ -2438,9 +2438,9 @@ static int __devinit snd_rme9652_create_pcm(struct snd_card *card, return 0; } -static int __devinit snd_rme9652_create(struct snd_card *card, - struct snd_rme9652 *rme9652, - int precise_ptr) +static int snd_rme9652_create(struct snd_card *card, + struct snd_rme9652 *rme9652, + int precise_ptr) { struct pci_dev *pci = rme9652->pci; int err; @@ -2578,8 +2578,8 @@ static void snd_rme9652_card_free(struct snd_card *card) snd_rme9652_free(rme9652); } -static int __devinit snd_rme9652_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int snd_rme9652_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { static int dev; struct snd_rme9652 *rme9652; @@ -2625,7 +2625,7 @@ static int __devinit snd_rme9652_probe(struct pci_dev *pci, return 0; } -static void __devexit snd_rme9652_remove(struct pci_dev *pci) +static void snd_rme9652_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); pci_set_drvdata(pci, NULL); @@ -2635,7 +2635,7 @@ static struct pci_driver rme9652_driver = { .name = KBUILD_MODNAME, .id_table = snd_rme9652_ids, .probe = snd_rme9652_probe, - .remove = __devexit_p(snd_rme9652_remove), + .remove = snd_rme9652_remove, }; module_pci_driver(rme9652_driver); diff --git a/sound/pci/sis7019.c b/sound/pci/sis7019.c index 51e43407ebc5..d59abe1682c5 100644 --- a/sound/pci/sis7019.c +++ b/sound/pci/sis7019.c @@ -894,7 +894,7 @@ static struct snd_pcm_ops sis_capture_ops = { .pointer = sis_pcm_pointer, }; -static int __devinit sis_pcm_create(struct sis7019 *sis) +static int sis_pcm_create(struct sis7019 *sis) { struct snd_pcm *pcm; int rc; @@ -1013,7 +1013,7 @@ static unsigned short sis_ac97_read(struct snd_ac97 *ac97, unsigned short reg) (reg << 8) | cmd[ac97->num]); } -static int __devinit sis_mixer_create(struct sis7019 *sis) +static int sis_mixer_create(struct sis7019 *sis) { struct snd_ac97_bus *bus; struct snd_ac97_template ac97; @@ -1171,7 +1171,7 @@ static int sis_chip_init(struct sis7019 *sis) outl(SIS_DMA_CSR_PCI_SETTINGS, io + SIS_DMA_CSR); /* Reset the synchronization groups for all of the channels - * to be asyncronous. If we start doing SPDIF or 5.1 sound, etc. + * to be asynchronous. If we start doing SPDIF or 5.1 sound, etc. * we'll need to change how we handle these. Until then, we just * assign sub-mixer 0 to all playback channels, and avoid any * attenuation on the audio. @@ -1326,8 +1326,8 @@ static int sis_alloc_suspend(struct sis7019 *sis) return 0; } -static int __devinit sis_chip_create(struct snd_card *card, - struct pci_dev *pci) +static int sis_chip_create(struct snd_card *card, + struct pci_dev *pci) { struct sis7019 *sis = card->private_data; struct voice *voice; @@ -1417,8 +1417,8 @@ error_out: return rc; } -static int __devinit snd_sis7019_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int snd_sis7019_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { struct snd_card *card; struct sis7019 *sis; @@ -1478,7 +1478,7 @@ error_out: return rc; } -static void __devexit snd_sis7019_remove(struct pci_dev *pci) +static void snd_sis7019_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); pci_set_drvdata(pci, NULL); @@ -1488,7 +1488,7 @@ static struct pci_driver sis7019_driver = { .name = KBUILD_MODNAME, .id_table = snd_sis7019_ids, .probe = snd_sis7019_probe, - .remove = __devexit_p(snd_sis7019_remove), + .remove = snd_sis7019_remove, .driver = { .pm = SIS_PM_OPS, }, diff --git a/sound/pci/sonicvibes.c b/sound/pci/sonicvibes.c index baa9946bedf0..a2e7686e7ae3 100644 --- a/sound/pci/sonicvibes.c +++ b/sound/pci/sonicvibes.c @@ -877,7 +877,8 @@ static struct snd_pcm_ops snd_sonicvibes_capture_ops = { .pointer = snd_sonicvibes_capture_pointer, }; -static int __devinit snd_sonicvibes_pcm(struct sonicvibes * sonic, int device, struct snd_pcm ** rpcm) +static int snd_sonicvibes_pcm(struct sonicvibes *sonic, int device, + struct snd_pcm **rpcm) { struct snd_pcm *pcm; int err; @@ -1087,7 +1088,7 @@ static int snd_sonicvibes_put_double(struct snd_kcontrol *kcontrol, struct snd_c return change; } -static struct snd_kcontrol_new snd_sonicvibes_controls[] __devinitdata = { +static struct snd_kcontrol_new snd_sonicvibes_controls[] = { SONICVIBES_DOUBLE("Capture Volume", 0, SV_IREG_LEFT_ADC, SV_IREG_RIGHT_ADC, 0, 0, 15, 0), SONICVIBES_DOUBLE("Aux Playback Switch", 0, SV_IREG_LEFT_AUX1, SV_IREG_RIGHT_AUX1, 7, 7, 1, 1), SONICVIBES_DOUBLE("Aux Playback Volume", 0, SV_IREG_LEFT_AUX1, SV_IREG_RIGHT_AUX1, 0, 0, 31, 1), @@ -1118,7 +1119,7 @@ static void snd_sonicvibes_master_free(struct snd_kcontrol *kcontrol) sonic->master_volume = NULL; } -static int __devinit snd_sonicvibes_mixer(struct sonicvibes * sonic) +static int snd_sonicvibes_mixer(struct sonicvibes *sonic) { struct snd_card *card; struct snd_kcontrol *kctl; @@ -1175,7 +1176,7 @@ static void snd_sonicvibes_proc_read(struct snd_info_entry *entry, snd_iprintf(buffer, "MIDI to ext. Tx : %s\n", tmp & 0x04 ? "on" : "off"); } -static void __devinit snd_sonicvibes_proc_init(struct sonicvibes * sonic) +static void snd_sonicvibes_proc_init(struct sonicvibes *sonic) { struct snd_info_entry *entry; @@ -1188,10 +1189,10 @@ static void __devinit snd_sonicvibes_proc_init(struct sonicvibes * sonic) */ #ifdef SUPPORT_JOYSTICK -static struct snd_kcontrol_new snd_sonicvibes_game_control __devinitdata = +static struct snd_kcontrol_new snd_sonicvibes_game_control = SONICVIBES_SINGLE("Joystick Speed", 0, SV_IREG_GAME_PORT, 1, 15, 0); -static int __devinit snd_sonicvibes_create_gameport(struct sonicvibes *sonic) +static int snd_sonicvibes_create_gameport(struct sonicvibes *sonic) { struct gameport *gp; @@ -1246,11 +1247,11 @@ static int snd_sonicvibes_dev_free(struct snd_device *device) return snd_sonicvibes_free(sonic); } -static int __devinit snd_sonicvibes_create(struct snd_card *card, - struct pci_dev *pci, - int reverb, - int mge, - struct sonicvibes ** rsonic) +static int snd_sonicvibes_create(struct snd_card *card, + struct pci_dev *pci, + int reverb, + int mge, + struct sonicvibes **rsonic) { struct sonicvibes *sonic; unsigned int dmaa, dmac; @@ -1401,7 +1402,7 @@ static int __devinit snd_sonicvibes_create(struct snd_card *card, * MIDI section */ -static struct snd_kcontrol_new snd_sonicvibes_midi_controls[] __devinitdata = { +static struct snd_kcontrol_new snd_sonicvibes_midi_controls[] = { SONICVIBES_SINGLE("SonicVibes Wave Source RAM", 0, SV_IREG_WAVE_SOURCE, 0, 1, 0), SONICVIBES_SINGLE("SonicVibes Wave Source RAM+ROM", 0, SV_IREG_WAVE_SOURCE, 1, 1, 0), SONICVIBES_SINGLE("SonicVibes Onboard Synth", 0, SV_IREG_MPU401, 0, 1, 0), @@ -1422,8 +1423,8 @@ static void snd_sonicvibes_midi_input_close(struct snd_mpu401 * mpu) outb(sonic->irqmask |= SV_MIDI_MASK, SV_REG(sonic, IRQMASK)); } -static int __devinit snd_sonicvibes_midi(struct sonicvibes * sonic, - struct snd_rawmidi *rmidi) +static int snd_sonicvibes_midi(struct sonicvibes *sonic, + struct snd_rawmidi *rmidi) { struct snd_mpu401 * mpu = rmidi->private_data; struct snd_card *card = sonic->card; @@ -1441,8 +1442,8 @@ static int __devinit snd_sonicvibes_midi(struct sonicvibes * sonic, return 0; } -static int __devinit snd_sonic_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int snd_sonic_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { static int dev; struct snd_card *card; @@ -1524,7 +1525,7 @@ static int __devinit snd_sonic_probe(struct pci_dev *pci, return 0; } -static void __devexit snd_sonic_remove(struct pci_dev *pci) +static void snd_sonic_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); pci_set_drvdata(pci, NULL); @@ -1534,7 +1535,7 @@ static struct pci_driver sonicvibes_driver = { .name = KBUILD_MODNAME, .id_table = snd_sonic_ids, .probe = snd_sonic_probe, - .remove = __devexit_p(snd_sonic_remove), + .remove = snd_sonic_remove, }; module_pci_driver(sonicvibes_driver); diff --git a/sound/pci/trident/trident.c b/sound/pci/trident/trident.c index 8a6f1f76e870..1aefd6204a63 100644 --- a/sound/pci/trident/trident.c +++ b/sound/pci/trident/trident.c @@ -73,8 +73,8 @@ static DEFINE_PCI_DEVICE_TABLE(snd_trident_ids) = { MODULE_DEVICE_TABLE(pci, snd_trident_ids); -static int __devinit snd_trident_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int snd_trident_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { static int dev; struct snd_card *card; @@ -166,7 +166,7 @@ static int __devinit snd_trident_probe(struct pci_dev *pci, return 0; } -static void __devexit snd_trident_remove(struct pci_dev *pci) +static void snd_trident_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); pci_set_drvdata(pci, NULL); @@ -176,7 +176,7 @@ static struct pci_driver trident_driver = { .name = KBUILD_MODNAME, .id_table = snd_trident_ids, .probe = snd_trident_probe, - .remove = __devexit_p(snd_trident_remove), + .remove = snd_trident_remove, #ifdef CONFIG_PM_SLEEP .driver = { .pm = &snd_trident_pm, diff --git a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c index 06b10d1a76e5..fb0e1586a6f8 100644 --- a/sound/pci/trident/trident_main.c +++ b/sound/pci/trident/trident_main.c @@ -2171,8 +2171,8 @@ static struct snd_pcm_ops snd_trident_spdif_7018_ops = { ---------------------------------------------------------------------------*/ -int __devinit snd_trident_pcm(struct snd_trident * trident, - int device, struct snd_pcm ** rpcm) +int snd_trident_pcm(struct snd_trident *trident, + int device, struct snd_pcm **rpcm) { struct snd_pcm *pcm; int err; @@ -2229,8 +2229,8 @@ int __devinit snd_trident_pcm(struct snd_trident * trident, ---------------------------------------------------------------------------*/ -int __devinit snd_trident_foldback_pcm(struct snd_trident * trident, - int device, struct snd_pcm ** rpcm) +int snd_trident_foldback_pcm(struct snd_trident *trident, + int device, struct snd_pcm **rpcm) { struct snd_pcm *foldback; int err; @@ -2286,8 +2286,8 @@ int __devinit snd_trident_foldback_pcm(struct snd_trident * trident, ---------------------------------------------------------------------------*/ -int __devinit snd_trident_spdif_pcm(struct snd_trident * trident, - int device, struct snd_pcm ** rpcm) +int snd_trident_spdif_pcm(struct snd_trident *trident, + int device, struct snd_pcm **rpcm) { struct snd_pcm *spdif; int err; @@ -2371,7 +2371,7 @@ static int snd_trident_spdif_control_put(struct snd_kcontrol *kcontrol, return change; } -static struct snd_kcontrol_new snd_trident_spdif_control __devinitdata = +static struct snd_kcontrol_new snd_trident_spdif_control = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,SWITCH), @@ -2434,7 +2434,7 @@ static int snd_trident_spdif_default_put(struct snd_kcontrol *kcontrol, return change; } -static struct snd_kcontrol_new snd_trident_spdif_default __devinitdata = +static struct snd_kcontrol_new snd_trident_spdif_default = { .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), @@ -2467,7 +2467,7 @@ static int snd_trident_spdif_mask_get(struct snd_kcontrol *kcontrol, return 0; } -static struct snd_kcontrol_new snd_trident_spdif_mask __devinitdata = +static struct snd_kcontrol_new snd_trident_spdif_mask = { .access = SNDRV_CTL_ELEM_ACCESS_READ, .iface = SNDRV_CTL_ELEM_IFACE_PCM, @@ -2529,7 +2529,7 @@ static int snd_trident_spdif_stream_put(struct snd_kcontrol *kcontrol, return change; } -static struct snd_kcontrol_new snd_trident_spdif_stream __devinitdata = +static struct snd_kcontrol_new snd_trident_spdif_stream = { .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, .iface = SNDRV_CTL_ELEM_IFACE_PCM, @@ -2579,7 +2579,7 @@ static int snd_trident_ac97_control_put(struct snd_kcontrol *kcontrol, return change; } -static struct snd_kcontrol_new snd_trident_ac97_rear_control __devinitdata = +static struct snd_kcontrol_new snd_trident_ac97_rear_control = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Rear Path", @@ -2637,7 +2637,7 @@ static int snd_trident_vol_control_put(struct snd_kcontrol *kcontrol, return change; } -static struct snd_kcontrol_new snd_trident_vol_music_control __devinitdata = +static struct snd_kcontrol_new snd_trident_vol_music_control = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Music Playback Volume", @@ -2648,7 +2648,7 @@ static struct snd_kcontrol_new snd_trident_vol_music_control __devinitdata = .tlv = { .p = db_scale_gvol }, }; -static struct snd_kcontrol_new snd_trident_vol_wave_control __devinitdata = +static struct snd_kcontrol_new snd_trident_vol_wave_control = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Wave Playback Volume", @@ -2715,7 +2715,7 @@ static int snd_trident_pcm_vol_control_put(struct snd_kcontrol *kcontrol, return change; } -static struct snd_kcontrol_new snd_trident_pcm_vol_control __devinitdata = +static struct snd_kcontrol_new snd_trident_pcm_vol_control = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "PCM Front Playback Volume", @@ -2779,7 +2779,7 @@ static int snd_trident_pcm_pan_control_put(struct snd_kcontrol *kcontrol, return change; } -static struct snd_kcontrol_new snd_trident_pcm_pan_control __devinitdata = +static struct snd_kcontrol_new snd_trident_pcm_pan_control = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "PCM Pan Playback Control", @@ -2836,7 +2836,7 @@ static int snd_trident_pcm_rvol_control_put(struct snd_kcontrol *kcontrol, static const DECLARE_TLV_DB_SCALE(db_scale_crvol, -3175, 25, 1); -static struct snd_kcontrol_new snd_trident_pcm_rvol_control __devinitdata = +static struct snd_kcontrol_new snd_trident_pcm_rvol_control = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "PCM Reverb Playback Volume", @@ -2892,7 +2892,7 @@ static int snd_trident_pcm_cvol_control_put(struct snd_kcontrol *kcontrol, return change; } -static struct snd_kcontrol_new snd_trident_pcm_cvol_control __devinitdata = +static struct snd_kcontrol_new snd_trident_pcm_cvol_control = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "PCM Chorus Playback Volume", @@ -2972,7 +2972,7 @@ static int snd_trident_pcm_mixer_free(struct snd_trident *trident, struct snd_tr ---------------------------------------------------------------------------*/ -static int __devinit snd_trident_mixer(struct snd_trident * trident, int pcm_spdif_device) +static int snd_trident_mixer(struct snd_trident *trident, int pcm_spdif_device) { struct snd_ac97_template _ac97; struct snd_card *card = trident->card; @@ -3191,7 +3191,7 @@ static int snd_trident_gameport_open(struct gameport *gameport, int mode) } } -int __devinit snd_trident_create_gameport(struct snd_trident *chip) +int snd_trident_create_gameport(struct snd_trident *chip) { struct gameport *gp; @@ -3225,7 +3225,7 @@ static inline void snd_trident_free_gameport(struct snd_trident *chip) } } #else -int __devinit snd_trident_create_gameport(struct snd_trident *chip) { return -ENOSYS; } +int snd_trident_create_gameport(struct snd_trident *chip) { return -ENOSYS; } static inline void snd_trident_free_gameport(struct snd_trident *chip) { } #endif /* CONFIG_GAMEPORT */ @@ -3329,7 +3329,7 @@ static void snd_trident_proc_read(struct snd_info_entry *entry, } } -static void __devinit snd_trident_proc_init(struct snd_trident * trident) +static void snd_trident_proc_init(struct snd_trident *trident) { struct snd_info_entry *entry; const char *s = "trident"; @@ -3358,7 +3358,7 @@ static int snd_trident_dev_free(struct snd_device *device) ---------------------------------------------------------------------------*/ -static int __devinit snd_trident_tlb_alloc(struct snd_trident *trident) +static int snd_trident_tlb_alloc(struct snd_trident *trident) { int i; @@ -3539,7 +3539,7 @@ static int snd_trident_sis_init(struct snd_trident *trident) ---------------------------------------------------------------------------*/ -int __devinit snd_trident_create(struct snd_card *card, +int snd_trident_create(struct snd_card *card, struct pci_dev *pci, int pcm_streams, int pcm_spdif_device, diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index f0b4efdb483c..d756a3562706 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c @@ -1437,7 +1437,7 @@ static void init_viadev(struct via82xx *chip, int idx, unsigned int reg_offset, /* * create pcm instances for VIA8233, 8233C and 8235 (not 8233A) */ -static int __devinit snd_via8233_pcm_new(struct via82xx *chip) +static int snd_via8233_pcm_new(struct via82xx *chip) { struct snd_pcm *pcm; struct snd_pcm_chmap *chmap; @@ -1505,7 +1505,7 @@ static int __devinit snd_via8233_pcm_new(struct via82xx *chip) /* * create pcm instances for VIA8233A */ -static int __devinit snd_via8233a_pcm_new(struct via82xx *chip) +static int snd_via8233a_pcm_new(struct via82xx *chip) { struct snd_pcm *pcm; struct snd_pcm_chmap *chmap; @@ -1566,7 +1566,7 @@ static int __devinit snd_via8233a_pcm_new(struct via82xx *chip) /* * create a pcm instance for via686a/b */ -static int __devinit snd_via686_pcm_new(struct via82xx *chip) +static int snd_via686_pcm_new(struct via82xx *chip) { struct snd_pcm *pcm; int err; @@ -1643,7 +1643,7 @@ static int snd_via8233_capture_source_put(struct snd_kcontrol *kcontrol, return val != oval; } -static struct snd_kcontrol_new snd_via8233_capture_source __devinitdata = { +static struct snd_kcontrol_new snd_via8233_capture_source = { .name = "Input Source Select", .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .info = snd_via8233_capture_source_info, @@ -1683,7 +1683,7 @@ static int snd_via8233_dxs3_spdif_put(struct snd_kcontrol *kcontrol, return 0; } -static struct snd_kcontrol_new snd_via8233_dxs3_spdif_control __devinitdata = { +static struct snd_kcontrol_new snd_via8233_dxs3_spdif_control = { .name = SNDRV_CTL_NAME_IEC958("Output ",NONE,SWITCH), .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .info = snd_via8233_dxs3_spdif_info, @@ -1772,7 +1772,7 @@ static int snd_via8233_pcmdxs_volume_put(struct snd_kcontrol *kcontrol, static const DECLARE_TLV_DB_SCALE(db_scale_dxs, -4650, 150, 1); -static struct snd_kcontrol_new snd_via8233_pcmdxs_volume_control __devinitdata = { +static struct snd_kcontrol_new snd_via8233_pcmdxs_volume_control = { .name = "PCM Playback Volume", .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | @@ -1783,7 +1783,7 @@ static struct snd_kcontrol_new snd_via8233_pcmdxs_volume_control __devinitdata = .tlv = { .p = db_scale_dxs } }; -static struct snd_kcontrol_new snd_via8233_dxs_volume_control __devinitdata = { +static struct snd_kcontrol_new snd_via8233_dxs_volume_control = { .iface = SNDRV_CTL_ELEM_IFACE_PCM, .device = 0, /* .subdevice set later */ @@ -1895,7 +1895,7 @@ static struct ac97_quirk ac97_quirks[] = { { } /* terminator */ }; -static int __devinit snd_via82xx_mixer_new(struct via82xx *chip, const char *quirk_override) +static int snd_via82xx_mixer_new(struct via82xx *chip, const char *quirk_override) { struct snd_ac97_template ac97; int err; @@ -1930,7 +1930,7 @@ static int __devinit snd_via82xx_mixer_new(struct via82xx *chip, const char *qui #ifdef SUPPORT_JOYSTICK #define JOYSTICK_ADDR 0x200 -static int __devinit snd_via686_create_gameport(struct via82xx *chip, unsigned char *legacy) +static int snd_via686_create_gameport(struct via82xx *chip, unsigned char *legacy) { struct gameport *gp; struct resource *r; @@ -1990,7 +1990,7 @@ static inline void snd_via686_free_gameport(struct via82xx *chip) { } * */ -static int __devinit snd_via8233_init_misc(struct via82xx *chip) +static int snd_via8233_init_misc(struct via82xx *chip) { int i, err, caps; unsigned char val; @@ -2047,7 +2047,7 @@ static int __devinit snd_via8233_init_misc(struct via82xx *chip) return 0; } -static int __devinit snd_via686_init_misc(struct via82xx *chip) +static int snd_via686_init_misc(struct via82xx *chip) { unsigned char legacy, legacy_cfg; int rev_h = 0; @@ -2137,7 +2137,7 @@ static void snd_via82xx_proc_read(struct snd_info_entry *entry, } } -static void __devinit snd_via82xx_proc_init(struct via82xx *chip) +static void snd_via82xx_proc_init(struct via82xx *chip) { struct snd_info_entry *entry; @@ -2370,12 +2370,12 @@ static int snd_via82xx_dev_free(struct snd_device *device) return snd_via82xx_free(chip); } -static int __devinit snd_via82xx_create(struct snd_card *card, - struct pci_dev *pci, - int chip_type, - int revision, - unsigned int ac97_clock, - struct via82xx ** r_via) +static int snd_via82xx_create(struct snd_card *card, + struct pci_dev *pci, + int chip_type, + int revision, + unsigned int ac97_clock, + struct via82xx **r_via) { struct via82xx *chip; int err; @@ -2452,7 +2452,7 @@ struct via823x_info { char *name; int type; }; -static struct via823x_info via823x_cards[] __devinitdata = { +static struct via823x_info via823x_cards[] = { { VIA_REV_PRE_8233, "VIA 8233-Pre", TYPE_VIA8233 }, { VIA_REV_8233C, "VIA 8233C", TYPE_VIA8233 }, { VIA_REV_8233, "VIA 8233", TYPE_VIA8233 }, @@ -2466,7 +2466,7 @@ static struct via823x_info via823x_cards[] __devinitdata = { * auto detection of DXS channel supports. */ -static struct snd_pci_quirk dxs_whitelist[] __devinitdata = { +static struct snd_pci_quirk dxs_whitelist[] = { SND_PCI_QUIRK(0x1005, 0x4710, "Avance Logic Mobo", VIA_DXS_ENABLE), SND_PCI_QUIRK(0x1019, 0x0996, "ESC Mobo", VIA_DXS_48K), SND_PCI_QUIRK(0x1019, 0x0a81, "ECS K7VTA3 v8.0", VIA_DXS_NO_VRA), @@ -2510,14 +2510,14 @@ static struct snd_pci_quirk dxs_whitelist[] __devinitdata = { { } /* terminator */ }; -static int __devinit check_dxs_list(struct pci_dev *pci, int revision) +static int check_dxs_list(struct pci_dev *pci, int revision) { const struct snd_pci_quirk *w; w = snd_pci_quirk_lookup(pci, dxs_whitelist); if (w) { snd_printdd(KERN_INFO "via82xx: DXS white list for %s found\n", - w->name); + snd_pci_quirk_name(w)); return w->value; } @@ -2535,8 +2535,8 @@ static int __devinit check_dxs_list(struct pci_dev *pci, int revision) return VIA_DXS_48K; }; -static int __devinit snd_via82xx_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int snd_via82xx_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { struct snd_card *card; struct via82xx *chip; @@ -2643,7 +2643,7 @@ static int __devinit snd_via82xx_probe(struct pci_dev *pci, return err; } -static void __devexit snd_via82xx_remove(struct pci_dev *pci) +static void snd_via82xx_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); pci_set_drvdata(pci, NULL); @@ -2653,7 +2653,7 @@ static struct pci_driver via82xx_driver = { .name = KBUILD_MODNAME, .id_table = snd_via82xx_ids, .probe = snd_via82xx_probe, - .remove = __devexit_p(snd_via82xx_remove), + .remove = snd_via82xx_remove, .driver = { .pm = SND_VIA82XX_PM_OPS, }, diff --git a/sound/pci/via82xx_modem.c b/sound/pci/via82xx_modem.c index 8e0efc416f22..4f5fd80b7e56 100644 --- a/sound/pci/via82xx_modem.c +++ b/sound/pci/via82xx_modem.c @@ -836,7 +836,7 @@ static void init_viadev(struct via82xx_modem *chip, int idx, unsigned int reg_of /* * create a pcm instance for via686a/b */ -static int __devinit snd_via686_pcm_new(struct via82xx_modem *chip) +static int snd_via686_pcm_new(struct via82xx_modem *chip) { struct snd_pcm *pcm; int err; @@ -885,7 +885,7 @@ static void snd_via82xx_mixer_free_ac97(struct snd_ac97 *ac97) } -static int __devinit snd_via82xx_mixer_new(struct via82xx_modem *chip) +static int snd_via82xx_mixer_new(struct via82xx_modem *chip) { struct snd_ac97_template ac97; int err; @@ -928,7 +928,7 @@ static void snd_via82xx_proc_read(struct snd_info_entry *entry, struct snd_info_ } } -static void __devinit snd_via82xx_proc_init(struct via82xx_modem *chip) +static void snd_via82xx_proc_init(struct via82xx_modem *chip) { struct snd_info_entry *entry; @@ -1103,12 +1103,12 @@ static int snd_via82xx_dev_free(struct snd_device *device) return snd_via82xx_free(chip); } -static int __devinit snd_via82xx_create(struct snd_card *card, - struct pci_dev *pci, - int chip_type, - int revision, - unsigned int ac97_clock, - struct via82xx_modem ** r_via) +static int snd_via82xx_create(struct snd_card *card, + struct pci_dev *pci, + int chip_type, + int revision, + unsigned int ac97_clock, + struct via82xx_modem **r_via) { struct via82xx_modem *chip; int err; @@ -1168,8 +1168,8 @@ static int __devinit snd_via82xx_create(struct snd_card *card, } -static int __devinit snd_via82xx_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int snd_via82xx_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { struct snd_card *card; struct via82xx_modem *chip; @@ -1224,7 +1224,7 @@ static int __devinit snd_via82xx_probe(struct pci_dev *pci, return err; } -static void __devexit snd_via82xx_remove(struct pci_dev *pci) +static void snd_via82xx_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); pci_set_drvdata(pci, NULL); @@ -1234,7 +1234,7 @@ static struct pci_driver via82xx_modem_driver = { .name = KBUILD_MODNAME, .id_table = snd_via82xx_modem_ids, .probe = snd_via82xx_probe, - .remove = __devexit_p(snd_via82xx_remove), + .remove = snd_via82xx_remove, .driver = { .pm = SND_VIA82XX_PM_OPS, }, diff --git a/sound/pci/vx222/vx222.c b/sound/pci/vx222/vx222.c index fdfbaf857233..e2f1ab37e154 100644 --- a/sound/pci/vx222/vx222.c +++ b/sound/pci/vx222/vx222.c @@ -134,9 +134,9 @@ static int snd_vx222_dev_free(struct snd_device *device) } -static int __devinit snd_vx222_create(struct snd_card *card, struct pci_dev *pci, - struct snd_vx_hardware *hw, - struct snd_vx222 **rchip) +static int snd_vx222_create(struct snd_card *card, struct pci_dev *pci, + struct snd_vx_hardware *hw, + struct snd_vx222 **rchip) { struct vx_core *chip; struct snd_vx222 *vx; @@ -188,8 +188,8 @@ static int __devinit snd_vx222_create(struct snd_card *card, struct pci_dev *pci } -static int __devinit snd_vx222_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int snd_vx222_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { static int dev; struct snd_card *card; @@ -251,7 +251,7 @@ static int __devinit snd_vx222_probe(struct pci_dev *pci, return 0; } -static void __devexit snd_vx222_remove(struct pci_dev *pci) +static void snd_vx222_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); pci_set_drvdata(pci, NULL); @@ -300,7 +300,7 @@ static struct pci_driver vx222_driver = { .name = KBUILD_MODNAME, .id_table = snd_vx222_ids, .probe = snd_vx222_probe, - .remove = __devexit_p(snd_vx222_remove), + .remove = snd_vx222_remove, .driver = { .pm = SND_VX222_PM_OPS, }, diff --git a/sound/pci/ymfpci/ymfpci.c b/sound/pci/ymfpci/ymfpci.c index e01fe34db9ec..01c49655a3c1 100644 --- a/sound/pci/ymfpci/ymfpci.c +++ b/sound/pci/ymfpci/ymfpci.c @@ -79,8 +79,8 @@ static DEFINE_PCI_DEVICE_TABLE(snd_ymfpci_ids) = { MODULE_DEVICE_TABLE(pci, snd_ymfpci_ids); #ifdef SUPPORT_JOYSTICK -static int __devinit snd_ymfpci_create_gameport(struct snd_ymfpci *chip, int dev, - int legacy_ctrl, int legacy_ctrl2) +static int snd_ymfpci_create_gameport(struct snd_ymfpci *chip, int dev, + int legacy_ctrl, int legacy_ctrl2) { struct gameport *gp; struct resource *r = NULL; @@ -167,8 +167,8 @@ static inline int snd_ymfpci_create_gameport(struct snd_ymfpci *chip, int dev, i void snd_ymfpci_free_gameport(struct snd_ymfpci *chip) { } #endif /* SUPPORT_JOYSTICK */ -static int __devinit snd_card_ymfpci_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int snd_card_ymfpci_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { static int dev; struct snd_card *card; @@ -344,7 +344,7 @@ static int __devinit snd_card_ymfpci_probe(struct pci_dev *pci, return 0; } -static void __devexit snd_card_ymfpci_remove(struct pci_dev *pci) +static void snd_card_ymfpci_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); pci_set_drvdata(pci, NULL); @@ -354,7 +354,7 @@ static struct pci_driver ymfpci_driver = { .name = KBUILD_MODNAME, .id_table = snd_ymfpci_ids, .probe = snd_card_ymfpci_probe, - .remove = __devexit_p(snd_card_ymfpci_remove), + .remove = snd_card_ymfpci_remove, #ifdef CONFIG_PM_SLEEP .driver = { .pm = &snd_ymfpci_pm, diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c index 3a6f03f9b02f..22056c50fe39 100644 --- a/sound/pci/ymfpci/ymfpci_main.c +++ b/sound/pci/ymfpci/ymfpci_main.c @@ -25,7 +25,6 @@ #include <linux/pci.h> #include <linux/sched.h> #include <linux/slab.h> -#include <linux/vmalloc.h> #include <linux/mutex.h> #include <linux/module.h> @@ -598,7 +597,7 @@ static void snd_ymfpci_pcm_init_voice(struct snd_ymfpci_pcm *ypcm, unsigned int } } -static int __devinit snd_ymfpci_ac3_init(struct snd_ymfpci *chip) +static int snd_ymfpci_ac3_init(struct snd_ymfpci *chip) { if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), 4096, &chip->ac3_tmp_base) < 0) @@ -1144,7 +1143,7 @@ static struct snd_pcm_ops snd_ymfpci_capture_rec_ops = { .pointer = snd_ymfpci_capture_pointer, }; -int __devinit snd_ymfpci_pcm(struct snd_ymfpci *chip, int device, struct snd_pcm ** rpcm) +int snd_ymfpci_pcm(struct snd_ymfpci *chip, int device, struct snd_pcm **rpcm) { struct snd_pcm *pcm; int err; @@ -1187,7 +1186,7 @@ static struct snd_pcm_ops snd_ymfpci_capture_ac97_ops = { .pointer = snd_ymfpci_capture_pointer, }; -int __devinit snd_ymfpci_pcm2(struct snd_ymfpci *chip, int device, struct snd_pcm ** rpcm) +int snd_ymfpci_pcm2(struct snd_ymfpci *chip, int device, struct snd_pcm **rpcm) { struct snd_pcm *pcm; int err; @@ -1225,7 +1224,8 @@ static struct snd_pcm_ops snd_ymfpci_playback_spdif_ops = { .pointer = snd_ymfpci_playback_pointer, }; -int __devinit snd_ymfpci_pcm_spdif(struct snd_ymfpci *chip, int device, struct snd_pcm ** rpcm) +int snd_ymfpci_pcm_spdif(struct snd_ymfpci *chip, int device, + struct snd_pcm **rpcm) { struct snd_pcm *pcm; int err; @@ -1270,7 +1270,8 @@ static const struct snd_pcm_chmap_elem surround_map[] = { { } }; -int __devinit snd_ymfpci_pcm_4ch(struct snd_ymfpci *chip, int device, struct snd_pcm ** rpcm) +int snd_ymfpci_pcm_4ch(struct snd_ymfpci *chip, int device, + struct snd_pcm **rpcm) { struct snd_pcm *pcm; int err; @@ -1339,7 +1340,7 @@ static int snd_ymfpci_spdif_default_put(struct snd_kcontrol *kcontrol, return change; } -static struct snd_kcontrol_new snd_ymfpci_spdif_default __devinitdata = +static struct snd_kcontrol_new snd_ymfpci_spdif_default = { .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), @@ -1367,7 +1368,7 @@ static int snd_ymfpci_spdif_mask_get(struct snd_kcontrol *kcontrol, return 0; } -static struct snd_kcontrol_new snd_ymfpci_spdif_mask __devinitdata = +static struct snd_kcontrol_new snd_ymfpci_spdif_mask = { .access = SNDRV_CTL_ELEM_ACCESS_READ, .iface = SNDRV_CTL_ELEM_IFACE_PCM, @@ -1414,7 +1415,7 @@ static int snd_ymfpci_spdif_stream_put(struct snd_kcontrol *kcontrol, return change; } -static struct snd_kcontrol_new snd_ymfpci_spdif_stream __devinitdata = +static struct snd_kcontrol_new snd_ymfpci_spdif_stream = { .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, .iface = SNDRV_CTL_ELEM_IFACE_PCM, @@ -1462,7 +1463,7 @@ static int snd_ymfpci_drec_source_put(struct snd_kcontrol *kcontrol, struct snd_ return reg != old_reg; } -static struct snd_kcontrol_new snd_ymfpci_drec_source __devinitdata = { +static struct snd_kcontrol_new snd_ymfpci_drec_source = { .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Direct Recording Source", @@ -1632,7 +1633,7 @@ static int snd_ymfpci_put_dup4ch(struct snd_kcontrol *kcontrol, struct snd_ctl_e return change; } -static struct snd_kcontrol_new snd_ymfpci_dup4ch __devinitdata = { +static struct snd_kcontrol_new snd_ymfpci_dup4ch = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "4ch Duplication", .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, @@ -1641,7 +1642,7 @@ static struct snd_kcontrol_new snd_ymfpci_dup4ch __devinitdata = { .put = snd_ymfpci_put_dup4ch, }; -static struct snd_kcontrol_new snd_ymfpci_controls[] __devinitdata = { +static struct snd_kcontrol_new snd_ymfpci_controls[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Wave Playback Volume", @@ -1735,7 +1736,7 @@ static int snd_ymfpci_gpio_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ return 0; } -static struct snd_kcontrol_new snd_ymfpci_rear_shared __devinitdata = { +static struct snd_kcontrol_new snd_ymfpci_rear_shared = { .name = "Shared Rear/Line-In Switch", .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .info = snd_ymfpci_gpio_sw_info, @@ -1799,7 +1800,7 @@ static int snd_ymfpci_pcm_vol_put(struct snd_kcontrol *kcontrol, return 0; } -static struct snd_kcontrol_new snd_ymfpci_pcm_volume __devinitdata = { +static struct snd_kcontrol_new snd_ymfpci_pcm_volume = { .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = "PCM Playback Volume", .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | @@ -1826,7 +1827,7 @@ static void snd_ymfpci_mixer_free_ac97(struct snd_ac97 *ac97) chip->ac97 = NULL; } -int __devinit snd_ymfpci_mixer(struct snd_ymfpci *chip, int rear_switch) +int snd_ymfpci_mixer(struct snd_ymfpci *chip, int rear_switch) { struct snd_ac97_template ac97; struct snd_kcontrol *kctl; @@ -1970,7 +1971,7 @@ static struct snd_timer_hardware snd_ymfpci_timer_hw = { .precise_resolution = snd_ymfpci_timer_precise_resolution, }; -int __devinit snd_ymfpci_timer(struct snd_ymfpci *chip, int device) +int snd_ymfpci_timer(struct snd_ymfpci *chip, int device) { struct snd_timer *timer = NULL; struct snd_timer_id tid; @@ -2006,7 +2007,7 @@ static void snd_ymfpci_proc_read(struct snd_info_entry *entry, snd_iprintf(buffer, "%04x: %04x\n", i, snd_ymfpci_readl(chip, i)); } -static int __devinit snd_ymfpci_proc_init(struct snd_card *card, struct snd_ymfpci *chip) +static int snd_ymfpci_proc_init(struct snd_card *card, struct snd_ymfpci *chip) { struct snd_info_entry *entry; @@ -2128,7 +2129,7 @@ static void snd_ymfpci_download_image(struct snd_ymfpci *chip) snd_ymfpci_enable_dsp(chip); } -static int __devinit snd_ymfpci_memalloc(struct snd_ymfpci *chip) +static int snd_ymfpci_memalloc(struct snd_ymfpci *chip) { long size, playback_ctrl_size; int voice, bank, reg; @@ -2261,7 +2262,7 @@ static int snd_ymfpci_free(struct snd_ymfpci *chip) #endif #ifdef CONFIG_PM_SLEEP - vfree(chip->saved_regs); + kfree(chip->saved_regs); #endif if (chip->irq >= 0) free_irq(chip->irq, chip); @@ -2394,10 +2395,10 @@ static int snd_ymfpci_resume(struct device *dev) SIMPLE_DEV_PM_OPS(snd_ymfpci_pm, snd_ymfpci_suspend, snd_ymfpci_resume); #endif /* CONFIG_PM_SLEEP */ -int __devinit snd_ymfpci_create(struct snd_card *card, - struct pci_dev * pci, - unsigned short old_legacy_ctrl, - struct snd_ymfpci ** rchip) +int snd_ymfpci_create(struct snd_card *card, + struct pci_dev *pci, + unsigned short old_legacy_ctrl, + struct snd_ymfpci **rchip) { struct snd_ymfpci *chip; int err; @@ -2471,7 +2472,8 @@ int __devinit snd_ymfpci_create(struct snd_card *card, } #ifdef CONFIG_PM_SLEEP - chip->saved_regs = vmalloc(YDSXGR_NUM_SAVED_REGS * sizeof(u32)); + chip->saved_regs = kmalloc(YDSXGR_NUM_SAVED_REGS * sizeof(u32), + GFP_KERNEL); if (chip->saved_regs == NULL) { snd_ymfpci_free(chip); return -ENOMEM; diff --git a/sound/ppc/awacs.c b/sound/ppc/awacs.c index b36679384b27..5fbf5db2543d 100644 --- a/sound/ppc/awacs.c +++ b/sound/ppc/awacs.c @@ -477,7 +477,7 @@ static int snd_pmac_awacs_put_master_amp(struct snd_kcontrol *kcontrol, #define AMP_CH_SPK 0 #define AMP_CH_HD 1 -static struct snd_kcontrol_new snd_pmac_awacs_amp_vol[] __devinitdata = { +static struct snd_kcontrol_new snd_pmac_awacs_amp_vol[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Speaker Playback Volume", .info = snd_pmac_awacs_info_volume_amp, @@ -514,7 +514,7 @@ static struct snd_kcontrol_new snd_pmac_awacs_amp_vol[] __devinitdata = { }, }; -static struct snd_kcontrol_new snd_pmac_awacs_amp_hp_sw __devinitdata = { +static struct snd_kcontrol_new snd_pmac_awacs_amp_hp_sw = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Headphone Playback Switch", .info = snd_pmac_boolean_stereo_info, @@ -523,7 +523,7 @@ static struct snd_kcontrol_new snd_pmac_awacs_amp_hp_sw __devinitdata = { .private_value = AMP_CH_HD, }; -static struct snd_kcontrol_new snd_pmac_awacs_amp_spk_sw __devinitdata = { +static struct snd_kcontrol_new snd_pmac_awacs_amp_spk_sw = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Speaker Playback Switch", .info = snd_pmac_boolean_stereo_info, @@ -595,46 +595,46 @@ static int snd_pmac_screamer_mic_boost_put(struct snd_kcontrol *kcontrol, /* * lists of mixer elements */ -static struct snd_kcontrol_new snd_pmac_awacs_mixers[] __devinitdata = { +static struct snd_kcontrol_new snd_pmac_awacs_mixers[] = { AWACS_SWITCH("Master Capture Switch", 1, SHIFT_LOOPTHRU, 0), AWACS_VOLUME("Master Capture Volume", 0, 4, 0), /* AWACS_SWITCH("Unknown Playback Switch", 6, SHIFT_PAROUT0, 0), */ }; -static struct snd_kcontrol_new snd_pmac_screamer_mixers_beige[] __devinitdata = { +static struct snd_kcontrol_new snd_pmac_screamer_mixers_beige[] = { AWACS_VOLUME("Master Playback Volume", 2, 6, 1), AWACS_VOLUME("Play-through Playback Volume", 5, 6, 1), AWACS_SWITCH("Line Capture Switch", 0, SHIFT_MUX_MIC, 0), AWACS_SWITCH("CD Capture Switch", 0, SHIFT_MUX_LINE, 0), }; -static struct snd_kcontrol_new snd_pmac_screamer_mixers_lo[] __devinitdata = { +static struct snd_kcontrol_new snd_pmac_screamer_mixers_lo[] = { AWACS_VOLUME("Line out Playback Volume", 2, 6, 1), }; -static struct snd_kcontrol_new snd_pmac_screamer_mixers_imac[] __devinitdata = { +static struct snd_kcontrol_new snd_pmac_screamer_mixers_imac[] = { AWACS_VOLUME("Play-through Playback Volume", 5, 6, 1), AWACS_SWITCH("CD Capture Switch", 0, SHIFT_MUX_CD, 0), }; -static struct snd_kcontrol_new snd_pmac_screamer_mixers_g4agp[] __devinitdata = { +static struct snd_kcontrol_new snd_pmac_screamer_mixers_g4agp[] = { AWACS_VOLUME("Line out Playback Volume", 2, 6, 1), AWACS_VOLUME("Master Playback Volume", 5, 6, 1), AWACS_SWITCH("CD Capture Switch", 0, SHIFT_MUX_CD, 0), AWACS_SWITCH("Line Capture Switch", 0, SHIFT_MUX_MIC, 0), }; -static struct snd_kcontrol_new snd_pmac_awacs_mixers_pmac7500[] __devinitdata = { +static struct snd_kcontrol_new snd_pmac_awacs_mixers_pmac7500[] = { AWACS_VOLUME("Line out Playback Volume", 2, 6, 1), AWACS_SWITCH("CD Capture Switch", 0, SHIFT_MUX_CD, 0), AWACS_SWITCH("Line Capture Switch", 0, SHIFT_MUX_MIC, 0), }; -static struct snd_kcontrol_new snd_pmac_awacs_mixers_pmac5500[] __devinitdata = { +static struct snd_kcontrol_new snd_pmac_awacs_mixers_pmac5500[] = { AWACS_VOLUME("Headphone Playback Volume", 2, 6, 1), }; -static struct snd_kcontrol_new snd_pmac_awacs_mixers_pmac[] __devinitdata = { +static struct snd_kcontrol_new snd_pmac_awacs_mixers_pmac[] = { AWACS_VOLUME("Master Playback Volume", 2, 6, 1), AWACS_SWITCH("CD Capture Switch", 0, SHIFT_MUX_CD, 0), }; @@ -642,34 +642,34 @@ static struct snd_kcontrol_new snd_pmac_awacs_mixers_pmac[] __devinitdata = { /* FIXME: is this correct order? * screamer (powerbook G3 pismo) seems to have different bits... */ -static struct snd_kcontrol_new snd_pmac_awacs_mixers2[] __devinitdata = { +static struct snd_kcontrol_new snd_pmac_awacs_mixers2[] = { AWACS_SWITCH("Line Capture Switch", 0, SHIFT_MUX_LINE, 0), AWACS_SWITCH("Mic Capture Switch", 0, SHIFT_MUX_MIC, 0), }; -static struct snd_kcontrol_new snd_pmac_screamer_mixers2[] __devinitdata = { +static struct snd_kcontrol_new snd_pmac_screamer_mixers2[] = { AWACS_SWITCH("Line Capture Switch", 0, SHIFT_MUX_MIC, 0), AWACS_SWITCH("Mic Capture Switch", 0, SHIFT_MUX_LINE, 0), }; -static struct snd_kcontrol_new snd_pmac_awacs_mixers2_pmac5500[] __devinitdata = { +static struct snd_kcontrol_new snd_pmac_awacs_mixers2_pmac5500[] = { AWACS_SWITCH("CD Capture Switch", 0, SHIFT_MUX_CD, 0), }; -static struct snd_kcontrol_new snd_pmac_awacs_master_sw __devinitdata = +static struct snd_kcontrol_new snd_pmac_awacs_master_sw = AWACS_SWITCH("Master Playback Switch", 1, SHIFT_HDMUTE, 1); -static struct snd_kcontrol_new snd_pmac_awacs_master_sw_imac __devinitdata = +static struct snd_kcontrol_new snd_pmac_awacs_master_sw_imac = AWACS_SWITCH("Line out Playback Switch", 1, SHIFT_HDMUTE, 1); -static struct snd_kcontrol_new snd_pmac_awacs_master_sw_pmac5500 __devinitdata = +static struct snd_kcontrol_new snd_pmac_awacs_master_sw_pmac5500 = AWACS_SWITCH("Headphone Playback Switch", 1, SHIFT_HDMUTE, 1); -static struct snd_kcontrol_new snd_pmac_awacs_mic_boost[] __devinitdata = { +static struct snd_kcontrol_new snd_pmac_awacs_mic_boost[] = { AWACS_SWITCH("Mic Boost Capture Switch", 0, SHIFT_GAINLINE, 0), }; -static struct snd_kcontrol_new snd_pmac_screamer_mic_boost[] __devinitdata = { +static struct snd_kcontrol_new snd_pmac_screamer_mic_boost[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Mic Boost Capture Volume", .info = snd_pmac_screamer_mic_boost_info, @@ -678,34 +678,34 @@ static struct snd_kcontrol_new snd_pmac_screamer_mic_boost[] __devinitdata = { }, }; -static struct snd_kcontrol_new snd_pmac_awacs_mic_boost_pmac7500[] __devinitdata = +static struct snd_kcontrol_new snd_pmac_awacs_mic_boost_pmac7500[] = { AWACS_SWITCH("Line Boost Capture Switch", 0, SHIFT_GAINLINE, 0), }; -static struct snd_kcontrol_new snd_pmac_screamer_mic_boost_beige[] __devinitdata = +static struct snd_kcontrol_new snd_pmac_screamer_mic_boost_beige[] = { AWACS_SWITCH("Line Boost Capture Switch", 0, SHIFT_GAINLINE, 0), AWACS_SWITCH("CD Boost Capture Switch", 6, SHIFT_MIC_BOOST, 0), }; -static struct snd_kcontrol_new snd_pmac_screamer_mic_boost_imac[] __devinitdata = +static struct snd_kcontrol_new snd_pmac_screamer_mic_boost_imac[] = { AWACS_SWITCH("Line Boost Capture Switch", 0, SHIFT_GAINLINE, 0), AWACS_SWITCH("Mic Boost Capture Switch", 6, SHIFT_MIC_BOOST, 0), }; -static struct snd_kcontrol_new snd_pmac_awacs_speaker_vol[] __devinitdata = { +static struct snd_kcontrol_new snd_pmac_awacs_speaker_vol[] = { AWACS_VOLUME("Speaker Playback Volume", 4, 6, 1), }; -static struct snd_kcontrol_new snd_pmac_awacs_speaker_sw __devinitdata = +static struct snd_kcontrol_new snd_pmac_awacs_speaker_sw = AWACS_SWITCH("Speaker Playback Switch", 1, SHIFT_SPKMUTE, 1); -static struct snd_kcontrol_new snd_pmac_awacs_speaker_sw_imac1 __devinitdata = +static struct snd_kcontrol_new snd_pmac_awacs_speaker_sw_imac1 = AWACS_SWITCH("Speaker Playback Switch", 1, SHIFT_PAROUT1, 1); -static struct snd_kcontrol_new snd_pmac_awacs_speaker_sw_imac2 __devinitdata = +static struct snd_kcontrol_new snd_pmac_awacs_speaker_sw_imac2 = AWACS_SWITCH("Speaker Playback Switch", 1, SHIFT_PAROUT1, 0); @@ -872,7 +872,7 @@ static void snd_pmac_awacs_update_automute(struct snd_pmac *chip, int do_notify) /* * initialize chip */ -int __devinit +int snd_pmac_awacs_init(struct snd_pmac *chip) { int pm7500 = IS_PM7500; diff --git a/sound/ppc/beep.c b/sound/ppc/beep.c index a9d350789f55..0040f048221f 100644 --- a/sound/ppc/beep.c +++ b/sound/ppc/beep.c @@ -215,7 +215,7 @@ static struct snd_kcontrol_new snd_pmac_beep_mixer = { }; /* Initialize beep stuff */ -int __devinit snd_pmac_attach_beep(struct snd_pmac *chip) +int snd_pmac_attach_beep(struct snd_pmac *chip) { struct pmac_beep *beep; struct input_dev *input_dev; diff --git a/sound/ppc/burgundy.c b/sound/ppc/burgundy.c index 00e2d5166d0a..cb4f0a5e984e 100644 --- a/sound/ppc/burgundy.c +++ b/sound/ppc/burgundy.c @@ -467,7 +467,7 @@ static int snd_pmac_burgundy_put_switch_b(struct snd_kcontrol *kcontrol, /* * Burgundy mixers */ -static struct snd_kcontrol_new snd_pmac_burgundy_mixers[] __devinitdata = { +static struct snd_kcontrol_new snd_pmac_burgundy_mixers[] = { BURGUNDY_VOLUME_W("Master Playback Volume", 0, MASK_ADDR_BURGUNDY_MASTER_VOLUME, 8), BURGUNDY_VOLUME_W("CD Capture Volume", 0, @@ -495,7 +495,7 @@ static struct snd_kcontrol_new snd_pmac_burgundy_mixers[] __devinitdata = { */ BURGUNDY_SWITCH_B("PCM Capture Switch", 0, MASK_ADDR_BURGUNDY_HOSTIFEH, 0x01, 0, 0) }; -static struct snd_kcontrol_new snd_pmac_burgundy_mixers_imac[] __devinitdata = { +static struct snd_kcontrol_new snd_pmac_burgundy_mixers_imac[] = { BURGUNDY_VOLUME_W("Line in Capture Volume", 0, MASK_ADDR_BURGUNDY_VOLLINE, 16), BURGUNDY_VOLUME_W("Mic Capture Volume", 0, @@ -521,7 +521,7 @@ static struct snd_kcontrol_new snd_pmac_burgundy_mixers_imac[] __devinitdata = { BURGUNDY_SWITCH_B("Mic Boost Capture Switch", 0, MASK_ADDR_BURGUNDY_INPBOOST, 0x40, 0x80, 1) }; -static struct snd_kcontrol_new snd_pmac_burgundy_mixers_pmac[] __devinitdata = { +static struct snd_kcontrol_new snd_pmac_burgundy_mixers_pmac[] = { BURGUNDY_VOLUME_W("Line in Capture Volume", 0, MASK_ADDR_BURGUNDY_VOLMIC, 16), BURGUNDY_VOLUME_B("Line in Gain Capture Volume", 0, @@ -537,33 +537,33 @@ static struct snd_kcontrol_new snd_pmac_burgundy_mixers_pmac[] __devinitdata = { /* BURGUNDY_SWITCH_B("Line in Boost Capture Switch", 0, * MASK_ADDR_BURGUNDY_INPBOOST, 0x40, 0x80, 1) */ }; -static struct snd_kcontrol_new snd_pmac_burgundy_master_sw_imac __devinitdata = +static struct snd_kcontrol_new snd_pmac_burgundy_master_sw_imac = BURGUNDY_SWITCH_B("Master Playback Switch", 0, MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, BURGUNDY_OUTPUT_LEFT | BURGUNDY_LINEOUT_LEFT | BURGUNDY_HP_LEFT, BURGUNDY_OUTPUT_RIGHT | BURGUNDY_LINEOUT_RIGHT | BURGUNDY_HP_RIGHT, 1); -static struct snd_kcontrol_new snd_pmac_burgundy_master_sw_pmac __devinitdata = +static struct snd_kcontrol_new snd_pmac_burgundy_master_sw_pmac = BURGUNDY_SWITCH_B("Master Playback Switch", 0, MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, BURGUNDY_OUTPUT_INTERN | BURGUNDY_OUTPUT_LEFT, BURGUNDY_OUTPUT_RIGHT, 1); -static struct snd_kcontrol_new snd_pmac_burgundy_speaker_sw_imac __devinitdata = +static struct snd_kcontrol_new snd_pmac_burgundy_speaker_sw_imac = BURGUNDY_SWITCH_B("Speaker Playback Switch", 0, MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, BURGUNDY_OUTPUT_LEFT, BURGUNDY_OUTPUT_RIGHT, 1); -static struct snd_kcontrol_new snd_pmac_burgundy_speaker_sw_pmac __devinitdata = +static struct snd_kcontrol_new snd_pmac_burgundy_speaker_sw_pmac = BURGUNDY_SWITCH_B("Speaker Playback Switch", 0, MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, BURGUNDY_OUTPUT_INTERN, 0, 0); -static struct snd_kcontrol_new snd_pmac_burgundy_line_sw_imac __devinitdata = +static struct snd_kcontrol_new snd_pmac_burgundy_line_sw_imac = BURGUNDY_SWITCH_B("Line out Playback Switch", 0, MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, BURGUNDY_LINEOUT_LEFT, BURGUNDY_LINEOUT_RIGHT, 1); -static struct snd_kcontrol_new snd_pmac_burgundy_line_sw_pmac __devinitdata = +static struct snd_kcontrol_new snd_pmac_burgundy_line_sw_pmac = BURGUNDY_SWITCH_B("Line out Playback Switch", 0, MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, BURGUNDY_OUTPUT_LEFT, BURGUNDY_OUTPUT_RIGHT, 1); -static struct snd_kcontrol_new snd_pmac_burgundy_hp_sw_imac __devinitdata = +static struct snd_kcontrol_new snd_pmac_burgundy_hp_sw_imac = BURGUNDY_SWITCH_B("Headphone Playback Switch", 0, MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, BURGUNDY_HP_LEFT, BURGUNDY_HP_RIGHT, 1); @@ -617,7 +617,7 @@ static void snd_pmac_burgundy_update_automute(struct snd_pmac *chip, int do_noti /* * initialize burgundy */ -int __devinit snd_pmac_burgundy_init(struct snd_pmac *chip) +int snd_pmac_burgundy_init(struct snd_pmac *chip) { int imac = of_machine_is_compatible("iMac"); int i, err; diff --git a/sound/ppc/daca.c b/sound/ppc/daca.c index 24200b7bdace..b86526223e4e 100644 --- a/sound/ppc/daca.c +++ b/sound/ppc/daca.c @@ -244,7 +244,7 @@ static void daca_cleanup(struct snd_pmac *chip) } /* exported */ -int __devinit snd_pmac_daca_init(struct snd_pmac *chip) +int snd_pmac_daca_init(struct snd_pmac *chip) { int i, err; struct pmac_daca *mix; diff --git a/sound/ppc/keywest.c b/sound/ppc/keywest.c index 4080becf4cef..01aecc2b5073 100644 --- a/sound/ppc/keywest.c +++ b/sound/ppc/keywest.c @@ -115,7 +115,7 @@ void snd_pmac_keywest_cleanup(struct pmac_keywest *i2c) } } -int __devinit snd_pmac_tumbler_post_init(void) +int snd_pmac_tumbler_post_init(void) { int err; @@ -130,7 +130,7 @@ int __devinit snd_pmac_tumbler_post_init(void) } /* exported */ -int __devinit snd_pmac_keywest_init(struct pmac_keywest *i2c) +int snd_pmac_keywest_init(struct pmac_keywest *i2c) { int err; diff --git a/sound/ppc/pmac.c b/sound/ppc/pmac.c index ab96cde7417b..c93fbbb201fe 100644 --- a/sound/ppc/pmac.c +++ b/sound/ppc/pmac.c @@ -702,7 +702,7 @@ static struct snd_pcm_ops snd_pmac_capture_ops = { .pointer = snd_pmac_capture_pointer, }; -int __devinit snd_pmac_pcm_new(struct snd_pmac *chip) +int snd_pmac_pcm_new(struct snd_pmac *chip) { struct snd_pcm *pcm; int err; @@ -907,7 +907,7 @@ static int snd_pmac_dev_free(struct snd_device *device) * check the machine support byteswap (little-endian) */ -static void __devinit detect_byte_swap(struct snd_pmac *chip) +static void detect_byte_swap(struct snd_pmac *chip) { struct device_node *mio; @@ -933,7 +933,7 @@ static void __devinit detect_byte_swap(struct snd_pmac *chip) /* * detect a sound chip */ -static int __devinit snd_pmac_detect(struct snd_pmac *chip) +static int snd_pmac_detect(struct snd_pmac *chip) { struct device_node *sound; struct device_node *dn; @@ -1146,7 +1146,7 @@ static int pmac_hp_detect_get(struct snd_kcontrol *kcontrol, return 0; } -static struct snd_kcontrol_new auto_mute_controls[] __devinitdata = { +static struct snd_kcontrol_new auto_mute_controls[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Auto Mute Switch", .info = snd_pmac_boolean_mono_info, @@ -1161,7 +1161,7 @@ static struct snd_kcontrol_new auto_mute_controls[] __devinitdata = { }, }; -int __devinit snd_pmac_add_automute(struct snd_pmac *chip) +int snd_pmac_add_automute(struct snd_pmac *chip) { int err; chip->auto_mute = 1; @@ -1178,7 +1178,7 @@ int __devinit snd_pmac_add_automute(struct snd_pmac *chip) /* * create and detect a pmac chip record */ -int __devinit snd_pmac_new(struct snd_card *card, struct snd_pmac **chip_return) +int snd_pmac_new(struct snd_card *card, struct snd_pmac **chip_return) { struct snd_pmac *chip; struct device_node *np; diff --git a/sound/ppc/powermac.c b/sound/ppc/powermac.c index 210cafe04890..09fc848d32ec 100644 --- a/sound/ppc/powermac.c +++ b/sound/ppc/powermac.c @@ -51,7 +51,7 @@ static struct platform_device *device; /* */ -static int __devinit snd_pmac_probe(struct platform_device *devptr) +static int snd_pmac_probe(struct platform_device *devptr) { struct snd_card *card; struct snd_pmac *chip; @@ -136,7 +136,7 @@ __error: } -static int __devexit snd_pmac_remove(struct platform_device *devptr) +static int snd_pmac_remove(struct platform_device *devptr) { snd_card_free(platform_get_drvdata(devptr)); platform_set_drvdata(devptr, NULL); @@ -168,7 +168,7 @@ static SIMPLE_DEV_PM_OPS(snd_pmac_pm, snd_pmac_driver_suspend, snd_pmac_driver_r static struct platform_driver snd_pmac_driver = { .probe = snd_pmac_probe, - .remove = __devexit_p(snd_pmac_remove), + .remove = snd_pmac_remove, .driver = { .name = SND_PMAC_DRIVER, .owner = THIS_MODULE, diff --git a/sound/ppc/snd_ps3.c b/sound/ppc/snd_ps3.c index 9b18b5243a56..8c7dcbe0118d 100644 --- a/sound/ppc/snd_ps3.c +++ b/sound/ppc/snd_ps3.c @@ -786,7 +786,7 @@ static struct snd_pcm_ops snd_ps3_pcm_spdif_ops = { }; -static int __devinit snd_ps3_map_mmio(void) +static int snd_ps3_map_mmio(void) { the_card.mapped_mmio_vaddr = ioremap(the_card.ps3_dev->m_region->bus_addr, @@ -808,7 +808,7 @@ static void snd_ps3_unmap_mmio(void) the_card.mapped_mmio_vaddr = NULL; } -static int __devinit snd_ps3_allocate_irq(void) +static int snd_ps3_allocate_irq(void) { int ret; u64 lpar_addr, lpar_size; @@ -866,7 +866,7 @@ static void snd_ps3_free_irq(void) ps3_irq_plug_destroy(the_card.irq_no); } -static void __devinit snd_ps3_audio_set_base_addr(uint64_t ioaddr_start) +static void snd_ps3_audio_set_base_addr(uint64_t ioaddr_start) { uint64_t val; int ret; @@ -882,7 +882,7 @@ static void __devinit snd_ps3_audio_set_base_addr(uint64_t ioaddr_start) ret); } -static void __devinit snd_ps3_audio_fixup(struct snd_ps3_card_info *card) +static void snd_ps3_audio_fixup(struct snd_ps3_card_info *card) { /* * avsetting driver seems to never change the followings @@ -906,7 +906,7 @@ static void __devinit snd_ps3_audio_fixup(struct snd_ps3_card_info *card) PS3_AUDIO_AO_3WMCTRL_ASOPLRCK_DEFAULT); } -static int __devinit snd_ps3_init_avsetting(struct snd_ps3_card_info *card) +static int snd_ps3_init_avsetting(struct snd_ps3_card_info *card) { int ret; pr_debug("%s: start\n", __func__); @@ -928,7 +928,7 @@ static int __devinit snd_ps3_init_avsetting(struct snd_ps3_card_info *card) return ret; } -static int __devinit snd_ps3_driver_probe(struct ps3_system_bus_device *dev) +static int snd_ps3_driver_probe(struct ps3_system_bus_device *dev) { int i, ret; u64 lpar_addr, lpar_size; diff --git a/sound/ppc/tumbler.c b/sound/ppc/tumbler.c index 9cea84c3e0c6..b23354a4ceca 100644 --- a/sound/ppc/tumbler.c +++ b/sound/ppc/tumbler.c @@ -844,7 +844,7 @@ static int snapper_put_capture_source(struct snd_kcontrol *kcontrol, /* */ -static struct snd_kcontrol_new tumbler_mixers[] __devinitdata = { +static struct snd_kcontrol_new tumbler_mixers[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Volume", .info = tumbler_info_master_volume, @@ -868,7 +868,7 @@ static struct snd_kcontrol_new tumbler_mixers[] __devinitdata = { }, }; -static struct snd_kcontrol_new snapper_mixers[] __devinitdata = { +static struct snd_kcontrol_new snapper_mixers[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Volume", .info = tumbler_info_master_volume, @@ -901,7 +901,7 @@ static struct snd_kcontrol_new snapper_mixers[] __devinitdata = { }, }; -static struct snd_kcontrol_new tumbler_hp_sw __devinitdata = { +static struct snd_kcontrol_new tumbler_hp_sw = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Headphone Playback Switch", .info = snd_pmac_boolean_mono_info, @@ -909,7 +909,7 @@ static struct snd_kcontrol_new tumbler_hp_sw __devinitdata = { .put = tumbler_put_mute_switch, .private_value = TUMBLER_MUTE_HP, }; -static struct snd_kcontrol_new tumbler_speaker_sw __devinitdata = { +static struct snd_kcontrol_new tumbler_speaker_sw = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Speaker Playback Switch", .info = snd_pmac_boolean_mono_info, @@ -917,7 +917,7 @@ static struct snd_kcontrol_new tumbler_speaker_sw __devinitdata = { .put = tumbler_put_mute_switch, .private_value = TUMBLER_MUTE_AMP, }; -static struct snd_kcontrol_new tumbler_lineout_sw __devinitdata = { +static struct snd_kcontrol_new tumbler_lineout_sw = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Line Out Playback Switch", .info = snd_pmac_boolean_mono_info, @@ -925,7 +925,7 @@ static struct snd_kcontrol_new tumbler_lineout_sw __devinitdata = { .put = tumbler_put_mute_switch, .private_value = TUMBLER_MUTE_LINE, }; -static struct snd_kcontrol_new tumbler_drc_sw __devinitdata = { +static struct snd_kcontrol_new tumbler_drc_sw = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "DRC Switch", .info = snd_pmac_boolean_mono_info, @@ -1276,7 +1276,7 @@ static void tumbler_resume(struct snd_pmac *chip) #endif /* initialize tumbler */ -static int __devinit tumbler_init(struct snd_pmac *chip) +static int tumbler_init(struct snd_pmac *chip) { int irq; struct pmac_tumbler *mix = chip->mixer_data; @@ -1349,7 +1349,7 @@ static void tumbler_cleanup(struct snd_pmac *chip) } /* exported */ -int __devinit snd_pmac_tumbler_init(struct snd_pmac *chip) +int snd_pmac_tumbler_init(struct snd_pmac *chip) { int i, err; struct pmac_tumbler *mix; diff --git a/sound/sh/aica.c b/sound/sh/aica.c index d48b523207eb..e59a73a9bc42 100644 --- a/sound/sh/aica.c +++ b/sound/sh/aica.c @@ -540,7 +540,7 @@ static int aica_pcmvolume_put(struct snd_kcontrol *kcontrol, return 1; } -static struct snd_kcontrol_new snd_aica_pcmswitch_control __devinitdata = { +static struct snd_kcontrol_new snd_aica_pcmswitch_control = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "PCM Playback Switch", .index = 0, @@ -549,7 +549,7 @@ static struct snd_kcontrol_new snd_aica_pcmswitch_control __devinitdata = { .put = aica_pcmswitch_put }; -static struct snd_kcontrol_new snd_aica_pcmvolume_control __devinitdata = { +static struct snd_kcontrol_new snd_aica_pcmvolume_control = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "PCM Playback Volume", .index = 0, @@ -574,8 +574,7 @@ static int load_aica_firmware(void) return err; } -static int __devinit add_aicamixer_controls(struct snd_card_aica - *dreamcastcard) +static int add_aicamixer_controls(struct snd_card_aica *dreamcastcard) { int err; err = snd_ctl_add @@ -591,7 +590,7 @@ static int __devinit add_aicamixer_controls(struct snd_card_aica return 0; } -static int __devexit snd_aica_remove(struct platform_device *devptr) +static int snd_aica_remove(struct platform_device *devptr) { struct snd_card_aica *dreamcastcard; dreamcastcard = platform_get_drvdata(devptr); @@ -603,7 +602,7 @@ static int __devexit snd_aica_remove(struct platform_device *devptr) return 0; } -static int __devinit snd_aica_probe(struct platform_device *devptr) +static int snd_aica_probe(struct platform_device *devptr) { int err; struct snd_card_aica *dreamcastcard; @@ -652,7 +651,7 @@ static int __devinit snd_aica_probe(struct platform_device *devptr) static struct platform_driver snd_aica_driver = { .probe = snd_aica_probe, - .remove = __devexit_p(snd_aica_remove), + .remove = snd_aica_remove, .driver = { .name = SND_AICA_DRIVER, .owner = THIS_MODULE, diff --git a/sound/sh/sh_dac_audio.c b/sound/sh/sh_dac_audio.c index 0a3394751ed2..e68c4fc91a03 100644 --- a/sound/sh/sh_dac_audio.c +++ b/sound/sh/sh_dac_audio.c @@ -261,7 +261,7 @@ static struct snd_pcm_ops snd_sh_dac_pcm_ops = { .mmap = snd_pcm_lib_mmap_iomem, }; -static int __devinit snd_sh_dac_pcm(struct snd_sh_dac *chip, int device) +static int snd_sh_dac_pcm(struct snd_sh_dac *chip, int device) { int err; struct snd_pcm *pcm; @@ -346,9 +346,9 @@ static enum hrtimer_restart sh_dac_audio_timer(struct hrtimer *handle) } /* create -- chip-specific constructor for the cards components */ -static int __devinit snd_sh_dac_create(struct snd_card *card, - struct platform_device *devptr, - struct snd_sh_dac **rchip) +static int snd_sh_dac_create(struct snd_card *card, + struct platform_device *devptr, + struct snd_sh_dac **rchip) { struct snd_sh_dac *chip; int err; @@ -392,7 +392,7 @@ static int __devinit snd_sh_dac_create(struct snd_card *card, } /* driver .probe -- constructor */ -static int __devinit snd_sh_dac_probe(struct platform_device *devptr) +static int snd_sh_dac_probe(struct platform_device *devptr) { struct snd_sh_dac *chip; struct snd_card *card; diff --git a/sound/soc/atmel/Kconfig b/sound/soc/atmel/Kconfig index 72b09cfd3dc3..d1b691bf8e2d 100644 --- a/sound/soc/atmel/Kconfig +++ b/sound/soc/atmel/Kconfig @@ -6,6 +6,14 @@ config SND_ATMEL_SOC the ATMEL SSC interface. You will also need to select the audio interfaces to support below. +config SND_ATMEL_SOC_PDC + tristate + depends on SND_ATMEL_SOC + +config SND_ATMEL_SOC_DMA + tristate + depends on SND_ATMEL_SOC + config SND_ATMEL_SOC_SSC tristate depends on SND_ATMEL_SOC @@ -16,8 +24,8 @@ config SND_ATMEL_SOC_SSC config SND_AT91_SOC_SAM9G20_WM8731 tristate "SoC Audio support for WM8731-based At91sam9g20 evaluation board" - depends on ATMEL_SSC && ARCH_AT91SAM9G20 && SND_ATMEL_SOC && \ - AT91_PROGRAMMABLE_CLOCKS + depends on ATMEL_SSC && SND_ATMEL_SOC && AT91_PROGRAMMABLE_CLOCKS + select SND_ATMEL_SOC_PDC select SND_ATMEL_SOC_SSC select SND_SOC_WM8731 help @@ -27,6 +35,7 @@ config SND_AT91_SOC_SAM9G20_WM8731 config SND_AT91_SOC_AFEB9260 tristate "SoC Audio support for AFEB9260 board" depends on ATMEL_SSC && ARCH_AT91 && MACH_AFEB9260 && SND_ATMEL_SOC + select SND_ATMEL_SOC_PDC select SND_ATMEL_SOC_SSC select SND_SOC_TLV320AIC23 help diff --git a/sound/soc/atmel/Makefile b/sound/soc/atmel/Makefile index a5c0bf19da78..41967ccb6f41 100644 --- a/sound/soc/atmel/Makefile +++ b/sound/soc/atmel/Makefile @@ -1,8 +1,12 @@ # AT91 Platform Support snd-soc-atmel-pcm-objs := atmel-pcm.o +snd-soc-atmel-pcm-pdc-objs := atmel-pcm-pdc.o +snd-soc-atmel-pcm-dma-objs := atmel-pcm-dma.o snd-soc-atmel_ssc_dai-objs := atmel_ssc_dai.o obj-$(CONFIG_SND_ATMEL_SOC) += snd-soc-atmel-pcm.o +obj-$(CONFIG_SND_ATMEL_SOC_PDC) += snd-soc-atmel-pcm-pdc.o +obj-$(CONFIG_SND_ATMEL_SOC_DMA) += snd-soc-atmel-pcm-dma.o obj-$(CONFIG_SND_ATMEL_SOC_SSC) += snd-soc-atmel_ssc_dai.o # AT91 Machine Support diff --git a/sound/soc/atmel/atmel-pcm-dma.c b/sound/soc/atmel/atmel-pcm-dma.c new file mode 100644 index 000000000000..30184a4a147a --- /dev/null +++ b/sound/soc/atmel/atmel-pcm-dma.c @@ -0,0 +1,240 @@ +/* + * atmel-pcm-dma.c -- ALSA PCM DMA support for the Atmel SoC. + * + * Copyright (C) 2012 Atmel + * + * Author: Bo Shen <voice.shen@atmel.com> + * + * Based on atmel-pcm by: + * Sedji Gaouaou <sedji.gaouaou@atmel.com> + * Copyright 2008 Atmel + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/dma-mapping.h> +#include <linux/dmaengine.h> +#include <linux/atmel-ssc.h> +#include <linux/platform_data/dma-atmel.h> + +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/dmaengine_pcm.h> + +#include "atmel-pcm.h" + +/*--------------------------------------------------------------------------*\ + * Hardware definition +\*--------------------------------------------------------------------------*/ +static const struct snd_pcm_hardware atmel_pcm_dma_hardware = { + .info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_RESUME | + SNDRV_PCM_INFO_PAUSE, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .period_bytes_min = 256, /* lighting DMA overhead */ + .period_bytes_max = 2 * 0xffff, /* if 2 bytes format */ + .periods_min = 8, + .periods_max = 1024, /* no limit */ + .buffer_bytes_max = ATMEL_SSC_DMABUF_SIZE, +}; + +/** + * atmel_pcm_dma_irq: SSC interrupt handler for DMAENGINE enabled SSC + * + * We use DMAENGINE to send/receive data to/from SSC so this ISR is only to + * check if any overrun occured. + */ +static void atmel_pcm_dma_irq(u32 ssc_sr, + struct snd_pcm_substream *substream) +{ + struct atmel_pcm_dma_params *prtd; + + prtd = snd_dmaengine_pcm_get_data(substream); + + if (ssc_sr & prtd->mask->ssc_error) { + if (snd_pcm_running(substream)) + pr_warn("atmel-pcm: buffer %s on %s (SSC_SR=%#x)\n", + substream->stream == SNDRV_PCM_STREAM_PLAYBACK + ? "underrun" : "overrun", prtd->name, + ssc_sr); + + /* stop RX and capture: will be enabled again at restart */ + ssc_writex(prtd->ssc->regs, SSC_CR, prtd->mask->ssc_disable); + snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); + + /* now drain RHR and read status to remove xrun condition */ + ssc_readx(prtd->ssc->regs, SSC_RHR); + ssc_readx(prtd->ssc->regs, SSC_SR); + } +} + +/*--------------------------------------------------------------------------*\ + * DMAENGINE operations +\*--------------------------------------------------------------------------*/ +static bool filter(struct dma_chan *chan, void *slave) +{ + struct at_dma_slave *sl = slave; + + if (sl->dma_dev == chan->device->dev) { + chan->private = sl; + return true; + } else { + return false; + } +} + +static int atmel_pcm_configure_dma(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct atmel_pcm_dma_params *prtd; + struct ssc_device *ssc; + struct dma_chan *dma_chan; + struct dma_slave_config slave_config; + int ret; + + prtd = snd_dmaengine_pcm_get_data(substream); + ssc = prtd->ssc; + + ret = snd_hwparams_to_dma_slave_config(substream, params, + &slave_config); + if (ret) { + pr_err("atmel-pcm: hwparams to dma slave configure failed\n"); + return ret; + } + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + slave_config.dst_addr = (dma_addr_t)ssc->phybase + SSC_THR; + slave_config.dst_maxburst = 1; + } else { + slave_config.src_addr = (dma_addr_t)ssc->phybase + SSC_RHR; + slave_config.src_maxburst = 1; + } + + slave_config.device_fc = false; + + dma_chan = snd_dmaengine_pcm_get_chan(substream); + if (dmaengine_slave_config(dma_chan, &slave_config)) { + pr_err("atmel-pcm: failed to configure dma channel\n"); + ret = -EBUSY; + return ret; + } + + return 0; +} + +static int atmel_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct atmel_pcm_dma_params *prtd; + struct ssc_device *ssc; + struct at_dma_slave *sdata = NULL; + int ret; + + snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); + + prtd = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); + ssc = prtd->ssc; + if (ssc->pdev) + sdata = ssc->pdev->dev.platform_data; + + ret = snd_dmaengine_pcm_open(substream, filter, sdata); + if (ret) { + pr_err("atmel-pcm: dmaengine pcm open failed\n"); + return -EINVAL; + } + + snd_dmaengine_pcm_set_data(substream, prtd); + + ret = atmel_pcm_configure_dma(substream, params); + if (ret) { + pr_err("atmel-pcm: failed to configure dmai\n"); + goto err; + } + + prtd->dma_intr_handler = atmel_pcm_dma_irq; + + return 0; +err: + snd_dmaengine_pcm_close(substream); + return ret; +} + +static int atmel_pcm_dma_prepare(struct snd_pcm_substream *substream) +{ + struct atmel_pcm_dma_params *prtd; + + prtd = snd_dmaengine_pcm_get_data(substream); + + ssc_writex(prtd->ssc->regs, SSC_IER, prtd->mask->ssc_error); + ssc_writex(prtd->ssc->regs, SSC_CR, prtd->mask->ssc_enable); + + return 0; +} + +static int atmel_pcm_open(struct snd_pcm_substream *substream) +{ + snd_soc_set_runtime_hwparams(substream, &atmel_pcm_dma_hardware); + + return 0; +} + +static int atmel_pcm_close(struct snd_pcm_substream *substream) +{ + snd_dmaengine_pcm_close(substream); + + return 0; +} + +static struct snd_pcm_ops atmel_pcm_ops = { + .open = atmel_pcm_open, + .close = atmel_pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = atmel_pcm_hw_params, + .prepare = atmel_pcm_dma_prepare, + .trigger = snd_dmaengine_pcm_trigger, + .pointer = snd_dmaengine_pcm_pointer_no_residue, + .mmap = atmel_pcm_mmap, +}; + +static struct snd_soc_platform_driver atmel_soc_platform = { + .ops = &atmel_pcm_ops, + .pcm_new = atmel_pcm_new, + .pcm_free = atmel_pcm_free, +}; + +int atmel_pcm_dma_platform_register(struct device *dev) +{ + return snd_soc_register_platform(dev, &atmel_soc_platform); +} +EXPORT_SYMBOL(atmel_pcm_dma_platform_register); + +void atmel_pcm_dma_platform_unregister(struct device *dev) +{ + snd_soc_unregister_platform(dev); +} +EXPORT_SYMBOL(atmel_pcm_dma_platform_unregister); + +MODULE_AUTHOR("Bo Shen <voice.shen@atmel.com>"); +MODULE_DESCRIPTION("Atmel DMA based PCM module"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/atmel/atmel-pcm-pdc.c b/sound/soc/atmel/atmel-pcm-pdc.c new file mode 100644 index 000000000000..6a293c713a38 --- /dev/null +++ b/sound/soc/atmel/atmel-pcm-pdc.c @@ -0,0 +1,401 @@ +/* + * atmel-pcm.c -- ALSA PCM interface for the Atmel atmel SoC. + * + * Copyright (C) 2005 SAN People + * Copyright (C) 2008 Atmel + * + * Authors: Sedji Gaouaou <sedji.gaouaou@atmel.com> + * + * Based on at91-pcm. by: + * Frank Mandarino <fmandarino@endrelia.com> + * Copyright 2006 Endrelia Technologies Inc. + * + * Based on pxa2xx-pcm.c by: + * + * Author: Nicolas Pitre + * Created: Nov 30, 2004 + * Copyright: (C) 2004 MontaVista Software, Inc. + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/dma-mapping.h> +#include <linux/atmel_pdc.h> +#include <linux/atmel-ssc.h> + +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> + +#include "atmel-pcm.h" + + +/*--------------------------------------------------------------------------*\ + * Hardware definition +\*--------------------------------------------------------------------------*/ +/* TODO: These values were taken from the AT91 platform driver, check + * them against real values for AT32 + */ +static const struct snd_pcm_hardware atmel_pcm_hardware = { + .info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_PAUSE, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .period_bytes_min = 32, + .period_bytes_max = 8192, + .periods_min = 2, + .periods_max = 1024, + .buffer_bytes_max = ATMEL_SSC_DMABUF_SIZE, +}; + + +/*--------------------------------------------------------------------------*\ + * Data types +\*--------------------------------------------------------------------------*/ +struct atmel_runtime_data { + struct atmel_pcm_dma_params *params; + dma_addr_t dma_buffer; /* physical address of dma buffer */ + dma_addr_t dma_buffer_end; /* first address beyond DMA buffer */ + size_t period_size; + + dma_addr_t period_ptr; /* physical address of next period */ + + /* PDC register save */ + u32 pdc_xpr_save; + u32 pdc_xcr_save; + u32 pdc_xnpr_save; + u32 pdc_xncr_save; +}; + +/*--------------------------------------------------------------------------*\ + * ISR +\*--------------------------------------------------------------------------*/ +static void atmel_pcm_dma_irq(u32 ssc_sr, + struct snd_pcm_substream *substream) +{ + struct atmel_runtime_data *prtd = substream->runtime->private_data; + struct atmel_pcm_dma_params *params = prtd->params; + static int count; + + count++; + + if (ssc_sr & params->mask->ssc_endbuf) { + pr_warn("atmel-pcm: buffer %s on %s (SSC_SR=%#x, count=%d)\n", + substream->stream == SNDRV_PCM_STREAM_PLAYBACK + ? "underrun" : "overrun", + params->name, ssc_sr, count); + + /* re-start the PDC */ + ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, + params->mask->pdc_disable); + prtd->period_ptr += prtd->period_size; + if (prtd->period_ptr >= prtd->dma_buffer_end) + prtd->period_ptr = prtd->dma_buffer; + + ssc_writex(params->ssc->regs, params->pdc->xpr, + prtd->period_ptr); + ssc_writex(params->ssc->regs, params->pdc->xcr, + prtd->period_size / params->pdc_xfer_size); + ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, + params->mask->pdc_enable); + } + + if (ssc_sr & params->mask->ssc_endx) { + /* Load the PDC next pointer and counter registers */ + prtd->period_ptr += prtd->period_size; + if (prtd->period_ptr >= prtd->dma_buffer_end) + prtd->period_ptr = prtd->dma_buffer; + + ssc_writex(params->ssc->regs, params->pdc->xnpr, + prtd->period_ptr); + ssc_writex(params->ssc->regs, params->pdc->xncr, + prtd->period_size / params->pdc_xfer_size); + } + + snd_pcm_period_elapsed(substream); +} + + +/*--------------------------------------------------------------------------*\ + * PCM operations +\*--------------------------------------------------------------------------*/ +static int atmel_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct atmel_runtime_data *prtd = runtime->private_data; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + + /* this may get called several times by oss emulation + * with different params */ + + snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); + runtime->dma_bytes = params_buffer_bytes(params); + + prtd->params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); + prtd->params->dma_intr_handler = atmel_pcm_dma_irq; + + prtd->dma_buffer = runtime->dma_addr; + prtd->dma_buffer_end = runtime->dma_addr + runtime->dma_bytes; + prtd->period_size = params_period_bytes(params); + + pr_debug("atmel-pcm: " + "hw_params: DMA for %s initialized " + "(dma_bytes=%u, period_size=%u)\n", + prtd->params->name, + runtime->dma_bytes, + prtd->period_size); + return 0; +} + +static int atmel_pcm_hw_free(struct snd_pcm_substream *substream) +{ + struct atmel_runtime_data *prtd = substream->runtime->private_data; + struct atmel_pcm_dma_params *params = prtd->params; + + if (params != NULL) { + ssc_writex(params->ssc->regs, SSC_PDC_PTCR, + params->mask->pdc_disable); + prtd->params->dma_intr_handler = NULL; + } + + return 0; +} + +static int atmel_pcm_prepare(struct snd_pcm_substream *substream) +{ + struct atmel_runtime_data *prtd = substream->runtime->private_data; + struct atmel_pcm_dma_params *params = prtd->params; + + ssc_writex(params->ssc->regs, SSC_IDR, + params->mask->ssc_endx | params->mask->ssc_endbuf); + ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, + params->mask->pdc_disable); + return 0; +} + +static int atmel_pcm_trigger(struct snd_pcm_substream *substream, + int cmd) +{ + struct snd_pcm_runtime *rtd = substream->runtime; + struct atmel_runtime_data *prtd = rtd->private_data; + struct atmel_pcm_dma_params *params = prtd->params; + int ret = 0; + + pr_debug("atmel-pcm:buffer_size = %ld," + "dma_area = %p, dma_bytes = %u\n", + rtd->buffer_size, rtd->dma_area, rtd->dma_bytes); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + prtd->period_ptr = prtd->dma_buffer; + + ssc_writex(params->ssc->regs, params->pdc->xpr, + prtd->period_ptr); + ssc_writex(params->ssc->regs, params->pdc->xcr, + prtd->period_size / params->pdc_xfer_size); + + prtd->period_ptr += prtd->period_size; + ssc_writex(params->ssc->regs, params->pdc->xnpr, + prtd->period_ptr); + ssc_writex(params->ssc->regs, params->pdc->xncr, + prtd->period_size / params->pdc_xfer_size); + + pr_debug("atmel-pcm: trigger: " + "period_ptr=%lx, xpr=%u, " + "xcr=%u, xnpr=%u, xncr=%u\n", + (unsigned long)prtd->period_ptr, + ssc_readx(params->ssc->regs, params->pdc->xpr), + ssc_readx(params->ssc->regs, params->pdc->xcr), + ssc_readx(params->ssc->regs, params->pdc->xnpr), + ssc_readx(params->ssc->regs, params->pdc->xncr)); + + ssc_writex(params->ssc->regs, SSC_IER, + params->mask->ssc_endx | params->mask->ssc_endbuf); + ssc_writex(params->ssc->regs, SSC_PDC_PTCR, + params->mask->pdc_enable); + + pr_debug("sr=%u imr=%u\n", + ssc_readx(params->ssc->regs, SSC_SR), + ssc_readx(params->ssc->regs, SSC_IER)); + break; /* SNDRV_PCM_TRIGGER_START */ + + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, + params->mask->pdc_disable); + break; + + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, + params->mask->pdc_enable); + break; + + default: + ret = -EINVAL; + } + + return ret; +} + +static snd_pcm_uframes_t atmel_pcm_pointer( + struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct atmel_runtime_data *prtd = runtime->private_data; + struct atmel_pcm_dma_params *params = prtd->params; + dma_addr_t ptr; + snd_pcm_uframes_t x; + + ptr = (dma_addr_t) ssc_readx(params->ssc->regs, params->pdc->xpr); + x = bytes_to_frames(runtime, ptr - prtd->dma_buffer); + + if (x == runtime->buffer_size) + x = 0; + + return x; +} + +static int atmel_pcm_open(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct atmel_runtime_data *prtd; + int ret = 0; + + snd_soc_set_runtime_hwparams(substream, &atmel_pcm_hardware); + + /* ensure that buffer size is a multiple of period size */ + ret = snd_pcm_hw_constraint_integer(runtime, + SNDRV_PCM_HW_PARAM_PERIODS); + if (ret < 0) + goto out; + + prtd = kzalloc(sizeof(struct atmel_runtime_data), GFP_KERNEL); + if (prtd == NULL) { + ret = -ENOMEM; + goto out; + } + runtime->private_data = prtd; + + out: + return ret; +} + +static int atmel_pcm_close(struct snd_pcm_substream *substream) +{ + struct atmel_runtime_data *prtd = substream->runtime->private_data; + + kfree(prtd); + return 0; +} + +static struct snd_pcm_ops atmel_pcm_ops = { + .open = atmel_pcm_open, + .close = atmel_pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = atmel_pcm_hw_params, + .hw_free = atmel_pcm_hw_free, + .prepare = atmel_pcm_prepare, + .trigger = atmel_pcm_trigger, + .pointer = atmel_pcm_pointer, + .mmap = atmel_pcm_mmap, +}; + + +/*--------------------------------------------------------------------------*\ + * ASoC platform driver +\*--------------------------------------------------------------------------*/ +#ifdef CONFIG_PM +static int atmel_pcm_suspend(struct snd_soc_dai *dai) +{ + struct snd_pcm_runtime *runtime = dai->runtime; + struct atmel_runtime_data *prtd; + struct atmel_pcm_dma_params *params; + + if (!runtime) + return 0; + + prtd = runtime->private_data; + params = prtd->params; + + /* disable the PDC and save the PDC registers */ + + ssc_writel(params->ssc->regs, PDC_PTCR, params->mask->pdc_disable); + + prtd->pdc_xpr_save = ssc_readx(params->ssc->regs, params->pdc->xpr); + prtd->pdc_xcr_save = ssc_readx(params->ssc->regs, params->pdc->xcr); + prtd->pdc_xnpr_save = ssc_readx(params->ssc->regs, params->pdc->xnpr); + prtd->pdc_xncr_save = ssc_readx(params->ssc->regs, params->pdc->xncr); + + return 0; +} + +static int atmel_pcm_resume(struct snd_soc_dai *dai) +{ + struct snd_pcm_runtime *runtime = dai->runtime; + struct atmel_runtime_data *prtd; + struct atmel_pcm_dma_params *params; + + if (!runtime) + return 0; + + prtd = runtime->private_data; + params = prtd->params; + + /* restore the PDC registers and enable the PDC */ + ssc_writex(params->ssc->regs, params->pdc->xpr, prtd->pdc_xpr_save); + ssc_writex(params->ssc->regs, params->pdc->xcr, prtd->pdc_xcr_save); + ssc_writex(params->ssc->regs, params->pdc->xnpr, prtd->pdc_xnpr_save); + ssc_writex(params->ssc->regs, params->pdc->xncr, prtd->pdc_xncr_save); + + ssc_writel(params->ssc->regs, PDC_PTCR, params->mask->pdc_enable); + return 0; +} +#else +#define atmel_pcm_suspend NULL +#define atmel_pcm_resume NULL +#endif + +static struct snd_soc_platform_driver atmel_soc_platform = { + .ops = &atmel_pcm_ops, + .pcm_new = atmel_pcm_new, + .pcm_free = atmel_pcm_free, + .suspend = atmel_pcm_suspend, + .resume = atmel_pcm_resume, +}; + +int atmel_pcm_pdc_platform_register(struct device *dev) +{ + return snd_soc_register_platform(dev, &atmel_soc_platform); +} +EXPORT_SYMBOL(atmel_pcm_pdc_platform_register); + +void atmel_pcm_pdc_platform_unregister(struct device *dev) +{ + snd_soc_unregister_platform(dev); +} +EXPORT_SYMBOL(atmel_pcm_pdc_platform_unregister); + +MODULE_AUTHOR("Sedji Gaouaou <sedji.gaouaou@atmel.com>"); +MODULE_DESCRIPTION("Atmel PCM module"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/atmel/atmel-pcm.c b/sound/soc/atmel/atmel-pcm.c index 9b84f985770e..e99f1811300a 100644 --- a/sound/soc/atmel/atmel-pcm.c +++ b/sound/soc/atmel/atmel-pcm.c @@ -32,80 +32,25 @@ */ #include <linux/module.h> -#include <linux/init.h> -#include <linux/platform_device.h> -#include <linux/slab.h> #include <linux/dma-mapping.h> -#include <linux/atmel_pdc.h> -#include <linux/atmel-ssc.h> - -#include <sound/core.h> #include <sound/pcm.h> -#include <sound/pcm_params.h> #include <sound/soc.h> - #include "atmel-pcm.h" - -/*--------------------------------------------------------------------------*\ - * Hardware definition -\*--------------------------------------------------------------------------*/ -/* TODO: These values were taken from the AT91 platform driver, check - * them against real values for AT32 - */ -static const struct snd_pcm_hardware atmel_pcm_hardware = { - .info = SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_PAUSE, - .formats = SNDRV_PCM_FMTBIT_S16_LE, - .period_bytes_min = 32, - .period_bytes_max = 8192, - .periods_min = 2, - .periods_max = 1024, - .buffer_bytes_max = 32 * 1024, -}; - - -/*--------------------------------------------------------------------------*\ - * Data types -\*--------------------------------------------------------------------------*/ -struct atmel_runtime_data { - struct atmel_pcm_dma_params *params; - dma_addr_t dma_buffer; /* physical address of dma buffer */ - dma_addr_t dma_buffer_end; /* first address beyond DMA buffer */ - size_t period_size; - - dma_addr_t period_ptr; /* physical address of next period */ - - /* PDC register save */ - u32 pdc_xpr_save; - u32 pdc_xcr_save; - u32 pdc_xnpr_save; - u32 pdc_xncr_save; -}; - - -/*--------------------------------------------------------------------------*\ - * Helper functions -\*--------------------------------------------------------------------------*/ static int atmel_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) { struct snd_pcm_substream *substream = pcm->streams[stream].substream; struct snd_dma_buffer *buf = &substream->dma_buffer; - size_t size = atmel_pcm_hardware.buffer_bytes_max; + size_t size = ATMEL_SSC_DMABUF_SIZE; buf->dev.type = SNDRV_DMA_TYPE_DEV; buf->dev.dev = pcm->card->dev; buf->private_data = NULL; buf->area = dma_alloc_coherent(pcm->card->dev, size, - &buf->addr, GFP_KERNEL); - pr_debug("atmel-pcm:" - "preallocate_dma_buffer: area=%p, addr=%p, size=%d\n", - (void *) buf->area, - (void *) buf->addr, - size); + &buf->addr, GFP_KERNEL); + pr_debug("atmel-pcm: alloc dma buffer: area=%p, addr=%p, size=%d\n", + (void *)buf->area, (void *)buf->addr, size); if (!buf->area) return -ENOMEM; @@ -113,258 +58,19 @@ static int atmel_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, buf->bytes = size; return 0; } -/*--------------------------------------------------------------------------*\ - * ISR -\*--------------------------------------------------------------------------*/ -static void atmel_pcm_dma_irq(u32 ssc_sr, - struct snd_pcm_substream *substream) -{ - struct atmel_runtime_data *prtd = substream->runtime->private_data; - struct atmel_pcm_dma_params *params = prtd->params; - static int count; - - count++; - - if (ssc_sr & params->mask->ssc_endbuf) { - pr_warning("atmel-pcm: buffer %s on %s" - " (SSC_SR=%#x, count=%d)\n", - substream->stream == SNDRV_PCM_STREAM_PLAYBACK - ? "underrun" : "overrun", - params->name, ssc_sr, count); - - /* re-start the PDC */ - ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, - params->mask->pdc_disable); - prtd->period_ptr += prtd->period_size; - if (prtd->period_ptr >= prtd->dma_buffer_end) - prtd->period_ptr = prtd->dma_buffer; - - ssc_writex(params->ssc->regs, params->pdc->xpr, - prtd->period_ptr); - ssc_writex(params->ssc->regs, params->pdc->xcr, - prtd->period_size / params->pdc_xfer_size); - ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, - params->mask->pdc_enable); - } - - if (ssc_sr & params->mask->ssc_endx) { - /* Load the PDC next pointer and counter registers */ - prtd->period_ptr += prtd->period_size; - if (prtd->period_ptr >= prtd->dma_buffer_end) - prtd->period_ptr = prtd->dma_buffer; - - ssc_writex(params->ssc->regs, params->pdc->xnpr, - prtd->period_ptr); - ssc_writex(params->ssc->regs, params->pdc->xncr, - prtd->period_size / params->pdc_xfer_size); - } - - snd_pcm_period_elapsed(substream); -} - - -/*--------------------------------------------------------------------------*\ - * PCM operations -\*--------------------------------------------------------------------------*/ -static int atmel_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct atmel_runtime_data *prtd = runtime->private_data; - struct snd_soc_pcm_runtime *rtd = substream->private_data; - - /* this may get called several times by oss emulation - * with different params */ - - snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); - runtime->dma_bytes = params_buffer_bytes(params); - - prtd->params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); - prtd->params->dma_intr_handler = atmel_pcm_dma_irq; - - prtd->dma_buffer = runtime->dma_addr; - prtd->dma_buffer_end = runtime->dma_addr + runtime->dma_bytes; - prtd->period_size = params_period_bytes(params); - - pr_debug("atmel-pcm: " - "hw_params: DMA for %s initialized " - "(dma_bytes=%u, period_size=%u)\n", - prtd->params->name, - runtime->dma_bytes, - prtd->period_size); - return 0; -} - -static int atmel_pcm_hw_free(struct snd_pcm_substream *substream) -{ - struct atmel_runtime_data *prtd = substream->runtime->private_data; - struct atmel_pcm_dma_params *params = prtd->params; - - if (params != NULL) { - ssc_writex(params->ssc->regs, SSC_PDC_PTCR, - params->mask->pdc_disable); - prtd->params->dma_intr_handler = NULL; - } - - return 0; -} - -static int atmel_pcm_prepare(struct snd_pcm_substream *substream) -{ - struct atmel_runtime_data *prtd = substream->runtime->private_data; - struct atmel_pcm_dma_params *params = prtd->params; - - ssc_writex(params->ssc->regs, SSC_IDR, - params->mask->ssc_endx | params->mask->ssc_endbuf); - ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, - params->mask->pdc_disable); - return 0; -} - -static int atmel_pcm_trigger(struct snd_pcm_substream *substream, - int cmd) -{ - struct snd_pcm_runtime *rtd = substream->runtime; - struct atmel_runtime_data *prtd = rtd->private_data; - struct atmel_pcm_dma_params *params = prtd->params; - int ret = 0; - - pr_debug("atmel-pcm:buffer_size = %ld," - "dma_area = %p, dma_bytes = %u\n", - rtd->buffer_size, rtd->dma_area, rtd->dma_bytes); - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - prtd->period_ptr = prtd->dma_buffer; - - ssc_writex(params->ssc->regs, params->pdc->xpr, - prtd->period_ptr); - ssc_writex(params->ssc->regs, params->pdc->xcr, - prtd->period_size / params->pdc_xfer_size); - - prtd->period_ptr += prtd->period_size; - ssc_writex(params->ssc->regs, params->pdc->xnpr, - prtd->period_ptr); - ssc_writex(params->ssc->regs, params->pdc->xncr, - prtd->period_size / params->pdc_xfer_size); - - pr_debug("atmel-pcm: trigger: " - "period_ptr=%lx, xpr=%u, " - "xcr=%u, xnpr=%u, xncr=%u\n", - (unsigned long)prtd->period_ptr, - ssc_readx(params->ssc->regs, params->pdc->xpr), - ssc_readx(params->ssc->regs, params->pdc->xcr), - ssc_readx(params->ssc->regs, params->pdc->xnpr), - ssc_readx(params->ssc->regs, params->pdc->xncr)); - - ssc_writex(params->ssc->regs, SSC_IER, - params->mask->ssc_endx | params->mask->ssc_endbuf); - ssc_writex(params->ssc->regs, SSC_PDC_PTCR, - params->mask->pdc_enable); - - pr_debug("sr=%u imr=%u\n", - ssc_readx(params->ssc->regs, SSC_SR), - ssc_readx(params->ssc->regs, SSC_IER)); - break; /* SNDRV_PCM_TRIGGER_START */ - - case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, - params->mask->pdc_disable); - break; - - case SNDRV_PCM_TRIGGER_RESUME: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, - params->mask->pdc_enable); - break; - - default: - ret = -EINVAL; - } - return ret; -} - -static snd_pcm_uframes_t atmel_pcm_pointer( - struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct atmel_runtime_data *prtd = runtime->private_data; - struct atmel_pcm_dma_params *params = prtd->params; - dma_addr_t ptr; - snd_pcm_uframes_t x; - - ptr = (dma_addr_t) ssc_readx(params->ssc->regs, params->pdc->xpr); - x = bytes_to_frames(runtime, ptr - prtd->dma_buffer); - - if (x == runtime->buffer_size) - x = 0; - - return x; -} - -static int atmel_pcm_open(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct atmel_runtime_data *prtd; - int ret = 0; - - snd_soc_set_runtime_hwparams(substream, &atmel_pcm_hardware); - - /* ensure that buffer size is a multiple of period size */ - ret = snd_pcm_hw_constraint_integer(runtime, - SNDRV_PCM_HW_PARAM_PERIODS); - if (ret < 0) - goto out; - - prtd = kzalloc(sizeof(struct atmel_runtime_data), GFP_KERNEL); - if (prtd == NULL) { - ret = -ENOMEM; - goto out; - } - runtime->private_data = prtd; - - out: - return ret; -} - -static int atmel_pcm_close(struct snd_pcm_substream *substream) -{ - struct atmel_runtime_data *prtd = substream->runtime->private_data; - - kfree(prtd); - return 0; -} - -static int atmel_pcm_mmap(struct snd_pcm_substream *substream, +int atmel_pcm_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *vma) { return remap_pfn_range(vma, vma->vm_start, substream->dma_buffer.addr >> PAGE_SHIFT, vma->vm_end - vma->vm_start, vma->vm_page_prot); } +EXPORT_SYMBOL_GPL(atmel_pcm_mmap); -static struct snd_pcm_ops atmel_pcm_ops = { - .open = atmel_pcm_open, - .close = atmel_pcm_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = atmel_pcm_hw_params, - .hw_free = atmel_pcm_hw_free, - .prepare = atmel_pcm_prepare, - .trigger = atmel_pcm_trigger, - .pointer = atmel_pcm_pointer, - .mmap = atmel_pcm_mmap, -}; - - -/*--------------------------------------------------------------------------*\ - * ASoC platform driver -\*--------------------------------------------------------------------------*/ static u64 atmel_pcm_dmamask = DMA_BIT_MASK(32); -static int atmel_pcm_new(struct snd_soc_pcm_runtime *rtd) +int atmel_pcm_new(struct snd_soc_pcm_runtime *rtd) { struct snd_card *card = rtd->card->snd_card; struct snd_pcm *pcm = rtd->pcm; @@ -376,6 +82,7 @@ static int atmel_pcm_new(struct snd_soc_pcm_runtime *rtd) card->dev->coherent_dma_mask = DMA_BIT_MASK(32); if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) { + pr_debug("atmel-pcm: allocating PCM playback DMA buffer\n"); ret = atmel_pcm_preallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_PLAYBACK); if (ret) @@ -383,8 +90,7 @@ static int atmel_pcm_new(struct snd_soc_pcm_runtime *rtd) } if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) { - pr_debug("atmel-pcm:" - "Allocating PCM capture DMA buffer\n"); + pr_debug("atmel-pcm: allocating PCM capture DMA buffer\n"); ret = atmel_pcm_preallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_CAPTURE); if (ret) @@ -393,8 +99,9 @@ static int atmel_pcm_new(struct snd_soc_pcm_runtime *rtd) out: return ret; } +EXPORT_SYMBOL_GPL(atmel_pcm_new); -static void atmel_pcm_free_dma_buffers(struct snd_pcm *pcm) +void atmel_pcm_free(struct snd_pcm *pcm) { struct snd_pcm_substream *substream; struct snd_dma_buffer *buf; @@ -413,89 +120,5 @@ static void atmel_pcm_free_dma_buffers(struct snd_pcm *pcm) buf->area = NULL; } } +EXPORT_SYMBOL_GPL(atmel_pcm_free); -#ifdef CONFIG_PM -static int atmel_pcm_suspend(struct snd_soc_dai *dai) -{ - struct snd_pcm_runtime *runtime = dai->runtime; - struct atmel_runtime_data *prtd; - struct atmel_pcm_dma_params *params; - - if (!runtime) - return 0; - - prtd = runtime->private_data; - params = prtd->params; - - /* disable the PDC and save the PDC registers */ - - ssc_writel(params->ssc->regs, PDC_PTCR, params->mask->pdc_disable); - - prtd->pdc_xpr_save = ssc_readx(params->ssc->regs, params->pdc->xpr); - prtd->pdc_xcr_save = ssc_readx(params->ssc->regs, params->pdc->xcr); - prtd->pdc_xnpr_save = ssc_readx(params->ssc->regs, params->pdc->xnpr); - prtd->pdc_xncr_save = ssc_readx(params->ssc->regs, params->pdc->xncr); - - return 0; -} - -static int atmel_pcm_resume(struct snd_soc_dai *dai) -{ - struct snd_pcm_runtime *runtime = dai->runtime; - struct atmel_runtime_data *prtd; - struct atmel_pcm_dma_params *params; - - if (!runtime) - return 0; - - prtd = runtime->private_data; - params = prtd->params; - - /* restore the PDC registers and enable the PDC */ - ssc_writex(params->ssc->regs, params->pdc->xpr, prtd->pdc_xpr_save); - ssc_writex(params->ssc->regs, params->pdc->xcr, prtd->pdc_xcr_save); - ssc_writex(params->ssc->regs, params->pdc->xnpr, prtd->pdc_xnpr_save); - ssc_writex(params->ssc->regs, params->pdc->xncr, prtd->pdc_xncr_save); - - ssc_writel(params->ssc->regs, PDC_PTCR, params->mask->pdc_enable); - return 0; -} -#else -#define atmel_pcm_suspend NULL -#define atmel_pcm_resume NULL -#endif - -static struct snd_soc_platform_driver atmel_soc_platform = { - .ops = &atmel_pcm_ops, - .pcm_new = atmel_pcm_new, - .pcm_free = atmel_pcm_free_dma_buffers, - .suspend = atmel_pcm_suspend, - .resume = atmel_pcm_resume, -}; - -static int __devinit atmel_soc_platform_probe(struct platform_device *pdev) -{ - return snd_soc_register_platform(&pdev->dev, &atmel_soc_platform); -} - -static int __devexit atmel_soc_platform_remove(struct platform_device *pdev) -{ - snd_soc_unregister_platform(&pdev->dev); - return 0; -} - -static struct platform_driver atmel_pcm_driver = { - .driver = { - .name = "atmel-pcm-audio", - .owner = THIS_MODULE, - }, - - .probe = atmel_soc_platform_probe, - .remove = __devexit_p(atmel_soc_platform_remove), -}; - -module_platform_driver(atmel_pcm_driver); - -MODULE_AUTHOR("Sedji Gaouaou <sedji.gaouaou@atmel.com>"); -MODULE_DESCRIPTION("Atmel PCM module"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/atmel/atmel-pcm.h b/sound/soc/atmel/atmel-pcm.h index 5e0a95e64329..bb45d20e7250 100644 --- a/sound/soc/atmel/atmel-pcm.h +++ b/sound/soc/atmel/atmel-pcm.h @@ -36,6 +36,8 @@ #include <linux/atmel-ssc.h> +#define ATMEL_SSC_DMABUF_SIZE (64 * 1024) + /* * Registers and status bits that are required by the PCM driver. */ @@ -50,6 +52,7 @@ struct atmel_pdc_regs { struct atmel_ssc_mask { u32 ssc_enable; /* SSC recv/trans enable */ u32 ssc_disable; /* SSC recv/trans disable */ + u32 ssc_error; /* SSC error conditions */ u32 ssc_endx; /* SSC ENDTX or ENDRX */ u32 ssc_endbuf; /* SSC TXBUFE or RXBUFF */ u32 pdc_enable; /* PDC recv/trans enable */ @@ -80,4 +83,35 @@ struct atmel_pcm_dma_params { #define ssc_readx(base, reg) (__raw_readl((base) + (reg))) #define ssc_writex(base, reg, value) __raw_writel((value), (base) + (reg)) +int atmel_pcm_new(struct snd_soc_pcm_runtime *rtd); +void atmel_pcm_free(struct snd_pcm *pcm); +int atmel_pcm_mmap(struct snd_pcm_substream *substream, + struct vm_area_struct *vma); + +#ifdef CONFIG_SND_ATMEL_SOC_PDC +int atmel_pcm_pdc_platform_register(struct device *dev); +void atmel_pcm_pdc_platform_unregister(struct device *dev); +#else +static inline int atmel_pcm_pdc_platform_register(struct device *dev) +{ + return 0; +} +static inline void atmel_pcm_pdc_platform_unregister(struct device *dev) +{ +} +#endif + +#ifdef CONFIG_SND_ATMEL_SOC_DMA +int atmel_pcm_dma_platform_register(struct device *dev); +void atmel_pcm_dma_platform_unregister(struct device *dev); +#else +static inline int atmel_pcm_dma_platform_register(struct device *dev) +{ + return 0; +} +static inline void atmel_pcm_dma_platform_unregister(struct device *dev) +{ +} +#endif + #endif /* _ATMEL_PCM_H */ diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c index 354341ec0f42..1c7663422054 100644 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ b/sound/soc/atmel/atmel_ssc_dai.c @@ -48,11 +48,7 @@ #include "atmel_ssc_dai.h" -#if defined(CONFIG_ARCH_AT91SAM9260) || defined(CONFIG_ARCH_AT91SAM9G20) -#define NUM_SSC_DEVICES 1 -#else #define NUM_SSC_DEVICES 3 -#endif /* * SSC PDC registers required by the PCM DMA engine. @@ -107,7 +103,6 @@ static struct atmel_pcm_dma_params ssc_dma_params[NUM_SSC_DEVICES][2] = { .pdc = &pdc_rx_reg, .mask = &ssc_rx_mask, } }, -#if NUM_SSC_DEVICES == 3 {{ .name = "SSC1 PCM out", .pdc = &pdc_tx_reg, @@ -128,7 +123,6 @@ static struct atmel_pcm_dma_params ssc_dma_params[NUM_SSC_DEVICES][2] = { .pdc = &pdc_rx_reg, .mask = &ssc_rx_mask, } }, -#endif }; @@ -139,7 +133,6 @@ static struct atmel_ssc_info ssc_info[NUM_SSC_DEVICES] = { .dir_mask = SSC_DIR_MASK_UNUSED, .initialized = 0, }, -#if NUM_SSC_DEVICES == 3 { .name = "ssc1", .lock = __SPIN_LOCK_UNLOCKED(ssc_info[1].lock), @@ -152,7 +145,6 @@ static struct atmel_ssc_info ssc_info[NUM_SSC_DEVICES] = { .dir_mask = SSC_DIR_MASK_UNUSED, .initialized = 0, }, -#endif }; @@ -690,27 +682,9 @@ static int atmel_ssc_resume(struct snd_soc_dai *cpu_dai) static int atmel_ssc_probe(struct snd_soc_dai *dai) { struct atmel_ssc_info *ssc_p = &ssc_info[dai->id]; - int ret = 0; snd_soc_dai_set_drvdata(dai, ssc_p); - /* - * Request SSC device - */ - ssc_p->ssc = ssc_request(dai->id); - if (IS_ERR(ssc_p->ssc)) { - printk(KERN_ERR "ASoC: Failed to request SSC %d\n", dai->id); - ret = PTR_ERR(ssc_p->ssc); - } - - return ret; -} - -static int atmel_ssc_remove(struct snd_soc_dai *dai) -{ - struct atmel_ssc_info *ssc_p = snd_soc_dai_get_drvdata(dai); - - ssc_free(ssc_p->ssc); return 0; } @@ -728,30 +702,8 @@ static const struct snd_soc_dai_ops atmel_ssc_dai_ops = { .set_clkdiv = atmel_ssc_set_dai_clkdiv, }; -static struct snd_soc_dai_driver atmel_ssc_dai[NUM_SSC_DEVICES] = { - { - .name = "atmel-ssc-dai.0", - .probe = atmel_ssc_probe, - .remove = atmel_ssc_remove, - .suspend = atmel_ssc_suspend, - .resume = atmel_ssc_resume, - .playback = { - .channels_min = 1, - .channels_max = 2, - .rates = ATMEL_SSC_RATES, - .formats = ATMEL_SSC_FORMATS,}, - .capture = { - .channels_min = 1, - .channels_max = 2, - .rates = ATMEL_SSC_RATES, - .formats = ATMEL_SSC_FORMATS,}, - .ops = &atmel_ssc_dai_ops, - }, -#if NUM_SSC_DEVICES == 3 - { - .name = "atmel-ssc-dai.1", +static struct snd_soc_dai_driver atmel_ssc_dai = { .probe = atmel_ssc_probe, - .remove = atmel_ssc_remove, .suspend = atmel_ssc_suspend, .resume = atmel_ssc_resume, .playback = { @@ -765,50 +717,50 @@ static struct snd_soc_dai_driver atmel_ssc_dai[NUM_SSC_DEVICES] = { .rates = ATMEL_SSC_RATES, .formats = ATMEL_SSC_FORMATS,}, .ops = &atmel_ssc_dai_ops, - }, - { - .name = "atmel-ssc-dai.2", - .probe = atmel_ssc_probe, - .remove = atmel_ssc_remove, - .suspend = atmel_ssc_suspend, - .resume = atmel_ssc_resume, - .playback = { - .channels_min = 1, - .channels_max = 2, - .rates = ATMEL_SSC_RATES, - .formats = ATMEL_SSC_FORMATS,}, - .capture = { - .channels_min = 1, - .channels_max = 2, - .rates = ATMEL_SSC_RATES, - .formats = ATMEL_SSC_FORMATS,}, - .ops = &atmel_ssc_dai_ops, - }, -#endif }; -static __devinit int asoc_ssc_probe(struct platform_device *pdev) +static int asoc_ssc_init(struct device *dev) { - BUG_ON(pdev->id < 0); - BUG_ON(pdev->id >= ARRAY_SIZE(atmel_ssc_dai)); - return snd_soc_register_dai(&pdev->dev, &atmel_ssc_dai[pdev->id]); -} + struct platform_device *pdev = to_platform_device(dev); + struct ssc_device *ssc = platform_get_drvdata(pdev); + int ret; + + ret = snd_soc_register_dai(dev, &atmel_ssc_dai); + if (ret) { + dev_err(dev, "Could not register DAI: %d\n", ret); + goto err; + } + + if (ssc->pdata->use_dma) + ret = atmel_pcm_dma_platform_register(dev); + else + ret = atmel_pcm_pdc_platform_register(dev); + + if (ret) { + dev_err(dev, "Could not register PCM: %d\n", ret); + goto err_unregister_dai; + }; -static int __devexit asoc_ssc_remove(struct platform_device *pdev) -{ - snd_soc_unregister_dai(&pdev->dev); return 0; + +err_unregister_dai: + snd_soc_unregister_dai(dev); +err: + return ret; } -static struct platform_driver asoc_ssc_driver = { - .driver = { - .name = "atmel-ssc-dai", - .owner = THIS_MODULE, - }, +static void asoc_ssc_exit(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct ssc_device *ssc = platform_get_drvdata(pdev); - .probe = asoc_ssc_probe, - .remove = __devexit_p(asoc_ssc_remove), -}; + if (ssc->pdata->use_dma) + atmel_pcm_dma_platform_unregister(dev); + else + atmel_pcm_pdc_platform_unregister(dev); + + snd_soc_unregister_dai(dev); +} /** * atmel_ssc_set_audio - Allocate the specified SSC for audio use. @@ -816,50 +768,32 @@ static struct platform_driver asoc_ssc_driver = { int atmel_ssc_set_audio(int ssc_id) { struct ssc_device *ssc; - static struct platform_device *dma_pdev; - struct platform_device *ssc_pdev; int ret; - if (ssc_id < 0 || ssc_id >= ARRAY_SIZE(atmel_ssc_dai)) - return -EINVAL; - - /* Allocate a dummy device for DMA if we don't have one already */ - if (!dma_pdev) { - dma_pdev = platform_device_alloc("atmel-pcm-audio", -1); - if (!dma_pdev) - return -ENOMEM; - - ret = platform_device_add(dma_pdev); - if (ret < 0) { - platform_device_put(dma_pdev); - dma_pdev = NULL; - return ret; - } - } - - ssc_pdev = platform_device_alloc("atmel-ssc-dai", ssc_id); - if (!ssc_pdev) - return -ENOMEM; - /* If we can grab the SSC briefly to parent the DAI device off it */ ssc = ssc_request(ssc_id); - if (IS_ERR(ssc)) - pr_warn("Unable to parent ASoC SSC DAI on SSC: %ld\n", + if (IS_ERR(ssc)) { + pr_err("Unable to parent ASoC SSC DAI on SSC: %ld\n", PTR_ERR(ssc)); - else { - ssc_pdev->dev.parent = &(ssc->pdev->dev); - ssc_free(ssc); + return PTR_ERR(ssc); + } else { + ssc_info[ssc_id].ssc = ssc; } - ret = platform_device_add(ssc_pdev); - if (ret < 0) - platform_device_put(ssc_pdev); + ret = asoc_ssc_init(&ssc->pdev->dev); return ret; } EXPORT_SYMBOL_GPL(atmel_ssc_set_audio); -module_platform_driver(asoc_ssc_driver); +void atmel_ssc_put_audio(int ssc_id) +{ + struct ssc_device *ssc = ssc_info[ssc_id].ssc; + + ssc_free(ssc); + asoc_ssc_exit(&ssc->pdev->dev); +} +EXPORT_SYMBOL_GPL(atmel_ssc_put_audio); /* Module information */ MODULE_AUTHOR("Sedji Gaouaou, sedji.gaouaou@atmel.com, www.atmel.com"); diff --git a/sound/soc/atmel/atmel_ssc_dai.h b/sound/soc/atmel/atmel_ssc_dai.h index 5d4f0f9b4d9a..b1f08d511495 100644 --- a/sound/soc/atmel/atmel_ssc_dai.h +++ b/sound/soc/atmel/atmel_ssc_dai.h @@ -117,6 +117,7 @@ struct atmel_ssc_info { struct atmel_ssc_state ssc_state; }; -int atmel_ssc_set_audio(int ssc); +int atmel_ssc_set_audio(int ssc_id); +void atmel_ssc_put_audio(int ssc_id); #endif /* _AT91_SSC_DAI_H */ diff --git a/sound/soc/atmel/sam9g20_wm8731.c b/sound/soc/atmel/sam9g20_wm8731.c index c88351488f45..da976291da9e 100644 --- a/sound/soc/atmel/sam9g20_wm8731.c +++ b/sound/soc/atmel/sam9g20_wm8731.c @@ -38,6 +38,8 @@ #include <linux/platform_device.h> #include <linux/i2c.h> +#include <linux/pinctrl/consumer.h> + #include <linux/atmel-ssc.h> #include <sound/core.h> @@ -179,10 +181,10 @@ static int at91sam9g20ek_wm8731_init(struct snd_soc_pcm_runtime *rtd) static struct snd_soc_dai_link at91sam9g20ek_dai = { .name = "WM8731", .stream_name = "WM8731 PCM", - .cpu_dai_name = "atmel-ssc-dai.0", + .cpu_dai_name = "at91rm9200_ssc.0", .codec_dai_name = "wm8731-hifi", .init = at91sam9g20ek_wm8731_init, - .platform_name = "atmel-pcm-audio", + .platform_name = "at91rm9200_ssc.0", .codec_name = "wm8731.0-001b", .ops = &at91sam9g20ek_ops, }; @@ -195,20 +197,31 @@ static struct snd_soc_card snd_soc_at91sam9g20ek = { .set_bias_level = at91sam9g20ek_set_bias_level, }; -static struct platform_device *at91sam9g20ek_snd_device; - -static int __init at91sam9g20ek_init(void) +static int at91sam9g20ek_audio_probe(struct platform_device *pdev) { + struct device_node *np = pdev->dev.of_node; + struct device_node *codec_np, *cpu_np; struct clk *pllb; + struct snd_soc_card *card = &snd_soc_at91sam9g20ek; + struct pinctrl *pinctrl; int ret; - if (!(machine_is_at91sam9g20ek() || machine_is_at91sam9g20ek_2mmc())) - return -ENODEV; + pinctrl = devm_pinctrl_get_select_default(&pdev->dev); + if (IS_ERR(pinctrl)) { + dev_err(&pdev->dev, "Failed to request pinctrl for mck\n"); + return PTR_ERR(pinctrl); + } + + if (!np) { + if (!(machine_is_at91sam9g20ek() || + machine_is_at91sam9g20ek_2mmc())) + return -ENODEV; + } ret = atmel_ssc_set_audio(0); - if (ret != 0) { - pr_err("Failed to set SSC 0 for audio: %d\n", ret); - return ret; + if (ret) { + dev_err(&pdev->dev, "ssc channel is not valid\n"); + return -EINVAL; } /* @@ -236,45 +249,92 @@ static int __init at91sam9g20ek_init(void) clk_set_rate(mclk, MCLK_RATE); - at91sam9g20ek_snd_device = platform_device_alloc("soc-audio", -1); - if (!at91sam9g20ek_snd_device) { - printk(KERN_ERR "ASoC: Platform device allocation failed\n"); - ret = -ENOMEM; - goto err_mclk; + card->dev = &pdev->dev; + + /* Parse device node info */ + if (np) { + ret = snd_soc_of_parse_card_name(card, "atmel,model"); + if (ret) + goto err; + + ret = snd_soc_of_parse_audio_routing(card, + "atmel,audio-routing"); + if (ret) + goto err; + + /* Parse codec info */ + at91sam9g20ek_dai.codec_name = NULL; + codec_np = of_parse_phandle(np, "atmel,audio-codec", 0); + if (!codec_np) { + dev_err(&pdev->dev, "codec info missing\n"); + return -EINVAL; + } + at91sam9g20ek_dai.codec_of_node = codec_np; + + /* Parse dai and platform info */ + at91sam9g20ek_dai.cpu_dai_name = NULL; + at91sam9g20ek_dai.platform_name = NULL; + cpu_np = of_parse_phandle(np, "atmel,ssc-controller", 0); + if (!cpu_np) { + dev_err(&pdev->dev, "dai and pcm info missing\n"); + return -EINVAL; + } + at91sam9g20ek_dai.cpu_of_node = cpu_np; + at91sam9g20ek_dai.platform_of_node = cpu_np; + + of_node_put(codec_np); + of_node_put(cpu_np); } - platform_set_drvdata(at91sam9g20ek_snd_device, - &snd_soc_at91sam9g20ek); - - ret = platform_device_add(at91sam9g20ek_snd_device); + ret = snd_soc_register_card(card); if (ret) { - printk(KERN_ERR "ASoC: Platform device allocation failed\n"); - goto err_device_add; + printk(KERN_ERR "ASoC: snd_soc_register_card() failed\n"); } return ret; -err_device_add: - platform_device_put(at91sam9g20ek_snd_device); err_mclk: clk_put(mclk); mclk = NULL; err: + atmel_ssc_put_audio(0); return ret; } -static void __exit at91sam9g20ek_exit(void) +static int at91sam9g20ek_audio_remove(struct platform_device *pdev) { - platform_device_unregister(at91sam9g20ek_snd_device); - at91sam9g20ek_snd_device = NULL; + struct snd_soc_card *card = platform_get_drvdata(pdev); + + atmel_ssc_put_audio(0); + snd_soc_unregister_card(card); clk_put(mclk); mclk = NULL; + + return 0; } -module_init(at91sam9g20ek_init); -module_exit(at91sam9g20ek_exit); +#ifdef CONFIG_OF +static const struct of_device_id at91sam9g20ek_wm8731_dt_ids[] = { + { .compatible = "atmel,at91sam9g20ek-wm8731-audio", }, + { } +}; +MODULE_DEVICE_TABLE(of, at91sam9g20ek_wm8731_dt_ids); +#endif + +static struct platform_driver at91sam9g20ek_audio_driver = { + .driver = { + .name = "at91sam9g20ek-audio", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(at91sam9g20ek_wm8731_dt_ids), + }, + .probe = at91sam9g20ek_audio_probe, + .remove = at91sam9g20ek_audio_remove, +}; + +module_platform_driver(at91sam9g20ek_audio_driver); /* Module information */ MODULE_AUTHOR("Sedji Gaouaou <sedji.gaouaou@atmel.com>"); MODULE_DESCRIPTION("ALSA SoC AT91SAM9G20EK_WM8731"); +MODULE_ALIAS("platform:at91sam9g20ek-audio"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/au1x/ac97c.c b/sound/soc/au1x/ac97c.c index c5ac2449563a..ea7d9d157022 100644 --- a/sound/soc/au1x/ac97c.c +++ b/sound/soc/au1x/ac97c.c @@ -223,7 +223,7 @@ static struct snd_soc_dai_driver au1xac97c_dai_driver = { .ops = &alchemy_ac97c_ops, }; -static int __devinit au1xac97c_drvprobe(struct platform_device *pdev) +static int au1xac97c_drvprobe(struct platform_device *pdev) { int ret; struct resource *iores, *dmares; @@ -276,7 +276,7 @@ static int __devinit au1xac97c_drvprobe(struct platform_device *pdev) return 0; } -static int __devexit au1xac97c_drvremove(struct platform_device *pdev) +static int au1xac97c_drvremove(struct platform_device *pdev) { struct au1xpsc_audio_data *ctx = platform_get_drvdata(pdev); @@ -330,7 +330,7 @@ static struct platform_driver au1xac97c_driver = { .pm = AU1XPSCAC97_PMOPS, }, .probe = au1xac97c_drvprobe, - .remove = __devexit_p(au1xac97c_drvremove), + .remove = au1xac97c_drvremove, }; static int __init au1xac97c_load(void) diff --git a/sound/soc/au1x/db1000.c b/sound/soc/au1x/db1000.c index 511d83c11a9a..376d976bcc2d 100644 --- a/sound/soc/au1x/db1000.c +++ b/sound/soc/au1x/db1000.c @@ -34,14 +34,14 @@ static struct snd_soc_card db1000_ac97 = { .num_links = 1, }; -static int __devinit db1000_audio_probe(struct platform_device *pdev) +static int db1000_audio_probe(struct platform_device *pdev) { struct snd_soc_card *card = &db1000_ac97; card->dev = &pdev->dev; return snd_soc_register_card(card); } -static int __devexit db1000_audio_remove(struct platform_device *pdev) +static int db1000_audio_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); snd_soc_unregister_card(card); @@ -55,7 +55,7 @@ static struct platform_driver db1000_audio_driver = { .pm = &snd_soc_pm_ops, }, .probe = db1000_audio_probe, - .remove = __devexit_p(db1000_audio_remove), + .remove = db1000_audio_remove, }; module_platform_driver(db1000_audio_driver); diff --git a/sound/soc/au1x/db1200.c b/sound/soc/au1x/db1200.c index 30ea513d81d7..a497a0cfeba1 100644 --- a/sound/soc/au1x/db1200.c +++ b/sound/soc/au1x/db1200.c @@ -167,7 +167,7 @@ static struct snd_soc_card db1550_i2s_machine = { /*------------------------- COMMON PART ---------------------------*/ -static struct snd_soc_card *db1200_cards[] __devinitdata = { +static struct snd_soc_card *db1200_cards[] = { &db1200_ac97_machine, &db1200_i2s_machine, &db1300_ac97_machine, @@ -176,7 +176,7 @@ static struct snd_soc_card *db1200_cards[] __devinitdata = { &db1550_i2s_machine, }; -static int __devinit db1200_audio_probe(struct platform_device *pdev) +static int db1200_audio_probe(struct platform_device *pdev) { const struct platform_device_id *pid = platform_get_device_id(pdev); struct snd_soc_card *card; @@ -186,7 +186,7 @@ static int __devinit db1200_audio_probe(struct platform_device *pdev) return snd_soc_register_card(card); } -static int __devexit db1200_audio_remove(struct platform_device *pdev) +static int db1200_audio_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); snd_soc_unregister_card(card); @@ -201,7 +201,7 @@ static struct platform_driver db1200_audio_driver = { }, .id_table = db1200_pids, .probe = db1200_audio_probe, - .remove = __devexit_p(db1200_audio_remove), + .remove = db1200_audio_remove, }; module_platform_driver(db1200_audio_driver); diff --git a/sound/soc/au1x/dbdma2.c b/sound/soc/au1x/dbdma2.c index 8372cd35f0d6..3b4eafaf30d3 100644 --- a/sound/soc/au1x/dbdma2.c +++ b/sound/soc/au1x/dbdma2.c @@ -347,7 +347,7 @@ static struct snd_soc_platform_driver au1xpsc_soc_platform = { .pcm_free = au1xpsc_pcm_free_dma_buffers, }; -static int __devinit au1xpsc_pcm_drvprobe(struct platform_device *pdev) +static int au1xpsc_pcm_drvprobe(struct platform_device *pdev) { struct au1xpsc_audio_dmadata *dmadata; @@ -362,7 +362,7 @@ static int __devinit au1xpsc_pcm_drvprobe(struct platform_device *pdev) return snd_soc_register_platform(&pdev->dev, &au1xpsc_soc_platform); } -static int __devexit au1xpsc_pcm_drvremove(struct platform_device *pdev) +static int au1xpsc_pcm_drvremove(struct platform_device *pdev) { snd_soc_unregister_platform(&pdev->dev); @@ -375,7 +375,7 @@ static struct platform_driver au1xpsc_pcm_driver = { .owner = THIS_MODULE, }, .probe = au1xpsc_pcm_drvprobe, - .remove = __devexit_p(au1xpsc_pcm_drvremove), + .remove = au1xpsc_pcm_drvremove, }; module_platform_driver(au1xpsc_pcm_driver); diff --git a/sound/soc/au1x/dma.c b/sound/soc/au1x/dma.c index 0a91b186a86f..befd1074f9bd 100644 --- a/sound/soc/au1x/dma.c +++ b/sound/soc/au1x/dma.c @@ -322,7 +322,7 @@ static struct snd_soc_platform_driver alchemy_pcm_soc_platform = { .pcm_free = alchemy_pcm_free_dma_buffers, }; -static int __devinit alchemy_pcm_drvprobe(struct platform_device *pdev) +static int alchemy_pcm_drvprobe(struct platform_device *pdev) { struct alchemy_pcm_ctx *ctx; @@ -335,7 +335,7 @@ static int __devinit alchemy_pcm_drvprobe(struct platform_device *pdev) return snd_soc_register_platform(&pdev->dev, &alchemy_pcm_soc_platform); } -static int __devexit alchemy_pcm_drvremove(struct platform_device *pdev) +static int alchemy_pcm_drvremove(struct platform_device *pdev) { snd_soc_unregister_platform(&pdev->dev); @@ -348,7 +348,7 @@ static struct platform_driver alchemy_pcmdma_driver = { .owner = THIS_MODULE, }, .probe = alchemy_pcm_drvprobe, - .remove = __devexit_p(alchemy_pcm_drvremove), + .remove = alchemy_pcm_drvremove, }; module_platform_driver(alchemy_pcmdma_driver); diff --git a/sound/soc/au1x/i2sc.c b/sound/soc/au1x/i2sc.c index d4b9e364a47a..072448afc219 100644 --- a/sound/soc/au1x/i2sc.c +++ b/sound/soc/au1x/i2sc.c @@ -225,7 +225,7 @@ static struct snd_soc_dai_driver au1xi2s_dai_driver = { .ops = &au1xi2s_dai_ops, }; -static int __devinit au1xi2s_drvprobe(struct platform_device *pdev) +static int au1xi2s_drvprobe(struct platform_device *pdev) { struct resource *iores, *dmares; struct au1xpsc_audio_data *ctx; @@ -263,7 +263,7 @@ static int __devinit au1xi2s_drvprobe(struct platform_device *pdev) return snd_soc_register_dai(&pdev->dev, &au1xi2s_dai_driver); } -static int __devexit au1xi2s_drvremove(struct platform_device *pdev) +static int au1xi2s_drvremove(struct platform_device *pdev) { struct au1xpsc_audio_data *ctx = platform_get_drvdata(pdev); @@ -309,7 +309,7 @@ static struct platform_driver au1xi2s_driver = { .pm = AU1XI2SC_PMOPS, }, .probe = au1xi2s_drvprobe, - .remove = __devexit_p(au1xi2s_drvremove), + .remove = au1xi2s_drvremove, }; module_platform_driver(au1xi2s_driver); diff --git a/sound/soc/au1x/psc-ac97.c b/sound/soc/au1x/psc-ac97.c index 476b79a1c11a..6ba07e365967 100644 --- a/sound/soc/au1x/psc-ac97.c +++ b/sound/soc/au1x/psc-ac97.c @@ -361,7 +361,7 @@ static const struct snd_soc_dai_driver au1xpsc_ac97_dai_template = { .ops = &au1xpsc_ac97_dai_ops, }; -static int __devinit au1xpsc_ac97_drvprobe(struct platform_device *pdev) +static int au1xpsc_ac97_drvprobe(struct platform_device *pdev) { int ret; struct resource *iores, *dmares; @@ -427,7 +427,7 @@ static int __devinit au1xpsc_ac97_drvprobe(struct platform_device *pdev) return 0; } -static int __devexit au1xpsc_ac97_drvremove(struct platform_device *pdev) +static int au1xpsc_ac97_drvremove(struct platform_device *pdev) { struct au1xpsc_audio_data *wd = platform_get_drvdata(pdev); @@ -495,7 +495,7 @@ static struct platform_driver au1xpsc_ac97_driver = { .pm = AU1XPSCAC97_PMOPS, }, .probe = au1xpsc_ac97_drvprobe, - .remove = __devexit_p(au1xpsc_ac97_drvremove), + .remove = au1xpsc_ac97_drvremove, }; static int __init au1xpsc_ac97_load(void) diff --git a/sound/soc/au1x/psc-i2s.c b/sound/soc/au1x/psc-i2s.c index 0607ba3d9258..360b4e50d7c8 100644 --- a/sound/soc/au1x/psc-i2s.c +++ b/sound/soc/au1x/psc-i2s.c @@ -288,7 +288,7 @@ static const struct snd_soc_dai_driver au1xpsc_i2s_dai_template = { .ops = &au1xpsc_i2s_dai_ops, }; -static int __devinit au1xpsc_i2s_drvprobe(struct platform_device *pdev) +static int au1xpsc_i2s_drvprobe(struct platform_device *pdev) { struct resource *iores, *dmares; unsigned long sel; @@ -353,7 +353,7 @@ static int __devinit au1xpsc_i2s_drvprobe(struct platform_device *pdev) return snd_soc_register_dai(&pdev->dev, &wd->dai_drv); } -static int __devexit au1xpsc_i2s_drvremove(struct platform_device *pdev) +static int au1xpsc_i2s_drvremove(struct platform_device *pdev) { struct au1xpsc_audio_data *wd = platform_get_drvdata(pdev); @@ -418,7 +418,7 @@ static struct platform_driver au1xpsc_i2s_driver = { .pm = AU1XPSCI2S_PMOPS, }, .probe = au1xpsc_i2s_drvprobe, - .remove = __devexit_p(au1xpsc_i2s_drvremove), + .remove = au1xpsc_i2s_drvremove, }; module_platform_driver(au1xpsc_i2s_driver); diff --git a/sound/soc/blackfin/bf5xx-ac97-pcm.c b/sound/soc/blackfin/bf5xx-ac97-pcm.c index d7dc9bde0976..7e2f36004a5a 100644 --- a/sound/soc/blackfin/bf5xx-ac97-pcm.c +++ b/sound/soc/blackfin/bf5xx-ac97-pcm.c @@ -453,12 +453,12 @@ static struct snd_soc_platform_driver bf5xx_ac97_soc_platform = { .pcm_free = bf5xx_pcm_free_dma_buffers, }; -static int __devinit bf5xx_soc_platform_probe(struct platform_device *pdev) +static int bf5xx_soc_platform_probe(struct platform_device *pdev) { return snd_soc_register_platform(&pdev->dev, &bf5xx_ac97_soc_platform); } -static int __devexit bf5xx_soc_platform_remove(struct platform_device *pdev) +static int bf5xx_soc_platform_remove(struct platform_device *pdev) { snd_soc_unregister_platform(&pdev->dev); return 0; @@ -471,7 +471,7 @@ static struct platform_driver bf5xx_pcm_driver = { }, .probe = bf5xx_soc_platform_probe, - .remove = __devexit_p(bf5xx_soc_platform_remove), + .remove = bf5xx_soc_platform_remove, }; module_platform_driver(bf5xx_pcm_driver); diff --git a/sound/soc/blackfin/bf5xx-ac97.c b/sound/soc/blackfin/bf5xx-ac97.c index f4e9dc4e262e..8e41bcb020eb 100644 --- a/sound/soc/blackfin/bf5xx-ac97.c +++ b/sound/soc/blackfin/bf5xx-ac97.c @@ -282,7 +282,7 @@ static struct snd_soc_dai_driver bfin_ac97_dai = { .formats = SNDRV_PCM_FMTBIT_S16_LE, }, }; -static int __devinit asoc_bfin_ac97_probe(struct platform_device *pdev) +static int asoc_bfin_ac97_probe(struct platform_device *pdev) { struct sport_device *sport_handle; int ret; @@ -352,7 +352,7 @@ gpio_err: return ret; } -static int __devexit asoc_bfin_ac97_remove(struct platform_device *pdev) +static int asoc_bfin_ac97_remove(struct platform_device *pdev) { struct sport_device *sport_handle = platform_get_drvdata(pdev); @@ -372,7 +372,7 @@ static struct platform_driver asoc_bfin_ac97_driver = { }, .probe = asoc_bfin_ac97_probe, - .remove = __devexit_p(asoc_bfin_ac97_remove), + .remove = asoc_bfin_ac97_remove, }; module_platform_driver(asoc_bfin_ac97_driver); diff --git a/sound/soc/blackfin/bf5xx-ad1836.c b/sound/soc/blackfin/bf5xx-ad1836.c index 16b9c9efd19a..d23f4b0ea54f 100644 --- a/sound/soc/blackfin/bf5xx-ad1836.c +++ b/sound/soc/blackfin/bf5xx-ad1836.c @@ -75,7 +75,7 @@ static struct snd_soc_card bf5xx_ad1836 = { .num_links = 1, }; -static __devinit int bf5xx_ad1836_driver_probe(struct platform_device *pdev) +static int bf5xx_ad1836_driver_probe(struct platform_device *pdev) { struct snd_soc_card *card = &bf5xx_ad1836; const char **link_name; @@ -98,7 +98,7 @@ static __devinit int bf5xx_ad1836_driver_probe(struct platform_device *pdev) return ret; } -static int __devexit bf5xx_ad1836_driver_remove(struct platform_device *pdev) +static int bf5xx_ad1836_driver_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); @@ -113,7 +113,7 @@ static struct platform_driver bf5xx_ad1836_driver = { .pm = &snd_soc_pm_ops, }, .probe = bf5xx_ad1836_driver_probe, - .remove = __devexit_p(bf5xx_ad1836_driver_remove), + .remove = bf5xx_ad1836_driver_remove, }; module_platform_driver(bf5xx_ad1836_driver); diff --git a/sound/soc/blackfin/bf5xx-i2s-pcm.c b/sound/soc/blackfin/bf5xx-i2s-pcm.c index 63205d723eab..262c1de364d8 100644 --- a/sound/soc/blackfin/bf5xx-i2s-pcm.c +++ b/sound/soc/blackfin/bf5xx-i2s-pcm.c @@ -292,12 +292,12 @@ static struct snd_soc_platform_driver bf5xx_i2s_soc_platform = { .pcm_free = bf5xx_pcm_free_dma_buffers, }; -static int __devinit bfin_i2s_soc_platform_probe(struct platform_device *pdev) +static int bfin_i2s_soc_platform_probe(struct platform_device *pdev) { return snd_soc_register_platform(&pdev->dev, &bf5xx_i2s_soc_platform); } -static int __devexit bfin_i2s_soc_platform_remove(struct platform_device *pdev) +static int bfin_i2s_soc_platform_remove(struct platform_device *pdev) { snd_soc_unregister_platform(&pdev->dev); return 0; @@ -310,7 +310,7 @@ static struct platform_driver bfin_i2s_pcm_driver = { }, .probe = bfin_i2s_soc_platform_probe, - .remove = __devexit_p(bfin_i2s_soc_platform_remove), + .remove = bfin_i2s_soc_platform_remove, }; module_platform_driver(bfin_i2s_pcm_driver); diff --git a/sound/soc/blackfin/bf5xx-i2s.c b/sound/soc/blackfin/bf5xx-i2s.c index 4dccf0374fe7..168d88bccb41 100644 --- a/sound/soc/blackfin/bf5xx-i2s.c +++ b/sound/soc/blackfin/bf5xx-i2s.c @@ -245,7 +245,7 @@ static struct snd_soc_dai_driver bf5xx_i2s_dai = { .ops = &bf5xx_i2s_dai_ops, }; -static int __devinit bf5xx_i2s_probe(struct platform_device *pdev) +static int bf5xx_i2s_probe(struct platform_device *pdev) { struct sport_device *sport_handle; int ret; @@ -267,7 +267,7 @@ static int __devinit bf5xx_i2s_probe(struct platform_device *pdev) return 0; } -static int __devexit bf5xx_i2s_remove(struct platform_device *pdev) +static int bf5xx_i2s_remove(struct platform_device *pdev) { struct sport_device *sport_handle = platform_get_drvdata(pdev); @@ -281,7 +281,7 @@ static int __devexit bf5xx_i2s_remove(struct platform_device *pdev) static struct platform_driver bfin_i2s_driver = { .probe = bf5xx_i2s_probe, - .remove = __devexit_p(bf5xx_i2s_remove), + .remove = bf5xx_i2s_remove, .driver = { .name = "bfin-i2s", .owner = THIS_MODULE, diff --git a/sound/soc/blackfin/bf5xx-tdm-pcm.c b/sound/soc/blackfin/bf5xx-tdm-pcm.c index 254490cf1876..0e6b888bb4cc 100644 --- a/sound/soc/blackfin/bf5xx-tdm-pcm.c +++ b/sound/soc/blackfin/bf5xx-tdm-pcm.c @@ -317,12 +317,12 @@ static struct snd_soc_platform_driver bf5xx_tdm_soc_platform = { .pcm_free = bf5xx_pcm_free_dma_buffers, }; -static int __devinit bf5xx_soc_platform_probe(struct platform_device *pdev) +static int bf5xx_soc_platform_probe(struct platform_device *pdev) { return snd_soc_register_platform(&pdev->dev, &bf5xx_tdm_soc_platform); } -static int __devexit bf5xx_soc_platform_remove(struct platform_device *pdev) +static int bf5xx_soc_platform_remove(struct platform_device *pdev) { snd_soc_unregister_platform(&pdev->dev); return 0; @@ -335,7 +335,7 @@ static struct platform_driver bfin_tdm_driver = { }, .probe = bf5xx_soc_platform_probe, - .remove = __devexit_p(bf5xx_soc_platform_remove), + .remove = bf5xx_soc_platform_remove, }; module_platform_driver(bfin_tdm_driver); diff --git a/sound/soc/blackfin/bf5xx-tdm.c b/sound/soc/blackfin/bf5xx-tdm.c index 594f88217c74..c1e516ec53ad 100644 --- a/sound/soc/blackfin/bf5xx-tdm.c +++ b/sound/soc/blackfin/bf5xx-tdm.c @@ -249,7 +249,7 @@ static struct snd_soc_dai_driver bf5xx_tdm_dai = { .ops = &bf5xx_tdm_dai_ops, }; -static int __devinit bfin_tdm_probe(struct platform_device *pdev) +static int bfin_tdm_probe(struct platform_device *pdev) { struct sport_device *sport_handle; int ret; @@ -295,7 +295,7 @@ sport_config_err: return ret; } -static int __devexit bfin_tdm_remove(struct platform_device *pdev) +static int bfin_tdm_remove(struct platform_device *pdev) { struct sport_device *sport_handle = platform_get_drvdata(pdev); @@ -307,7 +307,7 @@ static int __devexit bfin_tdm_remove(struct platform_device *pdev) static struct platform_driver bfin_tdm_driver = { .probe = bfin_tdm_probe, - .remove = __devexit_p(bfin_tdm_remove), + .remove = bfin_tdm_remove, .driver = { .name = "bfin-tdm", .owner = THIS_MODULE, diff --git a/sound/soc/blackfin/bf6xx-i2s.c b/sound/soc/blackfin/bf6xx-i2s.c index c3c2466d3a42..8f337972f438 100644 --- a/sound/soc/blackfin/bf6xx-i2s.c +++ b/sound/soc/blackfin/bf6xx-i2s.c @@ -186,7 +186,7 @@ static struct snd_soc_dai_driver bfin_i2s_dai = { .ops = &bfin_i2s_dai_ops, }; -static int __devinit bfin_i2s_probe(struct platform_device *pdev) +static int bfin_i2s_probe(struct platform_device *pdev) { struct sport_device *sport; struct device *dev = &pdev->dev; @@ -208,7 +208,7 @@ static int __devinit bfin_i2s_probe(struct platform_device *pdev) return 0; } -static int __devexit bfin_i2s_remove(struct platform_device *pdev) +static int bfin_i2s_remove(struct platform_device *pdev) { struct sport_device *sport = platform_get_drvdata(pdev); @@ -220,7 +220,7 @@ static int __devexit bfin_i2s_remove(struct platform_device *pdev) static struct platform_driver bfin_i2s_driver = { .probe = bfin_i2s_probe, - .remove = __devexit_p(bfin_i2s_remove), + .remove = bfin_i2s_remove, .driver = { .name = "bfin-i2s", .owner = THIS_MODULE, diff --git a/sound/soc/blackfin/bfin-eval-adau1373.c b/sound/soc/blackfin/bfin-eval-adau1373.c index f3adbdbdd5e1..4ef9683bcad8 100644 --- a/sound/soc/blackfin/bfin-eval-adau1373.c +++ b/sound/soc/blackfin/bfin-eval-adau1373.c @@ -157,7 +157,7 @@ static int bfin_eval_adau1373_probe(struct platform_device *pdev) return snd_soc_register_card(&bfin_eval_adau1373); } -static int __devexit bfin_eval_adau1373_remove(struct platform_device *pdev) +static int bfin_eval_adau1373_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); @@ -173,7 +173,7 @@ static struct platform_driver bfin_eval_adau1373_driver = { .pm = &snd_soc_pm_ops, }, .probe = bfin_eval_adau1373_probe, - .remove = __devexit_p(bfin_eval_adau1373_remove), + .remove = bfin_eval_adau1373_remove, }; module_platform_driver(bfin_eval_adau1373_driver); diff --git a/sound/soc/blackfin/bfin-eval-adau1701.c b/sound/soc/blackfin/bfin-eval-adau1701.c index b0531fc9d814..3b55081a96c0 100644 --- a/sound/soc/blackfin/bfin-eval-adau1701.c +++ b/sound/soc/blackfin/bfin-eval-adau1701.c @@ -97,7 +97,7 @@ static int bfin_eval_adau1701_probe(struct platform_device *pdev) return snd_soc_register_card(&bfin_eval_adau1701); } -static int __devexit bfin_eval_adau1701_remove(struct platform_device *pdev) +static int bfin_eval_adau1701_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); @@ -113,7 +113,7 @@ static struct platform_driver bfin_eval_adau1701_driver = { .pm = &snd_soc_pm_ops, }, .probe = bfin_eval_adau1701_probe, - .remove = __devexit_p(bfin_eval_adau1701_remove), + .remove = bfin_eval_adau1701_remove, }; module_platform_driver(bfin_eval_adau1701_driver); diff --git a/sound/soc/blackfin/bfin-eval-adav80x.c b/sound/soc/blackfin/bfin-eval-adav80x.c index 84b09987b7f3..3b1b61a44815 100644 --- a/sound/soc/blackfin/bfin-eval-adav80x.c +++ b/sound/soc/blackfin/bfin-eval-adav80x.c @@ -122,7 +122,7 @@ static int bfin_eval_adav80x_probe(struct platform_device *pdev) return snd_soc_register_card(&bfin_eval_adav80x); } -static int __devexit bfin_eval_adav80x_remove(struct platform_device *pdev) +static int bfin_eval_adav80x_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); @@ -145,7 +145,7 @@ static struct platform_driver bfin_eval_adav80x_driver = { .pm = &snd_soc_pm_ops, }, .probe = bfin_eval_adav80x_probe, - .remove = __devexit_p(bfin_eval_adav80x_remove), + .remove = bfin_eval_adav80x_remove, .id_table = bfin_eval_adav80x_ids, }; diff --git a/sound/soc/cirrus/edb93xx.c b/sound/soc/cirrus/edb93xx.c index e01cb02abd3a..5db68cf7b281 100644 --- a/sound/soc/cirrus/edb93xx.c +++ b/sound/soc/cirrus/edb93xx.c @@ -80,7 +80,7 @@ static struct snd_soc_card snd_soc_edb93xx = { .num_links = 1, }; -static int __devinit edb93xx_probe(struct platform_device *pdev) +static int edb93xx_probe(struct platform_device *pdev) { struct snd_soc_card *card = &snd_soc_edb93xx; int ret; @@ -101,7 +101,7 @@ static int __devinit edb93xx_probe(struct platform_device *pdev) return ret; } -static int __devexit edb93xx_remove(struct platform_device *pdev) +static int edb93xx_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); @@ -117,7 +117,7 @@ static struct platform_driver edb93xx_driver = { .owner = THIS_MODULE, }, .probe = edb93xx_probe, - .remove = __devexit_p(edb93xx_remove), + .remove = edb93xx_remove, }; module_platform_driver(edb93xx_driver); diff --git a/sound/soc/cirrus/ep93xx-ac97.c b/sound/soc/cirrus/ep93xx-ac97.c index c3521653cfd3..f3f50e6fd6eb 100644 --- a/sound/soc/cirrus/ep93xx-ac97.c +++ b/sound/soc/cirrus/ep93xx-ac97.c @@ -352,7 +352,7 @@ static struct snd_soc_dai_driver ep93xx_ac97_dai = { .ops = &ep93xx_ac97_dai_ops, }; -static int __devinit ep93xx_ac97_probe(struct platform_device *pdev) +static int ep93xx_ac97_probe(struct platform_device *pdev) { struct ep93xx_ac97_info *info; struct resource *res; @@ -402,7 +402,7 @@ fail: return ret; } -static int __devexit ep93xx_ac97_remove(struct platform_device *pdev) +static int ep93xx_ac97_remove(struct platform_device *pdev) { struct ep93xx_ac97_info *info = platform_get_drvdata(pdev); @@ -420,7 +420,7 @@ static int __devexit ep93xx_ac97_remove(struct platform_device *pdev) static struct platform_driver ep93xx_ac97_driver = { .probe = ep93xx_ac97_probe, - .remove = __devexit_p(ep93xx_ac97_remove), + .remove = ep93xx_ac97_remove, .driver = { .name = "ep93xx-ac97", .owner = THIS_MODULE, diff --git a/sound/soc/cirrus/ep93xx-i2s.c b/sound/soc/cirrus/ep93xx-i2s.c index ac4a7515e7be..3365d4e843b7 100644 --- a/sound/soc/cirrus/ep93xx-i2s.c +++ b/sound/soc/cirrus/ep93xx-i2s.c @@ -422,7 +422,7 @@ fail: return err; } -static int __devexit ep93xx_i2s_remove(struct platform_device *pdev) +static int ep93xx_i2s_remove(struct platform_device *pdev) { struct ep93xx_i2s_info *info = dev_get_drvdata(&pdev->dev); @@ -436,7 +436,7 @@ static int __devexit ep93xx_i2s_remove(struct platform_device *pdev) static struct platform_driver ep93xx_i2s_driver = { .probe = ep93xx_i2s_probe, - .remove = __devexit_p(ep93xx_i2s_remove), + .remove = ep93xx_i2s_remove, .driver = { .name = "ep93xx-i2s", .owner = THIS_MODULE, diff --git a/sound/soc/cirrus/ep93xx-pcm.c b/sound/soc/cirrus/ep93xx-pcm.c index 665d9c94cc17..72eb7a49e16a 100644 --- a/sound/soc/cirrus/ep93xx-pcm.c +++ b/sound/soc/cirrus/ep93xx-pcm.c @@ -213,12 +213,12 @@ static struct snd_soc_platform_driver ep93xx_soc_platform = { .pcm_free = &ep93xx_pcm_free_dma_buffers, }; -static int __devinit ep93xx_soc_platform_probe(struct platform_device *pdev) +static int ep93xx_soc_platform_probe(struct platform_device *pdev) { return snd_soc_register_platform(&pdev->dev, &ep93xx_soc_platform); } -static int __devexit ep93xx_soc_platform_remove(struct platform_device *pdev) +static int ep93xx_soc_platform_remove(struct platform_device *pdev) { snd_soc_unregister_platform(&pdev->dev); return 0; @@ -231,7 +231,7 @@ static struct platform_driver ep93xx_pcm_driver = { }, .probe = ep93xx_soc_platform_probe, - .remove = __devexit_p(ep93xx_soc_platform_remove), + .remove = ep93xx_soc_platform_remove, }; module_platform_driver(ep93xx_pcm_driver); diff --git a/sound/soc/cirrus/simone.c b/sound/soc/cirrus/simone.c index dd997094eb30..a397bb0d8179 100644 --- a/sound/soc/cirrus/simone.c +++ b/sound/soc/cirrus/simone.c @@ -41,7 +41,7 @@ static struct snd_soc_card snd_soc_simone = { static struct platform_device *simone_snd_ac97_device; -static int __devinit simone_probe(struct platform_device *pdev) +static int simone_probe(struct platform_device *pdev) { struct snd_soc_card *card = &snd_soc_simone; int ret; @@ -63,7 +63,7 @@ static int __devinit simone_probe(struct platform_device *pdev) return ret; } -static int __devexit simone_remove(struct platform_device *pdev) +static int simone_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); @@ -79,7 +79,7 @@ static struct platform_driver simone_driver = { .owner = THIS_MODULE, }, .probe = simone_probe, - .remove = __devexit_p(simone_remove), + .remove = simone_remove, }; module_platform_driver(simone_driver); diff --git a/sound/soc/cirrus/snappercl15.c b/sound/soc/cirrus/snappercl15.c index a193cea3cf3c..9d77fe28dfcc 100644 --- a/sound/soc/cirrus/snappercl15.c +++ b/sound/soc/cirrus/snappercl15.c @@ -98,7 +98,7 @@ static struct snd_soc_card snd_soc_snappercl15 = { .num_links = 1, }; -static int __devinit snappercl15_probe(struct platform_device *pdev) +static int snappercl15_probe(struct platform_device *pdev) { struct snd_soc_card *card = &snd_soc_snappercl15; int ret; @@ -119,7 +119,7 @@ static int __devinit snappercl15_probe(struct platform_device *pdev) return ret; } -static int __devexit snappercl15_remove(struct platform_device *pdev) +static int snappercl15_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); @@ -135,7 +135,7 @@ static struct platform_driver snappercl15_driver = { .owner = THIS_MODULE, }, .probe = snappercl15_probe, - .remove = __devexit_p(snappercl15_remove), + .remove = snappercl15_remove, }; module_platform_driver(snappercl15_driver); diff --git a/sound/soc/codecs/88pm860x-codec.c b/sound/soc/codecs/88pm860x-codec.c index 9fd3b6827bba..60159c07448d 100644 --- a/sound/soc/codecs/88pm860x-codec.c +++ b/sound/soc/codecs/88pm860x-codec.c @@ -1423,7 +1423,7 @@ static struct snd_soc_codec_driver soc_codec_dev_pm860x = { .num_dapm_routes = ARRAY_SIZE(pm860x_dapm_routes), }; -static int __devinit pm860x_codec_probe(struct platform_device *pdev) +static int pm860x_codec_probe(struct platform_device *pdev) { struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent); struct pm860x_priv *pm860x; @@ -1463,7 +1463,7 @@ out: return -EINVAL; } -static int __devexit pm860x_codec_remove(struct platform_device *pdev) +static int pm860x_codec_remove(struct platform_device *pdev) { snd_soc_unregister_codec(&pdev->dev); platform_set_drvdata(pdev, NULL); @@ -1476,7 +1476,7 @@ static struct platform_driver pm860x_codec_driver = { .owner = THIS_MODULE, }, .probe = pm860x_codec_probe, - .remove = __devexit_p(pm860x_codec_remove), + .remove = pm860x_codec_remove, }; module_platform_driver(pm860x_codec_driver); diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index b92759a39361..3a847828932a 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -44,6 +44,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_LM4857 if I2C select SND_SOC_LM49453 if I2C select SND_SOC_MAX98088 if I2C + select SND_SOC_MAX98090 if I2C select SND_SOC_MAX98095 if I2C select SND_SOC_MAX9850 if I2C select SND_SOC_MAX9768 if I2C @@ -54,6 +55,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_PCM3008 select SND_SOC_RT5631 if I2C select SND_SOC_SGTL5000 if I2C + select SND_SOC_SI476X if MFD_SI476X_CORE select SND_SOC_SN95031 if INTEL_SCU_IPC select SND_SOC_SPDIF select SND_SOC_SSM2602 if SND_SOC_I2C_AND_SPI @@ -146,6 +148,13 @@ config SND_SOC_WM_HUBS default y if SND_SOC_WM8993=y || SND_SOC_WM8994=y default m if SND_SOC_WM8993=m || SND_SOC_WM8994=m +config SND_SOC_WM_ADSP + tristate + default y if SND_SOC_WM5102=y + default y if SND_SOC_WM2200=y + default m if SND_SOC_WM5102=m + default m if SND_SOC_WM2200=m + config SND_SOC_AB8500_CODEC tristate @@ -229,6 +238,7 @@ config SND_SOC_CX20442 tristate config SND_SOC_JZ4740_CODEC + select REGMAP_MMIO tristate config SND_SOC_L3 @@ -258,6 +268,9 @@ config SND_SOC_LM49453 config SND_SOC_MAX98088 tristate +config SND_SOC_MAX98090 + tristate + config SND_SOC_MAX98095 tristate @@ -277,6 +290,9 @@ config SND_SOC_RT5631 config SND_SOC_SGTL5000 tristate +config SND_SOC_SI476X + tristate + config SND_SOC_SIGMADSP tristate select CRC32 diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 9bd4d95aab4f..f6e8e36cceb7 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -34,6 +34,7 @@ snd-soc-lm4857-objs := lm4857.o snd-soc-lm49453-objs := lm49453.o snd-soc-max9768-objs := max9768.o snd-soc-max98088-objs := max98088.o +snd-soc-max98090-objs := max98090.o snd-soc-max98095-objs := max98095.o snd-soc-max9850-objs := max9850.o snd-soc-mc13783-objs := mc13783.o @@ -45,6 +46,7 @@ snd-soc-sgtl5000-objs := sgtl5000.o snd-soc-alc5623-objs := alc5623.o snd-soc-alc5632-objs := alc5632.o snd-soc-sigmadsp-objs := sigmadsp.o +snd-soc-si476x-objs := si476x.o snd-soc-sn95031-objs := sn95031.o snd-soc-spdif-tx-objs := spdif_transciever.o snd-soc-spdif-rx-objs := spdif_receiver.o @@ -62,6 +64,7 @@ snd-soc-twl6040-objs := twl6040.o snd-soc-uda134x-objs := uda134x.o snd-soc-uda1380-objs := uda1380.o snd-soc-wl1273-objs := wl1273.o +snd-soc-wm-adsp-objs := wm_adsp.o snd-soc-wm0010-objs := wm0010.o snd-soc-wm1250-ev1-objs := wm1250-ev1.o snd-soc-wm2000-objs := wm2000.o @@ -155,6 +158,7 @@ obj-$(CONFIG_SND_SOC_LM4857) += snd-soc-lm4857.o obj-$(CONFIG_SND_SOC_LM49453) += snd-soc-lm49453.o obj-$(CONFIG_SND_SOC_MAX9768) += snd-soc-max9768.o obj-$(CONFIG_SND_SOC_MAX98088) += snd-soc-max98088.o +obj-$(CONFIG_SND_SOC_MAX98090) += snd-soc-max98090.o obj-$(CONFIG_SND_SOC_MAX98095) += snd-soc-max98095.o obj-$(CONFIG_SND_SOC_MAX9850) += snd-soc-max9850.o obj-$(CONFIG_SND_SOC_MC13783) += snd-soc-mc13783.o @@ -164,6 +168,7 @@ obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o obj-$(CONFIG_SND_SOC_SIGMADSP) += snd-soc-sigmadsp.o +obj-$(CONFIG_SND_SOC_SI476X) += snd-soc-si476x.o obj-$(CONFIG_SND_SOC_SN95031) +=snd-soc-sn95031.o obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif-rx.o snd-soc-spdif-tx.o obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o @@ -229,6 +234,7 @@ obj-$(CONFIG_SND_SOC_WM9090) += snd-soc-wm9090.o obj-$(CONFIG_SND_SOC_WM9705) += snd-soc-wm9705.o obj-$(CONFIG_SND_SOC_WM9712) += snd-soc-wm9712.o obj-$(CONFIG_SND_SOC_WM9713) += snd-soc-wm9713.o +obj-$(CONFIG_SND_SOC_WM_ADSP) += snd-soc-wm-adsp.o obj-$(CONFIG_SND_SOC_WM_HUBS) += snd-soc-wm-hubs.o # Amp diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c index af547490b4f7..6c12ac206ee9 100644 --- a/sound/soc/codecs/ab8500-codec.c +++ b/sound/soc/codecs/ab8500-codec.c @@ -2356,7 +2356,7 @@ static int ab8500_codec_set_dai_tdm_slot(struct snd_soc_dai *dai, return 0; } -struct snd_soc_dai_driver ab8500_codec_dai[] = { +static struct snd_soc_dai_driver ab8500_codec_dai[] = { { .name = "ab8500-codec-dai.0", .id = 0, @@ -2554,7 +2554,7 @@ static struct snd_soc_codec_driver ab8500_codec_driver = { .num_dapm_routes = ARRAY_SIZE(ab8500_dapm_routes), }; -static int __devinit ab8500_codec_driver_probe(struct platform_device *pdev) +static int ab8500_codec_driver_probe(struct platform_device *pdev) { int status; struct ab8500_codec_drvdata *drvdata; @@ -2580,7 +2580,7 @@ static int __devinit ab8500_codec_driver_probe(struct platform_device *pdev) return status; } -static int __devexit ab8500_codec_driver_remove(struct platform_device *pdev) +static int ab8500_codec_driver_remove(struct platform_device *pdev) { dev_info(&pdev->dev, "%s Enter.\n", __func__); @@ -2595,7 +2595,7 @@ static struct platform_driver ab8500_codec_platform_driver = { .owner = THIS_MODULE, }, .probe = ab8500_codec_driver_probe, - .remove = __devexit_p(ab8500_codec_driver_remove), + .remove = ab8500_codec_driver_remove, .suspend = NULL, .resume = NULL, }; diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c index ea06b834a7de..ef2ae32ffc66 100644 --- a/sound/soc/codecs/ac97.c +++ b/sound/soc/codecs/ac97.c @@ -118,13 +118,13 @@ static struct snd_soc_codec_driver soc_codec_dev_ac97 = { .resume = ac97_soc_resume, }; -static __devinit int ac97_probe(struct platform_device *pdev) +static int ac97_probe(struct platform_device *pdev) { return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_ac97, &ac97_dai, 1); } -static int __devexit ac97_remove(struct platform_device *pdev) +static int ac97_remove(struct platform_device *pdev) { snd_soc_unregister_codec(&pdev->dev); return 0; @@ -137,7 +137,7 @@ static struct platform_driver ac97_codec_driver = { }, .probe = ac97_probe, - .remove = __devexit_p(ac97_remove), + .remove = ac97_remove, }; module_platform_driver(ac97_codec_driver); diff --git a/sound/soc/codecs/ad1836.c b/sound/soc/codecs/ad1836.c index dce6ebeef452..9a92b7962f41 100644 --- a/sound/soc/codecs/ad1836.c +++ b/sound/soc/codecs/ad1836.c @@ -360,7 +360,7 @@ static const struct regmap_config ad1836_regmap_config = { .cache_type = REGCACHE_RBTREE, }; -static int __devinit ad1836_spi_probe(struct spi_device *spi) +static int ad1836_spi_probe(struct spi_device *spi) { struct ad1836_priv *ad1836; int ret; @@ -383,7 +383,7 @@ static int __devinit ad1836_spi_probe(struct spi_device *spi) return ret; } -static int __devexit ad1836_spi_remove(struct spi_device *spi) +static int ad1836_spi_remove(struct spi_device *spi) { snd_soc_unregister_codec(&spi->dev); return 0; @@ -405,7 +405,7 @@ static struct spi_driver ad1836_spi_driver = { .owner = THIS_MODULE, }, .probe = ad1836_spi_probe, - .remove = __devexit_p(ad1836_spi_remove), + .remove = ad1836_spi_remove, .id_table = ad1836_ids, }; diff --git a/sound/soc/codecs/ad193x.c b/sound/soc/codecs/ad193x.c index 2f752660f678..aea7e52cf714 100644 --- a/sound/soc/codecs/ad193x.c +++ b/sound/soc/codecs/ad193x.c @@ -378,7 +378,7 @@ static const struct regmap_config ad193x_spi_regmap_config = { .volatile_reg = adau193x_reg_volatile, }; -static int __devinit ad193x_spi_probe(struct spi_device *spi) +static int ad193x_spi_probe(struct spi_device *spi) { struct ad193x_priv *ad193x; @@ -397,7 +397,7 @@ static int __devinit ad193x_spi_probe(struct spi_device *spi) &ad193x_dai, 1); } -static int __devexit ad193x_spi_remove(struct spi_device *spi) +static int ad193x_spi_remove(struct spi_device *spi) { snd_soc_unregister_codec(&spi->dev); return 0; @@ -409,7 +409,7 @@ static struct spi_driver ad193x_spi_driver = { .owner = THIS_MODULE, }, .probe = ad193x_spi_probe, - .remove = __devexit_p(ad193x_spi_remove), + .remove = ad193x_spi_remove, }; #endif @@ -430,8 +430,8 @@ static const struct i2c_device_id ad193x_id[] = { }; MODULE_DEVICE_TABLE(i2c, ad193x_id); -static int __devinit ad193x_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ad193x_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct ad193x_priv *ad193x; @@ -450,7 +450,7 @@ static int __devinit ad193x_i2c_probe(struct i2c_client *client, &ad193x_dai, 1); } -static int __devexit ad193x_i2c_remove(struct i2c_client *client) +static int ad193x_i2c_remove(struct i2c_client *client) { snd_soc_unregister_codec(&client->dev); return 0; @@ -461,7 +461,7 @@ static struct i2c_driver ad193x_i2c_driver = { .name = "ad193x", }, .probe = ad193x_i2c_probe, - .remove = __devexit_p(ad193x_i2c_remove), + .remove = ad193x_i2c_remove, .id_table = ad193x_id, }; #endif diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c index 8c39dddd7d00..f385342947d3 100644 --- a/sound/soc/codecs/ad1980.c +++ b/sound/soc/codecs/ad1980.c @@ -255,13 +255,13 @@ static struct snd_soc_codec_driver soc_codec_dev_ad1980 = { .read = ac97_read, }; -static __devinit int ad1980_probe(struct platform_device *pdev) +static int ad1980_probe(struct platform_device *pdev) { return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_ad1980, &ad1980_dai, 1); } -static int __devexit ad1980_remove(struct platform_device *pdev) +static int ad1980_remove(struct platform_device *pdev) { snd_soc_unregister_codec(&pdev->dev); return 0; @@ -274,7 +274,7 @@ static struct platform_driver ad1980_codec_driver = { }, .probe = ad1980_probe, - .remove = __devexit_p(ad1980_remove), + .remove = ad1980_remove, }; module_platform_driver(ad1980_codec_driver); diff --git a/sound/soc/codecs/ad73311.c b/sound/soc/codecs/ad73311.c index ee7a68dcefd2..b1f2baf42b48 100644 --- a/sound/soc/codecs/ad73311.c +++ b/sound/soc/codecs/ad73311.c @@ -47,7 +47,7 @@ static int ad73311_probe(struct platform_device *pdev) &soc_codec_dev_ad73311, &ad73311_dai, 1); } -static int __devexit ad73311_remove(struct platform_device *pdev) +static int ad73311_remove(struct platform_device *pdev) { snd_soc_unregister_codec(&pdev->dev); return 0; @@ -60,7 +60,7 @@ static struct platform_driver ad73311_codec_driver = { }, .probe = ad73311_probe, - .remove = __devexit_p(ad73311_remove), + .remove = ad73311_remove, }; module_platform_driver(ad73311_codec_driver); diff --git a/sound/soc/codecs/adau1373.c b/sound/soc/codecs/adau1373.c index 704544bfc90d..068b3ae56a17 100644 --- a/sound/soc/codecs/adau1373.c +++ b/sound/soc/codecs/adau1373.c @@ -1353,8 +1353,8 @@ static struct snd_soc_codec_driver adau1373_codec_driver = { .num_dapm_routes = ARRAY_SIZE(adau1373_dapm_routes), }; -static int __devinit adau1373_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int adau1373_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct adau1373 *adau1373; int ret; @@ -1370,7 +1370,7 @@ static int __devinit adau1373_i2c_probe(struct i2c_client *client, return ret; } -static int __devexit adau1373_i2c_remove(struct i2c_client *client) +static int adau1373_i2c_remove(struct i2c_client *client) { snd_soc_unregister_codec(&client->dev); return 0; @@ -1388,7 +1388,7 @@ static struct i2c_driver adau1373_i2c_driver = { .owner = THIS_MODULE, }, .probe = adau1373_i2c_probe, - .remove = __devexit_p(adau1373_i2c_remove), + .remove = adau1373_i2c_remove, .id_table = adau1373_i2c_id, }; diff --git a/sound/soc/codecs/adau1701.c b/sound/soc/codecs/adau1701.c index 51f2f3cd8136..dafdbe87edeb 100644 --- a/sound/soc/codecs/adau1701.c +++ b/sound/soc/codecs/adau1701.c @@ -489,8 +489,8 @@ static struct snd_soc_codec_driver adau1701_codec_drv = { .set_sysclk = adau1701_set_sysclk, }; -static __devinit int adau1701_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int adau1701_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct adau1701 *adau1701; int ret; @@ -505,7 +505,7 @@ static __devinit int adau1701_i2c_probe(struct i2c_client *client, return ret; } -static __devexit int adau1701_i2c_remove(struct i2c_client *client) +static int adau1701_i2c_remove(struct i2c_client *client) { snd_soc_unregister_codec(&client->dev); return 0; @@ -523,7 +523,7 @@ static struct i2c_driver adau1701_i2c_driver = { .owner = THIS_MODULE, }, .probe = adau1701_i2c_probe, - .remove = __devexit_p(adau1701_i2c_remove), + .remove = adau1701_i2c_remove, .id_table = adau1701_i2c_id, }; diff --git a/sound/soc/codecs/adav80x.c b/sound/soc/codecs/adav80x.c index ebd7b37b902b..3c839cc4e00e 100644 --- a/sound/soc/codecs/adav80x.c +++ b/sound/soc/codecs/adav80x.c @@ -839,8 +839,8 @@ static struct snd_soc_codec_driver adav80x_codec_driver = { .num_dapm_routes = ARRAY_SIZE(adav80x_dapm_routes), }; -static int __devinit adav80x_bus_probe(struct device *dev, - enum snd_soc_control_type control_type) +static int adav80x_bus_probe(struct device *dev, + enum snd_soc_control_type control_type) { struct adav80x *adav80x; int ret; @@ -860,7 +860,7 @@ static int __devinit adav80x_bus_probe(struct device *dev, return ret; } -static int __devexit adav80x_bus_remove(struct device *dev) +static int adav80x_bus_remove(struct device *dev) { snd_soc_unregister_codec(dev); kfree(dev_get_drvdata(dev)); @@ -868,12 +868,12 @@ static int __devexit adav80x_bus_remove(struct device *dev) } #if defined(CONFIG_SPI_MASTER) -static int __devinit adav80x_spi_probe(struct spi_device *spi) +static int adav80x_spi_probe(struct spi_device *spi) { return adav80x_bus_probe(&spi->dev, SND_SOC_SPI); } -static int __devexit adav80x_spi_remove(struct spi_device *spi) +static int adav80x_spi_remove(struct spi_device *spi) { return adav80x_bus_remove(&spi->dev); } @@ -884,7 +884,7 @@ static struct spi_driver adav80x_spi_driver = { .owner = THIS_MODULE, }, .probe = adav80x_spi_probe, - .remove = __devexit_p(adav80x_spi_remove), + .remove = adav80x_spi_remove, }; #endif @@ -895,13 +895,13 @@ static const struct i2c_device_id adav80x_id[] = { }; MODULE_DEVICE_TABLE(i2c, adav80x_id); -static int __devinit adav80x_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int adav80x_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) { return adav80x_bus_probe(&client->dev, SND_SOC_I2C); } -static int __devexit adav80x_i2c_remove(struct i2c_client *client) +static int adav80x_i2c_remove(struct i2c_client *client) { return adav80x_bus_remove(&client->dev); } @@ -912,7 +912,7 @@ static struct i2c_driver adav80x_i2c_driver = { .owner = THIS_MODULE, }, .probe = adav80x_i2c_probe, - .remove = __devexit_p(adav80x_i2c_remove), + .remove = adav80x_i2c_remove, .id_table = adav80x_id, }; #endif diff --git a/sound/soc/codecs/ads117x.c b/sound/soc/codecs/ads117x.c index 8103b938b8c0..506d474c4d22 100644 --- a/sound/soc/codecs/ads117x.c +++ b/sound/soc/codecs/ads117x.c @@ -36,13 +36,13 @@ static struct snd_soc_dai_driver ads117x_dai = { static struct snd_soc_codec_driver soc_codec_dev_ads117x; -static __devinit int ads117x_probe(struct platform_device *pdev) +static int ads117x_probe(struct platform_device *pdev) { return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_ads117x, &ads117x_dai, 1); } -static int __devexit ads117x_remove(struct platform_device *pdev) +static int ads117x_remove(struct platform_device *pdev) { snd_soc_unregister_codec(&pdev->dev); return 0; @@ -55,7 +55,7 @@ static struct platform_driver ads117x_codec_driver = { }, .probe = ads117x_probe, - .remove = __devexit_p(ads117x_remove), + .remove = ads117x_remove, }; module_platform_driver(ads117x_codec_driver); diff --git a/sound/soc/codecs/ak4104.c b/sound/soc/codecs/ak4104.c index 31d4483245d0..6f6c335a5baa 100644 --- a/sound/soc/codecs/ak4104.c +++ b/sound/soc/codecs/ak4104.c @@ -15,6 +15,8 @@ #include <sound/soc.h> #include <sound/initval.h> #include <linux/spi/spi.h> +#include <linux/of_device.h> +#include <linux/of_gpio.h> #include <sound/asoundef.h> /* AK4104 registers addresses */ @@ -98,14 +100,32 @@ static int ak4104_hw_params(struct snd_pcm_substream *substream, val = 0; switch (params_rate(params)) { + case 22050: + val |= IEC958_AES3_CON_FS_22050; + break; + case 24000: + val |= IEC958_AES3_CON_FS_24000; + break; + case 32000: + val |= IEC958_AES3_CON_FS_32000; + break; case 44100: val |= IEC958_AES3_CON_FS_44100; break; case 48000: val |= IEC958_AES3_CON_FS_48000; break; - case 32000: - val |= IEC958_AES3_CON_FS_32000; + case 88200: + val |= IEC958_AES3_CON_FS_88200; + break; + case 96000: + val |= IEC958_AES3_CON_FS_96000; + break; + case 176400: + val |= IEC958_AES3_CON_FS_176400; + break; + case 192000: + val |= IEC958_AES3_CON_FS_192000; break; default: dev_err(codec->dev, "unsupported sampling rate\n"); @@ -186,6 +206,7 @@ static const struct regmap_config ak4104_regmap = { static int ak4104_spi_probe(struct spi_device *spi) { + struct device_node *np = spi->dev.of_node; struct ak4104_private *ak4104; unsigned int val; int ret; @@ -201,52 +222,62 @@ static int ak4104_spi_probe(struct spi_device *spi) if (ak4104 == NULL) return -ENOMEM; - ak4104->regmap = regmap_init_spi(spi, &ak4104_regmap); + ak4104->regmap = devm_regmap_init_spi(spi, &ak4104_regmap); if (IS_ERR(ak4104->regmap)) { ret = PTR_ERR(ak4104->regmap); return ret; } + if (np) { + enum of_gpio_flags flags; + int gpio = of_get_named_gpio_flags(np, "reset-gpio", 0, &flags); + + if (gpio_is_valid(gpio)) { + ret = devm_gpio_request_one(&spi->dev, gpio, + flags & OF_GPIO_ACTIVE_LOW ? + GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH, + "ak4104 reset"); + if (ret < 0) + return ret; + } + } + /* read the 'reserved' register - according to the datasheet, it * should contain 0x5b. Not a good way to verify the presence of * the device, but there is no hardware ID register. */ ret = regmap_read(ak4104->regmap, AK4104_REG_RESERVED, &val); if (ret != 0) - goto err; - if (val != AK4104_RESERVED_VAL) { - ret = -ENODEV; - goto err; - } + return ret; + if (val != AK4104_RESERVED_VAL) + return -ENODEV; spi_set_drvdata(spi, ak4104); ret = snd_soc_register_codec(&spi->dev, &soc_codec_device_ak4104, &ak4104_dai, 1); - if (ret != 0) - goto err; - - return 0; - -err: - regmap_exit(ak4104->regmap); return ret; } -static int __devexit ak4104_spi_remove(struct spi_device *spi) +static int ak4104_spi_remove(struct spi_device *spi) { - struct ak4104_private *ak4101 = spi_get_drvdata(spi); - regmap_exit(ak4101->regmap); snd_soc_unregister_codec(&spi->dev); return 0; } +static const struct of_device_id ak4104_of_match[] = { + { .compatible = "asahi-kasei,ak4104", }, + { } +}; +MODULE_DEVICE_TABLE(of, ak4104_of_match); + static struct spi_driver ak4104_spi_driver = { .driver = { .name = DRV_NAME, .owner = THIS_MODULE, + .of_match_table = ak4104_of_match, }, .probe = ak4104_spi_probe, - .remove = __devexit_p(ak4104_spi_remove), + .remove = ak4104_spi_remove, }; module_spi_driver(ak4104_spi_driver); diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c index 618fdc30f73e..684fe910669f 100644 --- a/sound/soc/codecs/ak4535.c +++ b/sound/soc/codecs/ak4535.c @@ -436,8 +436,8 @@ static struct snd_soc_codec_driver soc_codec_dev_ak4535 = { .num_dapm_routes = ARRAY_SIZE(ak4535_audio_map), }; -static __devinit int ak4535_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int ak4535_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) { struct ak4535_priv *ak4535; int ret; @@ -447,7 +447,7 @@ static __devinit int ak4535_i2c_probe(struct i2c_client *i2c, if (ak4535 == NULL) return -ENOMEM; - ak4535->regmap = regmap_init_i2c(i2c, &ak4535_regmap); + ak4535->regmap = devm_regmap_init_i2c(i2c, &ak4535_regmap); if (IS_ERR(ak4535->regmap)) { ret = PTR_ERR(ak4535->regmap); dev_err(&i2c->dev, "Failed to init regmap: %d\n", ret); @@ -458,18 +458,13 @@ static __devinit int ak4535_i2c_probe(struct i2c_client *i2c, ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_ak4535, &ak4535_dai, 1); - if (ret != 0) - regmap_exit(ak4535->regmap); return ret; } -static __devexit int ak4535_i2c_remove(struct i2c_client *client) +static int ak4535_i2c_remove(struct i2c_client *client) { - struct ak4535_priv *ak4535 = i2c_get_clientdata(client); - snd_soc_unregister_codec(&client->dev); - regmap_exit(ak4535->regmap); return 0; } @@ -485,7 +480,7 @@ static struct i2c_driver ak4535_i2c_driver = { .owner = THIS_MODULE, }, .probe = ak4535_i2c_probe, - .remove = __devexit_p(ak4535_i2c_remove), + .remove = ak4535_i2c_remove, .id_table = ak4535_i2c_id, }; diff --git a/sound/soc/codecs/ak4641.c b/sound/soc/codecs/ak4641.c index 543a12f471be..5f9af1fb76e8 100644 --- a/sound/soc/codecs/ak4641.c +++ b/sound/soc/codecs/ak4641.c @@ -557,8 +557,8 @@ static struct snd_soc_codec_driver soc_codec_dev_ak4641 = { }; -static int __devinit ak4641_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int ak4641_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) { struct ak4641_platform_data *pdata = i2c->dev.platform_data; struct ak4641_priv *ak4641; @@ -610,7 +610,7 @@ err_out: return ret; } -static int __devexit ak4641_i2c_remove(struct i2c_client *i2c) +static int ak4641_i2c_remove(struct i2c_client *i2c) { struct ak4641_platform_data *pdata = i2c->dev.platform_data; @@ -640,7 +640,7 @@ static struct i2c_driver ak4641_i2c_driver = { .owner = THIS_MODULE, }, .probe = ak4641_i2c_probe, - .remove = __devexit_p(ak4641_i2c_remove), + .remove = ak4641_i2c_remove, .id_table = ak4641_i2c_id, }; diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c index b3e24f289421..1f0cdab03294 100644 --- a/sound/soc/codecs/ak4642.c +++ b/sound/soc/codecs/ak4642.c @@ -194,12 +194,6 @@ static const struct snd_soc_dapm_route ak4642_intercon[] = { {"LINEOUT Mixer", "DACL", "DAC"}, }; -/* codec private data */ -struct ak4642_priv { - unsigned int sysclk; - enum snd_soc_control_type control_type; -}; - /* * ak4642 register cache */ @@ -468,10 +462,9 @@ static int ak4642_resume(struct snd_soc_codec *codec) static int ak4642_probe(struct snd_soc_codec *codec) { - struct ak4642_priv *ak4642 = snd_soc_codec_get_drvdata(codec); int ret; - ret = snd_soc_codec_set_cache_io(codec, 8, 8, ak4642->control_type); + ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C); if (ret < 0) { dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); return ret; @@ -520,27 +513,15 @@ static struct snd_soc_codec_driver soc_codec_dev_ak4648 = { }; #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) -static __devinit int ak4642_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int ak4642_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) { - struct ak4642_priv *ak4642; - int ret; - - ak4642 = devm_kzalloc(&i2c->dev, sizeof(struct ak4642_priv), - GFP_KERNEL); - if (!ak4642) - return -ENOMEM; - - i2c_set_clientdata(i2c, ak4642); - ak4642->control_type = SND_SOC_I2C; - - ret = snd_soc_register_codec(&i2c->dev, + return snd_soc_register_codec(&i2c->dev, (struct snd_soc_codec_driver *)id->driver_data, &ak4642_dai, 1); - return ret; } -static __devexit int ak4642_i2c_remove(struct i2c_client *client) +static int ak4642_i2c_remove(struct i2c_client *client) { snd_soc_unregister_codec(&client->dev); return 0; @@ -560,7 +541,7 @@ static struct i2c_driver ak4642_i2c_driver = { .owner = THIS_MODULE, }, .probe = ak4642_i2c_probe, - .remove = __devexit_p(ak4642_i2c_remove), + .remove = ak4642_i2c_remove, .id_table = ak4642_i2c_id, }; #endif diff --git a/sound/soc/codecs/ak4671.c b/sound/soc/codecs/ak4671.c index 2b457976a7bf..25bdf6ad4a54 100644 --- a/sound/soc/codecs/ak4671.c +++ b/sound/soc/codecs/ak4671.c @@ -655,8 +655,8 @@ static struct snd_soc_codec_driver soc_codec_dev_ak4671 = { .num_dapm_routes = ARRAY_SIZE(ak4671_intercon), }; -static int __devinit ak4671_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ak4671_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct ak4671_priv *ak4671; int ret; @@ -674,7 +674,7 @@ static int __devinit ak4671_i2c_probe(struct i2c_client *client, return ret; } -static __devexit int ak4671_i2c_remove(struct i2c_client *client) +static int ak4671_i2c_remove(struct i2c_client *client) { snd_soc_unregister_codec(&client->dev); return 0; @@ -692,7 +692,7 @@ static struct i2c_driver ak4671_i2c_driver = { .owner = THIS_MODULE, }, .probe = ak4671_i2c_probe, - .remove = __devexit_p(ak4671_i2c_remove), + .remove = ak4671_i2c_remove, .id_table = ak4671_i2c_id, }; diff --git a/sound/soc/codecs/alc5623.c b/sound/soc/codecs/alc5623.c index 1960478ce6bb..256c364193a5 100644 --- a/sound/soc/codecs/alc5623.c +++ b/sound/soc/codecs/alc5623.c @@ -991,8 +991,8 @@ static struct snd_soc_codec_driver soc_codec_device_alc5623 = { * low = 0x1a * high = 0x1b */ -static __devinit int alc5623_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int alc5623_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct alc5623_platform_data *pdata; struct alc5623_priv *alc5623; @@ -1058,7 +1058,7 @@ static __devinit int alc5623_i2c_probe(struct i2c_client *client, return ret; } -static __devexit int alc5623_i2c_remove(struct i2c_client *client) +static int alc5623_i2c_remove(struct i2c_client *client) { snd_soc_unregister_codec(&client->dev); return 0; @@ -1079,7 +1079,7 @@ static struct i2c_driver alc5623_i2c_driver = { .owner = THIS_MODULE, }, .probe = alc5623_i2c_probe, - .remove = __devexit_p(alc5623_i2c_remove), + .remove = alc5623_i2c_remove, .id_table = alc5623_i2c_table, }; diff --git a/sound/soc/codecs/alc5632.c b/sound/soc/codecs/alc5632.c index 7dd02420b36d..f2e62e45f912 100644 --- a/sound/soc/codecs/alc5632.c +++ b/sound/soc/codecs/alc5632.c @@ -1116,8 +1116,8 @@ static struct regmap_config alc5632_regmap = { * low = 0x1a * high = 0x1b */ -static __devinit int alc5632_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int alc5632_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct alc5632_priv *alc5632; int ret, ret1, ret2; @@ -1179,7 +1179,7 @@ static __devinit int alc5632_i2c_probe(struct i2c_client *client, return ret; } -static __devexit int alc5632_i2c_remove(struct i2c_client *client) +static int alc5632_i2c_remove(struct i2c_client *client) { snd_soc_unregister_codec(&client->dev); return 0; @@ -1198,7 +1198,7 @@ static struct i2c_driver alc5632_i2c_driver = { .owner = THIS_MODULE, }, .probe = alc5632_i2c_probe, - .remove = __devexit_p(alc5632_i2c_remove), + .remove = alc5632_i2c_remove, .id_table = alc5632_i2c_table, }; diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index c03b65af3059..ef62c435848e 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -226,6 +226,31 @@ EXPORT_SYMBOL_GPL(arizona_mixer_values); const DECLARE_TLV_DB_SCALE(arizona_mixer_tlv, -3200, 100, 0); EXPORT_SYMBOL_GPL(arizona_mixer_tlv); +static const char *arizona_vol_ramp_text[] = { + "0ms/6dB", "0.5ms/6dB", "1ms/6dB", "2ms/6dB", "4ms/6dB", "8ms/6dB", + "15ms/6dB", "30ms/6dB", +}; + +const struct soc_enum arizona_in_vd_ramp = + SOC_ENUM_SINGLE(ARIZONA_INPUT_VOLUME_RAMP, + ARIZONA_IN_VD_RAMP_SHIFT, 7, arizona_vol_ramp_text); +EXPORT_SYMBOL_GPL(arizona_in_vd_ramp); + +const struct soc_enum arizona_in_vi_ramp = + SOC_ENUM_SINGLE(ARIZONA_INPUT_VOLUME_RAMP, + ARIZONA_IN_VI_RAMP_SHIFT, 7, arizona_vol_ramp_text); +EXPORT_SYMBOL_GPL(arizona_in_vi_ramp); + +const struct soc_enum arizona_out_vd_ramp = + SOC_ENUM_SINGLE(ARIZONA_OUTPUT_VOLUME_RAMP, + ARIZONA_OUT_VD_RAMP_SHIFT, 7, arizona_vol_ramp_text); +EXPORT_SYMBOL_GPL(arizona_out_vd_ramp); + +const struct soc_enum arizona_out_vi_ramp = + SOC_ENUM_SINGLE(ARIZONA_OUTPUT_VOLUME_RAMP, + ARIZONA_OUT_VI_RAMP_SHIFT, 7, arizona_vol_ramp_text); +EXPORT_SYMBOL_GPL(arizona_out_vi_ramp); + static const char *arizona_lhpf_mode_text[] = { "Low-pass", "High-pass" }; @@ -268,7 +293,7 @@ EXPORT_SYMBOL_GPL(arizona_out_ev); static unsigned int arizona_sysclk_48k_rates[] = { 6144000, 12288000, - 22579200, + 24576000, 49152000, 73728000, 98304000, @@ -278,7 +303,7 @@ static unsigned int arizona_sysclk_48k_rates[] = { static unsigned int arizona_sysclk_44k1_rates[] = { 5644800, 11289600, - 24576000, + 22579200, 45158400, 67737600, 90316800, @@ -380,6 +405,18 @@ int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id, case 49152000: val |= 3 << ARIZONA_SYSCLK_FREQ_SHIFT; break; + case 67737600: + case 73728000: + val |= 4 << ARIZONA_SYSCLK_FREQ_SHIFT; + break; + case 90316800: + case 98304000: + val |= 5 << ARIZONA_SYSCLK_FREQ_SHIFT; + break; + case 135475200: + case 147456000: + val |= 6 << ARIZONA_SYSCLK_FREQ_SHIFT; + break; default: return -EINVAL; } @@ -409,15 +446,9 @@ static int arizona_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) case SND_SOC_DAIFMT_DSP_A: mode = 0; break; - case SND_SOC_DAIFMT_DSP_B: - mode = 1; - break; case SND_SOC_DAIFMT_I2S: mode = 2; break; - case SND_SOC_DAIFMT_LEFT_J: - mode = 3; - break; default: arizona_aif_err(dai, "Unsupported DAI format %d\n", fmt & SND_SOC_DAIFMT_FORMAT_MASK); @@ -654,7 +685,7 @@ static int arizona_hw_params(struct snd_pcm_substream *substream, } sr_val = i; - lrclk = snd_soc_params_to_bclk(params) / params_rate(params); + lrclk = rates[bclk] / params_rate(params); arizona_aif_dbg(dai, "BCLK %dHz LRCLK %dHz\n", rates[bclk], rates[bclk] / lrclk); @@ -677,7 +708,8 @@ static int arizona_hw_params(struct snd_pcm_substream *substream, snd_soc_update_bits(codec, ARIZONA_ASYNC_SAMPLE_RATE_1, ARIZONA_ASYNC_SAMPLE_RATE_MASK, sr_val); snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL, - ARIZONA_AIF1_RATE_MASK, 8); + ARIZONA_AIF1_RATE_MASK, + 8 << ARIZONA_AIF1_RATE_SHIFT); break; default: arizona_aif_err(dai, "Invalid clock %d\n", dai_priv->clk); @@ -737,6 +769,9 @@ static int arizona_dai_set_sysclk(struct snd_soc_dai *dai, return -EBUSY; } + dev_dbg(codec->dev, "Setting AIF%d to %s\n", dai->id + 1, + arizona_dai_clk_str(clk_id)); + memset(&routes, 0, sizeof(routes)); routes[0].sink = dai->driver->capture.stream_name; routes[1].sink = dai->driver->playback.stream_name; @@ -749,6 +784,8 @@ static int arizona_dai_set_sysclk(struct snd_soc_dai *dai, routes[1].source = arizona_dai_clk_str(clk_id); snd_soc_dapm_add_routes(&codec->dapm, routes, ARRAY_SIZE(routes)); + dai_priv->clk = clk_id; + return snd_soc_dapm_sync(&codec->dapm); } @@ -925,6 +962,9 @@ int arizona_set_fll(struct arizona_fll *fll, int source, bool ena; int ret; + if (fll->fref == Fref && fll->fout == Fout) + return 0; + ret = regmap_read(arizona->regmap, fll->base + 1, ®); if (ret != 0) { arizona_fll_err(fll, "Failed to read current state: %d\n", @@ -970,6 +1010,9 @@ int arizona_set_fll(struct arizona_fll *fll, int source, if (ena) pm_runtime_put_autosuspend(arizona->dev); + fll->fref = Fref; + fll->fout = Fout; + return 0; } @@ -998,10 +1041,13 @@ int arizona_set_fll(struct arizona_fll *fll, int source, ARIZONA_FLL1_SYNC_ENA); ret = wait_for_completion_timeout(&fll->ok, - msecs_to_jiffies(25)); + msecs_to_jiffies(250)); if (ret == 0) arizona_fll_warn(fll, "Timed out waiting for lock\n"); + fll->fref = Fref; + fll->fout = Fout; + return 0; } EXPORT_SYMBOL_GPL(arizona_set_fll); @@ -1036,6 +1082,9 @@ int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq, id, ret); } + regmap_update_bits(arizona->regmap, fll->base + 1, + ARIZONA_FLL1_FREERUN, 0); + return 0; } EXPORT_SYMBOL_GPL(arizona_init_fll); diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h index 36ec64946120..4deebeb07177 100644 --- a/sound/soc/codecs/arizona.h +++ b/sound/soc/codecs/arizona.h @@ -17,6 +17,8 @@ #include <sound/soc.h> +#include "wm_adsp.h" + #define ARIZONA_CLK_SYSCLK 1 #define ARIZONA_CLK_ASYNCCLK 2 #define ARIZONA_CLK_OPCLK 3 @@ -32,29 +34,32 @@ #define ARIZONA_FLL_SRC_MCLK1 0 #define ARIZONA_FLL_SRC_MCLK2 1 -#define ARIZONA_FLL_SRC_SLIMCLK 2 -#define ARIZONA_FLL_SRC_FLL1 3 -#define ARIZONA_FLL_SRC_FLL2 4 -#define ARIZONA_FLL_SRC_AIF1BCLK 5 -#define ARIZONA_FLL_SRC_AIF2BCLK 6 -#define ARIZONA_FLL_SRC_AIF3BCLK 7 -#define ARIZONA_FLL_SRC_AIF1LRCLK 8 -#define ARIZONA_FLL_SRC_AIF2LRCLK 9 -#define ARIZONA_FLL_SRC_AIF3LRCLK 10 +#define ARIZONA_FLL_SRC_SLIMCLK 3 +#define ARIZONA_FLL_SRC_FLL1 4 +#define ARIZONA_FLL_SRC_FLL2 5 +#define ARIZONA_FLL_SRC_AIF1BCLK 8 +#define ARIZONA_FLL_SRC_AIF2BCLK 9 +#define ARIZONA_FLL_SRC_AIF3BCLK 10 +#define ARIZONA_FLL_SRC_AIF1LRCLK 12 +#define ARIZONA_FLL_SRC_AIF2LRCLK 13 +#define ARIZONA_FLL_SRC_AIF3LRCLK 14 #define ARIZONA_MIXER_VOL_MASK 0x00FE #define ARIZONA_MIXER_VOL_SHIFT 1 #define ARIZONA_MIXER_VOL_WIDTH 7 -#define ARIZONA_MAX_DAI 3 +#define ARIZONA_MAX_DAI 4 +#define ARIZONA_MAX_ADSP 4 struct arizona; +struct wm_adsp; struct arizona_dai_priv { int clk; }; struct arizona_priv { + struct wm_adsp adsp[ARIZONA_MAX_ADSP]; struct arizona *arizona; int sysclk; int asyncclk; @@ -89,19 +94,30 @@ extern int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS]; const struct snd_kcontrol_new name##_mux = \ SOC_DAPM_VALUE_ENUM("Route", name##_enum) +#define ARIZONA_MUX_ENUMS(name, base_reg) \ + static ARIZONA_MUX_ENUM_DECL(name##_enum, base_reg); \ + static ARIZONA_MUX_CTL_DECL(name) + #define ARIZONA_MIXER_ENUMS(name, base_reg) \ - static ARIZONA_MUX_ENUM_DECL(name##_in1_enum, base_reg); \ - static ARIZONA_MUX_ENUM_DECL(name##_in2_enum, base_reg + 2); \ - static ARIZONA_MUX_ENUM_DECL(name##_in3_enum, base_reg + 4); \ - static ARIZONA_MUX_ENUM_DECL(name##_in4_enum, base_reg + 6); \ - static ARIZONA_MUX_CTL_DECL(name##_in1); \ - static ARIZONA_MUX_CTL_DECL(name##_in2); \ - static ARIZONA_MUX_CTL_DECL(name##_in3); \ - static ARIZONA_MUX_CTL_DECL(name##_in4) + ARIZONA_MUX_ENUMS(name##_in1, base_reg); \ + ARIZONA_MUX_ENUMS(name##_in2, base_reg + 2); \ + ARIZONA_MUX_ENUMS(name##_in3, base_reg + 4); \ + ARIZONA_MUX_ENUMS(name##_in4, base_reg + 6) + +#define ARIZONA_DSP_AUX_ENUMS(name, base_reg) \ + ARIZONA_MUX_ENUMS(name##_aux1, base_reg); \ + ARIZONA_MUX_ENUMS(name##_aux2, base_reg + 8); \ + ARIZONA_MUX_ENUMS(name##_aux3, base_reg + 16); \ + ARIZONA_MUX_ENUMS(name##_aux4, base_reg + 24); \ + ARIZONA_MUX_ENUMS(name##_aux5, base_reg + 32); \ + ARIZONA_MUX_ENUMS(name##_aux6, base_reg + 40) #define ARIZONA_MUX(name, ctrl) \ SND_SOC_DAPM_VALUE_MUX(name, SND_SOC_NOPM, 0, 0, ctrl) +#define ARIZONA_MUX_WIDGETS(name, name_str) \ + ARIZONA_MUX(name_str " Input", &name##_mux) + #define ARIZONA_MIXER_WIDGETS(name, name_str) \ ARIZONA_MUX(name_str " Input 1", &name##_in1_mux), \ ARIZONA_MUX(name_str " Input 2", &name##_in2_mux), \ @@ -109,6 +125,19 @@ extern int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS]; ARIZONA_MUX(name_str " Input 4", &name##_in4_mux), \ SND_SOC_DAPM_MIXER(name_str " Mixer", SND_SOC_NOPM, 0, 0, NULL, 0) +#define ARIZONA_DSP_WIDGETS(name, name_str) \ + ARIZONA_MIXER_WIDGETS(name##L, name_str "L"), \ + ARIZONA_MIXER_WIDGETS(name##R, name_str "R"), \ + ARIZONA_MUX(name_str " Aux 1", &name##_aux1_mux), \ + ARIZONA_MUX(name_str " Aux 2", &name##_aux2_mux), \ + ARIZONA_MUX(name_str " Aux 3", &name##_aux3_mux), \ + ARIZONA_MUX(name_str " Aux 4", &name##_aux4_mux), \ + ARIZONA_MUX(name_str " Aux 5", &name##_aux5_mux), \ + ARIZONA_MUX(name_str " Aux 6", &name##_aux6_mux) + +#define ARIZONA_MUX_ROUTES(name) \ + ARIZONA_MIXER_INPUT_ROUTES(name " Input") + #define ARIZONA_MIXER_ROUTES(widget, name) \ { widget, NULL, name " Mixer" }, \ { name " Mixer", NULL, name " Input 1" }, \ @@ -120,6 +149,28 @@ extern int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS]; ARIZONA_MIXER_INPUT_ROUTES(name " Input 3"), \ ARIZONA_MIXER_INPUT_ROUTES(name " Input 4") +#define ARIZONA_DSP_ROUTES(name) \ + { name, NULL, name " Aux 1" }, \ + { name, NULL, name " Aux 2" }, \ + { name, NULL, name " Aux 3" }, \ + { name, NULL, name " Aux 4" }, \ + { name, NULL, name " Aux 5" }, \ + { name, NULL, name " Aux 6" }, \ + ARIZONA_MIXER_INPUT_ROUTES(name " Aux 1"), \ + ARIZONA_MIXER_INPUT_ROUTES(name " Aux 2"), \ + ARIZONA_MIXER_INPUT_ROUTES(name " Aux 3"), \ + ARIZONA_MIXER_INPUT_ROUTES(name " Aux 4"), \ + ARIZONA_MIXER_INPUT_ROUTES(name " Aux 5"), \ + ARIZONA_MIXER_INPUT_ROUTES(name " Aux 6"), \ + ARIZONA_MIXER_ROUTES(name, name "L"), \ + ARIZONA_MIXER_ROUTES(name, name "R") + +extern const struct soc_enum arizona_in_vi_ramp; +extern const struct soc_enum arizona_in_vd_ramp; + +extern const struct soc_enum arizona_out_vi_ramp; +extern const struct soc_enum arizona_out_vd_ramp; + extern const struct soc_enum arizona_lhpf1_mode; extern const struct soc_enum arizona_lhpf2_mode; extern const struct soc_enum arizona_lhpf3_mode; @@ -146,6 +197,8 @@ struct arizona_fll { unsigned int vco_mult; struct completion lock; struct completion ok; + unsigned int fref; + unsigned int fout; char lock_name[ARIZONA_FLL_NAME_LEN]; char clock_ok_name[ARIZONA_FLL_NAME_LEN]; diff --git a/sound/soc/codecs/cq93vc.c b/sound/soc/codecs/cq93vc.c index 064cd6a93516..23316c887b19 100644 --- a/sound/soc/codecs/cq93vc.c +++ b/sound/soc/codecs/cq93vc.c @@ -201,7 +201,7 @@ static struct platform_driver cq93vc_codec_driver = { }, .probe = cq93vc_platform_probe, - .remove = __devexit_p(cq93vc_platform_remove), + .remove = cq93vc_platform_remove, }; module_platform_driver(cq93vc_codec_driver); diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c index f994af34f552..ac8742a1f25a 100644 --- a/sound/soc/codecs/cs4271.c +++ b/sound/soc/codecs/cs4271.c @@ -474,18 +474,28 @@ static int cs4271_probe(struct snd_soc_codec *codec) struct cs4271_platform_data *cs4271plat = codec->dev->platform_data; int ret; int gpio_nreset = -EINVAL; + bool amutec_eq_bmutec = false; #ifdef CONFIG_OF - if (of_match_device(cs4271_dt_ids, codec->dev)) + if (of_match_device(cs4271_dt_ids, codec->dev)) { gpio_nreset = of_get_named_gpio(codec->dev->of_node, "reset-gpio", 0); + + if (of_get_property(codec->dev->of_node, + "cirrus,amutec-eq-bmutec", NULL)) + amutec_eq_bmutec = true; + } #endif - if (cs4271plat && gpio_is_valid(cs4271plat->gpio_nreset)) - gpio_nreset = cs4271plat->gpio_nreset; + if (cs4271plat) { + if (gpio_is_valid(cs4271plat->gpio_nreset)) + gpio_nreset = cs4271plat->gpio_nreset; + + amutec_eq_bmutec = cs4271plat->amutec_eq_bmutec; + } if (gpio_nreset >= 0) - if (gpio_request(gpio_nreset, "CS4271 Reset")) + if (devm_gpio_request(codec->dev, gpio_nreset, "CS4271 Reset")) gpio_nreset = -EINVAL; if (gpio_nreset >= 0) { /* Reset codec */ @@ -528,6 +538,11 @@ static int cs4271_probe(struct snd_soc_codec *codec) /* Power-up sequence requires 85 uS */ udelay(85); + if (amutec_eq_bmutec) + snd_soc_update_bits(codec, CS4271_MODE2, + CS4271_MODE2_MUTECAEQUB, + CS4271_MODE2_MUTECAEQUB); + return snd_soc_add_codec_controls(codec, cs4271_snd_controls, ARRAY_SIZE(cs4271_snd_controls)); } @@ -535,15 +550,10 @@ static int cs4271_probe(struct snd_soc_codec *codec) static int cs4271_remove(struct snd_soc_codec *codec) { struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec); - int gpio_nreset; - - gpio_nreset = cs4271->gpio_nreset; - if (gpio_is_valid(gpio_nreset)) { + if (gpio_is_valid(cs4271->gpio_nreset)) /* Set codec to the reset state */ - gpio_set_value(gpio_nreset, 0); - gpio_free(gpio_nreset); - } + gpio_set_value(cs4271->gpio_nreset, 0); return 0; }; @@ -560,7 +570,7 @@ static struct snd_soc_codec_driver soc_codec_dev_cs4271 = { }; #if defined(CONFIG_SPI_MASTER) -static int __devinit cs4271_spi_probe(struct spi_device *spi) +static int cs4271_spi_probe(struct spi_device *spi) { struct cs4271_private *cs4271; @@ -575,7 +585,7 @@ static int __devinit cs4271_spi_probe(struct spi_device *spi) &cs4271_dai, 1); } -static int __devexit cs4271_spi_remove(struct spi_device *spi) +static int cs4271_spi_remove(struct spi_device *spi) { snd_soc_unregister_codec(&spi->dev); return 0; @@ -588,7 +598,7 @@ static struct spi_driver cs4271_spi_driver = { .of_match_table = of_match_ptr(cs4271_dt_ids), }, .probe = cs4271_spi_probe, - .remove = __devexit_p(cs4271_spi_remove), + .remove = cs4271_spi_remove, }; #endif /* defined(CONFIG_SPI_MASTER) */ @@ -599,8 +609,8 @@ static const struct i2c_device_id cs4271_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, cs4271_i2c_id); -static int __devinit cs4271_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int cs4271_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct cs4271_private *cs4271; @@ -615,7 +625,7 @@ static int __devinit cs4271_i2c_probe(struct i2c_client *client, &cs4271_dai, 1); } -static int __devexit cs4271_i2c_remove(struct i2c_client *client) +static int cs4271_i2c_remove(struct i2c_client *client) { snd_soc_unregister_codec(&client->dev); return 0; @@ -629,7 +639,7 @@ static struct i2c_driver cs4271_i2c_driver = { }, .id_table = cs4271_i2c_id, .probe = cs4271_i2c_probe, - .remove = __devexit_p(cs4271_i2c_remove), + .remove = cs4271_i2c_remove, }; #endif /* defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) */ diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c index 97a81051e88d..9811a5478c87 100644 --- a/sound/soc/codecs/cs42l52.c +++ b/sound/soc/codecs/cs42l52.c @@ -737,7 +737,7 @@ static const struct cs42l52_clk_para clk_map_table[] = { static int cs42l52_get_clk(int mclk, int rate) { - int i, ret = 0; + int i, ret = -EINVAL; u_int mclk1, mclk2 = 0; for (i = 0; i < ARRAY_SIZE(clk_map_table); i++) { @@ -749,8 +749,6 @@ static int cs42l52_get_clk(int mclk, int rate) } } } - if (ret > ARRAY_SIZE(clk_map_table)) - return -EINVAL; return ret; } @@ -1271,7 +1269,7 @@ static struct i2c_driver cs42l52_i2c_driver = { }, .id_table = cs42l52_id, .probe = cs42l52_i2c_probe, - .remove = __devexit_p(cs42l52_i2c_remove), + .remove = cs42l52_i2c_remove, }; module_i2c_driver(cs42l52_i2c_driver); diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c index 2c08c4cb465a..6361dab48bd1 100644 --- a/sound/soc/codecs/cs42l73.c +++ b/sound/soc/codecs/cs42l73.c @@ -40,6 +40,7 @@ struct cs42l73_private { u32 sysclk; u8 mclksel; u32 mclk; + int shutdwn_delay; }; static const struct reg_default cs42l73_reg_defaults[] = { @@ -588,7 +589,60 @@ static const struct snd_kcontrol_new cs42l73_snd_controls[] = { SOC_ENUM("XSPOUT Mono/Stereo Select", xsp_output_mux_enum), }; +static int cs42l73_spklo_spk_amp_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->codec; + struct cs42l73_private *priv = snd_soc_codec_get_drvdata(codec); + switch (event) { + case SND_SOC_DAPM_POST_PMD: + /* 150 ms delay between setting PDN and MCLKDIS */ + priv->shutdwn_delay = 150; + break; + default: + pr_err("Invalid event = 0x%x\n", event); + } + return 0; +} + +static int cs42l73_ear_amp_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->codec; + struct cs42l73_private *priv = snd_soc_codec_get_drvdata(codec); + switch (event) { + case SND_SOC_DAPM_POST_PMD: + /* 50 ms delay between setting PDN and MCLKDIS */ + if (priv->shutdwn_delay < 50) + priv->shutdwn_delay = 50; + break; + default: + pr_err("Invalid event = 0x%x\n", event); + } + return 0; +} + + +static int cs42l73_hp_amp_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->codec; + struct cs42l73_private *priv = snd_soc_codec_get_drvdata(codec); + switch (event) { + case SND_SOC_DAPM_POST_PMD: + /* 30 ms delay between setting PDN and MCLKDIS */ + if (priv->shutdwn_delay < 30) + priv->shutdwn_delay = 30; + break; + default: + pr_err("Invalid event = 0x%x\n", event); + } + return 0; +} + static const struct snd_soc_dapm_widget cs42l73_dapm_widgets[] = { + SND_SOC_DAPM_INPUT("DMICA"), + SND_SOC_DAPM_INPUT("DMICB"), SND_SOC_DAPM_INPUT("LINEINA"), SND_SOC_DAPM_INPUT("LINEINB"), SND_SOC_DAPM_INPUT("MIC1"), @@ -604,9 +658,7 @@ static const struct snd_soc_dapm_widget cs42l73_dapm_widgets[] = { CS42L73_PWRCTL2, 3, 1), SND_SOC_DAPM_AIF_OUT("ASPOUTR", NULL, 0, CS42L73_PWRCTL2, 3, 1), - SND_SOC_DAPM_AIF_OUT("VSPOUTL", NULL, 0, - CS42L73_PWRCTL2, 4, 1), - SND_SOC_DAPM_AIF_OUT("VSPOUTR", NULL, 0, + SND_SOC_DAPM_AIF_OUT("VSPINOUT", NULL, 0, CS42L73_PWRCTL2, 4, 1), SND_SOC_DAPM_PGA("PGA Left", SND_SOC_NOPM, 0, 0, NULL, 0), @@ -632,8 +684,7 @@ static const struct snd_soc_dapm_widget cs42l73_dapm_widgets[] = { SND_SOC_DAPM_MIXER("ASPR Output Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER("XSPL Output Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER("XSPR Output Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), - SND_SOC_DAPM_MIXER("VSPL Output Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), - SND_SOC_DAPM_MIXER("VSPR Output Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("VSP Output Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_AIF_IN("XSPINL", NULL, 0, CS42L73_PWRCTL2, 0, 1), @@ -649,7 +700,7 @@ static const struct snd_soc_dapm_widget cs42l73_dapm_widgets[] = { SND_SOC_DAPM_AIF_IN("ASPINM", NULL, 0, CS42L73_PWRCTL2, 2, 1), - SND_SOC_DAPM_AIF_IN("VSPIN", NULL, 0, + SND_SOC_DAPM_AIF_IN("VSPINOUT", NULL, 0, CS42L73_PWRCTL2, 4, 1), SND_SOC_DAPM_MIXER("HL Left Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), @@ -674,16 +725,20 @@ static const struct snd_soc_dapm_widget cs42l73_dapm_widgets[] = { SND_SOC_DAPM_PGA("SPK DAC", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_PGA("ESL DAC", SND_SOC_NOPM, 0, 0, NULL, 0), - SND_SOC_DAPM_SWITCH("HP Amp", CS42L73_PWRCTL3, 0, 1, - &hp_amp_ctl), + SND_SOC_DAPM_SWITCH_E("HP Amp", CS42L73_PWRCTL3, 0, 1, + &hp_amp_ctl, cs42l73_hp_amp_event, + SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_SWITCH("LO Amp", CS42L73_PWRCTL3, 1, 1, &lo_amp_ctl), - SND_SOC_DAPM_SWITCH("SPK Amp", CS42L73_PWRCTL3, 2, 1, - &spk_amp_ctl), - SND_SOC_DAPM_SWITCH("EAR Amp", CS42L73_PWRCTL3, 3, 1, - &ear_amp_ctl), - SND_SOC_DAPM_SWITCH("SPKLO Amp", CS42L73_PWRCTL3, 4, 1, - &spklo_amp_ctl), + SND_SOC_DAPM_SWITCH_E("SPK Amp", CS42L73_PWRCTL3, 2, 1, + &spk_amp_ctl, cs42l73_spklo_spk_amp_event, + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SWITCH_E("EAR Amp", CS42L73_PWRCTL3, 3, 1, + &ear_amp_ctl, cs42l73_ear_amp_event, + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SWITCH_E("SPKLO Amp", CS42L73_PWRCTL3, 4, 1, + &spklo_amp_ctl, cs42l73_spklo_spk_amp_event, + SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_OUTPUT("HPOUTA"), SND_SOC_DAPM_OUTPUT("HPOUTB"), @@ -705,7 +760,7 @@ static const struct snd_soc_dapm_route cs42l73_audio_map[] = { {"ESL DAC", "ESL-ASP Mono Volume", "ESL Mixer"}, {"ESL DAC", "ESL-XSP Mono Volume", "ESL Mixer"}, - {"ESL DAC", "ESL-VSP Mono Volume", "VSPIN"}, + {"ESL DAC", "ESL-VSP Mono Volume", "VSPINOUT"}, /* Loopback */ {"ESL DAC", "ESL-IP Mono Volume", "Input Left Capture"}, {"ESL DAC", "ESL-IP Mono Volume", "Input Right Capture"}, @@ -727,7 +782,7 @@ static const struct snd_soc_dapm_route cs42l73_audio_map[] = { {"SPK DAC", "SPK-ASP Mono Volume", "SPK Mixer"}, {"SPK DAC", "SPK-XSP Mono Volume", "SPK Mixer"}, - {"SPK DAC", "SPK-VSP Mono Volume", "VSPIN"}, + {"SPK DAC", "SPK-VSP Mono Volume", "VSPINOUT"}, /* Loopback */ {"SPK DAC", "SPK-IP Mono Volume", "Input Left Capture"}, {"SPK DAC", "SPK-IP Mono Volume", "Input Right Capture"}, @@ -770,8 +825,8 @@ static const struct snd_soc_dapm_route cs42l73_audio_map[] = { {"HL Right Mixer", NULL, "ASPINR"}, {"HL Left Mixer", NULL, "XSPINL"}, {"HL Right Mixer", NULL, "XSPINR"}, - {"HL Left Mixer", NULL, "VSPIN"}, - {"HL Right Mixer", NULL, "VSPIN"}, + {"HL Left Mixer", NULL, "VSPINOUT"}, + {"HL Right Mixer", NULL, "VSPINOUT"}, {"ASPINL", NULL, "ASP Playback"}, {"ASPINM", NULL, "ASP Playback"}, @@ -779,7 +834,7 @@ static const struct snd_soc_dapm_route cs42l73_audio_map[] = { {"XSPINL", NULL, "XSP Playback"}, {"XSPINM", NULL, "XSP Playback"}, {"XSPINR", NULL, "XSP Playback"}, - {"VSPIN", NULL, "VSP Playback"}, + {"VSPINOUT", NULL, "VSP Playback"}, /* Capture Paths */ {"MIC1", NULL, "MIC1 Bias"}, @@ -795,6 +850,8 @@ static const struct snd_soc_dapm_route cs42l73_audio_map[] = { {"ADC Left", NULL, "PGA Left"}, {"ADC Right", NULL, "PGA Right"}, + {"DMIC Left", NULL, "DMICA"}, + {"DMIC Right", NULL, "DMICB"}, {"Input Left Capture", "ADC Left Input", "ADC Left"}, {"Input Right Capture", "ADC Right Input", "ADC Right"}, @@ -819,21 +876,18 @@ static const struct snd_soc_dapm_route cs42l73_audio_map[] = { {"XSPOUTR", NULL, "XSPR Output Mixer"}, /* Voice Capture */ - {"VSPL Output Mixer", NULL, "Input Left Capture"}, - {"VSPR Output Mixer", NULL, "Input Left Capture"}, + {"VSP Output Mixer", NULL, "Input Left Capture"}, + {"VSP Output Mixer", NULL, "Input Right Capture"}, - {"VSPOUTL", "VSP-IP Volume", "VSPL Output Mixer"}, - {"VSPOUTR", "VSP-IP Volume", "VSPR Output Mixer"}, + {"VSPINOUT", "VSP-IP Volume", "VSP Output Mixer"}, - {"VSPOUTL", NULL, "VSPL Output Mixer"}, - {"VSPOUTR", NULL, "VSPR Output Mixer"}, + {"VSPINOUT", NULL, "VSP Output Mixer"}, {"ASP Capture", NULL, "ASPOUTL"}, {"ASP Capture", NULL, "ASPOUTR"}, {"XSP Capture", NULL, "XSPOUTL"}, {"XSP Capture", NULL, "XSPOUTR"}, - {"VSP Capture", NULL, "VSPOUTL"}, - {"VSP Capture", NULL, "VSPOUTR"}, + {"VSP Capture", NULL, "VSPINOUT"}, }; struct cs42l73_mclk_div { @@ -1167,6 +1221,14 @@ static int cs42l73_set_bias_level(struct snd_soc_codec *codec, case SND_SOC_BIAS_OFF: snd_soc_update_bits(codec, CS42L73_PWRCTL1, PDN, 1); + if (cs42l73->shutdwn_delay > 0) { + mdelay(cs42l73->shutdwn_delay); + cs42l73->shutdwn_delay = 0; + } else { + mdelay(15); /* Min amount of time requred to power + * down. + */ + } snd_soc_update_bits(codec, CS42L73_DMMCC, MCLKDIS, 1); break; } @@ -1345,8 +1407,8 @@ static struct regmap_config cs42l73_regmap = { .cache_type = REGCACHE_RBTREE, }; -static __devinit int cs42l73_i2c_probe(struct i2c_client *i2c_client, - const struct i2c_device_id *id) +static int cs42l73_i2c_probe(struct i2c_client *i2c_client, + const struct i2c_device_id *id) { struct cs42l73_private *cs42l73; int ret; @@ -1406,7 +1468,7 @@ static __devinit int cs42l73_i2c_probe(struct i2c_client *i2c_client, return 0; } -static __devexit int cs42l73_i2c_remove(struct i2c_client *client) +static int cs42l73_i2c_remove(struct i2c_client *client) { snd_soc_unregister_codec(&client->dev); return 0; @@ -1426,7 +1488,7 @@ static struct i2c_driver cs42l73_i2c_driver = { }, .id_table = cs42l73_id, .probe = cs42l73_i2c_probe, - .remove = __devexit_p(cs42l73_i2c_remove), + .remove = cs42l73_i2c_remove, }; diff --git a/sound/soc/codecs/da7210.c b/sound/soc/codecs/da7210.c index af5db7080519..9c1231456502 100644 --- a/sound/soc/codecs/da7210.c +++ b/sound/soc/codecs/da7210.c @@ -1218,8 +1218,8 @@ static const struct regmap_config da7210_regmap_config_i2c = { .cache_type = REGCACHE_RBTREE, }; -static int __devinit da7210_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int da7210_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) { struct da7210_priv *da7210; int ret; @@ -1231,7 +1231,7 @@ static int __devinit da7210_i2c_probe(struct i2c_client *i2c, i2c_set_clientdata(i2c, da7210); - da7210->regmap = regmap_init_i2c(i2c, &da7210_regmap_config_i2c); + da7210->regmap = devm_regmap_init_i2c(i2c, &da7210_regmap_config_i2c); if (IS_ERR(da7210->regmap)) { ret = PTR_ERR(da7210->regmap); dev_err(&i2c->dev, "regmap_init() failed: %d\n", ret); @@ -1245,24 +1245,15 @@ static int __devinit da7210_i2c_probe(struct i2c_client *i2c, ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_da7210, &da7210_dai, 1); - if (ret < 0) { + if (ret < 0) dev_err(&i2c->dev, "Failed to register codec: %d\n", ret); - goto err_regmap; - } - return ret; - -err_regmap: - regmap_exit(da7210->regmap); return ret; } -static int __devexit da7210_i2c_remove(struct i2c_client *client) +static int da7210_i2c_remove(struct i2c_client *client) { - struct da7210_priv *da7210 = i2c_get_clientdata(client); - snd_soc_unregister_codec(&client->dev); - regmap_exit(da7210->regmap); return 0; } @@ -1279,7 +1270,7 @@ static struct i2c_driver da7210_i2c_driver = { .owner = THIS_MODULE, }, .probe = da7210_i2c_probe, - .remove = __devexit_p(da7210_i2c_remove), + .remove = da7210_i2c_remove, .id_table = da7210_i2c_id, }; #endif @@ -1323,7 +1314,7 @@ static const struct regmap_config da7210_regmap_config_spi = { .cache_type = REGCACHE_RBTREE, }; -static int __devinit da7210_spi_probe(struct spi_device *spi) +static int da7210_spi_probe(struct spi_device *spi) { struct da7210_priv *da7210; int ret; @@ -1346,24 +1337,15 @@ static int __devinit da7210_spi_probe(struct spi_device *spi) if (ret != 0) dev_warn(&spi->dev, "Failed to apply regmap patch: %d\n", ret); - ret = snd_soc_register_codec(&spi->dev, + ret = snd_soc_register_codec(&spi->dev, &soc_codec_dev_da7210, &da7210_dai, 1); - if (ret < 0) - goto err_regmap; - - return ret; - -err_regmap: - regmap_exit(da7210->regmap); return ret; } -static int __devexit da7210_spi_remove(struct spi_device *spi) +static int da7210_spi_remove(struct spi_device *spi) { - struct da7210_priv *da7210 = spi_get_drvdata(spi); snd_soc_unregister_codec(&spi->dev); - regmap_exit(da7210->regmap); return 0; } @@ -1373,7 +1355,7 @@ static struct spi_driver da7210_spi_driver = { .owner = THIS_MODULE, }, .probe = da7210_spi_probe, - .remove = __devexit_p(da7210_spi_remove) + .remove = da7210_spi_remove }; #endif diff --git a/sound/soc/codecs/da732x.c b/sound/soc/codecs/da732x.c index 01be2a320e21..dc0284dc9e6f 100644 --- a/sound/soc/codecs/da732x.c +++ b/sound/soc/codecs/da732x.c @@ -1557,8 +1557,8 @@ static struct snd_soc_codec_driver soc_codec_dev_da732x = { .reg_cache_size = ARRAY_SIZE(da732x_reg_cache), }; -static __devinit int da732x_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int da732x_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) { struct da732x_priv *da732x; unsigned int reg; @@ -1596,7 +1596,7 @@ err: return ret; } -static __devexit int da732x_i2c_remove(struct i2c_client *client) +static int da732x_i2c_remove(struct i2c_client *client) { snd_soc_unregister_codec(&client->dev); @@ -1615,7 +1615,7 @@ static struct i2c_driver da732x_i2c_driver = { .owner = THIS_MODULE, }, .probe = da732x_i2c_probe, - .remove = __devexit_p(da732x_i2c_remove), + .remove = da732x_i2c_remove, .id_table = da732x_i2c_id, }; diff --git a/sound/soc/codecs/da9055.c b/sound/soc/codecs/da9055.c index f379b085c392..fc9802d1281d 100644 --- a/sound/soc/codecs/da9055.c +++ b/sound/soc/codecs/da9055.c @@ -173,6 +173,7 @@ #define DA9055_AIF_FORMAT_I2S_MODE (0 << 0) #define DA9055_AIF_FORMAT_LEFT_J (1 << 0) #define DA9055_AIF_FORMAT_RIGHT_J (2 << 0) +#define DA9055_AIF_FORMAT_DSP (3 << 0) #define DA9055_AIF_WORD_S16_LE (0 << 2) #define DA9055_AIF_WORD_S20_3LE (1 << 2) #define DA9055_AIF_WORD_S24_LE (2 << 2) @@ -752,6 +753,17 @@ static const struct snd_kcontrol_new da9055_dapm_mixoutr_controls[] = { 6, 1, 0), }; +/* Headphone Output Enable */ +static const struct snd_kcontrol_new da9055_dapm_hp_l_control = +SOC_DAPM_SINGLE("Switch", DA9055_HP_L_CTRL, 3, 1, 0); + +static const struct snd_kcontrol_new da9055_dapm_hp_r_control = +SOC_DAPM_SINGLE("Switch", DA9055_HP_R_CTRL, 3, 1, 0); + +/* Lineout Output Enable */ +static const struct snd_kcontrol_new da9055_dapm_lineout_control = +SOC_DAPM_SINGLE("Switch", DA9055_LINE_CTRL, 3, 1, 0); + /* DAPM widgets */ static const struct snd_soc_dapm_widget da9055_dapm_widgets[] = { /* Input Side */ @@ -816,6 +828,14 @@ static const struct snd_soc_dapm_widget da9055_dapm_widgets[] = { &da9055_dapm_mixoutr_controls[0], ARRAY_SIZE(da9055_dapm_mixoutr_controls)), + /* Output Enable Switches */ + SND_SOC_DAPM_SWITCH("Headphone Left Enable", SND_SOC_NOPM, 0, 0, + &da9055_dapm_hp_l_control), + SND_SOC_DAPM_SWITCH("Headphone Right Enable", SND_SOC_NOPM, 0, 0, + &da9055_dapm_hp_r_control), + SND_SOC_DAPM_SWITCH("Lineout Enable", SND_SOC_NOPM, 0, 0, + &da9055_dapm_lineout_control), + /* Output PGAs */ SND_SOC_DAPM_PGA("MIXOUT Left", DA9055_MIXOUT_L_CTRL, 7, 0, NULL, 0), SND_SOC_DAPM_PGA("MIXOUT Right", DA9055_MIXOUT_R_CTRL, 7, 0, NULL, 0), @@ -901,17 +921,20 @@ static const struct snd_soc_dapm_route da9055_audio_map[] = { {"Out Mixer Right", "DAC Right Switch", "DAC Right"}, {"MIXOUT Left", NULL, "Out Mixer Left"}, - {"Headphone Left", NULL, "MIXOUT Left"}, + {"Headphone Left Enable", "Switch", "MIXOUT Left"}, + {"Headphone Left", NULL, "Headphone Left Enable"}, {"Headphone Left", NULL, "Charge Pump"}, {"HPL", NULL, "Headphone Left"}, {"MIXOUT Right", NULL, "Out Mixer Right"}, - {"Headphone Right", NULL, "MIXOUT Right"}, + {"Headphone Right Enable", "Switch", "MIXOUT Right"}, + {"Headphone Right", NULL, "Headphone Right Enable"}, {"Headphone Right", NULL, "Charge Pump"}, {"HPR", NULL, "Headphone Right"}, {"MIXOUT Right", NULL, "Out Mixer Right"}, - {"Lineout", NULL, "MIXOUT Right"}, + {"Lineout Enable", "Switch", "MIXOUT Right"}, + {"Lineout", NULL, "Lineout Enable"}, {"LINE", NULL, "Lineout"}, }; @@ -1175,6 +1198,9 @@ static int da9055_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) case SND_SOC_DAIFMT_RIGHT_J: aif_ctrl = DA9055_AIF_FORMAT_RIGHT_J; break; + case SND_SOC_DAIFMT_DSP_A: + aif_ctrl = DA9055_AIF_FORMAT_DSP; + break; default: return -EINVAL; } @@ -1390,8 +1416,7 @@ static int da9055_probe(struct snd_soc_codec *codec) DA9055_GAIN_RAMPING_EN, DA9055_GAIN_RAMPING_EN); /* - * There are two separate control bits for input and output mixers as - * well as headphone and line outs. + * There are two separate control bits for input and output mixers. * One to enable corresponding amplifier and other to enable its * output. As amplifier bits are related to power control, they are * being managed by DAPM while other (non power related) bits are @@ -1407,14 +1432,6 @@ static int da9055_probe(struct snd_soc_codec *codec) snd_soc_update_bits(codec, DA9055_MIXOUT_R_CTRL, DA9055_MIXOUT_R_MIX_EN, DA9055_MIXOUT_R_MIX_EN); - snd_soc_update_bits(codec, DA9055_HP_L_CTRL, - DA9055_HP_L_AMP_OE, DA9055_HP_L_AMP_OE); - snd_soc_update_bits(codec, DA9055_HP_R_CTRL, - DA9055_HP_R_AMP_OE, DA9055_HP_R_AMP_OE); - - snd_soc_update_bits(codec, DA9055_LINE_CTRL, - DA9055_LINE_AMP_OE, DA9055_LINE_AMP_OE); - /* Set this as per your system configuration */ snd_soc_write(codec, DA9055_PLL_CTRL, DA9055_PLL_INDIV_10_20_MHZ); @@ -1467,8 +1484,8 @@ static const struct regmap_config da9055_regmap_config = { .cache_type = REGCACHE_RBTREE, }; -static int __devinit da9055_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int da9055_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) { struct da9055_priv *da9055; struct da9055_platform_data *pdata = dev_get_platdata(&i2c->dev); @@ -1500,7 +1517,7 @@ static int __devinit da9055_i2c_probe(struct i2c_client *i2c, return ret; } -static int __devexit da9055_remove(struct i2c_client *client) +static int da9055_remove(struct i2c_client *client) { snd_soc_unregister_codec(&client->dev); return 0; @@ -1519,7 +1536,7 @@ static struct i2c_driver da9055_i2c_driver = { .owner = THIS_MODULE, }, .probe = da9055_i2c_probe, - .remove = __devexit_p(da9055_remove), + .remove = da9055_remove, .id_table = da9055_i2c_id, }; diff --git a/sound/soc/codecs/dfbmcs320.c b/sound/soc/codecs/dfbmcs320.c index bfe46aa90362..4f4f7f41a7d1 100644 --- a/sound/soc/codecs/dfbmcs320.c +++ b/sound/soc/codecs/dfbmcs320.c @@ -33,13 +33,13 @@ static struct snd_soc_dai_driver dfbmcs320_dai = { static struct snd_soc_codec_driver soc_codec_dev_dfbmcs320; -static int __devinit dfbmcs320_probe(struct platform_device *pdev) +static int dfbmcs320_probe(struct platform_device *pdev) { return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_dfbmcs320, &dfbmcs320_dai, 1); } -static int __devexit dfbmcs320_remove(struct platform_device *pdev) +static int dfbmcs320_remove(struct platform_device *pdev) { snd_soc_unregister_codec(&pdev->dev); @@ -52,7 +52,7 @@ static struct platform_driver dfmcs320_driver = { .owner = THIS_MODULE, }, .probe = dfbmcs320_probe, - .remove = __devexit_p(dfbmcs320_remove), + .remove = dfbmcs320_remove, }; module_platform_driver(dfmcs320_driver); diff --git a/sound/soc/codecs/dmic.c b/sound/soc/codecs/dmic.c index 3e929f079a1f..66967ba6f757 100644 --- a/sound/soc/codecs/dmic.c +++ b/sound/soc/codecs/dmic.c @@ -66,13 +66,13 @@ static struct snd_soc_codec_driver soc_dmic = { .probe = dmic_probe, }; -static int __devinit dmic_dev_probe(struct platform_device *pdev) +static int dmic_dev_probe(struct platform_device *pdev) { return snd_soc_register_codec(&pdev->dev, &soc_dmic, &dmic_dai, 1); } -static int __devexit dmic_dev_remove(struct platform_device *pdev) +static int dmic_dev_remove(struct platform_device *pdev) { snd_soc_unregister_codec(&pdev->dev); return 0; @@ -86,7 +86,7 @@ static struct platform_driver dmic_driver = { .owner = THIS_MODULE, }, .probe = dmic_dev_probe, - .remove = __devexit_p(dmic_dev_remove), + .remove = dmic_dev_remove, }; module_platform_driver(dmic_driver); diff --git a/sound/soc/codecs/isabelle.c b/sound/soc/codecs/isabelle.c index 1bf55602c9eb..53b455b8c07a 100644 --- a/sound/soc/codecs/isabelle.c +++ b/sound/soc/codecs/isabelle.c @@ -1119,8 +1119,8 @@ static const struct regmap_config isabelle_regmap_config = { .cache_type = REGCACHE_RBTREE, }; -static int __devinit isabelle_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int isabelle_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) { struct regmap *isabelle_regmap; int ret = 0; @@ -1145,7 +1145,7 @@ static int __devinit isabelle_i2c_probe(struct i2c_client *i2c, return ret; } -static int __devexit isabelle_i2c_remove(struct i2c_client *client) +static int isabelle_i2c_remove(struct i2c_client *client) { snd_soc_unregister_codec(&client->dev); return 0; @@ -1163,7 +1163,7 @@ static struct i2c_driver isabelle_i2c_driver = { .owner = THIS_MODULE, }, .probe = isabelle_i2c_probe, - .remove = __devexit_p(isabelle_i2c_remove), + .remove = isabelle_i2c_remove, .id_table = isabelle_i2c_id, }; diff --git a/sound/soc/codecs/jz4740.c b/sound/soc/codecs/jz4740.c index 85d9cabe6d55..d991529e1aff 100644 --- a/sound/soc/codecs/jz4740.c +++ b/sound/soc/codecs/jz4740.c @@ -16,6 +16,7 @@ #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/io.h> +#include <linux/regmap.h> #include <linux/delay.h> @@ -24,9 +25,10 @@ #include <sound/pcm_params.h> #include <sound/initval.h> #include <sound/soc.h> +#include <sound/tlv.h> #define JZ4740_REG_CODEC_1 0x0 -#define JZ4740_REG_CODEC_2 0x1 +#define JZ4740_REG_CODEC_2 0x4 #define JZ4740_CODEC_1_LINE_ENABLE BIT(29) #define JZ4740_CODEC_1_MIC_ENABLE BIT(28) @@ -67,43 +69,36 @@ #define JZ4740_CODEC_2_MIC_BOOST_GAIN_OFFSET 4 #define JZ4740_CODEC_2_HEADPHONE_VOLUME_OFFSET 0 -static const uint32_t jz4740_codec_regs[] = { - 0x021b2302, 0x00170803, +static const struct reg_default jz4740_codec_reg_defaults[] = { + { JZ4740_REG_CODEC_1, 0x021b2302 }, + { JZ4740_REG_CODEC_2, 0x00170803 }, }; struct jz4740_codec { - void __iomem *base; - struct resource *mem; + struct regmap *regmap; }; -static unsigned int jz4740_codec_read(struct snd_soc_codec *codec, - unsigned int reg) -{ - struct jz4740_codec *jz4740_codec = snd_soc_codec_get_drvdata(codec); - return readl(jz4740_codec->base + (reg << 2)); -} - -static int jz4740_codec_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int val) -{ - struct jz4740_codec *jz4740_codec = snd_soc_codec_get_drvdata(codec); - u32 *cache = codec->reg_cache; - - cache[reg] = val; - writel(val, jz4740_codec->base + (reg << 2)); +static const unsigned int jz4740_mic_tlv[] = { + TLV_DB_RANGE_HEAD(2), + 0, 2, TLV_DB_SCALE_ITEM(0, 600, 0), + 3, 3, TLV_DB_SCALE_ITEM(2000, 0, 0), +}; - return 0; -} +static const DECLARE_TLV_DB_SCALE(jz4740_out_tlv, 0, 200, 0); +static const DECLARE_TLV_DB_SCALE(jz4740_in_tlv, -3450, 150, 0); static const struct snd_kcontrol_new jz4740_codec_controls[] = { - SOC_SINGLE("Master Playback Volume", JZ4740_REG_CODEC_2, - JZ4740_CODEC_2_HEADPHONE_VOLUME_OFFSET, 3, 0), - SOC_SINGLE("Master Capture Volume", JZ4740_REG_CODEC_2, - JZ4740_CODEC_2_INPUT_VOLUME_OFFSET, 31, 0), + SOC_SINGLE_TLV("Master Playback Volume", JZ4740_REG_CODEC_2, + JZ4740_CODEC_2_HEADPHONE_VOLUME_OFFSET, 3, 0, + jz4740_out_tlv), + SOC_SINGLE_TLV("Master Capture Volume", JZ4740_REG_CODEC_2, + JZ4740_CODEC_2_INPUT_VOLUME_OFFSET, 31, 0, + jz4740_in_tlv), SOC_SINGLE("Master Playback Switch", JZ4740_REG_CODEC_1, JZ4740_CODEC_1_HEADPHONE_DISABLE_OFFSET, 1, 1), - SOC_SINGLE("Mic Capture Volume", JZ4740_REG_CODEC_2, - JZ4740_CODEC_2_MIC_BOOST_GAIN_OFFSET, 3, 0), + SOC_SINGLE_TLV("Mic Capture Volume", JZ4740_REG_CODEC_2, + JZ4740_CODEC_2_MIC_BOOST_GAIN_OFFSET, 3, 0, + jz4740_mic_tlv), }; static const struct snd_kcontrol_new jz4740_codec_output_controls[] = { @@ -163,8 +158,8 @@ static const struct snd_soc_dapm_route jz4740_codec_dapm_routes[] = { static int jz4740_codec_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { + struct jz4740_codec *jz4740_codec = snd_soc_codec_get_drvdata(dai->codec); uint32_t val; - struct snd_soc_codec *codec = dai->codec; switch (params_rate(params)) { case 8000: @@ -200,7 +195,7 @@ static int jz4740_codec_hw_params(struct snd_pcm_substream *substream, val <<= JZ4740_CODEC_2_SAMPLE_RATE_OFFSET; - snd_soc_update_bits(codec, JZ4740_REG_CODEC_2, + regmap_update_bits(jz4740_codec->regmap, JZ4740_REG_CODEC_2, JZ4740_CODEC_2_SAMPLE_RATE_MASK, val); return 0; @@ -230,25 +225,23 @@ static struct snd_soc_dai_driver jz4740_codec_dai = { .symmetric_rates = 1, }; -static void jz4740_codec_wakeup(struct snd_soc_codec *codec) +static void jz4740_codec_wakeup(struct regmap *regmap) { - int i; - uint32_t *cache = codec->reg_cache; - - snd_soc_update_bits(codec, JZ4740_REG_CODEC_1, + regmap_update_bits(regmap, JZ4740_REG_CODEC_1, JZ4740_CODEC_1_RESET, JZ4740_CODEC_1_RESET); udelay(2); - snd_soc_update_bits(codec, JZ4740_REG_CODEC_1, + regmap_update_bits(regmap, JZ4740_REG_CODEC_1, JZ4740_CODEC_1_SUSPEND | JZ4740_CODEC_1_RESET, 0); - for (i = 0; i < ARRAY_SIZE(jz4740_codec_regs); ++i) - jz4740_codec_write(codec, i, cache[i]); + regcache_sync(regmap); } static int jz4740_codec_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { + struct jz4740_codec *jz4740_codec = snd_soc_codec_get_drvdata(codec); + struct regmap *regmap = jz4740_codec->regmap; unsigned int mask; unsigned int value; @@ -261,12 +254,12 @@ static int jz4740_codec_set_bias_level(struct snd_soc_codec *codec, JZ4740_CODEC_1_HEADPHONE_POWERDOWN_M; value = 0; - snd_soc_update_bits(codec, JZ4740_REG_CODEC_1, mask, value); + regmap_update_bits(regmap, JZ4740_REG_CODEC_1, mask, value); break; case SND_SOC_BIAS_STANDBY: /* The only way to clear the suspend flag is to reset the codec */ if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) - jz4740_codec_wakeup(codec); + jz4740_codec_wakeup(regmap); mask = JZ4740_CODEC_1_VREF_DISABLE | JZ4740_CODEC_1_VREF_AMP_DISABLE | @@ -275,13 +268,14 @@ static int jz4740_codec_set_bias_level(struct snd_soc_codec *codec, JZ4740_CODEC_1_VREF_AMP_DISABLE | JZ4740_CODEC_1_HEADPHONE_POWERDOWN_M; - snd_soc_update_bits(codec, JZ4740_REG_CODEC_1, mask, value); + regmap_update_bits(regmap, JZ4740_REG_CODEC_1, mask, value); break; case SND_SOC_BIAS_OFF: mask = JZ4740_CODEC_1_SUSPEND; value = JZ4740_CODEC_1_SUSPEND; - snd_soc_update_bits(codec, JZ4740_REG_CODEC_1, mask, value); + regmap_update_bits(regmap, JZ4740_REG_CODEC_1, mask, value); + regcache_mark_dirty(regmap); break; default: break; @@ -294,7 +288,9 @@ static int jz4740_codec_set_bias_level(struct snd_soc_codec *codec, static int jz4740_codec_dev_probe(struct snd_soc_codec *codec) { - snd_soc_update_bits(codec, JZ4740_REG_CODEC_1, + struct jz4740_codec *jz4740_codec = snd_soc_codec_get_drvdata(codec); + + regmap_update_bits(jz4740_codec->regmap, JZ4740_REG_CODEC_1, JZ4740_CODEC_1_SW2_ENABLE, JZ4740_CODEC_1_SW2_ENABLE); jz4740_codec_set_bias_level(codec, SND_SOC_BIAS_STANDBY); @@ -331,12 +327,7 @@ static struct snd_soc_codec_driver soc_codec_dev_jz4740_codec = { .remove = jz4740_codec_dev_remove, .suspend = jz4740_codec_suspend, .resume = jz4740_codec_resume, - .read = jz4740_codec_read, - .write = jz4740_codec_write, .set_bias_level = jz4740_codec_set_bias_level, - .reg_cache_default = jz4740_codec_regs, - .reg_word_size = sizeof(u32), - .reg_cache_size = 2, .controls = jz4740_codec_controls, .num_controls = ARRAY_SIZE(jz4740_codec_controls), @@ -346,11 +337,23 @@ static struct snd_soc_codec_driver soc_codec_dev_jz4740_codec = { .num_dapm_routes = ARRAY_SIZE(jz4740_codec_dapm_routes), }; -static int __devinit jz4740_codec_probe(struct platform_device *pdev) +static const struct regmap_config jz4740_codec_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = JZ4740_REG_CODEC_2, + + .reg_defaults = jz4740_codec_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(jz4740_codec_reg_defaults), + .cache_type = REGCACHE_RBTREE, +}; + +static int jz4740_codec_probe(struct platform_device *pdev) { int ret; struct jz4740_codec *jz4740_codec; struct resource *mem; + void __iomem *base; jz4740_codec = devm_kzalloc(&pdev->dev, sizeof(*jz4740_codec), GFP_KERNEL); @@ -358,56 +361,29 @@ static int __devinit jz4740_codec_probe(struct platform_device *pdev) return -ENOMEM; mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!mem) { - dev_err(&pdev->dev, "Failed to get mmio memory resource\n"); - ret = -ENOENT; - goto err_out; - } - - mem = request_mem_region(mem->start, resource_size(mem), pdev->name); - if (!mem) { - dev_err(&pdev->dev, "Failed to request mmio memory region\n"); - ret = -EBUSY; - goto err_out; - } + base = devm_request_and_ioremap(&pdev->dev, mem); + if (!base) + return -EBUSY; - jz4740_codec->base = ioremap(mem->start, resource_size(mem)); - if (!jz4740_codec->base) { - dev_err(&pdev->dev, "Failed to ioremap mmio memory\n"); - ret = -EBUSY; - goto err_release_mem_region; - } - jz4740_codec->mem = mem; + jz4740_codec->regmap = devm_regmap_init_mmio(&pdev->dev, base, + &jz4740_codec_regmap_config); + if (IS_ERR(jz4740_codec->regmap)) + return PTR_ERR(jz4740_codec->regmap); platform_set_drvdata(pdev, jz4740_codec); ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_jz4740_codec, &jz4740_codec_dai, 1); - if (ret) { + if (ret) dev_err(&pdev->dev, "Failed to register codec\n"); - goto err_iounmap; - } - return 0; - -err_iounmap: - iounmap(jz4740_codec->base); -err_release_mem_region: - release_mem_region(mem->start, resource_size(mem)); -err_out: return ret; } -static int __devexit jz4740_codec_remove(struct platform_device *pdev) +static int jz4740_codec_remove(struct platform_device *pdev) { - struct jz4740_codec *jz4740_codec = platform_get_drvdata(pdev); - struct resource *mem = jz4740_codec->mem; - snd_soc_unregister_codec(&pdev->dev); - iounmap(jz4740_codec->base); - release_mem_region(mem->start, resource_size(mem)); - platform_set_drvdata(pdev, NULL); return 0; @@ -415,7 +391,7 @@ static int __devexit jz4740_codec_remove(struct platform_device *pdev) static struct platform_driver jz4740_codec_driver = { .probe = jz4740_codec_probe, - .remove = __devexit_p(jz4740_codec_remove), + .remove = jz4740_codec_remove, .driver = { .name = "jz4740-codec", .owner = THIS_MODULE, diff --git a/sound/soc/codecs/lm4857.c b/sound/soc/codecs/lm4857.c index 81a328c78838..9f9f59573f72 100644 --- a/sound/soc/codecs/lm4857.c +++ b/sound/soc/codecs/lm4857.c @@ -209,8 +209,8 @@ static struct snd_soc_codec_driver soc_codec_dev_lm4857 = { .set_bias_level = lm4857_set_bias_level, }; -static int __devinit lm4857_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int lm4857_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) { struct lm4857 *lm4857; int ret; @@ -228,7 +228,7 @@ static int __devinit lm4857_i2c_probe(struct i2c_client *i2c, return ret; } -static int __devexit lm4857_i2c_remove(struct i2c_client *i2c) +static int lm4857_i2c_remove(struct i2c_client *i2c) { snd_soc_unregister_codec(&i2c->dev); return 0; @@ -246,7 +246,7 @@ static struct i2c_driver lm4857_i2c_driver = { .owner = THIS_MODULE, }, .probe = lm4857_i2c_probe, - .remove = __devexit_p(lm4857_i2c_remove), + .remove = lm4857_i2c_remove, .id_table = lm4857_i2c_id, }; diff --git a/sound/soc/codecs/lm49453.c b/sound/soc/codecs/lm49453.c index 99b0a9dcff34..e19490cfb3a8 100644 --- a/sound/soc/codecs/lm49453.c +++ b/sound/soc/codecs/lm49453.c @@ -111,9 +111,9 @@ static struct reg_default lm49453_reg_defs[] = { { 101, 0x00 }, { 102, 0x00 }, { 103, 0x01 }, - { 105, 0x01 }, - { 106, 0x00 }, - { 107, 0x01 }, + { 104, 0x01 }, + { 105, 0x00 }, + { 106, 0x01 }, { 107, 0x00 }, { 108, 0x00 }, { 109, 0x00 }, @@ -163,56 +163,25 @@ static struct reg_default lm49453_reg_defs[] = { { 184, 0x00 }, { 185, 0x00 }, { 186, 0x00 }, - { 189, 0x00 }, + { 187, 0x00 }, { 188, 0x00 }, - { 194, 0x00 }, - { 195, 0x00 }, - { 196, 0x00 }, - { 197, 0x00 }, - { 200, 0x00 }, - { 201, 0x00 }, - { 202, 0x00 }, - { 203, 0x00 }, - { 204, 0x00 }, - { 205, 0x00 }, - { 208, 0x00 }, + { 189, 0x00 }, + { 208, 0x06 }, { 209, 0x00 }, - { 210, 0x00 }, - { 211, 0x00 }, - { 213, 0x00 }, - { 214, 0x00 }, - { 215, 0x00 }, - { 216, 0x00 }, - { 217, 0x00 }, - { 218, 0x00 }, - { 219, 0x00 }, + { 210, 0x08 }, + { 211, 0x54 }, + { 212, 0x14 }, + { 213, 0x0d }, + { 214, 0x0d }, + { 215, 0x14 }, + { 216, 0x60 }, { 221, 0x00 }, { 222, 0x00 }, + { 223, 0x00 }, { 224, 0x00 }, - { 225, 0x00 }, - { 226, 0x00 }, - { 227, 0x00 }, - { 228, 0x00 }, - { 229, 0x00 }, - { 230, 0x13 }, - { 231, 0x00 }, - { 232, 0x80 }, - { 233, 0x0C }, - { 234, 0xDD }, - { 235, 0x00 }, - { 236, 0x04 }, - { 237, 0x00 }, - { 238, 0x00 }, - { 239, 0x00 }, - { 240, 0x00 }, - { 241, 0x00 }, - { 242, 0x00 }, - { 243, 0x00 }, - { 244, 0x00 }, - { 245, 0x00 }, { 248, 0x00 }, { 249, 0x00 }, - { 254, 0x00 }, + { 250, 0x00 }, { 255, 0x00 }, }; @@ -525,36 +494,41 @@ SOC_DAPM_SINGLE("Port2_2 Switch", LM49453_P0_PORT2_TX2_REG, 7, 1, 0), }; /* TLV Declarations */ -static const DECLARE_TLV_DB_SCALE(digital_tlv, -7650, 150, 1); -static const DECLARE_TLV_DB_SCALE(port_tlv, 0, 600, 0); +static const DECLARE_TLV_DB_SCALE(adc_dac_tlv, -7650, 150, 1); +static const DECLARE_TLV_DB_SCALE(mic_tlv, 0, 200, 1); +static const DECLARE_TLV_DB_SCALE(port_tlv, -1800, 600, 0); +static const DECLARE_TLV_DB_SCALE(stn_tlv, -7200, 150, 0); static const struct snd_kcontrol_new lm49453_sidetone_mixer_controls[] = { /* Sidetone supports mono only */ SOC_DAPM_SINGLE_TLV("Sidetone ADCL Volume", LM49453_P0_STN_VOL_ADCL_REG, - 0, 0x3F, 0, digital_tlv), + 0, 0x3F, 0, stn_tlv), SOC_DAPM_SINGLE_TLV("Sidetone ADCR Volume", LM49453_P0_STN_VOL_ADCR_REG, - 0, 0x3F, 0, digital_tlv), + 0, 0x3F, 0, stn_tlv), SOC_DAPM_SINGLE_TLV("Sidetone DMIC1L Volume", LM49453_P0_STN_VOL_DMIC1L_REG, - 0, 0x3F, 0, digital_tlv), + 0, 0x3F, 0, stn_tlv), SOC_DAPM_SINGLE_TLV("Sidetone DMIC1R Volume", LM49453_P0_STN_VOL_DMIC1R_REG, - 0, 0x3F, 0, digital_tlv), + 0, 0x3F, 0, stn_tlv), SOC_DAPM_SINGLE_TLV("Sidetone DMIC2L Volume", LM49453_P0_STN_VOL_DMIC2L_REG, - 0, 0x3F, 0, digital_tlv), + 0, 0x3F, 0, stn_tlv), SOC_DAPM_SINGLE_TLV("Sidetone DMIC2R Volume", LM49453_P0_STN_VOL_DMIC2R_REG, - 0, 0x3F, 0, digital_tlv), + 0, 0x3F, 0, stn_tlv), }; static const struct snd_kcontrol_new lm49453_snd_controls[] = { /* mic1 and mic2 supports mono only */ - SOC_SINGLE_TLV("Mic1 Volume", LM49453_P0_ADC_LEVELL_REG, 0, 6, - 0, digital_tlv), - SOC_SINGLE_TLV("Mic2 Volume", LM49453_P0_ADC_LEVELR_REG, 0, 6, - 0, digital_tlv), + SOC_SINGLE_TLV("Mic1 Volume", LM49453_P0_MICL_REG, 0, 15, 0, mic_tlv), + SOC_SINGLE_TLV("Mic2 Volume", LM49453_P0_MICR_REG, 0, 15, 0, mic_tlv), + + SOC_SINGLE_TLV("ADCL Volume", LM49453_P0_ADC_LEVELL_REG, 0, 63, + 0, adc_dac_tlv), + SOC_SINGLE_TLV("ADCR Volume", LM49453_P0_ADC_LEVELR_REG, 0, 63, + 0, adc_dac_tlv), SOC_DOUBLE_R_TLV("DMIC1 Volume", LM49453_P0_DMIC1_LEVELL_REG, - LM49453_P0_DMIC1_LEVELR_REG, 0, 6, 0, digital_tlv), + LM49453_P0_DMIC1_LEVELR_REG, 0, 63, 0, adc_dac_tlv), SOC_DOUBLE_R_TLV("DMIC2 Volume", LM49453_P0_DMIC2_LEVELL_REG, - LM49453_P0_DMIC2_LEVELR_REG, 0, 6, 0, digital_tlv), + LM49453_P0_DMIC2_LEVELR_REG, 0, 63, 0, adc_dac_tlv), SOC_DAPM_ENUM("Mic2Mode", lm49453_mic2mode_enum), SOC_DAPM_ENUM("DMIC12 SRC", lm49453_dmic12_cfg_enum), @@ -569,16 +543,16 @@ static const struct snd_kcontrol_new lm49453_snd_controls[] = { 2, 1, 0), SOC_DOUBLE_R_TLV("DAC HP Volume", LM49453_P0_DAC_HP_LEVELL_REG, - LM49453_P0_DAC_HP_LEVELR_REG, 0, 6, 0, digital_tlv), + LM49453_P0_DAC_HP_LEVELR_REG, 0, 63, 0, adc_dac_tlv), SOC_DOUBLE_R_TLV("DAC LO Volume", LM49453_P0_DAC_LO_LEVELL_REG, - LM49453_P0_DAC_LO_LEVELR_REG, 0, 6, 0, digital_tlv), + LM49453_P0_DAC_LO_LEVELR_REG, 0, 63, 0, adc_dac_tlv), SOC_DOUBLE_R_TLV("DAC LS Volume", LM49453_P0_DAC_LS_LEVELL_REG, - LM49453_P0_DAC_LS_LEVELR_REG, 0, 6, 0, digital_tlv), + LM49453_P0_DAC_LS_LEVELR_REG, 0, 63, 0, adc_dac_tlv), SOC_DOUBLE_R_TLV("DAC HA Volume", LM49453_P0_DAC_HA_LEVELL_REG, - LM49453_P0_DAC_HA_LEVELR_REG, 0, 6, 0, digital_tlv), + LM49453_P0_DAC_HA_LEVELR_REG, 0, 63, 0, adc_dac_tlv), SOC_SINGLE_TLV("EP Volume", LM49453_P0_DAC_LS_LEVELL_REG, - 0, 6, 0, digital_tlv), + 0, 63, 0, adc_dac_tlv), SOC_SINGLE_TLV("PORT1_1_RX_LVL Volume", LM49453_P0_PORT1_RX_LVL1_REG, 0, 3, 0, port_tlv), @@ -1218,7 +1192,7 @@ static int lm49453_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) } snd_soc_update_bits(codec, LM49453_P0_AUDIO_PORT1_BASIC_REG, - LM49453_AUDIO_PORT1_BASIC_FMT_MASK|BIT(1)|BIT(5), + LM49453_AUDIO_PORT1_BASIC_FMT_MASK|BIT(0)|BIT(5), (aif_val | mode | clk_phase)); snd_soc_write(codec, LM49453_P0_AUDIO_PORT1_RX_MSB_REG, clk_shift); @@ -1483,8 +1457,8 @@ static const struct regmap_config lm49453_regmap_config = { .cache_type = REGCACHE_RBTREE, }; -static __devinit int lm49453_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int lm49453_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) { struct lm49453_priv *lm49453; int ret = 0; @@ -1497,7 +1471,7 @@ static __devinit int lm49453_i2c_probe(struct i2c_client *i2c, i2c_set_clientdata(i2c, lm49453); - lm49453->regmap = regmap_init_i2c(i2c, &lm49453_regmap_config); + lm49453->regmap = devm_regmap_init_i2c(i2c, &lm49453_regmap_config); if (IS_ERR(lm49453->regmap)) { ret = PTR_ERR(lm49453->regmap); dev_err(&i2c->dev, "Failed to allocate register map: %d\n", @@ -1508,21 +1482,15 @@ static __devinit int lm49453_i2c_probe(struct i2c_client *i2c, ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_lm49453, lm49453_dai, ARRAY_SIZE(lm49453_dai)); - if (ret < 0) { + if (ret < 0) dev_err(&i2c->dev, "Failed to register codec: %d\n", ret); - regmap_exit(lm49453->regmap); - return ret; - } return ret; } -static int __devexit lm49453_i2c_remove(struct i2c_client *client) +static int lm49453_i2c_remove(struct i2c_client *client) { - struct lm49453_priv *lm49453 = i2c_get_clientdata(client); - snd_soc_unregister_codec(&client->dev); - regmap_exit(lm49453->regmap); return 0; } @@ -1538,7 +1506,7 @@ static struct i2c_driver lm49453_i2c_driver = { .owner = THIS_MODULE, }, .probe = lm49453_i2c_probe, - .remove = __devexit_p(lm49453_i2c_remove), + .remove = lm49453_i2c_remove, .id_table = lm49453_i2c_id, }; diff --git a/sound/soc/codecs/max9768.c b/sound/soc/codecs/max9768.c index 17b3ec2d05cb..a6ac2313047d 100644 --- a/sound/soc/codecs/max9768.c +++ b/sound/soc/codecs/max9768.c @@ -159,8 +159,8 @@ static const struct regmap_config max9768_i2c_regmap_config = { .cache_type = REGCACHE_RBTREE, }; -static int __devinit max9768_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int max9768_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct max9768 *max9768; struct max9768_pdata *pdata = client->dev.platform_data; @@ -187,7 +187,7 @@ static int __devinit max9768_i2c_probe(struct i2c_client *client, i2c_set_clientdata(client, max9768); - max9768->regmap = regmap_init_i2c(client, &max9768_i2c_regmap_config); + max9768->regmap = devm_regmap_init_i2c(client, &max9768_i2c_regmap_config); if (IS_ERR(max9768->regmap)) { err = PTR_ERR(max9768->regmap); goto err_gpio_free; @@ -195,12 +195,10 @@ static int __devinit max9768_i2c_probe(struct i2c_client *client, err = snd_soc_register_codec(&client->dev, &max9768_codec_driver, NULL, 0); if (err) - goto err_regmap_free; + goto err_gpio_free; return 0; - err_regmap_free: - regmap_exit(max9768->regmap); err_gpio_free: if (gpio_is_valid(max9768->shdn_gpio)) gpio_free(max9768->shdn_gpio); @@ -210,12 +208,11 @@ static int __devinit max9768_i2c_probe(struct i2c_client *client, return err; } -static int __devexit max9768_i2c_remove(struct i2c_client *client) +static int max9768_i2c_remove(struct i2c_client *client) { struct max9768 *max9768 = i2c_get_clientdata(client); snd_soc_unregister_codec(&client->dev); - regmap_exit(max9768->regmap); if (gpio_is_valid(max9768->shdn_gpio)) gpio_free(max9768->shdn_gpio); @@ -237,7 +234,7 @@ static struct i2c_driver max9768_i2c_driver = { .owner = THIS_MODULE, }, .probe = max9768_i2c_probe, - .remove = __devexit_p(max9768_i2c_remove), + .remove = max9768_i2c_remove, .id_table = max9768_i2c_id, }; module_i2c_driver(max9768_i2c_driver); diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c index 3264a5169306..a4c16fd70f77 100644 --- a/sound/soc/codecs/max98088.c +++ b/sound/soc/codecs/max98088.c @@ -2084,7 +2084,7 @@ static int max98088_i2c_probe(struct i2c_client *i2c, return ret; } -static int __devexit max98088_i2c_remove(struct i2c_client *client) +static int max98088_i2c_remove(struct i2c_client *client) { snd_soc_unregister_codec(&client->dev); return 0; @@ -2098,13 +2098,13 @@ static const struct i2c_device_id max98088_i2c_id[] = { MODULE_DEVICE_TABLE(i2c, max98088_i2c_id); static struct i2c_driver max98088_i2c_driver = { - .driver = { - .name = "max98088", - .owner = THIS_MODULE, - }, - .probe = max98088_i2c_probe, - .remove = __devexit_p(max98088_i2c_remove), - .id_table = max98088_i2c_id, + .driver = { + .name = "max98088", + .owner = THIS_MODULE, + }, + .probe = max98088_i2c_probe, + .remove = max98088_i2c_remove, + .id_table = max98088_i2c_id, }; module_i2c_driver(max98088_i2c_driver); diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c new file mode 100644 index 000000000000..c9772ca3da4f --- /dev/null +++ b/sound/soc/codecs/max98090.c @@ -0,0 +1,577 @@ +/* + * max98090.c -- MAX98090 ALSA SoC Audio driver + * based on Rev0p8 datasheet + * + * Copyright (C) 2012 Renesas Solutions Corp. + * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> + * + * Based on + * + * max98095.c + * Copyright 2011 Maxim Integrated Products + * + * https://github.com/hardkernel/linux/commit/\ + * 3417d7166b17113b3b33b0a337c74d1c7cc313df#sound/soc/codecs/max98090.c + * Copyright 2011 Maxim Integrated Products + * + * 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/i2c.h> +#include <linux/module.h> +#include <linux/regmap.h> +#include <sound/soc.h> +#include <sound/tlv.h> + +/* + * + * MAX98090 Registers Definition + * + */ + +/* RESET / STATUS / INTERRUPT REGISTERS */ +#define MAX98090_0x00_SW_RESET 0x00 +#define MAX98090_0x01_INT_STS 0x01 +#define MAX98090_0x02_JACK_STS 0x02 +#define MAX98090_0x03_INT_MASK 0x03 + +/* QUICK SETUP REGISTERS */ +#define MAX98090_0x04_SYS_CLK 0x04 +#define MAX98090_0x05_SAMPLE_RATE 0x05 +#define MAX98090_0x06_DAI_IF 0x06 +#define MAX98090_0x07_DAC_PATH 0x07 +#define MAX98090_0x08_MIC_TO_ADC 0x08 +#define MAX98090_0x09_LINE_TO_ADC 0x09 +#define MAX98090_0x0A_ANALOG_MIC_LOOP 0x0A +#define MAX98090_0x0B_ANALOG_LINE_LOOP 0x0B + +/* ANALOG INPUT CONFIGURATION REGISTERS */ +#define MAX98090_0x0D_INPUT_CONFIG 0x0D +#define MAX98090_0x0E_LINE_IN_LVL 0x0E +#define MAX98090_0x0F_LINI_IN_CFG 0x0F +#define MAX98090_0x10_MIC1_IN_LVL 0x10 +#define MAX98090_0x11_MIC2_IN_LVL 0x11 + +/* MICROPHONE CONFIGURATION REGISTERS */ +#define MAX98090_0x12_MIC_BIAS_VOL 0x12 +#define MAX98090_0x13_DIGITAL_MIC_CFG 0x13 +#define MAX98090_0x14_DIGITAL_MIC_MODE 0x14 + +/* ADC PATH AND CONFIGURATION REGISTERS */ +#define MAX98090_0x15_L_ADC_MIX 0x15 +#define MAX98090_0x16_R_ADC_MIX 0x16 +#define MAX98090_0x17_L_ADC_LVL 0x17 +#define MAX98090_0x18_R_ADC_LVL 0x18 +#define MAX98090_0x19_ADC_BIQUAD_LVL 0x19 +#define MAX98090_0x1A_ADC_SIDETONE 0x1A + +/* CLOCK CONFIGURATION REGISTERS */ +#define MAX98090_0x1B_SYS_CLK 0x1B +#define MAX98090_0x1C_CLK_MODE 0x1C +#define MAX98090_0x1D_ANY_CLK1 0x1D +#define MAX98090_0x1E_ANY_CLK2 0x1E +#define MAX98090_0x1F_ANY_CLK3 0x1F +#define MAX98090_0x20_ANY_CLK4 0x20 +#define MAX98090_0x21_MASTER_MODE 0x21 + +/* INTERFACE CONTROL REGISTERS */ +#define MAX98090_0x22_DAI_IF_FMT 0x22 +#define MAX98090_0x23_DAI_TDM_FMT1 0x23 +#define MAX98090_0x24_DAI_TDM_FMT2 0x24 +#define MAX98090_0x25_DAI_IO_CFG 0x25 +#define MAX98090_0x26_FILTER_CFG 0x26 +#define MAX98090_0x27_DAI_PLAYBACK_LVL 0x27 +#define MAX98090_0x28_EQ_PLAYBACK_LVL 0x28 + +/* HEADPHONE CONTROL REGISTERS */ +#define MAX98090_0x29_L_HP_MIX 0x29 +#define MAX98090_0x2A_R_HP_MIX 0x2A +#define MAX98090_0x2B_HP_CTR 0x2B +#define MAX98090_0x2C_L_HP_VOL 0x2C +#define MAX98090_0x2D_R_HP_VOL 0x2D + +/* SPEAKER CONFIGURATION REGISTERS */ +#define MAX98090_0x2E_L_SPK_MIX 0x2E +#define MAX98090_0x2F_R_SPK_MIX 0x2F +#define MAX98090_0x30_SPK_CTR 0x30 +#define MAX98090_0x31_L_SPK_VOL 0x31 +#define MAX98090_0x32_R_SPK_VOL 0x32 + +/* ALC CONFIGURATION REGISTERS */ +#define MAX98090_0x33_ALC_TIMING 0x33 +#define MAX98090_0x34_ALC_COMPRESSOR 0x34 +#define MAX98090_0x35_ALC_EXPANDER 0x35 +#define MAX98090_0x36_ALC_GAIN 0x36 + +/* RECEIVER AND LINE_OUTPUT REGISTERS */ +#define MAX98090_0x37_RCV_LOUT_L_MIX 0x37 +#define MAX98090_0x38_RCV_LOUT_L_CNTL 0x38 +#define MAX98090_0x39_RCV_LOUT_L_VOL 0x39 +#define MAX98090_0x3A_LOUT_R_MIX 0x3A +#define MAX98090_0x3B_LOUT_R_CNTL 0x3B +#define MAX98090_0x3C_LOUT_R_VOL 0x3C + +/* JACK DETECT AND ENABLE REGISTERS */ +#define MAX98090_0x3D_JACK_DETECT 0x3D +#define MAX98090_0x3E_IN_ENABLE 0x3E +#define MAX98090_0x3F_OUT_ENABLE 0x3F +#define MAX98090_0x40_LVL_CTR 0x40 +#define MAX98090_0x41_DSP_FILTER_ENABLE 0x41 + +/* BIAS AND POWER MODE CONFIGURATION REGISTERS */ +#define MAX98090_0x42_BIAS_CTR 0x42 +#define MAX98090_0x43_DAC_CTR 0x43 +#define MAX98090_0x44_ADC_CTR 0x44 +#define MAX98090_0x45_DEV_SHUTDOWN 0x45 + +/* REVISION ID REGISTER */ +#define MAX98090_0xFF_REV_ID 0xFF + +#define MAX98090_REG_MAX_CACHED 0x45 +#define MAX98090_REG_END 0xFF + +/* + * + * MAX98090 Registers Bit Fields + * + */ + +/* MAX98090_0x06_DAI_IF */ +#define MAX98090_DAI_IF_MASK 0x3F +#define MAX98090_RJ_M (1 << 5) +#define MAX98090_RJ_S (1 << 4) +#define MAX98090_LJ_M (1 << 3) +#define MAX98090_LJ_S (1 << 2) +#define MAX98090_I2S_M (1 << 1) +#define MAX98090_I2S_S (1 << 0) + +/* MAX98090_0x45_DEV_SHUTDOWN */ +#define MAX98090_SHDNRUN (1 << 7) + +/* codec private data */ +struct max98090_priv { + struct regmap *regmap; +}; + +static const struct reg_default max98090_reg_defaults[] = { + /* RESET / STATUS / INTERRUPT REGISTERS */ + {MAX98090_0x00_SW_RESET, 0x00}, + {MAX98090_0x01_INT_STS, 0x00}, + {MAX98090_0x02_JACK_STS, 0x00}, + {MAX98090_0x03_INT_MASK, 0x04}, + + /* QUICK SETUP REGISTERS */ + {MAX98090_0x04_SYS_CLK, 0x00}, + {MAX98090_0x05_SAMPLE_RATE, 0x00}, + {MAX98090_0x06_DAI_IF, 0x00}, + {MAX98090_0x07_DAC_PATH, 0x00}, + {MAX98090_0x08_MIC_TO_ADC, 0x00}, + {MAX98090_0x09_LINE_TO_ADC, 0x00}, + {MAX98090_0x0A_ANALOG_MIC_LOOP, 0x00}, + {MAX98090_0x0B_ANALOG_LINE_LOOP, 0x00}, + + /* ANALOG INPUT CONFIGURATION REGISTERS */ + {MAX98090_0x0D_INPUT_CONFIG, 0x00}, + {MAX98090_0x0E_LINE_IN_LVL, 0x1B}, + {MAX98090_0x0F_LINI_IN_CFG, 0x00}, + {MAX98090_0x10_MIC1_IN_LVL, 0x11}, + {MAX98090_0x11_MIC2_IN_LVL, 0x11}, + + /* MICROPHONE CONFIGURATION REGISTERS */ + {MAX98090_0x12_MIC_BIAS_VOL, 0x00}, + {MAX98090_0x13_DIGITAL_MIC_CFG, 0x00}, + {MAX98090_0x14_DIGITAL_MIC_MODE, 0x00}, + + /* ADC PATH AND CONFIGURATION REGISTERS */ + {MAX98090_0x15_L_ADC_MIX, 0x00}, + {MAX98090_0x16_R_ADC_MIX, 0x00}, + {MAX98090_0x17_L_ADC_LVL, 0x03}, + {MAX98090_0x18_R_ADC_LVL, 0x03}, + {MAX98090_0x19_ADC_BIQUAD_LVL, 0x00}, + {MAX98090_0x1A_ADC_SIDETONE, 0x00}, + + /* CLOCK CONFIGURATION REGISTERS */ + {MAX98090_0x1B_SYS_CLK, 0x00}, + {MAX98090_0x1C_CLK_MODE, 0x00}, + {MAX98090_0x1D_ANY_CLK1, 0x00}, + {MAX98090_0x1E_ANY_CLK2, 0x00}, + {MAX98090_0x1F_ANY_CLK3, 0x00}, + {MAX98090_0x20_ANY_CLK4, 0x00}, + {MAX98090_0x21_MASTER_MODE, 0x00}, + + /* INTERFACE CONTROL REGISTERS */ + {MAX98090_0x22_DAI_IF_FMT, 0x00}, + {MAX98090_0x23_DAI_TDM_FMT1, 0x00}, + {MAX98090_0x24_DAI_TDM_FMT2, 0x00}, + {MAX98090_0x25_DAI_IO_CFG, 0x00}, + {MAX98090_0x26_FILTER_CFG, 0x80}, + {MAX98090_0x27_DAI_PLAYBACK_LVL, 0x00}, + {MAX98090_0x28_EQ_PLAYBACK_LVL, 0x00}, + + /* HEADPHONE CONTROL REGISTERS */ + {MAX98090_0x29_L_HP_MIX, 0x00}, + {MAX98090_0x2A_R_HP_MIX, 0x00}, + {MAX98090_0x2B_HP_CTR, 0x00}, + {MAX98090_0x2C_L_HP_VOL, 0x1A}, + {MAX98090_0x2D_R_HP_VOL, 0x1A}, + + /* SPEAKER CONFIGURATION REGISTERS */ + {MAX98090_0x2E_L_SPK_MIX, 0x00}, + {MAX98090_0x2F_R_SPK_MIX, 0x00}, + {MAX98090_0x30_SPK_CTR, 0x00}, + {MAX98090_0x31_L_SPK_VOL, 0x2C}, + {MAX98090_0x32_R_SPK_VOL, 0x2C}, + + /* ALC CONFIGURATION REGISTERS */ + {MAX98090_0x33_ALC_TIMING, 0x00}, + {MAX98090_0x34_ALC_COMPRESSOR, 0x00}, + {MAX98090_0x35_ALC_EXPANDER, 0x00}, + {MAX98090_0x36_ALC_GAIN, 0x00}, + + /* RECEIVER AND LINE_OUTPUT REGISTERS */ + {MAX98090_0x37_RCV_LOUT_L_MIX, 0x00}, + {MAX98090_0x38_RCV_LOUT_L_CNTL, 0x00}, + {MAX98090_0x39_RCV_LOUT_L_VOL, 0x15}, + {MAX98090_0x3A_LOUT_R_MIX, 0x00}, + {MAX98090_0x3B_LOUT_R_CNTL, 0x00}, + {MAX98090_0x3C_LOUT_R_VOL, 0x15}, + + /* JACK DETECT AND ENABLE REGISTERS */ + {MAX98090_0x3D_JACK_DETECT, 0x00}, + {MAX98090_0x3E_IN_ENABLE, 0x00}, + {MAX98090_0x3F_OUT_ENABLE, 0x00}, + {MAX98090_0x40_LVL_CTR, 0x00}, + {MAX98090_0x41_DSP_FILTER_ENABLE, 0x00}, + + /* BIAS AND POWER MODE CONFIGURATION REGISTERS */ + {MAX98090_0x42_BIAS_CTR, 0x00}, + {MAX98090_0x43_DAC_CTR, 0x00}, + {MAX98090_0x44_ADC_CTR, 0x06}, + {MAX98090_0x45_DEV_SHUTDOWN, 0x00}, +}; + +static const unsigned int max98090_hp_tlv[] = { + TLV_DB_RANGE_HEAD(5), + 0x0, 0x6, TLV_DB_SCALE_ITEM(-6700, 400, 0), + 0x7, 0xE, TLV_DB_SCALE_ITEM(-4000, 300, 0), + 0xF, 0x15, TLV_DB_SCALE_ITEM(-1700, 200, 0), + 0x16, 0x1B, TLV_DB_SCALE_ITEM(-400, 100, 0), + 0x1C, 0x1F, TLV_DB_SCALE_ITEM(150, 50, 0), +}; + +static struct snd_kcontrol_new max98090_snd_controls[] = { + SOC_DOUBLE_R_TLV("Headphone Volume", MAX98090_0x2C_L_HP_VOL, + MAX98090_0x2D_R_HP_VOL, 0, 31, 0, max98090_hp_tlv), +}; + +/* Left HeadPhone Mixer Switch */ +static struct snd_kcontrol_new max98090_left_hp_mixer_controls[] = { + SOC_DAPM_SINGLE("DACR Switch", MAX98090_0x29_L_HP_MIX, 1, 1, 0), + SOC_DAPM_SINGLE("DACL Switch", MAX98090_0x29_L_HP_MIX, 0, 1, 0), +}; + +/* Right HeadPhone Mixer Switch */ +static struct snd_kcontrol_new max98090_right_hp_mixer_controls[] = { + SOC_DAPM_SINGLE("DACR Switch", MAX98090_0x2A_R_HP_MIX, 1, 1, 0), + SOC_DAPM_SINGLE("DACL Switch", MAX98090_0x2A_R_HP_MIX, 0, 1, 0), +}; + +static struct snd_soc_dapm_widget max98090_dapm_widgets[] = { + /* Output */ + SND_SOC_DAPM_OUTPUT("HPL"), + SND_SOC_DAPM_OUTPUT("HPR"), + + /* PGA */ + SND_SOC_DAPM_PGA("HPL Out", MAX98090_0x3F_OUT_ENABLE, 7, 0, NULL, 0), + SND_SOC_DAPM_PGA("HPR Out", MAX98090_0x3F_OUT_ENABLE, 6, 0, NULL, 0), + + /* Mixer */ + SND_SOC_DAPM_MIXER("HPL Mixer", SND_SOC_NOPM, 0, 0, + max98090_left_hp_mixer_controls, + ARRAY_SIZE(max98090_left_hp_mixer_controls)), + + SND_SOC_DAPM_MIXER("HPR Mixer", SND_SOC_NOPM, 0, 0, + max98090_right_hp_mixer_controls, + ARRAY_SIZE(max98090_right_hp_mixer_controls)), + + /* DAC */ + SND_SOC_DAPM_DAC("DACL", "Hifi Playback", MAX98090_0x3F_OUT_ENABLE, 0, 0), + SND_SOC_DAPM_DAC("DACR", "Hifi Playback", MAX98090_0x3F_OUT_ENABLE, 1, 0), +}; + +static struct snd_soc_dapm_route max98090_audio_map[] = { + /* Output */ + {"HPL", NULL, "HPL Out"}, + {"HPR", NULL, "HPR Out"}, + + /* PGA */ + {"HPL Out", NULL, "HPL Mixer"}, + {"HPR Out", NULL, "HPR Mixer"}, + + /* Mixer*/ + {"HPL Mixer", "DACR Switch", "DACR"}, + {"HPL Mixer", "DACL Switch", "DACL"}, + + {"HPR Mixer", "DACR Switch", "DACR"}, + {"HPR Mixer", "DACL Switch", "DACL"}, +}; + +static bool max98090_volatile(struct device *dev, unsigned int reg) +{ + if ((reg == MAX98090_0x01_INT_STS) || + (reg == MAX98090_0x02_JACK_STS) || + (reg > MAX98090_REG_MAX_CACHED)) + return true; + + return false; +} + +static int max98090_dai_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; + unsigned int val; + + switch (params_rate(params)) { + case 96000: + val = 1 << 5; + break; + case 32000: + val = 1 << 4; + break; + case 48000: + val = 1 << 3; + break; + case 44100: + val = 1 << 2; + break; + case 16000: + val = 1 << 1; + break; + case 8000: + val = 1 << 0; + break; + default: + dev_err(codec->dev, "unsupported rate\n"); + return -EINVAL; + } + snd_soc_update_bits(codec, MAX98090_0x05_SAMPLE_RATE, 0x03F, val); + + return 0; +} + +static int max98090_dai_set_sysclk(struct snd_soc_dai *dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = dai->codec; + unsigned int val; + + snd_soc_update_bits(codec, MAX98090_0x45_DEV_SHUTDOWN, + MAX98090_SHDNRUN, 0); + + switch (freq) { + case 26000000: + val = 1 << 7; + break; + case 19200000: + val = 1 << 6; + break; + case 13000000: + val = 1 << 5; + break; + case 12288000: + val = 1 << 4; + break; + case 12000000: + val = 1 << 3; + break; + case 11289600: + val = 1 << 2; + break; + default: + dev_err(codec->dev, "Invalid master clock frequency\n"); + return -EINVAL; + } + snd_soc_update_bits(codec, MAX98090_0x04_SYS_CLK, 0xFD, val); + + snd_soc_update_bits(codec, MAX98090_0x45_DEV_SHUTDOWN, + MAX98090_SHDNRUN, MAX98090_SHDNRUN); + + dev_dbg(dai->dev, "sysclk is %uHz\n", freq); + + return 0; +} + +static int max98090_dai_set_fmt(struct snd_soc_dai *dai, + unsigned int fmt) +{ + struct snd_soc_codec *codec = dai->codec; + int is_master; + u8 val; + + /* master/slave mode */ + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + is_master = 1; + break; + case SND_SOC_DAIFMT_CBS_CFS: + is_master = 0; + break; + default: + dev_err(codec->dev, "unsupported clock\n"); + return -EINVAL; + } + + /* format */ + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_I2S: + val = (is_master) ? MAX98090_I2S_M : MAX98090_I2S_S; + break; + case SND_SOC_DAIFMT_RIGHT_J: + val = (is_master) ? MAX98090_RJ_M : MAX98090_RJ_S; + break; + case SND_SOC_DAIFMT_LEFT_J: + val = (is_master) ? MAX98090_LJ_M : MAX98090_LJ_S; + break; + default: + dev_err(codec->dev, "unsupported format\n"); + return -EINVAL; + } + snd_soc_update_bits(codec, MAX98090_0x06_DAI_IF, + MAX98090_DAI_IF_MASK, val); + + return 0; +} + +#define MAX98090_RATES SNDRV_PCM_RATE_8000_96000 +#define MAX98090_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE) + +static struct snd_soc_dai_ops max98090_dai_ops = { + .set_sysclk = max98090_dai_set_sysclk, + .set_fmt = max98090_dai_set_fmt, + .hw_params = max98090_dai_hw_params, +}; + +static struct snd_soc_dai_driver max98090_dai = { + .name = "max98090-Hifi", + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 2, + .rates = MAX98090_RATES, + .formats = MAX98090_FORMATS, + }, + .ops = &max98090_dai_ops, +}; + +static int max98090_probe(struct snd_soc_codec *codec) +{ + struct max98090_priv *priv = snd_soc_codec_get_drvdata(codec); + struct device *dev = codec->dev; + int ret; + + codec->control_data = priv->regmap; + ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP); + if (ret < 0) { + dev_err(dev, "Failed to set cache I/O: %d\n", ret); + return ret; + } + + /* Device active */ + snd_soc_update_bits(codec, MAX98090_0x45_DEV_SHUTDOWN, + MAX98090_SHDNRUN, MAX98090_SHDNRUN); + + return 0; +} + +static int max98090_remove(struct snd_soc_codec *codec) +{ + return 0; +} + +static struct snd_soc_codec_driver soc_codec_dev_max98090 = { + .probe = max98090_probe, + .remove = max98090_remove, + .controls = max98090_snd_controls, + .num_controls = ARRAY_SIZE(max98090_snd_controls), + .dapm_widgets = max98090_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(max98090_dapm_widgets), + .dapm_routes = max98090_audio_map, + .num_dapm_routes = ARRAY_SIZE(max98090_audio_map), +}; + +static const struct regmap_config max98090_regmap = { + .reg_bits = 8, + .val_bits = 8, + .max_register = MAX98090_REG_END, + .volatile_reg = max98090_volatile, + .cache_type = REGCACHE_RBTREE, + .reg_defaults = max98090_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(max98090_reg_defaults), +}; + +static int max98090_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct max98090_priv *priv; + struct device *dev = &i2c->dev; + unsigned int val; + int ret; + + priv = devm_kzalloc(dev, sizeof(struct max98090_priv), + GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->regmap = devm_regmap_init_i2c(i2c, &max98090_regmap); + if (IS_ERR(priv->regmap)) { + ret = PTR_ERR(priv->regmap); + dev_err(dev, "Failed to init regmap: %d\n", ret); + return ret; + } + + i2c_set_clientdata(i2c, priv); + + ret = regmap_read(priv->regmap, MAX98090_0xFF_REV_ID, &val); + if (ret < 0) { + dev_err(dev, "Failed to read device revision: %d\n", ret); + return ret; + } + dev_info(dev, "revision 0x%02x\n", val); + + ret = snd_soc_register_codec(dev, + &soc_codec_dev_max98090, + &max98090_dai, 1); + + return ret; +} + +static int max98090_i2c_remove(struct i2c_client *client) +{ + snd_soc_unregister_codec(&client->dev); + return 0; +} + +static const struct i2c_device_id max98090_i2c_id[] = { + { "max98090", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, max98090_i2c_id); + +static struct i2c_driver max98090_i2c_driver = { + .driver = { + .name = "max98090", + .owner = THIS_MODULE, + }, + .probe = max98090_i2c_probe, + .remove = max98090_i2c_remove, + .id_table = max98090_i2c_id, +}; +module_i2c_driver(max98090_i2c_driver); + +MODULE_DESCRIPTION("ALSA SoC MAX98090 driver"); +MODULE_AUTHOR("Peter Hsiang, Kuninori Morimoto"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/max98095.c b/sound/soc/codecs/max98095.c index 38d43c59d3f4..41cdd1642970 100644 --- a/sound/soc/codecs/max98095.c +++ b/sound/soc/codecs/max98095.c @@ -2511,7 +2511,7 @@ static int max98095_i2c_probe(struct i2c_client *i2c, return ret; } -static int __devexit max98095_i2c_remove(struct i2c_client *client) +static int max98095_i2c_remove(struct i2c_client *client) { snd_soc_unregister_codec(&client->dev); return 0; @@ -2529,7 +2529,7 @@ static struct i2c_driver max98095_i2c_driver = { .owner = THIS_MODULE, }, .probe = max98095_i2c_probe, - .remove = __devexit_p(max98095_i2c_remove), + .remove = max98095_i2c_remove, .id_table = max98095_i2c_id, }; diff --git a/sound/soc/codecs/max9850.c b/sound/soc/codecs/max9850.c index efe535c37b39..58c38a5b481c 100644 --- a/sound/soc/codecs/max9850.c +++ b/sound/soc/codecs/max9850.c @@ -329,8 +329,8 @@ static struct snd_soc_codec_driver soc_codec_dev_max9850 = { .num_dapm_routes = ARRAY_SIZE(max9850_dapm_routes), }; -static int __devinit max9850_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int max9850_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) { struct max9850_priv *max9850; int ret; @@ -347,7 +347,7 @@ static int __devinit max9850_i2c_probe(struct i2c_client *i2c, return ret; } -static __devexit int max9850_i2c_remove(struct i2c_client *client) +static int max9850_i2c_remove(struct i2c_client *client) { snd_soc_unregister_codec(&client->dev); return 0; @@ -365,7 +365,7 @@ static struct i2c_driver max9850_i2c_driver = { .owner = THIS_MODULE, }, .probe = max9850_i2c_probe, - .remove = __devexit_p(max9850_i2c_remove), + .remove = max9850_i2c_remove, .id_table = max9850_i2c_id, }; diff --git a/sound/soc/codecs/max9877.c b/sound/soc/codecs/max9877.c index d15e5943c85e..6b6c74cd83e2 100644 --- a/sound/soc/codecs/max9877.c +++ b/sound/soc/codecs/max9877.c @@ -258,8 +258,8 @@ int max9877_add_controls(struct snd_soc_codec *codec) } EXPORT_SYMBOL_GPL(max9877_add_controls); -static int __devinit max9877_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int max9877_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) { i2c = client; @@ -268,7 +268,7 @@ static int __devinit max9877_i2c_probe(struct i2c_client *client, return 0; } -static __devexit int max9877_i2c_remove(struct i2c_client *client) +static int max9877_i2c_remove(struct i2c_client *client) { i2c = NULL; @@ -287,7 +287,7 @@ static struct i2c_driver max9877_i2c_driver = { .owner = THIS_MODULE, }, .probe = max9877_i2c_probe, - .remove = __devexit_p(max9877_i2c_remove), + .remove = max9877_i2c_remove, .id_table = max9877_i2c_id, }; diff --git a/sound/soc/codecs/mc13783.c b/sound/soc/codecs/mc13783.c index bc955999c8aa..5402dfbbb716 100644 --- a/sound/soc/codecs/mc13783.c +++ b/sound/soc/codecs/mc13783.c @@ -779,7 +779,7 @@ static struct platform_driver mc13783_codec_driver = { .owner = THIS_MODULE, }, .probe = mc13783_codec_probe, - .remove = __devexit_p(mc13783_codec_remove), + .remove = mc13783_codec_remove, }; module_platform_driver(mc13783_codec_driver); diff --git a/sound/soc/codecs/ml26124.c b/sound/soc/codecs/ml26124.c index 96aa5fa05160..26118828782b 100644 --- a/sound/soc/codecs/ml26124.c +++ b/sound/soc/codecs/ml26124.c @@ -626,8 +626,8 @@ static const struct regmap_config ml26124_i2c_regmap = { .write_flag_mask = 0x01, }; -static __devinit int ml26124_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int ml26124_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) { struct ml26124_priv *priv; int ret; @@ -649,7 +649,7 @@ static __devinit int ml26124_i2c_probe(struct i2c_client *i2c, &soc_codec_dev_ml26124, &ml26124_dai, 1); } -static __devexit int ml26124_i2c_remove(struct i2c_client *client) +static int ml26124_i2c_remove(struct i2c_client *client) { snd_soc_unregister_codec(&client->dev); return 0; @@ -667,7 +667,7 @@ static struct i2c_driver ml26124_i2c_driver = { .owner = THIS_MODULE, }, .probe = ml26124_i2c_probe, - .remove = __devexit_p(ml26124_i2c_remove), + .remove = ml26124_i2c_remove, .id_table = ml26124_i2c_id, }; diff --git a/sound/soc/codecs/omap-hdmi.c b/sound/soc/codecs/omap-hdmi.c index 1bf5c74f5f96..529d06444c54 100644 --- a/sound/soc/codecs/omap-hdmi.c +++ b/sound/soc/codecs/omap-hdmi.c @@ -39,13 +39,13 @@ static struct snd_soc_dai_driver omap_hdmi_codec_dai = { }, }; -static __devinit int omap_hdmi_codec_probe(struct platform_device *pdev) +static int omap_hdmi_codec_probe(struct platform_device *pdev) { return snd_soc_register_codec(&pdev->dev, &omap_hdmi_codec, &omap_hdmi_codec_dai, 1); } -static __devexit int omap_hdmi_codec_remove(struct platform_device *pdev) +static int omap_hdmi_codec_remove(struct platform_device *pdev) { snd_soc_unregister_codec(&pdev->dev); return 0; @@ -58,7 +58,7 @@ static struct platform_driver omap_hdmi_codec_driver = { }, .probe = omap_hdmi_codec_probe, - .remove = __devexit_p(omap_hdmi_codec_remove), + .remove = omap_hdmi_codec_remove, }; module_platform_driver(omap_hdmi_codec_driver); diff --git a/sound/soc/codecs/pcm3008.c b/sound/soc/codecs/pcm3008.c index edcaa7ea5487..f2a6282b41f4 100644 --- a/sound/soc/codecs/pcm3008.c +++ b/sound/soc/codecs/pcm3008.c @@ -149,13 +149,13 @@ static struct snd_soc_codec_driver soc_codec_dev_pcm3008 = { .resume = pcm3008_soc_resume, }; -static int __devinit pcm3008_codec_probe(struct platform_device *pdev) +static int pcm3008_codec_probe(struct platform_device *pdev) { return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_pcm3008, &pcm3008_dai, 1); } -static int __devexit pcm3008_codec_remove(struct platform_device *pdev) +static int pcm3008_codec_remove(struct platform_device *pdev) { snd_soc_unregister_codec(&pdev->dev); return 0; @@ -165,7 +165,7 @@ MODULE_ALIAS("platform:pcm3008-codec"); static struct platform_driver pcm3008_codec_driver = { .probe = pcm3008_codec_probe, - .remove = __devexit_p(pcm3008_codec_remove), + .remove = pcm3008_codec_remove, .driver = { .name = "pcm3008-codec", .owner = THIS_MODULE, diff --git a/sound/soc/codecs/rt5631.c b/sound/soc/codecs/rt5631.c index 960d0e93cce9..912c9cbc2724 100644 --- a/sound/soc/codecs/rt5631.c +++ b/sound/soc/codecs/rt5631.c @@ -1382,7 +1382,7 @@ static int rt5631_hifi_pcm_params(struct snd_pcm_substream *substream, timesofbclk); if (coeff < 0) { dev_err(codec->dev, "Fail to get coeff\n"); - return -EINVAL; + return coeff; } switch (params_format(params)) { @@ -1748,7 +1748,7 @@ static int rt5631_i2c_probe(struct i2c_client *i2c, return ret; } -static __devexit int rt5631_i2c_remove(struct i2c_client *client) +static int rt5631_i2c_remove(struct i2c_client *client) { snd_soc_unregister_codec(&client->dev); return 0; @@ -1760,7 +1760,7 @@ static struct i2c_driver rt5631_i2c_driver = { .owner = THIS_MODULE, }, .probe = rt5631_i2c_probe, - .remove = __devexit_p(rt5631_i2c_remove), + .remove = rt5631_i2c_remove, .id_table = rt5631_i2c_id, }; diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c index df2f99d1d428..92bbfec9b107 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c @@ -401,7 +401,7 @@ static const struct snd_kcontrol_new sgtl5000_snd_controls[] = { 5, 1, 0), SOC_SINGLE_TLV("Mic Volume", SGTL5000_CHIP_MIC_CTRL, - 0, 4, 0, mic_gain_tlv), + 0, 3, 0, mic_gain_tlv), }; /* mute the codec used by alsa core */ @@ -1344,7 +1344,7 @@ static int sgtl5000_probe(struct snd_soc_codec *codec) SGTL5000_HP_ZCD_EN | SGTL5000_ADC_ZCD_EN); - snd_soc_write(codec, SGTL5000_CHIP_MIC_CTRL, 0); + snd_soc_write(codec, SGTL5000_CHIP_MIC_CTRL, 2); /* * disable DAP @@ -1404,8 +1404,8 @@ static struct snd_soc_codec_driver sgtl5000_driver = { .num_dapm_routes = ARRAY_SIZE(sgtl5000_dapm_routes), }; -static __devinit int sgtl5000_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int sgtl5000_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct sgtl5000_priv *sgtl5000; int ret; @@ -1422,7 +1422,7 @@ static __devinit int sgtl5000_i2c_probe(struct i2c_client *client, return ret; } -static __devexit int sgtl5000_i2c_remove(struct i2c_client *client) +static int sgtl5000_i2c_remove(struct i2c_client *client) { snd_soc_unregister_codec(&client->dev); @@ -1449,7 +1449,7 @@ static struct i2c_driver sgtl5000_i2c_driver = { .of_match_table = sgtl5000_dt_ids, }, .probe = sgtl5000_i2c_probe, - .remove = __devexit_p(sgtl5000_i2c_remove), + .remove = sgtl5000_i2c_remove, .id_table = sgtl5000_id, }; diff --git a/sound/soc/codecs/si476x.c b/sound/soc/codecs/si476x.c new file mode 100644 index 000000000000..f2d61a187830 --- /dev/null +++ b/sound/soc/codecs/si476x.c @@ -0,0 +1,255 @@ +#include <linux/module.h> +#include <linux/slab.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/initval.h> + +#include <linux/i2c.h> + +#include <linux/mfd/si476x-core.h> + +enum si476x_audio_registers { + SI476X_DIGITAL_IO_OUTPUT_FORMAT = 0x0203, + SI476X_DIGITAL_IO_OUTPUT_SAMPLE_RATE = 0x0202, +}; + +enum si476x_digital_io_output_format { + SI476X_DIGITAL_IO_SLOT_SIZE_SHIFT = 11, + SI476X_DIGITAL_IO_SAMPLE_SIZE_SHIFT = 8, +}; + +#define SI476X_DIGITAL_IO_OUTPUT_WIDTH_MASK ((0b111 << SI476X_DIGITAL_IO_SLOT_SIZE_SHIFT) | \ + (0b111 << SI476X_DIGITAL_IO_SAMPLE_SIZE_SHIFT)) +#define SI476X_DIGITAL_IO_OUTPUT_FORMAT_MASK (0b1111110) + +enum si476x_daudio_formats { + SI476X_DAUDIO_MODE_I2S = (0x0 << 1), + SI476X_DAUDIO_MODE_DSP_A = (0x6 << 1), + SI476X_DAUDIO_MODE_DSP_B = (0x7 << 1), + SI476X_DAUDIO_MODE_LEFT_J = (0x8 << 1), + SI476X_DAUDIO_MODE_RIGHT_J = (0x9 << 1), + + SI476X_DAUDIO_MODE_IB = (1 << 5), + SI476X_DAUDIO_MODE_IF = (1 << 6), +}; + +enum si476x_pcm_format { + SI476X_PCM_FORMAT_S8 = 2, + SI476X_PCM_FORMAT_S16_LE = 4, + SI476X_PCM_FORMAT_S20_3LE = 5, + SI476X_PCM_FORMAT_S24_LE = 6, +}; + +static unsigned int si476x_codec_read(struct snd_soc_codec *codec, + unsigned int reg) +{ + int err; + struct si476x_core *core = codec->control_data; + + si476x_core_lock(core); + err = si476x_core_cmd_get_property(core, reg); + si476x_core_unlock(core); + + return err; +} + +static int si476x_codec_write(struct snd_soc_codec *codec, + unsigned int reg, unsigned int val) +{ + int err; + struct si476x_core *core = codec->control_data; + + si476x_core_lock(core); + err = si476x_core_cmd_set_property(core, reg, val); + si476x_core_unlock(core); + + return err; +} + +static int si476x_codec_set_dai_fmt(struct snd_soc_dai *codec_dai, + unsigned int fmt) +{ + int err; + u16 format = 0; + + if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) + return -EINVAL; + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_DSP_A: + format |= SI476X_DAUDIO_MODE_DSP_A; + break; + case SND_SOC_DAIFMT_DSP_B: + format |= SI476X_DAUDIO_MODE_DSP_B; + break; + case SND_SOC_DAIFMT_I2S: + format |= SI476X_DAUDIO_MODE_I2S; + break; + case SND_SOC_DAIFMT_RIGHT_J: + format |= SI476X_DAUDIO_MODE_RIGHT_J; + break; + case SND_SOC_DAIFMT_LEFT_J: + format |= SI476X_DAUDIO_MODE_LEFT_J; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_DSP_A: + case SND_SOC_DAIFMT_DSP_B: + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_IB_NF: + format |= SI476X_DAUDIO_MODE_IB; + break; + default: + return -EINVAL; + } + break; + case SND_SOC_DAIFMT_I2S: + case SND_SOC_DAIFMT_RIGHT_J: + case SND_SOC_DAIFMT_LEFT_J: + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_IB_IF: + format |= SI476X_DAUDIO_MODE_IB | + SI476X_DAUDIO_MODE_IF; + break; + case SND_SOC_DAIFMT_IB_NF: + format |= SI476X_DAUDIO_MODE_IB; + break; + case SND_SOC_DAIFMT_NB_IF: + format |= SI476X_DAUDIO_MODE_IF; + break; + default: + return -EINVAL; + } + break; + default: + return -EINVAL; + } + + err = snd_soc_update_bits(codec_dai->codec, SI476X_DIGITAL_IO_OUTPUT_FORMAT, + SI476X_DIGITAL_IO_OUTPUT_FORMAT_MASK, + format); + if (err < 0) { + dev_err(codec_dai->codec->dev, "Failed to set output format\n"); + return err; + } + + return 0; +} + +static int si476x_codec_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + int rate, width, err; + + rate = params_rate(params); + if (rate < 32000 || rate > 48000) { + dev_err(dai->codec->dev, "Rate: %d is not supported\n", rate); + return -EINVAL; + } + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S8: + width = SI476X_PCM_FORMAT_S8; + case SNDRV_PCM_FORMAT_S16_LE: + width = SI476X_PCM_FORMAT_S16_LE; + break; + case SNDRV_PCM_FORMAT_S20_3LE: + width = SI476X_PCM_FORMAT_S20_3LE; + break; + case SNDRV_PCM_FORMAT_S24_LE: + width = SI476X_PCM_FORMAT_S24_LE; + break; + default: + return -EINVAL; + } + + err = snd_soc_write(dai->codec, SI476X_DIGITAL_IO_OUTPUT_SAMPLE_RATE, + rate); + if (err < 0) { + dev_err(dai->codec->dev, "Failed to set sample rate\n"); + return err; + } + + err = snd_soc_update_bits(dai->codec, SI476X_DIGITAL_IO_OUTPUT_FORMAT, + SI476X_DIGITAL_IO_OUTPUT_WIDTH_MASK, + (width << SI476X_DIGITAL_IO_SLOT_SIZE_SHIFT) | + (width << SI476X_DIGITAL_IO_SAMPLE_SIZE_SHIFT)); + if (err < 0) { + dev_err(dai->codec->dev, "Failed to set output width\n"); + return err; + } + + return 0; +} + +static int si476x_codec_probe(struct snd_soc_codec *codec) +{ + codec->control_data = i2c_mfd_cell_to_core(codec->dev); + return 0; +} + +static struct snd_soc_dai_ops si476x_dai_ops = { + .hw_params = si476x_codec_hw_params, + .set_fmt = si476x_codec_set_dai_fmt, +}; + +static struct snd_soc_dai_driver si476x_dai = { + .name = "si476x-codec", + .capture = { + .stream_name = "Capture", + .channels_min = 2, + .channels_max = 2, + + .rates = SNDRV_PCM_RATE_32000 | + SNDRV_PCM_RATE_44100 | + SNDRV_PCM_RATE_48000, + .formats = SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S20_3LE | + SNDRV_PCM_FMTBIT_S24_LE + }, + .ops = &si476x_dai_ops, +}; + +static struct snd_soc_codec_driver soc_codec_dev_si476x = { + .probe = si476x_codec_probe, + .read = si476x_codec_read, + .write = si476x_codec_write, +}; + +static int si476x_platform_probe(struct platform_device *pdev) +{ + return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_si476x, + &si476x_dai, 1); +} + +static int si476x_platform_remove(struct platform_device *pdev) +{ + snd_soc_unregister_codec(&pdev->dev); + return 0; +} + +MODULE_ALIAS("platform:si476x-codec"); + +static struct platform_driver si476x_platform_driver = { + .driver = { + .name = "si476x-codec", + .owner = THIS_MODULE, + }, + .probe = si476x_platform_probe, + .remove = si476x_platform_remove, +}; +module_platform_driver(si476x_platform_driver); + +MODULE_AUTHOR("Andrey Smirnov <andrey.smirnov@convergeddevices.net>"); +MODULE_DESCRIPTION("ASoC Si4761/64 codec driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/sigmadsp.c b/sound/soc/codecs/sigmadsp.c index 5be42bf56996..4068f2491232 100644 --- a/sound/soc/codecs/sigmadsp.c +++ b/sound/soc/codecs/sigmadsp.c @@ -225,7 +225,7 @@ EXPORT_SYMBOL(process_sigma_firmware); static int sigma_action_write_regmap(void *control_data, const struct sigma_action *sa, size_t len) { - return regmap_raw_write(control_data, le16_to_cpu(sa->addr), + return regmap_raw_write(control_data, be16_to_cpu(sa->addr), sa->payload, len - 2); } diff --git a/sound/soc/codecs/sn95031.c b/sound/soc/codecs/sn95031.c index 50dbdb9357ea..d1ae869d3181 100644 --- a/sound/soc/codecs/sn95031.c +++ b/sound/soc/codecs/sn95031.c @@ -896,14 +896,14 @@ struct snd_soc_codec_driver sn95031_codec = { .num_dapm_routes = ARRAY_SIZE(sn95031_audio_map), }; -static int __devinit sn95031_device_probe(struct platform_device *pdev) +static int sn95031_device_probe(struct platform_device *pdev) { pr_debug("codec device probe called for %s\n", dev_name(&pdev->dev)); return snd_soc_register_codec(&pdev->dev, &sn95031_codec, sn95031_dais, ARRAY_SIZE(sn95031_dais)); } -static int __devexit sn95031_device_remove(struct platform_device *pdev) +static int sn95031_device_remove(struct platform_device *pdev) { pr_debug("codec device remove called\n"); snd_soc_unregister_codec(&pdev->dev); @@ -916,7 +916,7 @@ static struct platform_driver sn95031_codec_driver = { .owner = THIS_MODULE, }, .probe = sn95031_device_probe, - .remove = __devexit_p(sn95031_device_remove), + .remove = sn95031_device_remove, }; module_platform_driver(sn95031_codec_driver); diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c index 079066fef425..f8d30e5f6371 100644 --- a/sound/soc/codecs/ssm2602.c +++ b/sound/soc/codecs/ssm2602.c @@ -691,7 +691,7 @@ static const struct regmap_config ssm2602_regmap_config = { }; #if defined(CONFIG_SPI_MASTER) -static int __devinit ssm2602_spi_probe(struct spi_device *spi) +static int ssm2602_spi_probe(struct spi_device *spi) { struct ssm2602_priv *ssm2602; int ret; @@ -713,7 +713,7 @@ static int __devinit ssm2602_spi_probe(struct spi_device *spi) return ret; } -static int __devexit ssm2602_spi_remove(struct spi_device *spi) +static int ssm2602_spi_remove(struct spi_device *spi) { snd_soc_unregister_codec(&spi->dev); return 0; @@ -725,7 +725,7 @@ static struct spi_driver ssm2602_spi_driver = { .owner = THIS_MODULE, }, .probe = ssm2602_spi_probe, - .remove = __devexit_p(ssm2602_spi_remove), + .remove = ssm2602_spi_remove, }; #endif @@ -736,7 +736,7 @@ static struct spi_driver ssm2602_spi_driver = { * low = 0x1a * high = 0x1b */ -static int __devinit ssm2602_i2c_probe(struct i2c_client *i2c, +static int ssm2602_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct ssm2602_priv *ssm2602; @@ -759,7 +759,7 @@ static int __devinit ssm2602_i2c_probe(struct i2c_client *i2c, return ret; } -static int __devexit ssm2602_i2c_remove(struct i2c_client *client) +static int ssm2602_i2c_remove(struct i2c_client *client) { snd_soc_unregister_codec(&client->dev); return 0; @@ -780,7 +780,7 @@ static struct i2c_driver ssm2602_i2c_driver = { .owner = THIS_MODULE, }, .probe = ssm2602_i2c_probe, - .remove = __devexit_p(ssm2602_i2c_remove), + .remove = ssm2602_i2c_remove, .id_table = ssm2602_i2c_id, }; #endif diff --git a/sound/soc/codecs/sta32x.c b/sound/soc/codecs/sta32x.c index 0935bfe62471..cfb55fe35e98 100644 --- a/sound/soc/codecs/sta32x.c +++ b/sound/soc/codecs/sta32x.c @@ -995,8 +995,8 @@ static const struct regmap_config sta32x_regmap = { .volatile_reg = sta32x_reg_is_volatile, }; -static __devinit int sta32x_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int sta32x_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) { struct sta32x_priv *sta32x; int ret, i; @@ -1033,7 +1033,7 @@ static __devinit int sta32x_i2c_probe(struct i2c_client *i2c, return ret; } -static __devexit int sta32x_i2c_remove(struct i2c_client *client) +static int sta32x_i2c_remove(struct i2c_client *client) { snd_soc_unregister_codec(&client->dev); return 0; @@ -1053,7 +1053,7 @@ static struct i2c_driver sta32x_i2c_driver = { .owner = THIS_MODULE, }, .probe = sta32x_i2c_probe, - .remove = __devexit_p(sta32x_i2c_remove), + .remove = sta32x_i2c_remove, .id_table = sta32x_i2c_id, }; diff --git a/sound/soc/codecs/sta529.c b/sound/soc/codecs/sta529.c index 9e3144862386..40c07be9b581 100644 --- a/sound/soc/codecs/sta529.c +++ b/sound/soc/codecs/sta529.c @@ -74,9 +74,10 @@ SNDRV_PCM_FMTBIT_S32_LE) #define S2PC_VALUE 0x98 #define CLOCK_OUT 0x60 -#define LEFT_J_DATA_FORMAT 0x10 -#define I2S_DATA_FORMAT 0x12 -#define RIGHT_J_DATA_FORMAT 0x14 +#define DATA_FORMAT_MSK 0x0E +#define LEFT_J_DATA_FORMAT 0x00 +#define I2S_DATA_FORMAT 0x02 +#define RIGHT_J_DATA_FORMAT 0x04 #define CODEC_MUTE_VAL 0x80 #define POWER_CNTLMSAK 0x40 @@ -289,7 +290,7 @@ static int sta529_set_dai_fmt(struct snd_soc_dai *codec_dai, u32 fmt) return -EINVAL; } - snd_soc_update_bits(codec, STA529_S2PCFG0, 0x0D, mode); + snd_soc_update_bits(codec, STA529_S2PCFG0, DATA_FORMAT_MSK, mode); return 0; } @@ -380,8 +381,8 @@ static const struct regmap_config sta529_regmap = { .num_reg_defaults = ARRAY_SIZE(sta529_reg_defaults), }; -static __devinit int sta529_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int sta529_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) { struct sta529 *sta529; int ret; @@ -412,7 +413,7 @@ static __devinit int sta529_i2c_probe(struct i2c_client *i2c, return ret; } -static int __devexit sta529_i2c_remove(struct i2c_client *client) +static int sta529_i2c_remove(struct i2c_client *client) { snd_soc_unregister_codec(&client->dev); @@ -431,7 +432,7 @@ static struct i2c_driver sta529_i2c_driver = { .owner = THIS_MODULE, }, .probe = sta529_i2c_probe, - .remove = __devexit_p(sta529_i2c_remove), + .remove = sta529_i2c_remove, .id_table = sta529_i2c_id, }; diff --git a/sound/soc/codecs/stac9766.c b/sound/soc/codecs/stac9766.c index 982e437799a8..2eda85ba79ac 100644 --- a/sound/soc/codecs/stac9766.c +++ b/sound/soc/codecs/stac9766.c @@ -385,13 +385,13 @@ static struct snd_soc_codec_driver soc_codec_dev_stac9766 = { .reg_cache_default = stac9766_reg, }; -static __devinit int stac9766_probe(struct platform_device *pdev) +static int stac9766_probe(struct platform_device *pdev) { return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_stac9766, stac9766_dai, ARRAY_SIZE(stac9766_dai)); } -static int __devexit stac9766_remove(struct platform_device *pdev) +static int stac9766_remove(struct platform_device *pdev) { snd_soc_unregister_codec(&pdev->dev); return 0; @@ -404,7 +404,7 @@ static struct platform_driver stac9766_codec_driver = { }, .probe = stac9766_probe, - .remove = __devexit_p(stac9766_remove), + .remove = stac9766_remove, }; module_platform_driver(stac9766_codec_driver); diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c index f230292ba96b..17df4e32feac 100644 --- a/sound/soc/codecs/tlv320aic32x4.c +++ b/sound/soc/codecs/tlv320aic32x4.c @@ -28,6 +28,7 @@ #include <linux/init.h> #include <linux/delay.h> #include <linux/pm.h> +#include <linux/gpio.h> #include <linux/i2c.h> #include <linux/cdev.h> #include <linux/slab.h> @@ -65,6 +66,7 @@ struct aic32x4_priv { u32 power_cfg; u32 micpga_routing; bool swapdacs; + int rstn_gpio; }; /* 0dB min, 1dB steps */ @@ -627,10 +629,20 @@ static int aic32x4_probe(struct snd_soc_codec *codec) { struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec); u32 tmp_reg; + int ret; codec->hw_write = (hw_write_t) i2c_master_send; codec->control_data = aic32x4->control_data; + if (aic32x4->rstn_gpio >= 0) { + ret = devm_gpio_request_one(codec->dev, aic32x4->rstn_gpio, + GPIOF_OUT_INIT_LOW, "tlv320aic32x4 rstn"); + if (ret != 0) + return ret; + ndelay(10); + gpio_set_value(aic32x4->rstn_gpio, 1); + } + snd_soc_write(codec, AIC32X4_RESET, 0x01); /* Power platform configuration */ @@ -675,6 +687,16 @@ static int aic32x4_probe(struct snd_soc_codec *codec) ARRAY_SIZE(aic32x4_snd_controls)); aic32x4_add_widgets(codec); + /* + * Workaround: for an unknown reason, the ADC needs to be powered up + * and down for the first capture to work properly. It seems related to + * a HW BUG or some kind of behavior not documented in the datasheet. + */ + tmp_reg = snd_soc_read(codec, AIC32X4_ADCSETUP); + snd_soc_write(codec, AIC32X4_ADCSETUP, tmp_reg | + AIC32X4_LADC_EN | AIC32X4_RADC_EN); + snd_soc_write(codec, AIC32X4_ADCSETUP, tmp_reg); + return 0; } @@ -694,8 +716,8 @@ static struct snd_soc_codec_driver soc_codec_dev_aic32x4 = { .set_bias_level = aic32x4_set_bias_level, }; -static __devinit int aic32x4_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int aic32x4_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) { struct aic32x4_pdata *pdata = i2c->dev.platform_data; struct aic32x4_priv *aic32x4; @@ -713,10 +735,12 @@ static __devinit int aic32x4_i2c_probe(struct i2c_client *i2c, aic32x4->power_cfg = pdata->power_cfg; aic32x4->swapdacs = pdata->swapdacs; aic32x4->micpga_routing = pdata->micpga_routing; + aic32x4->rstn_gpio = pdata->rstn_gpio; } else { aic32x4->power_cfg = 0; aic32x4->swapdacs = false; aic32x4->micpga_routing = 0; + aic32x4->rstn_gpio = -1; } ret = snd_soc_register_codec(&i2c->dev, @@ -724,7 +748,7 @@ static __devinit int aic32x4_i2c_probe(struct i2c_client *i2c, return ret; } -static __devexit int aic32x4_i2c_remove(struct i2c_client *client) +static int aic32x4_i2c_remove(struct i2c_client *client) { snd_soc_unregister_codec(&client->dev); return 0; @@ -742,7 +766,7 @@ static struct i2c_driver aic32x4_i2c_driver = { .owner = THIS_MODULE, }, .probe = aic32x4_i2c_probe, - .remove = __devexit_p(aic32x4_i2c_remove), + .remove = aic32x4_i2c_remove, .id_table = aic32x4_i2c_id, }; diff --git a/sound/soc/codecs/tlv320aic32x4.h b/sound/soc/codecs/tlv320aic32x4.h index aae2b2440398..35774223fd91 100644 --- a/sound/soc/codecs/tlv320aic32x4.h +++ b/sound/soc/codecs/tlv320aic32x4.h @@ -94,6 +94,9 @@ #define AIC32X4_WORD_LEN_24BITS 0x02 #define AIC32X4_WORD_LEN_32BITS 0x03 +#define AIC32X4_LADC_EN (1 << 7) +#define AIC32X4_RADC_EN (1 << 6) + #define AIC32X4_I2S_MODE 0x00 #define AIC32X4_DSP_MODE 0x01 #define AIC32X4_RIGHT_JUSTIFIED_MODE 0x02 diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c index d2e16c5d7d1f..782b0cded2e6 100644 --- a/sound/soc/codecs/tlv320dac33.c +++ b/sound/soc/codecs/tlv320dac33.c @@ -1514,8 +1514,8 @@ static struct snd_soc_dai_driver dac33_dai = { .ops = &dac33_dai_ops, }; -static int __devinit dac33_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int dac33_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct tlv320dac33_platform_data *pdata; struct tlv320dac33_priv *dac33; @@ -1586,7 +1586,7 @@ err_gpio: return ret; } -static int __devexit dac33_i2c_remove(struct i2c_client *client) +static int dac33_i2c_remove(struct i2c_client *client) { struct tlv320dac33_priv *dac33 = i2c_get_clientdata(client); @@ -1617,7 +1617,7 @@ static struct i2c_driver tlv320dac33_i2c_driver = { .owner = THIS_MODULE, }, .probe = dac33_i2c_probe, - .remove = __devexit_p(dac33_i2c_remove), + .remove = dac33_i2c_remove, .id_table = tlv320dac33_i2c_id, }; diff --git a/sound/soc/codecs/tpa6130a2.c b/sound/soc/codecs/tpa6130a2.c index 565ff39ad3a3..c58bee8346ce 100644 --- a/sound/soc/codecs/tpa6130a2.c +++ b/sound/soc/codecs/tpa6130a2.c @@ -359,8 +359,8 @@ int tpa6130a2_add_controls(struct snd_soc_codec *codec) } EXPORT_SYMBOL_GPL(tpa6130a2_add_controls); -static int __devinit tpa6130a2_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int tpa6130a2_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct device *dev; struct tpa6130a2_data *data; @@ -398,7 +398,8 @@ static int __devinit tpa6130a2_probe(struct i2c_client *client, TPA6130A2_MUTE_L; if (data->power_gpio >= 0) { - ret = gpio_request(data->power_gpio, "tpa6130a2 enable"); + ret = devm_gpio_request(dev, data->power_gpio, + "tpa6130a2 enable"); if (ret < 0) { dev_err(dev, "Failed to request power GPIO (%d)\n", data->power_gpio); @@ -419,16 +420,16 @@ static int __devinit tpa6130a2_probe(struct i2c_client *client, break; } - data->supply = regulator_get(dev, regulator); + data->supply = devm_regulator_get(dev, regulator); if (IS_ERR(data->supply)) { ret = PTR_ERR(data->supply); dev_err(dev, "Failed to request supply: %d\n", ret); - goto err_regulator; + goto err_gpio; } ret = tpa6130a2_power(1); if (ret != 0) - goto err_power; + goto err_gpio; /* Read version */ @@ -440,31 +441,19 @@ static int __devinit tpa6130a2_probe(struct i2c_client *client, /* Disable the chip */ ret = tpa6130a2_power(0); if (ret != 0) - goto err_power; + goto err_gpio; return 0; -err_power: - regulator_put(data->supply); -err_regulator: - if (data->power_gpio >= 0) - gpio_free(data->power_gpio); err_gpio: tpa6130a2_client = NULL; return ret; } -static int __devexit tpa6130a2_remove(struct i2c_client *client) +static int tpa6130a2_remove(struct i2c_client *client) { - struct tpa6130a2_data *data = i2c_get_clientdata(client); - tpa6130a2_power(0); - - if (data->power_gpio >= 0) - gpio_free(data->power_gpio); - - regulator_put(data->supply); tpa6130a2_client = NULL; return 0; @@ -483,7 +472,7 @@ static struct i2c_driver tpa6130a2_i2c_driver = { .owner = THIS_MODULE, }, .probe = tpa6130a2_probe, - .remove = __devexit_p(tpa6130a2_remove), + .remove = tpa6130a2_remove, .id_table = tpa6130a2_id, }; diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index e7f608996c41..63b280b06035 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -2334,13 +2334,13 @@ static struct snd_soc_codec_driver soc_codec_dev_twl4030 = { .num_dapm_routes = ARRAY_SIZE(intercon), }; -static int __devinit twl4030_codec_probe(struct platform_device *pdev) +static int twl4030_codec_probe(struct platform_device *pdev) { return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_twl4030, twl4030_dai, ARRAY_SIZE(twl4030_dai)); } -static int __devexit twl4030_codec_remove(struct platform_device *pdev) +static int twl4030_codec_remove(struct platform_device *pdev) { snd_soc_unregister_codec(&pdev->dev); return 0; @@ -2350,7 +2350,7 @@ MODULE_ALIAS("platform:twl4030-codec"); static struct platform_driver twl4030_codec_driver = { .probe = twl4030_codec_probe, - .remove = __devexit_p(twl4030_codec_remove), + .remove = twl4030_codec_remove, .driver = { .name = "twl4030-codec", .owner = THIS_MODULE, diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c index 00b85cc1b9a3..3fc3fc64dd8b 100644 --- a/sound/soc/codecs/twl6040.c +++ b/sound/soc/codecs/twl6040.c @@ -1229,13 +1229,13 @@ static struct snd_soc_codec_driver soc_codec_dev_twl6040 = { .num_dapm_routes = ARRAY_SIZE(intercon), }; -static int __devinit twl6040_codec_probe(struct platform_device *pdev) +static int twl6040_codec_probe(struct platform_device *pdev) { return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_twl6040, twl6040_dai, ARRAY_SIZE(twl6040_dai)); } -static int __devexit twl6040_codec_remove(struct platform_device *pdev) +static int twl6040_codec_remove(struct platform_device *pdev) { snd_soc_unregister_codec(&pdev->dev); return 0; @@ -1247,7 +1247,7 @@ static struct platform_driver twl6040_codec_driver = { .owner = THIS_MODULE, }, .probe = twl6040_codec_probe, - .remove = __devexit_p(twl6040_codec_remove), + .remove = twl6040_codec_remove, }; module_platform_driver(twl6040_codec_driver); diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c index 6c3d43b8ee85..6d0aa44c3757 100644 --- a/sound/soc/codecs/uda134x.c +++ b/sound/soc/codecs/uda134x.c @@ -601,13 +601,13 @@ static struct snd_soc_codec_driver soc_codec_dev_uda134x = { .set_bias_level = uda134x_set_bias_level, }; -static int __devinit uda134x_codec_probe(struct platform_device *pdev) +static int uda134x_codec_probe(struct platform_device *pdev) { return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_uda134x, &uda134x_dai, 1); } -static int __devexit uda134x_codec_remove(struct platform_device *pdev) +static int uda134x_codec_remove(struct platform_device *pdev) { snd_soc_unregister_codec(&pdev->dev); return 0; @@ -619,7 +619,7 @@ static struct platform_driver uda134x_codec_driver = { .owner = THIS_MODULE, }, .probe = uda134x_codec_probe, - .remove = __devexit_p(uda134x_codec_remove), + .remove = uda134x_codec_remove, }; module_platform_driver(uda134x_codec_driver); diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c index 2502214b84ab..fd0a314bc209 100644 --- a/sound/soc/codecs/uda1380.c +++ b/sound/soc/codecs/uda1380.c @@ -795,8 +795,8 @@ static struct snd_soc_codec_driver soc_codec_dev_uda1380 = { }; #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) -static __devinit int uda1380_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int uda1380_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) { struct uda1380_priv *uda1380; int ret; @@ -814,7 +814,7 @@ static __devinit int uda1380_i2c_probe(struct i2c_client *i2c, return ret; } -static int __devexit uda1380_i2c_remove(struct i2c_client *i2c) +static int uda1380_i2c_remove(struct i2c_client *i2c) { snd_soc_unregister_codec(&i2c->dev); return 0; @@ -832,7 +832,7 @@ static struct i2c_driver uda1380_i2c_driver = { .owner = THIS_MODULE, }, .probe = uda1380_i2c_probe, - .remove = __devexit_p(uda1380_i2c_remove), + .remove = uda1380_i2c_remove, .id_table = uda1380_i2c_id, }; #endif diff --git a/sound/soc/codecs/wl1273.c b/sound/soc/codecs/wl1273.c index 7b24d6d192e1..54cd3da09abd 100644 --- a/sound/soc/codecs/wl1273.c +++ b/sound/soc/codecs/wl1273.c @@ -485,13 +485,13 @@ static struct snd_soc_codec_driver soc_codec_dev_wl1273 = { .remove = wl1273_remove, }; -static int __devinit wl1273_platform_probe(struct platform_device *pdev) +static int wl1273_platform_probe(struct platform_device *pdev) { return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wl1273, &wl1273_dai, 1); } -static int __devexit wl1273_platform_remove(struct platform_device *pdev) +static int wl1273_platform_remove(struct platform_device *pdev) { snd_soc_unregister_codec(&pdev->dev); return 0; @@ -505,7 +505,7 @@ static struct platform_driver wl1273_platform_driver = { .owner = THIS_MODULE, }, .probe = wl1273_platform_probe, - .remove = __devexit_p(wl1273_platform_remove), + .remove = wl1273_platform_remove, }; module_platform_driver(wl1273_platform_driver); diff --git a/sound/soc/codecs/wm0010.c b/sound/soc/codecs/wm0010.c index 99afc003a084..ad2fee4bb4cd 100644 --- a/sound/soc/codecs/wm0010.c +++ b/sound/soc/codecs/wm0010.c @@ -31,6 +31,9 @@ #define DEVICE_ID_WM0010 10 +/* We only support v1 of the .dfw INFO record */ +#define INFO_VERSION 1 + enum dfw_cmd { DFW_CMD_FUSE = 0x01, DFW_CMD_CODE_HDR, @@ -46,6 +49,13 @@ struct dfw_binrec { uint8_t data[0]; } __packed; +struct dfw_inforec { + u8 info_version; + u8 tool_major_version; + u8 tool_minor_version; + u8 dsp_target; +}; + struct dfw_pllrec { u8 command; u32 length:24; @@ -97,7 +107,6 @@ struct wm0010_priv { enum wm0010_state state; bool boot_failed; - int boot_done; bool ready; bool pll_running; int max_spi_freq; @@ -234,7 +243,7 @@ static void wm0010_boot_xfer_complete(void *data) break; case 0x55555555: - if (wm0010->boot_done == 0) + if (wm0010->state < WM0010_STAGE2) break; dev_err(codec->dev, "%d: ROM bootloader running in stage 2\n", i); @@ -321,7 +330,6 @@ static void wm0010_boot_xfer_complete(void *data) break; } - wm0010->boot_done++; if (xfer->done) complete(xfer->done); } @@ -334,94 +342,198 @@ static void byte_swap_64(u64 *data_in, u64 *data_out, u32 len) data_out[i] = cpu_to_be64(le64_to_cpu(data_in[i])); } -static int wm0010_boot(struct snd_soc_codec *codec) +static int wm0010_firmware_load(char *name, struct snd_soc_codec *codec) { struct spi_device *spi = to_spi_device(codec->dev); struct wm0010_priv *wm0010 = snd_soc_codec_get_drvdata(codec); - unsigned long flags; struct list_head xfer_list; struct wm0010_boot_xfer *xfer; int ret; struct completion done; const struct firmware *fw; const struct dfw_binrec *rec; - struct spi_message m; - struct spi_transfer t; - struct dfw_pllrec pll_rec; - u32 *img, *p; - u64 *img_swap; - u8 *out; + const struct dfw_inforec *inforec; + u64 *img; + u8 *out, dsp; u32 len, offset; - int i; - spin_lock_irqsave(&wm0010->irq_lock, flags); - if (wm0010->state != WM0010_POWER_OFF) - dev_warn(wm0010->dev, "DSP already powered up!\n"); - spin_unlock_irqrestore(&wm0010->irq_lock, flags); + INIT_LIST_HEAD(&xfer_list); - if (wm0010->sysclk > 26000000) { - dev_err(codec->dev, "Max DSP clock frequency is 26MHz\n"); - ret = -ECANCELED; - goto err; + ret = request_firmware(&fw, name, codec->dev); + if (ret != 0) { + dev_err(codec->dev, "Failed to request application: %d\n", + ret); + return ret; } - INIT_LIST_HEAD(&xfer_list); + rec = (const struct dfw_binrec *)fw->data; + inforec = (const struct dfw_inforec *)rec->data; + offset = 0; + dsp = inforec->dsp_target; + wm0010->boot_failed = false; + BUG_ON(!list_empty(&xfer_list)); + init_completion(&done); - mutex_lock(&wm0010->lock); - wm0010->pll_running = false; + /* First record should be INFO */ + if (rec->command != DFW_CMD_INFO) { + dev_err(codec->dev, "First record not INFO\r\n"); + ret = -EINVAL; + goto abort; + } - dev_dbg(codec->dev, "max_spi_freq: %d\n", wm0010->max_spi_freq); + if (inforec->info_version != INFO_VERSION) { + dev_err(codec->dev, + "Unsupported version (%02d) of INFO record\r\n", + inforec->info_version); + ret = -EINVAL; + goto abort; + } - ret = regulator_bulk_enable(ARRAY_SIZE(wm0010->core_supplies), - wm0010->core_supplies); - if (ret != 0) { - dev_err(&spi->dev, "Failed to enable core supplies: %d\n", - ret); - mutex_unlock(&wm0010->lock); - goto err; + dev_dbg(codec->dev, "Version v%02d INFO record found\r\n", + inforec->info_version); + + /* Check it's a DSP file */ + if (dsp != DEVICE_ID_WM0010) { + dev_err(codec->dev, "Not a WM0010 firmware file.\r\n"); + ret = -EINVAL; + goto abort; } - ret = regulator_enable(wm0010->dbvdd); - if (ret != 0) { - dev_err(&spi->dev, "Failed to enable DBVDD: %d\n", ret); - goto err_core; + /* Skip the info record as we don't need to send it */ + offset += ((rec->length) + 8); + rec = (void *)&rec->data[rec->length]; + + while (offset < fw->size) { + dev_dbg(codec->dev, + "Packet: command %d, data length = 0x%x\r\n", + rec->command, rec->length); + len = rec->length + 8; + + out = kzalloc(len, GFP_KERNEL); + if (!out) { + dev_err(codec->dev, + "Failed to allocate RX buffer\n"); + ret = -ENOMEM; + goto abort1; + } + + img = kzalloc(len, GFP_KERNEL); + if (!img) { + dev_err(codec->dev, + "Failed to allocate image buffer\n"); + ret = -ENOMEM; + goto abort1; + } + + byte_swap_64((u64 *)&rec->command, img, len); + + xfer = kzalloc(sizeof(*xfer), GFP_KERNEL); + if (!xfer) { + dev_err(codec->dev, "Failed to allocate xfer\n"); + ret = -ENOMEM; + goto abort1; + } + + xfer->codec = codec; + list_add_tail(&xfer->list, &xfer_list); + + spi_message_init(&xfer->m); + xfer->m.complete = wm0010_boot_xfer_complete; + xfer->m.context = xfer; + xfer->t.tx_buf = img; + xfer->t.rx_buf = out; + xfer->t.len = len; + xfer->t.bits_per_word = 8; + + if (!wm0010->pll_running) { + xfer->t.speed_hz = wm0010->sysclk / 6; + } else { + xfer->t.speed_hz = wm0010->max_spi_freq; + + if (wm0010->board_max_spi_speed && + (wm0010->board_max_spi_speed < wm0010->max_spi_freq)) + xfer->t.speed_hz = wm0010->board_max_spi_speed; + } + + /* Store max usable spi frequency for later use */ + wm0010->max_spi_freq = xfer->t.speed_hz; + + spi_message_add_tail(&xfer->t, &xfer->m); + + offset += ((rec->length) + 8); + rec = (void *)&rec->data[rec->length]; + + if (offset >= fw->size) { + dev_dbg(codec->dev, "All transfers scheduled\n"); + xfer->done = &done; + } + + ret = spi_async(spi, &xfer->m); + if (ret != 0) { + dev_err(codec->dev, "Write failed: %d\n", ret); + goto abort1; + } + + if (wm0010->boot_failed) { + dev_dbg(codec->dev, "Boot fail!\n"); + ret = -EINVAL; + goto abort1; + } } - /* Release reset */ - gpio_set_value_cansleep(wm0010->gpio_reset, !wm0010->gpio_reset_value); - spin_lock_irqsave(&wm0010->irq_lock, flags); - wm0010->state = WM0010_OUT_OF_RESET; - spin_unlock_irqrestore(&wm0010->irq_lock, flags); + wait_for_completion(&done); + + ret = 0; + +abort1: + while (!list_empty(&xfer_list)) { + xfer = list_first_entry(&xfer_list, struct wm0010_boot_xfer, + list); + kfree(xfer->t.rx_buf); + kfree(xfer->t.tx_buf); + list_del(&xfer->list); + kfree(xfer); + } + +abort: + release_firmware(fw); + return ret; +} + +static int wm0010_stage2_load(struct snd_soc_codec *codec) +{ + struct spi_device *spi = to_spi_device(codec->dev); + struct wm0010_priv *wm0010 = snd_soc_codec_get_drvdata(codec); + const struct firmware *fw; + struct spi_message m; + struct spi_transfer t; + u32 *img; + u8 *out; + int i; + int ret = 0; - /* First the bootloader */ ret = request_firmware(&fw, "wm0010_stage2.bin", codec->dev); if (ret != 0) { dev_err(codec->dev, "Failed to request stage2 loader: %d\n", ret); - goto abort; + return ret; } - if (!wait_for_completion_timeout(&wm0010->boot_completion, - msecs_to_jiffies(10))) - dev_err(codec->dev, "Failed to get interrupt from DSP\n"); - - spin_lock_irqsave(&wm0010->irq_lock, flags); - wm0010->state = WM0010_BOOTROM; - spin_unlock_irqrestore(&wm0010->irq_lock, flags); - dev_dbg(codec->dev, "Downloading %zu byte stage 2 loader\n", fw->size); /* Copy to local buffer first as vmalloc causes problems for dma */ img = kzalloc(fw->size, GFP_KERNEL); if (!img) { dev_err(codec->dev, "Failed to allocate image buffer\n"); - goto abort; + ret = -ENOMEM; + goto abort2; } out = kzalloc(fw->size, GFP_KERNEL); if (!out) { dev_err(codec->dev, "Failed to allocate output buffer\n"); - goto abort; + ret = -ENOMEM; + goto abort1; } memcpy(img, &fw->data[0], fw->size); @@ -447,20 +559,97 @@ static int wm0010_boot(struct snd_soc_codec *codec) /* Look for errors from the boot ROM */ for (i = 0; i < fw->size; i++) { if (out[i] != 0x55) { - ret = -EBUSY; dev_err(codec->dev, "Boot ROM error: %x in %d\n", out[i], i); wm0010_mark_boot_failure(wm0010); + ret = -EBUSY; goto abort; } } - - release_firmware(fw); - kfree(img); +abort: kfree(out); +abort1: + kfree(img); +abort2: + release_firmware(fw); + + return ret; +} + +static int wm0010_boot(struct snd_soc_codec *codec) +{ + struct spi_device *spi = to_spi_device(codec->dev); + struct wm0010_priv *wm0010 = snd_soc_codec_get_drvdata(codec); + unsigned long flags; + int ret; + const struct firmware *fw; + struct spi_message m; + struct spi_transfer t; + struct dfw_pllrec pll_rec; + u32 *p, len; + u64 *img_swap; + u8 *out; + int i; + + spin_lock_irqsave(&wm0010->irq_lock, flags); + if (wm0010->state != WM0010_POWER_OFF) + dev_warn(wm0010->dev, "DSP already powered up!\n"); + spin_unlock_irqrestore(&wm0010->irq_lock, flags); + + if (wm0010->sysclk > 26000000) { + dev_err(codec->dev, "Max DSP clock frequency is 26MHz\n"); + ret = -ECANCELED; + goto err; + } + + mutex_lock(&wm0010->lock); + wm0010->pll_running = false; + + dev_dbg(codec->dev, "max_spi_freq: %d\n", wm0010->max_spi_freq); + + ret = regulator_bulk_enable(ARRAY_SIZE(wm0010->core_supplies), + wm0010->core_supplies); + if (ret != 0) { + dev_err(&spi->dev, "Failed to enable core supplies: %d\n", + ret); + mutex_unlock(&wm0010->lock); + goto err; + } + + ret = regulator_enable(wm0010->dbvdd); + if (ret != 0) { + dev_err(&spi->dev, "Failed to enable DBVDD: %d\n", ret); + goto err_core; + } + + /* Release reset */ + gpio_set_value_cansleep(wm0010->gpio_reset, !wm0010->gpio_reset_value); + spin_lock_irqsave(&wm0010->irq_lock, flags); + wm0010->state = WM0010_OUT_OF_RESET; + spin_unlock_irqrestore(&wm0010->irq_lock, flags); + + /* First the bootloader */ + ret = request_firmware(&fw, "wm0010_stage2.bin", codec->dev); + if (ret != 0) { + dev_err(codec->dev, "Failed to request stage2 loader: %d\n", + ret); + goto abort; + } + + if (!wait_for_completion_timeout(&wm0010->boot_completion, + msecs_to_jiffies(20))) + dev_err(codec->dev, "Failed to get interrupt from DSP\n"); + + spin_lock_irqsave(&wm0010->irq_lock, flags); + wm0010->state = WM0010_BOOTROM; + spin_unlock_irqrestore(&wm0010->irq_lock, flags); + + ret = wm0010_stage2_load(codec); + if (ret) + goto abort; if (!wait_for_completion_timeout(&wm0010->boot_completion, - msecs_to_jiffies(10))) + msecs_to_jiffies(20))) dev_err(codec->dev, "Failed to get interrupt from DSP loader.\n"); spin_lock_irqsave(&wm0010->irq_lock, flags); @@ -535,110 +724,10 @@ static int wm0010_boot(struct snd_soc_codec *codec) } else dev_dbg(codec->dev, "Not enabling DSP PLL."); - ret = request_firmware(&fw, "wm0010.dfw", codec->dev); - if (ret != 0) { - dev_err(codec->dev, "Failed to request application: %d\n", - ret); - goto abort; - } - - rec = (const struct dfw_binrec *)fw->data; - offset = 0; - wm0010->boot_done = 0; - wm0010->boot_failed = false; - BUG_ON(!list_empty(&xfer_list)); - init_completion(&done); + ret = wm0010_firmware_load("wm0010.dfw", codec); - /* First record should be INFO */ - if (rec->command != DFW_CMD_INFO) { - dev_err(codec->dev, "First record not INFO\r\n"); - goto abort; - } - - /* Check it's a 0010 file */ - if (rec->data[0] != DEVICE_ID_WM0010) { - dev_err(codec->dev, "Not a WM0010 firmware file.\r\n"); + if (ret != 0) goto abort; - } - - /* Skip the info record as we don't need to send it */ - offset += ((rec->length) + 8); - rec = (void *)&rec->data[rec->length]; - - while (offset < fw->size) { - dev_dbg(codec->dev, - "Packet: command %d, data length = 0x%x\r\n", - rec->command, rec->length); - len = rec->length + 8; - - out = kzalloc(len, GFP_KERNEL); - if (!out) { - dev_err(codec->dev, - "Failed to allocate RX buffer\n"); - goto abort; - } - - img_swap = kzalloc(len, GFP_KERNEL); - if (!img_swap) { - dev_err(codec->dev, - "Failed to allocate image buffer\n"); - goto abort; - } - - /* We need to re-order for 0010 */ - byte_swap_64((u64 *)&rec->command, img_swap, len); - - xfer = kzalloc(sizeof(*xfer), GFP_KERNEL); - if (!xfer) { - dev_err(codec->dev, "Failed to allocate xfer\n"); - goto abort; - } - - xfer->codec = codec; - list_add_tail(&xfer->list, &xfer_list); - - spi_message_init(&xfer->m); - xfer->m.complete = wm0010_boot_xfer_complete; - xfer->m.context = xfer; - xfer->t.tx_buf = img_swap; - xfer->t.rx_buf = out; - xfer->t.len = len; - xfer->t.bits_per_word = 8; - - if (!wm0010->pll_running) { - xfer->t.speed_hz = wm0010->sysclk / 6; - } else { - xfer->t.speed_hz = wm0010->max_spi_freq; - - if (wm0010->board_max_spi_speed && - (wm0010->board_max_spi_speed < wm0010->max_spi_freq)) - xfer->t.speed_hz = wm0010->board_max_spi_speed; - } - - /* Store max usable spi frequency for later use */ - wm0010->max_spi_freq = xfer->t.speed_hz; - - spi_message_add_tail(&xfer->t, &xfer->m); - - offset += ((rec->length) + 8); - rec = (void *)&rec->data[rec->length]; - - if (offset >= fw->size) { - dev_dbg(codec->dev, "All transfers scheduled\n"); - xfer->done = &done; - } - - ret = spi_async(spi, &xfer->m); - if (ret != 0) { - dev_err(codec->dev, "Write failed: %d\n", ret); - goto abort; - } - - if (wm0010->boot_failed) - goto abort; - } - - wait_for_completion(&done); spin_lock_irqsave(&wm0010->irq_lock, flags); wm0010->state = WM0010_FIRMWARE; @@ -646,17 +735,6 @@ static int wm0010_boot(struct snd_soc_codec *codec) mutex_unlock(&wm0010->lock); - release_firmware(fw); - - while (!list_empty(&xfer_list)) { - xfer = list_first_entry(&xfer_list, struct wm0010_boot_xfer, - list); - kfree(xfer->t.rx_buf); - kfree(xfer->t.tx_buf); - list_del(&xfer->list); - kfree(xfer); - } - return 0; abort: @@ -784,7 +862,6 @@ static irqreturn_t wm0010_irq(int irq, void *data) struct wm0010_priv *wm0010 = data; switch (wm0010->state) { - case WM0010_POWER_OFF: case WM0010_OUT_OF_RESET: case WM0010_BOOTROM: case WM0010_STAGE2: @@ -808,7 +885,7 @@ static int wm0010_probe(struct snd_soc_codec *codec) return 0; } -static int __devinit wm0010_spi_probe(struct spi_device *spi) +static int wm0010_spi_probe(struct spi_device *spi) { unsigned long gpio_flags; int ret; @@ -908,7 +985,7 @@ static int __devinit wm0010_spi_probe(struct spi_device *spi) return 0; } -static int __devexit wm0010_spi_remove(struct spi_device *spi) +static int wm0010_spi_remove(struct spi_device *spi) { struct wm0010_priv *wm0010 = spi_get_drvdata(spi); @@ -930,7 +1007,7 @@ static struct spi_driver wm0010_spi_driver = { .owner = THIS_MODULE, }, .probe = wm0010_spi_probe, - .remove = __devexit_p(wm0010_spi_remove), + .remove = wm0010_spi_remove, }; module_spi_driver(wm0010_spi_driver); diff --git a/sound/soc/codecs/wm1250-ev1.c b/sound/soc/codecs/wm1250-ev1.c index 951d7b49476a..6e6b93d4696e 100644 --- a/sound/soc/codecs/wm1250-ev1.c +++ b/sound/soc/codecs/wm1250-ev1.c @@ -153,7 +153,7 @@ static struct snd_soc_codec_driver soc_codec_dev_wm1250_ev1 = { .idle_bias_off = true, }; -static int __devinit wm1250_ev1_pdata(struct i2c_client *i2c) +static int wm1250_ev1_pdata(struct i2c_client *i2c) { struct wm1250_ev1_pdata *pdata = dev_get_platdata(&i2c->dev); struct wm1250_priv *wm1250; @@ -199,8 +199,8 @@ static void wm1250_ev1_free(struct i2c_client *i2c) gpio_free_array(wm1250->gpios, ARRAY_SIZE(wm1250->gpios)); } -static int __devinit wm1250_ev1_probe(struct i2c_client *i2c, - const struct i2c_device_id *i2c_id) +static int wm1250_ev1_probe(struct i2c_client *i2c, + const struct i2c_device_id *i2c_id) { int id, board, rev, ret; @@ -237,7 +237,7 @@ static int __devinit wm1250_ev1_probe(struct i2c_client *i2c, return 0; } -static int __devexit wm1250_ev1_remove(struct i2c_client *i2c) +static int wm1250_ev1_remove(struct i2c_client *i2c) { snd_soc_unregister_codec(&i2c->dev); wm1250_ev1_free(i2c); @@ -257,7 +257,7 @@ static struct i2c_driver wm1250_ev1_i2c_driver = { .owner = THIS_MODULE, }, .probe = wm1250_ev1_probe, - .remove = __devexit_p(wm1250_ev1_remove), + .remove = wm1250_ev1_remove, .id_table = wm1250_ev1_i2c_id, }; diff --git a/sound/soc/codecs/wm2000.c b/sound/soc/codecs/wm2000.c index 683dc43b1d87..12bcae63a7f0 100644 --- a/sound/soc/codecs/wm2000.c +++ b/sound/soc/codecs/wm2000.c @@ -209,9 +209,9 @@ static int wm2000_power_up(struct i2c_client *i2c, int analogue) ret = wm2000_read(i2c, WM2000_REG_SPEECH_CLARITY); if (wm2000->speech_clarity) - ret &= ~WM2000_SPEECH_CLARITY; - else ret |= WM2000_SPEECH_CLARITY; + else + ret &= ~WM2000_SPEECH_CLARITY; wm2000_write(i2c, WM2000_REG_SPEECH_CLARITY, ret); wm2000_write(i2c, WM2000_REG_SYS_START0, 0x33); @@ -646,7 +646,7 @@ static const struct snd_kcontrol_new wm2000_controls[] = { static int wm2000_anc_power_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = w->codec; struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev); if (SND_SOC_DAPM_EVENT_ON(event)) @@ -764,8 +764,8 @@ static struct snd_soc_codec_driver soc_codec_dev_wm2000 = { .num_controls = ARRAY_SIZE(wm2000_controls), }; -static int __devinit wm2000_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *i2c_id) +static int wm2000_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *i2c_id) { struct wm2000_priv *wm2000; struct wm2000_platform_data *pdata; @@ -871,7 +871,7 @@ out: return ret; } -static __devexit int wm2000_i2c_remove(struct i2c_client *i2c) +static int wm2000_i2c_remove(struct i2c_client *i2c) { snd_soc_unregister_codec(&i2c->dev); @@ -890,7 +890,7 @@ static struct i2c_driver wm2000_i2c_driver = { .owner = THIS_MODULE, }, .probe = wm2000_i2c_probe, - .remove = __devexit_p(wm2000_i2c_remove), + .remove = wm2000_i2c_remove, .id_table = wm2000_i2c_id, }; diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c index eab64a193989..d8c65f574658 100644 --- a/sound/soc/codecs/wm2200.c +++ b/sound/soc/codecs/wm2200.c @@ -15,6 +15,7 @@ #include <linux/init.h> #include <linux/delay.h> #include <linux/pm.h> +#include <linux/firmware.h> #include <linux/gcd.h> #include <linux/gpio.h> #include <linux/i2c.h> @@ -32,6 +33,40 @@ #include <sound/wm2200.h> #include "wm2200.h" +#include "wmfw.h" +#include "wm_adsp.h" + +#define WM2200_DSP_CONTROL_1 0x00 +#define WM2200_DSP_CONTROL_2 0x02 +#define WM2200_DSP_CONTROL_3 0x03 +#define WM2200_DSP_CONTROL_4 0x04 +#define WM2200_DSP_CONTROL_5 0x06 +#define WM2200_DSP_CONTROL_6 0x07 +#define WM2200_DSP_CONTROL_7 0x08 +#define WM2200_DSP_CONTROL_8 0x09 +#define WM2200_DSP_CONTROL_9 0x0A +#define WM2200_DSP_CONTROL_10 0x0B +#define WM2200_DSP_CONTROL_11 0x0C +#define WM2200_DSP_CONTROL_12 0x0D +#define WM2200_DSP_CONTROL_13 0x0F +#define WM2200_DSP_CONTROL_14 0x10 +#define WM2200_DSP_CONTROL_15 0x11 +#define WM2200_DSP_CONTROL_16 0x12 +#define WM2200_DSP_CONTROL_17 0x13 +#define WM2200_DSP_CONTROL_18 0x14 +#define WM2200_DSP_CONTROL_19 0x16 +#define WM2200_DSP_CONTROL_20 0x17 +#define WM2200_DSP_CONTROL_21 0x18 +#define WM2200_DSP_CONTROL_22 0x1A +#define WM2200_DSP_CONTROL_23 0x1B +#define WM2200_DSP_CONTROL_24 0x1C +#define WM2200_DSP_CONTROL_25 0x1E +#define WM2200_DSP_CONTROL_26 0x20 +#define WM2200_DSP_CONTROL_27 0x21 +#define WM2200_DSP_CONTROL_28 0x22 +#define WM2200_DSP_CONTROL_29 0x23 +#define WM2200_DSP_CONTROL_30 0x24 +#define WM2200_DSP_CONTROL_31 0x26 /* The code assumes DCVDD is generated internally */ #define WM2200_NUM_CORE_SUPPLIES 2 @@ -49,6 +84,7 @@ struct wm2200_fll { /* codec private data */ struct wm2200_priv { + struct wm_adsp dsp[2]; struct regmap *regmap; struct device *dev; struct snd_soc_codec *codec; @@ -64,6 +100,72 @@ struct wm2200_priv { int sysclk; }; +#define WM2200_DSP_RANGE_BASE (WM2200_MAX_REGISTER + 1) +#define WM2200_DSP_SPACING 12288 + +#define WM2200_DSP1_DM_BASE (WM2200_DSP_RANGE_BASE + (0 * WM2200_DSP_SPACING)) +#define WM2200_DSP1_PM_BASE (WM2200_DSP_RANGE_BASE + (1 * WM2200_DSP_SPACING)) +#define WM2200_DSP1_ZM_BASE (WM2200_DSP_RANGE_BASE + (2 * WM2200_DSP_SPACING)) +#define WM2200_DSP2_DM_BASE (WM2200_DSP_RANGE_BASE + (3 * WM2200_DSP_SPACING)) +#define WM2200_DSP2_PM_BASE (WM2200_DSP_RANGE_BASE + (4 * WM2200_DSP_SPACING)) +#define WM2200_DSP2_ZM_BASE (WM2200_DSP_RANGE_BASE + (5 * WM2200_DSP_SPACING)) + +static const struct regmap_range_cfg wm2200_ranges[] = { + { .name = "DSP1DM", .range_min = WM2200_DSP1_DM_BASE, + .range_max = WM2200_DSP1_DM_BASE + 12287, + .selector_reg = WM2200_DSP1_CONTROL_3, + .selector_mask = WM2200_DSP1_PAGE_BASE_DM_0_MASK, + .selector_shift = WM2200_DSP1_PAGE_BASE_DM_0_SHIFT, + .window_start = WM2200_DSP1_DM_0, .window_len = 2048, }, + + { .name = "DSP1PM", .range_min = WM2200_DSP1_PM_BASE, + .range_max = WM2200_DSP1_PM_BASE + 12287, + .selector_reg = WM2200_DSP1_CONTROL_2, + .selector_mask = WM2200_DSP1_PAGE_BASE_PM_0_MASK, + .selector_shift = WM2200_DSP1_PAGE_BASE_PM_0_SHIFT, + .window_start = WM2200_DSP1_PM_0, .window_len = 768, }, + + { .name = "DSP1ZM", .range_min = WM2200_DSP1_ZM_BASE, + .range_max = WM2200_DSP1_ZM_BASE + 2047, + .selector_reg = WM2200_DSP1_CONTROL_4, + .selector_mask = WM2200_DSP1_PAGE_BASE_ZM_0_MASK, + .selector_shift = WM2200_DSP1_PAGE_BASE_ZM_0_SHIFT, + .window_start = WM2200_DSP1_ZM_0, .window_len = 1024, }, + + { .name = "DSP2DM", .range_min = WM2200_DSP2_DM_BASE, + .range_max = WM2200_DSP2_DM_BASE + 4095, + .selector_reg = WM2200_DSP2_CONTROL_3, + .selector_mask = WM2200_DSP2_PAGE_BASE_DM_0_MASK, + .selector_shift = WM2200_DSP2_PAGE_BASE_DM_0_SHIFT, + .window_start = WM2200_DSP2_DM_0, .window_len = 2048, }, + + { .name = "DSP2PM", .range_min = WM2200_DSP2_PM_BASE, + .range_max = WM2200_DSP2_PM_BASE + 11287, + .selector_reg = WM2200_DSP2_CONTROL_2, + .selector_mask = WM2200_DSP2_PAGE_BASE_PM_0_MASK, + .selector_shift = WM2200_DSP2_PAGE_BASE_PM_0_SHIFT, + .window_start = WM2200_DSP2_PM_0, .window_len = 768, }, + + { .name = "DSP2ZM", .range_min = WM2200_DSP2_ZM_BASE, + .range_max = WM2200_DSP2_ZM_BASE + 2047, + .selector_reg = WM2200_DSP2_CONTROL_4, + .selector_mask = WM2200_DSP2_PAGE_BASE_ZM_0_MASK, + .selector_shift = WM2200_DSP2_PAGE_BASE_ZM_0_SHIFT, + .window_start = WM2200_DSP2_ZM_0, .window_len = 1024, }, +}; + +static const struct wm_adsp_region wm2200_dsp1_regions[] = { + { .type = WMFW_ADSP1_PM, .base = WM2200_DSP1_PM_BASE }, + { .type = WMFW_ADSP1_DM, .base = WM2200_DSP1_DM_BASE }, + { .type = WMFW_ADSP1_ZM, .base = WM2200_DSP1_ZM_BASE }, +}; + +static const struct wm_adsp_region wm2200_dsp2_regions[] = { + { .type = WMFW_ADSP1_PM, .base = WM2200_DSP2_PM_BASE }, + { .type = WMFW_ADSP1_DM, .base = WM2200_DSP2_DM_BASE }, + { .type = WMFW_ADSP1_ZM, .base = WM2200_DSP2_ZM_BASE }, +}; + static struct reg_default wm2200_reg_defaults[] = { { 0x000B, 0x0000 }, /* R11 - Tone Generator 1 */ { 0x0102, 0x0000 }, /* R258 - Clocking 3 */ @@ -407,6 +509,16 @@ static struct reg_default wm2200_reg_defaults[] = { static bool wm2200_volatile_register(struct device *dev, unsigned int reg) { + int i; + + for (i = 0; i < ARRAY_SIZE(wm2200_ranges); i++) + if ((reg >= wm2200_ranges[i].window_start && + reg <= wm2200_ranges[i].window_start + + wm2200_ranges[i].window_len) || + (reg >= wm2200_ranges[i].range_min && + reg <= wm2200_ranges[i].range_max)) + return true; + switch (reg) { case WM2200_SOFTWARE_RESET: case WM2200_DEVICE_REVISION: @@ -423,6 +535,16 @@ static bool wm2200_volatile_register(struct device *dev, unsigned int reg) static bool wm2200_readable_register(struct device *dev, unsigned int reg) { + int i; + + for (i = 0; i < ARRAY_SIZE(wm2200_ranges); i++) + if ((reg >= wm2200_ranges[i].window_start && + reg <= wm2200_ranges[i].window_start + + wm2200_ranges[i].window_len) || + (reg >= wm2200_ranges[i].range_min && + reg <= wm2200_ranges[i].range_max)) + return true; + switch (reg) { case WM2200_SOFTWARE_RESET: case WM2200_DEVICE_REVISION: @@ -880,7 +1002,7 @@ static DECLARE_TLV_DB_SCALE(out_tlv, -6400, 100, 0); static const char *wm2200_mixer_texts[] = { "None", "Tone Generator", - "AEC loopback", + "AEC Loopback", "IN1L", "IN1R", "IN2L", @@ -897,8 +1019,6 @@ static const char *wm2200_mixer_texts[] = { "EQR", "LHPF1", "LHPF2", - "LHPF3", - "LHPF4", "DSP1.1", "DSP1.2", "DSP1.3", @@ -931,7 +1051,6 @@ static int wm2200_mixer_values[] = { 0x25, 0x50, /* EQ */ 0x51, - 0x52, 0x60, /* LHPF1 */ 0x61, /* LHPF2 */ 0x68, /* DSP1 */ @@ -976,6 +1095,20 @@ static int wm2200_mixer_values[] = { static WM2200_MUX_CTL_DECL(name##_in3); \ static WM2200_MUX_CTL_DECL(name##_in4) +#define WM2200_DSP_ENUMS(name, base_reg) \ + static WM2200_MUX_ENUM_DECL(name##_aux1_enum, base_reg); \ + static WM2200_MUX_ENUM_DECL(name##_aux2_enum, base_reg + 1); \ + static WM2200_MUX_ENUM_DECL(name##_aux3_enum, base_reg + 2); \ + static WM2200_MUX_ENUM_DECL(name##_aux4_enum, base_reg + 3); \ + static WM2200_MUX_ENUM_DECL(name##_aux5_enum, base_reg + 4); \ + static WM2200_MUX_ENUM_DECL(name##_aux6_enum, base_reg + 5); \ + static WM2200_MUX_CTL_DECL(name##_aux1); \ + static WM2200_MUX_CTL_DECL(name##_aux2); \ + static WM2200_MUX_CTL_DECL(name##_aux3); \ + static WM2200_MUX_CTL_DECL(name##_aux4); \ + static WM2200_MUX_CTL_DECL(name##_aux5); \ + static WM2200_MUX_CTL_DECL(name##_aux6); + static const struct snd_kcontrol_new wm2200_snd_controls[] = { SOC_SINGLE("IN1 High Performance Switch", WM2200_IN1L_CONTROL, WM2200_IN1_OSR_SHIFT, 1, 0), @@ -1051,6 +1184,9 @@ WM2200_MIXER_ENUMS(DSP1R, WM2200_DSP1RMIX_INPUT_1_SOURCE); WM2200_MIXER_ENUMS(DSP2L, WM2200_DSP2LMIX_INPUT_1_SOURCE); WM2200_MIXER_ENUMS(DSP2R, WM2200_DSP2RMIX_INPUT_1_SOURCE); +WM2200_DSP_ENUMS(DSP1, WM2200_DSP1AUX1MIX_INPUT_1_SOURCE); +WM2200_DSP_ENUMS(DSP2, WM2200_DSP2AUX1MIX_INPUT_1_SOURCE); + WM2200_MIXER_ENUMS(LHPF1, WM2200_LHPF1MIX_INPUT_1_SOURCE); WM2200_MIXER_ENUMS(LHPF2, WM2200_LHPF2MIX_INPUT_1_SOURCE); @@ -1064,8 +1200,19 @@ WM2200_MIXER_ENUMS(LHPF2, WM2200_LHPF2MIX_INPUT_1_SOURCE); WM2200_MUX(name_str " Input 4", &name##_in4_mux), \ SND_SOC_DAPM_MIXER(name_str " Mixer", SND_SOC_NOPM, 0, 0, NULL, 0) +#define WM2200_DSP_WIDGETS(name, name_str) \ + WM2200_MIXER_WIDGETS(name##L, name_str "L"), \ + WM2200_MIXER_WIDGETS(name##R, name_str "R"), \ + WM2200_MUX(name_str " Aux 1", &name##_aux1_mux), \ + WM2200_MUX(name_str " Aux 2", &name##_aux2_mux), \ + WM2200_MUX(name_str " Aux 3", &name##_aux3_mux), \ + WM2200_MUX(name_str " Aux 4", &name##_aux4_mux), \ + WM2200_MUX(name_str " Aux 5", &name##_aux5_mux), \ + WM2200_MUX(name_str " Aux 6", &name##_aux6_mux) + #define WM2200_MIXER_INPUT_ROUTES(name) \ { name, "Tone Generator", "Tone Generator" }, \ + { name, "AEC Loopback", "AEC Loopback" }, \ { name, "IN1L", "IN1L PGA" }, \ { name, "IN1R", "IN1R PGA" }, \ { name, "IN2L", "IN2L PGA" }, \ @@ -1106,6 +1253,33 @@ WM2200_MIXER_ENUMS(LHPF2, WM2200_LHPF2MIX_INPUT_1_SOURCE); WM2200_MIXER_INPUT_ROUTES(name " Input 3"), \ WM2200_MIXER_INPUT_ROUTES(name " Input 4") +#define WM2200_DSP_AUX_ROUTES(name) \ + { name, NULL, name " Aux 1" }, \ + { name, NULL, name " Aux 2" }, \ + { name, NULL, name " Aux 3" }, \ + { name, NULL, name " Aux 4" }, \ + { name, NULL, name " Aux 5" }, \ + { name, NULL, name " Aux 6" }, \ + WM2200_MIXER_INPUT_ROUTES(name " Aux 1"), \ + WM2200_MIXER_INPUT_ROUTES(name " Aux 2"), \ + WM2200_MIXER_INPUT_ROUTES(name " Aux 3"), \ + WM2200_MIXER_INPUT_ROUTES(name " Aux 4"), \ + WM2200_MIXER_INPUT_ROUTES(name " Aux 5"), \ + WM2200_MIXER_INPUT_ROUTES(name " Aux 6") + +static const char *wm2200_aec_loopback_texts[] = { + "OUT1L", "OUT1R", "OUT2L", "OUT2R", +}; + +static const struct soc_enum wm2200_aec_loopback = + SOC_ENUM_SINGLE(WM2200_DAC_AEC_CONTROL_1, + WM2200_AEC_LOOPBACK_SRC_SHIFT, + ARRAY_SIZE(wm2200_aec_loopback_texts), + wm2200_aec_loopback_texts); + +static const struct snd_kcontrol_new wm2200_aec_loopback_mux = + SOC_DAPM_ENUM("AEC Loopback", wm2200_aec_loopback); + static const struct snd_soc_dapm_widget wm2200_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY("SYSCLK", WM2200_CLOCKING_3, WM2200_SYSCLK_ENA_SHIFT, 0, NULL, 0), @@ -1165,8 +1339,8 @@ SND_SOC_DAPM_PGA("LHPF1", WM2200_HPLPF1_1, WM2200_LHPF1_ENA_SHIFT, 0, SND_SOC_DAPM_PGA("LHPF2", WM2200_HPLPF2_1, WM2200_LHPF2_ENA_SHIFT, 0, NULL, 0), -SND_SOC_DAPM_PGA_E("DSP1", SND_SOC_NOPM, 0, 0, NULL, 0, NULL, 0), -SND_SOC_DAPM_PGA_E("DSP2", SND_SOC_NOPM, 1, 0, NULL, 0, NULL, 0), +WM_ADSP1("DSP1", 0), +WM_ADSP1("DSP2", 1), SND_SOC_DAPM_AIF_OUT("AIF1TX1", "Capture", 0, WM2200_AUDIO_IF_1_22, WM2200_AIF1TX1_ENA_SHIFT, 0), @@ -1181,6 +1355,9 @@ SND_SOC_DAPM_AIF_OUT("AIF1TX5", "Capture", 4, SND_SOC_DAPM_AIF_OUT("AIF1TX6", "Capture", 5, WM2200_AUDIO_IF_1_22, WM2200_AIF1TX6_ENA_SHIFT, 0), +SND_SOC_DAPM_MUX("AEC Loopback", WM2200_DAC_AEC_CONTROL_1, + WM2200_AEC_LOOPBACK_ENA_SHIFT, 0, &wm2200_aec_loopback_mux), + SND_SOC_DAPM_PGA_S("OUT1L", 0, WM2200_OUTPUT_ENABLES, WM2200_OUT1L_ENA_SHIFT, 0, NULL, 0), SND_SOC_DAPM_PGA_S("OUT1R", 0, WM2200_OUTPUT_ENABLES, @@ -1231,10 +1408,8 @@ WM2200_MIXER_WIDGETS(EQR, "EQR"), WM2200_MIXER_WIDGETS(LHPF1, "LHPF1"), WM2200_MIXER_WIDGETS(LHPF2, "LHPF2"), -WM2200_MIXER_WIDGETS(DSP1L, "DSP1L"), -WM2200_MIXER_WIDGETS(DSP1R, "DSP1R"), -WM2200_MIXER_WIDGETS(DSP2L, "DSP2L"), -WM2200_MIXER_WIDGETS(DSP2R, "DSP2R"), +WM2200_DSP_WIDGETS(DSP1, "DSP1"), +WM2200_DSP_WIDGETS(DSP2, "DSP2"), WM2200_MIXER_WIDGETS(AIF1TX1, "AIF1TX1"), WM2200_MIXER_WIDGETS(AIF1TX2, "AIF1TX2"), @@ -1326,11 +1501,19 @@ static const struct snd_soc_dapm_route wm2200_dapm_routes[] = { { "SPK", NULL, "OUT2L" }, { "SPK", NULL, "OUT2R" }, + { "AEC Loopback", "OUT1L", "OUT1L" }, + { "AEC Loopback", "OUT1R", "OUT1R" }, + { "AEC Loopback", "OUT2L", "OUT2L" }, + { "AEC Loopback", "OUT2R", "OUT2R" }, + WM2200_MIXER_ROUTES("DSP1", "DSP1L"), WM2200_MIXER_ROUTES("DSP1", "DSP1R"), WM2200_MIXER_ROUTES("DSP2", "DSP2L"), WM2200_MIXER_ROUTES("DSP2", "DSP2R"), + WM2200_DSP_AUX_ROUTES("DSP1"), + WM2200_DSP_AUX_ROUTES("DSP2"), + WM2200_MIXER_ROUTES("OUT1L", "OUT1L"), WM2200_MIXER_ROUTES("OUT1R", "OUT1R"), WM2200_MIXER_ROUTES("OUT2L", "OUT2L"), @@ -1380,15 +1563,9 @@ static int wm2200_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) case SND_SOC_DAIFMT_DSP_A: fmt_val = 0; break; - case SND_SOC_DAIFMT_DSP_B: - fmt_val = 1; - break; case SND_SOC_DAIFMT_I2S: fmt_val = 2; break; - case SND_SOC_DAIFMT_LEFT_J: - fmt_val = 3; - break; default: dev_err(codec->dev, "Unsupported DAI format %d\n", fmt & SND_SOC_DAIFMT_FORMAT_MASK); @@ -1440,7 +1617,7 @@ static int wm2200_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) WM2200_AIF1TX_LRCLK_MSTR | WM2200_AIF1TX_LRCLK_INV, lrclk); snd_soc_update_bits(codec, WM2200_AUDIO_IF_1_5, - WM2200_AIF1_FMT_MASK << 1, fmt_val << 1); + WM2200_AIF1_FMT_MASK, fmt_val); return 0; } @@ -1968,12 +2145,15 @@ static const struct regmap_config wm2200_regmap = { .reg_bits = 16, .val_bits = 16, - .max_register = WM2200_MAX_REGISTER, + .max_register = WM2200_MAX_REGISTER + (ARRAY_SIZE(wm2200_ranges) * + WM2200_DSP_SPACING), .reg_defaults = wm2200_reg_defaults, .num_reg_defaults = ARRAY_SIZE(wm2200_reg_defaults), .volatile_reg = wm2200_volatile_register, .readable_reg = wm2200_readable_register, .cache_type = REGCACHE_RBTREE, + .ranges = wm2200_ranges, + .num_ranges = ARRAY_SIZE(wm2200_ranges), }; static const unsigned int wm2200_dig_vu[] = { @@ -1995,8 +2175,8 @@ static const unsigned int wm2200_mic_ctrl_reg[] = { WM2200_IN3L_CONTROL, }; -static __devinit int wm2200_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm2200_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) { struct wm2200_pdata *pdata = dev_get_platdata(&i2c->dev); struct wm2200_priv *wm2200; @@ -2011,14 +2191,30 @@ static __devinit int wm2200_i2c_probe(struct i2c_client *i2c, wm2200->dev = &i2c->dev; init_completion(&wm2200->fll_lock); - wm2200->regmap = regmap_init_i2c(i2c, &wm2200_regmap); + wm2200->regmap = devm_regmap_init_i2c(i2c, &wm2200_regmap); if (IS_ERR(wm2200->regmap)) { ret = PTR_ERR(wm2200->regmap); dev_err(&i2c->dev, "Failed to allocate register map: %d\n", ret); - goto err; + return ret; + } + + for (i = 0; i < 2; i++) { + wm2200->dsp[i].type = WMFW_ADSP1; + wm2200->dsp[i].part = "wm2200"; + wm2200->dsp[i].num = i + 1; + wm2200->dsp[i].dev = &i2c->dev; + wm2200->dsp[i].regmap = wm2200->regmap; } + wm2200->dsp[0].base = WM2200_DSP1_CONTROL_1; + wm2200->dsp[0].mem = wm2200_dsp1_regions; + wm2200->dsp[0].num_mems = ARRAY_SIZE(wm2200_dsp1_regions); + + wm2200->dsp[1].base = WM2200_DSP2_CONTROL_1; + wm2200->dsp[1].mem = wm2200_dsp2_regions; + wm2200->dsp[1].num_mems = ARRAY_SIZE(wm2200_dsp2_regions); + if (pdata) wm2200->pdata = *pdata; @@ -2027,12 +2223,13 @@ static __devinit int wm2200_i2c_probe(struct i2c_client *i2c, for (i = 0; i < ARRAY_SIZE(wm2200->core_supplies); i++) wm2200->core_supplies[i].supply = wm2200_core_supply_names[i]; - ret = regulator_bulk_get(&i2c->dev, ARRAY_SIZE(wm2200->core_supplies), - wm2200->core_supplies); + ret = devm_regulator_bulk_get(&i2c->dev, + ARRAY_SIZE(wm2200->core_supplies), + wm2200->core_supplies); if (ret != 0) { dev_err(&i2c->dev, "Failed to request core supplies: %d\n", ret); - goto err_regmap; + return ret; } ret = regulator_bulk_enable(ARRAY_SIZE(wm2200->core_supplies), @@ -2040,12 +2237,13 @@ static __devinit int wm2200_i2c_probe(struct i2c_client *i2c, if (ret != 0) { dev_err(&i2c->dev, "Failed to enable core supplies: %d\n", ret); - goto err_core; + return ret; } if (wm2200->pdata.ldo_ena) { - ret = gpio_request_one(wm2200->pdata.ldo_ena, - GPIOF_OUT_INIT_HIGH, "WM2200 LDOENA"); + ret = devm_gpio_request_one(&i2c->dev, wm2200->pdata.ldo_ena, + GPIOF_OUT_INIT_HIGH, + "WM2200 LDOENA"); if (ret < 0) { dev_err(&i2c->dev, "Failed to request LDOENA %d: %d\n", wm2200->pdata.ldo_ena, ret); @@ -2055,8 +2253,9 @@ static __devinit int wm2200_i2c_probe(struct i2c_client *i2c, } if (wm2200->pdata.reset) { - ret = gpio_request_one(wm2200->pdata.reset, - GPIOF_OUT_INIT_HIGH, "WM2200 /RESET"); + ret = devm_gpio_request_one(&i2c->dev, wm2200->pdata.reset, + GPIOF_OUT_INIT_HIGH, + "WM2200 /RESET"); if (ret < 0) { dev_err(&i2c->dev, "Failed to request /RESET %d: %d\n", wm2200->pdata.reset, ret); @@ -2166,45 +2365,28 @@ static __devinit int wm2200_i2c_probe(struct i2c_client *i2c, err_pm_runtime: pm_runtime_disable(&i2c->dev); err_reset: - if (wm2200->pdata.reset) { + if (wm2200->pdata.reset) gpio_set_value_cansleep(wm2200->pdata.reset, 0); - gpio_free(wm2200->pdata.reset); - } err_ldo: - if (wm2200->pdata.ldo_ena) { + if (wm2200->pdata.ldo_ena) gpio_set_value_cansleep(wm2200->pdata.ldo_ena, 0); - gpio_free(wm2200->pdata.ldo_ena); - } err_enable: regulator_bulk_disable(ARRAY_SIZE(wm2200->core_supplies), wm2200->core_supplies); -err_core: - regulator_bulk_free(ARRAY_SIZE(wm2200->core_supplies), - wm2200->core_supplies); -err_regmap: - regmap_exit(wm2200->regmap); -err: return ret; } -static __devexit int wm2200_i2c_remove(struct i2c_client *i2c) +static int wm2200_i2c_remove(struct i2c_client *i2c) { struct wm2200_priv *wm2200 = i2c_get_clientdata(i2c); snd_soc_unregister_codec(&i2c->dev); if (i2c->irq) free_irq(i2c->irq, wm2200); - if (wm2200->pdata.reset) { + if (wm2200->pdata.reset) gpio_set_value_cansleep(wm2200->pdata.reset, 0); - gpio_free(wm2200->pdata.reset); - } - if (wm2200->pdata.ldo_ena) { + if (wm2200->pdata.ldo_ena) gpio_set_value_cansleep(wm2200->pdata.ldo_ena, 0); - gpio_free(wm2200->pdata.ldo_ena); - } - regulator_bulk_free(ARRAY_SIZE(wm2200->core_supplies), - wm2200->core_supplies); - regmap_exit(wm2200->regmap); return 0; } @@ -2267,7 +2449,7 @@ static struct i2c_driver wm2200_i2c_driver = { .pm = &wm2200_pm, }, .probe = wm2200_i2c_probe, - .remove = __devexit_p(wm2200_i2c_remove), + .remove = wm2200_i2c_remove, .id_table = wm2200_i2c_id, }; diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c index 7f567585832e..54397a508073 100644 --- a/sound/soc/codecs/wm5100.c +++ b/sound/soc/codecs/wm5100.c @@ -1233,7 +1233,7 @@ static const struct snd_soc_dapm_route wm5100_dapm_routes[] = { { "PWM2", NULL, "PWM2 Driver" }, }; -static const __devinitconst struct reg_default wm5100_reva_patches[] = { +static const struct reg_default wm5100_reva_patches[] = { { WM5100_AUDIO_IF_1_10, 0 }, { WM5100_AUDIO_IF_1_11, 1 }, { WM5100_AUDIO_IF_1_12, 2 }, @@ -1279,15 +1279,9 @@ static int wm5100_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) case SND_SOC_DAIFMT_DSP_A: mask = 0; break; - case SND_SOC_DAIFMT_DSP_B: - mask = 1; - break; case SND_SOC_DAIFMT_I2S: mask = 2; break; - case SND_SOC_DAIFMT_LEFT_J: - mask = 3; - break; default: dev_err(codec->dev, "Unsupported DAI format %d\n", fmt & SND_SOC_DAIFMT_FORMAT_MASK); @@ -2414,8 +2408,8 @@ static const unsigned int wm5100_mic_ctrl_reg[] = { WM5100_IN4L_CONTROL, }; -static __devinit int wm5100_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm5100_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) { struct wm5100_pdata *pdata = dev_get_platdata(&i2c->dev); struct wm5100_priv *wm5100; @@ -2639,7 +2633,7 @@ err: return ret; } -static __devexit int wm5100_i2c_remove(struct i2c_client *i2c) +static int wm5100_i2c_remove(struct i2c_client *i2c) { struct wm5100_priv *wm5100 = i2c_get_clientdata(i2c); @@ -2717,7 +2711,7 @@ static struct i2c_driver wm5100_i2c_driver = { .pm = &wm5100_pm, }, .probe = wm5100_i2c_probe, - .remove = __devexit_p(wm5100_i2c_remove), + .remove = wm5100_i2c_remove, .id_table = wm5100_i2c_id, }; diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index 7394e73fa43c..1440b3f9b7bb 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c @@ -31,10 +31,14 @@ #include "arizona.h" #include "wm5102.h" +#include "wm_adsp.h" struct wm5102_priv { struct arizona_priv core; struct arizona_fll fll[2]; + + unsigned int spk_ena:2; + unsigned int spk_ena_pending:1; }; static DECLARE_TLV_DB_SCALE(ana_tlv, 0, 100, 0); @@ -42,6 +46,13 @@ static DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0); static DECLARE_TLV_DB_SCALE(digital_tlv, -6400, 50, 0); static DECLARE_TLV_DB_SCALE(noise_tlv, 0, 600, 0); +static const struct wm_adsp_region wm5102_dsp1_regions[] = { + { .type = WMFW_ADSP2_PM, .base = 0x100000 }, + { .type = WMFW_ADSP2_ZM, .base = 0x180000 }, + { .type = WMFW_ADSP2_XM, .base = 0x190000 }, + { .type = WMFW_ADSP2_YM, .base = 0x1a8000 }, +}; + static const struct reg_default wm5102_sysclk_reva_patch[] = { { 0x3000, 0x2225 }, { 0x3001, 0x3a03 }, @@ -627,11 +638,23 @@ SOC_DOUBLE_R_TLV("IN3 Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_3L, ARIZONA_ADC_DIGITAL_VOLUME_3R, ARIZONA_IN3L_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv), +SOC_ENUM("Input Ramp Up", arizona_in_vi_ramp), +SOC_ENUM("Input Ramp Down", arizona_in_vd_ramp), + ARIZONA_MIXER_CONTROLS("EQ1", ARIZONA_EQ1MIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("EQ2", ARIZONA_EQ2MIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("EQ3", ARIZONA_EQ3MIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("EQ4", ARIZONA_EQ4MIX_INPUT_1_SOURCE), +SND_SOC_BYTES_MASK("EQ1 Coefficeints", ARIZONA_EQ1_1, 21, + ARIZONA_EQ1_ENA_MASK), +SND_SOC_BYTES_MASK("EQ2 Coefficeints", ARIZONA_EQ2_1, 21, + ARIZONA_EQ2_ENA_MASK), +SND_SOC_BYTES_MASK("EQ3 Coefficeints", ARIZONA_EQ3_1, 21, + ARIZONA_EQ3_ENA_MASK), +SND_SOC_BYTES_MASK("EQ4 Coefficeints", ARIZONA_EQ4_1, 21, + ARIZONA_EQ4_ENA_MASK), + SOC_SINGLE_TLV("EQ1 B1 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B1_GAIN_SHIFT, 24, 0, eq_tlv), SOC_SINGLE_TLV("EQ1 B2 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B2_GAIN_SHIFT, @@ -687,6 +710,14 @@ ARIZONA_MIXER_CONTROLS("LHPF2", ARIZONA_HPLP2MIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("LHPF3", ARIZONA_HPLP3MIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("LHPF4", ARIZONA_HPLP4MIX_INPUT_1_SOURCE), +SND_SOC_BYTES("LHPF1 Coefficients", ARIZONA_HPLPF1_2, 1), +SND_SOC_BYTES("LHPF2 Coefficients", ARIZONA_HPLPF2_2, 1), +SND_SOC_BYTES("LHPF3 Coefficients", ARIZONA_HPLPF3_2, 1), +SND_SOC_BYTES("LHPF4 Coefficients", ARIZONA_HPLPF4_2, 1), + +ARIZONA_MIXER_CONTROLS("DSP1L", ARIZONA_DSP1LMIX_INPUT_1_SOURCE), +ARIZONA_MIXER_CONTROLS("DSP1R", ARIZONA_DSP1RMIX_INPUT_1_SOURCE), + SOC_ENUM("LHPF1 Mode", arizona_lhpf1_mode), SOC_ENUM("LHPF2 Mode", arizona_lhpf2_mode), SOC_ENUM("LHPF3 Mode", arizona_lhpf3_mode), @@ -708,14 +739,6 @@ ARIZONA_MIXER_CONTROLS("SPKOUTR", ARIZONA_OUT4RMIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("SPKDAT1L", ARIZONA_OUT5LMIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("SPKDAT1R", ARIZONA_OUT5RMIX_INPUT_1_SOURCE), -SOC_SINGLE("HPOUT1 High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_1L, - ARIZONA_OUT1_OSR_SHIFT, 1, 0), -SOC_SINGLE("OUT2 High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_2L, - ARIZONA_OUT2_OSR_SHIFT, 1, 0), -SOC_SINGLE("EPOUT High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_3L, - ARIZONA_OUT3_OSR_SHIFT, 1, 0), -SOC_SINGLE("Speaker High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_4L, - ARIZONA_OUT4_OSR_SHIFT, 1, 0), SOC_SINGLE("SPKDAT1 High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_5L, ARIZONA_OUT5_OSR_SHIFT, 1, 0), @@ -745,16 +768,8 @@ SOC_DOUBLE_R_TLV("SPKDAT1 Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_5L, ARIZONA_DAC_DIGITAL_VOLUME_5R, ARIZONA_OUT5L_VOL_SHIFT, 0xbf, 0, digital_tlv), -SOC_DOUBLE_R_RANGE_TLV("HPOUT1 Volume", ARIZONA_OUTPUT_PATH_CONFIG_1L, - ARIZONA_OUTPUT_PATH_CONFIG_1R, - ARIZONA_OUT1L_PGA_VOL_SHIFT, - 0x34, 0x40, 0, ana_tlv), -SOC_DOUBLE_R_RANGE_TLV("OUT2 Volume", ARIZONA_OUTPUT_PATH_CONFIG_2L, - ARIZONA_OUTPUT_PATH_CONFIG_2R, - ARIZONA_OUT2L_PGA_VOL_SHIFT, - 0x34, 0x40, 0, ana_tlv), -SOC_SINGLE_RANGE_TLV("EPOUT Volume", ARIZONA_OUTPUT_PATH_CONFIG_3L, - ARIZONA_OUT3L_PGA_VOL_SHIFT, 0x34, 0x40, 0, ana_tlv), +SOC_ENUM("Output Ramp Up", arizona_out_vi_ramp), +SOC_ENUM("Output Ramp Down", arizona_out_vd_ramp), SOC_DOUBLE("SPKDAT1 Switch", ARIZONA_PDM_SPK1_CTRL_1, ARIZONA_SPK1L_MUTE_SHIFT, ARIZONA_SPK1R_MUTE_SHIFT, 1, 1), @@ -775,6 +790,47 @@ ARIZONA_MIXER_CONTROLS("AIF3TX1", ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("AIF3TX2", ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE), }; +static int wm5102_spk_ev(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_codec *codec = w->codec; + struct arizona *arizona = dev_get_drvdata(codec->dev->parent); + struct wm5102_priv *wm5102 = snd_soc_codec_get_drvdata(codec); + + if (arizona->rev < 1) + return 0; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (!wm5102->spk_ena) { + snd_soc_write(codec, 0x4f5, 0x25a); + wm5102->spk_ena_pending = true; + } + break; + case SND_SOC_DAPM_POST_PMU: + if (wm5102->spk_ena_pending) { + msleep(75); + snd_soc_write(codec, 0x4f5, 0xda); + wm5102->spk_ena_pending = false; + wm5102->spk_ena++; + } + break; + case SND_SOC_DAPM_PRE_PMD: + wm5102->spk_ena--; + if (!wm5102->spk_ena) + snd_soc_write(codec, 0x4f5, 0x25a); + break; + case SND_SOC_DAPM_POST_PMD: + if (!wm5102->spk_ena) + snd_soc_write(codec, 0x4f5, 0x0da); + break; + } + + return 0; +} + + ARIZONA_MIXER_ENUMS(EQ1, ARIZONA_EQ1MIX_INPUT_1_SOURCE); ARIZONA_MIXER_ENUMS(EQ2, ARIZONA_EQ2MIX_INPUT_1_SOURCE); ARIZONA_MIXER_ENUMS(EQ3, ARIZONA_EQ3MIX_INPUT_1_SOURCE); @@ -819,11 +875,15 @@ ARIZONA_MIXER_ENUMS(AIF2TX2, ARIZONA_AIF2TX2MIX_INPUT_1_SOURCE); ARIZONA_MIXER_ENUMS(AIF3TX1, ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE); ARIZONA_MIXER_ENUMS(AIF3TX2, ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE); -ARIZONA_MIXER_ENUMS(ASRC1L, ARIZONA_ASRC1LMIX_INPUT_1_SOURCE); -ARIZONA_MIXER_ENUMS(ASRC1R, ARIZONA_ASRC1RMIX_INPUT_1_SOURCE); -ARIZONA_MIXER_ENUMS(ASRC2L, ARIZONA_ASRC2LMIX_INPUT_1_SOURCE); -ARIZONA_MIXER_ENUMS(ASRC2R, ARIZONA_ASRC2RMIX_INPUT_1_SOURCE); +ARIZONA_MUX_ENUMS(ASRC1L, ARIZONA_ASRC1LMIX_INPUT_1_SOURCE); +ARIZONA_MUX_ENUMS(ASRC1R, ARIZONA_ASRC1RMIX_INPUT_1_SOURCE); +ARIZONA_MUX_ENUMS(ASRC2L, ARIZONA_ASRC2LMIX_INPUT_1_SOURCE); +ARIZONA_MUX_ENUMS(ASRC2R, ARIZONA_ASRC2RMIX_INPUT_1_SOURCE); + +ARIZONA_MIXER_ENUMS(DSP1L, ARIZONA_DSP1LMIX_INPUT_1_SOURCE); +ARIZONA_MIXER_ENUMS(DSP1R, ARIZONA_DSP1RMIX_INPUT_1_SOURCE); +ARIZONA_DSP_AUX_ENUMS(DSP1, ARIZONA_DSP1AUX1MIX_INPUT_1_SOURCE); static const char *wm5102_aec_loopback_texts[] = { "HPOUT1L", "HPOUT1R", "HPOUT2L", "HPOUT2R", "EPOUT", @@ -836,8 +896,7 @@ static const unsigned int wm5102_aec_loopback_values[] = { static const struct soc_enum wm5102_aec_loopback = SOC_VALUE_ENUM_SINGLE(ARIZONA_DAC_AEC_CONTROL_1, - ARIZONA_AEC_LOOPBACK_SRC_SHIFT, - ARIZONA_AEC_LOOPBACK_SRC_MASK, + ARIZONA_AEC_LOOPBACK_SRC_SHIFT, 0xf, ARRAY_SIZE(wm5102_aec_loopback_texts), wm5102_aec_loopback_texts, wm5102_aec_loopback_values); @@ -864,6 +923,7 @@ SND_SOC_DAPM_REGULATOR_SUPPLY("SPKVDDR", 0, 0), SND_SOC_DAPM_SIGGEN("TONE"), SND_SOC_DAPM_SIGGEN("NOISE"), +SND_SOC_DAPM_SIGGEN("HAPTICS"), SND_SOC_DAPM_INPUT("IN1L"), SND_SOC_DAPM_INPUT("IN1R"), @@ -894,9 +954,9 @@ SND_SOC_DAPM_PGA_E("IN3R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN3R_ENA_SHIFT, SND_SOC_DAPM_SUPPLY("MICBIAS1", ARIZONA_MIC_BIAS_CTRL_1, ARIZONA_MICB1_ENA_SHIFT, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("MICBIAS2", ARIZONA_MIC_BIAS_CTRL_2, - ARIZONA_MICB1_ENA_SHIFT, 0, NULL, 0), + ARIZONA_MICB2_ENA_SHIFT, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("MICBIAS3", ARIZONA_MIC_BIAS_CTRL_3, - ARIZONA_MICB1_ENA_SHIFT, 0, NULL, 0), + ARIZONA_MICB3_ENA_SHIFT, 0, NULL, 0), SND_SOC_DAPM_PGA("Noise Generator", ARIZONA_COMFORT_NOISE_GENERATOR, ARIZONA_NOISE_GEN_ENA_SHIFT, 0, NULL, 0), @@ -996,6 +1056,8 @@ SND_SOC_DAPM_AIF_IN("AIF3RX1", NULL, 0, SND_SOC_DAPM_AIF_IN("AIF3RX2", NULL, 0, ARIZONA_AIF3_RX_ENABLES, ARIZONA_AIF3RX2_ENA_SHIFT, 0), +ARIZONA_DSP_WIDGETS(DSP1, "DSP1"), + SND_SOC_DAPM_VALUE_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1, ARIZONA_AEC_LOOPBACK_ENA, 0, &wm5102_aec_loopback_mux), @@ -1015,10 +1077,10 @@ SND_SOC_DAPM_PGA_E("OUT3L", ARIZONA_OUTPUT_ENABLES_1, ARIZONA_OUT3L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_PGA_E("OUT4L", ARIZONA_OUTPUT_ENABLES_1, - ARIZONA_OUT4L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, + ARIZONA_OUT4L_ENA_SHIFT, 0, NULL, 0, wm5102_spk_ev, SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_PGA_E("OUT4R", ARIZONA_OUTPUT_ENABLES_1, - ARIZONA_OUT4R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, + ARIZONA_OUT4R_ENA_SHIFT, 0, NULL, 0, wm5102_spk_ev, SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_PGA_E("OUT5L", ARIZONA_OUTPUT_ENABLES_1, ARIZONA_OUT5L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, @@ -1071,10 +1133,12 @@ ARIZONA_MIXER_WIDGETS(AIF2TX2, "AIF2TX2"), ARIZONA_MIXER_WIDGETS(AIF3TX1, "AIF3TX1"), ARIZONA_MIXER_WIDGETS(AIF3TX2, "AIF3TX2"), -ARIZONA_MIXER_WIDGETS(ASRC1L, "ASRC1L"), -ARIZONA_MIXER_WIDGETS(ASRC1R, "ASRC1R"), -ARIZONA_MIXER_WIDGETS(ASRC2L, "ASRC2L"), -ARIZONA_MIXER_WIDGETS(ASRC2R, "ASRC2R"), +ARIZONA_MUX_WIDGETS(ASRC1L, "ASRC1L"), +ARIZONA_MUX_WIDGETS(ASRC1R, "ASRC1R"), +ARIZONA_MUX_WIDGETS(ASRC2L, "ASRC2L"), +ARIZONA_MUX_WIDGETS(ASRC2R, "ASRC2R"), + +WM_ADSP2("DSP1", 0), SND_SOC_DAPM_OUTPUT("HPOUT1L"), SND_SOC_DAPM_OUTPUT("HPOUT1R"), @@ -1094,6 +1158,7 @@ SND_SOC_DAPM_OUTPUT("SPKDAT1R"), { name, "Noise Generator", "Noise Generator" }, \ { name, "Tone Generator 1", "Tone Generator 1" }, \ { name, "Tone Generator 2", "Tone Generator 2" }, \ + { name, "Haptics", "HAPTICS" }, \ { name, "AEC", "AEC Loopback" }, \ { name, "IN1L", "IN1L PGA" }, \ { name, "IN1R", "IN1R PGA" }, \ @@ -1127,7 +1192,13 @@ SND_SOC_DAPM_OUTPUT("SPKDAT1R"), { name, "ASRC1L", "ASRC1L" }, \ { name, "ASRC1R", "ASRC1R" }, \ { name, "ASRC2L", "ASRC2L" }, \ - { name, "ASRC2R", "ASRC2R" } + { name, "ASRC2R", "ASRC2R" }, \ + { name, "DSP1.1", "DSP1" }, \ + { name, "DSP1.2", "DSP1" }, \ + { name, "DSP1.3", "DSP1" }, \ + { name, "DSP1.4", "DSP1" }, \ + { name, "DSP1.5", "DSP1" }, \ + { name, "DSP1.6", "DSP1" } static const struct snd_soc_dapm_route wm5102_dapm_routes[] = { { "AIF2 Capture", NULL, "DBVDD2" }, @@ -1213,6 +1284,11 @@ static const struct snd_soc_dapm_route wm5102_dapm_routes[] = { { "IN3L PGA", NULL, "IN3L" }, { "IN3R PGA", NULL, "IN3R" }, + { "ASRC1L", NULL, "ASRC1L Input" }, + { "ASRC1R", NULL, "ASRC1R Input" }, + { "ASRC2L", NULL, "ASRC2L Input" }, + { "ASRC2R", NULL, "ASRC2R Input" }, + ARIZONA_MIXER_ROUTES("OUT1L", "HPOUT1L"), ARIZONA_MIXER_ROUTES("OUT1R", "HPOUT1R"), ARIZONA_MIXER_ROUTES("OUT2L", "HPOUT2L"), @@ -1255,10 +1331,12 @@ static const struct snd_soc_dapm_route wm5102_dapm_routes[] = { ARIZONA_MIXER_ROUTES("LHPF3", "LHPF3"), ARIZONA_MIXER_ROUTES("LHPF4", "LHPF4"), - ARIZONA_MIXER_ROUTES("ASRC1L", "ASRC1L"), - ARIZONA_MIXER_ROUTES("ASRC1R", "ASRC1R"), - ARIZONA_MIXER_ROUTES("ASRC2L", "ASRC2L"), - ARIZONA_MIXER_ROUTES("ASRC2R", "ASRC2R"), + ARIZONA_MUX_ROUTES("ASRC1L"), + ARIZONA_MUX_ROUTES("ASRC1R"), + ARIZONA_MUX_ROUTES("ASRC2L"), + ARIZONA_MUX_ROUTES("ASRC2R"), + + ARIZONA_DSP_ROUTES("DSP1"), { "AEC Loopback", "HPOUT1L", "OUT1L" }, { "AEC Loopback", "HPOUT1R", "OUT1R" }, @@ -1377,9 +1455,28 @@ static struct snd_soc_dai_driver wm5102_dai[] = { static int wm5102_codec_probe(struct snd_soc_codec *codec) { struct wm5102_priv *priv = snd_soc_codec_get_drvdata(codec); + int ret; codec->control_data = priv->core.arizona->regmap; - return snd_soc_codec_set_cache_io(codec, 32, 16, SND_SOC_REGMAP); + + ret = snd_soc_codec_set_cache_io(codec, 32, 16, SND_SOC_REGMAP); + if (ret != 0) + return ret; + + snd_soc_dapm_disable_pin(&codec->dapm, "HAPTICS"); + + priv->core.arizona->dapm = &codec->dapm; + + return 0; +} + +static int wm5102_codec_remove(struct snd_soc_codec *codec) +{ + struct wm5102_priv *priv = snd_soc_codec_get_drvdata(codec); + + priv->core.arizona->dapm = NULL; + + return 0; } #define WM5102_DIG_VU 0x0200 @@ -1406,6 +1503,7 @@ static unsigned int wm5102_digital_vu[] = { static struct snd_soc_codec_driver soc_codec_dev_wm5102 = { .probe = wm5102_codec_probe, + .remove = wm5102_codec_remove, .idle_bias_off = true, @@ -1420,11 +1518,11 @@ static struct snd_soc_codec_driver soc_codec_dev_wm5102 = { .num_dapm_routes = ARRAY_SIZE(wm5102_dapm_routes), }; -static int __devinit wm5102_probe(struct platform_device *pdev) +static int wm5102_probe(struct platform_device *pdev) { struct arizona *arizona = dev_get_drvdata(pdev->dev.parent); struct wm5102_priv *wm5102; - int i; + int i, ret; wm5102 = devm_kzalloc(&pdev->dev, sizeof(struct wm5102_priv), GFP_KERNEL); @@ -1434,6 +1532,19 @@ static int __devinit wm5102_probe(struct platform_device *pdev) wm5102->core.arizona = arizona; + wm5102->core.adsp[0].part = "wm5102"; + wm5102->core.adsp[0].num = 1; + wm5102->core.adsp[0].type = WMFW_ADSP2; + wm5102->core.adsp[0].base = ARIZONA_DSP1_CONTROL_1; + wm5102->core.adsp[0].dev = arizona->dev; + wm5102->core.adsp[0].regmap = arizona->regmap; + wm5102->core.adsp[0].mem = wm5102_dsp1_regions; + wm5102->core.adsp[0].num_mems = ARRAY_SIZE(wm5102_dsp1_regions); + + ret = wm_adsp2_init(&wm5102->core.adsp[0], true); + if (ret != 0) + return ret; + for (i = 0; i < ARRAY_SIZE(wm5102->fll); i++) wm5102->fll[i].vco_mult = 1; @@ -1459,7 +1570,7 @@ static int __devinit wm5102_probe(struct platform_device *pdev) wm5102_dai, ARRAY_SIZE(wm5102_dai)); } -static int __devexit wm5102_remove(struct platform_device *pdev) +static int wm5102_remove(struct platform_device *pdev) { snd_soc_unregister_codec(&pdev->dev); pm_runtime_disable(&pdev->dev); @@ -1473,7 +1584,7 @@ static struct platform_driver wm5102_codec_driver = { .owner = THIS_MODULE, }, .probe = wm5102_probe, - .remove = __devexit_p(wm5102_remove), + .remove = wm5102_remove, }; module_platform_driver(wm5102_codec_driver); diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index 9211e4192f71..7a090968c4f7 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -84,11 +84,23 @@ SOC_DOUBLE_R_TLV("IN4 Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_4L, ARIZONA_ADC_DIGITAL_VOLUME_4R, ARIZONA_IN4L_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv), +SOC_ENUM("Input Ramp Up", arizona_in_vi_ramp), +SOC_ENUM("Input Ramp Down", arizona_in_vd_ramp), + ARIZONA_MIXER_CONTROLS("EQ1", ARIZONA_EQ1MIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("EQ2", ARIZONA_EQ2MIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("EQ3", ARIZONA_EQ3MIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("EQ4", ARIZONA_EQ4MIX_INPUT_1_SOURCE), +SND_SOC_BYTES_MASK("EQ1 Coefficeints", ARIZONA_EQ1_1, 21, + ARIZONA_EQ1_ENA_MASK), +SND_SOC_BYTES_MASK("EQ2 Coefficeints", ARIZONA_EQ2_1, 21, + ARIZONA_EQ2_ENA_MASK), +SND_SOC_BYTES_MASK("EQ3 Coefficeints", ARIZONA_EQ3_1, 21, + ARIZONA_EQ3_ENA_MASK), +SND_SOC_BYTES_MASK("EQ4 Coefficeints", ARIZONA_EQ4_1, 21, + ARIZONA_EQ4_ENA_MASK), + SOC_SINGLE_TLV("EQ1 B1 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B1_GAIN_SHIFT, 24, 0, eq_tlv), SOC_SINGLE_TLV("EQ1 B2 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B2_GAIN_SHIFT, @@ -148,6 +160,11 @@ ARIZONA_MIXER_CONTROLS("LHPF2", ARIZONA_HPLP2MIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("LHPF3", ARIZONA_HPLP3MIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("LHPF4", ARIZONA_HPLP4MIX_INPUT_1_SOURCE), +SND_SOC_BYTES("LHPF1 Coefficients", ARIZONA_HPLPF1_2, 1), +SND_SOC_BYTES("LHPF2 Coefficients", ARIZONA_HPLPF2_2, 1), +SND_SOC_BYTES("LHPF3 Coefficients", ARIZONA_HPLPF3_2, 1), +SND_SOC_BYTES("LHPF4 Coefficients", ARIZONA_HPLPF4_2, 1), + SOC_ENUM("LHPF1 Mode", arizona_lhpf1_mode), SOC_ENUM("LHPF2 Mode", arizona_lhpf2_mode), SOC_ENUM("LHPF3 Mode", arizona_lhpf3_mode), @@ -243,6 +260,9 @@ SOC_DOUBLE("SPKDAT1 Switch", ARIZONA_PDM_SPK1_CTRL_1, ARIZONA_SPK1L_MUTE_SHIFT, SOC_DOUBLE("SPKDAT2 Switch", ARIZONA_PDM_SPK2_CTRL_1, ARIZONA_SPK2L_MUTE_SHIFT, ARIZONA_SPK2R_MUTE_SHIFT, 1, 1), +SOC_ENUM("Output Ramp Up", arizona_out_vi_ramp), +SOC_ENUM("Output Ramp Down", arizona_out_vd_ramp), + ARIZONA_MIXER_CONTROLS("AIF1TX1", ARIZONA_AIF1TX1MIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("AIF1TX2", ARIZONA_AIF1TX2MIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("AIF1TX3", ARIZONA_AIF1TX3MIX_INPUT_1_SOURCE), @@ -308,10 +328,10 @@ ARIZONA_MIXER_ENUMS(AIF2TX2, ARIZONA_AIF2TX2MIX_INPUT_1_SOURCE); ARIZONA_MIXER_ENUMS(AIF3TX1, ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE); ARIZONA_MIXER_ENUMS(AIF3TX2, ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE); -ARIZONA_MIXER_ENUMS(ASRC1L, ARIZONA_ASRC1LMIX_INPUT_1_SOURCE); -ARIZONA_MIXER_ENUMS(ASRC1R, ARIZONA_ASRC1RMIX_INPUT_1_SOURCE); -ARIZONA_MIXER_ENUMS(ASRC2L, ARIZONA_ASRC2LMIX_INPUT_1_SOURCE); -ARIZONA_MIXER_ENUMS(ASRC2R, ARIZONA_ASRC2RMIX_INPUT_1_SOURCE); +ARIZONA_MUX_ENUMS(ASRC1L, ARIZONA_ASRC1LMIX_INPUT_1_SOURCE); +ARIZONA_MUX_ENUMS(ASRC1R, ARIZONA_ASRC1RMIX_INPUT_1_SOURCE); +ARIZONA_MUX_ENUMS(ASRC2L, ARIZONA_ASRC2LMIX_INPUT_1_SOURCE); +ARIZONA_MUX_ENUMS(ASRC2R, ARIZONA_ASRC2RMIX_INPUT_1_SOURCE); static const char *wm5110_aec_loopback_texts[] = { "HPOUT1L", "HPOUT1R", "HPOUT2L", "HPOUT2R", "HPOUT3L", "HPOUT3R", @@ -324,8 +344,7 @@ static const unsigned int wm5110_aec_loopback_values[] = { static const struct soc_enum wm5110_aec_loopback = SOC_VALUE_ENUM_SINGLE(ARIZONA_DAC_AEC_CONTROL_1, - ARIZONA_AEC_LOOPBACK_SRC_SHIFT, - ARIZONA_AEC_LOOPBACK_SRC_MASK, + ARIZONA_AEC_LOOPBACK_SRC_SHIFT, 0xf, ARRAY_SIZE(wm5110_aec_loopback_texts), wm5110_aec_loopback_texts, wm5110_aec_loopback_values); @@ -352,6 +371,7 @@ SND_SOC_DAPM_REGULATOR_SUPPLY("SPKVDDR", 0, 0), SND_SOC_DAPM_SIGGEN("TONE"), SND_SOC_DAPM_SIGGEN("NOISE"), +SND_SOC_DAPM_SIGGEN("HAPTICS"), SND_SOC_DAPM_INPUT("IN1L"), SND_SOC_DAPM_INPUT("IN1R"), @@ -585,10 +605,10 @@ ARIZONA_MIXER_WIDGETS(AIF2TX2, "AIF2TX2"), ARIZONA_MIXER_WIDGETS(AIF3TX1, "AIF3TX1"), ARIZONA_MIXER_WIDGETS(AIF3TX2, "AIF3TX2"), -ARIZONA_MIXER_WIDGETS(ASRC1L, "ASRC1L"), -ARIZONA_MIXER_WIDGETS(ASRC1R, "ASRC1R"), -ARIZONA_MIXER_WIDGETS(ASRC2L, "ASRC2L"), -ARIZONA_MIXER_WIDGETS(ASRC2R, "ASRC2R"), +ARIZONA_MUX_WIDGETS(ASRC1L, "ASRC1L"), +ARIZONA_MUX_WIDGETS(ASRC1R, "ASRC1R"), +ARIZONA_MUX_WIDGETS(ASRC2L, "ASRC2L"), +ARIZONA_MUX_WIDGETS(ASRC2R, "ASRC2R"), SND_SOC_DAPM_OUTPUT("HPOUT1L"), SND_SOC_DAPM_OUTPUT("HPOUT1R"), @@ -610,6 +630,7 @@ SND_SOC_DAPM_OUTPUT("SPKDAT2R"), { name, "Noise Generator", "Noise Generator" }, \ { name, "Tone Generator 1", "Tone Generator 1" }, \ { name, "Tone Generator 2", "Tone Generator 2" }, \ + { name, "Haptics", "HAPTICS" }, \ { name, "AEC", "AEC Loopback" }, \ { name, "IN1L", "IN1L PGA" }, \ { name, "IN1R", "IN1R PGA" }, \ @@ -786,10 +807,10 @@ static const struct snd_soc_dapm_route wm5110_dapm_routes[] = { ARIZONA_MIXER_ROUTES("LHPF3", "LHPF3"), ARIZONA_MIXER_ROUTES("LHPF4", "LHPF4"), - ARIZONA_MIXER_ROUTES("ASRC1L", "ASRC1L"), - ARIZONA_MIXER_ROUTES("ASRC1R", "ASRC1R"), - ARIZONA_MIXER_ROUTES("ASRC2L", "ASRC2L"), - ARIZONA_MIXER_ROUTES("ASRC2R", "ASRC2R"), + ARIZONA_MUX_ROUTES("ASRC1L"), + ARIZONA_MUX_ROUTES("ASRC1R"), + ARIZONA_MUX_ROUTES("ASRC2L"), + ARIZONA_MUX_ROUTES("ASRC2R"), { "HPOUT1L", NULL, "OUT1L" }, { "HPOUT1R", NULL, "OUT1R" }, @@ -902,9 +923,29 @@ static struct snd_soc_dai_driver wm5110_dai[] = { static int wm5110_codec_probe(struct snd_soc_codec *codec) { struct wm5110_priv *priv = snd_soc_codec_get_drvdata(codec); + int ret; codec->control_data = priv->core.arizona->regmap; - return snd_soc_codec_set_cache_io(codec, 32, 16, SND_SOC_REGMAP); + priv->core.arizona->dapm = &codec->dapm; + + ret = snd_soc_codec_set_cache_io(codec, 32, 16, SND_SOC_REGMAP); + if (ret != 0) + return ret; + + snd_soc_dapm_disable_pin(&codec->dapm, "HAPTICS"); + + priv->core.arizona->dapm = &codec->dapm; + + return 0; +} + +static int wm5110_codec_remove(struct snd_soc_codec *codec) +{ + struct wm5110_priv *priv = snd_soc_codec_get_drvdata(codec); + + priv->core.arizona->dapm = NULL; + + return 0; } #define WM5110_DIG_VU 0x0200 @@ -935,6 +976,7 @@ static unsigned int wm5110_digital_vu[] = { static struct snd_soc_codec_driver soc_codec_dev_wm5110 = { .probe = wm5110_codec_probe, + .remove = wm5110_codec_remove, .idle_bias_off = true, @@ -949,7 +991,7 @@ static struct snd_soc_codec_driver soc_codec_dev_wm5110 = { .num_dapm_routes = ARRAY_SIZE(wm5110_dapm_routes), }; -static int __devinit wm5110_probe(struct platform_device *pdev) +static int wm5110_probe(struct platform_device *pdev) { struct arizona *arizona = dev_get_drvdata(pdev->dev.parent); struct wm5110_priv *wm5110; @@ -988,7 +1030,7 @@ static int __devinit wm5110_probe(struct platform_device *pdev) wm5110_dai, ARRAY_SIZE(wm5110_dai)); } -static int __devexit wm5110_remove(struct platform_device *pdev) +static int wm5110_remove(struct platform_device *pdev) { snd_soc_unregister_codec(&pdev->dev); pm_runtime_disable(&pdev->dev); @@ -1002,7 +1044,7 @@ static struct platform_driver wm5110_codec_driver = { .owner = THIS_MODULE, }, .probe = wm5110_probe, - .remove = __devexit_p(wm5110_remove), + .remove = wm5110_remove, }; module_platform_driver(wm5110_codec_driver); diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c index a4cae060bf26..fb92fb47d636 100644 --- a/sound/soc/codecs/wm8350.c +++ b/sound/soc/codecs/wm8350.c @@ -1500,7 +1500,7 @@ static int wm8350_codec_probe(struct snd_soc_codec *codec) for (i = 0; i < ARRAY_SIZE(supply_names); i++) priv->supplies[i].supply = supply_names[i]; - ret = regulator_bulk_get(wm8350->dev, ARRAY_SIZE(priv->supplies), + ret = devm_regulator_bulk_get(wm8350->dev, ARRAY_SIZE(priv->supplies), priv->supplies); if (ret != 0) return ret; @@ -1607,8 +1607,6 @@ static int wm8350_codec_remove(struct snd_soc_codec *codec) wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA); - regulator_bulk_free(ARRAY_SIZE(priv->supplies), priv->supplies); - return 0; } @@ -1627,13 +1625,13 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8350 = { .num_dapm_routes = ARRAY_SIZE(wm8350_dapm_routes), }; -static int __devinit wm8350_probe(struct platform_device *pdev) +static int wm8350_probe(struct platform_device *pdev) { return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm8350, &wm8350_dai, 1); } -static int __devexit wm8350_remove(struct platform_device *pdev) +static int wm8350_remove(struct platform_device *pdev) { snd_soc_unregister_codec(&pdev->dev); return 0; @@ -1645,7 +1643,7 @@ static struct platform_driver wm8350_codec_driver = { .owner = THIS_MODULE, }, .probe = wm8350_probe, - .remove = __devexit_p(wm8350_remove), + .remove = wm8350_remove, }; module_platform_driver(wm8350_codec_driver); diff --git a/sound/soc/codecs/wm8400.c b/sound/soc/codecs/wm8400.c index 5d277a915f81..af6d227e67be 100644 --- a/sound/soc/codecs/wm8400.c +++ b/sound/soc/codecs/wm8400.c @@ -1373,7 +1373,7 @@ static int wm8400_codec_probe(struct snd_soc_codec *codec) codec->control_data = priv->wm8400 = wm8400; priv->codec = codec; - ret = regulator_bulk_get(wm8400->dev, + ret = devm_regulator_bulk_get(wm8400->dev, ARRAY_SIZE(power), &power[0]); if (ret != 0) { dev_err(codec->dev, "Failed to get regulators: %d\n", ret); @@ -1398,15 +1398,9 @@ static int wm8400_codec_probe(struct snd_soc_codec *codec) snd_soc_write(codec, WM8400_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8)); snd_soc_write(codec, WM8400_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8)); - if (!schedule_work(&priv->work)) { - ret = -EINVAL; - goto err_regulator; - } + if (!schedule_work(&priv->work)) + return -EINVAL; return 0; - -err_regulator: - regulator_bulk_free(ARRAY_SIZE(power), power); - return ret; } static int wm8400_codec_remove(struct snd_soc_codec *codec) @@ -1417,8 +1411,6 @@ static int wm8400_codec_remove(struct snd_soc_codec *codec) snd_soc_write(codec, WM8400_POWER_MANAGEMENT_1, reg & (~WM8400_CODEC_ENA)); - regulator_bulk_free(ARRAY_SIZE(power), power); - return 0; } @@ -1439,13 +1431,13 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8400 = { .num_dapm_routes = ARRAY_SIZE(wm8400_dapm_routes), }; -static int __devinit wm8400_probe(struct platform_device *pdev) +static int wm8400_probe(struct platform_device *pdev) { return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm8400, &wm8400_dai, 1); } -static int __devexit wm8400_remove(struct platform_device *pdev) +static int wm8400_remove(struct platform_device *pdev) { snd_soc_unregister_codec(&pdev->dev); return 0; @@ -1457,7 +1449,7 @@ static struct platform_driver wm8400_codec_driver = { .owner = THIS_MODULE, }, .probe = wm8400_probe, - .remove = __devexit_p(wm8400_remove), + .remove = wm8400_remove, }; module_platform_driver(wm8400_codec_driver); diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c index c12a54e72e89..6ed5433943ea 100644 --- a/sound/soc/codecs/wm8510.c +++ b/sound/soc/codecs/wm8510.c @@ -608,10 +608,7 @@ static int wm8510_probe(struct snd_soc_codec *codec) /* power down chip */ static int wm8510_remove(struct snd_soc_codec *codec) { - struct wm8510_priv *wm8510 = snd_soc_codec_get_drvdata(codec); - wm8510_set_bias_level(codec, SND_SOC_BIAS_OFF); - kfree(wm8510); return 0; } @@ -648,7 +645,7 @@ static const struct regmap_config wm8510_regmap = { }; #if defined(CONFIG_SPI_MASTER) -static int __devinit wm8510_spi_probe(struct spi_device *spi) +static int wm8510_spi_probe(struct spi_device *spi) { struct wm8510_priv *wm8510; int ret; @@ -670,7 +667,7 @@ static int __devinit wm8510_spi_probe(struct spi_device *spi) return ret; } -static int __devexit wm8510_spi_remove(struct spi_device *spi) +static int wm8510_spi_remove(struct spi_device *spi) { snd_soc_unregister_codec(&spi->dev); return 0; @@ -683,13 +680,13 @@ static struct spi_driver wm8510_spi_driver = { .of_match_table = wm8510_of_match, }, .probe = wm8510_spi_probe, - .remove = __devexit_p(wm8510_spi_remove), + .remove = wm8510_spi_remove, }; #endif /* CONFIG_SPI_MASTER */ #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) -static __devinit int wm8510_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8510_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) { struct wm8510_priv *wm8510; int ret; @@ -711,7 +708,7 @@ static __devinit int wm8510_i2c_probe(struct i2c_client *i2c, return ret; } -static __devexit int wm8510_i2c_remove(struct i2c_client *client) +static int wm8510_i2c_remove(struct i2c_client *client) { snd_soc_unregister_codec(&client->dev); return 0; @@ -730,7 +727,7 @@ static struct i2c_driver wm8510_i2c_driver = { .of_match_table = wm8510_of_match, }, .probe = wm8510_i2c_probe, - .remove = __devexit_p(wm8510_i2c_remove), + .remove = wm8510_i2c_remove, .id_table = wm8510_i2c_id, }; #endif diff --git a/sound/soc/codecs/wm8523.c b/sound/soc/codecs/wm8523.c index 8d5c27673501..139bf9ac9407 100644 --- a/sound/soc/codecs/wm8523.c +++ b/sound/soc/codecs/wm8523.c @@ -453,8 +453,8 @@ static const struct regmap_config wm8523_regmap = { }; #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) -static __devinit int wm8523_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8523_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) { struct wm8523_priv *wm8523; unsigned int val; @@ -528,7 +528,7 @@ err_enable: return ret; } -static __devexit int wm8523_i2c_remove(struct i2c_client *client) +static int wm8523_i2c_remove(struct i2c_client *client) { snd_soc_unregister_codec(&client->dev); return 0; @@ -547,7 +547,7 @@ static struct i2c_driver wm8523_i2c_driver = { .of_match_table = wm8523_of_match, }, .probe = wm8523_i2c_probe, - .remove = __devexit_p(wm8523_i2c_remove), + .remove = wm8523_i2c_remove, .id_table = wm8523_i2c_id, }; #endif diff --git a/sound/soc/codecs/wm8711.c b/sound/soc/codecs/wm8711.c index 8b8bb70f1eb9..5b428b060d41 100644 --- a/sound/soc/codecs/wm8711.c +++ b/sound/soc/codecs/wm8711.c @@ -429,7 +429,7 @@ static const struct regmap_config wm8711_regmap = { }; #if defined(CONFIG_SPI_MASTER) -static int __devinit wm8711_spi_probe(struct spi_device *spi) +static int wm8711_spi_probe(struct spi_device *spi) { struct wm8711_priv *wm8711; int ret; @@ -451,7 +451,7 @@ static int __devinit wm8711_spi_probe(struct spi_device *spi) return ret; } -static int __devexit wm8711_spi_remove(struct spi_device *spi) +static int wm8711_spi_remove(struct spi_device *spi) { snd_soc_unregister_codec(&spi->dev); @@ -465,13 +465,13 @@ static struct spi_driver wm8711_spi_driver = { .of_match_table = wm8711_of_match, }, .probe = wm8711_spi_probe, - .remove = __devexit_p(wm8711_spi_remove), + .remove = wm8711_spi_remove, }; #endif /* CONFIG_SPI_MASTER */ #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) -static __devinit int wm8711_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int wm8711_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct wm8711_priv *wm8711; int ret; @@ -493,7 +493,7 @@ static __devinit int wm8711_i2c_probe(struct i2c_client *client, return ret; } -static __devexit int wm8711_i2c_remove(struct i2c_client *client) +static int wm8711_i2c_remove(struct i2c_client *client) { snd_soc_unregister_codec(&client->dev); return 0; @@ -512,7 +512,7 @@ static struct i2c_driver wm8711_i2c_driver = { .of_match_table = wm8711_of_match, }, .probe = wm8711_i2c_probe, - .remove = __devexit_p(wm8711_i2c_remove), + .remove = wm8711_i2c_remove, .id_table = wm8711_i2c_id, }; #endif diff --git a/sound/soc/codecs/wm8727.c b/sound/soc/codecs/wm8727.c index e81705620718..462f5e4d5c05 100644 --- a/sound/soc/codecs/wm8727.c +++ b/sound/soc/codecs/wm8727.c @@ -45,13 +45,13 @@ static struct snd_soc_dai_driver wm8727_dai = { static struct snd_soc_codec_driver soc_codec_dev_wm8727; -static __devinit int wm8727_probe(struct platform_device *pdev) +static int wm8727_probe(struct platform_device *pdev) { return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm8727, &wm8727_dai, 1); } -static int __devexit wm8727_remove(struct platform_device *pdev) +static int wm8727_remove(struct platform_device *pdev) { snd_soc_unregister_codec(&pdev->dev); return 0; @@ -64,7 +64,7 @@ static struct platform_driver wm8727_codec_driver = { }, .probe = wm8727_probe, - .remove = __devexit_p(wm8727_remove), + .remove = wm8727_remove, }; module_platform_driver(wm8727_codec_driver); diff --git a/sound/soc/codecs/wm8728.c b/sound/soc/codecs/wm8728.c index 00a12a0c3919..c6a292dcded0 100644 --- a/sound/soc/codecs/wm8728.c +++ b/sound/soc/codecs/wm8728.c @@ -280,7 +280,7 @@ static const struct regmap_config wm8728_regmap = { }; #if defined(CONFIG_SPI_MASTER) -static int __devinit wm8728_spi_probe(struct spi_device *spi) +static int wm8728_spi_probe(struct spi_device *spi) { struct wm8728_priv *wm8728; int ret; @@ -302,7 +302,7 @@ static int __devinit wm8728_spi_probe(struct spi_device *spi) return ret; } -static int __devexit wm8728_spi_remove(struct spi_device *spi) +static int wm8728_spi_remove(struct spi_device *spi) { snd_soc_unregister_codec(&spi->dev); @@ -316,13 +316,13 @@ static struct spi_driver wm8728_spi_driver = { .of_match_table = wm8728_of_match, }, .probe = wm8728_spi_probe, - .remove = __devexit_p(wm8728_spi_remove), + .remove = wm8728_spi_remove, }; #endif /* CONFIG_SPI_MASTER */ #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) -static __devinit int wm8728_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8728_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) { struct wm8728_priv *wm8728; int ret; @@ -344,7 +344,7 @@ static __devinit int wm8728_i2c_probe(struct i2c_client *i2c, return ret; } -static __devexit int wm8728_i2c_remove(struct i2c_client *client) +static int wm8728_i2c_remove(struct i2c_client *client) { snd_soc_unregister_codec(&client->dev); return 0; @@ -363,7 +363,7 @@ static struct i2c_driver wm8728_i2c_driver = { .of_match_table = wm8728_of_match, }, .probe = wm8728_i2c_probe, - .remove = __devexit_p(wm8728_i2c_remove), + .remove = wm8728_i2c_remove, .id_table = wm8728_i2c_id, }; #endif diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index bb1d26919b10..5276062d6c79 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c @@ -631,7 +631,7 @@ static const struct regmap_config wm8731_regmap = { }; #if defined(CONFIG_SPI_MASTER) -static int __devinit wm8731_spi_probe(struct spi_device *spi) +static int wm8731_spi_probe(struct spi_device *spi) { struct wm8731_priv *wm8731; int ret; @@ -661,7 +661,7 @@ static int __devinit wm8731_spi_probe(struct spi_device *spi) return 0; } -static int __devexit wm8731_spi_remove(struct spi_device *spi) +static int wm8731_spi_remove(struct spi_device *spi) { snd_soc_unregister_codec(&spi->dev); return 0; @@ -674,13 +674,13 @@ static struct spi_driver wm8731_spi_driver = { .of_match_table = wm8731_of_match, }, .probe = wm8731_spi_probe, - .remove = __devexit_p(wm8731_spi_remove), + .remove = wm8731_spi_remove, }; #endif /* CONFIG_SPI_MASTER */ #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) -static __devinit int wm8731_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8731_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) { struct wm8731_priv *wm8731; int ret; @@ -710,7 +710,7 @@ static __devinit int wm8731_i2c_probe(struct i2c_client *i2c, return 0; } -static __devexit int wm8731_i2c_remove(struct i2c_client *client) +static int wm8731_i2c_remove(struct i2c_client *client) { snd_soc_unregister_codec(&client->dev); return 0; @@ -729,7 +729,7 @@ static struct i2c_driver wm8731_i2c_driver = { .of_match_table = wm8731_of_match, }, .probe = wm8731_i2c_probe, - .remove = __devexit_p(wm8731_i2c_remove), + .remove = wm8731_i2c_remove, .id_table = wm8731_i2c_id, }; #endif diff --git a/sound/soc/codecs/wm8737.c b/sound/soc/codecs/wm8737.c index 5c9634f4c1f0..2f167a8ca01b 100644 --- a/sound/soc/codecs/wm8737.c +++ b/sound/soc/codecs/wm8737.c @@ -645,8 +645,8 @@ static const struct regmap_config wm8737_regmap = { }; #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) -static __devinit int wm8737_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8737_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) { struct wm8737_priv *wm8737; int ret, i; @@ -679,7 +679,7 @@ static __devinit int wm8737_i2c_probe(struct i2c_client *i2c, } -static __devexit int wm8737_i2c_remove(struct i2c_client *client) +static int wm8737_i2c_remove(struct i2c_client *client) { snd_soc_unregister_codec(&client->dev); @@ -699,13 +699,13 @@ static struct i2c_driver wm8737_i2c_driver = { .of_match_table = wm8737_of_match, }, .probe = wm8737_i2c_probe, - .remove = __devexit_p(wm8737_i2c_remove), + .remove = wm8737_i2c_remove, .id_table = wm8737_i2c_id, }; #endif #if defined(CONFIG_SPI_MASTER) -static int __devinit wm8737_spi_probe(struct spi_device *spi) +static int wm8737_spi_probe(struct spi_device *spi) { struct wm8737_priv *wm8737; int ret, i; @@ -737,7 +737,7 @@ static int __devinit wm8737_spi_probe(struct spi_device *spi) return ret; } -static int __devexit wm8737_spi_remove(struct spi_device *spi) +static int wm8737_spi_remove(struct spi_device *spi) { snd_soc_unregister_codec(&spi->dev); @@ -751,7 +751,7 @@ static struct spi_driver wm8737_spi_driver = { .of_match_table = wm8737_of_match, }, .probe = wm8737_spi_probe, - .remove = __devexit_p(wm8737_spi_remove), + .remove = wm8737_spi_remove, }; #endif /* CONFIG_SPI_MASTER */ diff --git a/sound/soc/codecs/wm8741.c b/sound/soc/codecs/wm8741.c index 4281a0802138..b18813cc7ba9 100644 --- a/sound/soc/codecs/wm8741.c +++ b/sound/soc/codecs/wm8741.c @@ -522,7 +522,7 @@ static int wm8741_i2c_probe(struct i2c_client *i2c, return ret; } - wm8741->regmap = regmap_init_i2c(i2c, &wm8741_regmap); + wm8741->regmap = devm_regmap_init_i2c(i2c, &wm8741_regmap); if (IS_ERR(wm8741->regmap)) { ret = PTR_ERR(wm8741->regmap); dev_err(&i2c->dev, "Failed to init regmap: %d\n", ret); @@ -562,7 +562,7 @@ static struct i2c_driver wm8741_i2c_driver = { #endif #if defined(CONFIG_SPI_MASTER) -static int __devinit wm8741_spi_probe(struct spi_device *spi) +static int wm8741_spi_probe(struct spi_device *spi) { struct wm8741_priv *wm8741; int ret, i; @@ -582,7 +582,7 @@ static int __devinit wm8741_spi_probe(struct spi_device *spi) return ret; } - wm8741->regmap = regmap_init_spi(spi, &wm8741_regmap); + wm8741->regmap = devm_regmap_init_spi(spi, &wm8741_regmap); if (IS_ERR(wm8741->regmap)) { ret = PTR_ERR(wm8741->regmap); dev_err(&spi->dev, "Failed to init regmap: %d\n", ret); @@ -596,7 +596,7 @@ static int __devinit wm8741_spi_probe(struct spi_device *spi) return ret; } -static int __devexit wm8741_spi_remove(struct spi_device *spi) +static int wm8741_spi_remove(struct spi_device *spi) { snd_soc_unregister_codec(&spi->dev); return 0; @@ -609,7 +609,7 @@ static struct spi_driver wm8741_spi_driver = { .of_match_table = wm8741_of_match, }, .probe = wm8741_spi_probe, - .remove = __devexit_p(wm8741_spi_remove), + .remove = wm8741_spi_remove, }; #endif /* CONFIG_SPI_MASTER */ diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c index 89151ca5e776..50d5ff616232 100644 --- a/sound/soc/codecs/wm8750.c +++ b/sound/soc/codecs/wm8750.c @@ -18,6 +18,7 @@ #include <linux/delay.h> #include <linux/pm.h> #include <linux/i2c.h> +#include <linux/regmap.h> #include <linux/spi/spi.h> #include <linux/slab.h> #include <linux/of_device.h> @@ -34,24 +35,55 @@ * We can't read the WM8750 register space when we * are using 2 wire for device control, so we cache them instead. */ -static const u16 wm8750_reg[] = { - 0x0097, 0x0097, 0x0079, 0x0079, /* 0 */ - 0x0000, 0x0008, 0x0000, 0x000a, /* 4 */ - 0x0000, 0x0000, 0x00ff, 0x00ff, /* 8 */ - 0x000f, 0x000f, 0x0000, 0x0000, /* 12 */ - 0x0000, 0x007b, 0x0000, 0x0032, /* 16 */ - 0x0000, 0x00c3, 0x00c3, 0x00c0, /* 20 */ - 0x0000, 0x0000, 0x0000, 0x0000, /* 24 */ - 0x0000, 0x0000, 0x0000, 0x0000, /* 28 */ - 0x0000, 0x0000, 0x0050, 0x0050, /* 32 */ - 0x0050, 0x0050, 0x0050, 0x0050, /* 36 */ - 0x0079, 0x0079, 0x0079, /* 40 */ +static const struct reg_default wm8750_reg_defaults[] = { + { 0, 0x0097 }, + { 1, 0x0097 }, + { 2, 0x0079 }, + { 3, 0x0079 }, + { 4, 0x0000 }, + { 5, 0x0008 }, + { 6, 0x0000 }, + { 7, 0x000a }, + { 8, 0x0000 }, + { 9, 0x0000 }, + { 10, 0x00ff }, + { 11, 0x00ff }, + { 12, 0x000f }, + { 13, 0x000f }, + { 14, 0x0000 }, + { 15, 0x0000 }, + { 16, 0x0000 }, + { 17, 0x007b }, + { 18, 0x0000 }, + { 19, 0x0032 }, + { 20, 0x0000 }, + { 21, 0x00c3 }, + { 22, 0x00c3 }, + { 23, 0x00c0 }, + { 24, 0x0000 }, + { 25, 0x0000 }, + { 26, 0x0000 }, + { 27, 0x0000 }, + { 28, 0x0000 }, + { 29, 0x0000 }, + { 30, 0x0000 }, + { 31, 0x0000 }, + { 32, 0x0000 }, + { 33, 0x0000 }, + { 34, 0x0050 }, + { 35, 0x0050 }, + { 36, 0x0050 }, + { 37, 0x0050 }, + { 38, 0x0050 }, + { 39, 0x0050 }, + { 40, 0x0079 }, + { 41, 0x0079 }, + { 42, 0x0079 }, }; /* codec private data */ struct wm8750_priv { unsigned int sysclk; - enum snd_soc_control_type control_type; }; #define wm8750_reset(c) snd_soc_write(c, WM8750_RESET, 0) @@ -668,10 +700,9 @@ static int wm8750_resume(struct snd_soc_codec *codec) static int wm8750_probe(struct snd_soc_codec *codec) { - struct wm8750_priv *wm8750 = snd_soc_codec_get_drvdata(codec); int ret; - ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8750->control_type); + ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP); if (ret < 0) { printk(KERN_ERR "wm8750: failed to set cache I/O: %d\n", ret); return ret; @@ -711,9 +742,6 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8750 = { .suspend = wm8750_suspend, .resume = wm8750_resume, .set_bias_level = wm8750_set_bias_level, - .reg_cache_size = ARRAY_SIZE(wm8750_reg), - .reg_word_size = sizeof(u16), - .reg_cache_default = wm8750_reg, .controls = wm8750_snd_controls, .num_controls = ARRAY_SIZE(wm8750_snd_controls), @@ -730,10 +758,21 @@ static const struct of_device_id wm8750_of_match[] = { }; MODULE_DEVICE_TABLE(of, wm8750_of_match); +static const struct regmap_config wm8750_regmap = { + .reg_bits = 7, + .val_bits = 9, + .max_register = WM8750_MOUTV, + + .reg_defaults = wm8750_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(wm8750_reg_defaults), + .cache_type = REGCACHE_RBTREE, +}; + #if defined(CONFIG_SPI_MASTER) -static int __devinit wm8750_spi_probe(struct spi_device *spi) +static int wm8750_spi_probe(struct spi_device *spi) { struct wm8750_priv *wm8750; + struct regmap *regmap; int ret; wm8750 = devm_kzalloc(&spi->dev, sizeof(struct wm8750_priv), @@ -741,7 +780,10 @@ static int __devinit wm8750_spi_probe(struct spi_device *spi) if (wm8750 == NULL) return -ENOMEM; - wm8750->control_type = SND_SOC_SPI; + regmap = devm_regmap_init_spi(spi, &wm8750_regmap); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + spi_set_drvdata(spi, wm8750); ret = snd_soc_register_codec(&spi->dev, @@ -749,7 +791,7 @@ static int __devinit wm8750_spi_probe(struct spi_device *spi) return ret; } -static int __devexit wm8750_spi_remove(struct spi_device *spi) +static int wm8750_spi_remove(struct spi_device *spi) { snd_soc_unregister_codec(&spi->dev); return 0; @@ -770,15 +812,16 @@ static struct spi_driver wm8750_spi_driver = { }, .id_table = wm8750_spi_ids, .probe = wm8750_spi_probe, - .remove = __devexit_p(wm8750_spi_remove), + .remove = wm8750_spi_remove, }; #endif /* CONFIG_SPI_MASTER */ #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) -static __devinit int wm8750_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8750_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) { struct wm8750_priv *wm8750; + struct regmap *regmap; int ret; wm8750 = devm_kzalloc(&i2c->dev, sizeof(struct wm8750_priv), @@ -787,14 +830,17 @@ static __devinit int wm8750_i2c_probe(struct i2c_client *i2c, return -ENOMEM; i2c_set_clientdata(i2c, wm8750); - wm8750->control_type = SND_SOC_I2C; + + regmap = devm_regmap_init_i2c(i2c, &wm8750_regmap); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm8750, &wm8750_dai, 1); return ret; } -static __devexit int wm8750_i2c_remove(struct i2c_client *client) +static int wm8750_i2c_remove(struct i2c_client *client) { snd_soc_unregister_codec(&client->dev); return 0; @@ -814,7 +860,7 @@ static struct i2c_driver wm8750_i2c_driver = { .of_match_table = wm8750_of_match, }, .probe = wm8750_i2c_probe, - .remove = __devexit_p(wm8750_i2c_remove), + .remove = wm8750_i2c_remove, .id_table = wm8750_i2c_id, }; #endif diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index 2e4a775ae560..0a4ab4c423d1 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c @@ -1550,7 +1550,7 @@ static const struct regmap_config wm8753_regmap = { }; #if defined(CONFIG_SPI_MASTER) -static int __devinit wm8753_spi_probe(struct spi_device *spi) +static int wm8753_spi_probe(struct spi_device *spi) { struct wm8753_priv *wm8753; int ret; @@ -1562,36 +1562,25 @@ static int __devinit wm8753_spi_probe(struct spi_device *spi) spi_set_drvdata(spi, wm8753); - wm8753->regmap = regmap_init_spi(spi, &wm8753_regmap); + wm8753->regmap = devm_regmap_init_spi(spi, &wm8753_regmap); if (IS_ERR(wm8753->regmap)) { ret = PTR_ERR(wm8753->regmap); dev_err(&spi->dev, "Failed to allocate register map: %d\n", ret); - goto err; + return ret; } ret = snd_soc_register_codec(&spi->dev, &soc_codec_dev_wm8753, wm8753_dai, ARRAY_SIZE(wm8753_dai)); - if (ret != 0) { + if (ret != 0) dev_err(&spi->dev, "Failed to register CODEC: %d\n", ret); - goto err_regmap; - } - return 0; - -err_regmap: - regmap_exit(wm8753->regmap); -err: return ret; } -static int __devexit wm8753_spi_remove(struct spi_device *spi) +static int wm8753_spi_remove(struct spi_device *spi) { - struct wm8753_priv *wm8753 = spi_get_drvdata(spi); - snd_soc_unregister_codec(&spi->dev); - regmap_exit(wm8753->regmap); - kfree(wm8753); return 0; } @@ -1602,13 +1591,13 @@ static struct spi_driver wm8753_spi_driver = { .of_match_table = wm8753_of_match, }, .probe = wm8753_spi_probe, - .remove = __devexit_p(wm8753_spi_remove), + .remove = wm8753_spi_remove, }; #endif /* CONFIG_SPI_MASTER */ #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) -static __devinit int wm8753_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8753_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) { struct wm8753_priv *wm8753; int ret; @@ -1620,35 +1609,25 @@ static __devinit int wm8753_i2c_probe(struct i2c_client *i2c, i2c_set_clientdata(i2c, wm8753); - wm8753->regmap = regmap_init_i2c(i2c, &wm8753_regmap); + wm8753->regmap = devm_regmap_init_i2c(i2c, &wm8753_regmap); if (IS_ERR(wm8753->regmap)) { ret = PTR_ERR(wm8753->regmap); dev_err(&i2c->dev, "Failed to allocate register map: %d\n", ret); - goto err; + return ret; } ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm8753, wm8753_dai, ARRAY_SIZE(wm8753_dai)); - if (ret != 0) { + if (ret != 0) dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret); - goto err_regmap; - } - return 0; - -err_regmap: - regmap_exit(wm8753->regmap); -err: return ret; } -static __devexit int wm8753_i2c_remove(struct i2c_client *client) +static int wm8753_i2c_remove(struct i2c_client *client) { - struct wm8753_priv *wm8753 = i2c_get_clientdata(client); - snd_soc_unregister_codec(&client->dev); - regmap_exit(wm8753->regmap); return 0; } @@ -1665,7 +1644,7 @@ static struct i2c_driver wm8753_i2c_driver = { .of_match_table = wm8753_of_match, }, .probe = wm8753_i2c_probe, - .remove = __devexit_p(wm8753_i2c_remove), + .remove = wm8753_i2c_remove, .id_table = wm8753_i2c_id, }; #endif diff --git a/sound/soc/codecs/wm8770.c b/sound/soc/codecs/wm8770.c index c7c0034d3966..89a18d82f303 100644 --- a/sound/soc/codecs/wm8770.c +++ b/sound/soc/codecs/wm8770.c @@ -17,6 +17,7 @@ #include <linux/of_device.h> #include <linux/pm.h> #include <linux/spi/spi.h> +#include <linux/regmap.h> #include <linux/regulator/consumer.h> #include <linux/slab.h> #include <sound/core.h> @@ -35,19 +36,52 @@ static const char *wm8770_supply_names[WM8770_NUM_SUPPLIES] = { "DVDD" }; -static const u16 wm8770_reg_defs[WM8770_CACHEREGNUM] = { - 0x7f, 0x7f, 0x7f, 0x7f, - 0x7f, 0x7f, 0x7f, 0x7f, - 0x7f, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0, 0x90, 0, - 0, 0x22, 0x22, 0x3e, - 0xc, 0xc, 0x100, 0x189, - 0x189, 0x8770 +static const struct reg_default wm8770_reg_defaults[] = { + { 0, 0x7f }, + { 1, 0x7f }, + { 2, 0x7f }, + { 3, 0x7f }, + { 4, 0x7f }, + { 5, 0x7f }, + { 6, 0x7f }, + { 7, 0x7f }, + { 8, 0x7f }, + { 9, 0xff }, + { 10, 0xff }, + { 11, 0xff }, + { 12, 0xff }, + { 13, 0xff }, + { 14, 0xff }, + { 15, 0xff }, + { 16, 0xff }, + { 17, 0xff }, + { 18, 0 }, + { 19, 0x90 }, + { 20, 0 }, + { 21, 0 }, + { 22, 0x22 }, + { 23, 0x22 }, + { 24, 0x3e }, + { 25, 0xc }, + { 26, 0xc }, + { 27, 0x100 }, + { 28, 0x189 }, + { 29, 0x189 }, + { 30, 0x8770 }, }; +static bool wm8770_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case WM8770_RESET: + return true; + default: + return false; + } +} + struct wm8770_priv { - enum snd_soc_control_type control_type; + struct regmap *regmap; struct regulator_bulk_data supplies[WM8770_NUM_SUPPLIES]; struct notifier_block disable_nb[WM8770_NUM_SUPPLIES]; struct snd_soc_codec *codec; @@ -71,7 +105,7 @@ static int wm8770_regulator_event_##n(struct notifier_block *nb, \ struct wm8770_priv *wm8770 = container_of(nb, struct wm8770_priv, \ disable_nb[n]); \ if (event & REGULATOR_EVENT_DISABLE) { \ - wm8770->codec->cache_sync = 1; \ + regcache_mark_dirty(wm8770->regmap); \ } \ return 0; \ } @@ -466,24 +500,6 @@ static int wm8770_set_sysclk(struct snd_soc_dai *dai, return 0; } -static void wm8770_sync_cache(struct snd_soc_codec *codec) -{ - int i; - u16 *cache; - - if (!codec->cache_sync) - return; - - codec->cache_only = 0; - cache = codec->reg_cache; - for (i = 0; i < codec->driver->reg_cache_size; i++) { - if (i == WM8770_RESET || cache[i] == wm8770_reg_defs[i]) - continue; - snd_soc_write(codec, i, cache[i]); - } - codec->cache_sync = 0; -} - static int wm8770_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { @@ -507,7 +523,9 @@ static int wm8770_set_bias_level(struct snd_soc_codec *codec, ret); return ret; } - wm8770_sync_cache(codec); + + regcache_sync(wm8770->regmap); + /* global powerup */ snd_soc_write(codec, WM8770_PWDNCTRL, 0); } @@ -554,68 +572,25 @@ static struct snd_soc_dai_driver wm8770_dai = { .symmetric_rates = 1 }; -#ifdef CONFIG_PM -static int wm8770_suspend(struct snd_soc_codec *codec) -{ - wm8770_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - -static int wm8770_resume(struct snd_soc_codec *codec) -{ - wm8770_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - return 0; -} -#else -#define wm8770_suspend NULL -#define wm8770_resume NULL -#endif - static int wm8770_probe(struct snd_soc_codec *codec) { struct wm8770_priv *wm8770; int ret; - int i; wm8770 = snd_soc_codec_get_drvdata(codec); wm8770->codec = codec; - ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8770->control_type); + ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP); if (ret < 0) { dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); return ret; } - for (i = 0; i < ARRAY_SIZE(wm8770->supplies); i++) - wm8770->supplies[i].supply = wm8770_supply_names[i]; - - ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8770->supplies), - wm8770->supplies); - if (ret) { - dev_err(codec->dev, "Failed to request supplies: %d\n", ret); - return ret; - } - - wm8770->disable_nb[0].notifier_call = wm8770_regulator_event_0; - wm8770->disable_nb[1].notifier_call = wm8770_regulator_event_1; - wm8770->disable_nb[2].notifier_call = wm8770_regulator_event_2; - - /* This should really be moved into the regulator core */ - for (i = 0; i < ARRAY_SIZE(wm8770->supplies); i++) { - ret = regulator_register_notifier(wm8770->supplies[i].consumer, - &wm8770->disable_nb[i]); - if (ret) { - dev_err(codec->dev, - "Failed to register regulator notifier: %d\n", - ret); - } - } - ret = regulator_bulk_enable(ARRAY_SIZE(wm8770->supplies), wm8770->supplies); if (ret) { dev_err(codec->dev, "Failed to enable supplies: %d\n", ret); - goto err_reg_get; + return ret; } ret = wm8770_reset(codec); @@ -624,8 +599,6 @@ static int wm8770_probe(struct snd_soc_codec *codec) goto err_reg_enable; } - wm8770_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - /* latch the volume update bits */ snd_soc_update_bits(codec, WM8770_MSDIGVOL, 0x100, 0x100); snd_soc_update_bits(codec, WM8770_MSALGVOL, 0x100, 0x100); @@ -641,46 +614,22 @@ static int wm8770_probe(struct snd_soc_codec *codec) /* mute all DACs */ snd_soc_update_bits(codec, WM8770_DACMUTE, 0x10, 0x10); - snd_soc_add_codec_controls(codec, wm8770_snd_controls, - ARRAY_SIZE(wm8770_snd_controls)); - snd_soc_dapm_new_controls(&codec->dapm, wm8770_dapm_widgets, - ARRAY_SIZE(wm8770_dapm_widgets)); - snd_soc_dapm_add_routes(&codec->dapm, wm8770_intercon, - ARRAY_SIZE(wm8770_intercon)); - return 0; - err_reg_enable: regulator_bulk_disable(ARRAY_SIZE(wm8770->supplies), wm8770->supplies); -err_reg_get: - regulator_bulk_free(ARRAY_SIZE(wm8770->supplies), wm8770->supplies); return ret; } -static int wm8770_remove(struct snd_soc_codec *codec) -{ - struct wm8770_priv *wm8770; - int i; - - wm8770 = snd_soc_codec_get_drvdata(codec); - wm8770_set_bias_level(codec, SND_SOC_BIAS_OFF); - - for (i = 0; i < ARRAY_SIZE(wm8770->supplies); ++i) - regulator_unregister_notifier(wm8770->supplies[i].consumer, - &wm8770->disable_nb[i]); - regulator_bulk_free(ARRAY_SIZE(wm8770->supplies), wm8770->supplies); - return 0; -} - static struct snd_soc_codec_driver soc_codec_dev_wm8770 = { .probe = wm8770_probe, - .remove = wm8770_remove, - .suspend = wm8770_suspend, - .resume = wm8770_resume, .set_bias_level = wm8770_set_bias_level, .idle_bias_off = true, - .reg_cache_size = ARRAY_SIZE(wm8770_reg_defs), - .reg_word_size = sizeof (u16), - .reg_cache_default = wm8770_reg_defs + + .controls = wm8770_snd_controls, + .num_controls = ARRAY_SIZE(wm8770_snd_controls), + .dapm_widgets = wm8770_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm8770_dapm_widgets), + .dapm_routes = wm8770_intercon, + .num_dapm_routes = ARRAY_SIZE(wm8770_intercon), }; static const struct of_device_id wm8770_of_match[] = { @@ -689,17 +638,57 @@ static const struct of_device_id wm8770_of_match[] = { }; MODULE_DEVICE_TABLE(of, wm8770_of_match); -static int __devinit wm8770_spi_probe(struct spi_device *spi) +static const struct regmap_config wm8770_regmap = { + .reg_bits = 7, + .val_bits = 9, + .max_register = WM8770_RESET, + + .reg_defaults = wm8770_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(wm8770_reg_defaults), + .cache_type = REGCACHE_RBTREE, + + .volatile_reg = wm8770_volatile_reg, +}; + +static int wm8770_spi_probe(struct spi_device *spi) { struct wm8770_priv *wm8770; - int ret; + int ret, i; wm8770 = devm_kzalloc(&spi->dev, sizeof(struct wm8770_priv), GFP_KERNEL); if (!wm8770) return -ENOMEM; - wm8770->control_type = SND_SOC_SPI; + for (i = 0; i < ARRAY_SIZE(wm8770->supplies); i++) + wm8770->supplies[i].supply = wm8770_supply_names[i]; + + ret = devm_regulator_bulk_get(&spi->dev, ARRAY_SIZE(wm8770->supplies), + wm8770->supplies); + if (ret) { + dev_err(&spi->dev, "Failed to request supplies: %d\n", ret); + return ret; + } + + wm8770->disable_nb[0].notifier_call = wm8770_regulator_event_0; + wm8770->disable_nb[1].notifier_call = wm8770_regulator_event_1; + wm8770->disable_nb[2].notifier_call = wm8770_regulator_event_2; + + /* This should really be moved into the regulator core */ + for (i = 0; i < ARRAY_SIZE(wm8770->supplies); i++) { + ret = regulator_register_notifier(wm8770->supplies[i].consumer, + &wm8770->disable_nb[i]); + if (ret) { + dev_err(&spi->dev, + "Failed to register regulator notifier: %d\n", + ret); + } + } + + wm8770->regmap = devm_regmap_init_spi(spi, &wm8770_regmap); + if (IS_ERR(wm8770->regmap)) + return PTR_ERR(wm8770->regmap); + spi_set_drvdata(spi, wm8770); ret = snd_soc_register_codec(&spi->dev, @@ -708,9 +697,17 @@ static int __devinit wm8770_spi_probe(struct spi_device *spi) return ret; } -static int __devexit wm8770_spi_remove(struct spi_device *spi) +static int wm8770_spi_remove(struct spi_device *spi) { + struct wm8770_priv *wm8770 = spi_get_drvdata(spi); + int i; + + for (i = 0; i < ARRAY_SIZE(wm8770->supplies); ++i) + regulator_unregister_notifier(wm8770->supplies[i].consumer, + &wm8770->disable_nb[i]); + snd_soc_unregister_codec(&spi->dev); + return 0; } @@ -721,7 +718,7 @@ static struct spi_driver wm8770_spi_driver = { .of_match_table = wm8770_of_match, }, .probe = wm8770_spi_probe, - .remove = __devexit_p(wm8770_spi_remove) + .remove = wm8770_spi_remove }; module_spi_driver(wm8770_spi_driver); diff --git a/sound/soc/codecs/wm8776.c b/sound/soc/codecs/wm8776.c index c32249ddb2e0..f31017ed1381 100644 --- a/sound/soc/codecs/wm8776.c +++ b/sound/soc/codecs/wm8776.c @@ -492,7 +492,7 @@ static const struct regmap_config wm8776_regmap = { }; #if defined(CONFIG_SPI_MASTER) -static int __devinit wm8776_spi_probe(struct spi_device *spi) +static int wm8776_spi_probe(struct spi_device *spi) { struct wm8776_priv *wm8776; int ret; @@ -514,7 +514,7 @@ static int __devinit wm8776_spi_probe(struct spi_device *spi) return ret; } -static int __devexit wm8776_spi_remove(struct spi_device *spi) +static int wm8776_spi_remove(struct spi_device *spi) { snd_soc_unregister_codec(&spi->dev); return 0; @@ -527,13 +527,13 @@ static struct spi_driver wm8776_spi_driver = { .of_match_table = wm8776_of_match, }, .probe = wm8776_spi_probe, - .remove = __devexit_p(wm8776_spi_remove), + .remove = wm8776_spi_remove, }; #endif /* CONFIG_SPI_MASTER */ #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) -static __devinit int wm8776_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8776_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) { struct wm8776_priv *wm8776; int ret; @@ -555,7 +555,7 @@ static __devinit int wm8776_i2c_probe(struct i2c_client *i2c, return ret; } -static __devexit int wm8776_i2c_remove(struct i2c_client *client) +static int wm8776_i2c_remove(struct i2c_client *client) { snd_soc_unregister_codec(&client->dev); return 0; @@ -575,7 +575,7 @@ static struct i2c_driver wm8776_i2c_driver = { .of_match_table = wm8776_of_match, }, .probe = wm8776_i2c_probe, - .remove = __devexit_p(wm8776_i2c_remove), + .remove = wm8776_i2c_remove, .id_table = wm8776_i2c_id, }; #endif diff --git a/sound/soc/codecs/wm8782.c b/sound/soc/codecs/wm8782.c index 3fdea98f732e..f1fdbf63abb4 100644 --- a/sound/soc/codecs/wm8782.c +++ b/sound/soc/codecs/wm8782.c @@ -42,13 +42,13 @@ static struct snd_soc_dai_driver wm8782_dai = { static struct snd_soc_codec_driver soc_codec_dev_wm8782; -static __devinit int wm8782_probe(struct platform_device *pdev) +static int wm8782_probe(struct platform_device *pdev) { return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm8782, &wm8782_dai, 1); } -static int __devexit wm8782_remove(struct platform_device *pdev) +static int wm8782_remove(struct platform_device *pdev) { snd_soc_unregister_codec(&pdev->dev); return 0; @@ -60,7 +60,7 @@ static struct platform_driver wm8782_codec_driver = { .owner = THIS_MODULE, }, .probe = wm8782_probe, - .remove = __devexit_p(wm8782_remove), + .remove = wm8782_remove, }; module_platform_driver(wm8782_codec_driver); diff --git a/sound/soc/codecs/wm8804.c b/sound/soc/codecs/wm8804.c index c088020172ab..d321a875b029 100644 --- a/sound/soc/codecs/wm8804.c +++ b/sound/soc/codecs/wm8804.c @@ -702,7 +702,7 @@ static struct regmap_config wm8804_regmap_config = { }; #if defined(CONFIG_SPI_MASTER) -static int __devinit wm8804_spi_probe(struct spi_device *spi) +static int wm8804_spi_probe(struct spi_device *spi) { struct wm8804_priv *wm8804; int ret; @@ -711,7 +711,7 @@ static int __devinit wm8804_spi_probe(struct spi_device *spi) if (!wm8804) return -ENOMEM; - wm8804->regmap = regmap_init_spi(spi, &wm8804_regmap_config); + wm8804->regmap = devm_regmap_init_spi(spi, &wm8804_regmap_config); if (IS_ERR(wm8804->regmap)) { ret = PTR_ERR(wm8804->regmap); return ret; @@ -725,11 +725,9 @@ static int __devinit wm8804_spi_probe(struct spi_device *spi) return ret; } -static int __devexit wm8804_spi_remove(struct spi_device *spi) +static int wm8804_spi_remove(struct spi_device *spi) { - struct wm8804_priv *wm8804 = spi_get_drvdata(spi); snd_soc_unregister_codec(&spi->dev); - regmap_exit(wm8804->regmap); return 0; } @@ -740,13 +738,13 @@ static struct spi_driver wm8804_spi_driver = { .of_match_table = wm8804_of_match, }, .probe = wm8804_spi_probe, - .remove = __devexit_p(wm8804_spi_remove) + .remove = wm8804_spi_remove }; #endif #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) -static __devinit int wm8804_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8804_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) { struct wm8804_priv *wm8804; int ret; @@ -755,7 +753,7 @@ static __devinit int wm8804_i2c_probe(struct i2c_client *i2c, if (!wm8804) return -ENOMEM; - wm8804->regmap = regmap_init_i2c(i2c, &wm8804_regmap_config); + wm8804->regmap = devm_regmap_init_i2c(i2c, &wm8804_regmap_config); if (IS_ERR(wm8804->regmap)) { ret = PTR_ERR(wm8804->regmap); return ret; @@ -765,23 +763,12 @@ static __devinit int wm8804_i2c_probe(struct i2c_client *i2c, ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm8804, &wm8804_dai, 1); - if (ret != 0) - goto err; - - return 0; - -err: - regmap_exit(wm8804->regmap); return ret; } -static __devexit int wm8804_i2c_remove(struct i2c_client *i2c) +static int wm8804_i2c_remove(struct i2c_client *i2c) { - struct wm8804_priv *wm8804 = i2c_get_clientdata(i2c); - snd_soc_unregister_codec(&i2c->dev); - regmap_exit(wm8804->regmap); - return 0; } @@ -798,7 +785,7 @@ static struct i2c_driver wm8804_i2c_driver = { .of_match_table = wm8804_of_match, }, .probe = wm8804_i2c_probe, - .remove = __devexit_p(wm8804_i2c_remove), + .remove = wm8804_i2c_remove, .id_table = wm8804_i2c_id }; #endif diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c index e781f865e5d7..7c8257c5a17b 100644 --- a/sound/soc/codecs/wm8900.c +++ b/sound/soc/codecs/wm8900.c @@ -1247,7 +1247,7 @@ static const struct regmap_config wm8900_regmap = { }; #if defined(CONFIG_SPI_MASTER) -static int __devinit wm8900_spi_probe(struct spi_device *spi) +static int wm8900_spi_probe(struct spi_device *spi) { struct wm8900_priv *wm8900; int ret; @@ -1269,7 +1269,7 @@ static int __devinit wm8900_spi_probe(struct spi_device *spi) return ret; } -static int __devexit wm8900_spi_remove(struct spi_device *spi) +static int wm8900_spi_remove(struct spi_device *spi) { snd_soc_unregister_codec(&spi->dev); return 0; @@ -1281,13 +1281,13 @@ static struct spi_driver wm8900_spi_driver = { .owner = THIS_MODULE, }, .probe = wm8900_spi_probe, - .remove = __devexit_p(wm8900_spi_remove), + .remove = wm8900_spi_remove, }; #endif /* CONFIG_SPI_MASTER */ #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) -static __devinit int wm8900_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8900_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) { struct wm8900_priv *wm8900; int ret; @@ -1309,7 +1309,7 @@ static __devinit int wm8900_i2c_probe(struct i2c_client *i2c, return ret; } -static __devexit int wm8900_i2c_remove(struct i2c_client *client) +static int wm8900_i2c_remove(struct i2c_client *client) { snd_soc_unregister_codec(&client->dev); return 0; @@ -1327,7 +1327,7 @@ static struct i2c_driver wm8900_i2c_driver = { .owner = THIS_MODULE, }, .probe = wm8900_i2c_probe, - .remove = __devexit_p(wm8900_i2c_remove), + .remove = wm8900_i2c_remove, .id_table = wm8900_i2c_id, }; #endif diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index 839414f9e2ed..134e41c870b9 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -2020,8 +2020,8 @@ static int wm8903_set_pdata_from_of(struct i2c_client *i2c, return 0; } -static __devinit int wm8903_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8903_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) { struct wm8903_platform_data *pdata = dev_get_platdata(&i2c->dev); struct wm8903_priv *wm8903; @@ -2206,7 +2206,7 @@ err: return ret; } -static __devexit int wm8903_i2c_remove(struct i2c_client *client) +static int wm8903_i2c_remove(struct i2c_client *client) { struct wm8903_priv *wm8903 = i2c_get_clientdata(client); @@ -2237,7 +2237,7 @@ static struct i2c_driver wm8903_i2c_driver = { .of_match_table = wm8903_of_match, }, .probe = wm8903_i2c_probe, - .remove = __devexit_p(wm8903_i2c_remove), + .remove = wm8903_i2c_remove, .id_table = wm8903_i2c_id, }; diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c index 7c8df52a8d9d..3ff195c541db 100644 --- a/sound/soc/codecs/wm8904.c +++ b/sound/soc/codecs/wm8904.c @@ -2111,8 +2111,8 @@ static const struct regmap_config wm8904_regmap = { .num_reg_defaults = ARRAY_SIZE(wm8904_reg_defaults), }; -static __devinit int wm8904_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8904_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) { struct wm8904_priv *wm8904; unsigned int val; @@ -2247,7 +2247,7 @@ err_enable: return ret; } -static __devexit int wm8904_i2c_remove(struct i2c_client *client) +static int wm8904_i2c_remove(struct i2c_client *client) { snd_soc_unregister_codec(&client->dev); return 0; @@ -2267,7 +2267,7 @@ static struct i2c_driver wm8904_i2c_driver = { .owner = THIS_MODULE, }, .probe = wm8904_i2c_probe, - .remove = __devexit_p(wm8904_i2c_remove), + .remove = wm8904_i2c_remove, .id_table = wm8904_i2c_id, }; diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c index b20aa4e7c3f9..b1591c61c254 100644 --- a/sound/soc/codecs/wm8940.c +++ b/sound/soc/codecs/wm8940.c @@ -742,8 +742,8 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8940 = { .volatile_register = wm8940_volatile_register, }; -static __devinit int wm8940_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8940_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) { struct wm8940_priv *wm8940; int ret; @@ -762,7 +762,7 @@ static __devinit int wm8940_i2c_probe(struct i2c_client *i2c, return ret; } -static __devexit int wm8940_i2c_remove(struct i2c_client *client) +static int wm8940_i2c_remove(struct i2c_client *client) { snd_soc_unregister_codec(&client->dev); @@ -781,7 +781,7 @@ static struct i2c_driver wm8940_i2c_driver = { .owner = THIS_MODULE, }, .probe = wm8940_i2c_probe, - .remove = __devexit_p(wm8940_i2c_remove), + .remove = wm8940_i2c_remove, .id_table = wm8940_i2c_id, }; diff --git a/sound/soc/codecs/wm8955.c b/sound/soc/codecs/wm8955.c index 2f1c075755b1..82c8ba975720 100644 --- a/sound/soc/codecs/wm8955.c +++ b/sound/soc/codecs/wm8955.c @@ -1012,8 +1012,8 @@ static const struct regmap_config wm8955_regmap = { .num_reg_defaults = ARRAY_SIZE(wm8955_reg_defaults), }; -static __devinit int wm8955_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8955_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) { struct wm8955_priv *wm8955; int ret; @@ -1023,7 +1023,7 @@ static __devinit int wm8955_i2c_probe(struct i2c_client *i2c, if (wm8955 == NULL) return -ENOMEM; - wm8955->regmap = regmap_init_i2c(i2c, &wm8955_regmap); + wm8955->regmap = devm_regmap_init_i2c(i2c, &wm8955_regmap); if (IS_ERR(wm8955->regmap)) { ret = PTR_ERR(wm8955->regmap); dev_err(&i2c->dev, "Failed to allocate register map: %d\n", @@ -1035,22 +1035,13 @@ static __devinit int wm8955_i2c_probe(struct i2c_client *i2c, ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm8955, &wm8955_dai, 1); - if (ret != 0) - goto err; return ret; - -err: - regmap_exit(wm8955->regmap); - return ret; } -static __devexit int wm8955_i2c_remove(struct i2c_client *client) +static int wm8955_i2c_remove(struct i2c_client *client) { - struct wm8955_priv *wm8955 = i2c_get_clientdata(client); - snd_soc_unregister_codec(&client->dev); - regmap_exit(wm8955->regmap); return 0; } @@ -1067,7 +1058,7 @@ static struct i2c_driver wm8955_i2c_driver = { .owner = THIS_MODULE, }, .probe = wm8955_i2c_probe, - .remove = __devexit_p(wm8955_i2c_remove), + .remove = wm8955_i2c_remove, .id_table = wm8955_i2c_id, }; diff --git a/sound/soc/codecs/wm8958-dsp2.c b/sound/soc/codecs/wm8958-dsp2.c index 00121ba36597..b0710d817a65 100644 --- a/sound/soc/codecs/wm8958-dsp2.c +++ b/sound/soc/codecs/wm8958-dsp2.c @@ -195,7 +195,7 @@ ok: static void wm8958_dsp_start_mbc(struct snd_soc_codec *codec, int path) { struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); - struct wm8994_pdata *pdata = wm8994->pdata; + struct wm8994 *control = wm8994->wm8994; int i; /* If the DSP is already running then noop */ @@ -210,9 +210,9 @@ static void wm8958_dsp_start_mbc(struct snd_soc_codec *codec, int path) WM8958_DSP2_ENA, WM8958_DSP2_ENA); /* If we've got user supplied MBC settings use them */ - if (pdata && pdata->num_mbc_cfgs) { + if (control->pdata.num_mbc_cfgs) { struct wm8958_mbc_cfg *cfg - = &pdata->mbc_cfgs[wm8994->mbc_cfg]; + = &control->pdata.mbc_cfgs[wm8994->mbc_cfg]; for (i = 0; i < ARRAY_SIZE(cfg->coeff_regs); i++) snd_soc_write(codec, i + WM8958_MBC_BAND_1_K_1, @@ -239,7 +239,7 @@ static void wm8958_dsp_start_mbc(struct snd_soc_codec *codec, int path) static void wm8958_dsp_start_vss(struct snd_soc_codec *codec, int path) { struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); - struct wm8994_pdata *pdata = wm8994->pdata; + struct wm8994 *control = wm8994->wm8994; int i, ena; if (wm8994->mbc_vss) @@ -249,26 +249,26 @@ static void wm8958_dsp_start_vss(struct snd_soc_codec *codec, int path) WM8958_DSP2_ENA, WM8958_DSP2_ENA); /* If we've got user supplied settings use them */ - if (pdata && pdata->num_mbc_cfgs) { + if (control->pdata.num_mbc_cfgs) { struct wm8958_mbc_cfg *cfg - = &pdata->mbc_cfgs[wm8994->mbc_cfg]; + = &control->pdata.mbc_cfgs[wm8994->mbc_cfg]; for (i = 0; i < ARRAY_SIZE(cfg->combined_regs); i++) snd_soc_write(codec, i + 0x2800, cfg->combined_regs[i]); } - if (pdata && pdata->num_vss_cfgs) { + if (control->pdata.num_vss_cfgs) { struct wm8958_vss_cfg *cfg - = &pdata->vss_cfgs[wm8994->vss_cfg]; + = &control->pdata.vss_cfgs[wm8994->vss_cfg]; for (i = 0; i < ARRAY_SIZE(cfg->regs); i++) snd_soc_write(codec, i + 0x2600, cfg->regs[i]); } - if (pdata && pdata->num_vss_hpf_cfgs) { + if (control->pdata.num_vss_hpf_cfgs) { struct wm8958_vss_hpf_cfg *cfg - = &pdata->vss_hpf_cfgs[wm8994->vss_hpf_cfg]; + = &control->pdata.vss_hpf_cfgs[wm8994->vss_hpf_cfg]; for (i = 0; i < ARRAY_SIZE(cfg->regs); i++) snd_soc_write(codec, i + 0x2400, cfg->regs[i]); @@ -300,7 +300,7 @@ static void wm8958_dsp_start_vss(struct snd_soc_codec *codec, int path) static void wm8958_dsp_start_enh_eq(struct snd_soc_codec *codec, int path) { struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); - struct wm8994_pdata *pdata = wm8994->pdata; + struct wm8994 *control = wm8994->wm8994; int i; wm8958_dsp2_fw(codec, "ENH_EQ", wm8994->enh_eq, false); @@ -309,9 +309,9 @@ static void wm8958_dsp_start_enh_eq(struct snd_soc_codec *codec, int path) WM8958_DSP2_ENA, WM8958_DSP2_ENA); /* If we've got user supplied settings use them */ - if (pdata && pdata->num_enh_eq_cfgs) { + if (control->pdata.num_enh_eq_cfgs) { struct wm8958_enh_eq_cfg *cfg - = &pdata->enh_eq_cfgs[wm8994->enh_eq_cfg]; + = &control->pdata.enh_eq_cfgs[wm8994->enh_eq_cfg]; for (i = 0; i < ARRAY_SIZE(cfg->regs); i++) snd_soc_write(codec, i + 0x2200, @@ -458,7 +458,7 @@ static int wm8958_put_mbc_enum(struct snd_kcontrol *kcontrol, { struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); - struct wm8994_pdata *pdata = wm8994->pdata; + struct wm8994 *control = wm8994->wm8994; int value = ucontrol->value.integer.value[0]; int reg; @@ -467,7 +467,7 @@ static int wm8958_put_mbc_enum(struct snd_kcontrol *kcontrol, if (reg < 0 || reg & WM8958_DSP2CLK_ENA) return -EBUSY; - if (value >= pdata->num_mbc_cfgs) + if (value >= control->pdata.num_mbc_cfgs) return -EINVAL; wm8994->mbc_cfg = value; @@ -548,7 +548,7 @@ static int wm8958_put_vss_enum(struct snd_kcontrol *kcontrol, { struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); - struct wm8994_pdata *pdata = wm8994->pdata; + struct wm8994 *control = wm8994->wm8994; int value = ucontrol->value.integer.value[0]; int reg; @@ -557,7 +557,7 @@ static int wm8958_put_vss_enum(struct snd_kcontrol *kcontrol, if (reg < 0 || reg & WM8958_DSP2CLK_ENA) return -EBUSY; - if (value >= pdata->num_vss_cfgs) + if (value >= control->pdata.num_vss_cfgs) return -EINVAL; wm8994->vss_cfg = value; @@ -581,7 +581,7 @@ static int wm8958_put_vss_hpf_enum(struct snd_kcontrol *kcontrol, { struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); - struct wm8994_pdata *pdata = wm8994->pdata; + struct wm8994 *control = wm8994->wm8994; int value = ucontrol->value.integer.value[0]; int reg; @@ -590,7 +590,7 @@ static int wm8958_put_vss_hpf_enum(struct snd_kcontrol *kcontrol, if (reg < 0 || reg & WM8958_DSP2CLK_ENA) return -EBUSY; - if (value >= pdata->num_vss_hpf_cfgs) + if (value >= control->pdata.num_vss_hpf_cfgs) return -EINVAL; wm8994->vss_hpf_cfg = value; @@ -748,7 +748,7 @@ static int wm8958_put_enh_eq_enum(struct snd_kcontrol *kcontrol, { struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); - struct wm8994_pdata *pdata = wm8994->pdata; + struct wm8994 *control = wm8994->wm8994; int value = ucontrol->value.integer.value[0]; int reg; @@ -757,7 +757,7 @@ static int wm8958_put_enh_eq_enum(struct snd_kcontrol *kcontrol, if (reg < 0 || reg & WM8958_DSP2CLK_ENA) return -EBUSY; - if (value >= pdata->num_enh_eq_cfgs) + if (value >= control->pdata.num_enh_eq_cfgs) return -EINVAL; wm8994->enh_eq_cfg = value; @@ -883,13 +883,6 @@ static void wm8958_mbc_vss_loaded(const struct firmware *fw, void *context) wm8994->mbc_vss = fw; mutex_unlock(&codec->mutex); } - - /* We can't have more than one request outstanding at once so - * we daisy chain. - */ - request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, - "wm8958_enh_eq.wfw", codec->dev, GFP_KERNEL, - codec, wm8958_enh_eq_loaded); } static void wm8958_mbc_loaded(const struct firmware *fw, void *context) @@ -897,25 +890,18 @@ static void wm8958_mbc_loaded(const struct firmware *fw, void *context) struct snd_soc_codec *codec = context; struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); - if (wm8958_dsp2_fw(codec, "MBC", fw, true) != 0) - return; - - mutex_lock(&codec->mutex); - wm8994->mbc = fw; - mutex_unlock(&codec->mutex); - - /* We can't have more than one request outstanding at once so - * we daisy chain. - */ - request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, - "wm8958_mbc_vss.wfw", codec->dev, GFP_KERNEL, - codec, wm8958_mbc_vss_loaded); + if (fw && (wm8958_dsp2_fw(codec, "MBC", fw, true) == 0)) { + mutex_lock(&codec->mutex); + wm8994->mbc = fw; + mutex_unlock(&codec->mutex); + } } void wm8958_dsp2_init(struct snd_soc_codec *codec) { struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); - struct wm8994_pdata *pdata = wm8994->pdata; + struct wm8994 *control = wm8994->wm8994; + struct wm8994_pdata *pdata = &control->pdata; int ret, i; wm8994->dsp_active = -1; @@ -932,9 +918,12 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec) request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, "wm8958_mbc.wfw", codec->dev, GFP_KERNEL, codec, wm8958_mbc_loaded); - - if (!pdata) - return; + request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, + "wm8958_mbc_vss.wfw", codec->dev, GFP_KERNEL, + codec, wm8958_mbc_vss_loaded); + request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, + "wm8958_enh_eq.wfw", codec->dev, GFP_KERNEL, + codec, wm8958_enh_eq_loaded); if (pdata->num_mbc_cfgs) { struct snd_kcontrol_new control[] = { diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index f0f6f6601785..9bb927325993 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c @@ -1028,8 +1028,8 @@ static const struct regmap_config wm8960_regmap = { .volatile_reg = wm8960_volatile, }; -static __devinit int wm8960_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8960_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) { struct wm8960_data *pdata = dev_get_platdata(&i2c->dev); struct wm8960_priv *wm8960; @@ -1040,7 +1040,7 @@ static __devinit int wm8960_i2c_probe(struct i2c_client *i2c, if (wm8960 == NULL) return -ENOMEM; - wm8960->regmap = regmap_init_i2c(i2c, &wm8960_regmap); + wm8960->regmap = devm_regmap_init_i2c(i2c, &wm8960_regmap); if (IS_ERR(wm8960->regmap)) return PTR_ERR(wm8960->regmap); @@ -1062,7 +1062,7 @@ static __devinit int wm8960_i2c_probe(struct i2c_client *i2c, return ret; } -static __devexit int wm8960_i2c_remove(struct i2c_client *client) +static int wm8960_i2c_remove(struct i2c_client *client) { snd_soc_unregister_codec(&client->dev); return 0; @@ -1080,7 +1080,7 @@ static struct i2c_driver wm8960_i2c_driver = { .owner = THIS_MODULE, }, .probe = wm8960_i2c_probe, - .remove = __devexit_p(wm8960_i2c_remove), + .remove = wm8960_i2c_remove, .id_table = wm8960_i2c_id, }; diff --git a/sound/soc/codecs/wm8961.c b/sound/soc/codecs/wm8961.c index f387670d0d75..900328e28a15 100644 --- a/sound/soc/codecs/wm8961.c +++ b/sound/soc/codecs/wm8961.c @@ -937,8 +937,8 @@ static const struct regmap_config wm8961_regmap = { .readable_reg = wm8961_readable, }; -static __devinit int wm8961_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8961_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) { struct wm8961_priv *wm8961; unsigned int val; @@ -993,7 +993,7 @@ static __devinit int wm8961_i2c_probe(struct i2c_client *i2c, return ret; } -static __devexit int wm8961_i2c_remove(struct i2c_client *client) +static int wm8961_i2c_remove(struct i2c_client *client) { snd_soc_unregister_codec(&client->dev); @@ -1012,7 +1012,7 @@ static struct i2c_driver wm8961_i2c_driver = { .owner = THIS_MODULE, }, .probe = wm8961_i2c_probe, - .remove = __devexit_p(wm8961_i2c_remove), + .remove = wm8961_i2c_remove, .id_table = wm8961_i2c_id, }; diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index ce6720073798..bd4b0db4cdaa 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -3588,8 +3588,8 @@ static const struct regmap_config wm8962_regmap = { .cache_type = REGCACHE_RBTREE, }; -static __devinit int wm8962_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8962_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) { struct wm8962_pdata *pdata = dev_get_platdata(&i2c->dev); struct wm8962_priv *wm8962; @@ -3610,7 +3610,7 @@ static __devinit int wm8962_i2c_probe(struct i2c_client *i2c, for (i = 0; i < ARRAY_SIZE(wm8962->supplies); i++) wm8962->supplies[i].supply = wm8962_supply_names[i]; - ret = regulator_bulk_get(&i2c->dev, ARRAY_SIZE(wm8962->supplies), + ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(wm8962->supplies), wm8962->supplies); if (ret != 0) { dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret); @@ -3621,10 +3621,10 @@ static __devinit int wm8962_i2c_probe(struct i2c_client *i2c, wm8962->supplies); if (ret != 0) { dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret); - goto err_get; + return ret; } - wm8962->regmap = regmap_init_i2c(i2c, &wm8962_regmap); + wm8962->regmap = devm_regmap_init_i2c(i2c, &wm8962_regmap); if (IS_ERR(wm8962->regmap)) { ret = PTR_ERR(wm8962->regmap); dev_err(&i2c->dev, "Failed to allocate regmap: %d\n", ret); @@ -3641,20 +3641,20 @@ static __devinit int wm8962_i2c_probe(struct i2c_client *i2c, ret = regmap_read(wm8962->regmap, WM8962_SOFTWARE_RESET, ®); if (ret < 0) { dev_err(&i2c->dev, "Failed to read ID register\n"); - goto err_regmap; + goto err_enable; } if (reg != 0x6243) { dev_err(&i2c->dev, "Device is not a WM8962, ID %x != 0x6243\n", reg); ret = -EINVAL; - goto err_regmap; + goto err_enable; } ret = regmap_read(wm8962->regmap, WM8962_RIGHT_INPUT_VOLUME, ®); if (ret < 0) { dev_err(&i2c->dev, "Failed to read device revision: %d\n", ret); - goto err_regmap; + goto err_enable; } dev_info(&i2c->dev, "customer id %x revision %c\n", @@ -3667,7 +3667,7 @@ static __devinit int wm8962_i2c_probe(struct i2c_client *i2c, ret = wm8962_reset(wm8962); if (ret < 0) { dev_err(&i2c->dev, "Failed to issue reset\n"); - goto err_regmap; + goto err_enable; } if (pdata && pdata->in4_dc_measure) { @@ -3686,30 +3686,22 @@ static __devinit int wm8962_i2c_probe(struct i2c_client *i2c, ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm8962, &wm8962_dai, 1); if (ret < 0) - goto err_regmap; + goto err_enable; /* The drivers should power up as needed */ regulator_bulk_disable(ARRAY_SIZE(wm8962->supplies), wm8962->supplies); return 0; -err_regmap: - regmap_exit(wm8962->regmap); err_enable: regulator_bulk_disable(ARRAY_SIZE(wm8962->supplies), wm8962->supplies); -err_get: - regulator_bulk_free(ARRAY_SIZE(wm8962->supplies), wm8962->supplies); err: return ret; } -static __devexit int wm8962_i2c_remove(struct i2c_client *client) +static int wm8962_i2c_remove(struct i2c_client *client) { - struct wm8962_priv *wm8962 = dev_get_drvdata(&client->dev); - snd_soc_unregister_codec(&client->dev); - regmap_exit(wm8962->regmap); - regulator_bulk_free(ARRAY_SIZE(wm8962->supplies), wm8962->supplies); return 0; } @@ -3773,7 +3765,7 @@ static struct i2c_driver wm8962_i2c_driver = { .pm = &wm8962_pm, }, .probe = wm8962_i2c_probe, - .remove = __devexit_p(wm8962_i2c_remove), + .remove = wm8962_i2c_remove, .id_table = wm8962_i2c_id, }; diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c index 5ce647758443..67aba78a7ca5 100644 --- a/sound/soc/codecs/wm8971.c +++ b/sound/soc/codecs/wm8971.c @@ -19,6 +19,7 @@ #include <linux/delay.h> #include <linux/pm.h> #include <linux/i2c.h> +#include <linux/regmap.h> #include <linux/slab.h> #include <sound/core.h> #include <sound/pcm.h> @@ -34,7 +35,6 @@ static struct workqueue_struct *wm8971_workq = NULL; /* codec private data */ struct wm8971_priv { - enum snd_soc_control_type control_type; unsigned int sysclk; }; @@ -43,18 +43,50 @@ struct wm8971_priv { * We can't read the WM8971 register space when we * are using 2 wire for device control, so we cache them instead. */ -static const u16 wm8971_reg[] = { - 0x0097, 0x0097, 0x0079, 0x0079, /* 0 */ - 0x0000, 0x0008, 0x0000, 0x000a, /* 4 */ - 0x0000, 0x0000, 0x00ff, 0x00ff, /* 8 */ - 0x000f, 0x000f, 0x0000, 0x0000, /* 12 */ - 0x0000, 0x007b, 0x0000, 0x0032, /* 16 */ - 0x0000, 0x00c3, 0x00c3, 0x00c0, /* 20 */ - 0x0000, 0x0000, 0x0000, 0x0000, /* 24 */ - 0x0000, 0x0000, 0x0000, 0x0000, /* 28 */ - 0x0000, 0x0000, 0x0050, 0x0050, /* 32 */ - 0x0050, 0x0050, 0x0050, 0x0050, /* 36 */ - 0x0079, 0x0079, 0x0079, /* 40 */ +static const struct reg_default wm8971_reg_defaults[] = { + { 0, 0x0097 }, + { 1, 0x0097 }, + { 2, 0x0079 }, + { 3, 0x0079 }, + { 4, 0x0000 }, + { 5, 0x0008 }, + { 6, 0x0000 }, + { 7, 0x000a }, + { 8, 0x0000 }, + { 9, 0x0000 }, + { 10, 0x00ff }, + { 11, 0x00ff }, + { 12, 0x000f }, + { 13, 0x000f }, + { 14, 0x0000 }, + { 15, 0x0000 }, + { 16, 0x0000 }, + { 17, 0x007b }, + { 18, 0x0000 }, + { 19, 0x0032 }, + { 20, 0x0000 }, + { 21, 0x00c3 }, + { 22, 0x00c3 }, + { 23, 0x00c0 }, + { 24, 0x0000 }, + { 25, 0x0000 }, + { 26, 0x0000 }, + { 27, 0x0000 }, + { 28, 0x0000 }, + { 29, 0x0000 }, + { 30, 0x0000 }, + { 31, 0x0000 }, + { 32, 0x0000 }, + { 33, 0x0000 }, + { 34, 0x0050 }, + { 35, 0x0050 }, + { 36, 0x0050 }, + { 37, 0x0050 }, + { 38, 0x0050 }, + { 39, 0x0050 }, + { 40, 0x0079 }, + { 41, 0x0079 }, + { 42, 0x0079 }, }; #define wm8971_reset(c) snd_soc_write(c, WM8971_RESET, 0) @@ -613,11 +645,10 @@ static int wm8971_resume(struct snd_soc_codec *codec) static int wm8971_probe(struct snd_soc_codec *codec) { - struct wm8971_priv *wm8971 = snd_soc_codec_get_drvdata(codec); int ret = 0; u16 reg; - ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8971->control_type); + ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP); if (ret < 0) { printk(KERN_ERR "wm8971: failed to set cache I/O: %d\n", ret); return ret; @@ -667,9 +698,6 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8971 = { .suspend = wm8971_suspend, .resume = wm8971_resume, .set_bias_level = wm8971_set_bias_level, - .reg_cache_size = ARRAY_SIZE(wm8971_reg), - .reg_word_size = sizeof(u16), - .reg_cache_default = wm8971_reg, .controls = wm8971_snd_controls, .num_controls = ARRAY_SIZE(wm8971_snd_controls), @@ -679,10 +707,21 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8971 = { .num_dapm_routes = ARRAY_SIZE(wm8971_dapm_routes), }; -static __devinit int wm8971_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static const struct regmap_config wm8971_regmap = { + .reg_bits = 7, + .val_bits = 9, + .max_register = WM8971_MOUTV, + + .reg_defaults = wm8971_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(wm8971_reg_defaults), + .cache_type = REGCACHE_RBTREE, +}; + +static int wm8971_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) { struct wm8971_priv *wm8971; + struct regmap *regmap; int ret; wm8971 = devm_kzalloc(&i2c->dev, sizeof(struct wm8971_priv), @@ -690,7 +729,10 @@ static __devinit int wm8971_i2c_probe(struct i2c_client *i2c, if (wm8971 == NULL) return -ENOMEM; - wm8971->control_type = SND_SOC_I2C; + regmap = devm_regmap_init_i2c(i2c, &wm8971_regmap); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + i2c_set_clientdata(i2c, wm8971); ret = snd_soc_register_codec(&i2c->dev, @@ -699,7 +741,7 @@ static __devinit int wm8971_i2c_probe(struct i2c_client *i2c, return ret; } -static __devexit int wm8971_i2c_remove(struct i2c_client *client) +static int wm8971_i2c_remove(struct i2c_client *client) { snd_soc_unregister_codec(&client->dev); return 0; @@ -717,7 +759,7 @@ static struct i2c_driver wm8971_i2c_driver = { .owner = THIS_MODULE, }, .probe = wm8971_i2c_probe, - .remove = __devexit_p(wm8971_i2c_remove), + .remove = wm8971_i2c_remove, .id_table = wm8971_i2c_id, }; diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c index 9a39511af52a..ea58b73e86b2 100644 --- a/sound/soc/codecs/wm8974.c +++ b/sound/soc/codecs/wm8974.c @@ -625,8 +625,8 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8974 = { .num_dapm_routes = ARRAY_SIZE(wm8974_dapm_routes), }; -static __devinit int wm8974_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8974_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) { int ret; @@ -636,7 +636,7 @@ static __devinit int wm8974_i2c_probe(struct i2c_client *i2c, return ret; } -static __devexit int wm8974_i2c_remove(struct i2c_client *client) +static int wm8974_i2c_remove(struct i2c_client *client) { snd_soc_unregister_codec(&client->dev); @@ -655,7 +655,7 @@ static struct i2c_driver wm8974_i2c_driver = { .owner = THIS_MODULE, }, .probe = wm8974_i2c_probe, - .remove = __devexit_p(wm8974_i2c_remove), + .remove = wm8974_i2c_remove, .id_table = wm8974_i2c_id, }; diff --git a/sound/soc/codecs/wm8978.c b/sound/soc/codecs/wm8978.c index 4c0a8e496131..f347af3a67c2 100644 --- a/sound/soc/codecs/wm8978.c +++ b/sound/soc/codecs/wm8978.c @@ -527,9 +527,6 @@ static int wm8978_configure_pll(struct snd_soc_codec *codec) return idx; wm8978->mclk_idx = idx; - - /* GPIO1 into default mode as input - before configuring PLL */ - snd_soc_update_bits(codec, WM8978_GPIO_CONTROL, 7, 0); } else { return -EINVAL; } @@ -1038,8 +1035,8 @@ static const struct regmap_config wm8978_regmap_config = { .num_reg_defaults = ARRAY_SIZE(wm8978_reg_defaults), }; -static __devinit int wm8978_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8978_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) { struct wm8978_priv *wm8978; int ret; @@ -1049,7 +1046,7 @@ static __devinit int wm8978_i2c_probe(struct i2c_client *i2c, if (wm8978 == NULL) return -ENOMEM; - wm8978->regmap = regmap_init_i2c(i2c, &wm8978_regmap_config); + wm8978->regmap = devm_regmap_init_i2c(i2c, &wm8978_regmap_config); if (IS_ERR(wm8978->regmap)) { ret = PTR_ERR(wm8978->regmap); dev_err(&i2c->dev, "Failed to allocate regmap: %d\n", ret); @@ -1062,29 +1059,22 @@ static __devinit int wm8978_i2c_probe(struct i2c_client *i2c, ret = regmap_write(wm8978->regmap, WM8978_RESET, 0); if (ret != 0) { dev_err(&i2c->dev, "Failed to issue reset: %d\n", ret); - goto err; + return ret; } ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm8978, &wm8978_dai, 1); if (ret != 0) { dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret); - goto err; + return ret; } return 0; - -err: - regmap_exit(wm8978->regmap); - return ret; } -static __devexit int wm8978_i2c_remove(struct i2c_client *client) +static int wm8978_i2c_remove(struct i2c_client *client) { - struct wm8978_priv *wm8978 = i2c_get_clientdata(client); - snd_soc_unregister_codec(&client->dev); - regmap_exit(wm8978->regmap); return 0; } @@ -1101,7 +1091,7 @@ static struct i2c_driver wm8978_i2c_driver = { .owner = THIS_MODULE, }, .probe = wm8978_i2c_probe, - .remove = __devexit_p(wm8978_i2c_remove), + .remove = wm8978_i2c_remove, .id_table = wm8978_i2c_id, }; diff --git a/sound/soc/codecs/wm8983.c b/sound/soc/codecs/wm8983.c index d8879f262d27..9fe1e041da49 100644 --- a/sound/soc/codecs/wm8983.c +++ b/sound/soc/codecs/wm8983.c @@ -1087,7 +1087,7 @@ static const struct regmap_config wm8983_regmap = { }; #if defined(CONFIG_SPI_MASTER) -static int __devinit wm8983_spi_probe(struct spi_device *spi) +static int wm8983_spi_probe(struct spi_device *spi) { struct wm8983_priv *wm8983; int ret; @@ -1110,7 +1110,7 @@ static int __devinit wm8983_spi_probe(struct spi_device *spi) return ret; } -static int __devexit wm8983_spi_remove(struct spi_device *spi) +static int wm8983_spi_remove(struct spi_device *spi) { snd_soc_unregister_codec(&spi->dev); return 0; @@ -1122,13 +1122,13 @@ static struct spi_driver wm8983_spi_driver = { .owner = THIS_MODULE, }, .probe = wm8983_spi_probe, - .remove = __devexit_p(wm8983_spi_remove) + .remove = wm8983_spi_remove }; #endif #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) -static __devinit int wm8983_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8983_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) { struct wm8983_priv *wm8983; int ret; @@ -1152,7 +1152,7 @@ static __devinit int wm8983_i2c_probe(struct i2c_client *i2c, return ret; } -static __devexit int wm8983_i2c_remove(struct i2c_client *client) +static int wm8983_i2c_remove(struct i2c_client *client) { snd_soc_unregister_codec(&client->dev); return 0; @@ -1170,7 +1170,7 @@ static struct i2c_driver wm8983_i2c_driver = { .owner = THIS_MODULE, }, .probe = wm8983_i2c_probe, - .remove = __devexit_p(wm8983_i2c_remove), + .remove = wm8983_i2c_remove, .id_table = wm8983_i2c_id }; #endif diff --git a/sound/soc/codecs/wm8985.c b/sound/soc/codecs/wm8985.c index 14f666398d0c..ab3782657ac8 100644 --- a/sound/soc/codecs/wm8985.c +++ b/sound/soc/codecs/wm8985.c @@ -1111,7 +1111,7 @@ static const struct regmap_config wm8985_regmap = { }; #if defined(CONFIG_SPI_MASTER) -static int __devinit wm8985_spi_probe(struct spi_device *spi) +static int wm8985_spi_probe(struct spi_device *spi) { struct wm8985_priv *wm8985; int ret; @@ -1122,33 +1122,22 @@ static int __devinit wm8985_spi_probe(struct spi_device *spi) spi_set_drvdata(spi, wm8985); - wm8985->regmap = regmap_init_spi(spi, &wm8985_regmap); + wm8985->regmap = devm_regmap_init_spi(spi, &wm8985_regmap); if (IS_ERR(wm8985->regmap)) { ret = PTR_ERR(wm8985->regmap); dev_err(&spi->dev, "Failed to allocate register map: %d\n", ret); - goto err; + return ret; } ret = snd_soc_register_codec(&spi->dev, &soc_codec_dev_wm8985, &wm8985_dai, 1); - if (ret != 0) - goto err; - - return 0; - -err: - regmap_exit(wm8985->regmap); return ret; } -static int __devexit wm8985_spi_remove(struct spi_device *spi) +static int wm8985_spi_remove(struct spi_device *spi) { - struct wm8985_priv *wm8985 = spi_get_drvdata(spi); - snd_soc_unregister_codec(&spi->dev); - regmap_exit(wm8985->regmap); - return 0; } @@ -1158,13 +1147,13 @@ static struct spi_driver wm8985_spi_driver = { .owner = THIS_MODULE, }, .probe = wm8985_spi_probe, - .remove = __devexit_p(wm8985_spi_remove) + .remove = wm8985_spi_remove }; #endif #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) -static __devinit int wm8985_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8985_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) { struct wm8985_priv *wm8985; int ret; @@ -1175,33 +1164,22 @@ static __devinit int wm8985_i2c_probe(struct i2c_client *i2c, i2c_set_clientdata(i2c, wm8985); - wm8985->regmap = regmap_init_i2c(i2c, &wm8985_regmap); + wm8985->regmap = devm_regmap_init_i2c(i2c, &wm8985_regmap); if (IS_ERR(wm8985->regmap)) { ret = PTR_ERR(wm8985->regmap); dev_err(&i2c->dev, "Failed to allocate register map: %d\n", ret); - goto err; + return ret; } ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm8985, &wm8985_dai, 1); - if (ret != 0) - goto err; - - return 0; - -err: - regmap_exit(wm8985->regmap); return ret; } -static __devexit int wm8985_i2c_remove(struct i2c_client *i2c) +static int wm8985_i2c_remove(struct i2c_client *i2c) { - struct wm8985_priv *wm8985 = i2c_get_clientdata(i2c); - snd_soc_unregister_codec(&i2c->dev); - regmap_exit(wm8985->regmap); - return 0; } @@ -1217,7 +1195,7 @@ static struct i2c_driver wm8985_i2c_driver = { .owner = THIS_MODULE, }, .probe = wm8985_i2c_probe, - .remove = __devexit_p(wm8985_i2c_remove), + .remove = wm8985_i2c_remove, .id_table = wm8985_i2c_id }; #endif diff --git a/sound/soc/codecs/wm8988.c b/sound/soc/codecs/wm8988.c index 1d4c5cf47b06..39b9acceb595 100644 --- a/sound/soc/codecs/wm8988.c +++ b/sound/soc/codecs/wm8988.c @@ -872,7 +872,7 @@ static struct regmap_config wm8988_regmap = { }; #if defined(CONFIG_SPI_MASTER) -static int __devinit wm8988_spi_probe(struct spi_device *spi) +static int wm8988_spi_probe(struct spi_device *spi) { struct wm8988_priv *wm8988; int ret; @@ -882,7 +882,7 @@ static int __devinit wm8988_spi_probe(struct spi_device *spi) if (wm8988 == NULL) return -ENOMEM; - wm8988->regmap = regmap_init_spi(spi, &wm8988_regmap); + wm8988->regmap = devm_regmap_init_spi(spi, &wm8988_regmap); if (IS_ERR(wm8988->regmap)) { ret = PTR_ERR(wm8988->regmap); dev_err(&spi->dev, "Failed to init regmap: %d\n", ret); @@ -893,17 +893,12 @@ static int __devinit wm8988_spi_probe(struct spi_device *spi) ret = snd_soc_register_codec(&spi->dev, &soc_codec_dev_wm8988, &wm8988_dai, 1); - if (ret != 0) - regmap_exit(wm8988->regmap); - return ret; } -static int __devexit wm8988_spi_remove(struct spi_device *spi) +static int wm8988_spi_remove(struct spi_device *spi) { - struct wm8988_priv *wm8988 = spi_get_drvdata(spi); snd_soc_unregister_codec(&spi->dev); - regmap_exit(wm8988->regmap); return 0; } @@ -913,13 +908,13 @@ static struct spi_driver wm8988_spi_driver = { .owner = THIS_MODULE, }, .probe = wm8988_spi_probe, - .remove = __devexit_p(wm8988_spi_remove), + .remove = wm8988_spi_remove, }; #endif /* CONFIG_SPI_MASTER */ #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) -static __devinit int wm8988_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8988_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) { struct wm8988_priv *wm8988; int ret; @@ -931,7 +926,7 @@ static __devinit int wm8988_i2c_probe(struct i2c_client *i2c, i2c_set_clientdata(i2c, wm8988); - wm8988->regmap = regmap_init_i2c(i2c, &wm8988_regmap); + wm8988->regmap = devm_regmap_init_i2c(i2c, &wm8988_regmap); if (IS_ERR(wm8988->regmap)) { ret = PTR_ERR(wm8988->regmap); dev_err(&i2c->dev, "Failed to init regmap: %d\n", ret); @@ -940,17 +935,12 @@ static __devinit int wm8988_i2c_probe(struct i2c_client *i2c, ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm8988, &wm8988_dai, 1); - if (ret != 0) - regmap_exit(wm8988->regmap); - return ret; } -static __devexit int wm8988_i2c_remove(struct i2c_client *client) +static int wm8988_i2c_remove(struct i2c_client *client) { - struct wm8988_priv *wm8988 = i2c_get_clientdata(client); snd_soc_unregister_codec(&client->dev); - regmap_exit(wm8988->regmap); return 0; } @@ -966,7 +956,7 @@ static struct i2c_driver wm8988_i2c_driver = { .owner = THIS_MODULE, }, .probe = wm8988_i2c_probe, - .remove = __devexit_p(wm8988_i2c_remove), + .remove = wm8988_i2c_remove, .id_table = wm8988_i2c_id, }; #endif diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c index c28c83e5395d..837978e16e9d 100644 --- a/sound/soc/codecs/wm8990.c +++ b/sound/soc/codecs/wm8990.c @@ -1382,8 +1382,8 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8990 = { }; #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) -static __devinit int wm8990_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8990_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) { struct wm8990_priv *wm8990; int ret; @@ -1401,7 +1401,7 @@ static __devinit int wm8990_i2c_probe(struct i2c_client *i2c, return ret; } -static __devexit int wm8990_i2c_remove(struct i2c_client *client) +static int wm8990_i2c_remove(struct i2c_client *client) { snd_soc_unregister_codec(&client->dev); @@ -1420,7 +1420,7 @@ static struct i2c_driver wm8990_i2c_driver = { .owner = THIS_MODULE, }, .probe = wm8990_i2c_probe, - .remove = __devexit_p(wm8990_i2c_remove), + .remove = wm8990_i2c_remove, .id_table = wm8990_i2c_id, }; #endif diff --git a/sound/soc/codecs/wm8991.c b/sound/soc/codecs/wm8991.c index fe439f027e10..3a39df7a3829 100644 --- a/sound/soc/codecs/wm8991.c +++ b/sound/soc/codecs/wm8991.c @@ -1357,8 +1357,8 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8991 = { .reg_cache_default = wm8991_reg_defs }; -static __devinit int wm8991_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8991_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) { struct wm8991_priv *wm8991; int ret; @@ -1376,7 +1376,7 @@ static __devinit int wm8991_i2c_probe(struct i2c_client *i2c, return ret; } -static __devexit int wm8991_i2c_remove(struct i2c_client *client) +static int wm8991_i2c_remove(struct i2c_client *client) { snd_soc_unregister_codec(&client->dev); @@ -1395,7 +1395,7 @@ static struct i2c_driver wm8991_i2c_driver = { .owner = THIS_MODULE, }, .probe = wm8991_i2c_probe, - .remove = __devexit_p(wm8991_i2c_remove), + .remove = wm8991_i2c_remove, .id_table = wm8991_i2c_id, }; diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c index 94737a30716b..433d59a0f3ef 100644 --- a/sound/soc/codecs/wm8993.c +++ b/sound/soc/codecs/wm8993.c @@ -1645,8 +1645,8 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8993 = { .set_bias_level = wm8993_set_bias_level, }; -static __devinit int wm8993_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8993_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) { struct wm8993_priv *wm8993; unsigned int reg; @@ -1660,7 +1660,7 @@ static __devinit int wm8993_i2c_probe(struct i2c_client *i2c, wm8993->dev = &i2c->dev; init_completion(&wm8993->fll_lock); - wm8993->regmap = regmap_init_i2c(i2c, &wm8993_regmap); + wm8993->regmap = devm_regmap_init_i2c(i2c, &wm8993_regmap); if (IS_ERR(wm8993->regmap)) { ret = PTR_ERR(wm8993->regmap); dev_err(&i2c->dev, "Failed to allocate regmap: %d\n", ret); @@ -1672,18 +1672,18 @@ static __devinit int wm8993_i2c_probe(struct i2c_client *i2c, for (i = 0; i < ARRAY_SIZE(wm8993->supplies); i++) wm8993->supplies[i].supply = wm8993_supply_names[i]; - ret = regulator_bulk_get(&i2c->dev, ARRAY_SIZE(wm8993->supplies), + ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(wm8993->supplies), wm8993->supplies); if (ret != 0) { dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret); - goto err; + return ret; } ret = regulator_bulk_enable(ARRAY_SIZE(wm8993->supplies), wm8993->supplies); if (ret != 0) { dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret); - goto err_get; + return ret; } ret = regmap_read(wm8993->regmap, WM8993_SOFTWARE_RESET, ®); @@ -1742,23 +1742,17 @@ err_irq: free_irq(i2c->irq, wm8993); err_enable: regulator_bulk_disable(ARRAY_SIZE(wm8993->supplies), wm8993->supplies); -err_get: - regulator_bulk_free(ARRAY_SIZE(wm8993->supplies), wm8993->supplies); -err: - regmap_exit(wm8993->regmap); return ret; } -static __devexit int wm8993_i2c_remove(struct i2c_client *i2c) +static int wm8993_i2c_remove(struct i2c_client *i2c) { struct wm8993_priv *wm8993 = i2c_get_clientdata(i2c); snd_soc_unregister_codec(&i2c->dev); if (i2c->irq) free_irq(i2c->irq, wm8993); - regmap_exit(wm8993->regmap); regulator_bulk_disable(ARRAY_SIZE(wm8993->supplies), wm8993->supplies); - regulator_bulk_free(ARRAY_SIZE(wm8993->supplies), wm8993->supplies); return 0; } @@ -1775,7 +1769,7 @@ static struct i2c_driver wm8993_i2c_driver = { .owner = THIS_MODULE, }, .probe = wm8993_i2c_probe, - .remove = __devexit_p(wm8993_i2c_remove), + .remove = wm8993_i2c_remove, .id_table = wm8993_i2c_id, }; diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index b2b2b37131bd..3b269fa226bd 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -91,8 +91,6 @@ static int wm8994_retune_mobile_base[] = { WM8994_AIF2_EQ_GAINS_1, }; -static void wm8958_default_micdet(u16 status, void *data); - static const struct wm8958_micd_rate micdet_rates[] = { { 32768, true, 1, 4 }, { 32768, false, 1, 1 }, @@ -110,15 +108,12 @@ static const struct wm8958_micd_rate jackdet_rates[] = { static void wm8958_micd_set_rate(struct snd_soc_codec *codec) { struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); + struct wm8994 *control = wm8994->wm8994; int best, i, sysclk, val; bool idle; const struct wm8958_micd_rate *rates; int num_rates; - if (!(wm8994->pdata && wm8994->pdata->micd_rates) && - wm8994->jack_cb != wm8958_default_micdet) - return; - idle = !wm8994->jack_mic; sysclk = snd_soc_read(codec, WM8994_CLOCKING_1); @@ -127,9 +122,9 @@ static void wm8958_micd_set_rate(struct snd_soc_codec *codec) else sysclk = wm8994->aifclk[0]; - if (wm8994->pdata && wm8994->pdata->micd_rates) { - rates = wm8994->pdata->micd_rates; - num_rates = wm8994->pdata->num_micd_rates; + if (control->pdata.micd_rates) { + rates = control->pdata.micd_rates; + num_rates = control->pdata.num_micd_rates; } else if (wm8994->jackdet) { rates = jackdet_rates; num_rates = ARRAY_SIZE(jackdet_rates); @@ -326,7 +321,8 @@ static int wm8994_put_drc_sw(struct snd_kcontrol *kcontrol, static void wm8994_set_drc(struct snd_soc_codec *codec, int drc) { struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); - struct wm8994_pdata *pdata = wm8994->pdata; + struct wm8994 *control = wm8994->wm8994; + struct wm8994_pdata *pdata = &control->pdata; int base = wm8994_drc_base[drc]; int cfg = wm8994->drc_cfg[drc]; int save, i; @@ -362,7 +358,8 @@ static int wm8994_put_drc_enum(struct snd_kcontrol *kcontrol, { struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); - struct wm8994_pdata *pdata = wm8994->pdata; + struct wm8994 *control = wm8994->wm8994; + struct wm8994_pdata *pdata = &control->pdata; int drc = wm8994_get_drc(kcontrol->id.name); int value = ucontrol->value.integer.value[0]; @@ -394,7 +391,8 @@ static int wm8994_get_drc_enum(struct snd_kcontrol *kcontrol, static void wm8994_set_retune_mobile(struct snd_soc_codec *codec, int block) { struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); - struct wm8994_pdata *pdata = wm8994->pdata; + struct wm8994 *control = wm8994->wm8994; + struct wm8994_pdata *pdata = &control->pdata; int base = wm8994_retune_mobile_base[block]; int iface, best, best_val, save, i, cfg; @@ -465,7 +463,8 @@ static int wm8994_put_retune_mobile_enum(struct snd_kcontrol *kcontrol, { struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); - struct wm8994_pdata *pdata = wm8994->pdata; + struct wm8994 *control = wm8994->wm8994; + struct wm8994_pdata *pdata = &control->pdata; int block = wm8994_get_retune_mobile_block(kcontrol->id.name); int value = ucontrol->value.integer.value[0]; @@ -736,7 +735,7 @@ static void wm1811_jackdet_set_mode(struct snd_soc_codec *codec, u16 mode) { struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); - if (!wm8994->jackdet || !wm8994->jack_cb) + if (!wm8994->jackdet || !wm8994->micdet[0].jack) return; if (wm8994->active_refcount) @@ -862,7 +861,7 @@ static void vmid_reference(struct snd_soc_codec *codec) WM8994_BIAS_SRC | WM8994_STARTUP_BIAS_ENA | WM8994_VMID_BUF_ENA | - (0x3 << WM8994_VMID_RAMP_SHIFT)); + (0x2 << WM8994_VMID_RAMP_SHIFT)); /* Main bias enable, VMID=2x40k */ snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1, @@ -870,7 +869,7 @@ static void vmid_reference(struct snd_soc_codec *codec) WM8994_VMID_SEL_MASK, WM8994_BIAS_ENA | 0x2); - msleep(50); + msleep(300); snd_soc_update_bits(codec, WM8994_ANTIPOP_2, WM8994_VMID_RAMP_MASK | @@ -939,16 +938,10 @@ static void vmid_dereference(struct snd_soc_codec *codec) WM8994_BIAS_SRC | WM8994_VMID_DISCH); - switch (wm8994->vmid_mode) { - case WM8994_VMID_FORCE: - msleep(350); - break; - default: - break; - } + snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1, + WM8994_VMID_SEL_MASK, 0); - snd_soc_update_bits(codec, WM8994_ADDITIONAL_CONTROL, - WM8994_VROI, WM8994_VROI); + msleep(400); /* Active discharge */ snd_soc_update_bits(codec, WM8994_ANTIPOP_1, @@ -957,17 +950,12 @@ static void vmid_dereference(struct snd_soc_codec *codec) WM8994_LINEOUT1_DISCH | WM8994_LINEOUT2_DISCH); - msleep(150); - snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_3, WM8994_LINEOUT1N_ENA | WM8994_LINEOUT1P_ENA | WM8994_LINEOUT2N_ENA | WM8994_LINEOUT2P_ENA, 0); - snd_soc_update_bits(codec, WM8994_ADDITIONAL_CONTROL, - WM8994_VROI, 0); - /* Switch off startup biases */ snd_soc_update_bits(codec, WM8994_ANTIPOP_2, WM8994_BIAS_SRC | @@ -976,10 +964,7 @@ static void vmid_dereference(struct snd_soc_codec *codec) WM8994_VMID_RAMP_MASK, 0); snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1, - WM8994_BIAS_ENA | WM8994_VMID_SEL_MASK, 0); - - snd_soc_update_bits(codec, WM8994_ANTIPOP_2, - WM8994_VMID_RAMP_MASK, 0); + WM8994_VMID_SEL_MASK, 0); } pm_runtime_put(codec->dev); @@ -2277,6 +2262,18 @@ out: configure_clock(codec); + /* + * If SYSCLK will be less than 50kHz adjust AIFnCLK dividers + * for detection. + */ + if (max(wm8994->aifclk[0], wm8994->aifclk[1]) < 50000) { + dev_dbg(codec->dev, "Configuring AIFs for 128fs\n"); + snd_soc_update_bits(codec, WM8994_AIF1_RATE, + WM8994_AIF1CLK_RATE_MASK, 0x1); + snd_soc_update_bits(codec, WM8994_AIF2_RATE, + WM8994_AIF2CLK_RATE_MASK, 0x1); + } + return 0; } @@ -2365,6 +2362,18 @@ static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai, configure_clock(codec); + /* + * If SYSCLK will be less than 50kHz adjust AIFnCLK dividers + * for detection. + */ + if (max(wm8994->aifclk[0], wm8994->aifclk[1]) < 50000) { + dev_dbg(codec->dev, "Configuring AIFs for 128fs\n"); + snd_soc_update_bits(codec, WM8994_AIF1_RATE, + WM8994_AIF1CLK_RATE_MASK, 0x1); + snd_soc_update_bits(codec, WM8994_AIF2_RATE, + WM8994_AIF2CLK_RATE_MASK, 0x1); + } + return 0; } @@ -3082,7 +3091,8 @@ static int wm8994_codec_resume(struct snd_soc_codec *codec) static void wm8994_handle_retune_mobile_pdata(struct wm8994_priv *wm8994) { struct snd_soc_codec *codec = wm8994->hubs.codec; - struct wm8994_pdata *pdata = wm8994->pdata; + struct wm8994 *control = wm8994->wm8994; + struct wm8994_pdata *pdata = &control->pdata; struct snd_kcontrol_new controls[] = { SOC_ENUM_EXT("AIF1.1 EQ Mode", wm8994->retune_mobile_enum, @@ -3149,7 +3159,8 @@ static void wm8994_handle_retune_mobile_pdata(struct wm8994_priv *wm8994) static void wm8994_handle_pdata(struct wm8994_priv *wm8994) { struct snd_soc_codec *codec = wm8994->hubs.codec; - struct wm8994_pdata *pdata = wm8994->pdata; + struct wm8994 *control = wm8994->wm8994; + struct wm8994_pdata *pdata = &control->pdata; int ret, i; if (!pdata) @@ -3389,38 +3400,80 @@ static irqreturn_t wm8994_mic_irq(int irq, void *data) return IRQ_HANDLED; } -/* Default microphone detection handler for WM8958 - the user can - * override this if they wish. - */ -static void wm8958_default_micdet(u16 status, void *data) +static void wm1811_micd_stop(struct snd_soc_codec *codec) +{ + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); + + if (!wm8994->jackdet) + return; + + mutex_lock(&wm8994->accdet_lock); + + snd_soc_update_bits(codec, WM8958_MIC_DETECT_1, WM8958_MICD_ENA, 0); + + wm1811_jackdet_set_mode(codec, WM1811_JACKDET_MODE_JACK); + + mutex_unlock(&wm8994->accdet_lock); + + if (wm8994->wm8994->pdata.jd_ext_cap) + snd_soc_dapm_disable_pin(&codec->dapm, + "MICBIAS2"); +} + +static void wm8958_button_det(struct snd_soc_codec *codec, u16 status) { - struct snd_soc_codec *codec = data; struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); int report; - dev_dbg(codec->dev, "MICDET %x\n", status); + report = 0; + if (status & 0x4) + report |= SND_JACK_BTN_0; + + if (status & 0x8) + report |= SND_JACK_BTN_1; + + if (status & 0x10) + report |= SND_JACK_BTN_2; + + if (status & 0x20) + report |= SND_JACK_BTN_3; + + if (status & 0x40) + report |= SND_JACK_BTN_4; + + if (status & 0x80) + report |= SND_JACK_BTN_5; + + snd_soc_jack_report(wm8994->micdet[0].jack, report, + wm8994->btn_mask); +} + +static void wm8958_mic_id(void *data, u16 status) +{ + struct snd_soc_codec *codec = data; + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); /* Either nothing present or just starting detection */ if (!(status & WM8958_MICD_STS)) { - if (!wm8994->jackdet) { - /* If nothing present then clear our statuses */ - dev_dbg(codec->dev, "Detected open circuit\n"); - wm8994->jack_mic = false; - wm8994->mic_detecting = true; + /* If nothing present then clear our statuses */ + dev_dbg(codec->dev, "Detected open circuit\n"); + wm8994->jack_mic = false; + wm8994->mic_detecting = true; - wm8958_micd_set_rate(codec); + wm1811_micd_stop(codec); - snd_soc_jack_report(wm8994->micdet[0].jack, 0, - wm8994->btn_mask | - SND_JACK_HEADSET); - } + wm8958_micd_set_rate(codec); + + snd_soc_jack_report(wm8994->micdet[0].jack, 0, + wm8994->btn_mask | + SND_JACK_HEADSET); return; } /* If the measurement is showing a high impedence we've got a * microphone. */ - if (wm8994->mic_detecting && (status & 0x600)) { + if (status & 0x600) { dev_dbg(codec->dev, "Detected microphone\n"); wm8994->mic_detecting = false; @@ -3433,64 +3486,67 @@ static void wm8958_default_micdet(u16 status, void *data) } - if (wm8994->mic_detecting && status & 0xfc) { + if (status & 0xfc) { dev_dbg(codec->dev, "Detected headphone\n"); wm8994->mic_detecting = false; wm8958_micd_set_rate(codec); /* If we have jackdet that will detect removal */ - if (wm8994->jackdet) { - mutex_lock(&wm8994->accdet_lock); - - snd_soc_update_bits(codec, WM8958_MIC_DETECT_1, - WM8958_MICD_ENA, 0); - - wm1811_jackdet_set_mode(codec, - WM1811_JACKDET_MODE_JACK); - - mutex_unlock(&wm8994->accdet_lock); - - if (wm8994->pdata->jd_ext_cap) - snd_soc_dapm_disable_pin(&codec->dapm, - "MICBIAS2"); - } + wm1811_micd_stop(codec); snd_soc_jack_report(wm8994->micdet[0].jack, SND_JACK_HEADPHONE, SND_JACK_HEADSET); } +} - /* Report short circuit as a button */ - if (wm8994->jack_mic) { - report = 0; - if (status & 0x4) - report |= SND_JACK_BTN_0; +/* Deferred mic detection to allow for extra settling time */ +static void wm1811_mic_work(struct work_struct *work) +{ + struct wm8994_priv *wm8994 = container_of(work, struct wm8994_priv, + mic_work.work); + struct wm8994 *control = wm8994->wm8994; + struct snd_soc_codec *codec = wm8994->hubs.codec; - if (status & 0x8) - report |= SND_JACK_BTN_1; + pm_runtime_get_sync(codec->dev); - if (status & 0x10) - report |= SND_JACK_BTN_2; + /* If required for an external cap force MICBIAS on */ + if (control->pdata.jd_ext_cap) { + snd_soc_dapm_force_enable_pin(&codec->dapm, + "MICBIAS2"); + snd_soc_dapm_sync(&codec->dapm); + } - if (status & 0x20) - report |= SND_JACK_BTN_3; + mutex_lock(&wm8994->accdet_lock); - if (status & 0x40) - report |= SND_JACK_BTN_4; + dev_dbg(codec->dev, "Starting mic detection\n"); - if (status & 0x80) - report |= SND_JACK_BTN_5; + /* Use a user-supplied callback if we have one */ + if (wm8994->micd_cb) { + wm8994->micd_cb(wm8994->micd_cb_data); + } else { + /* + * Start off measument of microphone impedence to find out + * what's actually there. + */ + wm8994->mic_detecting = true; + wm1811_jackdet_set_mode(codec, WM1811_JACKDET_MODE_MIC); - snd_soc_jack_report(wm8994->micdet[0].jack, report, - wm8994->btn_mask); + snd_soc_update_bits(codec, WM8958_MIC_DETECT_1, + WM8958_MICD_ENA, WM8958_MICD_ENA); } + + mutex_unlock(&wm8994->accdet_lock); + + pm_runtime_put(codec->dev); } static irqreturn_t wm1811_jackdet_irq(int irq, void *data) { struct wm8994_priv *wm8994 = data; + struct wm8994 *control = wm8994->wm8994; struct snd_soc_codec *codec = wm8994->hubs.codec; - int reg; + int reg, delay; bool present; pm_runtime_get_sync(codec->dev); @@ -3521,18 +3577,14 @@ static irqreturn_t wm1811_jackdet_irq(int irq, void *data) snd_soc_update_bits(codec, WM1811_JACKDET_CTRL, WM1811_JACKDET_DB, 0); - /* - * Start off measument of microphone impedence to find - * out what's actually there. - */ - wm8994->mic_detecting = true; - wm1811_jackdet_set_mode(codec, WM1811_JACKDET_MODE_MIC); - - snd_soc_update_bits(codec, WM8958_MIC_DETECT_1, - WM8958_MICD_ENA, WM8958_MICD_ENA); + delay = control->pdata.micdet_delay; + schedule_delayed_work(&wm8994->mic_work, + msecs_to_jiffies(delay)); } else { dev_dbg(codec->dev, "Jack not detected\n"); + cancel_delayed_work_sync(&wm8994->mic_work); + snd_soc_update_bits(codec, WM8958_MICBIAS2, WM8958_MICB2_DISCH, WM8958_MICB2_DISCH); @@ -3549,14 +3601,9 @@ static irqreturn_t wm1811_jackdet_irq(int irq, void *data) mutex_unlock(&wm8994->accdet_lock); - /* If required for an external cap force MICBIAS on */ - if (wm8994->pdata->jd_ext_cap) { - if (present) - snd_soc_dapm_force_enable_pin(&codec->dapm, - "MICBIAS2"); - else - snd_soc_dapm_disable_pin(&codec->dapm, "MICBIAS2"); - } + /* Turn off MICBIAS if it was on for an external cap */ + if (control->pdata.jd_ext_cap && !present) + snd_soc_dapm_disable_pin(&codec->dapm, "MICBIAS2"); if (present) snd_soc_jack_report(wm8994->micdet[0].jack, @@ -3599,7 +3646,8 @@ static void wm1811_jackdet_bootstrap(struct work_struct *work) * detection algorithm. */ int wm8958_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack, - wm8958_micdet_cb cb, void *cb_data) + wm1811_micdet_cb det_cb, void *det_cb_data, + wm1811_mic_id_cb id_cb, void *id_cb_data) { struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); struct wm8994 *control = wm8994->wm8994; @@ -3614,27 +3662,32 @@ int wm8958_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack, } if (jack) { - if (!cb) { - dev_dbg(codec->dev, "Using default micdet callback\n"); - cb = wm8958_default_micdet; - cb_data = codec; - } - snd_soc_dapm_force_enable_pin(&codec->dapm, "CLK_SYS"); snd_soc_dapm_sync(&codec->dapm); wm8994->micdet[0].jack = jack; - wm8994->jack_cb = cb; - wm8994->jack_cb_data = cb_data; - wm8994->mic_detecting = true; - wm8994->jack_mic = false; + if (det_cb) { + wm8994->micd_cb = det_cb; + wm8994->micd_cb_data = det_cb_data; + } else { + wm8994->mic_detecting = true; + wm8994->jack_mic = false; + } + + if (id_cb) { + wm8994->mic_id_cb = id_cb; + wm8994->mic_id_cb_data = id_cb_data; + } else { + wm8994->mic_id_cb = wm8958_mic_id; + wm8994->mic_id_cb_data = codec; + } wm8958_micd_set_rate(codec); /* Detect microphones and short circuits by default */ - if (wm8994->pdata->micd_lvl_sel) - micd_lvl_sel = wm8994->pdata->micd_lvl_sel; + if (control->pdata.micd_lvl_sel) + micd_lvl_sel = control->pdata.micd_lvl_sel; else micd_lvl_sel = 0x41; @@ -3728,10 +3781,22 @@ static irqreturn_t wm8958_mic_irq(int irq, void *data) trace_snd_soc_jack_irq(dev_name(codec->dev)); #endif - if (wm8994->jack_cb) - wm8994->jack_cb(reg, wm8994->jack_cb_data); + /* Avoid a transient report when the accessory is being removed */ + if (wm8994->jackdet) { + reg = snd_soc_read(codec, WM1811_JACKDET_CTRL); + if (reg < 0) { + dev_err(codec->dev, "Failed to read jack status: %d\n", + reg); + } else if (!(reg & WM1811_JACKDET_LVL)) { + dev_dbg(codec->dev, "Ignoring removed jack\n"); + return IRQ_HANDLED; + } + } + + if (wm8994->mic_detecting) + wm8994->mic_id_cb(wm8994->mic_id_cb_data, reg); else - dev_warn(codec->dev, "Accessory detection with no callback\n"); + wm8958_button_det(codec, reg); out: pm_runtime_put(codec->dev); @@ -3779,15 +3844,24 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) snd_soc_codec_set_cache_io(codec, 16, 16, SND_SOC_REGMAP); mutex_init(&wm8994->accdet_lock); - INIT_DELAYED_WORK(&wm8994->mic_work, wm8994_mic_work); INIT_DELAYED_WORK(&wm8994->jackdet_bootstrap, wm1811_jackdet_bootstrap); + switch (control->type) { + case WM8994: + INIT_DELAYED_WORK(&wm8994->mic_work, wm8994_mic_work); + break; + case WM1811: + INIT_DELAYED_WORK(&wm8994->mic_work, wm1811_mic_work); + break; + default: + break; + } + for (i = 0; i < ARRAY_SIZE(wm8994->fll_locked); i++) init_completion(&wm8994->fll_locked[i]); - if (wm8994->pdata && wm8994->pdata->micdet_irq) - wm8994->micdet_irq = wm8994->pdata->micdet_irq; + wm8994->micdet_irq = control->pdata.micdet_irq; pm_runtime_enable(codec->dev); pm_runtime_idle(codec->dev); @@ -3800,8 +3874,8 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) switch (control->type) { case WM8994: /* Single ended line outputs should have VMID on. */ - if (!wm8994->pdata->lineout1_diff || - !wm8994->pdata->lineout2_diff) + if (!control->pdata.lineout1_diff || + !control->pdata.lineout2_diff) codec->dapm.idle_bias_off = 0; switch (wm8994->revision) { @@ -3839,20 +3913,8 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) wm8994->hubs.no_cache_dac_hp_direct = true; wm8994->fll_byp = true; - switch (control->cust_id) { - case 0: - case 2: - wm8994->hubs.dcs_codes_l = -9; - wm8994->hubs.dcs_codes_r = -7; - break; - case 1: - case 3: - wm8994->hubs.dcs_codes_l = -8; - wm8994->hubs.dcs_codes_r = -7; - break; - default: - break; - } + wm8994->hubs.dcs_codes_l = -9; + wm8994->hubs.dcs_codes_r = -7; snd_soc_update_bits(codec, WM8994_ANALOGUE_HP_1, WM1811_HPOUT1_ATTN, WM1811_HPOUT1_ATTN); @@ -4225,7 +4287,7 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8994 = { .set_bias_level = wm8994_set_bias_level, }; -static int __devinit wm8994_probe(struct platform_device *pdev) +static int wm8994_probe(struct platform_device *pdev) { struct wm8994_priv *wm8994; @@ -4236,13 +4298,12 @@ static int __devinit wm8994_probe(struct platform_device *pdev) platform_set_drvdata(pdev, wm8994); wm8994->wm8994 = dev_get_drvdata(pdev->dev.parent); - wm8994->pdata = dev_get_platdata(pdev->dev.parent); return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm8994, wm8994_dai, ARRAY_SIZE(wm8994_dai)); } -static int __devexit wm8994_remove(struct platform_device *pdev) +static int wm8994_remove(struct platform_device *pdev) { snd_soc_unregister_codec(&pdev->dev); return 0; @@ -4266,7 +4327,7 @@ static int wm8994_resume(struct device *dev) { struct wm8994_priv *wm8994 = dev_get_drvdata(dev); - if (wm8994->jackdet && wm8994->jack_cb) + if (wm8994->jackdet && wm8994->jackdet_mode) regmap_update_bits(wm8994->wm8994->regmap, WM8994_ANTIPOP_2, WM1811_JACKDET_MODE_MASK, WM1811_JACKDET_MODE_AUDIO); @@ -4286,7 +4347,7 @@ static struct platform_driver wm8994_codec_driver = { .pm = &wm8994_pm_ops, }, .probe = wm8994_probe, - .remove = __devexit_p(wm8994_remove), + .remove = wm8994_remove, }; module_platform_driver(wm8994_codec_driver); diff --git a/sound/soc/codecs/wm8994.h b/sound/soc/codecs/wm8994.h index ccbce5791e95..45f192702024 100644 --- a/sound/soc/codecs/wm8994.h +++ b/sound/soc/codecs/wm8994.h @@ -39,12 +39,14 @@ enum wm8994_vmid_mode { WM8994_VMID_FORCE, }; -typedef void (*wm8958_micdet_cb)(u16 status, void *data); +typedef void (*wm1811_micdet_cb)(void *data); +typedef void (*wm1811_mic_id_cb)(void *data, u16 status); int wm8994_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack, int micbias); int wm8958_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack, - wm8958_micdet_cb cb, void *cb_data); + wm1811_micdet_cb cb, void *det_cb_data, + wm1811_mic_id_cb id_cb, void *id_cb_data); int wm8994_vmid_mode(struct snd_soc_codec *codec, enum wm8994_vmid_mode mode); @@ -138,12 +140,13 @@ struct wm8994_priv { int jackdet_mode; struct delayed_work jackdet_bootstrap; - wm8958_micdet_cb jack_cb; - void *jack_cb_data; int micdet_irq; + wm1811_micdet_cb micd_cb; + void *micd_cb_data; + wm1811_mic_id_cb mic_id_cb; + void *mic_id_cb_data; int revision; - struct wm8994_pdata *pdata; unsigned int aif1clk_enable:1; unsigned int aif2clk_enable:1; diff --git a/sound/soc/codecs/wm8995.c b/sound/soc/codecs/wm8995.c index 28c89b094c6e..90a65c427541 100644 --- a/sound/soc/codecs/wm8995.c +++ b/sound/soc/codecs/wm8995.c @@ -2256,46 +2256,33 @@ static struct regmap_config wm8995_regmap = { }; #if defined(CONFIG_SPI_MASTER) -static int __devinit wm8995_spi_probe(struct spi_device *spi) +static int wm8995_spi_probe(struct spi_device *spi) { struct wm8995_priv *wm8995; int ret; - wm8995 = kzalloc(sizeof *wm8995, GFP_KERNEL); + wm8995 = devm_kzalloc(&spi->dev, sizeof(*wm8995), GFP_KERNEL); if (!wm8995) return -ENOMEM; spi_set_drvdata(spi, wm8995); - wm8995->regmap = regmap_init_spi(spi, &wm8995_regmap); + wm8995->regmap = devm_regmap_init_spi(spi, &wm8995_regmap); if (IS_ERR(wm8995->regmap)) { ret = PTR_ERR(wm8995->regmap); dev_err(&spi->dev, "Failed to register regmap: %d\n", ret); - goto err_alloc; + return ret; } ret = snd_soc_register_codec(&spi->dev, &soc_codec_dev_wm8995, wm8995_dai, ARRAY_SIZE(wm8995_dai)); - if (ret < 0) - goto err_regmap; - - return ret; - -err_regmap: - regmap_exit(wm8995->regmap); -err_alloc: - kfree(wm8995); - return ret; } -static int __devexit wm8995_spi_remove(struct spi_device *spi) +static int wm8995_spi_remove(struct spi_device *spi) { - struct wm8995_priv *wm8995 = spi_get_drvdata(spi); snd_soc_unregister_codec(&spi->dev); - regmap_exit(wm8995->regmap); - kfree(wm8995); return 0; } @@ -2305,55 +2292,42 @@ static struct spi_driver wm8995_spi_driver = { .owner = THIS_MODULE, }, .probe = wm8995_spi_probe, - .remove = __devexit_p(wm8995_spi_remove) + .remove = wm8995_spi_remove }; #endif #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) -static __devinit int wm8995_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8995_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) { struct wm8995_priv *wm8995; int ret; - wm8995 = kzalloc(sizeof *wm8995, GFP_KERNEL); + wm8995 = devm_kzalloc(&i2c->dev, sizeof(*wm8995), GFP_KERNEL); if (!wm8995) return -ENOMEM; i2c_set_clientdata(i2c, wm8995); - wm8995->regmap = regmap_init_i2c(i2c, &wm8995_regmap); + wm8995->regmap = devm_regmap_init_i2c(i2c, &wm8995_regmap); if (IS_ERR(wm8995->regmap)) { ret = PTR_ERR(wm8995->regmap); dev_err(&i2c->dev, "Failed to register regmap: %d\n", ret); - goto err_alloc; + return ret; } ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm8995, wm8995_dai, ARRAY_SIZE(wm8995_dai)); - if (ret < 0) { + if (ret < 0) dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret); - goto err_regmap; - } - - return ret; - -err_regmap: - regmap_exit(wm8995->regmap); -err_alloc: - kfree(wm8995); return ret; } -static __devexit int wm8995_i2c_remove(struct i2c_client *client) +static int wm8995_i2c_remove(struct i2c_client *client) { - struct wm8995_priv *wm8995 = i2c_get_clientdata(client); - snd_soc_unregister_codec(&client->dev); - regmap_exit(wm8995->regmap); - kfree(wm8995); return 0; } @@ -2370,7 +2344,7 @@ static struct i2c_driver wm8995_i2c_driver = { .owner = THIS_MODULE, }, .probe = wm8995_i2c_probe, - .remove = __devexit_p(wm8995_i2c_remove), + .remove = wm8995_i2c_remove, .id_table = wm8995_i2c_id }; #endif diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c index 6dcb02c3666f..46fe83d2b224 100644 --- a/sound/soc/codecs/wm8996.c +++ b/sound/soc/codecs/wm8996.c @@ -2765,8 +2765,8 @@ static struct snd_soc_dai_driver wm8996_dai[] = { }, }; -static __devinit int wm8996_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8996_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) { struct wm8996_priv *wm8996; int ret, i; @@ -3077,7 +3077,7 @@ err: return ret; } -static __devexit int wm8996_i2c_remove(struct i2c_client *client) +static int wm8996_i2c_remove(struct i2c_client *client) { struct wm8996_priv *wm8996 = i2c_get_clientdata(client); int i; @@ -3107,7 +3107,7 @@ static struct i2c_driver wm8996_i2c_driver = { .owner = THIS_MODULE, }, .probe = wm8996_i2c_probe, - .remove = __devexit_p(wm8996_i2c_remove), + .remove = wm8996_i2c_remove, .id_table = wm8996_i2c_id, }; diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c index 2de74e1ea225..630b3d776ec2 100644 --- a/sound/soc/codecs/wm9081.c +++ b/sound/soc/codecs/wm9081.c @@ -1327,8 +1327,8 @@ static const struct regmap_config wm9081_regmap = { }; #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) -static __devinit int wm9081_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm9081_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) { struct wm9081_priv *wm9081; unsigned int reg; @@ -1341,28 +1341,27 @@ static __devinit int wm9081_i2c_probe(struct i2c_client *i2c, i2c_set_clientdata(i2c, wm9081); - wm9081->regmap = regmap_init_i2c(i2c, &wm9081_regmap); + wm9081->regmap = devm_regmap_init_i2c(i2c, &wm9081_regmap); if (IS_ERR(wm9081->regmap)) { ret = PTR_ERR(wm9081->regmap); dev_err(&i2c->dev, "regmap_init() failed: %d\n", ret); - goto err; + return ret; } ret = regmap_read(wm9081->regmap, WM9081_SOFTWARE_RESET, ®); if (ret != 0) { dev_err(&i2c->dev, "Failed to read chip ID: %d\n", ret); - goto err_regmap; + return ret; } if (reg != 0x9081) { dev_err(&i2c->dev, "Device is not a WM9081: ID=0x%x\n", reg); - ret = -EINVAL; - goto err_regmap; + return -EINVAL; } ret = wm9081_reset(wm9081->regmap); if (ret < 0) { dev_err(&i2c->dev, "Failed to issue reset\n"); - goto err_regmap; + return ret; } if (dev_get_platdata(&i2c->dev)) @@ -1382,23 +1381,14 @@ static __devinit int wm9081_i2c_probe(struct i2c_client *i2c, ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm9081, &wm9081_dai, 1); if (ret < 0) - goto err_regmap; + return ret; return 0; - -err_regmap: - regmap_exit(wm9081->regmap); -err: - - return ret; } -static __devexit int wm9081_i2c_remove(struct i2c_client *client) +static int wm9081_i2c_remove(struct i2c_client *client) { - struct wm9081_priv *wm9081 = i2c_get_clientdata(client); - snd_soc_unregister_codec(&client->dev); - regmap_exit(wm9081->regmap); return 0; } @@ -1414,7 +1404,7 @@ static struct i2c_driver wm9081_i2c_driver = { .owner = THIS_MODULE, }, .probe = wm9081_i2c_probe, - .remove = __devexit_p(wm9081_i2c_remove), + .remove = wm9081_i2c_remove, .id_table = wm9081_i2c_id, }; #endif diff --git a/sound/soc/codecs/wm9090.c b/sound/soc/codecs/wm9090.c index c7ddc56175d1..a07fe1618eec 100644 --- a/sound/soc/codecs/wm9090.c +++ b/sound/soc/codecs/wm9090.c @@ -628,7 +628,7 @@ static int wm9090_i2c_probe(struct i2c_client *i2c, return -ENOMEM; } - wm9090->regmap = regmap_init_i2c(i2c, &wm9090_regmap); + wm9090->regmap = devm_regmap_init_i2c(i2c, &wm9090_regmap); if (IS_ERR(wm9090->regmap)) { ret = PTR_ERR(wm9090->regmap); dev_err(&i2c->dev, "Failed to allocate regmap: %d\n", ret); @@ -637,16 +637,16 @@ static int wm9090_i2c_probe(struct i2c_client *i2c, ret = regmap_read(wm9090->regmap, WM9090_SOFTWARE_RESET, ®); if (ret < 0) - goto err; + return ret; + if (reg != 0x9093) { dev_err(&i2c->dev, "Device is not a WM9090, ID=%x\n", reg); - ret = -ENODEV; - goto err; + return -ENODEV; } ret = regmap_write(wm9090->regmap, WM9090_SOFTWARE_RESET, 0); if (ret < 0) - goto err; + return ret; if (i2c->dev.platform_data) memcpy(&wm9090->pdata, i2c->dev.platform_data, @@ -658,23 +658,15 @@ static int wm9090_i2c_probe(struct i2c_client *i2c, &soc_codec_dev_wm9090, NULL, 0); if (ret != 0) { dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret); - goto err; + return ret; } return 0; - -err: - regmap_exit(wm9090->regmap); - return ret; } -static int __devexit wm9090_i2c_remove(struct i2c_client *i2c) +static int wm9090_i2c_remove(struct i2c_client *i2c) { - struct wm9090_priv *wm9090 = i2c_get_clientdata(i2c); - snd_soc_unregister_codec(&i2c->dev); - regmap_exit(wm9090->regmap); - return 0; } @@ -691,7 +683,7 @@ static struct i2c_driver wm9090_i2c_driver = { .owner = THIS_MODULE, }, .probe = wm9090_i2c_probe, - .remove = __devexit_p(wm9090_i2c_remove), + .remove = wm9090_i2c_remove, .id_table = wm9090_id, }; diff --git a/sound/soc/codecs/wm9705.c b/sound/soc/codecs/wm9705.c index e8e782a0c78d..05b1f346695b 100644 --- a/sound/soc/codecs/wm9705.c +++ b/sound/soc/codecs/wm9705.c @@ -382,13 +382,13 @@ static struct snd_soc_codec_driver soc_codec_dev_wm9705 = { .num_dapm_routes = ARRAY_SIZE(wm9705_audio_map), }; -static __devinit int wm9705_probe(struct platform_device *pdev) +static int wm9705_probe(struct platform_device *pdev) { return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm9705, wm9705_dai, ARRAY_SIZE(wm9705_dai)); } -static int __devexit wm9705_remove(struct platform_device *pdev) +static int wm9705_remove(struct platform_device *pdev) { snd_soc_unregister_codec(&pdev->dev); return 0; @@ -401,7 +401,7 @@ static struct platform_driver wm9705_codec_driver = { }, .probe = wm9705_probe, - .remove = __devexit_p(wm9705_remove), + .remove = wm9705_remove, }; module_platform_driver(wm9705_codec_driver); diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c index 4dd73ea08d0b..8e9a6a3eeb1a 100644 --- a/sound/soc/codecs/wm9712.c +++ b/sound/soc/codecs/wm9712.c @@ -685,13 +685,13 @@ static struct snd_soc_codec_driver soc_codec_dev_wm9712 = { .num_dapm_routes = ARRAY_SIZE(wm9712_audio_map), }; -static __devinit int wm9712_probe(struct platform_device *pdev) +static int wm9712_probe(struct platform_device *pdev) { return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm9712, wm9712_dai, ARRAY_SIZE(wm9712_dai)); } -static int __devexit wm9712_remove(struct platform_device *pdev) +static int wm9712_remove(struct platform_device *pdev) { snd_soc_unregister_codec(&pdev->dev); return 0; @@ -704,7 +704,7 @@ static struct platform_driver wm9712_codec_driver = { }, .probe = wm9712_probe, - .remove = __devexit_p(wm9712_remove), + .remove = wm9712_remove, }; module_platform_driver(wm9712_codec_driver); diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index 3eb19fb71d17..f7afa68d8c7f 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c @@ -1254,13 +1254,13 @@ static struct snd_soc_codec_driver soc_codec_dev_wm9713 = { .num_dapm_routes = ARRAY_SIZE(wm9713_audio_map), }; -static __devinit int wm9713_probe(struct platform_device *pdev) +static int wm9713_probe(struct platform_device *pdev) { return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm9713, wm9713_dai, ARRAY_SIZE(wm9713_dai)); } -static int __devexit wm9713_remove(struct platform_device *pdev) +static int wm9713_remove(struct platform_device *pdev) { snd_soc_unregister_codec(&pdev->dev); return 0; @@ -1273,7 +1273,7 @@ static struct platform_driver wm9713_codec_driver = { }, .probe = wm9713_probe, - .remove = __devexit_p(wm9713_remove), + .remove = wm9713_remove, }; module_platform_driver(wm9713_codec_driver); diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c new file mode 100644 index 000000000000..b6b654837585 --- /dev/null +++ b/sound/soc/codecs/wm_adsp.c @@ -0,0 +1,720 @@ +/* + * wm_adsp.c -- Wolfson ADSP support + * + * Copyright 2012 Wolfson Microelectronics plc + * + * Author: Mark Brown <broonie@opensource.wolfsonmicro.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/init.h> +#include <linux/delay.h> +#include <linux/firmware.h> +#include <linux/pm.h> +#include <linux/pm_runtime.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> +#include <linux/slab.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/jack.h> +#include <sound/initval.h> +#include <sound/tlv.h> + +#include <linux/mfd/arizona/registers.h> + +#include "wm_adsp.h" + +#define adsp_crit(_dsp, fmt, ...) \ + dev_crit(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__) +#define adsp_err(_dsp, fmt, ...) \ + dev_err(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__) +#define adsp_warn(_dsp, fmt, ...) \ + dev_warn(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__) +#define adsp_info(_dsp, fmt, ...) \ + dev_info(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__) +#define adsp_dbg(_dsp, fmt, ...) \ + dev_dbg(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__) + +#define ADSP1_CONTROL_1 0x00 +#define ADSP1_CONTROL_2 0x02 +#define ADSP1_CONTROL_3 0x03 +#define ADSP1_CONTROL_4 0x04 +#define ADSP1_CONTROL_5 0x06 +#define ADSP1_CONTROL_6 0x07 +#define ADSP1_CONTROL_7 0x08 +#define ADSP1_CONTROL_8 0x09 +#define ADSP1_CONTROL_9 0x0A +#define ADSP1_CONTROL_10 0x0B +#define ADSP1_CONTROL_11 0x0C +#define ADSP1_CONTROL_12 0x0D +#define ADSP1_CONTROL_13 0x0F +#define ADSP1_CONTROL_14 0x10 +#define ADSP1_CONTROL_15 0x11 +#define ADSP1_CONTROL_16 0x12 +#define ADSP1_CONTROL_17 0x13 +#define ADSP1_CONTROL_18 0x14 +#define ADSP1_CONTROL_19 0x16 +#define ADSP1_CONTROL_20 0x17 +#define ADSP1_CONTROL_21 0x18 +#define ADSP1_CONTROL_22 0x1A +#define ADSP1_CONTROL_23 0x1B +#define ADSP1_CONTROL_24 0x1C +#define ADSP1_CONTROL_25 0x1E +#define ADSP1_CONTROL_26 0x20 +#define ADSP1_CONTROL_27 0x21 +#define ADSP1_CONTROL_28 0x22 +#define ADSP1_CONTROL_29 0x23 +#define ADSP1_CONTROL_30 0x24 +#define ADSP1_CONTROL_31 0x26 + +/* + * ADSP1 Control 19 + */ +#define ADSP1_WDMA_BUFFER_LENGTH_MASK 0x00FF /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */ +#define ADSP1_WDMA_BUFFER_LENGTH_SHIFT 0 /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */ +#define ADSP1_WDMA_BUFFER_LENGTH_WIDTH 8 /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */ + + +/* + * ADSP1 Control 30 + */ +#define ADSP1_DBG_CLK_ENA 0x0008 /* DSP1_DBG_CLK_ENA */ +#define ADSP1_DBG_CLK_ENA_MASK 0x0008 /* DSP1_DBG_CLK_ENA */ +#define ADSP1_DBG_CLK_ENA_SHIFT 3 /* DSP1_DBG_CLK_ENA */ +#define ADSP1_DBG_CLK_ENA_WIDTH 1 /* DSP1_DBG_CLK_ENA */ +#define ADSP1_SYS_ENA 0x0004 /* DSP1_SYS_ENA */ +#define ADSP1_SYS_ENA_MASK 0x0004 /* DSP1_SYS_ENA */ +#define ADSP1_SYS_ENA_SHIFT 2 /* DSP1_SYS_ENA */ +#define ADSP1_SYS_ENA_WIDTH 1 /* DSP1_SYS_ENA */ +#define ADSP1_CORE_ENA 0x0002 /* DSP1_CORE_ENA */ +#define ADSP1_CORE_ENA_MASK 0x0002 /* DSP1_CORE_ENA */ +#define ADSP1_CORE_ENA_SHIFT 1 /* DSP1_CORE_ENA */ +#define ADSP1_CORE_ENA_WIDTH 1 /* DSP1_CORE_ENA */ +#define ADSP1_START 0x0001 /* DSP1_START */ +#define ADSP1_START_MASK 0x0001 /* DSP1_START */ +#define ADSP1_START_SHIFT 0 /* DSP1_START */ +#define ADSP1_START_WIDTH 1 /* DSP1_START */ + +#define ADSP2_CONTROL 0 +#define ADSP2_CLOCKING 1 +#define ADSP2_STATUS1 4 + +/* + * ADSP2 Control + */ + +#define ADSP2_MEM_ENA 0x0010 /* DSP1_MEM_ENA */ +#define ADSP2_MEM_ENA_MASK 0x0010 /* DSP1_MEM_ENA */ +#define ADSP2_MEM_ENA_SHIFT 4 /* DSP1_MEM_ENA */ +#define ADSP2_MEM_ENA_WIDTH 1 /* DSP1_MEM_ENA */ +#define ADSP2_SYS_ENA 0x0004 /* DSP1_SYS_ENA */ +#define ADSP2_SYS_ENA_MASK 0x0004 /* DSP1_SYS_ENA */ +#define ADSP2_SYS_ENA_SHIFT 2 /* DSP1_SYS_ENA */ +#define ADSP2_SYS_ENA_WIDTH 1 /* DSP1_SYS_ENA */ +#define ADSP2_CORE_ENA 0x0002 /* DSP1_CORE_ENA */ +#define ADSP2_CORE_ENA_MASK 0x0002 /* DSP1_CORE_ENA */ +#define ADSP2_CORE_ENA_SHIFT 1 /* DSP1_CORE_ENA */ +#define ADSP2_CORE_ENA_WIDTH 1 /* DSP1_CORE_ENA */ +#define ADSP2_START 0x0001 /* DSP1_START */ +#define ADSP2_START_MASK 0x0001 /* DSP1_START */ +#define ADSP2_START_SHIFT 0 /* DSP1_START */ +#define ADSP2_START_WIDTH 1 /* DSP1_START */ + +/* + * ADSP2 clocking + */ +#define ADSP2_CLK_SEL_MASK 0x0007 /* CLK_SEL_ENA */ +#define ADSP2_CLK_SEL_SHIFT 0 /* CLK_SEL_ENA */ +#define ADSP2_CLK_SEL_WIDTH 3 /* CLK_SEL_ENA */ + +/* + * ADSP2 Status 1 + */ +#define ADSP2_RAM_RDY 0x0001 +#define ADSP2_RAM_RDY_MASK 0x0001 +#define ADSP2_RAM_RDY_SHIFT 0 +#define ADSP2_RAM_RDY_WIDTH 1 + + +static struct wm_adsp_region const *wm_adsp_find_region(struct wm_adsp *dsp, + int type) +{ + int i; + + for (i = 0; i < dsp->num_mems; i++) + if (dsp->mem[i].type == type) + return &dsp->mem[i]; + + return NULL; +} + +static int wm_adsp_load(struct wm_adsp *dsp) +{ + const struct firmware *firmware; + struct regmap *regmap = dsp->regmap; + unsigned int pos = 0; + const struct wmfw_header *header; + const struct wmfw_adsp1_sizes *adsp1_sizes; + const struct wmfw_adsp2_sizes *adsp2_sizes; + const struct wmfw_footer *footer; + const struct wmfw_region *region; + const struct wm_adsp_region *mem; + const char *region_name; + char *file, *text; + void *buf; + unsigned int reg; + int regions = 0; + int ret, offset, type, sizes; + + file = kzalloc(PAGE_SIZE, GFP_KERNEL); + if (file == NULL) + return -ENOMEM; + + snprintf(file, PAGE_SIZE, "%s-dsp%d.wmfw", dsp->part, dsp->num); + file[PAGE_SIZE - 1] = '\0'; + + ret = request_firmware(&firmware, file, dsp->dev); + if (ret != 0) { + adsp_err(dsp, "Failed to request '%s'\n", file); + goto out; + } + ret = -EINVAL; + + pos = sizeof(*header) + sizeof(*adsp1_sizes) + sizeof(*footer); + if (pos >= firmware->size) { + adsp_err(dsp, "%s: file too short, %zu bytes\n", + file, firmware->size); + goto out_fw; + } + + header = (void*)&firmware->data[0]; + + if (memcmp(&header->magic[0], "WMFW", 4) != 0) { + adsp_err(dsp, "%s: invalid magic\n", file); + goto out_fw; + } + + if (header->ver != 0) { + adsp_err(dsp, "%s: unknown file format %d\n", + file, header->ver); + goto out_fw; + } + + if (header->core != dsp->type) { + adsp_err(dsp, "%s: invalid core %d != %d\n", + file, header->core, dsp->type); + goto out_fw; + } + + switch (dsp->type) { + case WMFW_ADSP1: + pos = sizeof(*header) + sizeof(*adsp1_sizes) + sizeof(*footer); + adsp1_sizes = (void *)&(header[1]); + footer = (void *)&(adsp1_sizes[1]); + sizes = sizeof(*adsp1_sizes); + + adsp_dbg(dsp, "%s: %d DM, %d PM, %d ZM\n", + file, le32_to_cpu(adsp1_sizes->dm), + le32_to_cpu(adsp1_sizes->pm), + le32_to_cpu(adsp1_sizes->zm)); + break; + + case WMFW_ADSP2: + pos = sizeof(*header) + sizeof(*adsp2_sizes) + sizeof(*footer); + adsp2_sizes = (void *)&(header[1]); + footer = (void *)&(adsp2_sizes[1]); + sizes = sizeof(*adsp2_sizes); + + adsp_dbg(dsp, "%s: %d XM, %d YM %d PM, %d ZM\n", + file, le32_to_cpu(adsp2_sizes->xm), + le32_to_cpu(adsp2_sizes->ym), + le32_to_cpu(adsp2_sizes->pm), + le32_to_cpu(adsp2_sizes->zm)); + break; + + default: + BUG_ON(NULL == "Unknown DSP type"); + goto out_fw; + } + + if (le32_to_cpu(header->len) != sizeof(*header) + + sizes + sizeof(*footer)) { + adsp_err(dsp, "%s: unexpected header length %d\n", + file, le32_to_cpu(header->len)); + goto out_fw; + } + + adsp_dbg(dsp, "%s: timestamp %llu\n", file, + le64_to_cpu(footer->timestamp)); + + while (pos < firmware->size && + pos - firmware->size > sizeof(*region)) { + region = (void *)&(firmware->data[pos]); + region_name = "Unknown"; + reg = 0; + text = NULL; + offset = le32_to_cpu(region->offset) & 0xffffff; + type = be32_to_cpu(region->type) & 0xff; + mem = wm_adsp_find_region(dsp, type); + + switch (type) { + case WMFW_NAME_TEXT: + region_name = "Firmware name"; + text = kzalloc(le32_to_cpu(region->len) + 1, + GFP_KERNEL); + break; + case WMFW_INFO_TEXT: + region_name = "Information"; + text = kzalloc(le32_to_cpu(region->len) + 1, + GFP_KERNEL); + break; + case WMFW_ABSOLUTE: + region_name = "Absolute"; + reg = offset; + break; + case WMFW_ADSP1_PM: + BUG_ON(!mem); + region_name = "PM"; + reg = mem->base + (offset * 3); + break; + case WMFW_ADSP1_DM: + BUG_ON(!mem); + region_name = "DM"; + reg = mem->base + (offset * 2); + break; + case WMFW_ADSP2_XM: + BUG_ON(!mem); + region_name = "XM"; + reg = mem->base + (offset * 2); + break; + case WMFW_ADSP2_YM: + BUG_ON(!mem); + region_name = "YM"; + reg = mem->base + (offset * 2); + break; + case WMFW_ADSP1_ZM: + BUG_ON(!mem); + region_name = "ZM"; + reg = mem->base + (offset * 2); + break; + default: + adsp_warn(dsp, + "%s.%d: Unknown region type %x at %d(%x)\n", + file, regions, type, pos, pos); + break; + } + + adsp_dbg(dsp, "%s.%d: %d bytes at %d in %s\n", file, + regions, le32_to_cpu(region->len), offset, + region_name); + + if (text) { + memcpy(text, region->data, le32_to_cpu(region->len)); + adsp_info(dsp, "%s: %s\n", file, text); + kfree(text); + } + + if (reg) { + buf = kmemdup(region->data, le32_to_cpu(region->len), + GFP_KERNEL | GFP_DMA); + if (!buf) { + adsp_err(dsp, "Out of memory\n"); + return -ENOMEM; + } + + ret = regmap_raw_write(regmap, reg, buf, + le32_to_cpu(region->len)); + + kfree(buf); + + if (ret != 0) { + adsp_err(dsp, + "%s.%d: Failed to write %d bytes at %d in %s: %d\n", + file, regions, + le32_to_cpu(region->len), offset, + region_name, ret); + goto out_fw; + } + } + + pos += le32_to_cpu(region->len) + sizeof(*region); + regions++; + } + + if (pos > firmware->size) + adsp_warn(dsp, "%s.%d: %zu bytes at end of file\n", + file, regions, pos - firmware->size); + +out_fw: + release_firmware(firmware); +out: + kfree(file); + + return ret; +} + +static int wm_adsp_load_coeff(struct wm_adsp *dsp) +{ + struct regmap *regmap = dsp->regmap; + struct wmfw_coeff_hdr *hdr; + struct wmfw_coeff_item *blk; + const struct firmware *firmware; + const char *region_name; + int ret, pos, blocks, type, offset, reg; + char *file; + void *buf; + + file = kzalloc(PAGE_SIZE, GFP_KERNEL); + if (file == NULL) + return -ENOMEM; + + snprintf(file, PAGE_SIZE, "%s-dsp%d.bin", dsp->part, dsp->num); + file[PAGE_SIZE - 1] = '\0'; + + ret = request_firmware(&firmware, file, dsp->dev); + if (ret != 0) { + adsp_warn(dsp, "Failed to request '%s'\n", file); + ret = 0; + goto out; + } + ret = -EINVAL; + + if (sizeof(*hdr) >= firmware->size) { + adsp_err(dsp, "%s: file too short, %zu bytes\n", + file, firmware->size); + goto out_fw; + } + + hdr = (void*)&firmware->data[0]; + if (memcmp(hdr->magic, "WMDR", 4) != 0) { + adsp_err(dsp, "%s: invalid magic\n", file); + goto out_fw; + } + + adsp_dbg(dsp, "%s: v%d.%d.%d\n", file, + (le32_to_cpu(hdr->ver) >> 16) & 0xff, + (le32_to_cpu(hdr->ver) >> 8) & 0xff, + le32_to_cpu(hdr->ver) & 0xff); + + pos = le32_to_cpu(hdr->len); + + blocks = 0; + while (pos < firmware->size && + pos - firmware->size > sizeof(*blk)) { + blk = (void*)(&firmware->data[pos]); + + type = be32_to_cpu(blk->type) & 0xff; + offset = le32_to_cpu(blk->offset) & 0xffffff; + + adsp_dbg(dsp, "%s.%d: %x v%d.%d.%d\n", + file, blocks, le32_to_cpu(blk->id), + (le32_to_cpu(blk->ver) >> 16) & 0xff, + (le32_to_cpu(blk->ver) >> 8) & 0xff, + le32_to_cpu(blk->ver) & 0xff); + adsp_dbg(dsp, "%s.%d: %d bytes at 0x%x in %x\n", + file, blocks, le32_to_cpu(blk->len), offset, type); + + reg = 0; + region_name = "Unknown"; + switch (type) { + case WMFW_NAME_TEXT: + case WMFW_INFO_TEXT: + break; + case WMFW_ABSOLUTE: + region_name = "register"; + reg = offset; + break; + default: + adsp_err(dsp, "Unknown region type %x\n", type); + break; + } + + if (reg) { + buf = kmemdup(blk->data, le32_to_cpu(blk->len), + GFP_KERNEL | GFP_DMA); + if (!buf) { + adsp_err(dsp, "Out of memory\n"); + return -ENOMEM; + } + + ret = regmap_raw_write(regmap, reg, blk->data, + le32_to_cpu(blk->len)); + if (ret != 0) { + adsp_err(dsp, + "%s.%d: Failed to write to %x in %s\n", + file, blocks, reg, region_name); + } + + kfree(buf); + } + + pos += le32_to_cpu(blk->len) + sizeof(*blk); + blocks++; + } + + if (pos > firmware->size) + adsp_warn(dsp, "%s.%d: %zu bytes at end of file\n", + file, blocks, pos - firmware->size); + +out_fw: + release_firmware(firmware); +out: + kfree(file); + return 0; +} + +int wm_adsp1_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_codec *codec = w->codec; + struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec); + struct wm_adsp *dsp = &dsps[w->shift]; + int ret; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, + ADSP1_SYS_ENA, ADSP1_SYS_ENA); + + ret = wm_adsp_load(dsp); + if (ret != 0) + goto err; + + ret = wm_adsp_load_coeff(dsp); + if (ret != 0) + goto err; + + /* Start the core running */ + regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, + ADSP1_CORE_ENA | ADSP1_START, + ADSP1_CORE_ENA | ADSP1_START); + break; + + case SND_SOC_DAPM_PRE_PMD: + /* Halt the core */ + regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, + ADSP1_CORE_ENA | ADSP1_START, 0); + + regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_19, + ADSP1_WDMA_BUFFER_LENGTH_MASK, 0); + + regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, + ADSP1_SYS_ENA, 0); + break; + + default: + break; + } + + return 0; + +err: + regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, + ADSP1_SYS_ENA, 0); + return ret; +} +EXPORT_SYMBOL_GPL(wm_adsp1_event); + +static int wm_adsp2_ena(struct wm_adsp *dsp) +{ + unsigned int val; + int ret, count; + + ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, + ADSP2_SYS_ENA, ADSP2_SYS_ENA); + if (ret != 0) + return ret; + + /* Wait for the RAM to start, should be near instantaneous */ + count = 0; + do { + ret = regmap_read(dsp->regmap, dsp->base + ADSP2_STATUS1, + &val); + if (ret != 0) + return ret; + } while (!(val & ADSP2_RAM_RDY) && ++count < 10); + + if (!(val & ADSP2_RAM_RDY)) { + adsp_err(dsp, "Failed to start DSP RAM\n"); + return -EBUSY; + } + + adsp_dbg(dsp, "RAM ready after %d polls\n", count); + adsp_info(dsp, "RAM ready after %d polls\n", count); + + return 0; +} + +int wm_adsp2_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->codec; + struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec); + struct wm_adsp *dsp = &dsps[w->shift]; + unsigned int val; + int ret; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + /* + * For simplicity set the DSP clock rate to be the + * SYSCLK rate rather than making it configurable. + */ + ret = regmap_read(dsp->regmap, ARIZONA_SYSTEM_CLOCK_1, &val); + if (ret != 0) { + adsp_err(dsp, "Failed to read SYSCLK state: %d\n", + ret); + return ret; + } + val = (val & ARIZONA_SYSCLK_FREQ_MASK) + >> ARIZONA_SYSCLK_FREQ_SHIFT; + + ret = regmap_update_bits(dsp->regmap, + dsp->base + ADSP2_CLOCKING, + ADSP2_CLK_SEL_MASK, val); + if (ret != 0) { + adsp_err(dsp, "Failed to set clock rate: %d\n", + ret); + return ret; + } + + if (dsp->dvfs) { + ret = regmap_read(dsp->regmap, + dsp->base + ADSP2_CLOCKING, &val); + if (ret != 0) { + dev_err(dsp->dev, + "Failed to read clocking: %d\n", ret); + return ret; + } + + if ((val & ADSP2_CLK_SEL_MASK) >= 3) { + ret = regulator_enable(dsp->dvfs); + if (ret != 0) { + dev_err(dsp->dev, + "Failed to enable supply: %d\n", + ret); + return ret; + } + + ret = regulator_set_voltage(dsp->dvfs, + 1800000, + 1800000); + if (ret != 0) { + dev_err(dsp->dev, + "Failed to raise supply: %d\n", + ret); + return ret; + } + } + } + + ret = wm_adsp2_ena(dsp); + if (ret != 0) + return ret; + + ret = wm_adsp_load(dsp); + if (ret != 0) + goto err; + + ret = wm_adsp_load_coeff(dsp); + if (ret != 0) + goto err; + + ret = regmap_update_bits(dsp->regmap, + dsp->base + ADSP2_CONTROL, + ADSP2_CORE_ENA | ADSP2_START, + ADSP2_CORE_ENA | ADSP2_START); + if (ret != 0) + goto err; + break; + + case SND_SOC_DAPM_PRE_PMD: + regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, + ADSP2_SYS_ENA | ADSP2_CORE_ENA | + ADSP2_START, 0); + + if (dsp->dvfs) { + ret = regulator_set_voltage(dsp->dvfs, 1200000, + 1800000); + if (ret != 0) + dev_warn(dsp->dev, + "Failed to lower supply: %d\n", + ret); + + ret = regulator_disable(dsp->dvfs); + if (ret != 0) + dev_err(dsp->dev, + "Failed to enable supply: %d\n", + ret); + } + break; + + default: + break; + } + + return 0; +err: + regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, + ADSP2_SYS_ENA | ADSP2_CORE_ENA | ADSP2_START, 0); + return ret; +} +EXPORT_SYMBOL_GPL(wm_adsp2_event); + +int wm_adsp2_init(struct wm_adsp *adsp, bool dvfs) +{ + int ret; + + /* + * Disable the DSP memory by default when in reset for a small + * power saving. + */ + ret = regmap_update_bits(adsp->regmap, adsp->base + ADSP2_CONTROL, + ADSP2_MEM_ENA, 0); + if (ret != 0) { + adsp_err(adsp, "Failed to clear memory retention: %d\n", ret); + return ret; + } + + if (dvfs) { + adsp->dvfs = devm_regulator_get(adsp->dev, "DCVDD"); + if (IS_ERR(adsp->dvfs)) { + ret = PTR_ERR(adsp->dvfs); + dev_err(adsp->dev, "Failed to get DCVDD: %d\n", ret); + return ret; + } + + ret = regulator_enable(adsp->dvfs); + if (ret != 0) { + dev_err(adsp->dev, "Failed to enable DCVDD: %d\n", + ret); + return ret; + } + + ret = regulator_set_voltage(adsp->dvfs, 1200000, 1800000); + if (ret != 0) { + dev_err(adsp->dev, "Failed to initialise DVFS: %d\n", + ret); + return ret; + } + + ret = regulator_disable(adsp->dvfs); + if (ret != 0) { + dev_err(adsp->dev, "Failed to disable DCVDD: %d\n", + ret); + return ret; + } + } + + return 0; +} +EXPORT_SYMBOL_GPL(wm_adsp2_init); diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h new file mode 100644 index 000000000000..ffd29a4609e2 --- /dev/null +++ b/sound/soc/codecs/wm_adsp.h @@ -0,0 +1,59 @@ +/* + * wm_adsp.h -- Wolfson ADSP support + * + * Copyright 2012 Wolfson Microelectronics plc + * + * Author: Mark Brown <broonie@opensource.wolfsonmicro.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 __WM_ADSP_H +#define __WM_ADSP_H + +#include <sound/soc.h> +#include <sound/soc-dapm.h> + +#include "wmfw.h" + +struct regulator; + +struct wm_adsp_region { + int type; + unsigned int base; +}; + +struct wm_adsp { + const char *part; + int num; + int type; + struct device *dev; + struct regmap *regmap; + + int base; + + const struct wm_adsp_region *mem; + int num_mems; + + struct regulator *dvfs; +}; + +#define WM_ADSP1(wname, num) \ + { .id = snd_soc_dapm_pga, .name = wname, .reg = SND_SOC_NOPM, \ + .shift = num, .event = wm_adsp1_event, \ + .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD } + +#define WM_ADSP2(wname, num) \ +{ .id = snd_soc_dapm_pga, .name = wname, .reg = SND_SOC_NOPM, \ + .shift = num, .event = wm_adsp2_event, \ + .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD } + +int wm_adsp2_init(struct wm_adsp *adsp, bool dvfs); +int wm_adsp1_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event); +int wm_adsp2_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event); + +#endif diff --git a/sound/soc/codecs/wmfw.h b/sound/soc/codecs/wmfw.h new file mode 100644 index 000000000000..5632ded67fdd --- /dev/null +++ b/sound/soc/codecs/wmfw.h @@ -0,0 +1,128 @@ +/* + * wmfw.h - Wolfson firmware format information + * + * Copyright 2012 Wolfson Microelectronics plc + * + * Author: Mark Brown <broonie@opensource.wolfsonmicro.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 __WMFW_H +#define __WMFW_H + +#include <linux/types.h> + +struct wmfw_header { + char magic[4]; + __le32 len; + __le16 rev; + u8 core; + u8 ver; +} __packed; + +struct wmfw_footer { + __le64 timestamp; + __le32 checksum; +} __packed; + +struct wmfw_adsp1_sizes { + __le32 dm; + __le32 pm; + __le32 zm; +} __packed; + +struct wmfw_adsp2_sizes { + __le32 xm; + __le32 ym; + __le32 pm; + __le32 zm; +} __packed; + +struct wmfw_region { + union { + __be32 type; + __le32 offset; + }; + __le32 len; + u8 data[]; +} __packed; + +struct wmfw_id_hdr { + __be32 core_id; + __be32 core_rev; + __be32 id; + __be32 ver; +} __packed; + +struct wmfw_adsp1_id_hdr { + struct wmfw_id_hdr fw; + __be32 zm; + __be32 dm; + __be32 algs; +} __packed; + +struct wmfw_adsp2_id_hdr { + struct wmfw_id_hdr fw; + __be32 zm; + __be32 xm; + __be32 ym; + __be32 algs; +} __packed; + +struct wmfw_alg_hdr { + __be32 id; + __be32 ver; +} __packed; + +struct wmfw_adsp1_alg_hdr { + struct wmfw_alg_hdr alg; + __be32 zm; + __be32 dm; +} __packed; + +struct wmfw_adsp2_alg_hdr { + struct wmfw_alg_hdr alg; + __be32 zm; + __be32 xm; + __be32 ym; +} __packed; + +struct wmfw_coeff_hdr { + u8 magic[4]; + __le32 len; + __le32 ver; + u8 data[]; +} __packed; + +struct wmfw_coeff_item { + union { + __be32 type; + __le32 offset; + }; + __le32 id; + __le32 ver; + __le32 sr; + __le32 len; + u8 data[]; +} __packed; + +#define WMFW_ADSP1 1 +#define WMFW_ADSP2 2 + +#define WMFW_ABSOLUTE 0xf0 +#define WMFW_NAME_TEXT 0xfe +#define WMFW_INFO_TEXT 0xff + +#define WMFW_ADSP1_PM 2 +#define WMFW_ADSP1_DM 3 +#define WMFW_ADSP1_ZM 4 + +#define WMFW_ADSP2_PM 2 +#define WMFW_ADSP2_ZM 4 +#define WMFW_ADSP2_XM 5 +#define WMFW_ADSP2_YM 6 + +#endif diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c index 6fac5af13298..d55e6477bff0 100644 --- a/sound/soc/davinci/davinci-evm.c +++ b/sound/soc/davinci/davinci-evm.c @@ -71,6 +71,11 @@ static int evm_hw_params(struct snd_pcm_substream *substream, if (ret < 0) return ret; + /* set the CPU system clock */ + ret = snd_soc_dai_set_sysclk(cpu_dai, 0, sysclk, SND_SOC_CLOCK_OUT); + if (ret < 0) + return ret; + return 0; } diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index 714e51e5be5b..55e2bf652bef 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -199,6 +199,7 @@ #define ACLKXE BIT(5) #define TX_ASYNC BIT(6) #define ACLKXPOL BIT(7) +#define ACLKXDIV_MASK 0x1f /* * DAVINCI_MCASP_ACLKRCTL_REG Receive Clock Control Register Bits @@ -207,6 +208,7 @@ #define ACLKRE BIT(5) #define RX_ASYNC BIT(6) #define ACLKRPOL BIT(7) +#define ACLKRDIV_MASK 0x1f /* * DAVINCI_MCASP_AHCLKXCTL_REG - High Frequency Transmit Clock Control @@ -215,6 +217,7 @@ #define AHCLKXDIV(val) (val) #define AHCLKXPOL BIT(14) #define AHCLKXE BIT(15) +#define AHCLKXDIV_MASK 0xfff /* * DAVINCI_MCASP_AHCLKRCTL_REG - High Frequency Receive Clock Control @@ -223,6 +226,7 @@ #define AHCLKRDIV(val) (val) #define AHCLKRPOL BIT(14) #define AHCLKRE BIT(15) +#define AHCLKRDIV_MASK 0xfff /* * DAVINCI_MCASP_XRSRCTL_BASE_REG - Serializer Control Register Bits @@ -473,6 +477,23 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, struct davinci_audio_dev *dev = snd_soc_dai_get_drvdata(cpu_dai); void __iomem *base = dev->base; + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_DSP_B: + case SND_SOC_DAIFMT_AC97: + mcasp_clr_bits(dev->base + DAVINCI_MCASP_TXFMCTL_REG, FSXDUR); + mcasp_clr_bits(dev->base + DAVINCI_MCASP_RXFMCTL_REG, FSRDUR); + break; + default: + /* configure a full-word SYNC pulse (LRCLK) */ + mcasp_set_bits(dev->base + DAVINCI_MCASP_TXFMCTL_REG, FSXDUR); + mcasp_set_bits(dev->base + DAVINCI_MCASP_RXFMCTL_REG, FSRDUR); + + /* make 1st data bit occur one ACLK cycle after the frame sync */ + mcasp_set_bits(dev->base + DAVINCI_MCASP_TXFMT_REG, FSXDLY(1)); + mcasp_set_bits(dev->base + DAVINCI_MCASP_RXFMT_REG, FSRDLY(1)); + break; + } + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBS_CFS: /* codec is clock and frame slave */ @@ -482,8 +503,7 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, mcasp_set_bits(base + DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE); mcasp_set_bits(base + DAVINCI_MCASP_RXFMCTL_REG, AFSRE); - mcasp_set_bits(base + DAVINCI_MCASP_PDIR_REG, - ACLKX | AHCLKX | AFSX); + mcasp_set_bits(base + DAVINCI_MCASP_PDIR_REG, ACLKX | AFSX); break; case SND_SOC_DAIFMT_CBM_CFS: /* codec is clock master and frame slave */ @@ -554,59 +574,75 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, return 0; } -static int davinci_config_channel_size(struct davinci_audio_dev *dev, - int channel_size) +static int davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div) { - u32 fmt = 0; - u32 mask, rotate; - - switch (channel_size) { - case DAVINCI_AUDIO_WORD_8: - fmt = 0x03; - rotate = 6; - mask = 0x000000ff; - break; + struct davinci_audio_dev *dev = snd_soc_dai_get_drvdata(dai); - case DAVINCI_AUDIO_WORD_12: - fmt = 0x05; - rotate = 5; - mask = 0x00000fff; + switch (div_id) { + case 0: /* MCLK divider */ + mcasp_mod_bits(dev->base + DAVINCI_MCASP_AHCLKXCTL_REG, + AHCLKXDIV(div - 1), AHCLKXDIV_MASK); + mcasp_mod_bits(dev->base + DAVINCI_MCASP_AHCLKRCTL_REG, + AHCLKRDIV(div - 1), AHCLKRDIV_MASK); break; - case DAVINCI_AUDIO_WORD_16: - fmt = 0x07; - rotate = 4; - mask = 0x0000ffff; + case 1: /* BCLK divider */ + mcasp_mod_bits(dev->base + DAVINCI_MCASP_ACLKXCTL_REG, + ACLKXDIV(div - 1), ACLKXDIV_MASK); + mcasp_mod_bits(dev->base + DAVINCI_MCASP_ACLKRCTL_REG, + ACLKRDIV(div - 1), ACLKRDIV_MASK); break; - case DAVINCI_AUDIO_WORD_20: - fmt = 0x09; - rotate = 3; - mask = 0x000fffff; + case 2: /* BCLK/LRCLK ratio */ + dev->bclk_lrclk_ratio = div; break; - case DAVINCI_AUDIO_WORD_24: - fmt = 0x0B; - rotate = 2; - mask = 0x00ffffff; - break; + default: + return -EINVAL; + } - case DAVINCI_AUDIO_WORD_28: - fmt = 0x0D; - rotate = 1; - mask = 0x0fffffff; - break; + return 0; +} - case DAVINCI_AUDIO_WORD_32: - fmt = 0x0F; - rotate = 0; - mask = 0xffffffff; - break; +static int davinci_mcasp_set_sysclk(struct snd_soc_dai *dai, int clk_id, + unsigned int freq, int dir) +{ + struct davinci_audio_dev *dev = snd_soc_dai_get_drvdata(dai); - default: - return -EINVAL; + if (dir == SND_SOC_CLOCK_OUT) { + mcasp_set_bits(dev->base + DAVINCI_MCASP_AHCLKXCTL_REG, AHCLKXE); + mcasp_set_bits(dev->base + DAVINCI_MCASP_AHCLKRCTL_REG, AHCLKRE); + mcasp_set_bits(dev->base + DAVINCI_MCASP_PDIR_REG, AHCLKX); + } else { + mcasp_clr_bits(dev->base + DAVINCI_MCASP_AHCLKXCTL_REG, AHCLKXE); + mcasp_clr_bits(dev->base + DAVINCI_MCASP_AHCLKRCTL_REG, AHCLKRE); + mcasp_clr_bits(dev->base + DAVINCI_MCASP_PDIR_REG, AHCLKX); } + return 0; +} + +static int davinci_config_channel_size(struct davinci_audio_dev *dev, + int word_length) +{ + u32 fmt; + u32 rotate = (32 - word_length) / 4; + u32 mask = (1ULL << word_length) - 1; + + /* + * if s BCLK-to-LRCLK ratio has been configured via the set_clkdiv() + * callback, take it into account here. That allows us to for example + * send 32 bits per channel to the codec, while only 16 of them carry + * audio payload. + * The clock ratio is given for a full period of data (both left and + * right channels), so it has to be divided by 2. + */ + if (dev->bclk_lrclk_ratio) + word_length = dev->bclk_lrclk_ratio / 2; + + /* mapping of the XSSZ bit-field as described in the datasheet */ + fmt = (word_length >> 1) - 1; + mcasp_mod_bits(dev->base + DAVINCI_MCASP_RXFMT_REG, RXSSZ(fmt), RXSSZ(0x0F)); mcasp_mod_bits(dev->base + DAVINCI_MCASP_TXFMT_REG, @@ -709,8 +745,6 @@ static void davinci_hw_param(struct davinci_audio_dev *dev, int stream) if (stream == SNDRV_PCM_STREAM_PLAYBACK) { /* bit stream is MSB first with no delay */ /* DSP_B mode */ - mcasp_set_bits(dev->base + DAVINCI_MCASP_AHCLKXCTL_REG, - AHCLKXE); mcasp_set_reg(dev->base + DAVINCI_MCASP_TXTDM_REG, mask); mcasp_set_bits(dev->base + DAVINCI_MCASP_TXFMT_REG, TXORD); @@ -720,14 +754,10 @@ static void davinci_hw_param(struct davinci_audio_dev *dev, int stream) else printk(KERN_ERR "playback tdm slot %d not supported\n", dev->tdm_slots); - - mcasp_clr_bits(dev->base + DAVINCI_MCASP_TXFMCTL_REG, FSXDUR); } else { /* bit stream is MSB first with no delay */ /* DSP_B mode */ mcasp_set_bits(dev->base + DAVINCI_MCASP_RXFMT_REG, RXORD); - mcasp_set_bits(dev->base + DAVINCI_MCASP_AHCLKRCTL_REG, - AHCLKRE); mcasp_set_reg(dev->base + DAVINCI_MCASP_RXTDM_REG, mask); if ((dev->tdm_slots >= 2) && (dev->tdm_slots <= 32)) @@ -736,8 +766,6 @@ static void davinci_hw_param(struct davinci_audio_dev *dev, int stream) else printk(KERN_ERR "capture tdm slot %d not supported\n", dev->tdm_slots); - - mcasp_clr_bits(dev->base + DAVINCI_MCASP_RXFMCTL_REG, FSRDUR); } } @@ -800,19 +828,27 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, case SNDRV_PCM_FORMAT_U8: case SNDRV_PCM_FORMAT_S8: dma_params->data_type = 1; - word_length = DAVINCI_AUDIO_WORD_8; + word_length = 8; break; case SNDRV_PCM_FORMAT_U16_LE: case SNDRV_PCM_FORMAT_S16_LE: dma_params->data_type = 2; - word_length = DAVINCI_AUDIO_WORD_16; + word_length = 16; + break; + + case SNDRV_PCM_FORMAT_U24_3LE: + case SNDRV_PCM_FORMAT_S24_3LE: + dma_params->data_type = 3; + word_length = 24; break; + case SNDRV_PCM_FORMAT_U24_LE: + case SNDRV_PCM_FORMAT_S24_LE: case SNDRV_PCM_FORMAT_U32_LE: case SNDRV_PCM_FORMAT_S32_LE: dma_params->data_type = 4; - word_length = DAVINCI_AUDIO_WORD_32; + word_length = 32; break; default: @@ -880,13 +916,18 @@ static const struct snd_soc_dai_ops davinci_mcasp_dai_ops = { .trigger = davinci_mcasp_trigger, .hw_params = davinci_mcasp_hw_params, .set_fmt = davinci_mcasp_set_dai_fmt, - + .set_clkdiv = davinci_mcasp_set_clkdiv, + .set_sysclk = davinci_mcasp_set_sysclk, }; #define DAVINCI_MCASP_PCM_FMTS (SNDRV_PCM_FMTBIT_S8 | \ SNDRV_PCM_FMTBIT_U8 | \ SNDRV_PCM_FMTBIT_S16_LE | \ SNDRV_PCM_FMTBIT_U16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_U24_LE | \ + SNDRV_PCM_FMTBIT_S24_3LE | \ + SNDRV_PCM_FMTBIT_U24_3LE | \ SNDRV_PCM_FMTBIT_S32_LE | \ SNDRV_PCM_FMTBIT_U32_LE) @@ -1089,7 +1130,6 @@ static int davinci_mcasp_probe(struct platform_device *pdev) dev->tdm_slots = pdata->tdm_slots; dev->num_serializer = pdata->num_serializer; dev->serial_dir = pdata->serial_dir; - dev->codec_fmt = pdata->codec_fmt; dev->version = pdata->version; dev->txnumevt = pdata->txnumevt; dev->rxnumevt = pdata->rxnumevt; @@ -1098,6 +1138,7 @@ static int davinci_mcasp_probe(struct platform_device *pdev) dma_data = &dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK]; dma_data->asp_chan_q = pdata->asp_chan_q; dma_data->ram_chan_q = pdata->ram_chan_q; + dma_data->sram_pool = pdata->sram_pool; dma_data->sram_size = pdata->sram_size_playback; dma_data->dma_addr = (dma_addr_t) (pdata->tx_dma_offset + mem->start); @@ -1115,6 +1156,7 @@ static int davinci_mcasp_probe(struct platform_device *pdev) dma_data = &dev->dma_params[SNDRV_PCM_STREAM_CAPTURE]; dma_data->asp_chan_q = pdata->asp_chan_q; dma_data->ram_chan_q = pdata->ram_chan_q; + dma_data->sram_pool = pdata->sram_pool; dma_data->sram_size = pdata->sram_size_capture; dma_data->dma_addr = (dma_addr_t)(pdata->rx_dma_offset + mem->start); diff --git a/sound/soc/davinci/davinci-mcasp.h b/sound/soc/davinci/davinci-mcasp.h index 0de9ed6ce038..0edd3b5a37fd 100644 --- a/sound/soc/davinci/davinci-mcasp.h +++ b/sound/soc/davinci/davinci-mcasp.h @@ -23,26 +23,14 @@ #include "davinci-pcm.h" -#define DAVINCI_MCASP_RATES SNDRV_PCM_RATE_8000_96000 +#define DAVINCI_MCASP_RATES SNDRV_PCM_RATE_8000_192000 #define DAVINCI_MCASP_I2S_DAI 0 #define DAVINCI_MCASP_DIT_DAI 1 -enum { - DAVINCI_AUDIO_WORD_8 = 0, - DAVINCI_AUDIO_WORD_12, - DAVINCI_AUDIO_WORD_16, - DAVINCI_AUDIO_WORD_20, - DAVINCI_AUDIO_WORD_24, - DAVINCI_AUDIO_WORD_32, - DAVINCI_AUDIO_WORD_28, /* This is only valid for McASP */ -}; - struct davinci_audio_dev { struct davinci_pcm_dma_params dma_params[2]; void __iomem *base; - int sample_rate; struct device *dev; - unsigned int codec_fmt; /* McASP specific data */ int tdm_slots; @@ -50,6 +38,7 @@ struct davinci_audio_dev { u8 num_serializer; u8 *serial_dir; u8 version; + u8 bclk_lrclk_ratio; /* McASP FIFO related */ u8 txnumevt; diff --git a/sound/soc/davinci/davinci-pcm.c b/sound/soc/davinci/davinci-pcm.c index 93ea3bf567e1..afab81f844ae 100644 --- a/sound/soc/davinci/davinci-pcm.c +++ b/sound/soc/davinci/davinci-pcm.c @@ -16,6 +16,7 @@ #include <linux/slab.h> #include <linux/dma-mapping.h> #include <linux/kernel.h> +#include <linux/genalloc.h> #include <sound/core.h> #include <sound/pcm.h> @@ -23,7 +24,6 @@ #include <sound/soc.h> #include <asm/dma.h> -#include <mach/sram.h> #include "davinci-pcm.h" @@ -67,13 +67,9 @@ static struct snd_pcm_hardware pcm_hardware_playback = { SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME| SNDRV_PCM_INFO_BATCH), .formats = DAVINCI_PCM_FMTBITS, - .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | - SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | - SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | - SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | - SNDRV_PCM_RATE_KNOT), + .rates = SNDRV_PCM_RATE_8000_192000 | SNDRV_PCM_RATE_KNOT, .rate_min = 8000, - .rate_max = 96000, + .rate_max = 192000, .channels_min = 2, .channels_max = 384, .buffer_bytes_max = 128 * 1024, @@ -90,13 +86,9 @@ static struct snd_pcm_hardware pcm_hardware_capture = { SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_BATCH), .formats = DAVINCI_PCM_FMTBITS, - .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | - SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | - SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | - SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | - SNDRV_PCM_RATE_KNOT), + .rates = SNDRV_PCM_RATE_8000_192000 | SNDRV_PCM_RATE_KNOT, .rate_min = 8000, - .rate_max = 96000, + .rate_max = 192000, .channels_min = 2, .channels_max = 384, .buffer_bytes_max = 128 * 1024, @@ -259,7 +251,9 @@ static void davinci_pcm_dma_irq(unsigned link, u16 ch_status, void *data) } } -static int allocate_sram(struct snd_pcm_substream *substream, unsigned size, +#ifdef CONFIG_GENERIC_ALLOCATOR +static int allocate_sram(struct snd_pcm_substream *substream, + struct gen_pool *sram_pool, unsigned size, struct snd_pcm_hardware *ppcm) { struct snd_dma_buffer *buf = &substream->dma_buffer; @@ -271,9 +265,10 @@ static int allocate_sram(struct snd_pcm_substream *substream, unsigned size, return 0; ppcm->period_bytes_max = size; - iram_virt = sram_alloc(size, &iram_phys); + iram_virt = (void *)gen_pool_alloc(sram_pool, size); if (!iram_virt) goto exit1; + iram_phys = gen_pool_virt_to_phys(sram_pool, (unsigned)iram_virt); iram_dma = kzalloc(sizeof(*iram_dma), GFP_KERNEL); if (!iram_dma) goto exit2; @@ -285,11 +280,33 @@ static int allocate_sram(struct snd_pcm_substream *substream, unsigned size, return 0; exit2: if (iram_virt) - sram_free(iram_virt, size); + gen_pool_free(sram_pool, (unsigned)iram_virt, size); exit1: return -ENOMEM; } +static void davinci_free_sram(struct snd_pcm_substream *substream, + struct snd_dma_buffer *iram_dma) +{ + struct davinci_runtime_data *prtd = substream->runtime->private_data; + struct gen_pool *sram_pool = prtd->params->sram_pool; + + gen_pool_free(sram_pool, (unsigned) iram_dma->area, iram_dma->bytes); +} +#else +static int allocate_sram(struct snd_pcm_substream *substream, + struct gen_pool *sram_pool, unsigned size, + struct snd_pcm_hardware *ppcm) +{ + return 0; +} + +static void davinci_free_sram(struct snd_pcm_substream *substream, + struct snd_dma_buffer *iram_dma) +{ +} +#endif + /* * Only used with ping/pong. * This is called after runtime->dma_addr, period_bytes and data_type are valid @@ -676,7 +693,7 @@ static int davinci_pcm_open(struct snd_pcm_substream *substream) ppcm = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? &pcm_hardware_playback : &pcm_hardware_capture; - allocate_sram(substream, params->sram_size, ppcm); + allocate_sram(substream, params->sram_pool, params->sram_size, ppcm); snd_soc_set_runtime_hwparams(substream, ppcm); /* ensure that buffer size is a multiple of period size */ ret = snd_pcm_hw_constraint_integer(runtime, @@ -819,7 +836,7 @@ static void davinci_pcm_free(struct snd_pcm *pcm) buf->area = NULL; iram_dma = buf->private_data; if (iram_dma) { - sram_free(iram_dma->area, iram_dma->bytes); + davinci_free_sram(substream, iram_dma); kfree(iram_dma); } } diff --git a/sound/soc/davinci/davinci-pcm.h b/sound/soc/davinci/davinci-pcm.h index fc4d01cdd8c9..b6ef7039dd09 100644 --- a/sound/soc/davinci/davinci-pcm.h +++ b/sound/soc/davinci/davinci-pcm.h @@ -12,6 +12,7 @@ #ifndef _DAVINCI_PCM_H #define _DAVINCI_PCM_H +#include <linux/genalloc.h> #include <linux/platform_data/davinci_asp.h> #include <mach/edma.h> @@ -20,6 +21,7 @@ struct davinci_pcm_dma_params { unsigned short acnt; dma_addr_t dma_addr; /* device physical address for DMA */ unsigned sram_size; + struct gen_pool *sram_pool; /* SRAM gen_pool for ping pong */ enum dma_event_q asp_chan_q; /* event queue number for ASP channel */ enum dma_event_q ram_chan_q; /* event queue number for RAM channel */ unsigned char data_type; /* xfer data type */ diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index 4563b28bd625..a210c8d7b4bc 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -46,6 +46,20 @@ config SND_SOC_P1022_DS This will also include the Wolfson Microelectronics WM8776 codec driver. +config SND_SOC_P1022_RDK + tristate "ALSA SoC support for the Freescale / iVeia P1022 RDK board" + # I2C is necessary for the WM8960 driver + depends on P1022_RDK && I2C + select SND_SOC_FSL_SSI + select SND_SOC_FSL_UTILS + select SND_SOC_POWERPC_DMA + select SND_SOC_WM8960 + default y if P1022_RDK + help + Say Y if you want to enable audio on the Freescale / iVeia + P1022 RDK board. This will also include the Wolfson + Microelectronics WM8960 codec driver. + config SND_SOC_MPC5200_I2S tristate "Freescale MPC5200 PSC in I2S mode driver" depends on PPC_MPC52xx && PPC_BESTCOMM @@ -94,25 +108,20 @@ if SND_IMX_SOC config SND_SOC_IMX_SSI tristate -config SND_SOC_IMX_PCM - tristate - config SND_SOC_IMX_PCM_FIQ tristate select FIQ - select SND_SOC_IMX_PCM config SND_SOC_IMX_PCM_DMA tristate select SND_SOC_DMAENGINE_PCM - select SND_SOC_IMX_PCM config SND_SOC_IMX_AUDMUX tristate config SND_MXC_SOC_WM1133_EV1 tristate "Audio on the i.MX31ADS with WM1133-EV1 fitted" - depends on MACH_MX31ADS_WM1133_EV1 && EXPERIMENTAL + depends on MACH_MX31ADS_WM1133_EV1 select SND_SOC_WM8350 select SND_SOC_IMX_PCM_FIQ select SND_SOC_IMX_AUDMUX diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile index 5f3cf3f52ea0..ec1457915d7c 100644 --- a/sound/soc/fsl/Makefile +++ b/sound/soc/fsl/Makefile @@ -6,6 +6,10 @@ obj-$(CONFIG_SND_SOC_MPC8610_HPCD) += snd-soc-mpc8610-hpcd.o snd-soc-p1022-ds-objs := p1022_ds.o obj-$(CONFIG_SND_SOC_P1022_DS) += snd-soc-p1022-ds.o +# P1022 RDK Machine Support +snd-soc-p1022-rdk-objs := p1022_rdk.o +obj-$(CONFIG_SND_SOC_P1022_RDK) += snd-soc-p1022-rdk.o + # Freescale PowerPC SSI/DMA Platform Support snd-soc-fsl-ssi-objs := fsl_ssi.o snd-soc-fsl-utils-objs := fsl_utils.o @@ -26,14 +30,21 @@ obj-$(CONFIG_SND_MPC52xx_SOC_EFIKA) += efika-audio-fabric.o # i.MX Platform Support snd-soc-imx-ssi-objs := imx-ssi.o snd-soc-imx-audmux-objs := imx-audmux.o +snd-soc-imx-pcm-objs := imx-pcm.o +ifneq ($(CONFIG_SND_SOC_IMX_PCM_FIQ),) + snd-soc-imx-pcm-objs += imx-pcm-fiq.o +endif +ifneq ($(CONFIG_SND_SOC_IMX_PCM_DMA),) + snd-soc-imx-pcm-objs += imx-pcm-dma.o +endif obj-$(CONFIG_SND_SOC_IMX_SSI) += snd-soc-imx-ssi.o obj-$(CONFIG_SND_SOC_IMX_AUDMUX) += snd-soc-imx-audmux.o -obj-$(CONFIG_SND_SOC_IMX_PCM) += snd-soc-imx-pcm.o -snd-soc-imx-pcm-y := imx-pcm.o -snd-soc-imx-pcm-$(CONFIG_SND_SOC_IMX_PCM_FIQ) += imx-pcm-fiq.o -snd-soc-imx-pcm-$(CONFIG_SND_SOC_IMX_PCM_DMA) += imx-pcm-dma.o +obj-$(CONFIG_SND_SOC_IMX_PCM_FIQ) += snd-soc-imx-pcm-fiq.o +snd-soc-imx-pcm-fiq-y := imx-pcm-fiq.o imx-pcm.o +obj-$(CONFIG_SND_SOC_IMX_PCM_DMA) += snd-soc-imx-pcm-dma.o +snd-soc-imx-pcm-dma-y := imx-pcm-dma.o imx-pcm.o # i.MX Machine Support snd-soc-eukrea-tlv320-objs := eukrea-tlv320.o diff --git a/sound/soc/fsl/eukrea-tlv320.c b/sound/soc/fsl/eukrea-tlv320.c index 267d5b4b63ce..75ffdf0e2aad 100644 --- a/sound/soc/fsl/eukrea-tlv320.c +++ b/sound/soc/fsl/eukrea-tlv320.c @@ -93,7 +93,7 @@ static struct snd_soc_card eukrea_tlv320 = { .num_links = 1, }; -static int __devinit eukrea_tlv320_probe(struct platform_device *pdev) +static int eukrea_tlv320_probe(struct platform_device *pdev) { int ret; int int_port = 0, ext_port; @@ -142,7 +142,7 @@ static int __devinit eukrea_tlv320_probe(struct platform_device *pdev) return ret; } -static int __devexit eukrea_tlv320_remove(struct platform_device *pdev) +static int eukrea_tlv320_remove(struct platform_device *pdev) { snd_soc_unregister_card(&eukrea_tlv320); @@ -155,7 +155,7 @@ static struct platform_driver eukrea_tlv320_driver = { .owner = THIS_MODULE, }, .probe = eukrea_tlv320_probe, - .remove = __devexit_p(eukrea_tlv320_remove),}; + .remove = eukrea_tlv320_remove,}; module_platform_driver(eukrea_tlv320_driver); diff --git a/sound/soc/fsl/fsl_dma.c b/sound/soc/fsl/fsl_dma.c index 6feb26500580..9cc5c1f82f09 100644 --- a/sound/soc/fsl/fsl_dma.c +++ b/sound/soc/fsl/fsl_dma.c @@ -894,7 +894,7 @@ static struct snd_pcm_ops fsl_dma_ops = { .pointer = fsl_dma_pointer, }; -static int __devinit fsl_soc_dma_probe(struct platform_device *pdev) +static int fsl_soc_dma_probe(struct platform_device *pdev) { struct dma_object *dma; struct device_node *np = pdev->dev.of_node; @@ -958,7 +958,7 @@ static int __devinit fsl_soc_dma_probe(struct platform_device *pdev) return 0; } -static int __devexit fsl_soc_dma_remove(struct platform_device *pdev) +static int fsl_soc_dma_remove(struct platform_device *pdev) { struct dma_object *dma = dev_get_drvdata(&pdev->dev); @@ -983,7 +983,7 @@ static struct platform_driver fsl_soc_dma_driver = { .of_match_table = fsl_soc_dma_ids, }, .probe = fsl_soc_dma_probe, - .remove = __devexit_p(fsl_soc_dma_remove), + .remove = fsl_soc_dma_remove, }; module_platform_driver(fsl_soc_dma_driver); diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 4ed2afd47782..7decbd9b2340 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -639,7 +639,7 @@ static void make_lowercase(char *s) } } -static int __devinit fsl_ssi_probe(struct platform_device *pdev) +static int fsl_ssi_probe(struct platform_device *pdev) { struct fsl_ssi_private *ssi_private; int ret = 0; diff --git a/sound/soc/fsl/imx-audmux.c b/sound/soc/fsl/imx-audmux.c index 524ce6210cee..251f4d981e0c 100644 --- a/sound/soc/fsl/imx-audmux.c +++ b/sound/soc/fsl/imx-audmux.c @@ -162,7 +162,7 @@ static void __init audmux_debugfs_init(void) } } -static void __devexit audmux_debugfs_remove(void) +static void audmux_debugfs_remove(void) { debugfs_remove_recursive(audmux_debugfs_root); } @@ -244,7 +244,7 @@ int imx_audmux_v2_configure_port(unsigned int port, unsigned int ptcr, } EXPORT_SYMBOL_GPL(imx_audmux_v2_configure_port); -static int __devinit imx_audmux_probe(struct platform_device *pdev) +static int imx_audmux_probe(struct platform_device *pdev) { struct resource *res; struct pinctrl *pinctrl; @@ -278,7 +278,7 @@ static int __devinit imx_audmux_probe(struct platform_device *pdev) return 0; } -static int __devexit imx_audmux_remove(struct platform_device *pdev) +static int imx_audmux_remove(struct platform_device *pdev) { if (audmux_type == IMX31_AUDMUX) audmux_debugfs_remove(); @@ -289,7 +289,7 @@ static int __devexit imx_audmux_remove(struct platform_device *pdev) static struct platform_driver imx_audmux_driver = { .probe = imx_audmux_probe, - .remove = __devexit_p(imx_audmux_remove), + .remove = imx_audmux_remove, .id_table = imx_audmux_ids, .driver = { .name = DRIVER_NAME, diff --git a/sound/soc/fsl/imx-mc13783.c b/sound/soc/fsl/imx-mc13783.c index 549b31fdc9dd..4ae30f21fdb5 100644 --- a/sound/soc/fsl/imx-mc13783.c +++ b/sound/soc/fsl/imx-mc13783.c @@ -98,7 +98,7 @@ static struct snd_soc_card imx_mc13783 = { .num_dapm_routes = ARRAY_SIZE(imx_mc13783_routes), }; -static int __devinit imx_mc13783_probe(struct platform_device *pdev) +static int imx_mc13783_probe(struct platform_device *pdev) { int ret; @@ -148,7 +148,7 @@ static int __devinit imx_mc13783_probe(struct platform_device *pdev) return ret; } -static int __devexit imx_mc13783_remove(struct platform_device *pdev) +static int imx_mc13783_remove(struct platform_device *pdev) { snd_soc_unregister_card(&imx_mc13783); @@ -161,7 +161,7 @@ static struct platform_driver imx_mc13783_audio_driver = { .owner = THIS_MODULE, }, .probe = imx_mc13783_probe, - .remove = __devexit_p(imx_mc13783_remove) + .remove = imx_mc13783_remove }; module_platform_driver(imx_mc13783_audio_driver); diff --git a/sound/soc/fsl/imx-pcm-dma.c b/sound/soc/fsl/imx-pcm-dma.c index d85929b79c35..bf363d8d044a 100644 --- a/sound/soc/fsl/imx-pcm-dma.c +++ b/sound/soc/fsl/imx-pcm-dma.c @@ -154,12 +154,12 @@ static struct snd_soc_platform_driver imx_soc_platform_mx2 = { .pcm_free = imx_pcm_free, }; -static int __devinit imx_soc_platform_probe(struct platform_device *pdev) +static int imx_soc_platform_probe(struct platform_device *pdev) { return snd_soc_register_platform(&pdev->dev, &imx_soc_platform_mx2); } -static int __devexit imx_soc_platform_remove(struct platform_device *pdev) +static int imx_soc_platform_remove(struct platform_device *pdev) { snd_soc_unregister_platform(&pdev->dev); return 0; @@ -171,7 +171,7 @@ static struct platform_driver imx_pcm_driver = { .owner = THIS_MODULE, }, .probe = imx_soc_platform_probe, - .remove = __devexit_p(imx_soc_platform_remove), + .remove = imx_soc_platform_remove, }; module_platform_driver(imx_pcm_driver); diff --git a/sound/soc/fsl/imx-pcm-fiq.c b/sound/soc/fsl/imx-pcm-fiq.c index 22c6130957ba..5ec362ae4d01 100644 --- a/sound/soc/fsl/imx-pcm-fiq.c +++ b/sound/soc/fsl/imx-pcm-fiq.c @@ -29,7 +29,6 @@ #include <asm/fiq.h> -#include <mach/irqs.h> #include <linux/platform_data/asoc-imx-ssi.h> #include "imx-ssi.h" @@ -282,7 +281,7 @@ static struct snd_soc_platform_driver imx_soc_platform_fiq = { .pcm_free = imx_pcm_fiq_free, }; -static int __devinit imx_soc_platform_probe(struct platform_device *pdev) +static int imx_soc_platform_probe(struct platform_device *pdev) { struct imx_ssi *ssi = platform_get_drvdata(pdev); int ret; @@ -316,7 +315,7 @@ failed_register: return ret; } -static int __devexit imx_soc_platform_remove(struct platform_device *pdev) +static int imx_soc_platform_remove(struct platform_device *pdev) { snd_soc_unregister_platform(&pdev->dev); return 0; @@ -329,7 +328,7 @@ static struct platform_driver imx_pcm_driver = { }, .probe = imx_soc_platform_probe, - .remove = __devexit_p(imx_soc_platform_remove), + .remove = imx_soc_platform_remove, }; module_platform_driver(imx_pcm_driver); diff --git a/sound/soc/fsl/imx-pcm.c b/sound/soc/fsl/imx-pcm.c index 93dc360b1777..0c9f188ddc68 100644 --- a/sound/soc/fsl/imx-pcm.c +++ b/sound/soc/fsl/imx-pcm.c @@ -31,7 +31,6 @@ int snd_imx_pcm_mmap(struct snd_pcm_substream *substream, runtime->dma_bytes); return ret; } -EXPORT_SYMBOL_GPL(snd_imx_pcm_mmap); static int imx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) { @@ -80,7 +79,6 @@ int imx_pcm_new(struct snd_soc_pcm_runtime *rtd) out: return ret; } -EXPORT_SYMBOL_GPL(imx_pcm_new); void imx_pcm_free(struct snd_pcm *pcm) { @@ -102,4 +100,7 @@ void imx_pcm_free(struct snd_pcm *pcm) buf->area = NULL; } } -EXPORT_SYMBOL_GPL(imx_pcm_free); + +MODULE_DESCRIPTION("Freescale i.MX PCM driver"); +MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/fsl/imx-sgtl5000.c b/sound/soc/fsl/imx-sgtl5000.c index 199408ec4261..424347e9b2d7 100644 --- a/sound/soc/fsl/imx-sgtl5000.c +++ b/sound/soc/fsl/imx-sgtl5000.c @@ -56,7 +56,7 @@ static const struct snd_soc_dapm_widget imx_sgtl5000_dapm_widgets[] = { SND_SOC_DAPM_SPK("Ext Spk", NULL), }; -static int __devinit imx_sgtl5000_probe(struct platform_device *pdev) +static int imx_sgtl5000_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; struct device_node *ssi_np, *codec_np; @@ -162,6 +162,7 @@ static int __devinit imx_sgtl5000_probe(struct platform_device *pdev) if (ret) goto clk_fail; data->card.num_links = 1; + data->card.owner = THIS_MODULE; data->card.dai_link = &data->dai; data->card.dapm_widgets = imx_sgtl5000_dapm_widgets; data->card.num_dapm_widgets = ARRAY_SIZE(imx_sgtl5000_dapm_widgets); @@ -184,7 +185,7 @@ fail: return ret; } -static int __devexit imx_sgtl5000_remove(struct platform_device *pdev) +static int imx_sgtl5000_remove(struct platform_device *pdev) { struct imx_sgtl5000_data *data = platform_get_drvdata(pdev); @@ -210,7 +211,7 @@ static struct platform_driver imx_sgtl5000_driver = { .of_match_table = imx_sgtl5000_dt_ids, }, .probe = imx_sgtl5000_probe, - .remove = __devexit_p(imx_sgtl5000_remove), + .remove = imx_sgtl5000_remove, }; module_platform_driver(imx_sgtl5000_driver); diff --git a/sound/soc/fsl/imx-ssi.c b/sound/soc/fsl/imx-ssi.c index 006f7d465ed2..3b480423747f 100644 --- a/sound/soc/fsl/imx-ssi.c +++ b/sound/soc/fsl/imx-ssi.c @@ -48,7 +48,6 @@ #include <sound/soc.h> #include <linux/platform_data/asoc-imx-ssi.h> -#include <mach/hardware.h> #include "imx-ssi.h" @@ -639,7 +638,7 @@ failed_clk: return ret; } -static int __devexit imx_ssi_remove(struct platform_device *pdev) +static int imx_ssi_remove(struct platform_device *pdev) { struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); struct imx_ssi *ssi = platform_get_drvdata(pdev); @@ -660,7 +659,7 @@ static int __devexit imx_ssi_remove(struct platform_device *pdev) static struct platform_driver imx_ssi_driver = { .probe = imx_ssi_probe, - .remove = __devexit_p(imx_ssi_remove), + .remove = imx_ssi_remove, .driver = { .name = "imx-ssi", diff --git a/sound/soc/fsl/mpc5200_psc_ac97.c b/sound/soc/fsl/mpc5200_psc_ac97.c index a313c0ae36db..a4aec0488dd3 100644 --- a/sound/soc/fsl/mpc5200_psc_ac97.c +++ b/sound/soc/fsl/mpc5200_psc_ac97.c @@ -277,7 +277,7 @@ static struct snd_soc_dai_driver psc_ac97_dai[] = { * - Probe/remove operations * - OF device match table */ -static int __devinit psc_ac97_of_probe(struct platform_device *op) +static int psc_ac97_of_probe(struct platform_device *op) { int rc; struct snd_ac97 ac97; @@ -310,7 +310,7 @@ static int __devinit psc_ac97_of_probe(struct platform_device *op) return 0; } -static int __devexit psc_ac97_of_remove(struct platform_device *op) +static int psc_ac97_of_remove(struct platform_device *op) { mpc5200_audio_dma_destroy(op); snd_soc_unregister_dais(&op->dev, ARRAY_SIZE(psc_ac97_dai)); @@ -318,7 +318,7 @@ static int __devexit psc_ac97_of_remove(struct platform_device *op) } /* Match table for of_platform binding */ -static struct of_device_id psc_ac97_match[] __devinitdata = { +static struct of_device_id psc_ac97_match[] = { { .compatible = "fsl,mpc5200-psc-ac97", }, { .compatible = "fsl,mpc5200b-psc-ac97", }, {} @@ -327,7 +327,7 @@ MODULE_DEVICE_TABLE(of, psc_ac97_match); static struct platform_driver psc_ac97_driver = { .probe = psc_ac97_of_probe, - .remove = __devexit_p(psc_ac97_of_remove), + .remove = psc_ac97_of_remove, .driver = { .name = "mpc5200-psc-ac97", .owner = THIS_MODULE, diff --git a/sound/soc/fsl/mpc5200_psc_i2s.c b/sound/soc/fsl/mpc5200_psc_i2s.c index ba1f0a66358f..b95b966f25a0 100644 --- a/sound/soc/fsl/mpc5200_psc_i2s.c +++ b/sound/soc/fsl/mpc5200_psc_i2s.c @@ -153,7 +153,7 @@ static struct snd_soc_dai_driver psc_i2s_dai[] = {{ * - Probe/remove operations * - OF device match table */ -static int __devinit psc_i2s_of_probe(struct platform_device *op) +static int psc_i2s_of_probe(struct platform_device *op) { int rc; struct psc_dma *psc_dma; @@ -205,7 +205,7 @@ static int __devinit psc_i2s_of_probe(struct platform_device *op) } -static int __devexit psc_i2s_of_remove(struct platform_device *op) +static int psc_i2s_of_remove(struct platform_device *op) { mpc5200_audio_dma_destroy(op); snd_soc_unregister_dais(&op->dev, ARRAY_SIZE(psc_i2s_dai)); @@ -213,7 +213,7 @@ static int __devexit psc_i2s_of_remove(struct platform_device *op) } /* Match table for of_platform binding */ -static struct of_device_id psc_i2s_match[] __devinitdata = { +static struct of_device_id psc_i2s_match[] = { { .compatible = "fsl,mpc5200-psc-i2s", }, { .compatible = "fsl,mpc5200b-psc-i2s", }, {} @@ -222,7 +222,7 @@ MODULE_DEVICE_TABLE(of, psc_i2s_match); static struct platform_driver psc_i2s_driver = { .probe = psc_i2s_of_probe, - .remove = __devexit_p(psc_i2s_of_remove), + .remove = psc_i2s_of_remove, .driver = { .name = "mpc5200-psc-i2s", .owner = THIS_MODULE, diff --git a/sound/soc/fsl/mpc8610_hpcd.c b/sound/soc/fsl/mpc8610_hpcd.c index 9ff9318c52b9..228c52e71440 100644 --- a/sound/soc/fsl/mpc8610_hpcd.c +++ b/sound/soc/fsl/mpc8610_hpcd.c @@ -368,7 +368,7 @@ error_alloc: * * This function is called when the platform device is removed. */ -static int __devexit mpc8610_hpcd_remove(struct platform_device *pdev) +static int mpc8610_hpcd_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); struct mpc8610_hpcd_data *machine_data = @@ -382,7 +382,7 @@ static int __devexit mpc8610_hpcd_remove(struct platform_device *pdev) static struct platform_driver mpc8610_hpcd_driver = { .probe = mpc8610_hpcd_probe, - .remove = __devexit_p(mpc8610_hpcd_remove), + .remove = mpc8610_hpcd_remove, .driver = { /* The name must match 'compatible' property in the device tree, * in lowercase letters. diff --git a/sound/soc/fsl/mx27vis-aic32x4.c b/sound/soc/fsl/mx27vis-aic32x4.c index 2b76877b1789..3d1074179057 100644 --- a/sound/soc/fsl/mx27vis-aic32x4.c +++ b/sound/soc/fsl/mx27vis-aic32x4.c @@ -180,7 +180,7 @@ static struct snd_soc_card mx27vis_aic32x4 = { .num_dapm_routes = ARRAY_SIZE(aic32x4_dapm_routes), }; -static int __devinit mx27vis_aic32x4_probe(struct platform_device *pdev) +static int mx27vis_aic32x4_probe(struct platform_device *pdev) { struct snd_mx27vis_platform_data *pdata = pdev->dev.platform_data; int ret; @@ -219,7 +219,7 @@ static int __devinit mx27vis_aic32x4_probe(struct platform_device *pdev) return ret; } -static int __devexit mx27vis_aic32x4_remove(struct platform_device *pdev) +static int mx27vis_aic32x4_remove(struct platform_device *pdev) { snd_soc_unregister_card(&mx27vis_aic32x4); @@ -232,7 +232,7 @@ static struct platform_driver mx27vis_aic32x4_audio_driver = { .owner = THIS_MODULE, }, .probe = mx27vis_aic32x4_probe, - .remove = __devexit_p(mx27vis_aic32x4_remove), + .remove = mx27vis_aic32x4_remove, }; module_platform_driver(mx27vis_aic32x4_audio_driver); diff --git a/sound/soc/fsl/p1022_ds.c b/sound/soc/fsl/p1022_ds.c index 144d49603637..ba59c23a137b 100644 --- a/sound/soc/fsl/p1022_ds.c +++ b/sound/soc/fsl/p1022_ds.c @@ -376,7 +376,7 @@ error_put: * * This function is called when the platform device is removed. */ -static int __devexit p1022_ds_remove(struct platform_device *pdev) +static int p1022_ds_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); struct machine_data *mdata = @@ -390,7 +390,7 @@ static int __devexit p1022_ds_remove(struct platform_device *pdev) static struct platform_driver p1022_ds_driver = { .probe = p1022_ds_probe, - .remove = __devexit_p(p1022_ds_remove), + .remove = p1022_ds_remove, .driver = { /* * The name must match 'compatible' property in the device tree, diff --git a/sound/soc/fsl/p1022_rdk.c b/sound/soc/fsl/p1022_rdk.c new file mode 100644 index 000000000000..f21551911533 --- /dev/null +++ b/sound/soc/fsl/p1022_rdk.c @@ -0,0 +1,392 @@ +/** + * Freescale P1022RDK ALSA SoC Machine driver + * + * Author: Timur Tabi <timur@freescale.com> + * + * Copyright 2012 Freescale Semiconductor, Inc. + * + * 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. + * + * Note: in order for audio to work correctly, the output controls need + * to be enabled, because they control the clock. So for playback, for + * example: + * + * amixer sset 'Left Output Mixer PCM' on + * amixer sset 'Right Output Mixer PCM' on + */ + +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/of_device.h> +#include <linux/slab.h> +#include <sound/soc.h> +#include <asm/fsl_guts.h> + +#include "fsl_dma.h" +#include "fsl_ssi.h" +#include "fsl_utils.h" + +/* P1022-specific PMUXCR and DMUXCR bit definitions */ + +#define CCSR_GUTS_PMUXCR_UART0_I2C1_MASK 0x0001c000 +#define CCSR_GUTS_PMUXCR_UART0_I2C1_UART0_SSI 0x00010000 +#define CCSR_GUTS_PMUXCR_UART0_I2C1_SSI 0x00018000 + +#define CCSR_GUTS_PMUXCR_SSI_DMA_TDM_MASK 0x00000c00 +#define CCSR_GUTS_PMUXCR_SSI_DMA_TDM_SSI 0x00000000 + +#define CCSR_GUTS_DMUXCR_PAD 1 /* DMA controller/channel set to pad */ +#define CCSR_GUTS_DMUXCR_SSI 2 /* DMA controller/channel set to SSI */ + +/* + * Set the DMACR register in the GUTS + * + * The DMACR register determines the source of initiated transfers for each + * channel on each DMA controller. Rather than have a bunch of repetitive + * macros for the bit patterns, we just have a function that calculates + * them. + * + * guts: Pointer to GUTS structure + * co: The DMA controller (0 or 1) + * ch: The channel on the DMA controller (0, 1, 2, or 3) + * device: The device to set as the target (CCSR_GUTS_DMUXCR_xxx) + */ +static inline void guts_set_dmuxcr(struct ccsr_guts __iomem *guts, + unsigned int co, unsigned int ch, unsigned int device) +{ + unsigned int shift = 16 + (8 * (1 - co) + 2 * (3 - ch)); + + clrsetbits_be32(&guts->dmuxcr, 3 << shift, device << shift); +} + +/* There's only one global utilities register */ +static phys_addr_t guts_phys; + +/** + * machine_data: machine-specific ASoC device data + * + * This structure contains data for a single sound platform device on an + * P1022 RDK. Some of the data is taken from the device tree. + */ +struct machine_data { + struct snd_soc_dai_link dai[2]; + struct snd_soc_card card; + unsigned int dai_format; + unsigned int codec_clk_direction; + unsigned int cpu_clk_direction; + unsigned int clk_frequency; + unsigned int dma_id[2]; /* 0 = DMA1, 1 = DMA2, etc */ + unsigned int dma_channel_id[2]; /* 0 = ch 0, 1 = ch 1, etc*/ + char platform_name[2][DAI_NAME_SIZE]; /* One for each DMA channel */ +}; + +/** + * p1022_rdk_machine_probe: initialize the board + * + * This function is used to initialize the board-specific hardware. + * + * Here we program the DMACR and PMUXCR registers. + */ +static int p1022_rdk_machine_probe(struct snd_soc_card *card) +{ + struct machine_data *mdata = + container_of(card, struct machine_data, card); + struct ccsr_guts __iomem *guts; + + guts = ioremap(guts_phys, sizeof(struct ccsr_guts)); + if (!guts) { + dev_err(card->dev, "could not map global utilities\n"); + return -ENOMEM; + } + + /* Enable SSI Tx signal */ + clrsetbits_be32(&guts->pmuxcr, CCSR_GUTS_PMUXCR_UART0_I2C1_MASK, + CCSR_GUTS_PMUXCR_UART0_I2C1_UART0_SSI); + + /* Enable SSI Rx signal */ + clrsetbits_be32(&guts->pmuxcr, CCSR_GUTS_PMUXCR_SSI_DMA_TDM_MASK, + CCSR_GUTS_PMUXCR_SSI_DMA_TDM_SSI); + + /* Enable DMA Channel for SSI */ + guts_set_dmuxcr(guts, mdata->dma_id[0], mdata->dma_channel_id[0], + CCSR_GUTS_DMUXCR_SSI); + + guts_set_dmuxcr(guts, mdata->dma_id[1], mdata->dma_channel_id[1], + CCSR_GUTS_DMUXCR_SSI); + + iounmap(guts); + + return 0; +} + +/** + * p1022_rdk_startup: program the board with various hardware parameters + * + * This function takes board-specific information, like clock frequencies + * and serial data formats, and passes that information to the codec and + * transport drivers. + */ +static int p1022_rdk_startup(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct machine_data *mdata = + container_of(rtd->card, struct machine_data, card); + struct device *dev = rtd->card->dev; + int ret = 0; + + /* Tell the codec driver what the serial protocol is. */ + ret = snd_soc_dai_set_fmt(rtd->codec_dai, mdata->dai_format); + if (ret < 0) { + dev_err(dev, "could not set codec driver audio format (ret=%i)\n", + ret); + return ret; + } + + ret = snd_soc_dai_set_pll(rtd->codec_dai, 0, 0, mdata->clk_frequency, + mdata->clk_frequency); + if (ret < 0) { + dev_err(dev, "could not set codec PLL frequency (ret=%i)\n", + ret); + return ret; + } + + return 0; +} + +/** + * p1022_rdk_machine_remove: Remove the sound device + * + * This function is called to remove the sound device for one SSI. We + * de-program the DMACR and PMUXCR register. + */ +static int p1022_rdk_machine_remove(struct snd_soc_card *card) +{ + struct machine_data *mdata = + container_of(card, struct machine_data, card); + struct ccsr_guts __iomem *guts; + + guts = ioremap(guts_phys, sizeof(struct ccsr_guts)); + if (!guts) { + dev_err(card->dev, "could not map global utilities\n"); + return -ENOMEM; + } + + /* Restore the signal routing */ + clrbits32(&guts->pmuxcr, CCSR_GUTS_PMUXCR_UART0_I2C1_MASK); + clrbits32(&guts->pmuxcr, CCSR_GUTS_PMUXCR_SSI_DMA_TDM_MASK); + guts_set_dmuxcr(guts, mdata->dma_id[0], mdata->dma_channel_id[0], 0); + guts_set_dmuxcr(guts, mdata->dma_id[1], mdata->dma_channel_id[1], 0); + + iounmap(guts); + + return 0; +} + +/** + * p1022_rdk_ops: ASoC machine driver operations + */ +static struct snd_soc_ops p1022_rdk_ops = { + .startup = p1022_rdk_startup, +}; + +/** + * p1022_rdk_probe: platform probe function for the machine driver + * + * Although this is a machine driver, the SSI node is the "master" node with + * respect to audio hardware connections. Therefore, we create a new ASoC + * device for each new SSI node that has a codec attached. + */ +static int p1022_rdk_probe(struct platform_device *pdev) +{ + struct device *dev = pdev->dev.parent; + /* ssi_pdev is the platform device for the SSI node that probed us */ + struct platform_device *ssi_pdev = + container_of(dev, struct platform_device, dev); + struct device_node *np = ssi_pdev->dev.of_node; + struct device_node *codec_np = NULL; + struct machine_data *mdata; + const u32 *iprop; + int ret; + + /* Find the codec node for this SSI. */ + codec_np = of_parse_phandle(np, "codec-handle", 0); + if (!codec_np) { + dev_err(dev, "could not find codec node\n"); + return -EINVAL; + } + + mdata = kzalloc(sizeof(struct machine_data), GFP_KERNEL); + if (!mdata) { + ret = -ENOMEM; + goto error_put; + } + + mdata->dai[0].cpu_dai_name = dev_name(&ssi_pdev->dev); + mdata->dai[0].ops = &p1022_rdk_ops; + + /* ASoC core can match codec with device node */ + mdata->dai[0].codec_of_node = codec_np; + + /* + * We register two DAIs per SSI, one for playback and the other for + * capture. We support codecs that have separate DAIs for both playback + * and capture. + */ + memcpy(&mdata->dai[1], &mdata->dai[0], sizeof(struct snd_soc_dai_link)); + + /* The DAI names from the codec (snd_soc_dai_driver.name) */ + mdata->dai[0].codec_dai_name = "wm8960-hifi"; + mdata->dai[1].codec_dai_name = mdata->dai[0].codec_dai_name; + + /* + * Configure the SSI for I2S slave mode. Older device trees have + * an fsl,mode property, but we ignore that since there's really + * only one way to configure the SSI. + */ + mdata->dai_format = SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM; + mdata->codec_clk_direction = SND_SOC_CLOCK_OUT; + mdata->cpu_clk_direction = SND_SOC_CLOCK_IN; + + /* + * In i2s-slave mode, the codec has its own clock source, so we + * need to get the frequency from the device tree and pass it to + * the codec driver. + */ + iprop = of_get_property(codec_np, "clock-frequency", NULL); + if (!iprop || !*iprop) { + dev_err(&pdev->dev, "codec bus-frequency property is missing or invalid\n"); + ret = -EINVAL; + goto error; + } + mdata->clk_frequency = be32_to_cpup(iprop); + + if (!mdata->clk_frequency) { + dev_err(&pdev->dev, "unknown clock frequency\n"); + ret = -EINVAL; + goto error; + } + + /* Find the playback DMA channel to use. */ + mdata->dai[0].platform_name = mdata->platform_name[0]; + ret = fsl_asoc_get_dma_channel(np, "fsl,playback-dma", &mdata->dai[0], + &mdata->dma_channel_id[0], + &mdata->dma_id[0]); + if (ret) { + dev_err(&pdev->dev, "missing/invalid playback DMA phandle (ret=%i)\n", + ret); + goto error; + } + + /* Find the capture DMA channel to use. */ + mdata->dai[1].platform_name = mdata->platform_name[1]; + ret = fsl_asoc_get_dma_channel(np, "fsl,capture-dma", &mdata->dai[1], + &mdata->dma_channel_id[1], + &mdata->dma_id[1]); + if (ret) { + dev_err(&pdev->dev, "missing/invalid capture DMA phandle (ret=%i)\n", + ret); + goto error; + } + + /* Initialize our DAI data structure. */ + mdata->dai[0].stream_name = "playback"; + mdata->dai[1].stream_name = "capture"; + mdata->dai[0].name = mdata->dai[0].stream_name; + mdata->dai[1].name = mdata->dai[1].stream_name; + + mdata->card.probe = p1022_rdk_machine_probe; + mdata->card.remove = p1022_rdk_machine_remove; + mdata->card.name = pdev->name; /* The platform driver name */ + mdata->card.owner = THIS_MODULE; + mdata->card.dev = &pdev->dev; + mdata->card.num_links = 2; + mdata->card.dai_link = mdata->dai; + + /* Register with ASoC */ + ret = snd_soc_register_card(&mdata->card); + if (ret) { + dev_err(&pdev->dev, "could not register card (ret=%i)\n", ret); + goto error; + } + + return 0; + +error: + kfree(mdata); +error_put: + of_node_put(codec_np); + return ret; +} + +/** + * p1022_rdk_remove: remove the platform device + * + * This function is called when the platform device is removed. + */ +static int p1022_rdk_remove(struct platform_device *pdev) +{ + struct snd_soc_card *card = platform_get_drvdata(pdev); + struct machine_data *mdata = + container_of(card, struct machine_data, card); + + snd_soc_unregister_card(card); + kfree(mdata); + + return 0; +} + +static struct platform_driver p1022_rdk_driver = { + .probe = p1022_rdk_probe, + .remove = p1022_rdk_remove, + .driver = { + /* + * The name must match 'compatible' property in the device tree, + * in lowercase letters. + */ + .name = "snd-soc-p1022rdk", + .owner = THIS_MODULE, + }, +}; + +/** + * p1022_rdk_init: machine driver initialization. + * + * This function is called when this module is loaded. + */ +static int __init p1022_rdk_init(void) +{ + struct device_node *guts_np; + struct resource res; + + /* Get the physical address of the global utilities registers */ + guts_np = of_find_compatible_node(NULL, NULL, "fsl,p1022-guts"); + if (of_address_to_resource(guts_np, 0, &res)) { + pr_err("snd-soc-p1022rdk: missing/invalid global utils node\n"); + of_node_put(guts_np); + return -EINVAL; + } + guts_phys = res.start; + of_node_put(guts_np); + + return platform_driver_register(&p1022_rdk_driver); +} + +/** + * p1022_rdk_exit: machine driver exit + * + * This function is called when this driver is unloaded. + */ +static void __exit p1022_rdk_exit(void) +{ + platform_driver_unregister(&p1022_rdk_driver); +} + +late_initcall(p1022_rdk_init); +module_exit(p1022_rdk_exit); + +MODULE_AUTHOR("Timur Tabi <timur@freescale.com>"); +MODULE_DESCRIPTION("Freescale / iVeia P1022 RDK ALSA SoC machine driver"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/fsl/pcm030-audio-fabric.c b/sound/soc/fsl/pcm030-audio-fabric.c index 4b63ec8eb372..8e52c1485df3 100644 --- a/sound/soc/fsl/pcm030-audio-fabric.c +++ b/sound/soc/fsl/pcm030-audio-fabric.c @@ -29,14 +29,14 @@ struct pcm030_audio_data { static struct snd_soc_dai_link pcm030_fabric_dai[] = { { - .name = "AC97", + .name = "AC97.0", .stream_name = "AC97 Analog", .codec_dai_name = "wm9712-hifi", .cpu_dai_name = "mpc5200-psc-ac97.0", .codec_name = "wm9712-codec", }, { - .name = "AC97", + .name = "AC97.1", .stream_name = "AC97 IEC958", .codec_dai_name = "wm9712-aux", .cpu_dai_name = "mpc5200-psc-ac97.1", @@ -101,7 +101,7 @@ static int __init pcm030_fabric_probe(struct platform_device *op) return ret; } -static int __devexit pcm030_fabric_remove(struct platform_device *op) +static int pcm030_fabric_remove(struct platform_device *op) { struct pcm030_audio_data *pdata = platform_get_drvdata(op); int ret; @@ -120,7 +120,7 @@ MODULE_DEVICE_TABLE(of, pcm030_audio_match); static struct platform_driver pcm030_fabric_driver = { .probe = pcm030_fabric_probe, - .remove = __devexit_p(pcm030_fabric_remove), + .remove = pcm030_fabric_remove, .driver = { .name = DRV_NAME, .owner = THIS_MODULE, diff --git a/sound/soc/jz4740/jz4740-i2s.c b/sound/soc/jz4740/jz4740-i2s.c index 41349670adab..6cef491f4823 100644 --- a/sound/soc/jz4740/jz4740-i2s.c +++ b/sound/soc/jz4740/jz4740-i2s.c @@ -425,7 +425,7 @@ static struct snd_soc_dai_driver jz4740_i2s_dai = { .resume = jz4740_i2s_resume, }; -static int __devinit jz4740_i2s_dev_probe(struct platform_device *pdev) +static int jz4740_i2s_dev_probe(struct platform_device *pdev) { struct jz4740_i2s *i2s; int ret; @@ -492,7 +492,7 @@ err_free: return ret; } -static int __devexit jz4740_i2s_dev_remove(struct platform_device *pdev) +static int jz4740_i2s_dev_remove(struct platform_device *pdev) { struct jz4740_i2s *i2s = platform_get_drvdata(pdev); @@ -512,7 +512,7 @@ static int __devexit jz4740_i2s_dev_remove(struct platform_device *pdev) static struct platform_driver jz4740_i2s_driver = { .probe = jz4740_i2s_dev_probe, - .remove = __devexit_p(jz4740_i2s_dev_remove), + .remove = jz4740_i2s_dev_remove, .driver = { .name = "jz4740-i2s", .owner = THIS_MODULE, diff --git a/sound/soc/jz4740/jz4740-pcm.c b/sound/soc/jz4740/jz4740-pcm.c index 9b8cf256847d..710059292318 100644 --- a/sound/soc/jz4740/jz4740-pcm.c +++ b/sound/soc/jz4740/jz4740-pcm.c @@ -335,12 +335,12 @@ static struct snd_soc_platform_driver jz4740_soc_platform = { .pcm_free = jz4740_pcm_free, }; -static int __devinit jz4740_pcm_probe(struct platform_device *pdev) +static int jz4740_pcm_probe(struct platform_device *pdev) { return snd_soc_register_platform(&pdev->dev, &jz4740_soc_platform); } -static int __devexit jz4740_pcm_remove(struct platform_device *pdev) +static int jz4740_pcm_remove(struct platform_device *pdev) { snd_soc_unregister_platform(&pdev->dev); return 0; @@ -348,7 +348,7 @@ static int __devexit jz4740_pcm_remove(struct platform_device *pdev) static struct platform_driver jz4740_pcm_driver = { .probe = jz4740_pcm_probe, - .remove = __devexit_p(jz4740_pcm_remove), + .remove = jz4740_pcm_remove, .driver = { .name = "jz4740-pcm-audio", .owner = THIS_MODULE, diff --git a/sound/soc/jz4740/qi_lb60.c b/sound/soc/jz4740/qi_lb60.c index e8aaff18d7cc..55fd6b5df55f 100644 --- a/sound/soc/jz4740/qi_lb60.c +++ b/sound/soc/jz4740/qi_lb60.c @@ -96,7 +96,7 @@ static const struct gpio qi_lb60_gpios[] = { { QI_LB60_AMP_GPIO, GPIOF_OUT_INIT_LOW, "AMP" }, }; -static int __devinit qi_lb60_probe(struct platform_device *pdev) +static int qi_lb60_probe(struct platform_device *pdev) { struct snd_soc_card *card = &qi_lb60; int ret; @@ -116,7 +116,7 @@ static int __devinit qi_lb60_probe(struct platform_device *pdev) return ret; } -static int __devexit qi_lb60_remove(struct platform_device *pdev) +static int qi_lb60_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); @@ -131,7 +131,7 @@ static struct platform_driver qi_lb60_driver = { .owner = THIS_MODULE, }, .probe = qi_lb60_probe, - .remove = __devexit_p(qi_lb60_remove), + .remove = qi_lb60_remove, }; module_platform_driver(qi_lb60_driver); diff --git a/sound/soc/kirkwood/kirkwood-dma.c b/sound/soc/kirkwood/kirkwood-dma.c index b9f16598324c..d3d4bdca1cc6 100644 --- a/sound/soc/kirkwood/kirkwood-dma.c +++ b/sound/soc/kirkwood/kirkwood-dma.c @@ -22,12 +22,16 @@ #include "kirkwood.h" #define KIRKWOOD_RATES \ - (SNDRV_PCM_RATE_44100 | \ - SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000) + (SNDRV_PCM_RATE_8000_192000 | \ + SNDRV_PCM_RATE_CONTINUOUS | \ + SNDRV_PCM_RATE_KNOT) + #define KIRKWOOD_FORMATS \ (SNDRV_PCM_FMTBIT_S16_LE | \ SNDRV_PCM_FMTBIT_S24_LE | \ - SNDRV_PCM_FMTBIT_S32_LE) + SNDRV_PCM_FMTBIT_S32_LE | \ + SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE | \ + SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_BE) struct kirkwood_dma_priv { struct snd_pcm_substream *play_stream; @@ -43,10 +47,10 @@ static struct snd_pcm_hardware kirkwood_dma_snd_hw = { SNDRV_PCM_INFO_PAUSE), .formats = KIRKWOOD_FORMATS, .rates = KIRKWOOD_RATES, - .rate_min = 44100, - .rate_max = 96000, + .rate_min = 8000, + .rate_max = 384000, .channels_min = 1, - .channels_max = 2, + .channels_max = 8, .buffer_bytes_max = KIRKWOOD_SND_MAX_PERIOD_BYTES * KIRKWOOD_SND_MAX_PERIODS, .period_bytes_min = KIRKWOOD_SND_MIN_PERIOD_BYTES, .period_bytes_max = KIRKWOOD_SND_MAX_PERIOD_BYTES, @@ -71,7 +75,6 @@ static irqreturn_t kirkwood_dma_irq(int irq, void *dev_id) printk(KERN_WARNING "%s: got err interrupt 0x%lx\n", __func__, cause); writel(cause, priv->io + KIRKWOOD_ERR_CAUSE); - return IRQ_HANDLED; } /* we've enabled only bytes interrupts ... */ @@ -178,7 +181,7 @@ static int kirkwood_dma_open(struct snd_pcm_substream *substream) } dram = mv_mbus_dram_info(); - addr = virt_to_phys(substream->dma_buffer.area); + addr = substream->dma_buffer.addr; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { prdata->play_stream = substream; kirkwood_dma_conf_mbus_windows(priv->io, @@ -369,12 +372,12 @@ static struct snd_soc_platform_driver kirkwood_soc_platform = { .pcm_free = kirkwood_dma_free_dma_buffers, }; -static int __devinit kirkwood_soc_platform_probe(struct platform_device *pdev) +static int kirkwood_soc_platform_probe(struct platform_device *pdev) { return snd_soc_register_platform(&pdev->dev, &kirkwood_soc_platform); } -static int __devexit kirkwood_soc_platform_remove(struct platform_device *pdev) +static int kirkwood_soc_platform_remove(struct platform_device *pdev) { snd_soc_unregister_platform(&pdev->dev); return 0; @@ -387,7 +390,7 @@ static struct platform_driver kirkwood_pcm_driver = { }, .probe = kirkwood_soc_platform_probe, - .remove = __devexit_p(kirkwood_soc_platform_remove), + .remove = kirkwood_soc_platform_remove, }; module_platform_driver(kirkwood_pcm_driver); diff --git a/sound/soc/kirkwood/kirkwood-i2s.c b/sound/soc/kirkwood/kirkwood-i2s.c index 542538d10ab7..282d8b1163ba 100644 --- a/sound/soc/kirkwood/kirkwood-i2s.c +++ b/sound/soc/kirkwood/kirkwood-i2s.c @@ -95,10 +95,33 @@ static inline void kirkwood_set_dco(void __iomem *io, unsigned long rate) do { cpu_relax(); value = readl(io + KIRKWOOD_DCO_SPCR_STATUS); - value &= KIRKWOOD_DCO_SPCR_STATUS; + value &= KIRKWOOD_DCO_SPCR_STATUS_DCO_LOCK; } while (value == 0); } +static void kirkwood_set_rate(struct snd_soc_dai *dai, + struct kirkwood_dma_data *priv, unsigned long rate) +{ + uint32_t clks_ctrl; + + if (rate == 44100 || rate == 48000 || rate == 96000) { + /* use internal dco for supported rates */ + dev_dbg(dai->dev, "%s: dco set rate = %lu\n", + __func__, rate); + kirkwood_set_dco(priv->io, rate); + + clks_ctrl = KIRKWOOD_MCLK_SOURCE_DCO; + } else if (!IS_ERR(priv->extclk)) { + /* use optional external clk for other rates */ + dev_dbg(dai->dev, "%s: extclk set rate = %lu -> %lu\n", + __func__, rate, 256 * rate); + clk_set_rate(priv->extclk, 256 * rate); + + clks_ctrl = KIRKWOOD_MCLK_SOURCE_EXTCLK; + } + writel(clks_ctrl, priv->io + KIRKWOOD_CLOCKS_CTRL); +} + static int kirkwood_i2s_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { @@ -113,26 +136,21 @@ static int kirkwood_i2s_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai); - unsigned int i2s_reg, reg; - unsigned long i2s_value, value; + uint32_t ctl_play, ctl_rec; + unsigned int i2s_reg; + unsigned long i2s_value; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { i2s_reg = KIRKWOOD_I2S_PLAYCTL; - reg = KIRKWOOD_PLAYCTL; } else { i2s_reg = KIRKWOOD_I2S_RECCTL; - reg = KIRKWOOD_RECCTL; } - /* set dco conf */ - kirkwood_set_dco(priv->io, params_rate(params)); + kirkwood_set_rate(dai, priv, params_rate(params)); i2s_value = readl(priv->io+i2s_reg); i2s_value &= ~KIRKWOOD_I2S_CTL_SIZE_MASK; - value = readl(priv->io+reg); - value &= ~KIRKWOOD_PLAYCTL_SIZE_MASK; - /* * Size settings in play/rec i2s control regs and play/rec control * regs must be the same. @@ -140,38 +158,57 @@ static int kirkwood_i2s_hw_params(struct snd_pcm_substream *substream, switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: i2s_value |= KIRKWOOD_I2S_CTL_SIZE_16; - value |= KIRKWOOD_PLAYCTL_SIZE_16_C; + ctl_play = KIRKWOOD_PLAYCTL_SIZE_16_C | + KIRKWOOD_PLAYCTL_I2S_EN; + ctl_rec = KIRKWOOD_RECCTL_SIZE_16_C | + KIRKWOOD_RECCTL_I2S_EN; break; /* * doesn't work... S20_3LE != kirkwood 20bit format ? * case SNDRV_PCM_FORMAT_S20_3LE: i2s_value |= KIRKWOOD_I2S_CTL_SIZE_20; - value |= KIRKWOOD_PLAYCTL_SIZE_20; + ctl_play = KIRKWOOD_PLAYCTL_SIZE_20 | + KIRKWOOD_PLAYCTL_I2S_EN; + ctl_rec = KIRKWOOD_RECCTL_SIZE_20 | + KIRKWOOD_RECCTL_I2S_EN; break; */ case SNDRV_PCM_FORMAT_S24_LE: i2s_value |= KIRKWOOD_I2S_CTL_SIZE_24; - value |= KIRKWOOD_PLAYCTL_SIZE_24; + ctl_play = KIRKWOOD_PLAYCTL_SIZE_24 | + KIRKWOOD_PLAYCTL_I2S_EN; + ctl_rec = KIRKWOOD_RECCTL_SIZE_24 | + KIRKWOOD_RECCTL_I2S_EN; break; case SNDRV_PCM_FORMAT_S32_LE: i2s_value |= KIRKWOOD_I2S_CTL_SIZE_32; - value |= KIRKWOOD_PLAYCTL_SIZE_32; + ctl_play = KIRKWOOD_PLAYCTL_SIZE_32 | + KIRKWOOD_PLAYCTL_I2S_EN; + ctl_rec = KIRKWOOD_RECCTL_SIZE_32 | + KIRKWOOD_RECCTL_I2S_EN; break; default: return -EINVAL; } if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - value &= ~KIRKWOOD_PLAYCTL_MONO_MASK; if (params_channels(params) == 1) - value |= KIRKWOOD_PLAYCTL_MONO_BOTH; + ctl_play |= KIRKWOOD_PLAYCTL_MONO_BOTH; else - value |= KIRKWOOD_PLAYCTL_MONO_OFF; + ctl_play |= KIRKWOOD_PLAYCTL_MONO_OFF; + + priv->ctl_play &= ~(KIRKWOOD_PLAYCTL_MONO_MASK | + KIRKWOOD_PLAYCTL_I2S_EN | + KIRKWOOD_PLAYCTL_SPDIF_EN | + KIRKWOOD_PLAYCTL_SIZE_MASK); + priv->ctl_play |= ctl_play; + } else { + priv->ctl_rec &= ~KIRKWOOD_RECCTL_SIZE_MASK; + priv->ctl_rec |= ctl_rec; } writel(i2s_value, priv->io+i2s_reg); - writel(value, priv->io+reg); return 0; } @@ -180,67 +217,70 @@ static int kirkwood_i2s_play_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai); - unsigned long value; - - /* - * specs says KIRKWOOD_PLAYCTL must be read 2 times before - * changing it. So read 1 time here and 1 later. - */ - value = readl(priv->io + KIRKWOOD_PLAYCTL); + uint32_t ctl, value; + + ctl = readl(priv->io + KIRKWOOD_PLAYCTL); + if (ctl & KIRKWOOD_PLAYCTL_PAUSE) { + unsigned timeout = 5000; + /* + * The Armada510 spec says that if we enter pause mode, the + * busy bit must be read back as clear _twice_. Make sure + * we respect that otherwise we get DMA underruns. + */ + do { + value = ctl; + ctl = readl(priv->io + KIRKWOOD_PLAYCTL); + if (!((ctl | value) & KIRKWOOD_PLAYCTL_PLAY_BUSY)) + break; + udelay(1); + } while (timeout--); + + if ((ctl | value) & KIRKWOOD_PLAYCTL_PLAY_BUSY) + dev_notice(dai->dev, "timed out waiting for busy to deassert: %08x\n", + ctl); + } switch (cmd) { case SNDRV_PCM_TRIGGER_START: - /* stop audio, enable interrupts */ - value = readl(priv->io + KIRKWOOD_PLAYCTL); - value |= KIRKWOOD_PLAYCTL_PAUSE; + /* configure */ + ctl = priv->ctl_play; + value = ctl & ~(KIRKWOOD_PLAYCTL_I2S_EN | + KIRKWOOD_PLAYCTL_SPDIF_EN); writel(value, priv->io + KIRKWOOD_PLAYCTL); + /* enable interrupts */ value = readl(priv->io + KIRKWOOD_INT_MASK); value |= KIRKWOOD_INT_CAUSE_PLAY_BYTES; writel(value, priv->io + KIRKWOOD_INT_MASK); - /* configure audio & enable i2s playback */ - value = readl(priv->io + KIRKWOOD_PLAYCTL); - value &= ~KIRKWOOD_PLAYCTL_BURST_MASK; - value &= ~(KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE - | KIRKWOOD_PLAYCTL_SPDIF_EN); - - if (priv->burst == 32) - value |= KIRKWOOD_PLAYCTL_BURST_32; - else - value |= KIRKWOOD_PLAYCTL_BURST_128; - value |= KIRKWOOD_PLAYCTL_I2S_EN; - writel(value, priv->io + KIRKWOOD_PLAYCTL); + /* enable playback */ + writel(ctl, priv->io + KIRKWOOD_PLAYCTL); break; case SNDRV_PCM_TRIGGER_STOP: /* stop audio, disable interrupts */ - value = readl(priv->io + KIRKWOOD_PLAYCTL); - value |= KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE; - writel(value, priv->io + KIRKWOOD_PLAYCTL); + ctl |= KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE; + writel(ctl, priv->io + KIRKWOOD_PLAYCTL); value = readl(priv->io + KIRKWOOD_INT_MASK); value &= ~KIRKWOOD_INT_CAUSE_PLAY_BYTES; writel(value, priv->io + KIRKWOOD_INT_MASK); /* disable all playbacks */ - value = readl(priv->io + KIRKWOOD_PLAYCTL); - value &= ~(KIRKWOOD_PLAYCTL_I2S_EN | KIRKWOOD_PLAYCTL_SPDIF_EN); - writel(value, priv->io + KIRKWOOD_PLAYCTL); + ctl &= ~(KIRKWOOD_PLAYCTL_I2S_EN | KIRKWOOD_PLAYCTL_SPDIF_EN); + writel(ctl, priv->io + KIRKWOOD_PLAYCTL); break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_SUSPEND: - value = readl(priv->io + KIRKWOOD_PLAYCTL); - value |= KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE; - writel(value, priv->io + KIRKWOOD_PLAYCTL); + ctl |= KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE; + writel(ctl, priv->io + KIRKWOOD_PLAYCTL); break; case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - value = readl(priv->io + KIRKWOOD_PLAYCTL); - value &= ~(KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE); - writel(value, priv->io + KIRKWOOD_PLAYCTL); + ctl &= ~(KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE); + writel(ctl, priv->io + KIRKWOOD_PLAYCTL); break; default: @@ -254,35 +294,24 @@ static int kirkwood_i2s_rec_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai); - unsigned long value; + uint32_t ctl, value; value = readl(priv->io + KIRKWOOD_RECCTL); switch (cmd) { case SNDRV_PCM_TRIGGER_START: - /* stop audio, enable interrupts */ - value = readl(priv->io + KIRKWOOD_RECCTL); - value |= KIRKWOOD_RECCTL_PAUSE; + /* configure */ + ctl = priv->ctl_rec; + value = ctl & ~KIRKWOOD_RECCTL_I2S_EN; writel(value, priv->io + KIRKWOOD_RECCTL); + /* enable interrupts */ value = readl(priv->io + KIRKWOOD_INT_MASK); value |= KIRKWOOD_INT_CAUSE_REC_BYTES; writel(value, priv->io + KIRKWOOD_INT_MASK); - /* configure audio & enable i2s record */ - value = readl(priv->io + KIRKWOOD_RECCTL); - value &= ~KIRKWOOD_RECCTL_BURST_MASK; - value &= ~KIRKWOOD_RECCTL_MONO; - value &= ~(KIRKWOOD_RECCTL_PAUSE | KIRKWOOD_RECCTL_MUTE - | KIRKWOOD_RECCTL_SPDIF_EN); - - if (priv->burst == 32) - value |= KIRKWOOD_RECCTL_BURST_32; - else - value |= KIRKWOOD_RECCTL_BURST_128; - value |= KIRKWOOD_RECCTL_I2S_EN; - - writel(value, priv->io + KIRKWOOD_RECCTL); + /* enable record */ + writel(ctl, priv->io + KIRKWOOD_RECCTL); break; case SNDRV_PCM_TRIGGER_STOP: @@ -389,112 +418,146 @@ static struct snd_soc_dai_driver kirkwood_i2s_dai = { .channels_min = 1, .channels_max = 2, .rates = KIRKWOOD_I2S_RATES, - .formats = KIRKWOOD_I2S_FORMATS,}, + .formats = KIRKWOOD_I2S_FORMATS, + }, .capture = { .channels_min = 1, .channels_max = 2, .rates = KIRKWOOD_I2S_RATES, - .formats = KIRKWOOD_I2S_FORMATS,}, + .formats = KIRKWOOD_I2S_FORMATS, + }, .ops = &kirkwood_i2s_dai_ops, }; -static __devinit int kirkwood_i2s_dev_probe(struct platform_device *pdev) +static struct snd_soc_dai_driver kirkwood_i2s_dai_extclk = { + .probe = kirkwood_i2s_probe, + .remove = kirkwood_i2s_remove, + .playback = { + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_192000 | + SNDRV_PCM_RATE_CONTINUOUS | + SNDRV_PCM_RATE_KNOT, + .formats = KIRKWOOD_I2S_FORMATS, + }, + .capture = { + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_192000 | + SNDRV_PCM_RATE_CONTINUOUS | + SNDRV_PCM_RATE_KNOT, + .formats = KIRKWOOD_I2S_FORMATS, + }, + .ops = &kirkwood_i2s_dai_ops, +}; + +static int kirkwood_i2s_dev_probe(struct platform_device *pdev) { - struct resource *mem; - struct kirkwood_asoc_platform_data *data = - pdev->dev.platform_data; + struct kirkwood_asoc_platform_data *data = pdev->dev.platform_data; + struct snd_soc_dai_driver *soc_dai = &kirkwood_i2s_dai; struct kirkwood_dma_data *priv; + struct resource *mem; int err; - priv = kzalloc(sizeof(struct kirkwood_dma_data), GFP_KERNEL); + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); if (!priv) { dev_err(&pdev->dev, "allocation failed\n"); - err = -ENOMEM; - goto error; + return -ENOMEM; } dev_set_drvdata(&pdev->dev, priv); mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!mem) { dev_err(&pdev->dev, "platform_get_resource failed\n"); - err = -ENXIO; - goto err_alloc; - } - - priv->mem = request_mem_region(mem->start, SZ_16K, DRV_NAME); - if (!priv->mem) { - dev_err(&pdev->dev, "request_mem_region failed\n"); - err = -EBUSY; - goto err_alloc; + return -ENXIO; } - priv->io = ioremap(priv->mem->start, SZ_16K); + priv->io = devm_request_and_ioremap(&pdev->dev, mem); if (!priv->io) { - dev_err(&pdev->dev, "ioremap failed\n"); - err = -ENOMEM; - goto err_iomem; + dev_err(&pdev->dev, "devm_request_and_ioremap failed\n"); + return -ENOMEM; } priv->irq = platform_get_irq(pdev, 0); if (priv->irq <= 0) { dev_err(&pdev->dev, "platform_get_irq failed\n"); - err = -ENXIO; - goto err_ioremap; + return -ENXIO; } if (!data) { dev_err(&pdev->dev, "no platform data ?!\n"); - err = -EINVAL; - goto err_ioremap; + return -EINVAL; } priv->burst = data->burst; - priv->clk = clk_get(&pdev->dev, NULL); + priv->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(priv->clk)) { dev_err(&pdev->dev, "no clock\n"); - err = PTR_ERR(priv->clk); - goto err_ioremap; + return PTR_ERR(priv->clk); + } + + err = clk_prepare_enable(priv->clk); + if (err < 0) + return err; + + priv->extclk = clk_get(&pdev->dev, "extclk"); + if (!IS_ERR(priv->extclk)) { + if (priv->extclk == priv->clk) { + clk_put(priv->extclk); + priv->extclk = ERR_PTR(-EINVAL); + } else { + dev_info(&pdev->dev, "found external clock\n"); + clk_prepare_enable(priv->extclk); + soc_dai = &kirkwood_i2s_dai_extclk; + } + } + + /* Some sensible defaults - this reflects the powerup values */ + priv->ctl_play = KIRKWOOD_PLAYCTL_SIZE_24; + priv->ctl_rec = KIRKWOOD_RECCTL_SIZE_24; + + /* Select the burst size */ + if (data->burst == 32) { + priv->ctl_play |= KIRKWOOD_PLAYCTL_BURST_32; + priv->ctl_rec |= KIRKWOOD_RECCTL_BURST_32; + } else { + priv->ctl_play |= KIRKWOOD_PLAYCTL_BURST_128; + priv->ctl_rec |= KIRKWOOD_RECCTL_BURST_128; } - clk_prepare_enable(priv->clk); - err = snd_soc_register_dai(&pdev->dev, &kirkwood_i2s_dai); + err = snd_soc_register_dai(&pdev->dev, soc_dai); if (!err) return 0; dev_err(&pdev->dev, "snd_soc_register_dai failed\n"); + if (!IS_ERR(priv->extclk)) { + clk_disable_unprepare(priv->extclk); + clk_put(priv->extclk); + } clk_disable_unprepare(priv->clk); - clk_put(priv->clk); - -err_ioremap: - iounmap(priv->io); -err_iomem: - release_mem_region(priv->mem->start, SZ_16K); -err_alloc: - kfree(priv); -error: + return err; } -static __devexit int kirkwood_i2s_dev_remove(struct platform_device *pdev) +static int kirkwood_i2s_dev_remove(struct platform_device *pdev) { struct kirkwood_dma_data *priv = dev_get_drvdata(&pdev->dev); snd_soc_unregister_dai(&pdev->dev); + if (!IS_ERR(priv->extclk)) { + clk_disable_unprepare(priv->extclk); + clk_put(priv->extclk); + } clk_disable_unprepare(priv->clk); - clk_put(priv->clk); - - iounmap(priv->io); - release_mem_region(priv->mem->start, SZ_16K); - kfree(priv); return 0; } static struct platform_driver kirkwood_i2s_driver = { .probe = kirkwood_i2s_dev_probe, - .remove = __devexit_p(kirkwood_i2s_dev_remove), + .remove = kirkwood_i2s_dev_remove, .driver = { .name = DRV_NAME, .owner = THIS_MODULE, diff --git a/sound/soc/kirkwood/kirkwood-openrd.c b/sound/soc/kirkwood/kirkwood-openrd.c index c28540aeea25..b979c7154715 100644 --- a/sound/soc/kirkwood/kirkwood-openrd.c +++ b/sound/soc/kirkwood/kirkwood-openrd.c @@ -71,7 +71,7 @@ static struct snd_soc_card openrd_client = { .num_links = ARRAY_SIZE(openrd_client_dai), }; -static int __devinit openrd_probe(struct platform_device *pdev) +static int openrd_probe(struct platform_device *pdev) { struct snd_soc_card *card = &openrd_client; int ret; @@ -85,7 +85,7 @@ static int __devinit openrd_probe(struct platform_device *pdev) return ret; } -static int __devexit openrd_remove(struct platform_device *pdev) +static int openrd_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); @@ -99,7 +99,7 @@ static struct platform_driver openrd_driver = { .owner = THIS_MODULE, }, .probe = openrd_probe, - .remove = __devexit_p(openrd_remove), + .remove = openrd_remove, }; module_platform_driver(openrd_driver); diff --git a/sound/soc/kirkwood/kirkwood-t5325.c b/sound/soc/kirkwood/kirkwood-t5325.c index c67bbc574987..1d0ed6f8add7 100644 --- a/sound/soc/kirkwood/kirkwood-t5325.c +++ b/sound/soc/kirkwood/kirkwood-t5325.c @@ -92,7 +92,7 @@ static struct snd_soc_card t5325 = { .num_dapm_routes = ARRAY_SIZE(t5325_route), }; -static int __devinit t5325_probe(struct platform_device *pdev) +static int t5325_probe(struct platform_device *pdev) { struct snd_soc_card *card = &t5325; int ret; @@ -106,7 +106,7 @@ static int __devinit t5325_probe(struct platform_device *pdev) return ret; } -static int __devexit t5325_remove(struct platform_device *pdev) +static int t5325_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); @@ -120,7 +120,7 @@ static struct platform_driver t5325_driver = { .owner = THIS_MODULE, }, .probe = t5325_probe, - .remove = __devexit_p(t5325_remove), + .remove = t5325_remove, }; module_platform_driver(t5325_driver); diff --git a/sound/soc/kirkwood/kirkwood.h b/sound/soc/kirkwood/kirkwood.h index f9084d83e6bd..4d92637ddb3f 100644 --- a/sound/soc/kirkwood/kirkwood.h +++ b/sound/soc/kirkwood/kirkwood.h @@ -77,6 +77,11 @@ #define KIRKWOOD_DCO_SPCR_STATUS 0x120c #define KIRKWOOD_DCO_SPCR_STATUS_DCO_LOCK (1<<16) +#define KIRKWOOD_CLOCKS_CTRL 0x1230 +#define KIRKWOOD_MCLK_SOURCE_MASK (3<<0) +#define KIRKWOOD_MCLK_SOURCE_DCO (0<<0) +#define KIRKWOOD_MCLK_SOURCE_EXTCLK (3<<0) + #define KIRKWOOD_ERR_CAUSE 0x1300 #define KIRKWOOD_ERR_MASK 0x1304 @@ -119,11 +124,13 @@ #define KIRKWOOD_SND_MAX_PERIOD_BYTES 0x4000 struct kirkwood_dma_data { - struct resource *mem; void __iomem *io; + struct clk *clk; + struct clk *extclk; + uint32_t ctl_play; + uint32_t ctl_rec; int irq; int burst; - struct clk *clk; }; #endif diff --git a/sound/soc/mid-x86/mfld_machine.c b/sound/soc/mid-x86/mfld_machine.c index 2cc7782714b5..4139116c33b5 100644 --- a/sound/soc/mid-x86/mfld_machine.c +++ b/sound/soc/mid-x86/mfld_machine.c @@ -358,7 +358,7 @@ static irqreturn_t snd_mfld_jack_detection(int irq, void *data) return IRQ_HANDLED; } -static int __devinit snd_mfld_mc_probe(struct platform_device *pdev) +static int snd_mfld_mc_probe(struct platform_device *pdev) { int ret_val = 0, irq; struct mfld_mc_private *mc_drv_ctx; @@ -417,7 +417,7 @@ unalloc: return ret_val; } -static int __devexit snd_mfld_mc_remove(struct platform_device *pdev) +static int snd_mfld_mc_remove(struct platform_device *pdev) { struct mfld_mc_private *mc_drv_ctx = platform_get_drvdata(pdev); @@ -435,7 +435,7 @@ static struct platform_driver snd_mfld_mc_driver = { .name = "msic_audio", }, .probe = snd_mfld_mc_probe, - .remove = __devexit_p(snd_mfld_mc_remove), + .remove = snd_mfld_mc_remove, }; module_platform_driver(snd_mfld_mc_driver); diff --git a/sound/soc/mxs/mxs-pcm.c b/sound/soc/mxs/mxs-pcm.c index f82d766cbf9e..564b5b60319d 100644 --- a/sound/soc/mxs/mxs-pcm.c +++ b/sound/soc/mxs/mxs-pcm.c @@ -220,13 +220,13 @@ static struct snd_soc_platform_driver mxs_soc_platform = { .pcm_free = mxs_pcm_free, }; -int __devinit mxs_pcm_platform_register(struct device *dev) +int mxs_pcm_platform_register(struct device *dev) { return snd_soc_register_platform(dev, &mxs_soc_platform); } EXPORT_SYMBOL_GPL(mxs_pcm_platform_register); -void __devexit mxs_pcm_platform_unregister(struct device *dev) +void mxs_pcm_platform_unregister(struct device *dev) { snd_soc_unregister_platform(dev); } diff --git a/sound/soc/mxs/mxs-saif.c b/sound/soc/mxs/mxs-saif.c index c294fbb523fc..365d9d27a321 100644 --- a/sound/soc/mxs/mxs-saif.c +++ b/sound/soc/mxs/mxs-saif.c @@ -229,6 +229,7 @@ int mxs_saif_put_mclk(unsigned int saif_id) saif->mclk_in_use = 0; return 0; } +EXPORT_SYMBOL_GPL(mxs_saif_put_mclk); /* * Get MCLK and set clock rate, then enable it @@ -282,6 +283,7 @@ int mxs_saif_get_mclk(unsigned int saif_id, unsigned int mclk, return 0; } +EXPORT_SYMBOL_GPL(mxs_saif_get_mclk); /* * SAIF DAI format configuration. @@ -655,7 +657,7 @@ static irqreturn_t mxs_saif_irq(int irq, void *dev_id) return IRQ_HANDLED; } -static int __devinit mxs_saif_probe(struct platform_device *pdev) +static int mxs_saif_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; struct resource *iores, *dmares; @@ -790,7 +792,7 @@ failed_pdev_alloc: return ret; } -static int __devexit mxs_saif_remove(struct platform_device *pdev) +static int mxs_saif_remove(struct platform_device *pdev) { mxs_pcm_platform_unregister(&pdev->dev); snd_soc_unregister_dai(&pdev->dev); @@ -806,7 +808,7 @@ MODULE_DEVICE_TABLE(of, mxs_saif_dt_ids); static struct platform_driver mxs_saif_driver = { .probe = mxs_saif_probe, - .remove = __devexit_p(mxs_saif_remove), + .remove = mxs_saif_remove, .driver = { .name = "mxs-saif", diff --git a/sound/soc/mxs/mxs-sgtl5000.c b/sound/soc/mxs/mxs-sgtl5000.c index 215113b05f7d..b1d9b5ebeeeb 100644 --- a/sound/soc/mxs/mxs-sgtl5000.c +++ b/sound/soc/mxs/mxs-sgtl5000.c @@ -112,7 +112,7 @@ static struct snd_soc_card mxs_sgtl5000 = { .num_links = ARRAY_SIZE(mxs_sgtl5000_dai), }; -static int __devinit mxs_sgtl5000_probe_dt(struct platform_device *pdev) +static int mxs_sgtl5000_probe_dt(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; struct device_node *saif_np[2], *codec_np; @@ -145,7 +145,7 @@ static int __devinit mxs_sgtl5000_probe_dt(struct platform_device *pdev) return ret; } -static int __devinit mxs_sgtl5000_probe(struct platform_device *pdev) +static int mxs_sgtl5000_probe(struct platform_device *pdev) { struct snd_soc_card *card = &mxs_sgtl5000; int ret; @@ -176,7 +176,7 @@ static int __devinit mxs_sgtl5000_probe(struct platform_device *pdev) return 0; } -static int __devexit mxs_sgtl5000_remove(struct platform_device *pdev) +static int mxs_sgtl5000_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); @@ -200,7 +200,7 @@ static struct platform_driver mxs_sgtl5000_audio_driver = { .of_match_table = mxs_sgtl5000_dt_ids, }, .probe = mxs_sgtl5000_probe, - .remove = __devexit_p(mxs_sgtl5000_remove), + .remove = mxs_sgtl5000_remove, }; module_platform_driver(mxs_sgtl5000_audio_driver); diff --git a/sound/soc/nuc900/nuc900-ac97.c b/sound/soc/nuc900/nuc900-ac97.c index 946020a647db..0418467a4848 100644 --- a/sound/soc/nuc900/nuc900-ac97.c +++ b/sound/soc/nuc900/nuc900-ac97.c @@ -314,7 +314,7 @@ static struct snd_soc_dai_driver nuc900_ac97_dai = { .ops = &nuc900_ac97_dai_ops, }; -static int __devinit nuc900_ac97_drvprobe(struct platform_device *pdev) +static int nuc900_ac97_drvprobe(struct platform_device *pdev) { struct nuc900_audio *nuc900_audio; int ret; @@ -382,7 +382,7 @@ out0: return ret; } -static int __devexit nuc900_ac97_drvremove(struct platform_device *pdev) +static int nuc900_ac97_drvremove(struct platform_device *pdev) { snd_soc_unregister_dai(&pdev->dev); @@ -403,7 +403,7 @@ static struct platform_driver nuc900_ac97_driver = { .owner = THIS_MODULE, }, .probe = nuc900_ac97_drvprobe, - .remove = __devexit_p(nuc900_ac97_drvremove), + .remove = nuc900_ac97_drvremove, }; module_platform_driver(nuc900_ac97_driver); diff --git a/sound/soc/nuc900/nuc900-pcm.c b/sound/soc/nuc900/nuc900-pcm.c index 37585b47f4e3..c894ff0f2580 100644 --- a/sound/soc/nuc900/nuc900-pcm.c +++ b/sound/soc/nuc900/nuc900-pcm.c @@ -337,12 +337,12 @@ static struct snd_soc_platform_driver nuc900_soc_platform = { .pcm_free = nuc900_dma_free_dma_buffers, }; -static int __devinit nuc900_soc_platform_probe(struct platform_device *pdev) +static int nuc900_soc_platform_probe(struct platform_device *pdev) { return snd_soc_register_platform(&pdev->dev, &nuc900_soc_platform); } -static int __devexit nuc900_soc_platform_remove(struct platform_device *pdev) +static int nuc900_soc_platform_remove(struct platform_device *pdev) { snd_soc_unregister_platform(&pdev->dev); return 0; @@ -355,7 +355,7 @@ static struct platform_driver nuc900_pcm_driver = { }, .probe = nuc900_soc_platform_probe, - .remove = __devexit_p(nuc900_soc_platform_remove), + .remove = nuc900_soc_platform_remove, }; module_platform_driver(nuc900_pcm_driver); diff --git a/sound/soc/omap/am3517evm.c b/sound/soc/omap/am3517evm.c index fad350682ca2..c1900b2a6f28 100644 --- a/sound/soc/omap/am3517evm.c +++ b/sound/soc/omap/am3517evm.c @@ -25,8 +25,6 @@ #include <sound/soc.h> #include <asm/mach-types.h> -#include <mach/hardware.h> -#include <mach/gpio.h> #include <linux/platform_data/asoc-ti-mcbsp.h> #include "omap-mcbsp.h" diff --git a/sound/soc/omap/ams-delta.c b/sound/soc/omap/ams-delta.c index d8e96b2cd03e..2600447fa74f 100644 --- a/sound/soc/omap/ams-delta.c +++ b/sound/soc/omap/ams-delta.c @@ -575,7 +575,7 @@ static struct snd_soc_card ams_delta_audio_card = { }; /* Module init/exit */ -static __devinit int ams_delta_probe(struct platform_device *pdev) +static int ams_delta_probe(struct platform_device *pdev) { struct snd_soc_card *card = &ams_delta_audio_card; int ret; @@ -591,7 +591,7 @@ static __devinit int ams_delta_probe(struct platform_device *pdev) return 0; } -static int __devexit ams_delta_remove(struct platform_device *pdev) +static int ams_delta_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); @@ -616,7 +616,7 @@ static struct platform_driver ams_delta_driver = { .owner = THIS_MODULE, }, .probe = ams_delta_probe, - .remove = __devexit_p(ams_delta_remove), + .remove = ams_delta_remove, }; module_platform_driver(ams_delta_driver); diff --git a/sound/soc/omap/mcbsp.c b/sound/soc/omap/mcbsp.c index afb8d4f1bedf..285c8368cb47 100644 --- a/sound/soc/omap/mcbsp.c +++ b/sound/soc/omap/mcbsp.c @@ -28,8 +28,6 @@ #include <linux/platform_data/asoc-ti-mcbsp.h> -#include <plat/cpu.h> - #include "mcbsp.h" static void omap_mcbsp_write(struct omap_mcbsp *mcbsp, u16 reg, u32 val) @@ -612,7 +610,7 @@ void omap_mcbsp_free(struct omap_mcbsp *mcbsp) * system will refuse to enter idle if the CLKS pin source is not reset * back to internal source. */ - if (!cpu_class_is_omap1()) + if (!mcbsp_omap1()) omap2_mcbsp_set_clks_src(mcbsp, MCBSP_CLKS_PRCM_SRC); spin_lock(&mcbsp->lock); @@ -932,8 +930,7 @@ static const struct attribute_group sidetone_attr_group = { .attrs = (struct attribute **)sidetone_attrs, }; -static int __devinit omap_st_add(struct omap_mcbsp *mcbsp, - struct resource *res) +static int omap_st_add(struct omap_mcbsp *mcbsp, struct resource *res) { struct omap_mcbsp_st_data *st_data; int err; @@ -959,7 +956,7 @@ static int __devinit omap_st_add(struct omap_mcbsp *mcbsp, * McBSP1 and McBSP3 are directly mapped on 1610 and 1510. * 730 has only 2 McBSP, and both of them are MPU peripherals. */ -int __devinit omap_mcbsp_init(struct platform_device *pdev) +int omap_mcbsp_init(struct platform_device *pdev) { struct omap_mcbsp *mcbsp = platform_get_drvdata(pdev); struct resource *res; @@ -1087,7 +1084,7 @@ err_thres: return ret; } -void __devexit omap_mcbsp_sysfs_remove(struct omap_mcbsp *mcbsp) +void omap_mcbsp_sysfs_remove(struct omap_mcbsp *mcbsp) { if (mcbsp->pdata->buffer_size) sysfs_remove_group(&mcbsp->dev->kobj, &additional_attr_group); diff --git a/sound/soc/omap/mcbsp.h b/sound/soc/omap/mcbsp.h index 49a67259ce5a..f93e0b0af303 100644 --- a/sound/soc/omap/mcbsp.h +++ b/sound/soc/omap/mcbsp.h @@ -26,6 +26,12 @@ #include "omap-pcm.h" +#ifdef CONFIG_ARCH_OMAP1 +#define mcbsp_omap1() 1 +#else +#define mcbsp_omap1() 0 +#endif + /* McBSP register numbers. Register address offset = num * reg_step */ enum { /* Common registers */ @@ -341,7 +347,7 @@ int omap_st_enable(struct omap_mcbsp *mcbsp); int omap_st_disable(struct omap_mcbsp *mcbsp); int omap_st_is_enabled(struct omap_mcbsp *mcbsp); -int __devinit omap_mcbsp_init(struct platform_device *pdev); -void __devexit omap_mcbsp_sysfs_remove(struct omap_mcbsp *mcbsp); +int omap_mcbsp_init(struct platform_device *pdev); +void omap_mcbsp_sysfs_remove(struct omap_mcbsp *mcbsp); #endif /* __ASOC_MCBSP_H */ diff --git a/sound/soc/omap/n810.c b/sound/soc/omap/n810.c index 521bfc3d2b2b..230b8c144848 100644 --- a/sound/soc/omap/n810.c +++ b/sound/soc/omap/n810.c @@ -29,7 +29,6 @@ #include <sound/soc.h> #include <asm/mach-types.h> -#include <mach/hardware.h> #include <linux/gpio.h> #include <linux/module.h> #include <linux/platform_data/asoc-ti-mcbsp.h> diff --git a/sound/soc/omap/omap-abe-twl6040.c b/sound/soc/omap/omap-abe-twl6040.c index a57a4e68dcc6..e7d93fa412a9 100644 --- a/sound/soc/omap/omap-abe-twl6040.c +++ b/sound/soc/omap/omap-abe-twl6040.c @@ -273,7 +273,7 @@ static struct snd_soc_card omap_abe_card = { .num_dapm_routes = ARRAY_SIZE(audio_map), }; -static __devinit int omap_abe_probe(struct platform_device *pdev) +static int omap_abe_probe(struct platform_device *pdev) { struct omap_abe_twl6040_data *pdata = dev_get_platdata(&pdev->dev); struct device_node *node = pdev->dev.of_node; @@ -331,8 +331,8 @@ static __devinit int omap_abe_probe(struct platform_device *pdev) num_links = 1; } - of_property_read_u32(node, "ti,jack-detection", - &priv->jack_detection); + priv->jack_detection = of_property_read_bool(node, + "ti,jack-detection"); of_property_read_u32(node, "ti,mclk-freq", &priv->mclk_freq); if (!priv->mclk_freq) { @@ -390,7 +390,7 @@ err_unregister: return ret; } -static int __devexit omap_abe_remove(struct platform_device *pdev) +static int omap_abe_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); struct abe_twl6040 *priv = snd_soc_card_get_drvdata(card); @@ -417,7 +417,7 @@ static struct platform_driver omap_abe_driver = { .of_match_table = omap_abe_of_match, }, .probe = omap_abe_probe, - .remove = __devexit_p(omap_abe_remove), + .remove = omap_abe_remove, }; module_platform_driver(omap_abe_driver); diff --git a/sound/soc/omap/omap-dmic.c b/sound/soc/omap/omap-dmic.c index 5a6aeaf552a8..ba49ccd9eed9 100644 --- a/sound/soc/omap/omap-dmic.c +++ b/sound/soc/omap/omap-dmic.c @@ -448,7 +448,7 @@ static struct snd_soc_dai_driver omap_dmic_dai = { .ops = &omap_dmic_dai_ops, }; -static __devinit int asoc_dmic_probe(struct platform_device *pdev) +static int asoc_dmic_probe(struct platform_device *pdev) { struct omap_dmic *dmic; struct resource *res; @@ -518,7 +518,7 @@ err_put_clk: return ret; } -static int __devexit asoc_dmic_remove(struct platform_device *pdev) +static int asoc_dmic_remove(struct platform_device *pdev) { struct omap_dmic *dmic = platform_get_drvdata(pdev); @@ -541,7 +541,7 @@ static struct platform_driver asoc_dmic_driver = { .of_match_table = omap_dmic_of_match, }, .probe = asoc_dmic_probe, - .remove = __devexit_p(asoc_dmic_remove), + .remove = asoc_dmic_remove, }; module_platform_driver(asoc_dmic_driver); diff --git a/sound/soc/omap/omap-hdmi-card.c b/sound/soc/omap/omap-hdmi-card.c index eaa2ea0e3f81..d4eaa92e518e 100644 --- a/sound/soc/omap/omap-hdmi-card.c +++ b/sound/soc/omap/omap-hdmi-card.c @@ -45,7 +45,7 @@ static struct snd_soc_card snd_soc_omap_hdmi = { .num_links = 1, }; -static __devinit int omap_hdmi_probe(struct platform_device *pdev) +static int omap_hdmi_probe(struct platform_device *pdev) { struct snd_soc_card *card = &snd_soc_omap_hdmi; int ret; @@ -61,7 +61,7 @@ static __devinit int omap_hdmi_probe(struct platform_device *pdev) return 0; } -static int __devexit omap_hdmi_remove(struct platform_device *pdev) +static int omap_hdmi_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); @@ -76,7 +76,7 @@ static struct platform_driver omap_hdmi_driver = { .owner = THIS_MODULE, }, .probe = omap_hdmi_probe, - .remove = __devexit_p(omap_hdmi_remove), + .remove = omap_hdmi_remove, }; module_platform_driver(omap_hdmi_driver); diff --git a/sound/soc/omap/omap-hdmi.c b/sound/soc/omap/omap-hdmi.c index f59c69fb400e..7ea24819d570 100644 --- a/sound/soc/omap/omap-hdmi.c +++ b/sound/soc/omap/omap-hdmi.c @@ -262,7 +262,7 @@ static struct snd_soc_dai_driver omap_hdmi_dai = { .ops = &omap_hdmi_dai_ops, }; -static __devinit int omap_hdmi_probe(struct platform_device *pdev) +static int omap_hdmi_probe(struct platform_device *pdev) { int ret; struct resource *hdmi_rsrc; @@ -324,7 +324,7 @@ static __devinit int omap_hdmi_probe(struct platform_device *pdev) return ret; } -static int __devexit omap_hdmi_remove(struct platform_device *pdev) +static int omap_hdmi_remove(struct platform_device *pdev) { struct hdmi_priv *hdmi_data = dev_get_drvdata(&pdev->dev); @@ -345,7 +345,7 @@ static struct platform_driver hdmi_dai_driver = { .owner = THIS_MODULE, }, .probe = omap_hdmi_probe, - .remove = __devexit_p(omap_hdmi_remove), + .remove = omap_hdmi_remove, }; module_platform_driver(hdmi_dai_driver); diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index a6ee15747859..8d2defd6fdbe 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c @@ -34,7 +34,6 @@ #include <sound/initval.h> #include <sound/soc.h> -#include <plat/cpu.h> #include <linux/platform_data/asoc-ti-mcbsp.h> #include "mcbsp.h" #include "omap-mcbsp.h" @@ -512,7 +511,7 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, regs->srgr2 |= CLKSM; break; case OMAP_MCBSP_SYSCLK_CLKS_FCLK: - if (cpu_class_is_omap1()) { + if (mcbsp_omap1()) { err = -EINVAL; break; } @@ -520,7 +519,7 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, MCBSP_CLKS_PRCM_SRC); break; case OMAP_MCBSP_SYSCLK_CLKS_EXT: - if (cpu_class_is_omap1()) { + if (mcbsp_omap1()) { err = 0; break; } @@ -758,7 +757,7 @@ static const struct of_device_id omap_mcbsp_of_match[] = { }; MODULE_DEVICE_TABLE(of, omap_mcbsp_of_match); -static __devinit int asoc_mcbsp_probe(struct platform_device *pdev) +static int asoc_mcbsp_probe(struct platform_device *pdev) { struct omap_mcbsp_platform_data *pdata = dev_get_platdata(&pdev->dev); struct omap_mcbsp *mcbsp; @@ -799,7 +798,7 @@ static __devinit int asoc_mcbsp_probe(struct platform_device *pdev) return ret; } -static int __devexit asoc_mcbsp_remove(struct platform_device *pdev) +static int asoc_mcbsp_remove(struct platform_device *pdev) { struct omap_mcbsp *mcbsp = platform_get_drvdata(pdev); @@ -825,7 +824,7 @@ static struct platform_driver asoc_mcbsp_driver = { }, .probe = asoc_mcbsp_probe, - .remove = __devexit_p(asoc_mcbsp_remove), + .remove = asoc_mcbsp_remove, }; module_platform_driver(asoc_mcbsp_driver); diff --git a/sound/soc/omap/omap-mcpdm.c b/sound/soc/omap/omap-mcpdm.c index 56965bb3275c..2fe8be209452 100644 --- a/sound/soc/omap/omap-mcpdm.c +++ b/sound/soc/omap/omap-mcpdm.c @@ -429,7 +429,7 @@ void omap_mcpdm_configure_dn_offsets(struct snd_soc_pcm_runtime *rtd, } EXPORT_SYMBOL_GPL(omap_mcpdm_configure_dn_offsets); -static __devinit int asoc_mcpdm_probe(struct platform_device *pdev) +static int asoc_mcpdm_probe(struct platform_device *pdev) { struct omap_mcpdm *mcpdm; struct resource *res; @@ -487,7 +487,7 @@ static __devinit int asoc_mcpdm_probe(struct platform_device *pdev) return snd_soc_register_dai(&pdev->dev, &omap_mcpdm_dai); } -static int __devexit asoc_mcpdm_remove(struct platform_device *pdev) +static int asoc_mcpdm_remove(struct platform_device *pdev) { snd_soc_unregister_dai(&pdev->dev); return 0; @@ -507,7 +507,7 @@ static struct platform_driver asoc_mcpdm_driver = { }, .probe = asoc_mcpdm_probe, - .remove = __devexit_p(asoc_mcpdm_remove), + .remove = asoc_mcpdm_remove, }; module_platform_driver(asoc_mcpdm_driver); diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c index 340874ebf9ae..47bdbd415ad8 100644 --- a/sound/soc/omap/omap-pcm.c +++ b/sound/soc/omap/omap-pcm.c @@ -32,9 +32,14 @@ #include <sound/dmaengine_pcm.h> #include <sound/soc.h> -#include <plat/cpu.h> #include "omap-pcm.h" +#ifdef CONFIG_ARCH_OMAP1 +#define pcm_omap1510() cpu_is_omap1510() +#else +#define pcm_omap1510() 0 +#endif + static const struct snd_pcm_hardware omap_pcm_hardware = { .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | @@ -159,7 +164,7 @@ static snd_pcm_uframes_t omap_pcm_pointer(struct snd_pcm_substream *substream) { snd_pcm_uframes_t offset; - if (cpu_is_omap1510()) + if (pcm_omap1510()) offset = snd_dmaengine_pcm_pointer_no_residue(substream); else offset = snd_dmaengine_pcm_pointer(substream); @@ -297,13 +302,13 @@ static struct snd_soc_platform_driver omap_soc_platform = { .pcm_free = omap_pcm_free_dma_buffers, }; -static __devinit int omap_pcm_probe(struct platform_device *pdev) +static int omap_pcm_probe(struct platform_device *pdev) { return snd_soc_register_platform(&pdev->dev, &omap_soc_platform); } -static int __devexit omap_pcm_remove(struct platform_device *pdev) +static int omap_pcm_remove(struct platform_device *pdev) { snd_soc_unregister_platform(&pdev->dev); return 0; @@ -316,7 +321,7 @@ static struct platform_driver omap_pcm_driver = { }, .probe = omap_pcm_probe, - .remove = __devexit_p(omap_pcm_remove), + .remove = omap_pcm_remove, }; module_platform_driver(omap_pcm_driver); diff --git a/sound/soc/omap/omap-twl4030.c b/sound/soc/omap/omap-twl4030.c index 3b97b87971f5..4541d28b5314 100644 --- a/sound/soc/omap/omap-twl4030.c +++ b/sound/soc/omap/omap-twl4030.c @@ -107,7 +107,7 @@ static struct snd_soc_card omap_twl4030_card = { .num_links = ARRAY_SIZE(omap_twl4030_dai_links), }; -static __devinit int omap_twl4030_probe(struct platform_device *pdev) +static int omap_twl4030_probe(struct platform_device *pdev) { struct omap_tw4030_pdata *pdata = dev_get_platdata(&pdev->dev); struct device_node *node = pdev->dev.of_node; @@ -154,7 +154,7 @@ static __devinit int omap_twl4030_probe(struct platform_device *pdev) return 0; } -static int __devexit omap_twl4030_remove(struct platform_device *pdev) +static int omap_twl4030_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); @@ -177,7 +177,7 @@ static struct platform_driver omap_twl4030_driver = { .of_match_table = omap_twl4030_of_match, }, .probe = omap_twl4030_probe, - .remove = __devexit_p(omap_twl4030_remove), + .remove = omap_twl4030_remove, }; module_platform_driver(omap_twl4030_driver); diff --git a/sound/soc/omap/osk5912.c b/sound/soc/omap/osk5912.c index 3960e8df9c76..06ef8d67ed1c 100644 --- a/sound/soc/omap/osk5912.c +++ b/sound/soc/omap/osk5912.c @@ -28,7 +28,6 @@ #include <sound/soc.h> #include <asm/mach-types.h> -#include <mach/hardware.h> #include <linux/gpio.h> #include <linux/module.h> #include <linux/platform_data/asoc-ti-mcbsp.h> diff --git a/sound/soc/omap/sdp3430.c b/sound/soc/omap/sdp3430.c index 597cae769cea..b462a2c9385f 100644 --- a/sound/soc/omap/sdp3430.c +++ b/sound/soc/omap/sdp3430.c @@ -31,8 +31,6 @@ #include <sound/jack.h> #include <asm/mach-types.h> -#include <mach/hardware.h> -#include <mach/gpio.h> #include <linux/platform_data/gpio-omap.h> #include <linux/platform_data/asoc-ti-mcbsp.h> diff --git a/sound/soc/omap/zoom2.c b/sound/soc/omap/zoom2.c index 1ff6bb9ade5c..771bff27ac3e 100644 --- a/sound/soc/omap/zoom2.c +++ b/sound/soc/omap/zoom2.c @@ -37,8 +37,6 @@ #include "omap-mcbsp.h" #include "omap-pcm.h" -#define ZOOM2_HEADSET_MUX_GPIO (OMAP_MAX_GPIO_LINES + 15) - static int zoom2_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { @@ -187,9 +185,6 @@ static int __init zoom2_soc_init(void) if (ret) goto err1; - BUG_ON(gpio_request(ZOOM2_HEADSET_MUX_GPIO, "hs_mux") < 0); - gpio_direction_output(ZOOM2_HEADSET_MUX_GPIO, 0); - return 0; err1: @@ -202,8 +197,6 @@ module_init(zoom2_soc_init); static void __exit zoom2_soc_exit(void) { - gpio_free(ZOOM2_HEADSET_MUX_GPIO); - platform_device_unregister(zoom2_snd_device); } module_exit(zoom2_soc_exit); diff --git a/sound/soc/pxa/brownstone.c b/sound/soc/pxa/brownstone.c index 5e666e03d333..4ad76099dd43 100644 --- a/sound/soc/pxa/brownstone.c +++ b/sound/soc/pxa/brownstone.c @@ -140,7 +140,7 @@ static struct snd_soc_card brownstone = { .num_dapm_routes = ARRAY_SIZE(brownstone_audio_map), }; -static int __devinit brownstone_probe(struct platform_device *pdev) +static int brownstone_probe(struct platform_device *pdev) { int ret; @@ -152,7 +152,7 @@ static int __devinit brownstone_probe(struct platform_device *pdev) return ret; } -static int __devexit brownstone_remove(struct platform_device *pdev) +static int brownstone_remove(struct platform_device *pdev) { snd_soc_unregister_card(&brownstone); return 0; @@ -164,7 +164,7 @@ static struct platform_driver mmp_driver = { .owner = THIS_MODULE, }, .probe = brownstone_probe, - .remove = __devexit_p(brownstone_remove), + .remove = brownstone_remove, }; module_platform_driver(mmp_driver); diff --git a/sound/soc/pxa/corgi.c b/sound/soc/pxa/corgi.c index 863367ad89ce..f4cce1e80112 100644 --- a/sound/soc/pxa/corgi.c +++ b/sound/soc/pxa/corgi.c @@ -303,7 +303,7 @@ static struct snd_soc_card corgi = { .num_dapm_routes = ARRAY_SIZE(corgi_audio_map), }; -static int __devinit corgi_probe(struct platform_device *pdev) +static int corgi_probe(struct platform_device *pdev) { struct snd_soc_card *card = &corgi; int ret; @@ -317,7 +317,7 @@ static int __devinit corgi_probe(struct platform_device *pdev) return ret; } -static int __devexit corgi_remove(struct platform_device *pdev) +static int corgi_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); @@ -331,7 +331,7 @@ static struct platform_driver corgi_driver = { .owner = THIS_MODULE, }, .probe = corgi_probe, - .remove = __devexit_p(corgi_remove), + .remove = corgi_remove, }; module_platform_driver(corgi_driver); diff --git a/sound/soc/pxa/e740_wm9705.c b/sound/soc/pxa/e740_wm9705.c index 7b1bc2390039..70d799b13f0d 100644 --- a/sound/soc/pxa/e740_wm9705.c +++ b/sound/soc/pxa/e740_wm9705.c @@ -144,7 +144,7 @@ static struct gpio e740_audio_gpios[] = { { GPIO_E740_WM9705_nAVDD2, GPIOF_OUT_INIT_HIGH, "Audio power" }, }; -static int __devinit e740_probe(struct platform_device *pdev) +static int e740_probe(struct platform_device *pdev) { struct snd_soc_card *card = &e740; int ret; @@ -165,7 +165,7 @@ static int __devinit e740_probe(struct platform_device *pdev) return ret; } -static int __devexit e740_remove(struct platform_device *pdev) +static int e740_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); @@ -180,7 +180,7 @@ static struct platform_driver e740_driver = { .owner = THIS_MODULE, }, .probe = e740_probe, - .remove = __devexit_p(e740_remove), + .remove = e740_remove, }; module_platform_driver(e740_driver); diff --git a/sound/soc/pxa/e750_wm9705.c b/sound/soc/pxa/e750_wm9705.c index 47b89d71e287..f94d2ab51351 100644 --- a/sound/soc/pxa/e750_wm9705.c +++ b/sound/soc/pxa/e750_wm9705.c @@ -126,7 +126,7 @@ static struct gpio e750_audio_gpios[] = { { GPIO_E750_SPK_AMP_OFF, GPIOF_OUT_INIT_HIGH, "Speaker amp" }, }; -static int __devinit e750_probe(struct platform_device *pdev) +static int e750_probe(struct platform_device *pdev) { struct snd_soc_card *card = &e750; int ret; @@ -147,7 +147,7 @@ static int __devinit e750_probe(struct platform_device *pdev) return ret; } -static int __devexit e750_remove(struct platform_device *pdev) +static int e750_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); @@ -162,7 +162,7 @@ static struct platform_driver e750_driver = { .owner = THIS_MODULE, }, .probe = e750_probe, - .remove = __devexit_p(e750_remove), + .remove = e750_remove, }; module_platform_driver(e750_driver); diff --git a/sound/soc/pxa/e800_wm9712.c b/sound/soc/pxa/e800_wm9712.c index ea9707ec6f28..8768a640dd71 100644 --- a/sound/soc/pxa/e800_wm9712.c +++ b/sound/soc/pxa/e800_wm9712.c @@ -116,7 +116,7 @@ static struct gpio e800_audio_gpios[] = { { GPIO_E800_HP_AMP_OFF, GPIOF_OUT_INIT_HIGH, "Speaker amp" }, }; -static int __devinit e800_probe(struct platform_device *pdev) +static int e800_probe(struct platform_device *pdev) { struct snd_soc_card *card = &e800; int ret; @@ -137,7 +137,7 @@ static int __devinit e800_probe(struct platform_device *pdev) return ret; } -static int __devexit e800_remove(struct platform_device *pdev) +static int e800_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); @@ -152,7 +152,7 @@ static struct platform_driver e800_driver = { .owner = THIS_MODULE, }, .probe = e800_probe, - .remove = __devexit_p(e800_remove), + .remove = e800_remove, }; module_platform_driver(e800_driver); diff --git a/sound/soc/pxa/hx4700.c b/sound/soc/pxa/hx4700.c index 2a342c92d829..dcc9b04bd92c 100644 --- a/sound/soc/pxa/hx4700.c +++ b/sound/soc/pxa/hx4700.c @@ -183,7 +183,7 @@ static struct gpio hx4700_audio_gpios[] = { { GPIO92_HX4700_HP_DRIVER, GPIOF_OUT_INIT_LOW, "EP_POWER" }, }; -static int __devinit hx4700_audio_probe(struct platform_device *pdev) +static int hx4700_audio_probe(struct platform_device *pdev) { int ret; @@ -204,7 +204,7 @@ static int __devinit hx4700_audio_probe(struct platform_device *pdev) return ret; } -static int __devexit hx4700_audio_remove(struct platform_device *pdev) +static int hx4700_audio_remove(struct platform_device *pdev) { snd_soc_jack_free_gpios(&hs_jack, 1, &hs_jack_gpio); snd_soc_unregister_card(&snd_soc_card_hx4700); @@ -223,7 +223,7 @@ static struct platform_driver hx4700_audio_driver = { .pm = &snd_soc_pm_ops, }, .probe = hx4700_audio_probe, - .remove = __devexit_p(hx4700_audio_remove), + .remove = hx4700_audio_remove, }; module_platform_driver(hx4700_audio_driver); diff --git a/sound/soc/pxa/imote2.c b/sound/soc/pxa/imote2.c index b93dafd32b80..eef1f7b7b38e 100644 --- a/sound/soc/pxa/imote2.c +++ b/sound/soc/pxa/imote2.c @@ -65,7 +65,7 @@ static struct snd_soc_card imote2 = { .num_links = 1, }; -static int __devinit imote2_probe(struct platform_device *pdev) +static int imote2_probe(struct platform_device *pdev) { struct snd_soc_card *card = &imote2; int ret; @@ -79,7 +79,7 @@ static int __devinit imote2_probe(struct platform_device *pdev) return ret; } -static int __devexit imote2_remove(struct platform_device *pdev) +static int imote2_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); @@ -93,7 +93,7 @@ static struct platform_driver imote2_driver = { .owner = THIS_MODULE, }, .probe = imote2_probe, - .remove = __devexit_p(imote2_remove), + .remove = imote2_remove, }; module_platform_driver(imote2_driver); diff --git a/sound/soc/pxa/mioa701_wm9713.c b/sound/soc/pxa/mioa701_wm9713.c index 8687c1c65d29..97b711e12821 100644 --- a/sound/soc/pxa/mioa701_wm9713.c +++ b/sound/soc/pxa/mioa701_wm9713.c @@ -186,7 +186,7 @@ static struct snd_soc_card mioa701 = { .num_links = ARRAY_SIZE(mioa701_dai), }; -static int __devinit mioa701_wm9713_probe(struct platform_device *pdev) +static int mioa701_wm9713_probe(struct platform_device *pdev) { int rc; @@ -202,7 +202,7 @@ static int __devinit mioa701_wm9713_probe(struct platform_device *pdev) return rc; } -static int __devexit mioa701_wm9713_remove(struct platform_device *pdev) +static int mioa701_wm9713_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); @@ -212,7 +212,7 @@ static int __devexit mioa701_wm9713_remove(struct platform_device *pdev) static struct platform_driver mioa701_wm9713_driver = { .probe = mioa701_wm9713_probe, - .remove = __devexit_p(mioa701_wm9713_remove), + .remove = mioa701_wm9713_remove, .driver = { .name = "mioa701-wm9713", .owner = THIS_MODULE, diff --git a/sound/soc/pxa/mmp-pcm.c b/sound/soc/pxa/mmp-pcm.c index e834faf859fd..190eb0bccf5f 100644 --- a/sound/soc/pxa/mmp-pcm.c +++ b/sound/soc/pxa/mmp-pcm.c @@ -257,7 +257,7 @@ struct snd_soc_platform_driver mmp_soc_platform = { .pcm_free = mmp_pcm_free_dma_buffers, }; -static __devinit int mmp_pcm_probe(struct platform_device *pdev) +static int mmp_pcm_probe(struct platform_device *pdev) { struct mmp_audio_platdata *pdata = pdev->dev.platform_data; @@ -274,7 +274,7 @@ static __devinit int mmp_pcm_probe(struct platform_device *pdev) return snd_soc_register_platform(&pdev->dev, &mmp_soc_platform); } -static int __devexit mmp_pcm_remove(struct platform_device *pdev) +static int mmp_pcm_remove(struct platform_device *pdev) { snd_soc_unregister_platform(&pdev->dev); return 0; @@ -287,7 +287,7 @@ static struct platform_driver mmp_pcm_driver = { }, .probe = mmp_pcm_probe, - .remove = __devexit_p(mmp_pcm_remove), + .remove = mmp_pcm_remove, }; module_platform_driver(mmp_pcm_driver); diff --git a/sound/soc/pxa/mmp-sspa.c b/sound/soc/pxa/mmp-sspa.c index 4d6cb8a30fc8..41c3a09b53ea 100644 --- a/sound/soc/pxa/mmp-sspa.c +++ b/sound/soc/pxa/mmp-sspa.c @@ -405,7 +405,7 @@ struct snd_soc_dai_driver mmp_sspa_dai = { .ops = &mmp_sspa_dai_ops, }; -static __devinit int asoc_mmp_sspa_probe(struct platform_device *pdev) +static int asoc_mmp_sspa_probe(struct platform_device *pdev) { struct sspa_priv *priv; struct resource *res; @@ -453,7 +453,7 @@ static __devinit int asoc_mmp_sspa_probe(struct platform_device *pdev) return snd_soc_register_dai(&pdev->dev, &mmp_sspa_dai); } -static int __devexit asoc_mmp_sspa_remove(struct platform_device *pdev) +static int asoc_mmp_sspa_remove(struct platform_device *pdev) { struct sspa_priv *priv = platform_get_drvdata(pdev); @@ -470,7 +470,7 @@ static struct platform_driver asoc_mmp_sspa_driver = { .owner = THIS_MODULE, }, .probe = asoc_mmp_sspa_probe, - .remove = __devexit_p(asoc_mmp_sspa_remove), + .remove = asoc_mmp_sspa_remove, }; module_platform_driver(asoc_mmp_sspa_driver); diff --git a/sound/soc/pxa/palm27x.c b/sound/soc/pxa/palm27x.c index aa3da91907c6..2074e2daf9c6 100644 --- a/sound/soc/pxa/palm27x.c +++ b/sound/soc/pxa/palm27x.c @@ -187,7 +187,7 @@ put_device: return ret; } -static int __devexit palm27x_asoc_remove(struct platform_device *pdev) +static int palm27x_asoc_remove(struct platform_device *pdev) { platform_device_unregister(palm27x_snd_device); return 0; @@ -195,7 +195,7 @@ static int __devexit palm27x_asoc_remove(struct platform_device *pdev) static struct platform_driver palm27x_wm9712_driver = { .probe = palm27x_asoc_probe, - .remove = __devexit_p(palm27x_asoc_remove), + .remove = palm27x_asoc_remove, .driver = { .name = "palm27x-asoc", .owner = THIS_MODULE, diff --git a/sound/soc/pxa/poodle.c b/sound/soc/pxa/poodle.c index d2cc81735036..fafe46355c31 100644 --- a/sound/soc/pxa/poodle.c +++ b/sound/soc/pxa/poodle.c @@ -269,7 +269,7 @@ static struct snd_soc_card poodle = { .num_dapm_routes = ARRAY_SIZE(poodle_audio_map), }; -static int __devinit poodle_probe(struct platform_device *pdev) +static int poodle_probe(struct platform_device *pdev) { struct snd_soc_card *card = &poodle; int ret; @@ -291,7 +291,7 @@ static int __devinit poodle_probe(struct platform_device *pdev) return ret; } -static int __devexit poodle_remove(struct platform_device *pdev) +static int poodle_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); @@ -305,7 +305,7 @@ static struct platform_driver poodle_driver = { .owner = THIS_MODULE, }, .probe = poodle_probe, - .remove = __devexit_p(poodle_remove), + .remove = poodle_remove, }; module_platform_driver(poodle_driver); diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c index 4da5fc55c7ee..d3eb0c2eec77 100644 --- a/sound/soc/pxa/pxa-ssp.c +++ b/sound/soc/pxa/pxa-ssp.c @@ -794,12 +794,12 @@ static struct snd_soc_dai_driver pxa_ssp_dai = { .ops = &pxa_ssp_dai_ops, }; -static __devinit int asoc_ssp_probe(struct platform_device *pdev) +static int asoc_ssp_probe(struct platform_device *pdev) { return snd_soc_register_dai(&pdev->dev, &pxa_ssp_dai); } -static int __devexit asoc_ssp_remove(struct platform_device *pdev) +static int asoc_ssp_remove(struct platform_device *pdev) { snd_soc_unregister_dai(&pdev->dev); return 0; @@ -812,7 +812,7 @@ static struct platform_driver asoc_ssp_driver = { }, .probe = asoc_ssp_probe, - .remove = __devexit_p(asoc_ssp_remove), + .remove = asoc_ssp_remove, }; module_platform_driver(asoc_ssp_driver); diff --git a/sound/soc/pxa/pxa2xx-ac97.c b/sound/soc/pxa/pxa2xx-ac97.c index 06ea2744cc88..4b0a009bd683 100644 --- a/sound/soc/pxa/pxa2xx-ac97.c +++ b/sound/soc/pxa/pxa2xx-ac97.c @@ -104,7 +104,7 @@ static int pxa2xx_ac97_resume(struct snd_soc_dai *dai) #define pxa2xx_ac97_resume NULL #endif -static int __devinit pxa2xx_ac97_probe(struct snd_soc_dai *dai) +static int pxa2xx_ac97_probe(struct snd_soc_dai *dai) { return pxa2xx_ac97_hw_probe(to_platform_device(dai->dev)); } @@ -234,7 +234,7 @@ static struct snd_soc_dai_driver pxa_ac97_dai_driver[] = { EXPORT_SYMBOL_GPL(soc_ac97_ops); -static __devinit int pxa2xx_ac97_dev_probe(struct platform_device *pdev) +static int pxa2xx_ac97_dev_probe(struct platform_device *pdev) { if (pdev->id != -1) { dev_err(&pdev->dev, "PXA2xx has only one AC97 port.\n"); @@ -249,7 +249,7 @@ static __devinit int pxa2xx_ac97_dev_probe(struct platform_device *pdev) ARRAY_SIZE(pxa_ac97_dai_driver)); } -static int __devexit pxa2xx_ac97_dev_remove(struct platform_device *pdev) +static int pxa2xx_ac97_dev_remove(struct platform_device *pdev) { snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(pxa_ac97_dai_driver)); return 0; @@ -257,7 +257,7 @@ static int __devexit pxa2xx_ac97_dev_remove(struct platform_device *pdev) static struct platform_driver pxa2xx_ac97_driver = { .probe = pxa2xx_ac97_dev_probe, - .remove = __devexit_p(pxa2xx_ac97_dev_remove), + .remove = pxa2xx_ac97_dev_remove, .driver = { .name = "pxa2xx-ac97", .owner = THIS_MODULE, diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c index 3075a426124c..6b1a06f67564 100644 --- a/sound/soc/pxa/pxa2xx-i2s.c +++ b/sound/soc/pxa/pxa2xx-i2s.c @@ -365,7 +365,7 @@ static int pxa2xx_i2s_drv_probe(struct platform_device *pdev) return snd_soc_register_dai(&pdev->dev, &pxa_i2s_dai); } -static int __devexit pxa2xx_i2s_drv_remove(struct platform_device *pdev) +static int pxa2xx_i2s_drv_remove(struct platform_device *pdev) { snd_soc_unregister_dai(&pdev->dev); return 0; @@ -373,7 +373,7 @@ static int __devexit pxa2xx_i2s_drv_remove(struct platform_device *pdev) static struct platform_driver pxa2xx_i2s_driver = { .probe = pxa2xx_i2s_drv_probe, - .remove = __devexit_p(pxa2xx_i2s_drv_remove), + .remove = pxa2xx_i2s_drv_remove, .driver = { .name = "pxa2xx-i2s", diff --git a/sound/soc/pxa/pxa2xx-pcm.c b/sound/soc/pxa/pxa2xx-pcm.c index fdd6bedef9bd..ecff116cb7b0 100644 --- a/sound/soc/pxa/pxa2xx-pcm.c +++ b/sound/soc/pxa/pxa2xx-pcm.c @@ -120,12 +120,12 @@ static struct snd_soc_platform_driver pxa2xx_soc_platform = { .pcm_free = pxa2xx_pcm_free_dma_buffers, }; -static int __devinit pxa2xx_soc_platform_probe(struct platform_device *pdev) +static int pxa2xx_soc_platform_probe(struct platform_device *pdev) { return snd_soc_register_platform(&pdev->dev, &pxa2xx_soc_platform); } -static int __devexit pxa2xx_soc_platform_remove(struct platform_device *pdev) +static int pxa2xx_soc_platform_remove(struct platform_device *pdev) { snd_soc_unregister_platform(&pdev->dev); return 0; @@ -138,7 +138,7 @@ static struct platform_driver pxa_pcm_driver = { }, .probe = pxa2xx_soc_platform_probe, - .remove = __devexit_p(pxa2xx_soc_platform_remove), + .remove = pxa2xx_soc_platform_remove, }; module_platform_driver(pxa_pcm_driver); diff --git a/sound/soc/pxa/tosa.c b/sound/soc/pxa/tosa.c index 2aec63f3706a..a3fe19123f07 100644 --- a/sound/soc/pxa/tosa.c +++ b/sound/soc/pxa/tosa.c @@ -241,7 +241,7 @@ static struct snd_soc_card tosa = { .num_links = ARRAY_SIZE(tosa_dai), }; -static int __devinit tosa_probe(struct platform_device *pdev) +static int tosa_probe(struct platform_device *pdev) { struct snd_soc_card *card = ⤩ int ret; @@ -262,7 +262,7 @@ static int __devinit tosa_probe(struct platform_device *pdev) return ret; } -static int __devexit tosa_remove(struct platform_device *pdev) +static int tosa_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); @@ -277,7 +277,7 @@ static struct platform_driver tosa_driver = { .owner = THIS_MODULE, }, .probe = tosa_probe, - .remove = __devexit_p(tosa_remove), + .remove = tosa_remove, }; module_platform_driver(tosa_driver); diff --git a/sound/soc/pxa/ttc-dkb.c b/sound/soc/pxa/ttc-dkb.c index 935491a8a770..f4ea4f6663a2 100644 --- a/sound/soc/pxa/ttc-dkb.c +++ b/sound/soc/pxa/ttc-dkb.c @@ -131,7 +131,7 @@ static struct snd_soc_card ttc_dkb_card = { .num_dapm_routes = ARRAY_SIZE(ttc_audio_map), }; -static int __devinit ttc_dkb_probe(struct platform_device *pdev) +static int ttc_dkb_probe(struct platform_device *pdev) { struct snd_soc_card *card = &ttc_dkb_card; int ret; @@ -146,7 +146,7 @@ static int __devinit ttc_dkb_probe(struct platform_device *pdev) return ret; } -static int __devexit ttc_dkb_remove(struct platform_device *pdev) +static int ttc_dkb_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); @@ -161,7 +161,7 @@ static struct platform_driver ttc_dkb_driver = { .owner = THIS_MODULE, }, .probe = ttc_dkb_probe, - .remove = __devexit_p(ttc_dkb_remove), + .remove = ttc_dkb_remove, }; module_platform_driver(ttc_dkb_driver); diff --git a/sound/soc/s6000/s6000-i2s.c b/sound/soc/s6000/s6000-i2s.c index aaabdbaec19c..fee4d477a49c 100644 --- a/sound/soc/s6000/s6000-i2s.c +++ b/sound/soc/s6000/s6000-i2s.c @@ -436,7 +436,7 @@ static struct snd_soc_dai_driver s6000_i2s_dai = { .ops = &s6000_i2s_dai_ops, }; -static int __devinit s6000_i2s_probe(struct platform_device *pdev) +static int s6000_i2s_probe(struct platform_device *pdev) { struct s6000_i2s_dev *dev; struct resource *scbmem, *sifmem, *region, *dma1, *dma2; @@ -566,7 +566,7 @@ err_release_none: return ret; } -static void __devexit s6000_i2s_remove(struct platform_device *pdev) +static void s6000_i2s_remove(struct platform_device *pdev) { struct s6000_i2s_dev *dev = dev_get_drvdata(&pdev->dev); struct resource *region; @@ -597,7 +597,7 @@ static void __devexit s6000_i2s_remove(struct platform_device *pdev) static struct platform_driver s6000_i2s_driver = { .probe = s6000_i2s_probe, - .remove = __devexit_p(s6000_i2s_remove), + .remove = s6000_i2s_remove, .driver = { .name = "s6000-i2s", .owner = THIS_MODULE, diff --git a/sound/soc/s6000/s6000-pcm.c b/sound/soc/s6000/s6000-pcm.c index 716da861c629..1358c7de2521 100644 --- a/sound/soc/s6000/s6000-pcm.c +++ b/sound/soc/s6000/s6000-pcm.c @@ -500,12 +500,12 @@ static struct snd_soc_platform_driver s6000_soc_platform = { .pcm_free = s6000_pcm_free, }; -static int __devinit s6000_soc_platform_probe(struct platform_device *pdev) +static int s6000_soc_platform_probe(struct platform_device *pdev) { return snd_soc_register_platform(&pdev->dev, &s6000_soc_platform); } -static int __devexit s6000_soc_platform_remove(struct platform_device *pdev) +static int s6000_soc_platform_remove(struct platform_device *pdev) { snd_soc_unregister_platform(&pdev->dev); return 0; @@ -518,7 +518,7 @@ static struct platform_driver s6000_pcm_driver = { }, .probe = s6000_soc_platform_probe, - .remove = __devexit_p(s6000_soc_platform_remove), + .remove = s6000_soc_platform_remove, }; module_platform_driver(s6000_pcm_driver); diff --git a/sound/soc/samsung/ac97.c b/sound/soc/samsung/ac97.c index 14fbcd30cae5..0df3c5644cfa 100644 --- a/sound/soc/samsung/ac97.c +++ b/sound/soc/samsung/ac97.c @@ -370,7 +370,7 @@ static struct snd_soc_dai_driver s3c_ac97_dai[] = { }, }; -static __devinit int s3c_ac97_probe(struct platform_device *pdev) +static int s3c_ac97_probe(struct platform_device *pdev) { struct resource *mem_res, *dmatx_res, *dmarx_res, *dmamic_res, *irq_res; struct s3c_audio_pdata *ac97_pdata; @@ -442,7 +442,7 @@ static __devinit int s3c_ac97_probe(struct platform_device *pdev) ret = -ENODEV; goto err2; } - clk_enable(s3c_ac97.ac97_clk); + clk_prepare_enable(s3c_ac97.ac97_clk); if (ac97_pdata->cfg_gpio(pdev)) { dev_err(&pdev->dev, "Unable to configure gpio\n"); @@ -462,13 +462,20 @@ static __devinit int s3c_ac97_probe(struct platform_device *pdev) if (ret) goto err5; - return 0; + ret = asoc_dma_platform_register(&pdev->dev); + if (ret) { + dev_err(&pdev->dev, "failed to get register DMA: %d\n", ret); + goto err6; + } + return 0; +err6: + snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(s3c_ac97_dai)); err5: free_irq(irq_res->start, NULL); err4: err3: - clk_disable(s3c_ac97.ac97_clk); + clk_disable_unprepare(s3c_ac97.ac97_clk); clk_put(s3c_ac97.ac97_clk); err2: iounmap(s3c_ac97.regs); @@ -478,17 +485,18 @@ err1: return ret; } -static __devexit int s3c_ac97_remove(struct platform_device *pdev) +static int s3c_ac97_remove(struct platform_device *pdev) { struct resource *mem_res, *irq_res; + asoc_dma_platform_unregister(&pdev->dev); snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(s3c_ac97_dai)); irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (irq_res) free_irq(irq_res->start, NULL); - clk_disable(s3c_ac97.ac97_clk); + clk_disable_unprepare(s3c_ac97.ac97_clk); clk_put(s3c_ac97.ac97_clk); iounmap(s3c_ac97.regs); @@ -502,7 +510,7 @@ static __devexit int s3c_ac97_remove(struct platform_device *pdev) static struct platform_driver s3c_ac97_driver = { .probe = s3c_ac97_probe, - .remove = __devexit_p(s3c_ac97_remove), + .remove = s3c_ac97_remove, .driver = { .name = "samsung-ac97", .owner = THIS_MODULE, diff --git a/sound/soc/samsung/bells.c b/sound/soc/samsung/bells.c index b56b9a3c6169..ceed466af9ff 100644 --- a/sound/soc/samsung/bells.c +++ b/sound/soc/samsung/bells.c @@ -18,15 +18,6 @@ #include "../codecs/wm5102.h" #include "../codecs/wm9081.h" -/* - * 44.1kHz based clocks for the SYSCLK domain, use a very high clock - * to allow all the DSP functionality to be enabled if desired. - */ -#define SYSCLK_RATE (44100 * 1024) - -/* 48kHz based clocks for the ASYNC domain */ -#define ASYNCCLK_RATE (48000 * 512) - /* BCLK2 is fixed at this currently */ #define BCLK2_RATE (64 * 8000) @@ -36,15 +27,40 @@ */ #define MCLK_RATE 24576000 -#define WM9081_AUDIO_RATE 44100 -#define WM9081_MCLK_RATE (WM9081_AUDIO_RATE * 256) +#define SYS_AUDIO_RATE 44100 +#define SYS_MCLK_RATE (SYS_AUDIO_RATE * 512) + +#define DAI_AP_DSP 0 +#define DAI_DSP_CODEC 1 +#define DAI_CODEC_CP 2 +#define DAI_CODEC_SUB 3 + +struct bells_drvdata { + int sysclk_rate; + int asyncclk_rate; +}; + +static struct bells_drvdata wm2200_drvdata = { + .sysclk_rate = 22579200, +}; + +static struct bells_drvdata wm5102_drvdata = { + .sysclk_rate = 45158400, + .asyncclk_rate = 49152000, +}; + +static struct bells_drvdata wm5110_drvdata = { + .sysclk_rate = 135475200, + .asyncclk_rate = 147456000, +}; static int bells_set_bias_level(struct snd_soc_card *card, struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level) { - struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai; + struct snd_soc_dai *codec_dai = card->rtd[DAI_DSP_CODEC].codec_dai; struct snd_soc_codec *codec = codec_dai->codec; + struct bells_drvdata *bells = card->drvdata; int ret; if (dapm->dev != codec_dai->dev) @@ -52,18 +68,21 @@ static int bells_set_bias_level(struct snd_soc_card *card, switch (level) { case SND_SOC_BIAS_PREPARE: - if (dapm->bias_level == SND_SOC_BIAS_STANDBY) { - ret = snd_soc_codec_set_pll(codec, WM5102_FLL1, - ARIZONA_FLL_SRC_MCLK1, - MCLK_RATE, - SYSCLK_RATE); - if (ret < 0) - pr_err("Failed to start FLL: %d\n", ret); + if (dapm->bias_level != SND_SOC_BIAS_STANDBY) + break; + + ret = snd_soc_codec_set_pll(codec, WM5102_FLL1, + ARIZONA_FLL_SRC_MCLK1, + MCLK_RATE, + bells->sysclk_rate); + if (ret < 0) + pr_err("Failed to start FLL: %d\n", ret); + if (bells->asyncclk_rate) { ret = snd_soc_codec_set_pll(codec, WM5102_FLL2, ARIZONA_FLL_SRC_AIF2BCLK, BCLK2_RATE, - ASYNCCLK_RATE); + bells->asyncclk_rate); if (ret < 0) pr_err("Failed to start FLL: %d\n", ret); } @@ -80,8 +99,9 @@ static int bells_set_bias_level_post(struct snd_soc_card *card, struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level) { - struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai; + struct snd_soc_dai *codec_dai = card->rtd[DAI_DSP_CODEC].codec_dai; struct snd_soc_codec *codec = codec_dai->codec; + struct bells_drvdata *bells = card->drvdata; int ret; if (dapm->dev != codec_dai->dev) @@ -95,10 +115,13 @@ static int bells_set_bias_level_post(struct snd_soc_card *card, return ret; } - ret = snd_soc_codec_set_pll(codec, WM5102_FLL2, 0, 0, 0); - if (ret < 0) { - pr_err("Failed to stop FLL: %d\n", ret); - return ret; + if (bells->asyncclk_rate) { + ret = snd_soc_codec_set_pll(codec, WM5102_FLL2, + 0, 0, 0); + if (ret < 0) { + pr_err("Failed to stop FLL: %d\n", ret); + return ret; + } } break; @@ -113,56 +136,73 @@ static int bells_set_bias_level_post(struct snd_soc_card *card, static int bells_late_probe(struct snd_soc_card *card) { - struct snd_soc_codec *codec = card->rtd[0].codec; - struct snd_soc_dai *aif1_dai = card->rtd[0].codec_dai; - struct snd_soc_dai *aif2_dai = card->rtd[1].cpu_dai; - struct snd_soc_dai *aif3_dai = card->rtd[2].cpu_dai; - struct snd_soc_dai *wm9081_dai = card->rtd[2].codec_dai; + struct bells_drvdata *bells = card->drvdata; + struct snd_soc_codec *wm0010 = card->rtd[DAI_AP_DSP].codec; + struct snd_soc_codec *codec = card->rtd[DAI_DSP_CODEC].codec; + struct snd_soc_dai *aif1_dai = card->rtd[DAI_DSP_CODEC].codec_dai; + struct snd_soc_dai *aif2_dai; + struct snd_soc_dai *aif3_dai; + struct snd_soc_dai *wm9081_dai; int ret; - ret = snd_soc_dai_set_sysclk(aif1_dai, ARIZONA_CLK_SYSCLK, 0, 0); + ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_SYSCLK, + ARIZONA_CLK_SRC_FLL1, + bells->sysclk_rate, + SND_SOC_CLOCK_IN); if (ret != 0) { - dev_err(aif1_dai->dev, "Failed to set AIF1 clock: %d\n", ret); + dev_err(codec->dev, "Failed to set SYSCLK: %d\n", ret); return ret; } - ret = snd_soc_dai_set_sysclk(aif2_dai, ARIZONA_CLK_ASYNCCLK, 0, 0); + ret = snd_soc_codec_set_sysclk(wm0010, 0, 0, SYS_MCLK_RATE, 0); if (ret != 0) { - dev_err(aif2_dai->dev, "Failed to set AIF2 clock: %d\n", ret); + dev_err(wm0010->dev, "Failed to set WM0010 clock: %d\n", ret); return ret; } - ret = snd_soc_dai_set_sysclk(aif3_dai, ARIZONA_CLK_SYSCLK, 0, 0); - if (ret != 0) { + ret = snd_soc_dai_set_sysclk(aif1_dai, ARIZONA_CLK_SYSCLK, 0, 0); + if (ret != 0) dev_err(aif1_dai->dev, "Failed to set AIF1 clock: %d\n", ret); - return ret; - } - ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_SYSCLK, - ARIZONA_CLK_SRC_FLL1, SYSCLK_RATE, + ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_OPCLK, 0, + SYS_MCLK_RATE, SND_SOC_CLOCK_OUT); + if (ret != 0) + dev_err(codec->dev, "Failed to set OPCLK: %d\n", ret); + + if (card->num_rtd == DAI_CODEC_CP) + return 0; + + ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_ASYNCCLK, + ARIZONA_CLK_SRC_FLL2, + bells->asyncclk_rate, SND_SOC_CLOCK_IN); if (ret != 0) { - dev_err(codec->dev, "Failed to set SYSCLK: %d\n", ret); + dev_err(codec->dev, "Failed to set ASYNCCLK: %d\n", ret); return ret; } - ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_OPCLK, 0, - WM9081_MCLK_RATE, SND_SOC_CLOCK_OUT); + aif2_dai = card->rtd[DAI_CODEC_CP].cpu_dai; + + ret = snd_soc_dai_set_sysclk(aif2_dai, ARIZONA_CLK_ASYNCCLK, 0, 0); if (ret != 0) { - dev_err(codec->dev, "Failed to set OPCLK: %d\n", ret); + dev_err(aif2_dai->dev, "Failed to set AIF2 clock: %d\n", ret); return ret; } - ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_ASYNCCLK, - ARIZONA_CLK_SRC_FLL2, ASYNCCLK_RATE, - SND_SOC_CLOCK_IN); + if (card->num_rtd == DAI_CODEC_SUB) + return 0; + + aif3_dai = card->rtd[DAI_CODEC_SUB].cpu_dai; + wm9081_dai = card->rtd[DAI_CODEC_SUB].codec_dai; + + ret = snd_soc_dai_set_sysclk(aif3_dai, ARIZONA_CLK_SYSCLK, 0, 0); if (ret != 0) { - dev_err(codec->dev, "Failed to set SYSCLK: %d\n", ret); + dev_err(aif1_dai->dev, "Failed to set AIF1 clock: %d\n", ret); return ret; } ret = snd_soc_codec_set_sysclk(wm9081_dai->codec, WM9081_SYSCLK_MCLK, - 0, WM9081_MCLK_RATE, 0); + 0, SYS_MCLK_RATE, 0); if (ret != 0) { dev_err(wm9081_dai->dev, "Failed to set MCLK: %d\n", ret); return ret; @@ -181,22 +221,57 @@ static const struct snd_soc_pcm_stream baseband_params = { static const struct snd_soc_pcm_stream sub_params = { .formats = SNDRV_PCM_FMTBIT_S32_LE, - .rate_min = WM9081_AUDIO_RATE, - .rate_max = WM9081_AUDIO_RATE, + .rate_min = SYS_AUDIO_RATE, + .rate_max = SYS_AUDIO_RATE, .channels_min = 2, .channels_max = 2, }; +static struct snd_soc_dai_link bells_dai_wm2200[] = { + { + .name = "CPU-DSP", + .stream_name = "CPU-DSP", + .cpu_dai_name = "samsung-i2s.0", + .codec_dai_name = "wm0010-sdi1", + .platform_name = "samsung-i2s.0", + .codec_name = "spi0.0", + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF + | SND_SOC_DAIFMT_CBM_CFM, + }, + { + .name = "DSP-CODEC", + .stream_name = "DSP-CODEC", + .cpu_dai_name = "wm0010-sdi2", + .codec_dai_name = "wm2200", + .codec_name = "wm2200.1-003a", + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF + | SND_SOC_DAIFMT_CBM_CFM, + .params = &sub_params, + .ignore_suspend = 1, + }, +}; + static struct snd_soc_dai_link bells_dai_wm5102[] = { { - .name = "CPU", - .stream_name = "CPU", + .name = "CPU-DSP", + .stream_name = "CPU-DSP", .cpu_dai_name = "samsung-i2s.0", + .codec_dai_name = "wm0010-sdi1", + .platform_name = "samsung-i2s.0", + .codec_name = "spi0.0", + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF + | SND_SOC_DAIFMT_CBM_CFM, + }, + { + .name = "DSP-CODEC", + .stream_name = "DSP-CODEC", + .cpu_dai_name = "wm0010-sdi2", .codec_dai_name = "wm5102-aif1", - .platform_name = "samsung-audio", .codec_name = "wm5102-codec", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM, + .params = &sub_params, + .ignore_suspend = 1, }, { .name = "Baseband", @@ -212,7 +287,7 @@ static struct snd_soc_dai_link bells_dai_wm5102[] = { { .name = "Sub", .stream_name = "Sub", - .cpu_dai_name = "wm5110-aif3", + .cpu_dai_name = "wm5102-aif3", .codec_dai_name = "wm9081-hifi", .codec_name = "wm9081.1-006c", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF @@ -224,14 +299,25 @@ static struct snd_soc_dai_link bells_dai_wm5102[] = { static struct snd_soc_dai_link bells_dai_wm5110[] = { { - .name = "CPU", - .stream_name = "CPU", + .name = "CPU-DSP", + .stream_name = "CPU-DSP", .cpu_dai_name = "samsung-i2s.0", + .codec_dai_name = "wm0010-sdi1", + .platform_name = "samsung-i2s.0", + .codec_name = "spi0.0", + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF + | SND_SOC_DAIFMT_CBM_CFM, + }, + { + .name = "DSP-CODEC", + .stream_name = "DSP-CODEC", + .cpu_dai_name = "wm0010-sdi2", .codec_dai_name = "wm5110-aif1", - .platform_name = "samsung-audio", .codec_name = "wm5110-codec", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM, + .params = &sub_params, + .ignore_suspend = 1, }, { .name = "Baseband", @@ -247,7 +333,7 @@ static struct snd_soc_dai_link bells_dai_wm5110[] = { { .name = "Sub", .stream_name = "Sub", - .cpu_dai_name = "wm5102-aif3", + .cpu_dai_name = "wm5110-aif3", .codec_dai_name = "wm9081-hifi", .codec_name = "wm9081.1-006c", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF @@ -270,6 +356,24 @@ static struct snd_soc_dapm_route bells_routes[] = { static struct snd_soc_card bells_cards[] = { { + .name = "Bells WM2200", + .owner = THIS_MODULE, + .dai_link = bells_dai_wm2200, + .num_links = ARRAY_SIZE(bells_dai_wm2200), + .codec_conf = bells_codec_conf, + .num_configs = ARRAY_SIZE(bells_codec_conf), + + .late_probe = bells_late_probe, + + .dapm_routes = bells_routes, + .num_dapm_routes = ARRAY_SIZE(bells_routes), + + .set_bias_level = bells_set_bias_level, + .set_bias_level_post = bells_set_bias_level_post, + + .drvdata = &wm2200_drvdata, + }, + { .name = "Bells WM5102", .owner = THIS_MODULE, .dai_link = bells_dai_wm5102, @@ -284,6 +388,8 @@ static struct snd_soc_card bells_cards[] = { .set_bias_level = bells_set_bias_level, .set_bias_level_post = bells_set_bias_level_post, + + .drvdata = &wm5102_drvdata, }, { .name = "Bells WM5110", @@ -300,11 +406,13 @@ static struct snd_soc_card bells_cards[] = { .set_bias_level = bells_set_bias_level, .set_bias_level_post = bells_set_bias_level_post, + + .drvdata = &wm5110_drvdata, }, }; -static __devinit int bells_probe(struct platform_device *pdev) +static int bells_probe(struct platform_device *pdev) { int ret; @@ -321,7 +429,7 @@ static __devinit int bells_probe(struct platform_device *pdev) return 0; } -static int __devexit bells_remove(struct platform_device *pdev) +static int bells_remove(struct platform_device *pdev) { snd_soc_unregister_card(&bells_cards[pdev->id]); @@ -335,7 +443,7 @@ static struct platform_driver bells_driver = { .pm = &snd_soc_pm_ops, }, .probe = bells_probe, - .remove = __devexit_p(bells_remove), + .remove = bells_remove, }; module_platform_driver(bells_driver); diff --git a/sound/soc/samsung/dma.c b/sound/soc/samsung/dma.c index b70964ea448c..db87628d7630 100644 --- a/sound/soc/samsung/dma.c +++ b/sound/soc/samsung/dma.c @@ -432,30 +432,18 @@ static struct snd_soc_platform_driver samsung_asoc_platform = { .pcm_free = dma_free_dma_buffers, }; -static int __devinit samsung_asoc_platform_probe(struct platform_device *pdev) +int asoc_dma_platform_register(struct device *dev) { - return snd_soc_register_platform(&pdev->dev, &samsung_asoc_platform); + return snd_soc_register_platform(dev, &samsung_asoc_platform); } +EXPORT_SYMBOL_GPL(asoc_dma_platform_register); -static int __devexit samsung_asoc_platform_remove(struct platform_device *pdev) +void asoc_dma_platform_unregister(struct device *dev) { - snd_soc_unregister_platform(&pdev->dev); - return 0; + snd_soc_unregister_platform(dev); } - -static struct platform_driver asoc_dma_driver = { - .driver = { - .name = "samsung-audio", - .owner = THIS_MODULE, - }, - - .probe = samsung_asoc_platform_probe, - .remove = __devexit_p(samsung_asoc_platform_remove), -}; - -module_platform_driver(asoc_dma_driver); +EXPORT_SYMBOL_GPL(asoc_dma_platform_unregister); MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>"); MODULE_DESCRIPTION("Samsung ASoC DMA Driver"); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:samsung-audio"); diff --git a/sound/soc/samsung/dma.h b/sound/soc/samsung/dma.h index 7d1ead77ef21..73d8c7c8a1e8 100644 --- a/sound/soc/samsung/dma.h +++ b/sound/soc/samsung/dma.h @@ -21,4 +21,7 @@ struct s3c_dma_params { struct samsung_dma_ops *ops; }; +int asoc_dma_platform_register(struct device *dev); +void asoc_dma_platform_unregister(struct device *dev); + #endif diff --git a/sound/soc/samsung/goni_wm8994.c b/sound/soc/samsung/goni_wm8994.c index c23c2ae91f58..d37ede58e0a8 100644 --- a/sound/soc/samsung/goni_wm8994.c +++ b/sound/soc/samsung/goni_wm8994.c @@ -228,7 +228,7 @@ static struct snd_soc_dai_link goni_dai[] = { .stream_name = "WM8994 HiFi", .cpu_dai_name = "samsung-i2s.0", .codec_dai_name = "wm8994-aif1", - .platform_name = "samsung-audio", + .platform_name = "samsung-i2s.0", .codec_name = "wm8994-codec.0-001a", .init = goni_wm8994_init, .ops = &goni_hifi_ops, diff --git a/sound/soc/samsung/h1940_uda1380.c b/sound/soc/samsung/h1940_uda1380.c index 6e3257717c54..3870e9678b5d 100644 --- a/sound/soc/samsung/h1940_uda1380.c +++ b/sound/soc/samsung/h1940_uda1380.c @@ -207,7 +207,7 @@ static struct snd_soc_dai_link h1940_uda1380_dai[] = { .cpu_dai_name = "s3c24xx-iis", .codec_dai_name = "uda1380-hifi", .init = h1940_uda1380_init, - .platform_name = "samsung-audio", + .platform_name = "s3c24xx-iis", .codec_name = "uda1380-codec.0-001a", .ops = &h1940_ops, }, diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index 40b00a13dcd1..d2d124f1dd1b 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -49,8 +49,6 @@ struct i2s_dai { struct clk *clk; /* Clock for generating I2S signals */ struct clk *op_clk; - /* Array of clock names for op_clk */ - const char **src_clk; /* Pointer to the Primary_Fifo if this is Sec_Fifo, NULL otherwise */ struct i2s_dai *pri_dai; /* Pointer to the Secondary_Fifo if it has one, NULL otherwise */ @@ -423,7 +421,7 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, if (i2s->op_clk) { if ((clk_id && !(mod & MOD_IMS_SYSMUX)) || (!clk_id && (mod & MOD_IMS_SYSMUX))) { - clk_disable(i2s->op_clk); + clk_disable_unprepare(i2s->op_clk); clk_put(i2s->op_clk); } else { i2s->rclk_srcrate = @@ -432,9 +430,13 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, } } - i2s->op_clk = clk_get(&i2s->pdev->dev, - i2s->src_clk[clk_id]); - clk_enable(i2s->op_clk); + if (clk_id) + i2s->op_clk = clk_get(&i2s->pdev->dev, + "i2s_opclk1"); + else + i2s->op_clk = clk_get(&i2s->pdev->dev, + "i2s_opclk0"); + clk_prepare_enable(i2s->op_clk); i2s->rclk_srcrate = clk_get_rate(i2s->op_clk); /* Over-ride the other's */ @@ -880,7 +882,7 @@ static int samsung_i2s_dai_probe(struct snd_soc_dai *dai) iounmap(i2s->addr); return -ENOENT; } - clk_enable(i2s->clk); + clk_prepare_enable(i2s->clk); if (other) { other->addr = i2s->addr; @@ -922,7 +924,7 @@ static int samsung_i2s_dai_remove(struct snd_soc_dai *dai) if (i2s->quirks & QUIRK_NEED_RSTCLR) writel(0, i2s->addr + I2SCON); - clk_disable(i2s->clk); + clk_disable_unprepare(i2s->clk); clk_put(i2s->clk); iounmap(i2s->addr); @@ -950,8 +952,7 @@ static const struct snd_soc_dai_ops samsung_i2s_dai_ops = { SNDRV_PCM_FMTBIT_S16_LE | \ SNDRV_PCM_FMTBIT_S24_LE) -static __devinit -struct i2s_dai *i2s_alloc_dai(struct platform_device *pdev, bool sec) +static struct i2s_dai *i2s_alloc_dai(struct platform_device *pdev, bool sec) { struct i2s_dai *i2s; @@ -992,7 +993,7 @@ struct i2s_dai *i2s_alloc_dai(struct platform_device *pdev, bool sec) return i2s; } -static __devinit int samsung_i2s_probe(struct platform_device *pdev) +static int samsung_i2s_probe(struct platform_device *pdev) { u32 dma_pl_chan, dma_cp_chan, dma_pl_sec_chan; struct i2s_dai *pri_dai, *sec_dai = NULL; @@ -1007,6 +1008,7 @@ static __devinit int samsung_i2s_probe(struct platform_device *pdev) sec_dai = dev_get_drvdata(&pdev->dev); snd_soc_register_dai(&sec_dai->pdev->dev, &sec_dai->i2s_dai_drv); + asoc_dma_platform_register(&pdev->dev); return 0; } @@ -1067,7 +1069,6 @@ static __devinit int samsung_i2s_probe(struct platform_device *pdev) (struct s3c2410_dma_client *)&pri_dai->dma_capture; pri_dai->dma_playback.channel = dma_pl_chan; pri_dai->dma_capture.channel = dma_cp_chan; - pri_dai->src_clk = i2s_cfg->src_clk; pri_dai->dma_playback.dma_size = 4; pri_dai->dma_capture.dma_size = 4; pri_dai->base = regs_base; @@ -1088,7 +1089,6 @@ static __devinit int samsung_i2s_probe(struct platform_device *pdev) (struct s3c2410_dma_client *)&sec_dai->dma_playback; /* Use iDMA always if SysDMA not provided */ sec_dai->dma_playback.channel = dma_pl_sec_chan ? : -1; - sec_dai->src_clk = i2s_cfg->src_clk; sec_dai->dma_playback.dma_size = 4; sec_dai->base = regs_base; sec_dai->quirks = quirks; @@ -1107,6 +1107,8 @@ static __devinit int samsung_i2s_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); + asoc_dma_platform_register(&pdev->dev); + return 0; err: release_mem_region(regs_base, resource_size(res)); @@ -1114,7 +1116,7 @@ err: return ret; } -static __devexit int samsung_i2s_remove(struct platform_device *pdev) +static int samsung_i2s_remove(struct platform_device *pdev) { struct i2s_dai *i2s, *other; struct resource *res; @@ -1135,6 +1137,7 @@ static __devexit int samsung_i2s_remove(struct platform_device *pdev) i2s->pri_dai = NULL; i2s->sec_dai = NULL; + asoc_dma_platform_unregister(&pdev->dev); snd_soc_unregister_dai(&pdev->dev); return 0; @@ -1142,7 +1145,7 @@ static __devexit int samsung_i2s_remove(struct platform_device *pdev) static struct platform_driver samsung_i2s_driver = { .probe = samsung_i2s_probe, - .remove = __devexit_p(samsung_i2s_remove), + .remove = samsung_i2s_remove, .driver = { .name = "samsung-i2s", .owner = THIS_MODULE, diff --git a/sound/soc/samsung/idma.c b/sound/soc/samsung/idma.c index c227c3163cae..a07950b0c8ce 100644 --- a/sound/soc/samsung/idma.c +++ b/sound/soc/samsung/idma.c @@ -416,12 +416,12 @@ static struct snd_soc_platform_driver asoc_idma_platform = { .pcm_free = idma_free, }; -static int __devinit asoc_idma_platform_probe(struct platform_device *pdev) +static int asoc_idma_platform_probe(struct platform_device *pdev) { return snd_soc_register_platform(&pdev->dev, &asoc_idma_platform); } -static int __devexit asoc_idma_platform_remove(struct platform_device *pdev) +static int asoc_idma_platform_remove(struct platform_device *pdev) { snd_soc_unregister_platform(&pdev->dev); return 0; @@ -434,7 +434,7 @@ static struct platform_driver asoc_idma_driver = { }, .probe = asoc_idma_platform_probe, - .remove = __devexit_p(asoc_idma_platform_remove), + .remove = asoc_idma_platform_remove, }; module_platform_driver(asoc_idma_driver); diff --git a/sound/soc/samsung/jive_wm8750.c b/sound/soc/samsung/jive_wm8750.c index 1578663a1faa..b5f6abd9d221 100644 --- a/sound/soc/samsung/jive_wm8750.c +++ b/sound/soc/samsung/jive_wm8750.c @@ -118,7 +118,7 @@ static struct snd_soc_dai_link jive_dai = { .stream_name = "WM8750", .cpu_dai_name = "s3c2412-i2s", .codec_dai_name = "wm8750-hifi", - .platform_name = "samsung-audio", + .platform_name = "s3c2412-i2s", .codec_name = "wm8750.0-001a", .init = jive_wm8750_init, .ops = &jive_ops, diff --git a/sound/soc/samsung/littlemill.c b/sound/soc/samsung/littlemill.c index ee52c8a00779..bfb91f34a22a 100644 --- a/sound/soc/samsung/littlemill.c +++ b/sound/soc/samsung/littlemill.c @@ -145,7 +145,7 @@ static struct snd_soc_dai_link littlemill_dai[] = { .stream_name = "CPU", .cpu_dai_name = "samsung-i2s.0", .codec_dai_name = "wm8994-aif1", - .platform_name = "samsung-audio", + .platform_name = "samsung-i2s.0", .codec_name = "wm8994-codec", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM, @@ -270,7 +270,7 @@ static int littlemill_late_probe(struct snd_soc_card *card) return ret; /* This will check device compatibility itself */ - wm8958_mic_detect(codec, &littlemill_headset, NULL, NULL); + wm8958_mic_detect(codec, &littlemill_headset, NULL, NULL, NULL, NULL); /* As will this */ wm8994_mic_detect(codec, &littlemill_headset, 1); @@ -297,7 +297,7 @@ static struct snd_soc_card littlemill = { .late_probe = littlemill_late_probe, }; -static __devinit int littlemill_probe(struct platform_device *pdev) +static int littlemill_probe(struct platform_device *pdev) { struct snd_soc_card *card = &littlemill; int ret; @@ -314,7 +314,7 @@ static __devinit int littlemill_probe(struct platform_device *pdev) return 0; } -static int __devexit littlemill_remove(struct platform_device *pdev) +static int littlemill_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); @@ -330,7 +330,7 @@ static struct platform_driver littlemill_driver = { .pm = &snd_soc_pm_ops, }, .probe = littlemill_probe, - .remove = __devexit_p(littlemill_remove), + .remove = littlemill_remove, }; module_platform_driver(littlemill_driver); diff --git a/sound/soc/samsung/ln2440sbc_alc650.c b/sound/soc/samsung/ln2440sbc_alc650.c index 69c4a5934a4d..9342fc270c2b 100644 --- a/sound/soc/samsung/ln2440sbc_alc650.c +++ b/sound/soc/samsung/ln2440sbc_alc650.c @@ -28,7 +28,7 @@ static struct snd_soc_dai_link ln2440sbc_dai[] = { .cpu_dai_name = "samsung-ac97", .codec_dai_name = "ac97-hifi", .codec_name = "ac97-codec", - .platform_name = "samsung-audio", + .platform_name = "samsung-ac97", }, }; diff --git a/sound/soc/samsung/lowland.c b/sound/soc/samsung/lowland.c index 6abf341c4a2a..570cf5229508 100644 --- a/sound/soc/samsung/lowland.c +++ b/sound/soc/samsung/lowland.c @@ -99,7 +99,7 @@ static struct snd_soc_dai_link lowland_dai[] = { .stream_name = "CPU", .cpu_dai_name = "samsung-i2s.0", .codec_dai_name = "wm5100-aif1", - .platform_name = "samsung-audio", + .platform_name = "samsung-i2s.0", .codec_name = "wm5100.1-001a", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM, @@ -180,7 +180,7 @@ static struct snd_soc_card lowland = { .num_dapm_routes = ARRAY_SIZE(audio_paths), }; -static __devinit int lowland_probe(struct platform_device *pdev) +static int lowland_probe(struct platform_device *pdev) { struct snd_soc_card *card = &lowland; int ret; @@ -197,7 +197,7 @@ static __devinit int lowland_probe(struct platform_device *pdev) return 0; } -static int __devexit lowland_remove(struct platform_device *pdev) +static int lowland_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); @@ -213,7 +213,7 @@ static struct platform_driver lowland_driver = { .pm = &snd_soc_pm_ops, }, .probe = lowland_probe, - .remove = __devexit_p(lowland_remove), + .remove = lowland_remove, }; module_platform_driver(lowland_driver); diff --git a/sound/soc/samsung/neo1973_wm8753.c b/sound/soc/samsung/neo1973_wm8753.c index 321d51134e47..c7e965f80d2e 100644 --- a/sound/soc/samsung/neo1973_wm8753.c +++ b/sound/soc/samsung/neo1973_wm8753.c @@ -364,7 +364,7 @@ static struct snd_soc_dai_link neo1973_dai[] = { { /* Hifi Playback - for similatious use with voice below */ .name = "WM8753", .stream_name = "WM8753 HiFi", - .platform_name = "samsung-audio", + .platform_name = "s3c24xx-iis", .cpu_dai_name = "s3c24xx-iis", .codec_dai_name = "wm8753-hifi", .codec_name = "wm8753.0-001a", diff --git a/sound/soc/samsung/pcm.c b/sound/soc/samsung/pcm.c index c86081992dfd..13bab79ad93d 100644 --- a/sound/soc/samsung/pcm.c +++ b/sound/soc/samsung/pcm.c @@ -490,7 +490,7 @@ static struct snd_soc_dai_driver s3c_pcm_dai[] = { }, }; -static __devinit int s3c_pcm_dev_probe(struct platform_device *pdev) +static int s3c_pcm_dev_probe(struct platform_device *pdev) { struct s3c_pcm_info *pcm; struct resource *mem_res, *dmatx_res, *dmarx_res; @@ -543,7 +543,7 @@ static __devinit int s3c_pcm_dev_probe(struct platform_device *pdev) ret = PTR_ERR(pcm->cclk); goto err1; } - clk_enable(pcm->cclk); + clk_prepare_enable(pcm->cclk); /* record our pcm structure for later use in the callbacks */ dev_set_drvdata(&pdev->dev, pcm); @@ -568,7 +568,7 @@ static __devinit int s3c_pcm_dev_probe(struct platform_device *pdev) ret = -ENOENT; goto err4; } - clk_enable(pcm->pclk); + clk_prepare_enable(pcm->pclk); s3c_pcm_stereo_in[pdev->id].dma_addr = mem_res->start + S3C_PCM_RXFIFO; @@ -589,27 +589,36 @@ static __devinit int s3c_pcm_dev_probe(struct platform_device *pdev) goto err5; } + ret = asoc_dma_platform_register(&pdev->dev); + if (ret) { + dev_err(&pdev->dev, "failed to get register DMA: %d\n", ret); + goto err6; + } + return 0; +err6: + snd_soc_unregister_dai(&pdev->dev); err5: - clk_disable(pcm->pclk); + clk_disable_unprepare(pcm->pclk); clk_put(pcm->pclk); err4: iounmap(pcm->regs); err3: release_mem_region(mem_res->start, resource_size(mem_res)); err2: - clk_disable(pcm->cclk); + clk_disable_unprepare(pcm->cclk); clk_put(pcm->cclk); err1: return ret; } -static __devexit int s3c_pcm_dev_remove(struct platform_device *pdev) +static int s3c_pcm_dev_remove(struct platform_device *pdev) { struct s3c_pcm_info *pcm = &s3c_pcm[pdev->id]; struct resource *mem_res; + asoc_dma_platform_unregister(&pdev->dev); snd_soc_unregister_dai(&pdev->dev); pm_runtime_disable(&pdev->dev); @@ -619,8 +628,8 @@ static __devexit int s3c_pcm_dev_remove(struct platform_device *pdev) mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); release_mem_region(mem_res->start, resource_size(mem_res)); - clk_disable(pcm->cclk); - clk_disable(pcm->pclk); + clk_disable_unprepare(pcm->cclk); + clk_disable_unprepare(pcm->pclk); clk_put(pcm->pclk); clk_put(pcm->cclk); @@ -629,7 +638,7 @@ static __devexit int s3c_pcm_dev_remove(struct platform_device *pdev) static struct platform_driver s3c_pcm_driver = { .probe = s3c_pcm_dev_probe, - .remove = __devexit_p(s3c_pcm_dev_remove), + .remove = s3c_pcm_dev_remove, .driver = { .name = "samsung-pcm", .owner = THIS_MODULE, diff --git a/sound/soc/samsung/rx1950_uda1380.c b/sound/soc/samsung/rx1950_uda1380.c index 21e12361a9cd..a5826ea9cad6 100644 --- a/sound/soc/samsung/rx1950_uda1380.c +++ b/sound/soc/samsung/rx1950_uda1380.c @@ -85,7 +85,7 @@ static struct snd_soc_dai_link rx1950_uda1380_dai[] = { .cpu_dai_name = "s3c24xx-iis", .codec_dai_name = "uda1380-hifi", .init = rx1950_uda1380_init, - .platform_name = "samsung-audio", + .platform_name = "s3c24xx-iis", .codec_name = "uda1380-codec.0-001a", .ops = &rx1950_ops, }, diff --git a/sound/soc/samsung/s3c2412-i2s.c b/sound/soc/samsung/s3c2412-i2s.c index ac7701b3c5dc..221337716393 100644 --- a/sound/soc/samsung/s3c2412-i2s.c +++ b/sound/soc/samsung/s3c2412-i2s.c @@ -160,20 +160,38 @@ static struct snd_soc_dai_driver s3c2412_i2s_dai = { .ops = &s3c2412_i2s_dai_ops, }; -static __devinit int s3c2412_iis_dev_probe(struct platform_device *pdev) +static int s3c2412_iis_dev_probe(struct platform_device *pdev) { - return s3c_i2sv2_register_dai(&pdev->dev, -1, &s3c2412_i2s_dai); + int ret = 0; + + ret = s3c_i2sv2_register_dai(&pdev->dev, -1, &s3c2412_i2s_dai); + if (ret) { + pr_err("failed to register the dai\n"); + return ret; + } + + ret = asoc_dma_platform_register(&pdev->dev); + if (ret) { + pr_err("failed to register the DMA: %d\n", ret); + goto err; + } + + return 0; +err: + snd_soc_unregister_dai(&pdev->dev); + return ret; } -static __devexit int s3c2412_iis_dev_remove(struct platform_device *pdev) +static int s3c2412_iis_dev_remove(struct platform_device *pdev) { + asoc_dma_platform_unregister(&pdev->dev); snd_soc_unregister_dai(&pdev->dev); return 0; } static struct platform_driver s3c2412_iis_driver = { .probe = s3c2412_iis_dev_probe, - .remove = __devexit_p(s3c2412_iis_dev_remove), + .remove = s3c2412_iis_dev_remove, .driver = { .name = "s3c2412-iis", .owner = THIS_MODULE, diff --git a/sound/soc/samsung/s3c24xx-i2s.c b/sound/soc/samsung/s3c24xx-i2s.c index 0aae3a3883dc..ee10e8704e97 100644 --- a/sound/soc/samsung/s3c24xx-i2s.c +++ b/sound/soc/samsung/s3c24xx-i2s.c @@ -465,20 +465,38 @@ static struct snd_soc_dai_driver s3c24xx_i2s_dai = { .ops = &s3c24xx_i2s_dai_ops, }; -static __devinit int s3c24xx_iis_dev_probe(struct platform_device *pdev) +static int s3c24xx_iis_dev_probe(struct platform_device *pdev) { - return snd_soc_register_dai(&pdev->dev, &s3c24xx_i2s_dai); + int ret = 0; + + ret = s3c_i2sv2_register_dai(&pdev->dev, -1, &s3c2412_i2s_dai); + if (ret) { + pr_err("failed to register the dai\n"); + return ret; + } + + ret = asoc_dma_platform_register(&pdev->dev); + if (ret) { + pr_err("failed to register the dma: %d\n", ret); + goto err; + } + + return 0; +err: + snd_soc_unregister_dai(&pdev->dev); + return ret; } -static __devexit int s3c24xx_iis_dev_remove(struct platform_device *pdev) +static int s3c24xx_iis_dev_remove(struct platform_device *pdev) { + asoc_dma_platform_unregister(&pdev->dev); snd_soc_unregister_dai(&pdev->dev); return 0; } static struct platform_driver s3c24xx_iis_driver = { .probe = s3c24xx_iis_dev_probe, - .remove = __devexit_p(s3c24xx_iis_dev_remove), + .remove = s3c24xx_iis_dev_remove, .driver = { .name = "s3c24xx-iis", .owner = THIS_MODULE, diff --git a/sound/soc/samsung/s3c24xx_simtec.c b/sound/soc/samsung/s3c24xx_simtec.c index 335a7d8a4a8d..2c015f62ead6 100644 --- a/sound/soc/samsung/s3c24xx_simtec.c +++ b/sound/soc/samsung/s3c24xx_simtec.c @@ -313,8 +313,8 @@ const struct dev_pm_ops simtec_audio_pmops = { EXPORT_SYMBOL_GPL(simtec_audio_pmops); #endif -int __devinit simtec_audio_core_probe(struct platform_device *pdev, - struct snd_soc_card *card) +int simtec_audio_core_probe(struct platform_device *pdev, + struct snd_soc_card *card) { struct platform_device *snd_dev; int ret; @@ -371,7 +371,7 @@ err_clk: } EXPORT_SYMBOL_GPL(simtec_audio_core_probe); -int __devexit simtec_audio_remove(struct platform_device *pdev) +int simtec_audio_remove(struct platform_device *pdev) { struct platform_device *snd_dev = platform_get_drvdata(pdev); diff --git a/sound/soc/samsung/s3c24xx_simtec_hermes.c b/sound/soc/samsung/s3c24xx_simtec_hermes.c index 7ace6a87f41b..d8a0543cae5e 100644 --- a/sound/soc/samsung/s3c24xx_simtec_hermes.c +++ b/sound/soc/samsung/s3c24xx_simtec_hermes.c @@ -82,7 +82,7 @@ static struct snd_soc_dai_link simtec_dai_aic33 = { .codec_name = "tlv320aic3x-codec.0-001a", .cpu_dai_name = "s3c24xx-iis", .codec_dai_name = "tlv320aic3x-hifi", - .platform_name = "samsung-audio", + .platform_name = "s3c24xx-iis", .init = simtec_hermes_init, }; @@ -99,7 +99,7 @@ static struct snd_soc_card snd_soc_machine_simtec_aic33 = { .num_dapm_routes = ARRAY_SIZE(base_map), }; -static int __devinit simtec_audio_hermes_probe(struct platform_device *pd) +static int simtec_audio_hermes_probe(struct platform_device *pd) { dev_info(&pd->dev, "probing....\n"); return simtec_audio_core_probe(pd, &snd_soc_machine_simtec_aic33); @@ -112,7 +112,7 @@ static struct platform_driver simtec_audio_hermes_platdrv = { .pm = simtec_audio_pm, }, .probe = simtec_audio_hermes_probe, - .remove = __devexit_p(simtec_audio_remove), + .remove = simtec_audio_remove, }; module_platform_driver(simtec_audio_hermes_platdrv); diff --git a/sound/soc/samsung/s3c24xx_simtec_tlv320aic23.c b/sound/soc/samsung/s3c24xx_simtec_tlv320aic23.c index c42d5f00b0e1..1ac0d7a63a3a 100644 --- a/sound/soc/samsung/s3c24xx_simtec_tlv320aic23.c +++ b/sound/soc/samsung/s3c24xx_simtec_tlv320aic23.c @@ -71,7 +71,7 @@ static struct snd_soc_dai_link simtec_dai_aic23 = { .codec_name = "tlv320aic3x-codec.0-001a", .cpu_dai_name = "s3c24xx-iis", .codec_dai_name = "tlv320aic3x-hifi", - .platform_name = "samsung-audio", + .platform_name = "s3c24xx-iis", .init = simtec_tlv320aic23_init, }; @@ -88,7 +88,7 @@ static struct snd_soc_card snd_soc_machine_simtec_aic23 = { .num_dapm_routes = ARRAY_SIZE(base_map), }; -static int __devinit simtec_audio_tlv320aic23_probe(struct platform_device *pd) +static int simtec_audio_tlv320aic23_probe(struct platform_device *pd) { return simtec_audio_core_probe(pd, &snd_soc_machine_simtec_aic23); } @@ -100,7 +100,7 @@ static struct platform_driver simtec_audio_tlv320aic23_driver = { .pm = simtec_audio_pm, }, .probe = simtec_audio_tlv320aic23_probe, - .remove = __devexit_p(simtec_audio_remove), + .remove = simtec_audio_remove, }; module_platform_driver(simtec_audio_tlv320aic23_driver); diff --git a/sound/soc/samsung/s3c24xx_uda134x.c b/sound/soc/samsung/s3c24xx_uda134x.c index d731042e51b0..333e1b7f06c7 100644 --- a/sound/soc/samsung/s3c24xx_uda134x.c +++ b/sound/soc/samsung/s3c24xx_uda134x.c @@ -224,7 +224,7 @@ static struct snd_soc_dai_link s3c24xx_uda134x_dai_link = { .codec_dai_name = "uda134x-hifi", .cpu_dai_name = "s3c24xx-iis", .ops = &s3c24xx_uda134x_ops, - .platform_name = "samsung-audio", + .platform_name = "s3c24xx-iis", }; static struct snd_soc_card snd_soc_s3c24xx_uda134x = { diff --git a/sound/soc/samsung/smartq_wm8987.c b/sound/soc/samsung/smartq_wm8987.c index f2dcb424ea25..58ae3237ef69 100644 --- a/sound/soc/samsung/smartq_wm8987.c +++ b/sound/soc/samsung/smartq_wm8987.c @@ -189,7 +189,7 @@ static struct snd_soc_dai_link smartq_dai[] = { .stream_name = "SmartQ Hi-Fi", .cpu_dai_name = "samsung-i2s.0", .codec_dai_name = "wm8750-hifi", - .platform_name = "samsung-audio", + .platform_name = "samsung-i2s.0", .codec_name = "wm8750.0-0x1a", .init = smartq_wm8987_init, .ops = &smartq_hifi_ops, diff --git a/sound/soc/samsung/smdk2443_wm9710.c b/sound/soc/samsung/smdk2443_wm9710.c index 720ba29bb7e4..c390aad68cfb 100644 --- a/sound/soc/samsung/smdk2443_wm9710.c +++ b/sound/soc/samsung/smdk2443_wm9710.c @@ -24,7 +24,7 @@ static struct snd_soc_dai_link smdk2443_dai[] = { .cpu_dai_name = "samsung-ac97", .codec_dai_name = "ac97-hifi", .codec_name = "ac97-codec", - .platform_name = "samsung-audio", + .platform_name = "samsung-ac97", }, }; diff --git a/sound/soc/samsung/smdk_spdif.c b/sound/soc/samsung/smdk_spdif.c index beaa9c15d697..a2f2363fe1c2 100644 --- a/sound/soc/samsung/smdk_spdif.c +++ b/sound/soc/samsung/smdk_spdif.c @@ -151,7 +151,7 @@ static struct snd_soc_ops smdk_spdif_ops = { static struct snd_soc_dai_link smdk_dai = { .name = "S/PDIF", .stream_name = "S/PDIF PCM Playback", - .platform_name = "samsung-audio", + .platform_name = "samsung-spdif", .cpu_dai_name = "samsung-spdif", .codec_dai_name = "dit-hifi", .codec_name = "spdif-dit", diff --git a/sound/soc/samsung/smdk_wm8580.c b/sound/soc/samsung/smdk_wm8580.c index ade2809cf393..7e2b710763be 100644 --- a/sound/soc/samsung/smdk_wm8580.c +++ b/sound/soc/samsung/smdk_wm8580.c @@ -176,7 +176,7 @@ static struct snd_soc_dai_link smdk_dai[] = { .stream_name = "Playback", .cpu_dai_name = "samsung-i2s.0", .codec_dai_name = "wm8580-hifi-playback", - .platform_name = "samsung-audio", + .platform_name = "samsung-i2s.0", .codec_name = "wm8580.0-001b", .ops = &smdk_ops, }, @@ -185,7 +185,7 @@ static struct snd_soc_dai_link smdk_dai[] = { .stream_name = "Capture", .cpu_dai_name = "samsung-i2s.0", .codec_dai_name = "wm8580-hifi-capture", - .platform_name = "samsung-audio", + .platform_name = "samsung-i2s.0", .codec_name = "wm8580.0-001b", .init = smdk_wm8580_init_paiftx, .ops = &smdk_ops, @@ -195,7 +195,7 @@ static struct snd_soc_dai_link smdk_dai[] = { .stream_name = "Playback", .cpu_dai_name = "samsung-i2s.x", .codec_dai_name = "wm8580-hifi-playback", - .platform_name = "samsung-audio", + .platform_name = "samsung-i2s.x", .codec_name = "wm8580.0-001b", .ops = &smdk_ops, }, diff --git a/sound/soc/samsung/smdk_wm8580pcm.c b/sound/soc/samsung/smdk_wm8580pcm.c index fab5322e9f05..e43bd4294f99 100644 --- a/sound/soc/samsung/smdk_wm8580pcm.c +++ b/sound/soc/samsung/smdk_wm8580pcm.c @@ -135,7 +135,7 @@ static struct snd_soc_dai_link smdk_dai[] = { .stream_name = "Capture", .cpu_dai_name = "samsung-pcm.0", .codec_dai_name = "wm8580-hifi-capture", - .platform_name = "samsung-audio", + .platform_name = "samsung-pcm.0", .codec_name = "wm8580.0-001b", .ops = &smdk_wm8580_pcm_ops, }, @@ -153,7 +153,7 @@ static struct snd_soc_card smdk_pcm = { * is absent (or not connected), so we connect EXT_VOICE_CLK(OSC4), * 2.0484Mhz, directly with MCLK both Codec and SoC. */ -static int __devinit snd_smdk_probe(struct platform_device *pdev) +static int snd_smdk_probe(struct platform_device *pdev) { int ret = 0; @@ -173,7 +173,7 @@ static int __devinit snd_smdk_probe(struct platform_device *pdev) return 0; } -static int __devexit snd_smdk_remove(struct platform_device *pdev) +static int snd_smdk_remove(struct platform_device *pdev) { snd_soc_unregister_card(&smdk_pcm); platform_set_drvdata(pdev, NULL); @@ -186,7 +186,7 @@ static struct platform_driver snd_smdk_driver = { .name = "samsung-smdk-pcm", }, .probe = snd_smdk_probe, - .remove = __devexit_p(snd_smdk_remove), + .remove = snd_smdk_remove, }; module_platform_driver(snd_smdk_driver); diff --git a/sound/soc/samsung/smdk_wm8994.c b/sound/soc/samsung/smdk_wm8994.c index 48dd4dd9ee08..b0d0ab8bff5a 100644 --- a/sound/soc/samsung/smdk_wm8994.c +++ b/sound/soc/samsung/smdk_wm8994.c @@ -127,7 +127,7 @@ static struct snd_soc_dai_link smdk_dai[] = { .stream_name = "Pri_Dai", .cpu_dai_name = "samsung-i2s.0", .codec_dai_name = "wm8994-aif1", - .platform_name = "samsung-audio", + .platform_name = "samsung-i2s.0", .codec_name = "wm8994-codec", .init = smdk_wm8994_init_paiftx, .ops = &smdk_ops, @@ -136,7 +136,7 @@ static struct snd_soc_dai_link smdk_dai[] = { .stream_name = "Sec_Dai", .cpu_dai_name = "samsung-i2s.4", .codec_dai_name = "wm8994-aif1", - .platform_name = "samsung-audio", + .platform_name = "samsung-i2s.4", .codec_name = "wm8994-codec", .ops = &smdk_ops, }, @@ -150,7 +150,7 @@ static struct snd_soc_card smdk = { }; -static int __devinit smdk_audio_probe(struct platform_device *pdev) +static int smdk_audio_probe(struct platform_device *pdev) { int ret; struct snd_soc_card *card = &smdk; @@ -164,7 +164,7 @@ static int __devinit smdk_audio_probe(struct platform_device *pdev) return ret; } -static int __devexit smdk_audio_remove(struct platform_device *pdev) +static int smdk_audio_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); @@ -179,7 +179,7 @@ static struct platform_driver smdk_audio_driver = { .owner = THIS_MODULE, }, .probe = smdk_audio_probe, - .remove = __devexit_p(smdk_audio_remove), + .remove = smdk_audio_remove, }; module_platform_driver(smdk_audio_driver); diff --git a/sound/soc/samsung/smdk_wm8994pcm.c b/sound/soc/samsung/smdk_wm8994pcm.c index 77ecba935119..3688a32000a2 100644 --- a/sound/soc/samsung/smdk_wm8994pcm.c +++ b/sound/soc/samsung/smdk_wm8994pcm.c @@ -116,7 +116,7 @@ static struct snd_soc_dai_link smdk_dai[] = { .stream_name = "Primary PCM", .cpu_dai_name = "samsung-pcm.0", .codec_dai_name = "wm8994-aif1", - .platform_name = "samsung-audio", + .platform_name = "samsung-pcm.0", .codec_name = "wm8994-codec", .ops = &smdk_wm8994_pcm_ops, }, @@ -129,7 +129,7 @@ static struct snd_soc_card smdk_pcm = { .num_links = 1, }; -static int __devinit snd_smdk_probe(struct platform_device *pdev) +static int snd_smdk_probe(struct platform_device *pdev) { int ret = 0; @@ -143,7 +143,7 @@ static int __devinit snd_smdk_probe(struct platform_device *pdev) return 0; } -static int __devexit snd_smdk_remove(struct platform_device *pdev) +static int snd_smdk_remove(struct platform_device *pdev) { snd_soc_unregister_card(&smdk_pcm); platform_set_drvdata(pdev, NULL); @@ -156,7 +156,7 @@ static struct platform_driver snd_smdk_driver = { .name = "samsung-smdk-pcm", }, .probe = snd_smdk_probe, - .remove = __devexit_p(snd_smdk_remove), + .remove = snd_smdk_remove, }; module_platform_driver(snd_smdk_driver); diff --git a/sound/soc/samsung/smdk_wm9713.c b/sound/soc/samsung/smdk_wm9713.c index 55b2ca7f3290..0d20e4ed27aa 100644 --- a/sound/soc/samsung/smdk_wm9713.c +++ b/sound/soc/samsung/smdk_wm9713.c @@ -42,7 +42,7 @@ static struct snd_soc_card smdk; static struct snd_soc_dai_link smdk_dai = { .name = "AC97", .stream_name = "AC97 PCM", - .platform_name = "samsung-audio", + .platform_name = "samsung-ac97", .cpu_dai_name = "samsung-ac97", .codec_dai_name = "wm9713-hifi", .codec_name = "wm9713-codec", diff --git a/sound/soc/samsung/spdif.c b/sound/soc/samsung/spdif.c index bc24c7af02b2..5008e5bd6ed8 100644 --- a/sound/soc/samsung/spdif.c +++ b/sound/soc/samsung/spdif.c @@ -357,7 +357,7 @@ static struct snd_soc_dai_driver samsung_spdif_dai = { .resume = spdif_resume, }; -static __devinit int spdif_probe(struct platform_device *pdev) +static int spdif_probe(struct platform_device *pdev) { struct s3c_audio_pdata *spdif_pdata; struct resource *mem_res, *dma_res; @@ -397,7 +397,7 @@ static __devinit int spdif_probe(struct platform_device *pdev) ret = -ENOENT; goto err0; } - clk_enable(spdif->pclk); + clk_prepare_enable(spdif->pclk); spdif->sclk = clk_get(&pdev->dev, "sclk_spdif"); if (IS_ERR(spdif->sclk)) { @@ -405,7 +405,7 @@ static __devinit int spdif_probe(struct platform_device *pdev) ret = -ENOENT; goto err1; } - clk_enable(spdif->sclk); + clk_prepare_enable(spdif->sclk); /* Request S/PDIF Register's memory region */ if (!request_mem_region(mem_res->start, @@ -437,27 +437,35 @@ static __devinit int spdif_probe(struct platform_device *pdev) spdif->dma_playback = &spdif_stereo_out; - return 0; + ret = asoc_dma_platform_register(&pdev->dev); + if (ret) { + dev_err(&pdev->dev, "failed to register DMA: %d\n", ret); + goto err5; + } + return 0; +err5: + snd_soc_unregister_dai(&pdev->dev); err4: iounmap(spdif->regs); err3: release_mem_region(mem_res->start, resource_size(mem_res)); err2: - clk_disable(spdif->sclk); + clk_disable_unprepare(spdif->sclk); clk_put(spdif->sclk); err1: - clk_disable(spdif->pclk); + clk_disable_unprepare(spdif->pclk); clk_put(spdif->pclk); err0: return ret; } -static __devexit int spdif_remove(struct platform_device *pdev) +static int spdif_remove(struct platform_device *pdev) { struct samsung_spdif_info *spdif = &spdif_info; struct resource *mem_res; + asoc_dma_platform_unregister(&pdev->dev); snd_soc_unregister_dai(&pdev->dev); iounmap(spdif->regs); @@ -466,9 +474,9 @@ static __devexit int spdif_remove(struct platform_device *pdev) if (mem_res) release_mem_region(mem_res->start, resource_size(mem_res)); - clk_disable(spdif->sclk); + clk_disable_unprepare(spdif->sclk); clk_put(spdif->sclk); - clk_disable(spdif->pclk); + clk_disable_unprepare(spdif->pclk); clk_put(spdif->pclk); return 0; @@ -476,7 +484,7 @@ static __devexit int spdif_remove(struct platform_device *pdev) static struct platform_driver samsung_spdif_driver = { .probe = spdif_probe, - .remove = __devexit_p(spdif_remove), + .remove = spdif_remove, .driver = { .name = "samsung-spdif", .owner = THIS_MODULE, diff --git a/sound/soc/samsung/speyside.c b/sound/soc/samsung/speyside.c index c7e1c28528a4..57df90d6b7c1 100644 --- a/sound/soc/samsung/speyside.c +++ b/sound/soc/samsung/speyside.c @@ -198,7 +198,7 @@ static struct snd_soc_dai_link speyside_dai[] = { .stream_name = "CPU-DSP", .cpu_dai_name = "samsung-i2s.0", .codec_dai_name = "wm0010-sdi1", - .platform_name = "samsung-audio", + .platform_name = "samsung-i2s.0", .codec_name = "spi0.0", .init = speyside_wm0010_init, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF @@ -320,7 +320,7 @@ static struct snd_soc_card speyside = { .late_probe = speyside_late_probe, }; -static __devinit int speyside_probe(struct platform_device *pdev) +static int speyside_probe(struct platform_device *pdev) { struct snd_soc_card *card = &speyside; int ret; @@ -337,7 +337,7 @@ static __devinit int speyside_probe(struct platform_device *pdev) return 0; } -static int __devexit speyside_remove(struct platform_device *pdev) +static int speyside_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); @@ -353,7 +353,7 @@ static struct platform_driver speyside_driver = { .pm = &snd_soc_pm_ops, }, .probe = speyside_probe, - .remove = __devexit_p(speyside_remove), + .remove = speyside_remove, }; module_platform_driver(speyside_driver); diff --git a/sound/soc/samsung/tobermory.c b/sound/soc/samsung/tobermory.c index 9199649bf786..f21ff608a819 100644 --- a/sound/soc/samsung/tobermory.c +++ b/sound/soc/samsung/tobermory.c @@ -110,7 +110,7 @@ static struct snd_soc_dai_link tobermory_dai[] = { .stream_name = "CPU", .cpu_dai_name = "samsung-i2s.0", .codec_dai_name = "wm8962", - .platform_name = "samsung-audio", + .platform_name = "samsung-i2s.0", .codec_name = "wm8962.1-001a", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM, @@ -214,7 +214,7 @@ static struct snd_soc_card tobermory = { .late_probe = tobermory_late_probe, }; -static __devinit int tobermory_probe(struct platform_device *pdev) +static int tobermory_probe(struct platform_device *pdev) { struct snd_soc_card *card = &tobermory; int ret; @@ -231,7 +231,7 @@ static __devinit int tobermory_probe(struct platform_device *pdev) return 0; } -static int __devexit tobermory_remove(struct platform_device *pdev) +static int tobermory_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); @@ -247,7 +247,7 @@ static struct platform_driver tobermory_driver = { .pm = &snd_soc_pm_ops, }, .probe = tobermory_probe, - .remove = __devexit_p(tobermory_remove), + .remove = tobermory_remove, }; module_platform_driver(tobermory_driver); diff --git a/sound/soc/sh/dma-sh7760.c b/sound/soc/sh/dma-sh7760.c index 7da20186b19e..19eff8fc4fdd 100644 --- a/sound/soc/sh/dma-sh7760.c +++ b/sound/soc/sh/dma-sh7760.c @@ -348,12 +348,12 @@ static struct snd_soc_platform sh7760_soc_platform = { .pcm_free = camelot_pcm_free, }; -static int __devinit sh7760_soc_platform_probe(struct platform_device *pdev) +static int sh7760_soc_platform_probe(struct platform_device *pdev) { return snd_soc_register_platform(&pdev->dev, &sh7760_soc_platform); } -static int __devexit sh7760_soc_platform_remove(struct platform_device *pdev) +static int sh7760_soc_platform_remove(struct platform_device *pdev) { snd_soc_unregister_platform(&pdev->dev); return 0; @@ -366,7 +366,7 @@ static struct platform_driver sh7760_pcm_driver = { }, .probe = sh7760_soc_platform_probe, - .remove = __devexit_p(sh7760_soc_platform_remove), + .remove = sh7760_soc_platform_remove, }; module_platform_driver(sh7760_pcm_driver); diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index 9d7f30774a44..a606d0f93d1c 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -22,6 +22,7 @@ #include <linux/module.h> #include <linux/workqueue.h> #include <sound/soc.h> +#include <sound/pcm_params.h> #include <sound/sh_fsi.h> /* PortA/PortB register */ @@ -189,6 +190,14 @@ typedef int (*set_rate_func)(struct device *dev, int rate, int enable); */ /* + * FSI clock + * + * FSIxCLK [CPG] (ick) -------> | + * |-> FSI_DIV (div)-> FSI2 + * FSIxCK [external] (xck) ---> | + */ + +/* * struct */ @@ -228,6 +237,20 @@ struct fsi_stream { dma_addr_t dma; }; +struct fsi_clk { + /* see [FSI clock] */ + struct clk *own; + struct clk *xck; + struct clk *ick; + struct clk *div; + int (*set_rate)(struct device *dev, + struct fsi_priv *fsi, + unsigned long rate); + + unsigned long rate; + unsigned int count; +}; + struct fsi_priv { void __iomem *base; struct fsi_master *master; @@ -236,11 +259,17 @@ struct fsi_priv { struct fsi_stream playback; struct fsi_stream capture; + struct fsi_clk clock; + u32 fmt; int chan_num:16; int clk_master:1; + int clk_cpg:1; int spdif:1; + int enable_stream:1; + int bit_clk_inv:1; + int lr_clk_inv:1; long rate; }; @@ -370,6 +399,11 @@ static int fsi_is_spdif(struct fsi_priv *fsi) return fsi->spdif; } +static int fsi_is_enable_stream(struct fsi_priv *fsi) +{ + return fsi->enable_stream; +} + static int fsi_is_play(struct snd_pcm_substream *substream) { return substream->stream == SNDRV_PCM_STREAM_PLAYBACK; @@ -717,14 +751,335 @@ static void fsi_spdif_clk_ctrl(struct fsi_priv *fsi, int enable) /* * clock function */ +static int fsi_clk_init(struct device *dev, + struct fsi_priv *fsi, + int xck, + int ick, + int div, + int (*set_rate)(struct device *dev, + struct fsi_priv *fsi, + unsigned long rate)) +{ + struct fsi_clk *clock = &fsi->clock; + int is_porta = fsi_is_port_a(fsi); + + clock->xck = NULL; + clock->ick = NULL; + clock->div = NULL; + clock->rate = 0; + clock->count = 0; + clock->set_rate = set_rate; + + clock->own = devm_clk_get(dev, NULL); + if (IS_ERR(clock->own)) + return -EINVAL; + + /* external clock */ + if (xck) { + clock->xck = devm_clk_get(dev, is_porta ? "xcka" : "xckb"); + if (IS_ERR(clock->xck)) { + dev_err(dev, "can't get xck clock\n"); + return -EINVAL; + } + if (clock->xck == clock->own) { + dev_err(dev, "cpu doesn't support xck clock\n"); + return -EINVAL; + } + } + + /* FSIACLK/FSIBCLK */ + if (ick) { + clock->ick = devm_clk_get(dev, is_porta ? "icka" : "ickb"); + if (IS_ERR(clock->ick)) { + dev_err(dev, "can't get ick clock\n"); + return -EINVAL; + } + if (clock->ick == clock->own) { + dev_err(dev, "cpu doesn't support ick clock\n"); + return -EINVAL; + } + } + + /* FSI-DIV */ + if (div) { + clock->div = devm_clk_get(dev, is_porta ? "diva" : "divb"); + if (IS_ERR(clock->div)) { + dev_err(dev, "can't get div clock\n"); + return -EINVAL; + } + if (clock->div == clock->own) { + dev_err(dev, "cpu doens't support div clock\n"); + return -EINVAL; + } + } + + return 0; +} + +#define fsi_clk_invalid(fsi) fsi_clk_valid(fsi, 0) +static void fsi_clk_valid(struct fsi_priv *fsi, unsigned long rate) +{ + fsi->clock.rate = rate; +} + +static int fsi_clk_is_valid(struct fsi_priv *fsi) +{ + return fsi->clock.set_rate && + fsi->clock.rate; +} + +static int fsi_clk_enable(struct device *dev, + struct fsi_priv *fsi, + unsigned long rate) +{ + struct fsi_clk *clock = &fsi->clock; + int ret = -EINVAL; + + if (!fsi_clk_is_valid(fsi)) + return ret; + + if (0 == clock->count) { + ret = clock->set_rate(dev, fsi, rate); + if (ret < 0) { + fsi_clk_invalid(fsi); + return ret; + } + + if (clock->xck) + clk_enable(clock->xck); + if (clock->ick) + clk_enable(clock->ick); + if (clock->div) + clk_enable(clock->div); + + clock->count++; + } + + return ret; +} + +static int fsi_clk_disable(struct device *dev, + struct fsi_priv *fsi) +{ + struct fsi_clk *clock = &fsi->clock; + + if (!fsi_clk_is_valid(fsi)) + return -EINVAL; + + if (1 == clock->count--) { + if (clock->xck) + clk_disable(clock->xck); + if (clock->ick) + clk_disable(clock->ick); + if (clock->div) + clk_disable(clock->div); + } + + return 0; +} + +static int fsi_clk_set_ackbpf(struct device *dev, + struct fsi_priv *fsi, + int ackmd, int bpfmd) +{ + u32 data = 0; + + /* check ackmd/bpfmd relationship */ + if (bpfmd > ackmd) { + dev_err(dev, "unsupported rate (%d/%d)\n", ackmd, bpfmd); + return -EINVAL; + } + + /* ACKMD */ + switch (ackmd) { + case 512: + data |= (0x0 << 12); + break; + case 256: + data |= (0x1 << 12); + break; + case 128: + data |= (0x2 << 12); + break; + case 64: + data |= (0x3 << 12); + break; + case 32: + data |= (0x4 << 12); + break; + default: + dev_err(dev, "unsupported ackmd (%d)\n", ackmd); + return -EINVAL; + } + + /* BPFMD */ + switch (bpfmd) { + case 32: + data |= (0x0 << 8); + break; + case 64: + data |= (0x1 << 8); + break; + case 128: + data |= (0x2 << 8); + break; + case 256: + data |= (0x3 << 8); + break; + case 512: + data |= (0x4 << 8); + break; + case 16: + data |= (0x7 << 8); + break; + default: + dev_err(dev, "unsupported bpfmd (%d)\n", bpfmd); + return -EINVAL; + } + + dev_dbg(dev, "ACKMD/BPFMD = %d/%d\n", ackmd, bpfmd); + + fsi_reg_mask_set(fsi, CKG1, (ACKMD_MASK | BPFMD_MASK) , data); + udelay(10); + + return 0; +} + +static int fsi_clk_set_rate_external(struct device *dev, + struct fsi_priv *fsi, + unsigned long rate) +{ + struct clk *xck = fsi->clock.xck; + struct clk *ick = fsi->clock.ick; + unsigned long xrate; + int ackmd, bpfmd; + int ret = 0; + + /* check clock rate */ + xrate = clk_get_rate(xck); + if (xrate % rate) { + dev_err(dev, "unsupported clock rate\n"); + return -EINVAL; + } + + clk_set_parent(ick, xck); + clk_set_rate(ick, xrate); + + bpfmd = fsi->chan_num * 32; + ackmd = xrate / rate; + + dev_dbg(dev, "external/rate = %ld/%ld\n", xrate, rate); + + ret = fsi_clk_set_ackbpf(dev, fsi, ackmd, bpfmd); + if (ret < 0) + dev_err(dev, "%s failed", __func__); + + return ret; +} + +static int fsi_clk_set_rate_cpg(struct device *dev, + struct fsi_priv *fsi, + unsigned long rate) +{ + struct clk *ick = fsi->clock.ick; + struct clk *div = fsi->clock.div; + unsigned long target = 0; /* 12288000 or 11289600 */ + unsigned long actual, cout; + unsigned long diff, min; + unsigned long best_cout, best_act; + int adj; + int ackmd, bpfmd; + int ret = -EINVAL; + + if (!(12288000 % rate)) + target = 12288000; + if (!(11289600 % rate)) + target = 11289600; + if (!target) { + dev_err(dev, "unsupported rate\n"); + return ret; + } + + bpfmd = fsi->chan_num * 32; + ackmd = target / rate; + ret = fsi_clk_set_ackbpf(dev, fsi, ackmd, bpfmd); + if (ret < 0) { + dev_err(dev, "%s failed", __func__); + return ret; + } + + /* + * The clock flow is + * + * [CPG] = cout => [FSI_DIV] = audio => [FSI] => [codec] + * + * But, it needs to find best match of CPG and FSI_DIV + * combination, since it is difficult to generate correct + * frequency of audio clock from ick clock only. + * Because ick is created from its parent clock. + * + * target = rate x [512/256/128/64]fs + * cout = round(target x adjustment) + * actual = cout / adjustment (by FSI-DIV) ~= target + * audio = actual + */ + min = ~0; + best_cout = 0; + best_act = 0; + for (adj = 1; adj < 0xffff; adj++) { + + cout = target * adj; + if (cout > 100000000) /* max clock = 100MHz */ + break; + + /* cout/actual audio clock */ + cout = clk_round_rate(ick, cout); + actual = cout / adj; + + /* find best frequency */ + diff = abs(actual - target); + if (diff < min) { + min = diff; + best_cout = cout; + best_act = actual; + } + } + + ret = clk_set_rate(ick, best_cout); + if (ret < 0) { + dev_err(dev, "ick clock failed\n"); + return -EIO; + } + + ret = clk_set_rate(div, clk_round_rate(div, best_act)); + if (ret < 0) { + dev_err(dev, "div clock failed\n"); + return -EIO; + } + + dev_dbg(dev, "ick/div = %ld/%ld\n", + clk_get_rate(ick), clk_get_rate(div)); + + return ret; +} + static int fsi_set_master_clk(struct device *dev, struct fsi_priv *fsi, long rate, int enable) { set_rate_func set_rate = fsi_get_info_set_rate(fsi); int ret; - if (!set_rate) - return 0; + /* + * CAUTION + * + * set_rate will be deleted + */ + if (!set_rate) { + if (enable) + return fsi_clk_enable(dev, fsi, rate); + else + return fsi_clk_disable(dev, fsi); + } ret = set_rate(dev, rate, enable); if (ret < 0) /* error */ @@ -792,10 +1147,9 @@ static int fsi_set_master_clk(struct device *dev, struct fsi_priv *fsi, */ static void fsi_pio_push16(struct fsi_priv *fsi, u8 *_buf, int samples) { - u32 enable_stream = fsi_get_info_flags(fsi) & SH_FSI_ENABLE_STREAM_MODE; int i; - if (enable_stream) { + if (fsi_is_enable_stream(fsi)) { /* * stream mode * see @@ -953,8 +1307,6 @@ static void fsi_pio_start_stop(struct fsi_priv *fsi, struct fsi_stream *io, static int fsi_pio_push_init(struct fsi_priv *fsi, struct fsi_stream *io) { - u32 enable_stream = fsi_get_info_flags(fsi) & SH_FSI_ENABLE_STREAM_MODE; - /* * we can use 16bit stream mode * when "playback" and "16bit data" @@ -962,7 +1314,7 @@ static int fsi_pio_push_init(struct fsi_priv *fsi, struct fsi_stream *io) * see * fsi_pio_push16() */ - if (enable_stream) + if (fsi_is_enable_stream(fsi)) io->bus_option = BUSOP_SET(24, PACKAGE_24BITBUS_BACK) | BUSOP_SET(16, PACKAGE_16BITBUS_STREAM); else @@ -1296,6 +1648,16 @@ static int fsi_hw_startup(struct fsi_priv *fsi, /* clock inversion (CKG2) */ data = 0; + if (fsi->bit_clk_inv) + data |= (1 << 0); + if (fsi->lr_clk_inv) + data |= (1 << 4); + if (fsi_is_clk_master(fsi)) + data <<= 8; + /* FIXME + * + * SH_FSI_xxx_INV style will be removed + */ if (SH_FSI_LRM_INV & flags) data |= 1 << 12; if (SH_FSI_BRM_INV & flags) @@ -1334,14 +1696,21 @@ static int fsi_hw_startup(struct fsi_priv *fsi, /* fifo init */ fsi_fifo_init(fsi, io, dev); + /* start master clock */ + if (fsi_is_clk_master(fsi)) + return fsi_set_master_clk(dev, fsi, fsi->rate, 1); + return 0; } -static void fsi_hw_shutdown(struct fsi_priv *fsi, +static int fsi_hw_shutdown(struct fsi_priv *fsi, struct device *dev) { + /* stop master clock */ if (fsi_is_clk_master(fsi)) - fsi_set_master_clk(dev, fsi, fsi->rate, 0); + return fsi_set_master_clk(dev, fsi, fsi->rate, 0); + + return 0; } static int fsi_dai_startup(struct snd_pcm_substream *substream, @@ -1349,6 +1718,7 @@ static int fsi_dai_startup(struct snd_pcm_substream *substream, { struct fsi_priv *fsi = fsi_get_priv(substream); + fsi_clk_invalid(fsi); fsi->rate = 0; return 0; @@ -1359,6 +1729,7 @@ static void fsi_dai_shutdown(struct snd_pcm_substream *substream, { struct fsi_priv *fsi = fsi_get_priv(substream); + fsi_clk_invalid(fsi); fsi->rate = 0; } @@ -1372,13 +1743,16 @@ static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd, switch (cmd) { case SNDRV_PCM_TRIGGER_START: fsi_stream_init(fsi, io, substream); - fsi_hw_startup(fsi, io, dai->dev); - ret = fsi_stream_transfer(io); - if (0 == ret) + if (!ret) + ret = fsi_hw_startup(fsi, io, dai->dev); + if (!ret) + ret = fsi_stream_transfer(io); + if (!ret) fsi_stream_start(fsi, io); break; case SNDRV_PCM_TRIGGER_STOP: - fsi_hw_shutdown(fsi, dai->dev); + if (!ret) + ret = fsi_hw_shutdown(fsi, dai->dev); fsi_stream_stop(fsi, io); fsi_stream_quit(fsi, io); break; @@ -1414,7 +1788,6 @@ static int fsi_set_fmt_spdif(struct fsi_priv *fsi) fsi->fmt = CR_DTMD_SPDIF_PCM | CR_PCM; fsi->chan_num = 2; - fsi->spdif = 1; return 0; } @@ -1423,7 +1796,6 @@ static int fsi_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) { struct fsi_priv *fsi = fsi_get_priv_frm_dai(dai); set_rate_func set_rate = fsi_get_info_set_rate(fsi); - u32 flags = fsi_get_info_flags(fsi); int ret; /* set master/slave audio interface */ @@ -1437,23 +1809,50 @@ static int fsi_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return -EINVAL; } - if (fsi_is_clk_master(fsi) && !set_rate) { - dev_err(dai->dev, "platform doesn't have set_rate\n"); - return -EINVAL; - } - - /* set format */ - switch (flags & SH_FSI_FMT_MASK) { - case SH_FSI_FMT_DAI: - ret = fsi_set_fmt_dai(fsi, fmt & SND_SOC_DAIFMT_FORMAT_MASK); + /* set clock inversion */ + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_IF: + fsi->bit_clk_inv = 0; + fsi->lr_clk_inv = 1; break; - case SH_FSI_FMT_SPDIF: - ret = fsi_set_fmt_spdif(fsi); + case SND_SOC_DAIFMT_IB_NF: + fsi->bit_clk_inv = 1; + fsi->lr_clk_inv = 0; break; + case SND_SOC_DAIFMT_IB_IF: + fsi->bit_clk_inv = 1; + fsi->lr_clk_inv = 1; + break; + case SND_SOC_DAIFMT_NB_NF: default: - ret = -EINVAL; + fsi->bit_clk_inv = 0; + fsi->lr_clk_inv = 0; + break; + } + + if (fsi_is_clk_master(fsi)) { + /* + * CAUTION + * + * set_rate will be deleted + */ + if (set_rate) + dev_warn(dai->dev, "set_rate will be removed soon\n"); + + if (fsi->clk_cpg) + fsi_clk_init(dai->dev, fsi, 0, 1, 1, + fsi_clk_set_rate_cpg); + else + fsi_clk_init(dai->dev, fsi, 1, 1, 0, + fsi_clk_set_rate_external); } + /* set format */ + if (fsi_is_spdif(fsi)) + ret = fsi_set_fmt_spdif(fsi); + else + ret = fsi_set_fmt_dai(fsi, fmt & SND_SOC_DAIFMT_FORMAT_MASK); + return ret; } @@ -1462,19 +1861,13 @@ static int fsi_dai_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct fsi_priv *fsi = fsi_get_priv(substream); - long rate = params_rate(params); - int ret; - if (!fsi_is_clk_master(fsi)) - return 0; - - ret = fsi_set_master_clk(dai->dev, fsi, rate, 1); - if (ret < 0) - return ret; - - fsi->rate = rate; + if (fsi_is_clk_master(fsi)) { + fsi->rate = params_rate(params); + fsi_clk_valid(fsi, fsi->rate); + } - return ret; + return 0; } static const struct snd_soc_dai_ops fsi_dai_ops = { @@ -1498,7 +1891,7 @@ static struct snd_pcm_hardware fsi_pcm_hardware = { .rates = FSI_RATES, .rate_min = 8000, .rate_max = 192000, - .channels_min = 1, + .channels_min = 2, .channels_max = 2, .buffer_bytes_max = 64 * 1024, .period_bytes_min = 32, @@ -1586,14 +1979,14 @@ static struct snd_soc_dai_driver fsi_soc_dai[] = { .playback = { .rates = FSI_RATES, .formats = FSI_FMTS, - .channels_min = 1, - .channels_max = 8, + .channels_min = 2, + .channels_max = 2, }, .capture = { .rates = FSI_RATES, .formats = FSI_FMTS, - .channels_min = 1, - .channels_max = 8, + .channels_min = 2, + .channels_max = 2, }, .ops = &fsi_dai_ops, }, @@ -1602,14 +1995,14 @@ static struct snd_soc_dai_driver fsi_soc_dai[] = { .playback = { .rates = FSI_RATES, .formats = FSI_FMTS, - .channels_min = 1, - .channels_max = 8, + .channels_min = 2, + .channels_max = 2, }, .capture = { .rates = FSI_RATES, .formats = FSI_FMTS, - .channels_min = 1, - .channels_max = 8, + .channels_min = 2, + .channels_max = 2, }, .ops = &fsi_dai_ops, }, @@ -1624,15 +2017,29 @@ static struct snd_soc_platform_driver fsi_soc_platform = { /* * platform function */ -static void fsi_handler_init(struct fsi_priv *fsi) +static void fsi_port_info_init(struct fsi_priv *fsi, + struct sh_fsi_port_info *info) +{ + if (info->flags & SH_FSI_FMT_SPDIF) + fsi->spdif = 1; + + if (info->flags & SH_FSI_CLK_CPG) + fsi->clk_cpg = 1; + + if (info->flags & SH_FSI_ENABLE_STREAM_MODE) + fsi->enable_stream = 1; +} + +static void fsi_handler_init(struct fsi_priv *fsi, + struct sh_fsi_port_info *info) { fsi->playback.handler = &fsi_pio_push_handler; /* default PIO */ fsi->playback.priv = fsi; fsi->capture.handler = &fsi_pio_pop_handler; /* default PIO */ fsi->capture.priv = fsi; - if (fsi->info->tx_id) { - fsi->playback.slave.shdma_slave.slave_id = fsi->info->tx_id; + if (info->tx_id) { + fsi->playback.slave.shdma_slave.slave_id = info->tx_id; fsi->playback.handler = &fsi_dma_push_handler; } } @@ -1642,10 +2049,16 @@ static int fsi_probe(struct platform_device *pdev) struct fsi_master *master; const struct platform_device_id *id_entry; struct sh_fsi_platform_info *info = pdev->dev.platform_data; + struct sh_fsi_port_info nul_info, *pinfo; + struct fsi_priv *fsi; struct resource *res; unsigned int irq; int ret; + nul_info.flags = 0; + nul_info.tx_id = 0; + nul_info.rx_id = 0; + id_entry = pdev->id_entry; if (!id_entry) { dev_err(&pdev->dev, "unknown fsi device\n"); @@ -1678,22 +2091,28 @@ static int fsi_probe(struct platform_device *pdev) spin_lock_init(&master->lock); /* FSI A setting */ - master->fsia.base = master->base; - master->fsia.master = master; - master->fsia.info = &info->port_a; - fsi_handler_init(&master->fsia); - ret = fsi_stream_probe(&master->fsia, &pdev->dev); + pinfo = (info) ? &info->port_a : &nul_info; + fsi = &master->fsia; + fsi->base = master->base; + fsi->master = master; + fsi->info = pinfo; + fsi_port_info_init(fsi, pinfo); + fsi_handler_init(fsi, pinfo); + ret = fsi_stream_probe(fsi, &pdev->dev); if (ret < 0) { dev_err(&pdev->dev, "FSIA stream probe failed\n"); return ret; } /* FSI B setting */ - master->fsib.base = master->base + 0x40; - master->fsib.master = master; - master->fsib.info = &info->port_b; - fsi_handler_init(&master->fsib); - ret = fsi_stream_probe(&master->fsib, &pdev->dev); + pinfo = (info) ? &info->port_b : &nul_info; + fsi = &master->fsib; + fsi->base = master->base + 0x40; + fsi->master = master; + fsi->info = pinfo; + fsi_port_info_init(fsi, pinfo); + fsi_handler_init(fsi, pinfo); + ret = fsi_stream_probe(fsi, &pdev->dev); if (ret < 0) { dev_err(&pdev->dev, "FSIB stream probe failed\n"); goto exit_fsia; @@ -1702,7 +2121,7 @@ static int fsi_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); dev_set_drvdata(&pdev->dev, master); - ret = request_irq(irq, &fsi_interrupt, 0, + ret = devm_request_irq(&pdev->dev, irq, &fsi_interrupt, 0, id_entry->name, master); if (ret) { dev_err(&pdev->dev, "irq request err\n"); @@ -1712,7 +2131,7 @@ static int fsi_probe(struct platform_device *pdev) ret = snd_soc_register_platform(&pdev->dev, &fsi_soc_platform); if (ret < 0) { dev_err(&pdev->dev, "cannot snd soc register\n"); - goto exit_free_irq; + goto exit_fsib; } ret = snd_soc_register_dais(&pdev->dev, fsi_soc_dai, @@ -1726,8 +2145,6 @@ static int fsi_probe(struct platform_device *pdev) exit_snd_soc: snd_soc_unregister_platform(&pdev->dev); -exit_free_irq: - free_irq(irq, master); exit_fsib: pm_runtime_disable(&pdev->dev); fsi_stream_remove(&master->fsib); @@ -1743,7 +2160,6 @@ static int fsi_remove(struct platform_device *pdev) master = dev_get_drvdata(&pdev->dev); - free_irq(master->irq, master); pm_runtime_disable(&pdev->dev); snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(fsi_soc_dai)); @@ -1774,10 +2190,6 @@ static void __fsi_resume(struct fsi_priv *fsi, return; fsi_hw_startup(fsi, io, dev); - - if (fsi_is_clk_master(fsi) && fsi->rate) - fsi_set_master_clk(dev, fsi, fsi->rate, 1); - fsi_stream_start(fsi, io); } diff --git a/sound/soc/sh/hac.c b/sound/soc/sh/hac.c index 3474d7befe5a..4cc2d64ef476 100644 --- a/sound/soc/sh/hac.c +++ b/sound/soc/sh/hac.c @@ -310,13 +310,13 @@ static struct snd_soc_dai_driver sh4_hac_dai[] = { #endif }; -static int __devinit hac_soc_platform_probe(struct platform_device *pdev) +static int hac_soc_platform_probe(struct platform_device *pdev) { return snd_soc_register_dais(&pdev->dev, sh4_hac_dai, ARRAY_SIZE(sh4_hac_dai)); } -static int __devexit hac_soc_platform_remove(struct platform_device *pdev) +static int hac_soc_platform_remove(struct platform_device *pdev) { snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(sh4_hac_dai)); return 0; @@ -329,7 +329,7 @@ static struct platform_driver hac_pcm_driver = { }, .probe = hac_soc_platform_probe, - .remove = __devexit_p(hac_soc_platform_remove), + .remove = hac_soc_platform_remove, }; module_platform_driver(hac_pcm_driver); diff --git a/sound/soc/sh/siu_dai.c b/sound/soc/sh/siu_dai.c index 52d4c17b1232..34facdc9e4ac 100644 --- a/sound/soc/sh/siu_dai.c +++ b/sound/soc/sh/siu_dai.c @@ -726,7 +726,7 @@ static struct snd_soc_dai_driver siu_i2s_dai = { .ops = &siu_dai_ops, }; -static int __devinit siu_probe(struct platform_device *pdev) +static int siu_probe(struct platform_device *pdev) { const struct firmware *fw_entry; struct resource *res, *region; @@ -815,7 +815,7 @@ ereqfw: return ret; } -static int __devexit siu_remove(struct platform_device *pdev) +static int siu_remove(struct platform_device *pdev) { struct siu_info *info = dev_get_drvdata(&pdev->dev); struct resource *res; @@ -843,7 +843,7 @@ static struct platform_driver siu_driver = { .name = "siu-pcm-audio", }, .probe = siu_probe, - .remove = __devexit_p(siu_remove), + .remove = siu_remove, }; module_platform_driver(siu_driver); diff --git a/sound/soc/sh/ssi.c b/sound/soc/sh/ssi.c index ff82b56a8860..c8e73a703934 100644 --- a/sound/soc/sh/ssi.c +++ b/sound/soc/sh/ssi.c @@ -379,13 +379,13 @@ static struct snd_soc_dai_driver sh4_ssi_dai[] = { #endif }; -static int __devinit sh4_soc_dai_probe(struct platform_device *pdev) +static int sh4_soc_dai_probe(struct platform_device *pdev) { return snd_soc_register_dais(&pdev->dev, sh4_ssi_dai, ARRAY_SIZE(sh4_ssi_dai)); } -static int __devexit sh4_soc_dai_remove(struct platform_device *pdev) +static int sh4_soc_dai_remove(struct platform_device *pdev) { snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(sh4_ssi_dai)); return 0; @@ -398,7 +398,7 @@ static struct platform_driver sh4_ssi_driver = { }, .probe = sh4_soc_dai_probe, - .remove = __devexit_p(sh4_soc_dai_remove), + .remove = sh4_soc_dai_remove, }; module_platform_driver(sh4_ssi_driver); diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c index 9d56f0218f41..e72f55428f0b 100644 --- a/sound/soc/soc-cache.c +++ b/sound/soc/soc-cache.c @@ -88,7 +88,7 @@ static int snd_soc_flat_cache_sync(struct snd_soc_codec *codec) ret = snd_soc_write(codec, i, val); if (ret) return ret; - dev_dbg(codec->dev, "Synced register %#x, value = %#x\n", + dev_dbg(codec->dev, "ASoC: Synced register %#x, value = %#x\n", i, val); } return 0; @@ -156,7 +156,7 @@ int snd_soc_cache_init(struct snd_soc_codec *codec) /* Fall back to flat compression */ if (i == ARRAY_SIZE(cache_types)) { - dev_warn(codec->dev, "Could not match compress type: %d\n", + dev_warn(codec->dev, "ASoC: Could not match compress type: %d\n", codec->compress_type); i = 0; } @@ -166,7 +166,7 @@ int snd_soc_cache_init(struct snd_soc_codec *codec) if (codec->cache_ops->init) { if (codec->cache_ops->name) - dev_dbg(codec->dev, "Initializing %s cache for %s codec\n", + dev_dbg(codec->dev, "ASoC: Initializing %s cache for %s codec\n", codec->cache_ops->name, codec->name); return codec->cache_ops->init(codec); } @@ -181,7 +181,7 @@ int snd_soc_cache_exit(struct snd_soc_codec *codec) { if (codec->cache_ops && codec->cache_ops->exit) { if (codec->cache_ops->name) - dev_dbg(codec->dev, "Destroying %s cache for %s codec\n", + dev_dbg(codec->dev, "ASoC: Destroying %s cache for %s codec\n", codec->cache_ops->name, codec->name); return codec->cache_ops->exit(codec); } @@ -265,7 +265,7 @@ int snd_soc_cache_sync(struct snd_soc_codec *codec) name = "unknown"; if (codec->cache_ops->name) - dev_dbg(codec->dev, "Syncing %s cache for %s codec\n", + dev_dbg(codec->dev, "ASoC: Syncing %s cache for %s codec\n", codec->cache_ops->name, codec->name); trace_snd_soc_cache_sync(codec, name, "start"); ret = codec->cache_ops->sync(codec); diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index 967d0e173e1b..5fbfb06e8083 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -113,7 +113,7 @@ static int soc_compr_free(struct snd_compr_stream *cstream) SNDRV_PCM_STREAM_PLAYBACK, SND_SOC_DAPM_STREAM_STOP); } else - codec_dai->pop_wait = 1; + rtd->pop_wait = 1; schedule_delayed_work(&rtd->delayed_work, msecs_to_jiffies(rtd->pmdown_time)); } else { diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 10d21be383f6..2370063b5824 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -271,7 +271,8 @@ static void soc_init_codec_debugfs(struct snd_soc_codec *codec) codec->debugfs_codec_root = debugfs_create_dir(codec->name, debugfs_card_root); if (!codec->debugfs_codec_root) { - dev_warn(codec->dev, "Failed to create codec debugfs directory\n"); + dev_warn(codec->dev, "ASoC: Failed to create codec debugfs" + " directory\n"); return; } @@ -284,7 +285,8 @@ static void soc_init_codec_debugfs(struct snd_soc_codec *codec) codec->debugfs_codec_root, codec, &codec_reg_fops); if (!codec->debugfs_reg) - dev_warn(codec->dev, "Failed to create codec register debugfs file\n"); + dev_warn(codec->dev, "ASoC: Failed to create codec register" + " debugfs file\n"); snd_soc_dapm_debugfs_init(&codec->dapm, codec->debugfs_codec_root); } @@ -302,7 +304,7 @@ static void soc_init_platform_debugfs(struct snd_soc_platform *platform) debugfs_card_root); if (!platform->debugfs_platform_root) { dev_warn(platform->dev, - "Failed to create platform debugfs directory\n"); + "ASoC: Failed to create platform debugfs directory\n"); return; } @@ -430,7 +432,7 @@ static void soc_init_card_debugfs(struct snd_soc_card *card) &card->pop_time); if (!card->debugfs_pop_time) dev_warn(card->dev, - "Failed to create pop time debugfs file\n"); + "ASoC: Failed to create pop time debugfs file\n"); } static void soc_cleanup_card_debugfs(struct snd_soc_card *card) @@ -475,7 +477,7 @@ struct snd_pcm_substream *snd_soc_get_dai_substream(struct snd_soc_card *card, !strcmp(card->rtd[i].dai_link->name, dai_link)) return card->rtd[i].pcm->streams[stream].substream; } - dev_dbg(card->dev, "failed to find dai link %s\n", dai_link); + dev_dbg(card->dev, "ASoC: failed to find dai link %s\n", dai_link); return NULL; } EXPORT_SYMBOL_GPL(snd_soc_get_dai_substream); @@ -489,7 +491,7 @@ struct snd_soc_pcm_runtime *snd_soc_get_pcm_runtime(struct snd_soc_card *card, if (!strcmp(card->rtd[i].dai_link->name, dai_link)) return &card->rtd[i]; } - dev_dbg(card->dev, "failed to find rtd %s\n", dai_link); + dev_dbg(card->dev, "ASoC: failed to find rtd %s\n", dai_link); return NULL; } EXPORT_SYMBOL_GPL(snd_soc_get_pcm_runtime); @@ -519,7 +521,7 @@ static int soc_ac97_dev_register(struct snd_soc_codec *codec) codec->card->snd_card->number, 0, codec->name); err = device_register(&codec->ac97->dev); if (err < 0) { - snd_printk(KERN_ERR "Can't register ac97 bus\n"); + dev_err(codec->dev, "ASoC: Can't register ac97 bus\n"); codec->ac97->dev.bus = NULL; return err; } @@ -628,7 +630,8 @@ int snd_soc_suspend(struct device *dev) */ if (codec->dapm.idle_bias_off) { dev_dbg(codec->dev, - "idle_bias_off CODEC on over suspend\n"); + "ASoC: idle_bias_off CODEC on" + " over suspend\n"); break; } case SND_SOC_BIAS_OFF: @@ -639,7 +642,8 @@ int snd_soc_suspend(struct device *dev) regcache_mark_dirty(codec->control_data); break; default: - dev_dbg(codec->dev, "CODEC is on over suspend\n"); + dev_dbg(codec->dev, "ASoC: CODEC is on" + " over suspend\n"); break; } } @@ -676,7 +680,7 @@ static void soc_resume_deferred(struct work_struct *work) * so userspace apps are blocked from touching us */ - dev_dbg(card->dev, "starting resume work\n"); + dev_dbg(card->dev, "ASoC: starting resume work\n"); /* Bring us up into D2 so that DAPM starts enabling things */ snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D2); @@ -708,7 +712,8 @@ static void soc_resume_deferred(struct work_struct *work) codec->suspended = 0; break; default: - dev_dbg(codec->dev, "CODEC was on over suspend\n"); + dev_dbg(codec->dev, "ASoC: CODEC was on over" + " suspend\n"); break; } } @@ -758,7 +763,7 @@ static void soc_resume_deferred(struct work_struct *work) if (card->resume_post) card->resume_post(card); - dev_dbg(card->dev, "resume work completed\n"); + dev_dbg(card->dev, "ASoC: resume work completed\n"); /* userspace can access us now we are back as we were before */ snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D0); @@ -790,12 +795,12 @@ int snd_soc_resume(struct device *dev) ac97_control |= cpu_dai->driver->ac97_control; } if (ac97_control) { - dev_dbg(dev, "Resuming AC97 immediately\n"); + dev_dbg(dev, "ASoC: Resuming AC97 immediately\n"); soc_resume_deferred(&card->deferred_resume_work); } else { - dev_dbg(dev, "Scheduling resume work\n"); + dev_dbg(dev, "ASoC: Scheduling resume work\n"); if (!schedule_work(&card->deferred_resume_work)) - dev_err(dev, "resume work item may be lost\n"); + dev_err(dev, "ASoC: resume work item may be lost\n"); } return 0; @@ -818,7 +823,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num) struct snd_soc_dai *codec_dai, *cpu_dai; const char *platform_name; - dev_dbg(card->dev, "binding %s at idx %d\n", dai_link->name, num); + 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(cpu_dai, &dai_list, list) { @@ -836,7 +841,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num) } if (!rtd->cpu_dai) { - dev_err(card->dev, "CPU DAI %s not registered\n", + dev_err(card->dev, "ASoC: CPU DAI %s not registered\n", dai_link->cpu_dai_name); return -EPROBE_DEFER; } @@ -867,14 +872,14 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num) } if (!rtd->codec_dai) { - dev_err(card->dev, "CODEC DAI %s not registered\n", + dev_err(card->dev, "ASoC: CODEC DAI %s not registered\n", dai_link->codec_dai_name); return -EPROBE_DEFER; } } if (!rtd->codec) { - dev_err(card->dev, "CODEC %s not registered\n", + dev_err(card->dev, "ASoC: CODEC %s not registered\n", dai_link->codec_name); return -EPROBE_DEFER; } @@ -898,7 +903,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num) rtd->platform = platform; } if (!rtd->platform) { - dev_err(card->dev, "platform %s not registered\n", + dev_err(card->dev, "ASoC: platform %s not registered\n", dai_link->platform_name); return -EPROBE_DEFER; } @@ -915,8 +920,8 @@ static int soc_remove_platform(struct snd_soc_platform *platform) if (platform->driver->remove) { ret = platform->driver->remove(platform); if (ret < 0) - pr_err("asoc: failed to remove %s: %d\n", - platform->name, ret); + dev_err(platform->dev, "ASoC: failed to remove %d\n", + ret); } /* Make sure all DAPM widgets are freed */ @@ -937,9 +942,7 @@ static void soc_remove_codec(struct snd_soc_codec *codec) if (codec->driver->remove) { err = codec->driver->remove(codec); if (err < 0) - dev_err(codec->dev, - "asoc: failed to remove %s: %d\n", - codec->name, err); + dev_err(codec->dev, "ASoC: failed to remove %d\n", err); } /* Make sure all DAPM widgets are freed */ @@ -971,8 +974,9 @@ static void soc_remove_link_dais(struct snd_soc_card *card, int num, int order) if (codec_dai->driver->remove) { err = codec_dai->driver->remove(codec_dai); if (err < 0) - pr_err("asoc: failed to remove %s: %d\n", - codec_dai->name, err); + dev_err(codec_dai->dev, + "ASoC: failed to remove %s: %d\n", + codec_dai->name, err); } codec_dai->probed = 0; list_del(&codec_dai->card_list); @@ -984,8 +988,9 @@ static void soc_remove_link_dais(struct snd_soc_card *card, int num, int order) if (cpu_dai->driver->remove) { err = cpu_dai->driver->remove(cpu_dai); if (err < 0) - pr_err("asoc: failed to remove %s: %d\n", - cpu_dai->name, err); + dev_err(cpu_dai->dev, + "ASoC: failed to remove %s: %d\n", + cpu_dai->name, err); } cpu_dai->probed = 0; list_del(&cpu_dai->card_list); @@ -1099,8 +1104,7 @@ static int soc_probe_codec(struct snd_soc_card *card, ret = driver->probe(codec); if (ret < 0) { dev_err(codec->dev, - "asoc: failed to probe CODEC %s: %d\n", - codec->name, ret); + "ASoC: failed to probe CODEC %d\n", ret); goto err_probe; } } @@ -1163,8 +1167,7 @@ static int soc_probe_platform(struct snd_soc_card *card, ret = driver->probe(platform); if (ret < 0) { dev_err(platform->dev, - "asoc: failed to probe platform %s: %d\n", - platform->name, ret); + "ASoC: failed to probe platform %d\n", ret); goto err_probe; } } @@ -1229,7 +1232,7 @@ static int soc_post_component_init(struct snd_soc_card *card, else if (dailess && aux_dev->init) ret = aux_dev->init(&codec->dapm); if (ret < 0) { - dev_err(card->dev, "asoc: failed to init %s: %d\n", name, ret); + dev_err(card->dev, "ASoC: failed to init %s: %d\n", name, ret); return ret; } codec->name_prefix = temp; @@ -1252,8 +1255,10 @@ static int soc_post_component_init(struct snd_soc_card *card, INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_CAPTURE].fe_clients); ret = device_add(rtd->dev); if (ret < 0) { + /* calling put_device() here to free the rtd->dev */ + put_device(rtd->dev); dev_err(card->dev, - "asoc: failed to register runtime device: %d\n", ret); + "ASoC: failed to register runtime device: %d\n", ret); return ret; } rtd->dev_registered = 1; @@ -1262,14 +1267,13 @@ static int soc_post_component_init(struct snd_soc_card *card, ret = snd_soc_dapm_sys_add(rtd->dev); if (ret < 0) dev_err(codec->dev, - "asoc: failed to add codec dapm sysfs entries: %d\n", - ret); + "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(codec->dev, - "asoc: failed to add codec sysfs files: %d\n", ret); + "ASoC: failed to add codec sysfs files: %d\n", ret); #ifdef CONFIG_DEBUG_FS /* add DPCM sysfs entries */ @@ -1278,7 +1282,7 @@ static int soc_post_component_init(struct snd_soc_card *card, ret = soc_dpcm_debugfs_add(rtd); if (ret < 0) - dev_err(rtd->dev, "asoc: failed to add dpcm sysfs entries: %d\n", ret); + dev_err(rtd->dev, "ASoC: failed to add dpcm sysfs entries: %d\n", ret); out: #endif @@ -1333,7 +1337,7 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order) struct snd_soc_dapm_widget *play_w, *capture_w; int ret; - dev_dbg(card->dev, "probe %s dai link %d late %d\n", + dev_dbg(card->dev, "ASoC: probe %s dai link %d late %d\n", card->name, num, order); /* config components */ @@ -1359,8 +1363,9 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order) if (cpu_dai->driver->probe) { ret = cpu_dai->driver->probe(cpu_dai); if (ret < 0) { - pr_err("asoc: failed to probe CPU DAI %s: %d\n", - cpu_dai->name, ret); + 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; } @@ -1375,8 +1380,9 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order) if (codec_dai->driver->probe) { ret = codec_dai->driver->probe(codec_dai); if (ret < 0) { - pr_err("asoc: failed to probe CODEC DAI %s: %d\n", - codec_dai->name, ret); + dev_err(codec_dai->dev, + "ASoC: failed to probe CODEC DAI %s: %d\n", + codec_dai->name, ret); return ret; } } @@ -1396,13 +1402,14 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order) ret = device_create_file(rtd->dev, &dev_attr_pmdown_time); if (ret < 0) - pr_warn("asoc: failed to add pmdown_time sysfs:%d\n", ret); + dev_warn(rtd->dev, "ASoC: failed to add pmdown_time sysfs: %d\n", + ret); if (cpu_dai->driver->compress_dai) { /*create compress_device"*/ ret = soc_new_compress(rtd, num); if (ret < 0) { - pr_err("asoc: can't create compress %s\n", + dev_err(card->dev, "ASoC: can't create compress %s\n", dai_link->stream_name); return ret; } @@ -1412,7 +1419,7 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order) /* create the pcm */ ret = soc_new_pcm(rtd, num); if (ret < 0) { - pr_err("asoc: can't create pcm %s :%d\n", + dev_err(card->dev, "ASoC: can't create pcm %s :%d\n", dai_link->stream_name, ret); return ret; } @@ -1424,7 +1431,7 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order) ret = snd_soc_dapm_new_pcm(card, dai_link->params, capture_w, play_w); if (ret != 0) { - dev_err(card->dev, "Can't link %s to %s: %d\n", + dev_err(card->dev, "ASoC: Can't link %s to %s: %d\n", play_w->name, capture_w->name, ret); return ret; } @@ -1436,7 +1443,7 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order) ret = snd_soc_dapm_new_pcm(card, dai_link->params, capture_w, play_w); if (ret != 0) { - dev_err(card->dev, "Can't link %s to %s: %d\n", + dev_err(card->dev, "ASoC: Can't link %s to %s: %d\n", play_w->name, capture_w->name, ret); return ret; } @@ -1473,7 +1480,8 @@ static int soc_register_ac97_dai_link(struct snd_soc_pcm_runtime *rtd) ret = soc_ac97_dev_register(rtd->codec); if (ret < 0) { - pr_err("asoc: AC97 device register failed:%d\n", ret); + dev_err(rtd->codec->dev, + "ASoC: AC97 device register failed: %d\n", ret); return ret; } @@ -1502,7 +1510,7 @@ static int soc_check_aux_dev(struct snd_soc_card *card, int num) return 0; } - dev_err(card->dev, "%s not registered\n", aux_dev->codec_name); + dev_err(card->dev, "ASoC: %s not registered\n", aux_dev->codec_name); return -EPROBE_DEFER; } @@ -1518,7 +1526,7 @@ static int soc_probe_aux_dev(struct snd_soc_card *card, int num) if (!strcmp(codec->name, aux_dev->codec_name)) { if (codec->probed) { dev_err(codec->dev, - "asoc: codec already probed"); + "ASoC: codec already probed"); ret = -EBUSY; goto out; } @@ -1526,7 +1534,7 @@ static int soc_probe_aux_dev(struct snd_soc_card *card, int num) } } /* codec not found */ - dev_err(card->dev, "asoc: codec %s not found", aux_dev->codec_name); + dev_err(card->dev, "ASoC: codec %s not found", aux_dev->codec_name); return -EPROBE_DEFER; found: @@ -1548,7 +1556,7 @@ static void soc_remove_aux_dev(struct snd_soc_card *card, int num) /* unregister the rtd device */ if (rtd->dev_registered) { device_remove_file(rtd->dev, &dev_attr_codec_reg); - device_del(rtd->dev); + device_unregister(rtd->dev); rtd->dev_registered = 0; } @@ -1569,8 +1577,8 @@ static int snd_soc_init_codec_cache(struct snd_soc_codec *codec, codec->compress_type = compress_type; ret = snd_soc_cache_init(codec); if (ret < 0) { - dev_err(codec->dev, "Failed to set cache compression type: %d\n", - ret); + dev_err(codec->dev, "ASoC: Failed to set cache compression" + " type: %d\n", ret); return ret; } codec->cache_init = 1; @@ -1626,8 +1634,8 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) ret = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, card->owner, 0, &card->snd_card); if (ret < 0) { - pr_err("asoc: can't create sound card for card %s: %d\n", - card->name, ret); + dev_err(card->dev, "ASoC: can't create sound card for" + " card %s: %d\n", card->name, ret); goto base_error; } card->snd_card->dev = card->dev; @@ -1663,8 +1671,9 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) for (i = 0; i < card->num_links; i++) { ret = soc_probe_link_components(card, i, order); if (ret < 0) { - pr_err("asoc: failed to instantiate card %s: %d\n", - card->name, ret); + dev_err(card->dev, + "ASoC: failed to instantiate card %d\n", + ret); goto probe_dai_err; } } @@ -1676,8 +1685,9 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) for (i = 0; i < card->num_links; i++) { ret = soc_probe_link_dais(card, i, order); if (ret < 0) { - pr_err("asoc: failed to instantiate card %s: %d\n", - card->name, ret); + dev_err(card->dev, + "ASoC: failed to instantiate card %d\n", + ret); goto probe_dai_err; } } @@ -1686,8 +1696,9 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) for (i = 0; i < card->num_aux_devs; i++) { ret = soc_probe_aux_dev(card, i); if (ret < 0) { - pr_err("asoc: failed to add auxiliary devices %s: %d\n", - card->name, ret); + dev_err(card->dev, + "ASoC: failed to add auxiliary devices %d\n", + ret); goto probe_aux_dev_err; } } @@ -1712,7 +1723,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) dai_fmt); if (ret != 0 && ret != -ENOTSUPP) dev_warn(card->rtd[i].codec_dai->dev, - "Failed to set DAI format: %d\n", + "ASoC: Failed to set DAI format: %d\n", ret); } @@ -1723,7 +1734,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) dai_fmt); if (ret != 0 && ret != -ENOTSUPP) dev_warn(card->rtd[i].cpu_dai->dev, - "Failed to set DAI format: %d\n", + "ASoC: Failed to set DAI format: %d\n", ret); } else if (dai_fmt) { /* Flip the polarity for the "CPU" end */ @@ -1748,7 +1759,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) dai_fmt); if (ret != 0 && ret != -ENOTSUPP) dev_warn(card->rtd[i].cpu_dai->dev, - "Failed to set DAI format: %d\n", + "ASoC: Failed to set DAI format: %d\n", ret); } } @@ -1775,7 +1786,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) if (card->late_probe) { ret = card->late_probe(card); if (ret < 0) { - dev_err(card->dev, "%s late_probe() failed: %d\n", + dev_err(card->dev, "ASoC: %s late_probe() failed: %d\n", card->name, ret); goto probe_aux_dev_err; } @@ -1789,8 +1800,8 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) ret = snd_card_register(card->snd_card); if (ret < 0) { - pr_err("asoc: failed to register soundcard for %s: %d\n", - card->name, ret); + dev_err(card->dev, "ASoC: failed to register soundcard %d\n", + ret); goto probe_aux_dev_err; } @@ -1799,8 +1810,8 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) for (i = 0; i < card->num_rtd; i++) { ret = soc_register_ac97_dai_link(&card->rtd[i]); if (ret < 0) { - pr_err("asoc: failed to register AC97 %s: %d\n", - card->name, ret); + dev_err(card->dev, "ASoC: failed to register AC97:" + " %d\n", ret); while (--i >= 0) soc_unregister_ac97_dai_link(card->rtd[i].codec); goto probe_aux_dev_err; @@ -1846,7 +1857,7 @@ static int soc_probe(struct platform_device *pdev) return -EINVAL; dev_warn(&pdev->dev, - "ASoC machine %s should use snd_soc_register_card()\n", + "ASoC: machine %s should use snd_soc_register_card()\n", card->name); /* Bodge while we unpick instantiation */ @@ -1996,7 +2007,7 @@ int snd_soc_platform_read(struct snd_soc_platform *platform, unsigned int ret; if (!platform->driver->read) { - dev_err(platform->dev, "platform has no read back\n"); + dev_err(platform->dev, "ASoC: platform has no read back\n"); return -1; } @@ -2012,7 +2023,7 @@ int snd_soc_platform_write(struct snd_soc_platform *platform, unsigned int reg, unsigned int val) { if (!platform->driver->write) { - dev_err(platform->dev, "platform has no write back\n"); + dev_err(platform->dev, "ASoC: platform has no write back\n"); return -1; } @@ -2283,7 +2294,8 @@ static int snd_soc_add_controls(struct snd_card *card, struct device *dev, err = snd_ctl_add(card, snd_soc_cnew(control, data, control->name, prefix)); if (err < 0) { - dev_err(dev, "Failed to add %s: %d\n", control->name, err); + dev_err(dev, "ASoC: Failed to add %s: %d\n", + control->name, err); return err; } } @@ -2907,7 +2919,7 @@ int snd_soc_info_volsw_range(struct snd_kcontrol *kcontrol, platform_max = mc->platform_max; uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = 1; + uinfo->count = snd_soc_volsw_is_stereo(mc) ? 2 : 1; uinfo->value.integer.min = 0; uinfo->value.integer.max = platform_max - min; @@ -2931,12 +2943,14 @@ int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol, (struct soc_mixer_control *)kcontrol->private_value; struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); unsigned int reg = mc->reg; + unsigned int rreg = mc->rreg; unsigned int shift = mc->shift; int min = mc->min; int max = mc->max; unsigned int mask = (1 << fls(max)) - 1; unsigned int invert = mc->invert; unsigned int val, val_mask; + int ret; val = ((ucontrol->value.integer.value[0] + min) & mask); if (invert) @@ -2944,7 +2958,21 @@ int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol, val_mask = mask << shift; val = val << shift; - return snd_soc_update_bits_locked(codec, reg, val_mask, val); + ret = snd_soc_update_bits_locked(codec, reg, val_mask, val); + if (ret != 0) + return ret; + + if (snd_soc_volsw_is_stereo(mc)) { + val = ((ucontrol->value.integer.value[1] + min) & mask); + if (invert) + val = max - val; + val_mask = mask << shift; + val = val << shift; + + ret = snd_soc_update_bits_locked(codec, rreg, val_mask, val); + } + + return ret; } EXPORT_SYMBOL_GPL(snd_soc_put_volsw_range); @@ -2964,6 +2992,7 @@ int snd_soc_get_volsw_range(struct snd_kcontrol *kcontrol, (struct soc_mixer_control *)kcontrol->private_value; struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); unsigned int reg = mc->reg; + unsigned int rreg = mc->rreg; unsigned int shift = mc->shift; int min = mc->min; int max = mc->max; @@ -2978,6 +3007,16 @@ int snd_soc_get_volsw_range(struct snd_kcontrol *kcontrol, ucontrol->value.integer.value[0] = ucontrol->value.integer.value[0] - min; + if (snd_soc_volsw_is_stereo(mc)) { + ucontrol->value.integer.value[1] = + (snd_soc_read(codec, rreg) >> shift) & mask; + if (invert) + ucontrol->value.integer.value[1] = + max - ucontrol->value.integer.value[1]; + ucontrol->value.integer.value[1] = + ucontrol->value.integer.value[1] - min; + } + return 0; } EXPORT_SYMBOL_GPL(snd_soc_get_volsw_range); @@ -3534,15 +3573,14 @@ int snd_soc_register_card(struct snd_soc_card *card) * not both or neither. */ if (!!link->codec_name == !!link->codec_of_node) { - dev_err(card->dev, - "Neither/both codec name/of_node are set for %s\n", - link->name); + dev_err(card->dev, "ASoC: Neither/both codec" + " name/of_node are set for %s\n", link->name); return -EINVAL; } /* Codec DAI name must be specified */ if (!link->codec_dai_name) { - dev_err(card->dev, "codec_dai_name not set for %s\n", - link->name); + dev_err(card->dev, "ASoC: codec_dai_name not" + " set for %s\n", link->name); return -EINVAL; } @@ -3551,8 +3589,8 @@ int snd_soc_register_card(struct snd_soc_card *card) * can be left unspecified, and a dummy platform will be used. */ if (link->platform_name && link->platform_of_node) { - dev_err(card->dev, - "Both platform name/of_node are set for %s\n", link->name); + dev_err(card->dev, "ASoC: Both platform name/of_node" + " are set for %s\n", link->name); return -EINVAL; } @@ -3562,9 +3600,8 @@ int snd_soc_register_card(struct snd_soc_card *card) * name alone.. */ if (link->cpu_name && link->cpu_of_node) { - dev_err(card->dev, - "Neither/both cpu name/of_node are set for %s\n", - link->name); + dev_err(card->dev, "ASoC: Neither/both " + "cpu name/of_node are set for %s\n",link->name); return -EINVAL; } /* @@ -3573,9 +3610,8 @@ int snd_soc_register_card(struct snd_soc_card *card) */ if (!link->cpu_dai_name && !(link->cpu_name || link->cpu_of_node)) { - dev_err(card->dev, - "Neither cpu_dai_name nor cpu_name/of_node are set for %s\n", - link->name); + dev_err(card->dev, "ASoC: Neither cpu_dai_name nor " + "cpu_name/of_node are set for %s\n", link->name); return -EINVAL; } } @@ -3622,7 +3658,7 @@ int snd_soc_unregister_card(struct snd_soc_card *card) { if (card->instantiated) soc_cleanup_card_resources(card); - dev_dbg(card->dev, "Unregistered card '%s'\n", card->name); + dev_dbg(card->dev, "ASoC: Unregistered card '%s'\n", card->name); return 0; } @@ -3679,8 +3715,8 @@ static inline char *fmt_multiple_name(struct device *dev, struct snd_soc_dai_driver *dai_drv) { if (dai_drv->name == NULL) { - pr_err("asoc: error - multiple DAI %s registered with no name\n", - dev_name(dev)); + dev_err(dev, "ASoC: error - multiple DAI %s registered with" + " no name\n", dev_name(dev)); return NULL; } @@ -3698,7 +3734,7 @@ int snd_soc_register_dai(struct device *dev, struct snd_soc_codec *codec; struct snd_soc_dai *dai; - dev_dbg(dev, "dai register %s\n", dev_name(dev)); + dev_dbg(dev, "ASoC: dai register %s\n", dev_name(dev)); dai = kzalloc(sizeof(struct snd_soc_dai), GFP_KERNEL); if (dai == NULL) @@ -3721,7 +3757,7 @@ int snd_soc_register_dai(struct device *dev, list_for_each_entry(codec, &codec_list, list) { if (codec->dev == dev) { - dev_dbg(dev, "Mapped DAI %s to CODEC %s\n", + dev_dbg(dev, "ASoC: Mapped DAI %s to CODEC %s\n", dai->name, codec->name); dai->codec = codec; break; @@ -3735,7 +3771,7 @@ int snd_soc_register_dai(struct device *dev, mutex_unlock(&client_mutex); - pr_debug("Registered DAI '%s'\n", dai->name); + dev_dbg(dev, "ASoC: Registered DAI '%s'\n", dai->name); return 0; } @@ -3761,7 +3797,7 @@ found: list_del(&dai->list); mutex_unlock(&client_mutex); - pr_debug("Unregistered DAI '%s'\n", dai->name); + dev_dbg(dev, "ASoC: Unregistered DAI '%s'\n", dai->name); kfree(dai->name); kfree(dai); } @@ -3780,7 +3816,7 @@ int snd_soc_register_dais(struct device *dev, struct snd_soc_dai *dai; int i, ret = 0; - dev_dbg(dev, "dai register %s #%Zu\n", dev_name(dev), count); + dev_dbg(dev, "ASoC: dai register %s #%Zu\n", dev_name(dev), count); for (i = 0; i < count; i++) { @@ -3812,8 +3848,8 @@ int snd_soc_register_dais(struct device *dev, list_for_each_entry(codec, &codec_list, list) { if (codec->dev == dev) { - dev_dbg(dev, "Mapped DAI %s to CODEC %s\n", - dai->name, codec->name); + dev_dbg(dev, "ASoC: Mapped DAI %s to " + "CODEC %s\n", dai->name, codec->name); dai->codec = codec; break; } @@ -3826,7 +3862,7 @@ int snd_soc_register_dais(struct device *dev, mutex_unlock(&client_mutex); - pr_debug("Registered DAI '%s'\n", dai->name); + dev_dbg(dai->dev, "ASoC: Registered DAI '%s'\n", dai->name); } return 0; @@ -3864,7 +3900,7 @@ int snd_soc_register_platform(struct device *dev, { struct snd_soc_platform *platform; - dev_dbg(dev, "platform register %s\n", dev_name(dev)); + dev_dbg(dev, "ASoC: platform register %s\n", dev_name(dev)); platform = kzalloc(sizeof(struct snd_soc_platform), GFP_KERNEL); if (platform == NULL) @@ -3888,7 +3924,7 @@ int snd_soc_register_platform(struct device *dev, list_add(&platform->list, &platform_list); mutex_unlock(&client_mutex); - pr_debug("Registered platform '%s'\n", platform->name); + dev_dbg(dev, "ASoC: Registered platform '%s'\n", platform->name); return 0; } @@ -3914,7 +3950,7 @@ found: list_del(&platform->list); mutex_unlock(&client_mutex); - pr_debug("Unregistered platform '%s'\n", platform->name); + dev_dbg(dev, "ASoC: Unregistered platform '%s'\n", platform->name); kfree(platform->name); kfree(platform); } @@ -4007,7 +4043,7 @@ int snd_soc_register_codec(struct device *dev, codec->reg_size = reg_size; /* it is necessary to make a copy of the default register cache * because in the case of using a compression type that requires - * the default register cache to be marked as __devinitconst the + * the default register cache to be marked as the * kernel might have freed the array by the time we initialize * the cache. */ @@ -4043,11 +4079,11 @@ int snd_soc_register_codec(struct device *dev, if (num_dai) { ret = snd_soc_register_dais(dev, dai_drv, num_dai); if (ret < 0) - dev_err(codec->dev, "Failed to regster DAIs: %d\n", - ret); + dev_err(codec->dev, "ASoC: Failed to regster" + " DAIs: %d\n", ret); } - pr_debug("Registered codec '%s'\n", codec->name); + dev_dbg(codec->dev, "ASoC: Registered codec '%s'\n", codec->name); return 0; fail: @@ -4082,7 +4118,7 @@ found: list_del(&codec->list); mutex_unlock(&client_mutex); - pr_debug("Unregistered codec '%s'\n", codec->name); + dev_dbg(codec->dev, "ASoC: Unregistered codec '%s'\n", codec->name); snd_soc_cache_exit(codec); kfree(codec->reg_def_copy); @@ -4106,7 +4142,7 @@ int snd_soc_of_parse_card_name(struct snd_soc_card *card, */ if (ret < 0 && ret != -EINVAL) { dev_err(card->dev, - "Property '%s' could not be read: %d\n", + "ASoC: Property '%s' could not be read: %d\n", propname, ret); return ret; } @@ -4125,15 +4161,13 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, num_routes = of_property_count_strings(np, propname); if (num_routes < 0 || num_routes & 1) { - dev_err(card->dev, - "Property '%s' does not exist or its length is not even\n", - propname); + dev_err(card->dev, "ASoC: Property '%s' does not exist or its" + " length is not even\n", propname); return -EINVAL; } num_routes /= 2; if (!num_routes) { - dev_err(card->dev, - "Property '%s's length is zero\n", + dev_err(card->dev, "ASoC: Property '%s's length is zero\n", propname); return -EINVAL; } @@ -4142,7 +4176,7 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, GFP_KERNEL); if (!routes) { dev_err(card->dev, - "Could not allocate DAPM route table\n"); + "ASoC: Could not allocate DAPM route table\n"); return -EINVAL; } @@ -4151,7 +4185,7 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, 2 * i, &routes[i].sink); if (ret) { dev_err(card->dev, - "Property '%s' index %d could not be read: %d\n", + "ASoC: Property '%s' index %d could not be read: %d\n", propname, 2 * i, ret); kfree(routes); return -EINVAL; @@ -4160,7 +4194,7 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, (2 * i) + 1, &routes[i].source); if (ret) { dev_err(card->dev, - "Property '%s' index %d could not be read: %d\n", + "ASoC: Property '%s' index %d could not be read: %d\n", propname, (2 * i) + 1, ret); kfree(routes); return -EINVAL; diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 6e35bcae02df..258acadb9e7d 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -220,7 +220,7 @@ static int soc_widget_read(struct snd_soc_dapm_widget *w, int reg) else if (w->platform) return snd_soc_platform_read(w->platform, reg); - dev_err(w->dapm->dev, "no valid widget read method\n"); + dev_err(w->dapm->dev, "ASoC: no valid widget read method\n"); return -1; } @@ -231,7 +231,7 @@ static int soc_widget_write(struct snd_soc_dapm_widget *w, int reg, int val) else if (w->platform) return snd_soc_platform_write(w->platform, reg, val); - dev_err(w->dapm->dev, "no valid widget write method\n"); + dev_err(w->dapm->dev, "ASoC: no valid widget write method\n"); return -1; } @@ -546,7 +546,7 @@ static int dapm_new_mixer(struct snd_soc_dapm_widget *w) wlist = kzalloc(wlistsize, GFP_KERNEL); if (wlist == NULL) { dev_err(dapm->dev, - "asoc: can't allocate widget list for %s\n", + "ASoC: can't allocate widget list for %s\n", w->name); return -ENOMEM; } @@ -595,9 +595,9 @@ static int dapm_new_mixer(struct snd_soc_dapm_widget *w) prefix); ret = snd_ctl_add(card, path->kcontrol); if (ret < 0) { - dev_err(dapm->dev, - "asoc: failed to add dapm kcontrol %s: %d\n", - path->long_name, ret); + dev_err(dapm->dev, "ASoC: failed to add widget" + " %s dapm kcontrol %s: %d\n", + w->name, path->long_name, ret); kfree(wlist); kfree(path->long_name); path->long_name = NULL; @@ -626,7 +626,7 @@ static int dapm_new_mux(struct snd_soc_dapm_widget *w) if (w->num_kcontrols != 1) { dev_err(dapm->dev, - "asoc: mux %s has incorrect number of controls\n", + "ASoC: mux %s has incorrect number of controls\n", w->name); return -EINVAL; } @@ -645,7 +645,7 @@ static int dapm_new_mux(struct snd_soc_dapm_widget *w) wlist = krealloc(wlist, wlistsize, GFP_KERNEL); if (wlist == NULL) { dev_err(dapm->dev, - "asoc: can't allocate widget list for %s\n", w->name); + "ASoC: can't allocate widget list for %s\n", w->name); return -ENOMEM; } wlist->num_widgets = wlistentries; @@ -677,7 +677,7 @@ static int dapm_new_mux(struct snd_soc_dapm_widget *w) name + prefix_len, prefix); ret = snd_ctl_add(card, kcontrol); if (ret < 0) { - dev_err(dapm->dev, "failed to add kcontrol %s: %d\n", + dev_err(dapm->dev, "ASoC: failed to add kcontrol %s: %d\n", w->name, ret); kfree(wlist); return ret; @@ -699,7 +699,7 @@ static int dapm_new_pga(struct snd_soc_dapm_widget *w) { if (w->num_kcontrols) dev_err(w->dapm->dev, - "asoc: PGA controls not supported: '%s'\n", w->name); + "ASoC: PGA controls not supported: '%s'\n", w->name); return 0; } @@ -725,7 +725,7 @@ static int snd_soc_dapm_suspend_check(struct snd_soc_dapm_widget *widget) case SNDRV_CTL_POWER_D3hot: case SNDRV_CTL_POWER_D3cold: if (widget->ignore_suspend) - dev_dbg(widget->dapm->dev, "%s ignoring suspend\n", + dev_dbg(widget->dapm->dev, "ASoC: %s ignoring suspend\n", widget->name); return widget->ignore_suspend; default: @@ -757,14 +757,14 @@ static int dapm_list_add_widget(struct snd_soc_dapm_widget_list **list, wlistentries * sizeof(struct snd_soc_dapm_widget *); *list = krealloc(wlist, wlistsize, GFP_KERNEL); if (*list == NULL) { - dev_err(w->dapm->dev, "can't allocate widget list for %s\n", + dev_err(w->dapm->dev, "ASoC: can't allocate widget list for %s\n", w->name); return -ENOMEM; } wlist = *list; /* insert the widget */ - dev_dbg(w->dapm->dev, "added %s in widget list pos %d\n", + dev_dbg(w->dapm->dev, "ASoC: added %s in widget list pos %d\n", w->name, wlist->num_widgets); wlist->widgets[wlist->num_widgets] = w; @@ -844,7 +844,8 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget, int err; err = dapm_list_add_widget(list, path->sink); if (err < 0) { - dev_err(widget->dapm->dev, "could not add widget %s\n", + dev_err(widget->dapm->dev, + "ASoC: could not add widget %s\n", widget->name); return con; } @@ -943,7 +944,8 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget, int err; err = dapm_list_add_widget(list, path->source); if (err < 0) { - dev_err(widget->dapm->dev, "could not add widget %s\n", + dev_err(widget->dapm->dev, + "ASoC: could not add widget %s\n", widget->name); return con; } @@ -1021,20 +1023,20 @@ int dapm_regulator_event(struct snd_soc_dapm_widget *w, if (SND_SOC_DAPM_EVENT_ON(event)) { if (w->invert & SND_SOC_DAPM_REGULATOR_BYPASS) { - ret = regulator_allow_bypass(w->regulator, true); + ret = regulator_allow_bypass(w->regulator, false); if (ret != 0) dev_warn(w->dapm->dev, - "Failed to bypass %s: %d\n", + "ASoC: Failed to bypass %s: %d\n", w->name, ret); } return regulator_enable(w->regulator); } else { if (w->invert & SND_SOC_DAPM_REGULATOR_BYPASS) { - ret = regulator_allow_bypass(w->regulator, false); + ret = regulator_allow_bypass(w->regulator, true); if (ret != 0) dev_warn(w->dapm->dev, - "Failed to unbypass %s: %d\n", + "ASoC: Failed to unbypass %s: %d\n", w->name, ret); } @@ -1253,7 +1255,7 @@ static void dapm_seq_check_event(struct snd_soc_dapm_context *dapm, ret = w->event(w, NULL, event); trace_snd_soc_dapm_widget_event_done(w, event); if (ret < 0) - pr_err("%s: %s event failed: %d\n", + dev_err(dapm->dev, "ASoC: %s: %s event failed: %d\n", ev_name, w->name, ret); } } @@ -1402,7 +1404,7 @@ static void dapm_seq_run(struct snd_soc_dapm_context *dapm, if (ret < 0) dev_err(w->dapm->dev, - "Failed to apply widget power: %d\n", ret); + "ASoC: Failed to apply widget power: %d\n", ret); } if (!list_empty(&pending)) @@ -1431,20 +1433,21 @@ static void dapm_widget_update(struct snd_soc_dapm_context *dapm) (w->event_flags & SND_SOC_DAPM_PRE_REG)) { ret = w->event(w, update->kcontrol, SND_SOC_DAPM_PRE_REG); if (ret != 0) - pr_err("%s DAPM pre-event failed: %d\n", + dev_err(dapm->dev, "ASoC: %s DAPM pre-event failed: %d\n", w->name, ret); } ret = soc_widget_update_bits_locked(w, update->reg, update->mask, update->val); if (ret < 0) - pr_err("%s DAPM update failed: %d\n", w->name, ret); + dev_err(dapm->dev, "ASoC: %s DAPM update failed: %d\n", + w->name, ret); if (w->event && (w->event_flags & SND_SOC_DAPM_POST_REG)) { ret = w->event(w, update->kcontrol, SND_SOC_DAPM_POST_REG); if (ret != 0) - pr_err("%s DAPM post-event failed: %d\n", + dev_err(dapm->dev, "ASoC: %s DAPM post-event failed: %d\n", w->name, ret); } } @@ -1466,7 +1469,7 @@ static void dapm_pre_sequence_async(void *data, async_cookie_t cookie) ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_STANDBY); if (ret != 0) dev_err(d->dev, - "Failed to turn on bias: %d\n", ret); + "ASoC: Failed to turn on bias: %d\n", ret); } /* Prepare for a STADDBY->ON or ON->STANDBY transition */ @@ -1474,7 +1477,7 @@ static void dapm_pre_sequence_async(void *data, async_cookie_t cookie) ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_PREPARE); if (ret != 0) dev_err(d->dev, - "Failed to prepare bias: %d\n", ret); + "ASoC: Failed to prepare bias: %d\n", ret); } } @@ -1492,7 +1495,7 @@ static void dapm_post_sequence_async(void *data, async_cookie_t cookie) d->target_bias_level == SND_SOC_BIAS_OFF)) { ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_STANDBY); if (ret != 0) - dev_err(d->dev, "Failed to apply standby bias: %d\n", + dev_err(d->dev, "ASoC: Failed to apply standby bias: %d\n", ret); } @@ -1501,7 +1504,8 @@ static void dapm_post_sequence_async(void *data, async_cookie_t cookie) d->target_bias_level == SND_SOC_BIAS_OFF) { ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_OFF); if (ret != 0) - dev_err(d->dev, "Failed to turn off bias: %d\n", ret); + dev_err(d->dev, "ASoC: Failed to turn off bias: %d\n", + ret); if (d->dev) pm_runtime_put(d->dev); @@ -1512,7 +1516,7 @@ static void dapm_post_sequence_async(void *data, async_cookie_t cookie) d->target_bias_level == SND_SOC_BIAS_ON) { ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_ON); if (ret != 0) - dev_err(d->dev, "Failed to apply active bias: %d\n", + dev_err(d->dev, "ASoC: Failed to apply active bias: %d\n", ret); } } @@ -1838,7 +1842,7 @@ void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm, if (!dapm->debugfs_dapm) { dev_warn(dapm->dev, - "Failed to create DAPM debugfs directory\n"); + "ASoC: Failed to create DAPM debugfs directory\n"); return; } @@ -2123,7 +2127,7 @@ static int snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm, struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true); if (!w) { - dev_err(dapm->dev, "dapm: unknown pin %s\n", pin); + dev_err(dapm->dev, "ASoC: DAPM unknown pin %s\n", pin); return -EINVAL; } @@ -2212,8 +2216,16 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm, if (!wsource) wsource = wtsource; - if (wsource == NULL || wsink == NULL) + if (wsource == NULL) { + dev_err(dapm->dev, "ASoC: no source widget found for %s\n", + route->source); + return -ENODEV; + } + if (wsink == NULL) { + dev_err(dapm->dev, "ASoC: no sink widget found for %s\n", + route->sink); return -ENODEV; + } path = kzalloc(sizeof(struct snd_soc_dapm_path), GFP_KERNEL); if (!path) @@ -2308,7 +2320,7 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm, return 0; err: - dev_warn(dapm->dev, "asoc: no dapm match for %s --> %s --> %s\n", + dev_warn(dapm->dev, "ASoC: no dapm match for %s --> %s --> %s\n", source, control, sink); kfree(path); return ret; @@ -2325,7 +2337,7 @@ static int snd_soc_dapm_del_route(struct snd_soc_dapm_context *dapm, if (route->control) { dev_err(dapm->dev, - "Removal of routes with controls not supported\n"); + "ASoC: Removal of routes with controls not supported\n"); return -EINVAL; } @@ -2360,7 +2372,7 @@ static int snd_soc_dapm_del_route(struct snd_soc_dapm_context *dapm, list_del(&path->list_source); kfree(path); } else { - dev_warn(dapm->dev, "Route %s->%s does not exist\n", + dev_warn(dapm->dev, "ASoC: Route %s->%s does not exist\n", source, sink); } @@ -2389,8 +2401,10 @@ int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm, for (i = 0; i < num; i++) { r = snd_soc_dapm_add_route(dapm, route); if (r < 0) { - dev_err(dapm->dev, "Failed to add route %s->%s\n", - route->source, route->sink); + dev_err(dapm->dev, "ASoC: Failed to add route %s -> %s -> %s\n", + route->source, + route->control ? route->control : "direct", + route->sink); ret = r; } route++; @@ -2438,19 +2452,19 @@ static int snd_soc_dapm_weak_route(struct snd_soc_dapm_context *dapm, int count = 0; if (!source) { - dev_err(dapm->dev, "Unable to find source %s for weak route\n", + dev_err(dapm->dev, "ASoC: Unable to find source %s for weak route\n", route->source); return -ENODEV; } if (!sink) { - dev_err(dapm->dev, "Unable to find sink %s for weak route\n", + dev_err(dapm->dev, "ASoC: Unable to find sink %s for weak route\n", route->sink); return -ENODEV; } if (route->control || route->connected) - dev_warn(dapm->dev, "Ignoring control for weak route %s->%s\n", + dev_warn(dapm->dev, "ASoC: Ignoring control for weak route %s->%s\n", route->source, route->sink); list_for_each_entry(path, &source->sinks, list_source) { @@ -2461,10 +2475,10 @@ static int snd_soc_dapm_weak_route(struct snd_soc_dapm_context *dapm, } if (count == 0) - dev_err(dapm->dev, "No path found for weak route %s->%s\n", + dev_err(dapm->dev, "ASoC: No path found for weak route %s->%s\n", route->source, route->sink); if (count > 1) - dev_warn(dapm->dev, "%d paths found for weak route %s->%s\n", + dev_warn(dapm->dev, "ASoC: %d paths found for weak route %s->%s\n", count, route->source, route->sink); return 0; @@ -2601,7 +2615,7 @@ int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol, if (snd_soc_volsw_is_stereo(mc)) dev_warn(widget->dapm->dev, - "Control '%s' is stereo, which is not supported\n", + "ASoC: Control '%s' is stereo, which is not supported\n", kcontrol->id.name); ucontrol->value.integer.value[0] = @@ -2644,7 +2658,7 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, if (snd_soc_volsw_is_stereo(mc)) dev_warn(widget->dapm->dev, - "Control '%s' is stereo, which is not supported\n", + "ASoC: Control '%s' is stereo, which is not supported\n", kcontrol->id.name); val = (ucontrol->value.integer.value[0] & mask); @@ -3021,17 +3035,25 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, w->regulator = devm_regulator_get(dapm->dev, w->name); if (IS_ERR(w->regulator)) { ret = PTR_ERR(w->regulator); - dev_err(dapm->dev, "Failed to request %s: %d\n", + dev_err(dapm->dev, "ASoC: Failed to request %s: %d\n", w->name, ret); return NULL; } + + if (w->invert & SND_SOC_DAPM_REGULATOR_BYPASS) { + ret = regulator_allow_bypass(w->regulator, true); + if (ret != 0) + dev_warn(w->dapm->dev, + "ASoC: Failed to unbypass %s: %d\n", + w->name, ret); + } break; case snd_soc_dapm_clock_supply: #ifdef CONFIG_CLKDEV_LOOKUP w->clk = devm_clk_get(dapm->dev, w->name); if (IS_ERR(w->clk)) { ret = PTR_ERR(w->clk); - dev_err(dapm->dev, "Failed to request %s: %d\n", + dev_err(dapm->dev, "ASoC: Failed to request %s: %d\n", w->name, ret); return NULL; } @@ -3182,7 +3204,7 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, if (config->formats) { fmt = ffs(config->formats) - 1; } else { - dev_warn(w->dapm->dev, "Invalid format %llx specified\n", + dev_warn(w->dapm->dev, "ASoC: Invalid format %llx specified\n", config->formats); fmt = 0; } @@ -3215,7 +3237,7 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, params, source); if (ret != 0) { dev_err(source->dev, - "hw_params() failed: %d\n", ret); + "ASoC: hw_params() failed: %d\n", ret); goto out; } } @@ -3226,7 +3248,7 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, sink); if (ret != 0) { dev_err(sink->dev, - "hw_params() failed: %d\n", ret); + "ASoC: hw_params() failed: %d\n", ret); goto out; } } @@ -3235,14 +3257,14 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, case SND_SOC_DAPM_POST_PMU: ret = snd_soc_dai_digital_mute(sink, 0); if (ret != 0 && ret != -ENOTSUPP) - dev_warn(sink->dev, "Failed to unmute: %d\n", ret); + dev_warn(sink->dev, "ASoC: Failed to unmute: %d\n", ret); ret = 0; break; case SND_SOC_DAPM_PRE_PMD: ret = snd_soc_dai_digital_mute(sink, 1); if (ret != 0 && ret != -ENOTSUPP) - dev_warn(sink->dev, "Failed to mute: %d\n", ret); + dev_warn(sink->dev, "ASoC: Failed to mute: %d\n", ret); ret = 0; break; @@ -3281,11 +3303,11 @@ int snd_soc_dapm_new_pcm(struct snd_soc_card *card, template.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD; - dev_dbg(card->dev, "adding %s widget\n", link_name); + dev_dbg(card->dev, "ASoC: adding %s widget\n", link_name); w = snd_soc_dapm_new_control(&card->dapm, &template); if (!w) { - dev_err(card->dev, "Failed to create %s widget\n", + dev_err(card->dev, "ASoC: Failed to create %s widget\n", link_name); return -ENOMEM; } @@ -3319,12 +3341,12 @@ int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm, template.name = dai->driver->playback.stream_name; template.sname = dai->driver->playback.stream_name; - dev_dbg(dai->dev, "adding %s widget\n", + dev_dbg(dai->dev, "ASoC: adding %s widget\n", template.name); w = snd_soc_dapm_new_control(dapm, &template); if (!w) { - dev_err(dapm->dev, "Failed to create %s widget\n", + dev_err(dapm->dev, "ASoC: Failed to create %s widget\n", dai->driver->playback.stream_name); } @@ -3337,12 +3359,12 @@ int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm, template.name = dai->driver->capture.stream_name; template.sname = dai->driver->capture.stream_name; - dev_dbg(dai->dev, "adding %s widget\n", + dev_dbg(dai->dev, "ASoC: adding %s widget\n", template.name); w = snd_soc_dapm_new_control(dapm, &template); if (!w) { - dev_err(dapm->dev, "Failed to create %s widget\n", + dev_err(dapm->dev, "ASoC: Failed to create %s widget\n", dai->driver->capture.stream_name); } @@ -3518,11 +3540,11 @@ int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm, struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true); if (!w) { - dev_err(dapm->dev, "dapm: unknown pin %s\n", pin); + dev_err(dapm->dev, "ASoC: unknown pin %s\n", pin); return -EINVAL; } - dev_dbg(w->dapm->dev, "dapm: force enable pin %s\n", pin); + dev_dbg(w->dapm->dev, "ASoC: force enable pin %s\n", pin); w->connected = 1; w->force = 1; dapm_mark_dirty(w, "force enable"); @@ -3605,7 +3627,7 @@ int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm, struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, false); if (!w) { - dev_err(dapm->dev, "dapm: unknown pin %s\n", pin); + dev_err(dapm->dev, "ASoC: unknown pin %s\n", pin); return -EINVAL; } @@ -3664,7 +3686,7 @@ void snd_soc_dapm_auto_nc_codec_pins(struct snd_soc_codec *codec) struct snd_soc_dapm_context *dapm = &codec->dapm; struct snd_soc_dapm_widget *w; - dev_dbg(codec->dev, "Auto NC: DAPMs: card:%p codec:%p\n", + dev_dbg(codec->dev, "ASoC: Auto NC: DAPMs: card:%p codec:%p\n", &card->dapm, &codec->dapm); list_for_each_entry(w, &card->widgets, list) { @@ -3674,7 +3696,7 @@ void snd_soc_dapm_auto_nc_codec_pins(struct snd_soc_codec *codec) case snd_soc_dapm_input: case snd_soc_dapm_output: case snd_soc_dapm_micbias: - dev_dbg(codec->dev, "Auto NC: Checking widget %s\n", + dev_dbg(codec->dev, "ASoC: Auto NC: Checking widget %s\n", w->name); if (!snd_soc_dapm_widget_in_card_paths(card, w)) { dev_dbg(codec->dev, diff --git a/sound/soc/soc-dmaengine-pcm.c b/sound/soc/soc-dmaengine-pcm.c index bbc125748a38..111b7d921e89 100644 --- a/sound/soc/soc-dmaengine-pcm.c +++ b/sound/soc/soc-dmaengine-pcm.c @@ -317,3 +317,5 @@ int snd_dmaengine_pcm_close(struct snd_pcm_substream *substream) return 0; } EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_close); + +MODULE_LICENSE("GPL"); diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c index 1ab5fe04bfcc..0bb5cccd7766 100644 --- a/sound/soc/soc-jack.c +++ b/sound/soc/soc-jack.c @@ -66,7 +66,6 @@ void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask) struct snd_soc_dapm_context *dapm; struct snd_soc_jack_pin *pin; int enable; - int oldstatus; trace_snd_soc_jack_report(jack, mask, status); @@ -78,8 +77,6 @@ void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask) mutex_lock(&jack->mutex); - oldstatus = jack->status; - jack->status &= ~mask; jack->status |= status & mask; @@ -172,12 +169,13 @@ int snd_soc_jack_add_pins(struct snd_soc_jack *jack, int count, for (i = 0; i < count; i++) { if (!pins[i].pin) { - printk(KERN_ERR "No name for pin %d\n", i); + dev_err(jack->codec->dev, "ASoC: No name for pin %d\n", + i); return -EINVAL; } if (!pins[i].mask) { - printk(KERN_ERR "No mask for pin %d (%s)\n", i, - pins[i].pin); + dev_err(jack->codec->dev, "ASoC: No mask for pin %d" + " (%s)\n", i, pins[i].pin); return -EINVAL; } @@ -297,13 +295,13 @@ int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count, for (i = 0; i < count; i++) { if (!gpio_is_valid(gpios[i].gpio)) { - printk(KERN_ERR "Invalid gpio %d\n", + dev_err(jack->codec->dev, "ASoC: Invalid gpio %d\n", gpios[i].gpio); ret = -EINVAL; goto undo; } if (!gpios[i].name) { - printk(KERN_ERR "No name for gpio %d\n", + dev_err(jack->codec->dev, "ASoC: No name for gpio %d\n", gpios[i].gpio); ret = -EINVAL; goto undo; @@ -332,7 +330,7 @@ int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count, if (gpios[i].wake) { ret = irq_set_irq_wake(gpio_to_irq(gpios[i].gpio), 1); if (ret != 0) - printk(KERN_ERR + dev_err(jack->codec->dev, "ASoC: " "Failed to mark GPIO %d as wake source: %d\n", gpios[i].gpio, ret); } diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index ef22d0bd9e9e..cf191e6aebbe 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -43,7 +43,7 @@ static int dpcm_dapm_stream_event(struct snd_soc_pcm_runtime *fe, int dir, struct snd_soc_pcm_runtime *be = dpcm->be; - dev_dbg(be->dev, "pm: BE %s event %d dir %d\n", + dev_dbg(be->dev, "ASoC: BE %s event %d dir %d\n", be->dai_link->name, event, dir); snd_soc_dapm_stream_event(be, dir, event); @@ -70,18 +70,19 @@ static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream, */ if (!soc_dai->rate) { dev_warn(soc_dai->dev, - "Not enforcing symmetric_rates due to race\n"); + "ASoC: Not enforcing symmetric_rates due to race\n"); return 0; } - dev_dbg(soc_dai->dev, "Symmetry forces %dHz rate\n", soc_dai->rate); + dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %dHz rate\n", soc_dai->rate); ret = snd_pcm_hw_constraint_minmax(substream->runtime, SNDRV_PCM_HW_PARAM_RATE, soc_dai->rate, soc_dai->rate); if (ret < 0) { dev_err(soc_dai->dev, - "Unable to apply rate symmetry constraint: %d\n", ret); + "ASoC: Unable to apply rate symmetry constraint: %d\n", + ret); return ret; } @@ -118,7 +119,7 @@ static void soc_pcm_apply_msb(struct snd_pcm_substream *substream, sample_sizes[i], bits); if (ret != 0) dev_warn(dai->dev, - "Failed to set MSB %d/%d: %d\n", + "ASoC: Failed to set MSB %d/%d: %d\n", bits, sample_sizes[i], ret); } } @@ -149,8 +150,8 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) if (cpu_dai->driver->ops->startup) { ret = cpu_dai->driver->ops->startup(substream, cpu_dai); if (ret < 0) { - dev_err(cpu_dai->dev, "can't open interface %s: %d\n", - cpu_dai->name, ret); + dev_err(cpu_dai->dev, "ASoC: can't open interface" + " %s: %d\n", cpu_dai->name, ret); goto out; } } @@ -158,8 +159,8 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) if (platform->driver->ops && platform->driver->ops->open) { ret = platform->driver->ops->open(substream); if (ret < 0) { - dev_err(platform->dev, "can't open platform %s: %d\n", - platform->name, ret); + dev_err(platform->dev, "ASoC: can't open platform" + " %s: %d\n", platform->name, ret); goto platform_err; } } @@ -167,8 +168,8 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) if (codec_dai->driver->ops->startup) { ret = codec_dai->driver->ops->startup(substream, codec_dai); if (ret < 0) { - dev_err(codec_dai->dev, "can't open codec %s: %d\n", - codec_dai->name, ret); + dev_err(codec_dai->dev, "ASoC: can't open codec" + " %s: %d\n", codec_dai->name, ret); goto codec_dai_err; } } @@ -176,7 +177,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) if (rtd->dai_link->ops && rtd->dai_link->ops->startup) { ret = rtd->dai_link->ops->startup(substream); if (ret < 0) { - pr_err("asoc: %s startup failed: %d\n", + pr_err("ASoC: %s startup failed: %d\n", rtd->dai_link->name, ret); goto machine_err; } @@ -238,18 +239,18 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) ret = -EINVAL; snd_pcm_limit_hw_rates(runtime); if (!runtime->hw.rates) { - printk(KERN_ERR "asoc: %s <-> %s No matching rates\n", + printk(KERN_ERR "ASoC: %s <-> %s No matching rates\n", codec_dai->name, cpu_dai->name); goto config_err; } if (!runtime->hw.formats) { - printk(KERN_ERR "asoc: %s <-> %s No matching formats\n", + printk(KERN_ERR "ASoC: %s <-> %s No matching formats\n", codec_dai->name, cpu_dai->name); goto config_err; } if (!runtime->hw.channels_min || !runtime->hw.channels_max || runtime->hw.channels_min > runtime->hw.channels_max) { - printk(KERN_ERR "asoc: %s <-> %s No matching channels\n", + printk(KERN_ERR "ASoC: %s <-> %s No matching channels\n", codec_dai->name, cpu_dai->name); goto config_err; } @@ -270,12 +271,12 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) goto config_err; } - pr_debug("asoc: %s <-> %s info:\n", + pr_debug("ASoC: %s <-> %s info:\n", codec_dai->name, cpu_dai->name); - pr_debug("asoc: rate mask 0x%x\n", runtime->hw.rates); - pr_debug("asoc: min ch %d max ch %d\n", runtime->hw.channels_min, + pr_debug("ASoC: rate mask 0x%x\n", runtime->hw.rates); + pr_debug("ASoC: min ch %d max ch %d\n", runtime->hw.channels_min, runtime->hw.channels_max); - pr_debug("asoc: min rate %d max rate %d\n", runtime->hw.rate_min, + pr_debug("ASoC: min rate %d max rate %d\n", runtime->hw.rate_min, runtime->hw.rate_max); dynamic: @@ -330,14 +331,14 @@ static void close_delayed_work(struct work_struct *work) mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); - pr_debug("pop wq checking: %s status: %s waiting: %s\n", + dev_dbg(rtd->dev, "ASoC: pop wq checking: %s status: %s waiting: %s\n", codec_dai->driver->playback.stream_name, codec_dai->playback_active ? "active" : "inactive", - codec_dai->pop_wait ? "yes" : "no"); + rtd->pop_wait ? "yes" : "no"); /* are we waiting on this codec DAI stream */ - if (codec_dai->pop_wait == 1) { - codec_dai->pop_wait = 0; + if (rtd->pop_wait == 1) { + rtd->pop_wait = 0; snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK, SND_SOC_DAPM_STREAM_STOP); } @@ -407,7 +408,7 @@ static int soc_pcm_close(struct snd_pcm_substream *substream) SND_SOC_DAPM_STREAM_STOP); } else { /* start delayed pop wq here for playback streams */ - codec_dai->pop_wait = 1; + rtd->pop_wait = 1; schedule_delayed_work(&rtd->delayed_work, msecs_to_jiffies(rtd->pmdown_time)); } @@ -444,7 +445,8 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) if (rtd->dai_link->ops && rtd->dai_link->ops->prepare) { ret = rtd->dai_link->ops->prepare(substream); if (ret < 0) { - pr_err("asoc: machine prepare error: %d\n", ret); + dev_err(rtd->card->dev, "ASoC: machine prepare error:" + " %d\n", ret); goto out; } } @@ -452,8 +454,8 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) if (platform->driver->ops && platform->driver->ops->prepare) { ret = platform->driver->ops->prepare(substream); if (ret < 0) { - dev_err(platform->dev, "platform prepare error: %d\n", - ret); + dev_err(platform->dev, "ASoC: platform prepare error:" + " %d\n", ret); goto out; } } @@ -461,7 +463,7 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) if (codec_dai->driver->ops->prepare) { ret = codec_dai->driver->ops->prepare(substream, codec_dai); if (ret < 0) { - dev_err(codec_dai->dev, "DAI prepare error: %d\n", + dev_err(codec_dai->dev, "ASoC: DAI prepare error: %d\n", ret); goto out; } @@ -470,7 +472,7 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) if (cpu_dai->driver->ops->prepare) { ret = cpu_dai->driver->ops->prepare(substream, cpu_dai); if (ret < 0) { - dev_err(cpu_dai->dev, "DAI prepare error: %d\n", + dev_err(cpu_dai->dev, "ASoC: DAI prepare error: %d\n", ret); goto out; } @@ -478,8 +480,8 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) /* cancel any delayed stream shutdown that is pending */ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && - codec_dai->pop_wait) { - codec_dai->pop_wait = 0; + rtd->pop_wait) { + rtd->pop_wait = 0; cancel_delayed_work(&rtd->delayed_work); } @@ -512,7 +514,8 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, if (rtd->dai_link->ops && rtd->dai_link->ops->hw_params) { ret = rtd->dai_link->ops->hw_params(substream, params); if (ret < 0) { - pr_err("asoc: machine hw_params failed: %d\n", ret); + dev_err(rtd->card->dev, "ASoC: machine hw_params" + " failed: %d\n", ret); goto out; } } @@ -520,8 +523,8 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, if (codec_dai->driver->ops->hw_params) { ret = codec_dai->driver->ops->hw_params(substream, params, codec_dai); if (ret < 0) { - dev_err(codec_dai->dev, "can't set %s hw params: %d\n", - codec_dai->name, ret); + dev_err(codec_dai->dev, "ASoC: can't set %s hw params:" + " %d\n", codec_dai->name, ret); goto codec_err; } } @@ -529,7 +532,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, if (cpu_dai->driver->ops->hw_params) { ret = cpu_dai->driver->ops->hw_params(substream, params, cpu_dai); if (ret < 0) { - dev_err(cpu_dai->dev, "%s hw params failed: %d\n", + dev_err(cpu_dai->dev, "ASoC: %s hw params failed: %d\n", cpu_dai->name, ret); goto interface_err; } @@ -538,7 +541,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, if (platform->driver->ops && platform->driver->ops->hw_params) { ret = platform->driver->ops->hw_params(substream, params); if (ret < 0) { - dev_err(platform->dev, "%s hw params failed: %d\n", + dev_err(platform->dev, "ASoC: %s hw params failed: %d\n", platform->name, ret); goto platform_err; } @@ -760,7 +763,7 @@ static void dpcm_be_disconnect(struct snd_soc_pcm_runtime *fe, int stream) struct snd_soc_dpcm *dpcm, *d; list_for_each_entry_safe(dpcm, d, &fe->dpcm[stream].be_clients, list_be) { - dev_dbg(fe->dev, "BE %s disconnect check for %s\n", + dev_dbg(fe->dev, "ASoC: BE %s disconnect check for %s\n", stream ? "capture" : "playback", dpcm->be->dai_link->name); @@ -815,7 +818,7 @@ static struct snd_soc_pcm_runtime *dpcm_get_be(struct snd_soc_card *card, } } - dev_err(card->dev, "can't get %s BE for %s\n", + dev_err(card->dev, "ASoC: can't get %s BE for %s\n", stream ? "capture" : "playback", widget->name); return NULL; } @@ -866,7 +869,7 @@ static int dpcm_path_get(struct snd_soc_pcm_runtime *fe, /* get number of valid DAI paths and their widgets */ paths = snd_soc_dapm_dai_get_connected_widgets(cpu_dai, stream, &list); - dev_dbg(fe->dev, "found %d audio %s paths\n", paths, + dev_dbg(fe->dev, "ASoC: found %d audio %s paths\n", paths, stream ? "capture" : "playback"); *list_ = list; @@ -903,7 +906,7 @@ static int dpcm_prune_paths(struct snd_soc_pcm_runtime *fe, int stream, if (widget && widget_in_list(list, widget)) continue; - dev_dbg(fe->dev, "pruning %s BE %s for %s\n", + dev_dbg(fe->dev, "ASoC: pruning %s BE %s for %s\n", stream ? "capture" : "playback", dpcm->be->dai_link->name, fe->dai_link->name); dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE; @@ -911,7 +914,7 @@ static int dpcm_prune_paths(struct snd_soc_pcm_runtime *fe, int stream, prune++; } - dev_dbg(fe->dev, "found %d old BE paths for pruning\n", prune); + dev_dbg(fe->dev, "ASoC: found %d old BE paths for pruning\n", prune); return prune; } @@ -932,7 +935,7 @@ static int dpcm_add_paths(struct snd_soc_pcm_runtime *fe, int stream, /* is there a valid BE rtd for this widget */ be = dpcm_get_be(card, list->widgets[i], stream); if (!be) { - dev_err(fe->dev, "no BE found for %s\n", + dev_err(fe->dev, "ASoC: no BE found for %s\n", list->widgets[i]->name); continue; } @@ -948,7 +951,7 @@ static int dpcm_add_paths(struct snd_soc_pcm_runtime *fe, int stream, /* newly connected FE and BE */ err = dpcm_be_connect(fe, be, stream); if (err < 0) { - dev_err(fe->dev, "can't connect %s\n", + dev_err(fe->dev, "ASoC: can't connect %s\n", list->widgets[i]->name); break; } else if (err == 0) /* already connected */ @@ -959,7 +962,7 @@ static int dpcm_add_paths(struct snd_soc_pcm_runtime *fe, int stream, new++; } - dev_dbg(fe->dev, "found %d new BE paths\n", new); + dev_dbg(fe->dev, "ASoC: found %d new BE paths\n", new); return new; } @@ -998,7 +1001,7 @@ static void dpcm_be_dai_startup_unwind(struct snd_soc_pcm_runtime *fe, snd_soc_dpcm_get_substream(be, stream); if (be->dpcm[stream].users == 0) - dev_err(be->dev, "no users %s at close - state %d\n", + dev_err(be->dev, "ASoC: no users %s at close - state %d\n", stream ? "capture" : "playback", be->dpcm[stream].state); @@ -1032,7 +1035,7 @@ static int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream) /* first time the dpcm is open ? */ if (be->dpcm[stream].users == DPCM_MAX_BE_USERS) - dev_err(be->dev, "too many users %s at open %d\n", + dev_err(be->dev, "ASoC: too many users %s at open %d\n", stream ? "capture" : "playback", be->dpcm[stream].state); @@ -1043,15 +1046,15 @@ static int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream) (be->dpcm[stream].state != SND_SOC_DPCM_STATE_CLOSE)) continue; - dev_dbg(be->dev, "dpcm: open BE %s\n", be->dai_link->name); + dev_dbg(be->dev, "ASoC: open BE %s\n", be->dai_link->name); be_substream->runtime = be->dpcm[stream].runtime; err = soc_pcm_open(be_substream); if (err < 0) { - dev_err(be->dev, "BE open failed %d\n", err); + dev_err(be->dev, "ASoC: BE open failed %d\n", err); be->dpcm[stream].users--; if (be->dpcm[stream].users < 0) - dev_err(be->dev, "no users %s at unwind %d\n", + dev_err(be->dev, "ASoC: no users %s at unwind %d\n", stream ? "capture" : "playback", be->dpcm[stream].state); @@ -1076,7 +1079,7 @@ unwind: continue; if (be->dpcm[stream].users == 0) - dev_err(be->dev, "no users %s at close %d\n", + dev_err(be->dev, "ASoC: no users %s at close %d\n", stream ? "capture" : "playback", be->dpcm[stream].state); @@ -1128,16 +1131,16 @@ static int dpcm_fe_dai_startup(struct snd_pcm_substream *fe_substream) ret = dpcm_be_dai_startup(fe, fe_substream->stream); if (ret < 0) { - dev_err(fe->dev,"dpcm: failed to start some BEs %d\n", ret); + dev_err(fe->dev,"ASoC: failed to start some BEs %d\n", ret); goto be_err; } - dev_dbg(fe->dev, "dpcm: open FE %s\n", fe->dai_link->name); + dev_dbg(fe->dev, "ASoC: open FE %s\n", fe->dai_link->name); /* start the DAI frontend */ ret = soc_pcm_open(fe_substream); if (ret < 0) { - dev_err(fe->dev,"dpcm: failed to start FE %d\n", ret); + dev_err(fe->dev,"ASoC: failed to start FE %d\n", ret); goto unwind; } @@ -1172,7 +1175,7 @@ static int dpcm_be_dai_shutdown(struct snd_soc_pcm_runtime *fe, int stream) continue; if (be->dpcm[stream].users == 0) - dev_err(be->dev, "no users %s at close - state %d\n", + dev_err(be->dev, "ASoC: no users %s at close - state %d\n", stream ? "capture" : "playback", be->dpcm[stream].state); @@ -1183,7 +1186,7 @@ static int dpcm_be_dai_shutdown(struct snd_soc_pcm_runtime *fe, int stream) (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN)) continue; - dev_dbg(be->dev, "dpcm: close BE %s\n", + dev_dbg(be->dev, "ASoC: close BE %s\n", dpcm->fe->dai_link->name); soc_pcm_close(be_substream); @@ -1204,7 +1207,7 @@ static int dpcm_fe_dai_shutdown(struct snd_pcm_substream *substream) /* shutdown the BEs */ dpcm_be_dai_shutdown(fe, substream->stream); - dev_dbg(fe->dev, "dpcm: close FE %s\n", fe->dai_link->name); + dev_dbg(fe->dev, "ASoC: close FE %s\n", fe->dai_link->name); /* now shutdown the frontend */ soc_pcm_close(substream); @@ -1240,10 +1243,11 @@ static int dpcm_be_dai_hw_free(struct snd_soc_pcm_runtime *fe, int stream) if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) && (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) && (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) && + (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED) && (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP)) continue; - dev_dbg(be->dev, "dpcm: hw_free BE %s\n", + dev_dbg(be->dev, "ASoC: hw_free BE %s\n", dpcm->fe->dai_link->name); soc_pcm_hw_free(be_substream); @@ -1262,12 +1266,12 @@ static int dpcm_fe_dai_hw_free(struct snd_pcm_substream *substream) mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; - dev_dbg(fe->dev, "dpcm: hw_free FE %s\n", fe->dai_link->name); + dev_dbg(fe->dev, "ASoC: hw_free FE %s\n", fe->dai_link->name); /* call hw_free on the frontend */ err = soc_pcm_hw_free(substream); if (err < 0) - dev_err(fe->dev,"dpcm: hw_free FE %s failed\n", + dev_err(fe->dev,"ASoC: hw_free FE %s failed\n", fe->dai_link->name); /* only hw_params backends that are either sinks or sources @@ -1305,7 +1309,7 @@ static int dpcm_be_dai_hw_params(struct snd_soc_pcm_runtime *fe, int stream) (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE)) continue; - dev_dbg(be->dev, "dpcm: hw_params BE %s\n", + dev_dbg(be->dev, "ASoC: hw_params BE %s\n", dpcm->fe->dai_link->name); /* copy params for each dpcm */ @@ -1318,7 +1322,7 @@ static int dpcm_be_dai_hw_params(struct snd_soc_pcm_runtime *fe, int stream) &dpcm->hw_params); if (ret < 0) { dev_err(be->dev, - "dpcm: hw_params BE fixup failed %d\n", + "ASoC: hw_params BE fixup failed %d\n", ret); goto unwind; } @@ -1327,7 +1331,7 @@ static int dpcm_be_dai_hw_params(struct snd_soc_pcm_runtime *fe, int stream) ret = soc_pcm_hw_params(be_substream, &dpcm->hw_params); if (ret < 0) { dev_err(dpcm->be->dev, - "dpcm: hw_params BE failed %d\n", ret); + "ASoC: hw_params BE failed %d\n", ret); goto unwind; } @@ -1374,18 +1378,18 @@ static int dpcm_fe_dai_hw_params(struct snd_pcm_substream *substream, sizeof(struct snd_pcm_hw_params)); ret = dpcm_be_dai_hw_params(fe, substream->stream); if (ret < 0) { - dev_err(fe->dev,"dpcm: hw_params BE failed %d\n", ret); + dev_err(fe->dev,"ASoC: hw_params BE failed %d\n", ret); goto out; } - dev_dbg(fe->dev, "dpcm: hw_params FE %s rate %d chan %x fmt %d\n", + dev_dbg(fe->dev, "ASoC: hw_params FE %s rate %d chan %x fmt %d\n", fe->dai_link->name, params_rate(params), params_channels(params), params_format(params)); /* call hw_params on the frontend */ ret = soc_pcm_hw_params(substream, params); if (ret < 0) { - dev_err(fe->dev,"dpcm: hw_params FE failed %d\n", ret); + dev_err(fe->dev,"ASoC: hw_params FE failed %d\n", ret); dpcm_be_dai_hw_free(fe, stream); } else fe->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_PARAMS; @@ -1401,12 +1405,12 @@ static int dpcm_do_trigger(struct snd_soc_dpcm *dpcm, { int ret; - dev_dbg(dpcm->be->dev, "dpcm: trigger BE %s cmd %d\n", + dev_dbg(dpcm->be->dev, "ASoC: trigger BE %s cmd %d\n", dpcm->fe->dai_link->name, cmd); ret = soc_pcm_trigger(substream, cmd); if (ret < 0) - dev_err(dpcm->be->dev,"dpcm: trigger BE failed %d\n", ret); + dev_err(dpcm->be->dev,"ASoC: trigger BE failed %d\n", ret); return ret; } @@ -1517,12 +1521,12 @@ static int dpcm_fe_dai_trigger(struct snd_pcm_substream *substream, int cmd) case SND_SOC_DPCM_TRIGGER_PRE: /* call trigger on the frontend before the backend. */ - dev_dbg(fe->dev, "dpcm: pre trigger FE %s cmd %d\n", + dev_dbg(fe->dev, "ASoC: pre trigger FE %s cmd %d\n", fe->dai_link->name, cmd); ret = soc_pcm_trigger(substream, cmd); if (ret < 0) { - dev_err(fe->dev,"dpcm: trigger FE failed %d\n", ret); + dev_err(fe->dev,"ASoC: trigger FE failed %d\n", ret); goto out; } @@ -1533,11 +1537,11 @@ static int dpcm_fe_dai_trigger(struct snd_pcm_substream *substream, int cmd) ret = dpcm_be_dai_trigger(fe, substream->stream, cmd); if (ret < 0) { - dev_err(fe->dev,"dpcm: trigger FE failed %d\n", ret); + dev_err(fe->dev,"ASoC: trigger FE failed %d\n", ret); goto out; } - dev_dbg(fe->dev, "dpcm: post trigger FE %s cmd %d\n", + dev_dbg(fe->dev, "ASoC: post trigger FE %s cmd %d\n", fe->dai_link->name, cmd); ret = soc_pcm_trigger(substream, cmd); @@ -1545,17 +1549,17 @@ static int dpcm_fe_dai_trigger(struct snd_pcm_substream *substream, int cmd) case SND_SOC_DPCM_TRIGGER_BESPOKE: /* bespoke trigger() - handles both FE and BEs */ - dev_dbg(fe->dev, "dpcm: bespoke trigger FE %s cmd %d\n", + dev_dbg(fe->dev, "ASoC: bespoke trigger FE %s cmd %d\n", fe->dai_link->name, cmd); ret = soc_pcm_bespoke_trigger(substream, cmd); if (ret < 0) { - dev_err(fe->dev,"dpcm: trigger FE failed %d\n", ret); + dev_err(fe->dev,"ASoC: trigger FE failed %d\n", ret); goto out; } break; default: - dev_err(fe->dev, "dpcm: invalid trigger cmd %d for %s\n", cmd, + dev_err(fe->dev, "ASoC: invalid trigger cmd %d for %s\n", cmd, fe->dai_link->name); ret = -EINVAL; goto out; @@ -1598,12 +1602,12 @@ static int dpcm_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream) (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP)) continue; - dev_dbg(be->dev, "dpcm: prepare BE %s\n", + dev_dbg(be->dev, "ASoC: prepare BE %s\n", dpcm->fe->dai_link->name); ret = soc_pcm_prepare(be_substream); if (ret < 0) { - dev_err(be->dev, "dpcm: backend prepare failed %d\n", + dev_err(be->dev, "ASoC: backend prepare failed %d\n", ret); break; } @@ -1620,13 +1624,13 @@ static int dpcm_fe_dai_prepare(struct snd_pcm_substream *substream) mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); - dev_dbg(fe->dev, "dpcm: prepare FE %s\n", fe->dai_link->name); + dev_dbg(fe->dev, "ASoC: prepare FE %s\n", fe->dai_link->name); fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; /* there is no point preparing this FE if there are no BEs */ if (list_empty(&fe->dpcm[stream].be_clients)) { - dev_err(fe->dev, "dpcm: no backend DAIs enabled for %s\n", + dev_err(fe->dev, "ASoC: no backend DAIs enabled for %s\n", fe->dai_link->name); ret = -EINVAL; goto out; @@ -1639,7 +1643,7 @@ static int dpcm_fe_dai_prepare(struct snd_pcm_substream *substream) /* call prepare on the frontend */ ret = soc_pcm_prepare(substream); if (ret < 0) { - dev_err(fe->dev,"dpcm: prepare FE %s failed\n", + dev_err(fe->dev,"ASoC: prepare FE %s failed\n", fe->dai_link->name); goto out; } @@ -1673,33 +1677,33 @@ static int dpcm_run_update_shutdown(struct snd_soc_pcm_runtime *fe, int stream) enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream]; int err; - dev_dbg(fe->dev, "runtime %s close on FE %s\n", + dev_dbg(fe->dev, "ASoC: runtime %s close on FE %s\n", stream ? "capture" : "playback", fe->dai_link->name); if (trigger == SND_SOC_DPCM_TRIGGER_BESPOKE) { /* call bespoke trigger - FE takes care of all BE triggers */ - dev_dbg(fe->dev, "dpcm: bespoke trigger FE %s cmd stop\n", + dev_dbg(fe->dev, "ASoC: bespoke trigger FE %s cmd stop\n", fe->dai_link->name); err = soc_pcm_bespoke_trigger(substream, SNDRV_PCM_TRIGGER_STOP); if (err < 0) - dev_err(fe->dev,"dpcm: trigger FE failed %d\n", err); + dev_err(fe->dev,"ASoC: trigger FE failed %d\n", err); } else { - dev_dbg(fe->dev, "dpcm: trigger FE %s cmd stop\n", + dev_dbg(fe->dev, "ASoC: trigger FE %s cmd stop\n", fe->dai_link->name); err = dpcm_be_dai_trigger(fe, stream, SNDRV_PCM_TRIGGER_STOP); if (err < 0) - dev_err(fe->dev,"dpcm: trigger FE failed %d\n", err); + dev_err(fe->dev,"ASoC: trigger FE failed %d\n", err); } err = dpcm_be_dai_hw_free(fe, stream); if (err < 0) - dev_err(fe->dev,"dpcm: hw_free FE failed %d\n", err); + dev_err(fe->dev,"ASoC: hw_free FE failed %d\n", err); err = dpcm_be_dai_shutdown(fe, stream); if (err < 0) - dev_err(fe->dev,"dpcm: shutdown FE failed %d\n", err); + dev_err(fe->dev,"ASoC: shutdown FE failed %d\n", err); /* run the stream event for each BE */ dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_NOP); @@ -1715,7 +1719,7 @@ static int dpcm_run_update_startup(struct snd_soc_pcm_runtime *fe, int stream) enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream]; int ret; - dev_dbg(fe->dev, "runtime %s open on FE %s\n", + dev_dbg(fe->dev, "ASoC: runtime %s open on FE %s\n", stream ? "capture" : "playback", fe->dai_link->name); /* Only start the BE if the FE is ready */ @@ -1761,22 +1765,22 @@ static int dpcm_run_update_startup(struct snd_soc_pcm_runtime *fe, int stream) if (trigger == SND_SOC_DPCM_TRIGGER_BESPOKE) { /* call trigger on the frontend - FE takes care of all BE triggers */ - dev_dbg(fe->dev, "dpcm: bespoke trigger FE %s cmd start\n", + dev_dbg(fe->dev, "ASoC: bespoke trigger FE %s cmd start\n", fe->dai_link->name); ret = soc_pcm_bespoke_trigger(substream, SNDRV_PCM_TRIGGER_START); if (ret < 0) { - dev_err(fe->dev,"dpcm: bespoke trigger FE failed %d\n", ret); + dev_err(fe->dev,"ASoC: bespoke trigger FE failed %d\n", ret); goto hw_free; } } else { - dev_dbg(fe->dev, "dpcm: trigger FE %s cmd start\n", + dev_dbg(fe->dev, "ASoC: trigger FE %s cmd start\n", fe->dai_link->name); ret = dpcm_be_dai_trigger(fe, stream, SNDRV_PCM_TRIGGER_START); if (ret < 0) { - dev_err(fe->dev,"dpcm: trigger FE failed %d\n", ret); + dev_err(fe->dev,"ASoC: trigger FE failed %d\n", ret); goto hw_free; } } @@ -1805,7 +1809,7 @@ static int dpcm_run_new_update(struct snd_soc_pcm_runtime *fe, int stream) fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_BE; ret = dpcm_run_update_startup(fe, stream); if (ret < 0) - dev_err(fe->dev, "failed to startup some BEs\n"); + dev_err(fe->dev, "ASoC: failed to startup some BEs\n"); fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; return ret; @@ -1818,7 +1822,7 @@ static int dpcm_run_old_update(struct snd_soc_pcm_runtime *fe, int stream) fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_BE; ret = dpcm_run_update_shutdown(fe, stream); if (ret < 0) - dev_err(fe->dev, "failed to shutdown some BEs\n"); + dev_err(fe->dev, "ASoC: failed to shutdown some BEs\n"); fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; return ret; @@ -1853,7 +1857,7 @@ int soc_dpcm_runtime_update(struct snd_soc_dapm_widget *widget) continue; /* DAPM sync will call this to update DSP paths */ - dev_dbg(fe->dev, "DPCM runtime update for FE %s\n", + dev_dbg(fe->dev, "ASoC: DPCM runtime update for FE %s\n", fe->dai_link->name); /* skip if FE doesn't have playback capability */ @@ -1862,7 +1866,7 @@ int soc_dpcm_runtime_update(struct snd_soc_dapm_widget *widget) paths = dpcm_path_get(fe, SNDRV_PCM_STREAM_PLAYBACK, &list); if (paths < 0) { - dev_warn(fe->dev, "%s no valid %s path\n", + dev_warn(fe->dev, "ASoC: %s no valid %s path\n", fe->dai_link->name, "playback"); mutex_unlock(&card->mutex); return paths; @@ -1891,7 +1895,7 @@ capture: paths = dpcm_path_get(fe, SNDRV_PCM_STREAM_CAPTURE, &list); if (paths < 0) { - dev_warn(fe->dev, "%s no valid %s path\n", + dev_warn(fe->dev, "ASoC: %s no valid %s path\n", fe->dai_link->name, "capture"); mutex_unlock(&card->mutex); return paths; @@ -1934,7 +1938,7 @@ int soc_dpcm_be_digital_mute(struct snd_soc_pcm_runtime *fe, int mute) if (be->dai_link->ignore_suspend) continue; - dev_dbg(be->dev, "BE digital mute %s\n", be->dai_link->name); + dev_dbg(be->dev, "ASoC: BE digital mute %s\n", be->dai_link->name); if (drv->ops->digital_mute && dai->playback_active) drv->ops->digital_mute(dai, mute); @@ -1955,7 +1959,7 @@ static int dpcm_fe_dai_open(struct snd_pcm_substream *fe_substream) fe->dpcm[stream].runtime = fe_substream->runtime; if (dpcm_path_get(fe, stream, &list) <= 0) { - dev_dbg(fe->dev, "asoc: %s no valid %s route\n", + dev_dbg(fe->dev, "ASoC: %s no valid %s route\n", fe->dai_link->name, stream ? "capture" : "playback"); } @@ -2039,11 +2043,11 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) capture, &pcm); } if (ret < 0) { - dev_err(rtd->card->dev, "can't create pcm for %s\n", + dev_err(rtd->card->dev, "ASoC: can't create pcm for %s\n", rtd->dai_link->name); return ret; } - dev_dbg(rtd->card->dev, "registered pcm #%d %s\n",num, new_name); + dev_dbg(rtd->card->dev, "ASoC: registered pcm #%d %s\n",num, new_name); /* DAPM dai link stream work */ INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work); @@ -2097,7 +2101,9 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) if (platform->driver->pcm_new) { ret = platform->driver->pcm_new(rtd); if (ret < 0) { - dev_err(platform->dev, "pcm constructor failed\n"); + dev_err(platform->dev, + "ASoC: pcm constructor failed: %d\n", + ret); return ret; } } diff --git a/sound/soc/soc-utils.c b/sound/soc/soc-utils.c index 60053709e417..fe4541df498c 100644 --- a/sound/soc/soc-utils.c +++ b/sound/soc/soc-utils.c @@ -94,7 +94,7 @@ static struct snd_soc_dai_driver dummy_dai = { .name = "snd-soc-dummy-dai", }; -static __devinit int snd_soc_dummy_probe(struct platform_device *pdev) +static int snd_soc_dummy_probe(struct platform_device *pdev) { int ret; @@ -111,7 +111,7 @@ static __devinit int snd_soc_dummy_probe(struct platform_device *pdev) return ret; } -static __devexit int snd_soc_dummy_remove(struct platform_device *pdev) +static int snd_soc_dummy_remove(struct platform_device *pdev) { snd_soc_unregister_platform(&pdev->dev); snd_soc_unregister_codec(&pdev->dev); @@ -125,7 +125,7 @@ static struct platform_driver soc_dummy_driver = { .owner = THIS_MODULE, }, .probe = snd_soc_dummy_probe, - .remove = __devexit_p(snd_soc_dummy_remove), + .remove = snd_soc_dummy_remove, }; static struct platform_device *soc_dummy_dev; diff --git a/sound/soc/spear/spear_pcm.c b/sound/soc/spear/spear_pcm.c index 8c7f23729446..9b76cc5a1148 100644 --- a/sound/soc/spear/spear_pcm.c +++ b/sound/soc/spear/spear_pcm.c @@ -184,12 +184,12 @@ struct snd_soc_platform_driver spear_soc_platform = { .pcm_free = spear_pcm_free, }; -static int __devinit spear_soc_platform_probe(struct platform_device *pdev) +static int spear_soc_platform_probe(struct platform_device *pdev) { return snd_soc_register_platform(&pdev->dev, &spear_soc_platform); } -static int __devexit spear_soc_platform_remove(struct platform_device *pdev) +static int spear_soc_platform_remove(struct platform_device *pdev) { snd_soc_unregister_platform(&pdev->dev); @@ -203,7 +203,7 @@ static struct platform_driver spear_pcm_driver = { }, .probe = spear_soc_platform_probe, - .remove = __devexit_p(spear_soc_platform_remove), + .remove = spear_soc_platform_remove, }; module_platform_driver(spear_pcm_driver); diff --git a/sound/soc/tegra/tegra20_das.c b/sound/soc/tegra/tegra20_das.c index bf99296bce95..654318483877 100644 --- a/sound/soc/tegra/tegra20_das.c +++ b/sound/soc/tegra/tegra20_das.c @@ -131,7 +131,7 @@ static const struct regmap_config tegra20_das_regmap_config = { .cache_type = REGCACHE_RBTREE, }; -static int __devinit tegra20_das_probe(struct platform_device *pdev) +static int tegra20_das_probe(struct platform_device *pdev) { struct resource *res, *region; void __iomem *regs; @@ -200,7 +200,7 @@ err: return ret; } -static int __devexit tegra20_das_remove(struct platform_device *pdev) +static int tegra20_das_remove(struct platform_device *pdev) { if (!das) return -ENODEV; @@ -210,14 +210,14 @@ static int __devexit tegra20_das_remove(struct platform_device *pdev) return 0; } -static const struct of_device_id tegra20_das_of_match[] __devinitconst = { +static const struct of_device_id tegra20_das_of_match[] = { { .compatible = "nvidia,tegra20-das", }, {}, }; static struct platform_driver tegra20_das_driver = { .probe = tegra20_das_probe, - .remove = __devexit_p(tegra20_das_remove), + .remove = tegra20_das_remove, .driver = { .name = DRV_NAME, .owner = THIS_MODULE, diff --git a/sound/soc/tegra/tegra20_i2s.c b/sound/soc/tegra/tegra20_i2s.c index 0832e8afd73c..caa772de5a18 100644 --- a/sound/soc/tegra/tegra20_i2s.c +++ b/sound/soc/tegra/tegra20_i2s.c @@ -331,7 +331,7 @@ static const struct regmap_config tegra20_i2s_regmap_config = { .cache_type = REGCACHE_RBTREE, }; -static __devinit int tegra20_i2s_platform_probe(struct platform_device *pdev) +static int tegra20_i2s_platform_probe(struct platform_device *pdev) { struct tegra20_i2s *i2s; struct resource *mem, *memregion, *dmareq; @@ -447,7 +447,7 @@ err: return ret; } -static int __devexit tegra20_i2s_platform_remove(struct platform_device *pdev) +static int tegra20_i2s_platform_remove(struct platform_device *pdev) { struct tegra20_i2s *i2s = dev_get_drvdata(&pdev->dev); @@ -463,12 +463,12 @@ static int __devexit tegra20_i2s_platform_remove(struct platform_device *pdev) return 0; } -static const struct of_device_id tegra20_i2s_of_match[] __devinitconst = { +static const struct of_device_id tegra20_i2s_of_match[] = { { .compatible = "nvidia,tegra20-i2s", }, {}, }; -static const struct dev_pm_ops tegra20_i2s_pm_ops __devinitconst = { +static const struct dev_pm_ops tegra20_i2s_pm_ops = { SET_RUNTIME_PM_OPS(tegra20_i2s_runtime_suspend, tegra20_i2s_runtime_resume, NULL) }; @@ -481,7 +481,7 @@ static struct platform_driver tegra20_i2s_driver = { .pm = &tegra20_i2s_pm_ops, }, .probe = tegra20_i2s_platform_probe, - .remove = __devexit_p(tegra20_i2s_platform_remove), + .remove = tegra20_i2s_platform_remove, }; module_platform_driver(tegra20_i2s_driver); diff --git a/sound/soc/tegra/tegra20_spdif.c b/sound/soc/tegra/tegra20_spdif.c index 3ebc8670ba00..04771d14d343 100644 --- a/sound/soc/tegra/tegra20_spdif.c +++ b/sound/soc/tegra/tegra20_spdif.c @@ -257,7 +257,7 @@ static const struct regmap_config tegra20_spdif_regmap_config = { .cache_type = REGCACHE_RBTREE, }; -static __devinit int tegra20_spdif_platform_probe(struct platform_device *pdev) +static int tegra20_spdif_platform_probe(struct platform_device *pdev) { struct tegra20_spdif *spdif; struct resource *mem, *memregion, *dmareq; @@ -357,7 +357,7 @@ err: return ret; } -static int __devexit tegra20_spdif_platform_remove(struct platform_device *pdev) +static int tegra20_spdif_platform_remove(struct platform_device *pdev) { struct tegra20_spdif *spdif = dev_get_drvdata(&pdev->dev); @@ -373,7 +373,7 @@ static int __devexit tegra20_spdif_platform_remove(struct platform_device *pdev) return 0; } -static const struct dev_pm_ops tegra20_spdif_pm_ops __devinitconst = { +static const struct dev_pm_ops tegra20_spdif_pm_ops = { SET_RUNTIME_PM_OPS(tegra20_spdif_runtime_suspend, tegra20_spdif_runtime_resume, NULL) }; @@ -385,7 +385,7 @@ static struct platform_driver tegra20_spdif_driver = { .pm = &tegra20_spdif_pm_ops, }, .probe = tegra20_spdif_platform_probe, - .remove = __devexit_p(tegra20_spdif_platform_remove), + .remove = tegra20_spdif_platform_remove, }; module_platform_driver(tegra20_spdif_driver); diff --git a/sound/soc/tegra/tegra30_ahub.c b/sound/soc/tegra/tegra30_ahub.c index bf5610122c76..f354dc390a0b 100644 --- a/sound/soc/tegra/tegra30_ahub.c +++ b/sound/soc/tegra/tegra30_ahub.c @@ -26,7 +26,6 @@ #include <linux/regmap.h> #include <linux/slab.h> #include <mach/clk.h> -#include <mach/dma.h> #include <sound/soc.h> #include "tegra30_ahub.h" @@ -288,7 +287,7 @@ int tegra30_ahub_unset_rx_cif_source(enum tegra30_ahub_rxcif rxcif) } EXPORT_SYMBOL_GPL(tegra30_ahub_unset_rx_cif_source); -static const char * const configlink_clocks[] __devinitconst = { +static const char * const configlink_clocks[] = { "i2s0", "i2s1", "i2s2", @@ -300,7 +299,7 @@ static const char * const configlink_clocks[] __devinitconst = { "spdif_in", }; -struct of_dev_auxdata ahub_auxdata[] __devinitdata = { +struct of_dev_auxdata ahub_auxdata[] = { OF_DEV_AUXDATA("nvidia,tegra30-i2s", 0x70080300, "tegra30-i2s.0", NULL), OF_DEV_AUXDATA("nvidia,tegra30-i2s", 0x70080400, "tegra30-i2s.1", NULL), OF_DEV_AUXDATA("nvidia,tegra30-i2s", 0x70080500, "tegra30-i2s.2", NULL), @@ -434,7 +433,7 @@ static const struct regmap_config tegra30_ahub_ahub_regmap_config = { .cache_type = REGCACHE_RBTREE, }; -static int __devinit tegra30_ahub_probe(struct platform_device *pdev) +static int tegra30_ahub_probe(struct platform_device *pdev) { struct clk *clk; int i; @@ -586,7 +585,7 @@ err: return ret; } -static int __devexit tegra30_ahub_remove(struct platform_device *pdev) +static int tegra30_ahub_remove(struct platform_device *pdev) { if (!ahub) return -ENODEV; @@ -603,19 +602,19 @@ static int __devexit tegra30_ahub_remove(struct platform_device *pdev) return 0; } -static const struct of_device_id tegra30_ahub_of_match[] __devinitconst = { +static const struct of_device_id tegra30_ahub_of_match[] = { { .compatible = "nvidia,tegra30-ahub", }, {}, }; -static const struct dev_pm_ops tegra30_ahub_pm_ops __devinitconst = { +static const struct dev_pm_ops tegra30_ahub_pm_ops = { SET_RUNTIME_PM_OPS(tegra30_ahub_runtime_suspend, tegra30_ahub_runtime_resume, NULL) }; static struct platform_driver tegra30_ahub_driver = { .probe = tegra30_ahub_probe, - .remove = __devexit_p(tegra30_ahub_remove), + .remove = tegra30_ahub_remove, .driver = { .name = DRV_NAME, .owner = THIS_MODULE, diff --git a/sound/soc/tegra/tegra30_i2s.c b/sound/soc/tegra/tegra30_i2s.c index 44184228d1f0..27e91dd0b91c 100644 --- a/sound/soc/tegra/tegra30_i2s.c +++ b/sound/soc/tegra/tegra30_i2s.c @@ -391,7 +391,7 @@ static const struct regmap_config tegra30_i2s_regmap_config = { .cache_type = REGCACHE_RBTREE, }; -static __devinit int tegra30_i2s_platform_probe(struct platform_device *pdev) +static int tegra30_i2s_platform_probe(struct platform_device *pdev) { struct tegra30_i2s *i2s; u32 cif_ids[2]; @@ -492,7 +492,7 @@ err: return ret; } -static int __devexit tegra30_i2s_platform_remove(struct platform_device *pdev) +static int tegra30_i2s_platform_remove(struct platform_device *pdev) { struct tegra30_i2s *i2s = dev_get_drvdata(&pdev->dev); @@ -508,12 +508,12 @@ static int __devexit tegra30_i2s_platform_remove(struct platform_device *pdev) return 0; } -static const struct of_device_id tegra30_i2s_of_match[] __devinitconst = { +static const struct of_device_id tegra30_i2s_of_match[] = { { .compatible = "nvidia,tegra30-i2s", }, {}, }; -static const struct dev_pm_ops tegra30_i2s_pm_ops __devinitconst = { +static const struct dev_pm_ops tegra30_i2s_pm_ops = { SET_RUNTIME_PM_OPS(tegra30_i2s_runtime_suspend, tegra30_i2s_runtime_resume, NULL) }; @@ -526,7 +526,7 @@ static struct platform_driver tegra30_i2s_driver = { .pm = &tegra30_i2s_pm_ops, }, .probe = tegra30_i2s_platform_probe, - .remove = __devexit_p(tegra30_i2s_platform_remove), + .remove = tegra30_i2s_platform_remove, }; module_platform_driver(tegra30_i2s_driver); diff --git a/sound/soc/tegra/tegra_alc5632.c b/sound/soc/tegra/tegra_alc5632.c index 76cb1b363b71..c80adb9da472 100644 --- a/sound/soc/tegra/tegra_alc5632.c +++ b/sound/soc/tegra/tegra_alc5632.c @@ -150,7 +150,7 @@ static struct snd_soc_card snd_soc_tegra_alc5632 = { .fully_routed = true, }; -static __devinit int tegra_alc5632_probe(struct platform_device *pdev) +static int tegra_alc5632_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; struct snd_soc_card *card = &snd_soc_tegra_alc5632; @@ -227,7 +227,7 @@ err: return ret; } -static int __devexit tegra_alc5632_remove(struct platform_device *pdev) +static int tegra_alc5632_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); struct tegra_alc5632 *machine = snd_soc_card_get_drvdata(card); @@ -242,7 +242,7 @@ static int __devexit tegra_alc5632_remove(struct platform_device *pdev) return 0; } -static const struct of_device_id tegra_alc5632_of_match[] __devinitconst = { +static const struct of_device_id tegra_alc5632_of_match[] = { { .compatible = "nvidia,tegra-audio-alc5632", }, {}, }; @@ -255,7 +255,7 @@ static struct platform_driver tegra_alc5632_driver = { .of_match_table = tegra_alc5632_of_match, }, .probe = tegra_alc5632_probe, - .remove = __devexit_p(tegra_alc5632_remove), + .remove = tegra_alc5632_remove, }; module_platform_driver(tegra_alc5632_driver); diff --git a/sound/soc/tegra/tegra_pcm.c b/sound/soc/tegra/tegra_pcm.c index e18733963cb4..c925ab0adeb6 100644 --- a/sound/soc/tegra/tegra_pcm.c +++ b/sound/soc/tegra/tegra_pcm.c @@ -253,13 +253,13 @@ static struct snd_soc_platform_driver tegra_pcm_platform = { .pcm_free = tegra_pcm_free, }; -int __devinit tegra_pcm_platform_register(struct device *dev) +int tegra_pcm_platform_register(struct device *dev) { return snd_soc_register_platform(dev, &tegra_pcm_platform); } EXPORT_SYMBOL_GPL(tegra_pcm_platform_register); -void __devexit tegra_pcm_platform_unregister(struct device *dev) +void tegra_pcm_platform_unregister(struct device *dev) { snd_soc_unregister_platform(dev); } diff --git a/sound/soc/tegra/tegra_pcm.h b/sound/soc/tegra/tegra_pcm.h index b40279b9f413..bc8b46af928e 100644 --- a/sound/soc/tegra/tegra_pcm.h +++ b/sound/soc/tegra/tegra_pcm.h @@ -31,8 +31,6 @@ #ifndef __TEGRA_PCM_H__ #define __TEGRA_PCM_H__ -#include <mach/dma.h> - struct tegra_pcm_dma_params { unsigned long addr; unsigned long wrap; diff --git a/sound/soc/tegra/tegra_wm8753.c b/sound/soc/tegra/tegra_wm8753.c index ea9166d5c4eb..c8ef88a67c59 100644 --- a/sound/soc/tegra/tegra_wm8753.c +++ b/sound/soc/tegra/tegra_wm8753.c @@ -122,7 +122,7 @@ static struct snd_soc_card snd_soc_tegra_wm8753 = { .fully_routed = true, }; -static __devinit int tegra_wm8753_driver_probe(struct platform_device *pdev) +static int tegra_wm8753_driver_probe(struct platform_device *pdev) { struct snd_soc_card *card = &snd_soc_tegra_wm8753; struct tegra_wm8753 *machine; @@ -188,7 +188,7 @@ err: return ret; } -static int __devexit tegra_wm8753_driver_remove(struct platform_device *pdev) +static int tegra_wm8753_driver_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); struct tegra_wm8753 *machine = snd_soc_card_get_drvdata(card); @@ -200,7 +200,7 @@ static int __devexit tegra_wm8753_driver_remove(struct platform_device *pdev) return 0; } -static const struct of_device_id tegra_wm8753_of_match[] __devinitconst = { +static const struct of_device_id tegra_wm8753_of_match[] = { { .compatible = "nvidia,tegra-audio-wm8753", }, {}, }; @@ -213,7 +213,7 @@ static struct platform_driver tegra_wm8753_driver = { .of_match_table = tegra_wm8753_of_match, }, .probe = tegra_wm8753_driver_probe, - .remove = __devexit_p(tegra_wm8753_driver_remove), + .remove = tegra_wm8753_driver_remove, }; module_platform_driver(tegra_wm8753_driver); diff --git a/sound/soc/tegra/tegra_wm8903.c b/sound/soc/tegra/tegra_wm8903.c index cee13b7bfb94..bbd79bf56303 100644 --- a/sound/soc/tegra/tegra_wm8903.c +++ b/sound/soc/tegra/tegra_wm8903.c @@ -252,7 +252,7 @@ static struct snd_soc_card snd_soc_tegra_wm8903 = { .fully_routed = true, }; -static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev) +static int tegra_wm8903_driver_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; struct snd_soc_card *card = &snd_soc_tegra_wm8903; @@ -402,7 +402,7 @@ err: return ret; } -static int __devexit tegra_wm8903_driver_remove(struct platform_device *pdev) +static int tegra_wm8903_driver_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); @@ -417,7 +417,7 @@ static int __devexit tegra_wm8903_driver_remove(struct platform_device *pdev) return 0; } -static const struct of_device_id tegra_wm8903_of_match[] __devinitconst = { +static const struct of_device_id tegra_wm8903_of_match[] = { { .compatible = "nvidia,tegra-audio-wm8903", }, {}, }; @@ -430,7 +430,7 @@ static struct platform_driver tegra_wm8903_driver = { .of_match_table = tegra_wm8903_of_match, }, .probe = tegra_wm8903_driver_probe, - .remove = __devexit_p(tegra_wm8903_driver_remove), + .remove = tegra_wm8903_driver_remove, }; module_platform_driver(tegra_wm8903_driver); diff --git a/sound/soc/tegra/trimslice.c b/sound/soc/tegra/trimslice.c index e69a4f7000d6..7fcf6c2297db 100644 --- a/sound/soc/tegra/trimslice.c +++ b/sound/soc/tegra/trimslice.c @@ -120,7 +120,7 @@ static struct snd_soc_card snd_soc_trimslice = { .fully_routed = true, }; -static __devinit int tegra_snd_trimslice_probe(struct platform_device *pdev) +static int tegra_snd_trimslice_probe(struct platform_device *pdev) { struct snd_soc_card *card = &snd_soc_trimslice; struct tegra_trimslice *trimslice; @@ -183,7 +183,7 @@ err: return ret; } -static int __devexit tegra_snd_trimslice_remove(struct platform_device *pdev) +static int tegra_snd_trimslice_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); struct tegra_trimslice *trimslice = snd_soc_card_get_drvdata(card); @@ -195,7 +195,7 @@ static int __devexit tegra_snd_trimslice_remove(struct platform_device *pdev) return 0; } -static const struct of_device_id trimslice_of_match[] __devinitconst = { +static const struct of_device_id trimslice_of_match[] = { { .compatible = "nvidia,tegra-audio-trimslice", }, {}, }; @@ -208,7 +208,7 @@ static struct platform_driver tegra_snd_trimslice_driver = { .of_match_table = trimslice_of_match, }, .probe = tegra_snd_trimslice_probe, - .remove = __devexit_p(tegra_snd_trimslice_remove), + .remove = tegra_snd_trimslice_remove, }; module_platform_driver(tegra_snd_trimslice_driver); diff --git a/sound/soc/txx9/txx9aclc-ac97.c b/sound/soc/txx9/txx9aclc-ac97.c index 28db4ca997ca..16ab69635e2e 100644 --- a/sound/soc/txx9/txx9aclc-ac97.c +++ b/sound/soc/txx9/txx9aclc-ac97.c @@ -170,7 +170,7 @@ static struct snd_soc_dai_driver txx9aclc_ac97_dai = { }, }; -static int __devinit txx9aclc_ac97_dev_probe(struct platform_device *pdev) +static int txx9aclc_ac97_dev_probe(struct platform_device *pdev) { struct txx9aclc_plat_drvdata *drvdata; struct resource *r; @@ -208,7 +208,7 @@ static int __devinit txx9aclc_ac97_dev_probe(struct platform_device *pdev) return snd_soc_register_dai(&pdev->dev, &txx9aclc_ac97_dai); } -static int __devexit txx9aclc_ac97_dev_remove(struct platform_device *pdev) +static int txx9aclc_ac97_dev_remove(struct platform_device *pdev) { snd_soc_unregister_dai(&pdev->dev); return 0; @@ -216,7 +216,7 @@ static int __devexit txx9aclc_ac97_dev_remove(struct platform_device *pdev) static struct platform_driver txx9aclc_ac97_driver = { .probe = txx9aclc_ac97_dev_probe, - .remove = __devexit_p(txx9aclc_ac97_dev_remove), + .remove = txx9aclc_ac97_dev_remove, .driver = { .name = "txx9aclc-ac97", .owner = THIS_MODULE, diff --git a/sound/soc/txx9/txx9aclc.c b/sound/soc/txx9/txx9aclc.c index b609d2c64c55..45a6428cba8d 100644 --- a/sound/soc/txx9/txx9aclc.c +++ b/sound/soc/txx9/txx9aclc.c @@ -417,12 +417,12 @@ static struct snd_soc_platform_driver txx9aclc_soc_platform = { .pcm_free = txx9aclc_pcm_free_dma_buffers, }; -static int __devinit txx9aclc_soc_platform_probe(struct platform_device *pdev) +static int txx9aclc_soc_platform_probe(struct platform_device *pdev) { return snd_soc_register_platform(&pdev->dev, &txx9aclc_soc_platform); } -static int __devexit txx9aclc_soc_platform_remove(struct platform_device *pdev) +static int txx9aclc_soc_platform_remove(struct platform_device *pdev) { snd_soc_unregister_platform(&pdev->dev); return 0; @@ -435,7 +435,7 @@ static struct platform_driver txx9aclc_pcm_driver = { }, .probe = txx9aclc_soc_platform_probe, - .remove = __devexit_p(txx9aclc_soc_platform_remove), + .remove = txx9aclc_soc_platform_remove, }; module_platform_driver(txx9aclc_pcm_driver); diff --git a/sound/soc/ux500/mop500.c b/sound/soc/ux500/mop500.c index 54f7e25b6f7d..ae6990738783 100644 --- a/sound/soc/ux500/mop500.c +++ b/sound/soc/ux500/mop500.c @@ -33,7 +33,7 @@ struct snd_soc_dai_link mop500_dai_links[] = { .stream_name = "ab8500_0", .cpu_dai_name = "ux500-msp-i2s.1", .codec_dai_name = "ab8500-codec-dai.0", - .platform_name = "ux500-pcm.0", + .platform_name = "ux500-msp-i2s.1", .codec_name = "ab8500-codec.0", .init = mop500_ab8500_machine_init, .ops = mop500_ab8500_ops, @@ -43,7 +43,7 @@ struct snd_soc_dai_link mop500_dai_links[] = { .stream_name = "ab8500_1", .cpu_dai_name = "ux500-msp-i2s.3", .codec_dai_name = "ab8500-codec-dai.1", - .platform_name = "ux500-pcm.0", + .platform_name = "ux500-msp-i2s.3", .codec_name = "ab8500-codec.0", .init = NULL, .ops = mop500_ab8500_ops, @@ -71,8 +71,8 @@ static void mop500_of_node_put(void) } } -static int __devinit mop500_of_probe(struct platform_device *pdev, - struct device_node *np) +static int mop500_of_probe(struct platform_device *pdev, + struct device_node *np) { struct device_node *codec_np, *msp_np[2]; int i; @@ -99,7 +99,7 @@ static int __devinit mop500_of_probe(struct platform_device *pdev, return 0; } -static int __devinit mop500_probe(struct platform_device *pdev) +static int mop500_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; int ret; @@ -136,7 +136,7 @@ static int __devinit mop500_probe(struct platform_device *pdev) return ret; } -static int __devexit mop500_remove(struct platform_device *pdev) +static int mop500_remove(struct platform_device *pdev) { struct snd_soc_card *mop500_card = platform_get_drvdata(pdev); @@ -161,7 +161,7 @@ static struct platform_driver snd_soc_mop500_driver = { .of_match_table = snd_soc_mop500_match, }, .probe = mop500_probe, - .remove = __devexit_p(mop500_remove), + .remove = mop500_remove, }; module_platform_driver(snd_soc_mop500_driver); diff --git a/sound/soc/ux500/ux500_msp_dai.c b/sound/soc/ux500/ux500_msp_dai.c index be94bf9bf94f..94a3e5705aaa 100644 --- a/sound/soc/ux500/ux500_msp_dai.c +++ b/sound/soc/ux500/ux500_msp_dai.c @@ -28,6 +28,7 @@ #include "ux500_msp_i2s.h" #include "ux500_msp_dai.h" +#include "ux500_pcm.h" static int setup_pcm_multichan(struct snd_soc_dai *dai, struct ux500_msp_config *msp_config) @@ -398,11 +399,28 @@ static int ux500_msp_dai_startup(struct snd_pcm_substream *substream, return ret; } - /* Enable clock */ - dev_dbg(dai->dev, "%s: Enabling MSP-clock.\n", __func__); - clk_enable(drvdata->clk); + /* Prepare and enable clocks */ + dev_dbg(dai->dev, "%s: Enabling MSP-clocks.\n", __func__); + ret = clk_prepare_enable(drvdata->pclk); + if (ret) { + dev_err(drvdata->msp->dev, + "%s: Failed to prepare/enable pclk!\n", __func__); + goto err_pclk; + } - return 0; + ret = clk_prepare_enable(drvdata->clk); + if (ret) { + dev_err(drvdata->msp->dev, + "%s: Failed to prepare/enable clk!\n", __func__); + goto err_clk; + } + + return ret; +err_clk: + clk_disable_unprepare(drvdata->pclk); +err_pclk: + regulator_disable(drvdata->reg_vape); + return ret; } static void ux500_msp_dai_shutdown(struct snd_pcm_substream *substream, @@ -428,8 +446,9 @@ static void ux500_msp_dai_shutdown(struct snd_pcm_substream *substream, __func__, dai->id, snd_pcm_stream_str(substream)); } - /* Disable clock */ - clk_disable(drvdata->clk); + /* Disable and unprepare clocks */ + clk_disable_unprepare(drvdata->clk); + clk_disable_unprepare(drvdata->pclk); /* Disable regulator */ ret = regulator_disable(drvdata->reg_vape); @@ -749,7 +768,7 @@ static struct snd_soc_dai_driver ux500_msp_dai_drv[UX500_NBR_OF_DAI] = { }, }; -static int __devinit ux500_msp_drv_probe(struct platform_device *pdev) +static int ux500_msp_drv_probe(struct platform_device *pdev) { struct ux500_msp_i2s_drvdata *drvdata; int ret = 0; @@ -780,6 +799,14 @@ static int __devinit ux500_msp_drv_probe(struct platform_device *pdev) } prcmu_qos_add_requirement(PRCMU_QOS_APE_OPP, (char *)pdev->name, 50); + drvdata->pclk = clk_get(&pdev->dev, "apb_pclk"); + if (IS_ERR(drvdata->pclk)) { + ret = (int)PTR_ERR(drvdata->pclk); + dev_err(&pdev->dev, "%s: ERROR: clk_get of pclk failed (%d)!\n", + __func__, ret); + goto err_pclk; + } + drvdata->clk = clk_get(&pdev->dev, NULL); if (IS_ERR(drvdata->clk)) { ret = (int)PTR_ERR(drvdata->clk); @@ -806,27 +833,41 @@ static int __devinit ux500_msp_drv_probe(struct platform_device *pdev) goto err_init_msp; } + ret = ux500_pcm_register_platform(pdev); + if (ret < 0) { + dev_err(&pdev->dev, + "Error: %s: Failed to register PCM platform device!\n", + __func__); + goto err_reg_plat; + } + return 0; +err_reg_plat: + snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(ux500_msp_dai_drv)); err_init_msp: clk_put(drvdata->clk); - err_clk: + clk_put(drvdata->pclk); +err_pclk: devm_regulator_put(drvdata->reg_vape); return ret; } -static int __devexit ux500_msp_drv_remove(struct platform_device *pdev) +static int ux500_msp_drv_remove(struct platform_device *pdev) { struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(&pdev->dev); + ux500_pcm_unregister_platform(pdev); + snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(ux500_msp_dai_drv)); devm_regulator_put(drvdata->reg_vape); prcmu_qos_remove_requirement(PRCMU_QOS_APE_OPP, "ux500_msp_i2s"); clk_put(drvdata->clk); + clk_put(drvdata->pclk); ux500_msp_i2s_cleanup_msp(pdev, drvdata->msp); diff --git a/sound/soc/ux500/ux500_msp_dai.h b/sound/soc/ux500/ux500_msp_dai.h index 98202a34a5dd..9c778d9c3838 100644 --- a/sound/soc/ux500/ux500_msp_dai.h +++ b/sound/soc/ux500/ux500_msp_dai.h @@ -69,6 +69,7 @@ struct ux500_msp_i2s_drvdata { /* Clocks */ unsigned int master_clk; struct clk *clk; + struct clk *pclk; /* Regulators */ int vape_opp_constraint; diff --git a/sound/soc/ux500/ux500_pcm.c b/sound/soc/ux500/ux500_pcm.c index 1a04e248453c..846fa82a58d0 100644 --- a/sound/soc/ux500/ux500_pcm.c +++ b/sound/soc/ux500/ux500_pcm.c @@ -18,8 +18,7 @@ #include <linux/dma-mapping.h> #include <linux/dmaengine.h> #include <linux/slab.h> - -#include <plat/ste_dma40.h> +#include <linux/platform_data/dma-ste-dma40.h> #include <sound/pcm.h> #include <sound/pcm_params.h> @@ -282,7 +281,7 @@ static struct snd_soc_platform_driver ux500_pcm_soc_drv = { .pcm_new = ux500_pcm_new, }; -static int __devexit ux500_pcm_drv_probe(struct platform_device *pdev) +int ux500_pcm_register_platform(struct platform_device *pdev) { int ret; @@ -296,23 +295,12 @@ static int __devexit ux500_pcm_drv_probe(struct platform_device *pdev) return 0; } +EXPORT_SYMBOL_GPL(ux500_pcm_register_platform); -static int __devinit ux500_pcm_drv_remove(struct platform_device *pdev) +int ux500_pcm_unregister_platform(struct platform_device *pdev) { snd_soc_unregister_platform(&pdev->dev); return 0; } - -static struct platform_driver ux500_pcm_driver = { - .driver = { - .name = "ux500-pcm", - .owner = THIS_MODULE, - }, - - .probe = ux500_pcm_drv_probe, - .remove = __devexit_p(ux500_pcm_drv_remove), -}; -module_platform_driver(ux500_pcm_driver); - -MODULE_LICENSE("GPL v2"); +EXPORT_SYMBOL_GPL(ux500_pcm_unregister_platform); diff --git a/sound/soc/ux500/ux500_pcm.h b/sound/soc/ux500/ux500_pcm.h index 77ed44d371e9..76d344476afc 100644 --- a/sound/soc/ux500/ux500_pcm.h +++ b/sound/soc/ux500/ux500_pcm.h @@ -32,4 +32,7 @@ #define UX500_PLATFORM_PERIODS_MAX 48 #define UX500_PLATFORM_BUFFER_BYTES_MAX (2048 * PAGE_SIZE) +int ux500_pcm_register_platform(struct platform_device *pdev); +int ux500_pcm_unregister_platform(struct platform_device *pdev); + #endif diff --git a/sound/sound_core.c b/sound/sound_core.c index fb9255cca214..bb23009edc8d 100644 --- a/sound/sound_core.c +++ b/sound/sound_core.c @@ -146,8 +146,7 @@ extern int msnd_pinnacle_init(void); * devices only the standard chrdev aliases are requested. * * All these clutters are scheduled to be removed along with - * sound-slot/service-* module aliases. Please take a look at - * feature-removal-schedule.txt for details. + * sound-slot/service-* module aliases. */ #ifdef CONFIG_SOUND_OSS_CORE_PRECLAIM static int preclaim_oss = 1; diff --git a/sound/sparc/amd7930.c b/sound/sparc/amd7930.c index 5701787c0e6b..174d21fb56e2 100644 --- a/sound/sparc/amd7930.c +++ b/sound/sparc/amd7930.c @@ -755,7 +755,7 @@ static struct snd_pcm_ops snd_amd7930_capture_ops = { .pointer = snd_amd7930_capture_pointer, }; -static int __devinit snd_amd7930_pcm(struct snd_amd7930 *amd) +static int snd_amd7930_pcm(struct snd_amd7930 *amd) { struct snd_pcm *pcm; int err; @@ -854,7 +854,7 @@ static int snd_amd7930_put_volume(struct snd_kcontrol *kctl, struct snd_ctl_elem return change; } -static struct snd_kcontrol_new amd7930_controls[] __devinitdata = { +static struct snd_kcontrol_new amd7930_controls[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Monitor Volume", @@ -884,7 +884,7 @@ static struct snd_kcontrol_new amd7930_controls[] __devinitdata = { }, }; -static int __devinit snd_amd7930_mixer(struct snd_amd7930 *amd) +static int snd_amd7930_mixer(struct snd_amd7930 *amd) { struct snd_card *card; int idx, err; @@ -933,10 +933,10 @@ static struct snd_device_ops snd_amd7930_dev_ops = { .dev_free = snd_amd7930_dev_free, }; -static int __devinit snd_amd7930_create(struct snd_card *card, - struct platform_device *op, - int irq, int dev, - struct snd_amd7930 **ramd) +static int snd_amd7930_create(struct snd_card *card, + struct platform_device *op, + int irq, int dev, + struct snd_amd7930 **ramd) { struct snd_amd7930 *amd; unsigned long flags; @@ -1002,7 +1002,7 @@ static int __devinit snd_amd7930_create(struct snd_card *card, return 0; } -static int __devinit amd7930_sbus_probe(struct platform_device *op) +static int amd7930_sbus_probe(struct platform_device *op) { struct resource *rp = &op->resource[0]; static int dev_num; diff --git a/sound/sparc/cs4231.c b/sound/sparc/cs4231.c index f2eabd3f22fd..54aaad2a10f5 100644 --- a/sound/sparc/cs4231.c +++ b/sound/sparc/cs4231.c @@ -702,7 +702,7 @@ static int snd_cs4231_timer_stop(struct snd_timer *timer) return 0; } -static void __devinit snd_cs4231_init(struct snd_cs4231 *chip) +static void snd_cs4231_init(struct snd_cs4231 *chip) { unsigned long flags; @@ -1019,7 +1019,7 @@ static snd_pcm_uframes_t snd_cs4231_capture_pointer( return bytes_to_frames(substream->runtime, ptr); } -static int __devinit snd_cs4231_probe(struct snd_cs4231 *chip) +static int snd_cs4231_probe(struct snd_cs4231 *chip) { unsigned long flags; int i; @@ -1218,7 +1218,7 @@ static struct snd_pcm_ops snd_cs4231_capture_ops = { .pointer = snd_cs4231_capture_pointer, }; -static int __devinit snd_cs4231_pcm(struct snd_card *card) +static int snd_cs4231_pcm(struct snd_card *card) { struct snd_cs4231 *chip = card->private_data; struct snd_pcm *pcm; @@ -1247,7 +1247,7 @@ static int __devinit snd_cs4231_pcm(struct snd_card *card) return 0; } -static int __devinit snd_cs4231_timer(struct snd_card *card) +static int snd_cs4231_timer(struct snd_card *card) { struct snd_cs4231 *chip = card->private_data; struct snd_timer *timer; @@ -1498,7 +1498,7 @@ static int snd_cs4231_put_double(struct snd_kcontrol *kcontrol, .private_value = (left_reg) | ((right_reg) << 8) | ((shift_left) << 16) | \ ((shift_right) << 19) | ((mask) << 24) | ((invert) << 22) } -static struct snd_kcontrol_new snd_cs4231_controls[] __devinitdata = { +static struct snd_kcontrol_new snd_cs4231_controls[] = { CS4231_DOUBLE("PCM Playback Switch", 0, CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1), CS4231_DOUBLE("PCM Playback Volume", 0, CS4231_LEFT_OUTPUT, @@ -1537,7 +1537,7 @@ CS4231_SINGLE("Line Out Switch", 0, CS4231_PIN_CTRL, 6, 1, 1), CS4231_SINGLE("Headphone Out Switch", 0, CS4231_PIN_CTRL, 7, 1, 1) }; -static int __devinit snd_cs4231_mixer(struct snd_card *card) +static int snd_cs4231_mixer(struct snd_card *card) { struct snd_cs4231 *chip = card->private_data; int err, idx; @@ -1558,7 +1558,7 @@ static int __devinit snd_cs4231_mixer(struct snd_card *card) static int dev; -static int __devinit cs4231_attach_begin(struct snd_card **rcard) +static int cs4231_attach_begin(struct snd_card **rcard) { struct snd_card *card; struct snd_cs4231 *chip; @@ -1589,7 +1589,7 @@ static int __devinit cs4231_attach_begin(struct snd_card **rcard) return 0; } -static int __devinit cs4231_attach_finish(struct snd_card *card) +static int cs4231_attach_finish(struct snd_card *card) { struct snd_cs4231 *chip = card->private_data; int err; @@ -1793,9 +1793,9 @@ static struct snd_device_ops snd_cs4231_sbus_dev_ops = { .dev_free = snd_cs4231_sbus_dev_free, }; -static int __devinit snd_cs4231_sbus_create(struct snd_card *card, - struct platform_device *op, - int dev) +static int snd_cs4231_sbus_create(struct snd_card *card, + struct platform_device *op, + int dev) { struct snd_cs4231 *chip = card->private_data; int err; @@ -1856,7 +1856,7 @@ static int __devinit snd_cs4231_sbus_create(struct snd_card *card, return 0; } -static int __devinit cs4231_sbus_probe(struct platform_device *op) +static int cs4231_sbus_probe(struct platform_device *op) { struct resource *rp = &op->resource[0]; struct snd_card *card; @@ -1959,9 +1959,9 @@ static struct snd_device_ops snd_cs4231_ebus_dev_ops = { .dev_free = snd_cs4231_ebus_dev_free, }; -static int __devinit snd_cs4231_ebus_create(struct snd_card *card, - struct platform_device *op, - int dev) +static int snd_cs4231_ebus_create(struct snd_card *card, + struct platform_device *op, + int dev) { struct snd_cs4231 *chip = card->private_data; int err; @@ -2048,7 +2048,7 @@ static int __devinit snd_cs4231_ebus_create(struct snd_card *card, return 0; } -static int __devinit cs4231_ebus_probe(struct platform_device *op) +static int cs4231_ebus_probe(struct platform_device *op) { struct snd_card *card; int err; @@ -2072,7 +2072,7 @@ static int __devinit cs4231_ebus_probe(struct platform_device *op) } #endif -static int __devinit cs4231_probe(struct platform_device *op) +static int cs4231_probe(struct platform_device *op) { #ifdef EBUS_SUPPORT if (!strcmp(op->dev.of_node->parent->name, "ebus")) @@ -2086,7 +2086,7 @@ static int __devinit cs4231_probe(struct platform_device *op) return -ENODEV; } -static int __devexit cs4231_remove(struct platform_device *op) +static int cs4231_remove(struct platform_device *op) { struct snd_cs4231 *chip = dev_get_drvdata(&op->dev); @@ -2115,7 +2115,7 @@ static struct platform_driver cs4231_driver = { .of_match_table = cs4231_match, }, .probe = cs4231_probe, - .remove = __devexit_p(cs4231_remove), + .remove = cs4231_remove, }; module_platform_driver(cs4231_driver); diff --git a/sound/sparc/dbri.c b/sound/sparc/dbri.c index ae35f5342e10..75e6016d3efe 100644 --- a/sound/sparc/dbri.c +++ b/sound/sparc/dbri.c @@ -745,7 +745,7 @@ static void dbri_reset(struct snd_dbri *dbri) } /* Lock must not be held before calling this */ -static void __devinit dbri_initialize(struct snd_dbri *dbri) +static void dbri_initialize(struct snd_dbri *dbri) { s32 *cmd; u32 dma_addr; @@ -1305,7 +1305,7 @@ to the DBRI via the CHI interface and few of the DBRI's PIO pins. * Lock must not be held before calling it. */ -static __devinit void cs4215_setup_pipes(struct snd_dbri *dbri) +static void cs4215_setup_pipes(struct snd_dbri *dbri) { unsigned long flags; @@ -1338,7 +1338,7 @@ static __devinit void cs4215_setup_pipes(struct snd_dbri *dbri) dbri_cmdwait(dbri); } -static __devinit int cs4215_init_data(struct cs4215 *mm) +static int cs4215_init_data(struct cs4215 *mm) { /* * No action, memory resetting only. @@ -1630,7 +1630,7 @@ static int cs4215_prepare(struct snd_dbri *dbri, unsigned int rate, /* * */ -static __devinit int cs4215_init(struct snd_dbri *dbri) +static int cs4215_init(struct snd_dbri *dbri) { u32 reg2 = sbus_readl(dbri->regs + REG2); dprintk(D_MM, "cs4215_init: reg2=0x%x\n", reg2); @@ -2217,7 +2217,7 @@ static struct snd_pcm_ops snd_dbri_ops = { .pointer = snd_dbri_pointer, }; -static int __devinit snd_dbri_pcm(struct snd_card *card) +static int snd_dbri_pcm(struct snd_card *card) { struct snd_pcm *pcm; int err; @@ -2409,7 +2409,7 @@ static int snd_cs4215_put_single(struct snd_kcontrol *kcontrol, .private_value = (entry) | ((shift) << 8) | ((mask) << 16) | \ ((invert) << 24) }, -static struct snd_kcontrol_new dbri_controls[] __devinitdata = { +static struct snd_kcontrol_new dbri_controls[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Playback Volume", @@ -2436,7 +2436,7 @@ static struct snd_kcontrol_new dbri_controls[] __devinitdata = { CS4215_SINGLE("Mic boost", 4, 4, 1, 1) }; -static int __devinit snd_dbri_mixer(struct snd_card *card) +static int snd_dbri_mixer(struct snd_card *card) { int idx, err; struct snd_dbri *dbri; @@ -2500,7 +2500,7 @@ static void dbri_debug_read(struct snd_info_entry *entry, } #endif -static void __devinit snd_dbri_proc(struct snd_card *card) +static void snd_dbri_proc(struct snd_card *card) { struct snd_dbri *dbri = card->private_data; struct snd_info_entry *entry; @@ -2523,9 +2523,9 @@ static void __devinit snd_dbri_proc(struct snd_card *card) */ static void snd_dbri_free(struct snd_dbri *dbri); -static int __devinit snd_dbri_create(struct snd_card *card, - struct platform_device *op, - int irq, int dev) +static int snd_dbri_create(struct snd_card *card, + struct platform_device *op, + int irq, int dev) { struct snd_dbri *dbri = card->private_data; int err; @@ -2593,7 +2593,7 @@ static void snd_dbri_free(struct snd_dbri *dbri) (void *)dbri->dma, dbri->dma_dvma); } -static int __devinit dbri_probe(struct platform_device *op) +static int dbri_probe(struct platform_device *op) { struct snd_dbri *dbri; struct resource *rp; @@ -2663,7 +2663,7 @@ _err: return err; } -static int __devexit dbri_remove(struct platform_device *op) +static int dbri_remove(struct platform_device *op) { struct snd_card *card = dev_get_drvdata(&op->dev); @@ -2694,7 +2694,7 @@ static struct platform_driver dbri_sbus_driver = { .of_match_table = dbri_match, }, .probe = dbri_probe, - .remove = __devexit_p(dbri_remove), + .remove = dbri_remove, }; module_platform_driver(dbri_sbus_driver); diff --git a/sound/spi/at73c213.c b/sound/spi/at73c213.c index c6500d00053b..4dd60d8a4889 100644 --- a/sound/spi/at73c213.c +++ b/sound/spi/at73c213.c @@ -330,7 +330,7 @@ static struct snd_pcm_ops at73c213_playback_ops = { .pointer = snd_at73c213_pcm_pointer, }; -static int __devinit snd_at73c213_pcm_new(struct snd_at73c213 *chip, int device) +static int snd_at73c213_pcm_new(struct snd_at73c213 *chip, int device) { struct snd_pcm *pcm; int retval; @@ -665,7 +665,7 @@ static int snd_at73c213_aux_capture_volume_info( | (mask << 24) | (invert << 22)) \ } -static struct snd_kcontrol_new snd_at73c213_controls[] __devinitdata = { +static struct snd_kcontrol_new snd_at73c213_controls[] = { AT73C213_STEREO("Master Playback Volume", 0, DAC_LMPG, DAC_RMPG, 0, 0, 0x1f, 1), AT73C213_STEREO("Master Playback Switch", 0, DAC_LMPG, DAC_RMPG, 5, 5, 1, 1), AT73C213_STEREO("PCM Playback Volume", 0, DAC_LLOG, DAC_RLOG, 0, 0, 0x1f, 1), @@ -709,7 +709,7 @@ AT73C213_MONO_SWITCH("Aux Capture Switch", 0, DAC_CTRL, DAC_CTRL_ONAUXIN, AT73C213_MONO_SWITCH("Line Capture Switch", 0, DAC_CTRL, 0, 0x03, 0), }; -static int __devinit snd_at73c213_mixer(struct snd_at73c213 *chip) +static int snd_at73c213_mixer(struct snd_at73c213 *chip) { struct snd_card *card; int errval, idx; @@ -744,7 +744,7 @@ cleanup: /* * Device functions */ -static int __devinit snd_at73c213_ssc_init(struct snd_at73c213 *chip) +static int snd_at73c213_ssc_init(struct snd_at73c213 *chip) { /* * Continuous clock output. @@ -774,7 +774,7 @@ static int __devinit snd_at73c213_ssc_init(struct snd_at73c213 *chip) return 0; } -static int __devinit snd_at73c213_chip_init(struct snd_at73c213 *chip) +static int snd_at73c213_chip_init(struct snd_at73c213 *chip) { int retval; unsigned char dac_ctrl = 0; @@ -879,8 +879,8 @@ static int snd_at73c213_dev_free(struct snd_device *device) return 0; } -static int __devinit snd_at73c213_dev_init(struct snd_card *card, - struct spi_device *spi) +static int snd_at73c213_dev_init(struct snd_card *card, + struct spi_device *spi) { static struct snd_device_ops ops = { .dev_free = snd_at73c213_dev_free, @@ -940,7 +940,7 @@ out: return retval; } -static int __devinit snd_at73c213_probe(struct spi_device *spi) +static int snd_at73c213_probe(struct spi_device *spi) { struct snd_card *card; struct snd_at73c213 *chip; @@ -1007,7 +1007,7 @@ out: return retval; } -static int __devexit snd_at73c213_remove(struct spi_device *spi) +static int snd_at73c213_remove(struct spi_device *spi) { struct snd_card *card = dev_get_drvdata(&spi->dev); struct snd_at73c213 *chip = card->private_data; @@ -1109,7 +1109,7 @@ static struct spi_driver at73c213_driver = { .probe = snd_at73c213_probe, .suspend = snd_at73c213_suspend, .resume = snd_at73c213_resume, - .remove = __devexit_p(snd_at73c213_remove), + .remove = snd_at73c213_remove, }; module_spi_driver(at73c213_driver); diff --git a/sound/usb/6fire/chip.c b/sound/usb/6fire/chip.c index fc8cc823e438..4394ae796356 100644 --- a/sound/usb/6fire/chip.c +++ b/sound/usb/6fire/chip.c @@ -82,8 +82,8 @@ static void usb6fire_chip_destroy(struct sfire_chip *chip) } } -static int __devinit usb6fire_chip_probe(struct usb_interface *intf, - const struct usb_device_id *usb_id) +static int usb6fire_chip_probe(struct usb_interface *intf, + const struct usb_device_id *usb_id) { int ret; int i; diff --git a/sound/usb/6fire/comm.c b/sound/usb/6fire/comm.c index 6c3d531a250e..9e6e3ffd86bb 100644 --- a/sound/usb/6fire/comm.c +++ b/sound/usb/6fire/comm.c @@ -125,16 +125,17 @@ static int usb6fire_comm_write16(struct comm_runtime *rt, u8 request, return usb6fire_comm_send_buffer(buffer, rt->chip->dev); } -int __devinit usb6fire_comm_init(struct sfire_chip *chip) +int usb6fire_comm_init(struct sfire_chip *chip) { struct comm_runtime *rt = kzalloc(sizeof(struct comm_runtime), GFP_KERNEL); - struct urb *urb = &rt->receiver; + struct urb *urb; int ret; if (!rt) return -ENOMEM; + urb = &rt->receiver; rt->serial = 1; rt->chip = chip; usb_init_urb(urb); diff --git a/sound/usb/6fire/comm.h b/sound/usb/6fire/comm.h index d2af0a5ddcf3..6a0840b0dcff 100644 --- a/sound/usb/6fire/comm.h +++ b/sound/usb/6fire/comm.h @@ -36,7 +36,7 @@ struct comm_runtime { u8 vh, u8 vl); }; -int __devinit usb6fire_comm_init(struct sfire_chip *chip); +int usb6fire_comm_init(struct sfire_chip *chip); void usb6fire_comm_abort(struct sfire_chip *chip); void usb6fire_comm_destroy(struct sfire_chip *chip); #endif /* USB6FIRE_COMM_H */ diff --git a/sound/usb/6fire/control.c b/sound/usb/6fire/control.c index 07ed914d5e71..f6434c245720 100644 --- a/sound/usb/6fire/control.c +++ b/sound/usb/6fire/control.c @@ -411,7 +411,7 @@ static int usb6fire_control_digital_thru_get(struct snd_kcontrol *kcontrol, return 0; } -static struct __devinitdata snd_kcontrol_new vol_elements[] = { +static struct snd_kcontrol_new vol_elements[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Analog Playback Volume", @@ -451,7 +451,7 @@ static struct __devinitdata snd_kcontrol_new vol_elements[] = { {} }; -static struct __devinitdata snd_kcontrol_new mute_elements[] = { +static struct snd_kcontrol_new mute_elements[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Analog Playback Switch", @@ -485,7 +485,7 @@ static struct __devinitdata snd_kcontrol_new mute_elements[] = { {} }; -static struct __devinitdata snd_kcontrol_new elements[] = { +static struct snd_kcontrol_new elements[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Line/Phono Capture Route", @@ -561,7 +561,7 @@ static int usb6fire_control_add_virtual( return 0; } -int __devinit usb6fire_control_init(struct sfire_chip *chip) +int usb6fire_control_init(struct sfire_chip *chip) { int i; int ret; diff --git a/sound/usb/6fire/control.h b/sound/usb/6fire/control.h index 9a596d95474a..5a40ba143489 100644 --- a/sound/usb/6fire/control.h +++ b/sound/usb/6fire/control.h @@ -50,7 +50,7 @@ struct control_runtime { u8 ivol_updated; }; -int __devinit usb6fire_control_init(struct sfire_chip *chip); +int usb6fire_control_init(struct sfire_chip *chip); void usb6fire_control_abort(struct sfire_chip *chip); void usb6fire_control_destroy(struct sfire_chip *chip); #endif /* USB6FIRE_CONTROL_H */ diff --git a/sound/usb/6fire/firmware.h b/sound/usb/6fire/firmware.h index 008569895381..c109c4f75aba 100644 --- a/sound/usb/6fire/firmware.h +++ b/sound/usb/6fire/firmware.h @@ -22,6 +22,6 @@ enum /* firmware state of device */ FW_NOT_READY = 1 }; -int __devinit usb6fire_fw_init(struct usb_interface *intf); +int usb6fire_fw_init(struct usb_interface *intf); #endif /* USB6FIRE_FIRMWARE_H */ diff --git a/sound/usb/6fire/midi.c b/sound/usb/6fire/midi.c index f0e5179b242b..26722423330d 100644 --- a/sound/usb/6fire/midi.c +++ b/sound/usb/6fire/midi.c @@ -146,7 +146,7 @@ static struct snd_rawmidi_ops in_ops = { .trigger = usb6fire_midi_in_trigger }; -int __devinit usb6fire_midi_init(struct sfire_chip *chip) +int usb6fire_midi_init(struct sfire_chip *chip) { int ret; struct midi_runtime *rt = kzalloc(sizeof(struct midi_runtime), diff --git a/sound/usb/6fire/midi.h b/sound/usb/6fire/midi.h index 5114eccc1d8e..c321006e5430 100644 --- a/sound/usb/6fire/midi.h +++ b/sound/usb/6fire/midi.h @@ -38,7 +38,7 @@ struct midi_runtime { void (*in_received)(struct midi_runtime *rt, u8 *data, int length); }; -int __devinit usb6fire_midi_init(struct sfire_chip *chip); +int usb6fire_midi_init(struct sfire_chip *chip); void usb6fire_midi_abort(struct sfire_chip *chip); void usb6fire_midi_destroy(struct sfire_chip *chip); #endif /* USB6FIRE_MIDI_H */ diff --git a/sound/usb/6fire/pcm.c b/sound/usb/6fire/pcm.c index c97d05f0e966..e2ca12fe92e9 100644 --- a/sound/usb/6fire/pcm.c +++ b/sound/usb/6fire/pcm.c @@ -135,6 +135,9 @@ static void usb6fire_pcm_stream_stop(struct pcm_runtime *rt) struct control_runtime *ctrl_rt = rt->chip->control; if (rt->stream_state != STREAM_DISABLED) { + + rt->stream_state = STREAM_STOPPING; + for (i = 0; i < PCM_N_URBS; i++) { usb_kill_urb(&rt->in_urbs[i].instance); usb_kill_urb(&rt->out_urbs[i].instance); @@ -559,9 +562,9 @@ static struct snd_pcm_ops pcm_ops = { .pointer = usb6fire_pcm_pointer, }; -static void __devinit usb6fire_pcm_init_urb(struct pcm_urb *urb, - struct sfire_chip *chip, bool in, int ep, - void (*handler)(struct urb *)) +static void usb6fire_pcm_init_urb(struct pcm_urb *urb, + struct sfire_chip *chip, bool in, int ep, + void (*handler)(struct urb *)) { urb->chip = chip; usb_init_urb(&urb->instance); @@ -578,7 +581,7 @@ static void __devinit usb6fire_pcm_init_urb(struct pcm_urb *urb, urb->instance.number_of_packets = PCM_N_PACKETS_PER_URB; } -int __devinit usb6fire_pcm_init(struct sfire_chip *chip) +int usb6fire_pcm_init(struct sfire_chip *chip) { int i; int ret; diff --git a/sound/usb/6fire/pcm.h b/sound/usb/6fire/pcm.h index 3104301b257d..9b01133ee3fe 100644 --- a/sound/usb/6fire/pcm.h +++ b/sound/usb/6fire/pcm.h @@ -69,7 +69,7 @@ struct pcm_runtime { bool stream_wait_cond; }; -int __devinit usb6fire_pcm_init(struct sfire_chip *chip); +int usb6fire_pcm_init(struct sfire_chip *chip); void usb6fire_pcm_abort(struct sfire_chip *chip); void usb6fire_pcm_destroy(struct sfire_chip *chip); #endif /* USB6FIRE_PCM_H */ diff --git a/sound/usb/Kconfig b/sound/usb/Kconfig index ff77b28f3da1..225dfd737265 100644 --- a/sound/usb/Kconfig +++ b/sound/usb/Kconfig @@ -90,7 +90,7 @@ config SND_USB_CAIAQ_INPUT config SND_USB_US122L tristate "Tascam US-122L USB driver" - depends on X86 && EXPERIMENTAL + depends on X86 select SND_HWDEP select SND_RAWMIDI help diff --git a/sound/usb/caiaq/control.c b/sound/usb/caiaq/control.c index 00e5d0a469e1..adb8d03267a0 100644 --- a/sound/usb/caiaq/control.c +++ b/sound/usb/caiaq/control.c @@ -137,7 +137,7 @@ static int control_put(struct snd_kcontrol *kcontrol, return 1; } -static struct snd_kcontrol_new kcontrol_template __devinitdata = { +static struct snd_kcontrol_new kcontrol_template = { .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, .index = 0, @@ -489,8 +489,8 @@ static struct caiaq_controller kontrols4_controller[] = { { "LED: FX2: Mode", 133 | CNT_INTVAL }, }; -static int __devinit add_controls(struct caiaq_controller *c, int num, - struct snd_usb_caiaqdev *dev) +static int add_controls(struct caiaq_controller *c, int num, + struct snd_usb_caiaqdev *dev) { int i, ret; struct snd_kcontrol *kc; @@ -507,7 +507,7 @@ static int __devinit add_controls(struct caiaq_controller *c, int num, return 0; } -int __devinit snd_usb_caiaq_control_init(struct snd_usb_caiaqdev *dev) +int snd_usb_caiaq_control_init(struct snd_usb_caiaqdev *dev) { int ret = 0; diff --git a/sound/usb/caiaq/device.c b/sound/usb/caiaq/device.c index 7da0d0aa72cb..e4d6dbb0342d 100644 --- a/sound/usb/caiaq/device.c +++ b/sound/usb/caiaq/device.c @@ -48,10 +48,10 @@ MODULE_SUPPORTED_DEVICE("{{Native Instruments, RigKontrol2}," "{Native Instruments, Audio 8 DJ}," "{Native Instruments, Traktor Audio 2}," "{Native Instruments, Session I/O}," - "{Native Instruments, GuitarRig mobile}" - "{Native Instruments, Traktor Kontrol X1}" - "{Native Instruments, Traktor Kontrol S4}" - "{Native Instruments, Maschine Controller}"); + "{Native Instruments, GuitarRig mobile}," + "{Native Instruments, Traktor Kontrol X1}," + "{Native Instruments, Traktor Kontrol S4}," + "{Native Instruments, Maschine Controller}}"); static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-max */ static char* id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* Id for this card */ @@ -289,7 +289,7 @@ int snd_usb_caiaq_set_auto_msg(struct snd_usb_caiaqdev *dev, tmp, sizeof(tmp)); } -static void __devinit setup_card(struct snd_usb_caiaqdev *dev) +static void setup_card(struct snd_usb_caiaqdev *dev) { int ret; char val[4]; @@ -407,7 +407,7 @@ static int create_card(struct usb_device *usb_dev, return 0; } -static int __devinit init_card(struct snd_usb_caiaqdev *dev) +static int init_card(struct snd_usb_caiaqdev *dev) { char *c, usbpath[32]; struct usb_device *usb_dev = dev->chip.dev; @@ -481,7 +481,7 @@ static int __devinit init_card(struct snd_usb_caiaqdev *dev) return 0; } -static int __devinit snd_probe(struct usb_interface *intf, +static int snd_probe(struct usb_interface *intf, const struct usb_device_id *id) { int ret; diff --git a/sound/usb/card.c b/sound/usb/card.c index dbf7999d18b4..803953a9bff3 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c @@ -25,9 +25,6 @@ * * NOTES: * - * - async unlink should be used for avoiding the sleep inside lock. - * 2.4.22 usb-uhci seems buggy for async unlinking and results in - * oops. in such a cse, pass async_unlink=0 option. * - the linked URBs would be preferred but not used so far because of * the instability of unlinking. * - type II is not supported properly. there is no device which supports @@ -83,7 +80,6 @@ static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;/* Enable this card * static int vid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 }; static int pid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 }; static int nrpacks = 8; /* max. number of packets per urb */ -static bool async_unlink = 1; static int device_setup[SNDRV_CARDS]; /* device parameter for this card */ static bool ignore_ctl_error; @@ -99,8 +95,6 @@ module_param_array(pid, int, NULL, 0444); MODULE_PARM_DESC(pid, "Product ID for the USB audio device."); module_param(nrpacks, int, 0644); MODULE_PARM_DESC(nrpacks, "Max. number of packets per URB."); -module_param(async_unlink, bool, 0444); -MODULE_PARM_DESC(async_unlink, "Use async unlink mode."); module_param_array(device_setup, int, NULL, 0444); MODULE_PARM_DESC(device_setup, "Specific device setup (if needed)."); module_param(ignore_ctl_error, bool, 0444); @@ -345,7 +339,6 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx, chip->card = card; chip->setup = device_setup[idx]; chip->nrpacks = nrpacks; - chip->async_unlink = async_unlink; chip->probing = 1; chip->usb_id = USB_ID(le16_to_cpu(dev->descriptor.idVendor), @@ -653,7 +646,7 @@ 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; } - } + } } else { /* * otherwise we keep the rest of the system in the dark diff --git a/sound/usb/card.h b/sound/usb/card.h index 814cb357ff88..8a751b4887ea 100644 --- a/sound/usb/card.h +++ b/sound/usb/card.h @@ -27,6 +27,7 @@ struct audioformat { unsigned int nr_rates; /* number of rate table entries */ unsigned int *rate_table; /* rate table */ unsigned char clock; /* associated clock */ + struct snd_pcm_chmap_elem *chmap; /* (optional) channel map */ }; struct snd_usb_substream; @@ -109,6 +110,7 @@ struct snd_usb_substream { struct audioformat *cur_audiofmt; /* current audioformat pointer (for hw_params callback) */ snd_pcm_format_t pcm_format; /* current audio format (for hw_params callback) */ unsigned int channels; /* current number of channels (for hw_params callback) */ + unsigned int channels_max; /* max channels in the all audiofmts */ unsigned int cur_rate; /* current rate (for hw_params callback) */ unsigned int period_bytes; /* current period bytes (for hw_params callback) */ unsigned int altset_idx; /* USB data format: index of alternate setting */ diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index 34de6f2faf61..21049b882ee6 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c @@ -485,15 +485,10 @@ __exit_unlock: static int wait_clear_urbs(struct snd_usb_endpoint *ep) { unsigned long end_time = jiffies + msecs_to_jiffies(1000); - unsigned int i; int alive; do { - alive = 0; - for (i = 0; i < ep->nurbs; i++) - if (test_bit(i, &ep->active_mask)) - alive++; - + alive = bitmap_weight(&ep->active_mask, ep->nurbs); if (!alive) break; @@ -520,33 +515,24 @@ void snd_usb_endpoint_sync_pending_stop(struct snd_usb_endpoint *ep) /* * unlink active urbs. */ -static int deactivate_urbs(struct snd_usb_endpoint *ep, int force, int can_sleep) +static int deactivate_urbs(struct snd_usb_endpoint *ep, bool force) { unsigned int i; - int async; if (!force && ep->chip->shutdown) /* to be sure... */ return -EBADFD; - async = !can_sleep && ep->chip->async_unlink; - clear_bit(EP_FLAG_RUNNING, &ep->flags); INIT_LIST_HEAD(&ep->ready_playback_urbs); ep->next_packet_read_pos = 0; ep->next_packet_write_pos = 0; - if (!async && in_interrupt()) - return 0; - for (i = 0; i < ep->nurbs; i++) { if (test_bit(i, &ep->active_mask)) { if (!test_and_set_bit(i, &ep->unlink_mask)) { struct urb *u = ep->urb[i].urb; - if (async) - usb_unlink_urb(u); - else - usb_kill_urb(u); + usb_unlink_urb(u); } } } @@ -566,7 +552,7 @@ static void release_urbs(struct snd_usb_endpoint *ep, int force) ep->prepare_data_urb = NULL; /* stop urbs */ - deactivate_urbs(ep, force, 1); + deactivate_urbs(ep, force); wait_clear_urbs(ep); for (i = 0; i < ep->nurbs; i++) @@ -829,7 +815,7 @@ int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep, * * Returns an error if the URB submission failed, 0 in all other cases. */ -int snd_usb_endpoint_start(struct snd_usb_endpoint *ep, int can_sleep) +int snd_usb_endpoint_start(struct snd_usb_endpoint *ep, bool can_sleep) { int err; unsigned int i; @@ -842,7 +828,7 @@ int snd_usb_endpoint_start(struct snd_usb_endpoint *ep, int can_sleep) return 0; /* just to be sure */ - deactivate_urbs(ep, 0, can_sleep); + deactivate_urbs(ep, false); if (can_sleep) wait_clear_urbs(ep); @@ -896,7 +882,7 @@ int snd_usb_endpoint_start(struct snd_usb_endpoint *ep, int can_sleep) __error: clear_bit(EP_FLAG_RUNNING, &ep->flags); ep->use_count--; - deactivate_urbs(ep, 0, 0); + deactivate_urbs(ep, false); return -EPIPE; } @@ -910,9 +896,11 @@ __error: * actually be deactivated. * * Must be balanced to calls of snd_usb_endpoint_start(). + * + * The caller needs to synchronize the pending stop operation via + * snd_usb_endpoint_sync_pending_stop(). */ -void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep, - int force, int can_sleep, int wait) +void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep) { if (!ep) return; @@ -921,16 +909,12 @@ void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep, return; if (--ep->use_count == 0) { - deactivate_urbs(ep, force, can_sleep); + deactivate_urbs(ep, false); ep->data_subs = NULL; ep->sync_slave = NULL; ep->retire_data_urb = NULL; ep->prepare_data_urb = NULL; - - if (wait) - wait_clear_urbs(ep); - else - set_bit(EP_FLAG_STOPPING, &ep->flags); + set_bit(EP_FLAG_STOPPING, &ep->flags); } } @@ -952,7 +936,7 @@ int snd_usb_endpoint_deactivate(struct snd_usb_endpoint *ep) if (!ep) return -EINVAL; - deactivate_urbs(ep, 1, 1); + deactivate_urbs(ep, true); wait_clear_urbs(ep); if (ep->use_count != 0) @@ -1034,15 +1018,18 @@ void snd_usb_handle_sync_urb(struct snd_usb_endpoint *ep, /* * Iterate through the inbound packet and prepare the lengths * for the output packet. The OUT packet we are about to send - * will have the same amount of payload bytes than the IN - * packet we just received. + * will have the same amount of payload bytes per stride as the + * IN packet we just received. Since the actual size is scaled + * by the stride, use the sender stride to calculate the length + * in case the number of channels differ between the implicitly + * fed-back endpoint and the synchronizing endpoint. */ out_packet->packets = in_ctx->packets; for (i = 0; i < in_ctx->packets; i++) { if (urb->iso_frame_desc[i].status == 0) out_packet->packet_size[i] = - urb->iso_frame_desc[i].actual_length / ep->stride; + urb->iso_frame_desc[i].actual_length / sender->stride; else out_packet->packet_size[i] = 0; } diff --git a/sound/usb/endpoint.h b/sound/usb/endpoint.h index 3d4c9705041f..447902dd8a4a 100644 --- a/sound/usb/endpoint.h +++ b/sound/usb/endpoint.h @@ -16,9 +16,8 @@ int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep, struct audioformat *fmt, struct snd_usb_endpoint *sync_ep); -int snd_usb_endpoint_start(struct snd_usb_endpoint *ep, int can_sleep); -void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep, - int force, int can_sleep, int wait); +int snd_usb_endpoint_start(struct snd_usb_endpoint *ep, bool can_sleep); +void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep); void snd_usb_endpoint_sync_pending_stop(struct snd_usb_endpoint *ep); int snd_usb_endpoint_activate(struct snd_usb_endpoint *ep); int snd_usb_endpoint_deactivate(struct snd_usb_endpoint *ep); diff --git a/sound/usb/format.c b/sound/usb/format.c index ddfef57c4c9f..e831ee4238bb 100644 --- a/sound/usb/format.c +++ b/sound/usb/format.c @@ -155,7 +155,7 @@ static int parse_audio_format_rates_v1(struct snd_usb_audio *chip, struct audiof if (fmt[0] < offset + 1 + 3 * (nr_rates ? nr_rates : 2)) { snd_printk(KERN_ERR "%d:%u:%d : invalid UAC_FORMAT_TYPE desc\n", chip->dev->devnum, fp->iface, fp->altsetting); - return -1; + return -EINVAL; } if (nr_rates) { @@ -167,7 +167,7 @@ static int parse_audio_format_rates_v1(struct snd_usb_audio *chip, struct audiof fp->rate_table = kmalloc(sizeof(int) * nr_rates, GFP_KERNEL); if (fp->rate_table == NULL) { snd_printk(KERN_ERR "cannot malloc\n"); - return -1; + return -ENOMEM; } fp->nr_rates = 0; @@ -198,7 +198,7 @@ static int parse_audio_format_rates_v1(struct snd_usb_audio *chip, struct audiof } if (!fp->nr_rates) { hwc_debug("All rates were zero. Skipping format!\n"); - return -1; + return -EINVAL; } } else { /* continuous rates */ @@ -383,7 +383,7 @@ static int parse_audio_format_i(struct snd_usb_audio *chip, fp->formats = parse_audio_format_i_type(chip, fp, format, fmt, protocol); if (!fp->formats) - return -1; + return -EINVAL; } /* gather possible sample rates */ @@ -409,7 +409,7 @@ static int parse_audio_format_i(struct snd_usb_audio *chip, if (fp->channels < 1) { snd_printk(KERN_ERR "%d:%u:%d : invalid channels %d\n", chip->dev->devnum, fp->iface, fp->altsetting, fp->channels); - return -1; + return -EINVAL; } return ret; diff --git a/sound/usb/midi.c b/sound/usb/midi.c index c83f6143c0eb..34b9bb7fe87c 100644 --- a/sound/usb/midi.c +++ b/sound/usb/midi.c @@ -116,6 +116,7 @@ struct snd_usb_midi { struct list_head list; struct timer_list error_timer; spinlock_t disc_lock; + struct rw_semaphore disc_rwsem; struct mutex mutex; u32 usb_id; int next_midi_device; @@ -125,8 +126,10 @@ struct snd_usb_midi { struct snd_usb_midi_in_endpoint *in; } endpoints[MIDI_MAX_ENDPOINTS]; unsigned long input_triggered; - unsigned int opened; + bool autopm_reference; + unsigned int opened[2]; unsigned char disconnected; + unsigned char input_running; struct snd_kcontrol *roland_load_ctl; }; @@ -1032,29 +1035,58 @@ static void update_roland_altsetting(struct snd_usb_midi* umidi) snd_usbmidi_input_start(&umidi->list); } -static void substream_open(struct snd_rawmidi_substream *substream, int open) +static int substream_open(struct snd_rawmidi_substream *substream, int dir, + int open) { struct snd_usb_midi* umidi = substream->rmidi->private_data; struct snd_kcontrol *ctl; + int err; + + down_read(&umidi->disc_rwsem); + if (umidi->disconnected) { + up_read(&umidi->disc_rwsem); + return open ? -ENODEV : 0; + } mutex_lock(&umidi->mutex); if (open) { - if (umidi->opened++ == 0 && umidi->roland_load_ctl) { - ctl = umidi->roland_load_ctl; - ctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE; - snd_ctl_notify(umidi->card, + if (!umidi->opened[0] && !umidi->opened[1]) { + err = usb_autopm_get_interface(umidi->iface); + umidi->autopm_reference = err >= 0; + if (err < 0 && err != -EACCES) { + mutex_unlock(&umidi->mutex); + up_read(&umidi->disc_rwsem); + return -EIO; + } + if (umidi->roland_load_ctl) { + ctl = umidi->roland_load_ctl; + 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); + update_roland_altsetting(umidi); + } } + umidi->opened[dir]++; + if (umidi->opened[1]) + snd_usbmidi_input_start(&umidi->list); } else { - if (--umidi->opened == 0 && umidi->roland_load_ctl) { - ctl = umidi->roland_load_ctl; - ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE; - snd_ctl_notify(umidi->card, + umidi->opened[dir]--; + if (!umidi->opened[1]) + snd_usbmidi_input_stop(&umidi->list); + 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; + snd_ctl_notify(umidi->card, SNDRV_CTL_EVENT_MASK_INFO, &ctl->id); + } + if (umidi->autopm_reference) + usb_autopm_put_interface(umidi->iface); } } mutex_unlock(&umidi->mutex); + up_read(&umidi->disc_rwsem); + return 0; } static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream) @@ -1062,7 +1094,6 @@ 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; int i, j; - int err; for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) if (umidi->endpoints[i].out) @@ -1075,22 +1106,15 @@ static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream) snd_BUG(); return -ENXIO; } - err = usb_autopm_get_interface(umidi->iface); - if (err < 0) - return -EIO; + substream->runtime->private_data = port; port->state = STATE_UNKNOWN; - substream_open(substream, 1); - return 0; + return substream_open(substream, 0, 1); } static int snd_usbmidi_output_close(struct snd_rawmidi_substream *substream) { - struct snd_usb_midi* umidi = substream->rmidi->private_data; - - substream_open(substream, 0); - usb_autopm_put_interface(umidi->iface); - return 0; + return substream_open(substream, 0, 0); } static void snd_usbmidi_output_trigger(struct snd_rawmidi_substream *substream, int up) @@ -1143,14 +1167,12 @@ static void snd_usbmidi_output_drain(struct snd_rawmidi_substream *substream) static int snd_usbmidi_input_open(struct snd_rawmidi_substream *substream) { - substream_open(substream, 1); - return 0; + return substream_open(substream, 1, 1); } static int snd_usbmidi_input_close(struct snd_rawmidi_substream *substream) { - substream_open(substream, 0); - return 0; + return substream_open(substream, 1, 0); } static void snd_usbmidi_input_trigger(struct snd_rawmidi_substream *substream, int up) @@ -1399,9 +1421,12 @@ void snd_usbmidi_disconnect(struct list_head* p) * a timer may submit an URB. To reliably break the cycle * a flag under lock must be used */ + down_write(&umidi->disc_rwsem); spin_lock_irq(&umidi->disc_lock); umidi->disconnected = 1; spin_unlock_irq(&umidi->disc_lock); + up_write(&umidi->disc_rwsem); + for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) { struct snd_usb_midi_endpoint* ep = &umidi->endpoints[i]; if (ep->out) @@ -2056,12 +2081,15 @@ void snd_usbmidi_input_stop(struct list_head* p) 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]; if (ep->in) for (j = 0; j < INPUT_URBS; ++j) usb_kill_urb(ep->in->urbs[j]); } + umidi->input_running = 0; } static void snd_usbmidi_input_start_ep(struct snd_usb_midi_in_endpoint* ep) @@ -2086,8 +2114,11 @@ void snd_usbmidi_input_start(struct list_head* p) int i; umidi = list_entry(p, struct snd_usb_midi, list); + if (umidi->input_running || !umidi->opened[1]) + return; for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) snd_usbmidi_input_start_ep(umidi->endpoints[i].in); + umidi->input_running = 1; } /* @@ -2113,6 +2144,7 @@ int snd_usbmidi_create(struct snd_card *card, umidi->usb_protocol_ops = &snd_usbmidi_standard_ops; init_timer(&umidi->error_timer); spin_lock_init(&umidi->disc_lock); + init_rwsem(&umidi->disc_rwsem); mutex_init(&umidi->mutex); umidi->usb_id = USB_ID(le16_to_cpu(umidi->dev->descriptor.idVendor), le16_to_cpu(umidi->dev->descriptor.idProduct)); @@ -2225,9 +2257,6 @@ int snd_usbmidi_create(struct snd_card *card, } list_add_tail(&umidi->list, midi_list); - - for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) - snd_usbmidi_input_start_ep(umidi->endpoints[i].in); return 0; } diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 298070e8f2d4..e90daf8cdaa8 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -382,6 +382,8 @@ error: static int get_ctl_value(struct usb_mixer_elem_info *cval, int request, int validx, int *value_ret) { + validx += cval->idx_off; + return (cval->mixer->protocol == UAC_VERSION_1) ? get_ctl_value_v1(cval, request, validx, value_ret) : get_ctl_value_v2(cval, request, validx, value_ret); @@ -432,6 +434,8 @@ int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval, unsigned char buf[2]; int idx = 0, val_len, err, timeout = 10; + validx += cval->idx_off; + if (cval->mixer->protocol == UAC_VERSION_1) { val_len = cval->val_type >= USB_MIXER_S16 ? 2 : 1; } else { /* UAC_VERSION_2 */ @@ -719,8 +723,19 @@ static int check_input_term(struct mixer_build *state, int id, struct usb_audio_ return 0; } case UAC1_PROCESSING_UNIT: - case UAC1_EXTENSION_UNIT: { + case UAC1_EXTENSION_UNIT: + /* UAC2_PROCESSING_UNIT_V2 */ + /* UAC2_EFFECT_UNIT */ { struct uac_processing_unit_descriptor *d = p1; + + if (state->mixer->protocol == UAC_VERSION_2 && + hdr[2] == UAC2_EFFECT_UNIT) { + /* UAC2/UAC1 unit IDs overlap here in an + * uncompatible way. Ignore this unit for now. + */ + return 0; + } + if (d->bNrInPins) { id = d->baSourceID[0]; break; /* continue to parse */ @@ -791,6 +806,33 @@ static void volume_control_quirks(struct usb_mixer_elem_info *cval, struct snd_kcontrol *kctl) { switch (cval->mixer->chip->usb_id) { + case USB_ID(0x0763, 0x2030): /* M-Audio Fast Track C400 */ + if (strcmp(kctl->id.name, "Effect Duration") == 0) { + cval->min = 0x0000; + cval->max = 0xffff; + cval->res = 0x00e6; + break; + } + if (strcmp(kctl->id.name, "Effect Volume") == 0 || + strcmp(kctl->id.name, "Effect Feedback Volume") == 0) { + cval->min = 0x00; + cval->max = 0xff; + break; + } + if (strstr(kctl->id.name, "Effect Return") != NULL) { + cval->min = 0xb706; + cval->max = 0xff7b; + cval->res = 0x0073; + break; + } + if ((strstr(kctl->id.name, "Playback Volume") != NULL) || + (strstr(kctl->id.name, "Effect Send") != NULL)) { + cval->min = 0xb5fb; /* -73 dB = 0xb6ff */ + cval->max = 0xfcfe; + cval->res = 0x0073; + } + break; + case USB_ID(0x0763, 0x2081): /* M-Audio Fast Track Ultra 8R */ case USB_ID(0x0763, 0x2080): /* M-Audio Fast Track Ultra */ if (strcmp(kctl->id.name, "Effect Duration") == 0) { @@ -1094,6 +1136,32 @@ static size_t append_ctl_name(struct snd_kcontrol *kctl, const char *str) return strlcat(kctl->id.name, str, sizeof(kctl->id.name)); } +/* A lot of headsets/headphones have a "Speaker" mixer. Make sure we + rename it to "Headphone". We determine if something is a headphone + similar to how udev determines form factor. */ +static void check_no_speaker_on_headset(struct snd_kcontrol *kctl, + struct snd_card *card) +{ + const char *names_to_check[] = { + "Headset", "headset", "Headphone", "headphone", NULL}; + const char **s; + bool found = 0; + + if (strcmp("Speaker", kctl->id.name)) + return; + + for (s = names_to_check; *s; s++) + if (strstr(card->shortname, *s)) { + found = 1; + break; + } + + if (!found) + return; + + strlcpy(kctl->id.name, "Headphone", sizeof(kctl->id.name)); +} + static void build_feature_ctl(struct mixer_build *state, void *raw_desc, unsigned int ctl_mask, int control, struct usb_audio_term *iterm, int unitid, @@ -1180,6 +1248,10 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, len = snprintf(kctl->id.name, sizeof(kctl->id.name), "Feature %d", unitid); } + + if (!mapped_name) + check_no_speaker_on_headset(kctl, state->mixer->chip->card); + /* determine the stream direction: * if the connected output is USB stream, then it's likely a * capture stream. otherwise it should be playback (hopefully :) @@ -1259,16 +1331,23 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, void } channels = (hdr->bLength - 7) / csize - 1; bmaControls = hdr->bmaControls; + if (hdr->bLength < 7 + csize) { + snd_printk(KERN_ERR "usbaudio: unit %u: " + "invalid UAC_FEATURE_UNIT descriptor\n", + unitid); + return -EINVAL; + } } else { struct uac2_feature_unit_descriptor *ftr = _ftr; csize = 4; channels = (hdr->bLength - 6) / 4 - 1; bmaControls = ftr->bmaControls; - } - - if (hdr->bLength < 7 || !csize || hdr->bLength < 7 + csize) { - snd_printk(KERN_ERR "usbaudio: unit %u: invalid UAC_FEATURE_UNIT descriptor\n", unitid); - return -EINVAL; + if (hdr->bLength < 6 + csize) { + snd_printk(KERN_ERR "usbaudio: unit %u: " + "invalid UAC_FEATURE_UNIT descriptor\n", + unitid); + return -EINVAL; + } } /* parse the source unit */ diff --git a/sound/usb/mixer.h b/sound/usb/mixer.h index a7f3d45a8acf..aab80df201bd 100644 --- a/sound/usb/mixer.h +++ b/sound/usb/mixer.h @@ -43,6 +43,7 @@ struct usb_mixer_elem_info { unsigned int id; unsigned int control; /* CS or ICN (high byte) */ unsigned int cmask; /* channel mask bitmap: 0 = master */ + unsigned int idx_off; /* Control index offset */ unsigned int ch_readonly; unsigned int master_readonly; int channels; diff --git a/sound/usb/mixer_maps.c b/sound/usb/mixer_maps.c index e71fe55cebef..0e2ed3d05c45 100644 --- a/sound/usb/mixer_maps.c +++ b/sound/usb/mixer_maps.c @@ -179,6 +179,15 @@ static struct usbmix_name_map audigy2nx_map[] = { { 0 } /* terminator */ }; +static struct usbmix_selector_map c400_selectors[] = { + { + .id = 0x80, + .count = 2, + .names = (const char*[]) {"Internal", "SPDIF"} + }, + { 0 } /* terminator */ +}; + static struct usbmix_selector_map audigy2nx_selectors[] = { { .id = 14, /* Capture Source */ @@ -367,6 +376,10 @@ static struct usbmix_ctl_map usbmix_ctl_maps[] = { .map = hercules_usb51_map, }, { + .id = USB_ID(0x0763, 0x2030), + .selector_map = c400_selectors, + }, + { .id = USB_ID(0x08bb, 0x2702), .map = linex_map, .ignore_ctl_error = 1, diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index ae2b71435220..15520de1df56 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -63,11 +63,12 @@ static void usb_mixer_elem_free(struct snd_kcontrol *kctl) * Since there doesn't seem to be a devices that needs a multichannel * version, we keep it mono for simplicity. */ -static int snd_create_std_mono_ctl(struct usb_mixer_interface *mixer, +static int snd_create_std_mono_ctl_offset(struct usb_mixer_interface *mixer, unsigned int unitid, unsigned int control, unsigned int cmask, int val_type, + unsigned int idx_off, const char *name, snd_kcontrol_tlv_rw_t *tlv_callback) { @@ -85,6 +86,7 @@ static int snd_create_std_mono_ctl(struct usb_mixer_interface *mixer, cval->channels = 1; cval->control = control; cval->cmask = cmask; + cval->idx_off = idx_off; /* get_min_max() is called only for integer volumes later, * so provide a short-cut for booleans */ @@ -120,6 +122,18 @@ static int snd_create_std_mono_ctl(struct usb_mixer_interface *mixer, return 0; } +static int snd_create_std_mono_ctl(struct usb_mixer_interface *mixer, + unsigned int unitid, + unsigned int control, + unsigned int cmask, + int val_type, + const char *name, + snd_kcontrol_tlv_rw_t *tlv_callback) +{ + return snd_create_std_mono_ctl_offset(mixer, unitid, control, cmask, + val_type, 0 /* Offset */, name, tlv_callback); +} + /* * Create a set of standard UAC controls from a table */ @@ -416,6 +430,8 @@ static void snd_audigy2nx_proc_read(struct snd_info_entry *entry, } } +/* ASUS Xonar U1 / U3 controls */ + static int snd_xonar_u1_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -621,11 +637,13 @@ static int snd_nativeinstruments_create_mixer(struct usb_mixer_interface *mixer, } /* M-Audio FastTrack Ultra quirks */ -/* FTU Effect switch */ +/* FTU Effect switch (also used by C400) */ struct snd_ftu_eff_switch_priv_val { struct usb_mixer_interface *mixer; int cached_value; int is_cached; + int bUnitID; + int validx; }; static int snd_ftu_eff_switch_info(struct snd_kcontrol *kcontrol, @@ -660,9 +678,8 @@ static int snd_ftu_eff_switch_get(struct snd_kcontrol *kctl, struct snd_ftu_eff_switch_priv_val *pval; int err; unsigned char value[2]; + int id, validx; - const int id = 6; - const int validx = 1; const int val_len = 2; value[0] = 0x00; @@ -684,6 +701,8 @@ static int snd_ftu_eff_switch_get(struct snd_kcontrol *kctl, if (snd_BUG_ON(!chip)) return -EINVAL; + id = pval->bUnitID; + validx = pval->validx; down_read(&mixer->chip->shutdown_rwsem); if (mixer->chip->shutdown) @@ -714,10 +733,8 @@ static int snd_ftu_eff_switch_put(struct snd_kcontrol *kctl, struct usb_mixer_interface *mixer; int changed, cur_val, err, new_val; unsigned char value[2]; + int id, validx; - - const int id = 6; - const int validx = 1; const int val_len = 2; changed = 0; @@ -735,6 +752,9 @@ static int snd_ftu_eff_switch_put(struct snd_kcontrol *kctl, if (snd_BUG_ON(!chip)) return -EINVAL; + id = pval->bUnitID; + validx = pval->validx; + if (!pval->is_cached) { /* Read current value */ down_read(&mixer->chip->shutdown_rwsem); @@ -779,7 +799,8 @@ static int snd_ftu_eff_switch_put(struct snd_kcontrol *kctl, return changed; } -static int snd_ftu_create_effect_switch(struct usb_mixer_interface *mixer) +static int snd_ftu_create_effect_switch(struct usb_mixer_interface *mixer, + int validx, int bUnitID) { static struct snd_kcontrol_new template = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, @@ -802,6 +823,8 @@ static int snd_ftu_create_effect_switch(struct usb_mixer_interface *mixer) pval->cached_value = 0; pval->is_cached = 0; pval->mixer = mixer; + pval->bUnitID = bUnitID; + pval->validx = validx; template.private_value = (unsigned long) pval; kctl = snd_ctl_new1(&template, mixer->chip); @@ -960,9 +983,10 @@ static int snd_ftu_create_mixer(struct usb_mixer_interface *mixer) if (err < 0) return err; - err = snd_ftu_create_effect_switch(mixer); + err = snd_ftu_create_effect_switch(mixer, 1, 6); if (err < 0) return err; + err = snd_ftu_create_effect_volume_ctl(mixer); if (err < 0) return err; @@ -1005,12 +1029,184 @@ void snd_emuusb_set_samplerate(struct snd_usb_audio *chip, } } +/* M-Audio Fast Track C400 */ +/* C400 volume controls, this control needs a volume quirk, see mixer.c */ +static int snd_c400_create_vol_ctls(struct usb_mixer_interface *mixer) +{ + char name[64]; + unsigned int cmask, offset; + int out, chan, err; + + const unsigned int id = 0x40; + const int val_type = USB_MIXER_S16; + const int control = 1; + + for (chan = 0; chan < 10; chan++) { + for (out = 0; out < 6; out++) { + if (chan < 6) { + snprintf(name, sizeof(name), + "PCM%d-Out%d Playback Volume", + chan + 1, out + 1); + } else { + snprintf(name, sizeof(name), + "In%d-Out%d Playback Volume", + chan - 5, out + 1); + } + + cmask = (out == 0) ? 0 : 1 << (out - 1); + offset = chan * 6; + err = snd_create_std_mono_ctl_offset(mixer, id, control, + cmask, val_type, offset, name, + &snd_usb_mixer_vol_tlv); + if (err < 0) + return err; + } + } + + return 0; +} + +/* This control needs a volume quirk, see mixer.c */ +static int snd_c400_create_effect_volume_ctl(struct usb_mixer_interface *mixer) +{ + static const char name[] = "Effect Volume"; + const unsigned int id = 0x43; + const int val_type = USB_MIXER_U8; + const unsigned int control = 3; + const unsigned int cmask = 0; + + return snd_create_std_mono_ctl(mixer, id, control, cmask, val_type, + name, snd_usb_mixer_vol_tlv); +} + +/* This control needs a volume quirk, see mixer.c */ +static int snd_c400_create_effect_duration_ctl(struct usb_mixer_interface *mixer) +{ + static const char name[] = "Effect Duration"; + const unsigned int id = 0x43; + const int val_type = USB_MIXER_S16; + const unsigned int control = 4; + const unsigned int cmask = 0; + + return snd_create_std_mono_ctl(mixer, id, control, cmask, val_type, + name, snd_usb_mixer_vol_tlv); +} + +/* This control needs a volume quirk, see mixer.c */ +static int snd_c400_create_effect_feedback_ctl(struct usb_mixer_interface *mixer) +{ + static const char name[] = "Effect Feedback Volume"; + const unsigned int id = 0x43; + const int val_type = USB_MIXER_U8; + const unsigned int control = 5; + const unsigned int cmask = 0; + + return snd_create_std_mono_ctl(mixer, id, control, cmask, val_type, + name, NULL); +} + +static int snd_c400_create_effect_vol_ctls(struct usb_mixer_interface *mixer) +{ + char name[64]; + unsigned int cmask; + int chan, err; + + const unsigned int id = 0x42; + const int val_type = USB_MIXER_S16; + const int control = 1; + + for (chan = 0; chan < 10; chan++) { + if (chan < 6) { + snprintf(name, sizeof(name), + "Effect Send DOut%d", + chan + 1); + } else { + snprintf(name, sizeof(name), + "Effect Send AIn%d", + chan - 5); + } + + cmask = (chan == 0) ? 0 : 1 << (chan - 1); + err = snd_create_std_mono_ctl(mixer, id, control, + cmask, val_type, name, + &snd_usb_mixer_vol_tlv); + if (err < 0) + return err; + } + + return 0; +} + +static int snd_c400_create_effect_ret_vol_ctls(struct usb_mixer_interface *mixer) +{ + char name[64]; + unsigned int cmask; + int chan, err; + + const unsigned int id = 0x40; + const int val_type = USB_MIXER_S16; + const int control = 1; + const int chan_id[6] = { 0, 7, 2, 9, 4, 0xb }; + const unsigned int offset = 0x3c; + /* { 0x3c, 0x43, 0x3e, 0x45, 0x40, 0x47 } */ + + for (chan = 0; chan < 6; chan++) { + snprintf(name, sizeof(name), + "Effect Return %d", + chan + 1); + + cmask = (chan_id[chan] == 0) ? 0 : 1 << (chan_id[chan] - 1); + err = snd_create_std_mono_ctl_offset(mixer, id, control, + cmask, val_type, offset, name, + &snd_usb_mixer_vol_tlv); + if (err < 0) + return err; + } + + return 0; +} + +static int snd_c400_create_mixer(struct usb_mixer_interface *mixer) +{ + int err; + + err = snd_c400_create_vol_ctls(mixer); + if (err < 0) + return err; + + err = snd_c400_create_effect_vol_ctls(mixer); + if (err < 0) + return err; + + err = snd_c400_create_effect_ret_vol_ctls(mixer); + if (err < 0) + return err; + + err = snd_ftu_create_effect_switch(mixer, 2, 0x43); + if (err < 0) + return err; + + err = snd_c400_create_effect_volume_ctl(mixer); + if (err < 0) + return err; + + err = snd_c400_create_effect_duration_ctl(mixer); + if (err < 0) + return err; + + err = snd_c400_create_effect_feedback_ctl(mixer); + if (err < 0) + return err; + + return 0; +} + /* * The mixer units for Ebox-44 are corrupt, and even where they * are valid they presents mono controls as L and R channels of * stereo. So we provide a good mixer here. */ -struct std_mono_table ebox44_table[] = { +static struct std_mono_table ebox44_table[] = { { .unitid = 4, .control = 1, @@ -1102,13 +1298,18 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer) snd_audigy2nx_proc_read); break; + case USB_ID(0x0763, 0x2030): /* M-Audio Fast Track C400 */ + err = snd_c400_create_mixer(mixer); + break; + case USB_ID(0x0763, 0x2080): /* M-Audio Fast Track Ultra */ case USB_ID(0x0763, 0x2081): /* M-Audio Fast Track Ultra 8R */ err = snd_ftu_create_mixer(mixer); break; - case USB_ID(0x0b05, 0x1739): - case USB_ID(0x0b05, 0x1743): + case USB_ID(0x0b05, 0x1739): /* ASUS Xonar U1 */ + case USB_ID(0x0b05, 0x1743): /* ASUS Xonar U1 (2) */ + case USB_ID(0x0b05, 0x17a0): /* ASUS Xonar U3 */ err = snd_xonar_u1_controls_create(mixer); break; diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 5c12a3fe8c3e..81f70a719bb9 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -46,6 +46,9 @@ snd_pcm_uframes_t snd_usb_pcm_delay(struct snd_usb_substream *subs, int frame_diff; int est_delay; + if (!subs->last_delay) + return 0; /* short path */ + current_frame_number = usb_get_current_frame_number(subs->dev); /* * HCD implementations use different widths, use lower 8 bits. @@ -56,7 +59,12 @@ snd_pcm_uframes_t snd_usb_pcm_delay(struct snd_usb_substream *subs, /* Approximation based on number of samples per USB frame (ms), some truncation for 44.1 but the estimate is good enough */ - est_delay = subs->last_delay - (frame_diff * rate / 1000); + est_delay = frame_diff * rate / 1000; + if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK) + est_delay = subs->last_delay - est_delay; + else + est_delay = subs->last_delay + est_delay; + if (est_delay < 0) est_delay = 0; return est_delay; @@ -173,11 +181,8 @@ static int init_pitch_v2(struct snd_usb_audio *chip, int iface, { struct usb_device *dev = chip->dev; unsigned char data[1]; - unsigned int ep; int err; - ep = get_endpoint(alts, 0)->bEndpointAddress; - data[0] = 1; if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC2_CS_CUR, USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_OUT, @@ -214,7 +219,7 @@ int snd_usb_init_pitch(struct snd_usb_audio *chip, int iface, } } -static int start_endpoints(struct snd_usb_substream *subs, int can_sleep) +static int start_endpoints(struct snd_usb_substream *subs, bool can_sleep) { int err; @@ -266,16 +271,18 @@ static int start_endpoints(struct snd_usb_substream *subs, int can_sleep) return 0; } -static void stop_endpoints(struct snd_usb_substream *subs, - int force, int can_sleep, int wait) +static void stop_endpoints(struct snd_usb_substream *subs, bool wait) { if (test_and_clear_bit(SUBSTREAM_FLAG_SYNC_EP_STARTED, &subs->flags)) - snd_usb_endpoint_stop(subs->sync_endpoint, - force, can_sleep, wait); + snd_usb_endpoint_stop(subs->sync_endpoint); if (test_and_clear_bit(SUBSTREAM_FLAG_DATA_EP_STARTED, &subs->flags)) - snd_usb_endpoint_stop(subs->data_endpoint, - force, can_sleep, wait); + snd_usb_endpoint_stop(subs->data_endpoint); + + if (wait) { + snd_usb_endpoint_sync_pending_stop(subs->sync_endpoint); + snd_usb_endpoint_sync_pending_stop(subs->data_endpoint); + } } static int deactivate_endpoints(struct snd_usb_substream *subs) @@ -359,6 +366,19 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt) attr = fmt->ep_attr & USB_ENDPOINT_SYNCTYPE; switch (subs->stream->chip->usb_id) { + case USB_ID(0x0763, 0x2030): /* M-Audio Fast Track C400 */ + if (is_playback) { + implicit_fb = 1; + ep = 0x81; + iface = usb_ifnum_to_if(dev, 3); + + if (!iface || iface->num_altsetting == 0) + return -EINVAL; + + alts = &iface->altsetting[1]; + goto add_sync_ep; + } + break; case USB_ID(0x0763, 0x2080): /* M-Audio FastTrack Ultra */ case USB_ID(0x0763, 0x2081): if (is_playback) { @@ -381,7 +401,7 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt) /* ... and check descriptor size before accessing bSynchAddress because there is a version of the SB Audigy 2 NX firmware lacking the audio fields in the endpoint descriptors */ - if ((get_endpoint(alts, 1)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != 0x01 || + if ((get_endpoint(alts, 1)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_ISOC || (get_endpoint(alts, 1)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE && get_endpoint(alts, 1)->bSynchAddress != 0 && !implicit_fb)) { @@ -438,6 +458,113 @@ add_sync_ep: } /* + * Return the score of matching two audioformats. + * Veto the audioformat if: + * - It has no channels for some reason. + * - Requested PCM format is not supported. + * - Requested sample rate is not supported. + */ +static int match_endpoint_audioformats(struct audioformat *fp, + struct audioformat *match, int rate, + snd_pcm_format_t pcm_format) +{ + int i; + int score = 0; + + if (fp->channels < 1) { + snd_printdd("%s: (fmt @%p) no channels\n", __func__, fp); + return 0; + } + + if (!(fp->formats & (1ULL << pcm_format))) { + snd_printdd("%s: (fmt @%p) no match for format %d\n", __func__, + fp, pcm_format); + return 0; + } + + for (i = 0; i < fp->nr_rates; i++) { + if (fp->rate_table[i] == rate) { + score++; + break; + } + } + if (!score) { + snd_printdd("%s: (fmt @%p) no match for rate %d\n", __func__, + fp, rate); + return 0; + } + + if (fp->channels == match->channels) + score++; + + snd_printdd("%s: (fmt @%p) score %d\n", __func__, fp, score); + + return score; +} + +/* + * Configure the sync ep using the rate and pcm format of the data ep. + */ +static int configure_sync_endpoint(struct snd_usb_substream *subs) +{ + int ret; + struct audioformat *fp; + struct audioformat *sync_fp = NULL; + int cur_score = 0; + int sync_period_bytes = subs->period_bytes; + struct snd_usb_substream *sync_subs = + &subs->stream->substream[subs->direction ^ 1]; + + if (subs->sync_endpoint->type != SND_USB_ENDPOINT_TYPE_DATA || + !subs->stream) + return snd_usb_endpoint_set_params(subs->sync_endpoint, + subs->pcm_format, + subs->channels, + subs->period_bytes, + subs->cur_rate, + subs->cur_audiofmt, + NULL); + + /* Try to find the best matching audioformat. */ + list_for_each_entry(fp, &sync_subs->fmt_list, list) { + int score = match_endpoint_audioformats(fp, subs->cur_audiofmt, + subs->cur_rate, subs->pcm_format); + + if (score > cur_score) { + sync_fp = fp; + cur_score = score; + } + } + + if (unlikely(sync_fp == NULL)) { + snd_printk(KERN_ERR "%s: no valid audioformat for sync ep %x found\n", + __func__, sync_subs->ep_num); + return -EINVAL; + } + + /* + * Recalculate the period bytes if channel number differ between + * data and sync ep audioformat. + */ + if (sync_fp->channels != subs->channels) { + sync_period_bytes = (subs->period_bytes / subs->channels) * + sync_fp->channels; + snd_printdd("%s: adjusted sync ep period bytes (%d -> %d)\n", + __func__, subs->period_bytes, sync_period_bytes); + } + + ret = snd_usb_endpoint_set_params(subs->sync_endpoint, + subs->pcm_format, + sync_fp->channels, + sync_period_bytes, + subs->cur_rate, + sync_fp, + NULL); + + return ret; +} + +/* * configure endpoint params * * called during initial setup and upon resume @@ -447,7 +574,7 @@ static int configure_endpoint(struct snd_usb_substream *subs) int ret; /* format changed */ - stop_endpoints(subs, 0, 0, 0); + stop_endpoints(subs, true); ret = snd_usb_endpoint_set_params(subs->data_endpoint, subs->pcm_format, subs->channels, @@ -459,13 +586,8 @@ static int configure_endpoint(struct snd_usb_substream *subs) return ret; if (subs->sync_endpoint) - ret = snd_usb_endpoint_set_params(subs->data_endpoint, - subs->pcm_format, - subs->channels, - subs->period_bytes, - subs->cur_rate, - subs->cur_audiofmt, - NULL); + ret = configure_sync_endpoint(subs); + return ret; } @@ -533,7 +655,7 @@ static int snd_usb_hw_free(struct snd_pcm_substream *substream) subs->period_bytes = 0; down_read(&subs->stream->chip->shutdown_rwsem); if (!subs->stream->chip->shutdown) { - stop_endpoints(subs, 0, 1, 1); + stop_endpoints(subs, true); deactivate_endpoints(subs); } up_read(&subs->stream->chip->shutdown_rwsem); @@ -608,7 +730,7 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream) /* for playback, submit the URBs now; otherwise, the first hwptr_done * updates for all URBs would happen at the same time when starting */ if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK) - ret = start_endpoints(subs, 1); + ret = start_endpoints(subs, true); unlock: up_read(&subs->stream->chip->shutdown_rwsem); @@ -1013,7 +1135,7 @@ static int snd_usb_pcm_close(struct snd_pcm_substream *substream, int direction) struct snd_usb_stream *as = snd_pcm_substream_chip(substream); struct snd_usb_substream *subs = &as->substream[direction]; - stop_endpoints(subs, 0, 0, 0); + stop_endpoints(subs, true); if (!as->chip->shutdown && subs->interface >= 0) { usb_set_interface(subs->dev, subs->interface, 0); @@ -1039,6 +1161,10 @@ static void retire_capture_urb(struct snd_usb_substream *subs, int i, period_elapsed = 0; unsigned long flags; unsigned char *cp; + int current_frame_number; + + /* read frame number here, update pointer in critical section */ + current_frame_number = usb_get_current_frame_number(subs->dev); stride = runtime->frame_bits >> 3; @@ -1053,9 +1179,7 @@ static void retire_capture_urb(struct snd_usb_substream *subs, if (!subs->txfr_quirk) bytes = frames * stride; if (bytes % (runtime->sample_bits >> 3) != 0) { -#ifdef CONFIG_SND_DEBUG_VERBOSE int oldbytes = bytes; -#endif bytes = frames * stride; snd_printdd(KERN_ERR "Corrected urb data len. %d->%d\n", oldbytes, bytes); @@ -1072,6 +1196,15 @@ static void retire_capture_urb(struct snd_usb_substream *subs, subs->transfer_done -= runtime->period_size; period_elapsed = 1; } + /* capture delay is by construction limited to one URB, + * reset delays here + */ + runtime->delay = subs->last_delay = 0; + + /* realign last_frame_number */ + subs->last_frame_number = current_frame_number; + subs->last_frame_number &= 0xFF; /* keep 8 LSBs */ + spin_unlock_irqrestore(&subs->lock, flags); /* copy a data chunk */ if (oldptr + bytes > runtime->buffer_size * stride) { @@ -1195,6 +1328,9 @@ static void retire_playback_urb(struct snd_usb_substream *subs, return; spin_lock_irqsave(&subs->lock, flags); + if (!subs->last_delay) + goto out; /* short path */ + est_delay = snd_usb_pcm_delay(subs, runtime->rate); /* update delay with exact number of samples played */ if (processed > subs->last_delay) @@ -1212,6 +1348,15 @@ static void retire_playback_urb(struct snd_usb_substream *subs, snd_printk(KERN_DEBUG "delay: estimated %d, actual %d\n", est_delay, subs->last_delay); + if (!subs->running) { + /* update last_frame_number for delay counting here since + * prepare_playback_urb won't be called during pause + */ + subs->last_frame_number = + usb_get_current_frame_number(subs->dev) & 0xff; + } + + out: spin_unlock_irqrestore(&subs->lock, flags); } @@ -1248,12 +1393,13 @@ static int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substrea subs->running = 1; return 0; case SNDRV_PCM_TRIGGER_STOP: - stop_endpoints(subs, 0, 0, 0); + stop_endpoints(subs, false); subs->running = 0; return 0; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: subs->data_endpoint->prepare_data_urb = NULL; - subs->data_endpoint->retire_data_urb = NULL; + /* keep retire_data_urb for delay calculation */ + subs->data_endpoint->retire_data_urb = retire_playback_urb; subs->running = 0; return 0; } @@ -1269,7 +1415,7 @@ static int snd_usb_substream_capture_trigger(struct snd_pcm_substream *substream switch (cmd) { case SNDRV_PCM_TRIGGER_START: - err = start_endpoints(subs, 0); + err = start_endpoints(subs, false); if (err < 0) return err; @@ -1277,7 +1423,7 @@ static int snd_usb_substream_capture_trigger(struct snd_pcm_substream *substream subs->running = 1; return 0; case SNDRV_PCM_TRIGGER_STOP: - stop_endpoints(subs, 0, 0, 0); + stop_endpoints(subs, false); subs->running = 0; return 0; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index 88d8cebbb244..820580a6dfc3 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -50,6 +50,28 @@ } }, +{ + /* Creative BT-D1 */ + USB_DEVICE(0x041e, 0x0005), + .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { + .ifnum = 1, + .type = QUIRK_AUDIO_FIXED_ENDPOINT, + .data = &(const struct audioformat) { + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .channels = 2, + .iface = 1, + .altsetting = 1, + .altset_idx = 1, + .endpoint = 0x03, + .ep_attr = USB_ENDPOINT_XFER_ISOC, + .attributes = 0, + .rates = SNDRV_PCM_RATE_CONTINUOUS, + .rate_min = 48000, + .rate_max = 48000, + } + } +}, + /* Creative/Toshiba Multimedia Center SB-0500 */ { USB_DEVICE(0x041e, 0x3048), @@ -99,6 +121,42 @@ }, /* + * HP Wireless Audio + * When not ignored, causes instability issues for some users, forcing them to + * blacklist the entire module. + */ +{ + USB_DEVICE(0x0424, 0xb832), + .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { + .vendor_name = "Standard Microsystems Corp.", + .product_name = "HP Wireless Audio", + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const struct snd_usb_audio_quirk[]) { + /* Mixer */ + { + .ifnum = 0, + .type = QUIRK_IGNORE_INTERFACE, + }, + /* Playback */ + { + .ifnum = 1, + .type = QUIRK_IGNORE_INTERFACE, + }, + /* Capture */ + { + .ifnum = 2, + .type = QUIRK_IGNORE_INTERFACE, + }, + /* HID Device, .ifnum = 3 */ + { + .ifnum = -1, + } + } + } +}, + +/* * Logitech QuickCam: bDeviceClass is vendor-specific, so generic interface * class matches do not take effect without an explicit ID match. */ @@ -1457,6 +1515,40 @@ YAMAHA_DEVICE(0x7010, "UB99"), } }, { + /* Advanced mode of the Roland VG-99, with MIDI and 24-bit PCM at 44.1 + * kHz. In standard mode, the device has ID 0582:00b3, and offers + * 16-bit PCM at 44.1 kHz with no MIDI. + */ + USB_DEVICE(0x0582, 0x00b2), + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + .vendor_name = "Roland", + .product_name = "VG-99", + .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 = 0x0003, + .in_cables = 0x0003 + } + }, + { + .ifnum = -1 + } + } + } +}, +{ /* Roland SonicCell */ USB_DEVICE(0x0582, 0x00c2), .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { @@ -1658,7 +1750,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { /* .vendor_name = "Roland", */ /* .product_name = "A-PRO", */ - .ifnum = 1, + .ifnum = 0, .type = QUIRK_MIDI_FIXED_ENDPOINT, .data = & (const struct snd_usb_midi_endpoint_info) { .out_cables = 0x0003, @@ -2163,6 +2255,77 @@ YAMAHA_DEVICE(0x7010, "UB99"), } }, { + USB_DEVICE_VENDOR_SPEC(0x0763, 0x2030), + .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { + /* .vendor_name = "M-Audio", */ + /* .product_name = "Fast Track C400", */ + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = &(const struct snd_usb_audio_quirk[]) { + { + .ifnum = 1, + .type = QUIRK_AUDIO_STANDARD_MIXER, + }, + /* Playback */ + { + .ifnum = 2, + .type = QUIRK_AUDIO_FIXED_ENDPOINT, + .data = &(const struct audioformat) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 6, + .iface = 2, + .altsetting = 1, + .altset_idx = 1, + .attributes = UAC_EP_CS_ATTR_SAMPLE_RATE, + .endpoint = 0x01, + .ep_attr = 0x09, + .rates = SNDRV_PCM_RATE_44100 | + SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_88200 | + SNDRV_PCM_RATE_96000, + .rate_min = 44100, + .rate_max = 96000, + .nr_rates = 4, + .rate_table = (unsigned int[]) { + 44100, 48000, 88200, 96000 + }, + .clock = 0x80, + } + }, + /* Capture */ + { + .ifnum = 3, + .type = QUIRK_AUDIO_FIXED_ENDPOINT, + .data = &(const struct audioformat) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 4, + .iface = 3, + .altsetting = 1, + .altset_idx = 1, + .attributes = UAC_EP_CS_ATTR_SAMPLE_RATE, + .endpoint = 0x81, + .ep_attr = 0x05, + .rates = SNDRV_PCM_RATE_44100 | + SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_88200 | + SNDRV_PCM_RATE_96000, + .rate_min = 44100, + .rate_max = 96000, + .nr_rates = 4, + .rate_table = (unsigned int[]) { + 44100, 48000, 88200, 96000 + }, + .clock = 0x80, + } + }, + /* MIDI */ + { + .ifnum = -1 /* Interface = 4 */ + } + } + } +}, +{ USB_DEVICE_VENDOR_SPEC(0x0763, 0x2080), .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { /* .vendor_name = "M-Audio", */ @@ -2780,6 +2943,93 @@ YAMAHA_DEVICE(0x7010, "UB99"), } }, + +/* DIGIDESIGN MBOX 2 */ +{ + USB_DEVICE(0x0dba, 0x3000), + .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { + .vendor_name = "Digidesign", + .product_name = "Mbox 2", + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const struct snd_usb_audio_quirk[]) { + { + .ifnum = 0, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 1, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 2, + .type = QUIRK_AUDIO_FIXED_ENDPOINT, + .data = &(const struct audioformat) { + .formats = SNDRV_PCM_FMTBIT_S24_3BE, + .channels = 2, + .iface = 2, + .altsetting = 2, + .altset_idx = 1, + .attributes = 0x00, + .endpoint = 0x03, + .ep_attr = USB_ENDPOINT_SYNC_ASYNC, + .maxpacksize = 0x128, + .rates = SNDRV_PCM_RATE_48000, + .rate_min = 48000, + .rate_max = 48000, + .nr_rates = 1, + .rate_table = (unsigned int[]) { + 48000 + } + } + }, + { + .ifnum = 3, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 4, + .type = QUIRK_AUDIO_FIXED_ENDPOINT, + .data = &(const struct audioformat) { + .formats = SNDRV_PCM_FMTBIT_S24_3BE, + .channels = 2, + .iface = 4, + .altsetting = 2, + .altset_idx = 1, + .attributes = UAC_EP_CS_ATTR_SAMPLE_RATE, + .endpoint = 0x85, + .ep_attr = USB_ENDPOINT_SYNC_SYNC, + .maxpacksize = 0x128, + .rates = SNDRV_PCM_RATE_48000, + .rate_min = 48000, + .rate_max = 48000, + .nr_rates = 1, + .rate_table = (unsigned int[]) { + 48000 + } + } + }, + { + .ifnum = 5, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 6, + .type = QUIRK_MIDI_MIDIMAN, + .data = &(const struct snd_usb_midi_endpoint_info) { + .out_ep = 0x02, + .out_cables = 0x0001, + .in_ep = 0x81, + .in_interval = 0x01, + .in_cables = 0x0001 + } + }, + { + .ifnum = -1 + } + } + } +}, { /* Tascam US122 MKII - playback-only support */ .match_flags = USB_DEVICE_ID_MATCH_DEVICE, @@ -2880,6 +3130,99 @@ YAMAHA_DEVICE(0x7010, "UB99"), } }, +/* Reloop Play */ +{ + USB_DEVICE(0x200c, 0x100b), + .bInterfaceClass = USB_CLASS_PER_INTERFACE, + .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_MIXER, + }, + { + .ifnum = 1, + .type = QUIRK_AUDIO_FIXED_ENDPOINT, + .data = &(const struct audioformat) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 4, + .iface = 1, + .altsetting = 1, + .altset_idx = 1, + .attributes = UAC_EP_CS_ATTR_SAMPLE_RATE, + .endpoint = 0x01, + .ep_attr = USB_ENDPOINT_SYNC_ADAPTIVE, + .rates = SNDRV_PCM_RATE_44100 | + SNDRV_PCM_RATE_48000, + .rate_min = 44100, + .rate_max = 48000, + .nr_rates = 2, + .rate_table = (unsigned int[]) { + 44100, 48000 + } + } + }, + { + .ifnum = -1 + } + } + } +}, + +{ + /* + * Focusrite Scarlett 18i6 + * + * Avoid mixer creation, which otherwise fails because some of + * the interface descriptor subtypes for interface 0 are + * unknown. That should be fixed or worked-around but this at + * least allows the device to be used successfully with a DAW + * and an external mixer. See comments below about other + * ignored interfaces. + */ + USB_DEVICE(0x1235, 0x8004), + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + .vendor_name = "Focusrite", + .product_name = "Scarlett 18i6", + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = & (const struct snd_usb_audio_quirk[]) { + { + /* InterfaceSubClass 1 (Control Device) */ + .ifnum = 0, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 1, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + }, + { + .ifnum = 2, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + }, + { + /* InterfaceSubClass 1 (Control Device) */ + .ifnum = 3, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 4, + .type = QUIRK_MIDI_STANDARD_INTERFACE + }, + { + /* InterfaceSubClass 1 (Device Firmware Update) */ + .ifnum = 5, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = -1 + } + } + } +}, + { /* * Some USB MIDI devices don't have an audio control interface, diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index 0f58b4b6d702..2c971858d6b7 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -387,11 +387,13 @@ static int snd_usb_fasttrackpro_boot_quirk(struct usb_device *dev) * rules */ err = usb_driver_set_configuration(dev, 2); - if (err < 0) { + if (err < 0) snd_printdd("error usb_driver_set_configuration: %d\n", err); - return -ENODEV; - } + /* Always return an error, so that we stop creating a device + that will just be destroyed and recreated with a new + configuration */ + return -ENODEV; } else snd_printk(KERN_INFO "usb-audio: Fast Track Pro config OK\n"); @@ -497,6 +499,92 @@ static int snd_usb_nativeinstruments_boot_quirk(struct usb_device *dev) return -EAGAIN; } +static void mbox2_setup_48_24_magic(struct usb_device *dev) +{ + u8 srate[3]; + u8 temp[12]; + + /* Choose 48000Hz permanently */ + srate[0] = 0x80; + srate[1] = 0xbb; + srate[2] = 0x00; + + /* Send the magic! */ + snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), + 0x01, 0x22, 0x0100, 0x0085, &temp, 0x0003); + snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), + 0x81, 0xa2, 0x0100, 0x0085, &srate, 0x0003); + snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), + 0x81, 0xa2, 0x0100, 0x0086, &srate, 0x0003); + snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), + 0x81, 0xa2, 0x0100, 0x0003, &srate, 0x0003); + return; +} + +/* Digidesign Mbox 2 needs to load firmware onboard + * and driver must wait a few seconds for initialisation. + */ + +#define MBOX2_FIRMWARE_SIZE 646 +#define MBOX2_BOOT_LOADING 0x01 /* Hard coded into the device */ +#define MBOX2_BOOT_READY 0x02 /* Hard coded into the device */ + +static int snd_usb_mbox2_boot_quirk(struct usb_device *dev) +{ + struct usb_host_config *config = dev->actconfig; + int err; + u8 bootresponse[12]; + int fwsize; + int count; + + fwsize = le16_to_cpu(get_cfg_desc(config)->wTotalLength); + + if (fwsize != MBOX2_FIRMWARE_SIZE) { + snd_printk(KERN_ERR "usb-audio: Invalid firmware size=%d.\n", fwsize); + return -ENODEV; + } + + snd_printd("usb-audio: Sending Digidesign Mbox 2 boot sequence...\n"); + + count = 0; + bootresponse[0] = MBOX2_BOOT_LOADING; + while ((bootresponse[0] == MBOX2_BOOT_LOADING) && (count < 10)) { + msleep(500); /* 0.5 second delay */ + snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), + /* Control magic - load onboard firmware */ + 0x85, 0xc0, 0x0001, 0x0000, &bootresponse, 0x0012); + if (bootresponse[0] == MBOX2_BOOT_READY) + break; + snd_printd("usb-audio: device not ready, resending boot sequence...\n"); + count++; + } + + if (bootresponse[0] != MBOX2_BOOT_READY) { + snd_printk(KERN_ERR "usb-audio: Unknown bootresponse=%d, or timed out, ignoring device.\n", bootresponse[0]); + return -ENODEV; + } + + snd_printdd("usb-audio: device initialised!\n"); + + err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, + &dev->descriptor, sizeof(dev->descriptor)); + config = dev->actconfig; + if (err < 0) + snd_printd("error usb_get_descriptor: %d\n", err); + + err = usb_reset_configuration(dev); + if (err < 0) + snd_printd("error usb_reset_configuration: %d\n", err); + snd_printdd("mbox2_boot: new boot length = %d\n", + le16_to_cpu(get_cfg_desc(config)->wTotalLength)); + + mbox2_setup_48_24_magic(dev); + + snd_printk(KERN_INFO "usb-audio: Digidesign Mbox 2: 24bit 48kHz"); + + return 0; /* Successful boot */ +} + /* * Setup quirks */ @@ -573,7 +661,6 @@ static int audiophile_skip_setting_quirk(struct snd_usb_audio *chip, return 0; /* keep this altsetting */ } - static int fasttrackpro_skip_setting_quirk(struct snd_usb_audio *chip, int iface, int altno) { @@ -655,6 +742,10 @@ int snd_usb_apply_boot_quirk(struct usb_device *dev, case USB_ID(0x0ccd, 0x00b1): /* Terratec Aureon 7.1 USB */ return snd_usb_cm6206_boot_quirk(dev); + case USB_ID(0x0dba, 0x3000): + /* Digidesign Mbox 2 */ + return snd_usb_mbox2_boot_quirk(dev); + case USB_ID(0x133e, 0x0815): /* Access Music VirusTI Desktop */ return snd_usb_accessmusic_boot_quirk(dev); @@ -675,7 +766,7 @@ int snd_usb_apply_boot_quirk(struct usb_device *dev, */ int snd_usb_is_big_endian_format(struct snd_usb_audio *chip, struct audioformat *fp) { - /* it depends on altsetting wether the device is big-endian or not */ + /* it depends on altsetting whether the device is big-endian or not */ switch (chip->usb_id) { case USB_ID(0x0763, 0x2001): /* M-Audio Quattro: captured data only */ if (fp->altsetting == 2 || fp->altsetting == 3 || @@ -770,6 +861,17 @@ void snd_usb_endpoint_start_quirk(struct snd_usb_endpoint *ep) if ((le16_to_cpu(ep->chip->dev->descriptor.idVendor) == 0x23ba) && ep->type == SND_USB_ENDPOINT_TYPE_SYNC) ep->skip_packets = 4; + + /* + * M-Audio Fast Track C400 - when packets are not skipped, real world + * latency varies by approx. +/- 50 frames (at 96KHz) each time the + * stream is (re)started. When skipping packets 16 at endpoint start + * up, the real world latency is stable within +/- 1 frame (also + * across power cycles). + */ + if (ep->chip->usb_id == USB_ID(0x0763, 0x2030) && + ep->type == SND_USB_ENDPOINT_TYPE_DATA) + ep->skip_packets = 16; } void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe, diff --git a/sound/usb/stream.c b/sound/usb/stream.c index 1de0c8c002a8..ad181d538bd9 100644 --- a/sound/usb/stream.c +++ b/sound/usb/stream.c @@ -23,6 +23,8 @@ #include <sound/core.h> #include <sound/pcm.h> +#include <sound/control.h> +#include <sound/tlv.h> #include "usbaudio.h" #include "card.h" @@ -47,6 +49,7 @@ static void free_substream(struct snd_usb_substream *subs) list_for_each_safe(p, n, &subs->fmt_list) { struct audioformat *fp = list_entry(p, struct audioformat, list); kfree(fp->rate_table); + kfree(fp->chmap); kfree(fp); } kfree(subs->rate_list.list); @@ -99,6 +102,206 @@ static void snd_usb_init_substream(struct snd_usb_stream *as, subs->num_formats++; subs->fmt_type = fp->fmt_type; subs->ep_num = fp->endpoint; + if (fp->channels > subs->channels_max) + subs->channels_max = fp->channels; +} + +/* kctl callbacks for usb-audio channel maps */ +static int usb_chmap_ctl_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol); + struct snd_usb_substream *subs = info->private_data; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = subs->channels_max; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = SNDRV_CHMAP_LAST; + return 0; +} + +/* check whether a duplicated entry exists in the audiofmt list */ +static bool have_dup_chmap(struct snd_usb_substream *subs, + struct audioformat *fp) +{ + struct list_head *p; + + for (p = fp->list.prev; p != &subs->fmt_list; p = p->prev) { + struct audioformat *prev; + prev = list_entry(p, struct audioformat, list); + if (prev->chmap && + !memcmp(prev->chmap, fp->chmap, sizeof(*fp->chmap))) + return true; + } + return false; +} + +static int usb_chmap_ctl_tlv(struct snd_kcontrol *kcontrol, int op_flag, + unsigned int size, unsigned int __user *tlv) +{ + struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol); + struct snd_usb_substream *subs = info->private_data; + struct audioformat *fp; + unsigned int __user *dst; + int count = 0; + + if (size < 8) + return -ENOMEM; + if (put_user(SNDRV_CTL_TLVT_CONTAINER, tlv)) + return -EFAULT; + size -= 8; + dst = tlv + 2; + list_for_each_entry(fp, &subs->fmt_list, list) { + int i, ch_bytes; + + if (!fp->chmap) + continue; + if (have_dup_chmap(subs, fp)) + continue; + /* copy the entry */ + ch_bytes = fp->chmap->channels * 4; + if (size < 8 + ch_bytes) + return -ENOMEM; + if (put_user(SNDRV_CTL_TLVT_CHMAP_FIXED, dst) || + put_user(ch_bytes, dst + 1)) + return -EFAULT; + dst += 2; + for (i = 0; i < fp->chmap->channels; i++, dst++) { + if (put_user(fp->chmap->map[i], dst)) + return -EFAULT; + } + + count += 8 + ch_bytes; + size -= 8 + ch_bytes; + } + if (put_user(count, tlv + 1)) + return -EFAULT; + return 0; +} + +static int usb_chmap_ctl_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol); + struct snd_usb_substream *subs = info->private_data; + struct snd_pcm_chmap_elem *chmap = NULL; + int i; + + memset(ucontrol->value.integer.value, 0, + sizeof(ucontrol->value.integer.value)); + if (subs->cur_audiofmt) + chmap = subs->cur_audiofmt->chmap; + if (chmap) { + for (i = 0; i < chmap->channels; i++) + ucontrol->value.integer.value[i] = chmap->map[i]; + } + return 0; +} + +/* create a chmap kctl assigned to the given USB substream */ +static int add_chmap(struct snd_pcm *pcm, int stream, + struct snd_usb_substream *subs) +{ + struct audioformat *fp; + struct snd_pcm_chmap *chmap; + struct snd_kcontrol *kctl; + int err; + + list_for_each_entry(fp, &subs->fmt_list, list) + if (fp->chmap) + goto ok; + /* no chmap is found */ + return 0; + + ok: + err = snd_pcm_add_chmap_ctls(pcm, stream, NULL, 0, 0, &chmap); + if (err < 0) + return err; + + /* override handlers */ + chmap->private_data = subs; + kctl = chmap->kctl; + kctl->info = usb_chmap_ctl_info; + kctl->get = usb_chmap_ctl_get; + kctl->tlv.c = usb_chmap_ctl_tlv; + + return 0; +} + +/* convert from USB ChannelConfig bits to ALSA chmap element */ +static struct snd_pcm_chmap_elem *convert_chmap(int channels, unsigned int bits, + int protocol) +{ + static unsigned int uac1_maps[] = { + SNDRV_CHMAP_FL, /* left front */ + SNDRV_CHMAP_FR, /* right front */ + SNDRV_CHMAP_FC, /* center front */ + SNDRV_CHMAP_LFE, /* LFE */ + SNDRV_CHMAP_SL, /* left surround */ + SNDRV_CHMAP_SR, /* right surround */ + SNDRV_CHMAP_FLC, /* left of center */ + SNDRV_CHMAP_FRC, /* right of center */ + SNDRV_CHMAP_RC, /* surround */ + SNDRV_CHMAP_SL, /* side left */ + SNDRV_CHMAP_SR, /* side right */ + SNDRV_CHMAP_TC, /* top */ + 0 /* terminator */ + }; + static unsigned int uac2_maps[] = { + SNDRV_CHMAP_FL, /* front left */ + SNDRV_CHMAP_FR, /* front right */ + SNDRV_CHMAP_FC, /* front center */ + SNDRV_CHMAP_LFE, /* LFE */ + SNDRV_CHMAP_RL, /* back left */ + SNDRV_CHMAP_RR, /* back right */ + SNDRV_CHMAP_FLC, /* front left of center */ + SNDRV_CHMAP_FRC, /* front right of center */ + SNDRV_CHMAP_RC, /* back center */ + SNDRV_CHMAP_SL, /* side left */ + SNDRV_CHMAP_SR, /* side right */ + SNDRV_CHMAP_TC, /* top center */ + SNDRV_CHMAP_TFL, /* top front left */ + SNDRV_CHMAP_TFC, /* top front center */ + SNDRV_CHMAP_TFR, /* top front right */ + SNDRV_CHMAP_TRL, /* top back left */ + SNDRV_CHMAP_TRC, /* top back center */ + SNDRV_CHMAP_TRR, /* top back right */ + SNDRV_CHMAP_TFLC, /* top front left of center */ + SNDRV_CHMAP_TFRC, /* top front right of center */ + SNDRV_CHMAP_LLFE, /* left LFE */ + SNDRV_CHMAP_RLFE, /* right LFE */ + SNDRV_CHMAP_TSL, /* top side left */ + SNDRV_CHMAP_TSR, /* top side right */ + SNDRV_CHMAP_BC, /* bottom center */ + SNDRV_CHMAP_BLC, /* bottom left center */ + SNDRV_CHMAP_BRC, /* bottom right center */ + 0 /* terminator */ + }; + struct snd_pcm_chmap_elem *chmap; + const unsigned int *maps; + int c; + + if (!bits) + return NULL; + if (channels > ARRAY_SIZE(chmap->map)) + return NULL; + + chmap = kzalloc(sizeof(*chmap), GFP_KERNEL); + if (!chmap) + return NULL; + + maps = protocol == UAC_VERSION_2 ? uac2_maps : uac1_maps; + chmap->channels = channels; + c = 0; + for (; bits && *maps; maps++, bits >>= 1) { + if (bits & 1) + chmap->map[c++] = *maps; + } + + for (; c < channels; c++) + chmap->map[c] = SNDRV_CHMAP_UNKNOWN; + + return chmap; } /* @@ -140,7 +343,7 @@ int snd_usb_add_audio_stream(struct snd_usb_audio *chip, if (err < 0) return err; snd_usb_init_substream(as, stream, fp); - return 0; + return add_chmap(as->pcm, stream, subs); } /* create a new pcm */ @@ -174,7 +377,7 @@ int snd_usb_add_audio_stream(struct snd_usb_audio *chip, snd_usb_proc_pcm_format_add(as); - return 0; + return add_chmap(pcm, stream, &as->substream[stream]); } static int parse_uac_endpoint_attributes(struct snd_usb_audio *chip, @@ -218,8 +421,11 @@ static int parse_uac_endpoint_attributes(struct snd_usb_audio *chip, return attributes; } -static struct uac2_input_terminal_descriptor * - snd_usb_find_input_terminal_descriptor(struct usb_host_interface *ctrl_iface, +/* find an input terminal descriptor (either UAC1 or UAC2) with the given + * terminal id + */ +static void * +snd_usb_find_input_terminal_descriptor(struct usb_host_interface *ctrl_iface, int terminal_id) { struct uac2_input_terminal_descriptor *term = NULL; @@ -261,6 +467,7 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no) struct audioformat *fp = NULL; int num, protocol, clock = 0; struct uac_format_type_i_continuous_descriptor *fmt; + unsigned int chconfig; dev = chip->dev; @@ -300,6 +507,7 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no) if (snd_usb_apply_interface_quirk(chip, iface_no, altno)) continue; + chconfig = 0; /* get audio formats */ switch (protocol) { default: @@ -311,6 +519,7 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no) case UAC_VERSION_1: { struct uac1_as_header_descriptor *as = snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_AS_GENERAL); + struct uac_input_terminal_descriptor *iterm; if (!as) { snd_printk(KERN_ERR "%d:%u:%d : UAC_AS_GENERAL descriptor not found\n", @@ -325,6 +534,14 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no) } format = le16_to_cpu(as->wFormatTag); /* remember the format value */ + + iterm = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf, + as->bTerminalLink); + if (iterm) { + num_channels = iterm->bNrChannels; + chconfig = le16_to_cpu(iterm->wChannelConfig); + } + break; } @@ -355,6 +572,7 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no) as->bTerminalLink); if (input_term) { clock = input_term->bCSourceID; + chconfig = le32_to_cpu(input_term->bmChannelConfig); break; } @@ -413,13 +631,13 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no) fp->ep_attr = get_endpoint(alts, 0)->bmAttributes; fp->datainterval = snd_usb_parse_datainterval(chip, alts); fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize); - /* num_channels is only set for v2 interfaces */ fp->channels = num_channels; if (snd_usb_get_speed(dev) == USB_SPEED_HIGH) fp->maxpacksize = (((fp->maxpacksize >> 11) & 3) + 1) * (fp->maxpacksize & 0x7ff); fp->attributes = parse_uac_endpoint_attributes(chip, alts, protocol, iface_no); fp->clock = clock; + fp->chmap = convert_chmap(num_channels, chconfig, protocol); /* some quirks for attributes here */ @@ -455,6 +673,7 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no) /* ok, let's parse further... */ if (snd_usb_parse_audio_format(chip, fp, format, fmt, stream, alts) < 0) { kfree(fp->rate_table); + kfree(fp->chmap); kfree(fp); fp = NULL; continue; @@ -464,6 +683,7 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no) err = snd_usb_add_audio_stream(chip, stream, fp); if (err < 0) { kfree(fp->rate_table); + kfree(fp->chmap); kfree(fp); return err; } diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index ef42797f56fb..1ac3fd9cc5a6 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -56,7 +56,6 @@ struct snd_usb_audio { int setup; /* from the 'device_setup' module param */ int nrpacks; /* from the 'nrpacks' module param */ - int async_unlink; /* from the 'async_unlink' module param */ struct usb_host_interface *ctrl_intf; /* the audio control interface */ }; |